kumi 0.0.16 → 0.0.17

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.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/golden/cascade_logic/schema.kumi +3 -1
  4. data/lib/kumi/analyzer.rb +8 -11
  5. data/lib/kumi/core/analyzer/passes/broadcast_detector.rb +0 -81
  6. data/lib/kumi/core/analyzer/passes/lower_to_ir_pass.rb +0 -36
  7. data/lib/kumi/core/analyzer/passes/toposorter.rb +1 -36
  8. data/lib/kumi/core/analyzer/passes/unsat_detector.rb +8 -191
  9. data/lib/kumi/core/compiler/access_builder.rb +5 -8
  10. data/lib/kumi/version.rb +1 -1
  11. metadata +2 -25
  12. data/BACKLOG.md +0 -34
  13. data/config/functions.yaml +0 -352
  14. data/docs/functions/analyzer_integration.md +0 -199
  15. data/docs/functions/signatures.md +0 -171
  16. data/examples/hash_objects_demo.rb +0 -138
  17. data/lib/kumi/core/analyzer/passes/function_signature_pass.rb +0 -199
  18. data/lib/kumi/core/analyzer/passes/type_consistency_checker.rb +0 -48
  19. data/lib/kumi/core/functions/dimension.rb +0 -98
  20. data/lib/kumi/core/functions/dtypes.rb +0 -20
  21. data/lib/kumi/core/functions/errors.rb +0 -11
  22. data/lib/kumi/core/functions/kernel_adapter.rb +0 -45
  23. data/lib/kumi/core/functions/loader.rb +0 -119
  24. data/lib/kumi/core/functions/registry_v2.rb +0 -68
  25. data/lib/kumi/core/functions/shape.rb +0 -70
  26. data/lib/kumi/core/functions/signature.rb +0 -122
  27. data/lib/kumi/core/functions/signature_parser.rb +0 -86
  28. data/lib/kumi/core/functions/signature_resolver.rb +0 -272
  29. data/lib/kumi/kernels/ruby/aggregate_core.rb +0 -105
  30. data/lib/kumi/kernels/ruby/datetime_scalar.rb +0 -21
  31. data/lib/kumi/kernels/ruby/mask_scalar.rb +0 -15
  32. data/lib/kumi/kernels/ruby/scalar_core.rb +0 -63
  33. data/lib/kumi/kernels/ruby/string_scalar.rb +0 -19
  34. data/lib/kumi/kernels/ruby/vector_struct.rb +0 -39
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kumi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.16
4
+ version: 0.0.17
5
5
  platform: ruby
6
6
  authors:
7
7
  - André Muta
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-08-22 00:00:00.000000000 Z
11
+ date: 2025-09-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: zeitwerk
@@ -33,13 +33,11 @@ extra_rdoc_files: []
33
33
  files:
34
34
  - ".rspec"
35
35
  - ".rubocop.yml"
36
- - BACKLOG.md
37
36
  - CHANGELOG.md
38
37
  - CLAUDE.md
39
38
  - LICENSE.txt
40
39
  - README.md
41
40
  - Rakefile
42
- - config/functions.yaml
43
41
  - docs/AST.md
44
42
  - docs/DSL.md
45
43
  - docs/FUNCTIONS.md
@@ -58,8 +56,6 @@ files:
58
56
  - docs/features/input-declaration-system.md
59
57
  - docs/features/performance.md
60
58
  - docs/features/s-expression-printer.md
61
- - docs/functions/analyzer_integration.md
62
- - docs/functions/signatures.md
63
59
  - docs/schema_metadata.md
64
60
  - docs/schema_metadata/broadcasts.md
65
61
  - docs/schema_metadata/cascades.md
@@ -72,7 +68,6 @@ files:
72
68
  - examples/deep_schema_compilation_and_evaluation_benchmark.rb
73
69
  - examples/federal_tax_calculator_2024.rb
74
70
  - examples/game_of_life.rb
75
- - examples/hash_objects_demo.rb
76
71
  - examples/simple_rpg_game.rb
