# frozen_string_literal: truerequire'opal/nodes/base'moduleOpalmoduleNodes# This base class is used just to child the find_super_dispatcher method# body. This is then used by actual super calls, or a defined?(super) style# call.classBaseSuperNode<CallNodedefinitialize(*)superargs=*@sexp*rest,last_child=*argsiflast_child&&%i[iter block_pass].include?(last_child.type)@iter=last_childargs=restelse@iter=s(:js_tmp,'null')end@arglist=s(:arglist,*args)@recvr=s(:self)enddefcompile_using_sendhelper:send2push'$send2('compile_receivercompile_method_bodycompile_method_namecompile_argumentscompile_block_passpush')'endprivate# Using super in a block inside a method is allowed, e.g.# def a# { super }# end## This method finds returns a closest s(:def) (or s(:defs))defdef_scope@def_scope||=scope.def??scope:scope.find_parent_defenddefdefined_check_param'false'enddefimplicit_arguments_param'false'enddefmethod_iddef_scope.mid.to_senddefdef_scope_identitydef_scope.identify!(def_scope.mid)enddefallow_stubs'true'enddefsuper_method_invocationhelper:find_super"$find_super(#{scope.self}, '#{method_id}', #{def_scope_identity}, #{defined_check_param}, #{allow_stubs})"enddefsuper_block_invocationhelper:find_block_superchain,cur_defn,mid=scope.super_chaintrys=chain.map{|c|"#{c}.$$def"}.join(' || ')"$find_block_super(#{scope.self}, #{mid}, (#{trys} || #{cur_defn}), #{defined_check_param}, #{implicit_arguments_param})"enddefcompile_method_bodypush', 'ifscope.def?pushsuper_method_invocationelsifscope.iter?pushsuper_block_invocationelseraise'super must be called from method body or block'endenddefcompile_method_nameifscope.def?push", '#{method_id}'"elsifscope.iter?_chain,_cur_defn,mid=scope.super_chainpush", #{mid}"endendendclassDefinedSuperNode<BaseSuperNodehandle:defined_superdefallow_stubs'false'enddefdefined_check_param'true'enddefcompilecompile_receivercompile_method_bodywrap'((',') != null ? "super" : nil)'endend# super with explicit argsclassSuperNode<BaseSuperNodehandle:superdefinitialize(*)superifscope.def?scope.uses_block!endenddefcompilecompile_using_sendendend# super with implicit argsclassZsuperNode<SuperNodehandle:zsuperdefimplicit_arguments_param'true'enddefinitialize(*)super# preserve a block if we have one already but otherwise, assume a block is coming from higher# up the chainunlessiter.type==:iter# Need to support passing block up even if it's not referenced in this method at allscope.uses_block!@iter=s(:js_tmp,scope.block_name||'$yield')endenddefcompileifdef_scopeimplicit_args=implicit_arglist# If the method we're in has a block and we're using a default super call with no args, we need to grab the block# If an iter (block via braces) is provided, that takes precedenceifblock_name&&!iterblock_pass=s(:block_pass,s(:lvar,block_name))implicit_args<<block_passend@arglist=s(:arglist,*implicit_args)endcompile_using_sendenddefimplicit_arglistargs=[]kwargs=[]def_scope.original_args.children.eachdo|sexp|lvar_name=sexp.children[0]casesexp.typewhen:arg,:optargarg_node=s(:lvar,lvar_name)args<<arg_nodewhen:restargarg_node=lvar_name?s(:lvar,lvar_name):s(:js_tmp,'$rest_arg')args<<s(:splat,arg_node)when:kwarg,:kwoptargkey_name=sexp.meta[:arg_name]kwargs<<s(:pair,s(:sym,key_name),s(:lvar,lvar_name))when:kwrestargarg_node=lvar_name?s(:lvar,lvar_name):s(:js_tmp,'$kw_rest_arg')kwargs<<s(:kwsplat,arg_node)endendargs<<s(:hash,*kwargs)unlesskwargs.empty?argsenddefblock_namecasedef_scopewhenOpal::Nodes::IterNodedef_scope.block_namewhenOpal::Nodes::DefNodedef_scope.block_nameelseraise"Don't know what to do with super in the scope #{def_scope}"endendendendend