Class ComparisonCoalescingOperatorAsmGenerator
<?, >?, <=?, >=?).
Handles CONTROL_FLOW_CHAIN with chain_type: "LESS_THAN_COALESCING_OPERATOR",
"GREATER_THAN_COALESCING_OPERATOR", "LESS_EQUAL_COALESCING_OPERATOR",
or "GREATER_EQUAL_COALESCING_OPERATOR".
EK9 Comparison Coalescing Operator Patterns:
lhs <? rhs- Returns lesser value, gracefully handling null/unsetlhs >? rhs- Returns greater value, gracefully handling null/unsetlhs <=? rhs- Returns LHS if less-or-equal, else RHS, handling null/unsetlhs >=? rhs- Returns LHS if greater-or-equal, else RHS, handling null/unset
Comparison Logic for lhs <? rhs:
- If LHS is null → returns RHS
- If LHS is not null BUT unset → returns RHS
- If RHS is null → returns LHS
- If RHS is not null BUT unset → returns LHS
- If LHS < RHS → returns LHS (lesser value)
- Otherwise → returns RHS
Key Differences from Other Coalescing Operators:
- Null coalescing (??) - 1 case (NULL check only)
- Elvis coalescing (:?) - 1 case (LHS absent or not set, via the null-safe
?) - Comparison coalescing (<?, >?, <=?, >=?) - 3 cases (each operand absent or not set, then the comparison)
IR Structure (example for <? operator). Each operand is generated ONCE: both are evaluated before any
case (every path evaluates both, exactly once); "absent or not set" is the null-safe ? - a nested
QUESTION_OPERATOR chain, IS_NULL before _isSet() - inverted. Generating the RHS per case, as this once
did, made a nested chain grow as 3^n.
CONTROL_FLOW_CHAIN [chain_type: "LESS_THAN_COALESCING_OPERATOR"]
condition_chain:
[case 1: case_type: "EXPRESSION"]
condition_evaluation: [LOAD lhs, lhs_set = QUESTION_OPERATOR(lhs), LOAD rhs, CALL lhs_set._false()]
condition_result: lhs_set (EK9 Boolean)
primitive_condition: lhs_not_set
body_evaluation: [RETAIN rhs]
body_result: rhs
[case 2: case_type: "EXPRESSION"]
condition_evaluation: [rhs_set = QUESTION_OPERATOR(rhs), CALL rhs_set._false()]
condition_result: rhs_set (EK9 Boolean)
primitive_condition: rhs_not_set
body_evaluation: [RETAIN lhs]
body_result: lhs
[case 3: case_type: "EXPRESSION"]
condition_evaluation: [CALL lhs._cmp(rhs), CALL cmp._lt(0), CALL result._true()]
condition_result: comparison (EK9 Boolean)
primitive_condition: is_less_than
body_evaluation: [RETAIN lhs]
body_result: lhs
default_body_evaluation: [RETAIN rhs]
default_result: rhs
Safety: the null-safe ? never calls _isSet() on an absent operand.
Stack Frame Invariant: All paths arrive at 'end' label with empty stack. Result is stored in local variable (overall_result).
-
Field Summary
Fields inherited from class AbstractControlFlowAsmGenerator
contextFields inherited from class AbstractAsmGenerator
classWriter, constructTargetTuple, outputVisitor -
Constructor Summary
ConstructorsConstructorDescriptionComparisonCoalescingOperatorAsmGenerator(ConstructTargetTuple constructTargetTuple, OutputVisitor outputVisitor, org.objectweb.asm.ClassWriter classWriter, BytecodeGenerationContext context) -
Method Summary
Modifier and TypeMethodDescriptionvoidgenerate(ControlFlowChainInstr instr) Generate bytecode for comparison coalescing operators (<?, >?, <=?, >=?).Methods inherited from class AbstractControlFlowAsmGenerator
branchIfFalse, branchIfTrue, copyResultVariable, createControlFlowLabel, generateCoalescingPattern, jumpTo, placeLabel, processBodyEvaluation, processConditionCase, processConditionCaseWithoutLabelPlacement, processConditionEvaluation, processInstructions, processSequentialCaseChainMethods inherited from class AbstractAsmGenerator
convertToJvmDescriptor, convertToJvmName, extractFieldName, generateBooleanLiteral, generateCharacterLiteral, generateDebugInfo, generateFloatLiteral, generateIntegerLiteral, generateLoadVariable, generateLocalVariableTable, generateMethodDescriptor, generateObjectLiteral, generateStackOperation, generateStoreVariable, generateStoreVariableAsInt, generateStringLiteral, getCurrentMethodVisitor, getFieldDescriptor, getMethodContext, getOrCreateLabel, getOwnerClassName, getVariableIndex, isFieldAccess, isVariableAllocated, isVariableFieldAccess, setCurrentMethodVisitor, setSharedMethodContext, toJvmFieldName, trackTempVariableFromLiteral, trackTempVariableFromLoad
-
Constructor Details
-
ComparisonCoalescingOperatorAsmGenerator
ComparisonCoalescingOperatorAsmGenerator(ConstructTargetTuple constructTargetTuple, OutputVisitor outputVisitor, org.objectweb.asm.ClassWriter classWriter, BytecodeGenerationContext context)
-
-
Method Details
-
generate
Generate bytecode for comparison coalescing operators (<?, >?, <=?, >=?).Uses the common coalescing pattern from AbstractControlFlowAsmGenerator with an operator-specific label prefix.
Stack Frame Invariant: Pre-condition: stack is empty Post-condition: stack is empty (result in local variable)
- Parameters:
instr- CONTROL_FLOW_CHAIN instruction with comparison coalescing type
-