diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index e39f97452490a..6c93dbcd7ef39 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -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}; +type syntax_expander = {expander: syntax_expander_, span: option}; + 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}; +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 diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 26313e9749463..d7bb7835822b9 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -47,6 +47,39 @@ fn expand_expr(exts: hashmap, 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, 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 } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 02d08ab5ae8b9..13b68b2ce70f7 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -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;