Files
honey/source/diagnostics/diagnostics.hon
T

158 lines
5.8 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
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
}
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 currently requires a 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",
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",
})