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

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, #class_variable_owner, #closest_module_node, #comments, #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

#conditional_send, #current_indent, #empty_line, #indent, #js_falsy, #js_truthy, #js_truthy_optimize, #line, #mid_to_jsid, #property, #valid_name?

Constructor Details

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

Instance Attribute Details

#block_argObject

Returns the value of attribute block_arg



12
13
14
# File 'opal/lib/opal/nodes/iter.rb', line 12

def block_arg
  @block_arg
end

#shadow_argsObject

Returns the value of attribute shadow_args



12
13
14
# File 'opal/lib/opal/nodes/iter.rb', line 12

def shadow_args
  @shadow_args
end

Instance Method Details

#compileObject



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
71
72
73
# File 'opal/lib/opal/nodes/iter.rb', line 14

def compile
  inline_params = nil
  extract_block_arg
  extract_shadow_args
  extract_underscore_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(returned_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 contains_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



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'opal/lib/opal/nodes/iter.rb', line 177

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



86
87
88
89
90
91
92
93
94
95
# File 'opal/lib/opal/nodes/iter.rb', line 86

def compile_block_arg
  if block_arg
    scope.block_name = block_arg
    scope.add_temp block_arg
    scope_name = scope.identify!

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

#compile_norm_argsObject



79
80
81
82
83
84
# File 'opal/lib/opal/nodes/iter.rb', line 79

def compile_norm_args
  norm_args.each do |arg|
    arg_name, _ = *arg
    push "if (#{arg_name} == null) #{arg_name} = nil;"
  end
end

#compile_shadow_argsObject



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

def compile_shadow_args
  shadow_args.each do |shadow_arg|
    arg_name = shadow_arg.children[0]
    scope.locals << arg_name
    scope.add_arg(arg_name)
  end
end

#contains_break?Boolean

Returns:

  • (Boolean)


203
204
205
206
207
# File 'opal/lib/opal/nodes/iter.rb', line 203

def contains_break?
  finder = Opal::Rewriters::BreakFinder.new
  finder.process(@sexp)
  finder.found_break?
end

#extract_block_argObject



97
98
99
100
101
102
103
104
105
106
# File 'opal/lib/opal/nodes/iter.rb', line 97

def extract_block_arg
  *regular_args, last_arg = args.children
  if last_arg && last_arg.type == :blockarg
    @block_arg = last_arg.children[0]
    @sexp = @sexp.updated(nil, [
      s(:args, *regular_args),
      body
    ])
  end
end

#extract_shadow_argsObject



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

def extract_shadow_args
  @shadow_args = []
  valid_args = []
  return unless args

  args.children.each_with_index do |arg, idx|
    if arg.type == :shadowarg
      @shadow_args << arg
    else
      valid_args << arg
    end
  end

  @sexp = @sexp.updated(nil, [
    args.updated(nil, valid_args),
    body
  ])
end

#extract_underscore_argsObject



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'opal/lib/opal/nodes/iter.rb', line 135

def extract_underscore_args
  valid_args = []
  caught_blank_argument = false

  args.children.each do |arg|
    arg_name = arg.children.first
    if arg_name == :_
      unless caught_blank_argument
        caught_blank_argument = true
        valid_args << arg
      end
    else
      valid_args << arg
    end
  end

  @sexp = @sexp.updated(nil, [
    args.updated(nil, valid_args),
    body
  ])
end

#has_top_level_mlhs_arg?Boolean

Returns:

  • (Boolean)


165
166
167
# File 'opal/lib/opal/nodes/iter.rb', line 165

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

#has_trailing_comma_in_args?Boolean

Returns:

  • (Boolean)


169
170
171
172
173
174
# File 'opal/lib/opal/nodes/iter.rb', line 169

def has_trailing_comma_in_args?
  if args.loc && args.loc.expression
    args_source = args.loc.expression.source
    args_source.match(/,\s*\|/)
  end
end

#mlhs_argsObject



161
162
163
# File 'opal/lib/opal/nodes/iter.rb', line 161

def mlhs_args
  scope.mlhs_mapping.keys
end

#norm_argsObject



75
76
77
# File 'opal/lib/opal/nodes/iter.rb', line 75

def norm_args
  @norm_args ||= args.children.select { |arg| arg.type == :arg }
end

#returned_bodyObject



157
158
159
# File 'opal/lib/opal/nodes/iter.rb', line 157

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