kumi 0.0.17 → 0.0.19

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 (676) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -1
  3. data/.ruby-version +1 -0
  4. data/CHANGELOG.md +28 -0
  5. data/CLAUDE.md +26 -139
  6. data/README.md +143 -372
  7. data/data/functions/agg/boolean.yaml +14 -0
  8. data/data/functions/agg/numeric.yaml +80 -0
  9. data/data/functions/agg/string.yaml +8 -0
  10. data/data/functions/core/arithmetic.yaml +50 -0
  11. data/data/functions/core/boolean.yaml +18 -0
  12. data/data/functions/core/comparison.yaml +42 -0
  13. data/data/functions/core/constructor.yaml +32 -0
  14. data/data/functions/core/select.yaml +7 -0
  15. data/data/functions/core/stencil.yaml +21 -0
  16. data/data/functions/core/string.yaml +19 -0
  17. data/data/kernels/javascript/agg/boolean.yaml +12 -0
  18. data/data/kernels/javascript/agg/numeric.yaml +27 -0
  19. data/data/kernels/javascript/agg/string.yaml +5 -0
  20. data/data/kernels/javascript/core/arithmetic.yaml +32 -0
  21. data/data/kernels/javascript/core/boolean.yaml +12 -0
  22. data/data/kernels/javascript/core/comparison.yaml +24 -0
  23. data/data/kernels/javascript/core/constructor.yaml +15 -0
  24. data/data/kernels/javascript/core/select.yaml +7 -0
  25. data/data/kernels/javascript/core/string.yaml +12 -0
  26. data/data/kernels/ruby/agg/boolean.yaml +18 -0
  27. data/data/kernels/ruby/agg/numeric.yaml +29 -0
  28. data/data/kernels/ruby/agg/string.yaml +5 -0
  29. data/data/kernels/ruby/core/arithmetic.yaml +38 -0
  30. data/data/kernels/ruby/core/boolean.yaml +15 -0
  31. data/data/kernels/ruby/core/comparison.yaml +30 -0
  32. data/data/kernels/ruby/core/constructor.yaml +17 -0
  33. data/data/kernels/ruby/core/select.yaml +4 -0
  34. data/data/kernels/ruby/core/string.yaml +15 -0
  35. data/debug_ordering.rb +52 -0
  36. data/docs/FORM_SCHEMA.md +85 -0
  37. data/docs/OUTPUT_SCHEMA.md +69 -0
  38. data/docs/SYNTAX.md +626 -373
  39. data/golden/array_element/expected/ast.txt +21 -0
  40. data/golden/array_element/expected/input_plan.txt +5 -0
  41. data/golden/array_element/expected/lir_00_unoptimized.txt +13 -0
  42. data/golden/array_element/expected/lir_01_hoist_scalar_references.txt +13 -0
  43. data/golden/array_element/expected/lir_02_inlined.txt +13 -0
  44. data/golden/array_element/expected/lir_03_cse.txt +13 -0
  45. data/golden/array_element/expected/lir_04_1_loop_fusion.txt +13 -0
  46. data/golden/array_element/expected/lir_04_loop_invcm.txt +13 -0
  47. data/golden/array_element/expected/lir_06_const_prop.txt +13 -0
  48. data/golden/array_element/expected/nast.txt +7 -0
  49. data/golden/array_element/expected/schema_javascript.mjs +13 -0
  50. data/golden/array_element/expected/schema_ruby.rb +41 -0
  51. data/golden/array_element/expected/snast.txt +7 -0
  52. data/golden/array_element/expected.json +5 -0
  53. data/golden/array_element/input.json +9 -0
  54. data/golden/array_element/schema.kumi +11 -0
  55. data/golden/array_index/expected/ast.txt +59 -0
  56. data/golden/array_index/expected/input_plan.txt +5 -0
  57. data/golden/array_index/expected/lir_00_unoptimized.txt +41 -0
  58. data/golden/array_index/expected/lir_01_hoist_scalar_references.txt +41 -0
  59. data/golden/array_index/expected/lir_02_inlined.txt +42 -0
  60. data/golden/array_index/expected/lir_03_cse.txt +40 -0
  61. data/golden/array_index/expected/lir_04_1_loop_fusion.txt +40 -0
  62. data/golden/array_index/expected/lir_04_loop_invcm.txt +40 -0
  63. data/golden/array_index/expected/lir_06_const_prop.txt +40 -0
  64. data/golden/array_index/expected/nast.txt +33 -0
  65. data/golden/array_index/expected/schema_javascript.mjs +46 -0
  66. data/golden/array_index/expected/schema_ruby.rb +75 -0
  67. data/golden/array_index/expected/snast.txt +33 -0
  68. data/golden/array_index/expected.json +5 -0
  69. data/golden/array_index/input.json +1 -0
  70. data/golden/array_index/schema.kumi +19 -0
  71. data/golden/array_operations/expected/ast.txt +50 -0
  72. data/golden/array_operations/expected/input_plan.txt +10 -0
  73. data/golden/array_operations/expected/lir_00_unoptimized.txt +47 -0
  74. data/golden/array_operations/expected/lir_01_hoist_scalar_references.txt +47 -0
  75. data/golden/array_operations/expected/lir_02_inlined.txt +47 -0
  76. data/golden/array_operations/expected/lir_03_cse.txt +47 -0
  77. data/golden/array_operations/expected/lir_04_1_loop_fusion.txt +47 -0
  78. data/golden/array_operations/expected/lir_04_loop_invcm.txt +47 -0
  79. data/golden/array_operations/expected/lir_06_const_prop.txt +47 -0
  80. data/golden/array_operations/expected/nast.txt +32 -0
  81. data/golden/array_operations/expected/schema_javascript.mjs +60 -0
  82. data/golden/array_operations/expected/schema_ruby.rb +91 -0
  83. data/golden/array_operations/expected/snast.txt +32 -0
  84. data/golden/array_operations/expected.json +27 -0
  85. data/golden/array_operations/input.json +8 -0
  86. data/golden/array_operations/schema.kumi +12 -10
  87. data/golden/cascade_logic/expected/ast.txt +37 -0
  88. data/golden/cascade_logic/expected/input_plan.txt +2 -0
  89. data/golden/cascade_logic/expected/lir_00_unoptimized.txt +29 -0
  90. data/golden/cascade_logic/expected/lir_01_hoist_scalar_references.txt +29 -0
  91. data/golden/cascade_logic/expected/lir_02_inlined.txt +37 -0
  92. data/golden/cascade_logic/expected/lir_03_cse.txt +30 -0
  93. data/golden/cascade_logic/expected/lir_04_1_loop_fusion.txt +30 -0
  94. data/golden/cascade_logic/expected/lir_04_loop_invcm.txt +30 -0
  95. data/golden/cascade_logic/expected/lir_06_const_prop.txt +30 -0
  96. data/golden/cascade_logic/expected/nast.txt +32 -0
  97. data/golden/cascade_logic/expected/schema_javascript.mjs +31 -0
  98. data/golden/cascade_logic/expected/schema_ruby.rb +57 -0
  99. data/golden/cascade_logic/expected/snast.txt +32 -0
  100. data/golden/cascade_logic/expected.json +5 -0
  101. data/golden/cascade_logic/input.json +4 -0
  102. data/golden/cascade_logic/schema.kumi +1 -3
  103. data/golden/chained_fusion/expected/ast.txt +57 -0
  104. data/golden/chained_fusion/expected/input_plan.txt +13 -0
  105. data/golden/chained_fusion/expected/lir_00_unoptimized.txt +76 -0
  106. data/golden/chained_fusion/expected/lir_01_hoist_scalar_references.txt +76 -0
  107. data/golden/chained_fusion/expected/lir_02_inlined.txt +114 -0
  108. data/golden/chained_fusion/expected/lir_03_cse.txt +97 -0
  109. data/golden/chained_fusion/expected/lir_04_1_loop_fusion.txt +99 -0
  110. data/golden/chained_fusion/expected/lir_04_loop_invcm.txt +97 -0
  111. data/golden/chained_fusion/expected/lir_06_const_prop.txt +97 -0
  112. data/golden/chained_fusion/expected/nast.txt +55 -0
  113. data/golden/chained_fusion/expected/schema_javascript.mjs +116 -0
  114. data/golden/chained_fusion/expected/schema_ruby.rb +149 -0
  115. data/golden/chained_fusion/expected/snast.txt +55 -0
  116. data/golden/chained_fusion/expected.json +45 -0
  117. data/golden/chained_fusion/input.json +51 -0
  118. data/golden/chained_fusion/schema.kumi +52 -0
  119. data/golden/element_arrays/expected/ast.txt +55 -0
  120. data/golden/element_arrays/expected/input_plan.txt +7 -0
  121. data/golden/element_arrays/expected/lir_00_unoptimized.txt +81 -0
  122. data/golden/element_arrays/expected/lir_01_hoist_scalar_references.txt +81 -0
  123. data/golden/element_arrays/expected/lir_02_inlined.txt +85 -0
  124. data/golden/element_arrays/expected/lir_03_cse.txt +83 -0
  125. data/golden/element_arrays/expected/lir_04_1_loop_fusion.txt +83 -0
  126. data/golden/element_arrays/expected/lir_04_loop_invcm.txt +83 -0
  127. data/golden/element_arrays/expected/lir_06_const_prop.txt +83 -0
  128. data/golden/element_arrays/expected/nast.txt +42 -0
  129. data/golden/element_arrays/expected/schema_javascript.mjs +106 -0
  130. data/golden/element_arrays/expected/schema_ruby.rb +141 -0
  131. data/golden/element_arrays/expected/snast.txt +42 -0
  132. data/golden/element_arrays/expected.json +55 -0
  133. data/golden/element_arrays/input.json +12 -0
  134. data/golden/element_arrays/schema.kumi +21 -0
  135. data/golden/empty_and_null_inputs/expected/ast.txt +42 -0
  136. data/golden/empty_and_null_inputs/expected/input_plan.txt +12 -0
  137. data/golden/empty_and_null_inputs/expected/lir_00_unoptimized.txt +31 -0
  138. data/golden/empty_and_null_inputs/expected/lir_01_hoist_scalar_references.txt +31 -0
  139. data/golden/empty_and_null_inputs/expected/lir_02_inlined.txt +51 -0
  140. data/golden/empty_and_null_inputs/expected/lir_03_cse.txt +49 -0
  141. data/golden/empty_and_null_inputs/expected/lir_04_1_loop_fusion.txt +49 -0
  142. data/golden/empty_and_null_inputs/expected/lir_04_loop_invcm.txt +49 -0
  143. data/golden/empty_and_null_inputs/expected/lir_06_const_prop.txt +49 -0
  144. data/golden/empty_and_null_inputs/expected/nast.txt +18 -0
  145. data/golden/empty_and_null_inputs/expected/schema_javascript.mjs +47 -0
  146. data/golden/empty_and_null_inputs/expected/schema_ruby.rb +79 -0
  147. data/golden/empty_and_null_inputs/expected/snast.txt +18 -0
  148. data/golden/empty_and_null_inputs/expected.json +8 -0
  149. data/golden/empty_and_null_inputs/input.json +16 -0
  150. data/golden/empty_and_null_inputs/schema.kumi +30 -0
  151. data/golden/game_of_life/expected/ast.txt +118 -0
  152. data/golden/game_of_life/expected/input_plan.txt +5 -0
  153. data/golden/game_of_life/expected/lir_00_unoptimized.txt +343 -0
  154. data/golden/game_of_life/expected/lir_01_hoist_scalar_references.txt +343 -0
  155. data/golden/game_of_life/expected/lir_02_inlined.txt +1918 -0
  156. data/golden/game_of_life/expected/lir_03_cse.txt +766 -0
  157. data/golden/game_of_life/expected/lir_04_1_loop_fusion.txt +766 -0
  158. data/golden/game_of_life/expected/lir_04_loop_invcm.txt +766 -0
  159. data/golden/game_of_life/expected/lir_06_const_prop.txt +766 -0
  160. data/golden/game_of_life/expected/nast.txt +104 -0
  161. data/golden/game_of_life/expected/schema_javascript.mjs +98 -0
  162. data/golden/game_of_life/expected/schema_ruby.rb +125 -0
  163. data/golden/game_of_life/expected/snast.txt +104 -0
  164. data/golden/game_of_life/expected.json +3 -0
  165. data/golden/game_of_life/input.json +8 -0
  166. data/golden/game_of_life/schema.kumi +33 -0
  167. data/golden/hash_keys/expected/ast.txt +29 -0
  168. data/golden/hash_keys/expected/input_plan.txt +2 -0
  169. data/golden/hash_keys/expected/lir_00_unoptimized.txt +18 -0
  170. data/golden/hash_keys/expected/lir_01_hoist_scalar_references.txt +18 -0
  171. data/golden/hash_keys/expected/lir_02_inlined.txt +18 -0
  172. data/golden/hash_keys/expected/lir_03_cse.txt +18 -0
  173. data/golden/hash_keys/expected/lir_04_1_loop_fusion.txt +18 -0
  174. data/golden/hash_keys/expected/lir_04_loop_invcm.txt +18 -0
  175. data/golden/hash_keys/expected/lir_06_const_prop.txt +18 -0
  176. data/golden/hash_keys/expected/nast.txt +46 -0
  177. data/golden/hash_keys/expected/schema_javascript.mjs +34 -0
  178. data/golden/hash_keys/expected/schema_ruby.rb +61 -0
  179. data/golden/hash_keys/expected/snast.txt +46 -0
  180. data/golden/hash_keys/expected.json +20 -0
  181. data/golden/hash_keys/input.json +4 -0
  182. data/golden/hash_keys/schema.kumi +14 -0
  183. data/golden/hash_value/expected/ast.txt +37 -0
  184. data/golden/hash_value/expected/input_plan.txt +7 -0
  185. data/golden/hash_value/expected/lir_00_unoptimized.txt +30 -0
  186. data/golden/hash_value/expected/lir_01_hoist_scalar_references.txt +30 -0
  187. data/golden/hash_value/expected/lir_02_inlined.txt +36 -0
  188. data/golden/hash_value/expected/lir_03_cse.txt +33 -0
  189. data/golden/hash_value/expected/lir_04_1_loop_fusion.txt +33 -0
  190. data/golden/hash_value/expected/lir_04_loop_invcm.txt +33 -0
  191. data/golden/hash_value/expected/lir_06_const_prop.txt +33 -0
  192. data/golden/hash_value/expected/nast.txt +25 -0
  193. data/golden/hash_value/expected/schema_javascript.mjs +46 -0
  194. data/golden/hash_value/expected/schema_ruby.rb +75 -0
  195. data/golden/hash_value/expected/snast.txt +25 -0
  196. data/golden/hash_value/expected.json +19 -0
  197. data/golden/hash_value/input.json +12 -0
  198. data/golden/hash_value/schema.kumi +19 -0
  199. data/golden/hierarchical_complex/expected/ast.txt +85 -0
  200. data/golden/hierarchical_complex/expected/input_plan.txt +23 -0
  201. data/golden/hierarchical_complex/expected/lir_00_unoptimized.txt +87 -0
  202. data/golden/hierarchical_complex/expected/lir_01_hoist_scalar_references.txt +87 -0
  203. data/golden/hierarchical_complex/expected/lir_02_inlined.txt +115 -0
  204. data/golden/hierarchical_complex/expected/lir_03_cse.txt +89 -0
  205. data/golden/hierarchical_complex/expected/lir_04_1_loop_fusion.txt +89 -0
  206. data/golden/hierarchical_complex/expected/lir_04_loop_invcm.txt +89 -0
  207. data/golden/hierarchical_complex/expected/lir_06_const_prop.txt +89 -0
  208. data/golden/hierarchical_complex/expected/nast.txt +49 -0
  209. data/golden/hierarchical_complex/expected/schema_javascript.mjs +121 -0
  210. data/golden/hierarchical_complex/expected/schema_ruby.rb +151 -0
  211. data/golden/hierarchical_complex/expected/snast.txt +49 -0
  212. data/golden/hierarchical_complex/expected.json +34 -0
  213. data/golden/hierarchical_complex/input.json +26 -0
  214. data/golden/hierarchical_complex/schema.kumi +38 -0
  215. data/golden/input_reference/expected/ast.txt +46 -0
  216. data/golden/input_reference/expected/input_plan.txt +15 -0
  217. data/golden/input_reference/expected/lir_00_unoptimized.txt +39 -0
  218. data/golden/input_reference/expected/lir_01_hoist_scalar_references.txt +39 -0
  219. data/golden/input_reference/expected/lir_02_inlined.txt +39 -0
  220. data/golden/input_reference/expected/lir_03_cse.txt +39 -0
  221. data/golden/input_reference/expected/lir_04_1_loop_fusion.txt +39 -0
  222. data/golden/input_reference/expected/lir_04_loop_invcm.txt +39 -0
  223. data/golden/input_reference/expected/lir_06_const_prop.txt +39 -0
  224. data/golden/input_reference/expected/nast.txt +21 -0
  225. data/golden/input_reference/expected/schema_javascript.mjs +45 -0
  226. data/golden/input_reference/expected/schema_ruby.rb +74 -0
  227. data/golden/input_reference/expected/snast.txt +21 -0
  228. data/golden/input_reference/expected.json +7 -0
  229. data/golden/input_reference/input.json +11 -0
  230. data/golden/input_reference/schema.kumi +22 -0
  231. data/golden/interleaved_fusion/expected/ast.txt +51 -0
  232. data/golden/interleaved_fusion/expected/input_plan.txt +13 -0
  233. data/golden/interleaved_fusion/expected/lir_00_unoptimized.txt +53 -0
  234. data/golden/interleaved_fusion/expected/lir_01_hoist_scalar_references.txt +53 -0
  235. data/golden/interleaved_fusion/expected/lir_02_inlined.txt +89 -0
  236. data/golden/interleaved_fusion/expected/lir_03_cse.txt +77 -0
  237. data/golden/interleaved_fusion/expected/lir_04_1_loop_fusion.txt +77 -0
  238. data/golden/interleaved_fusion/expected/lir_04_loop_invcm.txt +77 -0
  239. data/golden/interleaved_fusion/expected/lir_06_const_prop.txt +77 -0
  240. data/golden/interleaved_fusion/expected/nast.txt +41 -0
  241. data/golden/interleaved_fusion/expected/schema_javascript.mjs +86 -0
  242. data/golden/interleaved_fusion/expected/schema_ruby.rb +122 -0
  243. data/golden/interleaved_fusion/expected/snast.txt +41 -0
  244. data/golden/interleaved_fusion/expected.json +37 -0
  245. data/golden/interleaved_fusion/input.json +26 -0
  246. data/golden/interleaved_fusion/schema.kumi +57 -0
  247. data/golden/let_inline/expected/ast.txt +33 -0
  248. data/golden/let_inline/expected/input_plan.txt +2 -0
  249. data/golden/let_inline/expected/lir_00_unoptimized.txt +26 -0
  250. data/golden/let_inline/expected/lir_01_hoist_scalar_references.txt +26 -0
  251. data/golden/let_inline/expected/lir_02_inlined.txt +36 -0
  252. data/golden/let_inline/expected/lir_03_cse.txt +30 -0
  253. data/golden/let_inline/expected/lir_04_1_loop_fusion.txt +30 -0
  254. data/golden/let_inline/expected/lir_04_loop_invcm.txt +30 -0
  255. data/golden/let_inline/expected/lir_06_const_prop.txt +30 -0
  256. data/golden/let_inline/expected/nast.txt +26 -0
  257. data/golden/let_inline/expected/schema_javascript.mjs +11 -0
  258. data/golden/let_inline/expected/schema_ruby.rb +37 -0
  259. data/golden/let_inline/expected/snast.txt +26 -0
  260. data/golden/let_inline/expected.json +1 -0
  261. data/golden/let_inline/input.json +1 -0
  262. data/golden/let_inline/schema.kumi +11 -0
  263. data/golden/loop_fusion/expected/ast.txt +44 -0
  264. data/golden/loop_fusion/expected/input_plan.txt +13 -0
  265. data/golden/loop_fusion/expected/lir_00_unoptimized.txt +43 -0
  266. data/golden/loop_fusion/expected/lir_01_hoist_scalar_references.txt +43 -0
  267. data/golden/loop_fusion/expected/lir_02_inlined.txt +62 -0
  268. data/golden/loop_fusion/expected/lir_03_cse.txt +57 -0
  269. data/golden/loop_fusion/expected/lir_04_1_loop_fusion.txt +57 -0
  270. data/golden/loop_fusion/expected/lir_04_loop_invcm.txt +57 -0
  271. data/golden/loop_fusion/expected/lir_06_const_prop.txt +57 -0
  272. data/golden/loop_fusion/expected/nast.txt +32 -0
  273. data/golden/loop_fusion/expected/schema_javascript.mjs +64 -0
  274. data/golden/loop_fusion/expected/schema_ruby.rb +97 -0
  275. data/golden/loop_fusion/expected/snast.txt +32 -0
  276. data/golden/loop_fusion/expected.json +30 -0
  277. data/golden/loop_fusion/input.json +28 -0
  278. data/golden/loop_fusion/schema.kumi +32 -0
  279. data/golden/min_reduce_scope/expected/ast.txt +49 -0
  280. data/golden/min_reduce_scope/expected/input_plan.txt +9 -0
  281. data/golden/min_reduce_scope/expected/lir_00_unoptimized.txt +59 -0
  282. data/golden/min_reduce_scope/expected/lir_01_hoist_scalar_references.txt +59 -0
  283. data/golden/min_reduce_scope/expected/lir_02_inlined.txt +63 -0
  284. data/golden/min_reduce_scope/expected/lir_03_cse.txt +60 -0
  285. data/golden/min_reduce_scope/expected/lir_04_1_loop_fusion.txt +60 -0
  286. data/golden/min_reduce_scope/expected/lir_04_loop_invcm.txt +60 -0
  287. data/golden/min_reduce_scope/expected/lir_06_const_prop.txt +60 -0
  288. data/golden/min_reduce_scope/expected/nast.txt +29 -0
  289. data/golden/min_reduce_scope/expected/schema_javascript.mjs +66 -0
  290. data/golden/min_reduce_scope/expected/schema_ruby.rb +99 -0
  291. data/golden/min_reduce_scope/expected/snast.txt +29 -0
  292. data/golden/min_reduce_scope/expected.json +9 -0
  293. data/golden/min_reduce_scope/input.json +18 -0
  294. data/golden/min_reduce_scope/schema.kumi +25 -0
  295. data/golden/mixed_dimensions/expected/ast.txt +54 -0
  296. data/golden/mixed_dimensions/expected/input_plan.txt +15 -0
  297. data/golden/mixed_dimensions/expected/lir_00_unoptimized.txt +42 -0
  298. data/golden/mixed_dimensions/expected/lir_01_hoist_scalar_references.txt +42 -0
  299. data/golden/mixed_dimensions/expected/lir_02_inlined.txt +48 -0
  300. data/golden/mixed_dimensions/expected/lir_03_cse.txt +48 -0
  301. data/golden/mixed_dimensions/expected/lir_04_1_loop_fusion.txt +48 -0
  302. data/golden/mixed_dimensions/expected/lir_04_loop_invcm.txt +48 -0
  303. data/golden/mixed_dimensions/expected/lir_06_const_prop.txt +48 -0
  304. data/golden/mixed_dimensions/expected/nast.txt +22 -0
  305. data/golden/mixed_dimensions/expected/schema_javascript.mjs +53 -0
  306. data/golden/mixed_dimensions/expected/schema_ruby.rb +84 -0
  307. data/golden/mixed_dimensions/expected/snast.txt +22 -0
  308. data/golden/mixed_dimensions/expected.json +6 -0
  309. data/golden/mixed_dimensions/input.json +22 -0
  310. data/golden/mixed_dimensions/schema.kumi +35 -0
  311. data/golden/multirank_hoisting/expected/ast.txt +72 -0
  312. data/golden/multirank_hoisting/expected/input_plan.txt +18 -0
  313. data/golden/multirank_hoisting/expected/lir_00_unoptimized.txt +75 -0
  314. data/golden/multirank_hoisting/expected/lir_01_hoist_scalar_references.txt +75 -0
  315. data/golden/multirank_hoisting/expected/lir_02_inlined.txt +126 -0
  316. data/golden/multirank_hoisting/expected/lir_03_cse.txt +109 -0
  317. data/golden/multirank_hoisting/expected/lir_04_1_loop_fusion.txt +109 -0
  318. data/golden/multirank_hoisting/expected/lir_04_loop_invcm.txt +109 -0
  319. data/golden/multirank_hoisting/expected/lir_06_const_prop.txt +109 -0
  320. data/golden/multirank_hoisting/expected/nast.txt +39 -0
  321. data/golden/multirank_hoisting/expected/schema_javascript.mjs +128 -0
  322. data/golden/multirank_hoisting/expected/schema_ruby.rb +162 -0
  323. data/golden/multirank_hoisting/expected/snast.txt +39 -0
  324. data/golden/multirank_hoisting/expected.json +15 -0
  325. data/golden/multirank_hoisting/input.json +19 -0
  326. data/golden/multirank_hoisting/schema.kumi +38 -0
  327. data/golden/nested_hash/expected/ast.txt +22 -0
  328. data/golden/nested_hash/expected/input_plan.txt +5 -0
  329. data/golden/nested_hash/expected/lir_00_unoptimized.txt +10 -0
  330. data/golden/nested_hash/expected/lir_01_hoist_scalar_references.txt +10 -0
  331. data/golden/nested_hash/expected/lir_02_inlined.txt +10 -0
  332. data/golden/nested_hash/expected/lir_03_cse.txt +10 -0
  333. data/golden/nested_hash/expected/lir_04_1_loop_fusion.txt +10 -0
  334. data/golden/nested_hash/expected/lir_04_loop_invcm.txt +10 -0
  335. data/golden/nested_hash/expected/lir_06_const_prop.txt +10 -0
  336. data/golden/nested_hash/expected/nast.txt +8 -0
  337. data/golden/nested_hash/expected/schema_javascript.mjs +9 -0
  338. data/golden/nested_hash/expected/schema_ruby.rb +35 -0
  339. data/golden/nested_hash/expected/snast.txt +8 -0
  340. data/golden/nested_hash/expected.json +3 -0
  341. data/golden/nested_hash/input.json +7 -0
  342. data/golden/nested_hash/schema.kumi +11 -0
  343. data/golden/reduction_broadcast/expected/ast.txt +49 -0
  344. data/golden/reduction_broadcast/expected/input_plan.txt +13 -0
  345. data/golden/reduction_broadcast/expected/lir_00_unoptimized.txt +49 -0
  346. data/golden/reduction_broadcast/expected/lir_01_hoist_scalar_references.txt +49 -0
  347. data/golden/reduction_broadcast/expected/lir_02_inlined.txt +80 -0
  348. data/golden/reduction_broadcast/expected/lir_03_cse.txt +68 -0
  349. data/golden/reduction_broadcast/expected/lir_04_1_loop_fusion.txt +68 -0
  350. data/golden/reduction_broadcast/expected/lir_04_loop_invcm.txt +68 -0
  351. data/golden/reduction_broadcast/expected/lir_06_const_prop.txt +68 -0
  352. data/golden/reduction_broadcast/expected/nast.txt +24 -0
  353. data/golden/reduction_broadcast/expected/schema_javascript.mjs +74 -0
  354. data/golden/reduction_broadcast/expected/schema_ruby.rb +110 -0
  355. data/golden/reduction_broadcast/expected/snast.txt +24 -0
  356. data/golden/reduction_broadcast/expected.json +25 -0
  357. data/golden/reduction_broadcast/input.json +19 -0
  358. data/golden/reduction_broadcast/schema.kumi +34 -0
  359. data/golden/roll/expected/ast.txt +36 -0
  360. data/golden/roll/expected/input_plan.txt +3 -0
  361. data/golden/roll/expected/lir_00_unoptimized.txt +56 -0
  362. data/golden/roll/expected/lir_01_hoist_scalar_references.txt +56 -0
  363. data/golden/roll/expected/lir_02_inlined.txt +56 -0
  364. data/golden/roll/expected/lir_03_cse.txt +55 -0
  365. data/golden/roll/expected/lir_04_1_loop_fusion.txt +55 -0
  366. data/golden/roll/expected/lir_04_loop_invcm.txt +55 -0
  367. data/golden/roll/expected/lir_06_const_prop.txt +55 -0
  368. data/golden/roll/expected/nast.txt +26 -0
  369. data/golden/roll/expected/schema_javascript.mjs +65 -0
  370. data/golden/roll/expected/schema_ruby.rb +95 -0
  371. data/golden/roll/expected/snast.txt +26 -0
  372. data/golden/roll/expected.json +6 -0
  373. data/golden/roll/input.json +1 -0
  374. data/golden/roll/schema.kumi +13 -0
  375. data/golden/shift/expected/ast.txt +48 -0
  376. data/golden/shift/expected/input_plan.txt +3 -0
  377. data/golden/shift/expected/lir_00_unoptimized.txt +96 -0
  378. data/golden/shift/expected/lir_01_hoist_scalar_references.txt +96 -0
  379. data/golden/shift/expected/lir_02_inlined.txt +96 -0
  380. data/golden/shift/expected/lir_03_cse.txt +90 -0
  381. data/golden/shift/expected/lir_04_1_loop_fusion.txt +90 -0
  382. data/golden/shift/expected/lir_04_loop_invcm.txt +90 -0
  383. data/golden/shift/expected/lir_06_const_prop.txt +90 -0
  384. data/golden/shift/expected/nast.txt +38 -0
  385. data/golden/shift/expected/schema_javascript.mjs +106 -0
  386. data/golden/shift/expected/schema_ruby.rb +138 -0
  387. data/golden/shift/expected/snast.txt +38 -0
  388. data/golden/shift/expected.json +8 -0
  389. data/golden/shift/input.json +1 -0
  390. data/golden/shift/schema.kumi +15 -0
  391. data/golden/shift_2d/expected/ast.txt +88 -0
  392. data/golden/shift_2d/expected/input_plan.txt +5 -0
  393. data/golden/shift_2d/expected/lir_00_unoptimized.txt +274 -0
  394. data/golden/shift_2d/expected/lir_01_hoist_scalar_references.txt +274 -0
  395. data/golden/shift_2d/expected/lir_02_inlined.txt +274 -0
  396. data/golden/shift_2d/expected/lir_03_cse.txt +262 -0
  397. data/golden/shift_2d/expected/lir_04_1_loop_fusion.txt +262 -0
  398. data/golden/shift_2d/expected/lir_04_loop_invcm.txt +262 -0
  399. data/golden/shift_2d/expected/lir_06_const_prop.txt +262 -0
  400. data/golden/shift_2d/expected/nast.txt +74 -0
  401. data/golden/shift_2d/expected/schema_javascript.mjs +320 -0
  402. data/golden/shift_2d/expected/schema_ruby.rb +358 -0
  403. data/golden/shift_2d/expected/snast.txt +74 -0
  404. data/golden/shift_2d/expected.json +15 -0
  405. data/golden/shift_2d/input.json +14 -0
  406. data/golden/shift_2d/schema.kumi +25 -0
  407. data/golden/simple_math/expected/ast.txt +40 -0
  408. data/golden/simple_math/expected/input_plan.txt +2 -0
  409. data/golden/simple_math/expected/lir_00_unoptimized.txt +31 -0
  410. data/golden/simple_math/expected/lir_01_hoist_scalar_references.txt +31 -0
  411. data/golden/simple_math/expected/lir_02_inlined.txt +31 -0
  412. data/golden/simple_math/expected/lir_03_cse.txt +31 -0
  413. data/golden/simple_math/expected/lir_04_1_loop_fusion.txt +31 -0
  414. data/golden/simple_math/expected/lir_04_loop_invcm.txt +31 -0
  415. data/golden/simple_math/expected/lir_06_const_prop.txt +31 -0
  416. data/golden/simple_math/expected/nast.txt +33 -0
  417. data/golden/simple_math/expected/schema_javascript.mjs +33 -0
  418. data/golden/simple_math/expected/schema_ruby.rb +59 -0
  419. data/golden/simple_math/expected/snast.txt +33 -0
  420. data/golden/simple_math/expected.json +1 -0
  421. data/golden/simple_math/input.json +4 -0
  422. data/golden/simple_math/schema.kumi +2 -1
  423. data/golden/streaming_basics/expected/ast.txt +64 -0
  424. data/golden/streaming_basics/expected/input_plan.txt +8 -0
  425. data/golden/streaming_basics/expected/lir_00_unoptimized.txt +73 -0
  426. data/golden/streaming_basics/expected/lir_01_hoist_scalar_references.txt +73 -0
  427. data/golden/streaming_basics/expected/lir_02_inlined.txt +100 -0
  428. data/golden/streaming_basics/expected/lir_03_cse.txt +84 -0
  429. data/golden/streaming_basics/expected/lir_04_1_loop_fusion.txt +84 -0
  430. data/golden/streaming_basics/expected/lir_04_loop_invcm.txt +84 -0
  431. data/golden/streaming_basics/expected/lir_06_const_prop.txt +84 -0
  432. data/golden/streaming_basics/expected/nast.txt +48 -0
  433. data/golden/streaming_basics/expected/schema_javascript.mjs +94 -0
  434. data/golden/streaming_basics/expected/schema_ruby.rb +127 -0
  435. data/golden/streaming_basics/expected/snast.txt +48 -0
  436. data/golden/streaming_basics/expected.json +10 -0
  437. data/golden/streaming_basics/input.json +8 -0
  438. data/golden/streaming_basics/schema.kumi +24 -0
  439. data/golden/tuples/expected/ast.txt +48 -0
  440. data/golden/tuples/expected/input_plan.txt +1 -0
  441. data/golden/tuples/expected/lir_00_unoptimized.txt +40 -0
  442. data/golden/tuples/expected/lir_01_hoist_scalar_references.txt +40 -0
  443. data/golden/tuples/expected/lir_02_inlined.txt +48 -0
  444. data/golden/tuples/expected/lir_03_cse.txt +48 -0
  445. data/golden/tuples/expected/lir_04_1_loop_fusion.txt +48 -0
  446. data/golden/tuples/expected/lir_04_loop_invcm.txt +48 -0
  447. data/golden/tuples/expected/lir_06_const_prop.txt +48 -0
  448. data/golden/tuples/expected/nast.txt +42 -0
  449. data/golden/tuples/expected/schema_javascript.mjs +51 -0
  450. data/golden/tuples/expected/schema_ruby.rb +77 -0
  451. data/golden/tuples/expected/snast.txt +42 -0
  452. data/golden/tuples/expected.json +7 -0
  453. data/golden/tuples/input.json +3 -0
  454. data/golden/tuples/schema.kumi +11 -0
  455. data/golden/tuples_and_arrays/expected/ast.txt +44 -0
  456. data/golden/tuples_and_arrays/expected/input_plan.txt +7 -0
  457. data/golden/tuples_and_arrays/expected/lir_00_unoptimized.txt +41 -0
  458. data/golden/tuples_and_arrays/expected/lir_01_hoist_scalar_references.txt +41 -0
  459. data/golden/tuples_and_arrays/expected/lir_02_inlined.txt +62 -0
  460. data/golden/tuples_and_arrays/expected/lir_03_cse.txt +51 -0
  461. data/golden/tuples_and_arrays/expected/lir_04_1_loop_fusion.txt +51 -0
  462. data/golden/tuples_and_arrays/expected/lir_04_loop_invcm.txt +51 -0
  463. data/golden/tuples_and_arrays/expected/lir_06_const_prop.txt +51 -0
  464. data/golden/tuples_and_arrays/expected/nast.txt +28 -0
  465. data/golden/tuples_and_arrays/expected/schema_javascript.mjs +58 -0
  466. data/golden/tuples_and_arrays/expected/schema_ruby.rb +88 -0
  467. data/golden/tuples_and_arrays/expected/snast.txt +28 -0
  468. data/golden/tuples_and_arrays/expected.json +18 -0
  469. data/golden/tuples_and_arrays/input.json +7 -0
  470. data/golden/tuples_and_arrays/schema.kumi +38 -0
  471. data/golden/with_constants/expected/ast.txt +28 -0
  472. data/golden/with_constants/expected/input_plan.txt +2 -0
  473. data/golden/with_constants/expected/lir_00_unoptimized.txt +17 -0
  474. data/golden/with_constants/expected/lir_01_hoist_scalar_references.txt +17 -0
  475. data/golden/with_constants/expected/lir_02_inlined.txt +17 -0
  476. data/golden/with_constants/expected/lir_03_cse.txt +17 -0
  477. data/golden/with_constants/expected/lir_04_1_loop_fusion.txt +17 -0
  478. data/golden/with_constants/expected/lir_04_loop_invcm.txt +17 -0
  479. data/golden/with_constants/expected/lir_06_const_prop.txt +17 -0
  480. data/golden/with_constants/expected/nast.txt +21 -0
  481. data/golden/with_constants/expected/schema_javascript.mjs +18 -0
  482. data/golden/with_constants/expected/schema_ruby.rb +44 -0
  483. data/golden/with_constants/expected/snast.txt +15 -0
  484. data/golden/with_constants/schema.kumi +10 -0
  485. data/lib/kumi/analyzer.rb +76 -24
  486. data/lib/kumi/configuration.rb +60 -0
  487. data/lib/kumi/core/analyzer/binder.rb +121 -0
  488. data/lib/kumi/core/analyzer/checkpoint.rb +15 -9
  489. data/lib/kumi/core/analyzer/constant_evaluator.rb +32 -37
  490. data/lib/kumi/core/analyzer/constant_folding_helpers.rb +55 -0
  491. data/lib/kumi/core/analyzer/debug.rb +14 -16
  492. data/lib/kumi/core/analyzer/fn_aliases.rb +46 -0
  493. data/lib/kumi/core/analyzer/folder.rb +94 -0
  494. data/lib/kumi/core/analyzer/macro_expander.rb +69 -0
  495. data/lib/kumi/core/analyzer/passes/assemble_irv2_pass.rb +130 -0
  496. data/lib/kumi/core/analyzer/passes/attach_anchors_pass.rb +71 -0
  497. data/lib/kumi/core/analyzer/passes/attach_terminal_info_pass.rb +181 -0
  498. data/lib/kumi/core/analyzer/passes/codegen/js/declaration_emitter.rb +317 -0
  499. data/lib/kumi/core/analyzer/passes/codegen/js/emitter.rb +75 -0
  500. data/lib/kumi/core/analyzer/passes/codegen/js/output_buffer.rb +103 -0
  501. data/lib/kumi/core/analyzer/passes/codegen/js_pass.rb +27 -0
  502. data/lib/kumi/core/analyzer/passes/codegen/ruby/declaration_emitter.rb +321 -0
  503. data/lib/kumi/core/analyzer/passes/codegen/ruby/emitter.rb +85 -0
  504. data/lib/kumi/core/analyzer/passes/codegen/ruby/output_buffer.rb +111 -0
  505. data/lib/kumi/core/analyzer/passes/codegen/ruby_pass.rb +32 -0
  506. data/lib/kumi/core/analyzer/passes/constant_folding_pass.rb +33 -0
  507. data/lib/kumi/core/analyzer/passes/contract_checker_pass.rb +220 -0
  508. data/lib/kumi/core/analyzer/passes/dependency_resolver.rb +5 -6
  509. data/lib/kumi/core/analyzer/passes/input_access_planner_pass.rb +7 -3
  510. data/lib/kumi/core/analyzer/passes/input_collector.rb +74 -122
  511. data/lib/kumi/core/analyzer/passes/input_form_schema_pass.rb +43 -0
  512. data/lib/kumi/core/analyzer/passes/ir_dependency_pass.rb +1 -1
  513. data/lib/kumi/core/analyzer/passes/ir_execution_schedule_pass.rb +1 -1
  514. data/lib/kumi/core/analyzer/passes/join_reduce_planning_pass.rb +21 -23
  515. data/lib/kumi/core/analyzer/passes/lir/constant_propagation_pass.rb +84 -0
  516. data/lib/kumi/core/analyzer/passes/lir/dead_code_elimination_pass.rb +93 -0
  517. data/lib/kumi/core/analyzer/passes/lir/hoist_scalar_references_pass.rb +115 -0
  518. data/lib/kumi/core/analyzer/passes/lir/inline_declarations_pass.rb +274 -0
  519. data/lib/kumi/core/analyzer/passes/lir/instruction_scheduling_pass.rb +198 -0
  520. data/lib/kumi/core/analyzer/passes/lir/kernel_binding_pass.rb +30 -0
  521. data/lib/kumi/core/analyzer/passes/lir/local_cse_pass.rb +121 -0
  522. data/lib/kumi/core/analyzer/passes/lir/loop_fusion_pass.rb +156 -0
  523. data/lib/kumi/core/analyzer/passes/lir/loop_invariant_code_motion_pass.rb +148 -0
  524. data/lib/kumi/core/analyzer/passes/lir/lower_pass.rb +407 -0
  525. data/lib/kumi/core/analyzer/passes/lir/stencil_emitter.rb +243 -0
  526. data/lib/kumi/core/analyzer/passes/lir/validation_pass.rb +83 -0
  527. data/lib/kumi/core/analyzer/passes/load_input_cse.rb +17 -16
  528. data/lib/kumi/core/analyzer/passes/lower_to_ir_pass.rb +4 -2
  529. data/lib/kumi/core/analyzer/passes/lower_to_irv2_pass.rb +197 -0
  530. data/lib/kumi/core/analyzer/passes/name_indexer.rb +4 -1
  531. data/lib/kumi/core/analyzer/passes/nast_dimensional_analyzer_pass.rb +237 -0
  532. data/lib/kumi/core/analyzer/passes/normalize_to_nast_pass.rb +156 -0
  533. data/lib/kumi/core/analyzer/passes/output_schema_pass.rb +38 -0
  534. data/lib/kumi/core/analyzer/passes/pass_base.rb +30 -4
  535. data/lib/kumi/core/analyzer/passes/precompute_access_paths_pass.rb +93 -0
  536. data/lib/kumi/core/analyzer/passes/scope_resolution_pass.rb +33 -30
  537. data/lib/kumi/core/analyzer/passes/semantic_constraint_validator.rb +5 -26
  538. data/lib/kumi/core/analyzer/passes/snast_pass.rb +229 -0
  539. data/lib/kumi/core/analyzer/passes/toposorter.rb +1 -0
  540. data/lib/kumi/core/analyzer/passes/type_checker.rb +13 -0
  541. data/lib/kumi/core/analyzer/passes/type_inferencer_pass.rb +14 -16
  542. data/lib/kumi/core/analyzer/passes/unsat_detector.rb +2 -1
  543. data/lib/kumi/core/analyzer/plans.rb +12 -0
  544. data/lib/kumi/core/analyzer/state_serde.rb +4 -4
  545. data/lib/kumi/core/analyzer/structs/access_plan.rb +2 -2
  546. data/lib/kumi/core/analyzer/unsat_constant_evaluator.rb +59 -0
  547. data/lib/kumi/core/compiler/access_codegen.rb +1 -1
  548. data/lib/kumi/core/compiler/access_emit/base.rb +9 -5
  549. data/lib/kumi/core/compiler/access_emit/each_indexed.rb +10 -3
  550. data/lib/kumi/core/compiler/access_emit/materialize.rb +12 -5
  551. data/lib/kumi/core/compiler/access_emit/ravel.rb +10 -3
  552. data/lib/kumi/core/compiler/access_emit/read.rb +4 -1
  553. data/lib/kumi/core/compiler/access_planner.rb +42 -4
  554. data/lib/kumi/core/compiler/access_planner_v2.rb +164 -0
  555. data/lib/kumi/core/explain.rb +18 -11
  556. data/lib/kumi/core/functions/loader.rb +47 -0
  557. data/lib/kumi/core/functions/model.rb +10 -0
  558. data/lib/kumi/core/functions/type_rules.rb +108 -0
  559. data/lib/kumi/core/ir/execution_engine/interpreter.rb +1 -1
  560. data/lib/kumi/core/ir/execution_engine/profiler.rb +107 -97
  561. data/lib/kumi/core/ir.rb +6 -2
  562. data/lib/kumi/core/irv2/builder.rb +48 -0
  563. data/lib/kumi/core/irv2/declaration.rb +28 -0
  564. data/lib/kumi/core/irv2/module.rb +108 -0
  565. data/lib/kumi/core/irv2/value.rb +28 -0
  566. data/lib/kumi/core/lir/analyze.rb +64 -0
  567. data/lib/kumi/core/lir/build.rb +363 -0
  568. data/lib/kumi/core/lir/emit.rb +62 -0
  569. data/lib/kumi/core/lir/structs/instruction.rb +44 -0
  570. data/lib/kumi/core/lir/structs/literal.rb +14 -0
  571. data/lib/kumi/core/lir/structs/stamp.rb +13 -0
  572. data/lib/kumi/core/lir/support/error.rb +9 -0
  573. data/lib/kumi/core/lir/support/ids.rb +34 -0
  574. data/lib/kumi/core/lir/validate.rb +74 -0
  575. data/lib/kumi/core/lir.rb +34 -0
  576. data/lib/kumi/core/nast.rb +216 -0
  577. data/lib/kumi/core/ruby_parser/dsl.rb +2 -2
  578. data/lib/kumi/core/ruby_parser/dsl_cascade_builder.rb +1 -1
  579. data/lib/kumi/core/ruby_parser/expression_converter.rb +10 -0
  580. data/lib/kumi/core/ruby_parser/input_builder.rb +16 -17
  581. data/lib/kumi/core/ruby_parser/schema_builder.rb +36 -10
  582. data/lib/kumi/core/ruby_parser/sugar.rb +64 -0
  583. data/lib/kumi/core/types/builder.rb +2 -2
  584. data/lib/kumi/core/types/normalizer.rb +2 -0
  585. data/lib/kumi/core/types/validator.rb +10 -3
  586. data/lib/kumi/core/types.rb +7 -0
  587. data/lib/kumi/dev/codegen.rb +194 -0
  588. data/lib/kumi/dev/golden/generator.rb +105 -0
  589. data/lib/kumi/dev/golden/reporter.rb +160 -0
  590. data/lib/kumi/dev/golden/representation.rb +45 -0
  591. data/lib/kumi/dev/golden/result.rb +98 -0
  592. data/lib/kumi/dev/golden/runtime_test.rb +93 -0
  593. data/lib/kumi/dev/golden/suite.rb +131 -0
  594. data/lib/kumi/dev/golden/verifier.rb +76 -0
  595. data/lib/kumi/dev/golden.rb +75 -0
  596. data/lib/kumi/dev/ir.rb +4 -4
  597. data/lib/kumi/dev/parse.rb +1 -1
  598. data/lib/kumi/dev/pretty_printer.rb +229 -0
  599. data/lib/kumi/dev/printer/irv2_formatter.rb +163 -0
  600. data/lib/kumi/dev/printer/width_aware_json.rb +44 -0
  601. data/lib/kumi/dev/profile_aggregator.rb +36 -38
  602. data/lib/kumi/dev/profile_runner.rb +19 -23
  603. data/lib/kumi/dev/runner.rb +12 -22
  604. data/lib/kumi/dev/support/kumi_runner.mjs +39 -0
  605. data/lib/kumi/dev.rb +3 -3
  606. data/lib/kumi/frontends/ruby.rb +12 -12
  607. data/lib/kumi/frontends/text.rb +26 -21
  608. data/lib/kumi/frontends.rb +6 -8
  609. data/lib/kumi/kernel_registry.rb +59 -0
  610. data/lib/kumi/pack/builder.rb +229 -0
  611. data/lib/kumi/pack.rb +15 -0
  612. data/lib/kumi/registry_v2/loader.rb +81 -0
  613. data/lib/kumi/registry_v2.rb +118 -0
  614. data/lib/kumi/schema.rb +83 -43
  615. data/lib/kumi/support/diff.rb +3 -2
  616. data/lib/kumi/support/ir_render.rb +1 -1
  617. data/lib/kumi/support/lir_printer.rb +143 -0
  618. data/lib/kumi/support/nast_printer.rb +93 -0
  619. data/lib/kumi/support/s_expression_printer.rb +5 -4
  620. data/lib/kumi/support/snast_printer.rb +111 -0
  621. data/lib/kumi/syntax/call_expression.rb +1 -1
  622. data/lib/kumi/syntax/input_declaration.rb +2 -2
  623. data/lib/kumi/syntax/node.rb +4 -12
  624. data/lib/kumi/syntax/root.rb +10 -0
  625. data/lib/kumi/syntax/trait_declaration.rb +1 -0
  626. data/lib/kumi/syntax/value_declaration.rb +1 -0
  627. data/lib/kumi/version.rb +1 -1
  628. data/lib/kumi.rb +47 -5
  629. metadata +571 -54
  630. data/docs/AST.md +0 -133
  631. data/docs/DSL.md +0 -154
  632. data/docs/FUNCTIONS.md +0 -176
  633. data/docs/VECTOR_SEMANTICS.md +0 -286
  634. data/docs/compiler_design_principles.md +0 -86
  635. data/docs/dev/analyzer-debug.md +0 -52
  636. data/docs/dev/parse-command.md +0 -64
  637. data/docs/dev/vm-profiling.md +0 -95
  638. data/docs/development/README.md +0 -120
  639. data/docs/development/error-reporting.md +0 -361
  640. data/docs/features/README.md +0 -58
  641. data/docs/features/analysis-type-inference.md +0 -42
  642. data/docs/features/analysis-unsat-detection.md +0 -71
  643. data/docs/features/hierarchical-broadcasting.md +0 -415
  644. data/docs/features/input-declaration-system.md +0 -58
  645. data/docs/features/performance.md +0 -14
  646. data/docs/features/s-expression-printer.md +0 -77
  647. data/docs/schema_metadata/broadcasts.md +0 -53
  648. data/docs/schema_metadata/cascades.md +0 -45
  649. data/docs/schema_metadata/declarations.md +0 -54
  650. data/docs/schema_metadata/dependencies.md +0 -57
  651. data/docs/schema_metadata/evaluation_order.md +0 -29
  652. data/docs/schema_metadata/examples.md +0 -95
  653. data/docs/schema_metadata/inferred_types.md +0 -46
  654. data/docs/schema_metadata/inputs.md +0 -86
  655. data/docs/schema_metadata.md +0 -108
  656. data/golden/mixed_nesting/schema.kumi +0 -42
  657. data/lib/kumi/core/function_registry/collection_functions.rb +0 -298
  658. data/lib/kumi/core/function_registry/comparison_functions.rb +0 -33
  659. data/lib/kumi/core/function_registry/conditional_functions.rb +0 -48
  660. data/lib/kumi/core/function_registry/function_builder.rb +0 -184
  661. data/lib/kumi/core/function_registry/logical_functions.rb +0 -214
  662. data/lib/kumi/core/function_registry/math_functions.rb +0 -74
  663. data/lib/kumi/core/function_registry/stat_functions.rb +0 -156
  664. data/lib/kumi/core/function_registry/string_functions.rb +0 -57
  665. data/lib/kumi/core/function_registry/type_functions.rb +0 -53
  666. data/lib/kumi/core/function_registry.rb +0 -176
  667. data/lib/kumi/registry.rb +0 -32
  668. data/lib/kumi/runtime/executable.rb +0 -135
  669. data/lib/kumi/runtime/run.rb +0 -105
  670. data/performance_results.txt +0 -63
  671. data/scripts/analyze_broadcast_methods.rb +0 -68
  672. data/scripts/analyze_cascade_methods.rb +0 -74
  673. data/scripts/check_broadcasting_coverage.rb +0 -51
  674. data/scripts/find_dead_code.rb +0 -114
  675. data/scripts/generate_function_docs.rb +0 -71
  676. data/scripts/test_mixed_nesting_performance.rb +0 -206
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "tmpdir"
4
+
5
+ module Kumi
6
+ # Holds the configuration state for the Kumi compiler and runtime.
7
+ # This object is yielded to the user in the `Kumi.configure` block.
8
+ class Configuration
9
+ # The directory where compiled schemas are stored as cached Ruby files.
10
+ # On file-based systems, this is crucial for performance.
11
+ attr_accessor :cache_path
12
+
13
+ # The compilation strategy.
14
+ # :jit (Just-in-Time): Compiles schemas on-the-fly at boot time if the
15
+ # source has changed. Ideal for development.
16
+ # :aot (Ahead-of-Time): Expects schemas to be precompiled via a build
17
+ # task. Raises an error at runtime if a compiled file is missing.
18
+ # Ideal for production and test environments.
19
+ attr_accessor :compilation_mode
20
+
21
+ # A master switch to bypass the cache and force recompilation on every run.
22
+ # Useful for debugging the compiler itself.
23
+ attr_accessor :force_recompile
24
+
25
+ def initialize
26
+ # Set smart, environment-aware defaults.
27
+ @cache_path = default_cache_path
28
+ @compilation_mode = default_compilation_mode
29
+ @force_recompile = false
30
+ end
31
+
32
+ private
33
+
34
+ # Provides a sensible default cache path.
35
+ # It prefers the Rails cache directory if available, otherwise uses the
36
+ # system's temporary directory.
37
+ def default_cache_path
38
+ if defined?(Rails) && Rails.root
39
+ Rails.root.join("tmp", "cache", "kumi")
40
+ else
41
+ File.join(Dir.tmpdir, "kumi_cache")
42
+ end
43
+ end
44
+
45
+ # Determines the best compilation mode based on the environment.
46
+ # The convention is to use JIT for development for a seamless "save and
47
+ # refresh" experience, and AOT for production to ensure fast boots
48
+ # and catch precompilation errors in CI.
49
+ def default_compilation_mode
50
+ # RACK_ENV is a common standard, but Rails.env is more specific.
51
+ env = defined?(Rails) ? Rails.env.to_s : ENV.fetch("RACK_ENV", nil)
52
+
53
+ if env == "development"
54
+ :jit
55
+ else
56
+ :aot
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "digest"
5
+
6
+ module Kumi
7
+ module Core
8
+ module Analyzer
9
+ module Binder
10
+ OPS_WITH_KERNELS = %i[KernelCall Accumulate Fold].freeze
11
+
12
+ module_function
13
+
14
+ def bind(lir_decls, registry, target:)
15
+ bindings = []
16
+ target_sym = target.to_sym
17
+
18
+ lir_decls.each do |decl_name, decl|
19
+ Array(decl[:operations]).each do |op|
20
+ opcode = op.opcode
21
+ next unless OPS_WITH_KERNELS.include?(opcode)
22
+
23
+ fn_name = op.attributes[:fn]
24
+ raise "KernelCall at #{op.location} is missing :fn attribute" unless fn_name
25
+
26
+ function = registry.function(fn_name)
27
+ fn_id = function.id
28
+
29
+ kernel = registry.kernel_for(fn_id, target: target_sym)
30
+ id = kernel.id
31
+ impl = kernel.impl
32
+ inline = kernel.inline
33
+ fold_inline = kernel.fold_inline
34
+ dtype = op.stamp&.dig("dtype")
35
+
36
+ attrs = {}
37
+
38
+ attrs["inline"] = inline if inline
39
+ attrs["fold_inline"] = fold_inline if fold_inline
40
+
41
+ # TODO: Make this logic clear, we are mixing reducers functions that works over scalars collections and eachwise, this is confusing.
42
+ if function.reduce? && opcode != :Fold
43
+ case function.reduction_strategy
44
+ when :identity
45
+
46
+ identity = registry.kernel_identity_for(fn_id, dtype: dtype, target: target_sym)
47
+ attrs["identity"] = identity if identity
48
+ when :first_element
49
+ attrs["first_element"] = true
50
+ end
51
+ end
52
+
53
+ fname = fn_id.split(".").join("_")
54
+
55
+ bindings << {
56
+ "decl" => decl_name.to_s,
57
+ "op_result_reg" => op.result_register,
58
+ "fn" => fn_name, # Original function name/alias
59
+ "fn_id" => fn_id, # Resolved canonical function ID
60
+ "fname" => fname, # Sanitized function name for use in Ruby method names
61
+ "id" => id,
62
+ "impl" => impl,
63
+ "attrs" => attrs
64
+ }
65
+ end
66
+ end
67
+
68
+ deduplicated = deduplicate_kernel_impls(bindings)
69
+
70
+ {
71
+ "lir_ref" => sha256_lir_ref(lir_decls),
72
+ "target" => target.to_s,
73
+ "registry_ref" => registry.registry_ref,
74
+ "bindings" => deduplicated[:bindings],
75
+ "kernels" => deduplicated[:kernels]
76
+ }
77
+ end
78
+
79
+ def deduplicate_kernel_impls(bindings)
80
+ kernels = {}
81
+ deduplicated_bindings = []
82
+
83
+ bindings.each do |binding|
84
+ id = binding["id"]
85
+ impl = binding["impl"]
86
+ attrs = binding["attrs"]
87
+
88
+ if kernels.key?(id)
89
+ raise "Inconsistent impl for #{id}" unless kernels[id]["impl"] == impl
90
+
91
+ kernels[id]["attrs"].merge!(attrs)
92
+ else
93
+ kernels[id] = {
94
+ "id" => id,
95
+ "fn_id" => binding["fn_id"],
96
+ "impl" => impl,
97
+ "attrs" => attrs
98
+ }
99
+ end
100
+
101
+ deduplicated_bindings << binding.reject { |k, _| %w[impl attrs].include?(k) }
102
+ end
103
+
104
+ {
105
+ bindings: deduplicated_bindings,
106
+ kernels: kernels.values
107
+ }
108
+ end
109
+
110
+ def sha256_lir_ref(lir_decls)
111
+ canonical_decls = lir_decls.transform_values do |decl|
112
+ decl[:operations].map(&:to_h)
113
+ end
114
+
115
+ json = JSON.generate(canonical_decls, { ascii_only: true, array_nl: "", object_nl: "", indent: "", space: "", space_before: "" })
116
+ "sha256:#{Digest::SHA256.hexdigest(json)}"
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -9,6 +9,8 @@ module Kumi
9
9
  class << self
