kumi 0.0.26 → 0.0.28

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 (177) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -0
  3. data/CLAUDE.md +4 -0
  4. data/README.md +36 -12
  5. data/data/functions/core/arithmetic.yaml +28 -8
  6. data/data/functions/core/boolean.yaml +8 -3
  7. data/data/functions/core/comparison.yaml +12 -4
  8. data/data/functions/core/conversion.yaml +32 -0
  9. data/data/kernels/javascript/core/arithmetic.yaml +6 -2
  10. data/data/kernels/javascript/core/coercion.yaml +20 -0
  11. data/data/kernels/ruby/core/arithmetic.yaml +7 -2
  12. data/data/kernels/ruby/core/coercion.yaml +20 -0
  13. data/docs/ARCHITECTURE.md +277 -0
  14. data/docs/DEVELOPMENT.md +62 -0
  15. data/docs/FUNCTIONS.md +955 -0
  16. data/docs/SYNTAX.md +8 -0
  17. data/docs/VSCODE_EXTENSION.md +114 -0
  18. data/docs/functions-reference.json +1821 -0
  19. data/golden/array_element/expected/schema_ruby.rb +1 -1
  20. data/golden/array_index/expected/lir_00_unoptimized.txt +2 -2
  21. data/golden/array_index/expected/lir_01_hoist_scalar_references.txt +2 -2
  22. data/golden/array_index/expected/lir_02_inlined.txt +2 -2
  23. data/golden/array_index/expected/lir_03_cse.txt +2 -2
  24. data/golden/array_index/expected/lir_04_1_loop_fusion.txt +2 -2
  25. data/golden/array_index/expected/lir_04_loop_invcm.txt +2 -2
  26. data/golden/array_index/expected/lir_06_const_prop.txt +2 -2
  27. data/golden/array_index/expected/schema_ruby.rb +1 -1
  28. data/golden/array_index/expected/snast.txt +2 -2
  29. data/golden/array_operations/expected/lir_00_unoptimized.txt +2 -2
  30. data/golden/array_operations/expected/lir_01_hoist_scalar_references.txt +2 -2
  31. data/golden/array_operations/expected/lir_02_inlined.txt +2 -2
  32. data/golden/array_operations/expected/lir_03_cse.txt +2 -2
  33. data/golden/array_operations/expected/lir_04_1_loop_fusion.txt +2 -2
  34. data/golden/array_operations/expected/lir_04_loop_invcm.txt +2 -2
  35. data/golden/array_operations/expected/lir_06_const_prop.txt +2 -2
  36. data/golden/array_operations/expected/schema_ruby.rb +1 -1
  37. data/golden/array_operations/expected/snast.txt +2 -2
  38. data/golden/cascade_logic/expected/schema_ruby.rb +1 -1
  39. data/golden/chained_fusion/expected/schema_ruby.rb +1 -1
  40. data/golden/decimal_explicit/expected/ast.txt +38 -0
  41. data/golden/decimal_explicit/expected/input_plan.txt +3 -0
  42. data/golden/decimal_explicit/expected/lir_00_unoptimized.txt +30 -0
  43. data/golden/decimal_explicit/expected/lir_01_hoist_scalar_references.txt +30 -0
  44. data/golden/decimal_explicit/expected/lir_02_inlined.txt +44 -0
  45. data/golden/decimal_explicit/expected/lir_03_cse.txt +40 -0
  46. data/golden/decimal_explicit/expected/lir_04_1_loop_fusion.txt +40 -0
  47. data/golden/decimal_explicit/expected/lir_04_loop_invcm.txt +40 -0
  48. data/golden/decimal_explicit/expected/lir_06_const_prop.txt +40 -0
  49. data/golden/decimal_explicit/expected/nast.txt +30 -0
  50. data/golden/decimal_explicit/expected/schema_javascript.mjs +31 -0
  51. data/golden/decimal_explicit/expected/schema_ruby.rb +57 -0
  52. data/golden/decimal_explicit/expected/snast.txt +30 -0
  53. data/golden/decimal_explicit/expected.json +1 -0
  54. data/golden/decimal_explicit/input.json +5 -0
  55. data/golden/decimal_explicit/schema.kumi +14 -0
  56. data/golden/element_arrays/expected/schema_ruby.rb +1 -1
  57. data/golden/empty_and_null_inputs/expected/schema_ruby.rb +1 -1
  58. data/golden/function_overload/expected/schema_ruby.rb +1 -1
  59. data/golden/game_of_life/expected/schema_ruby.rb +1 -1
  60. data/golden/hash_keys/expected/schema_ruby.rb +1 -1
  61. data/golden/hash_value/expected/schema_ruby.rb +1 -1
  62. data/golden/hierarchical_complex/expected/lir_00_unoptimized.txt +3 -3
  63. data/golden/hierarchical_complex/expected/lir_01_hoist_scalar_references.txt +3 -3
  64. data/golden/hierarchical_complex/expected/lir_02_inlined.txt +3 -3
  65. data/golden/hierarchical_complex/expected/lir_03_cse.txt +3 -3
  66. data/golden/hierarchical_complex/expected/lir_04_1_loop_fusion.txt +3 -3
  67. data/golden/hierarchical_complex/expected/lir_04_loop_invcm.txt +3 -3
  68. data/golden/hierarchical_complex/expected/lir_06_const_prop.txt +3 -3
  69. data/golden/hierarchical_complex/expected/schema_ruby.rb +1 -1
  70. data/golden/hierarchical_complex/expected/snast.txt +3 -3
  71. data/golden/inline_rename_scope_leak/expected/schema_ruby.rb +1 -1
  72. data/golden/input_reference/expected/schema_ruby.rb +1 -1
  73. data/golden/interleaved_fusion/expected/lir_00_unoptimized.txt +1 -1
  74. data/golden/interleaved_fusion/expected/lir_01_hoist_scalar_references.txt +1 -1
  75. data/golden/interleaved_fusion/expected/lir_02_inlined.txt +2 -2
  76. data/golden/interleaved_fusion/expected/lir_03_cse.txt +2 -2
  77. data/golden/interleaved_fusion/expected/lir_04_1_loop_fusion.txt +2 -2
  78. data/golden/interleaved_fusion/expected/lir_04_loop_invcm.txt +2 -2
  79. data/golden/interleaved_fusion/expected/lir_06_const_prop.txt +2 -2
  80. data/golden/interleaved_fusion/expected/schema_ruby.rb +1 -1
  81. data/golden/interleaved_fusion/expected/snast.txt +1 -1
  82. data/golden/let_inline/expected/lir_00_unoptimized.txt +2 -2
  83. data/golden/let_inline/expected/lir_01_hoist_scalar_references.txt +2 -2
  84. data/golden/let_inline/expected/lir_02_inlined.txt +6 -6
  85. data/golden/let_inline/expected/lir_03_cse.txt +6 -6
  86. data/golden/let_inline/expected/lir_04_1_loop_fusion.txt +6 -6
  87. data/golden/let_inline/expected/lir_04_loop_invcm.txt +6 -6
  88. data/golden/let_inline/expected/lir_06_const_prop.txt +6 -6
  89. data/golden/let_inline/expected/schema_ruby.rb +1 -1
  90. data/golden/let_inline/expected/snast.txt +2 -2
  91. data/golden/loop_fusion/expected/schema_ruby.rb +1 -1
  92. data/golden/min_reduce_scope/expected/schema_ruby.rb +1 -1
  93. data/golden/mixed_dimensions/expected/schema_ruby.rb +1 -1
  94. data/golden/multirank_hoisting/expected/lir_00_unoptimized.txt +2 -2
  95. data/golden/multirank_hoisting/expected/lir_01_hoist_scalar_references.txt +2 -2
  96. data/golden/multirank_hoisting/expected/lir_02_inlined.txt +7 -7
  97. data/golden/multirank_hoisting/expected/lir_03_cse.txt +7 -7
  98. data/golden/multirank_hoisting/expected/lir_04_1_loop_fusion.txt +7 -7
  99. data/golden/multirank_hoisting/expected/lir_04_loop_invcm.txt +7 -7
  100. data/golden/multirank_hoisting/expected/lir_06_const_prop.txt +7 -7
  101. data/golden/multirank_hoisting/expected/schema_ruby.rb +1 -1
  102. data/golden/multirank_hoisting/expected/snast.txt +2 -2
  103. data/golden/nested_hash/expected/lir_00_unoptimized.txt +1 -1
  104. data/golden/nested_hash/expected/lir_01_hoist_scalar_references.txt +1 -1
  105. data/golden/nested_hash/expected/lir_02_inlined.txt +1 -1
  106. data/golden/nested_hash/expected/lir_03_cse.txt +1 -1
  107. data/golden/nested_hash/expected/lir_04_1_loop_fusion.txt +1 -1
  108. data/golden/nested_hash/expected/lir_04_loop_invcm.txt +1 -1
  109. data/golden/nested_hash/expected/lir_06_const_prop.txt +1 -1
  110. data/golden/nested_hash/expected/schema_ruby.rb +1 -1
  111. data/golden/nested_hash/expected/snast.txt +1 -1
  112. data/golden/reduction_broadcast/expected/schema_ruby.rb +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 +2 -2
  117. data/golden/simple_math/expected/lir_01_hoist_scalar_references.txt +2 -2
  118. data/golden/simple_math/expected/lir_02_inlined.txt +2 -2
  119. data/golden/simple_math/expected/lir_03_cse.txt +2 -2
  120. data/golden/simple_math/expected/lir_04_1_loop_fusion.txt +2 -2
  121. data/golden/simple_math/expected/lir_04_loop_invcm.txt +2 -2
  122. data/golden/simple_math/expected/lir_06_const_prop.txt +2 -2
  123. data/golden/simple_math/expected/schema_ruby.rb +1 -1
  124. data/golden/simple_math/expected/snast.txt +2 -2
  125. data/golden/streaming_basics/expected/lir_00_unoptimized.txt +3 -3
  126. data/golden/streaming_basics/expected/lir_01_hoist_scalar_references.txt +3 -3
  127. data/golden/streaming_basics/expected/lir_02_inlined.txt +9 -9
  128. data/golden/streaming_basics/expected/lir_03_cse.txt +7 -7
  129. data/golden/streaming_basics/expected/lir_04_1_loop_fusion.txt +7 -7
  130. data/golden/streaming_basics/expected/lir_04_loop_invcm.txt +7 -7
  131. data/golden/streaming_basics/expected/lir_06_const_prop.txt +7 -7
  132. data/golden/streaming_basics/expected/schema_ruby.rb +1 -1
  133. data/golden/streaming_basics/expected/snast.txt +3 -3
  134. data/golden/tuples/expected/schema_ruby.rb +1 -1
  135. data/golden/tuples_and_arrays/expected/schema_ruby.rb +1 -1
  136. data/golden/us_tax_2024/expected/lir_00_unoptimized.txt +6 -6
  137. data/golden/us_tax_2024/expected/lir_01_hoist_scalar_references.txt +6 -6
  138. data/golden/us_tax_2024/expected/lir_02_inlined.txt +71 -71
  139. data/golden/us_tax_2024/expected/lir_03_cse.txt +43 -43
  140. data/golden/us_tax_2024/expected/lir_04_1_loop_fusion.txt +48 -48
  141. data/golden/us_tax_2024/expected/lir_04_loop_invcm.txt +43 -43
  142. data/golden/us_tax_2024/expected/lir_06_const_prop.txt +43 -43
  143. data/golden/us_tax_2024/expected/schema_ruby.rb +1 -1
  144. data/golden/us_tax_2024/expected/snast.txt +6 -6
  145. data/golden/with_constants/expected/schema_ruby.rb +1 -1
  146. data/lib/kumi/configuration.rb +6 -0
  147. data/lib/kumi/core/analyzer/passes/nast_dimensional_analyzer_pass.rb +1 -1
  148. data/lib/kumi/core/error_reporter.rb +1 -1
  149. data/lib/kumi/core/errors.rb +1 -1
  150. data/lib/kumi/core/functions/overload_resolver.rb +57 -11
  151. data/lib/kumi/core/functions/type_categories.rb +44 -0
  152. data/lib/kumi/core/input/type_matcher.rb +8 -1
  153. data/lib/kumi/core/ruby_parser/input_builder.rb +2 -2
  154. data/lib/kumi/core/types/normalizer.rb +1 -0
  155. data/lib/kumi/core/types/validator.rb +2 -2
  156. data/lib/kumi/core/types.rb +2 -2
  157. data/lib/kumi/dev/golden/reporter.rb +9 -0
  158. data/lib/kumi/dev/golden/result.rb +3 -1
  159. data/lib/kumi/dev/golden/runtime_test.rb +25 -0
  160. data/lib/kumi/dev/golden/suite.rb +4 -4
  161. data/lib/kumi/dev/golden/value_normalizer.rb +80 -0
  162. data/lib/kumi/dev/golden.rb +21 -12
  163. data/lib/kumi/doc_generator/formatters/json.rb +39 -0
  164. data/lib/kumi/doc_generator/formatters/markdown.rb +175 -0
  165. data/lib/kumi/doc_generator/loader.rb +37 -0
  166. data/lib/kumi/doc_generator/merger.rb +54 -0
  167. data/lib/kumi/doc_generator.rb +4 -0
  168. data/lib/kumi/frontends/text.rb +33 -5
  169. data/lib/kumi/syntax/location.rb +5 -1
  170. data/lib/kumi/version.rb +1 -1
  171. data/vscode-extension/.gitignore +4 -0
  172. data/vscode-extension/README.md +59 -0
  173. data/vscode-extension/TESTING.md +151 -0
  174. data/vscode-extension/package.json +51 -0
  175. data/vscode-extension/src/extension.ts +295 -0
  176. data/vscode-extension/tsconfig.json +15 -0
  177. metadata +38 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b422f7930abf2d8300bcc0a6f565a4adf1505cb722f1d51abf42e776617eb255
