flowrep.parsers.symbol_scope module
- class flowrep.parsers.symbol_scope.SymbolConsumption(symbol: str, consumer_node: str, consumer_port: str, source: flowrep.edge_models.InputSource | flowrep.edge_models.SourceHandle)[source]
Bases:
object- consumer_node: str
- consumer_port: str
- source: InputSource | SourceHandle
- symbol: str
- class flowrep.parsers.symbol_scope.SymbolProduction(output_port: str, source: flowrep.edge_models.SourceHandle | flowrep.edge_models.InputSource)[source]
Bases:
object- output_port: str
- source: SourceHandle | InputSource
- class flowrep.parsers.symbol_scope.SymbolScope(sources: dict[str, InputSource | SourceHandle], available_accumulators: set[str] | None = None, reserved_accumulators: set[str] | None = None)[source]
Bases:
Mapping[str,InputSource|SourceHandle]Tracks which symbols are in scope and where their data comes from.
Immutable-ish: forking for child scopes (e.g. for-node bodies) returns a new instance with remapped symbols.
Accumulators follow a three-stage lifecycle: - declared_accumulators: locally declared via
acc = []. Owned by this scopeand passed to child scopes as available_accumulators on fork.
- available_accumulators: inherited from the parent scope’s declared_accumulators.
These are the only accumulators a scope is allowed to
.append()to. This guarantees that an accumulator is only consumable one nesting level below its declaration, preventing grandparent accumulator access.
- consumed_accumulators: maps
accumulator_name → appended_symbol. Populated by use_accumulator()and read by the parent to finalise control-flow node outputs.
- consumed_accumulators: maps
- property all_accumulators: set[str]
- property assigned_symbols: list[str]
Identify symbols that were assigned (registered to child nodes) locally.
In a forked scope every inherited symbol starts as an
InputSource. Any key whose source is now aSourceHandlemust have been assigned by a node inside the branch.
- consume(symbol: str, consumer_node: str, consumer_port: str) None[source]
Record that consumer_node.consumer_port reads from symbol.
- property edges: dict[TargetHandle, SourceHandle]
- fork(symbol_remap: dict[str, str] | None = None, available_accumulators: set[str] | None = None) SymbolScope[source]
Create a child scope for a nested control-flow body.
Every symbol in the current
_sourcesis carried over as a freshInputSourcein the child. symbol_remap allows renaming symbols in transit (e.g. a for-loop replacing the iterable symbol with the iteration variable).Accumulator propagation is controlled explicitly via available_accumulators. For-loop bodies pass the parent’s
declared_accumulatorsso the body can.append(); while-loop and if/else bodies passNone(the default) to start with an empty set, since those control-flow models do not support cross-iteration accumulation.The parent’s
available_accumulatorsare always added to the child’sreserved_accumulatorsso that erroneous grandparent access is caught with a clear error rather than silently ignored.
- property input_edges: dict[TargetHandle, InputSource]
- property inputs: list[str]
Ordered unique symbols consumed from InputSources.
- property output_edges: dict[OutputTarget, SourceHandle | InputSource]
- property outputs: list[str]
Ordered unique output port names.
- produce(output_port: str, symbol: str | None = None) None[source]
Record that output_port is sourced from symbol.
- produce_symbols(symbols: list[str]) None[source]
Record that an output port of the same name is sources from each symbol.
- register(new_symbols: list[str], child: LabeledRecipe) None[source]
Map new symbols 1:1 to child node outputs. Enforces uniqueness.