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,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kumi
4
+ module Core
5
+ module Analyzer
6
+ module Passes
7
+ module LIR
8
+ class ValidationPass < PassBase
9
+ def run(_errors)
10
+ ops_by_decl = get_state(:lir_module)
11
+
12
+ ops_by_decl.each do |decl, payload|
13
+ validate_local_defs!(Array(payload[:operations]), decl)
14
+ validate_single_yield!(Array(payload[:operations]), decl)
15
+ end
16
+
17
+ state
18
+ end
19
+
20
+ private
21
+
22
+ def validate_local_defs!(ops, decl_name)
23
+ defs = Set.new
24
+ loop_depth = 0
25
+
26
+ ops.each_with_index do |ins, _idx|
27
+ # 1) check all inputs are defined
28
+ Array(ins.inputs).each do |r|
29
+ next if r.nil?
30
+ # --- ADD THIS LINE ---
31
+ next if r == :__immediate_placeholder__
32
+ # --- END OF FIX ---
33
+ raise "use-before-def #{r} in #{decl_name}" unless defs.include?(r)
34
+ end
35
+
36
+ # 2) special handling per opcode
37
+ case ins.opcode
38
+ when :LoopStart
39
+ # collection_register must be defined already (checked above)
40
+ # define loop-introduced registers *here*
41
+ el = ins.attributes&.[](:as_element)
42
+ ix = ins.attributes&.[](:as_index)
43
+ defs << el if el
44
+ defs << ix if ix
45
+ loop_depth += 1
46
+
47
+ when :LoopEnd
48
+ loop_depth -= 1
49
+ raise "unbalanced LoopEnd in #{decl_name}" if loop_depth < 0
50
+
51
+ when :DeclareAccumulator
52
+ # no regs defined (symbolic name only)
53
+
54
+ when :Yield
55
+ # input already checked
56
+
57
+ else
58
+ # 3) normal producers: record their result register as defined
59
+ defs << ins.result_register if ins.result_register
60
+ end
61
+ end
62
+
63
+ raise "unbalanced loops (depth=#{loop_depth}) in #{decl_name}" unless loop_depth.zero?
64
+ end
65
+
66
+ def validate_single_yield!(ops, decl_name)
67
+ yi = ops.index { _1.opcode == :Yield }
68
+ raise "no Yield in #{decl_name}" unless yi
69
+
70
+ # exactly one Yield
71
+ raise "multiple Yields in #{decl_name}" if ops.each_with_index.any? { |ins, i| ins.opcode == :Yield && i != yi }
72
+
73
+ # after Yield, only structural LoopEnd is allowed
74
+ trailing = ops[(yi + 1)..] || []
75
+ bad = trailing.reject { _1.opcode == :LoopEnd }
76
+ raise "instructions after Yield in #{decl_name}" unless bad.empty?
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -10,11 +10,11 @@ module Kumi
10
10
  # were already stored by earlier declarations.
11
11
  #
12
12
  # OPTIMIZATION STRATEGY:
13
- # - Cross-declaration load reuse: If a load_input with the same
14
- # (plan_id, scope, is_scalar, has_idx) was already stored by an
15
- # earlier declaration, rewrite later identical loads to ref the
13
+ # - Cross-declaration load reuse: If a load_input with the same
14
+ # (plan_id, scope, is_scalar, has_idx) was already stored by an
15
+ # earlier declaration, rewrite later identical loads to ref the
16
16
  # stored value instead of re-loading.
17
- # - Only reuses producers that appear earlier in module order
17
+ # - Only reuses producers that appear earlier in module order
18
18
  # (no reordering/hoisting).
19
19
  # - Safe because interpreter's outputs persist across declarations
20
20
  # and ref operations resolve previously stored values.
@@ -26,11 +26,11 @@ module Kumi
26
26
  # DEBUG:
27
27
  # - Set DEBUG_LOAD_CSE=1 to see optimization decisions
28
28
  class LoadInputCSE < PassBase
29
- def run(errors)
29
+ def run(_errors)
30
30
  ir = get_state(:ir_module, required: true)
31
31
  return state unless ir&.decls
32
32
 
33
- debug = ENV["DEBUG_LOAD_CSE"]
33
+ debug = ENV.fetch("DEBUG_LOAD_CSE", nil)
34
34
 
35
35
  # Map: key -> { name:, decl_index: }
36
36
  producers = {}
@@ -41,14 +41,14 @@ module Kumi
41
41
  ir.decls.each_with_index do |decl, di|
