require 'opal/nodes/base' require 'opal/nodes/call' module Opal module Nodes # recv.mid = rhs # s(:recv, :mid=, s(:arglist, rhs)) class AttrAssignNode < CallNode handle :attrasgn children :recvr, :meth, :arglist def default_compile # Skip, for now, if the method has square brackets: []= return super if meth.to_s !~ /^\w+=$/ with_temp do |args_tmp| with_temp do |recv_tmp| args = expr(arglist) mid = mid_to_jsid meth.to_s push "((#{args_tmp} = [", args, "]), "+ "#{recv_tmp} = ", recv(recv_sexp), ", ", recv_tmp, mid, ".apply(#{recv_tmp}, #{args_tmp}), "+ "#{args_tmp}[#{args_tmp}.length-1])" end end end end # lhs =~ rhs # s(:match3, lhs, rhs) class Match3Node < Base handle :match3 children :lhs, :rhs def compile sexp = s(:call, lhs, :=~, s(:arglist, rhs)) push process(sexp, @level) end end # a ||= rhs # s(:op_asgn_or, s(:lvar, :a), s(:lasgn, :a, rhs)) class OpAsgnOrNode < Base handle :op_asgn_or children :recvr, :rhs def compile sexp = s(:or, recvr, rhs) push expr(sexp) end end # a &&= rhs # s(:op_asgn_and, s(:lvar, :a), s(:lasgn, a:, rhs)) class OpAsgnAndNode < Base handle :op_asgn_and children :recvr, :rhs def compile sexp = s(:and, recvr, rhs) push expr(sexp) end end # lhs[args] ||= rhs # s(:op_asgn1, lhs, args, :||, rhs) class OpAsgn1Node < Base handle :op_asgn1 children :lhs, :args, :op, :rhs def first_arg args[1] end def compile case op.to_s when '||' then compile_or when '&&' then compile_and else compile_operator end end def compile_operator with_temp do |a| # args with_temp do |r| # recv cur = s(:call, s(:js_tmp, r), :[], s(:arglist, s(:js_tmp, a))) rhs = s(:call, cur, op.to_sym, s(:arglist, self.rhs)) call = s(:call, s(:js_tmp, r), :[]=, s(:arglist, s(:js_tmp, a), rhs)) push "(#{a} = ", expr(first_arg), ", #{r} = ", expr(lhs) push ", ", expr(call), ")" end end end def compile_or with_temp do |a| # args with_temp do |r| # recv aref = s(:call, s(:js_tmp, r), :[], s(:arglist, s(:js_tmp, a))) aset = s(:call, s(:js_tmp, r), :[]=, s(:arglist, s(:js_tmp, a), rhs)) orop = s(:or, aref, aset) push "(#{a} = ", expr(first_arg), ", #{r} = ", expr(lhs) push ", ", expr(orop), ")" end end end def compile_and with_temp do |a| # args with_temp do |r| # recv aref = s(:call, s(:js_tmp, r), :[], s(:arglist, s(:js_tmp, a))) aset = s(:call, s(:js_tmp, r), :[]=, s(:arglist, s(:js_tmp, a), rhs)) andop = s(:and, aref, aset) push "(#{a} = ", expr(first_arg), ", #{r} = ", expr(lhs) push ", ", expr(andop), ")" end end end end # lhs.b += rhs # s(:op_asgn2, lhs, :b=, :+, rhs) class OpAsgn2Node < Base handle :op_asgn2 children :lhs, :mid, :op, :rhs def meth mid.to_s[0..-2] end def compile case op.to_s when '||' then compile_or when '&&' then compile_and else compile_operator end end def compile_or with_temp do |tmp| getr = s(:call, s(:js_tmp, tmp), meth, s(:arglist)) asgn = s(:call, s(:js_tmp, tmp), mid, s(:arglist, rhs)) orop = s(:or, getr, asgn) push "(#{tmp} = ", expr(lhs), ", ", expr(orop), ")" end end def compile_and with_temp do |tmp| getr = s(:call, s(:js_tmp, tmp), meth, s(:arglist)) asgn = s(:call, s(:js_tmp, tmp), mid, s(:arglist, rhs)) andop = s(:and, getr, asgn) push "(#{tmp} = ", expr(lhs), ", ", expr(andop), ")" end end def compile_operator with_temp do |tmp| getr = s(:call, s(:js_tmp, tmp), meth, s(:arglist)) oper = s(:call, getr, op, s(:arglist, rhs)) asgn = s(:call, s(:js_tmp, tmp), mid, s(:arglist, oper)) push "(#{tmp} = ", expr(lhs), ", ", expr(asgn), ")" end end end end end