10
10
  # ===== Interface shape matches Debug =====
11
11
  def enabled?
12
+ return false if ENV["KUMI_CHECKPOINT"] == "0"
13
+
12
14
  ENV["KUMI_CHECKPOINT"] == "1" ||
13
15
  !resume_from.nil? || !resume_at.nil? || !stop_after.nil?
14
16
  end
@@ -17,26 +19,32 @@ module Kumi
17
19
  def dir = ENV["KUMI_CHECKPOINT_DIR"] || "tmp/analysis_snapshots"
18
20
  def phases = (ENV["KUMI_CHECKPOINT_PHASE"] || "before,after").split(",").map! { _1.strip.downcase.to_sym }
19
21
  def formats = (ENV["KUMI_CHECKPOINT_FORMAT"] || "marshal").split(",").map! { _1.strip.downcase } # marshal|json|both
20
- def resume_from = ENV["KUMI_RESUME_FROM"] # file path (.msh or .json)
21
- def resume_at = ENV["KUMI_RESUME_AT"] # pass short name
22
- def stop_after = ENV["KUMI_STOP_AFTER"] # pass short name
22
+ def resume_from = ENV.fetch("KUMI_RESUME_FROM", nil) # file path (.msh or .json)
23
+ def resume_at = ENV.fetch("KUMI_RESUME_AT", nil) # pass short name
24
+ def stop_after = ENV.fetch("KUMI_STOP_AFTER", nil) # pass short name
23
25
 
