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
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kumi
4
+ module Core
5
+ module Types
6
+ # Formats types for display and debugging
7
+ class Formatter
8
+ # Convert types to string representation
9
+ def self.type_to_s(type)
10
+ case type
11
+ when Hash
12
+ if type[:array]
13
+ "array(#{type_to_s(type[:array])})"
14
+ elsif type[:hash]
15
+ "hash(#{type_to_s(type[:hash][0])}, #{type_to_s(type[:hash][1])})"
16
+ else
17
+ type.to_s
18
+ end
19
+ else
20
+ type.to_s
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
4
+
5
+ module Kumi
6
+ module Core
7
+ module Types
8
+ # Infers types from Ruby values
9
+ class Inference
10
+ def self.infer_from_value(value)
11
+ case value
12
+ when String then :string
13
+ when Integer then :integer
14
+ when Float then :float
15
+ when TrueClass, FalseClass then :boolean
16
+ when Symbol then :symbol
17
+ when Regexp then :regexp
18
+ when Time then :time
19
+ when DateTime then :datetime
20
+ when Date then :date
21
+ when Array
22
+ return Kumi::Core::Types.array(:any) if value.empty?
23
+
24
+ # Infer element type from first element (simple heuristic)
25
+ first_elem_type = infer_from_value(value.first)
26
+ Kumi::Core::Types.array(first_elem_type)
27
+ when Hash
28
+ return Kumi::Core::Types.hash(:any, :any) if value.empty?
29
+
30
+ # Infer key/value types from first pair (simple heuristic)
31
+ first_key, first_value = value.first
32
+ key_type = infer_from_value(first_key)
33
+ value_type = infer_from_value(first_value)
34
+ Kumi::Core::Types.hash(key_type, value_type)
35
+ else
36
+ :any
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
4
+
5
+ module Kumi
6
+ module Core
7
+ module Types
8
+ # Normalizes different type inputs to canonical forms
9
+ class Normalizer
10
+ # Type normalization - convert various inputs to canonical type symbols
11
+ def self.normalize(type_input)
12
+ case type_input
13
+ when Symbol
14
+ return type_input if Validator.valid_type?(type_input)
15
+
16
+ raise ArgumentError, "Invalid type symbol: #{type_input}"
17
+ when String
18
+ symbol_type = type_input.to_sym
19
+ return symbol_type if Validator.valid_type?(symbol_type)
20
+
21
+ raise ArgumentError, "Invalid type string: #{type_input}"
22
+ when Hash
23
+ return type_input if Validator.valid_type?(type_input)
24
+
25
+ raise ArgumentError, "Invalid type hash: #{type_input}"
26
+ when Class
27
+ # Handle Ruby class inputs
28
+ case type_input.name
29
+ when "Integer" then :integer
30
+ when "String" then :string
31
+ when "Float" then :float
32
+ when "TrueClass", "FalseClass" then :boolean
33
+ when "Array" then raise ArgumentError, "Use array(:type) helper for array types"
34
+ when "Hash" then raise ArgumentError, "Use hash(:key_type, :value_type) helper for hash types"
35
+ else
36
+ raise ArgumentError, "Unsupported class type: #{type_input}"
37
+ end
38
+ else
39
+ case type_input
40
+ when Integer, Float, Numeric
41
+ raise ArgumentError, "Type must be a symbol, got #{type_input} (#{type_input.class})"
42
+ else
43
+ raise ArgumentError, "Invalid type input: #{type_input} (#{type_input.class})"
44
+ end
45
+ end
46
+ end
47
+
48
+ # Legacy compatibility - coerce old constants to symbols
49
+ def self.coerce(type_input)
50
+ # Handle legacy constant usage
51
+ return type_input if type_input.is_a?(Symbol) && Validator.valid_type?(type_input)
52
+
53
+ # Handle legacy constant objects
54
+ case type_input
55
+ when STRING then :string
56
+ when INT then :integer
57
+ when FLOAT, NUMERIC then :float # Both FLOAT and NUMERIC map to :float
58
+ when BOOL then :boolean
59
+ when ANY then :any
60
+ when SYMBOL then :symbol
61
+ when REGEXP then :regexp
62
+ when TIME then :time
63
+ when DATE then :date
64
+ when DATETIME then :datetime
65
+ else
66
+ normalize(type_input)
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kumi
4
+ module Core
5
+ module Types
6
+ # Validates type definitions and structures
7
+ class Validator
8
+ VALID_TYPES = %i[string integer float boolean any symbol regexp time date datetime array].freeze
9
+
10
+ def self.valid_type?(type)
11
+ return true if VALID_TYPES.include?(type)
12
+ return true if array_type?(type)
13
+ return true if hash_type?(type)
14
+
15
+ false
16
+ end
17
+
18
+ def self.array_type?(type)
19
+ type.is_a?(Hash) && type.keys == [:array] && valid_type?(type[:array])
20
+ end
21
+
22
+ def self.hash_type?(type)
23
+ type.is_a?(Hash) &&
24
+ type.keys.sort == [:hash] &&
25
+ type[:hash].is_a?(Array) &&
26
+ type[:hash].size == 2 &&
27
+ valid_type?(type[:hash][0]) &&
28
+ valid_type?(type[:hash][1])
29
+ end
30
+
31
+ def self.primitive_type?(type)
32
+ VALID_TYPES.include?(type)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kumi
4
+ module Core
5
+ module Types
6
+ # Re-export constants for compatibility
7
+ VALID_TYPES = Validator::VALID_TYPES
8
+
9
+ # Validation methods
10
+ def self.valid_type?(type)
11
+ Validator.valid_type?(type)
12
+ end
13
+
14
+ # Type builders
15
+ def self.array(elem_type)
16
+ Builder.array(elem_type)
17
+ end
18
+
19
+ def self.hash(key_type, val_type)
20
+ Builder.hash(key_type, val_type)
21
+ end
22
+
23
+ # Normalization
24
+ def self.normalize(type_input)
25
+ Normalizer.normalize(type_input)
26
+ end
27
+
28
+ def self.coerce(type_input)
29
+ Normalizer.coerce(type_input)
30
+ end
31
+
32
+ # Compatibility and unification
33
+ def self.compatible?(type1, type2)
34
+ Compatibility.compatible?(type1, type2)
35
+ end
36
+
37
+ def self.unify(type1, type2)
38
+ Compatibility.unify(type1, type2)
39
+ end
40
+
41
+ # Type inference
42
+ def self.infer_from_value(value)
43
+ Inference.infer_from_value(value)
44
+ end
45
+
46
+ # Formatting
47
+ def self.type_to_s(type)
48
+ Formatter.type_to_s(type)
49
+ end
50
+
51
+ # Legacy compatibility constants (will be phased out)
52
+ # These should be replaced with symbols in user code over time
53
+ STRING = :string
54
+ INT = :integer # NOTE: using :integer instead of :int for clarity
55
+ FLOAT = :float
56
+ BOOL = :boolean
57
+ ANY = :any
58
+ SYMBOL = :symbol
59
+ REGEXP = :regexp
60
+ TIME = :time
61
+ DATE = :date
62
+ DATETIME = :datetime
63
+ NUMERIC = :float # Legacy: represents numeric compatibility
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kumi
4
+ module Core
5
+ # Metadata system for vectorization detection and handling
6
+ module VectorizationMetadata
7
+ # Tracks which declarations are arrays with children (vectorizable)
8
+ class ArrayDeclarationTracker
9
+ def initialize
10
+ @array_declarations = {}
11
+ end
12
+
13
+ def register_array(name, children)
14
+ @array_declarations[name] = children.map(&:name)
15
+ end
16
+
17
+ def array_declaration?(name)
18
+ @array_declarations.key?(name)
19
+ end
20
+
21
+ def array_children(name)
22
+ @array_declarations[name] || []
23
+ end
24
+
25
+ def all_arrays
26
+ @array_declarations.keys
27
+ end
28
+ end
29
+
30
+ # Detects vectorized operations in expressions
31
+ class VectorizationDetector
32
+ def initialize(array_tracker)
33
+ @array_tracker = array_tracker
34
+ end
35
+
36
+ # Check if an expression should be vectorized
37
+ def vectorized_expression?(expression)
38
+ case expression
39
+ when Kumi::Syntax::CallExpression
40
+ vectorized_call?(expression)
41
+ when Kumi::Syntax::InputElementReference
42
+ vectorized_element_reference?(expression)
43
+ else
44
+ false
45
+ end
46
+ end
47
+
48
+ # Check if a function call should be treated as a reducer
49
+ def reducer_function?(fn_name, args)
50
+ REDUCER_FUNCTIONS.include?(fn_name) &&
51
+ args.any? { |arg| vectorized_expression?(arg) }
52
+ end
53
+
54
+ private
55
+
56
+ REDUCER_FUNCTIONS = %i[sum min max size length first last].freeze
57
+
58
+ def vectorized_call?(call_expr)
59
+ # Arithmetic operations between array elements are vectorized
60
+ ARITHMETIC_OPERATIONS.include?(call_expr.fn_name) &&
61
+ call_expr.args.any? { |arg| vectorized_expression?(arg) }
62
+ end
63
+
64
+ def vectorized_element_reference?(elem_ref)
65
+ return false unless elem_ref.path.size >= 2
66
+
67
+ array_name, _field_name = elem_ref.path
68
+ @array_tracker.array_declaration?(array_name)
69
+ end
70
+
71
+ ARITHMETIC_OPERATIONS = %i[add subtract multiply divide modulo power].freeze
72
+ end
73
+
74
+ # Metadata about how values should be computed
75
+ class ComputationMetadata
76
+ attr_reader :vectorized_values, :reducer_values, :scalar_values
77
+
78
+ def initialize
79
+ @vectorized_values = Set.new
80
+ @reducer_values = Set.new
81
+ @scalar_values = Set.new
82
+ end
83
+
84
+ def mark_vectorized(name)
85
+ @vectorized_values.add(name)
86
+ end
87
+
88
+ def mark_reducer(name)
89
+ @reducer_values.add(name)
90
+ end
91
+
92
+ def mark_scalar(name)
93
+ @scalar_values.add(name)
94
+ end
95
+
96
+ def vectorized?(name)
97
+ @vectorized_values.include?(name)
98
+ end
99
+
100
+ def reducer?(name)
101
+ @reducer_values.include?(name)
102
+ end
103
+
104
+ def scalar?(name)
105
+ @scalar_values.include?(name)
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
data/lib/kumi/errors.rb CHANGED
@@ -1,116 +1,5 @@
1
- # frozen_string_literal: true
2
-
3
1
  module Kumi
