2012-01-13 18:05:58 -06:00
|
|
|
import std::{io, term};
|
|
|
|
import io::writer_util;
|
|
|
|
import syntax::codemap;
|
|
|
|
import codemap::span;
|
|
|
|
|
2012-01-14 01:25:11 -06:00
|
|
|
export emitter, emit;
|
2012-01-14 00:11:29 -06:00
|
|
|
export level, fatal, error, warning, note;
|
2012-01-24 23:42:54 -06:00
|
|
|
export span_handler, handler, mk_span_handler, mk_handler;
|
|
|
|
export codemap_span_handler, codemap_handler;
|
2012-01-14 02:35:16 -06:00
|
|
|
export ice_msg;
|
2012-01-13 19:03:51 -06:00
|
|
|
|
2012-01-13 21:00:09 -06:00
|
|
|
type emitter = fn@(cmsp: option<(codemap::codemap, span)>,
|
2012-01-14 00:11:29 -06:00
|
|
|
msg: str, lvl: level);
|
2012-01-13 21:00:09 -06:00
|
|
|
|
|
|
|
|
2012-01-24 23:42:54 -06:00
|
|
|
iface span_handler {
|
2012-01-13 19:03:51 -06:00
|
|
|
fn span_fatal(sp: span, msg: str) -> !;
|
|
|
|
fn span_err(sp: span, msg: str);
|
2012-01-24 23:42:54 -06:00
|
|
|
fn span_warn(sp: span, msg: str);
|
|
|
|
fn span_note(sp: span, msg: str);
|
|
|
|
fn span_bug(sp: span, msg: str) -> !;
|
|
|
|
fn span_unimpl(sp: span, msg: str) -> !;
|
|
|
|
fn handler() -> handler;
|
|
|
|
}
|
|
|
|
|
|
|
|
iface handler {
|
|
|
|
fn fatal(msg: str) -> !;
|
2012-01-13 19:03:51 -06:00
|
|
|
fn err(msg: str);
|
2012-01-24 23:42:54 -06:00
|
|
|
fn bump_err_count();
|
2012-01-13 19:03:51 -06:00
|
|
|
fn has_errors() -> bool;
|
|
|
|
fn abort_if_errors();
|
|
|
|
fn warn(msg: str);
|
|
|
|
fn note(msg: str);
|
|
|
|
fn bug(msg: str) -> !;
|
|
|
|
fn unimpl(msg: str) -> !;
|
2012-01-24 23:42:54 -06:00
|
|
|
fn emit(cmsp: option<(codemap::codemap, span)>, msg: str, lvl: level);
|
2012-01-13 19:03:51 -06:00
|
|
|
}
|
|
|
|
|
2012-01-24 23:42:54 -06:00
|
|
|
type handler_t = @{
|
2012-01-13 21:00:09 -06:00
|
|
|
mutable err_count: uint,
|
2012-01-24 23:42:54 -06:00
|
|
|
_emit: emitter
|
|
|
|
};
|
|
|
|
|
|
|
|
type codemap_t = @{
|
|
|
|
handler: handler,
|
|
|
|
cm: codemap::codemap
|
2012-01-13 19:03:51 -06:00
|
|
|
};
|
|
|
|
|
2012-01-24 23:42:54 -06:00
|
|
|
impl codemap_span_handler of span_handler for codemap_t {
|
2012-01-13 19:03:51 -06:00
|
|
|
fn span_fatal(sp: span, msg: str) -> ! {
|
2012-01-24 23:42:54 -06:00
|
|
|
self.handler.emit(some((self.cm, sp)), msg, fatal);
|
2012-01-13 19:03:51 -06:00
|
|
|
fail;
|
|
|
|
}
|
2012-01-24 23:42:54 -06:00
|
|
|
fn span_err(sp: span, msg: str) {
|
|
|
|
self.handler.emit(some((self.cm, sp)), msg, error);
|
|
|
|
self.handler.bump_err_count();
|
|
|
|
}
|
|
|
|
fn span_warn(sp: span, msg: str) {
|
|
|
|
self.handler.emit(some((self.cm, sp)), msg, warning);
|
|
|
|
}
|
|
|
|
fn span_note(sp: span, msg: str) {
|
|
|
|
self.handler.emit(some((self.cm, sp)), msg, note);
|
|
|
|
}
|
|
|
|
fn span_bug(sp: span, msg: str) -> ! {
|
|
|
|
self.span_fatal(sp, ice_msg(msg));
|
|
|
|
}
|
|
|
|
fn span_unimpl(sp: span, msg: str) -> ! {
|
|
|
|
self.span_bug(sp, "unimplemented " + msg);
|
|
|
|
}
|
|
|
|
fn handler() -> handler {
|
|
|
|
self.handler
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl codemap_handler of handler for handler_t {
|
2012-01-13 19:03:51 -06:00
|
|
|
fn fatal(msg: str) -> ! {
|
2012-01-24 23:42:54 -06:00
|
|
|
self._emit(none, msg, fatal);
|
2012-01-13 19:03:51 -06:00
|
|
|
fail;
|
|
|
|
}
|
|
|
|
fn err(msg: str) {
|
2012-01-24 23:42:54 -06:00
|
|
|
self._emit(none, msg, error);
|
2012-01-25 01:07:16 -06:00
|
|
|
self.bump_err_count();
|
2012-01-24 23:42:54 -06:00
|
|
|
}
|
|
|
|
fn bump_err_count() {
|
2012-01-13 19:03:51 -06:00
|
|
|
self.err_count += 1u;
|
|
|
|
}
|
|
|
|
fn has_errors() -> bool { self.err_count > 0u }
|
|
|
|
fn abort_if_errors() {
|
|
|
|
if self.err_count > 0u {
|
|
|
|
self.fatal("aborting due to previous errors");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn warn(msg: str) {
|
2012-01-24 23:42:54 -06:00
|
|
|
self._emit(none, msg, warning);
|
2012-01-13 19:03:51 -06:00
|
|
|
}
|
|
|
|
fn note(msg: str) {
|
2012-01-24 23:42:54 -06:00
|
|
|
self._emit(none, msg, note);
|
2012-01-13 19:03:51 -06:00
|
|
|
}
|
|
|
|
fn bug(msg: str) -> ! {
|
2012-01-14 02:35:16 -06:00
|
|
|
self.fatal(ice_msg(msg));
|
2012-01-13 19:03:51 -06:00
|
|
|
}
|
|
|
|
fn unimpl(msg: str) -> ! { self.bug("unimplemented " + msg); }
|
2012-01-24 23:42:54 -06:00
|
|
|
fn emit(cmsp: option<(codemap::codemap, span)>, msg: str, lvl: level) {
|
|
|
|
self._emit(cmsp, msg, lvl);
|
|
|
|
}
|
2012-01-13 19:03:51 -06:00
|
|
|
}
|
|
|
|
|
2012-01-14 02:35:16 -06:00
|
|
|
fn ice_msg(msg: str) -> str {
|
|
|
|
#fmt["internal compiler error %s", msg]
|
|
|
|
}
|
|
|
|
|
2012-01-24 23:42:54 -06:00
|
|
|
fn mk_span_handler(handler: handler, cm: codemap::codemap) -> span_handler {
|
|
|
|
@{ handler: handler, cm: cm } as span_handler
|
|
|
|
}
|
|
|
|
|
|
|
|
fn mk_handler(emitter: option<emitter>) -> handler {
|
2012-01-13 21:00:09 -06:00
|
|
|
|
|
|
|
let emit = alt emitter {
|
|
|
|
some(e) { e }
|
2012-01-19 00:37:22 -06:00
|
|
|
none {
|
2012-01-13 21:00:09 -06:00
|
|
|
let f = fn@(cmsp: option<(codemap::codemap, span)>,
|
2012-01-14 00:11:29 -06:00
|
|
|
msg: str, t: level) {
|
2012-01-14 01:25:11 -06:00
|
|
|
emit(cmsp, msg, t);
|
2012-01-13 21:00:09 -06:00
|
|
|
};
|
|
|
|
f
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-01-13 19:03:51 -06:00
|
|
|
@{
|
|
|
|
mutable err_count: 0u,
|
2012-01-24 23:42:54 -06:00
|
|
|
_emit: emit
|
2012-01-13 19:03:51 -06:00
|
|
|
} as handler
|
|
|
|
}
|
2012-01-13 18:05:58 -06:00
|
|
|
|
2012-01-19 16:24:03 -06:00
|
|
|
enum level {
|
2012-01-19 19:56:05 -06:00
|
|
|
fatal,
|
|
|
|
error,
|
|
|
|
warning,
|
|
|
|
note,
|
2012-01-13 18:05:58 -06:00
|
|
|
}
|
|
|
|
|
2012-01-14 00:11:29 -06:00
|
|
|
fn diagnosticstr(lvl: level) -> str {
|
|
|
|
alt lvl {
|
2012-01-19 00:37:22 -06:00
|
|
|
fatal { "error" }
|
|
|
|
error { "error" }
|
|
|
|
warning { "warning" }
|
|
|
|
note { "note" }
|
2012-01-13 18:05:58 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-14 00:11:29 -06:00
|
|
|
fn diagnosticcolor(lvl: level) -> u8 {
|
|
|
|
alt lvl {
|
2012-01-19 00:37:22 -06:00
|
|
|
fatal { term::color_bright_red }
|
|
|
|
error { term::color_bright_red }
|
|
|
|
warning { term::color_bright_yellow }
|
|
|
|
note { term::color_bright_green }
|
2012-01-13 18:05:58 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-14 00:11:29 -06:00
|
|
|
fn print_diagnostic(topic: str, lvl: level, msg: str) {
|
2012-01-13 18:05:58 -06:00
|
|
|
if str::is_not_empty(topic) {
|
|
|
|
io::stdout().write_str(#fmt["%s ", topic]);
|
|
|
|
}
|
|
|
|
if term::color_supported() {
|
2012-01-14 00:11:29 -06:00
|
|
|
term::fg(io::stdout(), diagnosticcolor(lvl));
|
2012-01-13 18:05:58 -06:00
|
|
|
}
|
2012-01-14 00:11:29 -06:00
|
|
|
io::stdout().write_str(#fmt["%s:", diagnosticstr(lvl)]);
|
2012-01-13 18:05:58 -06:00
|
|
|
if term::color_supported() {
|
|
|
|
term::reset(io::stdout());
|
|
|
|
}
|
|
|
|
io::stdout().write_str(#fmt[" %s\n", msg]);
|
|
|
|
}
|
|
|
|
|
2012-01-14 01:25:11 -06:00
|
|
|
fn emit(cmsp: option<(codemap::codemap, span)>,
|
|
|
|
msg: str, lvl: level) {
|
2012-01-13 18:05:58 -06:00
|
|
|
alt cmsp {
|
|
|
|
some((cm, sp)) {
|
|
|
|
let ss = codemap::span_to_str(sp, cm);
|
|
|
|
let lines = codemap::span_to_lines(sp, cm);
|
2012-01-14 00:11:29 -06:00
|
|
|
print_diagnostic(ss, lvl, msg);
|
2012-01-13 18:05:58 -06:00
|
|
|
highlight_lines(cm, sp, lines);
|
|
|
|
}
|
2012-01-19 00:37:22 -06:00
|
|
|
none {
|
2012-01-14 00:11:29 -06:00
|
|
|
print_diagnostic("", lvl, msg);
|
2012-01-13 18:05:58 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn highlight_lines(cm: codemap::codemap, sp: span,
|
|
|
|
lines: @codemap::file_lines) {
|
|
|
|
|
2012-02-01 03:18:59 -06:00
|
|
|
let fm = lines.file;
|
2012-01-13 18:05:58 -06:00
|
|
|
|
|
|
|
// 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]);
|
2012-01-25 16:53:45 -06:00
|
|
|
let s = codemap::get_line(fm, line as int);
|
2012-01-13 18:05:58 -06:00
|
|
|
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");
|
|
|
|
}
|
|
|
|
}
|