24
26
  # ===== Lifecycle (called by analyzer) =====
25
27
  def load_initial_state(default_state)
26
28
  path = resume_from
27
29
  return default_state unless path && File.exist?(path)
30
+
28
31
  data = File.binread(path)
29
- path.end_with?(".msh") ? StateSerde.load_marshal(data)
30
- : StateSerde.load_json(data)
32
+ if path.end_with?(".msh")
33
+ StateSerde.load_marshal(data)
34
+ else
35
+ StateSerde.load_json(data)
36
+ end
31
37
  end
32
38
 
33
39
  def entering(pass_name:, idx:, state:)
34
40
  return unless enabled?
41
+
35
42
  snapshot(pass_name:, idx:, phase: :before, state:) if phases.include?(:before)
36
43
  end
37
44
 
38
45
  def leaving(pass_name:, idx:, state:)
39
46
  return unless enabled?
47
+
40
48
  snapshot(pass_name:, idx:, phase: :after, state:) if phases.include?(:after)
41
49
  end
42
50
 
@@ -59,9 +67,7 @@ module Kumi
59
67
  end
60
68
 
61
69
  # Fold checkpoint info into the same per-pass logs the Debugger uses.
62
- if Core::Analyzer::Debug.enabled?
63
- Core::Analyzer::Debug.info(:checkpoint, phase:, idx:, files:)
64
- end
70
+ Core::Analyzer::Debug.info(:checkpoint, phase:, idx:, files:) if Core::Analyzer::Debug.enabled?
65
71
 
