Class StreamPipelineMachinery
java.lang.Object
org.ek9lang.compiler.phase7.generator.AbstractGenerator
org.ek9lang.compiler.phase7.generator.AbstractStreamStageGenerator
org.ek9lang.compiler.phase7.generator.StreamPipelineMachinery
The pipeline machinery shared by the orchestrator and the buffered-emission engine: draining a
source to an iterator, planning the per-stage item variables, building the stream loop, and
setting up per-stage pre-loop state.
None of it touches StreamStageDispatcher, which is what lets it be a plain collaborator
both sides hold. Anything here that DID need the dispatcher would have to live with the engine
instead - that dependency is what separates the two.
-
Field Summary
Fields inherited from class AbstractStreamStageGenerator
generators, symbolTypeOrException, valuePromoterFields inherited from class AbstractGenerator
constantCopyOnAccessLoader, debugInfoCreator, instructionBuilder, MAX_MESSAGE_LENGTH, stackContext, typeNameOrException -
Constructor Summary
ConstructorsConstructorDescriptionStreamPipelineMachinery(IRGenerationContext stackContext, GeneratorSet generators) -
Method Summary
Modifier and TypeMethodDescription(package private) voidaddReferenceAndRegister(List<IRInstr> target, boolean typed, String var, String type, String scopeId, DebugInfo debugInfo) DeclarevaroftypeinscopeId(a typed reference whentyped, otherwise a plain reference) and SCOPE_REGISTER it.(package private) StringappendBoundedCondition(List<IRInstr> conditionEvaluation, List<IRInstr> leftInstructions, String leftResult, String leftPrimitive, List<IRInstr> rightInstructions, String rightResult, String scopeId, DebugInfo debugInfo) Append a short-circuitLEFT AND RIGHTBoolean condition toconditionEvaluationand return the combined Boolean result variable.(package private) StringappendHeadBoundedCondition(List<IRInstr> conditionEvaluation, List<IRInstr> managedHasNext, String hasNextResult, StageState headState, String scopeId, DebugInfo debugInfo) Append a short-circuitcounter < limit AND hasNext()condition toconditionEvaluationand return the combined Boolean result variable.(package private) ConditionAndPostLoopbuildStreamLoop(IteratorSetup iteratorSetup, StageState headState, String itemVar, ISymbol itemType, boolean rawIterator, EK9Parser.StreamCatContext catCtx, StreamLoopSink sink, DebugInfo debugInfo) The unified iterator-driven stream while-loop skeleton: condition scope (hasNext(), with an optionalheadshort-circuit folded in whenheadState != null) + body scope (binditerator.next()then theStreamLoopSinkbody-tail) + theConditionAndPostLoopthe caller feeds tocreateWhileLoop.(package private) booleanTrue if any stage is a pre-loop buffer-barrier (sort/group/split/tail) — these cannot be composed by the windowed async driver and (on an unbounded async) are rejected at phase 3.(package private) booleanTrue iffstagescontains a GROUP/SPLIT/ASYNC collection-buffer stage.(package private) DrainConditiondrainCondition(String sourceVar, String sourceTypeName, String hasNextMethod, DebugInfo debugInfo) THE drain-loop condition:source.hasNext()evaluated in its own scope.(package private) voiddrainNextIntoItem(List<IRInstr> body, String sourceVar, String sourceTypeName, String nextMethod, String castTypeName, String drainItemVar, DebugInfo debugInfo) THE drain-loop body preamble:raw = source.next()(typedAny), cast to the element type, then bound into the persistent drain item variable.(package private) IteratorSetupdrainSourceToIterator(String sourceVar, String sourceTypeName, String hasNextMethod, String nextMethod, CallDetails closeCall, ISymbol bucketType, DebugInfo debugInfo, List<IRInstr> instructions) MATERIALISE a buffering value source (a GROUP/SPLIT tracker's hasNextGroup/nextGroup, or an async executor's hasNext/next) into a fresh raw EK9_LIST buffer and return an IteratorSetup over it.(package private) ISymbolThe phase-3-resolved IN-edge (consumes) type of a stream stage, ornullif unresolved.(package private) ISymbolThe phase-3-resolved OUT-edge (produces) type of a stream stage, ornullif the stage has no recordedStreamCallSymbolor no produced type set.(package private) ISymboleffectivePostSortElementType(SortSetup sortSetup, List<EK9Parser.StreamPartContext> allStages, ISymbol sourceType) The element type the POST-sort pipeline (and terminal) observe.(package private) StageStatefindHeadStageState(List<EK9Parser.StreamPartContext> stages, List<StageState> stageStates) Locate the StageState of the first HEAD stage (carries counter/limit), or null if no HEAD present.(package private) FreshBooleanOperandfreshBooleanOperand(String boolVar, DebugInfo debugInfo) Load an alloca-backed Boolean variable into a fresh SSA temp (+ its primitive) for use as the LEFT operand ofappendBoundedCondition(List, List, String, String, List, String, String, DebugInfo).generateDynamicStageLimit(EK9Parser.StreamPartContext stageCtx, String limitVar, ISymbol integerType, String scopeId, DebugInfo debugInfo) Generate IR to evaluate a dynamic stage operand (function reference or call) and store the Integer result in the given limit variable.generatePipelineItemBinding(String iteratorVar, IAggregateSymbol iteratorType, String pipelineItemVar, ISymbol elementType, DebugInfo debugInfo, boolean rawIterator) Generate: pipelineItem = iterator.next() Follows ForInGenerator.generateLoopVariableBinding() pattern.(package private) StageSetupResultgenerateStageSetup(List<EK9Parser.StreamPartContext> stages, String scopeId, DebugInfo debugInfo) Generate pre-loop state initialization for stateful pipeline stages (HEAD, SKIPPING, TAIL).(package private) intIndex of the first GROUP/SPLIT/ASYNC collection-buffer stage instages, or -1.(package private) intIndex of the first SORT stage instages, or -1.(package private) PipelineVarPlanplanPipelineVars(List<EK9Parser.StreamPartContext> stages, String sourceVar, ISymbol sourceType, String scopeId, DebugInfo debugInfo, List<IRInstr> declarationsOut) Compute the per-boundary item-variable plan for an in-loop stage list, allocating a fresh variable (declared at the produced type) only where a stage changes the element type.(package private) SortAndIteratorResultsortBufferAndGetIterator(EK9Parser.StreamPartContext sortStage, String bufferVar, DebugInfo debugInfo) Sort a raw org.ek9.lang::List buffer in place and return an iterator over the sorted result.(package private) booleanTrue iff the NEXT buffering SORT instagesis reachable with no intervening collection-buffer (GROUP/SPLIT/ASYNC).Methods inherited from class AbstractStreamStageGenerator
addManagedCall, extractPrimitive, gate, generateCounterDelta, generateTerminalPipe, publishAndContinue, rebind, streamFunctionCall
-
Constructor Details
-
StreamPipelineMachinery
StreamPipelineMachinery(IRGenerationContext stackContext, GeneratorSet generators)
-
-
Method Details
-
drainCondition
DrainCondition drainCondition(String sourceVar, String sourceTypeName, String hasNextMethod, DebugInfo debugInfo) THE drain-loop condition:source.hasNext()evaluated in its own scope. Shared by every place that drains an iterator or an async executor into a buffer. -
drainNextIntoItem
void drainNextIntoItem(List<IRInstr> body, String sourceVar, String sourceTypeName, String nextMethod, String castTypeName, String drainItemVar, DebugInfo debugInfo) THE drain-loop body preamble:raw = source.next()(typedAny), cast to the element type, then bound into the persistent drain item variable.The item variable is declared in the DRAIN scope, not the body scope, so whatever the body pipes into a buffer outlives the iteration that produced it. Must be called with the body scope already entered - the cast registers against the current scope.
-
addReferenceAndRegister
void addReferenceAndRegister(List<IRInstr> target, boolean typed, String var, String type, String scopeId, DebugInfo debugInfo) DeclarevaroftypeinscopeId(a typed reference whentyped, otherwise a plain reference) and SCOPE_REGISTER it. Single-sources the repeated reference-then-register pair used when binding pipeline/loop variables. -
appendBoundedCondition
String appendBoundedCondition(List<IRInstr> conditionEvaluation, List<IRInstr> leftInstructions, String leftResult, String leftPrimitive, List<IRInstr> rightInstructions, String rightResult, String scopeId, DebugInfo debugInfo) Append a short-circuitLEFT AND RIGHTBoolean condition toconditionEvaluationand return the combined Boolean result variable. RIGHT is evaluated ONLY when LEFT's primitive is true (LOGICAL_AND_BLOCK short-circuit). This is the generic two-operand AND-block; callers build LEFT (the short-circuit decision: head'scounter < limit, the window'sinFlight < W, etc.) and pass its result+primitive, plus the RIGHT operand's instructions+result (e.g. the managed hasNext()). MirrorsGuardedConditionEvaluator's guard-into-condition fold. -
appendHeadBoundedCondition
String appendHeadBoundedCondition(List<IRInstr> conditionEvaluation, List<IRInstr> managedHasNext, String hasNextResult, StageState headState, String scopeId, DebugInfo debugInfo) Append a short-circuitcounter < limit AND hasNext()condition toconditionEvaluationand return the combined Boolean result variable. The counter ('LEFT') is evaluated first; hasNext() ('RIGHT') is evaluated ONLY when the counter is still below the head limit, so a satisfiedhead Nstops the loop without another (possibly blocking) hasNext()/next() on the source. Mirrors the short-circuit LOGICAL_AND_BLOCK thatGuardedConditionEvaluatoruses to fold a guard into a condition. -
buildStreamLoop
ConditionAndPostLoop buildStreamLoop(IteratorSetup iteratorSetup, StageState headState, String itemVar, ISymbol itemType, boolean rawIterator, EK9Parser.StreamCatContext catCtx, StreamLoopSink sink, DebugInfo debugInfo) The unified iterator-driven stream while-loop skeleton: condition scope (hasNext(), with an optionalheadshort-circuit folded in whenheadState != null) + body scope (binditerator.next()then theStreamLoopSinkbody-tail) + theConditionAndPostLoopthe caller feeds tocreateWhileLoop. Every iterator-based stream loop (streaming cat/for, and — after migration — the sort/group/split drains) is this skeleton differing only in headState and sink. -
containsBufferBarrier
True if any stage is a pre-loop buffer-barrier (sort/group/split/tail) — these cannot be composed by the windowed async driver and (on an unbounded async) are rejected at phase 3. -
containsBufferingCollection
True iffstagescontains a GROUP/SPLIT/ASYNC collection-buffer stage. -
drainSourceToIterator
IteratorSetup drainSourceToIterator(String sourceVar, String sourceTypeName, String hasNextMethod, String nextMethod, CallDetails closeCall, ISymbol bucketType, DebugInfo debugInfo, List<IRInstr> instructions) MATERIALISE a buffering value source (a GROUP/SPLIT tracker's hasNextGroup/nextGroup, or an async executor's hasNext/next) into a fresh raw EK9_LIST buffer and return an IteratorSetup over it. No pre-stages, no sort: each next() yields Any, is cast tobucketType, and piped into the buffer as-is. AcloseCall(async executor) fires after the drain; trackers pass null. Used to hand a collection-buffer's emitted elements toStreamEmissionEngine.continueOverIteratorso a DOWNSTREAM buffer (group|split, group|split|sort, async|split, ...) can drive them — the basis of unlimited buffer-after-buffer composition. -
edgeConsumes
The phase-3-resolved IN-edge (consumes) type of a stream stage, ornullif unresolved. Counterpart toedgeProduces(EK9Parser.StreamPartContext)— the element type ENTERING stage k. -
edgeProduces
The phase-3-resolved OUT-edge (produces) type of a stream stage, ornullif the stage has no recordedStreamCallSymbolor no produced type set. This is the SINGLE source of truth for "the element type leaving stage k": Phase 3 (StreamAssemblyOrError.streamPartOrError) stampssetProducesSymbolTypeon EVERY stage's StreamCallSymbol while threadingcurrentStreamType, so the whole typed-edge sequence already exists — read it here rather than re-deriving from the source type carried forward.edgeConsumes(EK9Parser.StreamPartContext)is the IN-edge counterpart. -
effectivePostSortElementType
ISymbol effectivePostSortElementType(SortSetup sortSetup, List<EK9Parser.StreamPartContext> allStages, ISymbol sourceType) The element type the POST-sort pipeline (and terminal) observe. SORT buffers and re-emits the type it consumes; when a type-changing stage (map/flatten/call) precedes SORT, that is the post-stage type, not the source type. Returns the SORT stage's resolved produced type when SORT is present, else the supplied source type unchanged (so non-sort pipelines and natural-type sorts are byte-identical). -
findHeadStageState
StageState findHeadStageState(List<EK9Parser.StreamPartContext> stages, List<StageState> stageStates) Locate the StageState of the first HEAD stage (carries counter/limit), or null if no HEAD present. -
freshBooleanOperand
Load an alloca-backed Boolean variable into a fresh SSA temp (+ its primitive) for use as the LEFT operand ofappendBoundedCondition(List, List, String, String, List, String, String, DebugInfo). SeeFreshBooleanOperand. -
generateDynamicStageLimit
List<IRInstr> generateDynamicStageLimit(EK9Parser.StreamPartContext stageCtx, String limitVar, ISymbol integerType, String scopeId, DebugInfo debugInfo) Generate IR to evaluate a dynamic stage operand (function reference or call) and store the Integer result in the given limit variable.For function references (
head GetThree): creates a function instance and calls it. For function calls (head GetThree()): evaluates the call expression. For Integer variables (head someVar): loads the variable value. -
generatePipelineItemBinding
List<IRInstr> generatePipelineItemBinding(String iteratorVar, IAggregateSymbol iteratorType, String pipelineItemVar, ISymbol elementType, DebugInfo debugInfo, boolean rawIterator) Generate: pipelineItem = iterator.next() Follows ForInGenerator.generateLoopVariableBinding() pattern.- Parameters:
rawIterator- true when iterating a raw org.ek9.lang.Iterator (buffered for-range), where next() returns Any and requires a cast to elementType
-
generateStageSetup
StageSetupResult generateStageSetup(List<EK9Parser.StreamPartContext> stages, String scopeId, DebugInfo debugInfo) Generate pre-loop state initialization for stateful pipeline stages (HEAD, SKIPPING, TAIL). Creates counter, limit, and one-constant variables for HEAD/SKIP stages. For TAIL, creates a bounded Ek9Tail circular buffer viaEk9Tail.create(tailLimit). Returns pre-loop instructions and per-stage state (null for stateless stages). -
indexOfFirstCollectionBuffer
Index of the first GROUP/SPLIT/ASYNC collection-buffer stage instages, or -1. -
indexOfFirstSort
Index of the first SORT stage instages, or -1. -
planPipelineVars
PipelineVarPlan planPipelineVars(List<EK9Parser.StreamPartContext> stages, String sourceVar, ISymbol sourceType, String scopeId, DebugInfo debugInfo, List<IRInstr> declarationsOut) Compute the per-boundary item-variable plan for an in-loop stage list, allocating a fresh variable (declared at the produced type) only where a stage changes the element type. Fresh-variable declarations (REFERENCE + SCOPE_REGISTER) are appended todeclarationsOut; the caller emits them once before the loop body. Type-preserving stages reuse the incoming variable, so pipelines without a type-changing stage produce byte-identical IR to before. -
sortBufferAndGetIterator
SortAndIteratorResult sortBufferAndGetIterator(EK9Parser.StreamPartContext sortStage, String bufferVar, DebugInfo debugInfo) Sort a raw org.ek9.lang::List buffer in place and return an iterator over the sorted result. Shared by both cat-pipeline and for-range pipeline sort paths. Uses Ek9Sort.sort(List) for natural sort or Ek9Sort.sort(List, Any) for comparator sort. No LOAD_FIELD delegate access — works correctly for both pre-built and generated types.- Parameters:
sortStage- the SORT stage parse context (may have pipelinePart for comparator)bufferVar- variable holding the raw org.ek9.lang::List bufferdebugInfo- debug information for generated instructions- Returns:
- instructions for the sort call and iterator creation, plus the new iterator setup
-
sortReachableBeforeBuffer
True iff the NEXT buffering SORT instagesis reachable with no intervening collection-buffer (GROUP/SPLIT/ASYNC). Those three stages own the sort that follows them — they buffer and emit in their own pre-loop path, where a downstream SORT is handled separately — so the source-drain sort loop must NOT drain through them (it would treat the GROUP/SPLIT/ASYNC as a no-op pre-sort stage and corrupt the stream). A SORT before any such buffer IS the source-drain loop's to handle. Used as the multi-sort loop condition sosort | map | sortkeeps draining butsort | group | sortstops at the group (leaving the trailing sort on postSortStages for the group path).
-