IfExp¶
A conditional expression.
Declaration¶
Syntax¶
IfExp(expr test, expr body, expr orelse, ttype type, expr? value)
Arguments¶
Argument |
Description |
|---|---|
|
the condition, of a logical type. |
|
the value when the condition is true. |
|
the value when it is false. |
|
the type of the expression. Both branches have it. |
|
the compile time value of the expression, when the frontend could fold it; |
Return values¶
The value of the expression.
Description¶
The two branches have the same type, and the type of the whole expression is
theirs. IfExp is LPython’s a if c else b and the Fortran 2023 conditional
expression ( test ? body : orelse ) (10.1.2.3 R1002), and it is also
convenient for compiler-generated code.
Unlike the If statement, both branches must produce a value.
The Fortran front end only produces IfExp from an executable expression. 10.1.11 and 10.1.12 enumerate the primaries a specification expression and a constant expression may contain, and a conditional expression is in neither list, so it is rejected in a kind type parameter, a character length, an array bound and an initialization expression. IfExp therefore never carries a compile time value from the Fortran front end.
Only the chosen branch is evaluated. Fortran 2023 requires this
(10.1.4 NOTE 3): a function call in the branch that is not taken must not run,
so IfExp must never be rewritten into merge, which evaluates both of its
arguments. The multi-arm form of R1002,
( c1 ? a : c2 ? b : d ), is represented by nesting IfExp in the orelse
position.
A result that is an array, a derived type or polymorphic takes its shape,
length type parameters and dynamic type from the branch that is chosen
(10.1.4 p22-23), so there is no single descriptor a backend could write into
before the branch is known. The conditional_expr pass lowers those results
into an allocatable temporary and an If statement.
Scalars of intrinsic type, including character, reach the backends as
IfExp and are lowered there with a real branch.
Examples¶
(IfExp
:test (Var
:v (SymbolRef 1 "b")
)
:body (IntegerConstant
:n 1
:type (Integer
:kind 4
)
:intboz_type :Decimal
)
:orelse (IntegerConstant
:n 0
:type (Integer
:kind 4
)
:intboz_type :Decimal
)
:type (Integer
:kind 4
)
:value nil
)
It comes from this complete ASR text document:
(TranslationUnit
:symtab (SymbolTable
:id 0
:symbols {
"main" (Program
:symtab (SymbolTable
:id 1
:symbols {
"b" (Variable
:parent_symtab 1
:name "b"
:dependencies []
:intent :Local
:symbolic_value nil
:value nil
:storage :Default
:type (Logical
:kind 4
)
:type_declaration nil
:abi :Source
:access :Public
:presence :Required
:value_attr false
:target_attr false
:contiguous_attr false
:bindc_name nil
:is_volatile false
:is_protected false
:pass_attr :NotMethod
:self_argument nil
:codims []
)
"i" (Variable
:parent_symtab 1
:name "i"
:dependencies []
:intent :Local
:symbolic_value nil
:value nil
:storage :Default
:type (Integer
:kind 4
)
:type_declaration nil
:abi :Source
:access :Public
:presence :Required
:value_attr false
:target_attr false
:contiguous_attr false
:bindc_name nil
:is_volatile false
:is_protected false
:pass_attr :NotMethod
:self_argument nil
:codims []
)
}
)
:name "main"
:dependencies []
:body [
(Assignment
:target (Var
:v (SymbolRef 1 "i")
)
:value (IfExp
:test (Var
:v (SymbolRef 1 "b")
)
:body (IntegerConstant
:n 1
:type (Integer
:kind 4
)
:intboz_type :Decimal
)
:orelse (IntegerConstant
:n 0
:type (Integer
:kind 4
)
:intboz_type :Decimal
)
:type (Integer
:kind 4
)
:value nil
)
:overloaded nil
:realloc_lhs false
:move_allocation false
)
]
)
}
)
:items []
)