Fix macro backtraces.

In addition add information about the macro doing the expansion, and
move the printing of the expansion backtrace from codemap::span_to_str
to the diagnostic code.  The backtrace is now more verbose and
includes information on the macro doing the expansion, in addition to
the expansion site.
This commit is contained in:
Kevin Atkinson 2012-02-04 18:37:24 -07:00 committed by Brian Anderson
parent 1d855ebc51
commit b7ec2488ff
7 changed files with 72 additions and 59 deletions

View File

@ -179,6 +179,7 @@ fn emit(cmsp: option<(codemap::codemap, span)>,
let lines = codemap::span_to_lines(sp, cm);
print_diagnostic(ss, lvl, msg);
highlight_lines(cm, sp, lines);
print_macro_backtrace(cm, sp);
}
none {
print_diagnostic("", lvl, msg);
@ -241,3 +242,15 @@ fn highlight_lines(cm: codemap::codemap, sp: span,
io::stderr().write_str(s + "\n");
}
}
fn print_macro_backtrace(cm: codemap::codemap, sp: span) {
option::may (sp.expn_info) {|ei|
let ss = option::maybe("", ei.callie.span,
bind codemap::span_to_str(_, cm));
print_diagnostic(ss, note,
#fmt("in expansion of #%s", ei.callie.name));
let ss = codemap::span_to_str(ei.call_site, cm);
print_diagnostic(ss, note, "expansion site");
print_macro_backtrace(cm, ei.call_site);
}
}

View File

@ -24,7 +24,7 @@ fn inject_libcore_ref(sess: session,
fn spanned<T: copy>(x: T) -> @ast::spanned<T> {
ret @{node: x,
span: {lo: 0u, hi: 0u,
expanded_from: codemap::os_none}};
expn_info: option::none}};
}
let n1 = sess.next_node_id();

View File

@ -7,7 +7,7 @@ fn respan<T: copy>(sp: span, t: T) -> spanned<T> {
/* assuming that we're not in macro expansion */
fn mk_sp(lo: uint, hi: uint) -> span {
ret {lo: lo, hi: hi, expanded_from: codemap::os_none};
ret {lo: lo, hi: hi, expn_info: none};
}
// make this a const, once the compiler supports it

View File

@ -92,38 +92,18 @@ fn lookup_byte_pos(map: codemap, pos: uint) -> loc {
ret lookup_pos(map, pos, lookup);
}
enum opt_span {
//hack (as opposed to option), to make `span` compile
os_none,
os_some(@span),
enum expn_info_ {
expanded_from({call_site: span,
callie: {name: str, span: option<span>}})
}
type span = {lo: uint, hi: uint, expanded_from: opt_span};
type expn_info = option<@expn_info_>;
type span = {lo: uint, hi: uint, expn_info: expn_info};
fn span_to_str(sp: span, cm: codemap) -> str {
let cur = sp;
let res = "";
// FIXME: Should probably be doing pointer comparison on filemap
let prev_file = none;
while true {
let lo = lookup_char_pos(cm, cur.lo);
let hi = lookup_char_pos(cm, cur.hi);
res +=
#fmt["%s:%u:%u: %u:%u",
if some(lo.file.name) == prev_file {
"-"
} else { lo.file.name }, lo.line, lo.col, hi.line, hi.col];
alt cur.expanded_from {
os_none { break; }
os_some(new_sp) {
cur = *new_sp;
prev_file = some(lo.file.name);
res += "<<";
}
}
}
ret res;
let lo = lookup_char_pos(cm, sp.lo);
let hi = lookup_char_pos(cm, sp.hi);
ret #fmt("%s:%u:%u: %u:%u", lo.file.name,
lo.line, lo.col, hi.line, hi.col)
}
type file_lines = {file: filemap, lines: [uint]};

View File

