Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Print error lines and highlight error span #660

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 83 additions & 1 deletion src/comp/driver/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import std::map;
import std::option;
import std::option::some;
import std::option::none;
import std::str;
import std::vec;

tag os { os_win32; os_macos; os_linux; }

Expand Down Expand Up @@ -50,8 +52,12 @@ fn span_to_str(span sp, codemap::codemap cm) -> str {
fn emit_diagnostic(option::t[span] sp, str msg, str kind, u8 color,
codemap::codemap cm) {
auto ss = "<input>:0:0:0:0";
let option::t[@file_lines] maybe_lines = none;
alt (sp) {
case (some(?ssp)) { ss = span_to_str(ssp, cm); }
case (some(?ssp)) {
ss = span_to_str(ssp, cm);
maybe_lines = some(span_to_lines(ssp, cm));
}
case (none) { }
}
io::stdout().write_str(ss + ": ");
Expand All @@ -63,6 +69,82 @@ fn emit_diagnostic(option::t[span] sp, str msg, str kind, u8 color,
term::reset(io::stdout().get_buf_writer());
}
io::stdout().write_str(#fmt(" %s\n", msg));
alt (maybe_lines) {
case (some(?lines)) {
// FIXME: reading in the entire file is the worst possible way to
// get access to the necessary lines.
auto rdr = io::file_reader(lines.name);
auto file = str::unsafe_from_bytes(rdr.read_whole_stream());
auto fm = codemap::get_filemap(cm, lines.name);

// arbitrarily only print up to six lines of the error
auto max_lines = 6u;
auto elided = false;
auto display_lines = lines.lines;
if (vec::len(display_lines) > max_lines) {
display_lines = vec::slice(display_lines, 0u, max_lines);
elided = true;
}
// Print the offending lines
for (uint line in display_lines) {
io::stdout().write_str(#fmt("%s:%u ", fm.name, line + 1u));
auto s = codemap::get_line(fm, line as int, file);
if (!str::ends_with(s, "\n")) {
s += "\n";
}
io::stdout().write_str(s);
}
if (elided) {
auto last_line = display_lines.(vec::len(display_lines) - 1u);
auto s = #fmt("%s:%u ", fm.name, last_line + 1u);
auto indent = str::char_len(s);
auto out = "";
while (indent > 0u) { out += " "; indent -= 1u; }
out += "...\n";
io::stdout().write_str(out);
}

// If there's one line at fault we can easily point to the problem
if (vec::len(lines.lines) == 1u) {
auto lo = codemap::lookup_pos(cm, option::get(sp).lo);
auto digits = 0u;
auto num = lines.lines.(0) / 10u;

// how many digits must be indent past?
while (num > 0u) { num /= 10u; digits += 1u; }

// indent past |name:## | and the 0-offset column location
auto left = str::char_len(fm.name) + digits + lo.col + 3u;
auto s = "";
while (left > 0u) { str::push_char(s, ' '); left -= 1u; }

s += "^";
auto hi = codemap::lookup_pos(cm, option::get(sp).hi);
if (hi.col != lo.col) {
// the ^ already takes up one space
auto width = hi.col - lo.col - 1u;
while (width > 0u) {
str::push_char(s, '~');
width -= 1u;
}
}
io::stdout().write_str(s + "\n");
}
}
case (_) {}
}
}

type file_lines = rec(str name, vec[uint] lines);

fn span_to_lines(span sp, codemap::codemap cm) -> @file_lines {
auto lo = codemap::lookup_pos(cm, sp.lo);
auto hi = codemap::lookup_pos(cm, sp.hi);
auto lines = [];
for each (uint i in uint::range(lo.line - 1u, hi.line as uint)) {
lines += [i];
}
ret @rec(name=lo.filename, lines=lines);
}

obj session(ast::crate_num cnum,
Expand Down
24 changes: 24 additions & 0 deletions src/comp/front/codemap.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

import std::vec;
import std::str;


/* A codemap is a thing that maps uints to file/line/column positions
Expand Down Expand Up @@ -40,6 +41,29 @@ fn lookup_pos(codemap map, uint pos) -> loc {
}
ret rec(filename=f.name, line=a + 1u, col=pos - f.lines.(a));
}

fn get_line(filemap fm, int line, &str file) -> str {
let uint end;
if ((line as uint) + 1u >= vec::len(fm.lines)) {
end = str::byte_len(file);
} else {
end = fm.lines.(line + 1);
}
auto begin = fm.lines.(line) - fm.start_pos;
end -= fm.start_pos;
ret str::slice(file, begin, end);
}

fn get_filemap(codemap cm, str filename) -> filemap {
for (filemap fm in cm.files) {
if (fm.name == filename) {
ret fm;
}
}
//XXjdm the following triggers a mismatched type bug
// (or expected function, found _|_)
fail;// ("asking for " + filename + " which we don't know about");
}
//
// Local Variables:
// mode: rust
Expand Down