2012-09-04 13:37:29 -05:00
|
|
|
use std::term;
|
|
|
|
use io::WriterUtil;
|
|
|
|
use codemap::span;
|
2012-01-13 18:05:58 -06:00
|
|
|
|
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-05-22 16:55:39 -05:00
|
|
|
export expect;
|
2012-01-13 19:03:51 -06:00
|
|
|
|
2012-11-12 18:56:39 -06:00
|
|
|
type emitter = fn@(cmsp: Option<(@codemap::CodeMap, span)>,
|
2012-09-28 14:22:33 -05:00
|
|
|
msg: &str, lvl: level);
|
2012-01-13 21:00:09 -06:00
|
|
|
|
|
|
|
|
2012-07-31 12:27:51 -05:00
|
|
|
trait span_handler {
|
2012-09-28 14:22:33 -05:00
|
|
|
fn span_fatal(sp: span, msg: &str) -> !;
|
|
|
|
fn span_err(sp: span, msg: &str);
|
|
|
|
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) -> !;
|
2012-01-24 23:42:54 -06:00
|
|
|
fn handler() -> handler;
|
|
|
|
}
|
|
|
|
|
2012-07-31 12:27:51 -05:00
|
|
|
trait handler {
|
2012-09-28 14:22:33 -05:00
|
|
|
fn fatal(msg: &str) -> !;
|
|
|
|
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();
|
2012-09-28 14:22:33 -05:00
|
|
|
fn warn(msg: &str);
|
|
|
|
fn note(msg: &str);
|
|
|
|
fn bug(msg: &str) -> !;
|
|
|
|
fn unimpl(msg: &str) -> !;
|
2012-11-12 18:56:39 -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-03-26 20:35:18 -05:00
|
|
|
mut err_count: uint,
|
2012-04-15 06:40:05 -05:00
|
|
|
emit: emitter
|
2012-01-24 23:42:54 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
type codemap_t = @{
|
|
|
|
handler: handler,
|
2012-11-12 18:56:39 -06:00
|
|
|
cm: @codemap::CodeMap
|
2012-01-13 19:03:51 -06:00
|
|
|
};
|
|
|
|
|
2012-08-07 20:10:06 -05:00
|
|
|
impl codemap_t: span_handler {
|
2012-09-28 14:22:33 -05:00
|
|
|
fn span_fatal(sp: span, msg: &str) -> ! {
|
2012-08-20 14:23:37 -05:00
|
|
|
self.handler.emit(Some((self.cm, sp)), msg, fatal);
|
2012-01-13 19:03:51 -06:00
|
|
|
fail;
|
|
|
|
}
|
2012-09-28 14:22:33 -05:00
|
|
|
fn span_err(sp: span, msg: &str) {
|
2012-08-20 14:23:37 -05:00
|
|
|
self.handler.emit(Some((self.cm, sp)), msg, error);
|
2012-01-24 23:42:54 -06:00
|
|
|
self.handler.bump_err_count();
|
|
|
|
}
|
2012-09-28 14:22:33 -05:00
|
|
|
fn span_warn(sp: span, msg: &str) {
|
2012-08-20 14:23:37 -05:00
|
|
|
self.handler.emit(Some((self.cm, sp)), msg, warning);
|
2012-01-24 23:42:54 -06:00
|
|
|
}
|
2012-09-28 14:22:33 -05:00
|
|
|
fn span_note(sp: span, msg: &str) {
|
2012-08-20 14:23:37 -05:00
|
|
|
self.handler.emit(Some((self.cm, sp)), msg, note);
|
2012-01-24 23:42:54 -06:00
|
|
|
}
|
2012-09-28 14:22:33 -05:00
|
|
|
fn span_bug(sp: span, msg: &str) -> ! {
|
2012-01-24 23:42:54 -06:00
|
|
|
self.span_fatal(sp, ice_msg(msg));
|
|
|
|
}
|
2012-09-28 14:22:33 -05:00
|
|
|
fn span_unimpl(sp: span, msg: &str) -> ! {
|
2012-07-14 00:57:48 -05:00
|
|
|
self.span_bug(sp, ~"unimplemented " + msg);
|
2012-01-24 23:42:54 -06:00
|
|
|
}
|
|
|
|
fn handler() -> handler {
|
|
|
|
self.handler
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-07 20:10:06 -05:00
|
|
|
impl handler_t: handler {
|
2012-09-28 14:22:33 -05:00
|
|
|
fn fatal(msg: &str) -> ! {
|
2012-08-20 14:23:37 -05:00
|
|
|
self.emit(None, msg, fatal);
|
2012-01-13 19:03:51 -06:00
|
|
|
fail;
|
|
|
|
}
|
2012-09-28 14:22:33 -05:00
|
|
|
fn err(msg: &str) {
|
2012-08-20 14:23:37 -05: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() {
|
2012-06-06 16:28:59 -05:00
|
|
|
let s;
|
2012-08-06 14:34:08 -05:00
|
|
|
match self.err_count {
|
2012-08-03 21:59:04 -05:00
|
|
|
0u => return,
|
|
|
|
1u => s = ~"aborting due to previous error",
|
|
|
|
_ => {
|
2012-08-22 19:24:52 -05:00
|
|
|
s = fmt!("aborting due to %u previous errors",
|
|
|
|
self.err_count);
|
2012-08-03 21:59:04 -05:00
|
|
|
}
|
2012-01-13 19:03:51 -06:00
|
|
|
}
|
2012-06-06 16:28:59 -05:00
|
|
|
self.fatal(s);
|
2012-01-13 19:03:51 -06:00
|
|
|
}
|
2012-09-28 14:22:33 -05:00
|
|
|
fn warn(msg: &str) {
|
2012-08-20 14:23:37 -05:00
|
|
|
self.emit(None, msg, warning);
|
2012-01-13 19:03:51 -06:00
|
|
|
}
|
2012-09-28 14:22:33 -05:00
|
|
|
fn note(msg: &str) {
|
2012-08-20 14:23:37 -05:00
|
|
|
self.emit(None, msg, note);
|
2012-01-13 19:03:51 -06:00
|
|
|
}
|
2012-09-28 14:22:33 -05: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
|
|
|
}
|
2012-09-28 14:22:33 -05:00
|
|
|
fn unimpl(msg: &str) -> ! { self.bug(~"unimplemented " + msg); }
|
2012-11-12 18:56:39 -06:00
|
|
|
fn emit(cmsp: Option<(@codemap::CodeMap, span)>, msg: &str, lvl: level) {
|
2012-04-15 06:40:05 -05:00
|
|
|
self.emit(cmsp, msg, lvl);
|
2012-01-24 23:42:54 -06:00
|
|
|
}
|
2012-01-13 19:03:51 -06:00
|
|
|
}
|
|
|
|
|
2012-09-28 14:22:33 -05:00
|
|
|
fn ice_msg(msg: &str) -> ~str {
|
2012-08-22 19:24:52 -05:00
|
|
|
fmt!("internal compiler error: %s", msg)
|
2012-01-14 02:35:16 -06:00
|
|
|
}
|
|
|
|
|
2012-11-12 18:56:39 -06:00
|
|
|
fn mk_span_handler(handler: handler, cm: @codemap::CodeMap) -> span_handler {
|
2012-01-24 23:42:54 -06:00
|
|
|
@{ handler: handler, cm: cm } as span_handler
|
|
|
|
}
|
|
|
|
|
2012-08-20 14:23:37 -05:00
|
|
|
fn mk_handler(emitter: Option<emitter>) -> handler {
|
2012-01-13 21:00:09 -06:00
|
|
|
|
2012-08-06 14:34:08 -05:00
|
|
|
let emit = match emitter {
|
2012-08-20 14:23:37 -05:00
|
|
|
Some(e) => e,
|
|
|
|
None => {
|
2012-11-12 18:56:39 -06:00
|
|
|
let f = fn@(cmsp: Option<(@codemap::CodeMap, span)>,
|
2012-09-28 14:22:33 -05: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-09-28 14:22:33 -05:00
|
|
|
let x: handler_t = @{
|
|
|
|
mut err_count: 0,
|
2012-04-15 06:40:05 -05:00
|
|
|
emit: emit
|
2012-09-28 14:22:33 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
x as handler
|
2012-01-13 19:03:51 -06:00
|
|
|
}
|
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-09-19 20:00:26 -05:00
|
|
|
impl level : cmp::Eq {
|
|
|
|
pure fn eq(other: &level) -> bool {
|
|
|
|
(self as uint) == ((*other) as uint)
|
|
|
|
}
|
|
|
|
pure fn ne(other: &level) -> bool { !self.eq(other) }
|
|
|
|
}
|
2012-08-27 18:26:35 -05:00
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
fn diagnosticstr(lvl: level) -> ~str {
|
2012-08-06 14:34:08 -05:00
|
|
|
match lvl {
|
2012-08-03 21:59:04 -05: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 {
|
2012-08-06 14:34:08 -05:00
|
|
|
match lvl {
|
2012-08-03 21:59:04 -05: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-09-28 14:22:33 -05:00
|
|
|
fn print_diagnostic(topic: ~str, lvl: level, msg: &str) {
|
2012-07-26 16:50:20 -05:00
|
|
|
let use_color = term::color_supported() &&
|
2012-08-14 15:38:35 -05:00
|
|
|
io::stderr().get_type() == io::Screen;
|
2012-01-13 18:05:58 -06:00
|
|
|
if str::is_not_empty(topic) {
|
2012-08-22 19:24:52 -05:00
|
|
|
io::stderr().write_str(fmt!("%s ", topic));
|
2012-01-13 18:05:58 -06:00
|
|
|
}
|
2012-07-26 16:50:20 -05:00
|
|
|
if use_color {
|
2012-02-08 07:31:17 -06:00
|
|
|
term::fg(io::stderr(), diagnosticcolor(lvl));
|
2012-01-13 18:05:58 -06:00
|
|
|
}
|
2012-08-22 19:24:52 -05:00
|
|
|
io::stderr().write_str(fmt!("%s:", diagnosticstr(lvl)));
|
2012-07-26 16:50:20 -05:00
|
|
|
if use_color {
|
2012-02-08 07:31:17 -06:00
|
|
|
term::reset(io::stderr());
|
2012-01-13 18:05:58 -06:00
|
|
|
}
|
2012-08-22 19:24:52 -05:00
|
|
|
io::stderr().write_str(fmt!(" %s\n", msg));
|
2012-01-13 18:05:58 -06:00
|
|
|
}
|
|
|
|
|
2012-11-12 18:56:39 -06:00
|
|
|
fn emit(cmsp: Option<(@codemap::CodeMap, span)>, msg: &str, lvl: level) {
|
2012-08-06 14:34:08 -05:00
|
|
|
match cmsp {
|
2012-08-20 14:23:37 -05:00
|
|
|
Some((cm, sp)) => {
|
2012-11-12 20:24:56 -06:00
|
|
|
let sp = cm.adjust_span(sp);
|
|
|
|
let ss = cm.span_to_str(sp);
|
|
|
|
let lines = cm.span_to_lines(sp);
|
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-02-04 19:37:24 -06:00
|
|
|
print_macro_backtrace(cm, sp);
|
2012-01-13 18:05:58 -06:00
|
|
|
}
|
2012-08-20 14:23:37 -05:00
|
|
|
None => {
|
2012-07-14 00:57:48 -05:00
|
|
|
print_diagnostic(~"", lvl, msg);
|
2012-01-13 18:05:58 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-12 18:56:39 -06:00
|
|
|
fn highlight_lines(cm: @codemap::CodeMap, sp: span,
|
2012-01-13 18:05:58 -06:00
|
|
|
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;
|
2012-03-15 08:47:03 -05:00
|
|
|
let mut elided = false;
|
2012-06-21 18:44:10 -05:00
|
|
|
let mut display_lines = /* FIXME (#2543) */ copy lines.lines;
|
2012-01-13 18:05:58 -06:00
|
|
|
if vec::len(display_lines) > max_lines {
|
|
|
|
display_lines = vec::slice(display_lines, 0u, max_lines);
|
|
|
|
elided = true;
|
|
|
|
}
|
|
|
|
// Print the offending lines
|
2012-06-30 18:19:07 -05:00
|
|
|
for display_lines.each |line| {
|
2012-09-19 18:55:01 -05:00
|
|
|
io::stderr().write_str(fmt!("%s:%u ", fm.name, *line + 1u));
|
2012-11-12 20:24:56 -06:00
|
|
|
let s = fm.get_line(*line as int) + ~"\n";
|
2012-02-08 07:31:17 -06:00
|
|
|
io::stderr().write_str(s);
|
2012-01-13 18:05:58 -06:00
|
|
|
}
|
|
|
|
if elided {
|
|
|
|
let last_line = display_lines[vec::len(display_lines) - 1u];
|
2012-08-22 19:24:52 -05:00
|
|
|
let s = fmt!("%s:%u ", fm.name, last_line + 1u);
|
2012-03-15 08:47:03 -05:00
|
|
|
let mut indent = str::len(s);
|
2012-07-14 00:57:48 -05:00
|
|
|
let mut out = ~"";
|
|
|
|
while indent > 0u { out += ~" "; indent -= 1u; }
|
|
|
|
out += ~"...\n";
|
2012-02-08 07:31:17 -06:00
|
|
|
io::stderr().write_str(out);
|
2012-01-13 18:05:58 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// If there's one line at fault we can easily point to the problem
|
|
|
|
if vec::len(lines.lines) == 1u {
|
2012-11-12 20:24:56 -06:00
|
|
|
let lo = cm.lookup_char_pos(sp.lo);
|
2012-03-15 08:47:03 -05:00
|
|
|
let mut digits = 0u;
|
|
|
|
let mut num = (lines.lines[0] + 1u) / 10u;
|
2012-01-13 18:05:58 -06:00
|
|
|
|
|
|
|
// how many digits must be indent past?
|
|
|
|
while num > 0u { num /= 10u; digits += 1u; }
|
|
|
|
|
|
|
|
// indent past |name:## | and the 0-offset column location
|
2012-03-15 08:47:03 -05:00
|
|
|
let mut left = str::len(fm.name) + digits + lo.col + 3u;
|
2012-07-14 00:57:48 -05:00
|
|
|
let mut s = ~"";
|
2012-09-21 20:36:32 -05:00
|
|
|
while left > 0u { str::push_char(&mut s, ' '); left -= 1u; }
|
2012-01-13 18:05:58 -06:00
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
s += ~"^";
|
2012-11-12 20:24:56 -06:00
|
|
|
let hi = cm.lookup_char_pos(sp.hi);
|
2012-01-13 18:05:58 -06:00
|
|
|
if hi.col != lo.col {
|
|
|
|
// the ^ already takes up one space
|
2012-03-15 08:47:03 -05:00
|
|
|
let mut width = hi.col - lo.col - 1u;
|
2012-09-21 20:36:32 -05:00
|
|
|
while width > 0u { str::push_char(&mut s, '~'); width -= 1u; }
|
2012-01-13 18:05:58 -06:00
|
|
|
}
|
2012-07-14 00:57:48 -05:00
|
|
|
io::stderr().write_str(s + ~"\n");
|
2012-01-13 18:05:58 -06:00
|
|
|
}
|
|
|
|
}
|
2012-02-04 19:37:24 -06:00
|
|
|
|
2012-11-12 18:56:39 -06:00
|
|
|
fn print_macro_backtrace(cm: @codemap::CodeMap, sp: span) {
|
2012-09-21 21:37:57 -05:00
|
|
|
do option::iter(&sp.expn_info) |ei| {
|
|
|
|
let ss = option::map_default(&ei.callie.span, @~"",
|
2012-11-12 20:24:56 -06:00
|
|
|
|span| @cm.span_to_str(*span));
|
2012-06-07 22:12:05 -05:00
|
|
|
print_diagnostic(*ss, note,
|
2012-10-12 14:32:36 -05:00
|
|
|
fmt!("in expansion of %s!", ei.callie.name));
|
2012-11-12 20:24:56 -06:00
|
|
|
let ss = cm.span_to_str(ei.call_site);
|
2012-07-14 00:57:48 -05:00
|
|
|
print_diagnostic(ss, note, ~"expansion site");
|
2012-02-04 19:37:24 -06:00
|
|
|
print_macro_backtrace(cm, ei.call_site);
|
|
|
|
}
|
|
|
|
}
|
2012-05-22 16:55:39 -05:00
|
|
|
|
2012-09-07 16:52:28 -05:00
|
|
|
fn expect<T: Copy>(diag: span_handler,
|
2012-08-20 14:23:37 -05:00
|
|
|
opt: Option<T>, msg: fn() -> ~str) -> T {
|
2012-08-06 14:34:08 -05:00
|
|
|
match opt {
|
2012-08-20 14:23:37 -05:00
|
|
|
Some(t) => t,
|
|
|
|
None => diag.handler().bug(msg())
|
2012-05-22 16:55:39 -05:00
|
|
|
}
|
|
|
|
}
|