@ -1,12 +1,15 @@
import core::{vec, option};
import std::map::hashmap;
import driver::session::session;
import codemap::span;
import codemap::{span, expn_info, expanded_from};
import std::map::new_str_hash;
import codemap;
type syntax_expander =
type syntax_expander_ =
fn@(ext_ctxt, span, ast::mac_arg, ast::mac_body) -> @ast::expr;
type syntax_expander = {
expander: syntax_expander_,
span: option<span>};
type macro_def = {ident: str, ext: syntax_extension};
type macro_definer =
fn@(ext_ctxt, span, ast::mac_arg, ast::mac_body) -> macro_def;
@ -19,27 +22,29 @@ enum syntax_extension {
// A temporary hard-coded map of methods for expanding syntax extension
// AST nodes into full ASTs
fn syntax_expander_table() -> hashmap<str, syntax_extension> {
fn builtin(f: syntax_expander_) -> syntax_extension
{normal({expander: f, span: none})}
let syntax_expanders = new_str_hash::<syntax_extension>();
syntax_expanders.insert("fmt", normal(ext::fmt::expand_syntax_ext));
syntax_expanders.insert("env", normal(ext::env::expand_syntax_ext));
syntax_expanders.insert("fmt", builtin(ext::fmt::expand_syntax_ext));
syntax_expanders.insert("env", builtin(ext::env::expand_syntax_ext));
syntax_expanders.insert("macro",
macro_defining(ext::simplext::add_new_extension));
syntax_expanders.insert("concat_idents",
normal(ext::concat_idents::expand_syntax_ext));
builtin(ext::concat_idents::expand_syntax_ext));
syntax_expanders.insert("ident_to_str",
normal(ext::ident_to_str::expand_syntax_ext));
builtin(ext::ident_to_str::expand_syntax_ext));
syntax_expanders.insert("log_syntax",
normal(ext::log_syntax::expand_syntax_ext));
builtin(ext::log_syntax::expand_syntax_ext));
syntax_expanders.insert("ast",
normal(ext::qquote::expand_ast));
builtin(ext::qquote::expand_ast));
ret syntax_expanders;
}
iface ext_ctxt {
fn session() -> session;
fn print_backtrace();
fn backtrace() -> codemap::opt_span;
fn bt_push(sp: span);
fn backtrace() -> expn_info;
fn bt_push(ei: codemap::expn_info_);
fn bt_pop();
fn span_fatal(sp: span, msg: str) -> !;
fn span_err(sp: span, msg: str);
@ -51,20 +56,26 @@ iface ext_ctxt {
fn mk_ctxt(sess: session) -> ext_ctxt {
type ctxt_repr = {sess: session,
mutable backtrace: codemap::opt_span};
mutable backtrace: expn_info};
impl of ext_ctxt for ctxt_repr {
fn session() -> session { self.sess }
fn print_backtrace() { }
fn backtrace() -> codemap::opt_span { self.backtrace }
fn bt_push(sp: span) {
self.backtrace = codemap::os_some(
@{lo: sp.lo, hi: sp.hi, expanded_from: self.backtrace});
fn backtrace() -> expn_info { self.backtrace }
fn bt_push(ei: codemap::expn_info_) {
alt ei {
expanded_from({call_site: cs, callie: callie}) {
self.backtrace =
some(@expanded_from({
call_site: {lo: cs.lo, hi: cs.hi,
expn_info: self.backtrace},
callie: callie}));
}
}
}
fn bt_pop() {
alt self.backtrace {
codemap::os_some(@{expanded_from: pre, _}) {
let tmp = pre;
self.backtrace = tmp;
some(@expanded_from({call_site: {expn_info: prev, _}, _})) {
self.backtrace = prev
}
_ { self.bug("tried to pop without a push"); }
}
@ -88,7 +99,8 @@ fn mk_ctxt(sess: session) -> ext_ctxt {
fn bug(msg: str) -> ! { self.print_backtrace(); self.sess.bug(msg); }
fn next_id() -> ast::node_id { ret self.sess.next_node_id(); }
}
{sess: sess, mutable backtrace: codemap::os_none} as ext_ctxt
let imp : ctxt_repr = {sess: sess, mutable backtrace: none};
ret imp as ext_ctxt
}
fn expr_to_str(cx: ext_ctxt, expr: @ast::expr, error: str) -> str {

View File

@ -11,7 +11,7 @@ import syntax::ext::base::*;
import syntax::ext::qquote::{expand_qquote,qq_helper};
import syntax::parse::parser::parse_expr_from_source_str;
import codemap::span;
import codemap::{span, expanded_from};
fn expand_expr(exts: hashmap<str, syntax_extension>, cx: ext_ctxt,
e: expr_, s: span, fld: ast_fold,
@ -29,10 +29,12 @@ fn expand_expr(exts: hashmap<str, syntax_extension>, cx: ext_ctxt,
cx.span_fatal(pth.span,
#fmt["macro undefined: '%s'", extname])
}
some(normal(ext)) {
let expanded = ext(cx, pth.span, args, body);
some(normal({expander: exp, span: exp_sp})) {
let expanded = exp(cx, pth.span, args, body);
cx.bt_push(mac.span);
let info = {call_site: s,
callie: {name: extname, span: exp_sp}};
cx.bt_push(expanded_from(info));
//keep going, outside-in
let fully_expanded = fld.fold_expr(expanded).node;
cx.bt_pop();
@ -53,6 +55,11 @@ fn expand_expr(exts: hashmap<str, syntax_extension>, cx: ext_ctxt,
};
}
fn new_span(cx: ext_ctxt, sp: span) -> span {
/* this discards information in the case of macro-defining macros */
ret {lo: sp.lo, hi: sp.hi, expn_info: cx.backtrace()};
}
// FIXME: this is a terrible kludge to inject some macros into the default
// compilation environment. When the macro-definition system is substantially
// more mature, these should move from here, into a compiled part of libcore
@ -73,7 +80,8 @@ fn expand_crate(sess: session::session, c: @crate) -> @crate {
let afp = default_ast_fold();
let cx: ext_ctxt = mk_ctxt(sess);
let f_pre =
{fold_expr: bind expand_expr(exts, cx, _, _, _, afp.fold_expr)
{fold_expr: bind expand_expr(exts, cx, _, _, _, afp.fold_expr),
new_span: bind new_span(cx, _)
with *afp};
let f = make_fold(f_pre);
let cm = parse_expr_from_source_str("<core-macros>",

View File

@ -190,7 +190,7 @@ fn transcribe(cx: ext_ctxt, b: bindings, body: @expr) -> @expr {
fn new_id(_old: node_id, cx: ext_ctxt) -> node_id { ret cx.next_id(); }
fn new_span(cx: ext_ctxt, sp: span) -> span {
/* this discards information in the case of macro-defining macros */
ret {lo: sp.lo, hi: sp.hi, expanded_from: cx.backtrace()};
ret {lo: sp.lo, hi: sp.hi, expn_info: cx.backtrace()};
}
let afp = default_ast_fold();
let f_pre =
@ -202,8 +202,8 @@ fn transcribe(cx: ext_ctxt, b: bindings, body: @expr) -> @expr {
fold_block:
bind transcribe_block(cx, b, idx_path, _, _, _, afp.fold_block),
map_exprs: bind transcribe_exprs(cx, b, idx_path, _, _),
new_id: bind new_id(_, cx),
new_span: bind new_span(cx, _) with *afp};
new_id: bind new_id(_, cx)
with *afp};
let f = make_fold(f_pre);
let result = f.fold_expr(body);
ret result;
@ -753,7 +753,7 @@ fn add_new_extension(cx: ext_ctxt, sp: span, arg: ast::mac_arg,
"at least one clause")
}
},
ext: normal(ext)};
ext: normal({expander: ext, span: some(arg.span)})};
fn generic_extension(cx: ext_ctxt, sp: span, arg: ast::mac_arg,
_body: ast::mac_body, clauses: [@clause]) -> @expr {