4
- data.tar.gz: b9920b8399e8521eb7517427a36118b0ccbdd9fb1d92644db822d9dbc755b0b6
3
+ metadata.gz: 644df492ff48a0f3490909636f678554b93cfea464e7c133366609743d6ac8a8
4
+ data.tar.gz: df9b82c1e0e29466e033fac43dafda4ad990402d005d606acdf41133c3860f25
5
5
  SHA512:
6
- metadata.gz: d541c8a5839a7f8e8f5cd2c4e9e8e1418e474bca0d81152f4e0043a09e059ab4839bda084aa32c141938dfb3971815071219daa2e3d5733590ba8e2d84f830ba
7
- data.tar.gz: 72f061aa65ec67d5f0d99812d5429225f5a623e0a5f49fdad27260fc6335629b85ae69dada088f05aef24b00a22c912194c8075c9d7373b43fbf433954f417ca
6
+ metadata.gz: 71555d229915f8a71d47fe719f976c3d0e212576f1bbf5061463ede08c0e49e7126b338646036eb2573e3f1492297da8e42bc40331ce02289d4112b9d71be6f2
7
+ data.tar.gz: '09cd854fca02d7e15f52ea51f7153e9105075d4509b19219cd4cc0924c25048126df97de350e06d845ab6d65c5027e23e710ef2cf0a1ca59922fea3cefb45a3a'
data/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.0.28] – 2025-10-20
4
+ ### Changed
5
+ - Error location formatting now uses explicit `line=` and `column=` keywords for clarity
6
+ - Location extraction prioritizes structured Location objects over message parsing
7
+ - Default file label changed from "(string)" to "schema" for better UX
8
+
9
+ ### Fixed
10
+ - Removed redundant location information from error messages
11
+ - Parse error messages now properly format location details
12
+
13
+ ## [0.0.27] – 2025-10-20
14
+ ### Added
15
+ - Decimal type system for precise money/bignum calculations
16
+ - Conversion functions (to_decimal, to_integer, to_float, to_string)
17
+ - Automatic documentation generation system for IDE support
18
+ - VSCode extension with schema block detection
19
+
3
20
  ## [0.0.26] – 2025-10-17
