9932750e21
Use typed singleton arrays for braceless arm blocks: &[statement] compiled but trapped under the Bro bootstrap.
106 lines
3.5 KiB
Plaintext
106 lines
3.5 KiB
Plaintext
import "@std/mem"
|
|
import "@std/arraylist"
|
|
|
|
Span :: struct {
|
|
start u32
|
|
end u32
|
|
}
|
|
|
|
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,
|
|
missing_entry,
|
|
invalid_entry,
|
|
literal_out_of_range,
|
|
invalid_escape,
|
|
read_before_initialization,
|
|
initialization_cycle,
|
|
integer_overflow,
|
|
}
|
|
|
|
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 }
|
|
|
|
#! 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
|
|
}
|
|
|
|
message proc(code Code) []u8 {
|
|
return match code {
|
|
.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: "if condition must have type bool"
|
|
.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"
|
|
.invalid_escape: "invalid string escape"
|
|
.read_before_initialization: "local value was read before initialization"
|
|
.initialization_cycle: "global initialization cycle"
|
|
.integer_overflow: "integer arithmetic overflow"
|
|
}
|
|
}
|