Implement anti-quotes.
This commit is contained in:
parent
477714f08e
commit
67e961c17f
@ -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<aq_ctxt>)
|
||||
{
|
||||
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, "<anon>"),
|
||||
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;
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -630,8 +630,19 @@ fn parse_seq<T: copy>(bra: token::token, ket: token::token,
|
||||
|
||||
fn have_dollar(p: parser) -> option::t<ast::mac_> {
|
||||
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}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user