kumi 0.0.25 → 0.0.27

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 (223) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -0
  3. data/CLAUDE.md +4 -0
  4. data/README.md +86 -78
  5. data/data/functions/agg/boolean.yaml +6 -2
  6. data/data/functions/agg/numeric.yaml +32 -16
  7. data/data/functions/agg/string.yaml +4 -3
  8. data/data/functions/core/arithmetic.yaml +62 -14
  9. data/data/functions/core/boolean.yaml +12 -6
  10. data/data/functions/core/comparison.yaml +25 -13
  11. data/data/functions/core/constructor.yaml +16 -8
  12. data/data/functions/core/conversion.yaml +32 -0
  13. data/data/functions/core/select.yaml +3 -1
  14. data/data/functions/core/stencil.yaml +14 -5
  15. data/data/functions/core/string.yaml +9 -4
  16. data/data/kernels/javascript/core/coercion.yaml +20 -0
  17. data/data/kernels/ruby/agg/numeric.yaml +1 -1
  18. data/data/kernels/ruby/core/coercion.yaml +20 -0
  19. data/docs/ARCHITECTURE.md +277 -0
  20. data/docs/DEVELOPMENT.md +62 -0
  21. data/docs/FUNCTIONS.md +955 -0
  22. data/docs/SYNTAX.md +8 -0
  23. data/docs/UNSAT_DETECTION.md +83 -0
  24. data/docs/VSCODE_EXTENSION.md +114 -0
  25. data/docs/functions-reference.json +1821 -0
  26. data/golden/array_element/expected/nast.txt +1 -1
  27. data/golden/array_element/expected/schema_ruby.rb +1 -1
  28. data/golden/array_index/expected/nast.txt +7 -7
  29. data/golden/array_index/expected/schema_ruby.rb +1 -1
  30. data/golden/array_operations/expected/nast.txt +2 -2
  31. data/golden/array_operations/expected/schema_ruby.rb +1 -1
  32. data/golden/array_operations/expected/snast.txt +3 -3
  33. data/golden/cascade_logic/expected/schema_ruby.rb +1 -1
  34. data/golden/cascade_logic/expected/snast.txt +2 -2
  35. data/golden/chained_fusion/expected/nast.txt +2 -2
  36. data/golden/chained_fusion/expected/schema_ruby.rb +1 -1
  37. data/golden/decimal_explicit/expected/ast.txt +38 -0
  38. data/golden/decimal_explicit/expected/input_plan.txt +3 -0
  39. data/golden/decimal_explicit/expected/lir_00_unoptimized.txt +30 -0
  40. data/golden/decimal_explicit/expected/lir_01_hoist_scalar_references.txt +30 -0
  41. data/golden/decimal_explicit/expected/lir_02_inlined.txt +44 -0
  42. data/golden/decimal_explicit/expected/lir_03_cse.txt +40 -0
  43. data/golden/decimal_explicit/expected/lir_04_1_loop_fusion.txt +40 -0
  44. data/golden/decimal_explicit/expected/lir_04_loop_invcm.txt +40 -0
  45. data/golden/decimal_explicit/expected/lir_06_const_prop.txt +40 -0
  46. data/golden/decimal_explicit/expected/nast.txt +30 -0
  47. data/golden/decimal_explicit/expected/schema_javascript.mjs +31 -0
  48. data/golden/decimal_explicit/expected/schema_ruby.rb +57 -0
  49. data/golden/decimal_explicit/expected/snast.txt +30 -0
  50. data/golden/decimal_explicit/expected.json +1 -0
  51. data/golden/decimal_explicit/input.json +5 -0
  52. data/golden/decimal_explicit/schema.kumi +14 -0
  53. data/golden/element_arrays/expected/nast.txt +2 -2
  54. data/golden/element_arrays/expected/schema_ruby.rb +1 -1
  55. data/golden/element_arrays/expected/snast.txt +1 -1
  56. data/golden/empty_and_null_inputs/expected/nast.txt +3 -3
  57. data/golden/empty_and_null_inputs/expected/schema_ruby.rb +1 -1
  58. data/golden/function_overload/expected/ast.txt +29 -0
  59. data/golden/function_overload/expected/input_plan.txt +4 -0
  60. data/golden/function_overload/expected/lir_00_unoptimized.txt +18 -0
  61. data/golden/function_overload/expected/lir_01_hoist_scalar_references.txt +18 -0
  62. data/golden/function_overload/expected/lir_02_inlined.txt +20 -0
  63. data/golden/function_overload/expected/lir_03_cse.txt +20 -0
  64. data/golden/function_overload/expected/lir_04_1_loop_fusion.txt +20 -0
  65. data/golden/function_overload/expected/lir_04_loop_invcm.txt +20 -0
  66. data/golden/function_overload/expected/lir_06_const_prop.txt +20 -0
  67. data/golden/function_overload/expected/nast.txt +22 -0
  68. data/golden/function_overload/expected/schema_javascript.mjs +12 -0
  69. data/golden/function_overload/expected/schema_ruby.rb +39 -0
  70. data/golden/function_overload/expected/snast.txt +22 -0
  71. data/golden/function_overload/input.json +8 -0
  72. data/golden/function_overload/schema.kumi +19 -0
  73. data/golden/game_of_life/expected/lir_00_unoptimized.txt +4 -4
  74. data/golden/game_of_life/expected/lir_01_hoist_scalar_references.txt +4 -4
  75. data/golden/game_of_life/expected/lir_02_inlined.txt +16 -16
  76. data/golden/game_of_life/expected/lir_03_cse.txt +20 -16
  77. data/golden/game_of_life/expected/lir_04_1_loop_fusion.txt +20 -16
  78. data/golden/game_of_life/expected/lir_04_loop_invcm.txt +20 -16
  79. data/golden/game_of_life/expected/lir_06_const_prop.txt +20 -16
  80. data/golden/game_of_life/expected/nast.txt +4 -4
  81. data/golden/game_of_life/expected/schema_javascript.mjs +4 -2
  82. data/golden/game_of_life/expected/schema_ruby.rb +5 -3
  83. data/golden/game_of_life/expected/snast.txt +10 -10
  84. data/golden/hash_keys/expected/schema_ruby.rb +1 -1
  85. data/golden/hash_value/expected/nast.txt +1 -1
  86. data/golden/hash_value/expected/schema_ruby.rb +1 -1
  87. data/golden/hash_value/expected/snast.txt +1 -1
  88. data/golden/hierarchical_complex/expected/nast.txt +3 -3
  89. data/golden/hierarchical_complex/expected/schema_ruby.rb +1 -1
  90. data/golden/hierarchical_complex/expected/snast.txt +3 -3
  91. data/golden/inline_rename_scope_leak/expected/nast.txt +3 -3
  92. data/golden/inline_rename_scope_leak/expected/schema_ruby.rb +1 -1
  93. data/golden/input_reference/expected/nast.txt +2 -2
  94. data/golden/input_reference/expected/schema_ruby.rb +1 -1
  95. data/golden/interleaved_fusion/expected/nast.txt +2 -2
  96. data/golden/interleaved_fusion/expected/schema_ruby.rb +1 -1
  97. data/golden/let_inline/expected/nast.txt +4 -4
  98. data/golden/let_inline/expected/schema_ruby.rb +1 -1
  99. data/golden/loop_fusion/expected/nast.txt +1 -1
  100. data/golden/loop_fusion/expected/schema_ruby.rb +1 -1
  101. data/golden/min_reduce_scope/expected/nast.txt +3 -3
  102. data/golden/min_reduce_scope/expected/schema_ruby.rb +1 -1
  103. data/golden/min_reduce_scope/expected/snast.txt +1 -1
  104. data/golden/mixed_dimensions/expected/nast.txt +2 -2
  105. data/golden/mixed_dimensions/expected/schema_ruby.rb +1 -1
  106. data/golden/multirank_hoisting/expected/nast.txt +7 -7
  107. data/golden/multirank_hoisting/expected/schema_ruby.rb +1 -1
  108. data/golden/nested_hash/expected/nast.txt +1 -1
  109. data/golden/nested_hash/expected/schema_ruby.rb +1 -1
  110. data/golden/reduction_broadcast/expected/nast.txt +3 -3
  111. data/golden/reduction_broadcast/expected/schema_ruby.rb +1 -1
  112. data/golden/reduction_broadcast/expected/snast.txt +1 -1
  113. data/golden/roll/expected/schema_ruby.rb +1 -1
  114. data/golden/shift/expected/schema_ruby.rb +1 -1
  115. data/golden/shift_2d/expected/schema_ruby.rb +1 -1
  116. data/golden/simple_math/expected/lir_00_unoptimized.txt +1 -1
  117. data/golden/simple_math/expected/lir_01_hoist_scalar_references.txt +1 -1
  118. data/golden/simple_math/expected/lir_02_inlined.txt +1 -1
  119. data/golden/simple_math/expected/lir_03_cse.txt +1 -1
  120. data/golden/simple_math/expected/lir_04_1_loop_fusion.txt +1 -1
  121. data/golden/simple_math/expected/lir_04_loop_invcm.txt +1 -1
  122. data/golden/simple_math/expected/lir_06_const_prop.txt +1 -1
  123. data/golden/simple_math/expected/nast.txt +5 -5
  124. data/golden/simple_math/expected/schema_ruby.rb +1 -1
  125. data/golden/simple_math/expected/snast.txt +2 -2
  126. data/golden/streaming_basics/expected/nast.txt +8 -8
  127. data/golden/streaming_basics/expected/schema_ruby.rb +1 -1
  128. data/golden/streaming_basics/expected/snast.txt +1 -1
  129. data/golden/tuples/expected/lir_00_unoptimized.txt +5 -5
  130. data/golden/tuples/expected/lir_01_hoist_scalar_references.txt +5 -5
  131. data/golden/tuples/expected/lir_02_inlined.txt +5 -5
  132. data/golden/tuples/expected/lir_03_cse.txt +5 -5
  133. data/golden/tuples/expected/lir_04_1_loop_fusion.txt +5 -5
  134. data/golden/tuples/expected/lir_04_loop_invcm.txt +5 -5
  135. data/golden/tuples/expected/lir_06_const_prop.txt +5 -5
  136. data/golden/tuples/expected/nast.txt +4 -4
  137. data/golden/tuples/expected/schema_ruby.rb +1 -1
  138. data/golden/tuples/expected/snast.txt +6 -6
  139. data/golden/tuples_and_arrays/expected/lir_00_unoptimized.txt +1 -1
  140. data/golden/tuples_and_arrays/expected/lir_01_hoist_scalar_references.txt +1 -1
  141. data/golden/tuples_and_arrays/expected/lir_02_inlined.txt +2 -2
  142. data/golden/tuples_and_arrays/expected/lir_03_cse.txt +2 -2
  143. data/golden/tuples_and_arrays/expected/lir_04_1_loop_fusion.txt +2 -2
  144. data/golden/tuples_and_arrays/expected/lir_04_loop_invcm.txt +2 -2
  145. data/golden/tuples_and_arrays/expected/lir_06_const_prop.txt +2 -2
  146. data/golden/tuples_and_arrays/expected/nast.txt +3 -3
  147. data/golden/tuples_and_arrays/expected/schema_ruby.rb +1 -1
  148. data/golden/tuples_and_arrays/expected/snast.txt +2 -2
  149. data/golden/us_tax_2024/expected/ast.txt +63 -670
  150. data/golden/us_tax_2024/expected/input_plan.txt +8 -45
  151. data/golden/us_tax_2024/expected/lir_00_unoptimized.txt +253 -863
  152. data/golden/us_tax_2024/expected/lir_01_hoist_scalar_references.txt +253 -863
  153. data/golden/us_tax_2024/expected/lir_02_inlined.txt +1215 -5139
  154. data/golden/us_tax_2024/expected/lir_03_cse.txt +587 -2460
  155. data/golden/us_tax_2024/expected/lir_04_1_loop_fusion.txt +632 -2480
  156. data/golden/us_tax_2024/expected/lir_04_loop_invcm.txt +587 -2460
  157. data/golden/us_tax_2024/expected/lir_06_const_prop.txt +587 -2460
  158. data/golden/us_tax_2024/expected/nast.txt +123 -826
  159. data/golden/us_tax_2024/expected/schema_javascript.mjs +127 -581
  160. data/golden/us_tax_2024/expected/schema_ruby.rb +135 -610
  161. data/golden/us_tax_2024/expected/snast.txt +155 -858
  162. data/golden/us_tax_2024/expected.json +120 -1
  163. data/golden/us_tax_2024/input.json +18 -9
  164. data/golden/us_tax_2024/schema.kumi +48 -178
  165. data/golden/with_constants/expected/lir_00_unoptimized.txt +1 -1
  166. data/golden/with_constants/expected/lir_01_hoist_scalar_references.txt +1 -1
  167. data/golden/with_constants/expected/lir_02_inlined.txt +1 -1
  168. data/golden/with_constants/expected/lir_03_cse.txt +1 -1
  169. data/golden/with_constants/expected/lir_04_1_loop_fusion.txt +1 -1
  170. data/golden/with_constants/expected/lir_04_loop_invcm.txt +1 -1
  171. data/golden/with_constants/expected/lir_06_const_prop.txt +1 -1
  172. data/golden/with_constants/expected/nast.txt +2 -2
  173. data/golden/with_constants/expected/schema_ruby.rb +1 -1
  174. data/golden/with_constants/expected/snast.txt +2 -2
  175. data/lib/kumi/analyzer.rb +12 -12
  176. data/lib/kumi/configuration.rb +6 -0
  177. data/lib/kumi/core/analyzer/passes/formal_constraint_propagator.rb +236 -0
  178. data/lib/kumi/core/analyzer/passes/input_collector.rb +22 -4
  179. data/lib/kumi/core/analyzer/passes/nast_dimensional_analyzer_pass.rb +64 -18
  180. data/lib/kumi/core/analyzer/passes/normalize_to_nast_pass.rb +9 -4
  181. data/lib/kumi/core/analyzer/passes/snast_pass.rb +3 -1
  182. data/lib/kumi/core/analyzer/passes/unsat_detector.rb +172 -198
  183. data/lib/kumi/core/error_reporter.rb +36 -1
  184. data/lib/kumi/core/errors.rb +33 -1
  185. data/lib/kumi/core/functions/function_spec.rb +5 -4
  186. data/lib/kumi/core/functions/loader.rb +17 -1
  187. data/lib/kumi/core/functions/overload_resolver.rb +164 -0
  188. data/lib/kumi/core/functions/type_error_reporter.rb +118 -0
  189. data/lib/kumi/core/functions/type_rules.rb +155 -35
  190. data/lib/kumi/core/input/type_matcher.rb +8 -1
  191. data/lib/kumi/core/ruby_parser/input_builder.rb +2 -2
  192. data/lib/kumi/core/types/inference.rb +29 -22
  193. data/lib/kumi/core/types/normalizer.rb +30 -45
  194. data/lib/kumi/core/types/validator.rb +17 -28
  195. data/lib/kumi/core/types/value_objects.rb +116 -0
  196. data/lib/kumi/core/types.rb +45 -37
  197. data/lib/kumi/dev/golden/reporter.rb +9 -0
  198. data/lib/kumi/dev/golden/result.rb +3 -1
  199. data/lib/kumi/dev/golden/runtime_test.rb +25 -0
  200. data/lib/kumi/dev/golden/suite.rb +4 -4
  201. data/lib/kumi/dev/golden/value_normalizer.rb +80 -0
  202. data/lib/kumi/dev/golden.rb +21 -12
  203. data/lib/kumi/doc_generator/formatters/json.rb +39 -0
  204. data/lib/kumi/doc_generator/formatters/markdown.rb +175 -0
  205. data/lib/kumi/doc_generator/loader.rb +37 -0
  206. data/lib/kumi/doc_generator/merger.rb +54 -0
  207. data/lib/kumi/doc_generator.rb +4 -0
  208. data/lib/kumi/registry_v2/loader.rb +90 -0
  209. data/lib/kumi/registry_v2.rb +18 -1
  210. data/lib/kumi/version.rb +1 -1
  211. data/vscode-extension/.gitignore +4 -0
  212. data/vscode-extension/README.md +59 -0
  213. data/vscode-extension/TESTING.md +151 -0
  214. data/vscode-extension/package.json +51 -0
  215. data/vscode-extension/src/extension.ts +295 -0
  216. data/vscode-extension/tsconfig.json +15 -0
  217. metadata +57 -7
  218. data/lib/kumi/core/analyzer/unsat_constant_evaluator.rb +0 -59
  219. data/lib/kumi/core/atom_unsat_solver.rb +0 -396
  220. data/lib/kumi/core/constraint_relationship_solver.rb +0 -641
  221. data/lib/kumi/core/types/builder.rb +0 -23
  222. data/lib/kumi/core/types/compatibility.rb +0 -96
  223. data/lib/kumi/core/types/formatter.rb +0 -26
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8d0a680258ba7c40a2f00d9af8d4abf116344071ddc61d8b587a9a5a49eed6c9
4
- data.tar.gz: e16a0a52944cfa45d0a2f15c82fbbaac07392d4a1060f490b4c2fa67cb11208b
3
+ metadata.gz: a850b47be185d9e65a5b86121f6208b80eac6eba1f8a4bc78879893304cd02ea
4
+ data.tar.gz: f8a14f4516963be8c6ff8e4b9839189ead2ee134f790ea46f8945e2be6b06876
5
5
  SHA512:
