Class ValueTrackingAnalyzer
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 Summary
ConstructorsConstructorDescriptionCreate a new analyzer (inactive until a callable scope is entered). -
Method Summary
Modifier and TypeMethodDescriptionvoidEnter a branching construct (if/switch).voidEnter a callable scope (function, method, operator).voidEnter a catch block.voidEnter a loop body.voidenterTry()Enter a try block.evaluateCondition(AbstractValue left, String operator, AbstractValue right) Evaluate a condition between two abstract values.evaluateIsSet(ISymbol symbol) Evaluate the isSet state of a variable based on its tracked value.voidExit a branching construct.voidExit a branching construct where only the true branch existed (no else).voidExit a callable scope.voidexitLoop()Exit a loop body.voidExit a try/catch construct.Get the current abstract value for a variable.booleanisActive()Check if the analyzer is currently tracking within a callable scope.booleanCheck if currently inside a loop body.booleanCheck if the current program point is unreachable.voidMark the current state as unreachable (after a throw statement).voidnarrowForCondition(ISymbol symbol, String operator, long operandValue, boolean isTrueBranch) Narrow a variable's value based on a comparison condition on the true branch.voidnarrowForIsSet(ISymbol symbol, boolean isTrueBranch) Narrow a variable's value based on an isSet check.voidrecordAssignment(ISymbol symbol, AbstractValue abstractValue) Record a variable assignment with a known constant value.voidrecordUnknownAssignment(ISymbol symbol) Record a variable assignment to an unknown value (function call result, etc.).voidregisterModuleConstant(ISymbol symbol, AbstractValue abstractValue) Register a module-level constant (from defines constant blocks).voidRecord 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).
-
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
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 symbolabstractValue- the constant's value
-
recordAssignment
Record a variable assignment with a known constant value.- Parameters:
symbol- the variable being assignedabstractValue- the abstract value being assigned
-
recordUnknownAssignment
Record a variable assignment to an unknown value (function call result, etc.). Sets the variable to TOP. -
getValue
Get the current abstract value for a variable. Checks the current scope state first, then falls back to module-level constants. -
evaluateCondition
Evaluate a condition between two abstract values.- Parameters:
left- the left operand valueoperator- the comparison operatorright- the right operand value- Returns:
- TRUE if always satisfied, FALSE if never, UNKNOWN if indeterminate
-
evaluateIsSet
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
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 checkedisTrueBranch- 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 variablecountis narrowed toRange(11, MAX)on the true path. For==, the variable is narrowed to the exact constant value.- Parameters:
symbol- the variable being comparedoperator- the comparison operatoroperandValue- the integer value being compared againstisTrueBranch- 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.
-