kumi 0.0.13 → 0.0.14

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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +0 -1
  3. data/BACKLOG.md +34 -0
  4. data/CLAUDE.md +4 -6
  5. data/README.md +0 -18
  6. data/config/functions.yaml +352 -0
  7. data/docs/dev/analyzer-debug.md +52 -0
  8. data/docs/dev/parse-command.md +64 -0
  9. data/docs/functions/analyzer_integration.md +199 -0
  10. data/docs/functions/signatures.md +171 -0
  11. data/examples/hash_objects_demo.rb +138 -0
  12. data/golden/array_operations/schema.kumi +17 -0
  13. data/golden/cascade_logic/schema.kumi +16 -0
  14. data/golden/mixed_nesting/schema.kumi +42 -0
  15. data/golden/simple_math/schema.kumi +10 -0
  16. data/lib/kumi/analyzer.rb +72 -21
  17. data/lib/kumi/core/analyzer/checkpoint.rb +72 -0
  18. data/lib/kumi/core/analyzer/debug.rb +167 -0
  19. data/lib/kumi/core/analyzer/passes/broadcast_detector.rb +1 -3
  20. data/lib/kumi/core/analyzer/passes/function_signature_pass.rb +199 -0
  21. data/lib/kumi/core/analyzer/passes/load_input_cse.rb +120 -0
  22. data/lib/kumi/core/analyzer/passes/lower_to_ir_pass.rb +72 -157
  23. data/lib/kumi/core/analyzer/passes/toposorter.rb +37 -1
  24. data/lib/kumi/core/analyzer/state_serde.rb +64 -0
  25. data/lib/kumi/core/analyzer/structs/access_plan.rb +12 -10
  26. data/lib/kumi/core/compiler/access_planner.rb +3 -2
  27. data/lib/kumi/core/function_registry/collection_functions.rb +3 -1
  28. data/lib/kumi/core/functions/dimension.rb +98 -0
  29. data/lib/kumi/core/functions/dtypes.rb +20 -0
  30. data/lib/kumi/core/functions/errors.rb +11 -0
  31. data/lib/kumi/core/functions/kernel_adapter.rb +45 -0
  32. data/lib/kumi/core/functions/loader.rb +119 -0
  33. data/lib/kumi/core/functions/registry_v2.rb +68 -0
  34. data/lib/kumi/core/functions/shape.rb +70 -0
  35. data/lib/kumi/core/functions/signature.rb +122 -0
  36. data/lib/kumi/core/functions/signature_parser.rb +86 -0
  37. data/lib/kumi/core/functions/signature_resolver.rb +272 -0
  38. data/lib/kumi/core/ir/execution_engine/interpreter.rb +98 -7
  39. data/lib/kumi/core/ir/execution_engine/profiler.rb +202 -0
  40. data/lib/kumi/dev/ir.rb +75 -0
  41. data/lib/kumi/dev/parse.rb +105 -0
  42. data/lib/kumi/dev/runner.rb +83 -0
  43. data/lib/kumi/frontends/ruby.rb +28 -0
  44. data/lib/kumi/frontends/text.rb +46 -0
  45. data/lib/kumi/frontends.rb +29 -0
  46. data/lib/kumi/kernels/ruby/aggregate_core.rb +105 -0
  47. data/lib/kumi/kernels/ruby/datetime_scalar.rb +21 -0
  48. data/lib/kumi/kernels/ruby/mask_scalar.rb +15 -0
  49. data/lib/kumi/kernels/ruby/scalar_core.rb +63 -0
  50. data/lib/kumi/kernels/ruby/string_scalar.rb +19 -0
  51. data/lib/kumi/kernels/ruby/vector_struct.rb +39 -0
  52. data/lib/kumi/runtime/executable.rb +57 -26
  53. data/lib/kumi/schema.rb +4 -4
  54. data/lib/kumi/support/diff.rb +22 -0
  55. data/lib/kumi/support/ir_render.rb +61 -0
  56. data/lib/kumi/version.rb +1 -1
  57. data/lib/kumi.rb +2 -0
  58. data/performance_results.txt +63 -0
  59. data/scripts/test_mixed_nesting_performance.rb +206 -0
  60. metadata +45 -5
  61. data/docs/features/javascript-transpiler.md +0 -148
  62. data/lib/kumi/js.rb +0 -23
  63. data/lib/kumi/support/ir_dump.rb +0 -491
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7af4bdb11ef5da5a25b799cef8387752636a8224634c70656efc203b9d923185
4
- data.tar.gz: 4e604513e42dcb8754fab54ead4140d5ca2d8443ae4d0461e62dc3b48bb925d4
3
+ metadata.gz: ec64db5a7b14df1a8656e2cedc569153a0f092d69a99544c5aa103241f61d931
4
+ data.tar.gz: 84bd4c7360eb74364e47103901fe8ccbcf6282a9cb40111d42b05357a2172c9e
5
5
  SHA512:
6
- metadata.gz: dcbd93268081ff8f0bcf112101603b180932196b1d6fcb59aae2f363d6bbfe4e9ea07cf3cbe811290222dcd15cdf132ea04f409bea34f81599412f729211a5fa
7
- data.tar.gz: 3e0c2e91609e742c2852457b2dd61a114a03b988ae983e0cfb23c9bbf46bc5c6c1714636961ed46b4b9ae924c6a77a79dc0aab9013cadbb73e49d5374f8b8dbc
6
+ metadata.gz: da7a9f3135e63779676ea5a802f48288ff2675935ab8dd8dcc751aaf309392275589f08fb92fede4dce351707369b5113e28540e5f4853629a02f4a1945ca75a
7
+ data.tar.gz: 5a45952056f81d9b4551bc7b48d3fd35c25065eb058e3cd6737879377a5c6e5f61d1cbba5b51955f54ad6ca14a797254e3381c69cd6b9eb145f3929e6e962dae
data/.rspec CHANGED
@@ -1,3 +1,2 @@
1
- --format documentation
2
1
  --color
3
2
  --require spec_helper
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/CLAUDE.md CHANGED
@@ -1,11 +1,9 @@
1
1
  # CLAUDE.md
2
2
 
3
- !! Important:
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
- !! Disregard linting or coverage issues unless asked to do so.
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
@@ -436,24 +436,6 @@ runner[:after_tax] # => 196,844.80 (cached)
436
436
  - Sequential procedural workflows
437
437
  - High-frequency processing
438
438
 
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
439
  ## Performance
458
440
 
459
441
  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
+ ```