Permalink
Browse files

Allowed options to be set temporarily

  • Loading branch information...
1 parent 9216766 commit 4707d6b3c47992a9d89ec356a24d90e4ea53e6e9 @cjheath cjheath committed Nov 16, 2010
Showing with 45 additions and 16 deletions.
  1. +11 −5 doc/using_in_ruby.markdown
  2. +3 −2 lib/treetop/runtime/compiled_parser.rb
  3. +31 −9 spec/runtime/compiled_parser_spec.rb
View
@@ -16,7 +16,10 @@ In order to use Polyglot dynamic loading of `.treetop` or `.tt` files though, yo
in order to use Polyglot auto loading with Treetop in Ruby.
##Instantiating and Using Parsers
-If a grammar by the name of `Foo` is defined, the compiled Ruby source will define a `FooParser` class. To parse input, create an instance and call its `parse` method with a string. The parser will return the syntax tree of the match or `nil` if there is a failure.
+If a grammar by the name of `Foo` is defined, the compiled Ruby source will define a `FooParser` class.
+To parse input, create an instance and call its `parse` method with a string.
+The parser will return the syntax tree of the match or `nil` if there is a failure.
+Note that by default, the parser will fail unless *all* input is consumed.
Treetop.load "arithmetic"
@@ -29,12 +32,15 @@ If a grammar by the name of `Foo` is defined, the compiled Ruby source will defi
##Parser Options
A Treetop parser has several options you may set.
-Some of these are settable by methods on the parser, and some may be passed in to the `parse` method
-(most of these *should* be available either way, but that's not currently the case).
+Some are settable permanently by methods on the parser, but all may be passed in as options to the `parse` method.
parser = ArithmeticParser.new
input = 'x = 2; y = x+3;'
+ # Temporarily override an option:
+ result1 = parser.parse(input, :consume_all_input => false)
+ puts "consumed #{parser.index} characters"
+
parser.consume_all_input = false
result1 = parser.parse(input)
puts "consumed #{parser.index} characters"
@@ -43,8 +49,8 @@ Some of these are settable by methods on the parser, and some may be passed in t
result2 = parser.parse(input, :index => parser.index)
# Parse, but match rule `variable` instead of the normal root rule:
- parser.root = :variable
- parser.parse(input)
+ parser.parse(input, :root => :variable)
+ parser.root = :variable # Permanent setting
If you have a statement-oriented language, you can save memory by parsing just one statement at a time,
and discarding the parse tree after each statement.
@@ -15,8 +15,9 @@ def initialize
def parse(input, options = {})
prepare_to_parse(input)
@index = options[:index] if options[:index]
- result = send("_nt_#{root}")
- return nil if (consume_all_input? && index != input.size)
+ result = send("_nt_#{options[:root] || root}")
+ should_consume_all = options.include?(:consume_all_input) ? options[:consume_all_input] : consume_all_input?
+ return nil if (should_consume_all && index != input.size)
return SyntaxNode.new(input, index...(index + 1)) if result == true
return result
end
@@ -3,45 +3,67 @@
module CompiledParserSpec
describe Runtime::CompiledParser, "for a grammar with two rules" do
attr_reader :parser
-
+
testing_grammar %{
grammar TwoRules
rule a
'a'
end
-
+
rule b
'b'
end
end
}
-
+
before do
@parser = parser_class_under_test.new
end
-
+
it "allows its root to be specified" do
parser.parse('a').should_not be_nil
parser.parse('b').should be_nil
-
+
+ # Check that the temporary-override works:
+ parser.parse('b', :root => :b).should_not be_nil
+ parser.parse('a', :root => :b).should be_nil
+
+ # Check that the temporary-override isn't sticky:
+ parser.parse('a').should_not be_nil
+
+ # Try a permanent override:
parser.root = :b
parser.parse('b').should_not be_nil
parser.parse('a').should be_nil
end
-
+
it "allows the requirement that all input be consumed to be disabled" do
parser.parse('ab').should be_nil
+
+ # Try a temporary override, and check it's not sticky:
+ result = parser.parse('ab', :consume_all_input => false)
+ result.should_not be_nil
+ result.interval.should == (0...1)
+ parser.parse('ab').should be_nil
+
+ # Now a permanent override:
parser.consume_all_input = false
result = parser.parse('ab')
result.should_not be_nil
result.interval.should == (0...1)
end
-
+
it "allows input to be parsed at a given index" do
parser.parse('ba').should be_nil
parser.parse('ba', :index => 1).should_not be_nil
+ # Check that the index defaults again to zero:
+ parser.parse('a').should_not be_nil
+
+ result = parser.parse('ba', :consume_all_input => false, :index => 1)
+ result.should_not be_nil
+ result.interval.should == (1...2)
end
-
+
end
describe Runtime::CompiledParser, "for a grammar with a choice between terminals" do
@@ -81,7 +103,7 @@ module CompiledParserSpec
before do
@parser = parser_class_under_test.new
end
-
+
it "is reset between parses" do
parser.parse('ac')
terminal_failures = parser.terminal_failures

0 comments on commit 4707d6b

Please sign in to comment.