feat(diag): add Diagnostic struct and Rust-style formatter
This commit is contained in:
+88
@@ -32,6 +32,94 @@ func DirExists(path: String) -> bool {
|
|||||||
return bux_dir_exists(path) != 0;
|
return bux_dir_exists(path) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Diagnostic formatting (Rust-style errors with snippets)
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
struct Diagnostic {
|
||||||
|
message: String;
|
||||||
|
line: uint32;
|
||||||
|
column: uint32;
|
||||||
|
severity: int;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read a single line from a file (1-based). Returns "" on error or EOF. */
|
||||||
|
func Diagnostic_GetLine(path: String, lineNum: uint32) -> String {
|
||||||
|
let content: String = bux_read_file(path);
|
||||||
|
if String_Eq(content, "") { return ""; }
|
||||||
|
|
||||||
|
var currentLine: uint32 = 1;
|
||||||
|
var pos: uint = 0;
|
||||||
|
let len: uint = String_Len(content);
|
||||||
|
|
||||||
|
/* Skip lines until we reach lineNum */
|
||||||
|
while currentLine < lineNum && pos < len {
|
||||||
|
if String_CharAt(content, pos) == 10 { /* '\n' */
|
||||||
|
currentLine = currentLine + 1;
|
||||||
|
}
|
||||||
|
pos = pos + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Collect characters until newline or EOF */
|
||||||
|
var buf: String = "";
|
||||||
|
while pos < len && String_CharAt(content, pos) != 10 {
|
||||||
|
buf = String_Concat(buf, String_FromChar(String_CharAt(content, pos) as int));
|
||||||
|
pos = pos + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print a diagnostic in Rust-style format:
|
||||||
|
* error: <message>
|
||||||
|
* --> <path>:<line>:<col>
|
||||||
|
* |
|
||||||
|
* 42 | <source_line>
|
||||||
|
* | <spaces>^
|
||||||
|
*/
|
||||||
|
func Diagnostic_Print(diag: *Diagnostic, sourcePath: String) {
|
||||||
|
/* Severity prefix */
|
||||||
|
if diag.severity == 0 {
|
||||||
|
Print("error: ");
|
||||||
|
} else if diag.severity == 1 {
|
||||||
|
Print("warning: ");
|
||||||
|
} else {
|
||||||
|
Print("note: ");
|
||||||
|
}
|
||||||
|
PrintLine(diag.message);
|
||||||
|
|
||||||
|
/* Location header */
|
||||||
|
Print(" --> ");
|
||||||
|
Print(sourcePath);
|
||||||
|
Print(":");
|
||||||
|
PrintInt(diag.line as int64);
|
||||||
|
Print(":");
|
||||||
|
PrintInt(diag.column as int64);
|
||||||
|
PrintLine("");
|
||||||
|
|
||||||
|
/* Source snippet */
|
||||||
|
let lineText: String = Diagnostic_GetLine(sourcePath, diag.line);
|
||||||
|
if !String_Eq(lineText, "") {
|
||||||
|
let lineNumStr: String = String_FromInt(diag.line as int64);
|
||||||
|
|
||||||
|
Print(" |");
|
||||||
|
PrintLine("");
|
||||||
|
Print(" ");
|
||||||
|
Print(lineNumStr);
|
||||||
|
Print(" | ");
|
||||||
|
PrintLine(lineText);
|
||||||
|
|
||||||
|
/* Underline */
|
||||||
|
Print(" | ");
|
||||||
|
var i: uint32 = 0;
|
||||||
|
while i < diag.column - 1 && i < 120 {
|
||||||
|
Print(" ");
|
||||||
|
i = i + 1;
|
||||||
|
}
|
||||||
|
PrintLine("^");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Import the compiler pipeline
|
// Import the compiler pipeline
|
||||||
// In self-hosting mode, these are compiled together from src/
|
// In self-hosting mode, these are compiled together from src/
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user