kumi 0.0.37 → 0.1.0
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/.rubocop.yml +39 -58
- data/.rubocop_todo.yml +931 -0
- data/CHANGELOG.md +37 -0
- data/README.md +3 -0
- data/data/functions/core/arithmetic.yaml +48 -0
- data/data/functions/core/conversion.yaml +13 -0
- data/data/functions/core/select.yaml +1 -1
- data/data/functions/core/stencil.yaml +32 -0
- data/data/kernels/javascript/agg/numeric.yaml +1 -0
- data/data/kernels/javascript/core/arithmetic.yaml +24 -0
- data/data/kernels/javascript/core/coercion.yaml +18 -4
- data/data/kernels/ruby/agg/numeric.yaml +2 -1
- data/data/kernels/ruby/core/arithmetic.yaml +31 -3
- data/data/kernels/ruby/core/coercion.yaml +8 -0
- data/docs/CROSS_TARGET_SEMANTICS.md +99 -0
- data/docs/FORM_SCHEMA.md +13 -8
- data/docs/FUNCTIONS.md +120 -13
- data/docs/INPUTS.md +164 -0
- data/docs/OUTPUT_SCHEMA.md +12 -8
- data/docs/PASSES.md +76 -0
- data/docs/PASS_AUDIT.md +179 -0
- data/docs/PORTAL.md +39 -0
- data/docs/SYNTAX.md +84 -121
- data/docs/SYNTAX_NOTES.md +612 -0
- data/docs/UNSAT_DETECTION.md +2 -2
- data/docs/functions-reference.json +276 -84
- data/docs/pairwise-design.md +125 -0
- data/docs/superpowers/plans/2026-06-12-pass-conventions-and-dedup.md +1559 -0
- data/docs/superpowers/specs/2026-06-12-pass-conventions-and-dedup-design.md +136 -0
- data/golden/algebraic_identities/expected/ast.txt +66 -0
- data/golden/algebraic_identities/expected/dfir.txt +47 -0
- data/golden/algebraic_identities/expected/dfir_optimized.txt +59 -0
- data/golden/algebraic_identities/expected/input_plan.txt +7 -0
- data/golden/algebraic_identities/expected/loopir.txt +61 -0
- data/golden/algebraic_identities/expected/nast.txt +51 -0
- data/golden/algebraic_identities/expected/runtime.json +24 -0
- data/golden/algebraic_identities/expected/schema_javascript.mjs +89 -0
- data/golden/algebraic_identities/expected/schema_ruby.rb +84 -0
- data/golden/algebraic_identities/expected/snast.txt +51 -0
- data/golden/algebraic_identities/expected/vecir.txt +47 -0
- data/golden/algebraic_identities/input.json +6 -0
- data/golden/algebraic_identities/schema.kumi +25 -0
- data/golden/array_element/expected/loopir.txt +1 -2
- data/golden/array_element/expected/runtime.json +5 -0
- data/golden/array_element/expected/schema_javascript.mjs +1 -2
- data/golden/array_element/expected/schema_ruby.rb +2 -3
- data/golden/array_index/expected/runtime.json +54 -0
- data/golden/array_index/expected/schema_ruby.rb +1 -1
- data/golden/array_operations/{expected.json → expected/runtime.json} +5 -15
- data/golden/array_operations/expected/schema_ruby.rb +1 -1
- data/golden/cascade_logic/expected/runtime.json +3 -0
- data/golden/cascade_logic/expected/schema_ruby.rb +1 -1
- data/golden/cascade_reuse_peephole/expected/ast.txt +193 -0
- data/golden/cascade_reuse_peephole/expected/dfir.txt +124 -0
- data/golden/cascade_reuse_peephole/expected/dfir_optimized.txt +320 -0
- data/golden/cascade_reuse_peephole/expected/input_plan.txt +2 -0
- data/golden/cascade_reuse_peephole/expected/loopir.txt +302 -0
- data/golden/cascade_reuse_peephole/expected/nast.txt +188 -0
- data/golden/cascade_reuse_peephole/expected/runtime.json +8 -0
- data/golden/cascade_reuse_peephole/expected/schema_javascript.mjs +335 -0
- data/golden/cascade_reuse_peephole/expected/schema_ruby.rb +337 -0
- data/golden/cascade_reuse_peephole/expected/snast.txt +188 -0
- data/golden/cascade_reuse_peephole/expected/vecir.txt +302 -0
- data/golden/cascade_reuse_peephole/input.json +4 -0
- data/golden/cascade_reuse_peephole/schema.kumi +31 -0
- data/golden/chained_fusion/expected/loopir.txt +5 -13
- data/golden/chained_fusion/expected/runtime.json +45 -0
- data/golden/chained_fusion/expected/schema_javascript.mjs +5 -13
- data/golden/chained_fusion/expected/schema_ruby.rb +6 -14
- data/golden/cross_import/expected/ast.txt +21 -0
- data/golden/cross_import/expected/dfir.txt +3 -0
- data/golden/cross_import/expected/dfir_optimized.txt +8 -0
- data/golden/cross_import/expected/input_plan.txt +5 -0
- data/golden/cross_import/expected/loopir.txt +14 -0
- data/golden/cross_import/expected/nast.txt +7 -0
- data/golden/cross_import/expected/runtime.json +10 -0
- data/golden/cross_import/expected/schema_javascript.mjs +19 -0
- data/golden/cross_import/expected/schema_ruby.rb +19 -0
- data/golden/cross_import/expected/snast.txt +7 -0
- data/golden/cross_import/expected/vecir.txt +8 -0
- data/golden/cross_import/input.json +1 -0
- data/golden/cross_import/schema.kumi +15 -0
- data/golden/cross_let/expected/ast.txt +62 -0
- data/golden/cross_let/expected/dfir.txt +35 -0
- data/golden/cross_let/expected/dfir_optimized.txt +51 -0
- data/golden/cross_let/expected/input_plan.txt +5 -0
- data/golden/cross_let/expected/loopir.txt +100 -0
- data/golden/cross_let/expected/nast.txt +46 -0
- data/golden/cross_let/expected/runtime.json +61 -0
- data/golden/cross_let/expected/schema_javascript.mjs +136 -0
- data/golden/cross_let/expected/schema_ruby.rb +123 -0
- data/golden/cross_let/expected/snast.txt +46 -0
- data/golden/cross_let/expected/vecir.txt +51 -0
- data/golden/cross_let/input.json +7 -0
- data/golden/cross_let/schema.kumi +25 -0
- data/golden/decimal_explicit/expected/dfir.txt +6 -6
- data/golden/decimal_explicit/expected/dfir_optimized.txt +6 -6
- data/golden/decimal_explicit/expected/loopir.txt +6 -6
- data/golden/decimal_explicit/expected/runtime.json +10 -0
- data/golden/decimal_explicit/expected/schema_ruby.rb +1 -1
- data/golden/decimal_explicit/expected/snast.txt +9 -9
- data/golden/decimal_explicit/expected/vecir.txt +6 -6
- data/golden/element_arrays/expected/loopir.txt +6 -13
- data/golden/element_arrays/expected/runtime.json +117 -0
- data/golden/element_arrays/expected/schema_javascript.mjs +7 -14
- data/golden/element_arrays/expected/schema_ruby.rb +8 -15
- data/golden/empty_and_null_inputs/expected/loopir.txt +4 -9
- data/golden/empty_and_null_inputs/expected/runtime.json +8 -0
- data/golden/empty_and_null_inputs/expected/schema_javascript.mjs +5 -10
- data/golden/empty_and_null_inputs/expected/schema_ruby.rb +6 -11
- data/golden/example_xpto/expected/runtime.json +4 -0
- data/golden/example_xpto/expected/schema_ruby.rb +1 -1
- data/golden/function_overload/expected/runtime.json +8 -0
- data/golden/function_overload/expected/schema_ruby.rb +1 -1
- data/golden/game_of_life/expected/loopir.txt +1 -58
- data/golden/game_of_life/expected/runtime.json +418 -0
- data/golden/game_of_life/expected/schema_javascript.mjs +1 -58
- data/golden/game_of_life/expected/schema_ruby.rb +2 -59
- data/golden/hash_keys/expected/runtime.json +20 -0
- data/golden/hash_keys/expected/schema_ruby.rb +1 -1
- data/golden/hash_value/expected/runtime.json +19 -0
- data/golden/hash_value/expected/schema_ruby.rb +1 -1
- data/golden/hierarchical_complex/expected/loopir.txt +0 -4
- data/golden/hierarchical_complex/expected/runtime.json +16 -0
- data/golden/hierarchical_complex/expected/schema_javascript.mjs +0 -4
- data/golden/hierarchical_complex/expected/schema_ruby.rb +1 -5
- data/golden/inline_rename_scope_leak/expected/loopir.txt +1 -5
- data/golden/inline_rename_scope_leak/expected/runtime.json +10 -0
- data/golden/inline_rename_scope_leak/expected/schema_javascript.mjs +3 -7
- data/golden/inline_rename_scope_leak/expected/schema_ruby.rb +4 -8
- data/golden/input_reference/expected/dfir.txt +2 -2
- data/golden/input_reference/expected/dfir_optimized.txt +2 -2
- data/golden/input_reference/expected/loopir.txt +2 -5
- data/golden/input_reference/expected/runtime.json +15 -0
- data/golden/input_reference/expected/schema_javascript.mjs +3 -6
- data/golden/input_reference/expected/schema_ruby.rb +4 -7
- data/golden/input_reference/expected/snast.txt +1 -1
- data/golden/input_reference/expected/vecir.txt +2 -2
- data/golden/interleaved_fusion/expected/loopir.txt +5 -10
- data/golden/interleaved_fusion/expected/runtime.json +37 -0
- data/golden/interleaved_fusion/expected/schema_javascript.mjs +5 -10
- data/golden/interleaved_fusion/expected/schema_ruby.rb +6 -11
- data/golden/let_inline/expected/runtime.json +6 -0
- data/golden/let_inline/expected/schema_ruby.rb +2 -2
- data/golden/loop_fusion/expected/loopir.txt +3 -7
- data/golden/loop_fusion/expected/runtime.json +29 -0
- data/golden/loop_fusion/expected/schema_javascript.mjs +3 -7
- data/golden/loop_fusion/expected/schema_ruby.rb +4 -8
- data/golden/min_max_empty_arrays/expected/loopir.txt +5 -12
- data/golden/min_max_empty_arrays/expected/runtime.json +16 -0
- data/golden/min_max_empty_arrays/expected/schema_javascript.mjs +7 -14
- data/golden/min_max_empty_arrays/expected/schema_ruby.rb +10 -17
- data/golden/min_reduce_scope/expected/loopir.txt +3 -7
- data/golden/min_reduce_scope/expected/runtime.json +11 -0
- data/golden/min_reduce_scope/expected/schema_javascript.mjs +4 -8
- data/golden/min_reduce_scope/expected/schema_ruby.rb +5 -9
- data/golden/mixed_dimensions/expected/loopir.txt +2 -5
- data/golden/mixed_dimensions/expected/runtime.json +34 -0
- data/golden/mixed_dimensions/expected/schema_javascript.mjs +3 -6
- data/golden/mixed_dimensions/expected/schema_ruby.rb +4 -7
- data/golden/mlp_backprop/expected/ast.txt +147 -0
- data/golden/mlp_backprop/expected/dfir.txt +99 -0
- data/golden/mlp_backprop/expected/dfir_optimized.txt +374 -0
- data/golden/mlp_backprop/expected/input_plan.txt +17 -0
- data/golden/mlp_backprop/expected/loopir.txt +440 -0
- data/golden/mlp_backprop/expected/nast.txt +120 -0
- data/golden/mlp_backprop/expected/runtime.json +43 -0
- data/golden/mlp_backprop/expected/schema_javascript.mjs +516 -0
- data/golden/mlp_backprop/expected/schema_ruby.rb +484 -0
- data/golden/mlp_backprop/expected/snast.txt +120 -0
- data/golden/mlp_backprop/expected/vecir.txt +374 -0
- data/golden/mlp_backprop/input.json +8 -0
- data/golden/mlp_backprop/schema.kumi +43 -0
- data/golden/multi_loop_reduction/expected/loopir.txt +2 -6
- data/golden/multi_loop_reduction/expected/runtime.json +5 -0
- data/golden/multi_loop_reduction/expected/schema_javascript.mjs +4 -8
- data/golden/multi_loop_reduction/expected/schema_ruby.rb +5 -9
- data/golden/multirank_hoisting/expected/loopir.txt +24 -42
- data/golden/multirank_hoisting/expected/runtime.json +47 -0
- data/golden/multirank_hoisting/expected/schema_javascript.mjs +24 -45
- data/golden/multirank_hoisting/expected/schema_ruby.rb +25 -43
- data/golden/nested_hash/expected/runtime.json +3 -0
- data/golden/nested_hash/expected/schema_ruby.rb +1 -1
- data/golden/outer_let/expected/ast.txt +106 -0
- data/golden/outer_let/expected/dfir.txt +66 -0
- data/golden/outer_let/expected/dfir_optimized.txt +145 -0
- data/golden/outer_let/expected/input_plan.txt +19 -0
- data/golden/outer_let/expected/loopir.txt +166 -0
- data/golden/outer_let/expected/nast.txt +78 -0
- data/golden/outer_let/expected/runtime.json +89 -0
- data/golden/outer_let/expected/schema_javascript.mjs +220 -0
- data/golden/outer_let/expected/schema_ruby.rb +201 -0
- data/golden/outer_let/expected/snast.txt +78 -0
- data/golden/outer_let/expected/vecir.txt +145 -0
- data/golden/outer_let/input.json +9 -0
- data/golden/outer_let/schema.kumi +32 -0
- data/golden/pairwise_cross/expected/ast.txt +62 -0
- data/golden/pairwise_cross/expected/dfir.txt +36 -0
- data/golden/pairwise_cross/expected/dfir_optimized.txt +50 -0
- data/golden/pairwise_cross/expected/input_plan.txt +8 -0
- data/golden/pairwise_cross/expected/loopir.txt +84 -0
- data/golden/pairwise_cross/expected/nast.txt +46 -0
- data/golden/pairwise_cross/expected/runtime.json +80 -0
- data/golden/pairwise_cross/expected/schema_javascript.mjs +113 -0
- data/golden/pairwise_cross/expected/schema_ruby.rb +104 -0
- data/golden/pairwise_cross/expected/snast.txt +46 -0
- data/golden/pairwise_cross/expected/vecir.txt +50 -0
- data/golden/pairwise_cross/input.json +8 -0
- data/golden/pairwise_cross/schema.kumi +18 -0
- data/golden/reduction_broadcast/expected/loopir.txt +4 -10
- data/golden/reduction_broadcast/expected/runtime.json +14 -0
- data/golden/reduction_broadcast/expected/schema_javascript.mjs +4 -10
- data/golden/reduction_broadcast/expected/schema_ruby.rb +5 -11
- data/golden/roll/expected/loopir.txt +4 -8
- data/golden/roll/expected/runtime.json +26 -0
- data/golden/roll/expected/schema_javascript.mjs +4 -8
- data/golden/roll/expected/schema_ruby.rb +5 -9
- data/golden/schema_imports_broadcasting_with_imports/expected/dfir.txt +3 -3
- data/golden/schema_imports_broadcasting_with_imports/expected/dfir_optimized.txt +3 -3
- data/golden/schema_imports_broadcasting_with_imports/expected/loopir.txt +3 -4
- data/golden/schema_imports_broadcasting_with_imports/expected/runtime.json +11 -0
- data/golden/schema_imports_broadcasting_with_imports/expected/schema_javascript.mjs +2 -3
- data/golden/schema_imports_broadcasting_with_imports/expected/schema_ruby.rb +3 -4
- data/golden/schema_imports_broadcasting_with_imports/expected/snast.txt +5 -5
- data/golden/schema_imports_broadcasting_with_imports/expected/vecir.txt +3 -3
- data/golden/schema_imports_complex_order_calc/expected/dfir.txt +20 -20
- data/golden/schema_imports_complex_order_calc/expected/dfir_optimized.txt +60 -60
- data/golden/schema_imports_complex_order_calc/expected/loopir.txt +34 -47
- data/golden/schema_imports_complex_order_calc/expected/runtime.json +33 -0
- data/golden/schema_imports_complex_order_calc/expected/schema_javascript.mjs +16 -29
- data/golden/schema_imports_complex_order_calc/expected/schema_ruby.rb +17 -30
- data/golden/schema_imports_complex_order_calc/expected/snast.txt +26 -26
- data/golden/schema_imports_complex_order_calc/expected/vecir.txt +60 -60
- data/golden/schema_imports_composed_order/expected/dfir.txt +3 -3
- data/golden/schema_imports_composed_order/expected/dfir_optimized.txt +6 -6
- data/golden/schema_imports_composed_order/expected/loopir.txt +6 -6
- data/golden/schema_imports_composed_order/expected/runtime.json +9 -0
- data/golden/schema_imports_composed_order/expected/schema_ruby.rb +1 -1
- data/golden/schema_imports_composed_order/expected/snast.txt +5 -5
- data/golden/schema_imports_composed_order/expected/vecir.txt +6 -6
- data/golden/schema_imports_discount_with_tax/expected/dfir.txt +7 -7
- data/golden/schema_imports_discount_with_tax/expected/dfir_optimized.txt +10 -10
- data/golden/schema_imports_discount_with_tax/expected/loopir.txt +10 -10
- data/golden/schema_imports_discount_with_tax/expected/runtime.json +10 -0
- data/golden/schema_imports_discount_with_tax/expected/schema_ruby.rb +1 -1
- data/golden/schema_imports_discount_with_tax/expected/snast.txt +11 -11
- data/golden/schema_imports_discount_with_tax/expected/vecir.txt +10 -10
- data/golden/schema_imports_line_items/expected/dfir.txt +1 -1
- data/golden/schema_imports_line_items/expected/dfir_optimized.txt +3 -3
- data/golden/schema_imports_line_items/expected/loopir.txt +3 -6
- data/golden/schema_imports_line_items/expected/runtime.json +8 -0
- data/golden/schema_imports_line_items/expected/schema_javascript.mjs +4 -7
- data/golden/schema_imports_line_items/expected/schema_ruby.rb +5 -8
- data/golden/schema_imports_line_items/expected/snast.txt +1 -1
- data/golden/schema_imports_line_items/expected/vecir.txt +3 -3
- data/golden/schema_imports_multiple/expected/dfir.txt +7 -7
- data/golden/schema_imports_multiple/expected/dfir_optimized.txt +13 -13
- data/golden/schema_imports_multiple/expected/loopir.txt +13 -13
- data/golden/schema_imports_multiple/expected/runtime.json +10 -0
- data/golden/schema_imports_multiple/expected/schema_ruby.rb +1 -1
- data/golden/schema_imports_multiple/expected/snast.txt +11 -11
- data/golden/schema_imports_multiple/expected/vecir.txt +13 -13
- data/golden/schema_imports_nested_expressions/expected/dfir.txt +4 -4
- data/golden/schema_imports_nested_expressions/expected/dfir_optimized.txt +6 -6
- data/golden/schema_imports_nested_expressions/expected/loopir.txt +6 -6
- data/golden/schema_imports_nested_expressions/expected/runtime.json +8 -0
- data/golden/schema_imports_nested_expressions/expected/schema_ruby.rb +1 -1
- data/golden/schema_imports_nested_expressions/expected/snast.txt +6 -6
- data/golden/schema_imports_nested_expressions/expected/vecir.txt +6 -6
- data/golden/schema_imports_nested_with_reductions/expected/dfir.txt +6 -6
- data/golden/schema_imports_nested_with_reductions/expected/dfir_optimized.txt +15 -15
- data/golden/schema_imports_nested_with_reductions/expected/loopir.txt +7 -14
- data/golden/schema_imports_nested_with_reductions/expected/runtime.json +12 -0
- data/golden/schema_imports_nested_with_reductions/expected/schema_javascript.mjs +8 -15
- data/golden/schema_imports_nested_with_reductions/expected/schema_ruby.rb +9 -16
- data/golden/schema_imports_nested_with_reductions/expected/snast.txt +6 -6
- data/golden/schema_imports_nested_with_reductions/expected/vecir.txt +15 -15
- data/golden/schema_imports_with_imports/expected/dfir.txt +3 -3
- data/golden/schema_imports_with_imports/expected/dfir_optimized.txt +3 -3
- data/golden/schema_imports_with_imports/expected/loopir.txt +3 -3
- data/golden/schema_imports_with_imports/expected/runtime.json +7 -0
- data/golden/schema_imports_with_imports/expected/schema_ruby.rb +1 -1
- data/golden/schema_imports_with_imports/expected/snast.txt +5 -5
- data/golden/schema_imports_with_imports/expected/vecir.txt +3 -3
- data/golden/shift/expected/loopir.txt +4 -8
- data/golden/shift/expected/runtime.json +38 -0
- data/golden/shift/expected/schema_javascript.mjs +4 -8
- data/golden/shift/expected/schema_ruby.rb +5 -9
- data/golden/shift_2d/expected/loopir.txt +8 -16
- data/golden/shift_2d/expected/runtime.json +146 -0
- data/golden/shift_2d/expected/schema_javascript.mjs +8 -16
- data/golden/shift_2d/expected/schema_ruby.rb +9 -17
- data/golden/simple_math/expected/runtime.json +10 -0
- data/golden/simple_math/expected/schema_ruby.rb +1 -1
- data/golden/streaming_basics/expected/loopir.txt +0 -3
- data/golden/streaming_basics/expected/runtime.json +25 -0
- data/golden/streaming_basics/expected/schema_javascript.mjs +3 -6
- data/golden/streaming_basics/expected/schema_ruby.rb +4 -7
- data/golden/transcendentals/expected/ast.txt +48 -0
- data/golden/transcendentals/expected/dfir.txt +31 -0
- data/golden/transcendentals/expected/dfir_optimized.txt +34 -0
- data/golden/transcendentals/expected/input_plan.txt +5 -0
- data/golden/transcendentals/expected/loopir.txt +46 -0
- data/golden/transcendentals/expected/nast.txt +34 -0
- data/golden/transcendentals/expected/runtime.json +27 -0
- data/golden/transcendentals/expected/schema_javascript.mjs +66 -0
- data/golden/transcendentals/expected/schema_ruby.rb +63 -0
- data/golden/transcendentals/expected/snast.txt +34 -0
- data/golden/transcendentals/expected/vecir.txt +34 -0
- data/golden/transcendentals/input.json +1 -0
- data/golden/transcendentals/schema.kumi +16 -0
- data/golden/tuples/expected/dfir.txt +4 -4
- data/golden/tuples/expected/runtime.json +12 -0
- data/golden/tuples/expected/schema_ruby.rb +1 -1
- data/golden/tuples_and_arrays/expected/dfir.txt +1 -1
- data/golden/tuples_and_arrays/expected/loopir.txt +0 -1
- data/golden/tuples_and_arrays/expected/runtime.json +13 -0
- data/golden/tuples_and_arrays/expected/schema_javascript.mjs +1 -2
- data/golden/tuples_and_arrays/expected/schema_ruby.rb +2 -3
- data/golden/type_promotion/expected/ast.txt +75 -0
- data/golden/type_promotion/expected/dfir.txt +38 -0
- data/golden/type_promotion/expected/dfir_optimized.txt +51 -0
- data/golden/type_promotion/expected/input_plan.txt +9 -0
- data/golden/type_promotion/expected/loopir.txt +57 -0
- data/golden/type_promotion/expected/nast.txt +57 -0
- data/golden/type_promotion/expected/runtime.json +23 -0
- data/golden/type_promotion/expected/schema_javascript.mjs +90 -0
- data/golden/type_promotion/expected/schema_ruby.rb +89 -0
- data/golden/type_promotion/expected/snast.txt +57 -0
- data/golden/type_promotion/expected/vecir.txt +51 -0
- data/golden/type_promotion/input.json +11 -0
- data/golden/type_promotion/schema.kumi +30 -0
- data/golden/us_tax_2024/expected/dfir.txt +6 -6
- data/golden/us_tax_2024/expected/loopir.txt +108 -217
- data/golden/us_tax_2024/expected/runtime.json +423 -0
- data/golden/us_tax_2024/expected/schema_javascript.mjs +108 -235
- data/golden/us_tax_2024/expected/schema_ruby.rb +109 -218
- data/golden/vector_make_object/expected/schema_ruby.rb +1 -1
- data/golden/with_constants/expected/schema_ruby.rb +1 -1
- data/lib/kumi/analyzer.rb +29 -34
- data/lib/kumi/configuration.rb +31 -0
- data/lib/kumi/core/analyzer/binder.rb +2 -2
- data/lib/kumi/core/analyzer/macro_expander.rb +3 -3
- data/lib/kumi/core/analyzer/pass_failure.rb +1 -1
- data/lib/kumi/core/analyzer/pass_manager.rb +211 -100
- data/lib/kumi/core/analyzer/passes/attach_anchors_pass.rb +44 -15
- data/lib/kumi/core/analyzer/passes/attach_terminal_info_pass.rb +6 -20
- data/lib/kumi/core/analyzer/passes/codegen/loop/js/emitter.rb +235 -35
- data/lib/kumi/core/analyzer/passes/codegen/loop/ruby/emitter.rb +6 -3
- data/lib/kumi/core/analyzer/passes/codegen/loop_js_pass.rb +3 -0
- data/lib/kumi/core/analyzer/passes/codegen/loop_ruby_pass.rb +3 -0
- data/lib/kumi/core/analyzer/passes/constant_folding_pass.rb +3 -0
- data/lib/kumi/core/analyzer/passes/contract_checker_pass.rb +1 -1
- data/lib/kumi/core/analyzer/passes/declaration_validator_pass.rb +83 -0
- data/lib/kumi/core/analyzer/passes/{dependency_resolver.rb → dependency_resolver_pass.rb} +8 -6
- data/lib/kumi/core/analyzer/passes/df_validate_pass.rb +3 -13
- data/lib/kumi/core/analyzer/passes/import_analysis_pass.rb +7 -2
- data/lib/kumi/core/analyzer/passes/input_access_planner_pass.rb +4 -28
- data/lib/kumi/core/analyzer/passes/{input_collector.rb → input_collector_pass.rb} +30 -3
- data/lib/kumi/core/analyzer/passes/input_form_schema_pass.rb +4 -1
- data/lib/kumi/core/analyzer/passes/ir_execution_schedule_pass.rb +4 -2
- data/lib/kumi/core/analyzer/passes/ir_lower_pass.rb +35 -0
- data/lib/kumi/core/analyzer/passes/ir_validate_pass.rb +43 -0
- data/lib/kumi/core/analyzer/passes/{load_input_cse.rb → load_input_cse_pass.rb} +1 -1
- data/lib/kumi/core/analyzer/passes/loop/lower_pass.rb +23 -10
- data/lib/kumi/core/analyzer/passes/loop_validate_pass.rb +2 -10
- data/lib/kumi/core/analyzer/passes/lower_to_dfir_pass.rb +4 -2
- data/lib/kumi/core/analyzer/passes/{name_indexer.rb → name_indexer_pass.rb} +3 -7
- data/lib/kumi/core/analyzer/passes/nast_dimensional_analyzer_pass.rb +174 -23
- data/lib/kumi/core/analyzer/passes/normalize_to_nast_pass.rb +19 -3
- data/lib/kumi/core/analyzer/passes/output_schema_pass.rb +3 -0
- data/lib/kumi/core/analyzer/passes/pass_base.rb +78 -5
- data/lib/kumi/core/analyzer/passes/precompute_access_paths_pass.rb +7 -1
- data/lib/kumi/core/analyzer/passes/{semantic_constraint_validator.rb → semantic_constraint_validator_pass.rb} +7 -14
- data/lib/kumi/core/analyzer/passes/snast_pass.rb +22 -48
- data/lib/kumi/core/analyzer/passes/{toposorter.rb → toposorter_pass.rb} +4 -5
- data/lib/kumi/core/analyzer/passes/{unsat_detector.rb → unsat_detector_pass.rb} +4 -15
- data/lib/kumi/core/analyzer/passes/vec/lower_pass.rb +6 -8
- data/lib/kumi/core/analyzer/passes/vec_validate_pass.rb +2 -10
- data/lib/kumi/core/analyzer/structs/input_meta.rb +1 -1
- data/lib/kumi/core/compiler/access_builder.rb +1 -1
- data/lib/kumi/core/compiler/access_codegen.rb +1 -1
- data/lib/kumi/core/compiler/access_emit/base.rb +1 -1
- data/lib/kumi/core/compiler/access_planner_v2.rb +2 -2
- data/lib/kumi/core/compiler/accessors/each_indexed_accessor.rb +1 -1
- data/lib/kumi/core/compiler/accessors/materialize_accessor.rb +1 -1
- data/lib/kumi/core/compiler/accessors/ravel_accessor.rb +1 -1
- data/lib/kumi/core/compiler/accessors/read_accessor.rb +1 -1
- data/lib/kumi/core/error_reporter.rb +6 -11
- data/lib/kumi/core/errors.rb +37 -11
- data/lib/kumi/core/expression_renderer.rb +97 -0
- data/lib/kumi/core/functions/overload_resolver.rb +79 -149
- data/lib/kumi/core/ir/execution_engine/combinators.rb +16 -10
- data/lib/kumi/core/nast.rb +24 -0
- data/lib/kumi/core/ruby_parser/dsl.rb +12 -2
- data/lib/kumi/core/ruby_parser/dsl_cascade_builder.rb +14 -12
- data/lib/kumi/core/ruby_parser/guard_rails.rb +15 -1
- data/lib/kumi/core/ruby_parser/input_builder.rb +55 -48
- data/lib/kumi/core/ruby_parser/parser.rb +25 -17
- data/lib/kumi/core/ruby_parser/schema_builder.rb +43 -15
- data/lib/kumi/core/ruby_parser/sugar.rb +0 -86
- data/lib/kumi/core/types/dtype_rule.rb +76 -0
- data/lib/kumi/core/types/normalizer.rb +2 -2
- data/lib/kumi/core/types/profile.rb +82 -0
- data/lib/kumi/core/types/registry.rb +87 -0
- data/lib/kumi/core/types/system.rb +96 -0
- data/lib/kumi/core/types/value_objects.rb +14 -13
- data/lib/kumi/core/types.rb +41 -34
- data/lib/kumi/dev/golden_runtime.rb +163 -0
- data/lib/kumi/dev/golden_v2.rb +30 -5
- data/lib/kumi/dev/pretty_printer.rb +40 -73
- data/lib/kumi/frontends/ruby.rb +52 -12
- data/lib/kumi/frontends/source_frame.rb +71 -0
- data/lib/kumi/frontends/text.rb +4 -48
- data/lib/kumi/function_registry/loader.rb +101 -0
- data/lib/kumi/function_registry.rb +150 -0
- data/lib/kumi/ir/base/block.rb +11 -2
- data/lib/kumi/ir/base/builder.rb +1 -1
- data/lib/kumi/ir/base/function.rb +2 -4
- data/lib/kumi/ir/base/instruction.rb +10 -23
- data/lib/kumi/ir/base/module.rb +5 -4
- data/lib/kumi/ir/buf/lower.rb +1 -2
- data/lib/kumi/ir/df/access_contract.rb +3 -5
- data/lib/kumi/ir/df/import_inliner.rb +2 -5
- data/lib/kumi/ir/df/lower.rb +72 -51
- data/lib/kumi/ir/df/ops/axis_cross.rb +34 -0
- data/lib/kumi/ir/df/ops/axis_outer.rb +35 -0
- data/lib/kumi/ir/df/passes/broadcast_simplify.rb +1 -2
- data/lib/kumi/ir/df/passes/cse.rb +8 -3
- data/lib/kumi/ir/df/passes/decl_inlining.rb +5 -26
- data/lib/kumi/ir/df/passes/import_inlining.rb +42 -36
- data/lib/kumi/ir/df/passes/load_dedup.rb +9 -4
- data/lib/kumi/ir/df/passes/stencil_cse.rb +2 -5
- data/lib/kumi/ir/df/passes/support/instruction_cloner.rb +41 -14
- data/lib/kumi/ir/df/passes/tuple_fold_canonicalization.rb +8 -3
- data/lib/kumi/ir/df/passes/tuple_to_object.rb +1 -2
- data/lib/kumi/ir/df/validator.rb +3 -3
- data/lib/kumi/ir/df.rb +8 -0
- data/lib/kumi/ir/loop/lower.rb +231 -37
- data/lib/kumi/ir/loop/passes/array_contraction.rb +124 -0
- data/lib/kumi/ir/loop/passes/copy_cleanup.rb +112 -0
- data/lib/kumi/ir/loop/passes/loop_fusion.rb +125 -0
- data/lib/kumi/ir/loop/passes/support/structure.rb +100 -0
- data/lib/kumi/ir/loop/passes.rb +14 -0
- data/lib/kumi/ir/loop/pipeline.rb +9 -1
- data/lib/kumi/ir/loop/validator.rb +29 -4
- data/lib/kumi/ir/loop.rb +1 -0
- data/lib/kumi/ir/passes/register_generator.rb +32 -0
- data/lib/kumi/ir/testing/snast_factory.rb +2 -4
- data/lib/kumi/ir/vec/lower.rb +17 -7
- data/lib/kumi/ir/vec/ops/core_ops.rb +41 -0
- data/lib/kumi/ir/vec/passes/axis_canonicalization.rb +1 -2
- data/lib/kumi/ir/vec/passes/constant_propagation.rb +75 -47
- data/lib/kumi/ir/vec/passes/dce.rb +2 -5
- data/lib/kumi/ir/vec/passes/gvn.rb +8 -3
- data/lib/kumi/ir/vec/passes/peephole_simplify.rb +30 -13
- data/lib/kumi/ir/vec/passes/stencil_detection.rb +1 -2
- data/lib/kumi/ir/vec/passes/support/algebraic_identities.rb +70 -0
- data/lib/kumi/ir/vec/passes/support/instruction_cloner.rb +17 -3
- data/lib/kumi/ir/vec/validator.rb +26 -6
- data/lib/kumi/schema.rb +14 -10
- data/lib/kumi/schema_metadata/printer.rb +111 -0
- data/lib/kumi/schema_metadata.rb +289 -0
- data/lib/kumi/syntax/location.rb +14 -1
- data/lib/kumi/syntax/root.rb +35 -3
- data/lib/kumi/test_shared_schemas/pairwise.rb +27 -0
- data/lib/kumi/version.rb +1 -1
- data/lib/kumi.rb +3 -5
- data/tasks/docs_portal.rake +135 -0
- metadata +203 -81
- data/golden/array_element/expected.json +0 -5
- data/golden/array_index/expected.json +0 -5
- data/golden/cascade_logic/expected.json +0 -5
- data/golden/chained_fusion/expected.json +0 -45
- data/golden/decimal_explicit/expected.json +0 -1
- data/golden/element_arrays/expected.json +0 -55
- data/golden/empty_and_null_inputs/expected.json +0 -8
- data/golden/example_xpto/expected.json +0 -4
- data/golden/game_of_life/expected.json +0 -3
- data/golden/hash_keys/expected.json +0 -20
- data/golden/hash_value/expected.json +0 -19
- data/golden/hierarchical_complex/expected.json +0 -34
- data/golden/inline_rename_scope_leak/expected.json +0 -7
- data/golden/input_reference/expected.json +0 -7
- data/golden/interleaved_fusion/expected.json +0 -37
- data/golden/let_inline/expected.json +0 -1
- data/golden/loop_fusion/expected.json +0 -30
- data/golden/min_max_empty_arrays/expected.json +0 -7
- data/golden/min_reduce_scope/expected.json +0 -9
- data/golden/mixed_dimensions/expected.json +0 -6
- data/golden/multi_loop_reduction/expected.json +0 -5
- data/golden/multirank_hoisting/expected.json +0 -15
- data/golden/nested_hash/expected.json +0 -3
- data/golden/reduction_broadcast/expected.json +0 -25
- data/golden/roll/expected.json +0 -6
- data/golden/schema_imports_broadcasting_with_imports/expected.json +0 -4
- data/golden/schema_imports_complex_order_calc/expected.json +0 -12
- data/golden/schema_imports_composed_order/expected.json +0 -6
- data/golden/schema_imports_discount_with_tax/expected.json +0 -7
- data/golden/schema_imports_line_items/expected.json +0 -5
- data/golden/schema_imports_multiple/expected.json +0 -7
- data/golden/schema_imports_nested_expressions/expected.json +0 -5
- data/golden/schema_imports_nested_with_reductions/expected.json +0 -6
- data/golden/schema_imports_with_imports/expected.json +0 -4
- data/golden/shift/expected.json +0 -8
- data/golden/shift_2d/expected.json +0 -15
- data/golden/simple_math/expected.json +0 -1
- data/golden/streaming_basics/expected.json +0 -10
- data/golden/tuples/expected.json +0 -7
- data/golden/tuples_and_arrays/expected.json +0 -18
- data/golden/us_tax_2024/expected.json +0 -120
- data/lib/kumi/core/analyzer/passes/assemble_irv2_pass.rb +0 -130
- data/lib/kumi/core/analyzer/passes/declaration_validator.rb +0 -45
- data/lib/kumi/core/analyzer/passes/lower_to_irv2_pass.rb +0 -197
- data/lib/kumi/core/compiler/access_planner.rb +0 -258
- data/lib/kumi/core/functions/function_spec.rb +0 -17
- data/lib/kumi/core/functions/loader.rb +0 -63
- data/lib/kumi/core/functions/type_categories.rb +0 -44
- data/lib/kumi/core/functions/type_error_reporter.rb +0 -116
- data/lib/kumi/core/functions/type_rules.rb +0 -228
- data/lib/kumi/core/irv2/builder.rb +0 -48
- data/lib/kumi/core/irv2/declaration.rb +0 -28
- data/lib/kumi/core/irv2/module.rb +0 -108
- data/lib/kumi/core/irv2/value.rb +0 -28
- data/lib/kumi/core/types/validator.rb +0 -33
- data/lib/kumi/dev/codegen.rb +0 -194
- data/lib/kumi/dev/golden/generator.rb +0 -109
- data/lib/kumi/dev/golden/reporter.rb +0 -169
- data/lib/kumi/dev/golden/representation.rb +0 -40
- data/lib/kumi/dev/golden/result.rb +0 -106
- data/lib/kumi/dev/golden/runtime_test.rb +0 -131
- data/lib/kumi/dev/golden/suite.rb +0 -147
- data/lib/kumi/dev/golden/value_normalizer.rb +0 -78
- data/lib/kumi/dev/golden/verifier.rb +0 -76
- data/lib/kumi/dev/golden.rb +0 -82
- data/lib/kumi/dev/golden_schema_wrapper.rb +0 -116
- data/lib/kumi/dev/printer/irv2_formatter.rb +0 -163
- data/lib/kumi/kernel_registry.rb +0 -59
- data/lib/kumi/pack/builder.rb +0 -229
- data/lib/kumi/pack.rb +0 -15
- data/lib/kumi/registry_v2/loader.rb +0 -170
- data/lib/kumi/registry_v2.rb +0 -135
data/docs/FUNCTIONS.md
CHANGED
|
@@ -134,9 +134,12 @@ Auto-generated documentation for Kumi functions and their kernels.
|
|
|
134
134
|
|
|
135
135
|
`agg.join:ruby:v1`
|
|
136
136
|
|
|
137
|
+
**Inline:** `+= $1` (`$0` = accumulator, `$1` = element)
|
|
138
|
+
|
|
137
139
|
**Fold:** `= $0.join`
|
|
138
140
|
|
|
139
|
-
|
|
141
|
+
**Identity:**
|
|
142
|
+
- string: ``
|
|
140
143
|
|
|
141
144
|
**Reduction:** First element is initial value (no identity)
|
|
142
145
|
|
|
@@ -253,6 +256,7 @@ _Note: No identity value. First element initializes accumulator._
|
|
|
253
256
|
**Identity:**
|
|
254
257
|
- float: `0.0`
|
|
255
258
|
- integer: `0`
|
|
259
|
+
- decimal: `0`
|
|
256
260
|
|
|
257
261
|
**Reduction:** Monoid operation with identity element
|
|
258
262
|
|
|
@@ -405,7 +409,7 @@ _Note: No identity value. First element initializes accumulator._
|
|
|
405
409
|
|
|
406
410
|
```ruby
|
|
407
411
|
(x, lo, hi)
|
|
408
|
-
|
|
412
|
+
x.clamp(lo, hi)
|
|
409
413
|
```
|
|
410
414
|
|
|
411
415
|
_Note: No identity value. First element initializes accumulator._
|
|
@@ -435,6 +439,23 @@ a.to_s + b.to_s
|
|
|
435
439
|
|
|
436
440
|
_Note: No identity value. First element initializes accumulator._
|
|
437
441
|
|
|
442
|
+
## `core.cos`
|
|
443
|
+
|
|
444
|
+
- **Arity:** 1
|
|
445
|
+
- **Type:** float
|
|
446
|
+
|
|
447
|
+
### Parameters
|
|
448
|
+
|
|
449
|
+
- `angle`
|
|
450
|
+
|
|
451
|
+
### Implementations
|
|
452
|
+
|
|
453
|
+
#### Ruby
|
|
454
|
+
|
|
455
|
+
`cos:ruby:v1`
|
|
456
|
+
|
|
457
|
+
_Note: No identity value. First element initializes accumulator._
|
|
458
|
+
|
|
438
459
|
## `core.div`
|
|
439
460
|
|
|
440
461
|
**Aliases:** `div`, `divide`
|
|
@@ -506,6 +527,23 @@ _Note: No identity value. First element initializes accumulator._
|
|
|
506
527
|
|
|
507
528
|
_Note: No identity value. First element initializes accumulator._
|
|
508
529
|
|
|
530
|
+
## `core.exp`
|
|
531
|
+
|
|
532
|
+
- **Arity:** 1
|
|
533
|
+
- **Type:** float
|
|
534
|
+
|
|
535
|
+
### Parameters
|
|
536
|
+
|
|
537
|
+
- `number`
|
|
538
|
+
|
|
539
|
+
### Implementations
|
|
540
|
+
|
|
541
|
+
#### Ruby
|
|
542
|
+
|
|
543
|
+
`exp:ruby:v1`
|
|
544
|
+
|
|
545
|
+
_Note: No identity value. First element initializes accumulator._
|
|
546
|
+
|
|
509
547
|
## `core.gt`
|
|
510
548
|
|
|
511
549
|
**Aliases:** `>`, `greater_than`, `gt`
|
|
@@ -597,6 +635,23 @@ _Note: No identity value. First element initializes accumulator._
|
|
|
597
635
|
|
|
598
636
|
_Note: No identity value. First element initializes accumulator._
|
|
599
637
|
|
|
638
|
+
## `core.log`
|
|
639
|
+
|
|
640
|
+
- **Arity:** 1
|
|
641
|
+
- **Type:** float
|
|
642
|
+
|
|
643
|
+
### Parameters
|
|
644
|
+
|
|
645
|
+
- `number`
|
|
646
|
+
|
|
647
|
+
### Implementations
|
|
648
|
+
|
|
649
|
+
#### Ruby
|
|
650
|
+
|
|
651
|
+
`log:ruby:v1`
|
|
652
|
+
|
|
653
|
+
_Note: No identity value. First element initializes accumulator._
|
|
654
|
+
|
|
600
655
|
## `core.lt`
|
|
601
656
|
|
|
602
657
|
**Aliases:** `<`, `less_than`, `lt`
|
|
@@ -671,29 +726,29 @@ _Note: No identity value. First element initializes accumulator._
|
|
|
671
726
|
|
|
672
727
|
_Note: No identity value. First element initializes accumulator._
|
|
673
728
|
|
|
674
|
-
## `core.mul`
|
|
729
|
+
## `core.mul:string_repeat`
|
|
675
730
|
|
|
676
731
|
**Aliases:** `mul`, `multiply`
|
|
677
732
|
|
|
678
733
|
- **Arity:** 2
|
|
679
|
-
- **Type:**
|
|
734
|
+
- **Type:** string
|
|
680
735
|
|
|
681
736
|
### Parameters
|
|
682
737
|
|
|
683
|
-
- `
|
|
684
|
-
- `
|
|
738
|
+
- `string_value`
|
|
739
|
+
- `repeat_count`
|
|
685
740
|
|
|
686
741
|
### Implementations
|
|
687
742
|
|
|
688
|
-
####
|
|
743
|
+
#### String_repeat
|
|
689
744
|
|
|
690
|
-
`mul:ruby:v1`
|
|
745
|
+
`mul:string_repeat:ruby:v1`
|
|
691
746
|
|
|
692
747
|
**Implementation:**
|
|
693
748
|
|
|
694
749
|
```ruby
|
|
695
|
-
(
|
|
696
|
-
|
|
750
|
+
(str, count)
|
|
751
|
+
str * count
|
|
697
752
|
```
|
|
698
753
|
|
|
699
754
|
_Note: No identity value. First element initializes accumulator._
|
|
@@ -800,11 +855,46 @@ _Note: No identity value. First element initializes accumulator._
|
|
|
800
855
|
|
|
801
856
|
```ruby
|
|
802
857
|
(a, b)
|
|
803
|
-
a ** b
|
|
858
|
+
r = a ** b
|
|
859
|
+
r.is_a?(Complex) ? Float::NAN : r
|
|
804
860
|
```
|
|
805
861
|
|
|
806
862
|
_Note: No identity value. First element initializes accumulator._
|
|
807
863
|
|
|
864
|
+
## `core.sin`
|
|
865
|
+
|
|
866
|
+
- **Arity:** 1
|
|
867
|
+
- **Type:** float
|
|
868
|
+
|
|
869
|
+
### Parameters
|
|
870
|
+
|
|
871
|
+
- `angle`
|
|
872
|
+
|
|
873
|
+
### Implementations
|
|
874
|
+
|
|
875
|
+
#### Ruby
|
|
876
|
+
|
|
877
|
+
`sin:ruby:v1`
|
|
878
|
+
|
|
879
|
+
_Note: No identity value. First element initializes accumulator._
|
|
880
|
+
|
|
881
|
+
## `core.sqrt`
|
|
882
|
+
|
|
883
|
+
- **Arity:** 1
|
|
884
|
+
- **Type:** float
|
|
885
|
+
|
|
886
|
+
### Parameters
|
|
887
|
+
|
|
888
|
+
- `number`
|
|
889
|
+
|
|
890
|
+
### Implementations
|
|
891
|
+
|
|
892
|
+
#### Ruby
|
|
893
|
+
|
|
894
|
+
`sqrt:ruby:v1`
|
|
895
|
+
|
|
896
|
+
_Note: No identity value. First element initializes accumulator._
|
|
897
|
+
|
|
808
898
|
## `core.sub`
|
|
809
899
|
|
|
810
900
|
**Aliases:** `sub`, `subtract`
|
|
@@ -832,6 +922,23 @@ _Note: No identity value. First element initializes accumulator._
|
|
|
832
922
|
|
|
833
923
|
_Note: No identity value. First element initializes accumulator._
|
|
834
924
|
|
|
925
|
+
## `core.tanh`
|
|
926
|
+
|
|
927
|
+
- **Arity:** 1
|
|
928
|
+
- **Type:** float
|
|
929
|
+
|
|
930
|
+
### Parameters
|
|
931
|
+
|
|
932
|
+
- `number`
|
|
933
|
+
|
|
934
|
+
### Implementations
|
|
935
|
+
|
|
936
|
+
#### Ruby
|
|
937
|
+
|
|
938
|
+
`tanh:ruby:v1`
|
|
939
|
+
|
|
940
|
+
_Note: No identity value. First element initializes accumulator._
|
|
941
|
+
|
|
835
942
|
## `core.to_decimal`
|
|
836
943
|
|
|
837
944
|
- **Arity:** 1
|
|
@@ -911,7 +1018,7 @@ _Note: No identity value. First element initializes accumulator._
|
|
|
911
1018
|
|
|
912
1019
|
_Note: No identity value. First element initializes accumulator._
|
|
913
1020
|
|
|
914
|
-
## `core.to_string`
|
|
1021
|
+
## `core.to_string:float`
|
|
915
1022
|
|
|
916
1023
|
**Aliases:** `to_str`, `to_string`
|
|
917
1024
|
|
|
@@ -926,7 +1033,7 @@ _Note: No identity value. First element initializes accumulator._
|
|
|
926
1033
|
|
|
927
1034
|
#### Ruby
|
|
928
1035
|
|
|
929
|
-
`
|
|
1036
|
+
`to_string_float:ruby:v1`
|
|
930
1037
|
|
|
931
1038
|
**Implementation:**
|
|
932
1039
|
|
data/docs/INPUTS.md
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# Kumi Input Shapes
|
|
2
|
+
|
|
3
|
+
The `input do … end` block declares the shape of the data a schema runs on:
|
|
4
|
+
scalars, arrays, hashes, and any nesting of them. Every value referenced in the
|
|
5
|
+
body (`input.foo.bar`) must trace back to a declaration here.
|
|
6
|
+
|
|
7
|
+
This is the reference for declaring inputs. For the rest of the language
|
|
8
|
+
(declarations, operators, functions, control flow) see [SYNTAX.md](SYNTAX.md).
|
|
9
|
+
|
|
10
|
+
## The element rule: always name the element
|
|
11
|
+
|
|
12
|
+
Kumi **maps over arrays by default** (unless you `zip`). The single child inside
|
|
13
|
+
an `array` block names the element that the map binds and iterates over — so the
|
|
14
|
+
element must always be named. Every `array` declares **exactly one child**:
|
|
15
|
+
|
|
16
|
+
- a primitive (`integer :value`) for a **scalar array**,
|
|
17
|
+
- a `hash` (`hash :item do … end`) when each element has **several fields**,
|
|
18
|
+
- a nested `array` for an **array of arrays**.
|
|
19
|
+
|
|
20
|
+
There is no childless/nameless array — without a name there is nothing for the
|
|
21
|
+
map to bind. Omitting the child is an error that tells you exactly this.
|
|
22
|
+
|
|
23
|
+
`index: :i` is **not** the element — it names the **axis/position** so you can
|
|
24
|
+
read the index value with `index(:i)`. You do *not* write `input.cells.i` to
|
|
25
|
+
reach the element; the element is the named child (`input.cells.value`) or the
|
|
26
|
+
broadcast array itself (`input.cells`).
|
|
27
|
+
|
|
28
|
+
## Scalars
|
|
29
|
+
|
|
30
|
+
Scalar inputs represent single values:
|
|
31
|
+
|
|
32
|
+
```kumi
|
|
33
|
+
input do
|
|
34
|
+
integer :x
|
|
35
|
+
float :rate
|
|
36
|
+
decimal :price # Precise decimal for money calculations
|
|
37
|
+
string :name
|
|
38
|
+
end
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Example:**
|
|
42
|
+
```kumi
|
|
43
|
+
schema do
|
|
44
|
+
input do
|
|
45
|
+
integer :x
|
|
46
|
+
integer :y
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
value :sum, input.x + input.y
|
|
50
|
+
value :product, input.x * input.y
|
|
51
|
+
end
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Arrays
|
|
55
|
+
|
|
56
|
+
Arrays represent sequences. Navigate using dot notation through each level.
|
|
57
|
+
Remember the [element rule](#the-element-rule-always-name-the-element): each
|
|
58
|
+
`array` declares exactly one named child.
|
|
59
|
+
|
|
60
|
+
**1D Array (scalar elements):**
|
|
61
|
+
```kumi
|
|
62
|
+
input do
|
|
63
|
+
array :cells do
|
|
64
|
+
integer :value # `value` names the element
|
|
65
|
+
# Access: input.cells.value (maps elementwise)
|
|
66
|
+
# input.cells (whole array, e.g. fn(:size, …))
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**2D Array (grid):**
|
|
72
|
+
```kumi
|
|
73
|
+
input do
|
|
74
|
+
array :rows do
|
|
75
|
+
array :col do
|
|
76
|
+
integer :v # Access: input.rows.col.v
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**3D Array (cube):**
|
|
83
|
+
```kumi
|
|
84
|
+
input do
|
|
85
|
+
array :cube do
|
|
86
|
+
array :layer do
|
|
87
|
+
array :row do
|
|
88
|
+
integer :cell # Access: input.cube.layer.row.cell
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Arrays of Hashes
|
|
96
|
+
|
|
97
|
+
Common pattern for structured collections — use a `hash` child when each element
|
|
98
|
+
has several fields:
|
|
99
|
+
|
|
100
|
+
```kumi
|
|
101
|
+
input do
|
|
102
|
+
array :items do
|
|
103
|
+
hash :item do
|
|
104
|
+
float :price
|
|
105
|
+
integer :quantity
|
|
106
|
+
string :category
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Access: input.items.item.price
|
|
112
|
+
# input.items.item.quantity
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Hashes
|
|
116
|
+
|
|
117
|
+
Hashes represent structured data with named fields:
|
|
118
|
+
|
|
119
|
+
```kumi
|
|
120
|
+
input do
|
|
121
|
+
hash :config do
|
|
122
|
+
string :app_name
|
|
123
|
+
array :servers do
|
|
124
|
+
hash :server do
|
|
125
|
+
string :hostname
|
|
126
|
+
integer :port
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Access scalar: input.config.app_name
|
|
133
|
+
# Access nested: input.config.servers.server.hostname
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Arrays with Named Indices
|
|
137
|
+
|
|
138
|
+
`index:` names an axis so you can read its **position** with `index(:name)`. It
|
|
139
|
+
is independent of the element — you still name the element child (here the
|
|
140
|
+
placeholder `integer :_`, since only the positions are used). `index(:i)` reads
|
|
141
|
+
the position; it is never an element accessor (`input.x.i` is not a thing).
|
|
142
|
+
|
|
143
|
+
```kumi
|
|
144
|
+
input do
|
|
145
|
+
array :x, index: :i do
|
|
146
|
+
array :y, index: :j do
|
|
147
|
+
integer :_ # element child (value unused, only positions matter)
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Use in expressions
|
|
153
|
+
let :W, fn(:array_size, input.x.y)
|
|
154
|
+
value :row_major, (index(:i) * W) + index(:j)
|
|
155
|
+
value :col_major, (index(:j) * fn(:array_size, input.x)) + index(:i)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## See also
|
|
159
|
+
|
|
160
|
+
- [SYNTAX.md](SYNTAX.md) — declarations, operators, functions, control flow.
|
|
161
|
+
- [SYNTAX_NOTES.md](SYNTAX_NOTES.md) — parser differences, mixed nested
|
|
162
|
+
array/hash recipes, expression literals, and post-parse analyzer errors.
|
|
163
|
+
- All-pairs over arrays: `cross` (one array, A × A') and `outer` (two arrays,
|
|
164
|
+
A × B) in [SYNTAX.md](SYNTAX.md#all-pairs-cross).
|
data/docs/OUTPUT_SCHEMA.md
CHANGED
|
@@ -31,15 +31,19 @@ bin/kumi analyze schema.kumi --dump output_schema --side-tables
|
|
|
31
31
|
|
|
32
32
|
**Schema:**
|
|
33
33
|
```kumi
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
schema do
|
|
35
|
+
input do
|
|
36
|
+
array :items do
|
|
37
|
+
hash :item do
|
|
38
|
+
float :price
|
|
39
|
+
integer :quantity
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
40
43
|
|
|
41
|
-
trait expensive
|
|
42
|
-
value total
|
|
44
|
+
trait :expensive, input.items.item.price > 100.0
|
|
45
|
+
value :total, input.items.item.price * input.items.item.quantity
|
|
46
|
+
end
|
|
43
47
|
```
|
|
44
48
|
|
|
45
49
|
**Generated Output Schema:**
|
data/docs/PASSES.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Compiler Pass Conventions
|
|
2
|
+
|
|
3
|
+
These rules are enforced by `spec/kumi/analyzer_pipeline_contract_spec.rb`,
|
|
4
|
+
`PassManager` contract checks, and RuboCop. Change the enforcement when you
|
|
5
|
+
change a rule.
|
|
6
|
+
|
|
7
|
+
## Naming
|
|
8
|
+
|
|
9
|
+
- Every pass class name ends in `Pass`; its file name ends in `_pass.rb`.
|
|
10
|
+
- New acronyms in class names require a zeitwerk inflector entry in
|
|
11
|
+
`lib/kumi.rb` and are discouraged — prefer plain words.
|
|
12
|
+
|
|
13
|
+
## Two pass shapes, never mixed
|
|
14
|
+
|
|
15
|
+
- **Analyzer passes** (`lib/kumi/core/analyzer/passes/`): subclass
|
|
16
|
+
`Passes::PassBase`. `run(errors)` takes an error accumulator and returns an
|
|
17
|
+
`AnalysisState`. State is immutable; produce new state with `state.with`.
|
|
18
|
+
- **IR passes** (`lib/kumi/ir/*/passes/`): subclass `Kumi::IR::Passes::Base`.
|
|
19
|
+
`run(graph:, context:)` returns a graph; compose with `IR::Passes::Pipeline`.
|
|
20
|
+
- Bridging happens only through the boundary adapters `IRValidatePass` and
|
|
21
|
+
`IRLowerPass` — never call an IR pipeline ad hoc from an analyzer pass.
|
|
22
|
+
|
|
23
|
+
## State contracts
|
|
24
|
+
|
|
25
|
+
Every analyzer pass declares what it touches, at the top of the class body:
|
|
26
|
+
|
|
27
|
+
class SNASTPass < PassBase
|
|
28
|
+
reads :nast_module, :metadata_table, :registry
|
|
29
|
+
writes :snast_module
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
- `reads` — required keys; fails fast in `PassManager` if absent. Also defines
|
|
33
|
+
a reader method per key.
|
|
34
|
+
- `optional_reads` — keys that may be absent; reader returns `nil`.
|
|
35
|
+
- `writes` — every key the pass adds or replaces. A pass that produces no
|
|
36
|
+
state declares bare `writes` (no arguments) so the contract is still
|
|
37
|
+
explicit. `PassManager` rejects any undeclared write.
|
|
38
|
+
- `# In:` / `# Out:` comments are banned — the DSL is the single source of
|
|
39
|
+
truth, and `spec/kumi/analyzer_pipeline_contract_spec.rb` checks that every
|
|
40
|
+
pipeline pass declares a contract and that pass ordering satisfies all reads.
|
|
41
|
+
- Passes that annotate IR/NAST nodes in place (e.g. `AttachTerminalInfoPass`)
|
|
42
|
+
declare bare `writes`; keep such in-place mutation limited to node `meta` /
|
|
43
|
+
annotation fields, never structure.
|
|
44
|
+
|
|
45
|
+
## Error reporting
|
|
46
|
+
|
|
47
|
+
One channel per logical error — never report AND raise the same problem (that
|
|
48
|
+
surfaces it twice, once via the accumulator and once via PassManager's exception
|
|
49
|
+
capture, which also leaks internal file paths).
|
|
50
|
+
|
|
51
|
+
- **User-facing errors** (the schema is wrong): record them in the `errors`
|
|
52
|
+
accumulator passed to `run`, with a real `location:` (pass the node's `loc`,
|
|
53
|
+
never interpolate it into the message string). Use `report(errors, msg, node:)`
|
|
54
|
+
to keep going and collect more, or `halt_pass!(errors, msg, node:)` to record
|
|
55
|
+
one and stop the pass cleanly. A halted/erroring pass fails because `errors`
|
|
56
|
+
is non-empty — no exception needed.
|
|
57
|
+
- **Internal invariants** ("can't happen" — a violated assumption, not bad user
|
|
58
|
+
input): `raise Kumi::Core::Errors::CompilerBug, "..."`. It is framed as a bug
|
|
59
|
+
to report and is never presented to users as if they wrote bad input.
|
|
60
|
+
- Do not raise `SemanticError`/`TypeError` directly from a pass for user errors;
|
|
61
|
+
route them through the accumulator so they are located and deduplicated.
|
|
62
|
+
|
|
63
|
+
## Loading
|
|
64
|
+
|
|
65
|
+
- zeitwerk owns everything under `lib/kumi/`. Inside `lib/`, only require
|
|
66
|
+
stdlib (`require "json"` etc.) — never `require "kumi/..."` for autoloadable
|
|
67
|
+
constants. Exceptions are the files explicitly ignored in `lib/kumi.rb`.
|
|
68
|
+
|
|
69
|
+
## Debug and checkpoint env vars
|
|
70
|
+
|
|
71
|
+
- `DEBUG_<SHORT_NAME>=1` enables per-pass debug output; the short name is the
|
|
72
|
+
class name minus the `Pass` suffix, underscored (`SNASTPass` → `DEBUG_SNAST`).
|
|
73
|
+
- `KUMI_RESUME_AT` / `KUMI_STOP_AFTER` take the pass short class name
|
|
74
|
+
(e.g. `SNASTPass`).
|
|
75
|
+
- `KUMI_DEBUG_REQUIRE_FROZEN=1` makes `PassManager` assert state values are
|
|
76
|
+
frozen after each pass (debug mode only).
|
data/docs/PASS_AUDIT.md
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# Analyzer Pass Audit — Findings & Plan
|
|
2
|
+
|
|
3
|
+
Audit of `lib/kumi/core/analyzer/` (≈45 passes + machinery). Baseline: 959 examples,
|
|
4
|
+
0 failures, 50/50 goldens. Each finding is evidence-backed; severity is impact × reach.
|
|
5
|
+
|
|
6
|
+
The framework itself (`PassManager`, `AnalysisState`, contract DSL in `PassBase`,
|
|
7
|
+
`docs/PASSES.md`, the contract spec) is **good** — immutable state, declared reads/writes,
|
|
8
|
+
ordering enforcement, per-pass budget, checkpoint/resume. The problems are in how passes
|
|
9
|
+
*report errors* and a few localized hygiene issues. Most value is in error reporting.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
> **STATUS (2026-06-18, later): widened beyond passes.** Fixed a SECOND user-facing leak
|
|
14
|
+
> (unknown function `fn(:nope,...)` leaked an internal pass/file path — the validator's
|
|
15
|
+
> existence check called a method that raised instead of returning false; added a non-raising
|
|
16
|
+
> `RegistryV2#function?`). Typed the registry kernel-lookup invariants, IR execution-engine
|
|
17
|
+
> combinator invariants, and schema.rb operational errors: added `Errors::ConfigurationError`
|
|
18
|
+
> (host-app misuse), put the unused `Errors::RuntimeError` to work for align_to's :error policy.
|
|
19
|
+
> ~70 bare `raise "string"` remain in lower-traffic IR-pipeline/dev paths. 971 specs, 50/50 goldens.
|
|
20
|
+
>
|
|
21
|
+
> **STATUS (2026-06-18): F1, F2, F3, F4, F5 DONE + location rendering unified.**
|
|
22
|
+
> Added `Errors::UnsupportedFeature` (a valid construct the backend can't emit) alongside
|
|
23
|
+
> `CompilerBug`. Converted the codegen "does not support opcode/shift-policy/inline" raises
|
|
24
|
+
> (Ruby + JS emitters) to `UnsupportedFeature`; converted the compiler accessor invariants
|
|
25
|
+
> ("unknown accessor mode/operation") and the binder/macro_expander/pass_manager contract
|
|
26
|
+
> invariants to `CompilerBug`. Unified all source-location rendering on one `file:line:col`
|
|
27
|
+
> format (Location#to_s is the single authority; ErrorEntry/LocatedError/PassFailure/SourceFrame
|
|
28
|
+
> all delegate; killed the double-location). Gated by error_reporting_spec + error_handling_spec.
|
|
29
|
+
> DISCOVERY: `compiler/access_planner.rb` (v1, 258 LOC) is DEAD — superseded by
|
|
30
|
+
> `AccessPlannerV2`, zero live refs, no specs; its 7 ArgumentError invariants were left
|
|
31
|
+
> untouched pending deletion (separate cleanup). Remaining: **F6**, **F7**, +delete dead v1.
|
|
32
|
+
> 969 specs, 50/50 goldens.
|
|
33
|
+
>
|
|
34
|
+
> **STATUS (2026-06-18): F1, F2, F4, F5 DONE.** A type mismatch now surfaces as exactly
|
|
35
|
+
> one located error with no internal leaks (was 3). Added `Errors::CompilerBug`; `PassBase`
|
|
36
|
+
> gained `report`/`halt_pass!` (via a `catch(HALT)` in PassManager) and lost the broken
|
|
37
|
+
> `error` footgun; removed the duplicate re-append in `analyzer.rb`; swept
|
|
38
|
+
> `nast_dimensional_analyzer_pass` + `snast_pass` + `ir_execution_schedule_pass` and the
|
|
39
|
+
> invariant lookups in `attach_anchors`/`attach_terminal_info`/`input_collector`/
|
|
40
|
+
> `precompute_access_paths` to CompilerBug. Rule documented in `PASSES.md`. Gated by
|
|
41
|
+
> `spec/kumi/core/analyzer/error_reporting_spec.rb`. Remaining: **F3** (codegen "does not
|
|
42
|
+
> support" capability raises — 7 sites), **F6**, **F7**. 965 specs, 50/50 goldens.
|
|
43
|
+
|
|
44
|
+
## F1 — Errors triple-report; located error buried under internal leaks ★★★ (highest impact)
|
|
45
|
+
|
|
46
|
+
**Evidence:** a single `add(string, string)` type mismatch surfaces THREE times to the user:
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
at s.kumi line=5 column=18: add(string, string) - type mismatch <- good, located
|
|
50
|
+
Error in Analysis Pass(NASTDimensionalAnalyzerPass) at .../nast_dimensional_analyzer_pass.rb:119: ... type mismatch
|
|
51
|
+
Error in Analysis Pass(NASTDimensionalAnalyzerPass) at .../nast_dimensional_analyzer_pass.rb:119: ... type mismatch
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**Root cause:** `NASTDimensionalAnalyzerPass` (and others) do BOTH
|
|
55
|
+
`report_type_error(errors, ...)` (accumulate, located) AND immediately `raise TypeError`
|
|
56
|
+
(`nast_dimensional_analyzer_pass.rb:108-128`, `:151`). `PassManager#capture_exception`
|
|
57
|
+
(`pass_manager.rb:148`) catches the raise and adds a SECOND error built from the backtrace
|
|
58
|
+
head (`Error in Analysis Pass(X) at <file:line>: …`) — leaking compiler internals + file
|
|
59
|
+
paths to the user. The duplication-to-three comes from the raise being captured and the
|
|
60
|
+
located error also flowing through.
|
|
61
|
+
|
|
62
|
+
**Fix:** pick ONE reporting channel per logical error. For user-facing errors: accumulate
|
|
63
|
+
via `report_*` and `return state` (or `throw`/sentinel to stop the pass) — do NOT also raise.
|
|
64
|
+
`capture_exception` should be reserved for genuine bugs (unexpected exceptions), and its
|
|
65
|
+
message should not be presented as a user error alongside located ones. Dedup errors before
|
|
66
|
+
`handle_analysis_errors` formats them.
|
|
67
|
+
|
|
68
|
+
## F2 — Location passed in the message string, not the structured field ★★★
|
|
69
|
+
|
|
70
|
+
**Evidence:** `snast_pass.rb:94` —
|
|
71
|
+
`raise SemanticError, "select mask axes ... at: #{n.loc}"`. The location is interpolated
|
|
72
|
+
into the text instead of `SemanticError.new(msg, n.loc)`, so `SourceFrame`/`PassFailure`
|
|
73
|
+
can't render a code frame and the coordinate can't be deduped.
|
|
74
|
+
|
|
75
|
+
**Also:** 14 sites do `raise Kumi::Core::Errors::SemanticError, "msg"` / `TypeError, "msg"`
|
|
76
|
+
with NO location arg at all (`snast_pass.rb:102,133,140,196,209`,
|
|
77
|
+
`nast_dimensional_analyzer_pass.rb:128,151,179,183,211,215,396`, `ir_execution_schedule_pass.rb:23,54`).
|
|
78
|
+
Each user-reachable one should pass the node's `loc`.
|
|
79
|
+
|
|
80
|
+
**Fix:** every `LocatedError` raised from a user-reachable condition passes `node.loc` as the
|
|
81
|
+
second arg; never interpolate location into the message.
|
|
82
|
+
|
|
83
|
+
## F3 — Bare `raise "string"` (RuntimeError) for both invariants and user errors ★★
|
|
84
|
+
|
|
85
|
+
**Evidence (14 sites):** `input_collector_pass.rb:120`, `attach_anchors_pass.rb:60,70,90`,
|
|
86
|
+
`attach_terminal_info_pass.rb:36`, `snast_pass.rb:102`, `nast_dimensional_analyzer_pass.rb:69,344`,
|
|
87
|
+
`precompute_access_paths_pass.rb:76` (`raise ArgumentError, "order"` — opaque), the three
|
|
88
|
+
codegen emitters (`"… codegen does not support …"`).
|
|
89
|
+
|
|
90
|
+
Two distinct intents are conflated:
|
|
91
|
+
- **Internal invariants** ("unknown parent container", "no anchor for axes") — "can't happen"
|
|
92
|
+
bugs. These SHOULD raise, but as a dedicated `Kumi::Core::Errors::CompilerBug` (new) so
|
|
93
|
+
they're never mistaken for user errors and carry a "please report" framing.
|
|
94
|
+
- **Capability limits** (codegen "does not support opcode X") — these are real, expected
|
|
95
|
+
conditions; should be a typed error with the offending opcode/policy, not a bare string.
|
|
96
|
+
|
|
97
|
+
**Fix:** introduce `CompilerBug < Error` for invariants; convert capability raises to a typed
|
|
98
|
+
`Errors::UnsupportedFeature` (or reuse `CompilationError`) with structured context.
|
|
99
|
+
|
|
100
|
+
## F4 — `PassBase#error` helper is a footgun (reads unset `@errors`) ★★
|
|
101
|
+
|
|
102
|
+
**Evidence:** `pass_base.rb:113-116` — `def error(...) add_error(@errors, ...)`. `@errors`
|
|
103
|
+
is never assigned by `PassBase`; `run(errors)` passes the accumulator as an ARGUMENT. Only
|
|
104
|
+
`snast_pass.rb:17` sets `@errors` manually (then ignores it and raises anyway). No other pass
|
|
105
|
+
calls `error`. So the base helper silently pushes to `nil` for any pass that uses it without
|
|
106
|
+
the undocumented `@errors =` ritual.
|
|
107
|
+
|
|
108
|
+
**Fix:** either (a) remove the broken `error`/`add_error` instance helpers from `PassBase` and
|
|
109
|
+
standardize on the `ErrorReporting` mixin's `report_*(errors, …)` (explicit accumulator), or
|
|
110
|
+
(b) make `PassBase#run` store `@errors = errors` via a `super`/template method so `error`
|
|
111
|
+
works. Prefer (a) — explicit accumulator threading matches the rest of the codebase.
|
|
112
|
+
|
|
113
|
+
## F5 — Two reporting idioms split the pipeline in half ★★
|
|
114
|
+
|
|
115
|
+
**Evidence:** ~15 passes take `run(errors)` and accumulate; ~14 take `run(_errors)` and only
|
|
116
|
+
`raise`. The accumulator path enables multi-error reporting + located `PassFailure`; the raise
|
|
117
|
+
path gives single-error, degraded `capture_exception` output. The split is not by intent
|
|
118
|
+
(validation vs lowering) — it's incidental.
|
|
119
|
+
|
|
120
|
+
**Fix:** document the rule in `PASSES.md` ("user-reachable errors accumulate; invariants
|
|
121
|
+
raise `CompilerBug`"), then bring the raise-only validators in line. Lowering passes that only
|
|
122
|
+
hit invariants legitimately keep `_errors`.
|
|
123
|
+
|
|
124
|
+
## F6 — `FormalConstraintPropagator` misfiled in `passes/`, breaks naming convention ★
|
|
125
|
+
|
|
126
|
+
**Evidence:** `passes/formal_constraint_propagator.rb` — class `FormalConstraintPropagator`,
|
|
127
|
+
no `Pass` suffix, not a `PassBase`, not in any pipeline list. It's a COLLABORATOR used by
|
|
128
|
+
`UnsatDetectorPass:19`. It also carries the banned `# RESPONSIBILITY:/DEPENDENCIES:/INTERFACE:`
|
|
129
|
+
header comment (cousin of the `# In:/# Out:` ban in PASSES.md).
|
|
130
|
+
|
|
131
|
+
**Fix:** move it to `lib/kumi/core/analyzer/` (alongside `binder.rb`, `folder.rb`,
|
|
132
|
+
`constant_evaluator.rb`) so `passes/` contains only passes; drop the header comment.
|
|
133
|
+
|
|
134
|
+
## F7 — Codegen emitters duplicate structure (JS 410 / Ruby 212 LOC) ★ (lower priority, higher risk)
|
|
135
|
+
|
|
136
|
+
**Evidence:** `codegen/loop/js/emitter.rb` and `codegen/loop/ruby/emitter.rb` share a parallel
|
|
137
|
+
method skeleton (`emit_instruction`, `emit_function`, `emit_acc_step`, `emit_shift_read`,
|
|
138
|
+
`apply_inline`, `kernel_expr`, `format_literal`, `format_object`, `tuple_keys?`, `reg`) and the
|
|
139
|
+
same opcode-dispatch + "does not support" raise pattern, but emit different target syntax.
|
|
140
|
+
|
|
141
|
+
**Assessment:** real duplication, but target languages legitimately diverge; over-abstraction
|
|
142
|
+
here is a known trap. Recommend a SMALL shared base (opcode dispatch table + the unsupported-
|
|
143
|
+
opcode raise via F3's typed error + register/scratch naming), NOT a unified emitter. Defer
|
|
144
|
+
until F1–F5 land; treat as opportunistic.
|
|
145
|
+
|
|
146
|
+
## F8 — Two error modules with overlapping names ★ (note, not necessarily a change)
|
|
147
|
+
|
|
148
|
+
`Core::ErrorReporting` (instance mixin: `report_*`, `raise_*`) vs `Core::ErrorReporter`
|
|
149
|
+
(module: `create_error`, `add_error`, `raise_error`, `ErrorEntry`). The split is defensible
|
|
150
|
+
(mixin vs factory) but the near-identical names invite confusion. Consider renaming the mixin
|
|
151
|
+
to `ErrorReportable` OR documenting the boundary in one place. Low priority.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Plan (ordered by impact, each independently shippable & test-gated)
|
|
156
|
+
|
|
157
|
+
1. **F1+F2+F4+F5 together (the error-model fix)** — the highest-value, coherent change:
|
|
158
|
+
- Add `CompilerBug` error class.
|
|
159
|
+
- Establish the rule: user-reachable → accumulate located error + stop pass cleanly;
|
|
160
|
+
invariant → raise `CompilerBug`. Document in `PASSES.md`.
|
|
161
|
+
- Remove/fix the `PassBase#error` footgun.
|
|
162
|
+
- Sweep `nast_dimensional_analyzer_pass` and `snast_pass` first (they cause the visible
|
|
163
|
+
triple-report), then the rest of the raise-only validators.
|
|
164
|
+
- Dedup errors in `analyzer.rb` before formatting.
|
|
165
|
+
- **Net user-visible win:** one clean, located error instead of three with leaked internals.
|
|
166
|
+
- Gate: new spec asserting the type-mismatch case yields exactly ONE located error with no
|
|
167
|
+
`Error in Analysis Pass(...)` / no internal file paths.
|
|
168
|
+
|
|
169
|
+
2. **F3** — typed errors for invariants (`CompilerBug`) and capability limits
|
|
170
|
+
(`UnsupportedFeature`/`CompilationError`) across passes + codegen emitters.
|
|
171
|
+
|
|
172
|
+
3. **F6** — relocate `FormalConstraintPropagator` out of `passes/`.
|
|
173
|
+
|
|
174
|
+
4. **F7** — opportunistic small shared codegen base (only after 1–3, only if low-risk).
|
|
175
|
+
|
|
176
|
+
5. **F8** — naming/doc clarification (optional).
|
|
177
|
+
|
|
178
|
+
Non-goals: rewriting the pass framework (it's sound), reordering the pipeline, touching IR
|
|
179
|
+
pass internals beyond error reporting.
|