treetop 1.5.3 → 1.6.2

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.
Files changed (42) hide show
  1. checksums.yaml +5 -13
  2. data/Rakefile +9 -3
  3. data/doc/pitfalls_and_advanced_techniques.markdown +1 -1
  4. data/doc/sitegen.rb +1 -1
  5. data/doc/syntactic_recognition.markdown +2 -0
  6. data/doc/tt.1 +1 -1
  7. data/lib/treetop/compiler/metagrammar.rb +81 -13
  8. data/lib/treetop/compiler/metagrammar.treetop +67 -13
  9. data/lib/treetop/compiler/node_classes/anything_symbol.rb +5 -1
  10. data/lib/treetop/compiler/node_classes/character_class.rb +6 -2
  11. data/lib/treetop/compiler/node_classes/choice.rb +9 -5
  12. data/lib/treetop/compiler/node_classes/nonterminal.rb +2 -2
  13. data/lib/treetop/compiler/node_classes/parenthesized_expression.rb +5 -1
  14. data/lib/treetop/compiler/node_classes/parsing_expression.rb +12 -2
  15. data/lib/treetop/compiler/node_classes/predicate.rb +8 -1
  16. data/lib/treetop/compiler/node_classes/predicate_block.rb +7 -0
  17. data/lib/treetop/compiler/node_classes/repetition.rb +31 -11
  18. data/lib/treetop/compiler/node_classes/sequence.rb +5 -1
  19. data/lib/treetop/compiler/node_classes/terminal.rb +12 -2
  20. data/lib/treetop/runtime/compiled_parser.rb +12 -6
  21. data/lib/treetop/runtime/syntax_node.rb +24 -15
  22. data/lib/treetop/runtime/terminal_parse_failure.rb +4 -3
  23. data/lib/treetop/version.rb +2 -2
  24. data/spec/compiler/and_predicate_spec.rb +1 -1
  25. data/spec/compiler/anything_symbol_spec.rb +4 -1
  26. data/spec/compiler/character_class_spec.rb +4 -1
  27. data/spec/compiler/choice_spec.rb +20 -11
  28. data/spec/compiler/failure_propagation_functional_spec.rb +1 -1
  29. data/spec/compiler/grammar_spec.rb +4 -1
  30. data/spec/compiler/not_predicate_spec.rb +20 -6
  31. data/spec/compiler/occurrence_range_spec.rb +25 -28
  32. data/spec/compiler/one_or_more_spec.rb +2 -2
  33. data/spec/compiler/optional_spec.rb +2 -2
  34. data/spec/compiler/parenthesized_expression_spec.rb +15 -1
  35. data/spec/compiler/semantic_predicate_spec.rb +17 -16
  36. data/spec/compiler/sequence_spec.rb +1 -1
  37. data/spec/compiler/terminal_spec.rb +8 -1
  38. data/spec/compiler/terminal_symbol_spec.rb +4 -1
  39. data/spec/compiler/zero_or_more_spec.rb +4 -2
  40. data/spec/runtime/compiled_parser_spec.rb +33 -3
  41. metadata +20 -21
  42. data/examples/lambda_calculus/lambda_calculus +0 -0
@@ -1,8 +1,8 @@
1
1
  module Treetop #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 1
4
- MINOR = 5
5
- TINY = 3
4
+ MINOR = 6
5
+ TINY = 2
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -29,7 +29,7 @@ module AndPredicateSpec
29
29
  terminal_failures.size.should == 1
30
30
  failure = terminal_failures[0]
31
31
  failure.index.should == 3
32
- failure.expected_string.should == 'bar'
32
+ failure.expected_string.should == '"bar"'
33
33
  end
34
34
  end
35
35
  end
@@ -19,7 +19,10 @@ module AnythingSymbolSpec
19
19
  end
20
20
 
21
21
  it "fails to parse epsilon" do
22
- parse('').should be_nil
22
+ parse('') do |result|
23
+ result.should be_nil
24
+ parser.terminal_failures.size.should == 1
25
+ end
23
26
  end
24
27
  end
25
28
 
@@ -21,7 +21,10 @@ module CharacterClassSpec
21
21
  end
22
22
 
23
23
  it "does not match single characters outside of that range" do
24
- parse('8').should be_nil
24
+ parse('8') do |result|
25
+ result.should be_nil
26
+ parser.terminal_failures.size.should == 1
27
+ end
25
28
  parse('a').should be_nil
26
29
  end
27
30
 