4
21
  ### Added
5
22
  - UNSAT detection via constraint propagation through operations
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,24 +7,37 @@
7
7
 
8
8
  ---
9
9
 
10
- **Status**: experimental. Public API may change. Typing and some static checks are still evolving.
10
+ ## What is Kumi?
11
11
 
12
- **Feedback**: have a use case or a paper cut? Open an issue or reach out.
12
+ Kumi is a **declarative DSL for building calculation systems** that are:
13
+ - **Typed & verifiable at compile time** (catch errors before they hit production)
14
+ - **Vectorized** (arrays and nested data structures work naturally)
15
+ - **Transparent** (inspect generated code and execution order)
16
+ - **Portable** (compile the same schema to Ruby or JavaScript)
13
17
 
14
- ---
18
+ Instead of writing procedural formulas, you declare *what* values depend on *what*, and Kumi figures out the computation order, validates types, detects impossible constraints, and generates efficient code.
19
+
20
+ ## Why Kumi Exists
21
+
22
+ Calculation systems are everywhere: tax engines, pricing models, financial projections, compliance checks. They're usually:
23
+ - Hard to verify (logic spread across multiple files)
24
+ - Fragile (changing one formula breaks hidden dependencies)
25
+ - Duplicated (same logic needed in backend and frontend)
26
+ - Opaque (hard to audit which rules applied to which data)
15
27
 
