Make it possible to make built-in tt syntax extensions

This commit is contained in:
Paul Stansifer 2012-06-25 15:04:50 -07:00
parent 4f104954a6
commit 4df2654f82
3 changed files with 53 additions and 6 deletions

View File

@ -6,19 +6,23 @@ import std::map::str_hash;
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 syntax_expander = {expander: syntax_expander_, span: option<span>};
type macro_def = {ident: ast::ident, ext: syntax_extension};
type macro_definer =
fn@(ext_ctxt, span, ast::mac_arg, ast::mac_body) -> macro_def;
type item_decorator =
fn@(ext_ctxt, span, ast::meta_item, [@ast::item]) -> [@ast::item];
type syntax_expander_tt = {expander: syntax_expander_tt_, span: option<span>};
type syntax_expander_tt_ = fn@(ext_ctxt, span, ast::token_tree) -> @ast::expr;
enum syntax_extension {
normal(syntax_expander),
macro_defining(macro_definer),
item_decorator(item_decorator),
normal_tt(syntax_expander_tt)
}
// A temporary hard-coded map of methods for expanding syntax extension

View File

@ -47,6 +47,39 @@ fn expand_expr(exts: hashmap<str, syntax_extension>, cx: ext_ctxt,
exts.insert(*named_extension.ident, named_extension.ext);
(ast::expr_rec([], none), s)
}
some(normal_tt(_)) {
cx.span_fatal(pth.span,
#fmt["this tt-style macro should be \
invoked '%s!{...}'", *extname])
}
}
}
mac_invoc_tt(pth, tt) {
assert (vec::len(pth.idents) > 0u);
let extname = pth.idents[0];
alt exts.find(*extname) {
none {
cx.span_fatal(pth.span,
#fmt["macro undefined: '%s'", *extname])
}
some(normal_tt({expander: exp, span: exp_sp})) {
let expanded = exp(cx, pth.span, tt);
cx.bt_push(expanded_from({call_site: s,
callie: {name: *extname, span: exp_sp}}));
//keep going, outside-in
let fully_expanded = fld.fold_expr(expanded).node;
cx.bt_pop();
(fully_expanded, s)
}
_ {
cx.span_fatal(pth.span,
#fmt["'%s' is not a tt-style macro",
*extname])
}
}
}
_ { cx.span_bug(mac.span, "naked syntactic bit") }
@ -75,7 +108,8 @@ fn expand_mod_items(exts: hashmap<str, syntax_extension>, cx: ext_ctxt,
ast::meta_list(n, _) { n }
};
alt exts.find(*mname) {
none | some(normal(_)) | some(macro_defining(_)) {
none | some(normal(_)) | some(macro_defining(_))
| some(normal_tt(_)) {
items
}

View File

@ -883,8 +883,17 @@ class parser {
is_ident(self.token) && !self.is_keyword("true") &&
!self.is_keyword("false") {
let pth = self.parse_path_with_tps(true);
hi = pth.span.hi;
ex = expr_path(pth);
/* `!`, as an operator, is prefix, so we know this isn't that */
if self.token == token::NOT {
self.bump();
let m_body = self.parse_token_tree();
let hi = self.span.hi;
ret pexpr(self.mk_mac_expr(lo, hi, mac_invoc_tt(pth,m_body)));
} else {
hi = pth.span.hi;
ex = expr_path(pth);
}
} else {
let lit = self.parse_lit();
hi = lit.span.hi;