42
42
  decl.ops.each_with_index do |op, oi|
43
43
  next unless op.tag == :load_input
44
-
44
+
45
45
  key = load_key(op)
46
46
  # Does this decl store that slot under a name?
47
47
  store_name = name_storing_slot(decl.ops, oi)
48
48
  next unless store_name
49
-
49
+
50
50
  # Keep earliest producer only
51
- if !producers.key?(key)
51
+ unless producers.key?(key)
52
52
  producers[key] = { name: store_name, decl_index: di }
53
53
  puts "LOAD_CSE: Found producer #{store_name} in decl #{di} for key #{key.inspect}" if debug
54
54
  end
@@ -62,10 +62,10 @@ module Kumi
62
62
  new_decls = ir.decls.each_with_index.map do |decl, di|
63
63
  new_ops = decl.ops.each_with_index.map do |op, oi|
64
64
  next op unless op.tag == :load_input
65
-
65
+
66
66
  key = load_key(op)
67
67
  prod = producers[key]
68
-
68
+
69
69
  # Only rewrite if producer is in an earlier decl
70
70
  if prod && prod[:decl_index] < di
71
71
  optimizations += 1
@@ -75,11 +75,11 @@ module Kumi
75
75
  op
76
76
  end
77
77
  end
78
-
78
+
79
79
  Kumi::Core::IR::Decl.new(
80
- name: decl.name,
81
- kind: decl.kind,
82
- shape: decl.shape,
80
+ name: decl.name,
81
+ kind: decl.kind,
82
+ shape: decl.shape,
83
83
  ops: new_ops
84
84
  )
85
85
  end
@@ -108,6 +108,7 @@ module Kumi
108
108
  def name_storing_slot(ops, slot_id)
109
109
  ops.each do |op|
110
110
  next unless op.tag == :store
111
+
111
112
  src = op.args && op.args[0]
112
113
  return op.attrs[:name] if src == slot_id
113
114
  end
@@ -117,4 +118,4 @@ module Kumi
117
118
  end
118
119
  end
119
120
  end
120
- end
121
+ end
@@ -294,7 +294,7 @@ module Kumi
294
294
  end
295
295
  end
296
296
 
297
- def lower_declaration(name, decl, access_plans, join_reduce_plans, scope_plan)
297
+ def lower_declaration(name, decl, access_plans, _join_reduce_plans, scope_plan)
298
298
  ops = []
299
299
 
300
300
  plan = @join_reduce_plans[name]
@@ -310,7 +310,7 @@ module Kumi
310
310
  end
311
311
 
312
312
  last_slot = lower_expression(decl.expression, ops, access_plans, scope_plan,
313
- need_indices = true, req_scope)
313
+ true, req_scope)
314
314
 
315
315
  # Apply broadcasting for scalar-to-vector join plans
316
316
  if plan && plan.respond_to?(:policy) && plan.policy == :broadcast
@@ -523,6 +523,8 @@ module Kumi
523
523
  elem_slots = insert_align_to_if_needed(elem_slots, ops, access_plans, on_missing: :error) unless target.empty?
524
524
  ops << Kumi::Core::IR::Ops.Array(elem_slots.size, *elem_slots)
525
525
  return ops.size - 1
526
+ when Syntax::HashExpression
527
+ # Skip
526
528
 
527
529
  when Syntax::CascadeExpression
528
530
  # Find a base (true) case, if present
