Class RangeIterationHelper

java.lang.Object
org.ek9lang.compiler.phase7.generator.AbstractGenerator
org.ek9lang.compiler.phase7.generator.RangeIterationHelper

final class RangeIterationHelper extends AbstractGenerator
Shared helper for range iteration logic used by both for-range loops and stream for-range sources.

Extracts the body-independent parts of range iteration from ForRangeGenerator: initialization (start/end/by evaluation, assertions, direction detection), dispatch case generation (ascending/descending/equal), loop condition evaluation, increment operations, and body setup (loop variable assignment).

Both ForRangeGenerator and StreamStatementGenerator delegate to this helper, each providing their own body instructions. This eliminates ~500 lines of duplication between for-range loops and stream for-range sources.

  • Constructor Details

  • Method Details

    • generateInitialization

      RangeIterationHelper.InitializationData generateInitialization(EK9Parser.ForRangeContext forRangeCtx, DebugInfo debugInfo)
      Generate initialization instructions for the loop. This includes: evaluating start/end/by, asserting they're set, direction detection.
    • generateDispatchCases

      ForRangePolymorphicInstr.DispatchCases generateDispatchCases(RangeIterationHelper.InitializationData initData, String loopVariableName, DebugInfo debugInfo)
      Generate dispatch cases with explicit IR for all three directions.
    • generateLoopMetadata

      Generate loop metadata containing variable names and types.
    • generateBodySetup

      List<IRInstr> generateBodySetup(String loopVariableName, String currentTemp, ISymbol rangeType, DebugInfo debugInfo)
      Generate body setup: loopVariable becomes a FRESH per-iteration value copied from the counter.

      Per-iteration value semantics (FOR-RANGE only). The internal counter (currentTemp) is a single object advanced in place by _inc()/_dec(). If the user-visible loop variable merely aliased that counter (the old STORE loopVariable, currentTemp), any capture / alias / escape of the loop variable would track the moving counter and read the FINAL value — the classic "closure captures the loop variable" footgun. Instead we give the loop variable a fresh object each iteration: default-construct it, then populate it from the counter via :=: (_copy). Once decoupled, captures hold the value the developer expects with no escape analysis required for correctness (a dead copy is later elided by a Phase 12 pass).

      Contrast FOR-IN (ForInGenerator): its loop variable is a reference to a REAL collection element from iterator.next(), so it must NOT be copied — see that generator. The asymmetry is principled: FOR-RANGE variable = a loop-owned synthesised value (copy it); FOR-IN variable = a reference to a real element (leave it).

      Pattern: RELEASE (drop previous iteration's object, NULL-safe on first iteration) + <init>() (fresh default object into the loop variable) + _copy(currentTemp) (snapshot the counter's value) + RETAIN. Variable already registered to loop scope at declaration. See docs/ir-and-codegen/EK9_LOOP_VARIABLE_PER_ITERATION_SEMANTICS.md.