66
72
  files
67
73
  end
@@ -69,4 +75,4 @@ module Kumi
69
75
  end
70
76
  end
71
77
  end
72
- end
78
+ end
@@ -4,54 +4,49 @@ module Kumi
4
4
  module Core
5
5
  module Analyzer
6
6
  class ConstantEvaluator
7
- include Syntax
7
+ NAST = Kumi::Core::NAST
8
8
 
9
- def initialize(definitions)
10
- @definitions = definitions
11
- @memo = {}
9
+ def self.evaluate(call_node, registry, known_constants = {})
10
+ new(call_node, registry, known_constants).evaluate
12
11
  end
13
12
 
14
- OPERATORS = {
15
- add: :+,
16
- subtract: :-,
17
- multiply: :*,
18
- divide: :/
19
- }.freeze
20
-
21
- def evaluate(node, visited = Set.new)
22
- return :unknown unless node
23
- return @memo[node] if @memo.key?(node)
24
- return node.value if node.is_a?(Literal)
25
-
26
- result = case node
27
- when DeclarationReference then evaluate_binding(node, visited)
28
- when CallExpression then evaluate_call_expression(node, visited)
29
- else :unknown
30
- end
31
-
32
- @memo[node] = result unless result == :unknown
33
- result
13
+ def initialize(call_node, registry, known_constants)
14
+ @node = call_node
15
+ @registry = registry
16
+ @known_constants = known_constants
34
17
  end
