Skip to content

Commit 7f30eef

Browse files
committed
Introduce MacroGenerable trait
1 parent 179539f commit 7f30eef

File tree

1 file changed

+46
-53
lines changed

1 file changed

+46
-53
lines changed

src/libsyntax/ext/expand.rs

Lines changed: 46 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,40 @@ use std_inject;
3535
use std::collections::HashSet;
3636
use std::env;
3737

38+
trait MacroGenerable: Sized {
39+
fn make_with<'a>(result: Box<MacResult + 'a>) -> Option<Self>;
40+
fn fold_with<F: Folder>(self, folder: &mut F) -> Self;
41+
fn dummy(span: Span) -> Self;
42+
fn kind_name() -> &'static str;
43+
}
44+
45+
macro_rules! impl_macro_generable {
46+
($($ty:ty: $kind_name:expr, .$make:ident, $(.$fold:ident)* $(lift .$fold_elt:ident)*,
47+
|$span:ident| $dummy:expr;)*) => { $(
48+
impl MacroGenerable for $ty {
49+
fn kind_name() -> &'static str { $kind_name }
50+
fn make_with<'a>(result: Box<MacResult + 'a>) -> Option<Self> { result.$make() }
51+
fn fold_with<F: Folder>(self, folder: &mut F) -> Self {
52+
$( folder.$fold(self) )*
53+
$( self.into_iter().flat_map(|item| folder. $fold_elt (item)).collect() )*
54+
}
55+
fn dummy($span: Span) -> Self { $dummy }
56+
}
57+
)* }
58+
}
59+
60+
impl_macro_generable! {
61+
P<ast::Expr>: "expression", .make_expr, .fold_expr, |span| DummyResult::raw_expr(span);
62+
P<ast::Pat>: "pattern", .make_pat, .fold_pat, |span| P(DummyResult::raw_pat(span));
63+
P<ast::Ty>: "type", .make_ty, .fold_ty, |span| DummyResult::raw_ty(span);
64+
SmallVector<ast::ImplItem>:
65+
"impl item", .make_impl_items, lift .fold_impl_item, |_span| SmallVector::zero();
66+
SmallVector<P<ast::Item>>:
67+
"item", .make_items, lift .fold_item, |_span| SmallVector::zero();
68+
SmallVector<ast::Stmt>:
69+
"statement", .make_stmts, lift .fold_stmt, |_span| SmallVector::zero();
70+
}
71+
3872
// this function is called to detect use of feature-gated or invalid attributes
3973
// on macro invoations since they will not be detected after macro expansion
4074
fn check_attributes(attrs: &[ast::Attribute], fld: &MacroExpander) {
@@ -59,9 +93,7 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
5993
// Assert that we drop any macro attributes on the floor here
6094
drop(attrs);
6195

62-
let expanded_expr = match expand_mac_invoc(mac, span,
63-
|r| r.make_expr(),
64-
mark_expr, fld) {
96+
let expanded_expr = match expand_mac_invoc(mac, span, fld) {
6597
Some(expr) => expr,
6698
None => {
6799
return DummyResult::raw_expr(span);
@@ -182,19 +214,9 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
182214
});
183215
}
184216

185-
/// Expand a (not-ident-style) macro invocation. Returns the result
186-
/// of expansion and the mark which must be applied to the result.
187-
/// Our current interface doesn't allow us to apply the mark to the
188-
/// result until after calling make_expr, make_items, etc.
189-
fn expand_mac_invoc<T, F, G>(mac: ast::Mac,
190-
span: codemap::Span,
191-
parse_thunk: F,
192-
mark_thunk: G,
193-
fld: &mut MacroExpander)
194-
-> Option<T> where
195-
F: for<'a> FnOnce(Box<MacResult+'a>) -> Option<T>,
196-
G: FnOnce(T, Mrk) -> T,
197-
{
217+
/// Expand a (not-ident-style) macro invocation. Returns the result of expansion.
218+
fn expand_mac_invoc<T: MacroGenerable>(mac: ast::Mac, span: Span, fld: &mut MacroExpander)
219+
-> Option<T> {
198220
// it would almost certainly be cleaner to pass the whole
199221
// macro invocation in, rather than pulling it apart and
200222
// marking the tts and the ctxt separately. This also goes
@@ -245,7 +267,7 @@ fn expand_mac_invoc<T, F, G>(mac: ast::Mac,
245267
let expanded = expandfun.expand(fld.cx,
246268
mac_span,
247269
&marked_before[..]);
248-
parse_thunk(expanded)
270+
T::make_with(expanded)
249271
};
250272
let parsed = match opt_parsed {
251273
Some(e) => e,
@@ -258,7 +280,7 @@ fn expand_mac_invoc<T, F, G>(mac: ast::Mac,
258280
return None;
259281
}
260282
};
261-
Some(mark_thunk(parsed,fm))
283+
Some(parsed.fold_with(&mut Marker { mark: fm }))
262284
}
263285
_ => {
264286
fld.cx.span_err(
@@ -523,11 +545,8 @@ fn expand_stmt(stmt: Stmt, fld: &mut MacroExpander) -> SmallVector<Stmt> {
523545
// Assert that we drop any macro attributes on the floor here
524546
drop(attrs);
525547

526-
let maybe_new_items =
527-
expand_mac_invoc(mac.unwrap(), stmt.span,
528-
|r| r.make_stmts(),
529-
|stmts, mark| stmts.move_map(|m| mark_stmt(m, mark)),
530-
fld);
548+
let maybe_new_items: Option<SmallVector<ast::Stmt>> =
549+
expand_mac_invoc(mac.unwrap(), stmt.span, fld);
531550

532551
let mut fully_expanded = match maybe_new_items {
533552
Some(stmts) => {
@@ -759,6 +778,7 @@ fn expand_pat(p: P<ast::Pat>, fld: &mut MacroExpander) -> P<ast::Pat> {
759778
PatKind::Mac(mac) => (mac.node.path, mac.node.tts),
760779
_ => unreachable!()
761780
};
781+
762782
if pth.segments.len() > 1 {
763783
fld.cx.span_err(pth.span, "expected macro name without module separators");
764784
return DummyResult::raw_pat(span);
@@ -1079,11 +1099,8 @@ fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander)
10791099
ast::ImplItemKind::Macro(mac) => {
10801100
check_attributes(&ii.attrs, fld);
10811101

1082-
let maybe_new_items =
1083-
expand_mac_invoc(mac, ii.span,
1084-
|r| r.make_impl_items(),
1085-
|meths, mark| meths.move_map(|m| mark_impl_item(m, mark)),
1086-
fld);
1102+
let maybe_new_items: Option<SmallVector<ast::ImplItem>> =
1103+
expand_mac_invoc(mac, ii.span, fld);
10871104

10881105
match maybe_new_items {
10891106
Some(impl_items) => {
@@ -1139,10 +1156,7 @@ pub fn expand_type(t: P<ast::Ty>, fld: &mut MacroExpander) -> P<ast::Ty> {
11391156
let t = match t.node.clone() {
11401157
ast::TyKind::Mac(mac) => {
11411158
if fld.cx.ecfg.features.unwrap().type_macros {
1142-
let expanded_ty = match expand_mac_invoc(mac, t.span,
1143-
|r| r.make_ty(),
1144-
mark_ty,
1145-
fld) {
1159+
let expanded_ty = match expand_mac_invoc(mac, t.span, fld) {
11461160
Some(ty) => ty,
11471161
None => {
11481162
return DummyResult::raw_ty(t.span);
@@ -1426,38 +1440,17 @@ fn mark_tts(tts: &[TokenTree], m: Mrk) -> Vec<TokenTree> {
14261440
noop_fold_tts(tts, &mut Marker{mark:m})
14271441
}
14281442

1429-
// apply a given mark to the given expr. Used following the expansion of a macro.
1430-
fn mark_expr(expr: P<ast::Expr>, m: Mrk) -> P<ast::Expr> {
1431-
Marker{mark:m}.fold_expr(expr)
1432-
}
1433-
14341443
// apply a given mark to the given pattern. Used following the expansion of a macro.
14351444
fn mark_pat(pat: P<ast::Pat>, m: Mrk) -> P<ast::Pat> {
14361445
Marker{mark:m}.fold_pat(pat)
14371446
}
14381447

1439-
// apply a given mark to the given stmt. Used following the expansion of a macro.
1440-
fn mark_stmt(stmt: ast::Stmt, m: Mrk) -> ast::Stmt {
1441-
Marker{mark:m}.fold_stmt(stmt)
1442-
.expect_one("marking a stmt didn't return exactly one stmt")
1443-
}
1444-
14451448
// apply a given mark to the given item. Used following the expansion of a macro.
14461449
fn mark_item(expr: P<ast::Item>, m: Mrk) -> P<ast::Item> {
14471450
Marker{mark:m}.fold_item(expr)
14481451
.expect_one("marking an item didn't return exactly one item")
14491452
}
14501453

1451-
// apply a given mark to the given item. Used following the expansion of a macro.
1452-
fn mark_impl_item(ii: ast::ImplItem, m: Mrk) -> ast::ImplItem {
1453-
Marker{mark:m}.fold_impl_item(ii)
1454-
.expect_one("marking an impl item didn't return exactly one impl item")
1455-
}
1456-
1457-
fn mark_ty(ty: P<ast::Ty>, m: Mrk) -> P<ast::Ty> {
1458-
Marker { mark: m }.fold_ty(ty)
1459-
}
1460-
14611454
/// Check that there are no macro invocations left in the AST:
14621455
pub fn check_for_macros(sess: &parse::ParseSess, krate: &ast::Crate) {
14631456
visit::walk_crate(&mut MacroExterminator{sess:sess}, krate);

0 commit comments

Comments
 (0)