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.
- checksums.yaml +4 -4
- data/CLAUDE.md +34 -177
- data/README.md +41 -7
- data/docs/SYNTAX.md +2 -7
- data/docs/features/array-broadcasting.md +1 -1
- 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/game_of_life.rb +1 -1
- data/examples/static_analysis_errors.rb +7 -7
- data/lib/kumi/analyzer.rb +20 -20
- data/lib/kumi/compiler.rb +44 -50
- data/lib/kumi/core/analyzer/analysis_state.rb +39 -0
- data/lib/kumi/core/analyzer/constant_evaluator.rb +59 -0
- data/lib/kumi/core/analyzer/passes/broadcast_detector.rb +248 -0
- data/lib/kumi/core/analyzer/passes/declaration_validator.rb +45 -0
- data/lib/kumi/core/analyzer/passes/dependency_resolver.rb +153 -0
- data/lib/kumi/core/analyzer/passes/input_collector.rb +139 -0
- data/lib/kumi/core/analyzer/passes/name_indexer.rb +26 -0
- data/lib/kumi/core/analyzer/passes/pass_base.rb +52 -0
- data/lib/kumi/core/analyzer/passes/semantic_constraint_validator.rb +111 -0
- data/lib/kumi/core/analyzer/passes/toposorter.rb +110 -0
- data/lib/kumi/core/analyzer/passes/type_checker.rb +162 -0
- data/lib/kumi/core/analyzer/passes/type_consistency_checker.rb +48 -0
- data/lib/kumi/core/analyzer/passes/type_inferencer.rb +236 -0
- data/lib/kumi/core/analyzer/passes/unsat_detector.rb +406 -0
- data/lib/kumi/core/analyzer/passes/visitor_pass.rb +44 -0
- data/lib/kumi/core/atom_unsat_solver.rb +396 -0
- data/lib/kumi/core/compiled_schema.rb +43 -0
- data/lib/kumi/core/constraint_relationship_solver.rb +641 -0
- data/lib/kumi/core/domain/enum_analyzer.rb +55 -0
- data/lib/kumi/core/domain/range_analyzer.rb +85 -0
- data/lib/kumi/core/domain/validator.rb +82 -0
- data/lib/kumi/core/domain/violation_formatter.rb +42 -0
- data/lib/kumi/core/error_reporter.rb +166 -0
- data/lib/kumi/core/error_reporting.rb +97 -0
- data/lib/kumi/core/errors.rb +120 -0
- data/lib/kumi/core/evaluation_wrapper.rb +40 -0
- data/lib/kumi/core/explain.rb +295 -0
- data/lib/kumi/core/export/deserializer.rb +41 -0
- data/lib/kumi/core/export/errors.rb +14 -0
- data/lib/kumi/core/export/node_builders.rb +142 -0
- data/lib/kumi/core/export/node_registry.rb +54 -0
- data/lib/kumi/core/export/node_serializers.rb +158 -0
- data/lib/kumi/core/export/serializer.rb +25 -0
- data/lib/kumi/core/export.rb +35 -0
- data/lib/kumi/core/function_registry/collection_functions.rb +202 -0
- data/lib/kumi/core/function_registry/comparison_functions.rb +33 -0
- data/lib/kumi/core/function_registry/conditional_functions.rb +38 -0
- data/lib/kumi/core/function_registry/function_builder.rb +95 -0
- data/lib/kumi/core/function_registry/logical_functions.rb +44 -0
- data/lib/kumi/core/function_registry/math_functions.rb +74 -0
- data/lib/kumi/core/function_registry/string_functions.rb +57 -0
- data/lib/kumi/core/function_registry/type_functions.rb +53 -0
- data/lib/kumi/{function_registry.rb → core/function_registry.rb} +28 -36
- data/lib/kumi/core/input/type_matcher.rb +97 -0
- data/lib/kumi/core/input/validator.rb +51 -0
- data/lib/kumi/core/input/violation_creator.rb +52 -0
- data/lib/kumi/core/json_schema/generator.rb +65 -0
- data/lib/kumi/core/json_schema/validator.rb +27 -0
- data/lib/kumi/core/json_schema.rb +16 -0
- data/lib/kumi/core/ruby_parser/build_context.rb +27 -0
- data/lib/kumi/core/ruby_parser/declaration_reference_proxy.rb +38 -0
- data/lib/kumi/core/ruby_parser/dsl.rb +14 -0
- data/lib/kumi/core/ruby_parser/dsl_cascade_builder.rb +138 -0
- data/lib/kumi/core/ruby_parser/expression_converter.rb +128 -0
- data/lib/kumi/core/ruby_parser/guard_rails.rb +45 -0
- data/lib/kumi/core/ruby_parser/input_builder.rb +127 -0
- data/lib/kumi/core/ruby_parser/input_field_proxy.rb +48 -0
- data/lib/kumi/core/ruby_parser/input_proxy.rb +31 -0
- data/lib/kumi/core/ruby_parser/nested_input.rb +17 -0
- data/lib/kumi/core/ruby_parser/parser.rb +71 -0
- data/lib/kumi/core/ruby_parser/schema_builder.rb +175 -0
- data/lib/kumi/core/ruby_parser/sugar.rb +263 -0
- data/lib/kumi/core/ruby_parser.rb +12 -0
- data/lib/kumi/core/schema_instance.rb +111 -0
- data/lib/kumi/core/types/builder.rb +23 -0
- data/lib/kumi/core/types/compatibility.rb +96 -0
- data/lib/kumi/core/types/formatter.rb +26 -0
- data/lib/kumi/core/types/inference.rb +42 -0
- data/lib/kumi/core/types/normalizer.rb +72 -0
- data/lib/kumi/core/types/validator.rb +37 -0
- data/lib/kumi/core/types.rb +66 -0
- data/lib/kumi/core/vectorization_metadata.rb +110 -0
- data/lib/kumi/errors.rb +1 -112
- data/lib/kumi/registry.rb +37 -0
- data/lib/kumi/schema.rb +13 -7
- data/lib/kumi/schema_metadata.rb +524 -0
- data/lib/kumi/syntax/array_expression.rb +6 -6
- data/lib/kumi/syntax/call_expression.rb +4 -4
- data/lib/kumi/syntax/cascade_expression.rb +4 -4
- data/lib/kumi/syntax/case_expression.rb +4 -4
- data/lib/kumi/syntax/declaration_reference.rb +4 -4
- data/lib/kumi/syntax/hash_expression.rb +4 -4
- data/lib/kumi/syntax/input_declaration.rb +5 -5
- data/lib/kumi/syntax/input_element_reference.rb +5 -5
- data/lib/kumi/syntax/input_reference.rb +5 -5
- data/lib/kumi/syntax/literal.rb +4 -4
- data/lib/kumi/syntax/node.rb +34 -34
- data/lib/kumi/syntax/root.rb +6 -6
- data/lib/kumi/syntax/trait_declaration.rb +4 -4
- data/lib/kumi/syntax/value_declaration.rb +4 -4
- data/lib/kumi/version.rb +1 -1
- data/lib/kumi.rb +14 -0
- data/migrate_to_core_iterative.rb +938 -0
- data/scripts/generate_function_docs.rb +9 -9
- metadata +85 -69
- data/lib/generators/trait_engine/templates/schema_spec.rb.erb +0 -27
- data/lib/kumi/analyzer/analysis_state.rb +0 -37
- data/lib/kumi/analyzer/constant_evaluator.rb +0 -57
- data/lib/kumi/analyzer/passes/broadcast_detector.rb +0 -251
- data/lib/kumi/analyzer/passes/declaration_validator.rb +0 -43
- data/lib/kumi/analyzer/passes/dependency_resolver.rb +0 -151
- data/lib/kumi/analyzer/passes/input_collector.rb +0 -137
- data/lib/kumi/analyzer/passes/name_indexer.rb +0 -24
- data/lib/kumi/analyzer/passes/pass_base.rb +0 -50
- data/lib/kumi/analyzer/passes/semantic_constraint_validator.rb +0 -110
- data/lib/kumi/analyzer/passes/toposorter.rb +0 -108
- data/lib/kumi/analyzer/passes/type_checker.rb +0 -162
- data/lib/kumi/analyzer/passes/type_consistency_checker.rb +0 -46
- data/lib/kumi/analyzer/passes/type_inferencer.rb +0 -232
- data/lib/kumi/analyzer/passes/unsat_detector.rb +0 -406
- data/lib/kumi/analyzer/passes/visitor_pass.rb +0 -42
- data/lib/kumi/atom_unsat_solver.rb +0 -394
- data/lib/kumi/compiled_schema.rb +0 -41
- data/lib/kumi/constraint_relationship_solver.rb +0 -638
- data/lib/kumi/domain/enum_analyzer.rb +0 -53
- data/lib/kumi/domain/range_analyzer.rb +0 -83
- data/lib/kumi/domain/validator.rb +0 -80
- data/lib/kumi/domain/violation_formatter.rb +0 -40
- data/lib/kumi/error_reporter.rb +0 -164
- data/lib/kumi/error_reporting.rb +0 -95
- data/lib/kumi/evaluation_wrapper.rb +0 -38
- data/lib/kumi/explain.rb +0 -281
- data/lib/kumi/export/deserializer.rb +0 -39
- data/lib/kumi/export/errors.rb +0 -12
- data/lib/kumi/export/node_builders.rb +0 -140
- data/lib/kumi/export/node_registry.rb +0 -52
- data/lib/kumi/export/node_serializers.rb +0 -156
- data/lib/kumi/export/serializer.rb +0 -23
- data/lib/kumi/export.rb +0 -33
- data/lib/kumi/function_registry/collection_functions.rb +0 -200
- data/lib/kumi/function_registry/comparison_functions.rb +0 -31
- data/lib/kumi/function_registry/conditional_functions.rb +0 -36
- data/lib/kumi/function_registry/function_builder.rb +0 -93
- data/lib/kumi/function_registry/logical_functions.rb +0 -42
- data/lib/kumi/function_registry/math_functions.rb +0 -72
- data/lib/kumi/function_registry/string_functions.rb +0 -54
- data/lib/kumi/function_registry/type_functions.rb +0 -51
- data/lib/kumi/input/type_matcher.rb +0 -95
- data/lib/kumi/input/validator.rb +0 -49
- data/lib/kumi/input/violation_creator.rb +0 -50
- data/lib/kumi/parser/build_context.rb +0 -25
- data/lib/kumi/parser/declaration_reference_proxy.rb +0 -36
- data/lib/kumi/parser/dsl.rb +0 -12
- data/lib/kumi/parser/dsl_cascade_builder.rb +0 -136
- data/lib/kumi/parser/expression_converter.rb +0 -126
- data/lib/kumi/parser/guard_rails.rb +0 -43
- data/lib/kumi/parser/input_builder.rb +0 -125
- data/lib/kumi/parser/input_field_proxy.rb +0 -46
- data/lib/kumi/parser/input_proxy.rb +0 -29
- data/lib/kumi/parser/nested_input.rb +0 -15
- data/lib/kumi/parser/parser.rb +0 -68
- data/lib/kumi/parser/schema_builder.rb +0 -173
- data/lib/kumi/parser/sugar.rb +0 -261
- data/lib/kumi/schema_instance.rb +0 -109
- data/lib/kumi/types/builder.rb +0 -21
- data/lib/kumi/types/compatibility.rb +0 -94
- data/lib/kumi/types/formatter.rb +0 -24
- data/lib/kumi/types/inference.rb +0 -40
- data/lib/kumi/types/normalizer.rb +0 -70
- data/lib/kumi/types/validator.rb +0 -35
- data/lib/kumi/types.rb +0 -64
- 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
|
data/lib/kumi/error_reporter.rb
DELETED
@@ -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
|
data/lib/kumi/error_reporting.rb
DELETED
@@ -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
|