class CodeTools::AST::OpAssignElement
Attributes
arguments[RW]
op[RW]
receiver[RW]
value[RW]
Public Class Methods
new(line, receiver, arguments, op, value)
click to toggle source
# File lib/rubinius/code/ast/operators.rb, line 107 def initialize(line, receiver, arguments, op, value) @line = line @receiver = receiver @op = op arguments = nil if arguments.is_a?(EmptyArray) @arguments = Arguments.new line, arguments @value = value end
Public Instance Methods
bytecode(g)
click to toggle source
# File lib/rubinius/code/ast/operators.rb, line 116 def bytecode(g) pos(g) # X: Snippet used for explanation: h[:a] += 3 # X: given h = { :a => 2 } # X: Pull h onto the stack @receiver.bytecode(g) # X: Pull :a in @arguments.bytecode(g) recv_stack = @arguments.stack_size + 1 # Dup the receiver and arguments to use later g.dup_many recv_stack # # X: Call [](:a) on h # # @arguments.size will be 1 if @arguments.splat? g.push_tagged_nil 0 g.send_with_splat :[], @arguments.size else g.send :[], @arguments.size end # X: 2 is now on the top of the stack (TOS) # A special case, where we use the value as boolean if @op == :or or @op == :and fnd = g.new_label fin = g.new_label assign = g.new_label # We dup the value from [] to leave it as the value of the # expression g.dup if @op == :or g.goto_if_true fnd else g.goto_if_false fnd end # Ok, take the extra copy off and pull the value onto the stack g.pop # The receiver and arguments are still on the stack old_break = g.break new_break = g.new_label g.break = new_break @value.bytecode(g) g.goto assign new_break.set! if old_break g.pop_many recv_stack + 1 g.push_tagged_nil 0 g.goto old_break end g.break = old_break assign.set! # retain the rhs as the expression value g.dup g.move_down recv_stack + 1 if @arguments.splat? g.send :push, 1 g.push_tagged_nil 0 g.send_with_splat :[]=, @arguments.size else g.send :[]=, @arguments.size + 1 end g.pop # Leaves the value we moved down the stack on the top g.goto fin fnd.set! # Clean up the stack but retain return value from :[] g.move_down recv_stack g.pop_many recv_stack fin.set! else assign = g.new_label old_break = g.break new_break = g.new_label g.break = new_break # @op is something like + or - # We pull in @value to the stack @value.bytecode(g) # X: 3 TOS g.goto assign new_break.set! if old_break g.pop_many recv_stack + 2 g.push_tagged_nil 0 g.goto old_break end g.break = old_break assign.set! # ... then call it as an argument to @or, called on the return # from []. # X: 2 + 3 g.send @op, 1 # X: 5 TOS # The new value is on the stack now. It is the last argument to the call # to []= because your dupd versions of recv and arguments are still on the stack. # retain the rhs as the expression value g.dup g.move_down recv_stack + 1 # X: Call []=(:a, 5) on h if @arguments.splat? g.send :push, 1 g.push_tagged_nil 0 g.send_with_splat :[]=, @arguments.size else g.send :[]=, @arguments.size + 1 end g.pop end end
to_sexp()
click to toggle source
# File lib/rubinius/code/ast/operators.rb, line 258 def to_sexp arguments = [:arglist] case @arguments when PushArguments arguments << @arguments.to_sexp else arguments += @arguments.to_sexp end case @op when :or op = :"||" when :and op = :"&&" else op = @op end [:op_asgn1, @receiver.to_sexp, arguments, op, @value.to_sexp] end