77
72
  - examples/static_analysis_errors.rb
78
73
  - examples/wide_schema_compilation_and_evaluation_benchmark.rb
@@ -90,7 +85,6 @@ files:
90
85
  - lib/kumi/core/analyzer/passes/broadcast_detector.rb
91
86
  - lib/kumi/core/analyzer/passes/declaration_validator.rb
92
87
  - lib/kumi/core/analyzer/passes/dependency_resolver.rb
93
- - lib/kumi/core/analyzer/passes/function_signature_pass.rb
94
88
  - lib/kumi/core/analyzer/passes/input_access_planner_pass.rb
95
89
  - lib/kumi/core/analyzer/passes/input_collector.rb
96
90
  - lib/kumi/core/analyzer/passes/ir_dependency_pass.rb
@@ -104,7 +98,6 @@ files:
104
98
  - lib/kumi/core/analyzer/passes/semantic_constraint_validator.rb
105
99
  - lib/kumi/core/analyzer/passes/toposorter.rb
106
100
  - lib/kumi/core/analyzer/passes/type_checker.rb
107
- - lib/kumi/core/analyzer/passes/type_consistency_checker.rb
108
101
  - lib/kumi/core/analyzer/passes/type_inferencer_pass.rb
109
102
  - lib/kumi/core/analyzer/passes/unsat_detector.rb
110
103
  - lib/kumi/core/analyzer/passes/visitor_pass.rb
@@ -153,16 +146,6 @@ files:
153
146
  - lib/kumi/core/function_registry/stat_functions.rb
154
147
  - lib/kumi/core/function_registry/string_functions.rb
155
148
  - lib/kumi/core/function_registry/type_functions.rb
156
- - lib/kumi/core/functions/dimension.rb
157
- - lib/kumi/core/functions/dtypes.rb
158
- - lib/kumi/core/functions/errors.rb
159
- - lib/kumi/core/functions/kernel_adapter.rb
160
- - lib/kumi/core/functions/loader.rb
161
- - lib/kumi/core/functions/registry_v2.rb
162
- - lib/kumi/core/functions/shape.rb
163
- - lib/kumi/core/functions/signature.rb
164
- - lib/kumi/core/functions/signature_parser.rb
165
- - lib/kumi/core/functions/signature_resolver.rb
166
149
  - lib/kumi/core/input/type_matcher.rb
167
150
  - lib/kumi/core/input/validator.rb
168
151
  - lib/kumi/core/input/violation_creator.rb
@@ -206,12 +189,6 @@ files:
206
189
  - lib/kumi/frontends.rb
207
190
  - lib/kumi/frontends/ruby.rb
208
191
  - lib/kumi/frontends/text.rb
209
- - lib/kumi/kernels/ruby/aggregate_core.rb
210
- - lib/kumi/kernels/ruby/datetime_scalar.rb
211
- - lib/kumi/kernels/ruby/mask_scalar.rb
212
- - lib/kumi/kernels/ruby/scalar_core.rb
213
- - lib/kumi/kernels/ruby/string_scalar.rb
214
- - lib/kumi/kernels/ruby/vector_struct.rb
215
192
  - lib/kumi/registry.rb
216
193
  - lib/kumi/runtime/executable.rb
217
194
  - lib/kumi/runtime/run.rb
