kumi 0.0.21 → 0.0.23

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1a372c01f8e35d9342f5a3464e1b4b2911b99c286bb244aab11049bcf1190266
4
- data.tar.gz: 8f7640952006b57ea0e16e6a4237309244c913370443d3ecf641da15ade5eb5c
3
+ metadata.gz: fb114ffa6a4c06a4a5c517757ba3030043095e62b54e15b206989cdcd10329fd
4
+ data.tar.gz: db8aa5df3fec33213cb27478523b24d3f94812b55e59ba5c39105f5ec1ae9a21
5
5
  SHA512:
6
- metadata.gz: c832c97b0b4c1888a46aae7130feef16da2ecfabb270dc14025f855e102b5d36961ca75b8a205bb496d8cb638454f2a1d3c022bd5b8d80885de9b33b9815360c
7
- data.tar.gz: 5f254ea25bcd5f38f333c1e0db71d01786cd0e25a66b332ac5b63d22c30877c72a772ca47bd6ceadebf6915db083d91ae5d63fbb6e49bde1864b7a5d150feb43
6
+ metadata.gz: d4af4d0d9406226983cf67d4cdf22b366fb01588c977cca449bbd221c5c25a633f04f98f0b9982c44228c526b452306a4c374cac823972581d9e0f4d7c368870
7
+ data.tar.gz: 73cf1f508cf9501177b80014bbf28c111979057191bc4643a2749339dabe85dcdee46e202825ec285a378b301540d23aa67d7d4ff39e343a7c5f833c62b6d199
data/CHANGELOG.md CHANGED
@@ -1,4 +1,14 @@
1
1
  ## [Unreleased]
2
+
3
+ ## [0.0.23] – 2025-10-13
4
+ ### Fixed
5
+ - OutputSchemaPass now excludes inline `:let` declarations from output_schema metadata, matching JS/Ruby codegen behavior
6
+
7
+ ## [0.0.22] – 2025-10-13
8
+ ### Removed
9
+ - Legacy analyzer passes and compiler components referencing old Registry and Runtime APIs
10
+ - Obsolete test files that depended on removed infrastructure
11
+
2
12
  ## [0.0.21] – 2025-10-13
3
13
  Fix - update Gemfile.lock to current version
4
14
 
