trait_items: BTreeMap<hir::TraitItemId, hir::TraitItem>,
impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>,
bodies: BTreeMap<hir::BodyId, hir::Body>,
+ exported_macros: Vec<hir::MacroDef>,
trait_impls: BTreeMap<DefId, Vec<NodeId>>,
trait_default_impl: BTreeMap<DefId, NodeId>,
bodies: BTreeMap::new(),
trait_impls: BTreeMap::new(),
trait_default_impl: BTreeMap::new(),
+ exported_macros: Vec::new(),
loop_scopes: Vec::new(),
is_in_loop_condition: false,
type_def_lifetime_params: DefIdMap(),
impl<'lcx, 'interner> Visitor<'lcx> for ItemLowerer<'lcx, 'interner> {
fn visit_item(&mut self, item: &'lcx Item) {
- let hir_item = self.lctx.lower_item(item);
- self.lctx.items.insert(item.id, hir_item);
- visit::walk_item(self, item);
+ if let Some(hir_item) = self.lctx.lower_item(item) {
+ self.lctx.items.insert(item.id, hir_item);
+ visit::walk_item(self, item);
+ }
}
fn visit_trait_item(&mut self, item: &'lcx TraitItem) {
let module = self.lower_mod(&c.module);
let attrs = self.lower_attrs(&c.attrs);
- let exported_macros = c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect();
let body_ids = body_ids(&self.bodies);
hir::Crate {
module: module,
attrs: attrs,
span: c.span,
- exported_macros: exported_macros,
+ exported_macros: hir::HirVec::from(self.exported_macros),
items: self.items,
trait_items: self.trait_items,
impl_items: self.impl_items,
bounds,
items)
}
- ItemKind::Mac(_) => panic!("Shouldn't still be around"),
+ ItemKind::MacroDef(..) | ItemKind::Mac(..) => panic!("Shouldn't still be around"),
}
}
}
}
- fn lower_macro_def(&mut self, m: &MacroDef) -> hir::MacroDef {
- hir::MacroDef {
- name: m.ident.name,
- attrs: self.lower_attrs(&m.attrs),
- id: m.id,
- span: m.span,
- body: m.body.clone().into(),
- }
- }
-
fn lower_item_id(&mut self, i: &Item) -> SmallVector<hir::ItemId> {
- if let ItemKind::Use(ref view_path) = i.node {
- if let ViewPathList(_, ref imports) = view_path.node {
- return iter::once(i.id).chain(imports.iter().map(|import| import.node.id))
- .map(|id| hir::ItemId { id: id }).collect();
+ match i.node {
+ ItemKind::Use(ref view_path) => {
+ if let ViewPathList(_, ref imports) = view_path.node {
+ return iter::once(i.id).chain(imports.iter().map(|import| import.node.id))
+ .map(|id| hir::ItemId { id: id }).collect();
+ }
}
+ ItemKind::MacroDef(..) => return SmallVector::new(),
+ _ => {}
}
SmallVector::one(hir::ItemId { id: i.id })
}
- pub fn lower_item(&mut self, i: &Item) -> hir::Item {
+ pub fn lower_item(&mut self, i: &Item) -> Option<hir::Item> {
let mut name = i.ident.name;
let attrs = self.lower_attrs(&i.attrs);
let mut vis = self.lower_visibility(&i.vis);
+ if let ItemKind::MacroDef(ref tts, _) = i.node {
+ if i.attrs.iter().any(|attr| attr.name() == "macro_export") {
+ self.exported_macros.push(hir::MacroDef {
+ name: name, attrs: attrs, id: i.id, span: i.span, body: tts.clone().into(),
+ });
+ }
+ return None;
+ }
+
let node = self.with_parent_def(i.id, |this| {
this.lower_item_kind(i.id, &mut name, &attrs, &mut vis, &i.node)
});
- hir::Item {
+ Some(hir::Item {
id: i.id,
name: name,
attrs: attrs,
node: node,
vis: vis,
span: i.span,
- }
+ })
}
fn lower_foreign_item(&mut self, i: &ForeignItem) -> hir::ForeignItem {
ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_str()),
ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) =>
DefPathData::ValueNs(i.ident.name.as_str()),
- ItemKind::Mac(..) if i.id == DUMMY_NODE_ID => return, // Scope placeholder
+ ItemKind::MacroDef(..) => DefPathData::MacroDef(i.ident.name.as_str()),
ItemKind::Mac(..) => return self.visit_macro_invoc(i.id, false),
ItemKind::Use(ref view_path) => {
match view_path.node {
self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name.as_str()));
}
- fn visit_macro_def(&mut self, macro_def: &'a MacroDef) {
- self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.ident.name.as_str()));
- }
-
fn visit_stmt(&mut self, stmt: &'a Stmt) {
match stmt.node {
StmtKind::Mac(..) => self.visit_macro_invoc(stmt.id, false),
}
pub enum LoadedMacro {
- MacroRules(ast::MacroDef),
+ MacroDef(ast::Item),
ProcMacro(Rc<SyntaxExtension>),
}
use serialize::json;
use std::env;
-use std::mem;
use std::ffi::{OsString, OsStr};
use std::fs;
use std::io::{self, Write};
krate
});
- krate.exported_macros = mem::replace(&mut resolver.exported_macros, Vec::new());
-
krate = time(time_passes, "maybe building test harness", || {
syntax::test::modify_for_testing(&sess.parse_sess,
&mut resolver,
use syntax::ast;
use syntax::attr;
+use syntax::ext::hygiene::Mark;
use syntax::parse::filemap_to_stream;
use syntax::symbol::Symbol;
use syntax_pos::{mk_sp, Span};
sess.imported_macro_spans.borrow_mut()
.insert(local_span, (name.to_string(), data.get_span(id.index, sess)));
- LoadedMacro::MacroRules(ast::MacroDef {
+ LoadedMacro::MacroDef(ast::Item {
ident: ast::Ident::with_empty_ctxt(name),
id: ast::DUMMY_NODE_ID,
span: local_span,
attrs: attrs,
- body: body.into(),
+ node: ast::ItemKind::MacroDef(body.into(), Mark::fresh()),
+ vis: ast::Visibility::Inherited,
})
}
fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
self.record("Attribute", Id::None, attr);
}
-
- fn visit_macro_def(&mut self, macro_def: &'v ast::MacroDef) {
- self.record("MacroDef", Id::None, macro_def);
- ast_visit::walk_macro_def(self, macro_def)
- }
}
use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple};
use syntax::ext::base::SyntaxExtension;
use syntax::ext::base::Determinacy::Undetermined;
-use syntax::ext::expand::mark_tts;
use syntax::ext::hygiene::Mark;
use syntax::ext::tt::macro_rules;
use syntax::parse::token;
self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
self.current_module = module;
}
- ItemKind::Mac(_) => panic!("unexpanded macro in resolve!"),
+ ItemKind::MacroDef(..) | ItemKind::Mac(_) => unreachable!(),
}
}
return ext.clone();
}
- let mut macro_rules = match self.session.cstore.load_macro(def_id, &self.session) {
- LoadedMacro::MacroRules(macro_rules) => macro_rules,
+ let macro_def = match self.session.cstore.load_macro(def_id, &self.session) {
+ LoadedMacro::MacroDef(macro_def) => macro_def,
LoadedMacro::ProcMacro(ext) => return ext,
};
- let mark = Mark::fresh();
let invocation = self.arenas.alloc_invocation_data(InvocationData {
module: Cell::new(self.get_extern_crate_root(def_id.krate)),
- def_index: CRATE_DEF_INDEX,
- const_expr: false,
- legacy_scope: Cell::new(LegacyScope::Empty),
- expansion: Cell::new(LegacyScope::Empty),
+ // FIXME(jseyfried) the following are irrelevant
+ def_index: CRATE_DEF_INDEX, const_expr: false,
+ legacy_scope: Cell::new(LegacyScope::Empty), expansion: Cell::new(LegacyScope::Empty),
});
- self.invocations.insert(mark, invocation);
- macro_rules.body = mark_tts(macro_rules.stream(), mark).into();
- let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, ¯o_rules));
+ if let ast::ItemKind::MacroDef(_, mark) = macro_def.node {
+ self.invocations.insert(mark, invocation);
+ }
+ let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, ¯o_def));
self.macro_map.insert(def_id, ext.clone());
ext
}
fn visit_item(&mut self, item: &'a Item) {
let macro_use = match item.node {
- ItemKind::Mac(ref mac) => {
- if mac.node.path.segments.is_empty() {
- self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(item.id));
- } else {
- self.resolver.define_macro(item, &mut self.legacy_scope);
- }
+ ItemKind::MacroDef(..) => {
+ self.resolver.define_macro(item, &mut self.legacy_scope);
+ return
+ }
+ ItemKind::Mac(..) => {
+ self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(item.id));
return
}
ItemKind::Mod(..) => self.resolver.contains_macro_use(&item.attrs),
pub definitions: Definitions,
- // Maps the node id of a statement to the expansions of the `macro_rules!`s
- // immediately above the statement (if appropriate).
- macros_at_scope: FxHashMap<NodeId, Vec<Mark>>,
-
graph_root: Module<'a>,
prelude: Option<Module<'a>>,
dummy_binding: &'a NameBinding<'a>,
use_extern_macros: bool, // true if `#![feature(use_extern_macros)]`
- pub exported_macros: Vec<ast::MacroDef>,
crate_loader: &'a mut CrateLoader,
macro_names: FxHashSet<Name>,
builtin_macros: FxHashMap<Name, &'a NameBinding<'a>>,
session: session,
definitions: definitions,
- macros_at_scope: FxHashMap(),
// The outermost module has def ID 0; this is not reflected in the
// AST.
// `#![feature(proc_macro)]` implies `#[feature(extern_macros)]`
use_extern_macros: features.use_extern_macros || features.proc_macro,
- exported_macros: Vec::new(),
crate_loader: crate_loader,
macro_names: FxHashSet(),
builtin_macros: FxHashMap(),
}
}
- ItemKind::ExternCrate(_) => {
+ ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) => {
// do nothing, these are just around to be encoded
}
// Descend into the block.
for stmt in &block.stmts {
- if let Some(marks) = self.macros_at_scope.remove(&stmt.id) {
- num_macro_definition_ribs += marks.len() as u32;
- for mark in marks {
+ if let ast::StmtKind::Item(ref item) = stmt.node {
+ if let ast::ItemKind::MacroDef(_, mark) = item.node {
+ num_macro_definition_ribs += 1;
self.ribs[ValueNS].push(Rib::new(MacroDefinition(mark)));
self.label_ribs.push(Rib::new(MacroDefinition(mark)));
}
use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator};
use syntax::ext::base::{Resolver as SyntaxResolver, SyntaxExtension};
use syntax::ext::base::MacroKind;
-use syntax::ext::expand::{Expansion, mark_tts};
+use syntax::ext::expand::Expansion;
use syntax::ext::hygiene::Mark;
use syntax::ext::tt::macro_rules;
use syntax::feature_gate::{self, emit_feature_err, GateIssue};
use syntax::ptr::P;
use syntax::symbol::{Symbol, keywords};
use syntax::util::lev_distance::find_best_match_for_name;
-use syntax::visit::Visitor;
use syntax_pos::{Span, DUMMY_SP};
#[derive(Clone)]
invocation.expansion.set(visitor.legacy_scope);
}
- fn add_ext(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>) {
+ fn add_builtin(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>) {
let def_id = DefId {
krate: BUILTIN_MACROS_CRATE,
index: DefIndex::new(self.macro_map.len()),
self.builtin_macros.insert(ident.name, binding);
}
- fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>) {
- self.macros_at_scope.insert(id, macros);
- }
-
fn resolve_imports(&mut self) {
ImportResolver { resolver: self }.resolve_imports()
}
}
pub fn define_macro(&mut self, item: &ast::Item, legacy_scope: &mut LegacyScope<'a>) {
- let tts = match item.node {
- ast::ItemKind::Mac(ref mac) => mac.node.stream(),
- _ => unreachable!(),
- };
-
if item.ident.name == "macro_rules" {
self.session.span_err(item.span, "user-defined macros may not be named `macro_rules`");
}
- let mark = Mark::from_placeholder_id(item.id);
- let invocation = self.invocations[&mark];
- invocation.module.set(self.current_module);
-
- let mut def = ast::MacroDef {
- ident: item.ident,
- attrs: item.attrs.clone(),
- id: ast::DUMMY_NODE_ID,
- span: item.span,
- body: mark_tts(tts, mark).into(),
- };
+ let invocation = self.arenas.alloc_invocation_data(InvocationData {
+ module: Cell::new(self.current_module),
+ // FIXME(jseyfried) the following are irrelevant
+ def_index: CRATE_DEF_INDEX, const_integer: false,
+ legacy_scope: Cell::new(LegacyScope::Empty), expansion: Cell::new(LegacyScope::Empty),
+ });
+ if let ast::ItemKind::MacroDef(_, mark) = item.node {
+ self.invocations.insert(mark, invocation);
+ }
*legacy_scope = LegacyScope::Binding(self.arenas.alloc_legacy_binding(LegacyBinding {
parent: Cell::new(*legacy_scope),
- name: def.ident.name,
- ext: Rc::new(macro_rules::compile(&self.session.parse_sess, &def)),
- span: def.span,
+ name: item.ident.name,
+ ext: Rc::new(macro_rules::compile(&self.session.parse_sess, item)),
+ span: item.span,
}));
- self.macro_names.insert(def.ident.name);
+ self.macro_names.insert(item.ident.name);
- if attr::contains_name(&def.attrs, "macro_export") {
- def.id = self.next_node_id();
- DefCollector::new(&mut self.definitions).with_parent(CRATE_DEF_INDEX, |collector| {
- collector.visit_macro_def(&def)
- });
+ if attr::contains_name(&item.attrs, "macro_export") {
self.macro_exports.push(Export {
- name: def.ident.name,
- def: Def::Macro(self.definitions.local_def_id(def.id), MacroKind::Bang),
+ name: item.ident.name,
+ def: Def::Macro(self.definitions.local_def_id(item.id), MacroKind::Bang),
});
- self.exported_macros.push(def);
}
}
use syntax::abi;
use syntax::ast;
use syntax::attr;
+use syntax::tokenstream::TokenStream;
use syntax_pos::Span;
use rustc::hir::map as hir_map;
}
let imported_from = self.cx.sess().cstore.original_crate_name(def_id.krate);
let def = match self.cx.sess().cstore.load_macro(def_id, self.cx.sess()) {
- LoadedMacro::MacroRules(macro_rules) => macro_rules,
+ LoadedMacro::MacroDef(macro_def) => macro_def,
// FIXME(jseyfried): document proc macro reexports
LoadedMacro::ProcMacro(..) => continue,
};
- // FIXME(jseyfried) merge with `self.visit_macro()`
- let tts = def.stream().trees().collect::<Vec<_>>();
- let matchers = tts.chunks(4).map(|arm| arm[0].span()).collect();
+ let matchers = if let ast::ItemKind::MacroDef(ref tokens, _) = def.node {
+ let tts: Vec<_> = TokenStream::from(tokens.clone()).into_trees().collect();
+ tts.chunks(4).map(|arm| arm[0].span()).collect()
+ } else {
+ unreachable!()
+ };
om.macros.push(Macro {
def_id: def_id,
attrs: def.attrs.clone().into(),
use syntax_pos::{mk_sp, Span, DUMMY_SP, ExpnId};
use codemap::{respan, Spanned};
use abi::Abi;
-use ext::hygiene::SyntaxContext;
+use ext::hygiene::{Mark, SyntaxContext};
use print::pprust;
use ptr::P;
use symbol::{Symbol, keywords};
pub module: Mod,
pub attrs: Vec<Attribute>,
pub span: Span,
- pub exported_macros: Vec<MacroDef>,
}
/// A spanned compile-time attribute list item.
Option<TraitRef>, // (optional) trait this impl implements
P<Ty>, // self
Vec<ImplItem>),
- /// A macro invocation (which includes macro definition).
+ /// A macro invocation.
///
/// E.g. `macro_rules! foo { .. }` or `foo!(..)`
Mac(Mac),
+
+ /// A macro definition.
+ MacroDef(ThinTokenStream, Mark /* FIXME(jseyfried) remove this */),
}
impl ItemKind {
ItemKind::Union(..) => "union",
ItemKind::Trait(..) => "trait",
ItemKind::Mac(..) |
+ ItemKind::MacroDef(..) |
ItemKind::Impl(..) |
ItemKind::DefaultImpl(..) => "item"
}
}
}
-/// A macro definition, in this crate or imported from another.
-///
-/// Not parsed directly, but created on macro import or `macro_rules!` expansion.
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub struct MacroDef {
- pub ident: Ident,
- pub attrs: Vec<Attribute>,
- pub id: NodeId,
- pub span: Span,
- pub body: ThinTokenStream,
-}
-
-impl MacroDef {
- pub fn stream(&self) -> TokenStream {
- self.body.clone().into()
- }
-}
-
#[cfg(test)]
mod tests {
use serialize;
fn is_whitelisted_legacy_custom_derive(&self, name: Name) -> bool;
fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion, derives: &[Mark]);
- fn add_ext(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>);
- fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>);
+ fn add_builtin(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>);
fn resolve_imports(&mut self);
// Resolves attribute and derive legacy macros from `#![plugin(..)]`.
fn is_whitelisted_legacy_custom_derive(&self, _name: Name) -> bool { false }
fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion, _derives: &[Mark]) {}
- fn add_ext(&mut self, _ident: ast::Ident, _ext: Rc<SyntaxExtension>) {}
- fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec<Mark>) {}
+ fn add_builtin(&mut self, _ident: ast::Ident, _ext: Rc<SyntaxExtension>) {}
fn resolve_imports(&mut self) {}
fn find_legacy_attr_invoc(&mut self, _attrs: &mut Vec<Attribute>) -> Option<Attribute> { None }
match item.node {
ast::ItemKind::Mac(..) => {
self.check_attributes(&item.attrs);
- let is_macro_def = if let ItemKind::Mac(ref mac) = item.node {
- mac.node.path.segments[0].identifier.name == "macro_rules"
- } else {
- unreachable!()
- };
-
- item.and_then(|mut item| match item.node {
- ItemKind::Mac(_) if is_macro_def => {
- item.id = Mark::fresh().as_placeholder_id();
- SmallVector::one(P(item))
- }
+ item.and_then(|item| match item.node {
ItemKind::Mac(mac) => {
self.collect(ExpansionKind::Items, InvocationKind::Bang {
mac: mac,
}
fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind {
- noop_fold_item_kind(self.cfg.configure_item_kind(item), self)
+ match item {
+ ast::ItemKind::MacroDef(..) => item,
+ _ => noop_fold_item_kind(self.cfg.configure_item_kind(item), self),
+ }
}
fn new_id(&mut self, id: ast::NodeId) -> ast::NodeId {
}
/// A mark is a unique id associated with a macro expansion.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default, RustcEncodable, RustcDecodable)]
pub struct Mark(u32);
impl Mark {
use util::small_vector::SmallVector;
use std::collections::HashMap;
-use std::mem;
pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion {
fn mac_placeholder() -> ast::Mac {
fn fold_block(&mut self, block: P<ast::Block>) -> P<ast::Block> {
noop_fold_block(block, self).map(|mut block| {
- let mut macros = Vec::new();
let mut remaining_stmts = block.stmts.len();
block.stmts = block.stmts.move_flat_map(|mut stmt| {
remaining_stmts -= 1;
- // `macro_rules!` macro definition
- if let ast::StmtKind::Item(ref item) = stmt.node {
- if let ast::ItemKind::Mac(_) = item.node {
- macros.push(Mark::from_placeholder_id(item.id));
- return None;
- }
- }
-
match stmt.node {
// Avoid wasting a node id on a trailing expression statement,
// which shares a HIR node with the expression itself.
_ => {}
}
- if self.monotonic && !macros.is_empty() {
- let macros = mem::replace(&mut macros, Vec::new());
- self.cx.resolver.add_expansions_at_stmt(stmt.id, macros);
- }
-
Some(stmt)
});
use syntax_pos::{Span, DUMMY_SP};
use ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension};
use ext::base::{NormalTT, TTMacroExpander};
-use ext::expand::{Expansion, ExpansionKind};
+use ext::expand::{Expansion, ExpansionKind, mark_tts};
use ext::tt::macro_parser::{Success, Error, Failure};
use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
use ext::tt::macro_parser::{parse, parse_failure_msg};
// Holy self-referential!
/// Converts a `macro_rules!` invocation into a syntax extension.
-pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension {
+pub fn compile(sess: &ParseSess, def: &ast::Item) -> SyntaxExtension {
let lhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("lhs"));
let rhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("rhs"));
];
// Parse the macro_rules! invocation
- let argument_map = match parse(sess, def.body.clone().into(), &argument_gram, None) {
+ let body = match def.node {
+ ast::ItemKind::MacroDef(ref body, mark) => mark_tts(body.clone().into(), mark),
+ _ => unreachable!(),
+ };
+ let argument_map = match parse(sess, body, &argument_gram, None) {
Success(m) => m,
Failure(sp, tok) => {
let s = parse_failure_msg(tok);
items.move_flat_map(|item| folder.fold_trait_item(item)),
),
ItemKind::Mac(m) => ItemKind::Mac(folder.fold_mac(m)),
+ ItemKind::MacroDef(tts, mark) => ItemKind::MacroDef(folder.fold_tts(tts.into()).into(),
+ mark),
}
}
}
}
-pub fn noop_fold_crate<T: Folder>(Crate {module, attrs, mut exported_macros, span}: Crate,
+pub fn noop_fold_crate<T: Folder>(Crate {module, attrs, span}: Crate,
folder: &mut T) -> Crate {
let mut items = folder.fold_item(P(ast::Item {
ident: keywords::Invalid.ident(),
}, vec![], span)
};
- for def in &mut exported_macros {
- def.id = folder.new_id(def.id);
- }
-
Crate {
module: module,
attrs: attrs,
- exported_macros: exported_macros,
span: span,
}
}
matches_codepattern,
"matches_codepattern",
pprust::to_string(|s| fake_print_crate(s, &folded_crate)),
- "zz!zz((zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+)));".to_string());
+ "macro_rules! zz((zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+)));".to_string());
}
}
use codemap::{self, CodeMap, Spanned, spanned, respan};
use syntax_pos::{self, Span, Pos, BytePos, mk_sp};
use errors::{self, DiagnosticBuilder};
+use ext::hygiene::Mark;
use parse::{self, classify, token};
use parse::common::SeqSep;
use parse::lexer::TokenAndSpan;
self.expected_tokens.clear();
}
- pub fn look_ahead<R, F>(&mut self, dist: usize, f: F) -> R where
+ pub fn look_ahead<R, F>(&self, dist: usize, f: F) -> R where
F: FnOnce(&token::Token) -> R,
{
if dist == 0 {
})
}
- fn is_union_item(&mut self) -> bool {
+ fn is_union_item(&self) -> bool {
self.token.is_keyword(keywords::Union) &&
self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword())
}
+ fn eat_macro_def(&mut self, attrs: &[Attribute], vis: &Visibility)
+ -> PResult<'a, Option<P<Item>>> {
+ let lo = self.span.lo;
+ match self.token {
+ token::Ident(ident) if ident.name == "macro_rules" => {
+ if self.look_ahead(1, |t| *t == token::Not) {
+ let prev_span = self.prev_span;
+ self.complain_if_pub_macro(vis, prev_span);
+ self.bump();
+ self.bump();
+ }
+ }
+ _ => return Ok(None),
+ };
+
+ let id = self.parse_ident()?;
+ let (delim, tts) = self.expect_delimited_token_tree()?;
+ if delim != token::Brace {
+ if !self.eat(&token::Semi) {
+ let msg = "macros that expand to items must either be surrounded with braces \
+ or followed by a semicolon";
+ self.span_err(self.prev_span, msg);
+ }
+ }
+
+ let hi = self.prev_span.hi;
+ let kind = ItemKind::MacroDef(tts, Mark::fresh());
+ Ok(Some(self.mk_item(lo, hi, id, kind, Visibility::Inherited, attrs.to_owned())))
+ }
+
fn parse_stmt_without_recovery(&mut self,
macro_legacy_warnings: bool)
-> PResult<'a, Option<Stmt>> {
node: StmtKind::Local(self.parse_local(attrs.into())?),
span: mk_sp(lo, self.prev_span.hi),
}
+ } else if let Some(macro_def) = self.eat_macro_def(&attrs, &Visibility::Inherited)? {
+ Stmt {
+ id: ast::DUMMY_NODE_ID,
+ node: StmtKind::Item(macro_def),
+ span: mk_sp(lo, self.prev_span.hi),
+ }
// Starts like a simple path, but not a union item.
} else if self.token.is_path_start() &&
!self.token.is_qpath_start() &&
maybe_append(attrs, extra_attrs));
return Ok(Some(item));
}
+ if let Some(macro_def) = self.eat_macro_def(&attrs, &visibility)? {
+ return Ok(Some(macro_def));
+ }
+
self.parse_macro_use_or_failure(attrs,macros_allowed,attributes_allowed,lo,visibility)
}
attrs: self.parse_inner_attributes()?,
module: self.parse_mod_items(&token::Eof, lo)?,
span: mk_sp(lo, self.span.lo),
- exported_macros: Vec::new(),
})
}
self.bclose(item.span)?;
}
ast::ItemKind::Mac(codemap::Spanned { ref node, .. }) => {
- self.print_visibility(&item.vis)?;
self.print_path(&node.path, false, 0, false)?;
word(&mut self.s, "! ")?;
self.print_ident(item.ident)?;
word(&mut self.s, ";")?;
self.end()?;
}
+ ast::ItemKind::MacroDef(ref tts, _) => {
+ word(&mut self.s, "macro_rules! ")?;
+ self.print_ident(item.ident)?;
+ self.cbox(INDENT_UNIT)?;
+ self.popen()?;
+ self.print_tts(tts.clone().into())?;
+ self.pclose()?;
+ word(&mut self.s, ";")?;
+ self.end()?;
+ }
}
self.ann.post(self, NodeItem(item))
}
fn visit_attribute(&mut self, _attr: &Attribute) {
self.count += 1;
}
- fn visit_macro_def(&mut self, macro_def: &MacroDef) {
- self.count += 1;
- walk_macro_def(self, macro_def)
- }
-
}
walk_assoc_type_binding(self, type_binding)
}
fn visit_attribute(&mut self, _attr: &'ast Attribute) {}
- fn visit_macro_def(&mut self, macro_def: &'ast MacroDef) {
- walk_macro_def(self, macro_def)
- }
fn visit_vis(&mut self, vis: &'ast Visibility) {
walk_vis(self, vis)
}
pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) {
visitor.visit_mod(&krate.module, krate.span, CRATE_NODE_ID);
walk_list!(visitor, visit_attribute, &krate.attrs);
- walk_list!(visitor, visit_macro_def, &krate.exported_macros);
-}
-
-pub fn walk_macro_def<'a, V: Visitor<'a>>(visitor: &mut V, macro_def: &'a MacroDef) {
- visitor.visit_ident(macro_def.span, macro_def.ident);
- walk_list!(visitor, visit_attribute, ¯o_def.attrs);
}
pub fn walk_mod<'a, V: Visitor<'a>>(visitor: &mut V, module: &'a Mod) {
walk_list!(visitor, visit_trait_item, methods);
}
ItemKind::Mac(ref mac) => visitor.visit_mac(mac),
+ ItemKind::MacroDef(..) => {},
}
walk_list!(visitor, visit_attribute, &item.attrs);
}
pub fn register_builtin_derives(resolver: &mut Resolver) {
$(
- resolver.add_ext(
+ resolver.add_builtin(
ast::Ident::with_empty_ctxt(Symbol::intern($name)),
Rc::new(SyntaxExtension::BuiltinDerive($func))
);
deriving::register_builtin_derives(resolver);
let mut register = |name, ext| {
- resolver.add_ext(ast::Ident::with_empty_ctxt(name), Rc::new(ext));
+ resolver.add_builtin(ast::Ident::with_empty_ctxt(name), Rc::new(ext));
};
macro_rules! register {
krate.module.items.push(mk_registrar(&mut cx, &derives, &attr_macros, &bang_macros));
- if krate.exported_macros.len() > 0 {
- handler.err("cannot export macro_rules! macros from a `proc-macro` \
- crate type currently");
- }
-
- return krate
+ krate
}
fn is_proc_macro_attr(attr: &ast::Attribute) -> bool {
impl<'a> Visitor<'a> for CollectProcMacros<'a> {
fn visit_item(&mut self, item: &'a ast::Item) {
+ if let ast::ItemKind::MacroDef(..) = item.node {
+ if self.is_proc_macro_crate &&
+ item.attrs.iter().any(|attr| attr.name() == "macro_export") {
+ let msg =
+ "cannot export macro_rules! macros from a `proc-macro` crate type currently";
+ self.handler.span_err(item.span, msg);
+ }
+ }
+
// First up, make sure we're checking a bare function. If we're not then
// we're just not interested in this item.
//
#![feature(no_core)]
#![no_core]
+macro_rules! foo /* 60#0 */(( $ x : ident ) => { y + $ x });
fn bar /* 62#0 */() { let x /* 59#2 */ = 1; y /* 61#4 */ + x /* 59#5 */ }