@@ -0,0 +1,197 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../irv2/builder"
4
+
5
+ module Kumi
6
+ module Core
7
+ module Analyzer
8
+ module Passes
9
+ class LowerToIRV2Pass < PassBase
10
+ # In: state[:snast_module], state[:evaluation_order], state[:input_table]
11
+ # Out: state[:irv2_module]
12
+ def run(errors)
13
+ snast = get_state(:snast_module, required: true)
14
+ order = get_state(:evaluation_order, required: true)
15
+ @input_table = get_state(:input_table, required: true)
16
+
17
+ builder = Kumi::Core::IRV2::Builder.new
18
+ declarations = {}
19
+
20
+ order.each do |decl_name|
21
+ declarations[decl_name] = lower_one_declaration(decl_name, snast, @input_table, builder, errors)
22
+ end
23
+
24
+ irv2_module = IRV2::Module.new(declarations, {})
25
+ state.with(:irv2_module, irv2_module)
26
+ end
27
+
28
+ private
29
+
30
+ def lower_one_declaration(decl_name, snast, _input_table, builder, errors)
31
+ decl = snast.decls.fetch(decl_name)
32
+
33
+ # Temporarily set instance variables for the context of this declaration.
34
+ @current_decl_name = decl_name
35
+ @b = builder # Use the shared builder
36
+ @input_cache = {}
37
+ @current_input_table = @input_table
38
+ @current_decls = snast.decls
39
+
40
+ start_op_count = builder.values.length
41
+ ir_val = lower_expr(decl.body, errors)
42
+
43
+ # NOTE: The optimizer and parameter collection now need to operate on a slice of the builder's operations.
44
+ new_ops = builder.values.slice(start_op_count..-1)
45
+ parameters = collect_declaration_parameters(new_ops, snast.decls)
46
+
47
+ # The declaration now just stores references to the globally unique operations.
48
+ IRV2::Declaration.new(decl_name, new_ops, ir_val, parameters)
49
+ ensure
50
+ # Clean up instance variables
51
+ @current_decl_name = @b = @input_cache = @current_input_table = @current_decls = nil
52
+ end
53
+
54
+ def fqid(val)
55
+ "#{@current_decl_name}/#{val.id}"
56
+ end
57
+
58
+ def ser_stamp(snast_stamp)
59
+ {
60
+ "dtype" => (snast_stamp["dtype"] || snast_stamp[:dtype]).to_s,
61
+ "axes" => Array(snast_stamp["axes"] || snast_stamp[:axes]).map(&:to_s)
62
+ }
63
+ end
64
+
65
+ def lower_expr(node, errors)
66
+ ir_val =
67
+ case node
68
+ when Kumi::Core::NAST::Const
69
+ stamp = ser_stamp(node.meta[:stamp])
70
+ @b.const(node.value, stamp: stamp)
71
+
72
+ when Kumi::Core::NAST::InputRef
73
+ plan = @input_table.find { |i| i.path_fqn == node.path_fqn }
74
+ unless @input_cache[node.path_fqn]
75
+ axes = plan.axes
76
+ dtype = plan.dtype
77
+ stamp = { "dtype" => dtype.to_s, "axes" => axes.map(&:to_s) }
78
+ @input_cache[node.path_fqn] = @b.load_input(node.path_fqn, stamp: stamp)
79
+ end
80
+ @input_cache[node.path_fqn]
81
+
82
+ when Kumi::Core::NAST::Ref
83
+ dep_name = node.name
84
+ stamp = ser_stamp(@current_decls[dep_name].meta[:stamp])
85
+ @b.load_declaration(dep_name.to_s, stamp: stamp)
86
+
87
+ when Kumi::Core::NAST::Tuple
88
+ node.meta[:plan] or (errors << "Missing plan on Tuple"
89
+ return @b.const(nil))
90
+
91
+ stamp = ser_stamp(node.meta[:stamp])
92
+ lowered = node.elements.map { |e| lower_expr(e, errors) }
93
+ node.elements.map { |elem| ser_stamp(elem.meta[:stamp]) }
94
+
95
+ @b.construct_tuple(*lowered, stamp: stamp)
96
+
97
+ when Kumi::Core::NAST::Call
98
+ plan = node.meta[:plan] or (errors << "Missing plan on Call #{node.fn}"
99
+ return @b.const(nil))
100
+
101
+ case plan[:kind]
102
+ when :elementwise
103
+ args = node.args.map { |a| lower_expr(a, errors) }
104
+ stamp = ser_stamp(node.meta[:stamp])
105
+ if node.fn == BUILTIN_SELECT
106
+ @b.select(*args, stamp: stamp)
107
+ else
108
+ @b.map(node.fn.to_s, *args, stamp: stamp)
109
+ end
110
+
111
+ when :reduce
112
+ unless node.args.size == 1
113
+ errors << "Reducer arity must be 1, got #{node.args.size}"
114
+ return @b.const(nil)
115
+ end
116
+ v = lower_expr(node.args.first, errors)
117
+ stamp = ser_stamp(node.meta[:stamp])
118
+ @b.reduce(node.fn.to_s, v, plan[:last_axis_token], stamp: stamp)
119
+
120
+ else
121
+ errors << "Unsupported call kind for lowering: #{plan[:kind].inspect}"
122
+ return @b.const(nil)
123
+ end
124
+
125
+ else
126
+ errors << "Unhandled SNAST node in lowering: #{node.class}"
127
+ return @b.const(nil)
128
+ end
129
+
130
+ ir_val or (errors << "Missing IR value from lowering"
131
+ @b.const(nil))
132
+ end
133
+
134
+ def collect_declaration_parameters(operations, _decls)
135
+ parameters = []
136
+
137
+ operations.select { |op| op.op == :LoadInput }.each do |op|
138
+ path = op.args.first
139
+ next if parameters.any? { |p| p[:type] == :input && p[:source] == path }
140
+
141
+ parameters << { type: :input, source: path }
142
+ end
143
+
144
+ operations.select { |op| op.op == :LoadDeclaration }.each do |op|
145
+ dep_name = op.args.first
146
+ next if parameters.any? { |p| p[:type] == :dependency && p[:source] == dep_name }
147
+
148
+ parameters << { type: :dependency, source: dep_name }
149
+ end
150
+
151
+ parameters
152
+ end
153
+
154
+ def optimize_declaration(builder)
155
+ value_map = {}
156
+
157
+ builder.values.each do |val|
158
+ signature = operation_signature(val)
159
+ if value_map[signature]
160
+ original = value_map[signature]
161
+ replace_references(builder.values, val, original)
162
+ else
163
+ value_map[signature] = val
164
+ end
165
+ end
166
+
167
+ builder.values.reject! do |val|
168
+ signature = operation_signature(val)
169
+ value_map[signature] != val
170
+ end
171
+ end
172
+
173
+ def operation_signature(val)
174
+ case val.op
175
+ when :LoadDeclaration, :LoadInput, :Const
176
+ [val.op, val.args.first]
177
+ when :AlignTo
178
+ [val.op, val.args.first.id, Array(val.attrs[:target_axes]).map(&:to_s)]
179
+ when :Map
180
+ [val.op, val.attrs[:fn], val.args.map(&:id)]
181
+ when :Reduce
182
+ [val.op, val.args.first.id, val.attrs[:axis].to_s, val.attrs[:fn]]
183
+ else
184
+ [val.op, val.args.map(&:id), val.attrs]
185
+ end
186
+ end
187
+
188
+ def replace_references(operations, old_val, new_val)
189
+ operations.each do |op|
190
+ op.args.map! { |arg| arg == old_val ? new_val : arg }
191
+ end
192
+ end
193
+ end
194
+ end
195
+ end
196
+ end
197
+ end
@@ -7,17 +7,20 @@ module Kumi
7
7
  # RESPONSIBILITY: Build definitions index and detect duplicate names
