treetop 1.1.1 → 1.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +2 -2
- data/doc/contributing_and_planned_features.markdown +106 -0
- data/doc/grammar_composition.markdown +65 -0
- data/doc/images/paren_language_output.png +0 -0
- data/doc/index.markdown +24 -0
- data/doc/pitfalls_and_advanced_techniques.markdown +51 -0
- data/doc/semantic_interpretation.markdown +187 -0
- data/doc/syntactic_recognition.markdown +103 -0
- data/doc/using_in_ruby.markdown +17 -0
- data/examples/lambda_calculus/lambda_calculus +0 -0
- data/examples/lambda_calculus/lambda_calculus.rb +751 -0
- data/examples/lambda_calculus/lambda_calculus.treetop +0 -1
- metadata +12 -1
@@ -0,0 +1,103 @@
|
|
1
|
+
#Syntactic Recognition
|
2
|
+
Treetop grammars are written in a custom language based on parsing expression grammars. Literature on the subject of parsing expression grammars is useful in writing Treetop grammars.
|
3
|
+
|
4
|
+
#Grammar Structure
|
5
|
+
Treetop grammars look like this:
|
6
|
+
|
7
|
+
grammar GrammarName
|
8
|
+
rule rule_name
|
9
|
+
...
|
10
|
+
end
|
11
|
+
|
12
|
+
rule rule_name
|
13
|
+
...
|
14
|
+
end
|
15
|
+
|
16
|
+
...
|
17
|
+
end
|
18
|
+
|
19
|
+
The main keywords are:
|
20
|
+
|
21
|
+
* `grammar` : This introduces a new grammar. It is followed by a constant name to which the grammar will be bound when it is loaded.
|
22
|
+
|
23
|
+
* `rule` : This defines a parsing rule within the grammar. It is followed by a name by which this rule can be referenced within other rules. It is then followed by a parsing expression defining the rule.
|
24
|
+
|
25
|
+
#Parsing Expressions
|
26
|
+
Each rule associates a name with a _parsing expression_. Parsing expressions are a generalization of vanilla regular expressions. Their key feature is the ability to reference other expressions in the grammar by name.
|
27
|
+
|
28
|
+
##Atomic Expressions
|
29
|
+
###Terminal Symbols
|
30
|
+
####Strings
|
31
|
+
Strings are surrounded in double or single quotes and must be matched exactly.
|
32
|
+
|
33
|
+
* `"foo"`
|
34
|
+
* `'foo'`
|
35
|
+
|
36
|
+
####Character Classes
|
37
|
+
Character classes are surrounded by brackets. Their semantics are identical to those used in Ruby's regular expressions.
|
38
|
+
|
39
|
+
* `[a-zA-Z]`
|
40
|
+
* `[0-9]`
|
41
|
+
|
42
|
+
####The Anything Symbol
|
43
|
+
The anything symbol is represented by a dot (`.`) and matches any single character.
|
44
|
+
|
45
|
+
###Nonterminal Symbols
|
46
|
+
Nonterminal symbols are unquoted references to other named rules. They are equivalent to an inline substitution of the named expression.
|
47
|
+
|
48
|
+
rule foo
|
49
|
+
"the dog " bar
|
50
|
+
end
|
51
|
+
|
52
|
+
rule bar
|
53
|
+
"jumped"
|
54
|
+
end
|
55
|
+
|
56
|
+
The above grammar is equivalent to:
|
57
|
+
|
58
|
+
rule foo
|
59
|
+
"the dog jumped"
|
60
|
+
end
|
61
|
+
|
62
|
+
##Composite Expressions
|
63
|
+
###Ordered Choice
|
64
|
+
Parsers attempt to match ordered choices in left-to-right order, and stop after the first successful match.
|
65
|
+
|
66
|
+
"foobar" / "foo" / "bar"
|
67
|
+
|
68
|
+
Note that if `"foo"` in the above expression came first, `"foobar"` would never be matched.
|
69
|
+
|
70
|
+
###Sequences
|
71
|
+
|
72
|
+
Sequences are a space-separated list of parsing expressions. They have higher precedence than choices, so choices must be parenthesized to be used as the elements of a sequence.
|
73
|
+
|
74
|
+
"foo" "bar" ("baz" / "bop")
|
75
|
+
|
76
|
+
###Repetitions
|
77
|
+
####Zero or More
|
78
|
+
Parsers will greedily match an expression zero or more times if it is followed by the star (`*`) symbol.
|
79
|
+
|
80
|
+
* `'foo'*` matches the empty string, `"foo"`, `"foofoo"`, etc.
|
81
|
+
|
82
|
+
####One or More
|
83
|
+
Parsers will greedily match an expression one or more times if it is followed by the star (`+`) symbol.
|
84
|
+
|
85
|
+
* `'foo'+` does not match the empty string, but matches `"foo"`, `"foofoo"`, etc.
|
86
|
+
|
87
|
+
###Optional Expressions
|
88
|
+
An expression can be declared optional by following it with a question mark (`?`).
|
89
|
+
|
90
|
+
* `'foo'?` matches `"foo"` or the empty string.
|
91
|
+
|
92
|
+
##Lookahead Assertions
|
93
|
+
Lookahead assertions can be used to give parsing expressions a limited degree of context-sensitivity. The parser will look ahead into the buffer and attempt to match an expression without consuming input.
|
94
|
+
|
95
|
+
###Positive Lookahead Assertion
|
96
|
+
Preceding an expression with an ampersand `(&)` indicates that it must match, but no input will be consumed in the process of determining whether this is true.
|
97
|
+
|
98
|
+
* `"foo" &"bar"` matches `"foobar"` but only consumes up to the end `"foo"`. It will not match `"foobaz"`.
|
99
|
+
|
100
|
+
###Negative Lookahead Assertion
|
101
|
+
Preceding an expression with a bang `(!)` indicates that the expression must not match, but no input will be consumed in the process of determining whether this is true.
|
102
|
+
|
103
|
+
* `"foo" !"bar"` matches `"foobaz"` but only consumes up to the end `"foo"`. It will not match `"foobar"`.
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#Using Treetop Grammars in Ruby
|
2
|
+
##Using the Command Line Compiler
|
3
|
+
You can `.treetop` files into Ruby source code with the `tt` command line script. `tt` takes an list of files with a `.treetop` extension and compiles them into `.rb` files of the same name. You can then `require` these files like any other Ruby script. Alternately, you can supply just one `.treetop` file and a `-o` flag to name specify the name of the output file. Improvements to this compilation script are welcome.
|
4
|
+
|
5
|
+
tt foo.treetop bar.treetop
|
6
|
+
tt foo.treetop -o foogrammar.rb
|
7
|
+
|
8
|
+
##Loading A Grammar Directly
|
9
|
+
The `load_grammar` method takes the path to a `.treetop` file (where the extension is optional), and automatically compiles and evaluates the Ruby source. If you are getting errors in methods you define on the syntax tree, try using the command line compiler for better stack trace feedback. The need to do this is being addressed.
|
10
|
+
|
11
|
+
##Instantiating and Using Parsers
|
12
|
+
If a grammar by the name of `Foo` is defined, the compiled Ruby source will define a `FooParser` class. To parse input, create an instance and call its `parse` method with a string.
|
13
|
+
|
14
|
+
load_grammar "arithmetic"
|
15
|
+
|
16
|
+
parser = ArithmeticParser.new
|
17
|
+
puts parser.parse('1+1').success?
|
File without changes
|
@@ -0,0 +1,751 @@
|
|
1
|
+
module LambdaCalculus
|
2
|
+
include ::Treetop::Runtime
|
3
|
+
|
4
|
+
def root
|
5
|
+
result = _nt_program
|
6
|
+
if index == input.size
|
7
|
+
return result
|
8
|
+
else
|
9
|
+
return ParseFailure.new(input, index, result.nested_failures)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
include Arithmetic
|
14
|
+
|
15
|
+
module Program0
|
16
|
+
def space
|
17
|
+
elements[1]
|
18
|
+
end
|
19
|
+
|
20
|
+
def expression
|
21
|
+
elements[2]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module Program1
|
26
|
+
def expression
|
27
|
+
elements[0]
|
28
|
+
end
|
29
|
+
|
30
|
+
def more_expressions
|
31
|
+
elements[1]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module Program2
|
36
|
+
def eval(env={})
|
37
|
+
env = env.clone
|
38
|
+
last_eval = nil
|
39
|
+
expressions.each do |exp|
|
40
|
+
last_eval = exp.eval(env)
|
41
|
+
end
|
42
|
+
last_eval
|
43
|
+
end
|
44
|
+
|
45
|
+
def expressions
|
46
|
+
[expression] + more_expressions.elements.map {|elt| elt.expression}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def _nt_program
|
51
|
+
start_index = index
|
52
|
+
cached = node_cache[:program][index]
|
53
|
+
if cached
|
54
|
+
@index = cached.interval.end
|
55
|
+
return cached
|
56
|
+
end
|
57
|
+
|
58
|
+
i0, s0, nr0 = index, [], []
|
59
|
+
r1 = _nt_expression
|
60
|
+
s0 << r1
|
61
|
+
if r1.success?
|
62
|
+
s2, nr2, i2 = [], [], index
|
63
|
+
loop do
|
64
|
+
i3, s3, nr3 = index, [], []
|
65
|
+
r4 = parse_terminal(';', SyntaxNode)
|
66
|
+
s3 << r4
|
67
|
+
if r4.success?
|
68
|
+
r5 = _nt_space
|
69
|
+
s3 << r5
|
70
|
+
if r5.success?
|
71
|
+
r6 = _nt_expression
|
72
|
+
s3 << r6
|
73
|
+
end
|
74
|
+
end
|
75
|
+
if s3.last.success?
|
76
|
+
r3 = (SyntaxNode).new(input, i3...index, s3)
|
77
|
+
r3.extend(Program0)
|
78
|
+
else
|
79
|
+
self.index = i3
|
80
|
+
r3 = ParseFailure.new(input, i3, s3)
|
81
|
+
end
|
82
|
+
nr2 << r3
|
83
|
+
if r3.success?
|
84
|
+
s2 << r3
|
85
|
+
else
|
86
|
+
break
|
87
|
+
end
|
88
|
+
end
|
89
|
+
r2 = SyntaxNode.new(input, i2...index, s2, nr2)
|
90
|
+
s0 << r2
|
91
|
+
end
|
92
|
+
if s0.last.success?
|
93
|
+
r0 = (SyntaxNode).new(input, i0...index, s0)
|
94
|
+
r0.extend(Program1)
|
95
|
+
r0.extend(Program2)
|
96
|
+
else
|
97
|
+
self.index = i0
|
98
|
+
r0 = ParseFailure.new(input, i0, s0)
|
99
|
+
end
|
100
|
+
|
101
|
+
node_cache[:program][start_index] = r0
|
102
|
+
|
103
|
+
return r0
|
104
|
+
end
|
105
|
+
|
106
|
+
def _nt_expression
|
107
|
+
start_index = index
|
108
|
+
cached = node_cache[:expression][index]
|
109
|
+
if cached
|
110
|
+
@index = cached.interval.end
|
111
|
+
return cached
|
112
|
+
end
|
113
|
+
|
114
|
+
i0, nr0 = index, []
|
115
|
+
r1 = _nt_definition
|
116
|
+
nr0 << r1
|
117
|
+
if r1.success?
|
118
|
+
r0 = r1
|
119
|
+
r1.update_nested_results(nr0)
|
120
|
+
else
|
121
|
+
r2 = _nt_conditional
|
122
|
+
nr0 << r2
|
123
|
+
if r2.success?
|
124
|
+
r0 = r2
|
125
|
+
r2.update_nested_results(nr0)
|
126
|
+
else
|
127
|
+
r3 = _nt_application
|
128
|
+
nr0 << r3
|
129
|
+
if r3.success?
|
130
|
+
r0 = r3
|
131
|
+
r3.update_nested_results(nr0)
|
132
|
+
else
|
133
|
+
r4 = _nt_function
|
134
|
+
nr0 << r4
|
135
|
+
if r4.success?
|
136
|
+
r0 = r4
|
137
|
+
r4.update_nested_results(nr0)
|
138
|
+
else
|
139
|
+
r5 = super
|
140
|
+
nr0 << r5
|
141
|
+
if r5.success?
|
142
|
+
r0 = r5
|
143
|
+
r5.update_nested_results(nr0)
|
144
|
+
else
|
145
|
+
self.index = i0
|
146
|
+
r0 = ParseFailure.new(input, i0, nr0)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
node_cache[:expression][start_index] = r0
|
154
|
+
|
155
|
+
return r0
|
156
|
+
end
|
157
|
+
|
158
|
+
module Definition0
|
159
|
+
def space
|
160
|
+
elements[1]
|
161
|
+
end
|
162
|
+
|
163
|
+
def variable
|
164
|
+
elements[2]
|
165
|
+
end
|
166
|
+
|
167
|
+
def space
|
168
|
+
elements[3]
|
169
|
+
end
|
170
|
+
|
171
|
+
def expression
|
172
|
+
elements[4]
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
module Definition1
|
177
|
+
def eval(env)
|
178
|
+
env[variable.name] = expression.eval(env)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def _nt_definition
|
183
|
+
start_index = index
|
184
|
+
cached = node_cache[:definition][index]
|
185
|
+
if cached
|
186
|
+
@index = cached.interval.end
|
187
|
+
return cached
|
188
|
+
end
|
189
|
+
|
190
|
+
i0, s0, nr0 = index, [], []
|
191
|
+
r1 = parse_terminal('def', SyntaxNode)
|
192
|
+
s0 << r1
|
193
|
+
if r1.success?
|
194
|
+
r2 = _nt_space
|
195
|
+
s0 << r2
|
196
|
+
if r2.success?
|
197
|
+
r3 = _nt_variable
|
198
|
+
s0 << r3
|
199
|
+
if r3.success?
|
200
|
+
r4 = _nt_space
|
201
|
+
s0 << r4
|
202
|
+
if r4.success?
|
203
|
+
r5 = _nt_expression
|
204
|
+
s0 << r5
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
if s0.last.success?
|
210
|
+
r0 = (SyntaxNode).new(input, i0...index, s0)
|
211
|
+
r0.extend(Definition0)
|
212
|
+
r0.extend(Definition1)
|
213
|
+
else
|
214
|
+
self.index = i0
|
215
|
+
r0 = ParseFailure.new(input, i0, s0)
|
216
|
+
end
|
217
|
+
|
218
|
+
node_cache[:definition][start_index] = r0
|
219
|
+
|
220
|
+
return r0
|
221
|
+
end
|
222
|
+
|
223
|
+
module Conditional0
|
224
|
+
def space
|
225
|
+
elements[1]
|
226
|
+
end
|
227
|
+
|
228
|
+
def space
|
229
|
+
elements[3]
|
230
|
+
end
|
231
|
+
|
232
|
+
def condition
|
233
|
+
elements[4]
|
234
|
+
end
|
235
|
+
|
236
|
+
def space
|
237
|
+
elements[5]
|
238
|
+
end
|
239
|
+
|
240
|
+
def space
|
241
|
+
elements[7]
|
242
|
+
end
|
243
|
+
|
244
|
+
def true_case
|
245
|
+
elements[8]
|
246
|
+
end
|
247
|
+
|
248
|
+
def space
|
249
|
+
elements[9]
|
250
|
+
end
|
251
|
+
|
252
|
+
def space
|
253
|
+
elements[11]
|
254
|
+
end
|
255
|
+
|
256
|
+
def false_case
|
257
|
+
elements[12]
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
module Conditional1
|
262
|
+
def eval(env)
|
263
|
+
if condition.eval(env)
|
264
|
+
true_case.eval(env)
|
265
|
+
else
|
266
|
+
false_case.eval(env)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
def _nt_conditional
|
272
|
+
start_index = index
|
273
|
+
cached = node_cache[:conditional][index]
|
274
|
+
if cached
|
275
|
+
@index = cached.interval.end
|
276
|
+
return cached
|
277
|
+
end
|
278
|
+
|
279
|
+
i0, s0, nr0 = index, [], []
|
280
|
+
r1 = parse_terminal('if', SyntaxNode)
|
281
|
+
s0 << r1
|
282
|
+
if r1.success?
|
283
|
+
r2 = _nt_space
|
284
|
+
s0 << r2
|
285
|
+
if r2.success?
|
286
|
+
r3 = parse_terminal('(', SyntaxNode)
|
287
|
+
s0 << r3
|
288
|
+
if r3.success?
|
289
|
+
r4 = _nt_space
|
290
|
+
s0 << r4
|
291
|
+
if r4.success?
|
292
|
+
r5 = _nt_expression
|
293
|
+
s0 << r5
|
294
|
+
if r5.success?
|
295
|
+
r6 = _nt_space
|
296
|
+
s0 << r6
|
297
|
+
if r6.success?
|
298
|
+
r7 = parse_terminal(')', SyntaxNode)
|
299
|
+
s0 << r7
|
300
|
+
if r7.success?
|
301
|
+
r8 = _nt_space
|
302
|
+
s0 << r8
|
303
|
+
if r8.success?
|
304
|
+
r9 = _nt_expression
|
305
|
+
s0 << r9
|
306
|
+
if r9.success?
|
307
|
+
r10 = _nt_space
|
308
|
+
s0 << r10
|
309
|
+
if r10.success?
|
310
|
+
r11 = parse_terminal('else', SyntaxNode)
|
311
|
+
s0 << r11
|
312
|
+
if r11.success?
|
313
|
+
r12 = _nt_space
|
314
|
+
s0 << r12
|
315
|
+
if r12.success?
|
316
|
+
r13 = _nt_expression
|
317
|
+
s0 << r13
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
330
|
+
if s0.last.success?
|
331
|
+
r0 = (SyntaxNode).new(input, i0...index, s0)
|
332
|
+
r0.extend(Conditional0)
|
333
|
+
r0.extend(Conditional1)
|
334
|
+
else
|
335
|
+
self.index = i0
|
336
|
+
r0 = ParseFailure.new(input, i0, s0)
|
337
|
+
end
|
338
|
+
|
339
|
+
node_cache[:conditional][start_index] = r0
|
340
|
+
|
341
|
+
return r0
|
342
|
+
end
|
343
|
+
|
344
|
+
def _nt_primary
|
345
|
+
start_index = index
|
346
|
+
cached = node_cache[:primary][index]
|
347
|
+
if cached
|
348
|
+
@index = cached.interval.end
|
349
|
+
return cached
|
350
|
+
end
|
351
|
+
|
352
|
+
i0, nr0 = index, []
|
353
|
+
r1 = _nt_application
|
354
|
+
nr0 << r1
|
355
|
+
if r1.success?
|
356
|
+
r0 = r1
|
357
|
+
r1.update_nested_results(nr0)
|
358
|
+
else
|
359
|
+
r2 = super
|
360
|
+
nr0 << r2
|
361
|
+
if r2.success?
|
362
|
+
r0 = r2
|
363
|
+
r2.update_nested_results(nr0)
|
364
|
+
else
|
365
|
+
self.index = i0
|
366
|
+
r0 = ParseFailure.new(input, i0, nr0)
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
node_cache[:primary][start_index] = r0
|
371
|
+
|
372
|
+
return r0
|
373
|
+
end
|
374
|
+
|
375
|
+
module Application0
|
376
|
+
def operator
|
377
|
+
elements[0]
|
378
|
+
end
|
379
|
+
|
380
|
+
def space
|
381
|
+
elements[1]
|
382
|
+
end
|
383
|
+
|
384
|
+
def expression
|
385
|
+
elements[2]
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
module Application1
|
390
|
+
def eval(env={})
|
391
|
+
left_associative_apply(operator.eval(env), env)
|
392
|
+
end
|
393
|
+
|
394
|
+
def left_associative_apply(operator, env)
|
395
|
+
if expression.instance_of?(Application)
|
396
|
+
expression.left_associative_apply(operator.apply(expression.operator.eval(env)), env)
|
397
|
+
else
|
398
|
+
operator.apply(expression.eval(env))
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
def to_s(env={})
|
403
|
+
operator.to_s(env) + ' ' + expression.to_s(env)
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
def _nt_application
|
408
|
+
start_index = index
|
409
|
+
cached = node_cache[:application][index]
|
410
|
+
if cached
|
411
|
+
@index = cached.interval.end
|
412
|
+
return cached
|
413
|
+
end
|
414
|
+
|
415
|
+
i0, s0, nr0 = index, [], []
|
416
|
+
r1 = _nt_operator
|
417
|
+
s0 << r1
|
418
|
+
if r1.success?
|
419
|
+
r2 = _nt_space
|
420
|
+
s0 << r2
|
421
|
+
if r2.success?
|
422
|
+
r3 = _nt_expression
|
423
|
+
s0 << r3
|
424
|
+
end
|
425
|
+
end
|
426
|
+
if s0.last.success?
|
427
|
+
r0 = (Application).new(input, i0...index, s0)
|
428
|
+
r0.extend(Application0)
|
429
|
+
r0.extend(Application1)
|
430
|
+
else
|
431
|
+
self.index = i0
|
432
|
+
r0 = ParseFailure.new(input, i0, s0)
|
433
|
+
end
|
434
|
+
|
435
|
+
node_cache[:application][start_index] = r0
|
436
|
+
|
437
|
+
return r0
|
438
|
+
end
|
439
|
+
|
440
|
+
def _nt_operator
|
441
|
+
start_index = index
|
442
|
+
cached = node_cache[:operator][index]
|
443
|
+
if cached
|
444
|
+
@index = cached.interval.end
|
445
|
+
return cached
|
446
|
+
end
|
447
|
+
|
448
|
+
i0, nr0 = index, []
|
449
|
+
r1 = _nt_function
|
450
|
+
nr0 << r1
|
451
|
+
if r1.success?
|
452
|
+
r0 = r1
|
453
|
+
r1.update_nested_results(nr0)
|
454
|
+
else
|
455
|
+
r2 = _nt_variable
|
456
|
+
nr0 << r2
|
457
|
+
if r2.success?
|
458
|
+
r0 = r2
|
459
|
+
r2.update_nested_results(nr0)
|
460
|
+
else
|
461
|
+
self.index = i0
|
462
|
+
r0 = ParseFailure.new(input, i0, nr0)
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
466
|
+
node_cache[:operator][start_index] = r0
|
467
|
+
|
468
|
+
return r0
|
469
|
+
end
|
470
|
+
|
471
|
+
def _nt_non_application
|
472
|
+
start_index = index
|
473
|
+
cached = node_cache[:non_application][index]
|
474
|
+
if cached
|
475
|
+
@index = cached.interval.end
|
476
|
+
return cached
|
477
|
+
end
|
478
|
+
|
479
|
+
i0, nr0 = index, []
|
480
|
+
r1 = _nt_function
|
481
|
+
nr0 << r1
|
482
|
+
if r1.success?
|
483
|
+
r0 = r1
|
484
|
+
r1.update_nested_results(nr0)
|
485
|
+
else
|
486
|
+
r2 = _nt_variable
|
487
|
+
nr0 << r2
|
488
|
+
if r2.success?
|
489
|
+
r0 = r2
|
490
|
+
r2.update_nested_results(nr0)
|
491
|
+
else
|
492
|
+
self.index = i0
|
493
|
+
r0 = ParseFailure.new(input, i0, nr0)
|
494
|
+
end
|
495
|
+
end
|
496
|
+
|
497
|
+
node_cache[:non_application][start_index] = r0
|
498
|
+
|
499
|
+
return r0
|
500
|
+
end
|
501
|
+
|
502
|
+
module Function0
|
503
|
+
def param
|
504
|
+
elements[1]
|
505
|
+
end
|
506
|
+
|
507
|
+
def body
|
508
|
+
elements[3]
|
509
|
+
end
|
510
|
+
|
511
|
+
end
|
512
|
+
|
513
|
+
module Function1
|
514
|
+
class Closure
|
515
|
+
attr_reader :env, :function
|
516
|
+
|
517
|
+
def initialize(function, env)
|
518
|
+
@function = function
|
519
|
+
@env = env
|
520
|
+
end
|
521
|
+
|
522
|
+
def apply(arg)
|
523
|
+
function.body.eval(function.param.bind(arg, env))
|
524
|
+
end
|
525
|
+
|
526
|
+
def to_s(other_env={})
|
527
|
+
"\\#{function.param.to_s}(#{function.body.to_s(other_env.merge(env))})"
|
528
|
+
end
|
529
|
+
end
|
530
|
+
|
531
|
+
def eval(env={})
|
532
|
+
Closure.new(self, env)
|
533
|
+
end
|
534
|
+
|
535
|
+
def to_s(env={})
|
536
|
+
eval(env).to_s
|
537
|
+
end
|
538
|
+
end
|
539
|
+
|
540
|
+
def _nt_function
|
541
|
+
start_index = index
|
542
|
+
cached = node_cache[:function][index]
|
543
|
+
if cached
|
544
|
+
@index = cached.interval.end
|
545
|
+
return cached
|
546
|
+
end
|
547
|
+
|
548
|
+
i0, s0, nr0 = index, [], []
|
549
|
+
r1 = parse_terminal('\\', SyntaxNode)
|
550
|
+
s0 << r1
|
551
|
+
if r1.success?
|
552
|
+
r2 = _nt_variable
|
553
|
+
s0 << r2
|
554
|
+
if r2.success?
|
555
|
+
r3 = parse_terminal('(', SyntaxNode)
|
556
|
+
s0 << r3
|
557
|
+
if r3.success?
|
558
|
+
r4 = _nt_expression
|
559
|
+
s0 << r4
|
560
|
+
if r4.success?
|
561
|
+
r5 = parse_terminal(')', SyntaxNode)
|
562
|
+
s0 << r5
|
563
|
+
end
|
564
|
+
end
|
565
|
+
end
|
566
|
+
end
|
567
|
+
if s0.last.success?
|
568
|
+
r0 = (SyntaxNode).new(input, i0...index, s0)
|
569
|
+
r0.extend(Function0)
|
570
|
+
r0.extend(Function1)
|
571
|
+
else
|
572
|
+
self.index = i0
|
573
|
+
r0 = ParseFailure.new(input, i0, s0)
|
574
|
+
end
|
575
|
+
|
576
|
+
node_cache[:function][start_index] = r0
|
577
|
+
|
578
|
+
return r0
|
579
|
+
end
|
580
|
+
|
581
|
+
module Variable0
|
582
|
+
def bind(value, env)
|
583
|
+
env.merge(name => value)
|
584
|
+
end
|
585
|
+
|
586
|
+
def to_s(env={})
|
587
|
+
env.has_key?(name) ? env[name].to_s : name
|
588
|
+
end
|
589
|
+
end
|
590
|
+
|
591
|
+
module Variable1
|
592
|
+
end
|
593
|
+
|
594
|
+
def _nt_variable
|
595
|
+
start_index = index
|
596
|
+
cached = node_cache[:variable][index]
|
597
|
+
if cached
|
598
|
+
@index = cached.interval.end
|
599
|
+
return cached
|
600
|
+
end
|
601
|
+
|
602
|
+
i0, s0, nr0 = index, [], []
|
603
|
+
i1 = index
|
604
|
+
r2 = _nt_keyword
|
605
|
+
if r2.success?
|
606
|
+
r1 = ParseFailure.new(input, i1, r2.nested_failures)
|
607
|
+
else
|
608
|
+
self.index = i1
|
609
|
+
r1 = SyntaxNode.new(input, index...index, r2.nested_failures)
|
610
|
+
end
|
611
|
+
s0 << r1
|
612
|
+
if r1.success?
|
613
|
+
r3 = super
|
614
|
+
r3.extend(Variable0)
|
615
|
+
s0 << r3
|
616
|
+
end
|
617
|
+
if s0.last.success?
|
618
|
+
r0 = (SyntaxNode).new(input, i0...index, s0)
|
619
|
+
r0.extend(Variable1)
|
620
|
+
else
|
621
|
+
self.index = i0
|
622
|
+
r0 = ParseFailure.new(input, i0, s0)
|
623
|
+
end
|
624
|
+
|
625
|
+
node_cache[:variable][start_index] = r0
|
626
|
+
|
627
|
+
return r0
|
628
|
+
end
|
629
|
+
|
630
|
+
module Keyword0
|
631
|
+
end
|
632
|
+
|
633
|
+
def _nt_keyword
|
634
|
+
start_index = index
|
635
|
+
cached = node_cache[:keyword][index]
|
636
|
+
if cached
|
637
|
+
@index = cached.interval.end
|
638
|
+
return cached
|
639
|
+
end
|
640
|
+
|
641
|
+
i0, s0, nr0 = index, [], []
|
642
|
+
i1, nr1 = index, []
|
643
|
+
r2 = parse_terminal('if', SyntaxNode)
|
644
|
+
nr1 << r2
|
645
|
+
if r2.success?
|
646
|
+
r1 = r2
|
647
|
+
r2.update_nested_results(nr1)
|
648
|
+
else
|
649
|
+
r3 = parse_terminal('else', SyntaxNode)
|
650
|
+
nr1 << r3
|
651
|
+
if r3.success?
|
652
|
+
r1 = r3
|
653
|
+
r3.update_nested_results(nr1)
|
654
|
+
else
|
655
|
+
self.index = i1
|
656
|
+
r1 = ParseFailure.new(input, i1, nr1)
|
657
|
+
end
|
658
|
+
end
|
659
|
+
s0 << r1
|
660
|
+
if r1.success?
|
661
|
+
i4 = index
|
662
|
+
r5 = _nt_non_space_char
|
663
|
+
if r5.success?
|
664
|
+
r4 = ParseFailure.new(input, i4, r5.nested_failures)
|
665
|
+
else
|
666
|
+
self.index = i4
|
667
|
+
r4 = SyntaxNode.new(input, index...index, r5.nested_failures)
|
668
|
+
end
|
669
|
+
s0 << r4
|
670
|
+
end
|
671
|
+
if s0.last.success?
|
672
|
+
r0 = (SyntaxNode).new(input, i0...index, s0)
|
673
|
+
r0.extend(Keyword0)
|
674
|
+
else
|
675
|
+
self.index = i0
|
676
|
+
r0 = ParseFailure.new(input, i0, s0)
|
677
|
+
end
|
678
|
+
|
679
|
+
node_cache[:keyword][start_index] = r0
|
680
|
+
|
681
|
+
return r0
|
682
|
+
end
|
683
|
+
|
684
|
+
module NonSpaceChar0
|
685
|
+
end
|
686
|
+
|
687
|
+
def _nt_non_space_char
|
688
|
+
start_index = index
|
689
|
+
cached = node_cache[:non_space_char][index]
|
690
|
+
if cached
|
691
|
+
@index = cached.interval.end
|
692
|
+
return cached
|
693
|
+
end
|
694
|
+
|
695
|
+
i0, s0, nr0 = index, [], []
|
696
|
+
i1 = index
|
697
|
+
r2 = parse_char_class(/[ \n]/, ' \n', SyntaxNode)
|
698
|
+
if r2.success?
|
699
|
+
r1 = ParseFailure.new(input, i1, r2.nested_failures)
|
700
|
+
else
|
701
|
+
self.index = i1
|
702
|
+
r1 = SyntaxNode.new(input, index...index, r2.nested_failures)
|
703
|
+
end
|
704
|
+
s0 << r1
|
705
|
+
if r1.success?
|
706
|
+
r3 = parse_anything(SyntaxNode)
|
707
|
+
s0 << r3
|
708
|
+
end
|
709
|
+
if s0.last.success?
|
710
|
+
r0 = (SyntaxNode).new(input, i0...index, s0)
|
711
|
+
r0.extend(NonSpaceChar0)
|
712
|
+
else
|
713
|
+
self.index = i0
|
714
|
+
r0 = ParseFailure.new(input, i0, s0)
|
715
|
+
end
|
716
|
+
|
717
|
+
node_cache[:non_space_char][start_index] = r0
|
718
|
+
|
719
|
+
return r0
|
720
|
+
end
|
721
|
+
|
722
|
+
def _nt_space
|
723
|
+
start_index = index
|
724
|
+
cached = node_cache[:space][index]
|
725
|
+
if cached
|
726
|
+
@index = cached.interval.end
|
727
|
+
return cached
|
728
|
+
end
|
729
|
+
|
730
|
+
s0, nr0, i0 = [], [], index
|
731
|
+
loop do
|
732
|
+
r1 = parse_char_class(/[ \n]/, ' \n', SyntaxNode)
|
733
|
+
nr0 << r1
|
734
|
+
if r1.success?
|
735
|
+
s0 << r1
|
736
|
+
else
|
737
|
+
break
|
738
|
+
end
|
739
|
+
end
|
740
|
+
r0 = SyntaxNode.new(input, i0...index, s0, nr0)
|
741
|
+
|
742
|
+
node_cache[:space][start_index] = r0
|
743
|
+
|
744
|
+
return r0
|
745
|
+
end
|
746
|
+
|
747
|
+
end
|
748
|
+
|
749
|
+
class LambdaCalculusParser < ::Treetop::Runtime::CompiledParser
|
750
|
+
include LambdaCalculus
|
751
|
+
end
|