class Opal::Nodes::PostArgsNode
4. list of required args (for both mlhs/post-args, can be blank)
3. restarg (for both mlhs/post-args, can be nil)
2. list of optargs (only for post-args, can be blank)
1. list of required arguments (only for mlhs, can be blank)
3. post_args here always have the same structure:
These statements simplify everything, keep them in mind.
3. splat/rest argument (restarg)
2. optional argument (optarg)
1. required arg (norm arg, mlhs arg)
c) precedence order:
b) optional args always appear in the sequence (i.e. you can’t have def m(a=1,b,c=1))
a) optional arg always goes BEFORE the rest arg
2. Super important:
b. JS arguments length < args sexp length - then our splat is blank
and we know how many of them should come to splat
a. JS arguments length > args sexp length - then our splat has some items
In this case if:
1. There can be some arguments after the splat, this is why this node exist.
Node responsible for extracting post-splat args
def compile
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
def compile_optarg(optarg)
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
def compile_required_arg(arg)
def compile_required_arg(arg) push process(arg) end
def compile_restarg
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
def extract_arguments
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
def extract_blank_restarg
def extract_blank_restarg if restarg[1] var_name = variable(restarg[1].to_sym) add_temp var_name line "#{var_name} = [];" end end
def extract_restarg
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
def initialize(*)
def initialize(*) super @kwargs = [] @required_left_args = [] @optargs = [] @restarg = nil @required_right_args = [] end
def kwargs_sexp
def kwargs_sexp s(:post_kwargs, *kwargs) end