Class BytecodeGenerationContext

java.lang.Object
org.ek9lang.compiler.backend.jvm.BytecodeGenerationContext

public class BytecodeGenerationContext extends Object
Context stack for bytecode generation control flow. Mirrors IRGenerationContext pattern from IR generation phase.

Manages stack of control flow contexts (loop, switch, try-catch, if-chain) allowing nested generators to query enclosing context for label information.

Phase 1: Loop support only (fixes nested if in for-range bug).

  • Constructor Details

    • BytecodeGenerationContext

      public BytecodeGenerationContext()
  • Method Details

    • enterLoop

      public void enterLoop(String scopeId, org.objectweb.asm.Label continueLabel, org.objectweb.asm.Label exitLabel)
      Enter loop context BEFORE processing loop body.
      Parameters:
      scopeId - Unique scope identifier (e.g., "for_loop_123")
      continueLabel - Where to jump for next iteration (increment point)
      exitLabel - Where to jump when loop exits naturally
    • exitLoop

      public void exitLoop()
      Exit loop context AFTER processing loop body. Must be called in finally block to ensure cleanup.
    • isInsideLoop

      public boolean isInsideLoop()
      Query: Are we currently inside a loop.
      Returns:
      true if any enclosing frame is a loop
    • getLoopContinueLabel

      public Optional<org.objectweb.asm.Label> getLoopContinueLabel()
      Get enclosing loop's continue label. Used by nested control flow (if statements) to determine where to jump after body.
      Returns:
      Continue label of nearest enclosing loop, or empty if not in loop
    • getLoopExitLabel

      public Optional<org.objectweb.asm.Label> getLoopExitLabel()
      Get enclosing loop's exit label. Used for early loop exit scenarios (future).
      Returns:
      Exit label of nearest enclosing loop, or empty if not in loop
    • enterDispatchCase

      public void enterDispatchCase(BytecodeGenerationContext.DispatchCase dispatchCase)
      Enter FOR_RANGE dispatch case BEFORE processing body for that case. Makes label names unique when same body IR is processed three times.
      Parameters:
      dispatchCase - Which dispatch case is being generated (EQUAL, ASCENDING, DESCENDING)
    • exitDispatchCase

      public void exitDispatchCase()
      Exit FOR_RANGE dispatch case AFTER processing body. Must be called in finally block to ensure cleanup.
    • getCurrentDispatchCase

      public Optional<BytecodeGenerationContext.DispatchCase> getCurrentDispatchCase()
      Query: Which FOR_RANGE dispatch case are we in? Used by label generation to make names unique per dispatch case.
      Returns:
      Current dispatch case, or empty if not in FOR_RANGE dispatch
    • isInside

      public boolean isInside(BytecodeFrameType frameType)
      Query: Are we inside a specific frame type.
      Parameters:
      frameType - Frame type to check for
      Returns:
      true if any enclosing frame matches type
    • findFrame

      public Optional<BytecodeStackFrame> findFrame(BytecodeFrameType frameType)
      Find nearest enclosing frame of specific type.
      Parameters:
      frameType - Frame type to search for
      Returns:
      Nearest matching frame, or empty if not found
    • getCurrentScopeId

      public Optional<String> getCurrentScopeId()
      Get current scope ID (top of stack).
      Returns:
      Current scope ID, or empty if stack is empty
    • getAllScopeIds

      public List<String> getAllScopeIds()
      Get all scope IDs in stack order (for debugging).
      Returns:
      List of scope IDs from top to bottom of stack
    • isEmpty

      public boolean isEmpty()
      Check if stack is empty (for validation).
      Returns:
      true if no frames on stack