Class: Opal::Nodes::MassAssignNode

Inherits:
Base
  • Object
show all
Defined in:
opal/lib/opal/nodes/masgn.rb

Constant Summary

SIMPLE_ASSIGNMENT =
[:lasgn, :iasgn, :lvar, :gasgn, :cdecl]

Constants included from Helpers

Helpers::BASIC_IDENTIFIER_RULES, Helpers::ES3_RESERVED_WORD_EXCLUSIVE, Helpers::ES51_RESERVED_WORD, Helpers::IMMUTABLE_PROPS, Helpers::PROTO_SPECIAL_METHODS, Helpers::PROTO_SPECIAL_PROPS, Helpers::RESERVED_FUNCTION_NAMES

Instance Attribute Summary

Attributes inherited from Base

#compiler, #type

Instance Method Summary collapse

Methods inherited from Base

#add_gvar, #add_ivar, #add_local, #add_temp, #children, children, #compile_to_fragments, #error, #expr, #expr?, #expr_or_nil, #fragment, handle, handlers, #has_rescue_else?, #helper, #in_ensure, #in_ensure?, #in_while?, #initialize, #process, #push, #recv, #recv?, #s, #scope, #stmt, #stmt?, truthy_optimize?, #unshift, #while_loop, #with_temp, #wrap

Methods included from Helpers

#current_indent, #empty_line, #indent, #ivar, #js_falsy, #js_truthy, #js_truthy_optimize, #line, #lvar_to_js, #mid_to_jsid, #property, #valid_ivar_name?, #valid_name?, #variable

Constructor Details

This class inherits a constructor from Opal::Nodes::Base

Instance Method Details

#compileObject

[View source]

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'opal/lib/opal/nodes/masgn.rb', line 11

def compile
  array = scope.new_temp

  if rhs.type == :array
    push "#{array} = ", expr(rhs)
    compile_masgn(lhs.children, array, rhs.size - 1)
    push ", #{array}" # a mass assignment evaluates to the RHS
  elsif rhs.type == :to_ary
    retval = scope.new_temp
    push "#{retval} = ", expr(rhs[1])
    push ", #{array} = Opal.to_ary(#{retval})"
    compile_masgn(lhs.children, array)
    push ", #{retval}"
    scope.queue_temp(retval)
  elsif rhs.type == :splat
    push "#{array} = Opal.to_a(", expr(rhs[1]), ")"
    compile_masgn(lhs.children, array)
    push ", #{array}"
  else
    raise "unsupported mlhs type"
  end

  scope.queue_temp(array)
end

#compile_assignment(child, array, idx, len = nil) ⇒ Object

[View source]

78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'opal/lib/opal/nodes/masgn.rb', line 78

def compile_assignment(child, array, idx, len = nil)
  if !len || idx >= len
    assign = s(:js_tmp, "(#{array}[#{idx}] == null ? nil : #{array}[#{idx}])")
  else
    assign = s(:js_tmp, "#{array}[#{idx}]")
  end

  part = child.dup
  if SIMPLE_ASSIGNMENT.include?(child.type)
    part << assign
  elsif child.type == :call
    part[2] = "#{part[2]}=".to_sym
    part.last << assign
  elsif child.type == :attrasgn
    part.last << assign
  elsif child.type == :array
    # nested destructuring
    tmp = scope.new_temp
    push ", (#{tmp} = Opal.to_ary(#{assign[1]})"
    compile_masgn(child.children, tmp)
    push ')'
    scope.queue_temp(tmp)
    return
  else
    raise "Bad child node in masgn LHS: #{child}. LHS: #{lhs}"
  end

  push ', '
  push expr(part)
end

#compile_masgn(lhs_items, array, len = nil) ⇒ Object

'len' is how many rhs items are we sure we have

[View source]

37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'opal/lib/opal/nodes/masgn.rb', line 37

def compile_masgn(lhs_items, array, len = nil)
  pre_splat  = lhs_items.take_while { |child| child.type != :splat }
  post_splat = lhs_items.drop(pre_splat.size)

  pre_splat.each_with_index do |child, idx|
    compile_assignment(child, array, idx, len)
  end

  unless post_splat.empty?
    splat = post_splat.shift

    if post_splat.empty? # trailing splat
      if part = splat[1]
        part = part.dup << s(:js_tmp, "$slice.call(#{array}, #{pre_splat.size})")
        push ', '
        push expr(part)
      end
    else
      tmp = scope.new_temp # end index for items consumed by splat
      push ", #{tmp} = #{array}.length - #{post_splat.size}"
      push ", #{tmp} = (#{tmp} < #{pre_splat.size}) ? #{pre_splat.size} : #{tmp}"

      if part = splat[1]
        part = part.dup << s(:js_tmp, "$slice.call(#{array}, #{pre_splat.size}, #{tmp})")
        push ', '
        push expr(part)
      end

      post_splat.each_with_index do |child, idx|
        if idx == 0
          compile_assignment(child, array, tmp)
        else
          compile_assignment(child, array, "#{tmp} + #{idx}")
        end
      end

      scope.queue_temp(tmp)
    end
  end
end