8
8
  # DEPENDENCIES: None (first pass in pipeline)
9
9
  # PRODUCES: :declarations - Hash mapping names to declaration nodes
10
+ # - annotates hints to declarations (e.g. inlining)
10
11
  # INTERFACE: new(schema, state).run(errors)
11
12
  class NameIndexer < PassBase
12
13
  def run(errors)
13
14
  definitions = {}
15
+ hints = {}
14
16
 
15
17
  each_decl do |decl|
16
18
  report_error(errors, "duplicated definition `#{decl.name}`", location: decl.loc) if definitions.key?(decl.name)
17
19
  definitions[decl.name] = decl
20
+ hints[decl.name] = decl.hints
18
21
  end
19
22
 
20
- state.with(:declarations, definitions.freeze)
23
+ state.with(:declarations, definitions.freeze).with(:hints, hints)
21
24
  end
22
25
  end
23
26
  end
@@ -0,0 +1,237 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kumi
4
+ module Core
5
+ module Analyzer
6
+ module Passes
7
+ # Extracts dimensional and type metadata from NAST tree
8
+ # Uses minimal function specs to resolve Call nodes and propagate types
9
+ #
10
+ # Input: state[:nast_module], state[:input_table] (chain-free; must include :axes and :dtype per path)
11
+ # Output: state[:metadata_table], state[:declaration_table]
12
+ class NASTDimensionalAnalyzerPass < PassBase
13
+ def run(errors)
14
+ nast_module = get_state(:nast_module, required: true)
15
+ @input_table = get_state(:input_table, required: true)
16
+ @registry = get_state(:registry, required: true)
17
+
18
+ @function_specs = Functions::Loader.load_minimal_functions
19
+
20
+ @metadata_table = {}
21
+ @declaration_table = {}
22
+
23
+ debug "Analyzing NAST module with #{nast_module.decls.size} declarations"
24
+ debug "Function specs loaded: #{@function_specs.keys.join(', ')}"
25
+
26
+ nast_module.decls.each { |name, decl| analyze_declaration(name, decl, errors) }
27
+
28
+ debug "Generated metadata_table with #{@metadata_table.size} entries"
29
+ debug "Generated declaration_table with #{@declaration_table.size} entries"
30
+
31
+ state.with(:metadata_table, @metadata_table.freeze)
32
+ .with(:declaration_table, @declaration_table.freeze)
33
+ end
34
+
35
+ private
36
+
37
+ def analyze_declaration(name, decl, errors)
38
+ debug "Analyzing #{name}"
39
+ result_metadata = analyze_expression(decl.body, errors)
40
+
41
+ decl_metadata = {
42
+ kind: decl.kind,
43
+ result_type: result_metadata[:type],
44
+ result_scope: result_metadata[:scope],
45
+ target_name: name
46
+ }.freeze
47
+
48
+ @metadata_table[node_id(decl)] = decl_metadata
49
+ @declaration_table[name] = decl_metadata
50
+
51
+ debug " #{name}: #{result_metadata[:type]} in scope #{result_metadata[:scope].inspect}"
52
+ end
53
+
54
+ def analyze_expression(expr, errors)
55
+ case expr
56
+ when Kumi::Core::NAST::Call then analyze_call_expression(expr, errors)
57
+ when Kumi::Core::NAST::Tuple then analyze_tuple(expr, errors)
58
+ when Kumi::Core::NAST::InputRef then analyze_input_ref(expr)
59
+ when Kumi::Core::NAST::IndexRef then analyze_index_ref(expr, errors)
60
+ when Kumi::Core::NAST::Const then analyze_const(expr)
61
+ when Kumi::Core::NAST::Pair then analyze_pair(expr, errors)
62
+ when Kumi::Core::NAST::Ref then analyze_declaration_ref(expr)
63
+ when Kumi::Core::NAST::Hash then analyze_hash(expr, errors)
64
+
65
+ else
66
+ raise "Unknown NAST node type: #{expr.class}"
67
+ end
68
+ end
69
+
70
+ def analyze_call_expression(call, errors)
71
+ function_spec = @registry.function(call.fn.to_s)
72
+
73
+ arg_metadata = call.args.map { |arg| analyze_expression(arg, errors) }
74
+ arg_types = arg_metadata.map { |m| m[:type] }
75
+ arg_scopes = arg_metadata.map { |m| m[:scope] }
76
+
77
+ debug " Call #{call.fn}: arg_scopes=#{arg_scopes.inspect}"
78
+
79
+ if ENV["DEBUG_NAST_DIMENSIONAL_ANALYZER"] == "1" && function_spec.param_names.size != arg_types.size
80
+ puts "[NASTDimensionalAnalyzer] WARNING: #{call.fn} expects #{function_spec.param_names.size} args, got #{arg_types.size}"
81
+ end
82
+
83
+ named_types =
84
+ if function_spec.params.size == arg_types.size
85
+ Hash[function_spec.param_names.zip(arg_types)]
86
+ else
87
+ { function_spec.param_names.first => arg_types } # variadic TODO: this is a hack
88
+ end
89
+
90
+ begin
91
+ result_type = function_spec.dtype_rule.call(named_types)
92
+ rescue StandardError
93
+ # Maybe we have the wrong function, lets try to see if another function with same name works
94
+ # TODO: Fix this hack
95
+
96
+ raise
97
+ end
98
+
99
+ over_collection = arg_types.size == 1 && Types.collection?(arg_types[0])
100
+ result_scope = compute_result_scope(function_spec, arg_scopes, over_collection)
101
+
102
+ @metadata_table[node_id(call)] = {
103
+ function: function_spec.id,
104
+ kind: function_spec.kind,
105
+ params: function_spec.params,
106
+ result_type: result_type,
107
+ result_scope: result_scope,
108
+ arg_types: arg_types,
109
+ arg_scopes: arg_scopes,
110
+ last_axis_token: (function_spec.kind == :reduce ? (arg_scopes.first || []).last : nil) # TODO: REMOVE
111
+ }.freeze
112
+
113
+ debug " Call #{function_spec.id}: (#{arg_types.join(', ')}) -> #{result_type} in #{result_scope.inspect}"
114
+ { type: result_type, scope: result_scope }
115
+ end
116
+
117
+ def analyze_tuple(node, errors)
118
+ elems = node.args.map { |e| analyze_expression(e, errors) }
119
+ element_types = elems.map { |m| m[:type] }
120
+ element_scopes = elems.map { |m| m[:scope] }
121
+ result_scope = lub_by_prefix(element_scopes)
122
+
123
+ result_type = if element_types.uniq.size == 1
124
+ "tuple<#{element_types.uniq[0]}>"
125
+ else
126
+ "tuple<#{element_types.join(', ')}>"
127
+ end
128
+
129
+ @metadata_table[node_id(node)] = {
130
+ parameter_names: [],
131
+ result_type: result_type,
132
+ result_scope: result_scope,
133
+ arg_types: element_types,
134
+ arg_scopes: element_scopes,
135
+ last_axis_token: nil
136
+ }.freeze
137
+
138
+ debug " Tuple: (#{element_types.join(', ')}) -> #{result_type} in #{result_scope.inspect}"
139
+ { type: result_type, scope: result_scope }
140
+ end
141
+
142
+ def analyze_hash(node, errors)
143
+ fields = node.pairs.map { |e| analyze_expression(e, errors) }
144
+ fields_scopes = fields.map { |m| m[:scope] }
145
+ scope = lub_by_prefix(fields_scopes)
146
+ dtype = :hash
147
+
148
+ @metadata_table[node_id(node)] = {
149
+ type: dtype,
150
+ scope: scope
151
+ }.freeze
152
+ end
153
+
154
+ def analyze_pair(node, errors)
155
+ value_node = analyze_expression(node.value, errors)
156
+ dtype = :pair
157
+
158
+ @metadata_table[node_id(node)] = {
159
+ type: dtype,
160
+ scope: value_node[:scope]
161
+ }.freeze
162
+ end
163
+
164
+ # STRICT: requires entry with :axes and :dtype (no fallbacks)
165
+ def analyze_input_ref(input_ref)
166
+ entry = @input_table.find { |imp| imp[:path_fqn] == input_ref.path_fqn }
167
+ entry or raise KeyError, "Input path not found in input_table: #{input_ref.path_fqn}"
168
+
169
+ axes = entry.axes
170
+ dtype = entry.dtype
171
+
172
+ { type: dtype, scope: axes }
173
+ end
174
+
175
+ def analyze_const(node)
176
+ type = Types.normalize(node.value.class)
177
+ meta = { type: type, scope: [] }
178
+
179
+ @metadata_table[node_id(node)] = meta
180
+ end
181
+
182
+ def analyze_index_ref(node, _errors)
183
+ meta = @input_table.find { _1.path_fqn == node.input_fqn } or raise "Index plan found: #{n.name.inspect}"
184
+ axes = Array(meta[:axes])
185
+ type = :integer
186
+
187
+ debug " IndexRef #{node.name}: input_fqn=#{node.input_fqn}, axes=#{axes.inspect}"
188
+
189
+ @metadata_table[node_id(node)] = { type:, scope: axes }.freeze
190
+ { type:, scope: axes }
191
+ end
192
+
193
+ def analyze_declaration_ref(ref)
194
+ meta = @declaration_table.fetch(ref.name)
195
+ @metadata_table[node_id(ref)] = {
196
+ kind: :ref,
197
+ result_type: meta[:result_type],
198
+ result_scope: meta[:result_scope],
199
+ referenced_name: ref.name
200
+ }.freeze
201
+ { type: meta[:result_type], scope: meta[:result_scope] }
202
+ end
203
+
204
+ def compute_result_scope(function_spec, arg_scopes, over_collection = false)
205
+ case function_spec.kind
206
+ when :elementwise, :constructor
207
+ lub_by_prefix(arg_scopes)
208
+ when :reduce
209
+ if over_collection
210
+ lub_by_prefix(arg_scopes)
211
+ else
212
+ child = arg_scopes.first || []
213
+ child[0...-1]
214
+ end
215
+ else
216
+ []
217
+ end
218
+ end
219
+
220
+ def lub_by_prefix(list)
221
+ return [] if list.empty?
222
+
223
+ candidate = list.max_by(&:length)
224
+ list.each do |axes|
225
+ unless axes.each_with_index.all? { |tok, i| candidate[i] == tok }
226
+ raise Kumi::Core::Errors::SemanticError, "prefix mismatch: #{axes.inspect} vs #{candidate.inspect}"
227
+ end
228
+ end
229
+ candidate
230
+ end
231
+
232
+ def node_id(node) = "#{node.class}_#{node.id}"
233
+ end
234
+ end
235
+ end
236
+ end
237
+ end