diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index b997106b4ed01..f919c1f03c0d8 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -10,6 +10,7 @@ use parse::{parser, parse_expr_from_source_str, new_parser_from_tts}; use codemap::{span, ExpandedFrom}; + fn expand_expr(exts: HashMap<~str, syntax_extension>, cx: ext_ctxt, e: expr_, s: span, fld: ast_fold, orig: fn@(expr_, span, ast_fold) -> (expr_, span)) @@ -191,21 +192,43 @@ fn expand_item(exts: HashMap<~str, syntax_extension>, } } +// avoid excess indentation when a series of nested `match`es +// has only one "good" outcome +macro_rules! biased_match ( + ( ($e :expr) ~ ($p :pat) else $err :stmt ; + $( ($e_cdr:expr) ~ ($p_cdr:pat) else $err_cdr:stmt ; )* + => $body:expr + ) => ( + match $e { + $p => { + biased_match!($( ($e_cdr) ~ ($p_cdr) else $err_cdr ; )* + => $body) + } + _ => { $err } + } + ); + ( => $body:expr ) => ( $body ) +) + // Support for item-position macro invocations, exactly the same // logic as for expression-position macro invocations. fn expand_item_mac(exts: HashMap<~str, syntax_extension>, cx: ext_ctxt, &&it: @ast::item, fld: ast_fold) -> Option<@ast::item> { - match it.node { - item_mac({node: mac_invoc_tt(pth, tts), _}) => { - let extname = cx.parse_sess().interner.get(pth.idents[0]); - let (expanded, ex_span) = match exts.find(*extname) { - None => { - cx.span_fatal(pth.span, - fmt!("macro undefined: '%s!'", *extname)) - } - Some(normal_tt(expand)) => { + let (pth, tts) = biased_match!( + (it.node) ~ (item_mac({node: mac_invoc_tt(pth, tts), _})) else { + cx.span_bug(it.span, ~"invalid item macro invocation") + }; + => (pth, tts) + ); + + let extname = cx.parse_sess().interner.get(pth.idents[0]); + let (expanded, ex_span) = match exts.find(*extname) { + None => cx.span_fatal(pth.span, + fmt!("macro undefined: '%s!'", *extname)), + + Some(normal_tt(expand)) => { if it.ident != parse::token::special_idents::invalid { cx.span_fatal(pth.span, fmt!("macro %s! expects no ident argument, \ @@ -213,39 +236,35 @@ fn expand_item_mac(exts: HashMap<~str, syntax_extension>, *cx.parse_sess().interner.get(it.ident))); } (expand.expander(cx, it.span, tts), expand.span) - } - Some(item_tt(expand)) => { + } + Some(item_tt(expand)) => { if it.ident == parse::token::special_idents::invalid { cx.span_fatal(pth.span, fmt!("macro %s! expects an ident argument", *extname)); } (expand.expander(cx, it.span, it.ident, tts), expand.span) - } - _ => cx.span_fatal( - it.span, fmt!("%s! is not legal in item position", *extname)) - }; + } + _ => cx.span_fatal( + it.span, fmt!("%s! is not legal in item position", *extname)) + }; - cx.bt_push(ExpandedFrom({call_site: it.span, - callie: {name: *extname, - span: ex_span}})); - let maybe_it = match expanded { - mr_item(it) => fld.fold_item(it), - mr_expr(_) => cx.span_fatal(pth.span, - ~"expr macro in item position: " + - *extname), - mr_any(_, item_maker, _) => - option::chain(item_maker(), |i| {fld.fold_item(i)}), - mr_def(mdef) => { - exts.insert(mdef.name, mdef.ext); - None - } - }; - cx.bt_pop(); - return maybe_it; - } - _ => cx.span_bug(it.span, ~"invalid item macro invocation") - } + cx.bt_push(ExpandedFrom({call_site: it.span, + callie: {name: *extname, span: ex_span}})); + let maybe_it = match expanded { + mr_item(it) => fld.fold_item(it), + mr_expr(_) => cx.span_fatal(pth.span, + ~"expr macro in item position: " + + *extname), + mr_any(_, item_maker, _) => + option::chain(item_maker(), |i| {fld.fold_item(i)}), + mr_def(mdef) => { + exts.insert(mdef.name, mdef.ext); + None + } + }; + cx.bt_pop(); + return maybe_it; } fn expand_stmt(exts: HashMap<~str, syntax_extension>, cx: ext_ctxt, @@ -253,51 +272,44 @@ fn expand_stmt(exts: HashMap<~str, syntax_extension>, cx: ext_ctxt, orig: fn@(&&s: stmt_, span, ast_fold) -> (stmt_, span)) -> (stmt_, span) { - return match s { - stmt_mac(mac) => { - match mac.node { - mac_invoc_tt(pth, tts) => { - assert(vec::len(pth.idents) == 1u); - let extname = cx.parse_sess().interner.get(pth.idents[0]); - match exts.find(*extname) { - None => { - cx.span_fatal( - pth.span, - fmt!("macro undefined: '%s'", *extname)) - } - Some(normal_tt({expander: exp, span: exp_sp})) => { - let expanded = match exp(cx, mac.span, tts) { - mr_expr(e) => - @{node: ast::stmt_expr(e, cx.next_id()), - span: e.span}, - mr_any(_,_,stmt_mkr) => stmt_mkr(), - _ => cx.span_fatal( - pth.span, - fmt!("non-stmt macro in stmt pos: %s", - *extname)) - }; + let (mac, pth, tts) = biased_match! ( + (s) ~ (stmt_mac(mac)) else return orig(s, sp, fld); + (mac.node) ~ (mac_invoc_tt(pth, tts)) else { + cx.span_bug(mac.span, ~"naked syntactic bit") + }; + => (mac, pth, tts)); + + assert(vec::len(pth.idents) == 1u); + let extname = cx.parse_sess().interner.get(pth.idents[0]); + match exts.find(*extname) { + None => + cx.span_fatal(pth.span, fmt!("macro undefined: '%s'", *extname)), + + Some(normal_tt({expander: exp, span: exp_sp})) => { + let expanded = match exp(cx, mac.span, tts) { + mr_expr(e) => + @{node: ast::stmt_expr(e, cx.next_id()), span: e.span}, + mr_any(_,_,stmt_mkr) => stmt_mkr(), + _ => cx.span_fatal( + pth.span, + fmt!("non-stmt macro in stmt pos: %s", *extname)) + }; - cx.bt_push(ExpandedFrom( - {call_site: sp, - callie: {name: *extname, span: exp_sp}})); - //keep going, outside-in - let fully_expanded = fld.fold_stmt(expanded).node; - cx.bt_pop(); + cx.bt_push(ExpandedFrom( + {call_site: sp, callie: {name: *extname, span: exp_sp}})); + //keep going, outside-in + let fully_expanded = fld.fold_stmt(expanded).node; + cx.bt_pop(); - (fully_expanded, sp) - } - _ => { - cx.span_fatal(pth.span, - fmt!("'%s' is not a tt-style macro", - *extname)) - } - } - } - _ => cx.span_bug(mac.span, ~"naked syntactic bit") - } + return (fully_expanded, sp) } - _ => orig(s, sp, fld) - }; + _ => { + cx.span_fatal(pth.span, + fmt!("'%s' is not a tt-style macro", + *extname)) + } + } + }