treetop 1.5.3 → 1.6.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +5 -13
  2. data/Gemfile +12 -0
  3. data/History.txt +18 -0
  4. data/README.md +4 -0
  5. data/Rakefile +20 -40
  6. data/Treetop.tmbundle/Preferences/Comments.tmPreferences +28 -0
  7. data/Treetop.tmbundle/Snippets/grammar ___ end.tmSnippet +20 -0
  8. data/Treetop.tmbundle/Snippets/rule ___ end.tmSnippet +18 -0
  9. data/Treetop.tmbundle/Support/nibs/SyntaxTreeViewer.nib/designable.nib +1524 -0
  10. data/Treetop.tmbundle/Support/nibs/SyntaxTreeViewer.nib/keyedobjects.nib +0 -0
  11. data/Treetop.tmbundle/Support/syntax_tree_viewer.rb +117 -0
  12. data/Treetop.tmbundle/Syntaxes/Treetop Grammar.tmLanguage +358 -0
  13. data/Treetop.tmbundle/info.plist +10 -0
  14. data/doc/pitfalls_and_advanced_techniques.markdown +7 -1
  15. data/doc/syntactic_recognition.markdown +7 -2
  16. data/doc/tt.1 +1 -1
  17. data/examples/indented_blocks/indented_blocks.tt +73 -0
  18. data/examples/indented_blocks/indented_blocks_test.rb +24 -0
  19. data/lib/treetop/compiler/grammar_compiler.rb +6 -3
  20. data/lib/treetop/compiler/metagrammar.rb +301 -159
  21. data/lib/treetop/compiler/metagrammar.treetop +96 -13
  22. data/lib/treetop/compiler/node_classes/anything_symbol.rb +10 -2
  23. data/lib/treetop/compiler/node_classes/atomic_expression.rb +2 -2
  24. data/lib/treetop/compiler/node_classes/character_class.rb +10 -2
  25. data/lib/treetop/compiler/node_classes/choice.rb +11 -7
  26. data/lib/treetop/compiler/node_classes/nonterminal.rb +6 -2
  27. data/lib/treetop/compiler/node_classes/parenthesized_expression.rb +5 -1
  28. data/lib/treetop/compiler/node_classes/parsing_expression.rb +10 -1
  29. data/lib/treetop/compiler/node_classes/parsing_rule.rb +1 -1
  30. data/lib/treetop/compiler/node_classes/predicate.rb +8 -1
  31. data/lib/treetop/compiler/node_classes/predicate_block.rb +7 -0
  32. data/lib/treetop/compiler/node_classes/repetition.rb +28 -8
  33. data/lib/treetop/compiler/node_classes/sequence.rb +5 -1
  34. data/lib/treetop/compiler/node_classes/terminal.rb +36 -22
  35. data/lib/treetop/compiler/ruby_builder.rb +2 -2
  36. data/lib/treetop/ruby_extensions/string.rb +0 -6
  37. data/lib/treetop/runtime/compiled_parser.rb +33 -14
  38. data/lib/treetop/runtime/syntax_node.rb +24 -15
  39. data/lib/treetop/runtime/terminal_parse_failure.rb +4 -3
  40. data/lib/treetop/runtime/terminal_syntax_node.rb +4 -4
  41. data/lib/treetop/version.rb +2 -2
  42. data/treetop.gemspec +25 -165
  43. metadata +43 -98
  44. data/doc/site.rb +0 -112
  45. data/doc/sitegen.rb +0 -65
  46. data/examples/lambda_calculus/lambda_calculus +0 -0
  47. data/spec/compiler/and_predicate_spec.rb +0 -36
  48. data/spec/compiler/anything_symbol_spec.rb +0 -44
  49. data/spec/compiler/character_class_spec.rb +0 -301
  50. data/spec/compiler/choice_spec.rb +0 -80
  51. data/spec/compiler/circular_compilation_spec.rb +0 -30
  52. data/spec/compiler/failure_propagation_functional_spec.rb +0 -21
  53. data/spec/compiler/grammar_compiler_spec.rb +0 -113
  54. data/spec/compiler/grammar_spec.rb +0 -41
  55. data/spec/compiler/multibyte_chars_spec.rb +0 -38
  56. data/spec/compiler/namespace_spec.rb +0 -42
  57. data/spec/compiler/nonterminal_symbol_spec.rb +0 -40
  58. data/spec/compiler/not_predicate_spec.rb +0 -38
  59. data/spec/compiler/occurrence_range_spec.rb +0 -189
  60. data/spec/compiler/one_or_more_spec.rb +0 -35
  61. data/spec/compiler/optional_spec.rb +0 -37
  62. data/spec/compiler/parenthesized_expression_spec.rb +0 -19
  63. data/spec/compiler/parsing_rule_spec.rb +0 -61
  64. data/spec/compiler/repeated_subrule_spec.rb +0 -29
  65. data/spec/compiler/semantic_predicate_spec.rb +0 -175
  66. data/spec/compiler/sequence_spec.rb +0 -129
  67. data/spec/compiler/terminal_spec.rb +0 -170
  68. data/spec/compiler/terminal_symbol_spec.rb +0 -37
  69. data/spec/compiler/test_grammar.treetop +0 -7
  70. data/spec/compiler/test_grammar.tt +0 -7
  71. data/spec/compiler/test_grammar_do.treetop +0 -7
  72. data/spec/compiler/test_grammar_magic_coding.treetop +0 -8
  73. data/spec/compiler/test_grammar_magic_encoding.treetop +0 -8
  74. data/spec/compiler/tt_compiler_spec.rb +0 -224
  75. data/spec/compiler/zero_or_more_spec.rb +0 -56
  76. data/spec/composition/a.treetop +0 -11
  77. data/spec/composition/b.treetop +0 -11
  78. data/spec/composition/c.treetop +0 -10
  79. data/spec/composition/d.treetop +0 -10
  80. data/spec/composition/f.treetop +0 -17
  81. data/spec/composition/grammar_composition_spec.rb +0 -40
  82. data/spec/composition/subfolder/e_includes_c.treetop +0 -15
  83. data/spec/ruby_extensions/string_spec.rb +0 -32
  84. data/spec/runtime/compiled_parser_spec.rb +0 -123
  85. data/spec/runtime/interval_skip_list/delete_spec.rb +0 -147
  86. data/spec/runtime/interval_skip_list/expire_range_spec.rb +0 -349
  87. data/spec/runtime/interval_skip_list/insert_and_delete_node_spec.rb +0 -385
  88. data/spec/runtime/interval_skip_list/insert_spec.rb +0 -660
  89. data/spec/runtime/interval_skip_list/interval_skip_list_spec.graffle +0 -6175
  90. data/spec/runtime/interval_skip_list/interval_skip_list_spec.rb +0 -58
  91. data/spec/runtime/interval_skip_list/palindromic_fixture.rb +0 -35
  92. data/spec/runtime/interval_skip_list/palindromic_fixture_spec.rb +0 -163
  93. data/spec/runtime/interval_skip_list/spec_helper.rb +0 -91
  94. data/spec/runtime/syntax_node_spec.rb +0 -77
  95. data/spec/spec_helper.rb +0 -115