@@ -2,42 +2,51 @@ require 'spec_helper'
2
2
 
3
3
  module ChoiceSpec
4
4
  describe "A choice between terminal symbols" do
5
- testing_expression '"foo" { def foo_method; end } / "bar" { def bar_method; end } / "baz" { def baz_method; end }'
5
+ testing_expression '("foo" { def foo_method; end } / "bar" { def bar_method; end } / "baz" { def baz_method; end }) {def bat_method; end}'
6
6
 
7
7
  it "successfully parses input matching any of the alternatives, returning a node that responds to methods defined in its respective inline module" do
8
8
  result = parse('foo')
9
9
  result.should_not be_nil
10
10
  result.should respond_to(:foo_method)
11
-
11
+ result.should_not respond_to(:bar_method)
12
+ result.should_not respond_to(:baz_method)
13
+ result.should respond_to(:bat_method)
14
+
12
15
  result = parse('bar')
13
16
  result.should_not be_nil
17
+ result.should_not respond_to(:foo_method)
14
18
  result.should respond_to(:bar_method)
15
-
19
+ result.should_not respond_to(:baz_method)
20
+ result.should respond_to(:bat_method)
21
+
16
22
  result = parse('baz')
17
23
  result.should_not be_nil
24
+ result.should_not respond_to(:foo_method)
25
+ result.should_not respond_to(:bar_method)
18
26
  result.should respond_to(:baz_method)
27
+ result.should respond_to(:bat_method)
19
28
  end
20
-
29
+
21
30
  it "upon parsing a string matching the second alternative, records the failure of the first terminal" do
22
31
  result = parse('bar')
23
32
  terminal_failures = parser.terminal_failures
24
33
  terminal_failures.size.should == 1
25
34
  failure = terminal_failures[0]
26
- failure.expected_string.should == 'foo'
35
+ failure.expected_string.should == '"foo"'
27
36
  failure.index.should == 0
28
37
  end
29
-
38
+
30
39
  it "upon parsing a string matching the third alternative, records the failure of the first two terminals" do
31
40
  result = parse('baz')
32
-
41
+
33
42
  terminal_failures = parser.terminal_failures
34
-
43
+
35
44
  terminal_failures.size.should == 2
36
45
 
37
46
  failure_1 = terminal_failures[0]
38
47
  failure_1.expected_string == 'foo'
39
48
  failure_1.index.should == 0
40
-
49
+
41
50
  failure_2 = terminal_failures[1]
42
51
  failure_2.expected_string == 'bar'
43
52
  failure_2.index.should == 0
@@ -53,7 +62,7 @@ module ChoiceSpec
53
62
  end
54
63
  end
55
64
 
56
- describe "A choice between terminals followed by a block" do
65
+ describe "A choice between terminals followed by a block" do
57
66
  testing_expression "('a'/ 'bb' / [c]) { def a_method; end }"
58
67
 
59
68
  it "extends a match of any of its subexpressions with a module created from the block" do
@@ -68,7 +77,7 @@ module ChoiceSpec
68
77
  end
69
78
  end
70
79
 
71
- describe "a choice followed by a declared module" do
80
+ describe "a choice followed by a declared module" do
72
81
  testing_expression "('a'/ 'bb' / [c]) <ChoiceSpec::TestModule>"
73
82
 
74
83
  it "extends a match of any of its subexpressions with a module created from the block" do
@@ -15,7 +15,7 @@ describe "An expression for braces surrounding zero or more letters followed by
15
15
  terminal_failures.size.should == 1
16
16
  failure = terminal_failures[0]
17
17
  failure.index.should == 6
18
- failure.expected_string.should == ';'
18
+ failure.expected_string.should == "';'"
19
19
  end
20
20
  end
21
21
  end
@@ -31,7 +31,10 @@ module GrammarSpec
31
31
  end
32
32
 
33
33
  it "fails if it does not parse all input" do
34
- parse('barbarbazbaz').should be_nil
34
+ parse('barbarbazbaz') do |result|
35
+ result.should be_nil
36
+ parser.terminal_failures.size.should == 1
37
+ end
35
38
  end
36
39
 
37
40
  it "mixes in included modules" do
@@ -5,7 +5,21 @@ module NotPredicateSpec
5
5
  testing_expression '!"foo"'
6
6
 
7
7
  it "fails to parse input matching the terminal symbol" do
