kumi 0.0.31 → 0.0.33

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 (294) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -1
  3. data/README.md +31 -99
  4. data/data/kernels/ruby/core/arithmetic.yaml +2 -2
  5. data/docs/COMPOSED_SCHEMAS.md +137 -0
  6. data/docs/SCHEMA_IMPORTS.md +275 -0
  7. data/docs/SYNTAX.md +48 -0
  8. data/golden/array_element/expected/schema_ruby.rb +2 -27
  9. data/golden/array_index/expected/nast.txt +6 -6
  10. data/golden/array_index/expected/schema_ruby.rb +4 -31
  11. data/golden/array_operations/expected/lir_06_const_prop.txt +4 -8
  12. data/golden/array_operations/expected/schema_javascript.mjs +4 -8
  13. data/golden/array_operations/expected/schema_ruby.rb +10 -43
  14. data/golden/cascade_logic/expected/lir_06_const_prop.txt +7 -14
  15. data/golden/cascade_logic/expected/schema_javascript.mjs +7 -14
  16. data/golden/cascade_logic/expected/schema_ruby.rb +11 -45
  17. data/golden/chained_fusion/expected/lir_06_const_prop.txt +8 -18
  18. data/golden/chained_fusion/expected/schema_javascript.mjs +8 -18
  19. data/golden/chained_fusion/expected/schema_ruby.rb +14 -53
  20. data/golden/decimal_explicit/expected/schema_ruby.rb +4 -31
  21. data/golden/element_arrays/expected/lir_06_const_prop.txt +5 -11
  22. data/golden/element_arrays/expected/schema_javascript.mjs +5 -11
  23. data/golden/element_arrays/expected/schema_ruby.rb +13 -50
  24. data/golden/empty_and_null_inputs/expected/schema_ruby.rb +4 -31
  25. data/golden/example_xpto/expected/ast.txt +23 -0
  26. data/golden/example_xpto/expected/input_plan.txt +1 -0
  27. data/golden/example_xpto/expected/lir_00_unoptimized.txt +16 -0
  28. data/golden/example_xpto/expected/lir_01_hoist_scalar_references.txt +16 -0
  29. data/golden/example_xpto/expected/lir_02_inlined.txt +16 -0
  30. data/golden/example_xpto/expected/lir_03_cse.txt +16 -0
  31. data/golden/example_xpto/expected/lir_04_1_loop_fusion.txt +16 -0
  32. data/golden/example_xpto/expected/lir_04_loop_invcm.txt +16 -0
  33. data/golden/example_xpto/expected/lir_06_const_prop.txt +13 -0
  34. data/golden/example_xpto/expected/nast.txt +17 -0
  35. data/golden/example_xpto/expected/schema_javascript.mjs +13 -0
  36. data/golden/example_xpto/expected/schema_ruby.rb +13 -0
  37. data/golden/example_xpto/expected/snast.txt +17 -0
  38. data/golden/example_xpto/expected.json +4 -0
  39. data/golden/example_xpto/input.json +3 -0
  40. data/golden/example_xpto/schema.kumi +8 -0
  41. data/golden/function_overload/expected/schema_ruby.rb +2 -27
  42. data/golden/game_of_life/expected/lir_06_const_prop.txt +236 -287
  43. data/golden/game_of_life/expected/schema_javascript.mjs +32 -39
  44. data/golden/game_of_life/expected/schema_ruby.rb +34 -66
  45. data/golden/hash_keys/expected/lir_06_const_prop.txt +4 -10
  46. data/golden/hash_keys/expected/schema_javascript.mjs +6 -12
  47. data/golden/hash_keys/expected/schema_ruby.rb +8 -39
  48. data/golden/hash_value/expected/lir_06_const_prop.txt +3 -6
  49. data/golden/hash_value/expected/schema_javascript.mjs +3 -6
  50. data/golden/hash_value/expected/schema_ruby.rb +7 -37
  51. data/golden/hierarchical_complex/expected/lir_06_const_prop.txt +9 -18
  52. data/golden/hierarchical_complex/expected/schema_javascript.mjs +9 -18
  53. data/golden/hierarchical_complex/expected/schema_ruby.rb +14 -51
  54. data/golden/inline_rename_scope_leak/expected/lir_06_const_prop.txt +2 -6
  55. data/golden/inline_rename_scope_leak/expected/schema_javascript.mjs +2 -6
  56. data/golden/inline_rename_scope_leak/expected/schema_ruby.rb +7 -39
  57. data/golden/input_reference/expected/schema_ruby.rb +6 -35
  58. data/golden/interleaved_fusion/expected/lir_06_const_prop.txt +6 -14
  59. data/golden/interleaved_fusion/expected/schema_javascript.mjs +6 -14
  60. data/golden/interleaved_fusion/expected/schema_ruby.rb +11 -47
  61. data/golden/let_inline/expected/lir_06_const_prop.txt +1 -2
  62. data/golden/let_inline/expected/schema_javascript.mjs +1 -2
  63. data/golden/let_inline/expected/schema_ruby.rb +3 -29
  64. data/golden/loop_fusion/expected/lir_06_const_prop.txt +4 -10
  65. data/golden/loop_fusion/expected/schema_javascript.mjs +4 -10
  66. data/golden/loop_fusion/expected/schema_ruby.rb +8 -41
  67. data/golden/min_reduce_scope/expected/lir_06_const_prop.txt +3 -6
  68. data/golden/min_reduce_scope/expected/schema_javascript.mjs +3 -6
  69. data/golden/min_reduce_scope/expected/schema_ruby.rb +8 -39
  70. data/golden/mixed_dimensions/expected/lir_06_const_prop.txt +1 -2
  71. data/golden/mixed_dimensions/expected/schema_javascript.mjs +1 -2
  72. data/golden/mixed_dimensions/expected/schema_ruby.rb +5 -33
  73. data/golden/multirank_hoisting/expected/lir_06_const_prop.txt +9 -18
  74. data/golden/multirank_hoisting/expected/schema_javascript.mjs +9 -18
  75. data/golden/multirank_hoisting/expected/schema_ruby.rb +16 -55
  76. data/golden/nested_hash/expected/lir_06_const_prop.txt +1 -2
  77. data/golden/nested_hash/expected/schema_javascript.mjs +1 -2
  78. data/golden/nested_hash/expected/schema_ruby.rb +3 -29
  79. data/golden/reduction_broadcast/expected/schema_ruby.rb +5 -33
  80. data/golden/roll/expected/lir_06_const_prop.txt +8 -15
  81. data/golden/roll/expected/schema_javascript.mjs +8 -15
  82. data/golden/roll/expected/schema_ruby.rb +13 -48
  83. data/golden/schema_imports_broadcasting_with_imports/expected/ast.txt +26 -0
  84. data/golden/schema_imports_broadcasting_with_imports/expected/input_plan.txt +5 -0
  85. data/golden/schema_imports_broadcasting_with_imports/expected/lir_00_unoptimized.txt +20 -0
  86. data/golden/schema_imports_broadcasting_with_imports/expected/lir_01_hoist_scalar_references.txt +20 -0
  87. data/golden/schema_imports_broadcasting_with_imports/expected/lir_02_inlined.txt +22 -0
  88. data/golden/schema_imports_broadcasting_with_imports/expected/lir_03_cse.txt +21 -0
  89. data/golden/schema_imports_broadcasting_with_imports/expected/lir_04_1_loop_fusion.txt +21 -0
  90. data/golden/schema_imports_broadcasting_with_imports/expected/lir_04_loop_invcm.txt +21 -0
  91. data/golden/schema_imports_broadcasting_with_imports/expected/lir_06_const_prop.txt +21 -0
  92. data/golden/schema_imports_broadcasting_with_imports/expected/nast.txt +12 -0
  93. data/golden/schema_imports_broadcasting_with_imports/expected/schema_javascript.mjs +22 -0
  94. data/golden/schema_imports_broadcasting_with_imports/expected/schema_ruby.rb +24 -0
  95. data/golden/schema_imports_broadcasting_with_imports/expected/snast.txt +12 -0
  96. data/golden/schema_imports_broadcasting_with_imports/expected.json +4 -0
  97. data/golden/schema_imports_broadcasting_with_imports/input.json +7 -0
  98. data/golden/schema_imports_broadcasting_with_imports/schema.kumi +14 -0
  99. data/golden/schema_imports_complex_order_calc/expected/ast.txt +82 -0
  100. data/golden/schema_imports_complex_order_calc/expected/input_plan.txt +16 -0
  101. data/golden/schema_imports_complex_order_calc/expected/lir_00_unoptimized.txt +94 -0
  102. data/golden/schema_imports_complex_order_calc/expected/lir_01_hoist_scalar_references.txt +94 -0
  103. data/golden/schema_imports_complex_order_calc/expected/lir_02_inlined.txt +187 -0
  104. data/golden/schema_imports_complex_order_calc/expected/lir_03_cse.txt +131 -0
  105. data/golden/schema_imports_complex_order_calc/expected/lir_04_1_loop_fusion.txt +131 -0
  106. data/golden/schema_imports_complex_order_calc/expected/lir_04_loop_invcm.txt +131 -0
  107. data/golden/schema_imports_complex_order_calc/expected/lir_06_const_prop.txt +131 -0
  108. data/golden/schema_imports_complex_order_calc/expected/nast.txt +56 -0
  109. data/golden/schema_imports_complex_order_calc/expected/schema_javascript.mjs +147 -0
  110. data/golden/schema_imports_complex_order_calc/expected/schema_ruby.rb +149 -0
  111. data/golden/schema_imports_complex_order_calc/expected/snast.txt +56 -0
  112. data/golden/schema_imports_complex_order_calc/expected.json +12 -0
  113. data/golden/schema_imports_complex_order_calc/input.json +20 -0
  114. data/golden/schema_imports_complex_order_calc/schema.kumi +33 -0
  115. data/golden/schema_imports_composed_order/expected/ast.txt +33 -0
  116. data/golden/schema_imports_composed_order/expected/input_plan.txt +3 -0
  117. data/golden/schema_imports_composed_order/expected/lir_00_unoptimized.txt +25 -0
  118. data/golden/schema_imports_composed_order/expected/lir_01_hoist_scalar_references.txt +25 -0
  119. data/golden/schema_imports_composed_order/expected/lir_02_inlined.txt +33 -0
  120. data/golden/schema_imports_composed_order/expected/lir_03_cse.txt +33 -0
  121. data/golden/schema_imports_composed_order/expected/lir_04_1_loop_fusion.txt +33 -0
  122. data/golden/schema_imports_composed_order/expected/lir_04_loop_invcm.txt +33 -0
  123. data/golden/schema_imports_composed_order/expected/lir_06_const_prop.txt +33 -0
  124. data/golden/schema_imports_composed_order/expected/nast.txt +25 -0
  125. data/golden/schema_imports_composed_order/expected/schema_javascript.mjs +35 -0
  126. data/golden/schema_imports_composed_order/expected/schema_ruby.rb +33 -0
  127. data/golden/schema_imports_composed_order/expected/snast.txt +25 -0
  128. data/golden/schema_imports_composed_order/expected.json +6 -0
  129. data/golden/schema_imports_composed_order/input.json +5 -0
  130. data/golden/schema_imports_composed_order/schema.kumi +15 -0
  131. data/golden/schema_imports_discount_with_tax/expected/ast.txt +37 -0
  132. data/golden/schema_imports_discount_with_tax/expected/input_plan.txt +2 -0
  133. data/golden/schema_imports_discount_with_tax/expected/lir_00_unoptimized.txt +30 -0
  134. data/golden/schema_imports_discount_with_tax/expected/lir_01_hoist_scalar_references.txt +30 -0
  135. data/golden/schema_imports_discount_with_tax/expected/lir_02_inlined.txt +37 -0
  136. data/golden/schema_imports_discount_with_tax/expected/lir_03_cse.txt +34 -0
  137. data/golden/schema_imports_discount_with_tax/expected/lir_04_1_loop_fusion.txt +34 -0
  138. data/golden/schema_imports_discount_with_tax/expected/lir_04_loop_invcm.txt +34 -0
  139. data/golden/schema_imports_discount_with_tax/expected/lir_06_const_prop.txt +34 -0
  140. data/golden/schema_imports_discount_with_tax/expected/nast.txt +30 -0
  141. data/golden/schema_imports_discount_with_tax/expected/schema_javascript.mjs +37 -0
  142. data/golden/schema_imports_discount_with_tax/expected/schema_ruby.rb +34 -0
  143. data/golden/schema_imports_discount_with_tax/expected/snast.txt +30 -0
  144. data/golden/schema_imports_discount_with_tax/expected.json +7 -0
  145. data/golden/schema_imports_discount_with_tax/input.json +4 -0
  146. data/golden/schema_imports_discount_with_tax/schema.kumi +15 -0
  147. data/golden/schema_imports_line_items/expected/ast.txt +35 -0
  148. data/golden/schema_imports_line_items/expected/input_plan.txt +8 -0
  149. data/golden/schema_imports_line_items/expected/lir_00_unoptimized.txt +19 -0
  150. data/golden/schema_imports_line_items/expected/lir_01_hoist_scalar_references.txt +19 -0
  151. data/golden/schema_imports_line_items/expected/lir_02_inlined.txt +24 -0
  152. data/golden/schema_imports_line_items/expected/lir_03_cse.txt +22 -0
  153. data/golden/schema_imports_line_items/expected/lir_04_1_loop_fusion.txt +22 -0
  154. data/golden/schema_imports_line_items/expected/lir_04_loop_invcm.txt +22 -0
  155. data/golden/schema_imports_line_items/expected/lir_06_const_prop.txt +22 -0
  156. data/golden/schema_imports_line_items/expected/nast.txt +19 -0
  157. data/golden/schema_imports_line_items/expected/schema_javascript.mjs +23 -0
  158. data/golden/schema_imports_line_items/expected/schema_ruby.rb +22 -0
  159. data/golden/schema_imports_line_items/expected/snast.txt +19 -0
  160. data/golden/schema_imports_line_items/expected.json +5 -0
  161. data/golden/schema_imports_line_items/input.json +13 -0
  162. data/golden/schema_imports_line_items/schema.kumi +17 -0
  163. data/golden/schema_imports_multiple/expected/ast.txt +35 -0
  164. data/golden/schema_imports_multiple/expected/input_plan.txt +2 -0
  165. data/golden/schema_imports_multiple/expected/lir_00_unoptimized.txt +29 -0
  166. data/golden/schema_imports_multiple/expected/lir_01_hoist_scalar_references.txt +29 -0
  167. data/golden/schema_imports_multiple/expected/lir_02_inlined.txt +41 -0
  168. data/golden/schema_imports_multiple/expected/lir_03_cse.txt +37 -0
  169. data/golden/schema_imports_multiple/expected/lir_04_1_loop_fusion.txt +37 -0
  170. data/golden/schema_imports_multiple/expected/lir_04_loop_invcm.txt +37 -0
  171. data/golden/schema_imports_multiple/expected/lir_06_const_prop.txt +37 -0
  172. data/golden/schema_imports_multiple/expected/nast.txt +28 -0
  173. data/golden/schema_imports_multiple/expected/schema_javascript.mjs +40 -0
  174. data/golden/schema_imports_multiple/expected/schema_ruby.rb +37 -0
  175. data/golden/schema_imports_multiple/expected/snast.txt +28 -0
  176. data/golden/schema_imports_multiple/expected.json +7 -0
  177. data/golden/schema_imports_multiple/input.json +4 -0
  178. data/golden/schema_imports_multiple/schema.kumi +15 -0
  179. data/golden/schema_imports_nested_expressions/expected/ast.txt +31 -0
  180. data/golden/schema_imports_nested_expressions/expected/input_plan.txt +3 -0
  181. data/golden/schema_imports_nested_expressions/expected/lir_00_unoptimized.txt +22 -0
  182. data/golden/schema_imports_nested_expressions/expected/lir_01_hoist_scalar_references.txt +22 -0
  183. data/golden/schema_imports_nested_expressions/expected/lir_02_inlined.txt +32 -0
  184. data/golden/schema_imports_nested_expressions/expected/lir_03_cse.txt +32 -0
  185. data/golden/schema_imports_nested_expressions/expected/lir_04_1_loop_fusion.txt +32 -0
  186. data/golden/schema_imports_nested_expressions/expected/lir_04_loop_invcm.txt +32 -0
  187. data/golden/schema_imports_nested_expressions/expected/lir_06_const_prop.txt +28 -0
  188. data/golden/schema_imports_nested_expressions/expected/nast.txt +23 -0
  189. data/golden/schema_imports_nested_expressions/expected/schema_javascript.mjs +29 -0
  190. data/golden/schema_imports_nested_expressions/expected/schema_ruby.rb +28 -0
  191. data/golden/schema_imports_nested_expressions/expected/snast.txt +23 -0
  192. data/golden/schema_imports_nested_expressions/expected.json +5 -0
  193. data/golden/schema_imports_nested_expressions/input.json +5 -0
  194. data/golden/schema_imports_nested_expressions/schema.kumi +13 -0
  195. data/golden/schema_imports_nested_with_reductions/expected/ast.txt +47 -0
  196. data/golden/schema_imports_nested_with_reductions/expected/input_plan.txt +12 -0
  197. data/golden/schema_imports_nested_with_reductions/expected/lir_00_unoptimized.txt +31 -0
  198. data/golden/schema_imports_nested_with_reductions/expected/lir_01_hoist_scalar_references.txt +31 -0
  199. data/golden/schema_imports_nested_with_reductions/expected/lir_02_inlined.txt +58 -0
  200. data/golden/schema_imports_nested_with_reductions/expected/lir_03_cse.txt +49 -0
  201. data/golden/schema_imports_nested_with_reductions/expected/lir_04_1_loop_fusion.txt +51 -0
  202. data/golden/schema_imports_nested_with_reductions/expected/lir_04_loop_invcm.txt +49 -0
  203. data/golden/schema_imports_nested_with_reductions/expected/lir_06_const_prop.txt +49 -0
  204. data/golden/schema_imports_nested_with_reductions/expected/nast.txt +23 -0
  205. data/golden/schema_imports_nested_with_reductions/expected/schema_javascript.mjs +49 -0
  206. data/golden/schema_imports_nested_with_reductions/expected/schema_ruby.rb +52 -0
  207. data/golden/schema_imports_nested_with_reductions/expected/snast.txt +23 -0
  208. data/golden/schema_imports_nested_with_reductions/expected.json +6 -0
  209. data/golden/schema_imports_nested_with_reductions/input.json +16 -0
  210. data/golden/schema_imports_nested_with_reductions/schema.kumi +23 -0
  211. data/golden/schema_imports_with_imports/expected/ast.txt +19 -0
  212. data/golden/schema_imports_with_imports/expected/input_plan.txt +1 -0
  213. data/golden/schema_imports_with_imports/expected/lir_00_unoptimized.txt +13 -0
  214. data/golden/schema_imports_with_imports/expected/lir_01_hoist_scalar_references.txt +13 -0
  215. data/golden/schema_imports_with_imports/expected/lir_02_inlined.txt +14 -0
  216. data/golden/schema_imports_with_imports/expected/lir_03_cse.txt +13 -0
  217. data/golden/schema_imports_with_imports/expected/lir_04_1_loop_fusion.txt +13 -0
  218. data/golden/schema_imports_with_imports/expected/lir_04_loop_invcm.txt +13 -0
  219. data/golden/schema_imports_with_imports/expected/lir_06_const_prop.txt +13 -0
  220. data/golden/schema_imports_with_imports/expected/nast.txt +13 -0
  221. data/golden/schema_imports_with_imports/expected/schema_javascript.mjs +13 -0
  222. data/golden/schema_imports_with_imports/expected/schema_ruby.rb +13 -0
  223. data/golden/schema_imports_with_imports/expected/snast.txt +13 -0
  224. data/golden/schema_imports_with_imports/expected.json +4 -0
  225. data/golden/schema_imports_with_imports/input.json +3 -0
  226. data/golden/schema_imports_with_imports/schema.kumi +10 -0
  227. data/golden/shift/expected/lir_06_const_prop.txt +18 -30
  228. data/golden/shift/expected/schema_javascript.mjs +18 -30
  229. data/golden/shift/expected/schema_ruby.rb +25 -67
  230. data/golden/shift_2d/expected/lir_06_const_prop.txt +36 -60
  231. data/golden/shift_2d/expected/schema_javascript.mjs +36 -60
  232. data/golden/shift_2d/expected/schema_ruby.rb +49 -109
  233. data/golden/simple_math/expected/lir_06_const_prop.txt +3 -6
  234. data/golden/simple_math/expected/schema_javascript.mjs +3 -6
  235. data/golden/simple_math/expected/schema_ruby.rb +8 -39
  236. data/golden/streaming_basics/expected/lir_06_const_prop.txt +6 -12
  237. data/golden/streaming_basics/expected/schema_javascript.mjs +6 -12
  238. data/golden/streaming_basics/expected/schema_ruby.rb +14 -51
  239. data/golden/tuples/expected/lir_06_const_prop.txt +5 -22
  240. data/golden/tuples/expected/schema_javascript.mjs +5 -22
  241. data/golden/tuples/expected/schema_ruby.rb +11 -57
  242. data/golden/tuples_and_arrays/expected/lir_06_const_prop.txt +4 -8
  243. data/golden/tuples_and_arrays/expected/schema_javascript.mjs +4 -8
  244. data/golden/tuples_and_arrays/expected/schema_ruby.rb +9 -41
  245. data/golden/us_tax_2024/expected/lir_06_const_prop.txt +94 -171
  246. data/golden/us_tax_2024/expected/schema_javascript.mjs +13 -21
  247. data/golden/us_tax_2024/expected/schema_ruby.rb +15 -48
  248. data/golden/with_constants/expected/lir_06_const_prop.txt +3 -8
  249. data/golden/with_constants/expected/schema_javascript.mjs +3 -8
  250. data/golden/with_constants/expected/schema_ruby.rb +5 -35
  251. data/lib/kumi/analyzer.rb +8 -7
  252. data/lib/kumi/configuration.rb +7 -6
  253. data/lib/kumi/core/analyzer/passes/attach_anchors_pass.rb +1 -1
  254. data/lib/kumi/core/analyzer/passes/attach_terminal_info_pass.rb +1 -1
  255. data/lib/kumi/core/analyzer/passes/codegen/js/declaration_emitter.rb +20 -0
  256. data/lib/kumi/core/analyzer/passes/codegen/ruby/declaration_emitter.rb +16 -7
  257. data/lib/kumi/core/analyzer/passes/codegen/ruby/output_buffer.rb +3 -35
  258. data/lib/kumi/core/analyzer/passes/dependency_resolver.rb +6 -0
  259. data/lib/kumi/core/analyzer/passes/import_analysis_pass.rb +90 -0
  260. data/lib/kumi/core/analyzer/passes/lir/constant_propagation_pass.rb +77 -36
  261. data/lib/kumi/core/analyzer/passes/lir/lower_pass.rb +26 -11
  262. data/lib/kumi/core/analyzer/passes/name_indexer.rb +20 -2
  263. data/lib/kumi/core/analyzer/passes/nast_dimensional_analyzer_pass.rb +44 -0
  264. data/lib/kumi/core/analyzer/passes/normalize_to_nast_pass.rb +30 -0
  265. data/lib/kumi/core/analyzer/passes/semantic_constraint_validator.rb +5 -1
  266. data/lib/kumi/core/analyzer/passes/snast_pass.rb +15 -0
  267. data/lib/kumi/core/lir/build.rb +27 -0
  268. data/lib/kumi/core/lir/peephole.rb +164 -0
  269. data/lib/kumi/core/nast.rb +16 -0
  270. data/lib/kumi/core/ruby_parser/build_context.rb +3 -1
  271. data/lib/kumi/core/ruby_parser/parser.rb +1 -1
  272. data/lib/kumi/core/ruby_parser/schema_builder.rb +33 -3
  273. data/lib/kumi/dev/golden/result.rb +9 -3
  274. data/lib/kumi/dev/golden/runtime_test.rb +16 -1
  275. data/lib/kumi/dev/golden.rb +18 -20
  276. data/lib/kumi/dev/golden_schema_modules.rb +8 -0
  277. data/lib/kumi/dev/golden_schema_wrapper.rb +116 -0
  278. data/lib/kumi/dev/support/kumi_runner.mjs +18 -0
  279. data/lib/kumi/schema.rb +44 -2
  280. data/lib/kumi/support/lir_printer.rb +21 -5
  281. data/lib/kumi/support/nast_printer.rb +11 -0
  282. data/lib/kumi/support/s_expression_printer.rb +9 -0
  283. data/lib/kumi/support/snast_printer.rb +6 -0
  284. data/lib/kumi/syntax/import_call.rb +11 -0
  285. data/lib/kumi/syntax/import_declaration.rb +11 -0
  286. data/lib/kumi/syntax/root.rb +2 -2
  287. data/lib/kumi/test_shared_schemas/compound.rb +21 -0
  288. data/lib/kumi/test_shared_schemas/discount.rb +19 -0
  289. data/lib/kumi/test_shared_schemas/price.rb +19 -0
  290. data/lib/kumi/test_shared_schemas/subtotal.rb +22 -0
  291. data/lib/kumi/test_shared_schemas/tax.rb +18 -0
  292. data/lib/kumi/version.rb +1 -1
  293. data/lib/kumi.rb +19 -4
  294. metadata +176 -3
