Introduce MacroGenerable
trait
This commit is contained in:
parent
179539f6eb
commit
7f30eef2ee
@ -35,6 +35,40 @@ use std_inject;
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
|
||||
trait MacroGenerable: Sized {
|
||||
fn make_with<'a>(result: Box<MacResult + 'a>) -> Option<Self>;
|
||||
fn fold_with<F: Folder>(self, folder: &mut F) -> Self;
|
||||
fn dummy(span: Span) -> Self;
|
||||
fn kind_name() -> &'static str;
|
||||
}
|
||||
|
||||
macro_rules! impl_macro_generable {
|
||||
($($ty:ty: $kind_name:expr, .$make:ident, $(.$fold:ident)* $(lift .$fold_elt:ident)*,
|
||||
|$span:ident| $dummy:expr;)*) => { $(
|
||||
impl MacroGenerable for $ty {
|
||||
fn kind_name() -> &'static str { $kind_name }
|
||||
fn make_with<'a>(result: Box<MacResult + 'a>) -> Option<Self> { result.$make() }
|
||||
fn fold_with<F: Folder>(self, folder: &mut F) -> Self {
|
||||
$( folder.$fold(self) )*
|
||||
$( self.into_iter().flat_map(|item| folder. $fold_elt (item)).collect() )*
|
||||
}
|
||||
fn dummy($span: Span) -> Self { $dummy }
|
||||
}
|
||||
)* }
|
||||
}
|
||||
|
||||
impl_macro_generable! {
|
||||
P<ast::Expr>: "expression", .make_expr, .fold_expr, |span| DummyResult::raw_expr(span);
|
||||
P<ast::Pat>: "pattern", .make_pat, .fold_pat, |span| P(DummyResult::raw_pat(span));
|
||||
P<ast::Ty>: "type", .make_ty, .fold_ty, |span| DummyResult::raw_ty(span);
|
||||
SmallVector<ast::ImplItem>:
|
||||
"impl item", .make_impl_items, lift .fold_impl_item, |_span| SmallVector::zero();
|
||||
SmallVector<P<ast::Item>>:
|
||||
"item", .make_items, lift .fold_item, |_span| SmallVector::zero();
|
||||
SmallVector<ast::Stmt>:
|
||||
"statement", .make_stmts, lift .fold_stmt, |_span| SmallVector::zero();
|
||||
}
|
||||
|
||||
// this function is called to detect use of feature-gated or invalid attributes
|
||||
// on macro invoations since they will not be detected after macro expansion
|
||||
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> {
|
||||
// Assert that we drop any macro attributes on the floor here
|
||||
drop(attrs);
|
||||
|
||||
let expanded_expr = match expand_mac_invoc(mac, span,
|
||||
|r| r.make_expr(),
|
||||
mark_expr, fld) {
|
||||
let expanded_expr = match expand_mac_invoc(mac, span, fld) {
|
||||
Some(expr) => expr,
|
||||
None => {
|
||||
return DummyResult::raw_expr(span);
|
||||
@ -182,19 +214,9 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
|
||||
});
|
||||
}
|
||||
|
||||
/// Expand a (not-ident-style) macro invocation. Returns the result
|
||||
/// of expansion and the mark which must be applied to the result.
|
||||
/// Our current interface doesn't allow us to apply the mark to the
|
||||
/// result until after calling make_expr, make_items, etc.
|
||||
fn expand_mac_invoc<T, F, G>(mac: ast::Mac,
|
||||
span: codemap::Span,
|
||||
parse_thunk: F,
|
||||
mark_thunk: G,
|
||||
fld: &mut MacroExpander)
|
||||
-> Option<T> where
|
||||
F: for<'a> FnOnce(Box<MacResult+'a>) -> Option<T>,
|
||||
G: FnOnce(T, Mrk) -> T,
|
||||
{
|
||||
/// Expand a (not-ident-style) macro invocation. Returns the result of expansion.
|
||||
fn expand_mac_invoc<T: MacroGenerable>(mac: ast::Mac, span: Span, fld: &mut MacroExpander)
|
||||
-> Option<T> {
|
||||
// it would almost certainly be cleaner to pass the whole
|
||||
// macro invocation in, rather than pulling it apart and
|
||||
// marking the tts and the ctxt separately. This also goes
|
||||
@ -245,7 +267,7 @@ fn expand_mac_invoc<T, F, G>(mac: ast::Mac,
|
||||
let expanded = expandfun.expand(fld.cx,
|
||||
mac_span,
|
||||
&marked_before[..]);
|
||||
parse_thunk(expanded)
|
||||
T::make_with(expanded)
|
||||
};
|
||||
let parsed = match opt_parsed {
|
||||
Some(e) => e,
|
||||
@ -258,7 +280,7 @@ fn expand_mac_invoc<T, F, G>(mac: ast::Mac,
|
||||
return None;
|
||||
}
|
||||
};
|
||||
Some(mark_thunk(parsed,fm))
|
||||
Some(parsed.fold_with(&mut Marker { mark: fm }))
|
||||
}
|
||||
_ => {
|
||||
fld.cx.span_err(
|
||||
@ -523,11 +545,8 @@ fn expand_stmt(stmt: Stmt, fld: &mut MacroExpander) -> SmallVector<Stmt> {
|
||||
// Assert that we drop any macro attributes on the floor here
|
||||
drop(attrs);
|
||||
|
||||
let maybe_new_items =
|
||||
expand_mac_invoc(mac.unwrap(), stmt.span,
|
||||
|r| r.make_stmts(),
|
||||
|stmts, mark| stmts.move_map(|m| mark_stmt(m, mark)),
|
||||
fld);
|
||||
let maybe_new_items: Option<SmallVector<ast::Stmt>> =
|
||||
expand_mac_invoc(mac.unwrap(), stmt.span, fld);
|
||||
|
||||
let mut fully_expanded = match maybe_new_items {
|
||||
Some(stmts) => {
|
||||
@ -759,6 +778,7 @@ fn expand_pat(p: P<ast::Pat>, fld: &mut MacroExpander) -> P<ast::Pat> {
|
||||
PatKind::Mac(mac) => (mac.node.path, mac.node.tts),
|
||||
_ => unreachable!()
|
||||
};
|
||||
|
||||
if pth.segments.len() > 1 {
|
||||
fld.cx.span_err(pth.span, "expected macro name without module separators");
|
||||
return DummyResult::raw_pat(span);
|
||||
@ -1079,11 +1099,8 @@ fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander)
|
||||
ast::ImplItemKind::Macro(mac) => {
|
||||
check_attributes(&ii.attrs, fld);
|
||||
|
||||
let maybe_new_items =
|
||||
expand_mac_invoc(mac, ii.span,
|
||||
|r| r.make_impl_items(),
|
||||
|meths, mark| meths.move_map(|m| mark_impl_item(m, mark)),
|
||||
fld);
|
||||
let maybe_new_items: Option<SmallVector<ast::ImplItem>> =
|
||||
expand_mac_invoc(mac, ii.span, fld);
|
||||
|
||||
match maybe_new_items {
|
||||
Some(impl_items) => {
|
||||
@ -1139,10 +1156,7 @@ pub fn expand_type(t: P<ast::Ty>, fld: &mut MacroExpander) -> P<ast::Ty> {
|
||||
let t = match t.node.clone() {
|
||||
ast::TyKind::Mac(mac) => {
|
||||
if fld.cx.ecfg.features.unwrap().type_macros {
|
||||
let expanded_ty = match expand_mac_invoc(mac, t.span,
|
||||
|r| r.make_ty(),
|
||||
mark_ty,
|
||||
fld) {
|
||||
let expanded_ty = match expand_mac_invoc(mac, t.span, fld) {
|
||||
Some(ty) => ty,
|
||||
None => {
|
||||
return DummyResult::raw_ty(t.span);
|
||||
@ -1426,38 +1440,17 @@ fn mark_tts(tts: &[TokenTree], m: Mrk) -> Vec<TokenTree> {
|
||||
noop_fold_tts(tts, &mut Marker{mark:m})
|
||||
}
|
||||
|
||||
// apply a given mark to the given expr. Used following the expansion of a macro.
|
||||
fn mark_expr(expr: P<ast::Expr>, m: Mrk) -> P<ast::Expr> {
|
||||
Marker{mark:m}.fold_expr(expr)
|
||||
}
|
||||
|
||||
// apply a given mark to the given pattern. Used following the expansion of a macro.
|
||||
fn mark_pat(pat: P<ast::Pat>, m: Mrk) -> P<ast::Pat> {
|
||||
Marker{mark:m}.fold_pat(pat)
|
||||
}
|
||||
|
||||
// apply a given mark to the given stmt. Used following the expansion of a macro.
|
||||
fn mark_stmt(stmt: ast::Stmt, m: Mrk) -> ast::Stmt {
|
||||
Marker{mark:m}.fold_stmt(stmt)
|
||||
.expect_one("marking a stmt didn't return exactly one stmt")
|
||||
}
|
||||
|
||||
// apply a given mark to the given item. Used following the expansion of a macro.
|
||||
fn mark_item(expr: P<ast::Item>, m: Mrk) -> P<ast::Item> {
|
||||
Marker{mark:m}.fold_item(expr)
|
||||
.expect_one("marking an item didn't return exactly one item")
|
||||
}
|
||||
|
||||
// apply a given mark to the given item. Used following the expansion of a macro.
|
||||
fn mark_impl_item(ii: ast::ImplItem, m: Mrk) -> ast::ImplItem {
|
||||
Marker{mark:m}.fold_impl_item(ii)
|
||||
.expect_one("marking an impl item didn't return exactly one impl item")
|
||||
}
|
||||
|
||||
fn mark_ty(ty: P<ast::Ty>, m: Mrk) -> P<ast::Ty> {
|
||||
Marker { mark: m }.fold_ty(ty)
|
||||
}
|
||||
|
||||
/// Check that there are no macro invocations left in the AST:
|
||||
pub fn check_for_macros(sess: &parse::ParseSess, krate: &ast::Crate) {
|
||||
visit::walk_crate(&mut MacroExterminator{sess:sess}, krate);
|
||||
|
Loading…
Reference in New Issue
Block a user