Class MustExecutePosition

java.lang.Object
org.ek9lang.compiler.support.MustExecutePosition
All Implemented Interfaces:
Predicate<org.antlr.v4.runtime.tree.ParseTree>

public final class MustExecutePosition extends Object implements Predicate<org.antlr.v4.runtime.tree.ParseTree>
THE answer to "does this code run every time its enclosing body runs?", read from its position in the parse tree. Use it wherever an analysis may only follow what ALWAYS executes; do not re-derive it. Written for FE77's construction-recursion check (E08263), where following a call that might not run would report legal, guarded recursion as an error.

The walk climbs from the node to the body it belongs to - a function, method, operator, service operation or dynamic function body, or a property initialiser - and every step must be a position that is always evaluated: a statement in a body, an initialiser, an argument, an operand, the first condition of an if, the subject of a switch, the condition and collection of a loop, a try body, a finally block, the source of a stream, its sink, a tee's side target and every stage operand written as an expression (all evaluated once, before any item is pulled).

Everything conditional answers false: if/else bodies and later conditions, case and default bodies, loop bodies (a do body too, deliberately, for now), catch blocks, the right operand of and/or/xor and of every coalescing operator, the arms of a ternary, the right of :=?, a condition after a guard, the per-item work of stream stages, and assertions.

🔑 It is a whitelist. Any position it does not recognise answers false, so a construct added to the grammar later can only make an analysis miss something, never report something that cannot happen. A code path that always throws before a call is not considered: the call still counts as executed.

Two scopes, one whitelist: new MustExecutePosition() asks "every time its BODY runs" (FE77), and withinItsStatement() asks "every time the evaluation that OWNS it runs" - the walk then ends, true, at the nearest owner: a blockStatement, or, for code in no statement at all, the initialiser of a returning variable (returningParam) or of a property (aggregateProperty), or a text's string (textBodyDeclaration). Two other differences: an assert statement's condition runs every time that statement does, and so does a do/while's condition (FE77 keeps both out). The statement form is what decides which closeable temporaries a statement or an initialiser owns (phase5/StatementOwnedCloseableCalls).

A third scope, withinItsEvaluation(), is the statement scope with one more kind of owner: an evaluation that runs only CONDITIONALLY, every time it runs (Steve, 2026-10-06: "an unnamed closeable is closed as soon as the evaluation that made it finishes"). Where the statement walk meets a conditional position and answers false, this walk answers true when that position is one of the conditionally evaluated operands IR generation wraps in its own owned region (isConditionalEvaluation(ParseTree, ParseTree)): the right of and/or/xor and of every coalescing operator, a ternary arm, a later else if condition, a condition after a guard, the right of :=?, a switch case expression. Every other conditional position still answers false.

  • Constructor Summary

    Constructors
    Constructor
    Description
    Does the code run every time its enclosing BODY runs.
  • Method Summary

    Modifier and Type
    Method
    Description
    static boolean
    isOwningEvaluation(org.antlr.v4.runtime.tree.ParseTree node)
    THE owners of the closeable temporaries made inside them (statement form only): a block statement, or what is in no statement - a returning variable's or a property's initialiser, or a text's string.
    static boolean
    Is part a stage's operand (| map with holder.mapper(), | sort with Ranked().comparator(), | head counter.limit(), a tee's transform or side target)? THE test: every stage operand written as an expression is evaluated ONCE, before any item is pulled - a function operand by StreamStatementGenerator.evaluateFunctionOperandsAhead (its captures are taken once and its state lives across items), a head/skip/tail limit and a tee's side target in the pre-loop setup (StreamPipelineMachinery) - exactly as the sink is.
    static boolean
    Is part the side target of a tee (| tee in target, its last pipelinePart)? THE test: the target is evaluated once, before any item is pulled, exactly as a stream's sink is (phase7/generator/StreamPipelineMachinery), so a closeable made there is its statement's to close.
    boolean
    test(org.antlr.v4.runtime.tree.ParseTree node)
     
    Does the code run every time the evaluation that owns it runs: its block statement (or initialiser), or the nearest conditionally evaluated operand it is part of (isConditionalEvaluation(ParseTree, ParseTree)).
    Does the code run every time the block statement it is part of runs.

    Methods inherited from class Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

    Methods inherited from interface Predicate

    and, negate, or
  • Constructor Details

    • MustExecutePosition

      public MustExecutePosition()
      Does the code run every time its enclosing BODY runs.
  • Method Details

    • withinItsStatement

      public static MustExecutePosition withinItsStatement()
      Does the code run every time the block statement it is part of runs.
    • withinItsEvaluation

      public static MustExecutePosition withinItsEvaluation()
      Does the code run every time the evaluation that owns it runs: its block statement (or initialiser), or the nearest conditionally evaluated operand it is part of (isConditionalEvaluation(ParseTree, ParseTree)).
    • test

      public boolean test(org.antlr.v4.runtime.tree.ParseTree node)
      Specified by:
      test in interface Predicate<org.antlr.v4.runtime.tree.ParseTree>
    • isOwningEvaluation

      public static boolean isOwningEvaluation(org.antlr.v4.runtime.tree.ParseTree node)
      THE owners of the closeable temporaries made inside them (statement form only): a block statement, or what is in no statement - a returning variable's or a property's initialiser, or a text's string. Public so that a rule asking "is this temporary part of that statement's evaluation?" stops exactly where this walk does (D20, E81071).
    • isTeeTarget

      public static boolean isTeeTarget(EK9Parser.PipelinePartContext part)
      Is part the side target of a tee (| tee in target, its last pipelinePart)? THE test: the target is evaluated once, before any item is pulled, exactly as a stream's sink is (phase7/generator/StreamPipelineMachinery), so a closeable made there is its statement's to close.
    • isStageOperand

      public static boolean isStageOperand(EK9Parser.PipelinePartContext part)
      Is part a stage's operand (| map with holder.mapper(), | sort with Ranked().comparator(), | head counter.limit(), a tee's transform or side target)? THE test: every stage operand written as an expression is evaluated ONCE, before any item is pulled - a function operand by StreamStatementGenerator.evaluateFunctionOperandsAhead (its captures are taken once and its state lives across items), a head/skip/tail limit and a tee's side target in the pre-loop setup (StreamPipelineMachinery) - exactly as the sink is. So a closeable made there (a receiver, an argument) is its statement's to close (the closeable route-matrix verifier, 2026-10-22: it was never closed). Only the function's CALLS run per item, and they are not written here.