kumi 0.0.5 → 0.0.7
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 +4 -4
- data/CLAUDE.md +76 -174
- data/README.md +205 -52
- data/{documents → docs}/AST.md +29 -29
- data/{documents → docs}/SYNTAX.md +95 -8
- data/docs/features/README.md +45 -0
- data/docs/features/analysis-cascade-mutual-exclusion.md +89 -0
- data/docs/features/analysis-type-inference.md +42 -0
- data/docs/features/analysis-unsat-detection.md +71 -0
- data/docs/features/array-broadcasting.md +170 -0
- data/docs/features/input-declaration-system.md +42 -0
- data/docs/features/performance.md +16 -0
- data/docs/schema_metadata/broadcasts.md +53 -0
- data/docs/schema_metadata/cascades.md +45 -0
- data/docs/schema_metadata/declarations.md +54 -0
- data/docs/schema_metadata/dependencies.md +57 -0
- data/docs/schema_metadata/evaluation_order.md +29 -0
- data/docs/schema_metadata/examples.md +95 -0
- data/docs/schema_metadata/inferred_types.md +46 -0
- data/docs/schema_metadata/inputs.md +86 -0
- data/docs/schema_metadata.md +108 -0
- data/examples/federal_tax_calculator_2024.rb +11 -6
- data/lib/kumi/analyzer/constant_evaluator.rb +1 -1
- data/lib/kumi/analyzer/passes/broadcast_detector.rb +246 -0
- data/lib/kumi/analyzer/passes/{definition_validator.rb → declaration_validator.rb} +4 -4
- data/lib/kumi/analyzer/passes/dependency_resolver.rb +78 -38
- data/lib/kumi/analyzer/passes/input_collector.rb +91 -30
- data/lib/kumi/analyzer/passes/name_indexer.rb +2 -2
- data/lib/kumi/analyzer/passes/pass_base.rb +1 -1
- data/lib/kumi/analyzer/passes/semantic_constraint_validator.rb +24 -25
- data/lib/kumi/analyzer/passes/toposorter.rb +44 -8
- data/lib/kumi/analyzer/passes/type_checker.rb +34 -14
- data/lib/kumi/analyzer/passes/type_consistency_checker.rb +2 -2
- data/lib/kumi/analyzer/passes/type_inferencer.rb +130 -21
- data/lib/kumi/analyzer/passes/unsat_detector.rb +134 -56
- data/lib/kumi/analyzer/passes/visitor_pass.rb +2 -2
- data/lib/kumi/analyzer.rb +16 -17
- data/lib/kumi/compiler.rb +188 -16
- data/lib/kumi/constraint_relationship_solver.rb +6 -6
- data/lib/kumi/domain/validator.rb +0 -4
- data/lib/kumi/error_reporting.rb +1 -1
- data/lib/kumi/explain.rb +32 -20
- data/lib/kumi/export/node_registry.rb +26 -12
- data/lib/kumi/export/node_serializers.rb +1 -1
- data/lib/kumi/function_registry/collection_functions.rb +14 -9
- data/lib/kumi/function_registry/function_builder.rb +4 -3
- data/lib/kumi/function_registry.rb +8 -2
- data/lib/kumi/input/type_matcher.rb +3 -0
- data/lib/kumi/input/validator.rb +0 -3
- data/lib/kumi/json_schema/generator.rb +63 -0
- data/lib/kumi/json_schema/validator.rb +25 -0
- data/lib/kumi/json_schema.rb +14 -0
- data/lib/kumi/{parser → ruby_parser}/build_context.rb +1 -1
- data/lib/kumi/ruby_parser/declaration_reference_proxy.rb +36 -0
- data/lib/kumi/{parser → ruby_parser}/dsl.rb +1 -1
- data/lib/kumi/{parser → ruby_parser}/dsl_cascade_builder.rb +5 -5
- data/lib/kumi/{parser → ruby_parser}/expression_converter.rb +20 -20
- data/lib/kumi/{parser → ruby_parser}/guard_rails.rb +1 -1
- data/lib/kumi/{parser → ruby_parser}/input_builder.rb +41 -10
- data/lib/kumi/ruby_parser/input_field_proxy.rb +46 -0
- data/lib/kumi/{parser → ruby_parser}/input_proxy.rb +4 -4
- data/lib/kumi/ruby_parser/nested_input.rb +15 -0
- data/lib/kumi/{parser → ruby_parser}/parser.rb +11 -10
- data/lib/kumi/{parser → ruby_parser}/schema_builder.rb +11 -10
- data/lib/kumi/{parser → ruby_parser}/sugar.rb +62 -10
- data/lib/kumi/ruby_parser.rb +10 -0
- data/lib/kumi/schema.rb +10 -4
- data/lib/kumi/schema_instance.rb +6 -6
- data/lib/kumi/schema_metadata.rb +524 -0
- data/lib/kumi/syntax/array_expression.rb +15 -0
- data/lib/kumi/syntax/call_expression.rb +11 -0
- data/lib/kumi/syntax/cascade_expression.rb +11 -0
- data/lib/kumi/syntax/case_expression.rb +11 -0
- data/lib/kumi/syntax/declaration_reference.rb +11 -0
- data/lib/kumi/syntax/hash_expression.rb +11 -0
- data/lib/kumi/syntax/input_declaration.rb +12 -0
- data/lib/kumi/syntax/input_element_reference.rb +12 -0
- data/lib/kumi/syntax/input_reference.rb +12 -0
- data/lib/kumi/syntax/literal.rb +11 -0
- data/lib/kumi/syntax/trait_declaration.rb +11 -0
- data/lib/kumi/syntax/value_declaration.rb +11 -0
- data/lib/kumi/vectorization_metadata.rb +108 -0
- data/lib/kumi/version.rb +1 -1
- data/lib/kumi.rb +14 -0
- metadata +55 -25
- data/lib/generators/trait_engine/templates/schema_spec.rb.erb +0 -27
- data/lib/kumi/domain.rb +0 -8
- data/lib/kumi/input.rb +0 -8
- data/lib/kumi/syntax/declarations.rb +0 -26
- data/lib/kumi/syntax/expressions.rb +0 -34
- data/lib/kumi/syntax/terminal_expressions.rb +0 -30
- data/lib/kumi/syntax.rb +0 -9
- /data/{documents → docs}/DSL.md +0 -0
- /data/{documents → docs}/FUNCTIONS.md +0 -0
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kumi
|
4
|
+
# Metadata system for vectorization detection and handling
|
5
|
+
module VectorizationMetadata
|
6
|
+
# Tracks which declarations are arrays with children (vectorizable)
|
7
|
+
class ArrayDeclarationTracker
|
8
|
+
def initialize
|
9
|
+
@array_declarations = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def register_array(name, children)
|
13
|
+
@array_declarations[name] = children.map(&:name)
|
14
|
+
end
|
15
|
+
|
16
|
+
def array_declaration?(name)
|
17
|
+
@array_declarations.key?(name)
|
18
|
+
end
|
19
|
+
|
20
|
+
def array_children(name)
|
21
|
+
@array_declarations[name] || []
|
22
|
+
end
|
23
|
+
|
24
|
+
def all_arrays
|
25
|
+
@array_declarations.keys
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Detects vectorized operations in expressions
|
30
|
+
class VectorizationDetector
|
31
|
+
def initialize(array_tracker)
|
32
|
+
@array_tracker = array_tracker
|
33
|
+
end
|
34
|
+
|
35
|
+
# Check if an expression should be vectorized
|
36
|
+
def vectorized_expression?(expression)
|
37
|
+
case expression
|
38
|
+
when Kumi::Syntax::CallExpression
|
39
|
+
vectorized_call?(expression)
|
40
|
+
when Kumi::Syntax::InputElementReference
|
41
|
+
vectorized_element_reference?(expression)
|
42
|
+
else
|
43
|
+
false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Check if a function call should be treated as a reducer
|
48
|
+
def reducer_function?(fn_name, args)
|
49
|
+
REDUCER_FUNCTIONS.include?(fn_name) &&
|
50
|
+
args.any? { |arg| vectorized_expression?(arg) }
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
REDUCER_FUNCTIONS = %i[sum min max size length first last].freeze
|
56
|
+
|
57
|
+
def vectorized_call?(call_expr)
|
58
|
+
# Arithmetic operations between array elements are vectorized
|
59
|
+
ARITHMETIC_OPERATIONS.include?(call_expr.fn_name) &&
|
60
|
+
call_expr.args.any? { |arg| vectorized_expression?(arg) }
|
61
|
+
end
|
62
|
+
|
63
|
+
def vectorized_element_reference?(elem_ref)
|
64
|
+
return false unless elem_ref.path.size >= 2
|
65
|
+
|
66
|
+
array_name, _field_name = elem_ref.path
|
67
|
+
@array_tracker.array_declaration?(array_name)
|
68
|
+
end
|
69
|
+
|
70
|
+
ARITHMETIC_OPERATIONS = %i[add subtract multiply divide modulo power].freeze
|
71
|
+
end
|
72
|
+
|
73
|
+
# Metadata about how values should be computed
|
74
|
+
class ComputationMetadata
|
75
|
+
attr_reader :vectorized_values, :reducer_values, :scalar_values
|
76
|
+
|
77
|
+
def initialize
|
78
|
+
@vectorized_values = Set.new
|
79
|
+
@reducer_values = Set.new
|
80
|
+
@scalar_values = Set.new
|
81
|
+
end
|
82
|
+
|
83
|
+
def mark_vectorized(name)
|
84
|
+
@vectorized_values.add(name)
|
85
|
+
end
|
86
|
+
|
87
|
+
def mark_reducer(name)
|
88
|
+
@reducer_values.add(name)
|
89
|
+
end
|
90
|
+
|
91
|
+
def mark_scalar(name)
|
92
|
+
@scalar_values.add(name)
|
93
|
+
end
|
94
|
+
|
95
|
+
def vectorized?(name)
|
96
|
+
@vectorized_values.include?(name)
|
97
|
+
end
|
98
|
+
|
99
|
+
def reducer?(name)
|
100
|
+
@reducer_values.include?(name)
|
101
|
+
end
|
102
|
+
|
103
|
+
def scalar?(name)
|
104
|
+
@scalar_values.include?(name)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
data/lib/kumi/version.rb
CHANGED
data/lib/kumi.rb
CHANGED
@@ -9,4 +9,18 @@ loader.setup
|
|
9
9
|
|
10
10
|
module Kumi
|
11
11
|
extend Schema
|
12
|
+
|
13
|
+
def self.inspector_from_schema
|
14
|
+
Inspector.new(@__syntax_tree__, @__analyzer_result__, @__compiled_schema__)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.reset!
|
18
|
+
@__syntax_tree__ = nil
|
19
|
+
@__analyzer_result__ = nil
|
20
|
+
@__compiled_schema__ = nil
|
21
|
+
@__schema_metadata__ = nil
|
22
|
+
end
|
23
|
+
|
24
|
+
# Reset on require to avoid state leakage in tests
|
25
|
+
reset!
|
12
26
|
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.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- André Muta
|
@@ -35,24 +35,40 @@ files:
|
|
35
35
|
- LICENSE.txt
|
36
36
|
- README.md
|
37
37
|
- Rakefile
|
38
|
+
- docs/AST.md
|
39
|
+
- docs/DSL.md
|
40
|
+
- docs/FUNCTIONS.md
|
41
|
+
- docs/SYNTAX.md
|
38
42
|
- docs/development/README.md
|
39
43
|
- docs/development/error-reporting.md
|
40
|
-
-
|
41
|
-
-
|
42
|
-
-
|
43
|
-
-
|
44
|
+
- docs/features/README.md
|
45
|
+
- docs/features/analysis-cascade-mutual-exclusion.md
|
46
|
+
- docs/features/analysis-type-inference.md
|
47
|
+
- docs/features/analysis-unsat-detection.md
|
48
|
+
- docs/features/array-broadcasting.md
|
49
|
+
- docs/features/input-declaration-system.md
|
50
|
+
- docs/features/performance.md
|
51
|
+
- docs/schema_metadata.md
|
52
|
+
- docs/schema_metadata/broadcasts.md
|
53
|
+
- docs/schema_metadata/cascades.md
|
54
|
+
- docs/schema_metadata/declarations.md
|
55
|
+
- docs/schema_metadata/dependencies.md
|
56
|
+
- docs/schema_metadata/evaluation_order.md
|
57
|
+
- docs/schema_metadata/examples.md
|
58
|
+
- docs/schema_metadata/inferred_types.md
|
59
|
+
- docs/schema_metadata/inputs.md
|
44
60
|
- examples/deep_schema_compilation_and_evaluation_benchmark.rb
|
45
61
|
- examples/federal_tax_calculator_2024.rb
|
46
62
|
- examples/game_of_life.rb
|
47
63
|
- examples/simple_rpg_game.rb
|
48
64
|
- examples/static_analysis_errors.rb
|
49
65
|
- examples/wide_schema_compilation_and_evaluation_benchmark.rb
|
50
|
-
- lib/generators/trait_engine/templates/schema_spec.rb.erb
|
51
66
|
- lib/kumi.rb
|
52
67
|
- lib/kumi/analyzer.rb
|
53
68
|
- lib/kumi/analyzer/analysis_state.rb
|
54
69
|
- lib/kumi/analyzer/constant_evaluator.rb
|
55
|
-
- lib/kumi/analyzer/passes/
|
70
|
+
- lib/kumi/analyzer/passes/broadcast_detector.rb
|
71
|
+
- lib/kumi/analyzer/passes/declaration_validator.rb
|
56
72
|
- lib/kumi/analyzer/passes/dependency_resolver.rb
|
57
73
|
- lib/kumi/analyzer/passes/input_collector.rb
|
58
74
|
- lib/kumi/analyzer/passes/name_indexer.rb
|
@@ -69,7 +85,6 @@ files:
|
|
69
85
|
- lib/kumi/compiled_schema.rb
|
70
86
|
- lib/kumi/compiler.rb
|
71
87
|
- lib/kumi/constraint_relationship_solver.rb
|
72
|
-
- lib/kumi/domain.rb
|
73
88
|
- lib/kumi/domain/enum_analyzer.rb
|
74
89
|
- lib/kumi/domain/range_analyzer.rb
|
75
90
|
- lib/kumi/domain/validator.rb
|
@@ -95,28 +110,43 @@ files:
|
|
95
110
|
- lib/kumi/function_registry/math_functions.rb
|
96
111
|
- lib/kumi/function_registry/string_functions.rb
|
97
112
|
- lib/kumi/function_registry/type_functions.rb
|
98
|
-
- lib/kumi/input.rb
|
99
113
|
- lib/kumi/input/type_matcher.rb
|
100
114
|
- lib/kumi/input/validator.rb
|
101
115
|
- lib/kumi/input/violation_creator.rb
|
102
|
-
- lib/kumi/
|
103
|
-
- lib/kumi/
|
104
|
-
- lib/kumi/
|
105
|
-
- lib/kumi/
|
106
|
-
- lib/kumi/
|
107
|
-
- lib/kumi/
|
108
|
-
- lib/kumi/
|
109
|
-
- lib/kumi/
|
110
|
-
- lib/kumi/
|
111
|
-
- lib/kumi/
|
116
|
+
- lib/kumi/json_schema.rb
|
117
|
+
- lib/kumi/json_schema/generator.rb
|
118
|
+
- lib/kumi/json_schema/validator.rb
|
119
|
+
- lib/kumi/ruby_parser.rb
|
120
|
+
- lib/kumi/ruby_parser/build_context.rb
|
121
|
+
- lib/kumi/ruby_parser/declaration_reference_proxy.rb
|
122
|
+
- lib/kumi/ruby_parser/dsl.rb
|
123
|
+
- lib/kumi/ruby_parser/dsl_cascade_builder.rb
|
124
|
+
- lib/kumi/ruby_parser/expression_converter.rb
|
125
|
+
- lib/kumi/ruby_parser/guard_rails.rb
|
126
|
+
- lib/kumi/ruby_parser/input_builder.rb
|
127
|
+
- lib/kumi/ruby_parser/input_field_proxy.rb
|
128
|
+
- lib/kumi/ruby_parser/input_proxy.rb
|
129
|
+
- lib/kumi/ruby_parser/nested_input.rb
|
130
|
+
- lib/kumi/ruby_parser/parser.rb
|
131
|
+
- lib/kumi/ruby_parser/schema_builder.rb
|
132
|
+
- lib/kumi/ruby_parser/sugar.rb
|
112
133
|
- lib/kumi/schema.rb
|
113
134
|
- lib/kumi/schema_instance.rb
|
114
|
-
- lib/kumi/
|
115
|
-
- lib/kumi/syntax/
|
116
|
-
- lib/kumi/syntax/
|
135
|
+
- lib/kumi/schema_metadata.rb
|
136
|
+
- lib/kumi/syntax/array_expression.rb
|
137
|
+
- lib/kumi/syntax/call_expression.rb
|
138
|
+
- lib/kumi/syntax/cascade_expression.rb
|
139
|
+
- lib/kumi/syntax/case_expression.rb
|
140
|
+
- lib/kumi/syntax/declaration_reference.rb
|
141
|
+
- lib/kumi/syntax/hash_expression.rb
|
142
|
+
- lib/kumi/syntax/input_declaration.rb
|
143
|
+
- lib/kumi/syntax/input_element_reference.rb
|
144
|
+
- lib/kumi/syntax/input_reference.rb
|
145
|
+
- lib/kumi/syntax/literal.rb
|
117
146
|
- lib/kumi/syntax/node.rb
|
118
147
|
- lib/kumi/syntax/root.rb
|
119
|
-
- lib/kumi/syntax/
|
148
|
+
- lib/kumi/syntax/trait_declaration.rb
|
149
|
+
- lib/kumi/syntax/value_declaration.rb
|
120
150
|
- lib/kumi/types.rb
|
121
151
|
- lib/kumi/types/builder.rb
|
122
152
|
- lib/kumi/types/compatibility.rb
|
@@ -124,6 +154,7 @@ files:
|
|
124
154
|
- lib/kumi/types/inference.rb
|
125
155
|
- lib/kumi/types/normalizer.rb
|
126
156
|
- lib/kumi/types/validator.rb
|
157
|
+
- lib/kumi/vectorization_metadata.rb
|
127
158
|
- lib/kumi/version.rb
|
128
159
|
- scripts/generate_function_docs.rb
|
129
160
|
homepage: https://github.com/amuta/kumi
|
@@ -151,6 +182,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
151
182
|
requirements: []
|
152
183
|
rubygems_version: 3.7.1
|
153
184
|
specification_version: 4
|
154
|
-
summary: A
|
155
|
-
dependency graph
|
185
|
+
summary: A Declarative logic framework with static analysis for Ruby.
|
156
186
|
test_files: []
|
@@ -1,27 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require "rails_helper"
|
3
|
-
|
4
|
-
RSpec.describe <%= schema_constant %> do
|
5
|
-
# Single shared instance for every example
|
6
|
-
let(:schema) { described_class }
|
7
|
-
|
8
|
-
# Minimal dummy context so every binding can run
|
9
|
-
let(:ctx) do
|
10
|
-
{
|
11
|
-
<% leaf_keys.each do |k| -%>
|
12
|
-
<%= "#{k}:" %> nil,
|
13
|
-
<% end -%>
|
14
|
-
}
|
15
|
-
end
|
16
|
-
|
17
|
-
<% expose_names.each do |name| -%>
|
18
|
-
describe "<%= name %>" do
|
19
|
-
it "evaluates without raising" do
|
20
|
-
expect {
|
21
|
-
schema.evaluate_binding(:<%= name %>, ctx)
|
22
|
-
}.not_to raise_error
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
<% end -%>
|
27
|
-
end
|
data/lib/kumi/domain.rb
DELETED
data/lib/kumi/input.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Kumi
|
4
|
-
module Syntax
|
5
|
-
module Declarations
|
6
|
-
Attribute = Struct.new(:name, :expression) do
|
7
|
-
include Node
|
8
|
-
|
9
|
-
def children = [expression]
|
10
|
-
end
|
11
|
-
|
12
|
-
Trait = Struct.new(:name, :expression) do
|
13
|
-
include Node
|
14
|
-
|
15
|
-
def children = [expression]
|
16
|
-
end
|
17
|
-
|
18
|
-
# For field metadata declarations inside input blocks
|
19
|
-
FieldDecl = Struct.new(:name, :domain, :type) do
|
20
|
-
include Node
|
21
|
-
|
22
|
-
def children = []
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Kumi
|
4
|
-
module Syntax
|
5
|
-
module Expressions
|
6
|
-
CallExpression = Struct.new(:fn_name, :args) do
|
7
|
-
include Node
|
8
|
-
|
9
|
-
def children = args
|
10
|
-
end
|
11
|
-
CascadeExpression = Struct.new(:cases) do
|
12
|
-
include Node
|
13
|
-
|
14
|
-
def children = cases
|
15
|
-
end
|
16
|
-
|
17
|
-
WhenCaseExpression = Struct.new(:condition, :result) do
|
18
|
-
include Node
|
19
|
-
|
20
|
-
def children = [condition, result]
|
21
|
-
end
|
22
|
-
|
23
|
-
ListExpression = Struct.new(:elements) do
|
24
|
-
include Node
|
25
|
-
|
26
|
-
def children = elements
|
27
|
-
|
28
|
-
def size
|
29
|
-
elements.size
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "node"
|
4
|
-
|
5
|
-
module Kumi
|
6
|
-
module Syntax
|
7
|
-
module TerminalExpressions
|
8
|
-
# Leaf expressions that represent a value or reference and terminate a branch.
|
9
|
-
|
10
|
-
Literal = Struct.new(:value) do
|
11
|
-
include Node
|
12
|
-
|
13
|
-
def children = []
|
14
|
-
end
|
15
|
-
|
16
|
-
# For field usage/reference in expressions (input.field_name)
|
17
|
-
FieldRef = Struct.new(:name) do
|
18
|
-
include Node
|
19
|
-
|
20
|
-
def children = []
|
21
|
-
end
|
22
|
-
|
23
|
-
Binding = Struct.new(:name) do
|
24
|
-
include Node
|
25
|
-
|
26
|
-
def children = []
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
data/lib/kumi/syntax.rb
DELETED
/data/{documents → docs}/DSL.md
RENAMED
File without changes
|
File without changes
|