6
- metadata.gz: 6002d0e6a6b86c345226d630f09279b8e24c5ab581c1d6dba1c3f76b70f91e5ce0a9e2200ee402d12e0b43b593d326cf314ce19b5dafdd7249c36d467ce99a4e
7
- data.tar.gz: d58b16b88031e3c9ed75598f71e999657f3e6f23b8f0b9e2fe211c74f8f43d1aa43ff5125f6faef7c713cdb1fac5edd7e59e0aaf29405aafe7123708d352ee36
6
+ metadata.gz: 2f4e71671cf52c9fbbdede6da6d401f44c4e55a6562fdda0b5d866f11d284a1a2645138e8f469d21fe0f7ab3546e5509348b6223f08d914a60a133b21ca9f57b
7
+ data.tar.gz: 7fa1e8c26b801ce265310f4dc8837ec7ec7f4218798d10360c4ab707f856ef8bb833c80f04cd08f52e1590df502c1d54fa44f270db384e7269abbda79de3eeec
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.0.27] – 2025-10-20
4
+ ### Added
5
+ - Decimal type system for precise money/bignum calculations
6
+ - Conversion functions (to_decimal, to_integer, to_float, to_string)
7
+ - Automatic documentation generation system for IDE support
8
+ - VSCode extension with schema block detection
9
+
10
+ ## [0.0.26] – 2025-10-17
11
+ ### Added
12
+ - UNSAT detection via constraint propagation through operations
13
+ - Documentation for UNSAT detection in `docs/UNSAT_DETECTION.md`
14
+
15
+ ### Changed
16
+ - Moved `UnsatDetector` to work over SNAST for full resolution context (axes/types)
17
+ - Refactored Typing system, added proper typing metadata on data/functions
18
+
3
19
  ## [0.0.25] – 2025-10-17
