jade-lang 0.11.1 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c07abf955aeeae107bd0cbb0f2f9ba95aab3c9240946e96d69521c2ae406f56b
4
- data.tar.gz: a6750f4f9734070babfde95fa657a37cec27acc43c705742b63b58691f4c225a
3
+ metadata.gz: 5529a34cf9b8a3d407d78642bca0281ec0a422dcded4f5875636e85f7018d7e4
4
+ data.tar.gz: c8da773021523ebb4d93836d8c8dee0ba0dca6acf4115f32ff46443a8dfbf08e
5
5
  SHA512:
6
- metadata.gz: c485c3028caa4b4ad1da0abd708c9c6c1b935ed26a242f19efbc5440f3e9a46e6236cf9e93912e870c941ba64096ae488499ce351c0dfd04a75084a6e8b9f6c1
7
- data.tar.gz: 2176bf5dc17eacdbbc902a3243e8676c2232350846a45913181489ee74ea6ff9f576d9278b0f5bfaffb1d235c7d8337ce6ebd0d03ff141e23d3bc74b95f2f8dd
6
+ metadata.gz: 26bab9740a9f008e4611a52210ec002f314e1fec4169239cd1a4aaa37eb090829a6fd20f4742ab475c169e4dc856652deddf12eca95f862f413668accdeda724
7
+ data.tar.gz: 243a05ffe69948767ccb7900b4e2cf443dccdb50d540f6cd16998863a6917e2742718769b742c0d0bf9f1e121aa4ee51cd85b70084ea7f26d669a1e49bf14d54
data/CHANGELOG.md CHANGED
@@ -4,6 +4,48 @@ 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
+
31
+ ## [0.11.2] - 2026-09-15
32
+
33
+ ### Fixed
34
+
35
+ - **A constraint raised inside a field access reached nothing.**
36
+ `RecordAccess` built its result from the expected type alone, so whatever
37
+ the target raised was dropped at the dot. A function whose body is
38
+ `to_sel(q).cols` therefore recorded no constraint of its own: it took no
39
+ dictionary parameter, and the interface call inside it fell through to
40
+ `Runtime.impl_for`, which keys on the argument's own class. That dispatches
41
+ on `Q` when the interface is over the `c` inside it, and fails at the first
42
+ call — at run time, though both the types and the call sites were settled
43
+ when it compiled.
44
+
45
+ Deleting the `.cols` from the same program made it work, which is the
46
+ asymmetry that gave it away. It matters wherever an interface is over a type
47
+ a struct holds rather than the struct itself.
48
+
7
49
  ## [0.11.1] - 2026-09-15
8
50
 
9
51
  ### Added
@@ -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
@@ -393,7 +393,7 @@ module Jade
393
393
  end
394
394
 
395
395
  def emit(ir, registry)
396
- Emitter.emit(ir)
396
+ Emitter.emit(ir, registry)
397
397
  end
398
398
  end
399
399
  end
@@ -24,7 +24,7 @@ module Jade
24
24
  )
25
25
  end
26
26
 
27
- Result.init(expected_.type)
27
+ Result.init(expected_.type, target_result.constraints)
28
28
  .then { it.apply(after_state.env.substitution) }
29
29
  .then { [after_state, it] }
30
30
  end
data/lib/jade/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Jade
2
- VERSION = '0.11.1'
2
+ VERSION = '0.11.3'
3
3
  end
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.1
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-15 00:00:00.000000000 Z
10
+ date: 2026-09-16 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: base64