From ced0aa13d385df40f21dcb8471326b2a6b08ba0f Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 13 Jan 2012 16:05:58 -0800 Subject: [PATCH] rustc: Extract driver::diagnostic from syntax::codemap --- src/comp/driver/diagnostic.rs | 137 ++++++++++++++++++++++++++++++++ src/comp/driver/driver.rs | 2 +- src/comp/driver/session.rs | 16 ++-- src/comp/rustc.rc | 1 + src/comp/syntax/codemap.rs | 132 ------------------------------ src/comp/syntax/parse/lexer.rs | 3 +- src/comp/syntax/parse/parser.rs | 9 ++- 7 files changed, 154 insertions(+), 146 deletions(-) create mode 100644 src/comp/driver/diagnostic.rs diff --git a/src/comp/driver/diagnostic.rs b/src/comp/driver/diagnostic.rs new file mode 100644 index 00000000000..5a425eb8429 --- /dev/null +++ b/src/comp/driver/diagnostic.rs @@ -0,0 +1,137 @@ +import std::{io, term}; +import io::writer_util; +import syntax::codemap; +import codemap::span; + +export diagnostictype, warning, error, note; +export print_diagnostic, emit_warning, emit_error, emit_note; + +tag diagnostictype { + warning; + error; + note; +} + +fn diagnosticstr(t: diagnostictype) -> str { + alt t { + warning. { "warning" } + error. { "error" } + note. { "note" } + } +} + +fn diagnosticcolor(t: diagnostictype) -> u8 { + alt t { + warning. { term::color_bright_yellow } + error. { term::color_bright_red } + note. { term::color_bright_green } + } +} + +fn print_diagnostic(topic: str, t: diagnostictype, msg: str) { + if str::is_not_empty(topic) { + io::stdout().write_str(#fmt["%s ", topic]); + } + if term::color_supported() { + term::fg(io::stdout(), diagnosticcolor(t)); + } + io::stdout().write_str(#fmt["%s:", diagnosticstr(t)]); + if term::color_supported() { + term::reset(io::stdout()); + } + io::stdout().write_str(#fmt[" %s\n", msg]); +} + +fn emit_diagnostic(cmsp: option<(codemap::codemap, span)>, + msg: str, t: diagnostictype) { + alt cmsp { + some((cm, sp)) { + let ss = codemap::span_to_str(sp, cm); + let lines = codemap::span_to_lines(sp, cm); + print_diagnostic(ss, t, msg); + highlight_lines(cm, sp, lines); + } + none. { + print_diagnostic("", t, msg); + } + } +} + +fn highlight_lines(cm: codemap::codemap, sp: span, + lines: @codemap::file_lines) { + + // If we're not looking at a real file then we can't re-open it to + // pull out the lines + if lines.name == "-" { ret; } + + // FIXME: reading in the entire file is the worst possible way to + // get access to the necessary lines. + let file = alt io::read_whole_file_str(lines.name) { + result::ok(file) { file } + result::err(e) { + emit_error(none, e); + fail; + } + }; + let fm = codemap::get_filemap(cm, lines.name); + + // arbitrarily only print up to six lines of the error + let max_lines = 6u; + let elided = false; + let 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 line: uint in display_lines { + io::stdout().write_str(#fmt["%s:%u ", fm.name, line + 1u]); + let s = codemap::get_line(fm, line as int, file); + if !str::ends_with(s, "\n") { s += "\n"; } + io::stdout().write_str(s); + } + if elided { + let last_line = display_lines[vec::len(display_lines) - 1u]; + let s = #fmt["%s:%u ", fm.name, last_line + 1u]; + let indent = str::char_len(s); + let 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 { + let lo = codemap::lookup_char_pos(cm, sp.lo); + let digits = 0u; + let num = (lines.lines[0] + 1u) / 10u; + + // how many digits must be indent past? + while num > 0u { num /= 10u; digits += 1u; } + + // indent past |name:## | and the 0-offset column location + let left = str::char_len(fm.name) + digits + lo.col + 3u; + let s = ""; + while left > 0u { str::push_char(s, ' '); left -= 1u; } + + s += "^"; + let hi = codemap::lookup_char_pos(cm, sp.hi); + if hi.col != lo.col { + // the ^ already takes up one space + let width = hi.col - lo.col - 1u; + while width > 0u { str::push_char(s, '~'); width -= 1u; } + } + io::stdout().write_str(s + "\n"); + } +} + +fn emit_warning(cmsp: option<(codemap::codemap, span)>, msg: str) { + emit_diagnostic(cmsp, msg, warning); +} +fn emit_error(cmsp: option<(codemap::codemap, span)>, msg: str) { + emit_diagnostic(cmsp, msg, error); +} +fn emit_note(cmsp: option<(codemap::codemap, span)>, msg: str) { + emit_diagnostic(cmsp, msg, note); +} diff --git a/src/comp/driver/driver.rs b/src/comp/driver/driver.rs index 8d33e83cb58..a2963e7bd91 100644 --- a/src/comp/driver/driver.rs +++ b/src/comp/driver/driver.rs @@ -580,7 +580,7 @@ fn build_output_filenames(ifile: str, } fn early_error(msg: str) -> ! { - codemap::print_diagnostic("", codemap::error, msg); + diagnostic::print_diagnostic("", diagnostic::error, msg); fail; } diff --git a/src/comp/driver/session.rs b/src/comp/driver/session.rs index 479fd97083c..fc8bc444e20 100644 --- a/src/comp/driver/session.rs +++ b/src/comp/driver/session.rs @@ -65,19 +65,19 @@ impl session for session { fn span_fatal(sp: span, msg: str) -> ! { - codemap::emit_error(some((self.parse_sess.cm, sp)), msg); + diagnostic::emit_error(some((self.parse_sess.cm, sp)), msg); fail; } fn fatal(msg: str) -> ! { - codemap::emit_error(none, msg); + diagnostic::emit_error(none, msg); fail; } fn span_err(sp: span, msg: str) { - codemap::emit_error(some((self.parse_sess.cm, sp)), msg); + diagnostic::emit_error(some((self.parse_sess.cm, sp)), msg); self.err_count += 1u; } fn err(msg: str) { - codemap::emit_error(none, msg); + diagnostic::emit_error(none, msg); self.err_count += 1u; } fn has_errors() -> bool { self.err_count > 0u } @@ -87,16 +87,16 @@ fn abort_if_errors() { } } fn span_warn(sp: span, msg: str) { - codemap::emit_warning(some((self.parse_sess.cm, sp)), msg); + diagnostic::emit_warning(some((self.parse_sess.cm, sp)), msg); } fn warn(msg: str) { - codemap::emit_warning(none, msg); + diagnostic::emit_warning(none, msg); } fn span_note(sp: span, msg: str) { - codemap::emit_note(some((self.parse_sess.cm, sp)), msg); + diagnostic::emit_note(some((self.parse_sess.cm, sp)), msg); } fn note(msg: str) { - codemap::emit_note(none, msg); + diagnostic::emit_note(none, msg); } fn span_bug(sp: span, msg: str) -> ! { self.span_fatal(sp, #fmt["internal compiler error %s", msg]); diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc index bc28ea0480a..f688be64374 100644 --- a/src/comp/rustc.rc +++ b/src/comp/rustc.rc @@ -123,6 +123,7 @@ mod metadata { mod driver { mod driver; mod session; + mod diagnostic; } mod util { diff --git a/src/comp/syntax/codemap.rs b/src/comp/syntax/codemap.rs index fc575d1c149..da5e9d13d8d 100644 --- a/src/comp/syntax/codemap.rs +++ b/src/comp/syntax/codemap.rs @@ -1,6 +1,4 @@ import core::{vec, uint, str, option, result}; -import std::{term, io}; -import io::writer_util; import option::{some, none}; type filename = str; @@ -100,136 +98,6 @@ fn span_to_str(sp: span, cm: codemap) -> str { ret res; } -tag diagnostictype { - warning; - error; - note; -} - -fn diagnosticstr(t: diagnostictype) -> str { - alt t { - warning. { "warning" } - error. { "error" } - note. { "note" } - } -} - -fn diagnosticcolor(t: diagnostictype) -> u8 { - alt t { - warning. { term::color_bright_yellow } - error. { term::color_bright_red } - note. { term::color_bright_green } - } -} - -fn print_diagnostic(topic: str, t: diagnostictype, msg: str) { - if str::is_not_empty(topic) { - io::stdout().write_str(#fmt["%s ", topic]); - } - if term::color_supported() { - term::fg(io::stdout(), diagnosticcolor(t)); - } - io::stdout().write_str(#fmt["%s:", diagnosticstr(t)]); - if term::color_supported() { - term::reset(io::stdout()); - } - io::stdout().write_str(#fmt[" %s\n", msg]); -} - -fn emit_diagnostic(cmsp: option<(codemap, span)>, msg: str, - t: diagnostictype) { - alt cmsp { - some((cm, sp)) { - let ss = span_to_str(sp, cm); - let lines = span_to_lines(sp, cm); - print_diagnostic(ss, t, msg); - highlight_lines(cm, sp, lines); - } - none. { - print_diagnostic("", t, msg); - } - } -} - -fn highlight_lines(cm: codemap, sp: span, - lines: @file_lines) { - - // If we're not looking at a real file then we can't re-open it to - // pull out the lines - if lines.name == "-" { ret; } - - // FIXME: reading in the entire file is the worst possible way to - // get access to the necessary lines. - let file = alt io::read_whole_file_str(lines.name) { - result::ok(file) { file } - result::err(e) { - emit_error(none, e); - fail; - } - }; - let fm = get_filemap(cm, lines.name); - - // arbitrarily only print up to six lines of the error - let max_lines = 6u; - let elided = false; - let 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 line: uint in display_lines { - io::stdout().write_str(#fmt["%s:%u ", fm.name, line + 1u]); - let s = get_line(fm, line as int, file); - if !str::ends_with(s, "\n") { s += "\n"; } - io::stdout().write_str(s); - } - if elided { - let last_line = display_lines[vec::len(display_lines) - 1u]; - let s = #fmt["%s:%u ", fm.name, last_line + 1u]; - let indent = str::char_len(s); - let 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 { - let lo = lookup_char_pos(cm, sp.lo); - let digits = 0u; - let num = (lines.lines[0] + 1u) / 10u; - - // how many digits must be indent past? - while num > 0u { num /= 10u; digits += 1u; } - - // indent past |name:## | and the 0-offset column location - let left = str::char_len(fm.name) + digits + lo.col + 3u; - let s = ""; - while left > 0u { str::push_char(s, ' '); left -= 1u; } - - s += "^"; - let hi = lookup_char_pos(cm, sp.hi); - if hi.col != lo.col { - // the ^ already takes up one space - let width = hi.col - lo.col - 1u; - while width > 0u { str::push_char(s, '~'); width -= 1u; } - } - io::stdout().write_str(s + "\n"); - } -} - -fn emit_warning(cmsp: option<(codemap, span)>, msg: str) { - emit_diagnostic(cmsp, msg, warning); -} -fn emit_error(cmsp: option<(codemap, span)>, msg: str) { - emit_diagnostic(cmsp, msg, error); -} -fn emit_note(cmsp: option<(codemap, span)>, msg: str) { - emit_diagnostic(cmsp, msg, note); -} - type file_lines = {name: str, lines: [uint]}; fn span_to_lines(sp: span, cm: codemap::codemap) -> @file_lines { diff --git a/src/comp/syntax/parse/lexer.rs b/src/comp/syntax/parse/lexer.rs index cb247e12a40..cc0850d88b0 100644 --- a/src/comp/syntax/parse/lexer.rs +++ b/src/comp/syntax/parse/lexer.rs @@ -6,6 +6,7 @@ import util::interner; import util::interner::intern; import codemap; +import driver::diagnostic; type reader = @{ cm: codemap::codemap, @@ -47,7 +48,7 @@ fn bump() { } else { self.curr = -1 as char; } } fn err(m: str) { - codemap::emit_error( + diagnostic::emit_error( some((self.cm, ast_util::mk_sp(self.chpos, self.chpos))), m); } } diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index ad8eb0d5175..097ac8e7162 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -10,6 +10,7 @@ import ast::{node_id, spanned}; import front::attr; import lexer::reader; +import driver::diagnostic; tag restriction { UNRESTRICTED; @@ -71,11 +72,11 @@ fn fatal(m: str) -> ! { self.span_fatal(self.span, m); } fn span_fatal(sp: span, m: str) -> ! { - codemap::emit_error(some((self.sess.cm, sp)), m); + diagnostic::emit_error(some((self.sess.cm, sp)), m); fail; } fn warn(m: str) { - codemap::emit_warning(some((self.sess.cm, self.span)), m); + diagnostic::emit_warning(some((self.sess.cm, self.span)), m); } fn get_str(i: token::str_num) -> str { interner::get(*self.reader.interner, i) @@ -92,7 +93,7 @@ fn new_parser_from_file(sess: parse_sess, cfg: ast::crate_cfg, path: str, src } result::err(e) { - codemap::emit_error(none, e); + diagnostic::emit_error(none, e); fail; } }; @@ -2525,7 +2526,7 @@ fn parse_crate_from_file(input: str, cfg: ast::crate_cfg, sess: parse_sess) -> } else if str::ends_with(input, ".rs") { parse_crate_from_source_file(input, cfg, sess) } else { - codemap::emit_error(none, "unknown input file type: " + input); + diagnostic::emit_error(none, "unknown input file type: " + input); fail } }