Class: PackratParser::Rule
- Defined in:
- lib/packrat_parser/parser.rb
Overview
A lazy, memoizing reference to a named grammar rule.
Rule methods on a PackratParser subclass return a Rule instead of building
their combinator immediately. This is essential: a comprehension evaluates
its generator receivers eagerly (to call flat_map/map on them), so a
self-referential rule like additive would recurse forever at build time if
the body ran on every reference. Returning a lazy Rule breaks that cycle.
Memoizing the result per (rule, pos) gives the packrat property: each rule is evaluated at most once per input position, so parsing stays linear.
The combinator graph is rebuilt on every (memo-missed) entry rather than
cached, and that is deliberate. The for ... then comprehension's loop
variables currently leak into the enclosing rule-method scope instead of
being block-local, so a single built closure shares those slots. If the same
closure were reused for a recursive activation (e.g. additive calling
additive), the inner activation would clobber the outer's leaked variables.
Building fresh gives each activation its own scope. The rebuild is bounded:
result memoization means a build happens at most once per (rule, pos).
NOTE: this rebuild is a workaround for the loop-variable leak in the fork's
comprehension (parse.y: new_for_comp_gen leaves the loop var in the
surrounding scope, like the legacy for). If the comprehension is changed to
make loop variables block-local, this clobbering goes away and built can be
cached once per (owner, name) again -- e.g. @owner.__built[@name] ||= ....
Instance Method Summary collapse
- #call(input, pos) ⇒ Object
-
#initialize(owner, name, body) ⇒ Rule
constructor
A new instance of Rule.
Methods inherited from Parser
#+, #<<, #>>, #filter, #flat_map, #map, #|
Constructor Details
#initialize(owner, name, body) ⇒ Rule
Returns a new instance of Rule.
128 129 130 131 132 |
# File 'lib/packrat_parser/parser.rb', line 128 def initialize(owner, name, body) @owner = owner @name = name @body = body end |
Instance Method Details
#call(input, pos) ⇒ Object
134 135 136 137 138 139 140 |
# File 'lib/packrat_parser/parser.rb', line 134 def call(input, pos) memo = @owner.__memo key = [@name, pos] return memo[key] if memo.key?(key) combinator = @body.bind(@owner).call memo[key] = combinator.call(input, pos) end |