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, } 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 }