initial draft
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user