treetop 0.1.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +3 -0
- data/Rakefile +35 -0
- data/bin/tt +25 -0
- data/lib/treetop.rb +10 -6
- data/lib/treetop/compiler.rb +7 -0
- data/lib/treetop/compiler/grammar_compiler.rb +21 -0
- data/lib/treetop/compiler/lexical_address_space.rb +17 -0
- data/lib/treetop/compiler/load_grammar.rb +7 -0
- data/lib/treetop/compiler/metagrammar.rb +2441 -0
- data/lib/treetop/compiler/metagrammar.treetop +384 -0
- data/lib/treetop/compiler/node_classes.rb +18 -0
- data/lib/treetop/compiler/node_classes/anything_symbol.rb +10 -0
- data/lib/treetop/compiler/node_classes/atomic_expression.rb +9 -0
- data/lib/treetop/compiler/node_classes/character_class.rb +10 -0
- data/lib/treetop/compiler/node_classes/choice.rb +31 -0
- data/lib/treetop/compiler/node_classes/declaration_sequence.rb +24 -0
- data/lib/treetop/compiler/node_classes/grammar.rb +28 -0
- data/lib/treetop/compiler/node_classes/inline_module.rb +27 -0
- data/lib/treetop/compiler/node_classes/nonterminal.rb +11 -0
- data/lib/treetop/compiler/node_classes/optional.rb +19 -0
- data/lib/treetop/compiler/node_classes/parenthesized_expression.rb +9 -0
- data/lib/treetop/compiler/node_classes/parsing_expression.rb +132 -0
- data/lib/treetop/compiler/node_classes/parsing_rule.rb +55 -0
- data/lib/treetop/compiler/node_classes/predicate.rb +45 -0
- data/lib/treetop/compiler/node_classes/repetition.rb +56 -0
- data/lib/treetop/compiler/node_classes/sequence.rb +64 -0
- data/lib/treetop/compiler/node_classes/terminal.rb +10 -0
- data/lib/treetop/compiler/node_classes/treetop_file.rb +9 -0
- data/lib/treetop/compiler/ruby_builder.rb +109 -0
- data/lib/treetop/ruby_extensions.rb +2 -0
- data/lib/treetop/ruby_extensions/string.rb +19 -0
- data/lib/treetop/runtime.rb +9 -0
- data/lib/treetop/runtime/compiled_parser.rb +66 -0
- data/lib/treetop/runtime/node_cache.rb +27 -0
- data/lib/treetop/runtime/parse_cache.rb +19 -0
- data/lib/treetop/runtime/parse_failure.rb +32 -0
- data/lib/treetop/runtime/parse_result.rb +30 -0
- data/lib/treetop/runtime/syntax_node.rb +53 -0
- data/lib/treetop/runtime/terminal_parse_failure.rb +33 -0
- data/lib/treetop/runtime/terminal_syntax_node.rb +12 -0
- data/test/compilation_target/target.rb +143 -0
- data/test/compilation_target/target.treetop +15 -0
- data/test/compilation_target/target_test.rb +56 -0
- data/test/compiler/and_predicate_test.rb +33 -0
- data/test/compiler/anything_symbol_test.rb +24 -0
- data/test/compiler/character_class_test.rb +45 -0
- data/test/compiler/choice_test.rb +49 -0
- data/test/compiler/circular_compilation_test.rb +20 -0
- data/test/compiler/failure_propagation_functional_test.rb +20 -0
- data/test/compiler/grammar_compiler_test.rb +58 -0
- data/test/compiler/grammar_test.rb +33 -0
- data/test/compiler/nonterminal_symbol_test.rb +15 -0
- data/test/compiler/not_predicate_test.rb +35 -0
- data/test/compiler/one_or_more_test.rb +30 -0
- data/test/compiler/optional_test.rb +32 -0
- data/test/compiler/parsing_rule_test.rb +30 -0
- data/test/compiler/sequence_test.rb +68 -0
- data/test/compiler/terminal_symbol_test.rb +35 -0
- data/test/compiler/test_grammar.treetop +7 -0
- data/test/compiler/zero_or_more_test.rb +51 -0
- data/test/composition/a.treetop +11 -0
- data/test/composition/b.treetop +11 -0
- data/test/composition/c.treetop +10 -0
- data/test/composition/d.treetop +10 -0
- data/test/composition/grammar_composition_test.rb +23 -0
- data/test/parser/syntax_node_test.rb +53 -0
- data/test/parser/terminal_parse_failure_test.rb +22 -0
- data/test/ruby_extensions/string_test.rb +33 -0
- data/test/screw/Rakefile +16 -0
- data/test/screw/unit.rb +37 -0
- data/test/screw/unit/assertion_failed_error.rb +14 -0
- data/test/screw/unit/assertions.rb +615 -0
- data/test/screw/unit/auto_runner.rb +227 -0
- data/test/screw/unit/collector.rb +45 -0
- data/test/screw/unit/collector/dir.rb +107 -0
- data/test/screw/unit/collector/objectspace.rb +28 -0
- data/test/screw/unit/error.rb +48 -0
- data/test/screw/unit/failure.rb +45 -0
- data/test/screw/unit/sugar.rb +25 -0
- data/test/screw/unit/test_case.rb +176 -0
- data/test/screw/unit/test_result.rb +73 -0
- data/test/screw/unit/test_suite.rb +70 -0
- data/test/screw/unit/ui.rb +4 -0
- data/test/screw/unit/ui/console/test_runner.rb +118 -0
- data/test/screw/unit/ui/fox/test_runner.rb +268 -0
- data/test/screw/unit/ui/gtk/test_runner.rb +416 -0
- data/test/screw/unit/ui/gtk2/testrunner.rb +465 -0
- data/test/screw/unit/ui/test_runner_mediator.rb +58 -0
- data/test/screw/unit/ui/test_runner_utilities.rb +46 -0
- data/test/screw/unit/ui/tk/test_runner.rb +260 -0
- data/test/screw/unit/util.rb +4 -0
- data/test/screw/unit/util/backtrace_filter.rb +40 -0
- data/test/screw/unit/util/observable.rb +82 -0
- data/test/screw/unit/util/proc_wrapper.rb +48 -0
- data/test/test_helper.rb +89 -0
- metadata +127 -69
- data/lib/treetop/api.rb +0 -3
- data/lib/treetop/api/load_grammar.rb +0 -16
- data/lib/treetop/api/malformed_grammar_exception.rb +0 -9
- data/lib/treetop/grammar.rb +0 -7
- data/lib/treetop/grammar/grammar.rb +0 -48
- data/lib/treetop/grammar/grammar_builder.rb +0 -35
- data/lib/treetop/grammar/parsing_expression_builder.rb +0 -5
- data/lib/treetop/grammar/parsing_expression_builder_helper.rb +0 -121
- data/lib/treetop/grammar/parsing_expressions.rb +0 -18
- data/lib/treetop/grammar/parsing_expressions/and_predicate.rb +0 -17
- data/lib/treetop/grammar/parsing_expressions/anything_symbol.rb +0 -20
- data/lib/treetop/grammar/parsing_expressions/character_class.rb +0 -24
- data/lib/treetop/grammar/parsing_expressions/node_instantiating_parsing_expression.rb +0 -14
- data/lib/treetop/grammar/parsing_expressions/node_propagating_parsing_expression.rb +0 -4
- data/lib/treetop/grammar/parsing_expressions/nonterminal_symbol.rb +0 -42
- data/lib/treetop/grammar/parsing_expressions/not_predicate.rb +0 -18
- data/lib/treetop/grammar/parsing_expressions/one_or_more.rb +0 -12
- data/lib/treetop/grammar/parsing_expressions/optional.rb +0 -14
- data/lib/treetop/grammar/parsing_expressions/ordered_choice.rb +0 -27
- data/lib/treetop/grammar/parsing_expressions/parsing_expression.rb +0 -36
- data/lib/treetop/grammar/parsing_expressions/predicate.rb +0 -25
- data/lib/treetop/grammar/parsing_expressions/repeating_parsing_expression.rb +0 -29
- data/lib/treetop/grammar/parsing_expressions/sequence.rb +0 -41
- data/lib/treetop/grammar/parsing_expressions/terminal_parsing_expression.rb +0 -11
- data/lib/treetop/grammar/parsing_expressions/terminal_symbol.rb +0 -31
- data/lib/treetop/grammar/parsing_expressions/zero_or_more.rb +0 -11
- data/lib/treetop/grammar/parsing_rule.rb +0 -10
- data/lib/treetop/metagrammar.rb +0 -2
- data/lib/treetop/metagrammar/metagrammar.rb +0 -14
- data/lib/treetop/metagrammar/metagrammar.treetop +0 -320
- data/lib/treetop/parser.rb +0 -11
- data/lib/treetop/parser/node_cache.rb +0 -25
- data/lib/treetop/parser/parse_cache.rb +0 -17
- data/lib/treetop/parser/parse_failure.rb +0 -22
- data/lib/treetop/parser/parse_result.rb +0 -26
- data/lib/treetop/parser/parser.rb +0 -24
- data/lib/treetop/parser/sequence_syntax_node.rb +0 -14
- data/lib/treetop/parser/syntax_node.rb +0 -31
- data/lib/treetop/parser/terminal_parse_failure.rb +0 -18
- data/lib/treetop/parser/terminal_syntax_node.rb +0 -7
- data/lib/treetop/protometagrammar.rb +0 -16
- data/lib/treetop/protometagrammar/anything_symbol_expression_builder.rb +0 -13
- data/lib/treetop/protometagrammar/block_expression_builder.rb +0 -17
- data/lib/treetop/protometagrammar/character_class_expression_builder.rb +0 -25
- data/lib/treetop/protometagrammar/grammar_expression_builder.rb +0 -38
- data/lib/treetop/protometagrammar/nonterminal_symbol_expression_builder.rb +0 -45
- data/lib/treetop/protometagrammar/ordered_choice_expression_builder.rb +0 -21
- data/lib/treetop/protometagrammar/parsing_rule_expression_builder.rb +0 -23
- data/lib/treetop/protometagrammar/parsing_rule_sequence_expression_builder.rb +0 -14
- data/lib/treetop/protometagrammar/prefix_expression_builder.rb +0 -25
- data/lib/treetop/protometagrammar/primary_expression_builder.rb +0 -71
- data/lib/treetop/protometagrammar/protometagrammar.rb +0 -25
- data/lib/treetop/protometagrammar/sequence_expression_builder.rb +0 -37
- data/lib/treetop/protometagrammar/suffix_expression_builder.rb +0 -33
- data/lib/treetop/protometagrammar/terminal_symbol_expression_builder.rb +0 -52
- data/lib/treetop/protometagrammar/trailing_block_expression_builder.rb +0 -30
- data/lib/treetop/ruby_extension.rb +0 -11
@@ -0,0 +1,143 @@
|
|
1
|
+
class Target < Treetop::Runtime::CompiledParser
|
2
|
+
class Bar < SyntaxNode
|
3
|
+
|
4
|
+
end
|
5
|
+
|
6
|
+
|
7
|
+
attr_accessor :root
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
self.root = :foo
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse(input)
|
14
|
+
prepare_to_parse(input)
|
15
|
+
return self.send("_nt_#{root}".to_sym)
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
module FooInlineModule
|
20
|
+
def foo
|
21
|
+
'foo'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# parsing expression:
|
26
|
+
# 'a' ('b' 'c' / 'b' 'd')+ 'e'
|
27
|
+
|
28
|
+
# lexical address assignment for results
|
29
|
+
# 'a' ('b' 'c' / 'b' 'd')+ 'e'
|
30
|
+
# 5 6 8 9 10
|
31
|
+
# 4 7
|
32
|
+
# 3
|
33
|
+
# 1 2
|
34
|
+
# 0
|
35
|
+
def _nt_foo
|
36
|
+
s0, i0 = [], index
|
37
|
+
|
38
|
+
r1 = parse_terminal('a')
|
39
|
+
|
40
|
+
s0 << r1
|
41
|
+
if s0.last.success?
|
42
|
+
# begin + closure
|
43
|
+
s2, nr2, i2 = [], [], index
|
44
|
+
loop do
|
45
|
+
# begin ('b' 'c' / 'b' 'd')
|
46
|
+
nr3, i3 = [], index
|
47
|
+
# begin 'b' 'c'
|
48
|
+
s4, i4 = [], index
|
49
|
+
r5 = parse_terminal('b')
|
50
|
+
s4 << r5
|
51
|
+
if s4.last.success?
|
52
|
+
r6 = parse_terminal('c')
|
53
|
+
s4 << r6
|
54
|
+
end
|
55
|
+
|
56
|
+
if s4.last.success?
|
57
|
+
r4 = SyntaxNode.new(input, i4...index, s4)
|
58
|
+
else
|
59
|
+
self.index = i4
|
60
|
+
r4 = ParseFailure.new(input, i4, s4)
|
61
|
+
end
|
62
|
+
# end 'b' 'c'; result in r4
|
63
|
+
|
64
|
+
nr3 << r4
|
65
|
+
|
66
|
+
# test if we need to try expression 3's next alternative
|
67
|
+
if r4.success?
|
68
|
+
r3 = r4
|
69
|
+
else
|
70
|
+
# begin 'b' 'd'
|
71
|
+
s7, i7 = [], index
|
72
|
+
r8 = parse_terminal('b')
|
73
|
+
s7 << r8
|
74
|
+
if s7.last.success?
|
75
|
+
r9 = parse_terminal('d')
|
76
|
+
s7 << r9
|
77
|
+
end
|
78
|
+
|
79
|
+
if s7.last.success?
|
80
|
+
r7 = SyntaxNode.new(input, i7...index, s7)
|
81
|
+
else
|
82
|
+
self.index = i7
|
83
|
+
r7 = ParseFailure.new(input, i7, s7)
|
84
|
+
end
|
85
|
+
# end 'b' 'c'; result in r7
|
86
|
+
|
87
|
+
nr3 << r7
|
88
|
+
|
89
|
+
if r7.success?
|
90
|
+
r3 = r7
|
91
|
+
else
|
92
|
+
self.index = i3
|
93
|
+
r3 = ParseFailure.new(input, i3, nr3)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
# end ('b' 'c' / 'b' 'd'); result in r3
|
97
|
+
nr2 << r3
|
98
|
+
if r3.success?
|
99
|
+
s2 << r3
|
100
|
+
else
|
101
|
+
break
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# s2 has intermediate results of the + closure
|
106
|
+
if s2.empty?
|
107
|
+
self.index = i2
|
108
|
+
r2 = ParseFailure.new(input, i2, nr2)
|
109
|
+
else
|
110
|
+
r2 = SyntaxNode.new(input, i2...index, s2, nr2)
|
111
|
+
end
|
112
|
+
# end + closure; results in r2
|
113
|
+
|
114
|
+
s0 << r2 # put r2 on sequence
|
115
|
+
|
116
|
+
if s0.last.success?
|
117
|
+
r10 = parse_terminal('e')
|
118
|
+
s0 << r10
|
119
|
+
end
|
120
|
+
|
121
|
+
if s0.last.success?
|
122
|
+
r0 = Bar.new(input, i0...index, s0)
|
123
|
+
else
|
124
|
+
self.index = i0
|
125
|
+
r0 = ParseFailure.new(input, i0, s0)
|
126
|
+
end
|
127
|
+
# end of the sequence... r0 has a value
|
128
|
+
|
129
|
+
r0.extend(FooInlineModule)
|
130
|
+
|
131
|
+
return r0
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def _nt_optional
|
136
|
+
r1 = parse_terminal('foo')
|
137
|
+
if r1.success?
|
138
|
+
r0 = r1
|
139
|
+
else
|
140
|
+
r0 = SyntaxNode.new(input, index...index, r1.nested_failures)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
dir = File.dirname(__FILE__)
|
2
|
+
require "#{dir}/../test_helper"
|
3
|
+
|
4
|
+
require "#{dir}/target"
|
5
|
+
|
6
|
+
describe "An instance of a hand-built Bar parser" do
|
7
|
+
|
8
|
+
def setup
|
9
|
+
@parser = Target.new
|
10
|
+
end
|
11
|
+
|
12
|
+
it "can parse matching input, associating it with the correct node class and that can respond to methods from the inlined module" do
|
13
|
+
result = @parser.parse('abce')
|
14
|
+
result.should be_success
|
15
|
+
result.should be_an_instance_of(Target::Bar)
|
16
|
+
result.foo.should == 'foo'
|
17
|
+
end
|
18
|
+
|
19
|
+
it "can parse matching input that exercises foo's positive closure" do
|
20
|
+
@parser.parse('abcbcbce').should be_success
|
21
|
+
end
|
22
|
+
|
23
|
+
it "can parse matching input that exercises foo's second alternative" do
|
24
|
+
@parser.parse('abde').should be_success
|
25
|
+
end
|
26
|
+
|
27
|
+
it "fails to parse ae and returns the failure to match 'b' as its sole nested failure" do
|
28
|
+
result = @parser.parse('ae')
|
29
|
+
result.should be_failure
|
30
|
+
|
31
|
+
result.nested_failures.size.should == 1
|
32
|
+
nested_failure = result.nested_failures.first
|
33
|
+
nested_failure.index.should == 1
|
34
|
+
nested_failure.expected_string.should == 'b'
|
35
|
+
end
|
36
|
+
|
37
|
+
it "fails to parse abe and returns the failure to match 'c' or 'd' as its nested failures" do
|
38
|
+
result = @parser.parse('abe')
|
39
|
+
result.should be_failure
|
40
|
+
result.nested_failures.size.should == 2
|
41
|
+
|
42
|
+
nested_failure = result.nested_failures[0]
|
43
|
+
nested_failure.index.should == 2
|
44
|
+
nested_failure.expected_string.should == 'c'
|
45
|
+
|
46
|
+
nested_failure = result.nested_failures[1]
|
47
|
+
nested_failure.index.should == 2
|
48
|
+
nested_failure.expected_string.should == 'd'
|
49
|
+
end
|
50
|
+
|
51
|
+
it "parses the optional expression or epsilon" do
|
52
|
+
@parser.root = :optional
|
53
|
+
@parser.parse('foo').should be_success
|
54
|
+
@parser.parse('').should be_success
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'test_helper')
|
2
|
+
|
3
|
+
describe "An &-predicated terminal symbol", :extend => CompilerTestCase do
|
4
|
+
testing_expression '&"foo"'
|
5
|
+
|
6
|
+
it "successfully parses input matching the terminal symbol, returning an epsilon syntax node" do
|
7
|
+
parse('foo') do |result|
|
8
|
+
result.should be_success
|
9
|
+
result.interval.should == (0...0)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "A sequence of a terminal and an and another &-predicated terminal", :extend => CompilerTestCase do
|
15
|
+
testing_expression '"foo" &"bar"'
|
16
|
+
|
17
|
+
it "matches input matching both terminals, but only consumes the first" do
|
18
|
+
parse('foobar') do |result|
|
19
|
+
result.should be_success
|
20
|
+
result.text_value.should == 'foo'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it "fails to parse input matching only the first terminal, with the nested failure of the second" do
|
25
|
+
parse('foo') do |result|
|
26
|
+
result.should be_failure
|
27
|
+
result.nested_failures.size.should == 1
|
28
|
+
nested_failure = result.nested_failures[0]
|
29
|
+
nested_failure.index.should == 3
|
30
|
+
nested_failure.expected_string.should == 'bar'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
dir = File.dirname(__FILE__)
|
2
|
+
require "#{dir}/../test_helper"
|
3
|
+
|
4
|
+
class AnythingSymbolTest < CompilerTestCase
|
5
|
+
class Foo < Treetop::Runtime::SyntaxNode
|
6
|
+
end
|
7
|
+
|
8
|
+
testing_expression '. <Foo> { def a_method; end }'
|
9
|
+
|
10
|
+
it "matches any single character in a big range, returning an instance of the declared node class that responds to methods defined in the inline module" do
|
11
|
+
(33..127).each do |digit|
|
12
|
+
parse(digit.chr) do |result|
|
13
|
+
result.should be_success
|
14
|
+
result.should be_an_instance_of(Foo)
|
15
|
+
result.should respond_to(:a_method)
|
16
|
+
result.interval.should == (0...1)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it "fails to parse epsilon" do
|
22
|
+
parse('').should be_failure
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'test_helper')
|
2
|
+
|
3
|
+
class CharacterClassTest < CompilerTestCase
|
4
|
+
class Foo < Treetop::Runtime::SyntaxNode
|
5
|
+
end
|
6
|
+
|
7
|
+
testing_expression "[A-Z] <Foo> { def a_method; end }"
|
8
|
+
|
9
|
+
it "matches single characters within that range, returning instances of the declared node class that respond to the method defined in the inline module" do
|
10
|
+
result = parse('A')
|
11
|
+
result.should be_an_instance_of(Foo)
|
12
|
+
result.should respond_to(:a_method)
|
13
|
+
result = parse('N')
|
14
|
+
result.should be_an_instance_of(Foo)
|
15
|
+
result.should respond_to(:a_method)
|
16
|
+
result = parse('Z')
|
17
|
+
result.should be_an_instance_of(Foo)
|
18
|
+
result.should respond_to(:a_method)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "does not match single characters outside of that range" do
|
22
|
+
parse('8').should be_failure
|
23
|
+
parse('a').should be_failure
|
24
|
+
end
|
25
|
+
|
26
|
+
it "matches a single character within that range at index 1" do
|
27
|
+
parse(' A', :at_index => 1).should be_success
|
28
|
+
end
|
29
|
+
|
30
|
+
it "fails to match a single character out of that range at index 1" do
|
31
|
+
parse(' 1', :at_index => 1).should be_failure
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "A character class containing quotes", :extend => CompilerTestCase do
|
36
|
+
testing_expression "[\"']"
|
37
|
+
|
38
|
+
it "matches a quote" do
|
39
|
+
parse("'").should be_success
|
40
|
+
end
|
41
|
+
|
42
|
+
it "matches a double-quote" do
|
43
|
+
parse('"').should be_success
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'test_helper')
|
2
|
+
|
3
|
+
describe "A choice between terminal symbols", :extend => CompilerTestCase do
|
4
|
+
testing_expression '"foo" { def foo_method; end } / "bar" { def bar_method; end } / "baz" { def baz_method; end }'
|
5
|
+
|
6
|
+
it "successfully parses input matching any of the alternatives, returning a node that responds to methods defined in its respective inline module" do
|
7
|
+
result = parse('foo')
|
8
|
+
result.should be_success
|
9
|
+
result.should respond_to(:foo_method)
|
10
|
+
|
11
|
+
result = parse('bar')
|
12
|
+
result.should be_success
|
13
|
+
result.should respond_to(:bar_method)
|
14
|
+
|
15
|
+
result = parse('baz')
|
16
|
+
result.should be_success
|
17
|
+
result.should respond_to(:baz_method)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "attaches the nested failure of the first terminal to a successful parsing of input matching the second" do
|
21
|
+
result = parse('bar')
|
22
|
+
result.nested_failures.size.should == 1
|
23
|
+
nested_failure = result.nested_failures[0]
|
24
|
+
nested_failure.expected_string.should == 'foo'
|
25
|
+
nested_failure.index.should == 0
|
26
|
+
end
|
27
|
+
|
28
|
+
it "attaches the nested failure of the first and second terminal to a successful parsing of input matching the third" do
|
29
|
+
result = parse('baz')
|
30
|
+
result.nested_failures.size.should == 2
|
31
|
+
|
32
|
+
first_nested_failure = result.nested_failures[0]
|
33
|
+
first_nested_failure.expected_string == 'foo'
|
34
|
+
first_nested_failure.index.should == 0
|
35
|
+
|
36
|
+
first_nested_failure = result.nested_failures[1]
|
37
|
+
first_nested_failure.expected_string == 'bar'
|
38
|
+
first_nested_failure.index.should == 0
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "A choice between sequences", :extend => CompilerTestCase do
|
43
|
+
testing_expression "'foo' 'bar' 'baz'\n/\n'bing' 'bang' 'boom'"
|
44
|
+
|
45
|
+
it "successfully parses input matching any of the alternatives" do
|
46
|
+
parse('foobarbaz').should be_success
|
47
|
+
parse('bingbangboom').should be_success
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'test_helper')
|
2
|
+
require 'benchmark'
|
3
|
+
|
4
|
+
class CircularCompilationTest < CompilerTestCase
|
5
|
+
test "the generated metagrammar parser can parse the treetop file whence it came" do
|
6
|
+
File.open(METAGRAMMAR_PATH, 'r') do |file|
|
7
|
+
input = file.read
|
8
|
+
result = Treetop::Compiler::MetagrammarParser.new.parse(input)
|
9
|
+
result.should be_success
|
10
|
+
|
11
|
+
Treetop::Compiler.send(:remove_const, :Metagrammar)
|
12
|
+
parser_code = result.compile
|
13
|
+
|
14
|
+
Object.class_eval(parser_code)
|
15
|
+
|
16
|
+
r = Treetop::Compiler::MetagrammarParser.new.parse(input)
|
17
|
+
r.should be_success
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'test_helper')
|
2
|
+
|
3
|
+
describe "An expression for braces surrounding zero or more letters followed by semicolons", :extend => CompilerTestCase do
|
4
|
+
testing_expression "'{' ([a-z] ';')* '}'"
|
5
|
+
|
6
|
+
it "parses matching input successfully" do
|
7
|
+
parse('{a;b;c;}').should be_success
|
8
|
+
end
|
9
|
+
|
10
|
+
it "fails to parse input with an expression that is missing a semicolon, reporting the correct nested failure" do
|
11
|
+
parse('{a;b;c}') do |result|
|
12
|
+
result.should be_failure
|
13
|
+
|
14
|
+
result.nested_failures.size.should == 1
|
15
|
+
nested_failure = result.nested_failures[0]
|
16
|
+
nested_failure.index.should == 6
|
17
|
+
nested_failure.expected_string.should == ';'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'test_helper')
|
2
|
+
|
3
|
+
class GrammarCompilerTest < Screw::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@compiler = Compiler::GrammarCompiler.new
|
7
|
+
@source_path = File.join(File.dirname(__FILE__), 'test_grammar.treetop')
|
8
|
+
@target_path = File.join(File.dirname(__FILE__), 'test_grammar.rb')
|
9
|
+
@alternate_target_path = File.join(File.dirname(__FILE__), 'test_grammar_alt.rb')
|
10
|
+
delete_target_files
|
11
|
+
end
|
12
|
+
|
13
|
+
def teardown
|
14
|
+
delete_target_files
|
15
|
+
Object.class_eval do
|
16
|
+
remove_const(:Test) if const_defined?(:Test)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
test "compilation of a single file to a default file name" do
|
21
|
+
assert !File.exists?(@target_path)
|
22
|
+
@compiler.compile(@source_path)
|
23
|
+
assert File.exists?(@target_path)
|
24
|
+
require @target_path
|
25
|
+
Test::GrammarParser.new.parse('foo').should be_success
|
26
|
+
end
|
27
|
+
|
28
|
+
test "compilation of a single file to an explicit file name" do
|
29
|
+
assert !File.exists?(@alternate_target_path)
|
30
|
+
@compiler.compile(@source_path, @alternate_target_path)
|
31
|
+
assert File.exists?(@alternate_target_path)
|
32
|
+
require @alternate_target_path
|
33
|
+
Test::GrammarParser.new.parse('foo').should be_success
|
34
|
+
end
|
35
|
+
|
36
|
+
test "compilation of a single file without writing it to an output file" do
|
37
|
+
@compiler.ruby_source(@source_path).should_not be_nil
|
38
|
+
end
|
39
|
+
|
40
|
+
test "load_grammar compiles and evaluates source grammar with extension" do
|
41
|
+
load_grammar @source_path
|
42
|
+
Test::GrammarParser.new.parse('foo').should be_success
|
43
|
+
end
|
44
|
+
|
45
|
+
test "load_grammar compiles and evaluates source grammar with no extension" do
|
46
|
+
path_without_extension = @source_path.gsub(/\.treetop\Z/, '')
|
47
|
+
load_grammar path_without_extension
|
48
|
+
Test::GrammarParser.new.parse('foo').should be_success
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
def delete_target_files
|
53
|
+
File.delete(@target_path) if File.exists?(@target_path)
|
54
|
+
File.delete(@alternate_target_path) if File.exists?(@alternate_target_path)
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|