initial draft

This commit is contained in:
2026-06-09 17:28:28 +02:00
commit 087fdb45d5
40 changed files with 4371 additions and 0 deletions
+104
View File
@@ -0,0 +1,104 @@
package source
import "core:fmt"
import "core:mem"
Span :: struct {
start: int,
end: int,
}
Source :: struct {
path: string,
text: string,
}
Diagnostic :: struct {
span: Span,
message: string,
}
Diagnostics :: struct {
source: ^Source,
items: [dynamic]Diagnostic,
allocator: mem.Allocator,
}
init_diagnostics :: proc(source_file: ^Source, allocator := context.allocator) -> Diagnostics {
result: Diagnostics
result.source = source_file
result.allocator = allocator
result.items.allocator = allocator
return result
}
destroy_diagnostics :: proc(diagnostics: ^Diagnostics) {
for diagnostic in diagnostics.items {
delete(diagnostic.message, diagnostics.allocator)
}
delete(diagnostics.items)
}
add :: proc(diagnostics: ^Diagnostics, span: Span, message: string) -> int {
for diagnostic, id in diagnostics.items {
if diagnostic.span == span && diagnostic.message == message {
return id
}
}
id := len(diagnostics.items)
cloned := fmt.aprintf("%s", message, allocator=diagnostics.allocator)
append(&diagnostics.items, Diagnostic{span=span, message=cloned})
return id
}
addf :: proc(diagnostics: ^Diagnostics, span: Span, format: string, args: ..any) -> int {
message := fmt.aprintf(format, ..args, allocator=diagnostics.allocator)
for diagnostic, id in diagnostics.items {
if diagnostic.span == span && diagnostic.message == message {
delete(message, diagnostics.allocator)
return id
}
}
id := len(diagnostics.items)
append(&diagnostics.items, Diagnostic{span=span, message=message})
return id
}
line_and_column :: proc(source_file: ^Source, offset: int) -> (line, column: int) {
line = 1
column = 1
limit := min(offset, len(source_file.text))
for byte_value in transmute([]byte)source_file.text[:limit] {
if byte_value == '\n' {
line += 1
column = 1
} else {
column += 1
}
}
return
}
format :: proc(diagnostics: ^Diagnostics, id: int, allocator := context.allocator) -> string {
if id < 0 || id >= len(diagnostics.items) {
return fmt.aprintf("%s: compiler recovery error", diagnostics.source.path, allocator=allocator)
}
diagnostic := diagnostics.items[id]
line, column := line_and_column(diagnostics.source, diagnostic.span.start)
return fmt.aprintf(
"%s:%d:%d: error: %s",
diagnostics.source.path,
line,
column,
diagnostic.message,
allocator=allocator,
)
}
print_all :: proc(diagnostics: ^Diagnostics) {
for _, id in diagnostics.items {
message := format(diagnostics, id)
fmt.eprintln(message)
delete(message)
}
}