Class ValueTrackingAnalyzer

java.lang.Object
org.ek9lang.compiler.phase5.flow.ValueTrackingAnalyzer

public final class ValueTrackingAnalyzer extends Object
Tracks variable values through control flow for tautological condition detection.

Maintains a constraint state per program point and manages branch splitting/joining as control flow constructs (if/else, switch, while, for, try/catch) are entered and exited. This is a single-pass AST walk analyzer that exploits EK9's perfectly nested SESE control flow (no break/continue/return/goto) for O(N) analysis.

Phase 1 tracks: Integer, Boolean, and String constants. Variables assigned from function calls or non-pure mutations become TOP (unknown).

The analyzer is scoped per function/method/operator. It is reset when entering a new callable scope and produces results at expression evaluation points within that scope.

  • Constructor Details

    • ValueTrackingAnalyzer

      public ValueTrackingAnalyzer()
      Create a new analyzer (inactive until a callable scope is entered).
  • Method Details

    • enterCallableScope

      public void enterCallableScope()
      Enter a callable scope (function, method, operator). Resets the analyzer state for a fresh analysis.
    • exitCallableScope

      public void exitCallableScope()
      Exit a callable scope.
    • isActive

      public boolean isActive()
      Check if the analyzer is currently tracking within a callable scope.
    • registerModuleConstant

      public void registerModuleConstant(ISymbol symbol, AbstractValue abstractValue)
      Register a module-level constant (from defines constant blocks). These persist across callable scope resets and are available for value lookups.
      Parameters:
      symbol - the constant symbol
      abstractValue - the constant's value
    • recordAssignment

      public void recordAssignment(ISymbol symbol, AbstractValue abstractValue)
      Record a variable assignment with a known constant value.
      Parameters:
      symbol - the variable being assigned
      abstractValue - the abstract value being assigned
    • recordUnknownAssignment

      public void recordUnknownAssignment(ISymbol symbol)
      Record a variable assignment to an unknown value (function call result, etc.). Sets the variable to TOP.
    • getValue

      public AbstractValue getValue(ISymbol symbol)
      Get the current abstract value for a variable. Checks the current scope state first, then falls back to module-level constants.
    • evaluateCondition

      public ConditionResult evaluateCondition(AbstractValue left, String operator, AbstractValue right)
      Evaluate a condition between two abstract values.
      Parameters:
      left - the left operand value
      operator - the comparison operator
      right - the right operand value
      Returns:
      TRUE if always satisfied, FALSE if never, UNKNOWN if indeterminate
    • evaluateIsSet

      public ConditionResult evaluateIsSet(ISymbol symbol)
      Evaluate the isSet state of a variable based on its tracked value.

      A variable is provably SET if it holds a ConstantValue, RangeValue, or SetStateValue(SET). A variable is provably UNSET only if it holds SetStateValue(UNSET). Otherwise, the result is UNKNOWN.

      Parameters:
      symbol - the variable to check
      Returns:
      TRUE if provably SET, FALSE if provably UNSET, UNKNOWN otherwise
    • narrowForIsSet

      public void narrowForIsSet(ISymbol symbol, boolean isTrueBranch)
      Narrow a variable's value based on an isSet check.

      On the true branch (isSet is true), records the variable as SET. On the false branch (isSet is false), records the variable as UNSET. If the variable already has a more precise value (ConstantValue, RangeValue), preserves the more precise value on the true branch.

      Parameters:
      symbol - the variable being checked
      isTrueBranch - true for the true/if branch, false for the else branch
    • narrowForCondition

      public void narrowForCondition(ISymbol symbol, String operator, long operandValue, boolean isTrueBranch)
      Narrow a variable's value based on a comparison condition on the true branch.

      When entering if count > 10, the variable count is narrowed to Range(11, MAX) on the true path. For ==, the variable is narrowed to the exact constant value.

      Parameters:
      symbol - the variable being compared
      operator - the comparison operator
      operandValue - the integer value being compared against
      isTrueBranch - true for the true/if branch, false for the else branch
    • enterBranch

      public void enterBranch()
      Enter a branching construct (if/switch). Pushes the current state as a snapshot for the false/else branch and creates a new scope for tracking branch exit states.
    • switchToAlternateBranch

      public void switchToAlternateBranch()
      Record the end of the current branch (e.g., end of if-body) and switch to the alternative branch state (e.g., else-body or else-if).

      Saves the current state as a branch exit state and restores the pre-branch snapshot for the alternative path. The pre-branch state remains on the stack for subsequent alternate branches (else-if chains).

    • exitBranch

      public void exitBranch()
      Exit a branching construct. Joins the current branch state with all accumulated branch exit states from this nesting level.

      Call this after the final branch (else/default) has been processed.

    • exitBranchNoAlternate

      public void exitBranchNoAlternate()
      Exit a branching construct where only the true branch existed (no else).

      When there is no else clause, the false path retains the pre-branch state. Join the true-branch exit with the pre-branch snapshot.

    • enterTry

      public void enterTry()
      Enter a try block. Snapshots the pre-try state for catch block entry and creates a scope for tracking try/catch exit states.
    • enterCatch

      public void enterCatch()
      Enter a catch block. Restores the pre-try snapshot (conservative).

      The catch handler can be entered from any exception-throwing point in the try body, so the constraint state reverts to the pre-try snapshot. This is always sound: may miss optimizable cases but never false-positives.

    • exitTryCatch

      public void exitTryCatch()
      Exit a try/catch construct. Joins the try-exit and catch-exit states.
    • isInsideLoop

      public boolean isInsideLoop()
      Check if currently inside a loop body. Used to suppress tautology detection inside loops because widening has not yet been applied — variables still hold their pre-loop constant values during the first pass through the body.
    • enterLoop

      public void enterLoop()
      Enter a loop body. Snapshots the pre-loop state.
    • exitLoop

      public void exitLoop()
      Exit a loop body. Applies widening: any variable whose value changed during the loop body is widened to TOP.

      Uses bounded widening (2 passes max): if pre-loop value differs from post-body value, the variable is widened to TOP. This is sound for EK9 because loops have no break/continue — the body always fully executes or not at all.

    • markUnreachable

      public void markUnreachable()
      Mark the current state as unreachable (after a throw statement). Subsequent code in the same block is dead.
    • isUnreachable

      public boolean isUnreachable()
      Check if the current program point is unreachable.