compact compiler ids and spans to reduce memory usage
This commit is contained in:
+63
-27
@@ -3,17 +3,48 @@ package source
|
||||
import "core:fmt"
|
||||
import "core:mem"
|
||||
|
||||
Source_Id :: distinct u32
|
||||
Diagnostic_Id :: distinct u32
|
||||
Offset :: distinct u32
|
||||
|
||||
INVALID_SOURCE :: Source_Id(0xffff_ffff)
|
||||
INVALID_DIAGNOSTIC :: Diagnostic_Id(0xffff_ffff)
|
||||
|
||||
source_id :: proc(index: int) -> Source_Id {
|
||||
assert(index >= 0 && u64(index) < u64(INVALID_SOURCE))
|
||||
return Source_Id(index)
|
||||
}
|
||||
|
||||
diagnostic_id :: proc(index: int) -> Diagnostic_Id {
|
||||
assert(index >= 0 && u64(index) < u64(INVALID_DIAGNOSTIC))
|
||||
return Diagnostic_Id(index)
|
||||
}
|
||||
|
||||
source_index :: proc(id: Source_Id, count: int) -> (int, bool) {
|
||||
index := int(id)
|
||||
return index, id != INVALID_SOURCE && index < count
|
||||
}
|
||||
|
||||
diagnostic_index :: proc(id: Diagnostic_Id, count: int) -> (int, bool) {
|
||||
index := int(id)
|
||||
return index, id != INVALID_DIAGNOSTIC && index < count
|
||||
}
|
||||
|
||||
fits_source_length :: proc(length: u64) -> bool {
|
||||
return length <= u64(max(Offset))
|
||||
}
|
||||
|
||||
Span :: struct {
|
||||
file: int,
|
||||
start: int,
|
||||
end: int,
|
||||
file: Source_Id,
|
||||
start: Offset,
|
||||
end: Offset,
|
||||
}
|
||||
|
||||
Source :: struct {
|
||||
id: int,
|
||||
id: Source_Id,
|
||||
path: string,
|
||||
text: string,
|
||||
line_starts: []int,
|
||||
line_starts: []Offset,
|
||||
}
|
||||
|
||||
Store :: struct {
|
||||
@@ -30,7 +61,7 @@ Diagnostics :: struct {
|
||||
source: ^Source,
|
||||
store: ^Store,
|
||||
items: [dynamic]Diagnostic,
|
||||
index: map[Diagnostic_Key]int,
|
||||
index: map[Diagnostic_Key]Diagnostic_Id,
|
||||
allocator: mem.Allocator,
|
||||
}
|
||||
|
||||
@@ -55,20 +86,22 @@ destroy_store :: proc(store: ^Store) {
|
||||
delete(store.items)
|
||||
}
|
||||
|
||||
make_line_starts :: proc(text: string, allocator: mem.Allocator) -> []int {
|
||||
result: [dynamic]int
|
||||
make_line_starts :: proc(text: string, allocator: mem.Allocator) -> []Offset {
|
||||
assert(fits_source_length(u64(len(text))))
|
||||
result: [dynamic]Offset
|
||||
result.allocator = allocator
|
||||
append(&result, 0)
|
||||
for value, offset in transmute([]byte)text {
|
||||
if value == '\n' {
|
||||
append(&result, offset+1)
|
||||
append(&result, Offset(offset+1))
|
||||
}
|
||||
}
|
||||
return result[:]
|
||||
}
|
||||
|
||||
add_source_owned :: proc(store: ^Store, path: string, text: []byte) -> int {
|
||||
id := len(store.items)
|
||||
add_source_owned :: proc(store: ^Store, path: string, text: []byte) -> Source_Id {
|
||||
assert(fits_source_length(u64(len(text))))
|
||||
id := source_id(len(store.items))
|
||||
owned_text := string(text)
|
||||
append(&store.items, Source{
|
||||
id=id,
|
||||
@@ -79,7 +112,7 @@ add_source_owned :: proc(store: ^Store, path: string, text: []byte) -> int {
|
||||
return id
|
||||
}
|
||||
|
||||
add_source :: proc(store: ^Store, path, text: string) -> int {
|
||||
add_source :: proc(store: ^Store, path, text: string) -> Source_Id {
|
||||
owned := make([]byte, len(text), store.allocator)
|
||||
copy(owned, transmute([]byte)text)
|
||||
return add_source_owned(store, path, owned)
|
||||
@@ -111,51 +144,51 @@ destroy_diagnostics :: proc(diagnostics: ^Diagnostics) {
|
||||
delete(diagnostics.items)
|
||||
}
|
||||
|
||||
add :: proc(diagnostics: ^Diagnostics, span: Span, message: string) -> int {
|
||||
add :: proc(diagnostics: ^Diagnostics, span: Span, message: string) -> Diagnostic_Id {
|
||||
key := Diagnostic_Key{span=span, message=message}
|
||||
if id, ok := diagnostics.index[key]; ok {
|
||||
return id
|
||||
}
|
||||
id := len(diagnostics.items)
|
||||
id := diagnostic_id(len(diagnostics.items))
|
||||
cloned := fmt.aprintf("%s", message, allocator=diagnostics.allocator)
|
||||
append(&diagnostics.items, Diagnostic{span=span, message=cloned})
|
||||
diagnostics.index[Diagnostic_Key{span=span, message=cloned}] = id
|
||||
return id
|
||||
}
|
||||
|
||||
addf :: proc(diagnostics: ^Diagnostics, span: Span, format: string, args: ..any) -> int {
|
||||
addf :: proc(diagnostics: ^Diagnostics, span: Span, format: string, args: ..any) -> Diagnostic_Id {
|
||||
message := fmt.aprintf(format, ..args, allocator=diagnostics.allocator)
|
||||
key := Diagnostic_Key{span=span, message=message}
|
||||
if id, ok := diagnostics.index[key]; ok {
|
||||
delete(message, diagnostics.allocator)
|
||||
return id
|
||||
}
|
||||
id := len(diagnostics.items)
|
||||
id := diagnostic_id(len(diagnostics.items))
|
||||
append(&diagnostics.items, Diagnostic{span=span, message=message})
|
||||
diagnostics.index[Diagnostic_Key{span=span, message=message}] = id
|
||||
return id
|
||||
}
|
||||
|
||||
line_and_column :: proc(source_file: ^Source, offset: int) -> (line, column: int) {
|
||||
line_and_column :: proc(source_file: ^Source, offset: Offset) -> (line, column: int) {
|
||||
if len(source_file.line_starts) > 0 {
|
||||
limit := min(max(offset, 0), len(source_file.text))
|
||||
limit := min(int(offset), len(source_file.text))
|
||||
low := 0
|
||||
high := len(source_file.line_starts)
|
||||
for low < high {
|
||||
middle := low + (high-low)/2
|
||||
if source_file.line_starts[middle] <= limit {
|
||||
if int(source_file.line_starts[middle]) <= limit {
|
||||
low = middle+1
|
||||
} else {
|
||||
high = middle
|
||||
}
|
||||
}
|
||||
line = max(low, 1)
|
||||
column = limit-source_file.line_starts[line-1]+1
|
||||
column = limit-int(source_file.line_starts[line-1])+1
|
||||
return
|
||||
}
|
||||
line = 1
|
||||
column = 1
|
||||
limit := min(max(offset, 0), len(source_file.text))
|
||||
limit := min(int(offset), len(source_file.text))
|
||||
for byte_value in transmute([]byte)source_file.text[:limit] {
|
||||
if byte_value == '\n' {
|
||||
line += 1
|
||||
@@ -168,14 +201,17 @@ line_and_column :: proc(source_file: ^Source, offset: int) -> (line, column: int
|
||||
}
|
||||
|
||||
source_for_span :: proc(diagnostics: ^Diagnostics, span: Span) -> ^Source {
|
||||
if diagnostics.store != nil && span.file >= 0 && span.file < len(diagnostics.store.items) {
|
||||
return &diagnostics.store.items[span.file]
|
||||
if diagnostics.store != nil {
|
||||
if index, ok := source_index(span.file, len(diagnostics.store.items)); ok {
|
||||
return &diagnostics.store.items[index]
|
||||
}
|
||||
}
|
||||
return diagnostics.source
|
||||
}
|
||||
|
||||
format :: proc(diagnostics: ^Diagnostics, id: int, allocator := context.allocator) -> string {
|
||||
if id < 0 || id >= len(diagnostics.items) {
|
||||
format :: proc(diagnostics: ^Diagnostics, id: Diagnostic_Id, allocator := context.allocator) -> string {
|
||||
index, ok := diagnostic_index(id, len(diagnostics.items))
|
||||
if !ok {
|
||||
path := "<unknown>"
|
||||
if diagnostics.source != nil {
|
||||
path = diagnostics.source.path
|
||||
@@ -184,7 +220,7 @@ format :: proc(diagnostics: ^Diagnostics, id: int, allocator := context.allocato
|
||||
}
|
||||
return fmt.aprintf("%s: compiler recovery error", path, allocator=allocator)
|
||||
}
|
||||
diagnostic := diagnostics.items[id]
|
||||
diagnostic := diagnostics.items[index]
|
||||
source_file := source_for_span(diagnostics, diagnostic.span)
|
||||
if source_file == nil {
|
||||
return fmt.aprintf("<unknown>: error: %s", diagnostic.message, allocator=allocator)
|
||||
@@ -202,7 +238,7 @@ format :: proc(diagnostics: ^Diagnostics, id: int, allocator := context.allocato
|
||||
|
||||
print_all :: proc(diagnostics: ^Diagnostics) {
|
||||
for _, id in diagnostics.items {
|
||||
message := format(diagnostics, id)
|
||||
message := format(diagnostics, diagnostic_id(id))
|
||||
fmt.eprintln(message)
|
||||
delete(message)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user