8
- parse('foo').should be_nil
8
+ parse('foo') do |result|
9
+ result.should be_nil
10
+ parser.terminal_failures.size.should == 1
11
+ end
12
+ end
13
+ end
14
+
15
+ describe "A !-predicated character class symbol" do
16
+ testing_expression '![aeiou]'
17
+
18
+ it "fails to parse input matching the terminal symbol" do
19
+ parse('e') do |result|
20
+ result.should be_nil
21
+ parser.terminal_failures.size.should == 1
22
+ end
9
23
  end
10
24
  end
11
25
 
@@ -20,10 +34,7 @@ module NotPredicateSpec
20
34
  parse('foo') do |result|
21
35
  result.should_not be_nil
22
36
  terminal_failures = parser.terminal_failures
23
- terminal_failures.size.should == 1
24
- failure = terminal_failures.first
25
- failure.index.should == 3
26
- failure.expected_string.should == 'bar'
37
+ terminal_failures.size.should == 0
27
38
  end
28
39
  end
29
40
  end
@@ -32,7 +43,10 @@ module NotPredicateSpec
32
43
  testing_expression '!("a" "b" "cc")'
33
44
 
34
45
  it "fails to parse matching input" do
35
- parse('abcc').should be_nil
46
+ parse('abcc') do |result|
47
+ result.should be_nil
48
+ parser.terminal_failures.size.should == 1
49
+ end
36
50
  end
37
51
  end
38
52
  end
@@ -14,10 +14,7 @@ module OccurrenceRangeSpec
14
14
  result.should respond_to(:a_method)
15
15
 
16
16
  terminal_failures = parser.terminal_failures
17
- terminal_failures.size.should == 1
18
- failure = terminal_failures.first
19
- failure.index.should == 0
20
- failure.expected_string.should == 'foo'
17
+ terminal_failures.size.should == 0
21
18
  end
22
19
  end
23
20
 
@@ -28,10 +25,7 @@ module OccurrenceRangeSpec
28
25
  result.should respond_to(:a_method)
29
26
 
30
27
  terminal_failures = parser.terminal_failures
31
- terminal_failures.size.should == 1
32
- failure = terminal_failures.first
33
- failure.index.should == 0
34
- failure.expected_string.should == 'foo'
28
+ terminal_failures.size.should == 0
35
29
  end
36
30
  end
37
31
 
@@ -42,10 +36,7 @@ module OccurrenceRangeSpec
42
36
  result.should respond_to(:a_method)
43
37
 
44
38
  terminal_failures = parser.terminal_failures
45
- terminal_failures.size.should == 1
46
- failure = terminal_failures.first
47
- failure.index.should == 3
48
- failure.expected_string.should == 'foo'
39
+ terminal_failures.size.should == 0
49
40
  end
50
41
  end
51
42
 
@@ -60,14 +51,23 @@ module OccurrenceRangeSpec
60
51
  end
61
52
  end
62
53
 
63
- it "fails to parses three of that terminal, returning an instance of the declared node class and reporting no failure" do
54
+ it "fails to parses two of that terminal but fails because of an extra one" do
64
55
  parse("foofoofoo") do |result|
65
56
  result.should be_nil
66
57
 
67
- terminal_failures = parser.terminal_failures
68
- terminal_failures.size.should == 0
58
+ parser.terminal_failures.size.should == 1
69
59
  end
70
60
  end
61
+
62
+ it "parses two of three of that terminal, reporting no failure" do
63
+ parse("foofoofoo", :consume_all_input => false) do |result|
64
+ result.should_not be_nil
65
+ result.elements.size.should == 2
66
+
67
+ parser.terminal_failures.size.should == 0
68
+ end
69
+ end
70
+
71
71
  end
72
72
 
73
73
  describe "two to four of a terminal symbol followed by a node class declaration and a block" do
@@ -80,7 +80,7 @@ module OccurrenceRangeSpec
80
80
  terminal_failures.size.should == 1
81
81
  failure = terminal_failures.first
82
82
  failure.index.should == 0
83
- failure.expected_string.should == 'foo'
83
+ failure.expected_string.should == '"foo"'
84
84
  end
85
85
  end
86
86
 
@@ -92,7 +92,7 @@ module OccurrenceRangeSpec
92
92
  terminal_failures.size.should == 1
93
93
  failure = terminal_failures.first
94
94
  failure.index.should == 3
95
- failure.expected_string.should == 'foo'
95
+ failure.expected_string.should == '"foo"'
96
96
  end
97
97
  end
98
98
 
