rustc: Extract driver::diagnostic from syntax::codemap
This commit is contained in:
parent
bb1e8d2339
commit
ced0aa13d3
7 changed files with 154 additions and 146 deletions
137
src/comp/driver/diagnostic.rs
Normal file
137
src/comp/driver/diagnostic.rs
Normal file
|
@ -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);
|
||||||
|
}
|
|
@ -580,7 +580,7 @@ fn build_output_filenames(ifile: str,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn early_error(msg: str) -> ! {
|
fn early_error(msg: str) -> ! {
|
||||||
codemap::print_diagnostic("", codemap::error, msg);
|
diagnostic::print_diagnostic("", diagnostic::error, msg);
|
||||||
fail;
|
fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,19 +65,19 @@ type session = @{targ_cfg: @config,
|
||||||
|
|
||||||
impl session for session {
|
impl session for session {
|
||||||
fn span_fatal(sp: span, msg: str) -> ! {
|
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;
|
fail;
|
||||||
}
|
}
|
||||||
fn fatal(msg: str) -> ! {
|
fn fatal(msg: str) -> ! {
|
||||||
codemap::emit_error(none, msg);
|
diagnostic::emit_error(none, msg);
|
||||||
fail;
|
fail;
|
||||||
}
|
}
|
||||||
fn span_err(sp: span, msg: str) {
|
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;
|
self.err_count += 1u;
|
||||||
}
|
}
|
||||||
fn err(msg: str) {
|
fn err(msg: str) {
|
||||||
codemap::emit_error(none, msg);
|
diagnostic::emit_error(none, msg);
|
||||||
self.err_count += 1u;
|
self.err_count += 1u;
|
||||||
}
|
}
|
||||||
fn has_errors() -> bool { self.err_count > 0u }
|
fn has_errors() -> bool { self.err_count > 0u }
|
||||||
|
@ -87,16 +87,16 @@ impl session for session {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn span_warn(sp: span, msg: str) {
|
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) {
|
fn warn(msg: str) {
|
||||||
codemap::emit_warning(none, msg);
|
diagnostic::emit_warning(none, msg);
|
||||||
}
|
}
|
||||||
fn span_note(sp: span, msg: str) {
|
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) {
|
fn note(msg: str) {
|
||||||
codemap::emit_note(none, msg);
|
diagnostic::emit_note(none, msg);
|
||||||
}
|
}
|
||||||
fn span_bug(sp: span, msg: str) -> ! {
|
fn span_bug(sp: span, msg: str) -> ! {
|
||||||
self.span_fatal(sp, #fmt["internal compiler error %s", msg]);
|
self.span_fatal(sp, #fmt["internal compiler error %s", msg]);
|
||||||
|
|
|
@ -123,6 +123,7 @@ mod metadata {
|
||||||
mod driver {
|
mod driver {
|
||||||
mod driver;
|
mod driver;
|
||||||
mod session;
|
mod session;
|
||||||
|
mod diagnostic;
|
||||||
}
|
}
|
||||||
|
|
||||||
mod util {
|
mod util {
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
import core::{vec, uint, str, option, result};
|
import core::{vec, uint, str, option, result};
|
||||||
import std::{term, io};
|
|
||||||
import io::writer_util;
|
|
||||||
import option::{some, none};
|
import option::{some, none};
|
||||||
|
|
||||||
type filename = str;
|
type filename = str;
|
||||||
|
@ -100,136 +98,6 @@ fn span_to_str(sp: span, cm: codemap) -> str {
|
||||||
ret res;
|
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]};
|
type file_lines = {name: str, lines: [uint]};
|
||||||
|
|
||||||
fn span_to_lines(sp: span, cm: codemap::codemap) -> @file_lines {
|
fn span_to_lines(sp: span, cm: codemap::codemap) -> @file_lines {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import option::{some, none};
|
||||||
import util::interner;
|
import util::interner;
|
||||||
import util::interner::intern;
|
import util::interner::intern;
|
||||||
import codemap;
|
import codemap;
|
||||||
|
import driver::diagnostic;
|
||||||
|
|
||||||
type reader = @{
|
type reader = @{
|
||||||
cm: codemap::codemap,
|
cm: codemap::codemap,
|
||||||
|
@ -47,7 +48,7 @@ impl reader for reader {
|
||||||
} else { self.curr = -1 as char; }
|
} else { self.curr = -1 as char; }
|
||||||
}
|
}
|
||||||
fn err(m: str) {
|
fn err(m: str) {
|
||||||
codemap::emit_error(
|
diagnostic::emit_error(
|
||||||
some((self.cm, ast_util::mk_sp(self.chpos, self.chpos))), m);
|
some((self.cm, ast_util::mk_sp(self.chpos, self.chpos))), m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import util::interner;
|
||||||
import ast::{node_id, spanned};
|
import ast::{node_id, spanned};
|
||||||
import front::attr;
|
import front::attr;
|
||||||
import lexer::reader;
|
import lexer::reader;
|
||||||
|
import driver::diagnostic;
|
||||||
|
|
||||||
tag restriction {
|
tag restriction {
|
||||||
UNRESTRICTED;
|
UNRESTRICTED;
|
||||||
|
@ -71,11 +72,11 @@ impl parser for parser {
|
||||||
self.span_fatal(self.span, m);
|
self.span_fatal(self.span, m);
|
||||||
}
|
}
|
||||||
fn span_fatal(sp: span, m: str) -> ! {
|
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;
|
fail;
|
||||||
}
|
}
|
||||||
fn warn(m: str) {
|
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 {
|
fn get_str(i: token::str_num) -> str {
|
||||||
interner::get(*self.reader.interner, i)
|
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
|
src
|
||||||
}
|
}
|
||||||
result::err(e) {
|
result::err(e) {
|
||||||
codemap::emit_error(none, e);
|
diagnostic::emit_error(none, e);
|
||||||
fail;
|
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") {
|
} else if str::ends_with(input, ".rs") {
|
||||||
parse_crate_from_source_file(input, cfg, sess)
|
parse_crate_from_source_file(input, cfg, sess)
|
||||||
} else {
|
} else {
|
||||||
codemap::emit_error(none, "unknown input file type: " + input);
|
diagnostic::emit_error(none, "unknown input file type: " + input);
|
||||||
fail
|
fail
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue