kumi 0.0.7 → 0.0.9

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 (175) hide show
  1. checksums.yaml +4 -4
  2. data/CLAUDE.md +1 -1
  3. data/README.md +21 -5
  4. data/docs/AST.md +7 -0
  5. data/docs/features/README.md +7 -0
  6. data/docs/features/s-expression-printer.md +77 -0
  7. data/examples/game_of_life.rb +1 -1
  8. data/examples/static_analysis_errors.rb +7 -7
  9. data/lib/kumi/analyzer.rb +15 -15
  10. data/lib/kumi/compiler.rb +6 -6
  11. data/lib/kumi/core/analyzer/analysis_state.rb +39 -0
  12. data/lib/kumi/core/analyzer/constant_evaluator.rb +59 -0
  13. data/lib/kumi/core/analyzer/passes/broadcast_detector.rb +248 -0
  14. data/lib/kumi/core/analyzer/passes/declaration_validator.rb +45 -0
  15. data/lib/kumi/core/analyzer/passes/dependency_resolver.rb +153 -0
  16. data/lib/kumi/core/analyzer/passes/input_collector.rb +139 -0
  17. data/lib/kumi/core/analyzer/passes/name_indexer.rb +26 -0
  18. data/lib/kumi/core/analyzer/passes/pass_base.rb +52 -0
  19. data/lib/kumi/core/analyzer/passes/semantic_constraint_validator.rb +111 -0
  20. data/lib/kumi/core/analyzer/passes/toposorter.rb +110 -0
  21. data/lib/kumi/core/analyzer/passes/type_checker.rb +162 -0
  22. data/lib/kumi/core/analyzer/passes/type_consistency_checker.rb +48 -0
  23. data/lib/kumi/core/analyzer/passes/type_inferencer.rb +236 -0
  24. data/lib/kumi/core/analyzer/passes/unsat_detector.rb +406 -0
  25. data/lib/kumi/core/analyzer/passes/visitor_pass.rb +44 -0
  26. data/lib/kumi/core/atom_unsat_solver.rb +396 -0
  27. data/lib/kumi/core/compiled_schema.rb +43 -0
  28. data/lib/kumi/core/constraint_relationship_solver.rb +641 -0
  29. data/lib/kumi/core/domain/enum_analyzer.rb +55 -0
  30. data/lib/kumi/core/domain/range_analyzer.rb +85 -0
  31. data/lib/kumi/core/domain/validator.rb +82 -0
  32. data/lib/kumi/core/domain/violation_formatter.rb +42 -0
  33. data/lib/kumi/core/error_reporter.rb +166 -0
  34. data/lib/kumi/core/error_reporting.rb +97 -0
  35. data/lib/kumi/core/errors.rb +120 -0
  36. data/lib/kumi/core/evaluation_wrapper.rb +40 -0
  37. data/lib/kumi/core/explain.rb +295 -0
  38. data/lib/kumi/core/export/deserializer.rb +41 -0
  39. data/lib/kumi/core/export/errors.rb +14 -0
  40. data/lib/kumi/core/export/node_builders.rb +142 -0
  41. data/lib/kumi/core/export/node_registry.rb +54 -0
  42. data/lib/kumi/core/export/node_serializers.rb +158 -0
  43. data/lib/kumi/core/export/serializer.rb +25 -0
  44. data/lib/kumi/core/export.rb +35 -0
  45. data/lib/kumi/core/function_registry/collection_functions.rb +202 -0
  46. data/lib/kumi/core/function_registry/comparison_functions.rb +33 -0
  47. data/lib/kumi/core/function_registry/conditional_functions.rb +38 -0
  48. data/lib/kumi/core/function_registry/function_builder.rb +95 -0
  49. data/lib/kumi/core/function_registry/logical_functions.rb +44 -0
  50. data/lib/kumi/core/function_registry/math_functions.rb +74 -0
  51. data/lib/kumi/core/function_registry/string_functions.rb +57 -0
  52. data/lib/kumi/core/function_registry/type_functions.rb +53 -0
  53. data/lib/kumi/{function_registry.rb → core/function_registry.rb} +28 -36
  54. data/lib/kumi/core/input/type_matcher.rb +97 -0
  55. data/lib/kumi/core/input/validator.rb +51 -0
  56. data/lib/kumi/core/input/violation_creator.rb +52 -0
  57. data/lib/kumi/core/json_schema/generator.rb +65 -0
  58. data/lib/kumi/core/json_schema/validator.rb +27 -0
  59. data/lib/kumi/core/json_schema.rb +16 -0
  60. data/lib/kumi/core/ruby_parser/build_context.rb +27 -0
  61. data/lib/kumi/core/ruby_parser/declaration_reference_proxy.rb +38 -0
  62. data/lib/kumi/core/ruby_parser/dsl.rb +14 -0
  63. data/lib/kumi/core/ruby_parser/dsl_cascade_builder.rb +138 -0
  64. data/lib/kumi/core/ruby_parser/expression_converter.rb +128 -0
  65. data/lib/kumi/core/ruby_parser/guard_rails.rb +45 -0
  66. data/lib/kumi/core/ruby_parser/input_builder.rb +127 -0
  67. data/lib/kumi/core/ruby_parser/input_field_proxy.rb +48 -0
  68. data/lib/kumi/core/ruby_parser/input_proxy.rb +31 -0
  69. data/lib/kumi/core/ruby_parser/nested_input.rb +17 -0
  70. data/lib/kumi/core/ruby_parser/parser.rb +71 -0
  71. data/lib/kumi/core/ruby_parser/schema_builder.rb +175 -0
  72. data/lib/kumi/core/ruby_parser/sugar.rb +263 -0
  73. data/lib/kumi/core/ruby_parser.rb +12 -0
  74. data/lib/kumi/core/schema_instance.rb +111 -0
  75. data/lib/kumi/core/types/builder.rb +23 -0
  76. data/lib/kumi/core/types/compatibility.rb +96 -0
  77. data/lib/kumi/core/types/formatter.rb +26 -0
  78. data/lib/kumi/core/types/inference.rb +42 -0
  79. data/lib/kumi/core/types/normalizer.rb +72 -0
  80. data/lib/kumi/core/types/validator.rb +37 -0
  81. data/lib/kumi/core/types.rb +66 -0
  82. data/lib/kumi/core/vectorization_metadata.rb +110 -0
  83. data/lib/kumi/errors.rb +1 -112
  84. data/lib/kumi/registry.rb +37 -0
  85. data/lib/kumi/schema.rb +5 -5
  86. data/lib/kumi/schema_metadata.rb +3 -3
  87. data/lib/kumi/support/s_expression_printer.rb +161 -0
  88. data/lib/kumi/syntax/array_expression.rb +6 -6
  89. data/lib/kumi/syntax/call_expression.rb +4 -4
  90. data/lib/kumi/syntax/cascade_expression.rb +4 -4
  91. data/lib/kumi/syntax/case_expression.rb +4 -4
  92. data/lib/kumi/syntax/declaration_reference.rb +4 -4
  93. data/lib/kumi/syntax/hash_expression.rb +4 -4
  94. data/lib/kumi/syntax/input_declaration.rb +5 -5
  95. data/lib/kumi/syntax/input_element_reference.rb +5 -5
  96. data/lib/kumi/syntax/input_reference.rb +5 -5
  97. data/lib/kumi/syntax/literal.rb +4 -4
  98. data/lib/kumi/syntax/node.rb +34 -34
  99. data/lib/kumi/syntax/root.rb +6 -6
  100. data/lib/kumi/syntax/trait_declaration.rb +4 -4
  101. data/lib/kumi/syntax/value_declaration.rb +4 -4
  102. data/lib/kumi/version.rb +1 -1
  103. data/migrate_to_core_iterative.rb +938 -0
  104. data/scripts/generate_function_docs.rb +9 -9
  105. metadata +77 -72
  106. data/lib/kumi/analyzer/analysis_state.rb +0 -37
  107. data/lib/kumi/analyzer/constant_evaluator.rb +0 -57
  108. data/lib/kumi/analyzer/passes/broadcast_detector.rb +0 -246
  109. data/lib/kumi/analyzer/passes/declaration_validator.rb +0 -43
  110. data/lib/kumi/analyzer/passes/dependency_resolver.rb +0 -151
  111. data/lib/kumi/analyzer/passes/input_collector.rb +0 -137
  112. data/lib/kumi/analyzer/passes/name_indexer.rb +0 -24
  113. data/lib/kumi/analyzer/passes/pass_base.rb +0 -50
  114. data/lib/kumi/analyzer/passes/semantic_constraint_validator.rb +0 -109
  115. data/lib/kumi/analyzer/passes/toposorter.rb +0 -108
  116. data/lib/kumi/analyzer/passes/type_checker.rb +0 -160
  117. data/lib/kumi/analyzer/passes/type_consistency_checker.rb +0 -46
  118. data/lib/kumi/analyzer/passes/type_inferencer.rb +0 -232
  119. data/lib/kumi/analyzer/passes/unsat_detector.rb +0 -404
  120. data/lib/kumi/analyzer/passes/visitor_pass.rb +0 -42
  121. data/lib/kumi/atom_unsat_solver.rb +0 -394
  122. data/lib/kumi/compiled_schema.rb +0 -41
  123. data/lib/kumi/constraint_relationship_solver.rb +0 -638
  124. data/lib/kumi/domain/enum_analyzer.rb +0 -53
  125. data/lib/kumi/domain/range_analyzer.rb +0 -83
  126. data/lib/kumi/domain/validator.rb +0 -80
  127. data/lib/kumi/domain/violation_formatter.rb +0 -40
  128. data/lib/kumi/error_reporter.rb +0 -164
  129. data/lib/kumi/error_reporting.rb +0 -95
  130. data/lib/kumi/evaluation_wrapper.rb +0 -38
  131. data/lib/kumi/explain.rb +0 -293
  132. data/lib/kumi/export/deserializer.rb +0 -39
  133. data/lib/kumi/export/errors.rb +0 -12
  134. data/lib/kumi/export/node_builders.rb +0 -140
  135. data/lib/kumi/export/node_registry.rb +0 -52
  136. data/lib/kumi/export/node_serializers.rb +0 -156
  137. data/lib/kumi/export/serializer.rb +0 -23
  138. data/lib/kumi/export.rb +0 -33
  139. data/lib/kumi/function_registry/collection_functions.rb +0 -200
  140. data/lib/kumi/function_registry/comparison_functions.rb +0 -31
  141. data/lib/kumi/function_registry/conditional_functions.rb +0 -36
  142. data/lib/kumi/function_registry/function_builder.rb +0 -93
  143. data/lib/kumi/function_registry/logical_functions.rb +0 -42
  144. data/lib/kumi/function_registry/math_functions.rb +0 -72
  145. data/lib/kumi/function_registry/string_functions.rb +0 -54
  146. data/lib/kumi/function_registry/type_functions.rb +0 -51
  147. data/lib/kumi/input/type_matcher.rb +0 -95
  148. data/lib/kumi/input/validator.rb +0 -49
  149. data/lib/kumi/input/violation_creator.rb +0 -50
  150. data/lib/kumi/json_schema/generator.rb +0 -63
  151. data/lib/kumi/json_schema/validator.rb +0 -25
  152. data/lib/kumi/json_schema.rb +0 -14
  153. data/lib/kumi/ruby_parser/build_context.rb +0 -25
  154. data/lib/kumi/ruby_parser/declaration_reference_proxy.rb +0 -36
  155. data/lib/kumi/ruby_parser/dsl.rb +0 -12
  156. data/lib/kumi/ruby_parser/dsl_cascade_builder.rb +0 -136
  157. data/lib/kumi/ruby_parser/expression_converter.rb +0 -126
  158. data/lib/kumi/ruby_parser/guard_rails.rb +0 -43
  159. data/lib/kumi/ruby_parser/input_builder.rb +0 -125
  160. data/lib/kumi/ruby_parser/input_field_proxy.rb +0 -46
  161. data/lib/kumi/ruby_parser/input_proxy.rb +0 -29
  162. data/lib/kumi/ruby_parser/nested_input.rb +0 -15
  163. data/lib/kumi/ruby_parser/parser.rb +0 -69
  164. data/lib/kumi/ruby_parser/schema_builder.rb +0 -173
  165. data/lib/kumi/ruby_parser/sugar.rb +0 -261
  166. data/lib/kumi/ruby_parser.rb +0 -10
  167. data/lib/kumi/schema_instance.rb +0 -109
  168. data/lib/kumi/types/builder.rb +0 -21
  169. data/lib/kumi/types/compatibility.rb +0 -94
  170. data/lib/kumi/types/formatter.rb +0 -24
  171. data/lib/kumi/types/inference.rb +0 -40
  172. data/lib/kumi/types/normalizer.rb +0 -70
  173. data/lib/kumi/types/validator.rb +0 -35
  174. data/lib/kumi/types.rb +0 -64
  175. data/lib/kumi/vectorization_metadata.rb +0 -108
@@ -1,261 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Kumi
4
- module RubyParser
5
- module Sugar
6
- include Syntax
7
-
8
- ARITHMETIC_OPS = {
9
- :+ => :add, :- => :subtract, :* => :multiply,
10
- :/ => :divide, :% => :modulo, :** => :power
11
- }.freeze
12
-
13
- COMPARISON_OPS = %i[< <= > >= == !=].freeze
14
-
15
- LITERAL_TYPES = [
16
- Integer, String, Symbol, TrueClass, FalseClass, Float, Regexp, NilClass
17
- ].freeze
18
-
19
- # Collection methods that can be applied to arrays/syntax nodes
20
- COLLECTION_METHODS = %i[
21
- sum size length first last sort reverse unique min max empty? flatten
22
- map_with_index indices
23
- ].freeze
24
-
25
- def self.ensure_literal(obj)
26
- return Kumi::Syntax::Literal.new(obj) if LITERAL_TYPES.any? { |type| obj.is_a?(type) }
27
- return obj if obj.is_a?(Syntax::Node)
28
- return obj.to_ast_node if obj.respond_to?(:to_ast_node)
29
-
30
- Kumi::Syntax::Literal.new(obj)
31
- end
32
-
33
- def self.syntax_expression?(obj)
34
- obj.is_a?(Syntax::Node) || obj.respond_to?(:to_ast_node)
35
- end
36
-
37
- # Create a call expression with consistent error handling
38
- def self.create_call_expression(fn_name, args)
39
- Kumi::Syntax::CallExpression.new(fn_name, args)
40
- end
41
-
42
- module ExpressionRefinement
43
- refine Syntax::Node do
44
- # Arithmetic operations
45
- ARITHMETIC_OPS.each do |op, op_name|
46
- define_method(op) do |other|
47
- other_node = Sugar.ensure_literal(other)
48
- Sugar.create_call_expression(op_name, [self, other_node])
49
- end
50
- end
51
-
52
- # Comparison operations
53
- COMPARISON_OPS.each do |op|
54
- define_method(op) do |other|
55
- other_node = Sugar.ensure_literal(other)
56
- Sugar.create_call_expression(op, [self, other_node])
57
- end
58
- end
59
-
60
- # Array access
61
- def [](index)
62
- Sugar.create_call_expression(:at, [self, Sugar.ensure_literal(index)])
63
- end
64
-
65
- # Unary minus
66
- def -@
67
- Sugar.create_call_expression(:subtract, [Sugar.ensure_literal(0), self])
68
- end
69
-
70
- # Logical operations
71
- def &(other)
72
- Sugar.create_call_expression(:and, [self, Sugar.ensure_literal(other)])
73
- end
74
-
75
- def |(other)
76
- Sugar.create_call_expression(:or, [self, Sugar.ensure_literal(other)])
77
- end
78
-
79
- # Collection methods - single argument (self)
80
- COLLECTION_METHODS.each do |method_name|
81
- next if method_name == :include? # Special case with element argument
82
-
83
- define_method(method_name) do
84
- Sugar.create_call_expression(method_name, [self])
85
- end
86
- end
87
-
88
- # Special case: include? takes an element argument
89
- def include?(element)
90
- Sugar.create_call_expression(:include?, [self, Sugar.ensure_literal(element)])
91
- end
92
- end
93
- end
94
-
95
- module NumericRefinement
96
- [Integer, Float].each do |klass|
97
- refine klass do
98
- # Arithmetic operations with syntax expressions
99
- ARITHMETIC_OPS.each do |op, op_name|
100
- define_method(op) do |other|
101
- if Sugar.syntax_expression?(other)
102
- other_node = Sugar.ensure_literal(other)
103
- Sugar.create_call_expression(op_name, [Kumi::Syntax::Literal.new(self), other_node])
104
- else
105
- super(other)
106
- end
107
- end
108
- end
109
-
110
- # Comparison operations with syntax expressions
111
- COMPARISON_OPS.each do |op|
112
- define_method(op) do |other|
113
- if Sugar.syntax_expression?(other)
114
- other_node = Sugar.ensure_literal(other)
115
- Sugar.create_call_expression(op, [Kumi::Syntax::Literal.new(self), other_node])
116
- else
117
- super(other)
118
- end
119
- end
120
- end
121
- end
122
- end
123
- end
124
-
125
- module StringRefinement
126
- refine String do
127
- def +(other)
128
- if Sugar.syntax_expression?(other)
129
- other_node = Sugar.ensure_literal(other)
130
- Sugar.create_call_expression(:concat, [Kumi::Syntax::Literal.new(self), other_node])
131
- else
132
- super
133
- end
134
- end
135
-
136
- %i[== !=].each do |op|
137
- define_method(op) do |other|
138
- if Sugar.syntax_expression?(other)
139
- other_node = Sugar.ensure_literal(other)
140
- Sugar.create_call_expression(op, [Kumi::Syntax::Literal.new(self), other_node])
141
- else
142
- super(other)
143
- end
144
- end
145
- end
146
- end
147
- end
148
-
149
- module ArrayRefinement
150
- refine Array do
151
- # Helper method to check if array contains any syntax expressions
152
- def any_syntax_expressions?
153
- any? { |item| Sugar.syntax_expression?(item) }
154
- end
155
-
156
- # Convert array to syntax list expression with all elements as syntax nodes
157
- def to_syntax_list
158
- syntax_elements = map { |item| Sugar.ensure_literal(item) }
159
- Kumi::Syntax::ArrayExpression.new(syntax_elements)
160
- end
161
-
162
- # Create array method that works with syntax expressions
163
- def self.define_array_syntax_method(method_name, has_argument: false)
164
- define_method(method_name) do |*args|
165
- if any_syntax_expressions?
166
- array_literal = to_syntax_list
167
- call_args = [array_literal]
168
- call_args.concat(args.map { |arg| Sugar.ensure_literal(arg) }) if has_argument
169
- Sugar.create_call_expression(method_name, call_args)
170
- else
171
- super(*args)
172
- end
173
- end
174
- end
175
-
176
- # Define collection methods without arguments
177
- %i[sum size length first last sort reverse unique min max empty? flatten].each do |method_name|
178
- define_array_syntax_method(method_name)
179
- end
180
-
181
- # Define methods with arguments
182
- define_array_syntax_method(:include?, has_argument: true)
183
- end
184
- end
185
-
186
- module ModuleRefinement
187
- refine Module do
188
- # Allow modules to provide schema utilities and helpers
189
- def with_schema_utilities
190
- include Kumi::Schema if respond_to?(:include)
191
- extend Kumi::Schema if respond_to?(:extend)
192
- end
193
-
194
- # Helper for defining schema constants that can be used in multiple schemas
195
- def schema_const(name, value)
196
- const_set(name, value.freeze)
197
- end
198
-
199
- # Enable easy schema composition
200
- def compose_schema(*modules)
201
- modules.each do |mod|
202
- include mod if mod.is_a?(Module)
203
- end
204
- end
205
- end
206
- end
207
-
208
- # Shared refinement for proxy objects that need to handle operators
209
- # Both DeclarationReferenceProxy and InputFieldProxy can use this
210
- module ProxyRefinement
211
- def self.extended(proxy_class)
212
- # Add operator methods directly to the proxy class
213
- proxy_class.class_eval do
214
- # Arithmetic operations
215
- ARITHMETIC_OPS.each do |op, op_name|
216
- define_method(op) do |other|
217
- ast_node = to_ast_node
218
- other_node = Sugar.ensure_literal(other)
219
- Sugar.create_call_expression(op_name, [ast_node, other_node])
220
- end
221
- end
222
-
223
- # Comparison operations (including == and != that don't work with refinements)
224
- COMPARISON_OPS.each do |op|
225
- define_method(op) do |other|
226
- ast_node = to_ast_node
227
- other_node = Sugar.ensure_literal(other)
228
- Sugar.create_call_expression(op, [ast_node, other_node])
229
- end
230
- end
231
-
232
- # Logical operations
233
- define_method(:&) do |other|
234
- ast_node = to_ast_node
235
- other_node = Sugar.ensure_literal(other)
236
- Sugar.create_call_expression(:and, [ast_node, other_node])
237
- end
238
-
239
- define_method(:|) do |other|
240
- ast_node = to_ast_node
241
- other_node = Sugar.ensure_literal(other)
242
- Sugar.create_call_expression(:or, [ast_node, other_node])
243
- end
244
-
245
- # Array access
246
- define_method(:[]) do |index|
247
- ast_node = to_ast_node
248
- Sugar.create_call_expression(:at, [ast_node, Sugar.ensure_literal(index)])
249
- end
250
-
251
- # Unary minus
252
- define_method(:-@) do
253
- ast_node = to_ast_node
254
- Sugar.create_call_expression(:subtract, [Sugar.ensure_literal(0), ast_node])
255
- end
256
- end
257
- end
258
- end
259
- end
260
- end
261
- end
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Kumi
4
- # Ruby DSL parser for Kumi schemas
5
- # Converts Ruby block syntax into AST nodes
6
- module RubyParser
7
- # This module contains all Ruby DSL parsing functionality
8
- # The main entry point is through Dsl.build_syntax_tree
9
- end
10
- end
@@ -1,109 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Kumi
4
- # A bound pair of <compiled schema + context>. Immutable.
5
- #
6
- # Public API ----------------------------------------------------------
7
- # instance.evaluate # => full Hash of all bindings
8
- # instance.evaluate(:tax_due, :rate)
9
- # instance.slice(:tax_due) # alias for evaluate(*keys)
10
- # instance.explain(:tax_due) # pretty trace string
11
- # instance.input # original context (read‑only)
12
-
13
- class SchemaInstance
14
- attr_reader :compiled_schema, :metadata, :context
15
-
16
- def initialize(compiled_schema, metadata, context)
17
- @compiled_schema = compiled_schema # Kumi::CompiledSchema
18
- @metadata = metadata # Frozen state hash
19
- @context = context.is_a?(EvaluationWrapper) ? context : EvaluationWrapper.new(context)
20
- end
21
-
22
- # Hash‑like read of one or many bindings
23
- def evaluate(*key_names)
24
- if key_names.empty?
25
- @compiled_schema.evaluate(@context)
26
- else
27
- @compiled_schema.evaluate(@context, *key_names)
28
- end
29
- end
30
-
31
- def slice(*key_names)
32
- return {} if key_names.empty?
33
-
34
- evaluate(*key_names)
35
- end
36
-
37
- def [](key_name)
38
- evaluate(key_name)[key_name]
39
- end
40
-
41
- # Update input values and clear affected cached computations
42
- def update(**changes)
43
- changes.each do |field, value|
44
- # Validate field exists
45
- raise ArgumentError, "unknown input field: #{field}" unless input_field_exists?(field)
46
-
47
- # Validate domain constraints
48
- validate_domain_constraint(field, value)
49
-
50
- # Update the input data
51
- @context[field] = value
52
-
53
- # Clear affected cached values using transitive closure by default
54
- if ENV["KUMI_SIMPLE_CACHE"] == "true"
55
- # Simple fallback: clear all cached values
56
- @context.clear_cache
57
- else
58
- # Default: selective cache clearing using precomputed transitive closure
59
- affected_keys = find_dependent_declarations_optimized(field)
60
- affected_keys.each { |key| @context.clear_cache(key) }
61
- end
62
- end
63
-
64
- self # Return self for chaining
65
- end
66
-
67
- private
68
-
69
- def input_field_exists?(field)
70
- # Check if field is declared in input block
71
- input_meta = @metadata[:inputs] || {}
72
- input_meta.key?(field) || @context.key?(field)
73
- end
74
-
75
- def validate_domain_constraint(field, value)
76
- input_meta = @metadata[:inputs] || {}
77
- field_meta = input_meta[field]
78
- return unless field_meta&.dig(:domain)
79
-
80
- domain = field_meta[:domain]
81
- return unless violates_domain?(value, domain)
82
-
83
- raise ArgumentError, "value #{value} is not in domain #{domain}"
84
- end
85
-
86
- def violates_domain?(value, domain)
87
- case domain
88
- when Range
89
- !domain.include?(value)
90
- when Array
91
- !domain.include?(value)
92
- when Proc
93
- # For Proc domains, we can't statically analyze
94
- false
95
- else
96
- false
97
- end
98
- end
99
-
100
- def find_dependent_declarations_optimized(field)
101
- # Use precomputed transitive closure for true O(1) lookup!
102
- transitive_dependents = @metadata[:dependents]
103
- return [] unless transitive_dependents
104
-
105
- # This is truly O(1) - just array lookup, no traversal needed
106
- transitive_dependents[field] || []
107
- end
108
- end
109
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Kumi
4
- module Types
5
- # Builds complex type structures
6
- class Builder
7
- def self.array(elem_type)
8
- raise ArgumentError, "Invalid array element type: #{elem_type}" unless Validator.valid_type?(elem_type)
9
-
10
- { array: elem_type }
11
- end
12
-
13
- def self.hash(key_type, val_type)
14
- raise ArgumentError, "Invalid hash key type: #{key_type}" unless Validator.valid_type?(key_type)
15
- raise ArgumentError, "Invalid hash value type: #{val_type}" unless Validator.valid_type?(val_type)
16
-
17
- { hash: [key_type, val_type] }
18
- end
19
- end
20
- end
21
- end
@@ -1,94 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Kumi
4
- module Types
5
- # Handles type compatibility and unification
6
- class Compatibility
7
- # Check if two types are compatible
8
- def self.compatible?(type1, type2)
9
- # Any type is compatible with anything
10
- return true if type1 == :any || type2 == :any
11
-
12
- # Exact match
13
- return true if type1 == type2
14
-
15
- # Generic array compatibility: :array is compatible with any structured array
16
- return true if (type1 == :array && Validator.array_type?(type2)) ||
17
- (type2 == :array && Validator.array_type?(type1))
18
-
19
- # Numeric compatibility
20
- return true if numeric_compatible?(type1, type2)
21
-
22
- # Array compatibility
23
- return array_compatible?(type1, type2) if array_types?(type1, type2)
24
-
25
- # Hash compatibility
26
- return hash_compatible?(type1, type2) if hash_types?(type1, type2)
27
-
28
- false
29
- end
30
-
31
- # Find the most specific common type between two types
32
- def self.unify(type1, type2)
33
- return type1 if type1 == type2
34
-
35
- # :any unifies to the other type (more specific)
36
- return type2 if type1 == :any
37
- return type1 if type2 == :any
38
-
39
- # Generic array unification: structured array is more specific than :array
40
- return type2 if type1 == :array && Validator.array_type?(type2)
41
- return type1 if type2 == :array && Validator.array_type?(type1)
42
-
43
- # Numeric unification
44
- if numeric_compatible?(type1, type2)
45
- return :integer if type1 == :integer && type2 == :integer
46
-
47
- return :float # One or both are float
48
- end
49
-
50
- # Array unification
51
- if array_types?(type1, type2)
52
- elem1 = type1[:array]
53
- elem2 = type2[:array]
54
- unified_elem = unify(elem1, elem2)
55
- return Kumi::Types.array(unified_elem)
56
- end
57
-
58
- # Hash unification
59
- if hash_types?(type1, type2)
60
- key1, val1 = type1[:hash]
61
- key2, val2 = type2[:hash]
62
- unified_key = unify(key1, key2)
63
- unified_val = unify(val1, val2)
64
- return Kumi::Types.hash(unified_key, unified_val)
65
- end
66
-
67
- # Fall back to :any for incompatible types
68
- :any
69
- end
70
-
71
- def self.numeric_compatible?(type1, type2)
72
- numeric_types = %i[integer float]
73
- numeric_types.include?(type1) && numeric_types.include?(type2)
74
- end
75
-
76
- def self.array_types?(type1, type2)
77
- Validator.array_type?(type1) && Validator.array_type?(type2)
78
- end
79
-
80
- def self.hash_types?(type1, type2)
81
- Validator.hash_type?(type1) && Validator.hash_type?(type2)
82
- end
83
-
84
- def self.array_compatible?(type1, type2)
85
- compatible?(type1[:array], type2[:array])
86
- end
87
-
88
- def self.hash_compatible?(type1, type2)
89
- compatible?(type1[:hash][0], type2[:hash][0]) &&
90
- compatible?(type1[:hash][1], type2[:hash][1])
91
- end
92
- end
93
- end
94
- end
@@ -1,24 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Kumi
4
- module Types
5
- # Formats types for display and debugging
6
- class Formatter
7
- # Convert types to string representation
8
- def self.type_to_s(type)
9
- case type
10
- when Hash
11
- if type[:array]
12
- "array(#{type_to_s(type[:array])})"
13
- elsif type[:hash]
14
- "hash(#{type_to_s(type[:hash][0])}, #{type_to_s(type[:hash][1])})"
15
- else
16
- type.to_s
17
- end
18
- else
19
- type.to_s
20
- end
21
- end
22
- end
23
- end
24
- end
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "date"
4
-
5
- module Kumi
6
- module Types
7
- # Infers types from Ruby values
8
- class Inference
9
- def self.infer_from_value(value)
10
- case value
11
- when String then :string
12
- when Integer then :integer
13
- when Float then :float
14
- when TrueClass, FalseClass then :boolean
15
- when Symbol then :symbol
16
- when Regexp then :regexp
17
- when Time then :time
18
- when DateTime then :datetime
19
- when Date then :date
20
- when Array
21
- return Kumi::Types.array(:any) if value.empty?
22
-
23
- # Infer element type from first element (simple heuristic)
24
- first_elem_type = infer_from_value(value.first)
25
- Kumi::Types.array(first_elem_type)
26
- when Hash
27
- return Kumi::Types.hash(:any, :any) if value.empty?
28
-
29
- # Infer key/value types from first pair (simple heuristic)
30
- first_key, first_value = value.first
31
- key_type = infer_from_value(first_key)
32
- value_type = infer_from_value(first_value)
33
- Kumi::Types.hash(key_type, value_type)
34
- else
35
- :any
36
- end
37
- end
38
- end
39
- end
40
- end
@@ -1,70 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "date"
4
-
5
- module Kumi
6
- module Types
7
- # Normalizes different type inputs to canonical forms
8
- class Normalizer
9
- # Type normalization - convert various inputs to canonical type symbols
10
- def self.normalize(type_input)
11
- case type_input
12
- when Symbol
13
- return type_input if Validator.valid_type?(type_input)
14
-
15
- raise ArgumentError, "Invalid type symbol: #{type_input}"
16
- when String
17
- symbol_type = type_input.to_sym
18
- return symbol_type if Validator.valid_type?(symbol_type)
19
-
20
- raise ArgumentError, "Invalid type string: #{type_input}"
21
- when Hash
22
- return type_input if Validator.valid_type?(type_input)
23
-
24
- raise ArgumentError, "Invalid type hash: #{type_input}"
25
- when Class
26
- # Handle Ruby class inputs
27
- case type_input.name
28
- when "Integer" then :integer
29
- when "String" then :string
30
- when "Float" then :float
31
- when "TrueClass", "FalseClass" then :boolean
32
- when "Array" then raise ArgumentError, "Use array(:type) helper for array types"
33
- when "Hash" then raise ArgumentError, "Use hash(:key_type, :value_type) helper for hash types"
34
- else
35
- raise ArgumentError, "Unsupported class type: #{type_input}"
36
- end
37
- else
38
- case type_input
39
- when Integer, Float, Numeric
40
- raise ArgumentError, "Type must be a symbol, got #{type_input} (#{type_input.class})"
41
- else
42
- raise ArgumentError, "Invalid type input: #{type_input} (#{type_input.class})"
43
- end
44
- end
45
- end
46
-
47
- # Legacy compatibility - coerce old constants to symbols
48
- def self.coerce(type_input)
49
- # Handle legacy constant usage
50
- return type_input if type_input.is_a?(Symbol) && Validator.valid_type?(type_input)
51
-
52
- # Handle legacy constant objects
53
- case type_input
54
- when STRING then :string
55
- when INT then :integer
56
- when FLOAT, NUMERIC then :float # Both FLOAT and NUMERIC map to :float
57
- when BOOL then :boolean
58
- when ANY then :any
59
- when SYMBOL then :symbol
60
- when REGEXP then :regexp
61
- when TIME then :time
62
- when DATE then :date
63
- when DATETIME then :datetime
64
- else
65
- normalize(type_input)
66
- end
67
- end
68
- end
69
- end
70
- end
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Kumi
4
- module Types
5
- # Validates type definitions and structures
6
- class Validator
7
- VALID_TYPES = %i[string integer float boolean any symbol regexp time date datetime array].freeze
8
-
9
- def self.valid_type?(type)
10
- return true if VALID_TYPES.include?(type)
11
- return true if array_type?(type)
12
- return true if hash_type?(type)
13
-
14
- false
15
- end
16
-
17
- def self.array_type?(type)
18
- type.is_a?(Hash) && type.keys == [:array] && valid_type?(type[:array])
19
- end
20
-
21
- def self.hash_type?(type)
22
- type.is_a?(Hash) &&
23
- type.keys.sort == [:hash] &&
24
- type[:hash].is_a?(Array) &&
25
- type[:hash].size == 2 &&
26
- valid_type?(type[:hash][0]) &&
27
- valid_type?(type[:hash][1])
28
- end
29
-
30
- def self.primitive_type?(type)
31
- VALID_TYPES.include?(type)
32
- end
33
- end
34
- end
35
- end