treetop 0.1.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|