Module: Jade::Codegen::Implementation
Constant Summary
collapse
- COMPARABLE_DERIVATIONS =
[
"def <(other); compare(other) in Jade::Basics::LT; end",
"def >(other); compare(other) in Jade::Basics::GT; end",
"def <=(other); !(compare(other) in Jade::Basics::GT); end",
"def >=(other); !(compare(other) in Jade::Basics::LT); end",
].freeze
Constants included
from Helpers
Helpers::NATIVE_RUBY_CLASSES
Instance Method Summary
collapse
-
#class_reopens(ruby_classes, method_defs) ⇒ Object
-
#comparable_derivations(iface_qname) ⇒ Object
-
#generate(node, registry) ⇒ Object
-
#generate_defs(node, registry) ⇒ Object
-
#generate_operator_impl(node, registry) ⇒ Object
-
#generate_operator_method(impl_fn, impl_sym, registry) ⇒ Object
-
#generate_registrations_for(node, registry) ⇒ Object
-
#method_bodies_for(node, registry) ⇒ Object
Just the method-def strings (no surrounding ‘class … end`).
-
#operator_impl_or_empty(node, registry, iface_qname) ⇒ Object
-
#operator_method_body(ruby_method, fn, impl_sym, fn_name, registry) ⇒ Object
-
#simple_lambda_param?(pattern) ⇒ Boolean
‘(Pepe(id), other) -> { … }` would rebind a destructured pattern to `self` — invalid Ruby.
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
#class_reopens(ruby_classes, method_defs) ⇒ Object
48
49
50
51
52
53
|
# File 'lib/jade/codegen/implementation.rb', line 48
def class_reopens(ruby_classes, method_defs)
method_defs
.join(Pretty.newline(2))
.then { |body| ruby_classes.map { Pretty.block("class #{it}", body) } }
.join(Pretty.newline(2))
end
|
#comparable_derivations(iface_qname) ⇒ Object
104
105
106
|
# File 'lib/jade/codegen/implementation.rb', line 104
def comparable_derivations(iface_qname)
iface_qname == 'Basics.Comparable' ? COMPARABLE_DERIVATIONS : []
end
|
#generate(node, registry) ⇒ Object
7
8
9
10
11
12
13
14
15
16
17
|
# File 'lib/jade/codegen/implementation.rb', line 7
def generate(node, registry)
node => AST::Implementation(symbol:)
[
generate_defs(node, registry),
generate_registrations_for(node, registry),
operator_impl_or_empty(node, registry, symbol.interface.qualified_name),
]
.reject(&:empty?)
.join(Pretty.newline(2))
end
|
#generate_defs(node, registry) ⇒ Object
108
109
110
111
112
113
114
115
116
117
118
119
120
|
# File 'lib/jade/codegen/implementation.rb', line 108
def generate_defs(node, registry)
node => AST::Implementation(interface:, applied_type:, functions:)
type_name =
case applied_type.constructor
in AST::TypeName(type:) then type
in AST::QualifiedTypeName(path:) then path.last
end
functions
.filter_map { generate_function(it, registry, interface, type_name) }
.join(Pretty.newline(2))
end
|
#generate_operator_impl(node, registry) ⇒ Object
25
26
27
28
29
30
31
32
33
34
|
# File 'lib/jade/codegen/implementation.rb', line 25
def generate_operator_impl(node, registry)
node => AST::Implementation(functions:, symbol:)
ruby_classes_for_type(symbol.type, registry).then { |ruby_classes|
next "" if ruby_classes.empty?
method_bodies_for(node, registry)
.then { it.empty? ? "" : class_reopens(ruby_classes, it) }
}
end
|
#generate_operator_method(impl_fn, impl_sym, registry) ⇒ Object
55
56
57
58
59
60
61
|
# File 'lib/jade/codegen/implementation.rb', line 55
def generate_operator_method(impl_fn, impl_sym, registry)
impl_fn => AST::ImplementationFunction(name: fn_name, fn:)
MethodNames
.interface_method(impl_sym.interface.qualified_name, fn_name)
&.then { |ruby_method| operator_method_body(ruby_method, fn, impl_sym, fn_name, registry) }
end
|
#generate_registrations_for(node, registry) ⇒ Object
122
123
124
125
|
# File 'lib/jade/codegen/implementation.rb', line 122
def generate_registrations_for(node, registry)
node => AST::Implementation(symbol:)
generate_registrations(symbol, registry)
end
|
#method_bodies_for(node, registry) ⇒ Object
Just the method-def strings (no surrounding ‘class … end`). Used by `Codegen.collect_dispatched_methods` to gather impl methods for inlining into the type’s ‘Data.define do … end` block.
39
40
41
42
43
44
45
46
|
# File 'lib/jade/codegen/implementation.rb', line 39
def method_bodies_for(node, registry)
node => AST::Implementation(functions:, symbol:)
[
*functions.filter_map { generate_operator_method(it, symbol, registry) },
*comparable_derivations(symbol.interface.qualified_name),
]
end
|
#operator_impl_or_empty(node, registry, iface_qname) ⇒ Object
19
20
21
22
23
|
# File 'lib/jade/codegen/implementation.rb', line 19
def operator_impl_or_empty(node, registry, iface_qname)
MethodNames.operator_interface?(iface_qname) \
? generate_operator_impl(node, registry)
: ""
end
|
#operator_method_body(ruby_method, fn, impl_sym, fn_name, registry) ⇒ Object
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
# File 'lib/jade/codegen/implementation.rb', line 63
def operator_method_body(ruby_method, fn, impl_sym, fn_name, registry)
case fn
in AST::Lambda(params: [first_param, *rest_params], body:)
return nil unless simple_lambda_param?(first_param)
return nil unless rest_params.all? { simple_lambda_param?(it) }
rest_str = rest_params.map { generate_node(it, registry) }.join(', ')
first_name =
case first_param
in AST::Pattern::Binding(name:) then name
else nil
end
Codegen
.with_self_var_name(first_name) { generate_node(body, registry) }
.then { Pretty.block("def #{ruby_method}(#{rest_str})", it) }
in AST::VariableReference | AST::FunctionCall
impl_sym
.functions[fn_name]
.then { it.is_a?(Symbol::ValueRef) ? it : nil }
&.then { "::#{to_qualified(it.module_name)}::Internal.#{it.name}" }
&.then { Pretty.block("def #{ruby_method}(other)", "#{it}(self, other)") }
end
end
|
#simple_lambda_param?(pattern) ⇒ Boolean
‘(Pepe(id), other) -> { … }` would rebind a destructured pattern to `self` — invalid Ruby. Fall back to the dispatch-table path.
93
94
95
|
# File 'lib/jade/codegen/implementation.rb', line 93
def simple_lambda_param?(pattern)
pattern in AST::Pattern::Binding | AST::Pattern::Wildcard
end
|