35
18
 
36
- private
19
+ def evaluate
20
+ arg_values = @node.args.map { |arg| resolve_constant_value(arg) }
37
21
 
38
- def evaluate_binding(node, visited)
39
- return :unknown if visited.include?(node.name)
22
+ return nil if arg_values.any?(&:nil?)
40
23
 
41
- visited << node.name
42
- definition = @definitions[node.name]
43
- return :unknown unless definition
24
+ func = @registry.function(@node.fn)
44
25
 
45
- evaluate(definition.expression, visited)
46
- end
26
+ return nil unless func.respond_to?(:folding_class_method) && func.folding_class_method
47
27
 
48
- def evaluate_call_expression(node, visited)
49
- return :unknown unless OPERATORS.key?(node.fn_name)
28
+ method_name = func.folding_class_method.to_sym
50
29
 
51
- args = node.args.map { |arg| evaluate(arg, visited) }
52
- return :unknown if args.any?(:unknown)
30
+ ConstantFoldingHelpers.send(method_name, *arg_values)
31
+ rescue StandardError
32
+ nil
33
+ end
34
+
35
+ private
53
36
 
54
- args.reduce(OPERATORS[node.fn_name])
37
+ def resolve_constant_value(node)
38
+ case node
39
+ when NAST::Const
40
+ node.value
41
+ when NAST::Ref
42
+ const_node = @known_constants[node.name]
43
+ resolve_constant_value(const_node) if const_node
44
+ when NAST::Tuple
45
+ values = node.args.map { |arg| resolve_constant_value(arg) }
46
+ values.all? ? values : nil
47
+ else
48
+ nil
49
+ end
55
50
  end