@@ -103,10 +103,7 @@ module OccurrenceRangeSpec
103
103
  result.should respond_to(:a_method)
104
104
 
105
105
  terminal_failures = parser.terminal_failures
106
- terminal_failures.size.should == 1
107
- failure = terminal_failures.first
108
- failure.index.should == 6
109
- failure.expected_string.should == 'foo'
106
+ terminal_failures.size.should == 0
110
107
  end
111
108
  end
112
109
 
@@ -117,16 +114,16 @@ module OccurrenceRangeSpec
117
114
  result.should respond_to(:a_method)
118
115
 
119
116
  terminal_failures = parser.terminal_failures
120
- terminal_failures.size.should == 0
117
+ terminal_failures.size.should == 0
121
118
  end
122
119
  end
123
120
 
124
- it "fails to parses five of that terminal, returning an instance of the declared node class and reporting no failure" do
121
+ it "fails to parses four of that terminal because there's an extra unconsumed one" do
125
122
  parse("foofoofoofoofoo") do |result|
126
123
  result.should be_nil
127
124
 
128
125
  terminal_failures = parser.terminal_failures
129
- terminal_failures.size.should == 0
126
+ terminal_failures.size.should == 1
130
127
  end
131
128
  end
132
129
  end
@@ -141,7 +138,7 @@ module OccurrenceRangeSpec
141
138
  terminal_failures.size.should == 1
142
139
  failure = terminal_failures.first
143
140
  failure.index.should == 0
144
- failure.expected_string.should == 'foo'
141
+ failure.expected_string.should == '"foo"'
145
142
  end
146
143
  end
147
144
 
@@ -153,7 +150,7 @@ module OccurrenceRangeSpec
153
150
  terminal_failures.size.should == 1
154
151
  failure = terminal_failures.first
155
152
  failure.index.should == 3
156
- failure.expected_string.should == 'foo'
153
+ failure.expected_string.should == '"foo"'
157
154
  end
158
155
  end
159
156
 
@@ -167,7 +164,7 @@ module OccurrenceRangeSpec
167
164
  terminal_failures.size.should == 1
168
165
  failure = terminal_failures.first
169
166
  failure.index.should == 6
170
- failure.expected_string.should == 'foo'
167
+ failure.expected_string.should == '"foo"'
171
168
  end
172
169
  end
173
170
 
@@ -181,7 +178,7 @@ module OccurrenceRangeSpec
181
178
  terminal_failures.size.should == 1
182
179
  failure = terminal_failures.first
183
180
  failure.index.should == 12
184
- failure.expected_string.should == 'foo'
181
+ failure.expected_string.should == '"foo"'
185
182
  end
186
183
  end
187
184
  end
@@ -14,7 +14,7 @@ module OneOrMoreSpec
14
14
  terminal_failures.size.should == 1
15
15
  failure = terminal_failures.first
16
16
  failure.index.should == 0
17
- failure.expected_string.should == 'foo'
17
+ failure.expected_string.should == '"foo"'
18
18
  end
19
19
  end
20
20
 
@@ -28,7 +28,7 @@ module OneOrMoreSpec
28
28
  terminal_failures.size.should == 1
29
29
  failure = terminal_failures.first
30
30
  failure.index.should == 6
31
- failure.expected_string.should == 'foo'
31
+ failure.expected_string.should == '"foo"'
32
32
  end
33
33
  end
34
34
  end
@@ -17,7 +17,7 @@ module OptionalSpec
17
17
  terminal_failures.size.should == 1
18
18
  failure = terminal_failures.first
19
19
  failure.index.should == 0
20
- failure.expected_string.should == 'foo'
20
+ failure.expected_string.should == '"foo"'
21
21
  end
22
22
  end
23
23
 
@@ -30,7 +30,7 @@ module OptionalSpec
30
30
  terminal_failures.size.should == 1
31
31
  failure = terminal_failures.first
32
32
  failure.index.should == 0
33
- failure.expected_string.should == 'foo'
33
+ failure.expected_string.should == '"foo"'
34
34
  end
35
35
  end
36
36
  end
@@ -13,7 +13,21 @@ module ParenthesizedExpressionSpec
13
13
  testing_expression '(!"foo")'
14
14
 
15
15
  it "should behave as normal" do
16
- parse('foo').should be_nil
16
+ parse('foo') do |result|
17
+ result.should be_nil
18
+ parser.terminal_failures.size.should == 1
19
+ end
17
20
  end
18
21
  end
