about summary refs log tree commit diff
path: root/src/comp/driver
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2012-01-13 16:05:58 -0800
committerBrian Anderson <banderson@mozilla.com>2012-01-13 16:06:56 -0800
commitced0aa13d385df40f21dcb8471326b2a6b08ba0f (patch)
tree05158b52a4a724704fbfc998eed34b5fc34ac7c5 /src/comp/driver
parentbb1e8d2339cfb360c845b7435e97b4f5eb241991 (diff)
downloadrust-ced0aa13d385df40f21dcb8471326b2a6b08ba0f.tar.gz
rust-ced0aa13d385df40f21dcb8471326b2a6b08ba0f.zip
rustc: Extract driver::diagnostic from syntax::codemap
Diffstat (limited to 'src/comp/driver')
-rw-r--r--src/comp/driver/diagnostic.rs137
-rw-r--r--src/comp/driver/driver.rs2
-rw-r--r--src/comp/driver/session.rs16
3 files changed, 146 insertions, 9 deletions
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 @@ type session = @{targ_cfg: @config,
 
 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 @@ impl session for session {
         }
     }
     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]);