56
51
  end
57
52
  end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kumi
4
+ module Core
5
+ module Analyzer
6
+ # This module provides pure Ruby implementations of primitive functions
7
+ # specifically for the ConstantEvaluator to use at compile time.
8
+ # This approach avoids all use of `eval` and is fast and secure.
9
+ # It is references by the functions data yamls, as folding_method
10
+ module ConstantFoldingHelpers
11
+ module_function
12
+
13
+ # :agg :booleans
14
+ def all?(collection) = collection.all?
15
+ def any?(collection) = collection.any?
16
+
17
+ # :agg :numeric
18
+ def sum(collection) = collection.sum
19
+ def count(collection) = collection.size
20
+ def avg(collection) = collection.sum.to_f / collection.size
21
+ def min(collection) = collection.min
22
+ def max(collection) = collection.max
23
+
24
+ # :core :numeric
25
+ def add(a, b) = a + b
26
+ def sub(a, b) = a - b
27
+ def mul(a, b) = a * b
28
+ def div(a, b) = a.to_f / b
29
+ def mod(a, b) = a % b
30
+ def at(collection, index) = collection[index]
31
+
32
+ # :core :booleans
33
+ def and(a, b) = a && b
34
+ def or(a, b) = a || b
35
+ def not?(a) = !a
36
+
37
+ # :core :comparisons
38
+ def lt?(a, b) = a < b
39
+ def gt?(a, b) = a > b
40
+ def gte?(a, b) = a >= b
41
+ def eq?(a, b) = a == b
42
+ def neq?(a, b) = a != b
43
+
44
+ # :core :constructor
45
+ def length(collection) = collection.size
46
+ def tuple(*args) = args
47
+
48
+ # :core :select
49
+ def select(condition_mask, value_when_true, value_when_false)
50
+ condition_mask ? value_when_true : value_when_false
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -8,14 +8,14 @@ module Kumi
8
8
  module Analyzer
