rubinius-ast 1.0.1

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.
@@ -0,0 +1,18 @@
1
+ # -*- encoding: us-ascii -*-
2
+
3
+ module Rubinius::ToolSet.current::TS
4
+ module AST
5
+ class File < Node
6
+ def bytecode(g)
7
+ pos(g)
8
+
9
+ g.push_scope
10
+ g.send :active_path, 0
11
+ end
12
+
13
+ def to_sexp
14
+ [:file]
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,89 @@
1
+ # -*- encoding: us-ascii -*-
2
+
3
+ module Rubinius::ToolSet.current::TS
4
+ module AST
5
+ class AsciiGrapher
6
+ def initialize(ast, node_kind=Node)
7
+ @ast = ast
8
+ @node_kind = node_kind
9
+ end
10
+
11
+ def print
12
+ graph_node @ast
13
+ end
14
+
15
+ def indented_print(level, value)
16
+ puts "#{" " * level}#{value}"
17
+ end
18
+
19
+ def print_node(node, level, idx=nil)
20
+ name = node.class.to_s.split("::").last
21
+
22
+ name = "#{name} [#{idx}]" if idx
23
+
24
+ indented_print level, name
25
+ end
26
+
27
+ def graph_node(node, level=0, idx=nil)
28
+ print_node node, level, idx
29
+ level += 2
30
+
31
+ nodes = []
32
+ node.instance_variables.each do |v|
33
+ next if v == "@compiler"
34
+
35
+ value = node.instance_variable_get v
36
+
37
+ # lame, yes. remove when Node doesn't have @body by default
38
+ next if v == "@body" and value.nil? and not v.respond_to? :body=
39
+
40
+ if value.kind_of? @node_kind
41
+ nodes << [v, value]
42
+ else
43
+ graph_value v, value, level
44
+ end
45
+ end
46
+
47
+ nodes.each do |name, n|
48
+ puts "#{" " * level}#{name}: \\"
49
+ graph_node n, level + 2
50
+ end
51
+ end
52
+
53
+ def graph_simple(name, value, level)
54
+ puts "#{" " * level}#{name}: #{value}"
55
+ end
56
+
57
+ def graph_value(name, value, level)
58
+ case value
59
+ when NilClass, String
60
+ graph_simple name, value.inspect, level
61
+ when Symbol
62
+ puts "#{" " * level}#{name}: :#{value}"
63
+ when TrueClass, FalseClass, Fixnum
64
+ graph_simple name, value, level
65
+ when Array
66
+ if value.empty?
67
+ puts "#{" " * level}#{name}: []"
68
+ else
69
+ puts "#{" " * level}#{name}: ["
70
+ nodes = []
71
+ value.each_with_index do |v,i|
72
+ if v.kind_of? @node_kind
73
+ nodes << [v, i]
74
+ else
75
+ graph_value "[#{i}] ", v, level + 2
76
+ end
77
+ end
78
+
79
+ nodes.each { |n| graph_node n[0], level + 2, n[1] }
80
+
81
+ puts "#{' ' * level}]"
82
+ end
83
+ else
84
+ graph_simple name, value.class, level
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,555 @@
1
+ # -*- encoding: us-ascii -*-
2
+
3
+ module Rubinius::ToolSet.current::TS
4
+ module AST
5
+ class ArrayLiteral < Node
6
+ attr_accessor :body
7
+
8
+ def initialize(line, array)
9
+ @line = line
10
+ @body = array
11
+ end
12
+
13
+ def bytecode(g)
14
+ pos(g)
15
+
16
+ @body.each do |x|
17
+ x.bytecode(g)
18
+ end
19
+
20
+ g.make_array @body.size
21
+ end
22
+
23
+ def defined(g)
24
+ not_found = g.new_label
25
+ done = g.new_label
26
+ @body.each do |x|
27
+ x.defined(g)
28
+ g.gif not_found
29
+ end
30
+ g.push_literal "expression"
31
+ g.goto done
32
+ not_found.set!
33
+ g.push_nil
34
+ g.goto done
35
+
36
+ done.set!
37
+ end
38
+
39
+ def to_sexp
40
+ @body.inject([:array]) { |s, x| s << x.to_sexp }
41
+ end
42
+ end
43
+
44
+ class EmptyArray < Node
45
+ def bytecode(g)
46
+ pos(g)
47
+
48
+ g.make_array 0
49
+ end
50
+
51
+ def defined(g)
52
+ g.push_literal "expression"
53
+ end
54
+
55
+ def to_sexp
56
+ [:array]
57
+ end
58
+ end
59
+
60
+ class FalseLiteral < Node
61
+ def bytecode(g)
62
+ pos(g)
63
+
64
+ g.push :false
65
+ end
66
+
67
+ def defined(g)
68
+ g.push_literal "false"
69
+ end
70
+
71
+ def to_sexp
72
+ [:false]
73
+ end
74
+ end
75
+
76
+ class TrueLiteral < Node
77
+ def bytecode(g)
78
+ pos(g)
79
+
80
+ g.push :true
81
+ end
82
+
83
+ def defined(g)
84
+ g.push_literal "true"
85
+ end
86
+
87
+ def to_sexp
88
+ [:true]
89
+ end
90
+ end
91
+
92
+ class FloatLiteral < Node
93
+ attr_accessor :value
94
+
95
+ def initialize(line, str)
96
+ @line = line
97
+ @value = str.to_f
98
+ end
99
+
100
+ def bytecode(g)
101
+ pos(g)
102
+
103
+ g.push_unique_literal @value
104
+ end
105
+
106
+ def defined(g)
107
+ g.push_literal "expression"
108
+ end
109
+
110
+ def to_sexp
111
+ [:lit, @value]
112
+ end
113
+ end
114
+
115
+ class HashLiteral < Node
116
+ attr_accessor :array
117
+
118
+ def initialize(line, array)
119
+ @line = line
120
+ @array = array
121
+ end
122
+
123
+ def bytecode(g)
124
+ pos(g)
125
+
126
+ count = @array.size
127
+ i = 0
128
+
129
+ g.push_cpath_top
130
+ g.find_const :Hash
131
+ g.push count / 2
132
+ g.send :new_from_literal, 1
133
+
134
+ while i < count
135
+ k = @array[i]
136
+ v = @array[i + 1]
137
+
138
+ g.dup
139
+ k.bytecode(g)
140
+ v.bytecode(g)
141
+ g.send :[]=, 2
142
+ g.pop
143
+
144
+ i += 2
145
+ end
146
+ end
147
+
148
+ def defined(g)
149
+ g.push_literal "expression"
150
+ end
151
+
152
+ def to_sexp
153
+ @array.inject([:hash]) { |s, x| s << x.to_sexp }
154
+ end
155
+ end
156
+
157
+ class SymbolLiteral < Node
158
+ attr_accessor :value
159
+
160
+ def initialize(line, sym)
161
+ @line = line
162
+ @value = sym
163
+ end
164
+
165
+ def bytecode(g)
166
+ pos(g)
167
+
168
+ g.push_literal @value
169
+ end
170
+
171
+ def defined(g)
172
+ g.push_literal "expression"
173
+ end
174
+
175
+ def to_sexp
176
+ [:lit, @value]
177
+ end
178
+ end
179
+
180
+ class NilLiteral < Node
181
+ def bytecode(g)
182
+ pos(g)
183
+
184
+ g.push :nil
185
+ end
186
+
187
+ def defined(g)
188
+ g.push_literal "nil"
189
+ end
190
+
191
+ def to_sexp
192
+ [:nil]
193
+ end
194
+ end
195
+
196
+ class NumberLiteral < Node
197
+ attr_accessor :value
198
+
199
+ def initialize(line, value)
200
+ @line = line
201
+ @value = value
202
+ end
203
+
204
+ def bytecode(g)
205
+ pos(g)
206
+
207
+ g.push_unique_literal @value
208
+ end
209
+
210
+ def defined(g)
211
+ g.push_literal "expression"
212
+ end
213
+
214
+ def to_sexp
215
+ [:lit, @value]
216
+ end
217
+ end
218
+
219
+ class FixnumLiteral < NumberLiteral
220
+ def initialize(line, value)
221
+ @line = line
222
+ @value = value
223
+ end
224
+
225
+ def bytecode(g)
226
+ pos(g)
227
+
228
+ g.push @value
229
+ end
230
+
231
+ def defined(g)
232
+ g.push_literal "expression"
233
+ end
234
+ end
235
+
236
+ class Range < Node
237
+ attr_accessor :start, :finish
238
+
239
+ def initialize(line, start, finish)
240
+ @line = line
241
+ @start = start
242
+ @finish = finish
243
+ end
244
+
245
+ def bytecode(g)
246
+ pos(g)
247
+
248
+ g.push_cpath_top
249
+ g.find_const :Range
250
+ g.send :allocate, 0, true
251
+ g.dup
252
+ @start.bytecode(g)
253
+ @finish.bytecode(g)
254
+ g.send :initialize, 2, true
255
+ g.pop
256
+ end
257
+
258
+ def defined(g)
259
+ g.push_literal "expression"
260
+ end
261
+
262
+ def to_sexp
263
+ [:dot2, @start.to_sexp, @finish.to_sexp]
264
+ end
265
+ end
266
+
267
+ class RangeExclude < Range
268
+ def initialize(line, start, finish)
269
+ @line = line
270
+ @start = start
271
+ @finish = finish
272
+ end
273
+
274
+ def bytecode(g)
275
+ pos(g)
276
+
277
+ g.push_cpath_top
278
+ g.find_const :Range
279
+ g.send :allocate, 0, true
280
+ g.dup
281
+ @start.bytecode(g)
282
+ @finish.bytecode(g)
283
+ g.push :true
284
+ g.send :initialize, 3, true
285
+ g.pop
286
+ end
287
+
288
+ def to_sexp
289
+ [:dot3, @start.to_sexp, @finish.to_sexp]
290
+ end
291
+ end
292
+
293
+ class RegexLiteral < Node
294
+ attr_accessor :source, :options
295
+
296
+ def initialize(line, str, flags)
297
+ @line = line
298
+ @source = str
299
+ @options = flags
300
+ end
301
+
302
+ def bytecode(g)
303
+ pos(g)
304
+
305
+ # A regex literal should only be converted to a Regexp the first time it
306
+ # is encountered. We push a literal nil here, and then overwrite the
307
+ # literal value with the created Regexp if it is nil, i.e. the first time
308
+ # only. Subsequent encounters will use the previously created Regexp
309
+ idx = g.add_literal(nil)
310
+ g.push_literal_at idx
311
+ g.dup
312
+ g.is_nil
313
+
314
+ lbl = g.new_label
315
+ g.gif lbl
316
+ g.pop
317
+ g.push_cpath_top
318
+ g.find_const :Regexp
319
+ g.push_literal @source
320
+ g.push @options
321
+ g.send :new, 2
322
+ g.set_literal idx
323
+ lbl.set!
324
+ end
325
+
326
+ def defined(g)
327
+ g.push_literal "expression"
328
+ end
329
+
330
+ def to_sexp
331
+ [:regex, @source, @options]
332
+ end
333
+ end
334
+
335
+ class StringLiteral < Node
336
+ attr_accessor :string
337
+
338
+ def initialize(line, str)
339
+ @line = line
340
+ @string = str
341
+ end
342
+
343
+ def bytecode(g)
344
+ pos(g)
345
+
346
+ # TODO: change to push_unique_literal
347
+ g.push_literal @string
348
+ g.string_dup
349
+ end
350
+
351
+ def defined(g)
352
+ g.push_literal "expression"
353
+ end
354
+
355
+ def to_sexp
356
+ [:str, @string]
357
+ end
358
+ end
359
+
360
+ class DynamicString < StringLiteral
361
+ attr_accessor :array, :options
362
+
363
+ def initialize(line, str, array)
364
+ @line = line
365
+ @string = str
366
+ @array = array
367
+ end
368
+
369
+ # This extensive logic is 100% for optimizing rather ridiculous edge
370
+ # cases for string interpolation and I (brixen) do not think it is
371
+ # worthwhile.
372
+ #
373
+ # Some examples:
374
+ #
375
+ # "#{}"
376
+ # "#{} foo"
377
+ # "foo #{}"
378
+ # "#{}#{}"
379
+ # "#{bar}"
380
+ #
381
+ # Also, as Zocx pointed out in IRC, the following code is not compatible
382
+ # in Rubinius because we convert an empty evstr into "" directly in
383
+ # Melbourne parse tree to AST processor rather than calling #to_s on
384
+ # 'nil'.
385
+ #
386
+ # def nil.to_s; "hello"; end
387
+ # a = "#{}" # => "hello" in MRI
388
+ #
389
+ # We also do not handle any case where #to_s does not actually return a
390
+ # String instance.
391
+ #
392
+ def bytecode(g)
393
+ pos(g)
394
+
395
+ if @string.empty?
396
+ if @array.size == 1
397
+ case x = @array.first
398
+ when StringLiteral
399
+ x.bytecode(g)
400
+ else
401
+ x.bytecode(g)
402
+ # string_build has some auto-conversion logic, use it.
403
+ g.string_build 1
404
+ end
405
+ return
406
+ end
407
+
408
+ prefix = false
409
+ else
410
+ prefix = true
411
+ g.push_literal @string
412
+ end
413
+
414
+ total = 0
415
+ @array.each do |e|
416
+ case e
417
+ when StringLiteral
418
+ unless e.string.empty?
419
+ g.push_literal e.string
420
+ total += 1
421
+ end
422
+ else
423
+ e.bytecode(g)
424
+ total += 1
425
+ end
426
+ end
427
+
428
+ if prefix
429
+ if total == 0
430
+ g.string_dup
431
+ return
432
+ end
433
+ total += 1
434
+ else
435
+ if total == 0
436
+ g.push_literal ""
437
+ g.string_dup
438
+ return
439
+ elsif total == 1
440
+ g.string_build 1
441
+ return
442
+ end
443
+ end
444
+
445
+ g.string_build total
446
+ end
447
+
448
+ def defined(g)
449
+ f = g.new_label
450
+ done = g.new_label
451
+
452
+ @array.each do |x|
453
+ x.value_defined(g, f)
454
+ g.pop
455
+ end
456
+
457
+ g.push_literal "expression"
458
+ g.goto done
459
+
460
+ f.set!
461
+ g.push :nil
462
+
463
+ done.set!
464
+ end
465
+
466
+ def sexp_name
467
+ :dstr
468
+ end
469
+
470
+ def to_sexp
471
+ @array.inject([sexp_name, @string]) { |s, x| s << x.to_sexp }
472
+ end
473
+ end
474
+
475
+ class DynamicSymbol < DynamicString
476
+ def bytecode(g)
477
+ super(g)
478
+ g.send :to_sym, 0, true
479
+ end
480
+
481
+ def sexp_name
482
+ :dsym
483
+ end
484
+ end
485
+
486
+ class DynamicExecuteString < DynamicString
487
+ def bytecode(g)
488
+ g.push :self
489
+ super(g)
490
+ g.send :`, 1, true #`
491
+ end
492
+
493
+ def sexp_name
494
+ :dxstr
495
+ end
496
+ end
497
+
498
+ class DynamicRegex < DynamicString
499
+ def initialize(line, str, array, flags)
500
+ super line, str, array
501
+ @options = flags || 0
502
+ end
503
+
504
+ def bytecode(g)
505
+ g.push_cpath_top
506
+ g.find_const :Regexp
507
+ super(g)
508
+ g.push @options
509
+ g.send :new, 2
510
+ end
511
+
512
+ def sexp_name
513
+ :dregx
514
+ end
515
+ end
516
+
517
+ class DynamicOnceRegex < DynamicRegex
518
+ def bytecode(g)
519
+ pos(g)
520
+
521
+ idx = g.add_literal(nil)
522
+ g.push_literal_at idx
523
+ g.dup
524
+ g.is_nil
525
+
526
+ lbl = g.new_label
527
+ g.gif lbl
528
+ g.pop
529
+
530
+ super(g)
531
+
532
+ g.set_literal idx
533
+ lbl.set!
534
+ end
535
+
536
+ def sexp_name
537
+ :dregx_once
538
+ end
539
+ end
540
+
541
+ class ExecuteString < StringLiteral
542
+ def bytecode(g)
543
+ pos(g)
544
+
545
+ g.push :self
546
+ super(g)
547
+ g.send :`, 1, true # ` (silly vim/emacs)
548
+ end
549
+
550
+ def to_sexp
551
+ [:xstr, @string]
552
+ end
553
+ end
554
+ end
555
+ end