kumi 0.0.6 → 0.0.8

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 (180) hide show
  1. checksums.yaml +4 -4
  2. data/CLAUDE.md +34 -177
  3. data/README.md +41 -7
  4. data/docs/SYNTAX.md +2 -7
  5. data/docs/features/array-broadcasting.md +1 -1
  6. data/docs/schema_metadata/broadcasts.md +53 -0
  7. data/docs/schema_metadata/cascades.md +45 -0
  8. data/docs/schema_metadata/declarations.md +54 -0
  9. data/docs/schema_metadata/dependencies.md +57 -0
  10. data/docs/schema_metadata/evaluation_order.md +29 -0
  11. data/docs/schema_metadata/examples.md +95 -0
  12. data/docs/schema_metadata/inferred_types.md +46 -0
  13. data/docs/schema_metadata/inputs.md +86 -0
  14. data/docs/schema_metadata.md +108 -0
  15. data/examples/game_of_life.rb +1 -1
  16. data/examples/static_analysis_errors.rb +7 -7
  17. data/lib/kumi/analyzer.rb +20 -20
  18. data/lib/kumi/compiler.rb +44 -50
  19. data/lib/kumi/core/analyzer/analysis_state.rb +39 -0
  20. data/lib/kumi/core/analyzer/constant_evaluator.rb +59 -0
  21. data/lib/kumi/core/analyzer/passes/broadcast_detector.rb +248 -0
  22. data/lib/kumi/core/analyzer/passes/declaration_validator.rb +45 -0
  23. data/lib/kumi/core/analyzer/passes/dependency_resolver.rb +153 -0
  24. data/lib/kumi/core/analyzer/passes/input_collector.rb +139 -0
  25. data/lib/kumi/core/analyzer/passes/name_indexer.rb +26 -0
  26. data/lib/kumi/core/analyzer/passes/pass_base.rb +52 -0
  27. data/lib/kumi/core/analyzer/passes/semantic_constraint_validator.rb +111 -0
  28. data/lib/kumi/core/analyzer/passes/toposorter.rb +110 -0
  29. data/lib/kumi/core/analyzer/passes/type_checker.rb +162 -0
  30. data/lib/kumi/core/analyzer/passes/type_consistency_checker.rb +48 -0
  31. data/lib/kumi/core/analyzer/passes/type_inferencer.rb +236 -0
  32. data/lib/kumi/core/analyzer/passes/unsat_detector.rb +406 -0
  33. data/lib/kumi/core/analyzer/passes/visitor_pass.rb +44 -0
  34. data/lib/kumi/core/atom_unsat_solver.rb +396 -0
  35. data/lib/kumi/core/compiled_schema.rb +43 -0
  36. data/lib/kumi/core/constraint_relationship_solver.rb +641 -0
  37. data/lib/kumi/core/domain/enum_analyzer.rb +55 -0
  38. data/lib/kumi/core/domain/range_analyzer.rb +85 -0
  39. data/lib/kumi/core/domain/validator.rb +82 -0
  40. data/lib/kumi/core/domain/violation_formatter.rb +42 -0
  41. data/lib/kumi/core/error_reporter.rb +166 -0
  42. data/lib/kumi/core/error_reporting.rb +97 -0
  43. data/lib/kumi/core/errors.rb +120 -0
  44. data/lib/kumi/core/evaluation_wrapper.rb +40 -0
  45. data/lib/kumi/core/explain.rb +295 -0
  46. data/lib/kumi/core/export/deserializer.rb +41 -0
  47. data/lib/kumi/core/export/errors.rb +14 -0
  48. data/lib/kumi/core/export/node_builders.rb +142 -0
  49. data/lib/kumi/core/export/node_registry.rb +54 -0
  50. data/lib/kumi/core/export/node_serializers.rb +158 -0
  51. data/lib/kumi/core/export/serializer.rb +25 -0
  52. data/lib/kumi/core/export.rb +35 -0
  53. data/lib/kumi/core/function_registry/collection_functions.rb +202 -0
  54. data/lib/kumi/core/function_registry/comparison_functions.rb +33 -0
  55. data/lib/kumi/core/function_registry/conditional_functions.rb +38 -0
  56. data/lib/kumi/core/function_registry/function_builder.rb +95 -0
  57. data/lib/kumi/core/function_registry/logical_functions.rb +44 -0
  58. data/lib/kumi/core/function_registry/math_functions.rb +74 -0
  59. data/lib/kumi/core/function_registry/string_functions.rb +57 -0
  60. data/lib/kumi/core/function_registry/type_functions.rb +53 -0
  61. data/lib/kumi/{function_registry.rb → core/function_registry.rb} +28 -36
  62. data/lib/kumi/core/input/type_matcher.rb +97 -0
  63. data/lib/kumi/core/input/validator.rb +51 -0
  64. data/lib/kumi/core/input/violation_creator.rb +52 -0
  65. data/lib/kumi/core/json_schema/generator.rb +65 -0
  66. data/lib/kumi/core/json_schema/validator.rb +27 -0
  67. data/lib/kumi/core/json_schema.rb +16 -0
  68. data/lib/kumi/core/ruby_parser/build_context.rb +27 -0
  69. data/lib/kumi/core/ruby_parser/declaration_reference_proxy.rb +38 -0
  70. data/lib/kumi/core/ruby_parser/dsl.rb +14 -0
  71. data/lib/kumi/core/ruby_parser/dsl_cascade_builder.rb +138 -0
  72. data/lib/kumi/core/ruby_parser/expression_converter.rb +128 -0
  73. data/lib/kumi/core/ruby_parser/guard_rails.rb +45 -0
  74. data/lib/kumi/core/ruby_parser/input_builder.rb +127 -0
  75. data/lib/kumi/core/ruby_parser/input_field_proxy.rb +48 -0
  76. data/lib/kumi/core/ruby_parser/input_proxy.rb +31 -0
  77. data/lib/kumi/core/ruby_parser/nested_input.rb +17 -0
  78. data/lib/kumi/core/ruby_parser/parser.rb +71 -0
  79. data/lib/kumi/core/ruby_parser/schema_builder.rb +175 -0
  80. data/lib/kumi/core/ruby_parser/sugar.rb +263 -0
  81. data/lib/kumi/core/ruby_parser.rb +12 -0
  82. data/lib/kumi/core/schema_instance.rb +111 -0
  83. data/lib/kumi/core/types/builder.rb +23 -0
  84. data/lib/kumi/core/types/compatibility.rb +96 -0
  85. data/lib/kumi/core/types/formatter.rb +26 -0
  86. data/lib/kumi/core/types/inference.rb +42 -0
  87. data/lib/kumi/core/types/normalizer.rb +72 -0
  88. data/lib/kumi/core/types/validator.rb +37 -0
  89. data/lib/kumi/core/types.rb +66 -0
  90. data/lib/kumi/core/vectorization_metadata.rb +110 -0
  91. data/lib/kumi/errors.rb +1 -112
  92. data/lib/kumi/registry.rb +37 -0
  93. data/lib/kumi/schema.rb +13 -7
  94. data/lib/kumi/schema_metadata.rb +524 -0
  95. data/lib/kumi/syntax/array_expression.rb +6 -6
  96. data/lib/kumi/syntax/call_expression.rb +4 -4
  97. data/lib/kumi/syntax/cascade_expression.rb +4 -4
  98. data/lib/kumi/syntax/case_expression.rb +4 -4
  99. data/lib/kumi/syntax/declaration_reference.rb +4 -4
  100. data/lib/kumi/syntax/hash_expression.rb +4 -4
  101. data/lib/kumi/syntax/input_declaration.rb +5 -5
  102. data/lib/kumi/syntax/input_element_reference.rb +5 -5
  103. data/lib/kumi/syntax/input_reference.rb +5 -5
  104. data/lib/kumi/syntax/literal.rb +4 -4
  105. data/lib/kumi/syntax/node.rb +34 -34
  106. data/lib/kumi/syntax/root.rb +6 -6
  107. data/lib/kumi/syntax/trait_declaration.rb +4 -4
  108. data/lib/kumi/syntax/value_declaration.rb +4 -4
  109. data/lib/kumi/version.rb +1 -1
  110. data/lib/kumi.rb +14 -0
  111. data/migrate_to_core_iterative.rb +938 -0
  112. data/scripts/generate_function_docs.rb +9 -9
  113. metadata +85 -69
  114. data/lib/generators/trait_engine/templates/schema_spec.rb.erb +0 -27
  115. data/lib/kumi/analyzer/analysis_state.rb +0 -37
  116. data/lib/kumi/analyzer/constant_evaluator.rb +0 -57
  117. data/lib/kumi/analyzer/passes/broadcast_detector.rb +0 -251
  118. data/lib/kumi/analyzer/passes/declaration_validator.rb +0 -43
  119. data/lib/kumi/analyzer/passes/dependency_resolver.rb +0 -151
  120. data/lib/kumi/analyzer/passes/input_collector.rb +0 -137
  121. data/lib/kumi/analyzer/passes/name_indexer.rb +0 -24
  122. data/lib/kumi/analyzer/passes/pass_base.rb +0 -50
  123. data/lib/kumi/analyzer/passes/semantic_constraint_validator.rb +0 -110
  124. data/lib/kumi/analyzer/passes/toposorter.rb +0 -108
  125. data/lib/kumi/analyzer/passes/type_checker.rb +0 -162
  126. data/lib/kumi/analyzer/passes/type_consistency_checker.rb +0 -46
  127. data/lib/kumi/analyzer/passes/type_inferencer.rb +0 -232
  128. data/lib/kumi/analyzer/passes/unsat_detector.rb +0 -406
  129. data/lib/kumi/analyzer/passes/visitor_pass.rb +0 -42
  130. data/lib/kumi/atom_unsat_solver.rb +0 -394
  131. data/lib/kumi/compiled_schema.rb +0 -41
  132. data/lib/kumi/constraint_relationship_solver.rb +0 -638
  133. data/lib/kumi/domain/enum_analyzer.rb +0 -53
  134. data/lib/kumi/domain/range_analyzer.rb +0 -83
  135. data/lib/kumi/domain/validator.rb +0 -80
  136. data/lib/kumi/domain/violation_formatter.rb +0 -40
  137. data/lib/kumi/error_reporter.rb +0 -164
  138. data/lib/kumi/error_reporting.rb +0 -95
  139. data/lib/kumi/evaluation_wrapper.rb +0 -38
  140. data/lib/kumi/explain.rb +0 -281
  141. data/lib/kumi/export/deserializer.rb +0 -39
  142. data/lib/kumi/export/errors.rb +0 -12
  143. data/lib/kumi/export/node_builders.rb +0 -140
  144. data/lib/kumi/export/node_registry.rb +0 -52
  145. data/lib/kumi/export/node_serializers.rb +0 -156
  146. data/lib/kumi/export/serializer.rb +0 -23
  147. data/lib/kumi/export.rb +0 -33
  148. data/lib/kumi/function_registry/collection_functions.rb +0 -200
  149. data/lib/kumi/function_registry/comparison_functions.rb +0 -31
  150. data/lib/kumi/function_registry/conditional_functions.rb +0 -36
  151. data/lib/kumi/function_registry/function_builder.rb +0 -93
  152. data/lib/kumi/function_registry/logical_functions.rb +0 -42
  153. data/lib/kumi/function_registry/math_functions.rb +0 -72
  154. data/lib/kumi/function_registry/string_functions.rb +0 -54
  155. data/lib/kumi/function_registry/type_functions.rb +0 -51
  156. data/lib/kumi/input/type_matcher.rb +0 -95
  157. data/lib/kumi/input/validator.rb +0 -49
  158. data/lib/kumi/input/violation_creator.rb +0 -50
  159. data/lib/kumi/parser/build_context.rb +0 -25
  160. data/lib/kumi/parser/declaration_reference_proxy.rb +0 -36
  161. data/lib/kumi/parser/dsl.rb +0 -12
  162. data/lib/kumi/parser/dsl_cascade_builder.rb +0 -136
  163. data/lib/kumi/parser/expression_converter.rb +0 -126
  164. data/lib/kumi/parser/guard_rails.rb +0 -43
  165. data/lib/kumi/parser/input_builder.rb +0 -125
  166. data/lib/kumi/parser/input_field_proxy.rb +0 -46
  167. data/lib/kumi/parser/input_proxy.rb +0 -29
  168. data/lib/kumi/parser/nested_input.rb +0 -15
  169. data/lib/kumi/parser/parser.rb +0 -68
  170. data/lib/kumi/parser/schema_builder.rb +0 -173
  171. data/lib/kumi/parser/sugar.rb +0 -261
  172. data/lib/kumi/schema_instance.rb +0 -109
  173. data/lib/kumi/types/builder.rb +0 -21
  174. data/lib/kumi/types/compatibility.rb +0 -94
  175. data/lib/kumi/types/formatter.rb +0 -24
  176. data/lib/kumi/types/inference.rb +0 -40
  177. data/lib/kumi/types/normalizer.rb +0 -70
  178. data/lib/kumi/types/validator.rb +0 -35
  179. data/lib/kumi/types.rb +0 -64
  180. data/lib/kumi/vectorization_metadata.rb +0 -108