data/BACKLOG.md DELETED
@@ -1,34 +0,0 @@
1
- # Kumi Development Backlog
2
-
3
- ## High Priority
4
-
5
- ### RegistryV2 Migration Cleanup
6
- - [ ] Remove legacy `lib/kumi/core/function_registry.rb` and related modules after RegistryV2 is fully integrated
7
- - [ ] Clean up bridge code in `FunctionSignaturePass` once all functions are migrated
8
- - [ ] Remove `create_basic_signature` fallback logic
9
- - [ ] Update all tests to use RegistryV2 functions
10
-
11
- ## Medium Priority
12
-
13
- ### Function Registry Enhancements
14
- - [ ] Add YAML linting for function definitions
15
- - [ ] Implement golden-IR test fixtures for signature resolution
16
- - [ ] Add Arrow/JS kernel mapping support
17
- - [ ] Implement type promotion rules from YAML dtypes
18
-
19
- ### Performance Optimizations
20
- - [ ] Cache RegistryV2 loading for repeated schema compilations
21
- - [ ] Optimize signature resolution for large function sets
22
- - [ ] Implement lazy loading of function kernels
23
-
24
- ## Low Priority
25
-
26
- ### Documentation
27
- - [ ] Auto-generate function reference docs from YAML
28
- - [ ] Add examples for each function in registry
29
- - [ ] Document kernel implementation guidelines
30
-
31
- ### Testing
32
- - [ ] Add comprehensive NEP-20 compliance test suite
33
- - [ ] Stress test RegistryV2 with large function sets
34
- - [ ] Add performance benchmarks for signature resolution
@@ -1,352 +0,0 @@
1
- # ==================== CORE - SCALAR (elementwise) ====================
2
-
3
- - name: core.add
4
- domain: core
5
- opset: 1
6
- class: scalar
7
- summary: Numeric addition with broadcasting
8
- signature: ["(),()->()", "(i),(i)->(i)", "(i,j),(i,j)->(i,j)"]
9
- type_vars: {T: Numeric, U: Numeric}
10
- dtypes: {result: "promote(T,U)", casting: "same_kind"}
11
- null_policy: propagate
12
- algebra: {associative: true, commutative: true, identity: 0}
13
- vectorization: {mask_aware: true}
14
- kernels:
15
- - backend: ruby
16
- impl: kumi_add
17
- priority: 10
18
-
19
- - name: core.sub
20
- domain: core
21
- opset: 1
22
- class: scalar
23
- signature: ["(),()->()", "(i),(i)->(i)", "(i,j),(i,j)->(i,j)"]
24
- type_vars: {T: Numeric, U: Numeric}
25
- dtypes: {result: "promote(T,U)", casting: "same_kind"}
26
- null_policy: propagate
27
- kernels:
28
- - backend: ruby
29
- impl: kumi_sub
30
- priority: 10
31
-
32
- - name: core.mul
33
- domain: core
34
- opset: 1
35
- class: scalar
36
- signature: ["(),()->()", "(i),(i)->(i)", "(i,j),(i,j)->(i,j)"]
37
- type_vars: {T: Numeric, U: Numeric}
38
- dtypes: {result: "promote(T,U)", casting: "same_kind"}
39
- null_policy: propagate
40
- algebra: {associative: true, commutative: true, identity: 1, annihilator: 0}
41
- kernels:
42
- - backend: ruby
43
- impl: kumi_mul
44
- priority: 10
45
-
46
- - name: core.div
47
- domain: core
48
- opset: 1
49
- class: scalar
50
- signature: ["(),()->()", "(i),(i)->(i)", "(i,j),(i,j)->(i,j)"]
51
- type_vars: {T: Numeric, U: Numeric}
52
- dtypes: {result: "promote_float(T,U)", casting: "same_kind"}
53
- null_policy: propagate
54
- kernels:
55
- - backend: ruby
56
- impl: kumi_div
57
- priority: 10
58
-
59
- - name: core.eq
60
- domain: core
61
- opset: 1
62
- class: scalar
63
- signature: ["(),()->()", "(i),(i)->(i)", "(i,j),(i,j)->(i,j)"]
64
- type_vars: {T: Any, U: Any}
65
- dtypes: {result: "bool"}
66
- null_policy: propagate
67
- algebra: {idempotent: true}
68
- kernels:
69
- - backend: ruby
70
- impl: kumi_eq
71
- priority: 10
72
-
73
- - name: core.gt
74
- domain: core
75
- opset: 1
76
- class: scalar
77
- signature: ["(),()->()", "(i),(i)->(i)"]
78
- type_vars: {T: Orderable, U: Orderable}
79
- dtypes: {result: "bool"}
80
- null_policy: propagate
81
- kernels:
82
- - backend: ruby
83
- impl: kumi_gt
84
- priority: 10
85
-
86
- - name: core.gte
87
- domain: core
88
- opset: 1
89
- class: scalar
90
- signature: ["(),()->()", "(i),(i)->(i)"]
91
- type_vars: {T: Orderable, U: Orderable}
92
- dtypes: {result: "bool"}
93
- null_policy: propagate
94
- kernels:
95
- - backend: ruby
96
- impl: kumi_gte
97
- priority: 10
98
-
99
- - name: core.and
100
- domain: core
101
- opset: 1
102
- class: scalar
103
- signature: ["(),()->()", "(i),(i)->(i)"]
104
- type_vars: {B1: Bool, B2: Bool}
105
- dtypes: {result: "bool"}
106
- null_policy: propagate
107
- algebra: {associative: true, commutative: true, identity: true, annihilator: false}
108
- vectorization: {short_circuit: left_to_right, mask_aware: true}
109
- kernels:
110
- - backend: ruby
111
- impl: kumi_and
112
- priority: 10
113
-
114
- - name: core.or
115
- domain: core
116
- opset: 1
117
- class: scalar
118
- signature: ["(),()->()", "(i),(i)->(i)"]
119
- type_vars: {B1: Bool, B2: Bool}
120
- dtypes: {result: "bool"}
121
- null_policy: propagate
122
- algebra: {associative: true, commutative: true, identity: false, annihilator: true}
123
- vectorization: {short_circuit: left_to_right, mask_aware: true}
124
- kernels:
125
- - backend: ruby
126
- impl: kumi_or
127
- priority: 10
128
-
129
- - name: core.not
130
- domain: core
131
- opset: 1
132
- class: scalar
133
- signature: ["()->()", "(i)->(i)"]
134
- type_vars: {B: Bool}
135
- dtypes: {result: "bool"}
136
- null_policy: propagate
137
- kernels:
138
- - backend: ruby
139
- impl: kumi_not
140
- priority: 10
141
-
142
- # ==================== AGGREGATES (reduce last axis in signature) ==============
143
-
144
- - name: agg.sum
145
- domain: core
146
- opset: 1
147
- class: aggregate
148
- signature: ["(i)->()", "(i,j)->(i)"]
149
- type_vars: {T: Numeric}
150
- dtypes: {result: "promote(T)"}
151
- null_policy: skip
152
- options: {min_count: 0}
153
- algebra: {associative: true, commutative: true, identity: 0}
154
- kernels:
155
- - backend: ruby
156
- impl: kumi_sum
157
- priority: 10
158
-
159
- - name: agg.min
160
- domain: core
161
- opset: 1
162
- class: aggregate
163
- signature: ["(i)->()", "(i,j)->(i)"]
164
- type_vars: {T: Orderable}
165
- dtypes: {result: "T"}
166
- null_policy: skip
167
- kernels:
168
- - backend: ruby
169
- impl: kumi_min
170
- priority: 10
171
-
172
- - name: agg.max
173
- domain: core
174
- opset: 1
175
- class: aggregate
176
- signature: ["(i)->()", "(i,j)->(i)"]
177
- type_vars: {T: Orderable}
178
- dtypes: {result: "T"}
179
- null_policy: skip
180
- kernels:
181
- - backend: ruby
182
- impl: kumi_max
183
- priority: 10
184
-
185
- - name: agg.mean
186
- domain: core
187
- opset: 1
188
- class: aggregate
189
- signature: ["(i)->()", "(i,j)->(i)"]
190
- type_vars: {T: Numeric}
191
- dtypes: {result: "float"}
192
- null_policy: skip
193
- options: {min_count: 0}
194
- kernels:
195
- - backend: ruby
196
- impl: kumi_mean
197
- priority: 10
198
-
199
- # ==================== STRUCTURE / SHAPE / JOIN ================================
200
-
201
- - name: struct.join
202
- domain: struct
203
- opset: 1
204
- class: structure
205
- summary: Align inputs by axes using zip or product
206
- signature: ["(i),(i)->(i)@zip", "(i),(j)->(i,j)@product"]
207
- null_policy: error_on_missing
208
- kernels:
209
- - backend: ruby
210
- impl: join_zip
211
- when: {policy: zip}
212
- priority: 10
213
- - backend: ruby
214
- impl: join_product
215
- when: {policy: product}
216
- priority: 10
217
-
218
- - name: struct.align_to
219
- domain: struct
220
- opset: 1
221
- class: structure
222
- signature: ["(i)->(i)", "(i,j)->(i,j)"]
223
- traits: {reorders: false}
224
- null_policy: error_on_missing
225
- kernels:
226
- - backend: ruby
227
- impl: align_to
228
- priority: 10
229
-
230
- - name: struct.lift
231
- domain: struct
232
- opset: 1
233
- class: structure
234
- signature: ["(i)->(i)", "(i,j)->(i,j)"]
235
- summary: Group flat rows back to nested collections based on indices
236
- kernels:
237
- - backend: ruby
238
- impl: lift
239
- priority: 10
240
-
241
- - name: struct.flatten
242
- domain: struct
243
- opset: 1
244
- class: structure
245
- signature: ["(i,j)->(k)"]
246
- shape_fn: "flatten_axes(i,j)->k"
247
- kernels:
248
- - backend: ruby
249
- impl: flatten
250
- priority: 10
251
-
252
- - name: struct.take
253
- domain: struct
254
- opset: 1
255
- class: structure
256
- signature: ["(i),(i)->(i)"] # take(values, indices) elemwise
257
- type_vars: {T: Any}
258
- dtypes: {result: "T"}
259
- null_policy: error
260
- kernels:
261
- - backend: ruby
262
- impl: take
263
- priority: 10
264
-
265
- - name: struct.size
266
- domain: struct
267
- opset: 1
268
- class: vector
269
- signature: ["(i)->()", "(i,j)->()"]
270
- dtypes: {result: "int"}
271
- null_policy: error
272
- kernels:
273
- - backend: ruby
274
- impl: size
275
- priority: 10
276
-
277
- # ==================== MASK / CONDITIONAL ======================================
278
-
279
- - name: mask.where
280
- domain: mask
281
- opset: 1
282
- class: scalar
283
- summary: Ternary select with broadcasting of then/else
284
- signature:
285
- - "(i),(i),(i)->(i)"
286
- - "(i),(),()->(i)"
287
- - "(),(i),()->(i)"
288
- - "(),(),()->()"
289
- type_vars: {B: Bool, T: Any, U: Any}
290
- dtypes: {result: "unify(T,U)"}
291
- null_policy: propagate
292
- vectorization: {mask_aware: true, short_circuit: left_to_right}
293
- kernels:
294
- - backend: ruby
295
- impl: where
296
- priority: 10
297
-
298
- # ==================== STRING (minimal) ========================================
299
-
300
- - name: string.concat
301
- domain: string
302
- opset: 1
303
- class: scalar
304
- signature: ["(),()->()", "(i),(i)->(i)"]
305
- type_vars: {S1: String, S2: String}
306
- dtypes: {result: "string"}
307
- null_policy: propagate
308
- kernels:
309
- - backend: ruby
310
- impl: str_concat
311
- priority: 10
312
-
313
- - name: string.length
314
- domain: string
315
- opset: 1
316
- class: vector
317
- signature: ["(i)->(i)", "()->()"]
318
- type_vars: {S: String}
319
- dtypes: {result: "int"}
320
- null_policy: propagate
321
- kernels:
322
- - backend: ruby
323
- impl: str_length
324
- priority: 10
325
-
326
- # ==================== DATETIME (minimal) ======================================
327
-
328
- - name: datetime.add_days
329
- domain: datetime
330
- opset: 1
331
- class: scalar
332
- signature: ["(),()->()", "(i),(i)->(i)"]
333
- type_vars: {D: DateLike, N: IntLike}
334
- dtypes: {result: "datetime"}
335
- null_policy: propagate
336
- kernels:
337
- - backend: ruby
338
- impl: dt_add_days
339
- priority: 10
340
-
341
- - name: datetime.diff_days
342
- domain: datetime
343
- opset: 1
344
- class: scalar
345
- signature: ["(),()->()", "(i),(i)->(i)"]
346
- type_vars: {D1: DateLike, D2: DateLike}
347
- dtypes: {result: "int"}
348
- null_policy: propagate
349
- kernels:
350
- - backend: ruby
351
- impl: dt_diff_days
352
- priority: 10
@@ -1,199 +0,0 @@
1
- # Function Signature Analysis Integration
2
-
3
- This document describes how NEP-20 function signatures integrate with Kumi's multi-pass analyzer architecture.
4
-
5
- ## Architecture Overview
6
-
7
- Function signature resolution is integrated into the analyzer pipeline through a node index system that allows passes to share metadata efficiently.
8
-
9
- ```
10
- ┌─────────────────┐ ┌──────────────────────┐ ┌────────────────────┐
11
- │ Toposorter │───▶│ FunctionSignaturePass │───▶│ LowerToIRPass │
12
- │ Creates node │ │ Resolves signatures │ │ Validates metadata │
13
- │ index by ID │ │ Attaches metadata │ │ Emits IR ops │
14
- └─────────────────┘ └──────────────────────┘ └────────────────────┘
15
- ```
16
-
17
- ## Node Index System
18
-
19
- ### Creation (Toposorter)
20
-
21
- The `Toposorter` pass creates a comprehensive index of all nodes in the AST:
22
-
23
- ```ruby
24
- # State structure after Toposorter
25
- state[:node_index] = {
26
- object_id_1 => {
27
- node: CallExpression_instance,
28
- type: "CallExpression",
29
- metadata: {}
30
- },
31
- # ... more nodes
32
- }
33
- ```
34
-
35
- ### Population (FunctionSignaturePass)
36
-
37
- The `FunctionSignaturePass` populates metadata for `CallExpression` nodes:
38
-
39
- ```ruby
40
- # After FunctionSignaturePass
41
- entry[:metadata] = {
42
- signature: Signature_object, # Full signature object
43
- result_axes: [:i, :j], # Output dimension names
44
- join_policy: :zip, # Cross-dimensional policy
45
- dropped_axes: [:k], # Dimensions eliminated by reductions
46
- effective_signature: { # Normalized for lowering
47
- in_shapes: [[:i, :k], [:k, :j]],
48
- out_shape: [:i, :j],
49
- join_policy: :zip
50
- },
51
- dim_env: { i: :i, j: :j, k: :k }, # Dimension variable bindings
52
- shape_contract: { # Simplified for lowering
53
- in: [[:i, :k], [:k, :j]],
54
- out: [:i, :j],
55
- join: :zip
56
- },
57
- signature_score: 0 # Match quality (0 = exact)
58
- }
59
- ```
60
-
61
- ### Consumption (LowerToIRPass)
62
-
63
- The lowering pass validates and uses the signature metadata:
64
-
65
- ```ruby
66
- def validate_signature_metadata(expr, entry)
67
- node_index = get_state(:node_index)
68
- metadata = node_index[expr.object_id][:metadata]
69
-
70
- # Validate dropped axes for reductions
71
- if entry&.reducer && metadata[:dropped_axes]
72
- # Assert axis exists in scope
73
- end
74
-
75
- # Warn about join policies not yet implemented
76
- if metadata[:join_policy]
77
- # Log warning or feature flag check
78
- end
79
- end
80
- ```
81
-
82
- ## Pass Integration Points
83
-
84
- ### 1. Signature Resolution
85
-
86
- **Location**: After `BroadcastDetector`, before `TypeChecker`
87
-
88
- **Purpose**: Resolve NEP-20 signatures for all function calls
89
-
90
- **Input**:
91
- - Node index from Toposorter
92
- - Broadcast metadata (optional)
93
- - Current function registry
94
-
95
- **Output**: Rich signature metadata attached to call nodes
96
-
97
- ### 2. Type Checking Enhancement
98
-
99
- **Integration**: `TypeChecker` can now use signature metadata for enhanced validation:
100
-
101
- ```ruby
102
- def validate_function_call(node, errors)
103
- # Get resolved signature metadata
104
- node_entry = node_index[node.object_id]
105
- if node_entry && node_entry[:metadata][:signature]
106
- # Use NEP-20 signature for validation
107
- validate_nep20_signature(node, node_entry[:metadata], errors)
108
- else
109
- # Fall back to legacy registry-based validation
110
- validate_legacy_signature(node, errors)
111
- end
112
- end
113
- ```
114
-
115
- ### 3. Lowering Integration
116
-
117
- **Integration**: `LowerToIRPass` validates signature consistency and emits appropriate IR:
118
-
119
- ```ruby
120
- when Syntax::CallExpression
121
- entry = Kumi::Registry.entry(expr.fn_name)
122
- validate_signature_metadata(expr, entry) # Read-only validation
123
-
124
- # Use shape contract for IR generation
125
- if node_entry = node_index[expr.object_id]
126
- contract = node_entry[:metadata][:shape_contract]
127
- # Use contract to emit appropriate reduce/join ops
128
- end
129
- ```
130
-
131
- ## Metadata Contract
132
-
133
- All passes can rely on this metadata structure for `CallExpression` nodes:
134
-
135
- | Field | Type | Description |
136
- |-------|------|-------------|
137
- | `:signature` | `Signature` | Full signature object with dimensions |
138
- | `:result_axes` | `Array<Symbol>` | Output dimension names |
139
- | `:join_policy` | `Symbol?` | `:zip`, `:product`, or `nil` |
140
- | `:dropped_axes` | `Array<Symbol>` | Dimensions eliminated (reductions) |
141
- | `:effective_signature` | `Hash` | Normalized signature for lowering |
142
- | `:dim_env` | `Hash` | Dimension variable bindings |
143
- | `:shape_contract` | `Hash` | Simplified contract for IR generation |
144
- | `:signature_score` | `Integer` | Match quality (0 = exact) |
145
-
146
- ## Error Handling
147
-
148
- Enhanced error messages include signature information:
149
-
150
- ```ruby
151
- # Before
152
- "operator `multiply` expects 2 args, got 3"
153
-
154
- # After
155
- "Signature mismatch for `multiply` with args (i,j), (k).
156
- Candidates: (),()->() | (i),(i)->(i).
157
- no matching signature for shapes (i,j), (k)"
158
- ```
159
-
160
- ## Feature Flags
161
-
162
- Control NEP-20 behavior at runtime:
163
-
164
- ```bash
165
- export KUMI_ENABLE_FLEX=1 # Enable flexible dimension matching (?)
166
- export KUMI_ENABLE_BCAST1=1 # Enable broadcastable matching (|1)
167
- ```
168
-
169
- ## Future Extensions
170
-
171
- The node index architecture supports future enhancements:
172
-
173
- ### Registry V2 Integration
174
- ```ruby
175
- # Read signatures from YAML registry
176
- signatures = RegistryV2.get_function_signatures(node.fn_name)
177
- ```
178
-
179
- ### Type System Integration
180
- ```ruby
181
- # Add dtype metadata alongside shape metadata
182
- metadata[:result_dtype] = infer_result_dtype(args, signature)
183
- ```
184
-
185
- ### Optimization Metadata
186
- ```ruby
187
- # Add optimization hints
188
- metadata[:can_vectorize] = true
189
- metadata[:memory_access_pattern] = :sequential
190
- ```
191
-
192
- ## Performance Considerations
193
-
194
- - **Node index creation**: O(n) where n = total AST nodes
195
- - **Signature resolution**: O(k*m) where k = signatures, m = arguments
196
- - **Memory overhead**: ~100 bytes per CallExpression node
197
- - **Pass integration**: Zero performance impact on existing passes
198
-
199
- The architecture is designed for extensibility while maintaining backward compatibility with the existing analyzer pipeline.