Module: Jade::Codegen::FunctionCall
- Extended by:
- FunctionCall, Helpers
- Included in:
- FunctionCall
- Defined in:
- lib/jade/codegen/function_call.rb
Constant Summary
Constants included from Helpers
Instance Method Summary collapse
- #callee_qname(callee, registry) ⇒ Object
- #constructor_call(callee, args, registry) ⇒ Object
- #constructor_callee?(callee, registry) ⇒ Boolean
-
#dispatch_for_dep(dep, registry) ⇒ Object
An Implementation’s dep is one of two dictionary-slot shapes: a concrete Implementation (recurse to a ‘=> ruby_code` hash) or a Type::Constraint(Var) marker for a free-var dep that’s late-bound from the caller’s dict env (emit the raw dict reference as a String — build_impl_arg threads it into the impl_arg slot without re-wrapping).
- #dispatch_value(entry, registry) ⇒ Object
- #emit_operator(op, args, registry) ⇒ Object
- #generate(node, registry) ⇒ Object
- #generate_impl_dispatch(impl, registry) ⇒ Object
-
#invocation_op(callee, registry) ⇒ Object
Direct-def call sites (‘Foo::Internal.name(args)`) for plain user fns; `.call(args)` for everything else (lambdas, Procs, Methods).
- #invocation_op_for(symbol) ⇒ Object
-
#reference_with_dictionaries(symbol, dictionaries, registry) ⇒ Object
Polymorphic fn referenced as a value (not called).
- #try_operator_call(callee, args, registry) ⇒ Object
Methods included from Helpers
data_define, dict_constraints, dict_synthetic_name, fn_constraints, fn_impl_synthetic_name, generate_many, generate_node, impl_synthetic_name, param_synthetic_name, resolve_callee_symbol, ruby_classes_for_type, to_qualified
Instance Method Details
#callee_qname(callee, registry) ⇒ Object
58 59 60 61 62 63 |
# File 'lib/jade/codegen/function_call.rb', line 58 def callee_qname(callee, registry) case resolve_callee_symbol(callee, registry) in Symbol::InterfaceFunction | Symbol::StdlibFunction => sym then sym.qualified_name else nil end end |
#constructor_call(callee, args, registry) ⇒ Object
27 28 29 30 31 |
# File 'lib/jade/codegen/function_call.rb', line 27 def constructor_call(callee, args, registry) resolve_callee_symbol(callee, registry) .then { to_qualified(it.qualified_name) } .then { "#{it}[#{generate_many(args, registry)}]" } end |
#constructor_callee?(callee, registry) ⇒ Boolean
33 34 35 36 37 |
# File 'lib/jade/codegen/function_call.rb', line 33 def constructor_callee?(callee, registry) return true if callee.is_a?(AST::ConstructorReference) resolve_callee_symbol(callee, registry).is_a?(Symbol::Constructor) end |
#dispatch_for_dep(dep, registry) ⇒ Object
An Implementation’s dep is one of two dictionary-slot shapes: a concrete Implementation (recurse to a ‘=> ruby_code` hash) or a Type::Constraint(Var) marker for a free-var dep that’s late-bound from the caller’s dict env (emit the raw dict reference as a String —build_impl_arg threads it into the impl_arg slot without re-wrapping).
87 88 89 90 91 92 93 94 95 |
# File 'lib/jade/codegen/function_call.rb', line 87 def dispatch_for_dep(dep, registry) case dep in Symbol::Implementation generate_impl_dispatch(dep, registry) in Type::Constraint(type: Type::Var) dispatch_value(dep, registry) end end |
#dispatch_value(entry, registry) ⇒ Object
97 98 99 100 101 102 103 104 105 |
# File 'lib/jade/codegen/function_call.rb', line 97 def dispatch_value(entry, registry) case entry in Type::Constraint(interface:, type: Type::Var(id:)) Codegen.dict_env[[interface, id]] in Symbol::Implementation Pretty.hash(generate_impl_dispatch(entry, registry)) end end |
#emit_operator(op, args, registry) ⇒ Object
65 66 67 68 69 |
# File 'lib/jade/codegen/function_call.rb', line 65 def emit_operator(op, args, registry) args .map { generate_node(it, registry) } .then { |(a, b)| op == 'compare' ? "#{a}.compare(#{b})" : "(#{a} #{op} #{b})" } end |
#generate(node, registry) ⇒ Object
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# File 'lib/jade/codegen/function_call.rb', line 7 def generate(node, registry) node => AST::FunctionCall(callee:, args:, dictionaries:) variant_sym = keyed_variant_constructor(callee, registry) return generate_keyed_variant_call(variant_sym, args, registry) if variant_sym try_operator_call(callee, args, registry) .then { return it if it } Inline.try_for(callee, args, dictionaries, registry) .then { return it if it } return constructor_call(callee, args, registry) if constructor_callee?(callee, registry) [generate_many(args, registry), generate_dict_args(callee, dictionaries, registry)] .reject(&:empty?) .join(', ') .then { "#{generate_callee(callee, args, registry, dictionaries)}#{invocation_op(callee, registry)}(#{it})" } end |
#generate_impl_dispatch(impl, registry) ⇒ Object
71 72 73 74 75 76 77 78 79 80 |
# File 'lib/jade/codegen/function_call.rb', line 71 def generate_impl_dispatch(impl, registry) impl .deps .map { |dep| dispatch_for_dep(dep, registry) } .then do |dep_dispatches| impl.functions.transform_values do |fn| generate_impl_fn(fn, dep_dispatches, impl.functions, registry) end end end |
#invocation_op(callee, registry) ⇒ Object
Direct-def call sites (‘Foo::Internal.name(args)`) for plain user fns; `.call(args)` for everything else (lambdas, Procs, Methods).
41 42 43 44 45 46 |
# File 'lib/jade/codegen/function_call.rb', line 41 def invocation_op(callee, registry) case callee.symbol in Symbol::ValueRef => ref then invocation_op_for(registry.lookup(ref)) in symbol then invocation_op_for(symbol) end end |
#invocation_op_for(symbol) ⇒ Object
48 49 50 |
# File 'lib/jade/codegen/function_call.rb', line 48 def invocation_op_for(symbol) symbol.is_a?(Symbol::Function) ? '' : '.call' end |
#reference_with_dictionaries(symbol, dictionaries, registry) ⇒ Object
Polymorphic fn referenced as a value (not called). Wraps the fn with its dispatched dictionaries so the result is a monomorphic callable matching the type at the use site. Returns nil when the symbol doesn’t need wrapping; the caller falls back to its default reference emission.
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 |
# File 'lib/jade/codegen/function_call.rb', line 112 def reference_with_dictionaries(symbol, dictionaries, registry) return nil if dictionaries.empty? case symbol in Symbol::StdlibFunction => fn if fn.constraints.any? dictionaries .map { dispatch_dict(it, registry) } .then { generate_impl_fn(fn.codegen, it, {}, registry) } in Symbol::Function => fn if dict_constraints(fn, registry).any? param_names = fn.params.size.times.map { param_synthetic_name(it) } fn_constraints(fn, registry) .each_with_index .filter_map { |c, i| dispatch_value(dictionaries[i], registry) if c.type.is_a?(Type::Var) } .then { (param_names + it).join(', ') } .then { "#{to_qualified(fn.module_name)}::Internal.#{fn_target_name(fn, registry)}(#{it})" } .then { Pretty.lambda(param_names.join(', '), it) } in Symbol::InterfaceFunction => fn dispatch_value(dictionaries.first, registry) &.then { "#{it}[#{fn.name.inspect}]" } || fail("no dict in scope to reference interface method `#{fn.qualified_name}` as a value") else nil end end |
#try_operator_call(callee, args, registry) ⇒ Object
52 53 54 55 56 |
# File 'lib/jade/codegen/function_call.rb', line 52 def try_operator_call(callee, args, registry) MethodNames .call_operator(callee_qname(callee, registry)) &.then { |op| emit_operator(op, args, registry) } end |