@@ -1,83 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Kumi
4
- module Domain
5
- class RangeAnalyzer
6
- def self.analyze(range)
7
- {
8
- type: :range,
9
- min: range.begin,
10
- max: range.end,
11
- exclusive_end: range.exclude_end?,
12
- size: calculate_size(range),
13
- sample_values: generate_samples(range),
14
- boundary_values: [range.begin, range.end],
15
- invalid_samples: generate_invalid_samples(range)
16
- }
17
- end
18
-
19
- def self.calculate_size(range)
20
- return :infinite if range.begin.nil? || range.end.nil?
21
- return :large if range.end - range.begin > 1000
22
-
23
- if integer_range?(range)
24
- range.exclude_end? ? range.end - range.begin : range.end - range.begin + 1
25
- else
26
- :continuous
27
- end
28
- end
29
-
30
- def self.generate_samples(range)
31
- samples = [range.begin]
32
-
33
- samples << calculate_midpoint(range) if numeric_range?(range)
34
-
35
- samples << calculate_endpoint(range)
36
- samples.uniq
37
- end
38
-
39
- def self.generate_invalid_samples(range)
40
- invalid = []
41
-
42
- invalid << calculate_before_start(range) if range.begin.is_a?(Numeric)
43
-
44
- invalid << calculate_after_end(range) if range.end.is_a?(Numeric)
45
-
46
- invalid
47
- end
48
-
49
- private_class_method def self.integer_range?(range)
50
- range.begin.is_a?(Integer) && range.end.is_a?(Integer)
51
- end
52
-
53
- private_class_method def self.numeric_range?(range)
54
- range.begin.is_a?(Numeric) && range.end.is_a?(Numeric)
55
- end
56
-
57
- private_class_method def self.calculate_midpoint(range)
58
- mid = (range.begin + range.end) / 2.0
59
- range.begin.is_a?(Integer) ? mid.round : mid
60
- end
61
-
62
- private_class_method def self.calculate_endpoint(range)
63
- if range.exclude_end?
64
- range.end - (range.begin.is_a?(Integer) ? 1 : 0.1)
65
- else
66
- range.end
67
- end
68
- end
69
-
70
- private_class_method def self.calculate_before_start(range)
71
- range.begin - (range.begin.is_a?(Integer) ? 1 : 0.1)
72
- end
73
-
74
- private_class_method def self.calculate_after_end(range)
75
- if range.exclude_end?
76
- range.end
77
- else
78
- range.end + (range.end.is_a?(Integer) ? 1 : 0.1)
79
- end
80
- end
81
- end
82
- end
83
- end
@@ -1,80 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Kumi
4
- module Domain
5
- class Validator
6
- def self.validate_field(_field_name, value, domain)
7
- return true if domain.nil?
8
-
9
- case domain
10
- when Range
11
- domain.cover?(value)
12
- when Array
13
- domain.include?(value)
14
- when Proc
15
- domain.call(value)
16
- else
17
- true
18
- end
19
- end
20
-
21
- def self.validate_context(context, input_meta)
22
- violations = []
23
-
24
- context.each do |field, value|
25
- meta = input_meta[field]
26
- next unless meta&.dig(:domain)
27
-
28
- violations << create_violation(field, value, meta[:domain]) unless validate_field(field, value, meta[:domain])
29
- end
30
-
31
- violations
32
- end
33
-
34
- def self.extract_domain_metadata(input_meta)
35
- metadata = {}
36
-
37
- input_meta.each do |field, meta|
38
- domain = meta[:domain]
39
- next unless domain
40
-
41
- metadata[field] = analyze_domain(field, domain)
42
- end
43
-
44
- metadata
45
- end
46
-
47
- def self.create_violation(field, value, domain)
48
- {
49
- field: field,
50
- value: value,
51
- domain: domain,
52
- message: ViolationFormatter.format_message(field, value, domain)
53
- }
54
- end
55
-
56
- def self.analyze_domain(_field, domain)
57
- case domain
58
- when Range
59
- RangeAnalyzer.analyze(domain)
60
- when Array
61
- EnumAnalyzer.analyze(domain)
62
- when Proc
63
- {
64
- type: :custom,
65
- description: "Custom constraint function",
66
- sample_values: [],
67
- invalid_samples: []
68
- }
69
- else
70
- {
71
- type: :unknown,
72
- constraint: domain,
73
- sample_values: [],
74
- invalid_samples: []
75
- }
76
- end
77
- end
78
- end
79
- end
80
- end
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Kumi
4
- module Domain
5
- class ViolationFormatter
6
- def self.format_message(field, value, domain)
7
- case domain
8
- when Range
9
- format_range_violation(field, value, domain)
10
- when Array
11
- format_array_violation(field, value, domain)
12
- when Proc
13
- format_proc_violation(field, value)
14
- else
15
- format_default_violation(field, value, domain)
16
- end
17
- end
18
-
19
- private_class_method def self.format_range_violation(field, value, range)
20
- if range.exclude_end?
21
- "Field :#{field} value #{value.inspect} is outside domain #{range.begin}...#{range.end} (exclusive)"
22
- else
23
- "Field :#{field} value #{value.inspect} is outside domain #{range.begin}..#{range.end}"
24
- end
25
- end
26
-
27
- private_class_method def self.format_array_violation(field, value, array)
28
- "Field :#{field} value #{value.inspect} is not in allowed values #{array.inspect}"
29
- end
30
-
31
- private_class_method def self.format_proc_violation(field, value)
32
- "Field :#{field} value #{value.inspect} does not satisfy custom domain constraint"
33
- end
34
-
35
- private_class_method def self.format_default_violation(field, value, domain)
36
- "Field :#{field} value #{value.inspect} violates domain constraint #{domain.inspect}"
37
- end
38
- end
39
- end
40
- end
@@ -1,164 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Kumi
4
- # Centralized error reporting interface for consistent location handling
5
- # and error message formatting across the entire codebase.
6
- #
7
- # This module provides a unified way to:
8
- # 1. Report errors with consistent location information
9
- # 2. Format error messages uniformly
10
- # 3. Handle missing location data gracefully
11
- # 4. Support both immediate raising and error accumulation patterns
12
- module ErrorReporter
13
- # Standard error structure for internal use
14
- ErrorEntry = Struct.new(:location, :message, :type, :context, keyword_init: true) do
15
- def to_s
16
- location_str = format_location(location)
17
- "#{location_str}: #{message}"
18
- end
19
-
20
- def location?
21
- location && !location.is_a?(Symbol)
22
- end
23
-
24
- private
25
-
26
- def format_location(loc)
27
- case loc
28
- when nil
29
- "at ?"
30
- when Symbol
31
- "at #{loc}"
32
- when Syntax::Location
33
- "at #{loc.file}:#{loc.line}:#{loc.column}"
34
- else
35
- "at <unknown>"
36
- end
37
- end
38
- end
39
-
40
- module_function
41
-
42
- # Create a standardized error entry
43
- #
44
- # @param message [String] The error message
45
- # @param location [Syntax::Location, Symbol, nil] Location information
46
- # @param type [Symbol] Optional error category (:syntax, :semantic, :type, etc.)
47
- # @param context [Hash] Optional additional context
48
- # @return [ErrorEntry] Structured error entry
49
- def create_error(message, location: nil, type: :semantic, context: {})
50
- ErrorEntry.new(
51
- location: location,
52
- message: message,
53
- type: type,
54
- context: context
55
- )
56
- end
57
-
58
- # Add an error to an accumulator array (for analyzer passes)
59
- #
60
- # @param errors [Array] Error accumulator array
61
- # @param message [String] The error message
62
- # @param location [Syntax::Location, Symbol, nil] Location information
63
- # @param type [Symbol] Error category
64
- # @param context [Hash] Additional context
65
- def add_error(errors, message, location: nil, type: :semantic, context: {})
66
- entry = create_error(message, location: location, type: type, context: context)
67
- errors << entry
68
- entry
69
- end
70
-
71
- # Immediately raise a localized error (for parser)
72
- #
73
- # @param message [String] The error message
74
- # @param location [Syntax::Location, Symbol, nil] Location information
75
- # @param error_class [Class] Exception class to raise
76
- # @param type [Symbol] Error category
77
- # @param context [Hash] Additional context
78
- def raise_error(message, location: nil, error_class: Errors::SemanticError, type: :semantic, context: {})
79
- entry = create_error(message, location: location, type: type, context: context)
80
- # Pass both the formatted message and the original location to the error constructor
81
- raise error_class.new(entry.to_s, location)
82
- end
83
-
84
- # Format multiple errors into a single message
85
- #
86
- # @param errors [Array<ErrorEntry>] Array of error entries
87
- # @return [String] Formatted error message
88
- def format_errors(errors)
89
- errors.map(&:to_s).join("\n")
90
- end
91
-
92
- # Group errors by type for better organization
93
- #
94
- # @param errors [Array<ErrorEntry>] Array of error entries
95
- # @return [Hash] Errors grouped by type
96
- def group_errors_by_type(errors)
97
- errors.group_by(&:type)
98
- end
99
-
100
- # Check if any errors lack location information
101
- #
102
- # @param errors [Array<ErrorEntry>] Array of error entries
103
- # @return [Array<ErrorEntry>] Errors without location info
104
- def missing_location_errors(errors)
105
- errors.reject(&:location?)
106
- end
107
-
108
- # Enhanced error reporting with suggestions and context
109
- #
110
- # @param message [String] Base error message
111
- # @param location [Syntax::Location, nil] Location information
112
- # @param suggestions [Array<String>] Suggested fixes
113
- # @param similar_names [Array<String>] Similar names for typo suggestions
114
- # @param type [Symbol] Error category
115
- # @return [ErrorEntry] Enhanced error entry
116
- def create_enhanced_error(message, location: nil, suggestions: [], similar_names: [], type: :semantic)
117
- enhanced_message = build_enhanced_message(message, suggestions, similar_names)
118
- create_error(enhanced_message, location: location, type: type, context: {
119
- suggestions: suggestions,
120
- similar_names: similar_names
121
- })
122
- end
123
-
124
- # Validate that location information is present where expected
125
- #
126
- # @param errors [Array<ErrorEntry>] Array of error entries
127
- # @param expected_with_location [Array<Symbol>] Error types that should have locations
128
- # @return [Hash] Validation report
129
- def validate_error_locations(errors, expected_with_location: %i[syntax semantic type])
130
- report = {
131
- total_errors: errors.size,
132
- errors_with_location: errors.count(&:location?),
133
- errors_without_location: errors.reject(&:location?),
134
- location_coverage: 0.0
135
- }
136
-
137
- report[:location_coverage] = (report[:errors_with_location].to_f / report[:total_errors]) * 100 if report[:total_errors].positive?
138
-
139
- # Check specific types that should have locations
140
- report[:problematic_errors] = errors.select do |error|
141
- expected_with_location.include?(error.type) && !error.location?
142
- end
143
-
144
- report
145
- end
146
-
147
- private
148
-
149
- def build_enhanced_message(base_message, suggestions, similar_names)
150
- parts = [base_message]
151
-
152
- parts << "Did you mean: #{similar_names.map { |name| "`#{name}`" }.join(', ')}?" unless similar_names.empty?
153
-
154
- unless suggestions.empty?
155
- parts << "Suggestions:"
156
- suggestions.each { |suggestion| parts << " - #{suggestion}" }
157
- end
158
-
159
- parts.join("\n")
160
- end
161
-
162
- module_function :build_enhanced_message
163
- end
164
- end
@@ -1,95 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Kumi
4
- # Mixin module providing error reporting capabilities to classes
5
- # that need to report localized errors consistently.
6
- #
7
- # Usage:
8
- # class MyAnalyzer
9
- # include ErrorReporting
10
- #
11
- # def analyze(errors)
12
- # report_error(errors, "Something went wrong", location: some_location)
13
- # raise_localized_error("Critical error", location: some_location)
14
- # end
15
- # end
16
- module ErrorReporting
17
- # Report an error to an accumulator (analyzer pattern)
18
- #
19
- # @param errors [Array] Error accumulator array
20
- # @param message [String] Error message
21
- # @param location [Syntax::Location, Symbol, nil] Location info
22
- # @param type [Symbol] Error category (:syntax, :semantic, :type, etc.)
23
- # @param context [Hash] Additional context
24
- # @return [ErrorReporter::ErrorEntry] The created error entry
25
- def report_error(errors, message, location: nil, type: :semantic, context: {})
26
- ErrorReporter.add_error(errors, message, location: location, type: type, context: context)
27
- end
28
-
29
- # Immediately raise a localized error (parser pattern)
30
- #
31
- # @param message [String] Error message
32
- # @param location [Syntax::Location, Symbol, nil] Location info
33
- # @param error_class [Class] Exception class to raise
34
- # @param type [Symbol] Error category
35
- # @param context [Hash] Additional context
36
- def raise_localized_error(message, location: nil, error_class: Errors::SemanticError, type: :semantic, context: {})
37
- ErrorReporter.raise_error(message, location: location, error_class: error_class, type: type, context: context)
38
- end
39
-
40
- # Report a syntax error to an accumulator
41
- def report_syntax_error(errors, message, location: nil, context: {})
42
- report_error(errors, message, location: location, type: :syntax, context: context)
43
- end
44
-
45
- # Report a type error to an accumulator
46
- def report_type_error(errors, message, location: nil, context: {})
47
- report_error(errors, message, location: location, type: :type, context: context)
48
- end
49
-
50
- # Report a semantic error to an accumulator
51
- def report_semantic_error(errors, message, location: nil, context: {})
52
- report_error(errors, message, location: location, type: :semantic, context: context)
53
- end
54
-
55
- # Immediately raise a syntax error
56
- def raise_syntax_error(message, location: nil, context: {})
57
- raise_localized_error(message, location: location, error_class: Errors::SyntaxError, type: :syntax, context: context)
58
- end
59
-
60
- # Immediately raise a type error
61
- def raise_type_error(message, location: nil, context: {})
62
- raise_localized_error(message, location: location, error_class: Errors::TypeError, type: :type, context: context)
63
- end
64
-
65
- # Create an enhanced error with suggestions
66
- #
67
- # @param errors [Array] Error accumulator array
68
- # @param message [String] Base error message
69
- # @param location [Syntax::Location, nil] Location info
70
- # @param suggestions [Array<String>] Suggested fixes
71
- # @param similar_names [Array<String>] Similar names for typos
72
- # @param type [Symbol] Error category
73
- def report_enhanced_error(errors, message, location: nil, suggestions: [], similar_names: [], type: :semantic)
74
- entry = ErrorReporter.create_enhanced_error(
75
- message,
76
- location: location,
77
- suggestions: suggestions,
78
- similar_names: similar_names,
79
- type: type
80
- )
81
- errors << entry
82
- entry
83
- end
84
-
85
- # Get current location from caller stack (fallback method)
86
- #
87
- # @return [Syntax::Location] Location based on caller stack
88
- def inferred_location
89
- fallback = caller_locations.find(&:absolute_path)
90
- return nil unless fallback
91
-
92
- Syntax::Location.new(file: fallback.path, line: fallback.lineno, column: 0)
93
- end
94
- end
95
- end
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Kumi
4
- EvaluationWrapper = Struct.new(:ctx) do
5
- def initialize(ctx)
6
- super
7
- @__schema_cache__ = {} # memoization cache for bindings
8
- end
9
-
10
- def [](key)
11
- ctx[key]
12
- end
13
-
14
- def []=(key, value)
15
- ctx[key] = value
16
- end
17
-
18
- def keys
19
- ctx.keys
20
- end
21
-
22
- def key?(key)
23
- ctx.key?(key)
24
- end
25
-
26
- def clear
27
- @__schema_cache__.clear
28
- end
29
-
30
- def clear_cache(*keys)
31
- if keys.empty?
32
- @__schema_cache__.clear
33
- else
34
- keys.each { |key| @__schema_cache__.delete(key) }
35
- end
36
- end
37
- end
38
- end