4
2
  module Errors
5
- class Error < StandardError; end
6
-
7
- class LocatedError < Error
8
- attr_reader :location
9
-
10
- def initialize(message, location = nil)
11
- super(message)
12
- @location = location
13
- end
14
-
15
- def to_s
16
- if @location
17
- "#{super} at #{@location.file}:#{@location.line}:#{@location.column}"
18
- else
19
- super
20
- end
21
- end
22
- end
23
-
24
- class SemanticError < LocatedError; end
25
-
26
- class TypeError < SemanticError; end
27
-
28
- class FieldMetadataError < SemanticError; end
29
-
30
- class SyntaxError < LocatedError; end
31
-
32
- class RuntimeError < Error; end
33
-
34
- class DomainViolationError < Error
35
- attr_reader :violations
36
-
37
- def initialize(violations)
38
- @violations = violations
39
- super(format_message)
40
- end
41
-
42
- def single_violation?
43
- violations.size == 1
44
- end
45
-
46
- def multiple_violations?
47
- violations.size > 1
48
- end
49
-
50
- private
51
-
52
- def format_message
53
- if single_violation?
54
- violations.first[:message]
55
- else
56
- "Multiple domain violations:\n#{violations.map { |v| " - #{v[:message]}" }.join("\n")}"
57
- end
58
- end
59
- end
60
-
61
- class InputValidationError < Error
62
- attr_reader :violations
63
-
64
- def initialize(violations)
65
- @violations = violations
66
- super(format_message)
67
- end
68
-
69
- def single_violation?
70
- violations.size == 1
71
- end
72
-
73
- def multiple_violations?
74
- violations.size > 1
75
- end
76
-
77
- def type_violations
78
- violations.select { |v| v[:type] == :type_violation }
79
- end
80
-
81
- def domain_violations
82
- violations.select { |v| v[:type] == :domain_violation }
83
- end
84
-
85
- def type_violations?
86
- type_violations.any?
87
- end
88
-
89
- def domain_violations?
90
- domain_violations.any?
91
- end
92
-
93
- private
94
-
95
- def format_message
96
- if single_violation?
97
- violations.first[:message]
98
- else
99
- message_parts = []
100
-
101
- if type_violations?
102
- message_parts << "Type violations:"
103
- type_violations.each { |v| message_parts << " - #{v[:message]}" }
104
- end
105
-
106
- if domain_violations?
107
- message_parts << "Domain violations:"
108
- domain_violations.each { |v| message_parts << " - #{v[:message]}" }
109
- end
110
-
111
- message_parts.join("\n")
112
- end
113
- end
114
- end
3
+ include Core::Errors
115
4
  end
116
5
  end
@@ -0,0 +1,37 @@
1
+ module Kumi
2
+ module Registry
3
+ extend Core::FunctionRegistry
4
+ Entry = Core::FunctionRegistry::FunctionBuilder::Entry
5
+
6
+ @functions = Core::FunctionRegistry::CORE_FUNCTIONS.transform_values(&:dup)
7
+ @frozen = false
8
+ @lock = Mutex.new
9
+
10
+ class FrozenError < RuntimeError; end
11
+
12
+ class << self
13
+ def reset!
14
+ @lock.synchronize do
15
+ @functions = Core::FunctionRegistry::CORE_FUNCTIONS.transform_values(&:dup)
16
+ @frozen = false
17
+ end
18
+ end
19
+
20
+ def register(name, &block)
21
+ @lock.synchronize do
22
+ raise FrozenError, "registry is frozen" if @frozen
23
+
24
+ super
25
+ end
26
+ end
27
+
28
+ def freeze!
29
+ @lock.synchronize do
30
+ @functions.each_value(&:freeze)
31
+ @functions.freeze
32
+ @frozen = true
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
data/lib/kumi/schema.rb CHANGED
@@ -17,11 +17,11 @@ module Kumi
17
17
 
18
18
  # Validate input types and domain constraints
19
19
  input_meta = @__analyzer_result__.state[:inputs] || {}
