Class ComparisonCoalescingOperatorAsmGenerator


final class ComparisonCoalescingOperatorAsmGenerator extends AbstractControlFlowAsmGenerator
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/unset
  • lhs >? rhs - Returns greater value, gracefully handling null/unset
  • lhs <=? rhs - Returns LHS if less-or-equal, else RHS, handling null/unset
  • lhs >=? rhs - Returns LHS if greater-or-equal, else RHS, handling null/unset

Comparison Logic for lhs <? rhs:

  1. If LHS is null → returns RHS
  2. If LHS is not null BUT unset → returns RHS
  3. If RHS is null → returns LHS
  4. If RHS is not null BUT unset → returns LHS
  5. If LHS < RHS → returns LHS (lesser value)
  6. 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).

  • Constructor Details

  • Method Details

    • generate

      public void generate(ControlFlowChainInstr instr)
      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