|
8 | 8 | // option. This file may not be copied, modified, or distributed
|
9 | 9 | // except according to those terms.
|
10 | 10 |
|
11 |
| -use ast::{P, Block, Crate, DeclLocal, ExprMac}; |
| 11 | +use ast::{P, Block, Crate, DeclLocal, ExprMac, PatMac}; |
12 | 12 | use ast::{Local, Ident, MacInvocTT};
|
13 | 13 | use ast::{ItemMac, Mrk, Stmt, StmtDecl, StmtMac, StmtExpr, StmtSemi};
|
14 | 14 | use ast::TokenTree;
|
@@ -92,8 +92,7 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr {
|
92 | 92 | None => {
|
93 | 93 | fld.cx.span_err(
|
94 | 94 | pth.span,
|
95 |
| - format!("non-expr macro in expr pos: \ |
96 |
| - {}", |
| 95 | + format!("non-expression macro in expression position: {}", |
97 | 96 | extnamestr.get().as_slice()
|
98 | 97 | ).as_slice());
|
99 | 98 | return DummyResult::raw_expr(e.span);
|
@@ -487,7 +486,7 @@ pub fn expand_item_mac(it: @ast::Item, fld: &mut MacroExpander)
|
487 | 486 | }
|
488 | 487 | None => {
|
489 | 488 | fld.cx.span_err(pth.span,
|
490 |
| - format!("expr macro in item position: {}", |
| 489 | + format!("non-item macro in item position: {}", |
491 | 490 | extnamestr.get()).as_slice());
|
492 | 491 | return SmallVector::zero();
|
493 | 492 | }
|
@@ -639,7 +638,7 @@ pub fn expand_stmt(s: &Stmt, fld: &mut MacroExpander) -> SmallVector<@Stmt> {
|
639 | 638 | Some(stmt) => stmt,
|
640 | 639 | None => {
|
641 | 640 | fld.cx.span_err(pth.span,
|
642 |
| - format!("non-stmt macro in stmt pos: {}", |
| 641 | + format!("non-statement macro in statement position: {}", |
643 | 642 | extnamestr).as_slice());
|
644 | 643 | return SmallVector::zero();
|
645 | 644 | }
|
@@ -842,6 +841,83 @@ pub fn expand_block_elts(b: &Block, fld: &mut MacroExpander) -> P<Block> {
|
842 | 841 | })
|
843 | 842 | }
|
844 | 843 |
|
| 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 | + |
845 | 921 | pub struct IdentRenamer<'a> {
|
846 | 922 | renames: &'a mut RenameList,
|
847 | 923 | }
|
@@ -885,6 +961,10 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
885 | 961 | expand_expr(expr, self)
|
886 | 962 | }
|
887 | 963 |
|
| 964 | + fn fold_pat(&mut self, pat: @ast::Pat) -> @ast::Pat { |
| 965 | + expand_pat(pat, self) |
| 966 | + } |
| 967 | + |
888 | 968 | fn fold_item(&mut self, item: @ast::Item) -> SmallVector<@ast::Item> {
|
889 | 969 | expand_item(item, self)
|
890 | 970 | }
|
@@ -974,6 +1054,11 @@ fn mark_expr(expr: @ast::Expr, m: Mrk) -> @ast::Expr {
|
974 | 1054 | new_mark_folder(m).fold_expr(expr)
|
975 | 1055 | }
|
976 | 1056 |
|
| 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 | + |
977 | 1062 | // apply a given mark to the given stmt. Used following the expansion of a macro.
|
978 | 1063 | fn mark_stmt(expr: &ast::Stmt, m: Mrk) -> @ast::Stmt {
|
979 | 1064 | new_mark_folder(m).fold_stmt(expr)
|
|
0 commit comments