@@ -2,15 +2,15 @@ module Treetop
2
2
  module Compiler
3
3
  grammar Metagrammar
4
4
  rule treetop_file
5
- requires:(space? require_statement)* prefix:space? module_or_grammar suffix:space? {
5
+ requires:(space? require_statement)* spacing:space? module_or_grammar suffix:space? {
6
6
  def compile
7
- requires.text_value + prefix.text_value + module_or_grammar.compile + suffix.text_value
7
+ requires.text_value + spacing.text_value + module_or_grammar.compile + suffix.text_value
8
8
  end
9
9
  }
10
10
  end
11
11
 
12
12
  rule require_statement
13
- prefix:space? "require" [ \t]+ [^\n\r]+ [\n\r]
13
+ spacing:space? "require" [ \t]+ [^\n\r]+ [\n\r]
14
14
  end
15
15
 
16
16
  rule module_or_grammar
@@ -18,13 +18,13 @@ module Treetop
18
18
  end
19
19
 
20
20
  rule module_declaration
21
- prefix:('module' space name:([A-Z] alphanumeric_char* ('::' [A-Z] alphanumeric_char*)*) space) module_contents:(module_declaration / grammar) suffix:(space 'end') {
21
+ module_prefix:(('module'/'class') space name:([A-Z] alphanumeric_char* ('::' [A-Z] alphanumeric_char*)*) space) module_contents:(module_declaration / grammar) suffix:(space 'end') {
22
22
  def compile
23
- prefix.text_value + module_contents.compile + suffix.text_value
23
+ module_prefix.text_value + module_contents.compile + suffix.text_value
24
24
  end
25
25
 
26
26
  def parser_name
27
- prefix.name.text_value+'::'+module_contents.parser_name
27
+ module_prefix.name.text_value+'::'+module_contents.parser_name
28
28
  end
29
29
  }
30
30
  end
@@ -84,9 +84,17 @@ module Treetop
84
84
  super.elements.map {|elt| elt.alternative}
85
85
  end
86
86
 
87
+ def parent_modules
88
+ []
89
+ end
90
+
87
91
  def inline_modules
88
92
  (alternatives.map {|alt| alt.inline_modules }).flatten
89
93
  end
94
+
95
+ def inline_module
96
+ nil
97
+ end
90
98
  }
91
99
  end
92
100
 
@@ -100,12 +108,20 @@ module Treetop
100
108
  sequence_body.tail
101
109
  end
102
110
 
111
+ def parent_modules
112
+ node_class_declarations.inline_modules
113
+ end
114
+
103
115
  def inline_modules
104
116
  (sequence_elements.map {|elt| elt.inline_modules}).flatten +
105
117
  [sequence_element_accessor_module] +
106
- node_class_declarations.inline_modules
118
+ parent_modules
107
119
  end
108
120
 
121
+ def inline_module
122
+ node_class_declarations.inline_module
123
+ end
124
+
109
125
  def inline_module_name
110
126
  node_class_declarations.inline_module_name
111
127
  end
@@ -150,29 +166,46 @@ module Treetop
150
166
  atomic
151
167
  end
152
168
 
169
+ def parent_modules
170
+ []
171
+ end
172
+
153
173
  def inline_modules
154
174
  atomic.inline_modules
155
175
  end
156
176
 
177
+ def inline_module
178
+ atomic.inline_module
179
+ end
180
+
157
181
  def inline_module_name
158
182
  nil
159
183
  end
160
184
  }
