rust/src/libsyntax/ast_map.rs

740 lines
24 KiB
Rust
Raw Normal View History

// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use abi;
2012-09-04 13:37:29 -05:00
use ast::*;
use ast_util;
use codemap::Span;
use fold::Folder;
2014-01-06 06:00:46 -06:00
use fold;
use parse::token;
use print::pprust;
2014-01-06 06:00:46 -06:00
use util::small_vector::SmallVector;
2013-12-27 18:09:29 -06:00
use std::cell::RefCell;
use std::fmt;
use std::iter;
use std::slice;
use std::strbuf::StrBuf;
2013-07-02 14:47:32 -05:00
#[deriving(Clone, Eq)]
pub enum PathElem {
PathMod(Name),
PathName(Name)
2012-08-27 18:26:35 -05:00
}
impl PathElem {
pub fn name(&self) -> Name {
match *self {
PathMod(name) | PathName(name) => name
}
}
}
impl fmt::Show for PathElem {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let slot = token::get_name(self.name());
write!(f, "{}", slot)
}
}
#[deriving(Clone)]
struct LinkedPathNode<'a> {
node: PathElem,
next: LinkedPath<'a>,
}
type LinkedPath<'a> = Option<&'a LinkedPathNode<'a>>;
impl<'a> Iterator<PathElem> for LinkedPath<'a> {
fn next(&mut self) -> Option<PathElem> {
match *self {
Some(node) => {
*self = node.next;
Some(node.node)
}
None => None
}
}
}
// HACK(eddyb) move this into libstd (value wrapper for slice::Items).
#[deriving(Clone)]
pub struct Values<'a, T>(pub slice::Items<'a, T>);
impl<'a, T: Copy> Iterator<T> for Values<'a, T> {
fn next(&mut self) -> Option<T> {
let &Values(ref mut items) = self;
items.next().map(|&x| x)
}
}
/// The type of the iterator used by with_path.
pub type PathElems<'a, 'b> = iter::Chain<Values<'a, PathElem>, LinkedPath<'b>>;
pub fn path_to_str<PI: Iterator<PathElem>>(mut path: PI) -> StrBuf {
let itr = token::get_ident_interner();
path.fold(StrBuf::new(), |mut s, e| {
let e = itr.get(e.name());
if !s.is_empty() {
s.push_str("::");
}
s.push_str(e.as_slice());
s
}).to_strbuf()
}
2013-07-02 14:47:32 -05:00
#[deriving(Clone)]
pub enum Node {
NodeItem(@Item),
NodeForeignItem(@ForeignItem),
NodeTraitMethod(@TraitMethod),
NodeMethod(@Method),
NodeVariant(P<Variant>),
NodeExpr(@Expr),
NodeStmt(@Stmt),
NodeArg(@Pat),
NodeLocal(@Pat),
NodePat(@Pat),
NodeBlock(P<Block>),
/// NodeStructCtor represents a tuple struct.
NodeStructCtor(@StructDef),
NodeLifetime(@Lifetime),
}
// The odd layout is to bring down the total size.
#[deriving(Clone)]
enum MapEntry {
// Placeholder for holes in the map.
NotPresent,
// All the node types, with a parent ID.
EntryItem(NodeId, @Item),
EntryForeignItem(NodeId, @ForeignItem),
EntryTraitMethod(NodeId, @TraitMethod),
EntryMethod(NodeId, @Method),
EntryVariant(NodeId, P<Variant>),
EntryExpr(NodeId, @Expr),
EntryStmt(NodeId, @Stmt),
EntryArg(NodeId, @Pat),
EntryLocal(NodeId, @Pat),
EntryPat(NodeId, @Pat),
EntryBlock(NodeId, P<Block>),
EntryStructCtor(NodeId, @StructDef),
EntryLifetime(NodeId, @Lifetime),
// Roots for node trees.
RootCrate,
RootInlinedParent(P<InlinedParent>)
}
struct InlinedParent {
path: Vec<PathElem> ,
// Required by NodeTraitMethod and NodeMethod.
def_id: DefId
}
impl MapEntry {
fn parent(&self) -> Option<NodeId> {
Some(match *self {
EntryItem(id, _) => id,
EntryForeignItem(id, _) => id,
EntryTraitMethod(id, _) => id,
EntryMethod(id, _) => id,
EntryVariant(id, _) => id,
EntryExpr(id, _) => id,
EntryStmt(id, _) => id,
EntryArg(id, _) => id,
EntryLocal(id, _) => id,
EntryPat(id, _) => id,
EntryBlock(id, _) => id,
EntryStructCtor(id, _) => id,
EntryLifetime(id, _) => id,
_ => return None
})
}
fn to_node(&self) -> Option<Node> {
Some(match *self {
EntryItem(_, p) => NodeItem(p),
EntryForeignItem(_, p) => NodeForeignItem(p),
EntryTraitMethod(_, p) => NodeTraitMethod(p),
EntryMethod(_, p) => NodeMethod(p),
EntryVariant(_, p) => NodeVariant(p),
EntryExpr(_, p) => NodeExpr(p),
EntryStmt(_, p) => NodeStmt(p),
EntryArg(_, p) => NodeArg(p),
EntryLocal(_, p) => NodeLocal(p),
EntryPat(_, p) => NodePat(p),
EntryBlock(_, p) => NodeBlock(p),
EntryStructCtor(_, p) => NodeStructCtor(p),
EntryLifetime(_, p) => NodeLifetime(p),
_ => return None
})
}
}
pub struct Map {
/// NodeIds are sequential integers from 0, so we can be
/// super-compact by storing them in a vector. Not everything with
/// a NodeId is in the map, but empirically the occupancy is about
/// 75-80%, so there's not too much overhead (certainly less than
/// a hashmap, since they (at the time of writing) have a maximum
/// of 75% occupancy).
///
/// Also, indexing is pretty quick when you've got a vector and
/// plain old integers.
map: RefCell<Vec<MapEntry> >
}
impl Map {
fn find_entry(&self, id: NodeId) -> Option<MapEntry> {
let map = self.map.borrow();
2014-03-20 17:05:37 -05:00
if map.len() > id as uint {
Some(*map.get(id as uint))
} else {
None
}
}
/// Retrieve the Node corresponding to `id`, failing if it cannot
/// be found.
pub fn get(&self, id: NodeId) -> Node {
match self.find(id) {
Some(node) => node,
None => fail!("couldn't find node id {} in the AST map", id)
}
}
/// Retrieve the Node corresponding to `id`, returning None if
/// cannot be found.
pub fn find(&self, id: NodeId) -> Option<Node> {
self.find_entry(id).and_then(|x| x.to_node())
}
/// Retrieve the parent NodeId for `id`, or `id` itself if no
/// parent is registered in this map.
pub fn get_parent(&self, id: NodeId) -> NodeId {
self.find_entry(id).and_then(|x| x.parent()).unwrap_or(id)
}
pub fn get_parent_did(&self, id: NodeId) -> DefId {
let parent = self.get_parent(id);
match self.find_entry(parent) {
Some(RootInlinedParent(data)) => data.def_id,
_ => ast_util::local_def(parent)
}
}
pub fn get_foreign_abi(&self, id: NodeId) -> abi::Abi {
let parent = self.get_parent(id);
let abi = match self.find_entry(parent) {
Some(EntryItem(_, i)) => match i.node {
ItemForeignMod(ref nm) => Some(nm.abi),
_ => None
},
// Wrong but OK, because the only inlined foreign items are intrinsics.
Some(RootInlinedParent(_)) => Some(abi::RustIntrinsic),
_ => None
};
match abi {
Some(abi) => abi,
None => fail!("expected foreign mod or inlined parent, found {}",
self.node_to_str(parent))
}
}
pub fn get_foreign_vis(&self, id: NodeId) -> Visibility {
let vis = self.expect_foreign_item(id).vis;
match self.find(self.get_parent(id)) {
Some(NodeItem(i)) => vis.inherit_from(i.vis),
_ => vis
}
}
pub fn expect_item(&self, id: NodeId) -> @Item {
match self.find(id) {
Some(NodeItem(item)) => item,
_ => fail!("expected item, found {}", self.node_to_str(id))
}
}
pub fn expect_struct(&self, id: NodeId) -> @StructDef {
match self.find(id) {
Some(NodeItem(i)) => {
match i.node {
ItemStruct(struct_def, _) => struct_def,
_ => fail!("struct ID bound to non-struct")
}
}
Some(NodeVariant(ref variant)) => {
match (*variant).node.kind {
StructVariantKind(struct_def) => struct_def,
_ => fail!("struct ID bound to enum variant that isn't struct-like"),
}
}
_ => fail!(format!("expected struct, found {}", self.node_to_str(id))),
}
}
pub fn expect_variant(&self, id: NodeId) -> P<Variant> {
match self.find(id) {
Some(NodeVariant(variant)) => variant,
_ => fail!(format!("expected variant, found {}", self.node_to_str(id))),
}
}
pub fn expect_foreign_item(&self, id: NodeId) -> @ForeignItem {
match self.find(id) {
Some(NodeForeignItem(item)) => item,
_ => fail!("expected foreign item, found {}", self.node_to_str(id))
}
}
pub fn get_path_elem(&self, id: NodeId) -> PathElem {
match self.get(id) {
NodeItem(item) => {
match item.node {
ItemMod(_) | ItemForeignMod(_) => {
PathMod(item.ident.name)
}
_ => PathName(item.ident.name)
}
}
NodeForeignItem(i) => PathName(i.ident.name),
NodeMethod(m) => PathName(m.ident.name),
NodeTraitMethod(tm) => match *tm {
Required(ref m) => PathName(m.ident.name),
Provided(ref m) => PathName(m.ident.name)
},
NodeVariant(v) => PathName(v.node.name.name),
node => fail!("no path elem for {:?}", node)
}
}
pub fn with_path<T>(&self, id: NodeId, f: |PathElems| -> T) -> T {
self.with_path_next(id, None, f)
}
pub fn path_to_str(&self, id: NodeId) -> StrBuf {
self.with_path(id, |path| path_to_str(path))
}
fn path_to_str_with_ident(&self, id: NodeId, i: Ident) -> StrBuf {
self.with_path(id, |path| {
path_to_str(path.chain(Some(PathName(i.name)).move_iter()))
})
}
fn with_path_next<T>(&self, id: NodeId, next: LinkedPath, f: |PathElems| -> T) -> T {
let parent = self.get_parent(id);
let parent = match self.find_entry(id) {
Some(EntryForeignItem(..)) | Some(EntryVariant(..)) => {
// Anonymous extern items, enum variants and struct ctors
// go in the parent scope.
self.get_parent(parent)
}
// But tuple struct ctors don't have names, so use the path of its
// parent, the struct item. Similarly with closure expressions.
Some(EntryStructCtor(..)) | Some(EntryExpr(..)) => {
return self.with_path_next(parent, next, f);
}
_ => parent
};
if parent == id {
match self.find_entry(id) {
Some(RootInlinedParent(data)) => {
f(Values(data.path.iter()).chain(next))
}
_ => f(Values([].iter()).chain(next))
}
} else {
self.with_path_next(parent, Some(&LinkedPathNode {
node: self.get_path_elem(id),
next: next
}), f)
}
}
pub fn with_attrs<T>(&self, id: NodeId, f: |Option<&[Attribute]>| -> T) -> T {
2014-04-23 11:16:06 -05:00
let node = self.get(id);
let attrs = match node {
NodeItem(ref i) => Some(i.attrs.as_slice()),
NodeForeignItem(ref fi) => Some(fi.attrs.as_slice()),
NodeTraitMethod(ref tm) => match **tm {
Required(ref type_m) => Some(type_m.attrs.as_slice()),
2014-04-23 11:16:06 -05:00
Provided(ref m) => Some(m.attrs.as_slice())
},
2014-04-23 11:16:06 -05:00
NodeMethod(ref m) => Some(m.attrs.as_slice()),
NodeVariant(ref v) => Some(v.node.attrs.as_slice()),
// unit/tuple structs take the attributes straight from
// the struct definition.
// FIXME(eddyb) make this work again (requires access to the map).
NodeStructCtor(_) => {
return self.with_attrs(self.get_parent(id), f);
}
_ => None
};
f(attrs)
}
pub fn opt_span(&self, id: NodeId) -> Option<Span> {
let sp = match self.find(id) {
Some(NodeItem(item)) => item.span,
Some(NodeForeignItem(foreign_item)) => foreign_item.span,
Some(NodeTraitMethod(trait_method)) => {
match *trait_method {
Required(ref type_method) => type_method.span,
Provided(ref method) => method.span,
}
}
Some(NodeMethod(method)) => method.span,
Some(NodeVariant(variant)) => variant.span,
Some(NodeExpr(expr)) => expr.span,
Some(NodeStmt(stmt)) => stmt.span,
Some(NodeArg(pat)) | Some(NodeLocal(pat)) => pat.span,
Some(NodePat(pat)) => pat.span,
Some(NodeBlock(block)) => block.span,
Some(NodeStructCtor(_)) => self.expect_item(self.get_parent(id)).span,
_ => return None,
};
Some(sp)
}
pub fn span(&self, id: NodeId) -> Span {
self.opt_span(id)
.unwrap_or_else(|| fail!("AstMap.span: could not find span for id {}", id))
}
pub fn node_to_str(&self, id: NodeId) -> StrBuf {
node_id_to_str(self, id)
}
}
2014-01-06 06:00:46 -06:00
pub trait FoldOps {
fn new_id(&self, id: NodeId) -> NodeId {
2014-01-06 06:00:46 -06:00
id
}
fn new_span(&self, span: Span) -> Span {
span
}
}
pub struct Ctx<'a, F> {
map: &'a Map,
// The node in which we are currently mapping (an item or a method).
// When equal to DUMMY_NODE_ID, the next mapped node becomes the parent.
parent: NodeId,
2014-01-06 06:00:46 -06:00
fold_ops: F
}
impl<'a, F> Ctx<'a, F> {
fn insert(&self, id: NodeId, entry: MapEntry) {
2014-03-20 17:05:37 -05:00
(*self.map.map.borrow_mut()).grow_set(id as uint, &NotPresent, entry);
}
2014-01-06 06:00:46 -06:00
}
impl<'a, F: FoldOps> Folder for Ctx<'a, F> {
fn new_id(&mut self, id: NodeId) -> NodeId {
let id = self.fold_ops.new_id(id);
if self.parent == DUMMY_NODE_ID {
self.parent = id;
}
id
}
2014-01-06 06:00:46 -06:00
fn new_span(&mut self, span: Span) -> Span {
self.fold_ops.new_span(span)
}
fn fold_item(&mut self, i: @Item) -> SmallVector<@Item> {
let parent = self.parent;
self.parent = DUMMY_NODE_ID;
2014-01-06 06:00:46 -06:00
let i = fold::noop_fold_item(i, self).expect_one("expected one item");
assert_eq!(self.parent, i.id);
2014-01-06 06:00:46 -06:00
match i.node {
ItemImpl(_, _, _, ref ms) => {
2014-01-06 06:00:46 -06:00
for &m in ms.iter() {
self.insert(m.id, EntryMethod(self.parent, m));
}
}
ItemEnum(ref enum_definition, _) => {
for &v in enum_definition.variants.iter() {
self.insert(v.node.id, EntryVariant(self.parent, v));
}
}
ItemForeignMod(ref nm) => {
for &nitem in nm.items.iter() {
self.insert(nitem.id, EntryForeignItem(self.parent, nitem));
}
}
ItemStruct(struct_def, _) => {
2014-01-06 06:00:46 -06:00
// If this is a tuple-like struct, register the constructor.
match struct_def.ctor_id {
Some(ctor_id) => {
self.insert(ctor_id, EntryStructCtor(self.parent,
struct_def));
2014-01-06 06:00:46 -06:00
}
None => {}
2014-01-06 06:00:46 -06:00
}
}
ItemTrait(_, _, ref traits, ref methods) => {
2014-01-06 06:00:46 -06:00
for t in traits.iter() {
self.insert(t.ref_id, EntryItem(self.parent, i));
}
2014-01-06 06:00:46 -06:00
for tm in methods.iter() {
match *tm {
Required(ref m) => {
self.insert(m.id, EntryTraitMethod(self.parent,
@(*tm).clone()));
}
Provided(m) => {
self.insert(m.id, EntryTraitMethod(self.parent,
@Provided(m)));
}
}
}
}
_ => {}
}
self.parent = parent;
self.insert(i.id, EntryItem(self.parent, i));
2014-01-06 06:00:46 -06:00
SmallVector::one(i)
}
fn fold_pat(&mut self, pat: @Pat) -> @Pat {
let pat = fold::noop_fold_pat(pat, self);
match pat.node {
PatIdent(..) => {
2014-01-06 06:00:46 -06:00
// Note: this is at least *potentially* a pattern...
self.insert(pat.id, EntryLocal(self.parent, pat));
}
_ => {
self.insert(pat.id, EntryPat(self.parent, pat));
}
}
2014-01-06 06:00:46 -06:00
pat
}
2014-01-06 06:00:46 -06:00
fn fold_expr(&mut self, expr: @Expr) -> @Expr {
let expr = fold::noop_fold_expr(expr, self);
self.insert(expr.id, EntryExpr(self.parent, expr));
2014-01-06 06:00:46 -06:00
expr
}
2014-01-06 06:00:46 -06:00
fn fold_stmt(&mut self, stmt: &Stmt) -> SmallVector<@Stmt> {
let stmt = fold::noop_fold_stmt(stmt, self).expect_one("expected one statement");
self.insert(ast_util::stmt_id(stmt), EntryStmt(self.parent, stmt));
2014-01-06 06:00:46 -06:00
SmallVector::one(stmt)
}
fn fold_type_method(&mut self, m: &TypeMethod) -> TypeMethod {
let parent = self.parent;
self.parent = DUMMY_NODE_ID;
let m = fold::noop_fold_type_method(m, self);
assert_eq!(self.parent, m.id);
self.parent = parent;
m
}
fn fold_method(&mut self, m: @Method) -> @Method {
let parent = self.parent;
self.parent = DUMMY_NODE_ID;
2014-01-06 06:00:46 -06:00
let m = fold::noop_fold_method(m, self);
assert_eq!(self.parent, m.id);
self.parent = parent;
2014-01-06 06:00:46 -06:00
m
}
fn fold_fn_decl(&mut self, decl: &FnDecl) -> P<FnDecl> {
2014-01-06 06:00:46 -06:00
let decl = fold::noop_fold_fn_decl(decl, self);
for a in decl.inputs.iter() {
self.insert(a.id, EntryArg(self.parent, a.pat));
2014-01-06 06:00:46 -06:00
}
decl
}
2014-01-06 06:00:46 -06:00
fn fold_block(&mut self, block: P<Block>) -> P<Block> {
let block = fold::noop_fold_block(block, self);
self.insert(block.id, EntryBlock(self.parent, block));
2014-01-06 06:00:46 -06:00
block
}
fn fold_lifetime(&mut self, lifetime: &Lifetime) -> Lifetime {
let lifetime = fold::noop_fold_lifetime(lifetime, self);
self.insert(lifetime.id, EntryLifetime(self.parent, @lifetime));
lifetime
}
}
pub fn map_crate<F: FoldOps>(krate: Crate, fold_ops: F) -> (Crate, Map) {
let map = Map { map: RefCell::new(Vec::new()) };
let krate = {
let mut cx = Ctx {
map: &map,
parent: CRATE_NODE_ID,
fold_ops: fold_ops
};
cx.insert(CRATE_NODE_ID, RootCrate);
cx.fold_crate(krate)
};
log: Introduce liblog, the old std::logging This commit moves all logging out of the standard library into an external crate. This crate is the new crate which is responsible for all logging macros and logging implementation. A few reasons for this change are: * The crate map has always been a bit of a code smell among rust programs. It has difficulty being loaded on almost all platforms, and it's used almost exclusively for logging and only logging. Removing the crate map is one of the end goals of this movement. * The compiler has a fair bit of special support for logging. It has the __log_level() expression as well as generating a global word per module specifying the log level. This is unfairly favoring the built-in logging system, and is much better done purely in libraries instead of the compiler itself. * Initialization of logging is much easier to do if there is no reliance on a magical crate map being available to set module log levels. * If the logging library can be written outside of the standard library, there's no reason that it shouldn't be. It's likely that we're not going to build the highest quality logging library of all time, so third-party libraries should be able to provide just as high-quality logging systems as the default one provided in the rust distribution. With a migration such as this, the change does not come for free. There are some subtle changes in the behavior of liblog vs the previous logging macros: * The core change of this migration is that there is no longer a physical log-level per module. This concept is still emulated (it is quite useful), but there is now only a global log level, not a local one. This global log level is a reflection of the maximum of all log levels specified. The previously generated logging code looked like: if specified_level <= __module_log_level() { println!(...) } The newly generated code looks like: if specified_level <= ::log::LOG_LEVEL { if ::log::module_enabled(module_path!()) { println!(...) } } Notably, the first layer of checking is still intended to be "super fast" in that it's just a load of a global word and a compare. The second layer of checking is executed to determine if the current module does indeed have logging turned on. This means that if any module has a debug log level turned on, all modules with debug log levels get a little bit slower (they all do more expensive dynamic checks to determine if they're turned on or not). Semantically, this migration brings no change in this respect, but runtime-wise, this will have a perf impact on some code. * A `RUST_LOG=::help` directive will no longer print out a list of all modules that can be logged. This is because the crate map will no longer specify the log levels of all modules, so the list of modules is not known. Additionally, warnings can no longer be provided if a malformed logging directive was supplied. The new "hello world" for logging looks like: #[phase(syntax, link)] extern crate log; fn main() { debug!("Hello, world!"); }
2014-03-09 00:11:44 -06:00
if log_enabled!(::log::DEBUG) {
let map = map.map.borrow();
// This only makes sense for ordered stores; note the
// enumerate to count the number of entries.
2014-03-20 17:05:37 -05:00
let (entries_less_1, _) = (*map).iter().filter(|&x| {
match *x {
NotPresent => false,
_ => true
}
}).enumerate().last().expect("AST map was empty after folding?");
let entries = entries_less_1 + 1;
2014-03-20 17:05:37 -05:00
let vector_length = (*map).len();
debug!("The AST map has {} entries with a maximum of {}: occupancy {:.1}%",
entries, vector_length, (entries as f64 / vector_length as f64) * 100.);
}
(krate, map)
}
// Used for items loaded from external crate that are being inlined into this
// crate. The `path` should be the path to the item but should not include
// the item itself.
pub fn map_decoded_item<F: FoldOps>(map: &Map,
path: Vec<PathElem> ,
fold_ops: F,
fold: |&mut Ctx<F>| -> InlinedItem)
-> InlinedItem {
let mut cx = Ctx {
2013-03-23 20:45:27 -05:00
map: map,
parent: DUMMY_NODE_ID,
2014-01-06 06:00:46 -06:00
fold_ops: fold_ops
};
// Generate a NodeId for the RootInlinedParent inserted below.
cx.new_id(DUMMY_NODE_ID);
2014-01-06 06:00:46 -06:00
// Methods get added to the AST map when their impl is visited. Since we
// don't decode and instantiate the impl, but just the method, we have to
// add it to the table now. Likewise with foreign items.
let mut def_id = DefId { krate: LOCAL_CRATE, node: DUMMY_NODE_ID };
let ii = fold(&mut cx);
2014-01-06 06:00:46 -06:00
match ii {
IIItem(_) => {}
IIMethod(impl_did, is_provided, m) => {
2014-01-06 06:00:46 -06:00
let entry = if is_provided {
EntryTraitMethod(cx.parent, @Provided(m))
2014-01-06 06:00:46 -06:00
} else {
EntryMethod(cx.parent, m)
2014-01-06 06:00:46 -06:00
};
cx.insert(m.id, entry);
def_id = impl_did;
}
IIForeign(i) => {
cx.insert(i.id, EntryForeignItem(cx.parent, i));
}
}
2013-03-15 14:24:24 -05:00
cx.insert(cx.parent, RootInlinedParent(P(InlinedParent {
path: path,
def_id: def_id
})));
2014-01-06 06:00:46 -06:00
ii
}
fn node_id_to_str(map: &Map, id: NodeId) -> StrBuf {
match map.find(id) {
Some(NodeItem(item)) => {
let path_str = map.path_to_str_with_ident(id, item.ident);
let item_str = match item.node {
ItemStatic(..) => "static",
ItemFn(..) => "fn",
ItemMod(..) => "mod",
ItemForeignMod(..) => "foreign mod",
ItemTy(..) => "ty",
ItemEnum(..) => "enum",
ItemStruct(..) => "struct",
ItemTrait(..) => "trait",
ItemImpl(..) => "impl",
ItemMac(..) => "macro"
};
(format!("{} {} (id={})", item_str, path_str, id)).to_strbuf()
}
Some(NodeForeignItem(item)) => {
let path_str = map.path_to_str_with_ident(id, item.ident);
(format!("foreign item {} (id={})", path_str, id)).to_strbuf()
}
Some(NodeMethod(m)) => {
(format!("method {} in {} (id={})",
token::get_ident(m.ident),
map.path_to_str(id), id)).to_strbuf()
}
Some(NodeTraitMethod(ref tm)) => {
let m = ast_util::trait_method_to_ty_method(&**tm);
(format!("method {} in {} (id={})",
token::get_ident(m.ident),
map.path_to_str(id), id)).to_strbuf()
}
Some(NodeVariant(ref variant)) => {
(format!("variant {} in {} (id={})",
token::get_ident(variant.node.name),
map.path_to_str(id), id)).to_strbuf()
}
Some(NodeExpr(expr)) => {
(format!("expr {} (id={})",
pprust::expr_to_str(expr), id)).to_strbuf()
}
Some(NodeStmt(stmt)) => {
(format!("stmt {} (id={})",
pprust::stmt_to_str(stmt), id)).to_strbuf()
}
Some(NodeArg(pat)) => {
(format!("arg {} (id={})",
pprust::pat_to_str(pat), id)).to_strbuf()
}
Some(NodeLocal(pat)) => {
(format!("local {} (id={})",
pprust::pat_to_str(pat), id)).to_strbuf()
}
Some(NodePat(pat)) => {
(format!("pat {} (id={})", pprust::pat_to_str(pat), id)).to_strbuf()
}
Some(NodeBlock(block)) => {
(format!("block {} (id={})",
pprust::block_to_str(block), id)).to_strbuf()
}
Some(NodeStructCtor(_)) => {
(format!("struct_ctor {} (id={})",
map.path_to_str(id), id)).to_strbuf()
}
Some(NodeLifetime(ref l)) => {
(format!("lifetime {} (id={})",
pprust::lifetime_to_str(*l), id)).to_strbuf()
}
None => {
(format!("unknown node (id={})", id)).to_strbuf()
}
}
}