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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4b228964d7834bd37eb2b5f969fb288edbb4dab6e27ef72d45a04fa9fb87a2d0
4
- data.tar.gz: 79e0b9db5acedb69e61eb6799844fa6a849fca4ed604e79522af03147e3e0436
3
+ metadata.gz: 7b98e39a72b87991ec1e2055ca1ad9ca996a1e95924ca5d4e201043f679564ed
4
+ data.tar.gz: ac6b469fd9cb3aa8d01bc4907c4f40ba5dbbc900e95e8309a9c68595b57d9c30
5
5
  SHA512:
6
- metadata.gz: b28eb238da8e21b0ec51dd1f5c3e2ac769fd07bef7461787a456fded7dba4a5d7603e2d3eff110e23bbe69af8d28e303834d0aa12b2a06fe6ee7d8c441eae289
7
- data.tar.gz: 98fa5a9f34f3ab1c8d9aea17ce888025713d73665de5a85608a4108fdcd697d587986ba24d404f505b35cabffadb8880765ec7f9cd803a232d2295bd4b6b36fc
6
+ metadata.gz: 3e8b32dbcb228a886a4089992ddaa2cabbe977477226561d09be2d6a3583ebf9d3276f338e99e9612e4c1dbfe6e911801b70747aa4dbc47b820949b2425661f0
7
+ data.tar.gz: 6537e18270ed92b04a80f14c24758cda316a5658a2d92d7940b2f7770ef51518eabd2f421e85516484f0c49b2c699f4bc2bac63e07b08b8108f8cd500654282f
data/CHANGELOG.md CHANGED
@@ -1,4 +1,24 @@
1
1
  ## [Unreleased]
2
+
3
+ ## [0.0.33] – 2025-11-05
4
+ ### Added
5
+ - **Peephole Optimization Helper:** `Kumi::Core::LIR::Peephole` plus specs for safer peephole transforms, inline Ruby clamp kernel, richer LIR dumps, and refreshed golden files
6
+ - **Import Diagnostics:** Clearer errors with available declaration hints when imports fail
7
+
8
+ ### Changed
9
+ - Default `Kumi.configure.compilation_mode` now `:jit`; override via config or `KUMI_COMPILATION_MODE`
10
+ - Improved constant propagation output formatting for Ruby/JS codegen
11
+
12
+ ## [0.0.32] – 2025-10-23
13
+ ### Added
14
+ - **Schema Imports:** Reuse declarations from other schemas with `import :name, from: Module` syntax
15
+ - **Improved Import Errors:** Clearer messages with available declaration hints when imports fail
16
+ - Documentation: `docs/COMPOSED_SCHEMAS.md` and `docs/SCHEMA_IMPORTS.md`
17
+
18
+ ## [0.0.31] – 2025-10-22
19
+ ### Changed
20
+ - Documentation for schema imports in README and SYNTAX
21
+
2
22
  ## [0.0.30] – 2025-10-21
3
23
  ### Changed
4
24
  - **Analyzer Refactoring:** PassManager now centralizes pass orchestration, replacing manual orchestration in Analyzer.run_analysis_passes
@@ -174,4 +194,4 @@ Fix - Remove require of pry gem on runtime.
174
194
  - Ruby >= 3.1 (Was >= 3.0)
175
195
 
176
196
  ### Notes
177
- - No expected DSL changes for typical schemas; report regressions.
197
+ - No expected DSL changes for typical schemas; report regressions.
data/README.md CHANGED
@@ -10,116 +10,36 @@
10
10
 
11
11
  ## What is Kumi?
12
12
 
13
- Kumi is a **declarative DSL for building calculation systems** that are:
14
- - **Typed & verifiable at compile time** (catch errors before they hit production)
15
- - **Vectorized** (arrays and nested data structures work naturally)
16
- - **Transparent** (inspect generated code and execution order)
17
- - **Portable** (compile the same schema to Ruby or JavaScript)
13
+ Kumi is a **declarative DSL for building calculation systems**.
18
14
 
19
- Instead of writing procedural formulas, you declare *what* values depend on *what*, and Kumi figures out the computation order, validates types, detects impossible constraints, and generates efficient code.
15
+ Schemas define:
16
+ - Input shape (scalars, arrays, nested structures)
17
+ - Declarations (computed values and boolean conditions)
18
+ - Dependencies between declarations
20
19
 
