ruby-internal 0.8.2 → 0.8.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,23 +0,0 @@
1
- require 'internal/node/as_code'
2
- require 'internal/proc'
3
- require 'internal/proc/signature'
4
-
5
- class Proc
6
- # Return a string representation of a proc's definition/body,
7
- # similarly to +Method#as_code+.
8
- def as_code(indent=0)
9
- sig = self.signature
10
- body_expression = self.body ? self.body.as_code(indent+1) : nil
11
- s = "#{' '*indent}proc do"
12
- if not sig.args.unspecified then
13
- s += " #{sig}"
14
- end
15
- s += "\n"
16
- if body_expression then
17
- s += "#{body_expression}\n"
18
- end
19
- s += "#{' '*indent}end"
20
- return s
21
- end
22
- end
23
-
@@ -1,16 +0,0 @@
1
- require 'internal/node/as_expression'
2
- require 'internal/proc/signature'
3
- require 'internal/proc'
4
-
5
- class Proc
6
- # Return a single-line string representation of a proc's
7
- # definition/body, similarly to +Method#as_expression+.
8
- def as_expression
9
- sig = self.signature
10
- body_expression = self.body ? self.body.as_expression : nil
11
- s = sig.args.unspecified ? "" : sig.to_s + ' '
12
- b = body_expression ? body_expression + ' ' : ''
13
- return "proc { #{s}#{b}}"
14
- end
15
- end
16
-
@@ -1,184 +0,0 @@
1
- require 'internal/node'
2
- require 'internal/proc'
3
- require 'internal/vm'
4
-
5
- class Proc
6
- class Arguments
7
- include Enumerable
8
-
9
- def initialize(names, multiple_assignment, rest_arg)
10
- @names = names
11
- @multiple_assignment = multiple_assignment
12
- @rest_arg = rest_arg
13
- end
14
-
15
- def unspecified
16
- if defined?(RubyVM) and defined?(RubyVM::InstructionSequence) then
17
- # YARV
18
- return @names.length == 0
19
- else
20
- # pre-YARV
21
- @names.nil?
22
- end
23
- end
24
-
25
- def single_assignment
26
- !@multiple_assignment
27
- end
28
-
29
- def multiple_assignment
30
- @multiple_assignment
31
- end
32
-
33
- def names
34
- @names
35
- end
36
-
37
- def [](idx)
38
- @names[idx]
39
- end
40
-
41
- def each(&block)
42
- (@names || []).each(&block)
43
- end
44
-
45
- def size
46
- @names.size
47
- end
48
-
49
- def rest_arg
50
- @rest_arg
51
- end
52
-
53
- def empty_last_arg
54
- if defined?(VM) and defined?(VM::InstructionSequence) then
55
- # YARV
56
- return (@rest_arg and @names[-1] == nil)
57
- else
58
- # pre-YARV
59
- return (@names.size == 1 and not @rest_arg)
60
- end
61
- end
62
- end
63
-
64
- # Return an Arguments object representing the arguments in the order
65
- # in which they appear in the argument list.
66
- def arguments
67
- has_rest_arg = self.has_rest_arg
68
-
69
- if self.respond_to?(:var) then
70
- # pre-YARV
71
- case self.var
72
- when Node::DASGN_CURR
73
- return Arguments.new([ self.var.vid ], false, has_rest_arg ? 0 : nil)
74
- when Node::MASGN
75
- if self.var.head then
76
- a = self.var.head.to_a
77
- args = a.map { |n| n.vid }
78
- else
79
- args = []
80
- end
81
- if self.var.args then
82
- args.push(self.var.args.vid)
83
- end
84
- return Arguments.new(args, true, has_rest_arg ? args.size - 1: nil)
85
- when nil
86
- return Arguments.new(nil, false, has_rest_arg ? 0 : nil)
87
- when Fixnum
88
- return Arguments.new([], false, has_rest_arg ? 0 : nil)
89
- else
90
- raise "Unexpected node type: #{self.var.class}"
91
- end
92
- elsif
93
- # YARV
94
- iseq = self.body
95
- local_vars = iseq.local_table
96
- has_rest_arg = iseq.arg_rest != -1
97
- has_block_arg = iseq.arg_block != -1
98
- num_args = \
99
- iseq.argc + \
100
- iseq.arg_opt_table.size + \
101
- (has_rest_arg ? 1 : 0) + \
102
- (has_block_arg ? 1 : 0)
103
- names = local_vars[0...num_args]
104
- # TODO: masgn
105
- return Arguments.new(names, true, has_rest_arg ? -1 : nil)
106
- else
107
- return Arguments.new(nil, false, nil)
108
- end
109
- end
110
-
111
- # Return true if the proc has a rest arg
112
- def has_rest_arg
113
- if self.respond_to?(:var) then
114
- # pre-YARV
115
- has_rest_arg = false
116
- if self.var then
117
- if self.var.class == Node::MASGN then
118
- if self.var.args then
119
- has_rest_arg = true
120
- end
121
- end
122
- end
123
- else
124
- # YARV
125
- rest = self.body.arg_rest
126
- has_rest_arg = (rest >= 0 ? rest - 1 : nil)
127
- end
128
- return has_rest_arg
129
- end
130
-
131
- # Return a hash mapping each argument name to a description of that
132
- # argument.
133
- def argument_info
134
- args = self.arguments()
135
-
136
- info = {}
137
- args.each do |name|
138
- info[name] = name.to_s
139
- end
140
-
141
- # Rest arg
142
- if args.rest_arg then
143
- rest_name = args[args.rest_arg]
144
- if rest_name then
145
- info[rest_name] = "*#{rest_name}"
146
- end
147
- end
148
-
149
- return info
150
- end
151
-
152
- class Signature
153
- attr_reader :args, :arg_info
154
-
155
- def initialize(args, arg_info)
156
- @args = args
157
- @arg_info = arg_info
158
- end
159
-
160
- def to_s
161
- if @args.unspecified then
162
- return ""
163
- elsif @args.multiple_assignment then
164
- if @args.empty_last_arg then
165
- params = @args.map{ |n| arg_info[n] }
166
- return "|#{@arg_info[@args[0]]},|"
167
- else
168
- params = @args.map{ |n| arg_info[n] }
169
- return "|#{params.join(', ')}|"
170
- end
171
- else
172
- return "|#{@arg_info[@args[0]]}|"
173
- end
174
- end
175
- end
176
-
177
- # Return a String representing the method's signature.
178
- def signature
179
- return Signature.new(
180
- arguments(),
181
- argument_info)
182
- end
183
- end
184
-
@@ -1,866 +0,0 @@
1
- require 'internal/vm/iseq'
2
- require 'internal/vm/instruction'
3
- require 'internal/vm/inline_cache'
4
- require 'internal/vm/constants'
5
-
6
- module Internal
7
-
8
- # A module for decoding YARV bytecode.
9
- #
10
- # This is actually pretty cool. It's actually a miniature VM, where the
11
- # result of evaluating an expression is itself another expression. This
12
- # turns out to be much simpler than a full ruby VM, but I think one
13
- # could use this as a base for building one.
14
- #
15
- # Example usage:
16
- # env = Internal::ByteDecoder::Environment.new(is.local_table)
17
- # is = RubyVM::InstructionSequence.new('1 + 1')
18
- # is.bytedecode(env)
19
- # env.expressions.each do |expr|
20
- # puts expr
21
- # end
22
- # puts stack[-1]
23
- #
24
- module ByteDecoder
25
-
26
- class Environment
27
- attr_reader :stack
28
- attr_reader :expressions
29
- attr_reader :local_table
30
- attr_accessor :last
31
- attr_reader :seq
32
- attr_accessor :pc
33
-
34
- def initialize(local_table)
35
- @stack = []
36
- @expressions = []
37
- @local_table = local_table
38
- @last = nil
39
- @pc = 0
40
- end
41
-
42
- def advance(instruction_length)
43
- @pc += instruction_length
44
- end
45
-
46
- def remember(expression)
47
- if not expression.is_a?(Expression::Literal) then
48
- @expressions << expression
49
- end
50
- end
51
- end
52
-
53
- class Expression
54
- attr_reader :pc
55
-
56
- def initialize(pc)
57
- @pc = pc
58
- end
59
-
60
- def <=>(rhs)
61
- return @pc <=> rhs.pc
62
- end
63
-
64
- def fmt(arg)
65
- if arg.respond_to?(:precedence)
66
- p = arg.precedence
67
- else
68
- p = 0
69
- end
70
-
71
- if p >= self.precedence then
72
- return "(#{arg})"
73
- else
74
- return arg
75
- end
76
- end
77
-
78
- class Literal < Expression
79
- attr_reader :value
80
-
81
- def initialize(pc, value)
82
- super(pc)
83
- @value = value
84
- end
85
-
86
- def to_s
87
- case @value
88
- when Regexp then "/#{@value.inspect[1..-2]}/"
89
- else; return @value.inspect
90
- end
91
- end
92
-
93
- def precedence
94
- return 1
95
- end
96
- end
97
-
98
- class Infix < Expression
99
- attr_reader :op
100
- attr_reader :lhs
101
- attr_reader :rhs
102
-
103
- def initialize(pc, op, lhs, rhs)
104
- super(pc)
105
- @op = op
106
- @lhs = lhs
107
- @rhs = rhs
108
- end
109
-
110
- def to_s
111
- return "#{fmt(@lhs)} #{@op} #{fmt(@rhs)}"
112
- end
113
-
114
- def precedence
115
- case @op
116
- when :*, :/, :%
117
- return 2
118
- when '+'.intern, '-'.intern
119
- return 3
120
- when :<<, :>>
121
- return 4
122
- when :>, :>=, :<, :<=, :==, :===, :!=
123
- return 5
124
- when :undef
125
- return 6
126
- else
127
- raise ArgumentError, "Unknown op: #{@op}"
128
- end
129
- end
130
- end
131
-
132
- class Prefix < Expression
133
- def initialize(pc, op, expr)
134
- super(pc)
135
- @op = op
136
- @expr = expr
137
- end
138
-
139
- def to_s
140
- op = @op.to_s
141
- op.chop! if op[-1] == ?@
142
- if @op == '!'.intern and @expr.is_a?(Infix) and @expr.op == :== then
143
- return "#{@expr.fmt(@expr.lhs)} != #{@expr.fmt(@expr.rhs)}"
144
- elsif self.precedence < @expr.precedence then
145
- return "#{op}(#{@expr})"
146
- else
147
- return "#{op}#{@expr}"
148
- end
149
- end
150
-
151
- def precedence
152
- return 1
153
- end
154
- end
155
-
156
- class Send < Expression
157
- attr_reader :is_assignment
158
-
159
- def initialize(pc, id, has_receiver, has_parens, receiver, block, splat_last, *args)
160
- super(pc)
161
- @id = id
162
- @is_assignment = id.to_s[-1] == ?=
163
- @has_receiver = has_receiver
164
- @has_parens = has_parens
165
- @receiver = receiver
166
- @block = block
167
- @splat_last = splat_last
168
- @args = args
169
- end
170
-
171
- def to_s
172
- s = ''
173
- receiver_str = @has_receiver \
174
- ? "#{@receiver}." \
175
- : nil
176
- args = @args.map { |x| x.to_s }
177
- if @splat_last then
178
- args[-1] = "*#{@args[-1]}"
179
- end
180
- if @is_assignment and args.size == 1 then
181
- s = "#{receiver_str}#{@id.to_s[0..-2]} = #{args[0]}"
182
- else
183
- open = @has_parens ? '(' : ''
184
- close = @has_parens ? ')' : ''
185
- s = "#{receiver_str}#{@id}#{open}#{args.join(', ')}#{close}"
186
- end
187
- if @block then
188
- # TODO: this code is duplicated elsewhere
189
- # TODO: handle block args
190
- env = Environment.new(@block.local_table)
191
- @block.bytedecode(env)
192
- expressions = env.expressions + env.stack
193
- expressions.sort!
194
- expressions.map! { |x| x.to_s }
195
- if expressions.length == 1 and
196
- expressions[0].is_a?(Literal) and
197
- expressions[0].value == nil then
198
- # empty
199
- else
200
- s << " { #{expressions.join('; ')} }"
201
- end
202
- end
203
- return s
204
- end
205
-
206
- def precedence
207
- if @has_receiver then
208
- if @receiver.respond_to?(:precedence) then
209
- return @receiver.precedence
210
- end
211
- end
212
- return 1
213
- end
214
- end
215
-
216
- class Self < Expression
217
- def initialize(pc)
218
- super(pc)
219
- end
220
-
221
- def to_s
222
- return "self"
223
- end
224
-
225
- def precedence
226
- return 1
227
- end
228
- end
229
-
230
- class Hash < Expression
231
- def initialize(pc, args)
232
- super(pc)
233
- @args = args
234
- end
235
-
236
- def to_s
237
- s = '{ '
238
- a = []
239
- i = 0
240
- while i < @args.length do
241
- a << "#{@args[i]} => #{@args[i + 1]}"
242
- i += 2
243
- end
244
- s << a.join(', ')
245
- s << ' ' if a.length != 0
246
- s << '}'
247
- return s
248
- end
249
-
250
- def precedence
251
- return 1
252
- end
253
- end
254
-
255
- class Array < Expression
256
- def initialize(pc, args)
257
- super(pc)
258
- @args = args
259
- end
260
-
261
- def to_s
262
- s = '[ '
263
- s << @args.join(', ')
264
- s << ' ]'
265
- return s
266
- end
267
-
268
- def precedence
269
- return 1
270
- end
271
- end
272
-
273
- class ConcatArray < Expression
274
- def initialize(array, splat)
275
- @array = array
276
- @splat = splat
277
- end
278
-
279
- def to_s
280
- s = '[ '
281
- case @array
282
- when Array then s << @array.args.join(', ')
283
- when Literal then s << @array.value.join(', ')
284
- else; raise "Unexpected: #{@array.inspect}"
285
- end
286
- s << ', *'
287
- s << @splat.to_s
288
- s << ' ]'
289
- end
290
-
291
- def precedence
292
- return 1
293
- end
294
- end
295
-
296
- class Defined < Expression
297
- def initialize(pc, arg)
298
- super(pc)
299
- @arg = arg
300
- end
301
-
302
- def to_s
303
- return "defined?(#{@arg.to_s})"
304
- end
305
-
306
- def precedence
307
- return 1
308
- end
309
- end
310
-
311
- class Variable < Expression
312
- def initialize(pc, name)
313
- super(pc)
314
- @name = name
315
- end
316
-
317
- def to_s
318
- return @name.to_s
319
- end
320
-
321
- def precedence
322
- return 1
323
- end
324
- end
325
-
326
- class Constant < Expression
327
- def initialize(pc, klass, name)
328
- super(pc)
329
- @klass = klass
330
- @name = name
331
- end
332
-
333
- def to_s
334
- if @klass then
335
- if @klass == Object then
336
- return "::#{@name}"
337
- else
338
- return "#{@klass}::#{@name}"
339
- end
340
- else
341
- return "#{@name}"
342
- end
343
- end
344
-
345
- def precedence
346
- return 1
347
- end
348
- end
349
-
350
- class ConstantAssignment < Constant
351
- def initialize(pc, klass, name, value)
352
- super(pc, klass, name)
353
- @value = value
354
- end
355
-
356
- def to_s
357
- s = super()
358
- s << " = #{@value}"
359
- return s
360
- end
361
- end
362
-
363
- class ConcatStrings < Expression
364
- def initialize(pc, args)
365
- super(pc)
366
- @args = args
367
- end
368
-
369
- def to_s
370
- s = "\""
371
- @args.each do |arg|
372
- case arg
373
- when Literal
374
- case arg.value
375
- when String then s << arg.value
376
- else; s << arg.to_s
377
- end
378
- else
379
- s << "\#{#{arg.to_s}}"
380
- end
381
- end
382
- s << "\""
383
- end
384
-
385
- def precedence
386
- return 1
387
- end
388
- end
389
-
390
- class Assignment < Expression
391
- attr_reader :rhs
392
-
393
- def initialize(pc, name, rhs)
394
- super(pc)
395
- @name = name
396
- @rhs = rhs
397
- end
398
-
399
- def to_s
400
- return "#{@name} = #{@rhs}"
401
- end
402
-
403
- def precedence
404
- return 5
405
- end
406
- end
407
-
408
- class ToRegexp < Expression
409
- def initialize(pc, value)
410
- super(pc)
411
- @value = value
412
- end
413
-
414
- def to_s
415
- case @value
416
- when ConcatStrings
417
- string = @value.to_s
418
- unstring = string[1..-2]
419
- return Regexp.compile(unstring).inspect
420
- else
421
- return Regexp.compile(@value.to_s).inspect
422
- end
423
- end
424
-
425
- def precedence
426
- return 1
427
- end
428
- end
429
-
430
- class Throw < Expression
431
- def initialize(pc, value)
432
- super(pc)
433
- @value = value
434
- end
435
-
436
- def to_s
437
- # TODO: not all throws are breaks...
438
- if not @value or (@value.is_a?(Literal) and @value.value == nil) then
439
- return "break"
440
- else
441
- return "break #{@value}"
442
- end
443
- end
444
-
445
- def precedence
446
- return 1
447
- end
448
- end
449
- end
450
-
451
- end # ByteDecoder
452
-
453
- end # Internal
454
-
455
- class RubyVM
456
- class Instruction
457
- include Internal::ByteDecoder
458
-
459
- class PUTOBJECT
460
- def bytedecode(env)
461
- env.stack.push Expression::Literal.new(env.pc, self.operands[0])
462
- end
463
- end
464
-
465
- INFIX_OPCODES = {
466
- OPT_PLUS => '+'.intern,
467
- OPT_MINUS => '-'.intern,
468
- OPT_MULT => :*,
469
- OPT_DIV => :/,
470
- OPT_MOD => :%,
471
- OPT_LTLT => :<<,
472
- # OPT_GTGT => :>>,
473
- OPT_EQ => :==,
474
- OPT_NEQ => :!=,
475
- OPT_GT => :>,
476
- OPT_GE => :>=,
477
- OPT_LT => :<,
478
- OPT_LE => :<=,
479
- }
480
-
481
- INFIX_OPERATORS = INFIX_OPCODES.values + [ :===, :>> ]
482
-
483
- INFIX_OPCODES.each do |klass, op|
484
- klass.class_eval do
485
- define_method(:bytedecode) do |env|
486
- rhs = env.stack.pop
487
- lhs = env.stack.pop
488
- env.stack.push Expression::Infix.new(env.pc, op, lhs, rhs)
489
- end
490
- end
491
- end
492
-
493
- PREFIX_OPCODES = {
494
- OPT_NOT => :!,
495
- }
496
-
497
- if defined?(UNDEF)
498
- PREFIX_OPCODES[UNDEF] = :undef
499
- end
500
-
501
- PREFIX_OPERATORS = PREFIX_OPCODES.values + [ :~, :+@, :-@ ]
502
-
503
- PREFIX_OPCODES.each do |klass, op|
504
- klass.class_eval do
505
- define_method(:bytedecode) do |env|
506
- expr = env.stack.pop
507
- env.stack.push Expression::Prefix.new(env.pc, op, expr)
508
- end
509
- end
510
- end
511
-
512
- class TRACE
513
- def bytedecode(env)
514
- end
515
- end
516
-
517
- class LEAVE
518
- def bytedecode(env)
519
- end
520
- end
521
-
522
- LITERAL_OPCODES = [
523
- PUTNIL,
524
- DUPARRAY,
525
- PUTSTRING,
526
- ]
527
-
528
- LITERAL_OPCODES.each do |klass|
529
- klass.class_eval do
530
- define_method(:bytedecode) do |env|
531
- env.stack.push Expression::Literal.new(env.pc, @operands[0])
532
- end
533
- end
534
- end
535
-
536
- class SEND
537
- def bytedecode(env)
538
- id = @operands[0]
539
- num_args = @operands[1]
540
- args = []
541
- num_args.times do
542
- args.unshift env.stack.pop
543
- end
544
- has_receiver = !flag_set(RubyVM::CALL_FCALL_BIT)
545
- has_parens = !flag_set(RubyVM::CALL_VCALL_BIT)
546
- splat_last = flag_set(RubyVM::CALL_ARGS_SPLAT_BIT)
547
- receiver = env.stack.pop
548
- block = @operands[2]
549
- if INFIX_OPERATORS.include?(id) and args.size == 1 then
550
- env.stack.push Expression::Infix.new(env.pc, id, receiver, args[0])
551
- elsif PREFIX_OPERATORS.include?(id) and args.size == 0 then
552
- env.stack.push Expression::Prefix.new(env.pc, id, receiver)
553
- else
554
- env.stack.push Expression::Send.new(
555
- env.pc, id, has_receiver, has_parens, receiver, block, splat_last, *args)
556
- end
557
- end
558
-
559
- def flag_set(flag)
560
- flags = @operands[3]
561
- return flags & flag == flag
562
- end
563
- end
564
-
565
- class PUTSELF
566
- def bytedecode(env)
567
- env.stack.push Expression::Self.new(env.pc)
568
- end
569
- end
570
-
571
- class NEWHASH
572
- def bytedecode(env)
573
- i = @operands[0]
574
- args = []
575
- while i > 0 do
576
- args.unshift env.stack.pop
577
- i -= 1
578
- end
579
- env.stack.push Expression::Hash.new(env.pc, args)
580
- end
581
- end
582
-
583
- class NEWARRAY
584
- def bytedecode(env)
585
- i = @operands[0]
586
- args = []
587
- while i > 0 do
588
- args.unshift env.stack.pop
589
- i -= 1
590
- end
591
- env.stack.push Expression::Array.new(env.pc, args)
592
- end
593
- end
594
-
595
- class DEFINED
596
- def bytedecode(env)
597
- env.stack.push Expression::Defined.new(env.pc, @operands[1])
598
- end
599
- end
600
-
601
- GET_VARIABLE_OPCODES = [
602
- GETCLASSVARIABLE,
603
- GETINSTANCEVARIABLE,
604
- GETGLOBAL,
605
- ]
606
-
607
- GET_VARIABLE_OPCODES.each do |klass|
608
- klass.class_eval do
609
- define_method(:bytedecode) do |env|
610
- env.stack.push Expression::Variable.new(env.pc, @operands[0])
611
- end
612
- end
613
- end
614
-
615
- SET_VARIABLE_OPCODES = [
616
- SETCLASSVARIABLE,
617
- SETINSTANCEVARIABLE,
618
- SETGLOBAL,
619
- ]
620
-
621
- SET_VARIABLE_OPCODES.each do |klass|
622
- klass.class_eval do
623
- define_method(:bytedecode) do |env|
624
- value = env.stack.pop
625
- env.stack.delete_at(-1) # TODO: dup'd value.. is this right?
626
- env.stack.push Expression::Assignment.new(env.pc, @operands[0], value)
627
- end
628
- end
629
- end
630
-
631
- class GETCONSTANT
632
- def bytedecode(env)
633
- klass = env.stack.pop
634
- env.stack.push Expression::Constant.new(env.pc, klass, @operands[0])
635
- end
636
- end
637
-
638
- class SETCONSTANT
639
- def bytedecode(env)
640
- klass = env.stack.pop
641
- value = env.stack.pop
642
- env.stack.push Expression::ConstantAssignment.new(env.pc, klass, @operands[0], value)
643
- end
644
- end
645
-
646
- class GETSPECIAL
647
- def bytedecode(env)
648
- type = @operands[1] >> 1
649
- type += ?0.ord if type < 10
650
- env.stack.push Expression::Variable.new(env.pc, "$#{type.chr}")
651
- end
652
- end
653
-
654
- class GETINLINECACHE
655
- def bytedecode(env)
656
- env.stack.push nil
657
- end
658
- end
659
-
660
- class SETINLINECACHE
661
- def bytedecode(env)
662
- end
663
- end
664
-
665
- class NOP
666
- def bytedecode(env)
667
- end
668
- end
669
-
670
- class TOSTRING
671
- def bytedecode(env)
672
- end
673
- end
674
-
675
- class CONCATSTRINGS
676
- def bytedecode(env)
677
- i = @operands[0]
678
- args = []
679
- while i > 0 do
680
- args.unshift env.stack.pop
681
- i -= 1
682
- end
683
- env.stack.push Expression::ConcatStrings.new(env.pc, args)
684
- end
685
- end
686
-
687
- class TOREGEXP
688
- def bytedecode(env)
689
- env.stack.push Expression::ToRegexp.new(env.pc, env.stack.pop)
690
- end
691
- end
692
-
693
- class DUP
694
- def bytedecode(env)
695
- arg = env.stack.pop
696
- env.stack.push arg
697
- env.stack.push arg
698
- end
699
- end
700
-
701
- class SETLOCAL
702
- def bytedecode(env)
703
- idx = env.local_table.size - @operands[0] + 1
704
- name = env.local_table[idx]
705
- value = env.stack.pop
706
- env.stack.push Expression::Assignment.new(env.pc, name, value)
707
- end
708
- end
709
-
710
- class GETLOCAL
711
- def bytedecode(env)
712
- idx = env.local_table.size - @operands[0] + 1
713
- name = env.local_table[idx]
714
- env.stack.push Expression::Variable.new(env.pc, name)
715
- end
716
- end
717
-
718
- class SETDYNAMIC
719
- def bytedecode(env)
720
- idx = env.local_table.size - @operands[0]
721
- name = env.local_table[idx]
722
- value = env.stack.pop
723
- env.stack.push Expression::Assignment.new(env.pc, name, value)
724
- end
725
- end
726
-
727
- class GETDYNAMIC
728
- def bytedecode(env)
729
- idx = env.local_table.size - @operands[0]
730
- name = env.local_table[idx]
731
- env.stack.push Expression::Variable.new(env.pc, name)
732
- end
733
- end
734
-
735
- class SETN
736
- # set nth stack entry to stack top
737
- def bytedecode(env)
738
- n = @operands[0]
739
- dest = -(n+1)
740
- if env.stack[dest].is_a?(Expression) then
741
- env.remember env.stack[dest]
742
- end
743
- env.stack[dest] = env.stack[-1]
744
- end
745
- end
746
-
747
- class TOPN
748
- # get nth stack entry from stack top
749
- def bytedecode(env)
750
- n = @operands[0]
751
- idx = -(n+1)
752
- env.stack[idx]
753
- end
754
- end
755
-
756
- class POP
757
- def bytedecode(env)
758
- top = env.stack[-1]
759
- if top.is_a?(Expression::Send) and top.is_assignment then
760
- # special case - the return value from the assignment gets
761
- # thrown away and the result is the rhs
762
- env.remember env.stack[-2]
763
- env.stack.delete_at(-2)
764
- end
765
- env.remember top
766
- env.stack.pop
767
- end
768
- end
769
-
770
- class THROW
771
- def bytedecode(env)
772
- value = env.stack.pop
773
- env.remember env.stack.pop
774
- env.stack.push Expression::Throw.new(env.pc, value)
775
- end
776
- end
777
-
778
- class CONCATARRAY
779
- def bytedecode(env)
780
- splat = env.stack.pop
781
- array = env.stack.pop
782
- env.stack.push Expression::ConcatArray.new(array, splat)
783
- end
784
- end
785
- end
786
-
787
- class InstructionSequence
788
- def bytedecode(env, start_pc=0, end_pc=nil, &block)
789
- self.each(start_pc) do |instruction|
790
- # p instruction
791
- instruction.bytedecode(env)
792
- # p env.stack
793
- env.advance(instruction.length)
794
- break if end_pc and env.pc >= end_pc
795
- break if block and block.call(instruction)
796
- end
797
- end
798
-
799
- def opt_pc
800
- opt_table = self.arg_opt_table
801
- return opt_table.length > 0 ? opt_table[-1] : 0
802
- end
803
- end
804
- end
805
-
806
- if __FILE__ == $0 then
807
- # def foo; @@foo = 1; end
808
- # def foo; a = [2, 3]; foo(1, *a); end
809
- # def foo; not true; end
810
- # def foo; catch(:foo) { throw :foo; 42 }; end
811
- # def foo; a ? b : c; end
812
- # def foo; loop { a = 1; break }; end
813
- # def foo; ::BAR; end
814
- # def foo; a != b; end
815
- # def foo; 1 - 2; end
816
- # def foo; +a; end
817
- # def foo; !a; end
818
- # def foo; a << b; end
819
- # def foo; a === b; end
820
- # def foo; []; end
821
- def foo; foo.bar = 42; end
822
- # def foo; h = {}; h.default = true; h; end
823
- # def foo; @FOO; end
824
- # def foo; $FOO; end
825
- # def foo; /foo#{bar}/; end
826
- # def foo; /foo/; end
827
- # def foo; foo = 1; bar=2; baz=3 end
828
- # def foo; "foo#{bar}"; end
829
- # def foo; $`; end
830
- # def foo; FOO; end
831
- # def foo; @@foo; end
832
- # def foo; defined?(FOO); end
833
- # def foo; [1+1, 2, 3, 4] ; end
834
- # def foo; { 1 => 2, 3 => 4 }; end
835
- # def foo; foo(1 + 2 * (3 + 4), 5); end
836
- # def foo; 1 + 2 * (3 + 4); end
837
-
838
- n = method(:foo).body
839
- is = n.body
840
- puts is.disasm
841
-
842
- env = Internal::ByteDecoder::Environment.new(is.local_table)
843
- s = ''
844
- # puts "local_table = #{is.local_table.inspect}"
845
- is.each do |i|
846
- # p i.operand_types, i.operand_names
847
- # p i #, i.operand_types, i.operand_names
848
- print i.class, ' '
849
- a = []
850
- i.operand_names.each_with_index do |name, idx|
851
- a << "#{name}(#{i.operand_types[idx]})=#{i.operands[idx].inspect}"
852
- end
853
- puts a.join(', ')
854
- i.bytedecode(env)
855
- env.advance(i.length)
856
- # p env.stack
857
- # p env.stack.map { |x| x.to_s }
858
- # puts
859
- end
860
-
861
- puts "---"
862
- (env.expressions + env.stack).sort.each do |expr|
863
- puts expr.to_s
864
- end
865
- end
866
-