jade-lang 0.11.2 → 0.11.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +24 -0
- data/lib/jade/codegen/emitter.rb +55 -13
- data/lib/jade/codegen/function_call.rb +1 -1
- data/lib/jade/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5529a34cf9b8a3d407d78642bca0281ec0a422dcded4f5875636e85f7018d7e4
|
|
4
|
+
data.tar.gz: c8da773021523ebb4d93836d8c8dee0ba0dca6acf4115f32ff46443a8dfbf08e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 26bab9740a9f008e4611a52210ec002f314e1fec4169239cd1a4aaa37eb090829a6fd20f4742ab475c169e4dc856652deddf12eca95f862f413668accdeda724
|
|
7
|
+
data.tar.gz: 243a05ffe69948767ccb7900b4e2cf443dccdb50d540f6cd16998863a6917e2742718769b742c0d0bf9f1e121aa4ee51cd85b70084ea7f26d669a1e49bf14d54
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,30 @@ All notable changes to this project are documented here. The format follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
|
|
5
5
|
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.11.3] - 2026-09-16
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **A derived body can call a Jade function.** A deriver's body is an
|
|
12
|
+
s-expression over a fixed vocabulary, and none of it reached an ordinary
|
|
13
|
+
function: `:stdlib_fn` finds intrinsics, `:struct_constructor` finds
|
|
14
|
+
constructors, and `:call` needs a callee one of those produced. A deriver
|
|
15
|
+
that wanted to reuse a function had to rebuild it, and the copy drifts from
|
|
16
|
+
the original in silence.
|
|
17
|
+
|
|
18
|
+
[:call, [:fn, "Sql.Query.selected", [0]], [[:var, "q"]]]
|
|
19
|
+
|
|
20
|
+
The name resolves through the registry, which is what knows whether the
|
|
21
|
+
target is constrained — those are compiled twice, as `name` wrapping the Ruby
|
|
22
|
+
boundary and `__name__impl__` taking the dictionaries, and the boundary
|
|
23
|
+
wrapper is the wrong one to call from generated code.
|
|
24
|
+
|
|
25
|
+
Dictionaries come from the deriver's own `impl_arg`, one index per
|
|
26
|
+
constraint, in the order the callee declares them. A count that does not
|
|
27
|
+
match what the callee takes is refused where it is written, rather than
|
|
28
|
+
becoming Ruby that loads and misbehaves later. `[:impl_dict, i]` yields a
|
|
29
|
+
whole dictionary, where `[:impl_arg, i, fn]` yields one function out of one.
|
|
30
|
+
|
|
7
31
|
## [0.11.2] - 2026-09-15
|
|
8
32
|
|
|
9
33
|
### Fixed
|
data/lib/jade/codegen/emitter.rb
CHANGED
|
@@ -6,19 +6,19 @@ module Jade
|
|
|
6
6
|
extend self
|
|
7
7
|
extend Helpers
|
|
8
8
|
|
|
9
|
-
def emit(ir)
|
|
9
|
+
def emit(ir, registry = nil)
|
|
10
10
|
case ir
|
|
11
11
|
in [:var, expr]
|
|
12
12
|
expr
|
|
13
13
|
|
|
14
14
|
in [:!, expr]
|
|
15
|
-
"!(#{emit(expr)})"
|
|
15
|
+
"!(#{emit(expr, registry)})"
|
|
16
16
|
|
|
17
17
|
in [:and, expr1, expr2]
|
|
18
|
-
"#{emit(expr1)} && #{emit(expr2)}"
|
|
18
|
+
"#{emit(expr1, registry)} && #{emit(expr2, registry)}"
|
|
19
19
|
|
|
20
20
|
in [:==, expr1, expr2]
|
|
21
|
-
"#{emit(expr1)} == #{emit(expr2)}"
|
|
21
|
+
"#{emit(expr1, registry)} == #{emit(expr2, registry)}"
|
|
22
22
|
|
|
23
23
|
in Integer | TrueClass | FalseClass | Float
|
|
24
24
|
ir.to_s
|
|
@@ -29,24 +29,33 @@ module Jade
|
|
|
29
29
|
in [:case, subject, branches]
|
|
30
30
|
branches
|
|
31
31
|
.map { [:case_branch, *it] }
|
|
32
|
-
.map { emit(it) }
|
|
32
|
+
.map { emit(it, registry) }
|
|
33
33
|
.join("\n")
|
|
34
|
-
.then { "case #{emit(subject)}\n#{it}\nend" }
|
|
34
|
+
.then { "case #{emit(subject, registry)}\n#{it}\nend" }
|
|
35
35
|
|
|
36
36
|
in [:case_branch, pattern, body]
|
|
37
37
|
body
|
|
38
|
-
.map { emit(it) }.join('; ')
|
|
39
|
-
.then { "in #{emit(pattern)} then #{it}" }
|
|
38
|
+
.map { emit(it, registry) }.join('; ')
|
|
39
|
+
.then { "in #{emit(pattern, registry)} then #{it}" }
|
|
40
40
|
|
|
41
41
|
in [:call, callee, args]
|
|
42
42
|
args
|
|
43
|
-
.map { emit(it) }
|
|
43
|
+
.map { emit(it, registry) }
|
|
44
44
|
.join(', ')
|
|
45
|
-
.then { "#{emit(callee)}.call(#{it})"}
|
|
45
|
+
.then { "#{emit(callee, registry)}.call(#{it})"}
|
|
46
46
|
|
|
47
47
|
in [:impl_arg, index, fn]
|
|
48
48
|
"impl_arg[#{index}]['#{fn}']"
|
|
49
49
|
|
|
50
|
+
in [:impl_dict, index]
|
|
51
|
+
"impl_arg[#{index}]"
|
|
52
|
+
|
|
53
|
+
in [:fn, qualified_name]
|
|
54
|
+
fn_reference(qualified_name, [], registry)
|
|
55
|
+
|
|
56
|
+
in [:fn, qualified_name, dict_indices]
|
|
57
|
+
fn_reference(qualified_name, dict_indices, registry)
|
|
58
|
+
|
|
50
59
|
in [:stdlib_fn, name]
|
|
51
60
|
"Jade::Runtime.intr(#{name.inspect})"
|
|
52
61
|
|
|
@@ -61,18 +70,18 @@ module Jade
|
|
|
61
70
|
|
|
62
71
|
in [:list, exprs]
|
|
63
72
|
exprs
|
|
64
|
-
.map { emit(it) }
|
|
73
|
+
.map { emit(it, registry) }
|
|
65
74
|
.join(', ')
|
|
66
75
|
.then { "[#{it}]" }
|
|
67
76
|
|
|
68
77
|
in [:hash, pairs]
|
|
69
78
|
pairs
|
|
70
|
-
.map { |key, value| "#{key.inspect} => #{emit(value)}" }
|
|
79
|
+
.map { |key, value| "#{key.inspect} => #{emit(value, registry)}" }
|
|
71
80
|
.join(', ')
|
|
72
81
|
.then { it.empty? ? '{}' : "{ #{it} }" }
|
|
73
82
|
|
|
74
83
|
in [:access, expr, key]
|
|
75
|
-
"#{emit(expr)}.#{key}"
|
|
84
|
+
"#{emit(expr, registry)}.#{key}"
|
|
76
85
|
|
|
77
86
|
# patterns
|
|
78
87
|
|
|
@@ -88,6 +97,39 @@ module Jade
|
|
|
88
97
|
end
|
|
89
98
|
end
|
|
90
99
|
|
|
100
|
+
private
|
|
101
|
+
|
|
102
|
+
def fn_reference(qualified_name, dict_indices, registry)
|
|
103
|
+
registry or fail("[:fn, #{qualified_name.inspect}] needs a registry")
|
|
104
|
+
|
|
105
|
+
*module_parts, name = qualified_name.split('.')
|
|
106
|
+
|
|
107
|
+
Symbol
|
|
108
|
+
.value_ref(module_parts.join('.'), name)
|
|
109
|
+
.then { registry.lookup(it) }
|
|
110
|
+
.then { checked_reference(it, qualified_name, dict_indices, registry) }
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def checked_reference(symbol, qualified_name, dict_indices, registry)
|
|
114
|
+
wanted = dict_constraints(symbol, registry).size
|
|
115
|
+
|
|
116
|
+
unless wanted == dict_indices.size
|
|
117
|
+
fail(
|
|
118
|
+
"#{qualified_name} takes #{wanted} #{wanted == 1 ? 'dictionary' : 'dictionaries'}, " \
|
|
119
|
+
"#{dict_indices.size} given — a derived body passes one impl_arg " \
|
|
120
|
+
'index per constraint, in the order the callee declares them'
|
|
121
|
+
)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
target = "#{internal(symbol.module_name)}.#{fn_target_name(symbol, registry)}"
|
|
125
|
+
return "#{internal(symbol.module_name)}.method(:#{fn_target_name(symbol, registry)})" if wanted.zero?
|
|
126
|
+
|
|
127
|
+
dict_indices
|
|
128
|
+
.map { "impl_arg[#{it}]" }
|
|
129
|
+
.join(', ')
|
|
130
|
+
.then { "->(*args) { #{target}(*args, #{it}) }" }
|
|
131
|
+
end
|
|
132
|
+
|
|
91
133
|
end
|
|
92
134
|
end
|
|
93
135
|
end
|
data/lib/jade/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jade-lang
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.11.
|
|
4
|
+
version: 0.11.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Agustin Cornu
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-09-
|
|
10
|
+
date: 2026-09-16 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: base64
|