From 6d3513eaee512e0143cd75927b8ff56a5bf98152 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 10 Jul 2011 17:00:28 -0700 Subject: [PATCH] Make #fmt work from inside std. Issue #175 At long last, this patch makes #fmt usable from inside the standard library. The way it does it us very hackish, but at least it works now. --- src/comp/syntax/ext/base.rs | 15 +++++++++++++-- src/comp/syntax/ext/fmt.rs | 20 ++++++++++++-------- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/comp/syntax/ext/base.rs b/src/comp/syntax/ext/base.rs index 7b0accb573be..0990b3bdacbb 100644 --- a/src/comp/syntax/ext/base.rs +++ b/src/comp/syntax/ext/base.rs @@ -36,7 +36,8 @@ type next_id_fn = fn() -> ast::node_id ; // Provides a limited set of services necessary for syntax extensions // to do their thing type ext_ctxt = - rec(span_msg_fn span_fatal, + rec(str crate_file_name_hack, + span_msg_fn span_fatal, span_msg_fn span_unimpl, next_id_fn next_id); @@ -50,9 +51,19 @@ fn mk_ctxt(&parse_sess sess) -> ext_ctxt { codemap::emit_error(option::some(sp), "unimplemented " + msg, cm); fail; } + + // FIXME: Some extensions work by building ASTs with paths to functions + // they need to call at runtime. As those functions live in the std crate, + // the paths are prefixed with "std::". Unfortunately, these paths can't + // work for code called from inside the stdard library, so here we pass + // the extensions the file name of the crate being compiled so they can + // use it to guess whether paths should be prepended with "std::". This is + // super-ugly and needs a better solution. + auto crate_file_name_hack = sess.cm.files.(0).name; auto ext_span_unimpl = bind ext_span_unimpl_(sess.cm, _, _); auto ext_next_id = bind parse::parser::next_node_id(sess); - ret rec(span_fatal=ext_span_fatal, + ret rec(crate_file_name_hack=crate_file_name_hack, + span_fatal=ext_span_fatal, span_unimpl=ext_span_unimpl, next_id=ext_next_id); } diff --git a/src/comp/syntax/ext/fmt.rs b/src/comp/syntax/ext/fmt.rs index 0f3b38a808bd..ffae97b1b0ce 100644 --- a/src/comp/syntax/ext/fmt.rs +++ b/src/comp/syntax/ext/fmt.rs @@ -92,15 +92,19 @@ fn pieces_to_expr(&ext_ctxt cx, span sp, vec[piece] pieces, auto recexpr = ast::expr_rec(astfields, option::none[@ast::expr]); ret @rec(id=cx.next_id(), node=recexpr, span=sp); } - fn make_path_vec(str ident) -> str[] { - // FIXME: #fmt can't currently be used from within std - // because we're explicitly referencing the 'std' crate here - - ret ~["std", "extfmt", "rt", ident]; + fn make_path_vec(&ext_ctxt cx, str ident) -> str[] { + fn compiling_std(&ext_ctxt cx) -> bool { + ret str::find(cx.crate_file_name_hack, "std.rc") >= 0; + } + if (compiling_std(cx)) { + ret ~["extfmt", "rt", ident]; + } else { + ret ~["std", "extfmt", "rt", ident]; + } } fn make_rt_path_expr(&ext_ctxt cx, span sp, str ident) -> @ast::expr { - auto path = make_path_vec(ident); + auto path = make_path_vec(cx, ident); ret make_path_expr(cx, sp, path); } // Produces an AST expression that represents a RT::conv record, @@ -141,7 +145,7 @@ fn pieces_to_expr(&ext_ctxt cx, span sp, vec[piece] pieces, } case (count_is(?c)) { auto count_lit = make_new_int(cx, sp, c); - auto count_is_path = make_path_vec("count_is"); + auto count_is_path = make_path_vec(cx, "count_is"); auto count_is_args = ~[count_lit]; ret make_call(cx, sp, count_is_path, count_is_args); } @@ -184,7 +188,7 @@ fn pieces_to_expr(&ext_ctxt cx, span sp, vec[piece] pieces, fn make_conv_call(&ext_ctxt cx, span sp, str conv_type, &conv cnv, @ast::expr arg) -> @ast::expr { auto fname = "conv_" + conv_type; - auto path = make_path_vec(fname); + auto path = make_path_vec(cx, fname); auto cnv_expr = make_rt_conv_expr(cx, sp, cnv); auto args = ~[cnv_expr, arg]; ret make_call(cx, arg.span, path, args);