9
9
  module Debug
10
10
  KEY = :kumi_debug_log
11
-
11
+
12
12
  class << self
13
13
  def enabled?
14
14
  ENV["KUMI_DEBUG_STATE"] == "1"
15
15
  end
16
16
 
17
17
  def output_path
18
- ENV["KUMI_DEBUG_OUTPUT_PATH"]
18
+ ENV.fetch("KUMI_DEBUG_OUTPUT_PATH", nil)
19
19
  end
20
20
 
21
21
  def max_depth
@@ -65,21 +65,20 @@ module Kumi
65
65
 
66
66
  def trace(id, **start_fields)
67
67
  t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
68
- info("#{id}_start".to_sym, **start_fields)
69
- yield.tap do |ret|
68
+ info(:"#{id}_start", **start_fields)
69
+ yield.tap do |_ret|
70
70
  dt = ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0) * 1000).round(2)
71
- info("#{id}_finish".to_sym, ms: dt)
72
- ret
71
+ info(:"#{id}_finish", ms: dt)
73
72
  end
74
- rescue => e
75
- log(level: :error, id: "#{id}_error".to_sym, error: e.class.name, message: e.message)
73
+ rescue StandardError => e
74
+ log(level: :error, id: :"#{id}_error", error: e.class.name, message: e.message)
76
75
  raise