22
+
23
+ describe "An expression with code both inside and outside parentheses" do
24
+ testing_expression '("foo" { def inner; end } ) { def outer; end} '
25
+ it "should extend both code modules " do
26
+ parse('foo') do |result|
27
+ result.should respond_to(:inner)
28
+ result.should respond_to(:outer)
29
+ end
30
+ end
31
+ end
32
+
19
33
  end
@@ -17,7 +17,7 @@ module SemanticPredicateSpec
17
17
  parse('foo', :consume_all_input => false) do |result|
18
18
  result.should be_nil
19
19
  terminal_failures = parser.terminal_failures
20
- terminal_failures.size.should == 0
20
+ terminal_failures.size.should == 1
21
21
  end
22
22
  end
23
23
 
@@ -44,7 +44,7 @@ module SemanticPredicateSpec
44
44
  result.should be_nil
45
45
  $value.should == 'prior '
46
46
  terminal_failures = parser.terminal_failures
47
- terminal_failures.size.should == 0
47
+ terminal_failures.size.should == 1
48
48
  end
49
49
  end
50
50
 
@@ -63,13 +63,13 @@ module SemanticPredicateSpec
63
63
  end
64
64
  end
65
65
 
66
- it "fails with no terminal_failures if the block returns false" do
66
+ it "fails with one terminal_failure if the block returns false" do
67
67
  $ok_to_succeed = false
68
68
  parse('prior foo', :consume_all_input => false) do |result|
69
69
  result.should be_nil
70
70
  $value.should == 'prior '
71
71
  terminal_failures = parser.terminal_failures
72
- terminal_failures.size.should == 0
72
+ terminal_failures.size.should == 1
73
73
  end
74
74
  end
75
75
 
@@ -78,10 +78,12 @@ module SemanticPredicateSpec
78
78
  parse('foo', :consume_all_input => false) do |result|
79
79
  result.should be_nil
80
80
  terminal_failures = parser.terminal_failures
81
- terminal_failures.size.should == 1
82
- failure = terminal_failures[0]
83
- failure.index.should == 0
84
- failure.expected_string.should == 'prior '
81
+ # We should get "prior " failed, and also the predicate block
82
+ terminal_failures.size.should == 2
83
+ terminal_failures[0].index.should == 0
84
+ terminal_failures[0].expected_string.should == '"prior "'
85
+ terminal_failures[1].index.should == 0
86
+ terminal_failures[1].expected_string.should == '<semantic predicate>'
85
87
  end
86
88
  end
87
89
 
@@ -103,7 +105,7 @@ module SemanticPredicateSpec
103
105
  parse('foo', :consume_all_input => false) do |result|
104
106
  result.should be_nil
105
107
  terminal_failures = parser.terminal_failures
106
- terminal_failures.size.should == 0
108
+ terminal_failures.size.should == 1
107
109
  end
108
110
  end
109
111
 
@@ -130,7 +132,7 @@ module SemanticPredicateSpec
130
132
  result.should be_nil
131
133
  $value.should == 'prior '
132
134
  terminal_failures = parser.terminal_failures
133
- terminal_failures.size.should == 0
135
+ terminal_failures.size.should == 1
134
136
  end
135
137
  end
136
138
 
@@ -149,13 +151,13 @@ module SemanticPredicateSpec
149
151
  end
150
152
  end
151
153
 
152
- it "fails with no terminal_failures if the block returns true" do
154
+ it "fails with one terminal_failure if the block returns true" do
153
155
  $ok_to_succeed = true
154
156
  parse('prior foo', :consume_all_input => false) do |result|
155
157
  result.should be_nil
156
158
  $value.should == 'prior '
157
159
  terminal_failures = parser.terminal_failures
158
- terminal_failures.size.should == 0
160
+ terminal_failures.size.should == 1
159
161
  end
160
162
  end
161
163
 
@@ -164,10 +166,9 @@ module SemanticPredicateSpec
164
166
  parse('foo', :consume_all_input => false) do |result|
165
167
  result.should be_nil
166
168
  terminal_failures = parser.terminal_failures
167
- terminal_failures.size.should == 1
168
- failure = terminal_failures[0]
169
- failure.index.should == 0
170
- failure.expected_string.should == 'prior '
169
+ terminal_failures.size.should == 2
170
+ terminal_failures[0].index.should == 0
171
+ terminal_failures[0].expected_string.should == '"prior "'
171
172
  end
172
173
  end
173
174