28
+ Kumi makes them explicit, testable, and portable.
16
29
 
17
- **Declarative calculation DSL for Ruby.** Write business rules once, run them anywhere.
30
+ ---
18
31
 
19
- Kumi compiles high-level schemas into standalone Ruby and JavaScript with no runtime dependencies. Includes static analysis to catch impossible constraints before runtime.
32
+ **Status**: experimental. Public API may change. Typing and some static checks are still evolving.
20
33
 
21
- **Built for:** finance, tax, pricing, insurance, payroll, analytics—domains where correctness and transparency matter.
34
+ **Feedback**: have a use case or hit a rough edge? Open an issue or reach out.
22
35
 
23
36
  ---
24
37
 
25
38
  ## Example: US Tax Calculator (2024)
26
39
 
27
- 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).
40
+ A single schema computes federal, state, FICA taxes across multiple filing statuses—all types verified at compile time. Try it in the [interactive demo](https://kumi-play-web.fly.dev/) or inspect the [full schema, input, output, and generated code](golden/us_tax_2024/).
28
41
 
29
42
  <details>
30
43
  <summary><strong>Schema</strong></summary>
@@ -122,10 +135,6 @@ Requires Ruby 3.1+. No external dependencies.
122
135
  ```ruby
123
136
  require 'kumi'
124
137
 
125
- Kumi.configure do |config|
126
- config.compilation_mode = :jit
127
- end
128
-
129
138
  module Double
130
139
  extend Kumi::Schema
131
140
 
@@ -139,10 +148,25 @@ end
139
148
  result = Double.from(x: 5)
140
149
  result[:doubled] # => 10
141
150
 
142
- # Export to JavaScript
151
+ # Export to JavaScript (same logic)
143
152
  Double.write_source("output.mjs", platform: :javascript)
144
153
  ```
145
154
 
155
+ Try the [interactive demo](https://kumi-play-web.fly.dev/) (no setup required).
156
+
157
+ ---
158
+
159
+ ## Documentation
160
+
161
+ Auto-generated reference for all functions and kernels:
162
+
163
+ - **[Functions Reference](docs/FUNCTIONS.md)** - Human-readable docs with parameters and kernels
164
+ - **[functions-reference.json](docs/functions-reference.json)** - Machine-readable format for IDEs (VSCode, Monaco, etc.)
165
+
166
+ To regenerate: `bin/kumi-doc-gen`
167
+
168
+ See [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md) for development workflows.
169
+
146
170
  ---
147
171
 
148
172
  ## License
@@ -9,7 +9,9 @@ functions:
9
9
 
10
10
  - id: core.add
11
11
  kind: elementwise
12
- params: [{ name: left_operand }, { name: right_operand }]
12
+ params:
13
+ - { name: left_operand, dtype: numeric }
14
+ - { name: right_operand, dtype: numeric }
13
15
  dtype:
14
16
  rule: promote
15
17
  params: [left_operand, right_operand]
@@ -33,15 +35,19 @@ functions:
33
35
 
34
36
  - id: core.sub
35
37
  kind: elementwise
36
- params: [{ name: left_operand }, { name: right_operand }]
38
+ params:
39
+ - { name: left_operand, dtype: numeric }
40
+ - { name: right_operand, dtype: numeric }
37
41
  dtype:
38
42
  rule: promote
39
43
  params: [left_operand, right_operand]
40
44
  aliases: ["sub", "subtract"]
41
45
 
42
- - id: core.mul
46
+ - id: core.mul:numeric
43
47
  kind: elementwise
44
- params: [{ name: left_operand }, { name: right_operand }]
48
+ params:
49
+ - { name: left_operand, dtype: numeric }
50
+ - { name: right_operand, dtype: numeric }
45
51
  dtype:
46
52
  rule: promote
47
53
  params: [left_operand, right_operand]
@@ -63,9 +69,21 @@ functions:
63
69
  # For multiplication: divide by absolute values considering sign changes
64
70
  range: "derive from result bounds and operand bounds considering sign combinations"
65
71
 
72
+ - id: core.mul:string_repeat
73
+ kind: elementwise
74
+ params:
75
+ - { name: string_value, dtype: string }
76
+ - { name: repeat_count, dtype: integer }
77
+ dtype:
78
+ rule: scalar
79
+ kind: string
80
+ aliases: ["mul", "multiply"]
81
+
66
82
  - id: core.pow
67
83
  kind: elementwise
68
- params: [{ name: base }, { name: exponent }]
84
+ params:
85
+ - { name: base, dtype: numeric }
86
+ - { name: exponent, dtype: numeric }
69
87
  dtype:
70
88
  rule: promote
71
89
  params: [base, exponent]
@@ -73,7 +91,9 @@ functions:
73
91
 
74
92
  - id: core.div
75
93
  kind: elementwise
76
- params: [{ name: left_operand }, { name: right_operand }]
94
+ params:
95
+ - { name: left_operand, dtype: numeric }
96
+ - { name: right_operand, dtype: numeric }
77
97
  dtype:
78
98
  rule: scalar
79
99
  kind: float
@@ -82,8 +102,8 @@ functions:
82
102
  - id: core.mod
83
103
  kind: elementwise
84
104
  params:
85
- - { name: left_operand }
86
- - { name: right_operand }
105
+ - { name: left_operand, dtype: numeric }
106
+ - { name: right_operand, dtype: numeric }
87
107
  dtype:
88
108
  rule: promote
89
109
  params: [left_operand, right_operand]
@@ -1,7 +1,9 @@
1
1
  functions:
2
2
  - id: core.and
3
3
  kind: elementwise
4
- params: [{ name: left_operand }, { name: right_operand }]
4
+ params:
5
+ - { name: left_operand, dtype: boolean }
6
+ - { name: right_operand, dtype: boolean }
5
7
  dtype:
6
8
  rule: scalar
7
9
  kind: boolean
@@ -9,7 +11,9 @@ functions:
9
11
 
10
12
  - id: core.or
11
13
  kind: elementwise
12
- params: [{ name: left_operand }, { name: right_operand }]
14
+ params:
15
+ - { name: left_operand, dtype: boolean }
16
+ - { name: right_operand, dtype: boolean }
13
17
  dtype:
14
18
  rule: scalar
15
19
  kind: boolean
@@ -17,7 +21,8 @@ functions:
17
21
 
18
22
  - id: core.not
19
23
  kind: elementwise
20
- params: [{ name: operand }]
24
+ params:
25
+ - { name: operand, dtype: boolean }
21
26
  dtype:
22
27
  rule: scalar
23
28
  kind: boolean
@@ -1,7 +1,9 @@
1
1
  functions:
2
2
  - id: core.gte
3
3
  kind: elementwise
4
- params: [{ name: left_operand }, { name: right_operand }]
4
+ params:
5
+ - { name: left_operand, dtype: orderable }
6
+ - { name: right_operand, dtype: orderable }
5
7
  dtype:
6
8
  rule: scalar
7
9
  kind: boolean
@@ -10,7 +12,9 @@ functions:
10
12
 
11
13
  - id: core.gt
12
14
  kind: elementwise
13
- params: [{ name: left_operand }, { name: right_operand }]
15
+ params:
16
+ - { name: left_operand, dtype: orderable }
17
+ - { name: right_operand, dtype: orderable }
14
18
  dtype:
15
19
  rule: scalar
16
20
  kind: boolean
@@ -19,7 +23,9 @@ functions:
19
23
 
20
24
  - id: core.lte
21
25
  kind: elementwise
22
- params: [{ name: left_operand }, { name: right_operand }]
26
+ params:
27
+ - { name: left_operand, dtype: orderable }
28
+ - { name: right_operand, dtype: orderable }
23
29
  dtype:
24
30
  rule: scalar
25
31
  kind: boolean
@@ -28,7 +34,9 @@ functions:
28
34
 
29
35
  - id: core.lt
30
36
  kind: elementwise
31
- params: [{ name: left_operand }, { name: right_operand }]
37
+ params:
38
+ - { name: left_operand, dtype: orderable }
39
+ - { name: right_operand, dtype: orderable }
32
40
  dtype:
33
41
  rule: scalar
34
42
  kind: boolean
@@ -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"]
@@ -15,10 +15,14 @@ kernels:
15
15
  fn: core.sub
16
16
  inline: "= $0 - $1"
17
17
 
18
- - id: mul:javascript:v1
19
- fn: core.mul
18
+ - id: mul:numeric:javascript:v1
19
+ fn: core.mul:numeric
20
20
  inline: "= $0 * $1"
21
21
 
22
+ - id: mul:string_repeat:javascript:v1
23
+ fn: core.mul:string_repeat
24
+ inline: "= $0.repeat($1)"
25
+
22
26
  - id: pow:javascript:v1
23
27
  fn: core.pow
24
28
  inline: "= Math.pow($0, $1)"
@@ -0,0 +1,20 @@
1
+ kernels:
2
+ - id: to_decimal:javascript:v1
3
+ fn: core.to_decimal
4
+ inline: "= typeof $0 === 'string' ? parseFloat($0) : Number($0)"
5
+ impl: "(value) {\n if (typeof value === 'string') return parseFloat(value);\n return Number(value);\n}"
6
+
7
+ - id: to_integer:javascript:v1
8
+ fn: core.to_integer
9
+ inline: "= parseInt($0)"
10
+ impl: "(value) { return parseInt(value); }"
11
+
12
+ - id: to_float:javascript:v1
13
+ fn: core.to_float
14
+ inline: "= parseFloat($0)"
15
+ impl: "(value) { return parseFloat(value); }"
16
+
17
+ - id: to_string:javascript:v1
18
+ fn: core.to_string
19
+ inline: "= String($0)"
20
+ impl: "(value) { return String(value); }"
@@ -17,11 +17,16 @@ kernels:
17
17
  inline: "= $0 - $1"
18
18
  impl: "(a, b)\n a - b"
19
19
 
20
- - id: mul:ruby:v1
21
- fn: core.mul
20
+ - id: mul:numeric:ruby:v1
21
+ fn: core.mul:numeric
22
22
  inline: "= $0 * $1"
23
23
  impl: "(a, b)\n a * b"
24
24
 
25
+ - id: mul:string_repeat:ruby:v1
26
+ fn: core.mul:string_repeat
27
+ inline: "= $0 * $1"
28
+ impl: "(str, count)\n str * count"
29
+
25
30
  - id: pow:ruby:v1
26
31
  fn: core.pow
27
32
  inline: "= $0 ** $1"
@@ -0,0 +1,20 @@
1
+ kernels:
2
+ - id: to_decimal:ruby:v1
3
+ fn: core.to_decimal
4
+ inline: "= $0.is_a?(BigDecimal) ? $0 : BigDecimal($0.to_s)"
5
+ impl: "(value)\n case value\n when BigDecimal then value\n when String then BigDecimal(value)\n when Numeric then BigDecimal(value.to_s)\n else raise TypeError, \"Cannot coerce #{value.class} to Decimal\"\n end"
6
+
7
+ - id: to_integer:ruby:v1
8
+ fn: core.to_integer
9
+ inline: "= $0.to_i"
10
+ impl: "(value)\n value.to_i"
11
+
12
+ - id: to_float:ruby:v1
13
+ fn: core.to_float
14
+ inline: "= $0.to_f"
15
+ impl: "(value)\n value.to_f"
16
+
17
+ - id: to_string:ruby:v1
18
+ fn: core.to_string
19
+ inline: "= $0.to_s"
20
+ impl: "(value)\n value.to_s"
@@ -0,0 +1,277 @@
1
+ # Kumi Documentation & IDE Architecture
2
+
3
+ ## Overview
4
+
5
+ This document describes the automatic documentation generation system and IDE support infrastructure for Kumi functions and kernels.
6
+
7
+ ## System Architecture
8
+
9
+ ```
10
+ ┌─────────────────────────────────────┐
11
+ │ Function & Kernel Definitions │
12
+ ├─────────────────────────────────────┤
13
+ │ data/functions/*.yaml │
14
+ │ data/kernels/**/*.yaml │
15
+ └──────────────┬──────────────────────┘
16
+
17
+ ┌──────▼──────┐
18
+ │ bin/kumi- │
19
+ │ doc-gen │
20
+ └──────┬──────┘
21
+
22
+ ┌────────┴────────┐
23
+ │ │
24
+ ┌──▼───┐ ┌─────▼──────┐
25
+ │ JSON │ │ Markdown │
26
+ │ Data │ │ Reference │
27
+ └──┬───┘ └─────┬──────┘
28
+ │ │
29
+ ┌───▼──────────┐ ┌───▼─────────────────┐
30
+ │ IDE Tools │ │ Developers/Docs │
31
+ ├──────────────┤ ├─────────────────────┤
32
+ │ VSCode │ │ docs/FUNCTIONS.md │
33
+ │ Monaco │ │ GitHub Reference │
34
+ │ LSP Servers │ │ API Documentation │
35
+ └──────────────┘ └─────────────────────┘
36
+ ```
37
+
38
+ ## Core Components
39
+
40
+ ### 1. Data Sources
41
+
42
+ **Function Definitions** (`data/functions/*.yaml`)
43
+ ```yaml
44
+ functions:
45
+ - id: agg.sum
46
+ kind: reduce
47
+ params: [{ name: source_value }]
48
+ dtype: { rule: same_as, param: source_value }
49
+ reduction_strategy: identity # KEY: Identity-based reducer
50
+ aliases: ["sum"]
51
+
52
+ - id: agg.min
53
+ kind: reduce
54
+ params: [{ name: source_value }]
55
+ dtype: { rule: element_of, param: source_value }
56
+ reduction_strategy: first_element # KEY: First-element reducer
57
+ aliases: ["min"]
58
+ ```
59
+
60
+ **Kernel Implementations** (`data/kernels/ruby/*.yaml`)
61
+ ```yaml
62
+ kernels:
63
+ - id: agg.sum:ruby:v1
64
+ fn: agg.sum
65
+ inline: "+= $1"
66
+ impl: "(a,b)\n a + b"
67
+ fold_inline: "= $0.sum"
68
+ identity:
69
+ float: 0.0
70
+ integer: 0
71
+ ```
72
+
73
+ ### 2. Doc Generator Module
74
+
75
+ **Location:** `lib/kumi/doc_generator/`
76
+
77
+ #### Loader
78
+ - Parses YAML files from `data/functions/` and `data/kernels/`
79
+ - Returns raw function and kernel definitions
80
+ - No transformation or filtering
81
+
82
+ #### Merger
83
+ - Combines function definitions with kernel implementations
84
+ - Creates entries indexed by function aliases (so `sum`, `add`, `sub` all resolvable)
85
+ - Extracts important metadata:
86
+ - `reduction_strategy` - How the reducer initializes
87
+ - `dtype` - Type inference rules
88
+ - `arity` - Parameter count
89
+ - `kernels` - Available implementations
90
+
91
+ #### Formatters
92
+
93
+ **Json Formatter**
94
+ - Output: `docs/functions-reference.json`
95
+ - Consumer: IDE plugins (VSCode, Monaco, etc.)
96
+ - Data:
97
+ - Function ID and aliases
98
+ - Arity and parameter info
99
+ - Type information
100
+ - Kernel availability
101
+ - **Reduction strategy** (for reducer distinction)
102
+
103
+ **Markdown Formatter**
104
+ - Output: `docs/FUNCTIONS.md`
105
+ - Consumer: Developers, documentation sites
106
+ - Presentation:
107
+ - Human-readable function descriptions
108
+ - Inline operations (`$0 = accumulator, $1 = element`)
109
+ - Actual implementation code
110
+ - Fold strategies
111
+ - Identity values (when applicable)
112
+ - **Reduction semantics** (monoid vs first-element)
113
+
114
+ ### 3. VSCode Extension
115
+
116
+ **Location:** `vscode-extension/`
117
+
118
+ **Features:**
119
+ - Autocomplete for functions when typing `fn(:`
120
+ - Hover tooltips with signatures
121
+ - Schema block context detection (Ruby files only)
122
+ - Works with `.kumi` and `.rb` files
123
+
124
+ **Components:**
125
+ - `FunctionCompletionProvider` - Offers suggestions
126
+ - `FunctionHoverProvider` - Shows detailed information
127
+ - `isInSchemaBlock()` - Detects if inside `schema do...end` block (Ruby files)
128
+
129
+ ## Key Design Decisions
130
+
131
+ ### 1. Reduction Strategy Distinction
132
+
133
+ **Problem:** Min/Max don't have identity values like Sum/Count do.
134
+
135
+ **Solution:** Capture `reduction_strategy` from YAML:
136
+ - `identity` → Monoid operation, can use identity element
137
+ - `first_element` → First array element initializes accumulator
138
+
139
+ **Display:**
140
+ - Markdown shows: "Monoid operation with identity element" or "First element is initial value"
141
+ - JSON includes: `"reduction_strategy": "identity" | "first_element"`
142
+
143
+ ### 2. Kernel Implementation Visibility
144
+
145
+ **Decision:** Show actual kernel code inline in markdown.
146
+
147
+ **Benefits:**
148
+ - Developers see what the function actually does
149
+ - Inline operations (`+= $1` vs `= $1 if $1 < $0`) show the pattern
150
+ - Implementation code is actual Ruby/JavaScript
151
+
152
+ **Format:**
153
+ ```markdown
154
+ **Inline:** `+= $1` ($0 = accumulator, $1 = element)
155
+ **Implementation:**
156
+ ```ruby
157
+ (a,b)
158
+ a + b
159
+ ```
160
+ **Fold:** `= $0.sum`
161
+ **Identity:** float: 0.0, integer: 0
162
+ ```
163
+
164
+ ### 3. Single Source of Truth
165
+
166
+ **Flow:**
167
+ ```
168
+ YAML definitions
169
+
170
+ bin/kumi-doc-gen (one command)
171
+
172
+ ├→ docs/FUNCTIONS.md (auto-generated)
173
+ ├→ docs/functions-reference.json (auto-generated)
174
+ └→ IDE/Tools consume JSON
175
+ ```
176
+
177
+ Changes to function definitions automatically flow to:
178
+ - IDE completions
179
+ - Markdown reference
180
+ - JSON API
181
+
182
+ ### 4. Context-Aware IDE Support
183
+
184
+ **Ruby files:** Only offer completions inside `schema do...end` blocks
185
+ - Prevents noise from unrelated `fn(:` calls
186
+ - Tracks brace nesting to detect context
187
+
188
+ **Kumi files:** Always available
189
+ - Native language file type
190
+
191
+ ## Data Model
192
+
193
+ ### Function Entry (After Merge)
194
+ ```json
195
+ {
196
+ "id": "agg.sum",
197
+ "kind": "reduce",
198
+ "arity": 1,
199
+ "params": [{ "name": "source_value" }],
200
+ "dtype": { "rule": "same_as", "param": "source_value" },
201
+ "aliases": ["sum"],
202
+ "reduction_strategy": "identity",
203
+ "kernels": {
204
+ "ruby": {
205
+ "id": "agg.sum:ruby:v1",
206
+ "inline": "+= $1",
207
+ "impl": "(a,b)\n a + b",
208
+ "fold_inline": "= $0.sum",
209
+ "identity": { "float": 0.0, "integer": 0 }
210
+ }
211
+ }
212
+ }
213
+ ```
214
+
215
+ ## Usage Workflows
216
+
217
+ ### For End Users
218
+
219
+ **View function reference:**
220
+ ```bash
221
+ # Markdown documentation
222
+ open docs/FUNCTIONS.md
223
+
224
+ # IDE support (VSCode)
225
+ cd vscode-extension && npm install && npm run compile
226
+ # Press F5 in VSCode
227
+ ```
228
+
229
+ ### For Developers
230
+
231
+ **Modify functions:**
232
+ 1. Update `data/functions/category/*.yaml`
233
+ 2. Run `bin/kumi-doc-gen`
234
+ 3. Commit both YAML and generated files
235
+
236
+ **Add new reducer:**
237
+ ```yaml
238
+ - id: agg.product
239
+ kind: reduce
240
+ params: [{ name: source_value }]
241
+ reduction_strategy: identity
242
+ aliases: ["product"]
243
+ ```
244
+ Add kernel in `data/kernels/ruby/agg/numeric.yaml`, then regenerate docs.
245
+
246
+ ## Extension Points
247
+
248
+ The architecture supports adding:
249
+
250
+ 1. **New formatters** (HTML, PDF, LSP protocol)
251
+ 2. **New generators** (TypeScript definitions, GraphQL schema)
252
+ 3. **New IDE support** (Neovim, Emacs plugins via LSP)
253
+ 4. **Validation** (against declared types/arity)
254
+
255
+ All through the same YAML source data.
256
+
257
+ ## Testing
258
+
259
+ - 8 comprehensive tests for doc generation
260
+ - All 944 existing Kumi tests pass
261
+ - No regression in core functionality
262
+
263
+ ## Performance
264
+
265
+ - **Generation time:** <100ms for all functions
266
+ - **File sizes:**
267
+ - FUNCTIONS.md: ~950 lines
268
+ - functions-reference.json: ~1800 lines
269
+ - **IDE load time:** Instant (JSON loaded once on activation)
270
+
271
+ ## Future Improvements
272
+
273
+ 1. **LSP Server**: Standalone language server for any editor
274
+ 2. **Type validation**: Check function call arity at compile time
275
+ 3. **IDE diagnostics**: Show type mismatches as you type
276
+ 4. **Documentation linking**: Cross-reference related functions
277
+ 5. **Kernel visualization**: Show kernel implementations side-by-side