treetop 1.1.4 → 1.2.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 +1 -1
- data/Rakefile +3 -2
- data/doc/contributing_and_planned_features.markdown +1 -1
- data/doc/using_in_ruby.markdown +2 -2
- data/examples/lambda_calculus/arithmetic.rb +551 -0
- data/examples/lambda_calculus/arithmetic_test.rb +1 -1
- data/examples/lambda_calculus/lambda_calculus.rb +39 -72
- data/examples/lambda_calculus/lambda_calculus_test.rb +2 -2
- data/examples/lambda_calculus/test_helper.rb +3 -3
- data/lib/treetop.rb +3 -0
- data/lib/treetop/bootstrap_gen_1_metagrammar.rb +22 -14
- data/lib/treetop/compiler.rb +1 -2
- data/lib/treetop/compiler/grammar_compiler.rb +12 -5
- data/lib/treetop/compiler/metagrammar.rb +931 -558
- data/lib/treetop/compiler/metagrammar.treetop +26 -6
- data/lib/treetop/compiler/node_classes/anything_symbol.rb +10 -2
- data/lib/treetop/compiler/node_classes/atomic_expression.rb +4 -0
- data/lib/treetop/compiler/node_classes/character_class.rb +10 -1
- data/lib/treetop/compiler/node_classes/choice.rb +2 -4
- data/lib/treetop/compiler/node_classes/parsing_expression.rb +8 -17
- data/lib/treetop/compiler/node_classes/parsing_rule.rb +3 -3
- data/lib/treetop/compiler/node_classes/predicate.rb +1 -1
- data/lib/treetop/compiler/node_classes/repetition.rb +3 -4
- data/lib/treetop/compiler/node_classes/sequence.rb +4 -4
- data/lib/treetop/compiler/node_classes/terminal.rb +11 -1
- data/lib/treetop/compiler/ruby_builder.rb +2 -2
- data/lib/treetop/ruby_extensions.rb +1 -1
- data/lib/treetop/runtime.rb +0 -3
- data/lib/treetop/runtime/compiled_parser.rb +42 -34
- data/lib/treetop/runtime/node_cache.rb +1 -1
- data/lib/treetop/runtime/syntax_node.rb +51 -32
- data/lib/treetop/runtime/terminal_parse_failure.rb +7 -24
- data/lib/treetop/runtime/terminal_syntax_node.rb +7 -2
- metadata +12 -7
- data/examples/TALK +0 -33
- data/lib/treetop/compiler/load_grammar.rb +0 -7
- data/lib/treetop/compiler/metagrammar. +0 -0
- data/lib/treetop/runtime/parse_failure.rb +0 -32
- data/lib/treetop/runtime/parse_result.rb +0 -30
@@ -297,19 +297,31 @@ module Treetop
|
|
297
297
|
end
|
298
298
|
|
299
299
|
rule terminal
|
300
|
-
|
300
|
+
quoted_string / character_class / anything_symbol
|
301
|
+
end
|
302
|
+
|
303
|
+
rule quoted_string
|
304
|
+
(single_quoted_string / double_quoted_string) {
|
305
|
+
def string
|
306
|
+
super.text_value
|
307
|
+
end
|
308
|
+
}
|
301
309
|
end
|
302
310
|
|
303
311
|
rule double_quoted_string
|
304
|
-
'"' (!'"' ("\\\\" / '\"' / .))* '"' <Terminal>
|
312
|
+
'"' string:(!'"' ("\\\\" / '\"' / .))* '"' <Terminal>
|
305
313
|
end
|
306
314
|
|
307
315
|
rule single_quoted_string
|
308
|
-
"'" (!"'" ("\\\\" / "\\'" / .))* "'" <Terminal>
|
316
|
+
"'" string:(!"'" ("\\\\" / "\\'" / .))* "'" <Terminal>
|
309
317
|
end
|
310
318
|
|
311
319
|
rule character_class
|
312
|
-
'[' (!']' ('\]'/.))+ ']' <CharacterClass>
|
320
|
+
'[' characters:(!']' ('\]'/.))+ ']' <CharacterClass> {
|
321
|
+
def characters
|
322
|
+
super.text_value
|
323
|
+
end
|
324
|
+
}
|
313
325
|
end
|
314
326
|
|
315
327
|
rule anything_symbol
|
@@ -377,8 +389,16 @@ module Treetop
|
|
377
389
|
end
|
378
390
|
|
379
391
|
rule space
|
380
|
-
|
392
|
+
(white / comment_to_eol)+
|
393
|
+
end
|
394
|
+
|
395
|
+
rule comment_to_eol
|
396
|
+
'#' (!"\n" .)+
|
397
|
+
end
|
398
|
+
|
399
|
+
rule white
|
400
|
+
[ \t\n\r]
|
381
401
|
end
|
382
402
|
end
|
383
403
|
end
|
384
|
-
end
|
404
|
+
end
|
@@ -3,8 +3,16 @@ module Treetop
|
|
3
3
|
class AnythingSymbol < AtomicExpression
|
4
4
|
def compile(address, builder, parent_expression = nil)
|
5
5
|
super
|
6
|
-
|
6
|
+
builder.if__ "index < input_length" do
|
7
|
+
assign_result "(#{node_class_name}).new(input, index...(index + 1))"
|
8
|
+
extend_result_with_inline_module
|
9
|
+
builder << "@index += 1"
|
10
|
+
end
|
11
|
+
builder.else_ do
|
12
|
+
builder << 'terminal_parse_failure("any character")'
|
13
|
+
assign_result 'nil'
|
14
|
+
end
|
7
15
|
end
|
8
16
|
end
|
9
17
|
end
|
10
|
-
end
|
18
|
+
end
|
@@ -3,7 +3,16 @@ module Treetop
|
|
3
3
|
class CharacterClass < AtomicExpression
|
4
4
|
def compile(address, builder, parent_expression = nil)
|
5
5
|
super
|
6
|
-
|
6
|
+
|
7
|
+
builder.if__ "input.index(/#{text_value}/, index) == index" do
|
8
|
+
assign_result "(#{node_class_name}).new(input, index...(index + 1))"
|
9
|
+
extend_result_with_inline_module
|
10
|
+
builder << "@index += 1"
|
11
|
+
end
|
12
|
+
builder.else_ do
|
13
|
+
"terminal_parse_failure(#{single_quote(characters)})"
|
14
|
+
assign_result 'nil'
|
15
|
+
end
|
7
16
|
end
|
8
17
|
end
|
9
18
|
end
|
@@ -4,7 +4,7 @@ module Treetop
|
|
4
4
|
def compile(address, builder, parent_expression = nil)
|
5
5
|
super
|
6
6
|
begin_comment(self)
|
7
|
-
use_vars :result, :start_index
|
7
|
+
use_vars :result, :start_index
|
8
8
|
compile_alternatives(alternatives)
|
9
9
|
end_comment(self)
|
10
10
|
end
|
@@ -12,17 +12,15 @@ module Treetop
|
|
12
12
|
def compile_alternatives(alternatives)
|
13
13
|
obtain_new_subexpression_address
|
14
14
|
alternatives.first.compile(subexpression_address, builder)
|
15
|
-
accumulate_nested_result
|
16
15
|
builder.if__ subexpression_success? do
|
17
16
|
assign_result subexpression_result_var
|
18
17
|
extend_result_with_declared_module
|
19
18
|
extend_result_with_inline_module
|
20
|
-
builder << "#{subexpression_result_var}.update_nested_results(#{nested_results_var})"
|
21
19
|
end
|
22
20
|
builder.else_ do
|
23
21
|
if alternatives.size == 1
|
24
22
|
reset_index
|
25
|
-
assign_failure start_index_var
|
23
|
+
assign_failure start_index_var
|
26
24
|
else
|
27
25
|
compile_alternatives(alternatives[1..-1])
|
28
26
|
end
|
@@ -41,11 +41,7 @@ module Treetop
|
|
41
41
|
def accumulator_var
|
42
42
|
var(:accumulator)
|
43
43
|
end
|
44
|
-
|
45
|
-
def nested_results_var
|
46
|
-
var(:nested_results)
|
47
|
-
end
|
48
|
-
|
44
|
+
|
49
45
|
def start_index_var
|
50
46
|
var(:start_index)
|
51
47
|
end
|
@@ -55,17 +51,13 @@ module Treetop
|
|
55
51
|
end
|
56
52
|
|
57
53
|
def subexpression_success?
|
58
|
-
subexpression_result_var
|
54
|
+
subexpression_result_var
|
59
55
|
end
|
60
56
|
|
61
57
|
def obtain_new_subexpression_address
|
62
58
|
@subexpression_address = builder.next_address
|
63
59
|
end
|
64
|
-
|
65
|
-
def accumulate_nested_result
|
66
|
-
builder.accumulate nested_results_var, subexpression_result_var
|
67
|
-
end
|
68
|
-
|
60
|
+
|
69
61
|
def accumulate_subexpression_result
|
70
62
|
builder.accumulate accumulator_var, subexpression_result_var
|
71
63
|
end
|
@@ -91,11 +83,11 @@ module Treetop
|
|
91
83
|
end
|
92
84
|
|
93
85
|
def epsilon_node
|
94
|
-
"SyntaxNode.new(input, index...index
|
86
|
+
"SyntaxNode.new(input, index...index)"
|
95
87
|
end
|
96
88
|
|
97
|
-
def assign_failure(start_index_var
|
98
|
-
assign_result("
|
89
|
+
def assign_failure(start_index_var)
|
90
|
+
assign_result("nil")
|
99
91
|
end
|
100
92
|
|
101
93
|
def var_initialization
|
@@ -117,7 +109,6 @@ module Treetop
|
|
117
109
|
case var_symbol
|
118
110
|
when :result then "r#{address}"
|
119
111
|
when :accumulator then "s#{address}"
|
120
|
-
when :nested_results then "nr#{address}"
|
121
112
|
when :start_index then "i#{address}"
|
122
113
|
else raise "Unknown var symbol #{var_symbol}."
|
123
114
|
end
|
@@ -125,7 +116,7 @@ module Treetop
|
|
125
116
|
|
126
117
|
def init_value(var_symbol)
|
127
118
|
case var_symbol
|
128
|
-
when :accumulator
|
119
|
+
when :accumulator then '[]'
|
129
120
|
when :start_index then 'index'
|
130
121
|
else nil
|
131
122
|
end
|
@@ -144,4 +135,4 @@ module Treetop
|
|
144
135
|
end
|
145
136
|
end
|
146
137
|
end
|
147
|
-
end
|
138
|
+
end
|
@@ -32,9 +32,9 @@ module Treetop
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def generate_cache_lookup(builder)
|
35
|
-
builder.
|
36
|
-
|
37
|
-
builder << '@index = cached.interval.end'
|
35
|
+
builder.if_ "node_cache[:#{name}].has_key?(index)" do
|
36
|
+
builder.assign 'cached', "node_cache[:#{name}][index]"
|
37
|
+
builder << '@index = cached.interval.end if cached'
|
38
38
|
builder << 'return cached'
|
39
39
|
end
|
40
40
|
end
|
@@ -5,12 +5,11 @@ module Treetop
|
|
5
5
|
super
|
6
6
|
repeated_expression = parent_expression.atomic
|
7
7
|
begin_comment(parent_expression)
|
8
|
-
use_vars :result, :accumulator, :
|
8
|
+
use_vars :result, :accumulator, :start_index
|
9
9
|
|
10
10
|
builder.loop do
|
11
11
|
obtain_new_subexpression_address
|
12
12
|
repeated_expression.compile(subexpression_address, builder)
|
13
|
-
accumulate_nested_result
|
14
13
|
builder.if__ subexpression_success? do
|
15
14
|
accumulate_subexpression_result
|
16
15
|
end
|
@@ -25,7 +24,7 @@ module Treetop
|
|
25
24
|
end
|
26
25
|
|
27
26
|
def assign_and_extend_result
|
28
|
-
assign_result "#{node_class_name}.new(input, #{start_index_var}...index, #{accumulator_var}
|
27
|
+
assign_result "#{node_class_name}.new(input, #{start_index_var}...index, #{accumulator_var})"
|
29
28
|
extend_result_with_inline_module
|
30
29
|
end
|
31
30
|
end
|
@@ -44,7 +43,7 @@ module Treetop
|
|
44
43
|
super
|
45
44
|
builder.if__ "#{accumulator_var}.empty?" do
|
46
45
|
reset_index
|
47
|
-
assign_failure start_index_var
|
46
|
+
assign_failure start_index_var
|
48
47
|
end
|
49
48
|
builder.else_ do
|
50
49
|
assign_and_extend_result
|
@@ -4,16 +4,16 @@ module Treetop
|
|
4
4
|
def compile(address, builder, parent_expression = nil)
|
5
5
|
super
|
6
6
|
begin_comment(self)
|
7
|
-
use_vars :result, :start_index, :accumulator
|
7
|
+
use_vars :result, :start_index, :accumulator
|
8
8
|
compile_sequence_elements(sequence_elements)
|
9
|
-
builder.if__ "#{accumulator_var}.last
|
9
|
+
builder.if__ "#{accumulator_var}.last" do
|
10
10
|
assign_result "(#{node_class_name}).new(input, #{start_index_var}...index, #{accumulator_var})"
|
11
11
|
extend_result sequence_element_accessor_module_name if sequence_element_accessor_module_name
|
12
12
|
extend_result_with_inline_module
|
13
13
|
end
|
14
14
|
builder.else_ do
|
15
15
|
reset_index
|
16
|
-
assign_failure start_index_var
|
16
|
+
assign_failure start_index_var
|
17
17
|
end
|
18
18
|
end_comment(self)
|
19
19
|
end
|
@@ -65,4 +65,4 @@ module Treetop
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
end
|
68
|
-
end
|
68
|
+
end
|
@@ -3,7 +3,17 @@ module Treetop
|
|
3
3
|
class Terminal < AtomicExpression
|
4
4
|
def compile(address, builder, parent_expression = nil)
|
5
5
|
super
|
6
|
-
|
6
|
+
string_length = eval(text_value).length
|
7
|
+
|
8
|
+
builder.if__ "input.index(#{text_value}, index) == index" do
|
9
|
+
assign_result "(#{node_class_name}).new(input, index...(index + #{string_length}))"
|
10
|
+
extend_result_with_inline_module
|
11
|
+
builder << "@index += #{string_length}"
|
12
|
+
end
|
13
|
+
builder.else_ do
|
14
|
+
builder << "terminal_parse_failure(#{text_value})"
|
15
|
+
assign_result 'nil'
|
16
|
+
end
|
7
17
|
end
|
8
18
|
end
|
9
19
|
end
|
@@ -1,2 +1,2 @@
|
|
1
1
|
dir = File.dirname(__FILE__)
|
2
|
-
require "#{dir}/ruby_extensions/string"
|
2
|
+
require "#{dir}/ruby_extensions/string"
|
data/lib/treetop/runtime.rb
CHANGED
@@ -1,9 +1,6 @@
|
|
1
1
|
dir = File.dirname(__FILE__)
|
2
2
|
require "#{dir}/runtime/compiled_parser"
|
3
|
-
require "#{dir}/runtime/parse_result"
|
4
3
|
require "#{dir}/runtime/syntax_node"
|
5
|
-
require "#{dir}/runtime/parse_failure"
|
6
4
|
require "#{dir}/runtime/node_cache"
|
7
5
|
require "#{dir}/runtime/parse_cache"
|
8
|
-
require "#{dir}/runtime/parse_failure"
|
9
6
|
require "#{dir}/runtime/terminal_parse_failure"
|
@@ -3,11 +3,11 @@ module Treetop
|
|
3
3
|
class CompiledParser
|
4
4
|
include Treetop::Runtime
|
5
5
|
|
6
|
-
|
6
|
+
attr_reader :input, :index, :terminal_failures, :max_terminal_failure_index
|
7
7
|
attr_writer :root
|
8
|
+
attr_accessor :consume_all_input
|
8
9
|
alias :consume_all_input? :consume_all_input
|
9
|
-
|
10
|
-
|
10
|
+
|
11
11
|
def initialize
|
12
12
|
self.consume_all_input = true
|
13
13
|
end
|
@@ -16,50 +16,52 @@ module Treetop
|
|
16
16
|
prepare_to_parse(input)
|
17
17
|
@index = options[:index] if options[:index]
|
18
18
|
result = send("_nt_#{root}")
|
19
|
-
if consume_all_input? && index != input.size
|
20
|
-
|
21
|
-
else
|
22
|
-
return result
|
23
|
-
end
|
19
|
+
return nil if (consume_all_input? && index != input.size)
|
20
|
+
return result
|
24
21
|
end
|
25
|
-
|
22
|
+
|
23
|
+
def failure_index
|
24
|
+
max_terminal_failure_index
|
25
|
+
end
|
26
|
+
|
27
|
+
def failure_line
|
28
|
+
terminal_failures && input.line_of(failure_index)
|
29
|
+
end
|
30
|
+
|
31
|
+
def failure_column
|
32
|
+
terminal_failures && input.column_of(failure_index)
|
33
|
+
end
|
34
|
+
|
35
|
+
def failure_reason
|
36
|
+
return nil unless (tf = terminal_failures) && tf.size > 0
|
37
|
+
"Expected " +
|
38
|
+
(tf.size == 1 ?
|
39
|
+
tf[0].expected_string :
|
40
|
+
"one of #{tf.map{|f| f.expected_string}.uniq*', '}"
|
41
|
+
) +
|
42
|
+
" at line #{failure_line}, column #{failure_column} (byte #{failure_index+1})" +
|
43
|
+
" after #{input[index...failure_index]}"
|
44
|
+
end
|
45
|
+
|
46
|
+
|
26
47
|
protected
|
27
48
|
|
28
|
-
attr_reader :node_cache
|
49
|
+
attr_reader :node_cache, :input_length
|
29
50
|
attr_writer :index
|
30
51
|
|
31
52
|
def prepare_to_parse(input)
|
32
53
|
@input = input
|
54
|
+
@input_length = input.length
|
33
55
|
reset_index
|
34
56
|
@node_cache = Hash.new {|hash, key| hash[key] = Hash.new}
|
57
|
+
@terminal_failures = []
|
58
|
+
@max_terminal_failure_index = 0
|
35
59
|
end
|
36
60
|
|
37
61
|
def reset_index
|
38
62
|
@index = 0
|
39
63
|
end
|
40
64
|
|
41
|
-
def parse_char_class(char_class_re, char_class_string, node_class = SyntaxNode, inline_module = nil)
|
42
|
-
if input.index(char_class_re, index) == index
|
43
|
-
result = node_class.new(input, index...(index + 1))
|
44
|
-
result.extend(inline_module) if inline_module
|
45
|
-
@index += 1
|
46
|
-
result
|
47
|
-
else
|
48
|
-
terminal_parse_failure("[#{char_class_string}]")
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def parse_terminal(terminal_string, node_class = SyntaxNode, inline_module = nil)
|
53
|
-
if input.index(terminal_string, index) == index
|
54
|
-
result = node_class.new(input, index...(index + terminal_string.length))
|
55
|
-
result.extend(inline_module) if inline_module
|
56
|
-
@index += terminal_string.length
|
57
|
-
result
|
58
|
-
else
|
59
|
-
terminal_parse_failure(terminal_string)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
65
|
def parse_anything(node_class = SyntaxNode, inline_module = nil)
|
64
66
|
if index < input.length
|
65
67
|
result = node_class.new(input, index...(index + 1))
|
@@ -72,8 +74,14 @@ module Treetop
|
|
72
74
|
end
|
73
75
|
|
74
76
|
def terminal_parse_failure(expected_string)
|
75
|
-
|
77
|
+
return nil if index < max_terminal_failure_index
|
78
|
+
if index > max_terminal_failure_index
|
79
|
+
@max_terminal_failure_index = index
|
80
|
+
@terminal_failures = []
|
81
|
+
end
|
82
|
+
terminal_failures << TerminalParseFailure.new(index, expected_string)
|
83
|
+
return nil
|
76
84
|
end
|
77
85
|
end
|
78
86
|
end
|
79
|
-
end
|
87
|
+
end
|