Add Invocation
and Expansion
, remove MacroGenerable
.
This commit is contained in:
parent
9b3bc7a9e9
commit
de2e67836e
1 changed files with 259 additions and 231 deletions
|
@ -30,249 +30,230 @@ use std_inject;
|
|||
|
||||
use std::path::PathBuf;
|
||||
|
||||
// A trait for AST nodes and AST node lists into which macro invocations may expand.
|
||||
trait MacroGenerable: Sized {
|
||||
// Expand the given MacResult using its appropriate `make_*` method.
|
||||
fn make_with<'a>(result: Box<MacResult + 'a>) -> Option<Self>;
|
||||
macro_rules! expansions {
|
||||
($($kind:ident: $ty:ty, $kind_name:expr, .$make:ident,
|
||||
$(.$fold:ident)* $(lift .$fold_elt:ident)*,
|
||||
$(.$visit:ident)* $(lift .$visit_elt:ident)*;)*) => {
|
||||
#[derive(Copy, Clone)]
|
||||
enum ExpansionKind { OptExpr, $( $kind, )* }
|
||||
enum Expansion { OptExpr(Option<P<ast::Expr>>), $( $kind($ty), )* }
|
||||
|
||||
// Fold this node or list of nodes using the given folder.
|
||||
fn fold_with<F: Folder>(self, folder: &mut F) -> Self;
|
||||
fn visit_with<V: Visitor>(&self, visitor: &mut V);
|
||||
impl ExpansionKind {
|
||||
fn name(self) -> &'static str {
|
||||
match self {
|
||||
ExpansionKind::OptExpr => "expression",
|
||||
$( ExpansionKind::$kind => $kind_name, )*
|
||||
}
|
||||
}
|
||||
|
||||
// The user-friendly name of the node type (e.g. "expression", "item", etc.) for diagnostics.
|
||||
fn kind_name() -> &'static str;
|
||||
fn make_from<'a>(self, result: Box<MacResult + 'a>) -> Option<Expansion> {
|
||||
match self {
|
||||
ExpansionKind::OptExpr => result.make_expr().map(Some).map(Expansion::OptExpr),
|
||||
$( ExpansionKind::$kind => result.$make().map(Expansion::$kind), )*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return a placeholder expansion to allow compilation to continue after an erroring expansion.
|
||||
fn dummy(span: Span) -> Self {
|
||||
Self::make_with(DummyResult::any(span)).unwrap()
|
||||
impl Expansion {
|
||||
fn make_opt_expr(self) -> Option<P<ast::Expr>> {
|
||||
match self {
|
||||
Expansion::OptExpr(expr) => expr,
|
||||
_ => panic!("Expansion::make_* called on the wrong kind of expansion"),
|
||||
}
|
||||
}
|
||||
$( fn $make(self) -> $ty {
|
||||
match self {
|
||||
Expansion::$kind(ast) => ast,
|
||||
_ => panic!("Expansion::make_* called on the wrong kind of expansion"),
|
||||
}
|
||||
} )*
|
||||
|
||||
fn fold_with<F: Folder>(self, folder: &mut F) -> Self {
|
||||
use self::Expansion::*;
|
||||
match self {
|
||||
OptExpr(expr) => OptExpr(expr.and_then(|expr| folder.fold_opt_expr(expr))),
|
||||
$($( $kind(ast) => $kind(folder.$fold(ast)), )*)*
|
||||
$($( $kind(ast) => {
|
||||
$kind(ast.into_iter().flat_map(|ast| folder.$fold_elt(ast)).collect())
|
||||
}, )*)*
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_with<V: Visitor>(&self, visitor: &mut V) {
|
||||
match *self {
|
||||
Expansion::OptExpr(Some(ref expr)) => visitor.visit_expr(expr),
|
||||
$($( Expansion::$kind(ref ast) => visitor.$visit(ast), )*)*
|
||||
$($( Expansion::$kind(ref ast) => for ast in ast.as_slice() {
|
||||
visitor.$visit_elt(ast);
|
||||
}, )*)*
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_macro_generable {
|
||||
($($ty:ty: $kind_name:expr, .$make:ident,
|
||||
$(.$fold:ident)* $(lift .$fold_elt:ident)*,
|
||||
$(.$visit:ident)* $(lift .$visit_elt:ident)*;)*) => { $(
|
||||
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 visit_with<V: Visitor>(&self, visitor: &mut V) {
|
||||
$( visitor.$visit(self) )*
|
||||
$( for item in self.as_slice() { visitor. $visit_elt (item) } )*
|
||||
}
|
||||
}
|
||||
)* }
|
||||
}
|
||||
|
||||
impl_macro_generable! {
|
||||
P<ast::Expr>: "expression", .make_expr, .fold_expr, .visit_expr;
|
||||
P<ast::Pat>: "pattern", .make_pat, .fold_pat, .visit_pat;
|
||||
P<ast::Ty>: "type", .make_ty, .fold_ty, .visit_ty;
|
||||
SmallVector<ast::Stmt>: "statement", .make_stmts, lift .fold_stmt, lift .visit_stmt;
|
||||
SmallVector<P<ast::Item>>: "item", .make_items, lift .fold_item, lift .visit_item;
|
||||
SmallVector<ast::TraitItem>:
|
||||
expansions! {
|
||||
Expr: P<ast::Expr>, "expression", .make_expr, .fold_expr, .visit_expr;
|
||||
Pat: P<ast::Pat>, "pattern", .make_pat, .fold_pat, .visit_pat;
|
||||
Ty: P<ast::Ty>, "type", .make_ty, .fold_ty, .visit_ty;
|
||||
Stmts: SmallVector<ast::Stmt>, "statement", .make_stmts, lift .fold_stmt, lift .visit_stmt;
|
||||
Items: SmallVector<P<ast::Item>>, "item", .make_items, lift .fold_item, lift .visit_item;
|
||||
TraitItems: SmallVector<ast::TraitItem>,
|
||||
"trait item", .make_trait_items, lift .fold_trait_item, lift .visit_trait_item;
|
||||
SmallVector<ast::ImplItem>:
|
||||
ImplItems: SmallVector<ast::ImplItem>,
|
||||
"impl item", .make_impl_items, lift .fold_impl_item, lift .visit_impl_item;
|
||||
}
|
||||
|
||||
impl MacroGenerable for Option<P<ast::Expr>> {
|
||||
fn kind_name() -> &'static str { "expression" }
|
||||
fn make_with<'a>(result: Box<MacResult + 'a>) -> Option<Self> {
|
||||
result.make_expr().map(Some)
|
||||
}
|
||||
fn fold_with<F: Folder>(self, folder: &mut F) -> Self {
|
||||
self.and_then(|expr| folder.fold_opt_expr(expr))
|
||||
}
|
||||
fn visit_with<V: Visitor>(&self, visitor: &mut V) {
|
||||
self.as_ref().map(|expr| visitor.visit_expr(expr));
|
||||
impl ExpansionKind {
|
||||
fn dummy(self, span: Span) -> Expansion {
|
||||
self.make_from(DummyResult::any(span)).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Invocation {
|
||||
span: Span,
|
||||
attrs: Vec<ast::Attribute>,
|
||||
mac: ast::Mac,
|
||||
ident: Option<Ident>,
|
||||
mark: Mark,
|
||||
kind: ExpansionKind,
|
||||
}
|
||||
|
||||
pub fn expand_expr(expr: ast::Expr, fld: &mut MacroExpander) -> P<ast::Expr> {
|
||||
match expr.node {
|
||||
// expr_mac should really be expr_ext or something; it's the
|
||||
// entry-point for all syntax extensions.
|
||||
ast::ExprKind::Mac(mac) => {
|
||||
return expand_mac_invoc(mac, None, expr.attrs.into(), expr.span, fld);
|
||||
}
|
||||
_ => P(noop_fold_expr(expr, fld)),
|
||||
}
|
||||
}
|
||||
|
||||
struct MacroScopePlaceholder;
|
||||
impl MacResult for MacroScopePlaceholder {
|
||||
fn make_items(self: Box<Self>) -> Option<SmallVector<P<ast::Item>>> {
|
||||
Some(SmallVector::one(P(ast::Item {
|
||||
ident: keywords::Invalid.ident(),
|
||||
attrs: Vec::new(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
node: ast::ItemKind::Mac(dummy_spanned(ast::Mac_ {
|
||||
path: ast::Path { span: syntax_pos::DUMMY_SP, global: false, segments: Vec::new() },
|
||||
tts: Vec::new(),
|
||||
})),
|
||||
vis: ast::Visibility::Inherited,
|
||||
span: syntax_pos::DUMMY_SP,
|
||||
})))
|
||||
if let ast::ExprKind::Mac(mac) = expr.node {
|
||||
let invoc = fld.new_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::Expr);
|
||||
expand_mac_invoc(invoc, fld).make_expr()
|
||||
} else {
|
||||
P(noop_fold_expr(expr, fld))
|
||||
}
|
||||
}
|
||||
|
||||
/// Expand a macro invocation. Returns the result of expansion.
|
||||
fn expand_mac_invoc<T>(mac: ast::Mac, ident: Option<Ident>, attrs: Vec<ast::Attribute>, span: Span,
|
||||
fld: &mut MacroExpander) -> T
|
||||
where T: MacroGenerable,
|
||||
{
|
||||
// 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.
|
||||
fn expand_mac_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
|
||||
let Invocation { span, attrs, mac, ident, mark, kind } = invoc;
|
||||
let Mac_ { path, tts, .. } = mac.node;
|
||||
let mark = Mark::fresh();
|
||||
|
||||
fn mac_result<'a>(path: &ast::Path, ident: Option<Ident>, tts: Vec<TokenTree>, mark: Mark,
|
||||
attrs: Vec<ast::Attribute>, call_site: Span, fld: &'a mut MacroExpander)
|
||||
-> Option<Box<MacResult + 'a>> {
|
||||
// Detect use of feature-gated or invalid attributes on macro invoations
|
||||
// since they will not be detected after macro expansion.
|
||||
for attr in attrs.iter() {
|
||||
feature_gate::check_attribute(&attr, &fld.cx.parse_sess.span_diagnostic,
|
||||
&fld.cx.parse_sess.codemap(),
|
||||
&fld.cx.ecfg.features.unwrap());
|
||||
}
|
||||
|
||||
if path.segments.len() > 1 || path.global || !path.segments[0].parameters.is_empty() {
|
||||
fld.cx.span_err(path.span, "expected macro name without module separators");
|
||||
return None;
|
||||
}
|
||||
|
||||
let extname = path.segments[0].identifier.name;
|
||||
let extension = if let Some(extension) = fld.cx.syntax_env.find(extname) {
|
||||
extension
|
||||
} else {
|
||||
let mut err = fld.cx.struct_span_err(path.span,
|
||||
&format!("macro undefined: '{}!'", &extname));
|
||||
fld.cx.suggest_macro_name(&extname.as_str(), &mut err);
|
||||
err.emit();
|
||||
return None;
|
||||
};
|
||||
|
||||
let ident = ident.unwrap_or(keywords::Invalid.ident());
|
||||
let marked_tts = mark_tts(&tts, mark);
|
||||
match *extension {
|
||||
NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
|
||||
if ident.name != keywords::Invalid.name() {
|
||||
let msg =
|
||||
format!("macro {}! expects no ident argument, given '{}'", extname, ident);
|
||||
fld.cx.span_err(path.span, &msg);
|
||||
return None;
|
||||
}
|
||||
|
||||
fld.cx.bt_push(ExpnInfo {
|
||||
call_site: call_site,
|
||||
callee: NameAndSpan {
|
||||
format: MacroBang(extname),
|
||||
span: exp_span,
|
||||
allow_internal_unstable: allow_internal_unstable,
|
||||
},
|
||||
});
|
||||
|
||||
Some(expandfun.expand(fld.cx, call_site, &marked_tts))
|
||||
}
|
||||
|
||||
IdentTT(ref expander, tt_span, allow_internal_unstable) => {
|
||||
if ident.name == keywords::Invalid.name() {
|
||||
fld.cx.span_err(path.span,
|
||||
&format!("macro {}! expects an ident argument", extname));
|
||||
return None;
|
||||
};
|
||||
|
||||
fld.cx.bt_push(ExpnInfo {
|
||||
call_site: call_site,
|
||||
callee: NameAndSpan {
|
||||
format: MacroBang(extname),
|
||||
span: tt_span,
|
||||
allow_internal_unstable: allow_internal_unstable,
|
||||
}
|
||||
});
|
||||
|
||||
Some(expander.expand(fld.cx, call_site, ident, marked_tts))
|
||||
}
|
||||
|
||||
MacroRulesTT => {
|
||||
if ident.name == keywords::Invalid.name() {
|
||||
fld.cx.span_err(path.span,
|
||||
&format!("macro {}! expects an ident argument", extname));
|
||||
return None;
|
||||
};
|
||||
|
||||
fld.cx.bt_push(ExpnInfo {
|
||||
call_site: call_site,
|
||||
callee: NameAndSpan {
|
||||
format: MacroBang(extname),
|
||||
span: None,
|
||||
// `macro_rules!` doesn't directly allow unstable
|
||||
// (this is orthogonal to whether the macro it creates allows it)
|
||||
allow_internal_unstable: false,
|
||||
}
|
||||
});
|
||||
|
||||
let def = ast::MacroDef {
|
||||
ident: ident,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: call_site,
|
||||
imported_from: None,
|
||||
use_locally: true,
|
||||
body: marked_tts,
|
||||
export: attr::contains_name(&attrs, "macro_export"),
|
||||
allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"),
|
||||
attrs: attrs,
|
||||
};
|
||||
|
||||
fld.cx.insert_macro(def.clone());
|
||||
|
||||
// macro_rules! has a side effect, but expands to nothing.
|
||||
// If keep_macs is true, expands to a MacEager::items instead.
|
||||
if fld.keep_macs {
|
||||
Some(MacEager::items(SmallVector::one(P(ast::Item {
|
||||
ident: def.ident,
|
||||
attrs: def.attrs.clone(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
node: ast::ItemKind::Mac(ast::Mac {
|
||||
span: def.span,
|
||||
node: ast::Mac_ {
|
||||
path: path.clone(),
|
||||
tts: def.body.clone(),
|
||||
}
|
||||
}),
|
||||
vis: ast::Visibility::Inherited,
|
||||
span: def.span,
|
||||
}))))
|
||||
} else {
|
||||
Some(Box::new(MacroScopePlaceholder))
|
||||
}
|
||||
}
|
||||
|
||||
MultiDecorator(..) | MultiModifier(..) => {
|
||||
fld.cx.span_err(path.span,
|
||||
&format!("`{}` can only be used in attributes", extname));
|
||||
None
|
||||
}
|
||||
}
|
||||
// Detect use of feature-gated or invalid attributes on macro invoations
|
||||
// since they will not be detected after macro expansion.
|
||||
for attr in attrs.iter() {
|
||||
feature_gate::check_attribute(&attr, &fld.cx.parse_sess.span_diagnostic,
|
||||
&fld.cx.parse_sess.codemap(),
|
||||
&fld.cx.ecfg.features.unwrap());
|
||||
}
|
||||
|
||||
let opt_expanded = T::make_with(match mac_result(&path, ident, tts, mark, attrs, span, fld) {
|
||||
Some(result) => result,
|
||||
None => return T::dummy(span),
|
||||
});
|
||||
if path.segments.len() > 1 || path.global || !path.segments[0].parameters.is_empty() {
|
||||
fld.cx.span_err(path.span, "expected macro name without module separators");
|
||||
return kind.dummy(span);
|
||||
}
|
||||
|
||||
let extname = path.segments[0].identifier.name;
|
||||
let extension = if let Some(extension) = fld.cx.syntax_env.find(extname) {
|
||||
extension
|
||||
} else {
|
||||
let mut err =
|
||||
fld.cx.struct_span_err(path.span, &format!("macro undefined: '{}!'", &extname));
|
||||
fld.cx.suggest_macro_name(&extname.as_str(), &mut err);
|
||||
err.emit();
|
||||
return kind.dummy(span);
|
||||
};
|
||||
|
||||
let ident = ident.unwrap_or(keywords::Invalid.ident());
|
||||
let marked_tts = mark_tts(&tts, mark);
|
||||
let opt_expanded = match *extension {
|
||||
NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
|
||||
if ident.name != keywords::Invalid.name() {
|
||||
let msg =
|
||||
format!("macro {}! expects no ident argument, given '{}'", extname, ident);
|
||||
fld.cx.span_err(path.span, &msg);
|
||||
return kind.dummy(span);
|
||||
}
|
||||
|
||||
fld.cx.bt_push(ExpnInfo {
|
||||
call_site: span,
|
||||
callee: NameAndSpan {
|
||||
format: MacroBang(extname),
|
||||
span: exp_span,
|
||||
allow_internal_unstable: allow_internal_unstable,
|
||||
},
|
||||
});
|
||||
|
||||
kind.make_from(expandfun.expand(fld.cx, span, &marked_tts))
|
||||
}
|
||||
|
||||
IdentTT(ref expander, tt_span, allow_internal_unstable) => {
|
||||
if ident.name == keywords::Invalid.name() {
|
||||
fld.cx.span_err(path.span,
|
||||
&format!("macro {}! expects an ident argument", extname));
|
||||
return kind.dummy(span);
|
||||
};
|
||||
|
||||
fld.cx.bt_push(ExpnInfo {
|
||||
call_site: span,
|
||||
callee: NameAndSpan {
|
||||
format: MacroBang(extname),
|
||||
span: tt_span,
|
||||
allow_internal_unstable: allow_internal_unstable,
|
||||
}
|
||||
});
|
||||
|
||||
kind.make_from(expander.expand(fld.cx, span, ident, marked_tts))
|
||||
}
|
||||
|
||||
MacroRulesTT => {
|
||||
if ident.name == keywords::Invalid.name() {
|
||||
fld.cx.span_err(path.span,
|
||||
&format!("macro {}! expects an ident argument", extname));
|
||||
return kind.dummy(span);
|
||||
};
|
||||
|
||||
fld.cx.bt_push(ExpnInfo {
|
||||
call_site: span,
|
||||
callee: NameAndSpan {
|
||||
format: MacroBang(extname),
|
||||
span: None,
|
||||
// `macro_rules!` doesn't directly allow unstable
|
||||
// (this is orthogonal to whether the macro it creates allows it)
|
||||
allow_internal_unstable: false,
|
||||
}
|
||||
});
|
||||
|
||||
let def = ast::MacroDef {
|
||||
ident: ident,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: span,
|
||||
imported_from: None,
|
||||
use_locally: true,
|
||||
body: marked_tts,
|
||||
export: attr::contains_name(&attrs, "macro_export"),
|
||||
allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"),
|
||||
attrs: attrs,
|
||||
};
|
||||
|
||||
fld.cx.insert_macro(def.clone());
|
||||
|
||||
// If keep_macs is true, expands to a MacEager::items instead.
|
||||
if fld.keep_macs {
|
||||
Some(reconstruct_macro_rules(&def, &path))
|
||||
} else {
|
||||
Some(macro_scope_placeholder())
|
||||
}
|
||||
}
|
||||
|
||||
MultiDecorator(..) | MultiModifier(..) => {
|
||||
fld.cx.span_err(path.span,
|
||||
&format!("`{}` can only be used in attributes", extname));
|
||||
return kind.dummy(span);
|
||||
}
|
||||
};
|
||||
|
||||
let expanded = if let Some(expanded) = opt_expanded {
|
||||
expanded
|
||||
} else {
|
||||
let msg = format!("non-{kind} macro in {kind} position: {name}",
|
||||
name = path.segments[0].identifier.name, kind = T::kind_name());
|
||||
name = path.segments[0].identifier.name, kind = kind.name());
|
||||
fld.cx.span_err(path.span, &msg);
|
||||
return T::dummy(span);
|
||||
return kind.dummy(span);
|
||||
};
|
||||
|
||||
let marked = expanded.fold_with(&mut Marker { mark: mark, expn_id: Some(fld.cx.backtrace()) });
|
||||
|
@ -342,8 +323,8 @@ fn expand_stmt(stmt: Stmt, fld: &mut MacroExpander) -> SmallVector<Stmt> {
|
|||
_ => return noop_fold_stmt(stmt, fld)
|
||||
};
|
||||
|
||||
let mut fully_expanded: SmallVector<ast::Stmt> =
|
||||
expand_mac_invoc(mac, None, attrs.into(), stmt.span, fld);
|
||||
let invoc = fld.new_invoc(mac, attrs.into(), stmt.span, ExpansionKind::Stmts);
|
||||
let mut fully_expanded = expand_mac_invoc(invoc, fld).make_stmts();
|
||||
|
||||
// If this is a macro invocation with a semicolon, then apply that
|
||||
// semicolon to the final statement produced by expansion.
|
||||
|
@ -361,11 +342,12 @@ fn expand_pat(p: P<ast::Pat>, fld: &mut MacroExpander) -> P<ast::Pat> {
|
|||
PatKind::Mac(_) => {}
|
||||
_ => return noop_fold_pat(p, fld)
|
||||
}
|
||||
p.and_then(|ast::Pat {node, span, ..}| {
|
||||
match node {
|
||||
PatKind::Mac(mac) => expand_mac_invoc(mac, None, Vec::new(), span, fld),
|
||||
_ => unreachable!()
|
||||
p.and_then(|p| match p.node {
|
||||
PatKind::Mac(mac) => {
|
||||
let invoc = fld.new_invoc(mac, Vec::new(), p.span, ExpansionKind::Pat);
|
||||
expand_mac_invoc(invoc, fld).make_pat()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -380,8 +362,11 @@ fn expand_multi_modified(a: Annotatable, fld: &mut MacroExpander) -> SmallVector
|
|||
return SmallVector::one(Annotatable::Item(it));
|
||||
}
|
||||
it.and_then(|it| match it.node {
|
||||
ItemKind::Mac(mac) =>
|
||||
expand_mac_invoc(mac, Some(it.ident), it.attrs, it.span, fld),
|
||||
ItemKind::Mac(mac) => {
|
||||
let mut invoc = fld.new_invoc(mac, it.attrs, it.span, ExpansionKind::Items);
|
||||
invoc.ident = Some(it.ident);
|
||||
expand_mac_invoc(invoc, fld).make_items()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
})
|
||||
}
|
||||
|
@ -472,7 +457,8 @@ fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander)
|
|||
-> SmallVector<ast::ImplItem> {
|
||||
match ii.node {
|
||||
ast::ImplItemKind::Macro(mac) => {
|
||||
expand_mac_invoc(mac, None, ii.attrs, ii.span, fld)
|
||||
let invoc = fld.new_invoc(mac, ii.attrs, ii.span, ExpansionKind::ImplItems);
|
||||
expand_mac_invoc(invoc, fld).make_impl_items()
|
||||
}
|
||||
_ => fold::noop_fold_impl_item(ii, fld)
|
||||
}
|
||||
|
@ -482,7 +468,8 @@ fn expand_trait_item(ti: ast::TraitItem, fld: &mut MacroExpander)
|
|||
-> SmallVector<ast::TraitItem> {
|
||||
match ti.node {
|
||||
ast::TraitItemKind::Macro(mac) => {
|
||||
expand_mac_invoc(mac, None, ti.attrs, ti.span, fld)
|
||||
let invoc = fld.new_invoc(mac, ti.attrs, ti.span, ExpansionKind::TraitItems);
|
||||
expand_mac_invoc(invoc, fld).make_trait_items()
|
||||
}
|
||||
_ => fold::noop_fold_trait_item(ti, fld)
|
||||
}
|
||||
|
@ -496,7 +483,8 @@ pub fn expand_type(t: P<ast::Ty>, fld: &mut MacroExpander) -> P<ast::Ty> {
|
|||
|
||||
match t.node {
|
||||
ast::TyKind::Mac(mac) => {
|
||||
expand_mac_invoc(mac, None, Vec::new(), t.span, fld)
|
||||
let invoc = fld.new_invoc(mac, Vec::new(), t.span, ExpansionKind::Ty);
|
||||
expand_mac_invoc(invoc, fld).make_ty()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
@ -529,7 +517,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
fn load_macros<T: MacroGenerable>(&mut self, node: &T) {
|
||||
fn load_macros(&mut self, node: &Expansion) {
|
||||
struct MacroLoadingVisitor<'a, 'b: 'a>{
|
||||
cx: &'a mut ExtCtxt<'b>,
|
||||
at_crate_root: bool,
|
||||
|
@ -567,6 +555,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
cx: self.cx,
|
||||
});
|
||||
}
|
||||
|
||||
fn new_invoc(&self, mac: ast::Mac, attrs: Vec<ast::Attribute>, span: Span, kind: ExpansionKind)
|
||||
-> Invocation {
|
||||
let mark = Mark::fresh();
|
||||
Invocation { span: span, attrs: attrs, mac: mac, mark: mark, kind: kind, ident: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
||||
|
@ -583,8 +577,11 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
|||
|
||||
fn fold_opt_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
|
||||
expr.and_then(|expr| match expr.node {
|
||||
ast::ExprKind::Mac(mac) =>
|
||||
expand_mac_invoc(mac, None, expr.attrs.into(), expr.span, self),
|
||||
ast::ExprKind::Mac(mac) => {
|
||||
let invoc =
|
||||
self.new_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::OptExpr);
|
||||
expand_mac_invoc(invoc, self).make_opt_expr()
|
||||
}
|
||||
_ => Some(expand_expr(expr, self)),
|
||||
})
|
||||
}
|
||||
|
@ -647,6 +644,37 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
fn macro_scope_placeholder() -> Expansion {
|
||||
Expansion::Items(SmallVector::one(P(ast::Item {
|
||||
ident: keywords::Invalid.ident(),
|
||||
attrs: Vec::new(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
node: ast::ItemKind::Mac(dummy_spanned(ast::Mac_ {
|
||||
path: ast::Path { span: syntax_pos::DUMMY_SP, global: false, segments: Vec::new() },
|
||||
tts: Vec::new(),
|
||||
})),
|
||||
vis: ast::Visibility::Inherited,
|
||||
span: syntax_pos::DUMMY_SP,
|
||||
})))
|
||||
}
|
||||
|
||||
fn reconstruct_macro_rules(def: &ast::MacroDef, path: &ast::Path) -> Expansion {
|
||||
Expansion::Items(SmallVector::one(P(ast::Item {
|
||||
ident: def.ident,
|
||||
attrs: def.attrs.clone(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
node: ast::ItemKind::Mac(ast::Mac {
|
||||
span: def.span,
|
||||
node: ast::Mac_ {
|
||||
path: path.clone(),
|
||||
tts: def.body.clone(),
|
||||
}
|
||||
}),
|
||||
vis: ast::Visibility::Inherited,
|
||||
span: def.span,
|
||||
})))
|
||||
}
|
||||
|
||||
pub struct ExpansionConfig<'feat> {
|
||||
pub crate_name: String,
|
||||
pub features: Option<&'feat Features>,
|
||||
|
@ -718,10 +746,10 @@ pub fn expand_crate_with_expander(expander: &mut MacroExpander,
|
|||
expander.cx.syntax_env.insert(name, extension);
|
||||
}
|
||||
|
||||
let items = SmallVector::many(c.module.items);
|
||||
let items = Expansion::Items(SmallVector::many(c.module.items));
|
||||
let configured = items.fold_with(&mut expander.strip_unconfigured());
|
||||
expander.load_macros(&configured);
|
||||
c.module.items = configured.into();
|
||||
c.module.items = configured.make_items().into();
|
||||
|
||||
let err_count = expander.cx.parse_sess.span_diagnostic.err_count();
|
||||
let mut ret = expander.fold_crate(c);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue