Grammar.GLR.GSS (IchorRuntime v0.1.0)

Copy Markdown View Source

The graph-structured stack itself: nodes keyed by {state, stream_position} (deduplicated -- two derivations that reach the same state at the same position share one node, the actual efficiency win over independent parallel stacks), edges labeled with whatever that edge's own transition produced (a shifted %Grammar.VM.Token{}, or a reduced nonterminal's own already-built captures map) plus the provenance accumulated along it so far.

A node can have more than one incoming edge exactly when two previously-distinct derivations converge (a shift/reduce or reduce/reduce conflict both survived, or two different reduce paths happen to land on the same state and position) -- that's genuine local ambiguity, not a bug, and paths/3's whole job is enumerating every distinct way to walk backward through however many edges a reduce needs to pop, independently for each of a node's incoming edges.

Positions live on the node identity itself ({state, position}), not on the edge -- which is what makes a :text-kind capture's span (Grammar.LRTable.Captures) derivable per RHS position directly from the two nodes an edge connects, with no separate bookkeeping needed.

Summary

Functions

Adds an edge from -> to labeled value/provenance, unless an identical one already exists.

Every distinct length-k backward path from node: {origin_node, entries, combined_provenance}, entries in left-to-right (RHS) order as Grammar.LRTable.Captures.entry() triples ({value, start_pos, end_pos}, the span read straight off the two nodes each edge connects). More than one result means the popped span was reached via more than one derivation -- local ambiguity, resolved later by comparing accumulated provenance, not decided here.

Types

edge()

@type edge() :: {node_id(), term(), provenance()}

node_id()

@type node_id() :: {Grammar.LRTable.state_id(), non_neg_integer()}

provenance()

@type provenance() :: [non_neg_integer()]

t()

@type t() :: %Grammar.GLR.GSS{edges: %{required(node_id()) => [edge()]}}

Functions

add_edge(gss, from, to, value, provenance)

@spec add_edge(t(), node_id(), node_id(), term(), provenance()) :: t()

Adds an edge from -> to labeled value/provenance, unless an identical one already exists.

incoming(gss, node)

@spec incoming(t(), node_id()) :: [edge()]

new()

@spec new() :: t()

paths(gss, node, k)

@spec paths(t(), node_id(), non_neg_integer()) :: [
  {node_id(), [Grammar.LRTable.Captures.entry()], provenance()}
]

Every distinct length-k backward path from node: {origin_node, entries, combined_provenance}, entries in left-to-right (RHS) order as Grammar.LRTable.Captures.entry() triples ({value, start_pos, end_pos}, the span read straight off the two nodes each edge connects). More than one result means the popped span was reached via more than one derivation -- local ambiguity, resolved later by comparing accumulated provenance, not decided here.