Class: Opal::Nodes::IterNode

Inherits:
NodeWithArgs show all
Defined in:
opal/lib/opal/nodes/iter.rb

Constant Summary

Constants inherited from NodeWithArgs

NodeWithArgs::SEXP_TO_PARAMETERS

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 collapse

Attributes inherited from NodeWithArgs

#inline_args, #kwargs_initialized, #mlhs_mapping, #post_args, #used_kwargs, #working_arguments

Attributes inherited from ScopeNode

#block_name, #catch_return, #defs, #gvars, #has_break, #ivars, #locals, #methods, #mid, #name, #parent, #rescue_else_sexp, #scope_name, #uses_super, #uses_zuper

Attributes inherited from Base

#compiler, #type

Instance Method Summary collapse

Methods inherited from NodeWithArgs

#arity, #arity_checks, #build_parameter, #compile_inline_args, #compile_post_args, #has_only_optional_kwargs?, #has_required_kwargs?, #in_mlhs, #in_mlhs?, #initialize, #inline_args_sexp, #keyword_args, #negative_arity, #opt_args, #optimize_args!, #parameters_code, #positive_arity, #post_args_sexp, #rest_arg, #split_args, #with_inline_args

Methods inherited from ScopeNode

#add_arg, #add_proto_ivar, #add_scope_gvar, #add_scope_ivar, #add_scope_local, #add_scope_temp, #class?, #class_scope?, #def?, #def_in_class?, #find_parent_def, #get_super_chain, #has_local?, #has_rescue_else?, #has_temp?, #identify!, #identity, #in_ensure, #in_ensure?, #in_scope, #in_while?, #initialize, #iter?, #module?, #new_temp, #next_temp, #pop_while, #proto, #push_while, #queue_temp, #sclass?, #to_vars, #top?, #uses_block!, #uses_block?

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::NodeWithArgs

Instance Attribute Details

#block_argObject

Returns the value of attribute block_arg


10
11
12
# File 'opal/lib/opal/nodes/iter.rb', line 10

def block_arg
  @block_arg
end

#shadow_argsObject

Returns the value of attribute shadow_args


10
11
12
# File 'opal/lib/opal/nodes/iter.rb', line 10

def shadow_args
  @shadow_args
end

Instance Method Details

#argsObject


117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'opal/lib/opal/nodes/iter.rb', line 117

def args
  sexp = if Fixnum === args_sexp or args_sexp.nil?
    s(:args)
  elsif args_sexp.is_a?(Sexp) && args_sexp.type == :lasgn
    s(:args, s(:arg, *args_sexp[1]))
  else
    args_sexp[1]
  end

  # compacting _ arguments into a single one (only the first one leaves in the sexp)
  caught_blank_argument = false

  sexp.each_with_index do |part, idx|
    if part.is_a?(Sexp) && part.last == :_
      if caught_blank_argument
        sexp.delete_at(idx)
      end
      caught_blank_argument = true
    end
  end

  sexp
end

#bodyObject


141
142
143
# File 'opal/lib/opal/nodes/iter.rb', line 141

def body
  compiler.returns(body_sexp || s(:nil))
end

#compileObject


12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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
# File 'opal/lib/opal/nodes/iter.rb', line 12

def compile
  inline_params = nil
  extract_block_arg
  extract_shadow_args
  split_args

  to_vars = identity = body_code = nil

  in_scope do
    inline_params = process(inline_args_sexp)

    identity = scope.identify!
    add_temp "self = #{identity}.$$s || this"

    compile_block_arg
    compile_shadow_args
    compile_inline_args
    compile_post_args
    compile_norm_args

    if compiler.arity_check?
      compile_arity_check
    end

    body_code = stmt(body)
    to_vars = scope.to_vars
  end

  line body_code

  unshift to_vars

  unshift "(#{identity} = function(", inline_params, "){"
  push "}, #{identity}.$$s = self,"
  push " #{identity}.$$brk = $brk," if compiler.has_break?
  push " #{identity}.$$arity = #{arity},"

  if compiler.arity_check?
    push " #{identity}.$$parameters = #{parameters_code},"
  end

  # MRI expands a passed argument if the block:
  # 1. takes a single argument that is an array
  # 2. has more that one argument
  # With a few exceptions:
  # 1. mlhs arg: if a block takes |(a, b)| argument
  # 2. trailing ',' in the arg list (|a, |)
  # This flag on the method indicates that a block has a top level mlhs argument
  # which means that we have to expand passed array explicitly in runtime.
  if has_top_level_mlhs_arg?
    push " #{identity}.$$has_top_level_mlhs_arg = true,"
  end

  if has_trailing_comma_in_args?
    push " #{identity}.$$has_trailing_comma_in_args = true,"
  end

  push " #{identity})"
