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)

Constant Summary

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

#initializePostArgsNode

Returns a new instance of PostArgsNode


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

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


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

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


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

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)]


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

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)]


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

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)


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

def restarg
  @restarg
end

Instance Method Details

#compileObject


107
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
# File 'opal/lib/opal/nodes/args/post_args.rb', line 107

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


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

def compile_optarg(optarg)
  var_name = variable(optarg[1].to_sym)
  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


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

def compile_required_arg(arg)
  push process(arg)
end

#compile_restargObject


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

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


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

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


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

def extract_blank_restarg
  if restarg[1]
    var_name = variable(restarg[1].to_sym)
    add_temp var_name
    line "#{var_name} = [];"
  end
end

#extract_restargObject


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

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

#kwargs_sexpObject


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

def kwargs_sexp
  s(:post_kwargs, *kwargs)
end