I have a Treetop PEG grammar that matches some keys. I want to look up the values associated with those keys in a hash I give the parser. How can I make it so that the syntax nodes have access to methods or variables from the parser?
For example, here's a simple grammar that finds a single word and tries to look up its value:
# var.treetop
grammar VarResolver
include VarLookup
rule variable
[a-zA-Z] [a-zA-Z0-9_]*
{
def value
p found:text_value
find_variable(text_value)
end
}
end
end
Here's a test file using it:
# test.rb
require 'treetop'
module VarLookup
def set_variables(variable_hash)
@vars = variable_hash
end
def find_variable(str)
@vars[str.to_sym]
end
end
Treetop.load('var.treetop')
@p = VarResolverParser.new
@p.set_variables name:'Phrogz'
p @p.parse('name').value
Running this test, I get the output:
{:found=>"name"}
(eval):16:in `value': undefined method `find_variable'
for #<Treetop::Runtime::SyntaxNode:0x00007f88e091b340> (NoMethodError)
How can I make find_variable
accessible inside the value
method? (In the real parser, these rules are deeply nested, and need to resolve the value without returning the actual name to the top of the parse tree. I cannot just return the text_value
and look it up outside.)
This is a significant weakness in the design of Treetop.
I (as maintainer) didn't want to slow it down further by passing yet another argument to every SyntaxNode, and break any custom SyntaxNode classes folk have written. These constructors get the "input" object, a Range that selects part of that input, and optionally an array of child SyntaxNodes. They should have received the Parser itself instead of the input as a member.
So instead, for my own use (some years back), I made a custom proxy for the "input" and attached my Context to it. You might get away with doing something similar:
https://github.com/cjheath/activefacts-cql/blob/master/lib/activefacts/cql/parser.rb#L203-L249