kumi 0.0.13 → 0.0.15
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/.rspec +0 -1
- data/BACKLOG.md +34 -0
- data/CHANGELOG.md +33 -0
- data/CLAUDE.md +4 -6
- data/README.md +0 -45
- data/config/functions.yaml +352 -0
- data/docs/dev/analyzer-debug.md +52 -0
- data/docs/dev/parse-command.md +64 -0
- data/docs/dev/vm-profiling.md +95 -0
- data/docs/features/README.md +0 -7
- data/docs/functions/analyzer_integration.md +199 -0
- data/docs/functions/signatures.md +171 -0
- data/examples/hash_objects_demo.rb +138 -0
- data/golden/array_operations/schema.kumi +17 -0
- data/golden/cascade_logic/schema.kumi +16 -0
- data/golden/mixed_nesting/schema.kumi +42 -0
- data/golden/simple_math/schema.kumi +10 -0
- data/lib/kumi/analyzer.rb +76 -22
- data/lib/kumi/compiler.rb +6 -5
- data/lib/kumi/core/analyzer/checkpoint.rb +72 -0
- data/lib/kumi/core/analyzer/debug.rb +167 -0
- data/lib/kumi/core/analyzer/passes/broadcast_detector.rb +1 -3
- data/lib/kumi/core/analyzer/passes/function_signature_pass.rb +199 -0
- data/lib/kumi/core/analyzer/passes/ir_dependency_pass.rb +67 -0
- data/lib/kumi/core/analyzer/passes/load_input_cse.rb +120 -0
- data/lib/kumi/core/analyzer/passes/lower_to_ir_pass.rb +72 -157
- data/lib/kumi/core/analyzer/passes/toposorter.rb +40 -36
- data/lib/kumi/core/analyzer/state_serde.rb +64 -0
- data/lib/kumi/core/analyzer/structs/access_plan.rb +12 -10
- data/lib/kumi/core/compiler/access_planner.rb +3 -2
- data/lib/kumi/core/function_registry/collection_functions.rb +3 -1
- data/lib/kumi/core/functions/dimension.rb +98 -0
- data/lib/kumi/core/functions/dtypes.rb +20 -0
- data/lib/kumi/core/functions/errors.rb +11 -0
- data/lib/kumi/core/functions/kernel_adapter.rb +45 -0
- data/lib/kumi/core/functions/loader.rb +119 -0
- data/lib/kumi/core/functions/registry_v2.rb +68 -0
- data/lib/kumi/core/functions/shape.rb +70 -0
- data/lib/kumi/core/functions/signature.rb +122 -0
- data/lib/kumi/core/functions/signature_parser.rb +86 -0
- data/lib/kumi/core/functions/signature_resolver.rb +272 -0
- data/lib/kumi/core/ir/execution_engine/interpreter.rb +110 -7
- data/lib/kumi/core/ir/execution_engine/profiler.rb +330 -0
- data/lib/kumi/core/ir/execution_engine.rb +6 -15
- data/lib/kumi/dev/ir.rb +75 -0
- data/lib/kumi/dev/parse.rb +105 -0
- data/lib/kumi/dev/profile_aggregator.rb +301 -0
- data/lib/kumi/dev/profile_runner.rb +199 -0
- data/lib/kumi/dev/runner.rb +85 -0
- data/lib/kumi/dev.rb +14 -0
- data/lib/kumi/frontends/ruby.rb +28 -0
- data/lib/kumi/frontends/text.rb +46 -0
- data/lib/kumi/frontends.rb +29 -0
- data/lib/kumi/kernels/ruby/aggregate_core.rb +105 -0
- data/lib/kumi/kernels/ruby/datetime_scalar.rb +21 -0
- data/lib/kumi/kernels/ruby/mask_scalar.rb +15 -0
- data/lib/kumi/kernels/ruby/scalar_core.rb +63 -0
- data/lib/kumi/kernels/ruby/string_scalar.rb +19 -0
- data/lib/kumi/kernels/ruby/vector_struct.rb +39 -0
- data/lib/kumi/runtime/executable.rb +108 -45
- data/lib/kumi/schema.rb +12 -6
- data/lib/kumi/support/diff.rb +22 -0
- data/lib/kumi/support/ir_render.rb +61 -0
- data/lib/kumi/version.rb +1 -1
- data/lib/kumi.rb +3 -0
- data/performance_results.txt +63 -0
- data/scripts/test_mixed_nesting_performance.rb +206 -0
- metadata +50 -6
- data/docs/features/analysis-cascade-mutual-exclusion.md +0 -89
- data/docs/features/javascript-transpiler.md +0 -148
- data/lib/kumi/js.rb +0 -23
- data/lib/kumi/support/ir_dump.rb +0 -491
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5405d7d0612a81e5154bd1d452fdfc150691b022137fc0ee132c47ede1a58e2e
|
4
|
+
data.tar.gz: '093cf7a6d305c02f92de600b06f62be39f8af90d798a0f93ed3ef59f539ada9b'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b3ea711bf465e0c11cc95fabb3809dd632ebbfcc8c36297b161fb1f179fffdda5df1e5c033968e837dd8ed3f983639416de08bd371f30be9f2cefd5543efe1ff
|
7
|
+
data.tar.gz: 0a63fe824fb604639b4efb9cfc2ce24a93429110adc75cfd3edc905c58b3501273ad07a3cf66415eabce4e099c5fd4d202bd2c4064875d7a73e0c2a26f0689cb
|
data/.rspec
CHANGED
data/BACKLOG.md
ADDED
@@ -0,0 +1,34 @@
|
|
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
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,38 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.0.15] – 2025-08-21
|
4
|
+
### Added
|
5
|
+
- (DX) Schema-aware VM profiling with multi-schema performance analysis
|
6
|
+
- DAG-based execution optimization with pre-computed dependency resolution
|
7
|
+
|
8
|
+
### Performance
|
9
|
+
- Reference operations eliminated as VM bottleneck via O(1) hash lookups
|
10
|
+
|
11
|
+
## [0.0.14] – 2025-08-21
|
12
|
+
### Added
|
13
|
+
- Text schema frontend with `.kumi` file format support
|
14
|
+
- `bin/kumi parse` command for schema analysis and golden file testing
|
15
|
+
- LoadInputCSE optimization pass to eliminate redundant load operations
|
16
|
+
- Runtime accessor caching with precise field-based invalidation
|
17
|
+
- VM profiler with wall time, CPU time, and cache hit rate analysis
|
18
|
+
- Structured analyzer debug system with state inspection
|
19
|
+
- Checkpoint system for capturing and comparing analyzer states
|
20
|
+
- State serialization (StateSerde) for golden testing and regression detection
|
21
|
+
- Debug object printers with configurable truncation
|
22
|
+
- Multi-run averaging for stable performance benchmarking
|
23
|
+
|
24
|
+
### Fixed
|
25
|
+
- VM targeting for `__vec` twin declarations that were failing to resolve
|
26
|
+
- Demand-driven reference resolution with proper name indexing and cycle detection
|
27
|
+
- Accessor cache invalidation now uses precise field dependencies instead of clearing all caches
|
28
|
+
- StateSerde JSON serialization issues with frozen hashes, Sets, and Symbols
|
29
|
+
|
30
|
+
### Performance
|
31
|
+
- 14x improvement on update-heavy workloads (1.88k → 26.88k iterations/second)
|
32
|
+
- 30-40% reduction in IR module size for schemas with repeated field access
|
33
|
+
- Eliminated load_input performance bottleneck that was consuming ~99% of execution time
|
34
|
+
- Optional caching system (enabled via KUMI_VM_CACHE=1) for performance-critical scenarios
|
35
|
+
|
3
36
|
## [0.0.13] – 2025-08-14
|
4
37
|
### Added
|
5
38
|
- Runtime performance optimizations for interpreter execution
|
data/CLAUDE.md
CHANGED
@@ -1,11 +1,9 @@
|
|
1
1
|
# CLAUDE.md
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
!! Communication style - Write direct, factual statements. Avoid promotional language, unnecessary claims, or marketing speak. State what the system does, not what benefits it provides. Use TODOs for missing information rather than placeholder claims.
|
8
|
-
!! See all Available Functions in docs/FUNCTIONS.md
|
3
|
+
IMPORTANT!: Use `kumi parse` to see IR or Analysis States Diff - see docs/dev/parse-command.md
|
4
|
+
Remember, this gem is not on production yet, so no backward compatilibity is necessary. But do not change the public interfaces (e.g. DSL, Schema) without explicitly requested or demanded.
|
5
|
+
We are using zeitwerk, i.e.: no requires
|
6
|
+
See all Available Functions in docs/FUNCTIONS.md
|
9
7
|
|
10
8
|
## Project Overview
|
11
9
|
|
data/README.md
CHANGED
@@ -207,33 +207,6 @@ end
|
|
207
207
|
# ❌ Function arity error: divide expects 2 arguments, got 1
|
208
208
|
```
|
209
209
|
|
210
|
-
**Mutual Recursion**: Kumi supports mutual recursion when cascade conditions are mutually exclusive:
|
211
|
-
|
212
|
-
```ruby
|
213
|
-
trait :is_forward, input.operation == "forward"
|
214
|
-
trait :is_reverse, input.operation == "reverse"
|
215
|
-
|
216
|
-
# Safe mutual recursion - conditions are mutually exclusive
|
217
|
-
value :forward_processor do
|
218
|
-
on is_forward, input.value * 2 # Direct calculation
|
219
|
-
on is_reverse, reveAnalysisrse_processor + 10 # Delegates to reverse (safe)
|
220
|
-
base "invalid operation"
|
221
|
-
end
|
222
|
-
|
223
|
-
value :reverse_processor do
|
224
|
-
on is_forward, forward_processor - 5 # Delegates to forward (safe)
|
225
|
-
on is_reverse, input.value / 2 # Direct calculation
|
226
|
-
base "invalid operation"
|
227
|
-
end
|
228
|
-
|
229
|
-
# Usage examples:
|
230
|
-
# operation="forward", value=10 => forward: 20, reverse: 15
|
231
|
-
# operation="reverse", value=10 => forward: 15, reverse: 5
|
232
|
-
# operation="unknown", value=10 => both: "invalid operation"
|
233
|
-
```
|
234
|
-
|
235
|
-
This compiles because `operation` can only be "forward" or "reverse", never both. Each recursion executes one step before hitting a direct calculation.
|
236
|
-
|
237
210
|
#### **Runtime Introspection: Debug and Understand**
|
238
211
|
|
239
212
|
**Explainability**: Trace exactly how any value is computed, step-by-step. This is invaluable for debugging complex logic and auditing results.
|
@@ -436,24 +409,6 @@ runner[:after_tax] # => 196,844.80 (cached)
|
|
436
409
|
- Sequential procedural workflows
|
437
410
|
- High-frequency processing
|
438
411
|
|
439
|
-
## JavaScript Transpiler (V 0.0.10)
|
440
|
-
Note: On the current 0.0.11 this is disabled but will be back in later versions. reason: IR/Interpreter update.
|
441
|
-
Transpiles compiled schemas to standalone JavaScript code. See [docs/features/javascript-transpiler.md](docs/features/javascript-transpiler.md) for details.
|
442
|
-
|
443
|
-
```ruby
|
444
|
-
Kumi::Js.export_to_file(FederalTax2024, "federal-tax-2024.js")
|
445
|
-
```
|
446
|
-
|
447
|
-
```javascript
|
448
|
-
const { schema } = require('./federal-tax-2024.js');
|
449
|
-
const calculator = schema.from({ income: 100_000, filing_status: "single" });
|
450
|
-
console.log(calculator.fetch('total_tax')); // 21491
|
451
|
-
```
|
452
|
-
|
453
|
-
Generated JavaScript includes only functions used by the schema.
|
454
|
-
|
455
|
-
All tests run in dual mode to verify compiled schemas produce identical results in both Ruby and JavaScript.
|
456
|
-
|
457
412
|
## Performance
|
458
413
|
|
459
414
|
Benchmarks on Linux with Ruby 3.3.8 on a Dell Latitude 7450:
|
@@ -0,0 +1,352 @@
|
|
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
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# Analyzer Debug System
|
2
|
+
|
3
|
+
## Debug Module
|
4
|
+
|
5
|
+
**File**: `lib/kumi/core/analyzer/debug.rb`
|
6
|
+
|
7
|
+
**Enable**: `KUMI_DEBUG_STATE=1`
|
8
|
+
|
9
|
+
**Output**: JSONL to stdout with state diffs and timing per pass
|
10
|
+
|
11
|
+
**Configuration**:
|
12
|
+
- `KUMI_DEBUG_REQUIRE_FROZEN=1` - Enforce state immutability checks
|
13
|
+
|
14
|
+
## Checkpoint System
|
15
|
+
|
16
|
+
**Files**:
|
17
|
+
- `lib/kumi/core/analyzer/checkpoint.rb`
|
18
|
+
- `lib/kumi/core/analyzer/state_serde.rb`
|
19
|
+
|
20
|
+
**Enable**: `KUMI_CHECKPOINT=1`
|
21
|
+
|
22
|
+
**Configuration**:
|
23
|
+
- `KUMI_CHECKPOINT_DIR=path` - Output directory (default: `/tmp/kumi_checkpoints`)
|
24
|
+
- `KUMI_CHECKPOINT_FORMAT=marshal|json|both` - File format (default: `marshal`)
|
25
|
+
- `KUMI_CHECKPOINT_PHASE=before|after|both` - When to save (default: `both`)
|
26
|
+
|
27
|
+
**Resume/Stop**:
|
28
|
+
- `KUMI_RESUME_FROM=file.msh` - Resume from checkpoint file
|
29
|
+
- `KUMI_RESUME_AT=PassName` - Skip to specific pass
|
30
|
+
- `KUMI_STOP_AFTER=PassName` - Stop after specific pass
|
31
|
+
|
32
|
+
## Object Printers
|
33
|
+
|
34
|
+
**File**: `spec/support/debug_printers.rb`
|
35
|
+
|
36
|
+
Handles clean output for debug logs. Add new object types here when they appear as `#<Object:0x...>` in debug output.
|
37
|
+
|
38
|
+
## Usage
|
39
|
+
|
40
|
+
```bash
|
41
|
+
# Basic debug
|
42
|
+
KUMI_DEBUG_STATE=1 bundle exec ruby script.rb
|
43
|
+
|
44
|
+
# Debug with checkpoints
|
45
|
+
KUMI_DEBUG_STATE=1 KUMI_CHECKPOINT=1 bundle exec ruby script.rb
|
46
|
+
|
47
|
+
# Resume from checkpoint
|
48
|
+
KUMI_RESUME_FROM=/tmp/kumi_checkpoints/005_TypeChecker_after.msh bundle exec ruby script.rb
|
49
|
+
|
50
|
+
# Stop at specific pass for debugging
|
51
|
+
KUMI_STOP_AFTER=BroadcastDetector bundle exec ruby script.rb
|
52
|
+
```
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# Parse Command
|
2
|
+
|
3
|
+
One-command developer loop for text schemas: parse → analyze → render IR → diff.
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
```bash
|
8
|
+
# Default: show diff vs golden file (or print if no golden)
|
9
|
+
kumi parse golden/simple_math/schema.kumi
|
10
|
+
|
11
|
+
# Write/overwrite golden file
|
12
|
+
kumi parse golden/simple_math/schema.kumi --write
|
13
|
+
|
14
|
+
# Update golden only if different
|
15
|
+
kumi parse golden/simple_math/schema.kumi --update
|
16
|
+
|
17
|
+
# JSON format instead of text
|
18
|
+
kumi parse golden/simple_math/schema.kumi --json --write
|
19
|
+
|
20
|
+
# Enable state tracing
|
21
|
+
kumi parse golden/simple_math/schema.kumi --trace
|
22
|
+
|
23
|
+
# Snapshot analysis passes
|
24
|
+
kumi parse golden/simple_math/schema.kumi --snap after --snap-dir debug/
|
25
|
+
```
|
26
|
+
|
27
|
+
## Exit Codes
|
28
|
+
|
29
|
+
- `0` - No changes or successful write
|
30
|
+
- `1` - Diff mismatch or analysis error
|
31
|
+
|
32
|
+
## Output
|
33
|
+
|
34
|
+
**No changes:**
|
35
|
+
```
|
36
|
+
No changes (golden/simple_math/expected/ir.txt)
|
37
|
+
```
|
38
|
+
|
39
|
+
**Diff mismatch:**
|
40
|
+
```
|
41
|
+
--- expected
|
42
|
+
+++ actual
|
43
|
+
@@ -6,7 +6,7 @@
|
44
|
+
2: map argc=2 fn=:add [0, 1]
|
45
|
+
+ 2: map argc=2 fn=:power [0, 1]
|
46
|
+
```
|
47
|
+
|
48
|
+
**Write mode:**
|
49
|
+
```
|
50
|
+
Wrote: golden/simple_math/expected/ir.txt
|
51
|
+
```
|
52
|
+
|
53
|
+
## IR Format
|
54
|
+
|
55
|
+
Deterministic text representation:
|
56
|
+
```
|
57
|
+
IR Module
|
58
|
+
decls: 3
|
59
|
+
decl[0] value:sum shape=scalar ops=4
|
60
|
+
0: load_input has_idx=false is_scalar=true plan_id=x:read scope=[] []
|
61
|
+
1: load_input has_idx=false is_scalar=true plan_id=y:read scope=[] []
|
62
|
+
2: map argc=2 fn=:add [0, 1]
|
63
|
+
3: store name=:sum [2]
|
64
|
+
```
|