Skip to content

Commit

Permalink
Use biased_match! to avoid over-deep indentation in expand.rs.
Browse files Browse the repository at this point in the history
  • Loading branch information
paulstansifer authored and graydon committed Nov 29, 2012
1 parent cf26a7d commit b7fcc9b
Showing 1 changed file with 89 additions and 77 deletions.
166 changes: 89 additions & 77 deletions src/libsyntax/ext/expand.rs
Expand Up @@ -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))
Expand Down Expand Up @@ -191,113 +192,124 @@ 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, \
given '%s'", *extname,
*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,
&& s: stmt_, sp: span, fld: ast_fold,
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))
}
}

}


Expand Down

0 comments on commit b7fcc9b

Please sign in to comment.