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
data/docs/SYNTAX.md CHANGED
@@ -17,6 +17,7 @@ end
17
17
  ```kumi
18
18
  integer # Integer numbers
19
19
  float # Floating point numbers
20
+ decimal # Precise decimal numbers (money, bignum calculations)
20
21
  string # Text strings
21
22
  array # Sequential collections
22
23
  hash # Structured objects
@@ -58,6 +59,12 @@ trait :name, expr # Boolean mask
58
59
  - `fn(:abs, x)` — Absolute value
59
60
  - `fn(:clamp, x, lo, hi)` — Clamp to range
60
61
 
62
+ **Type Conversion:**
63
+ - `fn(:to_decimal, x)` — Convert to decimal
64
+ - `fn(:to_integer, x)` — Convert to integer
65
+ - `fn(:to_float, x)` — Convert to float
66
+ - `fn(:to_string, x)` — Convert to string
67
+
61
68
  **String:**
62
69
  - `fn(:concat, s1, s2)` — Concatenate strings
63
70
  - `fn(:upcase, str)` — Convert to uppercase
@@ -140,6 +147,7 @@ Scalar inputs represent single values:
140
147
  input do
141
148
  integer :x
142
149
  float :rate
150
+ decimal :price # Precise decimal for money calculations
143
151
  string :name
144
152
  end
145
153
  ```
