Refactor expand_invoc(.., fld)
-> self.expand_invoc(..)
.
This commit is contained in:
parent
79fa9eb643
commit
7a3ae576fa
@ -143,199 +143,6 @@ enum InvocationKind {
|
||||
},
|
||||
}
|
||||
|
||||
fn expand_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
|
||||
match invoc.kind {
|
||||
InvocationKind::Bang { .. } => expand_bang_invoc(invoc, fld),
|
||||
InvocationKind::Attr { .. } => expand_attr_invoc(invoc, fld),
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_attr_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
|
||||
let Invocation { expansion_kind: kind, .. } = invoc;
|
||||
let (attr, item) = match invoc.kind {
|
||||
InvocationKind::Attr { attr, item } => (attr, item),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let extension = match fld.cx.syntax_env.find(intern(&attr.name())) {
|
||||
Some(extension) => extension,
|
||||
None => unreachable!(),
|
||||
};
|
||||
|
||||
attr::mark_used(&attr);
|
||||
fld.cx.bt_push(ExpnInfo {
|
||||
call_site: attr.span,
|
||||
callee: NameAndSpan {
|
||||
format: MacroAttribute(intern(&attr.name())),
|
||||
span: Some(attr.span),
|
||||
allow_internal_unstable: false,
|
||||
}
|
||||
});
|
||||
|
||||
let modified = match *extension {
|
||||
MultiModifier(ref mac) => {
|
||||
kind.expect_from_annotatables(mac.expand(fld.cx, attr.span, &attr.node.value, item))
|
||||
}
|
||||
MultiDecorator(ref mac) => {
|
||||
let mut items = Vec::new();
|
||||
mac.expand(fld.cx, attr.span, &attr.node.value, &item, &mut |item| items.push(item));
|
||||
items.push(item);
|
||||
kind.expect_from_annotatables(items)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
fld.cx.bt_pop();
|
||||
|
||||
let configured = modified.fold_with(&mut fld.strip_unconfigured());
|
||||
configured.fold_with(fld)
|
||||
}
|
||||
|
||||
/// Expand a macro invocation. Returns the result of expansion.
|
||||
fn expand_bang_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
|
||||
let Invocation { mark, expansion_kind: kind, .. } = invoc;
|
||||
let (attrs, mac, ident, span) = match invoc.kind {
|
||||
InvocationKind::Bang { attrs, mac, ident, span } => (attrs, mac, ident, span),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let Mac_ { path, tts, .. } = mac.node;
|
||||
|
||||
// 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 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 = kind.name());
|
||||
fld.cx.span_err(path.span, &msg);
|
||||
return kind.dummy(span);
|
||||
};
|
||||
|
||||
let marked = expanded.fold_with(&mut Marker { mark: mark, expn_id: Some(fld.cx.backtrace()) });
|
||||
let configured = marked.fold_with(&mut fld.strip_unconfigured());
|
||||
fld.load_macros(&configured);
|
||||
|
||||
let fully_expanded = if fld.single_step {
|
||||
configured
|
||||
} else {
|
||||
configured.fold_with(fld)
|
||||
};
|
||||
|
||||
fld.cx.bt_pop();
|
||||
fully_expanded
|
||||
}
|
||||
|
||||
/// A tree-folder that performs macro expansion
|
||||
pub struct MacroExpander<'a, 'b:'a> {
|
||||
pub cx: &'a mut ExtCtxt<'b>,
|
||||
@ -467,6 +274,204 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn expand_invoc(&mut self, invoc: Invocation) -> Expansion {
|
||||
match invoc.kind {
|
||||
InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc),
|
||||
InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc),
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_attr_invoc(&mut self, invoc: Invocation) -> Expansion {
|
||||
let Invocation { expansion_kind: kind, .. } = invoc;
|
||||
let (attr, item) = match invoc.kind {
|
||||
InvocationKind::Attr { attr, item } => (attr, item),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let extension = match self.cx.syntax_env.find(intern(&attr.name())) {
|
||||
Some(extension) => extension,
|
||||
None => unreachable!(),
|
||||
};
|
||||
|
||||
attr::mark_used(&attr);
|
||||
self.cx.bt_push(ExpnInfo {
|
||||
call_site: attr.span,
|
||||
callee: NameAndSpan {
|
||||
format: MacroAttribute(intern(&attr.name())),
|
||||
span: Some(attr.span),
|
||||
allow_internal_unstable: false,
|
||||
}
|
||||
});
|
||||
|
||||
let modified = match *extension {
|
||||
MultiModifier(ref mac) => {
|
||||
let item = mac.expand(self.cx, attr.span, &attr.node.value, item);
|
||||
kind.expect_from_annotatables(item)
|
||||
}
|
||||
MultiDecorator(ref mac) => {
|
||||
let mut items = Vec::new();
|
||||
mac.expand(self.cx, attr.span, &attr.node.value, &item,
|
||||
&mut |item| items.push(item));
|
||||
items.push(item);
|
||||
kind.expect_from_annotatables(items)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
self.cx.bt_pop();
|
||||
|
||||
let configured = modified.fold_with(&mut self.strip_unconfigured());
|
||||
configured.fold_with(self)
|
||||
}
|
||||
|
||||
/// Expand a macro invocation. Returns the result of expansion.
|
||||
fn expand_bang_invoc(&mut self, invoc: Invocation) -> Expansion {
|
||||
let Invocation { mark, expansion_kind: kind, .. } = invoc;
|
||||
let (attrs, mac, ident, span) = match invoc.kind {
|
||||
InvocationKind::Bang { attrs, mac, ident, span } => (attrs, mac, ident, span),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let Mac_ { path, tts, .. } = mac.node;
|
||||
|
||||
// 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, &self.cx.parse_sess.span_diagnostic,
|
||||
&self.cx.parse_sess.codemap(),
|
||||
&self.cx.ecfg.features.unwrap());
|
||||
}
|
||||
|
||||
if path.segments.len() > 1 || path.global || !path.segments[0].parameters.is_empty() {
|
||||
self.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) = self.cx.syntax_env.find(extname) {
|
||||
extension
|
||||
} else {
|
||||
let mut err =
|
||||
self.cx.struct_span_err(path.span, &format!("macro undefined: '{}!'", &extname));
|
||||
self.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);
|
||||
self.cx.span_err(path.span, &msg);
|
||||
return kind.dummy(span);
|
||||
}
|
||||
|
||||
self.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(self.cx, span, &marked_tts))
|
||||
}
|
||||
|
||||
IdentTT(ref expander, tt_span, allow_internal_unstable) => {
|
||||
if ident.name == keywords::Invalid.name() {
|
||||
self.cx.span_err(path.span,
|
||||
&format!("macro {}! expects an ident argument", extname));
|
||||
return kind.dummy(span);
|
||||
};
|
||||
|
||||
self.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(self.cx, span, ident, marked_tts))
|
||||
}
|
||||
|
||||
MacroRulesTT => {
|
||||
if ident.name == keywords::Invalid.name() {
|
||||
self.cx.span_err(path.span,
|
||||
&format!("macro {}! expects an ident argument", extname));
|
||||
return kind.dummy(span);
|
||||
};
|
||||
|
||||
self.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,
|
||||
};
|
||||
|
||||
self.cx.insert_macro(def.clone());
|
||||
|
||||
// If keep_macs is true, expands to a MacEager::items instead.
|
||||
if self.keep_macs {
|
||||
Some(reconstruct_macro_rules(&def, &path))
|
||||
} else {
|
||||
Some(macro_scope_placeholder())
|
||||
}
|
||||
}
|
||||
|
||||
MultiDecorator(..) | MultiModifier(..) => {
|
||||
self.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 = kind.name());
|
||||
self.cx.span_err(path.span, &msg);
|
||||
return kind.dummy(span);
|
||||
};
|
||||
|
||||
let marked = expanded.fold_with(&mut Marker {
|
||||
mark: mark,
|
||||
expn_id: Some(self.cx.backtrace())
|
||||
});
|
||||
let configured = marked.fold_with(&mut self.strip_unconfigured());
|
||||
self.load_macros(&configured);
|
||||
|
||||
let fully_expanded = if self.single_step {
|
||||
configured
|
||||
} else {
|
||||
configured.fold_with(self)
|
||||
};
|
||||
|
||||
self.cx.bt_pop();
|
||||
fully_expanded
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
||||
@ -474,7 +479,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
||||
let expr = expr.unwrap();
|
||||
if let ast::ExprKind::Mac(mac) = expr.node {
|
||||
let invoc = self.new_bang_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::Expr);
|
||||
expand_invoc(invoc, self).make_expr()
|
||||
self.expand_invoc(invoc).make_expr()
|
||||
} else {
|
||||
P(noop_fold_expr(expr, self))
|
||||
}
|
||||
@ -485,7 +490,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
||||
if let ast::ExprKind::Mac(mac) = expr.node {
|
||||
let invoc =
|
||||
self.new_bang_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::OptExpr);
|
||||
expand_invoc(invoc, self).make_opt_expr()
|
||||
self.expand_invoc(invoc).make_opt_expr()
|
||||
} else {
|
||||
Some(P(noop_fold_expr(expr, self)))
|
||||
}
|
||||
@ -494,13 +499,13 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
||||
fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> {
|
||||
match pat.node {
|
||||
PatKind::Mac(_) => {}
|
||||
_ => return noop_fold_pat(pat, self)
|
||||
_ => return noop_fold_pat(pat, self),
|
||||
}
|
||||
|
||||
pat.and_then(|pat| match pat.node {
|
||||
PatKind::Mac(mac) => {
|
||||
let invoc = self.new_bang_invoc(mac, Vec::new(), pat.span, ExpansionKind::Pat);
|
||||
expand_invoc(invoc, self).make_pat()
|
||||
self.expand_invoc(invoc).make_pat()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
})
|
||||
@ -509,11 +514,11 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
||||
fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector<ast::Stmt> {
|
||||
let (mac, style, attrs) = match stmt.node {
|
||||
StmtKind::Mac(mac) => mac.unwrap(),
|
||||
_ => return noop_fold_stmt(stmt, self)
|
||||
_ => return noop_fold_stmt(stmt, self),
|
||||
};
|
||||
|
||||
let invoc = self.new_bang_invoc(mac, attrs.into(), stmt.span, ExpansionKind::Stmts);
|
||||
let mut fully_expanded = expand_invoc(invoc, self).make_stmts();
|
||||
let mut fully_expanded = self.expand_invoc(invoc).make_stmts();
|
||||
|
||||
// If this is a macro invocation with a semicolon, then apply that
|
||||
// semicolon to the final statement produced by expansion.
|
||||
@ -540,7 +545,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
||||
let (item, attr) = self.classify_item(item);
|
||||
if let Some(attr) = attr {
|
||||
let invoc = self.new_attr_invoc(attr, Annotatable::Item(item), ExpansionKind::Items);
|
||||
return expand_invoc(invoc, self).make_items();
|
||||
return self.expand_invoc(invoc).make_items();
|
||||
}
|
||||
|
||||
match item.node {
|
||||
@ -560,7 +565,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
||||
ident: Some(item.ident),
|
||||
span: item.span,
|
||||
});
|
||||
expand_invoc(invoc, self).make_items()
|
||||
self.expand_invoc(invoc).make_items()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
})
|
||||
@ -598,14 +603,14 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
||||
if let Some(attr) = attr {
|
||||
let item = Annotatable::TraitItem(P(item));
|
||||
let invoc = self.new_attr_invoc(attr, item, ExpansionKind::TraitItems);
|
||||
return expand_invoc(invoc, self).make_trait_items();
|
||||
return self.expand_invoc(invoc).make_trait_items();
|
||||
}
|
||||
|
||||
match item.node {
|
||||
ast::TraitItemKind::Macro(mac) => {
|
||||
let ast::TraitItem { attrs, span, .. } = item;
|
||||
let invoc = self.new_bang_invoc(mac, attrs, span, ExpansionKind::TraitItems);
|
||||
expand_invoc(invoc, self).make_trait_items()
|
||||
self.expand_invoc(invoc).make_trait_items()
|
||||
}
|
||||
_ => fold::noop_fold_trait_item(item, self),
|
||||
}
|
||||
@ -616,16 +621,16 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
||||
if let Some(attr) = attr {
|
||||
let item = Annotatable::ImplItem(P(item));
|
||||
let invoc = self.new_attr_invoc(attr, item, ExpansionKind::ImplItems);
|
||||
return expand_invoc(invoc, self).make_impl_items();
|
||||
return self.expand_invoc(invoc).make_impl_items();
|
||||
}
|
||||
|
||||
match item.node {
|
||||
ast::ImplItemKind::Macro(mac) => {
|
||||
let ast::ImplItem { attrs, span, .. } = item;
|
||||
let invoc = self.new_bang_invoc(mac, attrs, span, ExpansionKind::ImplItems);
|
||||
expand_invoc(invoc, self).make_impl_items()
|
||||
self.expand_invoc(invoc).make_impl_items()
|
||||
}
|
||||
_ => fold::noop_fold_impl_item(item, self)
|
||||
_ => fold::noop_fold_impl_item(item, self),
|
||||
}
|
||||
}
|
||||
|
||||
@ -638,7 +643,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
||||
match ty.node {
|
||||
ast::TyKind::Mac(mac) => {
|
||||
let invoc = self.new_bang_invoc(mac, Vec::new(), ty.span, ExpansionKind::Ty);
|
||||
expand_invoc(invoc, self).make_ty()
|
||||
self.expand_invoc(invoc).make_ty()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user