21
- ## Why Kumi Exists
20
+ The compiler:
21
+ - Performs type checking
22
+ - Detects unsatisfiable constraints
23
+ - Determines evaluation order
24
+ - Generates code for Ruby or JavaScript
22
25
 
23
- Calculation systems are everywhere: tax engines, pricing models, financial projections, compliance checks. They're usually:
24
- - Hard to verify (logic spread across multiple files)
25
- - Fragile (changing one formula breaks hidden dependencies)
26
- - Duplicated (same logic needed in backend and frontend)
27
- - Opaque (hard to audit which rules applied to which data)
26
+ ## Use Cases
28
27
 
29
- Kumi makes them explicit, testable, and portable.
28
+ Calculation systems appear in: tax engines, pricing models, financial projections, compliance systems, insurance underwriting, shipping rate calculators.
30
29
 
31
30
  ---
32
31
 
33
32
  **Status**: experimental. Public API may change. Typing and some static checks are still evolving.
34
33
 
35
- **Feedback**: have a use case or hit a rough edge? Open an issue or reach out.
34
+ **Feedback**: have a use case or hit a rough edge? Open an issue or reach out (andremuta+kumi@gmail.com).
36
35
 
37
36
  ---
38
37
 
39
- ## Example: US Tax Calculator (2024)
38
+ ## Examples
40
39
 
