diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 480cbfe0060..9a642818a53 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -44,6 +44,7 @@ type syntax_expander_tt_item_ enum mac_result { mr_expr(@ast::expr), mr_item(@ast::item), + mr_expr_or_item(fn@()-> @ast::expr, fn@()-> Option<@ast::item>), mr_def(macro_def) } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index c09655d73d3..f4d3111f0a2 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -81,6 +81,7 @@ fn expand_expr(exts: HashMap<~str, syntax_extension>, cx: ext_ctxt, Some(expr_tt({expander: exp, span: exp_sp})) => { let expanded = match exp(cx, mac.span, tts) { mr_expr(e) => e, + mr_expr_or_item(expr_maker,_) => expr_maker(), _ => cx.span_fatal( pth.span, fmt!("non-expr macro in expr pos: %s", *extname)) @@ -214,6 +215,8 @@ fn expand_item_mac(exts: HashMap<~str, syntax_extension>, mr_expr(_) => cx.span_fatal(pth.span, ~"expr macro in item position: " + *extname), + mr_expr_or_item(_, item_maker) => + option::chain(item_maker(), |i| {fld.fold_item(i)}), mr_def(mdef) => { exts.insert(mdef.name, mdef.ext); None diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 56418989c49..7957cde8fdc 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -1,4 +1,4 @@ -use base::{ext_ctxt, mac_result, mr_expr, mr_def, expr_tt}; +use base::{ext_ctxt, mac_result, mr_expr_or_item, mr_def, expr_tt}; use codemap::span; use ast::{ident, matcher_, matcher, match_tok, match_nonterminal, match_seq, tt_delim}; @@ -87,10 +87,13 @@ fn add_new_extension(cx: ext_ctxt, sp: span, name: ident, // rhs has holes ( `$id` and `$(...)` that need filled) let trncbr = new_tt_reader(s_d, itr, Some(named_matches), ~[rhs]); - let p = Parser(cx.parse_sess(), cx.cfg(), - trncbr as reader); - let e = p.parse_expr(); - return mr_expr(e); + let p = @Parser(cx.parse_sess(), cx.cfg(), + trncbr as reader); + + // Let the context choose how to interpret the result. + // Weird, but useful for X-macros. + return mr_expr_or_item(|| p.parse_expr(), + || p.parse_item(~[/* no attrs*/])); } failure(sp, msg) => if sp.lo >= best_fail_spot.lo { best_fail_spot = sp;