77
76
  end
78
77
 
79
78
  # State diffing
80
79
  def diff_state(before, after)
81
80
  changes = {}
82
-
81
+
83
82
  all_keys = (before.keys + after.keys).uniq
84
83
  all_keys.each do |key|
85
84
  if !before.key?(key)
@@ -94,7 +93,7 @@ module Kumi
94
93
  }
95
94
  end
96
95
  end
97
-
96
+
98
97
  changes
99
98
  end
100
99
 
@@ -107,7 +106,7 @@ module Kumi
107
106
  diff: diff,
108
107
  logs: logs
109
108
  }
110
-
109
+
111
110
  if output_path && !output_path.empty?
112
111
  File.open(output_path, "a") { |f| f.puts(JSON.dump(payload)) }
113
112
  else
@@ -120,7 +119,7 @@ module Kumi
120
119
 
121
120
  def truncate(value, depth = max_depth)
122
121
  return value if depth <= 0
123
-
122
+
124
123
  case value
125
124
  when Hash
126
125
  if value.size > max_items
@@ -144,7 +143,6 @@ module Kumi
144
143
  value
145
144
  end
146
145
  end
147
-
148
146
  end
149
147
 
150
148
  # Mixin for passes
@@ -157,11 +155,11 @@ module Kumi
157
155
  Debug.debug(id, method: __method__, **fields)
158
156
  end
159
157
 
160
- def trace(id, **fields, &block)
161
- Debug.trace(id, **fields, &block)
158
+ def trace(id, **fields, &)
159
+ Debug.trace(id, **fields, &)
162
160
  end
163
161
  end
164
162
  end
165
163
  end
166
164
  end
167
- end
165
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kumi
4
+ module Core
5
+ module Analyzer
6
+ module FnAliases
7
+ # Canonical names use simple domains:
8
+ # - core.* : elementwise / structural ops
9
+ # - agg.* : reductions (sum, etc.)
10
+ #
11
+ # NOTE: keep this lexical-only. Overload resolution (e.g. length on string vs array)
12
+ # should happen in a later resolver pass.
13
+
14
+ MAP = {
15
+ :+ => :"core.add",
16
+ :- => :"core.sub",
17
+ :* => :"core.mul",
18
+ :/ => :"core.div",
19
+ :% => :"core.mod",
20
+ :** => :"core.pow",
21
+ :"==" => :"core.eq",
22
+ :"!=" => :"core.neq",
23
+ :">" => :"core.gt",
24
+ :">=" => :"core.gte",
25
+ :"<" => :"core.lt",
26
+ :"<=" => :"core.lte",
27
+ :"&" => :"core.and",
28
+ :"!" => :"core.not"
29
+ }.freeze
30
+
31
+ # Public: normalize any fn identifier (String/Symbol) to canonical Symbol.
32
+ # Unknown names are returned unchanged (as Symbol).
33
+ def self.canonical(fn)
34
+ key =
35
+ case fn
36
+ when Symbol then fn
37
+ when String then fn.strip.downcase.to_sym
38
+ else fn.to_s.strip.downcase.to_sym
39
+ end
40
+
41
+ MAP.fetch(key, key)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kumi
4
+ module Core
5
+ module Analyzer
6
+ class Folder
7
+ def initialize(pass, nast_module, order, registry)
8
+ @nast_module = nast_module
9
+ @order = order
10
+ @registry = registry
11
+ @pass = pass
12
+ @known_constants = {}
13
+ @changed = false
14
+ end
15
+
16
+ def debug(msg)
17
+ @pass.method(:debug).call(msg)
18
+ end
19
+
20
+ def fold
21
+ folded_decls = {}
22
+ @order.each do |decl_name|
23
+ decl = @nast_module.decls[decl_name]
24
+ next unless decl
25
+
26
+ folded_decls[decl_name] = fold_declaration(decl)
27
+ end
28
+
29
+ [NAST::Module.new(decls: folded_decls), @changed]
30
+ end
31
+
32
+ def fold_declaration(decl)
33
+ debug "[FOLD] Folding declaration :#{decl.name}"
34
+ new_body = fold_node(decl.body)
35
+ @changed ||= !new_body.equal?(decl.body)
36
+
37
+ # *** FIX ***: A node is constant if it's a Const OR a Tuple of only Consts.
38
+ is_constant = new_body.is_a?(NAST::Const) ||
39
+ (new_body.is_a?(NAST::Tuple) && new_body.args.all? { |arg| arg.is_a?(NAST::Const) })
40
+
41
+ if is_constant
42
+ @known_constants[decl.name] = new_body
43
+ debug "[FOLD] - Identified :#{decl.name} as a constant value."
44
+ end
45
+
46
+ NAST::Declaration.new(name: decl.name, body: new_body, loc: decl.loc, meta: decl.meta)
47
+ end
48
+
49
+ def fold_node(node)
50
+ case node
51
+ when NAST::Call
52
+ fold_call(node)
53
+ when NAST::Ref
54
+ resolved_node = @known_constants.fetch(node.name, node)
55
+ unless resolved_node.equal?(node)
56
+ debug "[FOLD] - Propagating constant for ref :#{node.name}"
57
+ @changed = true
58
+ end
59
+ resolved_node
60
+ when NAST::Tuple
61
+ new_args = node.args.map { |arg| fold_node(arg) }
62
+ new_args.map(&:object_id) == node.args.map(&:object_id) ? node : NAST::Tuple.new(args: new_args, loc: node.loc)
63
+ else
64
+ node
65
+ end
66
+ end
67
+
68
+ def fold_call(node)
69
+ folded_args = node.args.map { |arg| fold_node(arg) }
70
+ folded_call = if folded_args.map(&:object_id) == node.args.map(&:object_id)
71
+ node
72
+ else
73
+ NAST::Call.new(fn: node.fn,
74
+ args: folded_args,
75
+ opts: node.opts,
76
+ loc: node.loc)
77
+ end
78
+
79
+ debug "[FOLD] - Attempting to evaluate call to :#{folded_call.fn}"
80
+ evaluated_value = ConstantEvaluator.evaluate(folded_call, @registry, @known_constants)
81
+
82
+ if evaluated_value.nil?
83
+ debug "[FOLD] - Could not evaluate. Keeping call."
84
+ folded_call
85
+ else
86
+ debug "[FOLD] - SUCCESS! Folded call to :#{folded_call.fn} -> #{evaluated_value.inspect}"
87
+ @changed = true
88
+ NAST::Const.new(value: evaluated_value, loc: node.loc)
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kumi
4
+ module Core
5
+ module Analyzer
6
+ # Takes a function's `expand` template and pre-normalized NAST arguments,
7
+ # and recursively builds a new NAST tree representing the expansion.
8
+ class MacroExpander
9
+ NAST = Kumi::Core::NAST
10
+
11
+ def self.expand(func, normalized_args, loc, errors)
12
+ new(func, normalized_args, loc, errors).expand
13
+ end
14
+
15
+ def initialize(func, normalized_args, loc, errors)
16
+ @func = func
17
+ @normalized_args = normalized_args
18
+ @loc = loc
19
+ @errors = errors
20
+ end
21
+
22
+ def expand
23
+ build_nast_node(@func.expand)
24
+ end
25
+
26
+ private
27
+
28
+ def build_nast_node(template_part)
29
+ case template_part
30
+ when Hash
31
+ if template_part.key?("fn")
32
+ build_call_node(template_part)
33
+ elsif template_part.key?("const")
34
+ NAST::Const.new(value: template_part["const"], loc: @loc)
35
+ else
36
+ raise "Invalid expansion template part: #{template_part}"
37
+ end
38
+ when String
39
+ build_argument_node(template_part)
40
+ else
41
+ raise "Invalid expansion template part: #{template_part}"
42
+ end
43
+ end
44
+
45
+ def build_call_node(template_hash)
46
+ new_args = template_hash.fetch("args", []).map do |arg_template|
47
+ build_nast_node(arg_template)
48
+ end
49
+
50
+ NAST::Call.new(
51
+ fn: template_hash.fetch("fn"),
52
+ args: new_args,
53
+ loc: @loc
54
+ )
55
+ end
56
+
57
+ def build_argument_node(arg_str)
58
+ raise "Invalid argument placeholder: #{arg_str}" unless arg_str.start_with?("$")
59
+
60
+ index = arg_str[1..].to_i - 1
61
+ @normalized_args.fetch(index) do
62
+ @errors << "Expansion for #{@func.id} requires at least #{index + 1} arguments."
63
+ NAST::Const.new(value: nil, loc: @loc)
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end