20
- violations = Input::Validator.validate_context(context, input_meta)
20
+ violations = Core::Input::Validator.validate_context(context, input_meta)
21
21
 
22
22
  raise Errors::InputValidationError, violations unless violations.empty?
23
23
 
24
- SchemaInstance.new(@__compiled_schema__, @__analyzer_result__.state, context)
24
+ Core::SchemaInstance.new(@__compiled_schema__, @__analyzer_result__.state, context)
25
25
  end
26
26
 
27
27
  def explain(context, *keys)
@@ -29,19 +29,19 @@ module Kumi
29
29
 
30
30
  # Validate input types and domain constraints
31
31
  input_meta = @__analyzer_result__.state[:inputs] || {}
32
- violations = Input::Validator.validate_context(context, input_meta)
32
+ violations = Core::Input::Validator.validate_context(context, input_meta)
33
33
 
34
34
  raise Errors::InputValidationError, violations unless violations.empty?
35
35
 
36
36
  keys.each do |key|
37
- puts Kumi::Explain.call(self, key, inputs: context)
37
+ puts Core::Explain.call(self, key, inputs: context)
38
38
  end
39
39
 
40
40
  nil
41
41
  end
42
42
 
43
43
  def schema(&block)
44
- @__syntax_tree__ = Kumi::RubyParser::Dsl.build_syntax_tree(&block).freeze
44
+ @__syntax_tree__ = Core::RubyParser::Dsl.build_syntax_tree(&block).freeze
45
45
  @__analyzer_result__ = Analyzer.analyze!(@__syntax_tree__).freeze
46
46
  @__compiled_schema__ = Compiler.compile(@__syntax_tree__, analyzer: @__analyzer_result__).freeze
47
47
 
@@ -210,7 +210,7 @@ module Kumi
210
210
  # # "x-kumi-traits": { ... }
211
211
  # # }
212
212
  def to_json_schema
213
- JsonSchema::Generator.new(self).generate
213
+ Core::JsonSchema::Generator.new(self).generate
214
214
  end
215
215
 
216
216
  # Returns processed declaration metadata.
@@ -412,9 +412,9 @@ module Kumi
412
412
  end
413
413
 
414
414
  function_calls.each_with_object({}) do |func_name, result|
415
- next unless Kumi::FunctionRegistry.supported?(func_name)
415
+ next unless Kumi::Registry.supported?(func_name)
416
416
 
417
- function_info = Kumi::FunctionRegistry.signature(func_name)
417
+ function_info = Kumi::Registry.signature(func_name)
418
418
  result[func_name] = {
419
419
  param_types: function_info[:param_types],
420
420
  return_type: function_info[:return_type],