end

#compile_arity_checkObject

Returns code used in debug mode to check arity of method call


158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'opal/lib/opal/nodes/iter.rb', line 158

def compile_arity_check
  if arity_checks.size > 0
    parent_scope = scope
    while !(parent_scope.top? || parent_scope.def? || parent_scope.class_scope?)
      parent_scope = parent_scope.parent
    end

    context = if parent_scope.top?
      "'<main>'"
    elsif parent_scope.def?
      "'#{parent_scope.mid}'"
    elsif parent_scope.class?
      "'<class:#{parent_scope.name}>'"
    elsif parent_scope.module?
      "'<module:#{parent_scope.name}>'"
    end

    identity = scope.identity

    line "if (#{identity}.$$is_lambda || #{identity}.$$define_meth) {"
    line "  var $arity = arguments.length;"
    line "  if (#{arity_checks.join(' || ')}) { Opal.block_ac($arity, #{arity}, #{context}); }"
    line "}"
  end
end

#compile_block_argObject


83
84
85
86
87
88
89
90
91
92
# File 'opal/lib/opal/nodes/iter.rb', line 83

def compile_block_arg
  if block_arg
    block_arg = variable(self.block_arg.to_s)
    scope.block_name = block_arg
    scope.add_temp block_arg
    scope_name = scope.identify!

    line "#{block_arg} = #{scope_name}.$$p || nil, #{scope_name}.$$p = null;"
  end
end

#compile_norm_argsObject


76
77
78
79
80
81
# File 'opal/lib/opal/nodes/iter.rb', line 76

def compile_norm_args
  norm_args.each do |arg|
    arg = variable(arg[1])
    push "if (#{arg} == null) #{arg} = nil;"
  end
end

#compile_shadow_argsObject


100
101
102
103
104
# File 'opal/lib/opal/nodes/iter.rb', line 100

def compile_shadow_args
  shadow_args.each do |shadow_arg|
    scope.add_local(shadow_arg.last)
  end
end

#extract_block_argObject


94
95
96
97
98
# File 'opal/lib/opal/nodes/iter.rb', line 94

def extract_block_arg
  if args.is_a?(Sexp) && args.last.is_a?(Sexp) and args.last.type == :block_pass
    self.block_arg = args.pop[1][1].to_sym
  end
end

#extract_shadow_argsObject


106
107
108
109
110
111
112
113
114
115
# File 'opal/lib/opal/nodes/iter.rb', line 106

def extract_shadow_args
  if args.is_a?(Sexp)
    @shadow_args = []
    args.children.each_with_index do |arg, idx|
      if arg.type == :shadowarg
        @shadow_args << args.delete(arg)
      end
    end
  end
end

#has_top_level_mlhs_arg?Boolean

Returns:

  • (Boolean)

149
150
151
# File 'opal/lib/opal/nodes/iter.rb', line 149

def has_top_level_mlhs_arg?
  args.children.any? { |arg| arg.type == :mlhs }
end

#has_trailing_comma_in_args?Boolean

Returns:

  • (Boolean)

153
154
155
# File 'opal/lib/opal/nodes/iter.rb', line 153

def has_trailing_comma_in_args?
  args.meta[:has_trailing_comma]
end

#mlhs_argsObject


145
146
147
# File 'opal/lib/opal/nodes/iter.rb', line 145

def mlhs_args
  scope.mlhs_mapping.keys
end

#norm_argsObject


72
73
74
# File 'opal/lib/opal/nodes/iter.rb', line 72

def norm_args
  @norm_args ||= args[1..-1].select { |arg| arg.type == :arg }
end