@@ -0,0 +1,83 @@
1
+ # UNSAT Detection & Constraint Analysis
2
+
3
+ Kumi includes static analysis to detect **unsatisfiable constraints**—impossible conditions that can never be true given input domains.
4
+
5
+ ## How It Works
6
+
7
+ ### Direct Contradictions
8
+ Kumi detects when the same variable is constrained to multiple different values:
9
+
10
+ ```ruby
11
+ schema do
12
+ input { integer :x }
13
+
14
+ # ✓ Detected as UNSAT: x cannot be both 5 and 10
15
+ trait :impossible, fn(:and, input.x == 5, input.x == 10)
16
+ end
17
+ ```
18
+
19
+ ### Domain Violations
20
+ Kumi checks when constraints violate input domains:
21
+
22
+ ```ruby
23
+ schema do
24
+ input { integer :age, domain: 0..150 }
25
+
26
+ # ✓ Detected as UNSAT: age can never be 200
27
+ trait :impossible_age, input.age == 200
28
+ end
29
+ ```
30
+
31
+ ### Constraint Propagation (Phase 2)
32
+ Kumi propagates constraints through operations to detect derived impossibilities:
33
+
34
+ ```ruby
35
+ schema do
36
+ input { integer :x, domain: 0..10 }
37
+
38
+ value :doubled, fn(:mul, input.x, 2) # doubled ∈ [0, 20]
39
+
40
+ # ✓ Detected as UNSAT: doubled can never be 50
41
+ trait :impossible_doubled, doubled == 50
42
+ end
43
+ ```
44
+
45
+ **Reverse propagation** derives input constraints from output constraints:
46
+
47
+ ```ruby
48
+ schema do
49
+ input { integer :x, domain: 0..10 }
50
+
51
+ value :result, fn(:add, input.x, 100) # result ∈ [100, 110]
52
+
53
+ # ✓ Detected as UNSAT: result == 50 would require x == -50 (outside domain)
54
+ trait :impossible_result, result == 50
55
+ end
56
+ ```
57
+
58
+ ## Error Messages
59
+
60
+ Impossible constraints raise `Kumi::Core::Errors::SemanticError`:
61
+
62
+ ```
63
+ conjunction `impossible_doubled` is impossible
64
+ ```
65
+
66
+ This message appears at schema compilation time, catching bugs before execution.
67
+
68
+ ## When UNSAT Detection Runs
69
+
70
+ UNSAT detection is performed during the **HIR-to-LIR compilation phase**, after:
71
+ - Function IDs are resolved
72
+ - Type information is inferred
73
+ - Dimensional metadata is computed
74
+
75
+ This ensures detection has access to complete operation semantics.
76
+
77
+ ## Future Enhancements
78
+
79
+ - **Multi-level propagation**: Chain constraints through multiple operations
80
+ - **Inequality constraints**: Handle `<`, `>`, `<=`, `>=` constraints
81
+ - **Combined constraints**: Detect contradictions across multiple traits
82
+
83
+ See `spec/integration/unsat_with_propagation_spec.rb` for examples and pending tests.
@@ -0,0 +1,114 @@
1
+ # VSCode Extension for Kumi
2
+
3
+ The `vscode-extension/` directory contains a VSCode extension that provides IDE support for Kumi functions using the auto-generated function reference.
4
+
5
+ ## What It Does
6
+
7
+ - **Autocomplete** - Suggest function names when typing `fn(:`
8
+ - **Hover Documentation** - Show function signatures, parameters, and types
9
+ - **Type Information** - Display type inference rules for each function
10
+ - **Arity Display** - Show parameter counts at a glance
11
+
12
+ ## Setup
13
+
14
+ ### 1. Build the Extension
15
+
16
+ ```bash
17
+ cd vscode-extension
18
+ npm install
19
+ npm run compile
20
+ ```
21
+
22
+ This generates JavaScript in `out/extension.js` from the TypeScript sources.
23
+
24
+ ### 2. Install in VSCode
25
+
26
+ **Option A: Load as Development Extension**
27
+
28
+ - Open the `vscode-extension` folder in VSCode
29
+ - Press `F5` to launch a debugging session
30
+ - The extension will activate automatically
31
+
32
+ **Option B: Package as VSIX**
33
+
34
+ ```bash
35
+ npm install -g vsce
36
+ vsce package
37
+ ```
38
+
39
+ Then install the generated `.vsix` file in VSCode via "Extensions: Install from VSIX"
40
+
41
+ ### 3. Generate Function Data
42
+
43
+ Before using the extension, ensure the function reference JSON is up-to-date:
44
+
45
+ ```bash
46
+ bin/kumi-doc-gen
47
+ ```
48
+
49
+ This creates `docs/functions-reference.json` which the extension reads.
50
+
51
+ ## Usage in VSCode
52
+
53
+ When editing Ruby files in a Kumi project:
54
+
55
+ ```ruby
56
+ # Start typing fn(: to get suggestions
57
+ fn(:add, x, y) # ← Autocomplete shows available functions
58
+
59
+ # Hover to see: core.add (arity: 2, type: promoted from left_operand, right_operand)
60
+
61
+ # Completions include:
62
+ # - add, sub, mul, div, pow (arithmetic)
63
+ # - sum, count, min, max, mean (aggregations)
64
+ # - ... and all other functions
65
+ ```
66
+
67
+ The extension provides:
68
+ - Full function name with backticks for easy identification
69
+ - Arity (parameter count)
70
+ - Type inference rules
71
+ - Parameter names
72
+ - Available kernel implementations
73
+
74
+ ## Data Flow
75
+
76
+ ```
77
+ data/functions/ (YAML)
78
+
79
+ bin/kumi-doc-gen
80
+
81
+ docs/functions-reference.json
82
+
83
+ vscode-extension/src/extension.ts
84
+
85
+ VSCode IDE features (autocomplete, hover, etc.)
86
+ ```
87
+
88
+ ## Development
89
+
90
+ To modify the extension:
91
+
92
+ 1. Edit `vscode-extension/src/extension.ts`
93
+ 2. Run `npm run watch` to auto-compile TypeScript
94
+ 3. Press `F5` in VSCode to reload the debugging session
95
+ 4. Test new features against the live extension
96
+
97
+ ## Limitations
98
+
99
+ Currently the extension:
100
+ - Only provides autocomplete after `fn(:`
101
+ - Only works with Ruby files
102
+ - Doesn't validate argument types at compile time
103
+ - Doesn't provide inline hints during parameter entry
104
+
105
+ These could be added as future enhancements!
106
+
107
+ ## Future Enhancements
108
+
109
+ - Parameter validation (type checking)
110
+ - Signature help (inline parameter hints)
111
+ - Go-to-definition for function implementations
112
+ - Diagnostics for arity mismatches
113
+ - Snippet expansion for common patterns
114
+ - LSP server for language-agnostic support