Class ComparisonCoalescingOperatorAsmGenerator
java.lang.Object
org.ek9lang.compiler.backend.jvm.AbstractAsmGenerator
org.ek9lang.compiler.backend.jvm.AbstractControlFlowAsmGenerator
org.ek9lang.compiler.backend.jvm.ComparisonCoalescingOperatorAsmGenerator
Specialized generator for EK9 comparison coalescing operators (
<?, >?, <=?, >=?).
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 (:?) - 2 cases (NULL + IS_SET on LHS only)
- Comparison coalescing (<?, >?, <=?, >=?) - 5 cases (NULL + IS_SET on BOTH operands + comparison)
IR Structure (example for <? operator):
CONTROL_FLOW_CHAIN [chain_type: "LESS_THAN_COALESCING_OPERATOR"]
condition_chain:
[case 1: case_type: "NULL_CHECK"]
condition_evaluation: [LOAD lhs, IS_NULL lhs]
primitive_condition: lhs_is_null
body_evaluation: [LOAD rhs]
body_result: rhs
[case 2: case_type: "EXPRESSION"]
condition_evaluation: [CALL lhs._isSet(), CALL result._false()]
condition_result: lhs_isSet (EK9 Boolean)
primitive_condition: lhs_not_set (inverted)
body_evaluation: [LOAD rhs]
body_result: rhs
[case 3: case_type: "NULL_CHECK"]
condition_evaluation: [LOAD rhs, IS_NULL rhs]
primitive_condition: rhs_is_null
body_evaluation: [] // LHS already loaded
body_result: lhs
[case 4: case_type: "EXPRESSION"]
condition_evaluation: [CALL rhs._isSet(), CALL result._false()]
condition_result: rhs_isSet (EK9 Boolean)
primitive_condition: rhs_not_set (inverted)
body_evaluation: [] // LHS already loaded
body_result: lhs
[case 5: case_type: "EXPRESSION"]
condition_evaluation: [CALL lhs._lt(rhs), CALL result._true()]
condition_result: comparison (EK9 Boolean)
primitive_condition: is_less_than
body_evaluation: [] // LHS already loaded
body_result: lhs
default_body_evaluation: [LOAD rhs]
default_result: rhs
Safety: NULL_CHECK cases always precede _isSet() calls to prevent accessing unallocated memory.
Stack Frame Invariant: All paths arrive at 'end' label with empty stack. Result is stored in local variable (overall_result).
-
Nested Class Summary
Nested classes/interfaces inherited from class AbstractAsmGenerator
AbstractAsmGenerator.LocalVariableInfo, AbstractAsmGenerator.MethodContext, AbstractAsmGenerator.ScopeInfo, AbstractAsmGenerator.TempVariableSource -
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, jumpTo, placeLabel, processBodyEvaluation, processConditionCase, processConditionCaseWithoutLabelPlacement, processConditionEvaluation, processInstructionsMethods inherited from class AbstractAsmGenerator
convertToJvmDescriptor, convertToJvmName, extractFieldName, generateBooleanLiteral, generateCharacterLiteral, generateDebugInfo, generateFloatLiteral, generateIntegerLiteral, generateLoadVariable, generateLocalVariableTable, generateMethodDescriptor, generateObjectLiteral, generateStackOperation, generateStoreVariable, generateStringLiteral, getCurrentMethodVisitor, getFieldDescriptor, getMethodContext, getOrCreateLabel, getOwnerClassName, getVariableIndex, isFieldAccess, isVariableAllocated, setCurrentMethodVisitor, setSharedMethodContext, 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 (<?, >?, <=?, >=?).Bytecode Pattern (example for
<?):// Case 1: Check if LHS is null ALOAD lhs_index IFNONNULL lhs_not_null_label // NULL case: load RHS ALOAD rhs_index ASTORE result_index GOTO end_label lhs_not_null_label: // Case 2: Check if LHS is set ALOAD lhs_index INVOKEVIRTUAL _isSet() INVOKEVIRTUAL _false() // Inverted: if NOT set ILOAD invertedPrimitive_index IFEQ lhs_is_set_label // UNSET case: load RHS ALOAD rhs_index ASTORE result_index GOTO end_label lhs_is_set_label: // Case 3: Check if RHS is null ALOAD rhs_index IFNONNULL rhs_not_null_label // NULL case: load LHS ALOAD lhs_index ASTORE result_index GOTO end_label rhs_not_null_label: // Case 4: Check if RHS is set ALOAD rhs_index INVOKEVIRTUAL _isSet() INVOKEVIRTUAL _false() // Inverted: if NOT set ILOAD invertedPrimitive_index IFEQ rhs_is_set_label // UNSET case: load LHS ALOAD lhs_index ASTORE result_index GOTO end_label rhs_is_set_label: // Case 5: Perform comparison (LHS < RHS) ALOAD lhs_index ALOAD rhs_index INVOKEVIRTUAL _lt(RHS_type) INVOKEVIRTUAL _true() ILOAD comparison_index IFEQ comparison_false_label // COMPARISON TRUE: load LHS ALOAD lhs_index ASTORE result_index GOTO end_label comparison_false_label: // COMPARISON FALSE: load RHS (default case) ALOAD rhs_index ASTORE result_index end_label: // result now holds correct value
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
-