4
20
  ### Fixed
5
21
  - Fix inlining bug caused by previous fix
data/CLAUDE.md CHANGED
@@ -25,6 +25,10 @@ Axes align by identity (lineage), not by name
25
25
  `bin/kumi golden verify [name]` - Verify current vs expected
26
26
  `bin/kumi golden diff <name>` - Show diffs when verification fails
27
27
 
28
+ # Documentation Generation
29
+ `bin/kumi-doc-gen` - Generate IDE-friendly JSON + Markdown docs from function/kernel definitions
30
+ See docs/DEVELOPMENT.md for details
31
+
28
32
  # Kernels Invariants
29
33
  All reducers are pure binary combiner f : T × T → T applied over the last axis of a value. Example: agg.sum(a,b) = a+b.
30
34
 
data/README.md CHANGED
@@ -7,103 +7,98 @@
7
7
 
8
8
  ---
9
9
 
10
- **Status**: experimental. Public API may change. Typing and some static checks are still evolving.
11
-
12
- **Feedback**: have a use case or a paper cut? Open an issue or reach out.
10
+ **Declarative, typed, vectorized calculation DSL (Ruby-embedded) that builds a deterministic dependency graph.**
11
+ Normalized, typed **AST → IR → LIR**. Static checks and **constraint UNSAT** at compile time. Codegen is thin.
13
12
 
