Skip to content

Commit a6a2601

Browse files
author
DigitalCodeCrafter
committed
slightly better error rendering
+ fixed grammar + added a space bteween `-` and operand when pretty printing unary rvalue of mir
1 parent a6bee54 commit a6a2601

3 files changed

Lines changed: 91 additions & 6 deletions

File tree

src/grammar.ebnf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ nud = Number
1919
| Identifier
2020
| "true"
2121
| "false"
22+
| "-", Expression
2223
| "(", Expression, ")"
2324
| "{", { Statement }, "}"
2425
;

src/main.rs

Lines changed: 89 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
1-
use ksi::{backend, common::diagnostics::sinks::Diagnostics, mir::{self, passes::{ConstPropagation, CopyPropagation, DeadLocalElim, Pass, run_passes}, pretty}, semantics, syntax};
1+
use ksi::{backend, common::diagnostics::{Diagnostic, Severity, sinks::Diagnostics}, mir::{self, passes::{ConstPropagation, CopyPropagation, DeadLocalElim, Pass, run_passes}, pretty}, semantics, syntax};
22

33

44
fn main() -> Result<(), ()> {
55
let file_path = std::env::args().nth(1).expect("Missing file path");
66

77
let content = std::fs::read_to_string(file_path).unwrap();
8+
let line_starts = line_indices(&content);
89

910
let mut diagnostics = Diagnostics::empty();
1011
let parsed_ast = syntax::parse(&content, &mut diagnostics);
1112
let (typed_ast, symbols) = semantics::analyze(parsed_ast, &mut diagnostics);
1213
if diagnostics.has_error() {
13-
eprintln!("{:#?}", diagnostics.diagnostics);
14+
render_all(&content, &line_starts, &diagnostics.diagnostics);
1415
return Err(());
1516
}
1617

@@ -26,9 +27,7 @@ fn main() -> Result<(), ()> {
2627

2728
let out = backend::emit(&prog_ir, &mut diagnostics);
2829

29-
if diagnostics.has_error() {
30-
eprintln!("{:#?}", diagnostics.diagnostics);
31-
}
30+
render_all(&content, &line_starts, &diagnostics.diagnostics);
3231

3332
let pretty_ir = pretty::format_body(&prog_ir, "main");
3433
for line in pretty_ir.lines() {
@@ -39,3 +38,88 @@ fn main() -> Result<(), ()> {
3938
Ok(())
4039
}
4140

41+
fn line_indices(src: &str) -> Vec<usize> {
42+
let mut line_starts = vec![0];
43+
for (i, b) in src.bytes().enumerate() {
44+
if b == b'\n' {
45+
line_starts.push(i + 1);
46+
}
47+
}
48+
line_starts
49+
}
50+
51+
fn line_col(src: &str, line_starts: &[usize], pos: usize) -> (usize, usize) {
52+
let line = match line_starts.binary_search(&pos) {
53+
Ok(i) => i,
54+
Err(i) => i - 1,
55+
};
56+
57+
let col = src[line_starts[line]..pos].chars().count();
58+
(line + 1, col + 1)
59+
}
60+
61+
fn get_line<'a>(src: &'a str, line_idx: usize, line_starts: &[usize]) -> &'a str {
62+
let start = line_starts[line_idx];
63+
let end = if line_idx + 1 < line_starts.len() {
64+
line_starts[line_idx + 1] - 1
65+
} else {
66+
src.len()
67+
};
68+
&src[start..end]
69+
}
70+
71+
fn print_marker(line: &str, col: usize, marker: char, message: Option<&str>) {
72+
let mut pos = 0;
73+
for c in line.chars().take(col - 1) {
74+
if c == '\t' { pos += 4 }
75+
else { pos += 1 }
76+
}
77+
let padding = " ".repeat(pos);
78+
if let Some(msg) = message {
79+
print!("{padding}{} {}\n", marker, msg);
80+
} else {
81+
print!("{padding}{}\n", marker)
82+
}
83+
}
84+
85+
fn render_diagnostic(diag: &Diagnostic, line_starts: &[usize], src: &str) {
86+
let severity = match diag.severity {
87+
Severity::Note => "note",
88+
Severity::Warning => "warning",
89+
Severity::Error => "error"
90+
};
91+
print!("{}: {}\n", severity, diag.message);
92+
93+
if let Some(span) = diag.span {
94+
let loc = line_col(src, line_starts, span.start);
95+
print!(" --> input:{}:{}\n", loc.0, loc.1);
96+
97+
let source_line = get_line(src, loc.0 - 1, line_starts);
98+
print!(" |\n{:>2} | {}\n", loc.0, source_line);
99+
}
100+
101+
for label in &diag.labels {
102+
let loc = line_col(src, line_starts, label.span.start);
103+
let source_line = get_line(src, loc.0 - 1, line_starts);
104+
let marker = if label.is_primary { '^' } else { '-' };
105+
print!(" ");
106+
print_marker(source_line, loc.1, marker, label.message.as_deref());
107+
}
108+
109+
for note in &diag.notes {
110+
print!(" = {}\n", note);
111+
}
112+
113+
println!();
114+
}
115+
116+
fn render_all(src: &str, line_starts: &[usize], diags: &[Diagnostic]) {
117+
let mut error_count = 0;
118+
for diag in diags {
119+
if diag.severity == Severity::Error { error_count += 1 }
120+
render_diagnostic(diag, line_starts, src);
121+
}
122+
if error_count > 0 {
123+
println!("error: compilation failed due to {} previous errors", error_count)
124+
}
125+
}

src/mir/pretty.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ pub fn format_rval(rv: &RValue) -> String {
4646
}
4747
RValue::Unary(op, val) => {
4848
let op_str = match op {
49-
UnaryOp::Neg => "-"
49+
UnaryOp::Neg => "- "
5050
};
5151
format!("{}{}",
5252
op_str,

0 commit comments

Comments
 (0)