@@ -1,22 +1,16 @@
1
1
  export function _summary(input) {
2
2
  let out = [];
3
3
  let t974 = input["income"];
4
- const t975 = 168600.0;
5
- let t976 = [t974, t975];
4
+ let t976 = [t974, 168600.0];
6
5
  let t977 = Math.min(...t976);
7
- const t978 = 0.062;
8
- let t979 = t977 * t978;
9
- const t981 = 0.0145;
10
- let t982 = t974 * t981;
6
+ let t979 = t977 * 0.062;
7
+ let t982 = t974 * 0.0145;
11
8
  let t1032 = input["state_rate"];
12
9
  let t1033 = t974 * t1032;
13
10
  let t1035 = input["local_rate"];
14
11
  let t1036 = t974 * t1035;
15
12
  let t181 = input["statuses"];
16
- const t824 = 0;
17
- const t857 = 1.0;
18
13
  let t971 = t979 + t982;
19
- const t990 = 0.009;
20
14
  let t195 = {
21
15
  "marginal": t1032,
22
16
  "effective": t1032,
@@ -28,9 +22,7 @@ export function _summary(input) {
28
22
  "tax": t1036
29
23
  };
30
24
  let t204 = input["retirement_contrib"];
31
- const t840 = -1;
32
- const t842 = 100000000000.0;
33
- let t858 = [t974, t857];
25
+ let t858 = [t974, 1.0];
34
26
  let t859 = Math.max(...t858);
35
27
  t181.forEach((statuses_el_182, statuses_i_183) => {
36
28
  let t184 = statuses_el_182["name"];
@@ -46,31 +38,31 @@ export function _summary(input) {
46
38
  let acc1315 = 0.0;
47
39
  let t823 = t974 - t822;
48
40
  let t986 = t974 - t985;
49
- let t825 = [t823, t824];
50
- let t988 = [t986, t824];
41
+ let t825 = [t823, 0];
42
+ let t988 = [t986, 0];
51
43
  let t826 = Math.max(...t825);
52
44
  let t989 = Math.max(...t988);
53
45
  t803.forEach((t804, t805) => {
54
46
  let t829 = t804["lo"];
55
47
  let t815 = t826 >= t829;
56
48
  let t847 = t804["hi"];
57
- let t841 = t847 == t840;
58
- let t844 = t841 ? t842 : t847;
49
+ let t841 = t847 == -1;
50
+ let t844 = t841 ? 100000000000.0 : t847;
59
51
  let t818 = t826 < t844;
60
52
  let t819 = t815 && t818;
61
53
  let t853 = t804["rate"];
62
- let t809 = t819 ? t853 : t824;
54
+ let t809 = t819 ? t853 : 0;
63
55
  acc802 += t809;
64
56
  });
65
- let t991 = t989 * t990;
57
+ let t991 = t989 * 0.009;
66
58
  t803.forEach((t865, t866) => {
67
59
  let t890 = t865["lo"];
68
60
  let t875 = t826 - t890;
69
61
  let t901 = t865["hi"];
70
- let t895 = t901 == t840;
71
- let t898 = t895 ? t842 : t901;
62
+ let t895 = t901 == -1;
63
+ let t898 = t895 ? 100000000000.0 : t901;
72
64
  let t879 = t898 - t890;
73
- let t880 = Math.min(Math.max(t875, t824), t879);
65
+ let t880 = Math.min(Math.max(t875, 0), t879);
74
66
  let t910 = t865["rate"];
75
67
  let t869 = t880 * t910;
76
68
  acc863 += t869;
@@ -1,49 +1,18 @@
1
1
  # Autogenerated by Kumi Codegen
2
- module Kumi::Compiled::KUMI_f570bd1470fbdb4fe98673449f7d2106c6eeb0a11dbd0d656e2d19485860c206
3
- def self.from(input_data = nil)
4
- instance = Object.new
5
- instance.extend(self)
6
- instance.instance_variable_set(:@input, input_data)
7
- instance
8
- end
9
-
10
- def self.__kumi_executable__
11
- instance = Object.new
12
- instance.extend(self)
13
- instance
14
- end
15
-
16
- def update(input_data)
17
- @input = @input.merge(input_data)
18
- self
19
- end
20
-
21
- def [](name)
22
- case name
23
- when :summary then _summary
24
- else raise KeyError, "Unknown declaration"
25
- end
26
- end
27
-
28
- def _summary(input = @input)
2
+ module Kumi::Compiled::KUMI_f93cd7180a38afa538b4e27322ce1f862595fccb54611929cd3b3d32b7a0a7f0
3
+ def self._summary(input)
29
4
  out = []
30
5
  t974 = input["income"] || input[:income]
31
- t975 = 168600.0
32
- t976 = [t974, t975]
6
+ t976 = [t974, 168600.0]
33
7
  t977 = t976.min
34
- t978 = 0.062
35
- t979 = t977 * t978
36
- t981 = 0.0145
37
- t982 = t974 * t981
8
+ t979 = t977 * 0.062
9
+ t982 = t974 * 0.0145
38
10
  t1032 = input["state_rate"] || input[:state_rate]
39
11
  t1033 = t974 * t1032
40
12
  t1035 = input["local_rate"] || input[:local_rate]
41
13
  t1036 = t974 * t1035
42
14
  t181 = input["statuses"] || input[:statuses]
43
- t824 = 0
44
- t857 = 1.0
45
15
  t971 = t979 + t982
46
- t990 = 0.009
47
16
  t195 = {
48
17
  "marginal" => t1032,
49
18
  "effective" => t1032,
@@ -55,9 +24,7 @@ module Kumi::Compiled::KUMI_f570bd1470fbdb4fe98673449f7d2106c6eeb0a11dbd0d656e2d
55
24
  "tax" => t1036
56
25
  }
57
26
  t204 = input["retirement_contrib"] || input[:retirement_contrib]
58
- t840 = -1
59
- t842 = 100000000000.0
60
- t858 = [t974, t857]
27
+ t858 = [t974, 1.0]
61
28
  t859 = t858.max
62
29
  t181.each_with_index do |statuses_el_182, statuses_i_183|
63
30
  t184 = statuses_el_182["name"] || statuses_el_182[:name]
@@ -73,32 +40,32 @@ module Kumi::Compiled::KUMI_f570bd1470fbdb4fe98673449f7d2106c6eeb0a11dbd0d656e2d
73
40
  acc1315 = 0.0
74
41
  t823 = t974 - t822
75
42
  t986 = t974 - t985
76
- t825 = [t823, t824]
77
- t988 = [t986, t824]
43
+ t825 = [t823, 0]
44
+ t988 = [t986, 0]
78
45
  t826 = t825.max
79
46
  t989 = t988.max
80
47
  t803.each_with_index do |t804, t805|
81
48
  t829 = t804["lo"] || t804[:lo]
82
49
  t815 = t826 >= t829
83
50
  t847 = t804["hi"] || t804[:hi]
84
- t841 = t847 == t840
85
- t844 = t841 ? t842 : t847
51
+ t841 = t847 == -1
52
+ t844 = t841 ? 100000000000.0 : t847
86
53
  t818 = t826 < t844
87
54
  t819 = t815 && t818
88
55
  t853 = t804["rate"] || t804[:rate]
89
- t809 = t819 ? t853 : t824
56
+ t809 = t819 ? t853 : 0
90
57
  acc802 += t809
91
58
  end
92
- t991 = t989 * t990
59
+ t991 = t989 * 0.009
93
60
  t810 = acc802
94
61
  t803.each_with_index do |t865, t866|
95
62
  t890 = t865["lo"] || t865[:lo]
96
63
  t875 = t826 - t890
97
64
  t901 = t865["hi"] || t865[:hi]
98
- t895 = t901 == t840
99
- t898 = t895 ? t842 : t901
65
+ t895 = t901 == -1
66
+ t898 = t895 ? 100000000000.0 : t901
100
67
  t879 = t898 - t890
101
- t880 = [[ t875, t824 ].max, t879 ].min
68
+ t880 = t875.clamp(0, t879)
102
69
  t910 = t865["rate"] || t865[:rate]
103
70
  t869 = t880 * t910
104
71
  acc863 += t869
@@ -1,17 +1,12 @@
1
1
  (LIR
2
2
  (Declaration scores
3
- %t1 = const 100 :: integer
4
- %t2 = const 85 :: integer
5
- %t3 = const 92 :: integer
6
- %t4 = make_tuple(%t1, %t2, %t3) :: tuple<integer, integer, integer>
3
+ %t4 = make_tuple(%__immediate_placeholder__, %__immediate_placeholder__, %__immediate_placeholder__) :: tuple<integer, integer, integer>
7
4
  yield %t4
8
5
  )
9
6
  (Declaration first_score
10
- %t5 = const 100 :: integer
11
- yield %t5
7
+ yield %__immediate_placeholder__
12
8
  )
13
9
  (Declaration second_score
14
- %t6 = const 85 :: integer
15
- yield %t6
10
+ yield %__immediate_placeholder__
16
11
  )
17
12
  )
@@ -1,18 +1,13 @@
1
1
  export function _scores(input) {
2
- const t1 = 100;
3
- const t2 = 85;
4
- const t3 = 92;
5
- let t4 = [t1, t2, t3];
2
+ let t4 = [100, 85, 92];
6
3
  return t4;
7
4
  }
8
5
 
9
6
  export function _first_score(input) {
10
- const t5 = 100;
11
- return t5;
7
+ return 100;
12
8
  }
13
9
 
14
10
  export function _second_score(input) {
15
- const t6 = 85;
16
- return t6;
11
+ return 85;
17
12
  }
18
13
 
@@ -1,44 +1,14 @@
1
1
  # Autogenerated by Kumi Codegen
2
- module Kumi::Compiled::KUMI_e200083314e8307addf1cf2056b27031a7256e95b7cde0d0bc3865b4aef4ead2
3
- def self.from(input_data = nil)
4
- instance = Object.new
5
- instance.extend(self)
6
- instance.instance_variable_set(:@input, input_data)
7
- instance
2
+ module Kumi::Compiled::KUMI_5108af24d012f937e1c0316f75655a9577ee8e16e0b0867506c94ceb7237ae46
3
+ def self._scores(input)
4
+ [100, 85, 92]
8
5
  end
9
6
 
10
- def self.__kumi_executable__
11
- instance = Object.new
12
- instance.extend(self)
13
- instance
14
- end
15
-
16
- def update(input_data)
17
- @input = @input.merge(input_data)
18
- self
19
- end
20
-
21
- def [](name)
22
- case name
23
- when :scores then _scores
24
- when :first_score then _first_score
25
- when :second_score then _second_score
26
- else raise KeyError, "Unknown declaration"
27
- end
28
- end
29
-
30
- def _scores(input = @input)
31
- t1 = 100
32
- t2 = 85
33
- t3 = 92
34
- [t1, t2, t3]
35
- end
36
-
37
- def _first_score(input = @input)
7
+ def self._first_score(input)
38
8
  100
39
9
  end
40
10
 
41
- def _second_score(input = @input)
11
+ def self._second_score(input)
42
12
  85
43
13
  end
44
14
  end
data/lib/kumi/analyzer.rb CHANGED
@@ -8,13 +8,14 @@ module Kumi
8
8
 
9
9
  DEFAULT_PASSES = [
10
10
  Passes::NameIndexer, # 1. Finds all names and checks for duplicates.
11
- Passes::InputCollector, # 2. Collects field metadata from input declarations.
12
- Passes::InputFormSchemaPass, # 3. Builds minimal form schema from input metadata.
13
- Passes::DeclarationValidator, # 4. Checks the basic structure of each rule.
14
- Passes::SemanticConstraintValidator, # 5. Validates DSL semantic constraints at AST level.
15
- Passes::DependencyResolver, # 6. Builds the dependency graph with conditional dependencies.
16
- Passes::Toposorter, # 7. Creates the final evaluation order, allowing safe cycles.
17
- Passes::InputAccessPlannerPass # 8. Plans access strategies for input fields.
11
+ Passes::ImportAnalysisPass, # 2. Loads source schemas for imports (NEW).
12
+ Passes::InputCollector, # 3. Collects field metadata from input declarations.
13
+ Passes::InputFormSchemaPass, # 4. Builds minimal form schema from input metadata.
14
+ Passes::DeclarationValidator, # 5. Checks the basic structure of each rule.
15
+ Passes::SemanticConstraintValidator, # 6. Validates DSL semantic constraints at AST level.
16
+ Passes::DependencyResolver, # 7. Builds the dependency graph with conditional dependencies.
17
+ Passes::Toposorter, # 8. Creates the final evaluation order, allowing safe cycles.
18
+ Passes::InputAccessPlannerPass # 9. Plans access strategies for input fields.
18
19
  ].freeze
19
20
 
20
21
  # Pipeline passes for the determinisitic NAST->LIR approach
@@ -53,14 +53,15 @@ module Kumi
53
53
  # refresh" experience, and AOT for production to ensure fast boots
54
54
  # and catch precompilation errors in CI.
55
55
  def default_compilation_mode
56
- # RACK_ENV is a common standard, but Rails.env is more specific.
57
- env = defined?(Rails) ? Rails.env.to_s : ENV.fetch("RACK_ENV", nil)
56
+ override = ENV.fetch("KUMI_COMPILATION_MODE", nil)
57
+ if override && !override.strip.empty?
58
+ normalized = override.strip.downcase.to_sym
59
+ return normalized if %i[jit aot].include?(normalized)
58
60
 
59
- if env == "development"
60
- :jit
61
- else
62
- :aot
61
+ warn "[kumi] Ignoring invalid KUMI_COMPILATION_MODE=#{override.inspect}; falling back to environment-based default"
63
62
  end
63
+
64
+ :jit
64
65
  end
65
66
  end
66
67
  end
@@ -46,7 +46,7 @@ module Kumi
46
46
  walk.call(x.on_false)
47
47
  when NAST::Reduce, NAST::Fold
48
48
  walk.call(x.arg)
49
- when NAST::Call, NAST::Tuple
49
+ when NAST::Call, NAST::Tuple, NAST::ImportCall
50
50
  x.args.each { walk.call(_1) }
51
51
  when NAST::Hash
52
52
  x.pairs.each { walk.call(_1) }
@@ -29,7 +29,7 @@ module Kumi
29
29
  annotate!(node.body, by_fqn)
30
30
  when NAST::InputRef
31
31
  annotate_input_ref!(node, by_fqn)
32
- when NAST::Tuple, NAST::Call
32
+ when NAST::Tuple, NAST::Call, NAST::ImportCall
33
33
  node.args.each { |a| annotate!(a, by_fqn) }
34
34
  when NAST::Hash
35
35
  node.pairs.each { |p| annotate!(p.value, by_fqn) }
@@ -123,6 +123,26 @@ module Kumi
123
123
  end
124
124
  end
125
125
 
126
+ def emit_importschemacall(ins, _i)
127
+ # Generate code to call an imported schema function
128
+ source_module = ins.attributes[:source_module]
129
+ fn_name = ins.attributes[:fn_name]
130
+ input_keys = ins.attributes[:input_mapping_keys]
131
+ args = operands_for(ins)
132
+
133
+ js_module = ruby_module_to_js(source_module)
134
+ input_obj = input_keys.zip(args).map { |k, v| "'#{k}': #{v}" }.join(", ")
135
+
136
+ write "let #{vreg(ins)} = #{js_module}.from({#{input_obj}})._#{fn_name};"
137
+ end
138
+
139
+ private
140
+
141
+ def ruby_module_to_js(ruby_module_path)
142
+ # Convert Ruby module path (GoldenSchemas::Tax) to JavaScript path (GoldenSchemas.Tax)
143
+ ruby_module_path.to_s.gsub('::', '.')
144
+ end
145
+
126
146
  def emit_fold(ins, _i)
127
147
  kernel = kernel_for(ins.result_register)
128
148
  args = operands_for(ins)
@@ -27,7 +27,7 @@ module Kumi
27
27
  # Pre-calculate the depth of the single Yield instruction.
28
28
  @yield_depth = find_yield_depth(ops)
29
29
 
30
- write "def _#{name}(input = @input)"
30
+ write "def self._#{name}(input)"
31
31
  indent!
32
32
 
33
33
  # Setup the top-level 'out' container if the result is an array.
@@ -129,18 +129,27 @@ module Kumi
129
129
 
130
130
  if (template = kernel[:attrs]["inline"])
131
131
  inlined_code = _inline_kernel(template, args)
132
- if template.start_with?("=") || template.include?("$0")
133
- write "#{vreg(ins)} #{inlined_code}"
134
- else
135
- # For +=, -= etc.
136
- write "#{vreg(ins)} #{inlined_code}".lstrip
137
- end
132
+ write "#{vreg(ins)} #{inlined_code}"
138
133
  else
139
134
  fn_name = kernel_method_name(kernel[:fn_id])
140
135
  write "#{vreg(ins)} = #{fn_name}(#{args.join(', ')})"
141
136
  end
142
137
  end
143
138
 
139
+ def emit_importschemacall(ins, _i)
140
+ # Generate code to call an imported schema function
141
+ source_module = ins.attributes[:source_module]
142
+ fn_name = ins.attributes[:fn_name]
143
+ input_keys = ins.attributes[:input_mapping_keys]
144
+ args = operands_for(ins)
145
+
146
+ # Create a hash of input parameters
147
+ input_hash = input_keys.zip(args).map { |k, v| "#{k.inspect} => #{v}" }.join(", ")
148
+
149
+ # Generate: imported_module._fn_name({input_mapping})
150
+ write "#{vreg(ins)} = #{source_module}._#{fn_name}({#{input_hash}})"
151
+ end
152
+
144
153
  def emit_fold(ins, _i)
145
154
  kernel = kernel_for(ins.result_register)
146
155
  args = operands_for(ins)
@@ -35,41 +35,9 @@ module Kumi
35
35
  write "end"
36
36
  end
37
37
 
38
- def emit_class_methods(decl_names)
39
- write "def self.from(input_data = nil)"
40
- indented do
41
- write "instance = Object.new"
42
- write "instance.extend(self)"
43
- write "instance.instance_variable_set(:@input, input_data)"
44
- write "instance"
45
- end
46
- write "end\n"
47
-
48
- write "def self.__kumi_executable__"
49
- indented do
50
- write "instance = Object.new"
51
- write "instance.extend(self)"
52
- write "instance"
53
- end
54
- write "end\n"
55
-
56
- write "def update(input_data)"
57
- indented do
58
- write "@input = @input.merge(input_data)"
59
- write "self"
60
- end
61
- write "end\n"
62
-
63
- return unless decl_names.size >= 1
64
-
65
- write "def [](name)"
66
- indented do
67
- write "case name"
68
- decl_names.each { |name| write "when :#{name} then _#{name}" }
69
- write "else raise KeyError, \"Unknown declaration\""
70
- write "end"
71
- end
72
- write "end\n"
38
+ def emit_class_methods(_decl_names)
39
+ # No boilerplate needed anymore - all declarations are pure module functions
40
+ # This method remains for backward compatibility with the emit pipeline
73
41
  end
74
42
 
75
43
  def section(name)
@@ -68,6 +68,12 @@ module Kumi
68
68
  # adds the root input declaration as a dependency
69
69
  root_input_declr_name = node.path.first
70
70
  add_dependency_edge(graph, reverse_deps, decl.name, root_input_declr_name, :key, context[:via])
71
+ when ImportCall
72
+ # Check that imported name exists
73
+ imported_schemas = get_state(:imported_schemas) || {}
74
+ report_error(errors, "undefined import reference `#{node.fn_name}`", location: node.loc) unless imported_schemas.key?(node.fn_name)
75
+
76
+ add_dependency_edge(graph, reverse_deps, decl.name, node.fn_name, :import_call, node.fn_name)
71
77
  when Literal
72
78
  leaves[decl.name] << node
73
79
  end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kumi
4
+ module Core
5
+ module Analyzer
6
+ module Passes
7
+ class ImportAnalysisPass < PassBase
8
+ def run(errors)
9
+ imported_decls = get_state(:imported_declarations)
10
+ imported_schemas = {}
11
+
12
+ imported_decls.each do |name, meta|
13
+ source_module_ref = meta[:from_module]
14
+
15
+ begin
16
+ source_module = resolve_source_module(source_module_ref)
17
+ rescue NameError => e
18
+ report_error(
19
+ errors,
20
+ "cannot import `#{name}`: module #{source_module_ref.inspect} not found (#{e.message})",
21
+ location: meta[:loc]
22
+ )
23
+ next
24
+ end
25
+
26
+ begin
27
+ syntax_tree = source_module.__kumi_syntax_tree__
28
+ rescue NoMethodError
29
+ report_error(
30
+ errors,
31
+ "cannot import `#{name}` from #{qualified_ref(source_module_ref, source_module)}: not a Kumi schema (missing __kumi_syntax_tree__)",
32
+ location: meta[:loc]
33
+ )
34
+ next
35
+ end
36
+
37
+ source_decl = syntax_tree.values.find { |v| v.name == name } ||
38
+ syntax_tree.traits.find { |t| t.name == name }
39
+
40
+ unless source_decl
41
+ available = (syntax_tree.values.map(&:name) + syntax_tree.traits.map(&:name)).sort
42
+ msg = "imported declaration `#{name}` not found in #{qualified_ref(source_module_ref, source_module)}"
43
+ msg += "\navailable declarations: #{available.join(', ')}" if available.any?
44
+ report_error(errors, msg, location: meta[:loc])
45
+ next
46
+ end
47
+
48
+ begin
49
+ analyzed_state = Kumi::Analyzer.analyze!(syntax_tree).state
50
+ rescue => e
51
+ report_error(
52
+ errors,
53
+ "failed to analyze imported schema from #{qualified_ref(source_module_ref, source_module)}: #{e.class}: #{e.message}",
54
+ location: meta[:loc]
55
+ )
56
+ next
57
+ end
58
+
59
+ imported_schemas[name] = {
60
+ decl: source_decl,
61
+ source_module: source_module,
62
+ source_root: syntax_tree,
63
+ analyzed_state: analyzed_state,
64
+ input_metadata: analyzed_state[:input_metadata] || {}
65
+ }
66
+ end
67
+
68
+ state.with(:imported_schemas, imported_schemas.freeze)
69
+ end
70
+
71
+ private
72
+
73
+ def resolve_source_module(source_module_ref)
74
+ if source_module_ref.is_a?(String)
75
+ Object.const_get(source_module_ref)
76
+ else
77
+ source_module_ref
78
+ end
79
+ end
80
+
81
+ def qualified_ref(ref, mod = nil)
82
+ return mod if mod
83
+ return ref if ref
84
+ "(unknown)"
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end