161
185
  /
162
- prefix space? predicate_block {
186
+ prefix space? atomic:predicate_block {
163
187
  def compile(address, builder, parent_expression=nil)
164
188
  prefix.compile(address, builder, self)
165
189
  end
166
190
  def prefixed_expression
167
- predicate_block
191
+ atomic
168
192
  end
193
+ def parent_modules
194
+ []
195
+ end
169
196
  def inline_modules
170
197
  []
171
198
  end
199
+ def inline_module
200
+ nil
201
+ end
172
202
  }
173
203
  /
174
204
  atomic suffix node_class_declarations {
175
205
  def compile(address, builder, parent_expression=nil)
206
+ if node_class_declarations.inline_module && atomic.inline_module
207
+ STDERR.puts "Extraneous module ignored after suffix: #{input[interval].inspect}"
208
+ end
176
209
  suffix.compile(address, builder, self)
177
210
  end
178
211
 
@@ -184,10 +217,18 @@ module Treetop
184
217
  node_class_declarations.node_class_name
185
218
  end
186
219
 
220
+ def parent_modules
221
+ node_class_declarations.inline_modules
222
+ end
223
+
187
224
  def inline_modules
188
- atomic.inline_modules + node_class_declarations.inline_modules
225
+ atomic.inline_modules + parent_modules
189
226
  end
190
227
 
228
+ def inline_module
229
+ node_class_declarations.inline_module
230
+ end
231
+
191
232
  def inline_module_name
192
233
  node_class_declarations.inline_module_name
193
234
  end
@@ -195,6 +236,9 @@ module Treetop
195
236
  /
196
237
  atomic node_class_declarations {
197
238
  def compile(address, builder, parent_expression=nil)
239
+ if node_class_declarations.inline_module && atomic.inline_module
240
+ STDERR.puts "Extraneous module ignored with nested atomic: #{input[interval].inspect}"
241
+ end
198
242
  atomic.compile(address, builder, self)
199
243
  end
200
244
 
@@ -202,10 +246,18 @@ module Treetop
202
246
  node_class_declarations.node_class_name
203
247
  end
204
248
 
249
+ def parent_modules
250
+ node_class_declarations.inline_modules
251
+ end
252
+
205
253
  def inline_modules
206
- atomic.inline_modules + node_class_declarations.inline_modules
254
+ atomic.inline_modules + parent_modules
207
255
  end
208
256
 
257
+ def inline_module
258
+ node_class_declarations.inline_module
259
+ end
260
+
209
261
  def inline_module_name
210
262
  node_class_declarations.inline_module_name
211
263
  end
@@ -222,6 +274,10 @@ module Treetop
222
274
  sequence_primary.compile(lexical_address, builder)
223
275
  end
224
276
 
277
+ def parent_modules
278
+ []
279
+ end
280
+
225
281
  def inline_modules
226
282
  sequence_primary.inline_modules
227
283
  end
@@ -238,6 +294,10 @@ module Treetop
238
294
  sequence_primary.compile(lexical_address, builder)
239
295
  end
240
296
 
297
+ def parent_modules
298
+ []
299
+ end
300
+
241
301
  def inline_modules
242
302
  sequence_primary.inline_modules
243
303
  end
@@ -282,6 +342,10 @@ module Treetop
282
342
  elements[1]
283
343
  end
284
344
 
345
+ def parent_modules
346
+ []
347
+ end
348
+
285
349
  def inline_modules
286
350
  atomic.inline_modules
287
351
  end
@@ -291,13 +355,16 @@ module Treetop
291
355
  end
292
356
  }
293
357
  /
294
- prefix space? predicate_block {
358
+ prefix space? atomic:predicate_block {
295
359
  def compile(address, builder, parent_expression=nil)
296
360
  prefix.compile(address, builder, self)
297
361
  end
298
362
  def prefixed_expression
299
- predicate_block
363
+ atomic
300
364
  end
365
+ def parent_modules
366
+ []
367
+ end
301
368
  def inline_modules
302
369
  []
303
370
  end
@@ -312,6 +379,10 @@ module Treetop
312
379
  nil
313
380
  end
314
381
 
382
+ def parent_modules
383
+ []
384
+ end
385
+
315
386
  def inline_modules
316
387
  atomic.inline_modules
317
388
  end
@@ -374,9 +445,15 @@ module Treetop
374
445
 
375
446
  rule parenthesized_expression
376
447
  '(' space? parsing_expression space? ')' <ParenthesizedExpression> {
448
+ def parent_modules
449
+ []
450
+ end
377
451
  def inline_modules
378
452
  parsing_expression.inline_modules
379
453
  end
454
+ def inline_module
455
+ parsing_expression.inline_module
456
+ end
380
457
  }
381
458
  end
382
459
 
@@ -439,6 +516,9 @@ module Treetop
439
516
 
440
517
  rule trailing_inline_module
441
518
  space inline_module {
519
+ def parent_modules
520
+ []
521
+ end
442
522
  def inline_modules
443
523
  [inline_module]
444
524
  end
@@ -449,6 +529,9 @@ module Treetop
449
529
  }
450
530
  /
451
531
  '' {
532
+ def parent_modules
533
+ []
534
+ end
452
535
  def inline_modules
453
536
  []
454
537
  end
@@ -5,8 +5,8 @@ module Treetop
5
5
  super
6
6
  builder.if__ "index < input_length" do
7
7
  if address == 0 || decorated?
8
- assign_result "instantiate_node(#{node_class_name},input, index...(index + 1))"
9
- extend_result_with_inline_module
8
+ assign_result "instantiate_node(#{node_class_name},input, index...(index + 1))"
9
+ extend_result_with_inline_module parent_expression
10
10
  else
11
11
  assign_lazily_instantiated_node
12
12
  end
@@ -17,6 +17,14 @@ module Treetop
17
17
  assign_result 'nil'
18
18
  end
19
19
  end
20
+
21
+ def expected
22
+ '"any character"'
23
+ end
24
+
25
+ def inline_module
26
+ nil
27
+ end
20
28
  end
21
29
  end
22
30
  end
@@ -6,8 +6,8 @@ module Treetop
6
6
  end
7
7
 
8
8
  def single_quote(string)
9
- # Double any backslashes, then backslash any single-quotes:
10
- "'#{string.gsub(/\\/) { '\\\\' }.gsub(/'/) { "\\'"}}'"
9
+ # Double any backslashes, then backslash any single-quotes:
10
+ "'#{string.gsub(/\\/) { '\\\\' }.gsub(/'/) { "\\'"}}'"
11
11
  end
12
12
  end
13
13
  end
@@ -7,18 +7,26 @@ module Treetop
7
7
  builder.if__ "has_terminal?(@regexps[gr = #{grounded_regexp(text_value)}] ||= Regexp.new(gr), :regexp, index)" do
8
8
  if address == 0 || decorated?
9
9
  assign_result "instantiate_node(#{node_class_name},input, index...(index + 1))"
10
- extend_result_with_inline_module
10
+ extend_result_with_inline_module parent_expression
11
11
  else
12
12
  assign_lazily_instantiated_node
13
13
  end
14
14
  builder << "@index += 1" # Always one character
15
15
  end
16
16
  builder.else_ do
17
- builder << "terminal_parse_failure(#{single_quote('['+characters+']')})"
17
+ builder << "terminal_parse_failure(#{expected})"
18
18
  assign_result 'nil'
19
19
  end
20
20
  end
21
21
 
22
+ def expected
23
+ single_quote('['+characters+']')
24
+ end
25
+
26
+ def inline_module
27
+ nil
28
+ end
29
+
22
30
  def grounded_regexp(string)
23
31
  # Double any backslashes, then backslash any single-quotes:
24
32
  "'\\A#{string.gsub(/\\/) { '\\\\' }.gsub(/'/) { "\\'"}}'"
@@ -5,29 +5,33 @@ module Treetop
5
5
  super
6
6
  begin_comment(self)
7
7
  use_vars :result, :start_index
8
- compile_alternatives(alternatives)
8
+ compile_alternatives(alternatives, parent_expression)
9
9
  end_comment(self)
10
10
  end
11
-
12
- def compile_alternatives(alternatives)
11
+
12
+ def compile_alternatives(alternatives, parent_expression)
13
13
  obtain_new_subexpression_address
14
14
  alternatives.first.compile(subexpression_address, builder)
15
15
  builder.if__ subexpression_success? do
16
- # Undo lazy instantiation:
17
- builder << "#{subexpression_result_var} = SyntaxNode.new(input, (index-1)...index) if #{subexpression_result_var} == true"
16
+ # Undo lazy instantiation:
17
+ builder << "#{subexpression_result_var} = SyntaxNode.new(input, (index-1)...index) if #{subexpression_result_var} == true"
18
18
  assign_result subexpression_result_var
19
19
  extend_result_with_declared_module
20
- extend_result_with_inline_module
20
+ extend_result_with_inline_module parent_expression
21
21
  end
22
22
  builder.else_ do
23
23
  if alternatives.size == 1
24
24
  reset_index
25
25
  assign_failure start_index_var
26
26
  else
27
- compile_alternatives(alternatives[1..-1])
27
+ compile_alternatives(alternatives[1..-1], parent_expression)
28
28
  end
29
29
  end
30
30
  end
31
+
32
+ def expected
33
+ '"(any alternative)"'
34
+ end
31
35
  end
32
36
  end
33
37
  end
@@ -6,8 +6,12 @@ module Treetop
6
6
  use_vars :result
7
7
  assign_result text_value == 'super' ? 'super' : "_nt_#{text_value}"
8
8
  extend_result_with_declared_module
9
- extend_result_with_inline_module
9
+ extend_result_with_inline_module parent_expression
10
+ end
11
+
12
+ def inline_module
13
+ nil
10
14
  end
11
15
  end
12
16
  end
13
- end
17
+ end
@@ -4,6 +4,10 @@ module Treetop
4
4
  def compile(address, builder, parent_expression = nil)
5
5
  elements[2].compile(address, builder, parent_expression)
6
6
  end
7
+
8
+ def expected
9
+ elements[2].expected
10
+ end
7
11
  end
8
12
  end
9
- end
13
+ end
@@ -78,7 +78,12 @@ module Treetop
78
78
  extend_result declared_module_name if declared_module_name
79
79
  end
80
80
 
81
- def extend_result_with_inline_module
81
+ def extend_result_with_inline_module parent_expression = nil
82
+ if parent_expression && parent_expression.parent_modules.size > 0
83
+ parent_expression.parent_modules.each do |inline|
84
+ extend_result inline.module_name
85
+ end
86
+ end
82
87
  extend_result inline_module_name if inline_module_name
83
88
  end
84
89
 
@@ -141,6 +146,10 @@ module Treetop
141
146
  def on_one_line(expression)
142
147
  expression.text_value.tr("\n", ' ')
143
148
  end
149
+
150
+ def expected
151
+ nil # Overridden for terminal parse failures
152
+ end
144
153
  end
145
154
  end
146
155
  end
@@ -33,7 +33,7 @@ module Treetop
33
33
 
34
34
  def generate_cache_lookup(builder)
35
35
  builder.if_ "node_cache[:#{name}].has_key?(index)" do
36
- cache_address = "node_cache[:#{name}][index]"
36
+ cache_address = "node_cache[:#{name}][index]"
37
37
  builder.assign 'cached', cache_address
38
38
  builder.if_ "cached" do
39
39
  # Handle lazily instantiated nodes:
@@ -13,6 +13,7 @@ module Treetop
13
13
  end
14
14
 
15
15
  def assign_failure
16
+ reset_index
16
17
  super(start_index_var)
17
18
  end
18
19
 
@@ -35,11 +36,17 @@ module Treetop
35
36
  class NotPredicate < Predicate
36
37
  def when_success
37
38
  assign_failure
39
+ if (e = parent.atomic.expected)
40
+ builder << "terminal_parse_failure(#{e}, true)"
41
+ end
38
42
  end
39
43
 
40
44
  def when_failure
45
+ if (e = parent.atomic.expected)
46
+ builder << "@terminal_failures.pop"
47
+ end
41
48
  assign_success
42
49
  end
43
50
  end
44
51
  end
45
- end
52
+ end
@@ -10,6 +10,13 @@ module Treetop
10
10
  p = parent
11
11
  p = p.parent while p && !p.respond_to?(:accumulator_var)
12
12
  assign_result "lambda #{text_value}.call(#{p ? p.accumulator_var : ""})"
13
+ builder.if_ '!'+result_var do
14
+ builder << "terminal_parse_failure(#{expected})"
15
+ end
16
+ end
17
+
18
+ def expected
19
+ '"<semantic predicate>"' # Should I include (some of) the text_value here?
13
20
  end
14
21
  end
15
22
  end
@@ -28,9 +28,9 @@ module Treetop
28
28
  parent_expression.inline_module_name
29
29
  end
30
30
 
31
- def assign_and_extend_result
31
+ def assign_and_extend_result parent_expression
32
32
  assign_result "instantiate_node(#{node_class_name},input, #{start_index_var}...index, #{accumulator_var})"
33
- extend_result_with_inline_module
33
+ extend_result_with_inline_module parent_expression
34
34
  end
35
35
  end
36
36
 
@@ -38,7 +38,7 @@ module Treetop
38
38
  class ZeroOrMore < Repetition
39
39
  def compile(address, builder, parent_expression)
40
40
  super
41
- assign_and_extend_result
41
+ assign_and_extend_result parent_expression
42
42
  end_comment(parent_expression)
43
43
  end
44
44
 
@@ -55,7 +55,7 @@ module Treetop
55
55
  assign_failure start_index_var
56
56
  end
57
57
  builder.else_ do
58
- assign_and_extend_result
58
+ assign_and_extend_result parent_expression
59
59
  end
60
60
  end_comment(parent_expression)
61
61
  end
@@ -63,26 +63,46 @@ module Treetop
63
63
  def max
64
64
  nil
65
65
  end
66
+
67
+ def expected
68
+ parent_expression.atomic.expected && '"at least one "+'+parent_expression.atomic.expected
69
+ end
66
70
  end
67
71
 
68
72
  class OccurrenceRange < Repetition
69
73
  def compile(address, builder, parent_expression)
70
74
  super
71
75
 
72
- if min.empty? || min.text_value.to_i == 0
73
- assign_and_extend_result
74
- else
76
+ if !min.empty? && min.text_value.to_i != 0
75
77
  # We got some, but fewer than we wanted. There'll be a failure reported already
76
78
  builder.if__ "#{accumulator_var}.size < #{min.text_value}" do
77
79
  reset_index
78
80
  assign_failure start_index_var
79
81
  end
80
82
  builder.else_ do
81
- assign_and_extend_result
83
+ clean_unsaturated
84
+ assign_and_extend_result parent_expression
82
85
  end
86
+ else
87
+ clean_unsaturated
88
+ assign_and_extend_result parent_expression
83
89
  end
90
+
84
91
  end_comment(parent_expression)
85
92
  end
93
+
94
+ # remove the last terminal_failure if we merely failed to reach the maximum
95
+ def clean_unsaturated
96
+ if !max.empty? && max.text_value.to_i > 0
97
+ builder.if_ "#{accumulator_var}.size < #{max.text_value}" do
98
+ builder << '@terminal_failures.pop' # Ignore the last failure.
99
+ end
100
+ end
101
+ end
102
+
103
+ def expected
104
+ parent_expression.atomic.expected && "at least #{min.text_value} "+parent_expression.atomic.expected
105
+ end
86
106
  end
87
107
 
88
108
  end
@@ -9,7 +9,7 @@ module Treetop
9
9
  builder.if__ "#{accumulator_var}.last" do
10
10
  assign_result "instantiate_node(#{node_class_name},input, #{start_index_var}...index, #{accumulator_var})"
11
11
  extend_result sequence_element_accessor_module_name if sequence_element_accessor_module_name
12
- extend_result_with_inline_module
12
+ extend_result_with_inline_module parent_expression
13
13
  end
14
14
  builder.else_ do
15
15
  reset_index
@@ -40,6 +40,10 @@ module Treetop
40
40
  def sequence_element_accessor_module_name
41
41
  sequence_element_accessor_module.module_name
42
42
  end
43
+
44
+ def expected
45
+ '"<a sequence>"'
46
+ end
43
47
  end
44
48
 
45
49
  class SequenceElementAccessorModule
@@ -3,39 +3,53 @@ module Treetop
3
3
  class Terminal < AtomicExpression
4
4
  def compile(address, builder, parent_expression = nil)
5
5
  super
6
- # Handle modifiers:
7
- insensitive = modifiers.text_value.include? 'i'
8
- re = modifiers.text_value.include? 'r'
9
- if re
10
- grounded_regexp = "#{('\A'+eval(string)).inspect}"
11
- cache_key = "'__#{modifiers.text_value}__'+(gr = #{grounded_regexp})"
12
- re_modifiers = "#{insensitive ? 'Regexp::IGNORECASE' : 0}"
13
- str = "@regexps[#{cache_key}] ||= Regexp.new(gr, #{re_modifiers})"
14
- mode = ':regexp'
15
- elsif insensitive
16
- str = string.downcase
17
- string_length = eval(str).length
18
- mode = ':insens'
19
- else
20
- str = string
21
- string_length = eval(str).length
22
- mode = 'false'
23
- end
6
+ # Handle modifiers:
7
+ insensitive = modifiers.text_value.include? 'i'
8
+ re = modifiers.text_value.include? 'r'
9
+ if re
10
+ grounded_regexp = "#{('\A'+eval(string)).inspect}"
11
+ cache_key = "'__#{modifiers.text_value}__'+(gr = #{grounded_regexp})"
12
+ re_modifiers = "#{insensitive ? 'Regexp::IGNORECASE' : 0}"
13
+ str = "@regexps[#{cache_key}] ||= Regexp.new(gr, #{re_modifiers})"
14
+ mode = ':regexp'
15
+ elsif insensitive
16
+ str = string.downcase
17
+ string_length = eval(str).length
18
+ mode = ':insens'
19
+ else
20
+ str = string
21
+ string_length = eval(str).length
22
+ mode = 'false'
23
+ end
24
24
 
25
25
  builder.if__ "(match_len = has_terminal?(#{str}, #{mode}, index))" do
26
26
  if address == 0 || decorated? || mode != 'false' || string_length > 1
27
- assign_result "instantiate_node(#{node_class_name},input, index...(index + match_len))"
28
- extend_result_with_inline_module
27
+ assign_result "instantiate_node(#{node_class_name},input, index...(index + match_len))"
28
+ # debugger if parent_expression and parent_expression.inline_modules.size > 0
29
+ # extend_result_with_inline_module parent_expression
30
+ if parent_expression
31
+ parent_expression.inline_modules.each do |inline|
32
+ extend_result inline.module_name
33
+ end
34
+ end
29
35
  else
30
36
  assign_lazily_instantiated_node
31
- end
37
+ end
32
38
  builder << "@index += match_len"
33
39
  end
34
40
  builder.else_ do
35
- builder << "terminal_parse_failure(#{string})"
41
+ builder << "terminal_parse_failure(#{expected})"
36
42
  assign_result 'nil'
37
43
  end
38
44
  end
45
+
46
+ def expected
47
+ single_quote(string)
48
+ end
49
+
50
+ def inline_module
51
+ nil
52
+ end
39
53
  end
40
54
  end
41
55
  end
@@ -9,11 +9,11 @@ module Treetop
9
9
  def initialize
10
10
  @level = 0
11
11
  @address_space = LexicalAddressSpace.new
12
- @ruby = ""
12
+ @ruby = String.new("")
13
13
  end
14
14
 
15
15
  def <<(ruby_line)
16
- return if ruby_line.blank?
16
+ return if ruby_line == ''
17
17
  ruby << ruby_line.tabto(level) << "\n"
18
18
  end
19
19
 
@@ -13,12 +13,6 @@ class String
13
13
  self[0...index].count("\n") + 1
14
14
  end
15
15
 
16
- unless method_defined?(:blank?)
17
- def blank?
18
- self == ""
19
- end
20
- end
21
-
22
16
  # The following methods are lifted from Facets 2.0.2
23
17
  def tabto(n)
24
18
  if self =~ /^( *)\S/