From a3c50305986416bfdfa29300fee1d101299a08b2 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Mon, 11 Jul 2011 02:27:03 -0400 Subject: [PATCH 1/3] Hack to print lines when error spans are available. --- src/comp/driver/session.rs | 35 ++++++++++++++++++++++++++++++++++- src/comp/front/codemap.rs | 22 ++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/comp/driver/session.rs b/src/comp/driver/session.rs index ed34933d36b2a..a831b7009f86f 100644 --- a/src/comp/driver/session.rs +++ b/src/comp/driver/session.rs @@ -10,6 +10,7 @@ import std::map; import std::option; import std::option::some; import std::option::none; +import std::str; tag os { os_win32; os_macos; os_linux; } @@ -50,8 +51,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 = ":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 + ": "); @@ -63,6 +68,34 @@ 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)) { + 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); + for (uint line in lines.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); + } + } + 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, diff --git a/src/comp/front/codemap.rs b/src/comp/front/codemap.rs index 3e1aa3c59400b..70c9d6915d877 100644 --- a/src/comp/front/codemap.rs +++ b/src/comp/front/codemap.rs @@ -1,5 +1,6 @@ import std::vec; +import std::str; /* A codemap is a thing that maps uints to file/line/column positions @@ -40,6 +41,27 @@ 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); + } + ret str::slice(file, fm.lines.(line), 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 From 1768a1d1ee7a9b4235f2ce552c4739c577486aee Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Mon, 11 Jul 2011 14:31:57 -0400 Subject: [PATCH 2/3] Only print up to six lines on error. Print ^~~~~ to highlight error span. --- src/comp/driver/session.rs | 49 +++++++++++++++++++++++++++++++++++++- src/comp/front/codemap.rs | 4 +++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/comp/driver/session.rs b/src/comp/driver/session.rs index a831b7009f86f..5b8682c7c9097 100644 --- a/src/comp/driver/session.rs +++ b/src/comp/driver/session.rs @@ -11,6 +11,7 @@ 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; } @@ -70,10 +71,20 @@ fn emit_diagnostic(option::t[span] sp, str msg, str kind, u8 color, io::stdout().write_str(#fmt(" %s\n", msg)); alt (maybe_lines) { case (some(?lines)) { + // Print the offending 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); - for (uint line in lines.lines) { + + // 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; + } + 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")) { @@ -81,6 +92,42 @@ fn emit_diagnostic(option::t[span] sp, str msg, str kind, u8 color, } 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 (_) {} } diff --git a/src/comp/front/codemap.rs b/src/comp/front/codemap.rs index 70c9d6915d877..e550b6a9e1675 100644 --- a/src/comp/front/codemap.rs +++ b/src/comp/front/codemap.rs @@ -49,7 +49,9 @@ fn get_line(filemap fm, int line, &str file) -> str { } else { end = fm.lines.(line + 1); } - ret str::slice(file, fm.lines.(line), end); + 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 { From b758cacd01785fd90d83939c8d9f292f601f86ca Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Mon, 11 Jul 2011 14:34:20 -0400 Subject: [PATCH 3/3] Add fixme. --- src/comp/driver/session.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/comp/driver/session.rs b/src/comp/driver/session.rs index 5b8682c7c9097..9a976c4aacf7d 100644 --- a/src/comp/driver/session.rs +++ b/src/comp/driver/session.rs @@ -71,7 +71,8 @@ fn emit_diagnostic(option::t[span] sp, str msg, str kind, u8 color, io::stdout().write_str(#fmt(" %s\n", msg)); alt (maybe_lines) { case (some(?lines)) { - // Print the offending 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); @@ -84,6 +85,7 @@ fn emit_diagnostic(option::t[span] sp, str msg, str kind, u8 color, 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);