41
- A single schema computes federal, state, FICA taxes across multiple filing statuses—all types verified at compile time. Try it in the [interactive demo](https://kumi-play-web.fly.dev/) or inspect the [full schema, input, output, and generated code](golden/us_tax_2024/).
42
-
43
- <details>
44
- <summary><strong>Schema</strong></summary>
45
-
46
- ```ruby
47
- schema do
48
- input do
49
- float :income
50
- float :state_rate
51
- float :local_rate
52
- float :retirement_contrib
53
- string :filing_status
54
-
55
- array :statuses do
56
- hash :status do
57
- string :name
58
- float :std
59
- float :addl_threshold
60
- array :rates do
61
- hash :bracket do
62
- float :lo
63
- float :hi # -1 = open-ended
64
- float :rate
65
- end
66
- end
67
- end
68
- end
69
- end
70
-
71
- # shared
72
- let :big_hi, 100_000_000_000.0
73
- let :state_tax, input.income * input.state_rate
74
- let :local_tax, input.income * input.local_rate
75
-
76
- # FICA constants
77
- let :ss_wage_base, 168_600.0
78
- let :ss_rate, 0.062
79
- let :med_base_rate, 0.0145
80
- let :addl_med_rate, 0.009
81
-
82
- # per-status federal
83
- let :taxable, fn(:max, [input.income - input.statuses.status.std, 0])
84
- let :lo, input.statuses.status.rates.bracket.lo
85
- let :hi, input.statuses.status.rates.bracket.hi
86
- let :rate, input.statuses.status.rates.bracket.rate
87
- let :hi_eff, select(hi == -1, big_hi, hi)
88
- let :amt, fn(:clamp, taxable - lo, 0, hi_eff - lo)
89
- let :fed_tax, fn(:sum, amt * rate)
90
- let :in_br, (taxable >= lo) & (taxable < hi_eff)
91
- let :fed_marg, fn(:sum_if, rate, in_br)
92
- let :fed_eff, fed_tax / fn(:max, [input.income, 1.0])
93
-
94
- # per-status FICA
95
- let :ss_tax, fn(:min, [input.income, ss_wage_base]) * ss_rate
96
- let :med_tax, input.income * med_base_rate
97
- let :addl_med_tax, fn(:max, [input.income - input.statuses.status.addl_threshold, 0]) * addl_med_rate
98
- let :fica_tax, ss_tax + med_tax + addl_med_tax
99
- let :fica_eff, fica_tax / fn(:max, [input.income, 1.0])
100
-
101
- # totals per status
102
- let :total_tax, fed_tax + fica_tax + state_tax + local_tax
103
- let :total_eff, total_tax / fn(:max, [input.income, 1.0])
104
- let :after_tax, input.income - total_tax
105
- let :take_home, after_tax - input.retirement_contrib
106
-
107
- # array of result objects, one per status
108
- value :summary, {
109
- filing_status: input.statuses.status.name,
110
- federal: { marginal: fed_marg, effective: fed_eff, tax: fed_tax },
111
- fica: { effective: fica_eff, tax: fica_tax },
112
- state: { marginal: input.state_rate, effective: input.state_rate, tax: state_tax },
113
- local: { marginal: input.local_rate, effective: input.local_rate, tax: local_tax },
114
- total: { effective: total_eff, tax: total_tax },
115
- after_tax: after_tax,
116
- retirement_contrib: input.retirement_contrib,
117
- take_home: take_home
118
- }
119
- end
120
- ```
121
-
122
- </details>
40
+ - **US Tax Calculator (2024)** — a single schema computes federal, state, and FICA taxes across multiple filing statuses. [Open in the demo](https://kumi-play-web.fly.dev/?example=us-federal-tax-2024).
41
+ - **Monte Carlo Portfolio** — demonstrates probabilistic simulations and table visualizations. [Open in the demo](https://kumi-play-web.fly.dev/?example=monte-carlo-simulation).
42
+ - **Conway's Game of Life** — showcases array operations powering a grid-based simulation. [Open in the demo](https://kumi-play-web.fly.dev/?example=game-of-life).
123
43
 
124
44
  ---
125
45
 
@@ -129,7 +49,7 @@ end
129
49
  gem install kumi
130
50
  ```
131
51
 
132
- Requires Ruby 3.1+. No external dependencies.
52
+ Requires Ruby 3.1+. Runtime dependencies: `mutex_m` and `zeitwerk` (bundled via Rubygems).
133
53
 
134
54
  ## Quick Start
135
55
 
@@ -149,17 +69,29 @@ end
149
69
  result = Double.from(x: 5)
150
70
  result[:doubled] # => 10
151
71
 
72
+ # or just call the method directly
73
+ Double._doubled(x: 5) # => 10
74
+
152
75
  # Export to JavaScript (same logic)
153
76
  Double.write_source("output.mjs", platform: :javascript)
77
+ # ./output.mjs
78
+ # export function _doubled(input) {
79
+ # let t1 = input["x"];
80
+ # let t3 = t1 * 2;
81
+ # return t3;
82
+ # }
154
83
  ```
155
84
 
85
+ You can also override the compilation strategy without touching code by setting
86
+ `KUMI_COMPILATION_MODE` to `jit` or `aot` (e.g. `export KUMI_COMPILATION_MODE=aot`).
87
+
156
88
  Try the [interactive demo](https://kumi-play-web.fly.dev/) (no setup required).
157
89
 
158
90
  ---
159
91
 
160
92
  ## Documentation
161
93
 
162
- - **[Syntax Reference](docs/SYNTAX.md)** - DSL syntax, types, operators, and functions
94
+ - **[Syntax Reference](docs/SYNTAX.md)** - DSL syntax, types, operators, functions, and schema imports
163
95
  - **[Functions Reference](docs/FUNCTIONS.md)** - Auto-generated docs for all functions and kernels
164
96
  - **[functions-reference.json](docs/functions-reference.json)** - Machine-readable format for IDEs (VSCode, Monaco, etc.)
165
97
  - **[Development Guide](docs/DEVELOPMENT.md)** - Testing, debugging, and contributing
@@ -39,5 +39,5 @@ kernels:
39
39
 
40
40
  - id: clamp:ruby:v1
41
41
  fn: core.clamp
42
- inline: "= [[ $0, $1 ].max, $2 ].min"
43
- impl: "(x, lo, hi)\n [[x, lo].max, hi].min"
42
+ inline: "= $0.clamp($1, $2)"
43
+ impl: "(x, lo, hi)\n x.clamp(lo, hi)"
@@ -0,0 +1,137 @@
1
+ # Composed Schemas
2
+
3
+ Multiple schemas can be imported and called within a single schema.
4
+
5
+ ## Example: Order Processing with Price and Tax
6
+
7
+ ### Step 1: Define Base Schemas
8
+
9
+ **Price Calculation** (`golden/_shared/price.rb`):
10
+ ```ruby
11
+ module GoldenSchemas
12
+ module Price
13
+ extend Kumi::Schema
14
+
15
+ schema do
16
+ input do
17
+ decimal :base_price
18
+ decimal :discount_rate
19
+ end
20
+
21
+ value :discounted, input.base_price * (1.0 - input.discount_rate)
22
+ value :discount_amount, input.base_price * input.discount_rate
23
+ end
24
+ end
25
+ end
26
+ ```
27
+
28
+ **Tax Calculation** (`golden/_shared/tax.rb`):
29
+ ```ruby
30
+ module GoldenSchemas
31
+ module Tax
32
+ extend Kumi::Schema
33
+
34
+ schema do
35
+ input do
36
+ decimal :amount
37
+ end
38
+
39
+ value :tax, input.amount * 0.15
40
+ value :total, input.amount + tax
41
+ end
42
+ end
43
+ end
44
+ ```
45
+
46
+ ### Composed Order Schema
47
+
48
+ ```ruby
49
+ module GoldenSchemas
50
+ module ComposedOrder
51
+ extend Kumi::Schema
52
+
53
+ schema do
54
+ import :discounted, :discount_amount, from: GoldenSchemas::Price
55
+ import :total, from: GoldenSchemas::Tax
56
+
57
+ input do
58
+ decimal :item_price
59
+ decimal :quantity
60
+ decimal :discount_rate
61
+ end
62
+
63
+ value :subtotal, input.item_price * input.quantity
64
+ value :price_after_discount, fn(:discounted, base_price: subtotal, discount_rate: input.discount_rate)
65
+ value :discount_amt, fn(:discount_amount, base_price: subtotal, discount_rate: input.discount_rate)
66
+ value :final_total, fn(:total, amount: price_after_discount)
67
+ end
68
+ end
69
+ end
70
+ ```
71
+
72
+ ### Test Data and Output
73
+
74
+ Input:
75
+ ```json
76
+ {
77
+ "item_price": 100.0,
78
+ "quantity": 3,
79
+ "discount_rate": 0.1
80
+ }
81
+ ```
82
+
83
+ Output:
84
+ ```json
85
+ {
86
+ "subtotal": 300.0,
87
+ "price_after_discount": 270.0,
88
+ "discount_amt": 30.0,
89
+ "final_total": 310.5
90
+ }
91
+ ```
92
+
93
+ ## Parameter Mapping
94
+
95
+ Imported functions are called with keyword arguments that map to the imported schema's input fields.
96
+
97
+ Price schema input fields: `base_price`, `discount_rate`
98
+ ```kumi
99
+ discounted(base_price: subtotal, discount_rate: input.discount_rate)
100
+ ```
101
+
102
+ Tax schema input fields: `amount`
103
+ ```kumi
104
+ total(amount: price_after_discount)
105
+ ```
106
+
107
+ The compiler maps keyword argument names to the imported schema's input field names and generates a runtime call that passes these values as an input hash to the imported schema's method.
108
+
109
+ ## Compilation
110
+
111
+ For each imported function call:
112
+ 1. Compiler locates the declaration in the imported schema
113
+ 2. Maps keyword arguments to input field names
114
+ 3. Generates a runtime call to the imported schema's generated method
115
+ 4. Passes parameter values as an input hash to the imported function
116
+ 5. The imported schema's compiled method executes independently at runtime
117
+
118
+ ## Testing
119
+
120
+ Base schemas tested independently:
121
+ ```bash
122
+ bin/kumi golden test schema_imports_discount_with_tax
123
+ bin/kumi golden test schema_imports_nested_with_reductions
124
+ ```
125
+
126
+ Composed schemas tested:
127
+ ```bash
128
+ bin/kumi golden test schema_imports_composed_order
129
+ ```
130
+
131
+ Working examples in `golden/`:
132
+ - `schema_imports_with_imports` - single import
133
+ - `schema_imports_broadcasting_with_imports` - broadcast across arrays
134
+ - `schema_imports_discount_with_tax` - multiple imports
135
+ - `schema_imports_nested_with_reductions` - nested arrays
136
+ - `schema_imports_complex_order_calc` - complex multi-import
137
+ - `schema_imports_composed_order` - composed price and tax
@@ -0,0 +1,275 @@
1
+ # Schema Imports Feature
2
+
3
+ ## Overview
4
+
5
+ Schema imports allow you to reuse declarations (values and traits) from one schema in another schema by importing them from a source module.
6
+
7
+ ## How It Works
8
+
9
+ ### Compilation Pipeline
10
+
11
+ The schema import feature works through multiple analysis passes:
12
+
13
+ 1. **NameIndexer**: Identifies all imported names in the schema
14
+ 2. **ImportAnalysisPass**: Loads the source schemas and extracts their analyzed state
15
+ 3. **ConvertCallToImportCall** (text parser only): Converts function calls to ImportCall nodes when the function name matches an imported declaration
16
+ 4. **DependencyResolver**: Creates dependency edges for ImportCall nodes
17
+ 5. **NormalizeToNASTPass**: **Substitutes** ImportCall nodes with the source expression, mapping parameters
18
+
19
+ ### Key Design Principle: Runtime Function Calls
20
+
21
+ Imports are **compiled as runtime function calls** to the imported schema:
22
+
23
+ 1. The compiler analyzes the imported schema and generates its module methods
24
+ 2. When an imported function is called, the generated code invokes `ImportedModule._function_name(input_hash)`
25
+ 3. This allows for modular code generation and schema reuse
26
+
27
+ **Behavior:**
28
+ - Imported functions are called at runtime via generated code
29
+ - Broadcasting still applies - the calling function iterates and calls the imported function for each array element
30
+ - Parameter mapping creates input hashes that are passed to the imported function
31
+
32
+ ### Example: Tax Calculation
33
+
34
+ **Imported Schema** (`GoldenSchemas::Tax`):
35
+ ```kumi
36
+ schema do
37
+ input do
38
+ decimal :amount
39
+ end
40
+
41
+ value :tax, input.amount * 0.15
42
+ value :total, input.amount + tax
43
+ end
44
+ ```
45
+
46
+ **Calling Schema**:
47
+ ```kumi
48
+ import :tax, from: GoldenSchemas::Tax
49
+
50
+ schema do
51
+ input do
52
+ decimal :amount
53
+ end
54
+
55
+ value :tax_result, tax(amount: input.amount)
56
+ value :total, input.amount + tax_result
57
+ end
58
+ ```
59
+
60
+ **Generated Ruby Code**:
61
+ ```ruby
62
+ def self._tax_result(input)
63
+ # The imported function is called at runtime:
64
+ t1 = input["amount"] || input[:amount]
65
+ t2 = GoldenSchemas::Tax._tax({"amount" => t1})
66
+ t2
67
+ end
68
+ ```
69
+
70
+ Note: The generated code uses module-level functions (`def self._name(input)`) rather than instance methods. Imported functions are invoked as module methods with parameter mapping, enabling schema composition and reuse.
71
+
72
+ ## Syntax
73
+
74
+ ### Import Declaration
75
+
76
+ Text parser syntax:
77
+ ```kumi
78
+ import :name1, :name2, from: Module::Path
79
+ ```
80
+
81
+ Ruby DSL syntax:
82
+ ```ruby
83
+ import :name1, :name2, from: SourceModule
84
+ ```
85
+
86
+ ### Imported Function Calls
87
+
88
+ **Text parser** (identifier syntax):
89
+ ```kumi
90
+ result = tax(amount: input.price)
91
+ ```
92
+
93
+ **Ruby DSL** (function call syntax):
94
+ ```ruby
95
+ result = fn(:tax, amount: input.price)
96
+ ```
97
+
98
+ Both create an `ImportCall` node which gets substituted during normalization.
99
+
100
+ ## Broadcasting with Imports
101
+
102
+ When you pass an array to an imported function, the calling schema iterates over the array and calls the imported function for each element:
103
+
104
+ ```kumi
105
+ import :tax, from: GoldenSchemas::Tax
106
+
107
+ schema do
108
+ input do
109
+ array :items do
110
+ hash :item do
111
+ decimal :amount
112
+ end
113
+ end
114
+ end
115
+
116
+ value :item_taxes, tax(amount: input.items.item.amount)
117
+ value :total_tax, fn(:sum, item_taxes)
118
+ end
119
+ ```
120
+
121
+ With input `items: [{amount: 100}, {amount: 200}, {amount: 300}]`:
122
+ - The generated code loops over each item and calls `GoldenSchemas::Tax._tax({"amount" => item.amount})`
123
+ - `item_taxes` becomes `[15, 30, 45]`
124
+ - `total_tax` sums to `90`
125
+
126
+ The generated code performs loop iteration and calls the imported function for each array element.
127
+
128
+ ## Parameter Mapping
129
+
130
+ When you call an imported function with keyword arguments, the compiler:
131
+
132
+ 1. Maps each keyword argument name to the corresponding input field in the imported schema
133
+ 2. Constructs an input hash with the mapped parameter values
134
+ 3. Generates a runtime call to the imported function with this hash
135
+
136
+ Example:
137
+ ```kumi
138
+ # Imported schema input field: amount
139
+ # Call: fn(:tax, amount: input.price)
140
+ # Generated: GoldenSchemas::Tax._tax({"amount" => input.price})
141
+ ```
142
+
143
+ Multiple parameters work similarly:
144
+ ```kumi
145
+ # Imported schema input fields: price, rate
146
+ # Call: fn(:discount, price: invoice.total, rate: 0.1)
147
+ # Generated: GoldenSchemas::Discount._discount({"price" => invoice.total, "rate" => 0.1})
148
+ ```
149
+
150
+ ## Golden Test Cases
151
+
152
+ ### Basic Tests
153
+ 1. **`schema_imports_with_imports`** - Single import, scalar parameters
154
+ 2. **`schema_imports_broadcasting_with_imports`** - Broadcasting imported functions across arrays
155
+
156
+ ### Advanced Tests
157
+ 3. **`schema_imports_line_items`** - Importing reduction functions
158
+ - Imports `:subtotal` (sums quantity × price over array)
159
+ - Tests array aggregation through imports
160
+
161
+ 4. **`schema_imports_discount_with_tax`** - Multiple imports from different schemas
162
+ - Imports `:tax`, `:discounted`, `:savings`
163
+ - Tests composing multiple imported functions in sequence
164
+
165
+ 5. **`schema_imports_nested_with_reductions`** - Nested arrays with imports
166
+ - Imports subtotal and applies it to nested order structure
167
+ - Tests broadcasting imports through multiple levels
168
+
169
+ 6. **`schema_imports_complex_order_calc`** - Multiple imports with nested arrays
170
+ - Imports tax, discount, and subtotal functions
171
+ - Tests order processing with taxes, discounts, and summaries across multiple orders
172
+
173
+ ## Creating Reusable Schemas
174
+
175
+ Shared schemas are defined in `golden/_shared/` as Ruby DSL modules:
176
+
177
+ ```ruby
178
+ module GoldenSchemas
179
+ module Subtotal
180
+ extend Kumi::Schema
181
+
182
+ schema do
183
+ input do
184
+ array :items do
185
+ hash :item do
186
+ integer :quantity
187
+ integer :unit_price
188
+ end
189
+ end
190
+ end
191
+
192
+ value :subtotal, fn(:sum, input.items.item.quantity * input.items.item.unit_price)
193
+ end
194
+ end
195
+ end
196
+ ```
197
+
198
+ Then import in any schema:
199
+ ```kumi
200
+ import :subtotal, from: GoldenSchemas::Subtotal
201
+
202
+ schema do
203
+ value :order_total, subtotal(items: input.order_items)
204
+ end
205
+ ```
206
+
207
+ The shared schemas are automatically loaded and compiled in JIT mode when running golden tests.
208
+
209
+ ## Implementation Details
210
+
211
+ ### Parser Level (kumi-parser gem)
212
+
213
+ **Text Parser Changes**:
214
+ - Added `import` and `from` keywords to tokenizer
215
+ - Extended `parse_imports()` to handle `import :name, from: Constant::Path` syntax
216
+ - Added `parse_imported_function_call()` to handle identifier syntax like `tax(amount: value)`
217
+ - Tracks `@imported_names` during parsing to create ImportCall nodes when appropriate
218
+
219
+ **Key Methods**:
220
+ - `parse_imports()`: Parses import declarations
221
+ - `parse_constant()`: Parses scope-resolved constants like `GoldenSchemas::Tax`
222
+ - `parse_imported_function_call()`: Parses direct function calls with keyword arguments
223
+
224
+ ### Analyzer Level (kumi gem)
225
+
226
+ **New/Modified Passes**:
227
+ - `ImportAnalysisPass`: Loads source schemas, extracts analyzed state, and prepares for runtime calls
228
+ - `SemanticConstraintValidator`: Skips validation for imported function names
229
+ - `CodegenPass`: Generates runtime function calls to imported schema methods
230
+
231
+ **Key Data Structures**:
232
+ - `ImportDeclaration`: Stores import metadata (names, source module)
233
+ - `ImportCall`: Represents a call to an imported function (fn_name, input_mapping)
234
+ - `imported_declarations`: State containing all imported names
235
+ - `imported_schemas`: State containing full analysis of imported schemas (used to ensure schemas are compiled before use)
236
+
237
+ ## How Imports Are Compiled
238
+
239
+ **Imports are compiled as runtime function calls:**
240
+
241
+ 1. The imported schema is fully analyzed and compiled as a standalone module with its own methods
242
+ 2. When you call an imported function, the compiler generates a call to that module's method
243
+ 3. Parameters are mapped and passed as a hash to the imported function at runtime
244
+
245
+ **Example:**
246
+
247
+ Imported schema defines: `value :tax, input.amount * 0.15`
248
+
249
+ Your schema calls: `fn(:tax, amount: input.price)`
250
+
251
+ Compiler produces:
252
+ ```ruby
253
+ t1 = input["price"] || input[:price]
254
+ t2 = GoldenSchemas::Tax._tax({"amount" => t1})
255
+ ```
256
+
257
+ The imported function executes independently and returns its result to the calling schema.
258
+
259
+ ## Testing Strategy
260
+
261
+ To verify imports are working correctly, test:
262
+
263
+ 1. **Parser correctness**: ImportCall nodes are created for imported functions
264
+ 2. **Parameter mapping**: Input hashes are correctly constructed from keyword arguments
265
+ 3. **Runtime calls**: Generated code properly invokes imported schema methods with parameter hashes
266
+ 4. **Broadcasting**: Loop iteration works correctly when passing arrays to imported functions
267
+ 5. **Runtime evaluation**: Generated code produces correct results by calling imported functions
268
+
269
+ ## Future Enhancements
270
+
271
+ 1. **Trait imports**: Support importing traits for reusable conditions
272
+ 2. **Nested imports**: Allow imported schemas to import other schemas
273
+ 3. **Import aliasing**: Rename imports on import (`import :tax as :tax_calc`)
274
+ 4. **Selective exports**: Mark declarations as publicly exportable
275
+ 5. **Cross-schema optimization**: Detect and optimize repeated patterns across imports
data/docs/SYNTAX.md CHANGED
@@ -328,6 +328,54 @@ trait :eligible, is_member | is_trial
328
328
  trait :not_active, !is_active
329
329
  ```
330
330
 
331
+ ### 3) Schema Imports
332
+
333
+ Reuse declarations from other schemas without duplicating code.
334
+
335
+ #### Basic Import
336
+
337
+ ```kumi
338
+ import :tax, from: MySchemas::TaxCalculator
339
+
340
+ schema do
341
+ input do
342
+ decimal :amount
343
+ end
344
+
345
+ # Call imported declaration with input mapping
346
+ value :total, tax(amount: input.amount)
347
+ end
348
+ ```
349
+
350
+ #### Multiple Imports
351
+
352
+ ```kumi
353
+ import :tax, :discount, from: MySchemas::Utilities
354
+
355
+ schema do
356
+ input do
357
+ decimal :price
358
+ end
359
+
360
+ value :after_tax, tax(amount: input.price)
361
+ value :final, discount(amount: after_tax)
362
+ end
363
+ ```
364
+
365
+ #### Nested Imports
366
+
367
+ Imported schemas can themselves import from other schemas. The compiler resolves the full chain automatically.
368
+
369
+ ```kumi
370
+ # PriceSchema imports TaxSchema internally
371
+ import :final_price, from: MySchemas::PriceSchema
372
+ ```
373
+
374
+ **Key Rules:**
375
+ - All imported declarations must be available when the schema loads
376
+ - Input parameters are mapped by name (no positional arguments)
377
+ - Imports work with reductions, broadcasts, and cascades like normal declarations
378
+
331
379
  ### 4) Functions
332
380
 
333
381
  All functions use `fn(:name, args...)` syntax.