@@ -135,14 +135,13 @@ register_r2f_handler(
135135
136136# ---- binary logical operators ----
137137
138- # TODO: the scalar || probably need some more type checking.
139138# TODO: gfortran supports implicit casting that of logical to integer when
140139# assigning a logical to a variable declared integer, converting `.true.` to `1`,
141140# but this is not a standard language feature, and Intel's `ifort` uses `-1` for `.true`.
142141# We should explicitly use
143142# `merge(1_c_int, 0_c_int, <lgl>)` to cast logical to int.
144143register_r2f_handler(
145- c(" &" , " && " , " | " , " | |" ),
144+ c(" &" , " |" ),
146145 function (args , scope , ... , hoist = NULL ) {
147146 args <- lapply(args , r2f , scope , ... , hoist = hoist )
148147 args <- lapply(args , function (a ) {
@@ -162,17 +161,65 @@ register_r2f_handler(
162161 scalarize_one_by_one = FALSE
163162 )
164163
165- operator <- switch (
166- last(list (... )$ calls ),
167- `&` = ,
168- `&&` = " .and." ,
169- `|` = ,
170- `||` = " .or."
171- )
164+ operator <- switch (last(list (... )$ calls ), `&` = " .and." , `|` = " .or." )
172165
173166 s <- glue(" {left} {operator} {right}" )
174167 val <- conform(left @ value , right @ value )
175168 val @ mode <- " logical"
176169 Fortran(s , val )
177170 }
178171)
172+
173+ andor_operand_is_length_one <- function (x ) {
174+ passes_as_scalar(x @ value ) ||
175+ x @ value @ rank > 0L &&
176+ all(vapply(x @ value @ dims , dim_is_one , logical (1L )))
177+ }
178+
179+ scalarize_andor_operand <- function (x , op , hoist ) {
180+ if (is.null(x @ value ) || ! identical(x @ value @ mode , " logical" )) {
181+ stop(" `" , op , " ` requires logical operands" , call. = FALSE )
182+ }
183+ if (! andor_operand_is_length_one(x )) {
184+ stop(
185+ " `" ,
186+ op ,
187+ " ` requires length-1 operands; use `" ,
188+ if (op == " &&" ) " &" else " |" ,
189+ " ` for elementwise operations" ,
190+ call. = FALSE
191+ )
192+ }
193+ if (passes_as_scalar(x @ value )) {
194+ return (booleanize_logical_as_int(x ))
195+ }
196+ if (is.null(hoist )) {
197+ stop(" internal error: `" , op , " ` requires hoist context" , call. = FALSE )
198+ }
199+
200+ if (isTRUE(x @ logical_booleanized )) {
201+ tmp <- hoist $ declare_tmp(mode = " logical" , dims = x @ value @ dims )
202+ hoist $ emit(glue(" {tmp@name} = {x}" ))
203+ x <- Fortran(tmp @ name , tmp )
204+ } else {
205+ x <- hoist_unless_name(x , hoist )
206+ }
207+ idxs <- rep(" 1" , x @ value @ rank )
208+ Fortran(
209+ glue(" {x}({str_flatten_commas(idxs)})" ),
210+ Variable(" logical" )
211+ )
212+ }
213+
214+ register_r2f_handler(
215+ c(" &&" , " ||" ),
216+ function (args , scope , ... , hoist = NULL ) {
217+ op <- last(list (... )$ calls )
218+ stopifnot(length(args ) == 2L , op %in% c(" &&" , " ||" ))
219+ . [left , right ] <- lapply(args , r2f , scope , ... , hoist = hoist )
220+ left <- scalarize_andor_operand(left , op , hoist )
221+ right <- scalarize_andor_operand(right , op , hoist )
222+ operator <- if (op == " &&" ) " .and." else " .or."
223+ Fortran(glue(" {left} {operator} {right}" ), Variable(" logical" ))
224+ }
225+ )
0 commit comments