diff --git a/src/comp/syntax/ext/qquote.rs b/src/comp/syntax/ext/qquote.rs index 90501870e73..b5ca673908e 100644 --- a/src/comp/syntax/ext/qquote.rs +++ b/src/comp/syntax/ext/qquote.rs @@ -2,31 +2,94 @@ import driver::session; import option::{none, some}; -import syntax::ast::{crate, expr_, expr_mac, mac_invoc, mac_qq, mac_var}; +import syntax::ast::{crate, expr_, expr_mac, mac_invoc, + mac_qq, mac_aq, mac_var}; import syntax::fold::*; +import syntax::visit::*; import syntax::ext::base::*; import syntax::ext::build::*; import syntax::parse::parser::parse_expr_from_source_str; +import syntax::print::*; +import std::io::*; + import codemap::span; -fn expand_qquote(cx: ext_ctxt, sp: span, _e: @ast::expr) -> ast::expr_ { - let str = codemap::span_to_snippet(sp, cx.session().parse_sess.cm); +type aq_ctxt = @{lo: uint, + mutable gather: [{lo: uint, hi: uint, e: @ast::expr}]}; + +fn gather_anti_quotes(lo: uint, e: @ast::expr) -> aq_ctxt +{ + let v = @{visit_expr: visit_expr_aq + with *default_visitor()}; + let cx = @{lo:lo, mutable gather: []}; + visit_expr_aq(e, cx, mk_vt(v)); + ret cx; +} + +fn visit_expr_aq(expr: @ast::expr, &&cx: aq_ctxt, v: vt) +{ + alt (expr.node) { + expr_mac({node: mac_aq(sp, e), _}) { + cx.gather += [{lo: sp.lo - cx.lo, hi: sp.hi - cx.lo, + e: e}]; + } + _ {visit_expr(expr, cx, v);} + } +} + +fn expand_qquote(ecx: ext_ctxt, sp: span, e: @ast::expr) -> ast::expr_ { + let str = codemap::span_to_snippet(sp, ecx.session().parse_sess.cm); + let qcx = gather_anti_quotes(sp.lo, e); + let cx = qcx; + let prev = 0u; + for {lo: lo, _} in cx.gather { + assert lo > prev; + prev = lo; + } + let str2 = ""; + let active = true; + let i = 0u, j = 0u; + let g_len = vec::len(cx.gather); + str::chars_iter(str) {|ch| + if (active && j < g_len && i == cx.gather[j].lo) { + assert ch == '$'; + active = false; + str2 += #fmt(" $%u ", j); + } + if (active) {str::push_char(str2, ch);} + i += 1u; + if (!active && j < g_len && i == cx.gather[j].hi) { + assert ch == ')'; + active = true; + j += 1u; + } + } + + let cx = ecx; let session_call = bind mk_call_(cx,sp, mk_access(cx,sp,["ext_cx"], "session"), []); - let call = mk_call(cx,sp, + let pcall = mk_call(cx,sp, ["syntax", "parse", "parser", "parse_expr_from_source_str"], [mk_str(cx,sp, ""), mk_unary(cx,sp, ast::box(ast::imm), - mk_str(cx,sp, str)), + mk_str(cx,sp, str2)), mk_access_(cx,sp, mk_access_(cx,sp, session_call(), "opts"), "cfg"), mk_access_(cx,sp, session_call(), "parse_sess")] ); - ret call.node; + let rcall = pcall; + if (g_len > 0u) { + rcall = mk_call(cx,sp, + ["syntax", "ext", "qquote", "replace"], + [pcall, + mk_vec_e(cx,sp, vec::map(qcx.gather, {|g| g.e}))]); + } + + ret rcall.node; } fn replace(e: @ast::expr, repls: [@ast::expr]) -> @ast::expr { @@ -43,14 +106,20 @@ fn replace_expr(repls: [@ast::expr], orig: fn@(ast::expr_, span, ast_fold)->(ast::expr_, span)) -> (ast::expr_, span) { - // note: nested enum matching will be really nice here so I can jusy say - // expr_mac(mac_var(i)) alt e { expr_mac({node: mac_var(i), _}) {let r = repls[i]; (r.node, r.span)} _ {orig(e,s,fld)} } } +fn print_expr(expr: @ast::expr) { + let stdout = std::io::stdout(); + let pp = pprust::rust_printer(stdout); + pprust::print_expr(pp, expr); + pp::eof(pp.s); + stdout.write_str("\n"); +} + // Local Variables: // mode: rust // fill-column: 78; diff --git a/src/comp/syntax/parse/lexer.rs b/src/comp/syntax/parse/lexer.rs index e023e5259fd..2ad3a7f0135 100644 --- a/src/comp/syntax/parse/lexer.rs +++ b/src/comp/syntax/parse/lexer.rs @@ -372,10 +372,11 @@ fn next_token_inner(rdr: reader) -> token::token { } rdr.bump(); ret token::DOLLAR_NUM(val); - } else if c == '(' { + } else if rdr.curr == '(' { + rdr.bump(); ret token::DOLLAR_LPAREN; } else { - rdr.fatal("expected digit3"); + rdr.fatal("expected digit"); } } diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index f2f1f7c14ed..ecbae8a1fc2 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -630,8 +630,19 @@ fn parse_seq(bra: token::token, ket: token::token, fn have_dollar(p: parser) -> option::t { alt p.token { - token::DOLLAR_NUM(num) {p.bump(); some(ast::mac_var(num))} - _ {none} + token::DOLLAR_NUM(num) { + p.bump(); + some(ast::mac_var(num)) + } + token::DOLLAR_LPAREN { + let lo = p.span.lo; + p.bump(); + let e = parse_expr(p); + expect(p, token::RPAREN); + let hi = p.last_span.hi; + some(ast::mac_aq(ast_util::mk_sp(lo,hi), e)) + } + _ {none} } }