260 lines
11 KiB
Plaintext
260 lines
11 KiB
Plaintext
import "@std/mem"
|
|
import "@std/arraylist"
|
|
import "@std/enummap"
|
|
|
|
SourceId :: distinct usize
|
|
|
|
#! borrows a source path and text owned by the compilation or caller.
|
|
Source :: struct {
|
|
path []u8
|
|
text []u8
|
|
}
|
|
|
|
Span :: struct {
|
|
start u32
|
|
end u32
|
|
source SourceId = SourceId(0)
|
|
}
|
|
|
|
DiagnosticId :: distinct u32
|
|
no_diagnostic :: maxval!(DiagnosticId)
|
|
|
|
Code :: enum {
|
|
invalid_character
|
|
float_must_end_with_digit
|
|
unterminated_string
|
|
unexpected_token
|
|
duplicate_name
|
|
unknown_name
|
|
expected_type
|
|
type_not_value
|
|
invalid_void_type
|
|
type_mismatch
|
|
invalid_operand
|
|
integer_division
|
|
not_callable
|
|
argument_count_mismatch
|
|
cannot_infer_type
|
|
missing_return
|
|
return_type_mismatch
|
|
condition_not_bool
|
|
invalid_assignment_target
|
|
break_outside_loop
|
|
continue_outside_loop
|
|
invalid_range_bound
|
|
invalid_for_iterable
|
|
range_value_not_supported
|
|
range_pointer_capture
|
|
range_index_capture
|
|
invalid_array_length
|
|
array_length_mismatch
|
|
invalid_array_element_type
|
|
array_size_overflow
|
|
invalid_index_type
|
|
not_indexable
|
|
invalid_index_assignment
|
|
index_out_of_bounds
|
|
unknown_field
|
|
duplicate_field
|
|
missing_field
|
|
tuple_arity_mismatch
|
|
not_record
|
|
recursive_record
|
|
invalid_record_field_type
|
|
missing_entry
|
|
invalid_entry
|
|
literal_out_of_range
|
|
inexact_integer_literal
|
|
invalid_escape
|
|
read_before_initialization
|
|
write_before_initialization
|
|
initialization_cycle
|
|
integer_overflow
|
|
import_cycle
|
|
invalid_import_path
|
|
package_unavailable
|
|
namespace_not_value
|
|
not_namespace
|
|
invalid_import_alias
|
|
invalid_enum_backing
|
|
invalid_enum_value
|
|
enum_context_required
|
|
invalid_distinct_backing
|
|
invalid_union_tag
|
|
union_initializer_count
|
|
invalid_match_subject
|
|
invalid_match_pattern
|
|
duplicate_match_pattern
|
|
non_exhaustive_match
|
|
unreachable_match_arm
|
|
invalid_match_capture
|
|
inactive_union_field
|
|
invalid_pointer_type
|
|
invalid_address_operand
|
|
invalid_dereference
|
|
invalid_pointer_assignment
|
|
invalid_pointer_access
|
|
null_unwrap
|
|
invalid_slice_bounds
|
|
sentinel_mismatch
|
|
overlapping_memory_copy
|
|
unsupported_foreign_call
|
|
invalid_fallible_type
|
|
invalid_sum_type
|
|
invalid_fallible_operand
|
|
try_outside_fallible
|
|
incompatible_propagated_error
|
|
catch_type_mismatch
|
|
errdefer_outside_fallible
|
|
cleanup_control_flow
|
|
comptime_argument_required
|
|
cannot_infer_generic
|
|
specialization_cycle
|
|
specialization_limit
|
|
comptime_execution_limit
|
|
comptime_value_escape
|
|
inline_loop_control
|
|
invalid_generated_field_name
|
|
invalid_struct_layout
|
|
invalid_c_record_field_type
|
|
}
|
|
|
|
Diagnostic :: struct {
|
|
code Code
|
|
span Span
|
|
}
|
|
|
|
#! owns diagnostic storage and retains its allocator; release with deinit.
|
|
Store :: struct { list arraylist.ArrayList(Diagnostic) }
|
|
|
|
CapacityError :: enum { diagnostic_limit_reached, storage_limit_reached }
|
|
|
|
#! retains `allocator` for added diagnostics; the caller owns the returned Store.
|
|
init proc(allocator mem.Allocator) Store {
|
|
return Store{ list = arraylist.init(allocator) }
|
|
}
|
|
|
|
#! releases diagnostic storage with the retained allocator.
|
|
deinit proc(store @mut Store) void {
|
|
arraylist.deinit(&store.list)
|
|
}
|
|
|
|
#! allocates from the retained allocator; the returned ID is valid until deinit.
|
|
add proc(store @mut Store, code Code, span Span) DiagnosticId ! (mem.AllocError | CapacityError) {
|
|
if (store.list.items.len >= usize(no_diagnostic)) return .diagnostic_limit_reached
|
|
id :: DiagnosticId(store.list.items.len)
|
|
try arraylist.append(&store.list, Diagnostic{ code = code, span = span })
|
|
return id
|
|
}
|
|
|
|
get proc(store @Store, id DiagnosticId) ?Diagnostic {
|
|
if (usize(id) >= store.list.items.len) return null
|
|
return store.list.items[usize(id)]
|
|
}
|
|
|
|
count proc(store @Store) usize {
|
|
return store.list.items.len
|
|
}
|
|
|
|
#! constructed at compile time so missing entries fail compilation; message bytes live for the process lifetime.
|
|
messages :: $enummap.init(Code, []u8, {
|
|
invalid_character = "invalid character",
|
|
float_must_end_with_digit = "float literal must end with a digit",
|
|
unterminated_string = "unterminated string literal",
|
|
unexpected_token = "unexpected token",
|
|
duplicate_name = "duplicate name or forbidden shadowing",
|
|
unknown_name = "unknown name",
|
|
expected_type = "annotation must name a type",
|
|
type_not_value = "type name cannot be used as a value",
|
|
invalid_void_type = "void cannot be stored or used as a parameter type",
|
|
type_mismatch = "incompatible value type",
|
|
invalid_operand = "operator requires compatible operand types",
|
|
integer_division = "division requires float operands",
|
|
not_callable = "value is not callable",
|
|
argument_count_mismatch = "argument count does not match the function signature",
|
|
cannot_infer_type = "cannot infer a type without a type anchor",
|
|
missing_return = "nonvoid function can finish without returning a value",
|
|
return_type_mismatch = "return does not match the function result type",
|
|
condition_not_bool = "condition must have type bool",
|
|
invalid_assignment_target = "assignment requires a mutable local binding",
|
|
break_outside_loop = "break requires an enclosing loop",
|
|
continue_outside_loop = "continue requires an enclosing loop",
|
|
invalid_range_bound = "range bounds must have compatible integer types",
|
|
invalid_for_iterable = "for-loop iteration requires an array, slice, string, single pointer to an array, or direct integer range",
|
|
range_value_not_supported = "first-class range values are not implemented",
|
|
range_pointer_capture = "range loops do not support pointer captures",
|
|
range_index_capture = "range loops do not support index captures",
|
|
invalid_array_length = "array length must be a nonnegative supported compile-time integer",
|
|
array_length_mismatch = "array literal length does not match its type",
|
|
invalid_array_element_type = "array element annotations require a supported concrete value type",
|
|
array_size_overflow = "array storage size exceeds the supported address space",
|
|
invalid_index_type = "array index must have type usize",
|
|
not_indexable = "indexing is currently implemented for fixed arrays only",
|
|
invalid_index_assignment = "indexed assignment requires a writable array element",
|
|
index_out_of_bounds = "index out of bounds",
|
|
unknown_field = "record has no such field",
|
|
duplicate_field = "record field is specified more than once",
|
|
missing_field = "record initializer is missing a required field",
|
|
tuple_arity_mismatch = "tuple initializer arity does not match its type",
|
|
not_record = "field selection requires a record or tuple",
|
|
recursive_record = "record has a recursive by-value layout",
|
|
invalid_record_field_type = "record fields require a concrete value type",
|
|
missing_entry = "program requires a main function",
|
|
invalid_entry = "main must be a function with no parameters",
|
|
literal_out_of_range = "numeric literal is outside its runtime type's range",
|
|
inexact_integer_literal = "integer literal is not exactly representable as float; use a floating literal to allow rounding",
|
|
invalid_escape = "invalid string escape",
|
|
read_before_initialization = "local value was read before initialization",
|
|
write_before_initialization = "local value was assigned before initialization",
|
|
initialization_cycle = "global initialization cycle",
|
|
integer_overflow = "integer arithmetic overflow",
|
|
import_cycle = "package import cycle",
|
|
invalid_import_path = "invalid import path",
|
|
package_unavailable = "cannot load package directory",
|
|
namespace_not_value = "package namespace cannot be used as a value",
|
|
not_namespace = "member selection requires a package namespace",
|
|
invalid_import_alias = "import requires an explicit valid identifier alias",
|
|
invalid_enum_backing = "enum backing must be a concrete integer type",
|
|
invalid_enum_value = "enum values require explicit backing and increasing representable constant integers",
|
|
enum_context_required = "enum literal requires an enum or tagged union context",
|
|
invalid_distinct_backing = "distinct requires a concrete runtime backing type",
|
|
invalid_union_tag = "union tag must be an enum containing every union variant",
|
|
union_initializer_count = "union construction requires exactly one member",
|
|
invalid_match_subject = "match subject must be an enum, tagged union, or scalar",
|
|
invalid_match_pattern = "invalid match pattern",
|
|
duplicate_match_pattern = "duplicate or overlapping match pattern",
|
|
non_exhaustive_match = "match is not exhaustive",
|
|
unreachable_match_arm = "match arm is unreachable",
|
|
invalid_match_capture = "payload capture requires compatible nonvoid tagged union variants",
|
|
inactive_union_field = "tagged union field is not active",
|
|
invalid_pointer_type = "pointer requires a supported concrete pointee type",
|
|
invalid_address_operand = "address-of requires addressable storage",
|
|
invalid_dereference = "dereference requires a pointer",
|
|
invalid_pointer_assignment = "pointer assignment requires a mutable pointee",
|
|
invalid_pointer_access = "pointer does not refer to live accessible storage",
|
|
null_unwrap = "cannot unwrap a null optional",
|
|
invalid_slice_bounds = "slice bounds are invalid",
|
|
sentinel_mismatch = "slice sentinel does not match the expected value",
|
|
overlapping_memory_copy = "memory copy source and destination overlap",
|
|
unsupported_foreign_call = "foreign function calls are unsupported by the interpreter",
|
|
invalid_fallible_type = "fallible type requires a concrete success type and an enum, struct, or tagged union error channel",
|
|
invalid_sum_type = "sum composition requires compatible named enum, struct, or tagged union variants",
|
|
invalid_fallible_operand = "try and catch require a fallible operand",
|
|
try_outside_fallible = "try requires an enclosing fallible function",
|
|
incompatible_propagated_error = "propagated errors are not a subset of the function error channel",
|
|
catch_type_mismatch = "catch handler must produce the success type or terminate",
|
|
errdefer_outside_fallible = "errdefer requires an enclosing fallible function",
|
|
cleanup_control_flow = "cleanup cannot escape with return, break, continue, or try",
|
|
comptime_argument_required = "generic argument must be a compile-time value",
|
|
cannot_infer_generic = "cannot infer consistent compile-time arguments from runtime arguments",
|
|
specialization_cycle = "compile-time specialization depends on its unfinished result",
|
|
specialization_limit = "compile-time specialization exceeds its recursion or instance limit",
|
|
comptime_execution_limit = "compile-time execution exceeds its recursion or step limit",
|
|
comptime_value_escape = "compile-time result cannot escape evaluation as a source value",
|
|
inline_loop_control = "break or continue targeting an inline loop must be compile-time-resolvable",
|
|
invalid_generated_field_name = "generated field name must be an ASCII identifier",
|
|
invalid_struct_layout = "generated record layout must be .auto or .c; C-layout records require at least one field",
|
|
invalid_c_record_field_type = "record field is not a supported C-layout value type",
|
|
})
|
|
|