Class: Opal::Nodes::PostArgsNode

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

Overview

Node responsible for extracting post-splat args

  1. There can be some arguments after the splat, this is why this node exist. In this case if: a. JS arguments length > args sexp length - then our splat has some items and we know how many of them should come to splat b. JS arguments length < args sexp length - then our splat is blank

  2. Super important: a) optional arg always goes BEFORE the rest arg b) optional args always appear in the sequence (i.e. you can't have def m(a=1,b,c=1)) c) precedence order: 1. required arg (norm arg, mlhs arg) 2. optional argument (optarg) 3. splat/rest argument (restarg) These statements simplify everything, keep them in mind.

  3. post_args here always have the same structure:

    1. list of required arguments (only for mlhs, can be blank)
    2. list of optargs (only for post-args, can be blank)
    3. restarg (for both mlhs/post-args, can be nil)
    4. list of required args (for both mlhs/post-args, can be blank)

Instance Attribute Summary collapse

Attributes inherited from Base

#compiler, #type

Instance Method Summary collapse

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?, #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

#initializePostArgsNode

Returns a new instance of PostArgsNode



73
74
75
76
77
78
79
80
81
# File 'opal/lib/opal/nodes/args/post_args.rb', line 73

def initialize(*)
  super

  @kwargs = []
  @required_left_args = []
  @optargs = []
  @restarg = nil
  @required_right_args = []
end

Instance Attribute Details

#kwargsObject (readonly)

kwargs contains the list of all post-kw* arguments all of them can be processed in the first oder



32
33
34
# File 'opal/lib/opal/nodes/args/post_args.rb', line 32

def kwargs
  @kwargs
end

#optargsObject (readonly)

optargs contains the list of optarg arguments all of them must be populated depending on the "arguments.length" if we have enough arguments - we fill them, if not - we populate it with its default value For post-args: can be provided from def m(a=1, *b) post-args = [(:optarg, :a, (:int, 1)), (:restarg, :b)] optargs = [(:optarg, :a, (:int, 1))] For mlhs: always blank



51
52
53
# File 'opal/lib/opal/nodes/args/post_args.rb', line 51

def optargs
  @optargs
end

#required_left_argsObject (readonly)

required_left_args contains the list of required post args like normarg or mlhs For post-args: always blank (post args always start with optarg/restarg) For mlhs: can be provided from mlhs = (a, b, c) required_left_args = [(:arg, :a), (:arg, :b)]



40
41
42
# File 'opal/lib/opal/nodes/args/post_args.rb', line 40

def required_left_args
  @required_left_args
end

#required_right_argsObject (readonly)

required_right_args contains the list of required post args like normarg and mlhs arg For post-args: can be provided from def m(a=1,*b,c) post-args = [(:optarg, :a, (:int, 1)), (:restarg, :b), (:arg, :c)] required_right_args = [(:arg, :c)] For mlhs: can be provided from (*a, b) required_right_args = [(:arg, :b)]



71
72
73
# File 'opal/lib/opal/nodes/args/post_args.rb', line 71

def required_right_args
  @required_right_args
end

#restargObject (readonly)

returns a restarg sexp if we have enough "arguments" - we fill it if not - we populate it with "[]" For post-args: can be provided from def m(a=1, *b) post-args = [(:optarg, :a, (:int, 1)), (:restarg, :b)] restarg (:restarg, :b)



60
61
62
# File 'opal/lib/opal/nodes/args/post_args.rb', line 60

def restarg
  @restarg
end

Instance Method Details

#compileObject



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'opal/lib/opal/nodes/args/post_args.rb', line 108

def compile
  return if children.empty?

  old_working_arguments = scope.working_arguments

  if @sexp.meta[:js_source]
    js_source = @sexp.meta[:js_source]
    scope.working_arguments = "#{js_source}_args"
  else
    js_source = "arguments"
    scope.working_arguments = "$post_args"
  end

  add_temp "#{scope.working_arguments}"
  line "#{scope.working_arguments} = Opal.slice.call(#{js_source}, #{scope.inline_args.size}, #{js_source}.length);"

  extract_arguments

  push process(kwargs_sexp)

  required_left_args.each do |arg|
    compile_required_arg(arg)
  end

  optargs.each do |optarg|
    compile_optarg(optarg)
  end

  compile_restarg

  required_right_args.each do |arg|
    compile_required_arg(arg)
  end

  scope.working_arguments = old_working_arguments
end

#compile_optarg(optarg) ⇒ Object



145
146
147
148
149
150
151
152
153
154
155
# File 'opal/lib/opal/nodes/args/post_args.rb', line 145

def compile_optarg(optarg)
  var_name, _ = *optarg
  add_temp var_name

  line "if (#{required_right_args.size} < #{scope.working_arguments}.length) {"
  indent do
    line "#{var_name} = #{scope.working_arguments}.splice(0,1)[0];"
  end
  line "}"
  push process(optarg)
end

#compile_required_arg(arg) ⇒ Object



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

def compile_required_arg(arg)
  push process(arg)
end

#compile_restargObject



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'opal/lib/opal/nodes/args/post_args.rb', line 161

def compile_restarg
  return unless restarg

  line "if (#{required_right_args.size} < #{scope.working_arguments}.length) {"
    indent do
      # there are some items coming to the splat, extracting them
      extract_restarg
    end
  line "} else {"
    indent do
      # splat is empty
      extract_blank_restarg
    end
  line "}"
end

#extract_argumentsObject



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'opal/lib/opal/nodes/args/post_args.rb', line 83

def extract_arguments
  found_opt_or_rest = false

  children.each do |arg|
    arg.meta[:post] = true

    case arg.type
    when :kwarg, :kwoptarg, :kwrestarg
      @kwargs << arg
    when :restarg
      @restarg = arg
      found_opt_or_rest = true
    when :optarg
      @optargs << arg
      found_opt_or_rest = true
    when :arg, :mlhs
      if found_opt_or_rest
        @required_right_args << arg
      else
        @required_left_args << arg
      end
    end
  end
end

#extract_blank_restargObject



188
189
190
191
192
193
194
# File 'opal/lib/opal/nodes/args/post_args.rb', line 188

def extract_blank_restarg
  var_name, _ = *restarg
  if var_name
    add_temp var_name
    line "#{var_name} = [];"
  end
end

#extract_restargObject



177
178
179
180
181
182
183
184
185
186
# File 'opal/lib/opal/nodes/args/post_args.rb', line 177

def extract_restarg
  extract_code = "#{scope.working_arguments}.splice(0, #{scope.working_arguments}.length - #{required_right_args.size});"
  var_name, _ = *restarg
  if var_name
    add_temp var_name
    line "#{var_name} = #{extract_code}"
  else
    line extract_code
  end
end

#kwargs_sexpObject



196
197
198
# File 'opal/lib/opal/nodes/args/post_args.rb', line 196

def kwargs_sexp
  s(:post_kwargs, *kwargs)
end