grammar 0.5 → 0.8
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/benchmark/json.benchmark.rb +355 -0
- data/benchmark/json.grammar.rb +56 -0
- data/benchmark/json.grammar0_5.rb +57 -0
- data/benchmark/json.ll1.rb +155 -0
- data/benchmark/json.peggy.rb +174 -0
- data/benchmark/json.re.rb +81 -0
- data/lib/grammar.rb +212 -639
- data/lib/grammar/ruby.rb +606 -0
- data/lib/grammar/ruby/code.rb +1030 -0
- data/lib/grammar/ruby0.rb +521 -0
- data/lib/grammar/ruby2cext.rb +19 -0
- data/lib/grammar/rubycall.rb +21 -0
- data/test/advanced.rb +105 -0
- data/test/atoms.rb +77 -0
- data/test/basic.rb +32 -0
- data/test/composite.rb +147 -0
- data/test/molecules.rb +125 -0
- data/test/test_demo.rb +200 -0
- data/test/test_ruby.rb +30 -0
- data/test/test_ruby0.rb +30 -0
- data/test/test_ruby2cext.rb +30 -0
- data/test/test_rubycall.rb +30 -0
- metadata +45 -28
- data/samples/fact.tcl +0 -12
- data/samples/infix2postfix.rb +0 -114
- data/samples/tcl.rb +0 -163
- data/samples/test.infix +0 -4
- data/test/test_grammar.rb +0 -274
@@ -0,0 +1,1030 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
class Grammar
|
4
|
+
class Ruby
|
5
|
+
|
6
|
+
# TODO: better list delimiter handling
|
7
|
+
|
8
|
+
class Code # :nodoc:
|
9
|
+
instance_methods.each { |m|
|
10
|
+
next if m.to_s[0]==?_
|
11
|
+
next if m.to_s=="object_id"
|
12
|
+
send(:alias_method, "_#{m}", m)
|
13
|
+
undef_method(m)
|
14
|
+
}
|
15
|
+
private_instance_methods.each { |m|
|
16
|
+
next if m.to_s=="initialize"
|
17
|
+
send(:alias_method, "_#{m}", m)
|
18
|
+
undef_method(m)
|
19
|
+
}
|
20
|
+
def self.[](object)
|
21
|
+
case object
|
22
|
+
when NilClass
|
23
|
+
Nil
|
24
|
+
when FalseClass
|
25
|
+
False
|
26
|
+
when TrueClass
|
27
|
+
True
|
28
|
+
when Fixnum,Symbol,Module # last 3 not really immediates
|
29
|
+
Immediate.new(object)
|
30
|
+
else
|
31
|
+
s = object.inspect
|
32
|
+
begin
|
33
|
+
object.eql?(eval(s)) && Primary.new(s)
|
34
|
+
rescue
|
35
|
+
end or
|
36
|
+
Immediate.new(Marshal).load(Primary.new(
|
37
|
+
Marshal.dump(object).inspect))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
def initialize(code)
|
41
|
+
@code = code
|
42
|
+
end
|
43
|
+
def _codes
|
44
|
+
[@code]
|
45
|
+
end
|
46
|
+
def _data
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
def _equal(other)
|
50
|
+
_class.equal?(other._class) && _data==other._data &&
|
51
|
+
!_codes.zip(other._codes) { |a,b|
|
52
|
+
break(true) unless a._equal(b)
|
53
|
+
}
|
54
|
+
end
|
55
|
+
def _classname
|
56
|
+
_class.name.gsub(/.*::/, "")
|
57
|
+
end
|
58
|
+
def _inspect(s="", newline="\n")
|
59
|
+
data = _data
|
60
|
+
codes = _codes
|
61
|
+
s.concat(_classname) << ?\(
|
62
|
+
s.concat(data.inspect) if data
|
63
|
+
if !codes.empty?
|
64
|
+
newline << ?\s
|
65
|
+
if codes.size==1
|
66
|
+
s.concat(", ") if data
|
67
|
+
codes[0]._inspect(s, newline)
|
68
|
+
newline[-1,1] = ""
|
69
|
+
else
|
70
|
+
codes.each { |code|
|
71
|
+
s << ?\, if data
|
72
|
+
s.concat(newline)
|
73
|
+
code._inspect(s, newline)
|
74
|
+
data = true
|
75
|
+
}
|
76
|
+
newline[-1,1] = ""
|
77
|
+
s.concat(newline)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
s << ?\)
|
81
|
+
end
|
82
|
+
def _lines(text, indent=0, op=nil, maxlen=72)
|
83
|
+
@code._lines(text, indent, op, maxlen)
|
84
|
+
end
|
85
|
+
def _code_self
|
86
|
+
self
|
87
|
+
end
|
88
|
+
def _always
|
89
|
+
@code._always
|
90
|
+
end
|
91
|
+
def _never
|
92
|
+
@code._never
|
93
|
+
end
|
94
|
+
def _immediate
|
95
|
+
false
|
96
|
+
end
|
97
|
+
def _or # :yield:
|
98
|
+
_always ? self :
|
99
|
+
Or.new(yield._ror(operands = [self]))
|
100
|
+
end
|
101
|
+
def _ror(before)
|
102
|
+
before <<
|
103
|
+
(before.last._never ? before.pop._step(self) : self)
|
104
|
+
end
|
105
|
+
def _and # :yield:
|
106
|
+
_never ? self :
|
107
|
+
And.new(yield._rand(operands = [self]))
|
108
|
+
end
|
109
|
+
def _rand(before)
|
110
|
+
before <<
|
111
|
+
(before.last._always ? before.pop._step(self) : self)
|
112
|
+
end
|
113
|
+
def _step(after)
|
114
|
+
Steps.new(after._rstep(_mid([])))
|
115
|
+
end
|
116
|
+
def _rstep(before)
|
117
|
+
before << self
|
118
|
+
end
|
119
|
+
def _mid(before)
|
120
|
+
before << self
|
121
|
+
end
|
122
|
+
def _not
|
123
|
+
Not.new(self)
|
124
|
+
end
|
125
|
+
def _question(yes, no)
|
126
|
+
Conditional.new(self, yes, no)
|
127
|
+
end
|
128
|
+
def _unless(cond, yes)
|
129
|
+
Conditional.new(cond, yes, self)
|
130
|
+
end
|
131
|
+
def _rcond(before)
|
132
|
+
before << self
|
133
|
+
end
|
134
|
+
def _assign(rvalue)
|
135
|
+
Assign.new([self, rvalue])
|
136
|
+
end
|
137
|
+
def _splat
|
138
|
+
Unary.new("*", self)
|
139
|
+
end
|
140
|
+
def _to_block
|
141
|
+
Unary.new("&", self)
|
142
|
+
end
|
143
|
+
def _locals(n=0)
|
144
|
+
@locals ||= (
|
145
|
+
_codes.each { |code|
|
146
|
+
n = code._locals(n)
|
147
|
+
}
|
148
|
+
n
|
149
|
+
)
|
150
|
+
end
|
151
|
+
def _dot(method)
|
152
|
+
Dot.new(self, method)
|
153
|
+
end
|
154
|
+
def _rescue(after, exception=nil, var=nil)
|
155
|
+
Begin.new(self)._rescue(after, exception, var)
|
156
|
+
end
|
157
|
+
def _ensure(after)
|
158
|
+
Begin.new(self)._ensure(after)
|
159
|
+
end
|
160
|
+
def _else(after)
|
161
|
+
Begin.new(self)._else(after)
|
162
|
+
end
|
163
|
+
def _def(name, *args)
|
164
|
+
Def.new(name.to_s, args, self)
|
165
|
+
end
|
166
|
+
def _while(condition)
|
167
|
+
While.new(condition, self)
|
168
|
+
end
|
169
|
+
def _until(condition)
|
170
|
+
Until.new(condition, self)
|
171
|
+
end
|
172
|
+
def method_missing(method, *args, &block)
|
173
|
+
if block
|
174
|
+
call = args.empty? ? _dot(method.to_s) :
|
175
|
+
Method.new(_dot(method.to_s), *args)
|
176
|
+
Blocked.new(call, &block)
|
177
|
+
else
|
178
|
+
case method
|
179
|
+
when :**,:*,:/,:%,:+,:-,:<<,:>>,:&,:|,:^,
|
180
|
+
:>,:>=,:<,:<=,:<=>,:==,:===,:=~
|
181
|
+
Binary.new(" #{method} ", self, args[0])
|
182
|
+
when :-@,:+@,:~@
|
183
|
+
Unary.new(method.to_s[0..-2], self)
|
184
|
+
when :[]
|
185
|
+
Brackets.new(self, *args)
|
186
|
+
when :[]=
|
187
|
+
Brackets.new(self, *args[0..-2])._assign(args[-1])
|
188
|
+
else
|
189
|
+
if method.to_s[-1] == ?= and args.size==1
|
190
|
+
Dot.new(self, method.to_s[0..-2])._assign(args[-1])
|
191
|
+
elsif args.empty?
|
192
|
+
_dot(method.to_s)
|
193
|
+
else
|
194
|
+
Method.new(_dot(method.to_s), *args)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
class Primary < Code
|
200
|
+
def _lines(text, indent=0, op=nil, maxlen=72)
|
201
|
+
text.last.concat(@code)
|
202
|
+
end
|
203
|
+
def _codes
|
204
|
+
[]
|
205
|
+
end
|
206
|
+
def _data
|
207
|
+
@code
|
208
|
+
end
|
209
|
+
def _always
|
210
|
+
false
|
211
|
+
end
|
212
|
+
def _never
|
213
|
+
false
|
214
|
+
end
|
215
|
+
def _mid(before)
|
216
|
+
before
|
217
|
+
end
|
218
|
+
def _step(after)
|
219
|
+
after
|
220
|
+
end
|
221
|
+
def _locals(n=0)
|
222
|
+
n
|
223
|
+
end
|
224
|
+
end
|
225
|
+
class Command < Code
|
226
|
+
def _lines(text, indent=0, op=nil, maxlen=72)
|
227
|
+
text.last.concat(@code)
|
228
|
+
end
|
229
|
+
def _codes
|
230
|
+
[]
|
231
|
+
end
|
232
|
+
def _data
|
233
|
+
@code
|
234
|
+
end
|
235
|
+
def _always
|
236
|
+
false
|
237
|
+
end
|
238
|
+
def _never
|
239
|
+
false
|
240
|
+
end
|
241
|
+
def _locals(n=0)
|
242
|
+
n
|
243
|
+
end
|
244
|
+
end
|
245
|
+
class Immediate < Primary
|
246
|
+
def _immediate
|
247
|
+
true
|
248
|
+
end
|
249
|
+
def _data
|
250
|
+
@code
|
251
|
+
end
|
252
|
+
def _lines(text, indent=0, op=nil, maxlen=72)
|
253
|
+
text.last.concat(@code.inspect)
|
254
|
+
end
|
255
|
+
end
|
256
|
+
class Singleton < Primary
|
257
|
+
def initialize
|
258
|
+
end
|
259
|
+
def _equal(other)
|
260
|
+
__id__.equal?(other.__id__)
|
261
|
+
end
|
262
|
+
def _lines(text, indent=0, op=nil, maxlen=72)
|
263
|
+
text
|
264
|
+
end
|
265
|
+
def _inspect(s="", newline="\n")
|
266
|
+
s
|
267
|
+
end
|
268
|
+
end
|
269
|
+
True = Class.new(Singleton) {
|
270
|
+
def _immediate; true; end
|
271
|
+
def _inspect(s="", newline="\n")
|
272
|
+
s.concat("True")
|
273
|
+
end
|
274
|
+
def _lines(text, indent=0, op=nil, maxlen=72)
|
275
|
+
text.last.concat(true.inspect)
|
276
|
+
end
|
277
|
+
def _always; true; end
|
278
|
+
def _ror (before); before << before.pop._step(self); end
|
279
|
+
def _and ; yield ; end
|
280
|
+
def _rand(before); before; end
|
281
|
+
def _not ; False ; end
|
282
|
+
}.new
|
283
|
+
FalseTerminator = Class.new(Singleton) {
|
284
|
+
def _inspect(s="", newline="\n")
|
285
|
+
s.concat("FalseTerminator")
|
286
|
+
end
|
287
|
+
def _lines(text, indent=0, op=nil, maxlen=72)
|
288
|
+
text.last.concat(false.inspect)
|
289
|
+
end
|
290
|
+
def _never; false; end
|
291
|
+
def _always; true; end
|
292
|
+
def _ror (before); before << Always.new(before.pop); end
|
293
|
+
def _and ; raise("#{inspect} &&"); end
|
294
|
+
def _or ; raise("#{inspect} ||"); end
|
295
|
+
def _not ; raise("!#{inspect}"); end
|
296
|
+
}.new
|
297
|
+
False = Class.new(Singleton) {
|
298
|
+
def _immediate; true; end
|
299
|
+
def _inspect(s="", newline="\n")
|
300
|
+
s.concat("False")
|
301
|
+
end
|
302
|
+
def _lines(text, indent=0, op=nil, maxlen=72)
|
303
|
+
text.last.concat(false.inspect)
|
304
|
+
end
|
305
|
+
def _never; true; end
|
306
|
+
def _rand(before); before << before.pop._step(self); end
|
307
|
+
def _or ; yield ; end
|
308
|
+
def _ror (before); before; end
|
309
|
+
def _not ; True ; end
|
310
|
+
}.new
|
311
|
+
Nil = Class.new(Singleton) {
|
312
|
+
def _immediate; true; end
|
313
|
+
def _inspect(s="", newline="\n")
|
314
|
+
s.concat("Nil")
|
315
|
+
end
|
316
|
+
def _lines(text, indent=0, op=nil, maxlen=72)
|
317
|
+
text.last.concat(nil.inspect)
|
318
|
+
end
|
319
|
+
def _never; true; end
|
320
|
+
def _rand(before); before << before.pop._step(self); end
|
321
|
+
def _or ; yield ; end
|
322
|
+
def _ror (before); before; end
|
323
|
+
def _not ; True ; end
|
324
|
+
}.new
|
325
|
+
Self = Class.new(Singleton) {
|
326
|
+
def _inspect(s="", newline="\n")
|
327
|
+
s.concat("Self")
|
328
|
+
end
|
329
|
+
def _lines(text, indent=0, op=nil, maxlen=72)
|
330
|
+
text.last.concat("self")
|
331
|
+
end
|
332
|
+
def _always; true; end
|
333
|
+
@@keywords = Hash.new
|
334
|
+
%w(
|
335
|
+
BEGIN END
|
336
|
+
begin if unless while until for case def class module
|
337
|
+
then elsif else when in do ensure rescue end
|
338
|
+
and or
|
339
|
+
not defined?
|
340
|
+
return yield super undef alias
|
341
|
+
break next retry redo
|
342
|
+
nil false true self
|
343
|
+
).each { |keyword|
|
344
|
+
@@keywords[keyword] = true
|
345
|
+
}
|
346
|
+
def _dot(method)
|
347
|
+
(@@keywords[method] || /^[A-Za-z]\w*[?!]?$/!~method) ? super :
|
348
|
+
Code::Command.new(method)
|
349
|
+
end
|
350
|
+
}.new
|
351
|
+
Implicit = Class.new(Singleton) {
|
352
|
+
def _inspect(s="", newline="\n")
|
353
|
+
s.concat("Implicit")
|
354
|
+
end
|
355
|
+
def _dot(method)
|
356
|
+
Code::Command.new(method.to_s)
|
357
|
+
end
|
358
|
+
}.new
|
359
|
+
class Always < Code
|
360
|
+
def _always; true; end
|
361
|
+
end
|
362
|
+
class Never < Code
|
363
|
+
def _never; true; end
|
364
|
+
end
|
365
|
+
class Unary < Code
|
366
|
+
def initialize(operator, operand)
|
367
|
+
@operator = operator
|
368
|
+
@operand = operand
|
369
|
+
end
|
370
|
+
def _codes
|
371
|
+
[@operand]
|
372
|
+
end
|
373
|
+
def _data
|
374
|
+
@operator
|
375
|
+
end
|
376
|
+
def _operator
|
377
|
+
@operator
|
378
|
+
end
|
379
|
+
def _always
|
380
|
+
false
|
381
|
+
end
|
382
|
+
def _never
|
383
|
+
false
|
384
|
+
end
|
385
|
+
def _lines(text, indent=0, op=nil, maxlen=72)
|
386
|
+
text.last.concat(_operator)
|
387
|
+
@operand._lines(text, indent+1, op, maxlen)
|
388
|
+
end
|
389
|
+
end
|
390
|
+
class Not < Unary
|
391
|
+
def initialize(operand)
|
392
|
+
@operand = operand
|
393
|
+
end
|
394
|
+
def _data
|
395
|
+
nil
|
396
|
+
end
|
397
|
+
def _operator
|
398
|
+
"!"
|
399
|
+
end
|
400
|
+
def _always
|
401
|
+
@operand._never
|
402
|
+
end
|
403
|
+
def _never
|
404
|
+
@operand._always
|
405
|
+
end
|
406
|
+
def _not
|
407
|
+
@operand
|
408
|
+
end
|
409
|
+
def _mid(before)
|
410
|
+
@operand._mid(before)
|
411
|
+
end
|
412
|
+
def _step(after)
|
413
|
+
@operand._step(after)
|
414
|
+
end
|
415
|
+
end
|
416
|
+
class Dot < Unary
|
417
|
+
def initialize(receiver, method)
|
418
|
+
@operand = receiver
|
419
|
+
@method = method
|
420
|
+
end
|
421
|
+
def _data
|
422
|
+
@method
|
423
|
+
end
|
424
|
+
def _operator
|
425
|
+
@method
|
426
|
+
end
|
427
|
+
def _lines(text, indent=0, op=nil, maxlen=72)
|
428
|
+
@operand._lines(text, indent, op, maxlen)
|
429
|
+
ensure
|
430
|
+
(text.last << ?\.).concat(@method)
|
431
|
+
end
|
432
|
+
end
|
433
|
+
class List < Code
|
434
|
+
def initialize(operands)
|
435
|
+
@operands = operands
|
436
|
+
end
|
437
|
+
def _codes
|
438
|
+
@operands
|
439
|
+
end
|
440
|
+
def _lines(text, indent=0, op=nil, maxlen=72)
|
441
|
+
delim = _operator
|
442
|
+
delim0 = _operator0
|
443
|
+
paren = _paren(op)
|
444
|
+
if paren
|
445
|
+
text.last << ?\(
|
446
|
+
indent += 1
|
447
|
+
end
|
448
|
+
if @operands.empty?
|
449
|
+
last = text.last
|
450
|
+
last << ?\) if paren
|
451
|
+
return last
|
452
|
+
end
|
453
|
+
op = (delim==", ") ? nil : delim
|
454
|
+
delim ||= ""
|
455
|
+
len = text[-2]+text.last.size-delim0.size-delim.size
|
456
|
+
n = text.size
|
457
|
+
needdelim0 = text.last.empty?
|
458
|
+
#text << indent << "" unless needdelim0
|
459
|
+
single = true
|
460
|
+
@operands.each_with_index { |operand, i|
|
461
|
+
text << indent << "" unless text.last.empty?
|
462
|
+
if operand._lines(text, indent, op, maxlen)
|
463
|
+
len += delim.size+delim0.size+text.last.size
|
464
|
+
else
|
465
|
+
single = nil
|
466
|
+
end
|
467
|
+
text.last.concat(delim) unless i==@operands.size-1
|
468
|
+
}
|
469
|
+
if single && len<=maxlen
|
470
|
+
last = text[n-1]
|
471
|
+
i = n+1
|
472
|
+
while i<text.size
|
473
|
+
last.concat(delim0) if needdelim0
|
474
|
+
last.concat(text[i])
|
475
|
+
needdelim0 = true
|
476
|
+
i += 2
|
477
|
+
end
|
478
|
+
text.slice!(n, i-n)
|
479
|
+
last << ?\) if paren
|
480
|
+
last
|
481
|
+
else
|
482
|
+
text << (indent-1) << ")" if paren
|
483
|
+
nil
|
484
|
+
end
|
485
|
+
end
|
486
|
+
def _operator
|
487
|
+
", "
|
488
|
+
end
|
489
|
+
def _operator0
|
490
|
+
""
|
491
|
+
end
|
492
|
+
def _paren(op)
|
493
|
+
op
|
494
|
+
end
|
495
|
+
def _always
|
496
|
+
false
|
497
|
+
end
|
498
|
+
def _never
|
499
|
+
false
|
500
|
+
end
|
501
|
+
end
|
502
|
+
class Binary < List
|
503
|
+
def initialize(operator, *operands)
|
504
|
+
@operator = operator
|
505
|
+
@operands = operands
|
506
|
+
end
|
507
|
+
def _data
|
508
|
+
@operator
|
509
|
+
end
|
510
|
+
def _operator
|
511
|
+
@operator
|
512
|
+
end
|
513
|
+
def method_missing(method, *args, &block)
|
514
|
+
if method.equal?(@operator) && !block
|
515
|
+
@operands.concat(args)
|
516
|
+
self
|
517
|
+
else
|
518
|
+
super
|
519
|
+
end
|
520
|
+
end
|
521
|
+
end
|
522
|
+
class Assign < List
|
523
|
+
def _operator
|
524
|
+
" = "
|
525
|
+
end
|
526
|
+
end
|
527
|
+
class And < List
|
528
|
+
def self.new(operands)
|
529
|
+
(operands.size==1) ? operands[0] : super
|
530
|
+
end
|
531
|
+
def _operator
|
532
|
+
" && "
|
533
|
+
end
|
534
|
+
def _never
|
535
|
+
@operands.last._never
|
536
|
+
end
|
537
|
+
def _and # :yield:
|
538
|
+
_never ? self :
|
539
|
+
(yield._rand(@operands); self)
|
540
|
+
end
|
541
|
+
def _rand(before)
|
542
|
+
@operands[0] = before.pop._step(@operands[0]) if
|
543
|
+
before.last._always
|
544
|
+
before.concat(@operands)
|
545
|
+
end
|
546
|
+
def _or # :yield:
|
547
|
+
after = yield
|
548
|
+
last = @operands.last
|
549
|
+
(!last._always||after._never) ? Or.new(after._ror(operands = [self])) :
|
550
|
+
after._unless(
|
551
|
+
(@operands.size==2) ? @operands.first : (@operands.pop;self),
|
552
|
+
last)
|
553
|
+
end
|
554
|
+
def _unless(cond, yes)
|
555
|
+
if @operands.last._equal(yes)
|
556
|
+
@operands.pop
|
557
|
+
cond._or{self}._and{yes}
|
558
|
+
else
|
559
|
+
super
|
560
|
+
end
|
561
|
+
end
|
562
|
+
def _mid(before)
|
563
|
+
@operands.pop._mid(@operands)
|
564
|
+
if @operands.size==1
|
565
|
+
@operands.first._mid(before)
|
566
|
+
else
|
567
|
+
before << self
|
568
|
+
end
|
569
|
+
end
|
570
|
+
end
|
571
|
+
class Or < List
|
572
|
+
def self.new(operands)
|
573
|
+
(operands.size==1) ? operands[0] : super
|
574
|
+
end
|
575
|
+
def _operator
|
576
|
+
" || "
|
577
|
+
end
|
578
|
+
def _always
|
579
|
+
@operands.last._always
|
580
|
+
end
|
581
|
+
def _or # :yield:
|
582
|
+
_always ? self :
|
583
|
+
(yield._ror(@operands); self)
|
584
|
+
end
|
585
|
+
def _ror(before)
|
586
|
+
@operands[0] = before.pop._step(@operands[0]) if
|
587
|
+
before.last._never
|
588
|
+
before.concat(@operands)
|
589
|
+
end
|
590
|
+
def _and # :yield:
|
591
|
+
after = yield
|
592
|
+
last = @operands.last
|
593
|
+
(!last._never||after._always) ? And.new(after._rand(operands = [self])) :
|
594
|
+
last._unless(
|
595
|
+
(@operands.size==2) ? @operands.first : (@operands.pop;self),
|
596
|
+
after)
|
597
|
+
end
|
598
|
+
def _mid(before)
|
599
|
+
@operands.pop._mid(@operands)
|
600
|
+
if @operands.size==1
|
601
|
+
@operands.first._mid(before)
|
602
|
+
else
|
603
|
+
before << self
|
604
|
+
end
|
605
|
+
end
|
606
|
+
end
|
607
|
+
class Steps < List
|
608
|
+
def self.new(operands)
|
609
|
+
(operands.size==1) ? operands[0] : super
|
610
|
+
end
|
611
|
+
def _operator
|
612
|
+
nil
|
613
|
+
end
|
614
|
+
def _operator0
|
615
|
+
"; "
|
616
|
+
end
|
617
|
+
def _always
|
618
|
+
@operands.last._always
|
619
|
+
end
|
620
|
+
def _never
|
621
|
+
@operands.last._never
|
622
|
+
end
|
623
|
+
def _step(after)
|
624
|
+
@operands.pop._mid(@operands)
|
625
|
+
after._rstep(@operands)
|
626
|
+
self
|
627
|
+
end
|
628
|
+
def _rstep(before)
|
629
|
+
before.concat(@operands)
|
630
|
+
end
|
631
|
+
def _not
|
632
|
+
@operands[-1] = @operands[-1]._not
|
633
|
+
end
|
634
|
+
def _mid(before)
|
635
|
+
@operands.pop._mid(@operands)
|
636
|
+
if @operands.size==1
|
637
|
+
@operands.first._mid(before)
|
638
|
+
else
|
639
|
+
before << self
|
640
|
+
end
|
641
|
+
end
|
642
|
+
end
|
643
|
+
class SharedSteps < Steps
|
644
|
+
def _mid(before)
|
645
|
+
Steps.new(@operands.clone)._mid(before)
|
646
|
+
end
|
647
|
+
def _step(after)
|
648
|
+
Steps.new(@operands.clone)._step(after)
|
649
|
+
end
|
650
|
+
def _not
|
651
|
+
Steps.new(@operands.clone)._not
|
652
|
+
end
|
653
|
+
end
|
654
|
+
class Conditional < List
|
655
|
+
class Question < List
|
656
|
+
def _operator
|
657
|
+
" ? "
|
658
|
+
end
|
659
|
+
def _paren(op)
|
660
|
+
false
|
661
|
+
end
|
662
|
+
def _always
|
663
|
+
@operands.last._always
|
664
|
+
end
|
665
|
+
def _never
|
666
|
+
@operands.last._never
|
667
|
+
end
|
668
|
+
def [](i)
|
669
|
+
@operands[i]
|
670
|
+
end
|
671
|
+
def []=(i, code)
|
672
|
+
@operands[i] = code
|
673
|
+
end
|
674
|
+
def _mid(before)
|
675
|
+
@operands.pop._mid(@operands)
|
676
|
+
if @operands.size==1
|
677
|
+
# TODO : translate to Or in this case
|
678
|
+
@operands << True
|
679
|
+
end
|
680
|
+
before << self
|
681
|
+
end
|
682
|
+
end
|
683
|
+
def self.new(cond, yes, no)
|
684
|
+
super([Question.new([cond, yes]), no])
|
685
|
+
end
|
686
|
+
def initialize(operands)
|
687
|
+
@operands = operands
|
688
|
+
always = true
|
689
|
+
never = true
|
690
|
+
@operands.each { |operand|
|
691
|
+
always &&= operand._always
|
692
|
+
never &&= operand._never
|
693
|
+
break if !always && !never
|
694
|
+
}
|
695
|
+
@always = always ? 1 : never ? -1 : 0
|
696
|
+
end
|
697
|
+
def _operator
|
698
|
+
" : "
|
699
|
+
end
|
700
|
+
def _always
|
701
|
+
@always>0
|
702
|
+
end
|
703
|
+
def _never
|
704
|
+
@always<0
|
705
|
+
end
|
706
|
+
def _unless(cond, yes)
|
707
|
+
if @operands.first[1]._equal(yes)
|
708
|
+
@operands.first[0] = cond._or{@operands.first[0]}
|
709
|
+
else
|
710
|
+
@operands.insert(0, operand=Question.new([cond, yes]))
|
711
|
+
@always = 0 if @always>0 && !operand._always
|
712
|
+
@always = 0 if @always<0 && !operand._never
|
713
|
+
end
|
714
|
+
self
|
715
|
+
end
|
716
|
+
def _mid(before)
|
717
|
+
operands = []
|
718
|
+
last = @operands.pop
|
719
|
+
@operands.map { |operand|
|
720
|
+
operand._mid(operands)
|
721
|
+
}
|
722
|
+
@operands = operands
|
723
|
+
n = @operands.size
|
724
|
+
last._mid(@operands)
|
725
|
+
# TODO : remove final else in this case (translate prev to And)
|
726
|
+
@operands << last if @operands.size==n
|
727
|
+
@always = 0
|
728
|
+
before << self
|
729
|
+
end
|
730
|
+
def _or # :yield:
|
731
|
+
last = @operands.pop
|
732
|
+
always = true
|
733
|
+
@operands.each { |operand|
|
734
|
+
always &&= operand._always or break
|
735
|
+
}
|
736
|
+
unless always
|
737
|
+
@operands << last
|
738
|
+
return(super)
|
739
|
+
end
|
740
|
+
last = last._or { yield }
|
741
|
+
always &&= last._always
|
742
|
+
@always = 1 if always
|
743
|
+
last._rcond(@operands)
|
744
|
+
self
|
745
|
+
end
|
746
|
+
def _rcond(before)
|
747
|
+
before.concat(@operands)
|
748
|
+
end
|
749
|
+
end
|
750
|
+
class Local < Code
|
751
|
+
def initialize(n=nil, &block) # :yield: *vars
|
752
|
+
n ||= block.arity
|
753
|
+
names = (0...n.abs).map { "_" }
|
754
|
+
args = names.map { |name| Code::Primary.new(name) }
|
755
|
+
@code = yield(*args)
|
756
|
+
@locals = @code._locals(0)
|
757
|
+
names.each { |name|
|
758
|
+
name.concat(@locals.to_s)
|
759
|
+
@locals += 1
|
760
|
+
}
|
761
|
+
end
|
762
|
+
def _data
|
763
|
+
@locals
|
764
|
+
end
|
765
|
+
def _locals(n=0)
|
766
|
+
(@locals>n) ? @locals : n
|
767
|
+
end
|
768
|
+
def _mid(before)
|
769
|
+
devalued = @code._mid([])
|
770
|
+
if devalued.empty?
|
771
|
+
before
|
772
|
+
else
|
773
|
+
@code = devalued[0]
|
774
|
+
before << self
|
775
|
+
end
|
776
|
+
end
|
777
|
+
end
|
778
|
+
class Blocked < List
|
779
|
+
def initialize(receiver, n=nil, &block) # :yield: *vars
|
780
|
+
@receiver = receiver
|
781
|
+
n ||= block.arity
|
782
|
+
names = (0...n.abs).map { "_" }
|
783
|
+
@operands = names.map { |name| Code::Primary.new(name) }
|
784
|
+
@block = yield(*@operands)
|
785
|
+
@locals = @block._locals(0)
|
786
|
+
@operands[-1] = @operands[-1]._splat if n<0
|
787
|
+
names.each { |name|
|
788
|
+
name.concat(@locals.to_s)
|
789
|
+
@locals += 1
|
790
|
+
}
|
791
|
+
@locals = @receiver._locals(@locals)
|
792
|
+
end
|
793
|
+
def _codes
|
794
|
+
[@receiver].concat(@operands) << @block
|
795
|
+
end
|
796
|
+
def _lines(text, indent=0, op=nil, maxlen=72)
|
797
|
+
single = @receiver._lines(text, indent, true, maxlen)
|
798
|
+
text.last << ?\s << ?\{
|
799
|
+
unless @operands.empty?
|
800
|
+
text << (indent+2) << "|"
|
801
|
+
if super(text, indent+3, nil, maxlen) && single &&
|
802
|
+
text[-4]+text[-3].size+text.last.size+1<=maxlen
|
803
|
+
last = text.last
|
804
|
+
text.pop
|
805
|
+
text.pop
|
806
|
+
(text.last << ?\s).concat(last)
|
807
|
+
else
|
808
|
+
single = nil
|
809
|
+
end
|
810
|
+
text.last << ?\|
|
811
|
+
end
|
812
|
+
text << (indent+2) << ""
|
813
|
+
if @block._lines(text, indent+2, nil, maxlen) && single &&
|
814
|
+
text[-4]+text[-3].size+text.last.size+1<=maxlen
|
815
|
+
last = text.last
|
816
|
+
text.pop
|
817
|
+
text.pop
|
818
|
+
(text.last << ?\s).concat(last).concat(" }")
|
819
|
+
else
|
820
|
+
text << indent << "}"
|
821
|
+
nil
|
822
|
+
end
|
823
|
+
end
|
824
|
+
def _locals(n=0)
|
825
|
+
(@locals>n) ? @locals : n
|
826
|
+
end
|
827
|
+
end
|
828
|
+
class Call < List
|
829
|
+
def initialize(receiver, *args)
|
830
|
+
@receiver = receiver
|
831
|
+
@operands = args
|
832
|
+
end
|
833
|
+
def _codes
|
834
|
+
[@receiver].concat(@operands)
|
835
|
+
end
|
836
|
+
def _lines(text, indent=0, op=nil, maxlen=72)
|
837
|
+
single = @receiver._lines(text, indent, op, maxlen)
|
838
|
+
text.last << op
|
839
|
+
if super(text, indent+2, nil, maxlen)
|
840
|
+
single
|
841
|
+
else
|
842
|
+
text << indent << ""
|
843
|
+
nil
|
844
|
+
end
|
845
|
+
end
|
846
|
+
end
|
847
|
+
class Brackets < Call
|
848
|
+
def _lines(text, indent=0, op=nil, maxlen=72)
|
849
|
+
super(text, indent, ?\[, maxlen)
|
850
|
+
ensure
|
851
|
+
text.last << ?\]
|
852
|
+
end
|
853
|
+
end
|
854
|
+
class Method < Call
|
855
|
+
def _lines(text, indent=0, op=nil, maxlen=72)
|
856
|
+
super(text, indent, ?\(, maxlen)
|
857
|
+
ensure
|
858
|
+
text.last << ?\)
|
859
|
+
end
|
860
|
+
end
|
861
|
+
class Rescue < Code
|
862
|
+
def initialize(exception=nil, var=nil)
|
863
|
+
@exception = exception
|
864
|
+
@var = var
|
865
|
+
end
|
866
|
+
def _codes
|
867
|
+
codes = []
|
868
|
+
codes << @exception if @exception
|
869
|
+
codes << @var if @var
|
870
|
+
codes
|
871
|
+
end
|
872
|
+
def _lines(text, indent=0, op=nil, maxlen=72)
|
873
|
+
text[-2] -= 2 if text.last.empty?
|
874
|
+
(last = text.last).concat("rescue")
|
875
|
+
single = true
|
876
|
+
if @exception
|
877
|
+
last << ?\s
|
878
|
+
single = @exception._lines(text, indent+1, nil, maxlen)
|
879
|
+
last = text.last
|
880
|
+
else
|
881
|
+
single = true
|
882
|
+
end
|
883
|
+
if @var
|
884
|
+
last.concat(" => ")
|
885
|
+
@var._lines(text, indent+1, nil, maxlen) && single
|
886
|
+
else
|
887
|
+
single
|
888
|
+
end
|
889
|
+
end
|
890
|
+
def _always
|
891
|
+
false
|
892
|
+
end
|
893
|
+
def _never
|
894
|
+
false
|
895
|
+
end
|
896
|
+
end
|
897
|
+
class Dedented < Command
|
898
|
+
def _lines(text, indent=0, op=nil, maxlen=72)
|
899
|
+
text[-2] -= 2 if text.last.empty?
|
900
|
+
text.last.concat(@code)
|
901
|
+
end
|
902
|
+
end
|
903
|
+
class Begin < List
|
904
|
+
def initialize(body)
|
905
|
+
@footer = 0
|
906
|
+
super([body])
|
907
|
+
end
|
908
|
+
def _operator
|
909
|
+
nil
|
910
|
+
end
|
911
|
+
def _operator0
|
912
|
+
"; "
|
913
|
+
end
|
914
|
+
def _lines(text, indent=0, op=nil, maxlen=72)
|
915
|
+
text.last.concat("begin ")
|
916
|
+
if super(text, indent+2, nil, maxlen)
|
917
|
+
text.last.concat(" end")
|
918
|
+
else
|
919
|
+
text << indent << "end"
|
920
|
+
nil
|
921
|
+
end
|
922
|
+
end
|
923
|
+
def _rescue(after, exception=nil, var=nil)
|
924
|
+
return(super) if @footer>1
|
925
|
+
@footer = 1
|
926
|
+
@operands << Rescue.new(exception, var) << after
|
927
|
+
self
|
928
|
+
end
|
929
|
+
def _ensure(after)
|
930
|
+
return(super) if @footer>=2
|
931
|
+
@footer = 2
|
932
|
+
@operands << Dedented.new("ensure") << after
|
933
|
+
self
|
934
|
+
end
|
935
|
+
def _else(after)
|
936
|
+
return(super) if @footer>=3
|
937
|
+
@footer = 3
|
938
|
+
@operands << Dedented.new("else") << after
|
939
|
+
self
|
940
|
+
end
|
941
|
+
def _def(name, *args)
|
942
|
+
Def.new(name.to_s, args, Steps.new(@operands))
|
943
|
+
end
|
944
|
+
def _always
|
945
|
+
false
|
946
|
+
end
|
947
|
+
def _never
|
948
|
+
false
|
949
|
+
end
|
950
|
+
end
|
951
|
+
class Def < List
|
952
|
+
def initialize(name, args, body)
|
953
|
+
@name = name
|
954
|
+
@operands = args
|
955
|
+
@body = body
|
956
|
+
end
|
957
|
+
def _codes
|
958
|
+
@operands+[@body]
|
959
|
+
end
|
960
|
+
def _data
|
961
|
+
@name
|
962
|
+
end
|
963
|
+
def _lines(text, indent=0, op=nil, maxlen=72)
|
964
|
+
text << indent << "" unless text.last.empty?
|
965
|
+
(last = text.last).concat("def ").concat(@name.to_s)
|
966
|
+
unless @operands.empty?
|
967
|
+
last << ?\(
|
968
|
+
super(text, indent+3, nil, maxlen) or
|
969
|
+
text << indent+2 << ""
|
970
|
+
text.last << ?\)
|
971
|
+
end
|
972
|
+
text << (indent+2) << ""
|
973
|
+
@body._lines(text, indent+2, nil, maxlen)
|
974
|
+
text << indent << "end"
|
975
|
+
nil
|
976
|
+
end
|
977
|
+
def _always
|
978
|
+
false
|
979
|
+
end
|
980
|
+
def _never
|
981
|
+
false
|
982
|
+
end
|
983
|
+
end
|
984
|
+
class While < Code
|
985
|
+
def initialize(condition, body=nil)
|
986
|
+
@condition = condition
|
987
|
+
@body = body && body._mid([])[0]
|
988
|
+
end
|
989
|
+
def _codes
|
990
|
+
codes = [@condition]
|
991
|
+
codes << @body if @body
|
992
|
+
codes
|
993
|
+
end
|
994
|
+
def _header
|
995
|
+
"while"
|
996
|
+
end
|
997
|
+
def _lines(text, indent=0, op=nil, maxlen=72)
|
998
|
+
(last = text.last).concat(_header) << ?\(
|
999
|
+
single = @condition._lines(text, indent+3, nil, maxlen) or
|
1000
|
+
text << indent+2 << ""
|
1001
|
+
text.last << ?\)
|
1002
|
+
if @body
|
1003
|
+
text << indent+2 << ""
|
1004
|
+
@body._lines(text, indent+2, nil, maxlen)
|
1005
|
+
single = nil
|
1006
|
+
end
|
1007
|
+
if single
|
1008
|
+
text.last.concat("; end")
|
1009
|
+
else
|
1010
|
+
text << indent << "end"
|
1011
|
+
nil
|
1012
|
+
end
|
1013
|
+
end
|
1014
|
+
def _always
|
1015
|
+
false
|
1016
|
+
end
|
1017
|
+
def _never
|
1018
|
+
false
|
1019
|
+
end
|
1020
|
+
end
|
1021
|
+
class Until < While
|
1022
|
+
def _header
|
1023
|
+
"until"
|
1024
|
+
end
|
1025
|
+
end
|
1026
|
+
end
|
1027
|
+
end
|
1028
|
+
end
|
1029
|
+
|
1030
|
+
|