data/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  [![CI](https://github.com/amuta/kumi/workflows/CI/badge.svg)](https://github.com/amuta/kumi/actions)
4
4
  [![Gem Version](https://badge.fury.io/rb/kumi.svg)](https://badge.fury.io/rb/kumi)
5
5
 
6
+ **[Try the interactive demo →](https://kumi-play.example.com)**
6
7
 
7
8
  ---
8
9
 
@@ -13,23 +14,15 @@
13
14
  ---
14
15
 
15
16
 
16
- Kumi is a **declarative calculation DSL for Ruby**. You write business rules once; Kumi:
17
+ **Declarative calculation DSL for Ruby.** Write business rules once, run them anywhere.
17
18
 
18
- - Builds a **typed dependency graph** with vector semantics.
19
- - Performs **static validation** at definition time.
20
- - Lowers to a **portable Low-level IR (LIR)**.
21
- - Code-generates standalone **Ruby** and **JavaScript**.
19
+ Kumi compiles high-level schemas into standalone Ruby and JavaScript with no runtime dependencies.
22
20
 
23
- Targets: finance, tax, pricing, insurance, payroll, analytics—domains where **correctness, transparency, and reproducibility** matter.
21
+ **Built for:** finance, tax, pricing, insurance, payroll, analytics—domains where correctness and transparency matter.
24
22
 
25
23
  ---
26
24
 
27
- ## Codegen: Currently Ruby and JavaScript
28
-
29
- *Note: this is not available on the last published gem version (0.0.18), but if you clone this repository you can just copy a ./golden/$schema_name and modify schema.kumi as you and run bin/kumi golden test $schema_name*
30
-
31
-
32
- Kumi emits the kernel for your schema with no runtime in the target language. You can use it within your ruby application backend and/or export to the client.
25
+ ## Example: Conway's Game of Life
33
26
 
34
27
 
35
28
  <details>
@@ -78,114 +71,39 @@ end
78
71
 
79
72
  </details>
80
73
 
81
- <details>
82
- <summary><strong>Optimized LIR (lowered IR)</strong></summary>
83
-
84
- ```bash
85
- # ...
86
- (Declaration next_state
87
- %t285 = load_input "rows" :: array
88
- %t1539 = Length %t285 :: integer
89
- %t1540 = const -1 :: integer
90
- %t1542 = const 0 :: integer
91
- %t1546 = const 1 :: integer
92
- %t1334 = const 3 :: integer
93
- %t1339 = const 2 :: integer
94
- %t1547 = call core.sub(%t1539, %t1546) :: integer
95
- loop rows id=L31 in %t285 as el=%rows_el_286, idx=%rows_i_287
96
- %t1541 = call core.sub(%rows_i_287, %t1540) :: integer
97
- %t1561 = call core.sub(%rows_i_287, %t1546) :: integer
98
- %t1580 = call core.mod(%rows_i_287, %t1539) :: integer
99
- # ...
100
- ```
101
-
102
- </details>
103
-
104
- <details>
105
- <summary><strong>Generated Ruby (excerpt)</strong></summary>
106
-
107
- ```ruby
108
- # Autogenerated by Kumi Codegen
109
- module Kumi::Compiled::KUMI_bd17a3ebee1bec4e58b72118d43e8c1c93bf773f257fc93d9c32a783d212ea4f
110
- def self.from(input_data = nil)
111
- instance = Object.new
112
- instance.extend(self)
113
- instance.instance_variable_set(:@input, input_data)
114
- instance
115
- end
116
-
117
- def self.__kumi_executable__
118
- instance = Object.new
119
- instance.extend(self)
120
- instance
121
- end
122
-
123
- def update(input_data)
124
- @input = @input.merge(input_data)
125
- self
126
- end
127
-
128
- def [](name)
129
- case name
130
- when :next_state then _next_state
131
- else raise KeyError, "Unknown declaration"
132
- end
133
- end
134
-
135
- def _next_state(input = @input)
136
- out = []
137
- t285 = input["rows"] || input[:rows]
138
- t1539 = t285.length
139
- t1540 = -1
140
- t1542 = 0
141
- t1546 = 1
142
- t1334 = 3
143
- t1339 = 2
144
- t1547 = t1539 - t1546
145
- t285.each_with_index do |rows_el_286, rows_i_287|
146
- out_1 = []
147
- t1541 = rows_i_287 - t1540
148
- t1561 = rows_i_287 - t1546
149
- t1580 = rows_i_287 % t1539
150
- t1543 = t1541 >= t1542
151
- t1544 = t1541 < t1539
152
- t1549 = [[ t1541, t1542 ].max, t1547 ].min
153
- t1563 = t1561 >= t1542
154
- # ...
155
- ```
156
-
157
- </details>
158
74
 
159
75
  <details>
160
76
  <summary><strong>Generated JavaScript (excerpt)</strong></summary>
161
77
 
162
78
  ```js
163
- export class KumiCompiledModule {
164
- _next_state(input) {
165
- let out = [];
166
- let t285 = input["rows"];
167
- let t1539 = t285.length
168
- const t1540 = -1;
169
- const t1542 = 0;
170
- const t1546 = 1;
171
- const t1334 = 3;
172
- const t1339 = 2;
173
- let t1547 = t1539 - t1546;
174
- t285.forEach((rows_el_286, rows_i_287) => {
175
- let out_1 = [];
176
- let t1541 = rows_i_287 - t1540;
177
- let t1561 = rows_i_287 - t1546;
178
- let t1580 = ((rows_i_287 % t1539) + t1539) % t1539;
179
- let t1543 = t1541 >= t1542;
180
- let t1544 = t1541 < t1539;
181
- let t1549 = Math.min(Math.max(t1541, t1542), t1547);
182
- let t1563 = t1561 >= t1542;
183
- let t1564 = t1561 < t1539;
184
- let t1569 = Math.min(Math.max(t1561, t1542), t1547);
185
- let t1581 = t1580 + t1539;
186
- let t1545 = t1543 && t1544;
187
- let t1550 = t285[t1549]
188
- // ...
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
+ }
189
107
  ```
190
108
 
191
109
  </details>
@@ -200,6 +118,32 @@ gem install kumi
200
118
 
201
119
  Requires Ruby 3.1+. No external dependencies.
202
120
 
121
+ ## Quick Start
122
+
123
+ ```ruby
124
+ require 'kumi'
125
+
126
+ Kumi.configure do |config|
127
+ config.compilation_mode = :jit
128
+ end
129
+
130
+ module Double
131
+ extend Kumi::Schema
132
+
133
+ schema do
134
+ input { integer :x }
135
+ value :doubled, input.x * 2
136
+ end
137
+ end
138
+
139
+ # Execute in Ruby
140
+ result = Double.from(x: 5)
141
+ result[:doubled] # => 10
142
+
143
+ # Export to JavaScript
144
+ Double.write_source("output.mjs", platform: :javascript)
145
+ ```
146
+
203
147
  ---
204
148
 
205
149
  ## License
@@ -9,15 +9,17 @@ module Kumi
9
9
  snast_module = get_state(:snast_module)
10
10
  return state unless snast_module
11
11
 
12
- output_schema = build_output_schema(snast_module)
12
+ hints = get_state(:hints)
13
+ output_schema = build_output_schema(snast_module, hints)
13
14
  state.with(:output_schema, output_schema.freeze)
14
15
  end
15
16
 
16
17
  private
17
18
 
18
- def build_output_schema(snast_module)
19
- snast_module.decls.transform_values do |decl|
20
- build_output_field(decl)
19
+ def build_output_schema(snast_module, hints)
20
+ snast_module.decls.each_with_object({}) do |(name, decl), acc|
21
+ next if hints[name][:inline]
22
+ acc[name] = build_output_field(decl)
21
23
  end
22
24
  end
23
25
 
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kumi
4
+ module Core
5
+ module Functions
6
+ # Minimal function specification for NAST dimensional analysis
7
+ FunctionSpec = Struct.new(
8
+ :id, # "core.add"
9
+ :kind, # :elementwise, :reduce, :constructor
10
+ :parameter_names, # [:left_operand, :right_operand]
11
+ :dtype_rule, # "promote(left_operand,right_operand)" or proc
12
+ keyword_init: true
13
+ )
14
+ end
15
+ end
16
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "yaml"
4
- require_relative "model"
4
+ require_relative "function_spec"
5
5
  require_relative "type_rules"
6
6
 
7
7
  module Kumi
@@ -34,7 +34,7 @@ module Kumi
34
34
  parameter_names = (fn_hash["params"] || []).map { |p| p["name"].to_sym }
35
35
  dtype_rule_fn = TypeRules.compile_dtype_rule(fn_hash.fetch("dtype"), parameter_names)
36
36
 
37
- FunctionSpec.new(
37
+ Functions::FunctionSpec.new(
38
38
  id: function_id,
39
39
  kind: function_kind,
40
40
  parameter_names: parameter_names,
data/lib/kumi/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kumi
4
- VERSION = "0.0.21"
4
+ VERSION = "0.0.23"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kumi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.21
4
+ version: 0.0.23
5
5
  platform: ruby
6
6
  authors:
7
7
  - André Muta
@@ -537,7 +537,6 @@ files:
537
537
  - golden/with_constants/schema.kumi
538
538
  - lib/kumi.rb
539
539
  - lib/kumi/analyzer.rb
540
- - lib/kumi/compiler.rb
541
540
  - lib/kumi/configuration.rb
542
541
  - lib/kumi/core/analyzer/analysis_state.rb
543
542
  - lib/kumi/core/analyzer/binder.rb
@@ -551,7 +550,6 @@ files:
551
550
  - lib/kumi/core/analyzer/passes/assemble_irv2_pass.rb
552
551
  - lib/kumi/core/analyzer/passes/attach_anchors_pass.rb
553
552
  - lib/kumi/core/analyzer/passes/attach_terminal_info_pass.rb
554
- - lib/kumi/core/analyzer/passes/broadcast_detector.rb
555
553
  - lib/kumi/core/analyzer/passes/codegen/js/declaration_emitter.rb
556
554
  - lib/kumi/core/analyzer/passes/codegen/js/emitter.rb
557
555
  - lib/kumi/core/analyzer/passes/codegen/js/output_buffer.rb
@@ -583,7 +581,6 @@ files:
583
581
  - lib/kumi/core/analyzer/passes/lir/stencil_emitter.rb
584
582
  - lib/kumi/core/analyzer/passes/lir/validation_pass.rb
585
583
  - lib/kumi/core/analyzer/passes/load_input_cse.rb
586
- - lib/kumi/core/analyzer/passes/lower_to_ir_pass.rb
587
584
  - lib/kumi/core/analyzer/passes/lower_to_irv2_pass.rb
588
585
  - lib/kumi/core/analyzer/passes/name_indexer.rb
589
586
  - lib/kumi/core/analyzer/passes/nast_dimensional_analyzer_pass.rb
@@ -591,12 +588,9 @@ files:
591
588
  - lib/kumi/core/analyzer/passes/output_schema_pass.rb
592
589
  - lib/kumi/core/analyzer/passes/pass_base.rb
593
590
  - lib/kumi/core/analyzer/passes/precompute_access_paths_pass.rb
594
- - lib/kumi/core/analyzer/passes/scope_resolution_pass.rb
595
591
  - lib/kumi/core/analyzer/passes/semantic_constraint_validator.rb
596
592
  - lib/kumi/core/analyzer/passes/snast_pass.rb
597
593
  - lib/kumi/core/analyzer/passes/toposorter.rb
598
- - lib/kumi/core/analyzer/passes/type_checker.rb
599
- - lib/kumi/core/analyzer/passes/type_inferencer_pass.rb
600
594
  - lib/kumi/core/analyzer/passes/unsat_detector.rb
601
595
  - lib/kumi/core/analyzer/passes/visitor_pass.rb
602
596
  - lib/kumi/core/analyzer/plans.rb
@@ -619,7 +613,6 @@ files:
619
613
  - lib/kumi/core/compiler/accessors/materialize_accessor.rb
620
614
  - lib/kumi/core/compiler/accessors/ravel_accessor.rb
621
615
  - lib/kumi/core/compiler/accessors/read_accessor.rb
622
- - lib/kumi/core/compiler_base.rb
623
616
  - lib/kumi/core/constraint_relationship_solver.rb
624
617
  - lib/kumi/core/domain/enum_analyzer.rb
625
618
  - lib/kumi/core/domain/range_analyzer.rb
@@ -628,7 +621,6 @@ files:
628
621
  - lib/kumi/core/error_reporter.rb
629
622
  - lib/kumi/core/error_reporting.rb
630
623
  - lib/kumi/core/errors.rb
631
- - lib/kumi/core/explain.rb
632
624
  - lib/kumi/core/export.rb
633
625
  - lib/kumi/core/export/deserializer.rb
634
626
  - lib/kumi/core/export/errors.rb
@@ -636,8 +628,8 @@ files:
636
628
  - lib/kumi/core/export/node_registry.rb
637
629
  - lib/kumi/core/export/node_serializers.rb
638
630
  - lib/kumi/core/export/serializer.rb
631
+ - lib/kumi/core/functions/function_spec.rb
639
632
  - lib/kumi/core/functions/loader.rb
640
- - lib/kumi/core/functions/model.rb
641
633
  - lib/kumi/core/functions/type_rules.rb
642
634
  - lib/kumi/core/input/type_matcher.rb
643
635
  - lib/kumi/core/input/validator.rb
@@ -716,7 +708,6 @@ files:
716
708
  - lib/kumi/registry_v2.rb
717
709
  - lib/kumi/registry_v2/loader.rb
718
710
  - lib/kumi/schema.rb
719
- - lib/kumi/schema_metadata.rb
720
711
  - lib/kumi/support/diff.rb
721
712
  - lib/kumi/support/ir_render.rb
722
713
  - lib/kumi/support/lir_printer.rb
data/lib/kumi/compiler.rb DELETED
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Kumi
4
- # Compiles an analyzed schema into executable lambdas
5
- class Compiler < Core::CompilerBase
6
- def self.compile(schema, analyzer:, schema_name: nil)
7
- new(schema, analyzer, schema_name: schema_name).compile
8
- end
9
-
10
- def initialize(schema, analyzer, schema_name: nil)
11
- super(schema, analyzer)
12
- @bindings = {}
13
- @schema_name = schema_name
14
- end
15
-
16
- def compile
17
- # Switch to LIR: Use the analysis state instead of old compilation
18
- Runtime::Executable.from_analysis(@analysis.state, schema_name: @schema_name)
19
- end
20
- end
21
- end