Skip to content

Commit b2f6dd5

Browse files
author
Keegan McAllister
committed
Expand macros in patterns
1 parent 00704ea commit b2f6dd5

File tree

1 file changed

+90
-5
lines changed

1 file changed

+90
-5
lines changed

src/libsyntax/ext/expand.rs

+90-5
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use ast::{P, Block, Crate, DeclLocal, ExprMac};
11+
use ast::{P, Block, Crate, DeclLocal, ExprMac, PatMac};
1212
use ast::{Local, Ident, MacInvocTT};
1313
use ast::{ItemMac, Mrk, Stmt, StmtDecl, StmtMac, StmtExpr, StmtSemi};
1414
use ast::TokenTree;
@@ -92,8 +92,7 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr {
9292
None => {
9393
fld.cx.span_err(
9494
pth.span,
95-
format!("non-expr macro in expr pos: \
96-
{}",
95+
format!("non-expression macro in expression position: {}",
9796
extnamestr.get().as_slice()
9897
).as_slice());
9998
return DummyResult::raw_expr(e.span);
@@ -487,7 +486,7 @@ pub fn expand_item_mac(it: @ast::Item, fld: &mut MacroExpander)
487486
}
488487
None => {
489488
fld.cx.span_err(pth.span,
490-
format!("expr macro in item position: {}",
489+
format!("non-item macro in item position: {}",
491490
extnamestr.get()).as_slice());
492491
return SmallVector::zero();
493492
}
@@ -639,7 +638,7 @@ pub fn expand_stmt(s: &Stmt, fld: &mut MacroExpander) -> SmallVector<@Stmt> {
639638
Some(stmt) => stmt,
640639
None => {
641640
fld.cx.span_err(pth.span,
642-
format!("non-stmt macro in stmt pos: {}",
641+
format!("non-statement macro in statement position: {}",
643642
extnamestr).as_slice());
644643
return SmallVector::zero();
645644
}
@@ -842,6 +841,83 @@ pub fn expand_block_elts(b: &Block, fld: &mut MacroExpander) -> P<Block> {
842841
})
843842
}
844843

844+
pub fn expand_pat(p: @ast::Pat, fld: &mut MacroExpander) -> @ast::Pat {
845+
let (pth, tts) = match p.node {
846+
PatMac(ref mac) => {
847+
match mac.node {
848+
MacInvocTT(ref pth, ref tts, _) => {
849+
(pth, (*tts).clone())
850+
}
851+
}
852+
}
853+
_ => return noop_fold_pat(p, fld),
854+
};
855+
if pth.segments.len() > 1u {
856+
fld.cx.span_err(pth.span, "expected macro name without module separators");
857+
return DummyResult::raw_pat(p.span);
858+
}
859+
let extname = pth.segments.get(0).identifier;
860+
let extnamestr = token::get_ident(extname);
861+
let marked_after = match fld.extsbox.find(&extname.name) {
862+
None => {
863+
fld.cx.span_err(pth.span,
864+
format!("macro undefined: '{}!'",
865+
extnamestr).as_slice());
866+
// let compilation continue
867+
return DummyResult::raw_pat(p.span);
868+
}
869+
870+
Some(&NormalTT(ref expander, span)) => {
871+
fld.cx.bt_push(ExpnInfo {
872+
call_site: p.span,
873+
callee: NameAndSpan {
874+
name: extnamestr.get().to_string(),
875+
format: MacroBang,
876+
span: span
877+
}
878+
});
879+
880+
let fm = fresh_mark();
881+
let marked_before = mark_tts(tts.as_slice(), fm);
882+
let mac_span = original_span(fld.cx);
883+
let expanded = match expander.expand(fld.cx,
884+
mac_span.call_site,
885+
marked_before.as_slice()).make_pat() {
886+
Some(e) => e,
887+
None => {
888+
fld.cx.span_err(
889+
pth.span,
890+
format!(
891+
"non-pattern macro in pattern position: {}",
892+
extnamestr.get()
893+
).as_slice()
894+
);
895+
return DummyResult::raw_pat(p.span);
896+
}
897+
};
898+
899+
// mark after:
900+
mark_pat(expanded,fm)
901+
}
902+
_ => {
903+
fld.cx.span_err(p.span,
904+
format!("{}! is not legal in pattern position",
905+
extnamestr.get()).as_slice());
906+
return DummyResult::raw_pat(p.span);
907+
}
908+
};
909+
910+
let fully_expanded =
911+
fld.fold_pat(marked_after).node.clone();
912+
fld.cx.bt_pop();
913+
914+
@ast::Pat {
915+
id: ast::DUMMY_NODE_ID,
916+
node: fully_expanded,
917+
span: p.span,
918+
}
919+
}
920+
845921
pub struct IdentRenamer<'a> {
846922
renames: &'a mut RenameList,
847923
}
@@ -885,6 +961,10 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
885961
expand_expr(expr, self)
886962
}
887963

964+
fn fold_pat(&mut self, pat: @ast::Pat) -> @ast::Pat {
965+
expand_pat(pat, self)
966+
}
967+
888968
fn fold_item(&mut self, item: @ast::Item) -> SmallVector<@ast::Item> {
889969
expand_item(item, self)
890970
}
@@ -974,6 +1054,11 @@ fn mark_expr(expr: @ast::Expr, m: Mrk) -> @ast::Expr {
9741054
new_mark_folder(m).fold_expr(expr)
9751055
}
9761056

1057+
// apply a given mark to the given pattern. Used following the expansion of a macro.
1058+
fn mark_pat(pat: @ast::Pat, m: Mrk) -> @ast::Pat {
1059+
new_mark_folder(m).fold_pat(pat)
1060+
}
1061+
9771062
// apply a given mark to the given stmt. Used following the expansion of a macro.
9781063
fn mark_stmt(expr: &ast::Stmt, m: Mrk) -> @ast::Stmt {
9791064
new_mark_folder(m).fold_stmt(expr)

0 commit comments

Comments
 (0)