14
13
  ---
15
14
 
15
+ **Status**: experimental. Public API may change. Typing and some static checks are still evolving.
16
16
 
17
- **Declarative calculation DSL for Ruby.** Write business rules once, run them anywhere.
18
-
19
- Kumi compiles high-level schemas into standalone Ruby and JavaScript with no runtime dependencies.
20
-
21
- **Built for:** finance, tax, pricing, insurance, payroll, analytics—domains where correctness and transparency matter.
17
+ **Feedback**: have a use case or a paper cut? Open an issue or reach out.
22
18
 
23
19
  ---
24
20
 
25
- ## Example: Conway's Game of Life
21
+ ## Example: US Tax Calculator (2024)
26
22
 
23
+ See the [interactive demo](https://kumi-play-web.fly.dev/) or browse the [golden test files](golden/us_tax_2024/) (schema, input, expected output, generated code).
27
24
 
28
25
  <details>
29
26
  <summary><strong>Schema</strong></summary>
30
27
 
31
28
  ```ruby
32
- module GameOfLife
33
- extend Kumi::Schema
34
-
35
- schema do
36
- input do
37
- array :rows do
38
- array :col do
39
- integer :alive # 0 or 1
29
+ schema do
30
+ input do
31
+ float :income
32
+ float :state_rate
33
+ float :local_rate
34
+ float :retirement_contrib
35
+ string :filing_status
36
+
37
+ array :statuses do
38
+ hash :status do
39
+ string :name
40
+ float :std
41
+ float :addl_threshold
42
+ array :rates do
43
+ hash :bracket do
44
+ float :lo
45
+ float :hi # -1 = open-ended
46
+ float :rate
47
+ end
40
48
  end
41
49
  end
42
50
  end
43
-
44
- let :a, input.rows.col.alive
45
-
46
- # axis_offset: 0 = x, 1 = y
47
- let :n, shift(a, -1, axis_offset: 1)
48
- let :s, shift(a, 1, axis_offset: 1)
49
- let :w, shift(a, -1)
50
- let :e, shift(a, 1)
51
- let :nw, shift(n, -1)
52
- let :ne, shift(n, 1)
53
- let :sw, shift(s, -1)
54
- let :se, shift(s, 1)
55
-
56
- let :neighbors, fn(:sum, [n, s, w, e, nw, ne, sw, se])
57
-
58
- # Conway rules
59
- let :alive, a > 0
60
- let :n3_alive, neighbors == 3
61
- let :n2_alive, neighbors == 2
62
- let :keep_alive, n2_alive & alive
63
-
64
- let :next_alive, n3_alive | keep_alive
65
-
66
- value :next_state, select(next_alive, 1, 0)
67
51
  end
68
52
 
53
+ # shared
54
+ let :big_hi, 100_000_000_000.0
55
+ let :state_tax, input.income * input.state_rate
56
+ let :local_tax, input.income * input.local_rate
57
+
58
+ # FICA constants
59
+ let :ss_wage_base, 168_600.0
60
+ let :ss_rate, 0.062
61
+ let :med_base_rate, 0.0145
62
+ let :addl_med_rate, 0.009
63
+
64
+ # per-status federal
65
+ let :taxable, fn(:max, [input.income - input.statuses.status.std, 0])
66
+ let :lo, input.statuses.status.rates.bracket.lo
67
+ let :hi, input.statuses.status.rates.bracket.hi
68
+ let :rate, input.statuses.status.rates.bracket.rate
69
+ let :hi_eff, select(hi == -1, big_hi, hi)
70
+ let :amt, fn(:clamp, taxable - lo, 0, hi_eff - lo)
71
+ let :fed_tax, fn(:sum, amt * rate)
72
+ let :in_br, (taxable >= lo) & (taxable < hi_eff)
73
+ let :fed_marg, fn(:sum_if, rate, in_br)
74
+ let :fed_eff, fed_tax / fn(:max, [input.income, 1.0])
75
+
76
+ # per-status FICA
77
+ let :ss_tax, fn(:min, [input.income, ss_wage_base]) * ss_rate
78
+ let :med_tax, input.income * med_base_rate
79
+ let :addl_med_tax, fn(:max, [input.income - input.statuses.status.addl_threshold, 0]) * addl_med_rate
80
+ let :fica_tax, ss_tax + med_tax + addl_med_tax
81
+ let :fica_eff, fica_tax / fn(:max, [input.income, 1.0])
82
+
83
+ # totals per status
84
+ let :total_tax, fed_tax + fica_tax + state_tax + local_tax
85
+ let :total_eff, total_tax / fn(:max, [input.income, 1.0])
86
+ let :after_tax, input.income - total_tax
87
+ let :take_home, after_tax - input.retirement_contrib
88
+
89
+ # array of result objects, one per status
90
+ value :summary, {
91
+ filing_status: input.statuses.status.name,
92
+ federal: { marginal: fed_marg, effective: fed_eff, tax: fed_tax },
93
+ fica: { effective: fica_eff, tax: fica_tax },
94
+ state: { marginal: input.state_rate, effective: input.state_rate, tax: state_tax },
95
+ local: { marginal: input.local_rate, effective: input.local_rate, tax: local_tax },
96
+ total: { effective: total_eff, tax: total_tax },
97
+ after_tax: after_tax,
98
+ retirement_contrib: input.retirement_contrib,
99
+ take_home: take_home
100
+ }
69
101
  end
70
- ````
71
-
72
- </details>
73
-
74
-
75
- <details>
76
- <summary><strong>Generated JavaScript (excerpt)</strong></summary>
77
-
78
- ```js
79
- export function _next_state(input) {
80
- let out = [];
81
- let t285 = input["rows"];
82
- let t1539 = t285.length;
83
- const t1540 = -1;
84
- const t1542 = 0;
85
- const t1546 = 1;
86
- const t1334 = 3;
87
- const t1339 = 2;
88
- let t1547 = t1539 - t1546;
89
- t285.forEach((rows_el_286, rows_i_287) => {
90
- let out_1 = [];
91
- let t1541 = rows_i_287 - t1540;
92
- let t1561 = rows_i_287 - t1546;
93
- let t1580 = ((rows_i_287 % t1539) + t1539) % t1539;
94
- // ... neighbor calculations, Conway's rules
95
- let t1332 = [t1557, t1577, t1597, t1617, t1645, t1673, t1701, t1729];
96
- let t1333 = t1332.reduce((a, b) => a + b, 0);
97
- let t1335 = t1333 == t1334;
98
- let t1340 = t1333 == t1339;
99
- let t1344 = col_el_288 > t1542;
100
- let t1345 = t1340 && t1344;
101
- let t528 = t1335 || t1345;
102
- let t293 = t528 ? t1546 : t1542;
103
- out_1.push(t293);
104
- });
105
- return out;
106
- }
107
102
  ```
108
103
 
109
104
  </details>
@@ -146,6 +141,19 @@ Double.write_source("output.mjs", platform: :javascript)
146
141
 
147
142
  ---
148
143
 
144
+ ## Documentation
145
+
146
+ Auto-generated reference for all functions and kernels:
147
+
148
+ - **[Functions Reference](docs/FUNCTIONS.md)** - Human-readable docs with parameters and kernels
149
+ - **[functions-reference.json](docs/functions-reference.json)** - Machine-readable format for IDEs (VSCode, Monaco, etc.)
150
+
151
+ To regenerate: `bin/kumi-doc-gen`
152
+
153
+ See [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md) for development workflows.
154
+
155
+ ---
156
+
149
157
  ## License
150
158
 
151
159
  MIT License. See [LICENSE](LICENSE).
@@ -2,13 +2,17 @@ functions:
2
2
  - id: agg.any
3
3
  kind: reduce
4
4
  params: [{ name: source_value }]
5
- dtype: "boolean"
5
+ dtype:
6
+ rule: scalar
7
+ kind: boolean
6
8
  aliases: ["any", "any?"]
7
9
  folding_class_method: any?
8
10
 
9
11
  - id: agg.all
10
12
  kind: reduce
11
13
  params: [{ name: source_value }]
12
- dtype: "boolean"
14
+ dtype:
15
+ rule: scalar
16
+ kind: boolean
13
17
  aliases: ["all", "all?"]
14
18
  folding_class_method: all?
@@ -2,65 +2,79 @@ functions:
2
2
  - id: agg.sum
3
3
  kind: reduce
4
4
  params: [{ name: source_value }]
5
- dtype: "same_as(source_value)"
5
+ dtype:
6
+ rule: same_as
7
+ param: source_value
6
8
  reduction_strategy: identity # This function has a true identity value.
7
9
  aliases: ["sum"]
8
-
10
+
9
11
  - id: agg.count
10
12
  kind: reduce
11
13
  params: [{ name: source_value }]
12
- dtype: "integer"
14
+ dtype:
15
+ rule: scalar
16
+ kind: integer
13
17
  reduction_strategy: identity # This function has a true identity value.
14
18
  aliases: ["count"]
15
19
 
16
20
  - id: agg.min
17
21
  kind: reduce
18
22
  params: [{ name: source_value }]
19
- dtype: "element_of(source_value)"
23
+ dtype:
24
+ rule: element_of
25
+ param: source_value
20
26
  reduction_strategy: first_element
21
27
  aliases: ["min"]
22
28
 
23
29
  - id: agg.max
24
30
  kind: reduce
25
31
  params: [{ name: source_value }]
26
- dtype: "element_of(source_value)"
32
+ dtype:
33
+ rule: element_of
34
+ param: source_value
27
35
  reduction_strategy: first_element
28
36
  aliases: ["max"]
29
-
37
+
30
38
  - id: agg.mean
31
39
  kind: reduce
32
40
  params: [{ name: source_value }]
33
- dtype: "float"
41
+ dtype:
42
+ rule: scalar
43
+ kind: float
34
44
  aliases: ["mean", "avg"]
35
45
  expand:
36
46
  fn: div
37
47
  args:
38
48
  - fn: sum
39
- args: [ "$1" ] # $1 is source_value
49
+ args: ["$1"] # $1 is source_value
40
50
  - fn: count
41
- args: [ "$1" ]
51
+ args: ["$1"]
42
52
 
43
53
  - id: agg.sum_if
44
54
  kind: reduce
45
55
  params: [{ name: source_value }, { name: condition }]
46
- dtype: "same_as(source_value)"
56
+ dtype:
57
+ rule: same_as
58
+ param: source_value
47
59
  aliases: ["sum_if"]
48
60
  expand:
49
61
  fn: sum
50
62
  args:
51
63
  - fn: __select__
52
- args: [ "$2", "$1", { const: 0 } ] # $1=source_value, $2=condition
64
+ args: ["$2", "$1", { const: 0 }] # $1=source_value, $2=condition
53
65
 
54
66
  - id: agg.count_if
55
67
  kind: reduce
56
68
  params: [{ name: condition }, { name: source_value }]
57
- dtype: "integer"
69
+ dtype:
70
+ rule: scalar
71
+ kind: integer
58
72
  aliases: ["count_if"]
59
73
  expand:
60
74
  fn: sum # Summing 1s and 0s is equivalent to a conditional count
61
75
  args:
62
76
  - fn: __select__
63
- args:
77
+ args:
64
78
  - fn: eq
65
79
  args: ["$1", "$2"]
66
80
  - { const: 1 }
@@ -69,12 +83,14 @@ functions:
69
83
  - id: agg.mean_if
70
84
  kind: reduce
71
85
  params: [{ name: source_value }, { name: condition }]
72
- dtype: "float"
86
+ dtype:
87
+ rule: scalar
88
+ kind: float
73
89
  aliases: ["avg_if", "mean_if"]
74
90
  expand:
75
91
  fn: div
76
92
  args:
77
93
  - fn: sum_if
78
- args: [ "$1", "$2" ] # Sum the values where the condition is true
94
+ args: ["$1", "$2"] # Sum the values where the condition is true
79
95
  - fn: count_if
80
- args: [ "$1", "$2" ] # Count the values where the condition is true
96
+ args: ["$1", "$2"] # Count the values where the condition is true
@@ -2,7 +2,8 @@ functions:
2
2
  - id: agg.join
3
3
  kind: reduce
4
4
  params: [{ name: source_value, dtype: string }]
5
- dtype: "string"
5
+ dtype:
6
+ rule: scalar
7
+ kind: string
6
8
  reduction_strategy: first_element
7
- aliases: ["join"]
8
-
9
+ aliases: ["join"]
@@ -2,49 +2,97 @@ functions:
2
2
  - id: core.abs
3
3
  kind: elementwise
4
4
  params: [{ name: number }]
5
- dtype: "same_as(number)"
5
+ dtype:
6
+ rule: same_as
7
+ param: number
6
8
  aliases: ["abs"]
7
9
 
8
10
  - id: core.add
9
- kind: elementwise
11
+ kind: elementwise
10
12
  params: [{ name: left_operand }, { name: right_operand }]
11
- dtype: "promote(left_operand,right_operand)"
13
+ dtype:
14
+ rule: promote
15
+ params: [left_operand, right_operand]
12
16
  aliases: ["add"]
17
+ constraint_semantics:
18
+ domain_effect: EXTEND
19
+ pure_combiner: true
20
+ commutativity: true
21
+ associativity: true
22
+ identity: 0
23
+ forward_propagation:
24
+ # If we know left == L and right == R, then result == L + R
25
+ equality: "result = left + right"
26
+ # If result is in [a, b] and left/right in domains, derive tighter bounds
27
+ range: "result_min = left_min + right_min; result_max = left_max + right_max"
28
+ reverse_propagation:
29
+ # If result == V, then left == V - right
30
+ equality: "left = result - right; right = result - left"
31
+ # If result in [a, b] and left in [l1, l2], then right in [a - l2, b - l1]
32
+ range: "left_min = result_min - right_max; left_max = result_max - right_min; right_min = result_min - left_max; right_max = result_max - left_min"
13
33
 
14
34
  - id: core.sub
15
35
  kind: elementwise
16
- params: [{ name: left_operand }, { name: right_operand }]
17
- dtype: "promote(left_operand,right_operand)"
36
+ params: [{ name: left_operand }, { name: right_operand }]
37
+ dtype:
38
+ rule: promote
39
+ params: [left_operand, right_operand]
18
40
  aliases: ["sub", "subtract"]
19
41
 
20
42
  - id: core.mul
21
43
  kind: elementwise
22
44
  params: [{ name: left_operand }, { name: right_operand }]
23
- dtype: "promote(left_operand,right_operand)"
45
+ dtype:
46
+ rule: promote
47
+ params: [left_operand, right_operand]
24
48
  aliases: ["mul", "multiply"]
49
+ constraint_semantics:
50
+ domain_effect: SCALE
51
+ pure_combiner: true
52
+ commutativity: true
53
+ associativity: true
54
+ identity: 1
55
+ forward_propagation:
56
+ # If we know left == L and right == R, then result == L * R
57
+ equality: "result = left * right"
58
+ # For multiplication: result bounds depend on sign of operands
59
+ range: "result = combinations of {left_min*right_min, left_min*right_max, left_max*right_min, left_max*right_max} -> [min, max]"
60
+ reverse_propagation:
61
+ # If result == V and right != 0, then left == V / right
62
+ equality: "left = result / right (if right != 0); right = result / left (if left != 0)"
63
+ # For multiplication: divide by absolute values considering sign changes
64
+ range: "derive from result bounds and operand bounds considering sign combinations"
25
65
 
26
66
  - id: core.pow
27
67
  kind: elementwise
28
68
  params: [{ name: base }, { name: exponent }]
29
- dtype: "promote(base,exponent)"
69
+ dtype:
70
+ rule: promote
71
+ params: [base, exponent]
30
72
  aliases: ["pow", "power"]
31
73
 
32
74
  - id: core.div
33
- kind: elementwise
75
+ kind: elementwise
34
76
  params: [{ name: left_operand }, { name: right_operand }]
35
- dtype: "float"
77
+ dtype:
78
+ rule: scalar
79
+ kind: float
36
80
  aliases: ["div", "divide"]
37
81
 
38
82
  - id: core.mod
39
83
  kind: elementwise
40
84
  params:
41
- - { name: left_operand}
42
- - { name: right_operand}
43
- dtype: "promote(left_operand,right_operand)"
85
+ - { name: left_operand }
86
+ - { name: right_operand }
87
+ dtype:
88
+ rule: promote
89
+ params: [left_operand, right_operand]
44
90
  aliases: ["mod", "modulo", "%"]
45
91
 
46
92
  - id: core.clamp
47
93
  kind: elementwise
48
- params: [{name: x},{name: lo},{name: hi}]
49
- dtype: "same_as(x)"
94
+ params: [{ name: x }, { name: lo }, { name: hi }]
95
+ dtype:
96
+ rule: same_as
97
+ param: x
50
98
  aliases: ["clamp"]
@@ -2,17 +2,23 @@ functions:
2
2
  - id: core.and
3
3
  kind: elementwise
4
4
  params: [{ name: left_operand }, { name: right_operand }]
5
- dtype: "boolean"
6
- aliases : ["and", "&"]
5
+ dtype:
6
+ rule: scalar
7
+ kind: boolean
8
+ aliases: ["and", "&"]
7
9
 
8
10
  - id: core.or
9
11
  kind: elementwise
10
12
  params: [{ name: left_operand }, { name: right_operand }]
11
- dtype: "boolean"
12
- aliases : ["or", "|"]
13
+ dtype:
14
+ rule: scalar
15
+ kind: boolean
16
+ aliases: ["or", "|"]
13
17
 
14
18
  - id: core.not
15
19
  kind: elementwise
16
20
  params: [{ name: operand }]
17
- dtype: "boolean"
18
- aliases : ["not", "!"]
21
+ dtype:
22
+ rule: scalar
23
+ kind: boolean
24
+ aliases: ["not", "!"]
@@ -2,41 +2,53 @@ functions:
2
2
  - id: core.gte
3
3
  kind: elementwise
4
4
  params: [{ name: left_operand }, { name: right_operand }]
5
- dtype: "boolean"
6
- aliases : ["gte", "ge", "greater_than_or_equal", ">="]
5
+ dtype:
6
+ rule: scalar
7
+ kind: boolean
8
+ aliases: ["gte", "ge", "greater_than_or_equal", ">="]
7
9
  folding_class_method: gte
8
10
 
9
11
  - id: core.gt
10
12
  kind: elementwise
11
13
  params: [{ name: left_operand }, { name: right_operand }]
12
- dtype: "boolean"
13
- aliases : ["gt", "greater_than", ">"]
14
+ dtype:
15
+ rule: scalar
16
+ kind: boolean
17
+ aliases: ["gt", "greater_than", ">"]
14
18
  folding_class_method: gt
15
19
 
16
20
  - id: core.lte
17
21
  kind: elementwise
18
22
  params: [{ name: left_operand }, { name: right_operand }]
19
- dtype: "boolean"
20
- aliases : ["lte", "le", "less_than_or_equal", "<="]
23
+ dtype:
24
+ rule: scalar
25
+ kind: boolean
26
+ aliases: ["lte", "le", "less_than_or_equal", "<="]
21
27
  folding_class_method: lte
22
28
 
23
29
  - id: core.lt
24
30
  kind: elementwise
25
31
  params: [{ name: left_operand }, { name: right_operand }]
26
- dtype: "boolean"
27
- aliases : ["lt", "less_than", "<"]
32
+ dtype:
33
+ rule: scalar
34
+ kind: boolean
35
+ aliases: ["lt", "less_than", "<"]
28
36
  folding_class_method: lt
29
37
 
30
38
  - id: core.eq
31
- kind: elementwise
39
+ kind: elementwise
32
40
  params: [{ name: left_operand }, { name: right_operand }]
33
- dtype: "boolean"
34
- aliases : ["eq", "equal", "=="]
41
+ dtype:
42
+ rule: scalar
43
+ kind: boolean
44
+ aliases: ["eq", "equal", "=="]
35
45
  folding_class_method: eq
36
46
 
37
47
  - id: core.neq
38
48
  kind: elementwise
39
49
  params: [{ name: left_operand }, { name: right_operand }]
40
- dtype: "boolean"
41
- aliases : ["neq", "not_equal", "!="]
50
+ dtype:
51
+ rule: scalar
52
+ kind: boolean
53
+ aliases: ["neq", "not_equal", "!="]
42
54
  folding_class_method: neq
@@ -1,32 +1,40 @@
1
1
  functions:
2
- # length is probably in the wrong place
2
+ # length is probably in the wrong place
3
3
  - id: core.length
4
4
  kind: elementwise
5
5
  params: [{ name: collection, dtype: string }]
6
- dtype: "integer"
6
+ dtype:
7
+ rule: scalar
8
+ kind: integer
7
9
  aliases: ["length", "len", "size"]
8
10
  folding_class_method: length
9
11
 
10
12
  - id: core.array_size
11
13
  kind: elementwise
12
14
  params: [{ name: collection, dtype: array }]
13
- dtype: "integer"
14
- aliases: ["array_size","size"]
15
+ dtype:
16
+ rule: scalar
17
+ kind: integer
18
+ aliases: ["array_size", "size"]
15
19
  folding_class_method: length
16
20
 
17
21
  - id: core.at
18
22
  kind: elementwise
19
- params:
23
+ params:
20
24
  - { name: collection }
21
25
  - { name: index, dtype: integer }
22
- dtype: "element_of(collection)"
26
+ dtype:
27
+ rule: element_of
28
+ param: collection
23
29
  aliases: ["at", "get", "[]"]
24
30
  folding_class_method: at
25
31
 
26
32
  - id: core.hash_fetch
27
33
  kind: elementwise
28
- params:
34
+ params:
29
35
  - { name: key, dtype: hash }
30
- dtype: "value_of(key)" # TODO, we can calculate,
36
+ dtype:
37
+ rule: scalar
38
+ kind: any
31
39
  aliases: ["fetch"]
32
40
  folding_class_method: "[]"
@@ -0,0 +1,32 @@
1
+ functions:
2
+ - id: core.to_decimal
3
+ kind: elementwise
4
+ params: [{ name: value }]
5
+ dtype:
6
+ rule: scalar
7
+ kind: decimal
8
+ aliases: ["to_decimal"]
9
+
10
+ - id: core.to_integer
11
+ kind: elementwise
12
+ params: [{ name: value }]
13
+ dtype:
14
+ rule: scalar
15
+ kind: integer
16
+ aliases: ["to_integer", "to_int"]
17
+
18
+ - id: core.to_float
19
+ kind: elementwise
20
+ params: [{ name: value }]
21
+ dtype:
22
+ rule: scalar
23
+ kind: float
24
+ aliases: ["to_float"]
25
+
26
+ - id: core.to_string
27
+ kind: elementwise
28
+ params: [{ name: value }]
29
+ dtype:
30
+ rule: scalar
31
+ kind: string
32
+ aliases: ["to_string", "to_str"]