]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ast_map/mod.rs
Add a doctest for the std::string::as_string method.
[rust.git] / src / libsyntax / ast_map / mod.rs
1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 pub use self::Node::*;
12 pub use self::PathElem::*;
13 use self::MapEntry::*;
14
15 use abi;
16 use ast::*;
17 use ast_util;
18 use codemap::{DUMMY_SP, Span, Spanned};
19 use fold::Folder;
20 use parse::token;
21 use print::pprust;
22 use ptr::P;
23 use visit::{mod, Visitor};
24
25 use arena::TypedArena;
26 use std::cell::RefCell;
27 use std::fmt;
28 use std::io::IoResult;
29 use std::iter;
30 use std::mem;
31 use std::slice;
32
33 pub mod blocks;
34
35 #[deriving(Clone, PartialEq)]
36 pub enum PathElem {
37     PathMod(Name),
38     PathName(Name)
39 }
40
41 impl PathElem {
42     pub fn name(&self) -> Name {
43         match *self {
44             PathMod(name) | PathName(name) => name
45         }
46     }
47 }
48
49 impl fmt::Show for PathElem {
50     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
51         let slot = token::get_name(self.name());
52         write!(f, "{}", slot)
53     }
54 }
55
56 #[deriving(Clone)]
57 struct LinkedPathNode<'a> {
58     node: PathElem,
59     next: LinkedPath<'a>,
60 }
61
62 type LinkedPath<'a> = Option<&'a LinkedPathNode<'a>>;
63
64 impl<'a> Iterator<PathElem> for LinkedPath<'a> {
65     fn next(&mut self) -> Option<PathElem> {
66         match *self {
67             Some(node) => {
68                 *self = node.next;
69                 Some(node.node)
70             }
71             None => None
72         }
73     }
74 }
75
76 // HACK(eddyb) move this into libstd (value wrapper for slice::Items).
77 #[deriving(Clone)]
78 pub struct Values<'a, T:'a>(pub slice::Items<'a, T>);
79
80 impl<'a, T: Copy> Iterator<T> for Values<'a, T> {
81     fn next(&mut self) -> Option<T> {
82         let &Values(ref mut items) = self;
83         items.next().map(|&x| x)
84     }
85 }
86
87 /// The type of the iterator used by with_path.
88 pub type PathElems<'a, 'b> = iter::Chain<Values<'a, PathElem>, LinkedPath<'b>>;
89
90 pub fn path_to_string<PI: Iterator<PathElem>>(path: PI) -> String {
91     let itr = token::get_ident_interner();
92
93     path.fold(String::new(), |mut s, e| {
94         let e = itr.get(e.name());
95         if !s.is_empty() {
96             s.push_str("::");
97         }
98         s.push_str(e.as_slice());
99         s
100     }).to_string()
101 }
102
103 #[deriving(Show)]
104 pub enum Node<'ast> {
105     NodeItem(&'ast Item),
106     NodeForeignItem(&'ast ForeignItem),
107     NodeTraitItem(&'ast TraitItem),
108     NodeImplItem(&'ast ImplItem),
109     NodeVariant(&'ast Variant),
110     NodeExpr(&'ast Expr),
111     NodeStmt(&'ast Stmt),
112     NodeArg(&'ast Pat),
113     NodeLocal(&'ast Pat),
114     NodePat(&'ast Pat),
115     NodeBlock(&'ast Block),
116
117     /// NodeStructCtor represents a tuple struct.
118     NodeStructCtor(&'ast StructDef),
119
120     NodeLifetime(&'ast Lifetime),
121 }
122
123 /// Represents an entry and its parent Node ID
124 /// The odd layout is to bring down the total size.
125 #[deriving(Show)]
126 enum MapEntry<'ast> {
127     /// Placeholder for holes in the map.
128     NotPresent,
129
130     /// All the node types, with a parent ID.
131     EntryItem(NodeId, &'ast Item),
132     EntryForeignItem(NodeId, &'ast ForeignItem),
133     EntryTraitItem(NodeId, &'ast TraitItem),
134     EntryImplItem(NodeId, &'ast ImplItem),
135     EntryVariant(NodeId, &'ast Variant),
136     EntryExpr(NodeId, &'ast Expr),
137     EntryStmt(NodeId, &'ast Stmt),
138     EntryArg(NodeId, &'ast Pat),
139     EntryLocal(NodeId, &'ast Pat),
140     EntryPat(NodeId, &'ast Pat),
141     EntryBlock(NodeId, &'ast Block),
142     EntryStructCtor(NodeId, &'ast StructDef),
143     EntryLifetime(NodeId, &'ast Lifetime),
144
145     /// Roots for node trees.
146     RootCrate,
147     RootInlinedParent(&'ast InlinedParent)
148 }
149
150 impl<'ast> Clone for MapEntry<'ast> {
151     fn clone(&self) -> MapEntry<'ast> {
152         *self
153     }
154 }
155
156 #[deriving(Show)]
157 struct InlinedParent {
158     path: Vec<PathElem>,
159     ii: InlinedItem
160 }
161
162 impl<'ast> MapEntry<'ast> {
163     fn from_node(p: NodeId, node: Node<'ast>) -> MapEntry<'ast> {
164         match node {
165             NodeItem(n) => EntryItem(p, n),
166             NodeForeignItem(n) => EntryForeignItem(p, n),
167             NodeTraitItem(n) => EntryTraitItem(p, n),
168             NodeImplItem(n) => EntryImplItem(p, n),
169             NodeVariant(n) => EntryVariant(p, n),
170             NodeExpr(n) => EntryExpr(p, n),
171             NodeStmt(n) => EntryStmt(p, n),
172             NodeArg(n) => EntryArg(p, n),
173             NodeLocal(n) => EntryLocal(p, n),
174             NodePat(n) => EntryPat(p, n),
175             NodeBlock(n) => EntryBlock(p, n),
176             NodeStructCtor(n) => EntryStructCtor(p, n),
177             NodeLifetime(n) => EntryLifetime(p, n)
178         }
179     }
180
181     fn parent(self) -> Option<NodeId> {
182         Some(match self {
183             EntryItem(id, _) => id,
184             EntryForeignItem(id, _) => id,
185             EntryTraitItem(id, _) => id,
186             EntryImplItem(id, _) => id,
187             EntryVariant(id, _) => id,
188             EntryExpr(id, _) => id,
189             EntryStmt(id, _) => id,
190             EntryArg(id, _) => id,
191             EntryLocal(id, _) => id,
192             EntryPat(id, _) => id,
193             EntryBlock(id, _) => id,
194             EntryStructCtor(id, _) => id,
195             EntryLifetime(id, _) => id,
196             _ => return None
197         })
198     }
199
200     fn to_node(self) -> Option<Node<'ast>> {
201         Some(match self {
202             EntryItem(_, n) => NodeItem(n),
203             EntryForeignItem(_, n) => NodeForeignItem(n),
204             EntryTraitItem(_, n) => NodeTraitItem(n),
205             EntryImplItem(_, n) => NodeImplItem(n),
206             EntryVariant(_, n) => NodeVariant(n),
207             EntryExpr(_, n) => NodeExpr(n),
208             EntryStmt(_, n) => NodeStmt(n),
209             EntryArg(_, n) => NodeArg(n),
210             EntryLocal(_, n) => NodeLocal(n),
211             EntryPat(_, n) => NodePat(n),
212             EntryBlock(_, n) => NodeBlock(n),
213             EntryStructCtor(_, n) => NodeStructCtor(n),
214             EntryLifetime(_, n) => NodeLifetime(n),
215             _ => return None
216         })
217     }
218 }
219
220 /// Stores a crate and any number of inlined items from other crates.
221 pub struct Forest {
222     krate: Crate,
223     inlined_items: TypedArena<InlinedParent>
224 }
225
226 impl Forest {
227     pub fn new(krate: Crate) -> Forest {
228         Forest {
229             krate: krate,
230             inlined_items: TypedArena::new()
231         }
232     }
233
234     pub fn krate<'ast>(&'ast self) -> &'ast Crate {
235         &self.krate
236     }
237 }
238
239 /// Represents a mapping from Node IDs to AST elements and their parent
240 /// Node IDs
241 pub struct Map<'ast> {
242     /// The backing storage for all the AST nodes.
243     forest: &'ast Forest,
244
245     /// NodeIds are sequential integers from 0, so we can be
246     /// super-compact by storing them in a vector. Not everything with
247     /// a NodeId is in the map, but empirically the occupancy is about
248     /// 75-80%, so there's not too much overhead (certainly less than
249     /// a hashmap, since they (at the time of writing) have a maximum
250     /// of 75% occupancy).
251     ///
252     /// Also, indexing is pretty quick when you've got a vector and
253     /// plain old integers.
254     map: RefCell<Vec<MapEntry<'ast>>>
255 }
256
257 impl<'ast> Map<'ast> {
258     fn entry_count(&self) -> uint {
259         self.map.borrow().len()
260     }
261
262     fn find_entry(&self, id: NodeId) -> Option<MapEntry<'ast>> {
263         self.map.borrow().as_slice().get(id as uint).map(|e| *e)
264     }
265
266     pub fn krate(&self) -> &'ast Crate {
267         &self.forest.krate
268     }
269
270     /// Retrieve the Node corresponding to `id`, panicking if it cannot
271     /// be found.
272     pub fn get(&self, id: NodeId) -> Node<'ast> {
273         match self.find(id) {
274             Some(node) => node,
275             None => panic!("couldn't find node id {} in the AST map", id)
276         }
277     }
278
279     /// Retrieve the Node corresponding to `id`, returning None if
280     /// cannot be found.
281     pub fn find(&self, id: NodeId) -> Option<Node<'ast>> {
282         self.find_entry(id).and_then(|x| x.to_node())
283     }
284
285     /// Retrieve the parent NodeId for `id`, or `id` itself if no
286     /// parent is registered in this map.
287     pub fn get_parent(&self, id: NodeId) -> NodeId {
288         self.find_entry(id).and_then(|x| x.parent()).unwrap_or(id)
289     }
290
291     pub fn get_parent_did(&self, id: NodeId) -> DefId {
292         let parent = self.get_parent(id);
293         match self.find_entry(parent) {
294             Some(RootInlinedParent(&InlinedParent {ii: IITraitItem(did, _), ..})) => did,
295             Some(RootInlinedParent(&InlinedParent {ii: IIImplItem(did, _), ..})) => did,
296             _ => ast_util::local_def(parent)
297         }
298     }
299
300     pub fn get_foreign_abi(&self, id: NodeId) -> abi::Abi {
301         let parent = self.get_parent(id);
302         let abi = match self.find_entry(parent) {
303             Some(EntryItem(_, i)) => {
304                 match i.node {
305                     ItemForeignMod(ref nm) => Some(nm.abi),
306                     _ => None
307                 }
308             }
309             /// Wrong but OK, because the only inlined foreign items are intrinsics.
310             Some(RootInlinedParent(_)) => Some(abi::RustIntrinsic),
311             _ => None
312         };
313         match abi {
314             Some(abi) => abi,
315             None => panic!("expected foreign mod or inlined parent, found {}",
316                           self.node_to_string(parent))
317         }
318     }
319
320     pub fn get_foreign_vis(&self, id: NodeId) -> Visibility {
321         let vis = self.expect_foreign_item(id).vis;
322         match self.find(self.get_parent(id)) {
323             Some(NodeItem(i)) => vis.inherit_from(i.vis),
324             _ => vis
325         }
326     }
327
328     pub fn expect_item(&self, id: NodeId) -> &'ast Item {
329         match self.find(id) {
330             Some(NodeItem(item)) => item,
331             _ => panic!("expected item, found {}", self.node_to_string(id))
332         }
333     }
334
335     pub fn expect_struct(&self, id: NodeId) -> &'ast StructDef {
336         match self.find(id) {
337             Some(NodeItem(i)) => {
338                 match i.node {
339                     ItemStruct(ref struct_def, _) => &**struct_def,
340                     _ => panic!("struct ID bound to non-struct")
341                 }
342             }
343             Some(NodeVariant(variant)) => {
344                 match variant.node.kind {
345                     StructVariantKind(ref struct_def) => &**struct_def,
346                     _ => panic!("struct ID bound to enum variant that isn't struct-like"),
347                 }
348             }
349             _ => panic!(format!("expected struct, found {}", self.node_to_string(id))),
350         }
351     }
352
353     pub fn expect_variant(&self, id: NodeId) -> &'ast Variant {
354         match self.find(id) {
355             Some(NodeVariant(variant)) => variant,
356             _ => panic!(format!("expected variant, found {}", self.node_to_string(id))),
357         }
358     }
359
360     pub fn expect_foreign_item(&self, id: NodeId) -> &'ast ForeignItem {
361         match self.find(id) {
362             Some(NodeForeignItem(item)) => item,
363             _ => panic!("expected foreign item, found {}", self.node_to_string(id))
364         }
365     }
366
367     pub fn expect_expr(&self, id: NodeId) -> &'ast Expr {
368         match self.find(id) {
369             Some(NodeExpr(expr)) => expr,
370             _ => panic!("expected expr, found {}", self.node_to_string(id))
371         }
372     }
373
374     /// returns the name associated with the given NodeId's AST
375     pub fn get_path_elem(&self, id: NodeId) -> PathElem {
376         let node = self.get(id);
377         match node {
378             NodeItem(item) => {
379                 match item.node {
380                     ItemMod(_) | ItemForeignMod(_) => {
381                         PathMod(item.ident.name)
382                     }
383                     _ => PathName(item.ident.name)
384                 }
385             }
386             NodeForeignItem(i) => PathName(i.ident.name),
387             NodeImplItem(ii) => {
388                 match *ii {
389                     MethodImplItem(ref m) => {
390                         match m.node {
391                             MethDecl(ident, _, _, _, _, _, _, _) => {
392                                 PathName(ident.name)
393                             }
394                             MethMac(_) => {
395                                 panic!("no path elem for {}", node)
396                             }
397                         }
398                     }
399                     TypeImplItem(ref t) => PathName(t.ident.name),
400                 }
401             },
402             NodeTraitItem(tm) => match *tm {
403                 RequiredMethod(ref m) => PathName(m.ident.name),
404                 ProvidedMethod(ref m) => {
405                     match m.node {
406                         MethDecl(ident, _, _, _, _, _, _, _) => {
407                             PathName(ident.name)
408                         }
409                         MethMac(_) => panic!("no path elem for {}", node),
410                     }
411                 }
412                 TypeTraitItem(ref m) => {
413                     PathName(m.ty_param.ident.name)
414                 }
415             },
416             NodeVariant(v) => PathName(v.node.name.name),
417             _ => panic!("no path elem for {}", node)
418         }
419     }
420
421     pub fn with_path<T>(&self, id: NodeId, f: |PathElems| -> T) -> T {
422         self.with_path_next(id, None, f)
423     }
424
425     pub fn path_to_string(&self, id: NodeId) -> String {
426         self.with_path(id, |path| path_to_string(path))
427     }
428
429     fn path_to_str_with_ident(&self, id: NodeId, i: Ident) -> String {
430         self.with_path(id, |path| {
431             path_to_string(path.chain(Some(PathName(i.name)).into_iter()))
432         })
433     }
434
435     fn with_path_next<T>(&self, id: NodeId, next: LinkedPath, f: |PathElems| -> T) -> T {
436         let parent = self.get_parent(id);
437         let parent = match self.find_entry(id) {
438             Some(EntryForeignItem(..)) | Some(EntryVariant(..)) => {
439                 // Anonymous extern items, enum variants and struct ctors
440                 // go in the parent scope.
441                 self.get_parent(parent)
442             }
443             // But tuple struct ctors don't have names, so use the path of its
444             // parent, the struct item. Similarly with closure expressions.
445             Some(EntryStructCtor(..)) | Some(EntryExpr(..)) => {
446                 return self.with_path_next(parent, next, f);
447             }
448             _ => parent
449         };
450         if parent == id {
451             match self.find_entry(id) {
452                 Some(RootInlinedParent(data)) => {
453                     f(Values(data.path.iter()).chain(next))
454                 }
455                 _ => f(Values([].iter()).chain(next))
456             }
457         } else {
458             self.with_path_next(parent, Some(&LinkedPathNode {
459                 node: self.get_path_elem(id),
460                 next: next
461             }), f)
462         }
463     }
464
465     /// Given a node ID and a closure, apply the closure to the array
466     /// of attributes associated with the AST corresponding to the Node ID
467     pub fn with_attrs<T>(&self, id: NodeId, f: |Option<&[Attribute]>| -> T) -> T {
468         let attrs = match self.get(id) {
469             NodeItem(i) => Some(i.attrs.as_slice()),
470             NodeForeignItem(fi) => Some(fi.attrs.as_slice()),
471             NodeTraitItem(ref tm) => match **tm {
472                 RequiredMethod(ref type_m) => Some(type_m.attrs.as_slice()),
473                 ProvidedMethod(ref m) => Some(m.attrs.as_slice()),
474                 TypeTraitItem(ref typ) => Some(typ.attrs.as_slice()),
475             },
476             NodeImplItem(ref ii) => {
477                 match **ii {
478                     MethodImplItem(ref m) => Some(m.attrs.as_slice()),
479                     TypeImplItem(ref t) => Some(t.attrs.as_slice()),
480                 }
481             }
482             NodeVariant(ref v) => Some(v.node.attrs.as_slice()),
483             // unit/tuple structs take the attributes straight from
484             // the struct definition.
485             // FIXME(eddyb) make this work again (requires access to the map).
486             NodeStructCtor(_) => {
487                 return self.with_attrs(self.get_parent(id), f);
488             }
489             _ => None
490         };
491         f(attrs)
492     }
493
494     /// Returns an iterator that yields the node id's with paths that
495     /// match `parts`.  (Requires `parts` is non-empty.)
496     ///
497     /// For example, if given `parts` equal to `["bar", "quux"]`, then
498     /// the iterator will produce node id's for items with paths
499     /// such as `foo::bar::quux`, `bar::quux`, `other::bar::quux`, and
500     /// any other such items it can find in the map.
501     pub fn nodes_matching_suffix<'a, S:Str>(&'a self, parts: &'a [S])
502                                  -> NodesMatchingSuffix<'a, 'ast, S> {
503         NodesMatchingSuffix {
504             map: self,
505             item_name: parts.last().unwrap(),
506             in_which: parts[..parts.len() - 1],
507             idx: 0,
508         }
509     }
510
511     pub fn opt_span(&self, id: NodeId) -> Option<Span> {
512         let sp = match self.find(id) {
513             Some(NodeItem(item)) => item.span,
514             Some(NodeForeignItem(foreign_item)) => foreign_item.span,
515             Some(NodeTraitItem(trait_method)) => {
516                 match *trait_method {
517                     RequiredMethod(ref type_method) => type_method.span,
518                     ProvidedMethod(ref method) => method.span,
519                     TypeTraitItem(ref typedef) => typedef.ty_param.span,
520                 }
521             }
522             Some(NodeImplItem(ref impl_item)) => {
523                 match **impl_item {
524                     MethodImplItem(ref method) => method.span,
525                     TypeImplItem(ref typedef) => typedef.span,
526                 }
527             }
528             Some(NodeVariant(variant)) => variant.span,
529             Some(NodeExpr(expr)) => expr.span,
530             Some(NodeStmt(stmt)) => stmt.span,
531             Some(NodeArg(pat)) | Some(NodeLocal(pat)) => pat.span,
532             Some(NodePat(pat)) => pat.span,
533             Some(NodeBlock(block)) => block.span,
534             Some(NodeStructCtor(_)) => self.expect_item(self.get_parent(id)).span,
535             _ => return None,
536         };
537         Some(sp)
538     }
539
540     pub fn span(&self, id: NodeId) -> Span {
541         self.opt_span(id)
542             .unwrap_or_else(|| panic!("AstMap.span: could not find span for id {}", id))
543     }
544
545     pub fn def_id_span(&self, def_id: DefId, fallback: Span) -> Span {
546         if def_id.krate == LOCAL_CRATE {
547             self.opt_span(def_id.node).unwrap_or(fallback)
548         } else {
549             fallback
550         }
551     }
552
553     pub fn node_to_string(&self, id: NodeId) -> String {
554         node_id_to_string(self, id, true)
555     }
556
557     pub fn node_to_user_string(&self, id: NodeId) -> String {
558         node_id_to_string(self, id, false)
559     }
560 }
561
562 pub struct NodesMatchingSuffix<'a, 'ast:'a, S:'a> {
563     map: &'a Map<'ast>,
564     item_name: &'a S,
565     in_which: &'a [S],
566     idx: NodeId,
567 }
568
569 impl<'a, 'ast, S:Str> NodesMatchingSuffix<'a, 'ast, S> {
570     /// Returns true only if some suffix of the module path for parent
571     /// matches `self.in_which`.
572     ///
573     /// In other words: let `[x_0,x_1,...,x_k]` be `self.in_which`;
574     /// returns true if parent's path ends with the suffix
575     /// `x_0::x_1::...::x_k`.
576     fn suffix_matches(&self, parent: NodeId) -> bool {
577         let mut cursor = parent;
578         for part in self.in_which.iter().rev() {
579             let (mod_id, mod_name) = match find_first_mod_parent(self.map, cursor) {
580                 None => return false,
581                 Some((node_id, name)) => (node_id, name),
582             };
583             if part.as_slice() != mod_name.as_str() {
584                 return false;
585             }
586             cursor = self.map.get_parent(mod_id);
587         }
588         return true;
589
590         // Finds the first mod in parent chain for `id`, along with
591         // that mod's name.
592         //
593         // If `id` itself is a mod named `m` with parent `p`, then
594         // returns `Some(id, m, p)`.  If `id` has no mod in its parent
595         // chain, then returns `None`.
596         fn find_first_mod_parent<'a>(map: &'a Map, mut id: NodeId) -> Option<(NodeId, Name)> {
597             loop {
598                 match map.find(id) {
599                     None => return None,
600                     Some(NodeItem(item)) if item_is_mod(&*item) =>
601                         return Some((id, item.ident.name)),
602                     _ => {}
603                 }
604                 let parent = map.get_parent(id);
605                 if parent == id { return None }
606                 id = parent;
607             }
608
609             fn item_is_mod(item: &Item) -> bool {
610                 match item.node {
611                     ItemMod(_) => true,
612                     _ => false,
613                 }
614             }
615         }
616     }
617
618     // We are looking at some node `n` with a given name and parent
619     // id; do their names match what I am seeking?
620     fn matches_names(&self, parent_of_n: NodeId, name: Name) -> bool {
621         name.as_str() == self.item_name.as_slice() &&
622             self.suffix_matches(parent_of_n)
623     }
624 }
625
626 impl<'a, 'ast, S:Str> Iterator<NodeId> for NodesMatchingSuffix<'a, 'ast, S> {
627     fn next(&mut self) -> Option<NodeId> {
628         loop {
629             let idx = self.idx;
630             if idx as uint >= self.map.entry_count() {
631                 return None;
632             }
633             self.idx += 1;
634             let (p, name) = match self.map.find_entry(idx) {
635                 Some(EntryItem(p, n))       => (p, n.name()),
636                 Some(EntryForeignItem(p, n))=> (p, n.name()),
637                 Some(EntryTraitItem(p, n))  => (p, n.name()),
638                 Some(EntryImplItem(p, n))   => (p, n.name()),
639                 Some(EntryVariant(p, n))    => (p, n.name()),
640                 _ => continue,
641             };
642             if self.matches_names(p, name) {
643                 return Some(idx)
644             }
645         }
646     }
647 }
648
649 trait Named {
650     fn name(&self) -> Name;
651 }
652
653 impl<T:Named> Named for Spanned<T> { fn name(&self) -> Name { self.node.name() } }
654
655 impl Named for Item { fn name(&self) -> Name { self.ident.name } }
656 impl Named for ForeignItem { fn name(&self) -> Name { self.ident.name } }
657 impl Named for Variant_ { fn name(&self) -> Name { self.name.name } }
658 impl Named for TraitItem {
659     fn name(&self) -> Name {
660         match *self {
661             RequiredMethod(ref tm) => tm.ident.name,
662             ProvidedMethod(ref m) => m.name(),
663             TypeTraitItem(ref at) => at.ty_param.ident.name,
664         }
665     }
666 }
667 impl Named for ImplItem {
668     fn name(&self) -> Name {
669         match *self {
670             MethodImplItem(ref m) => m.name(),
671             TypeImplItem(ref td) => td.ident.name,
672         }
673     }
674 }
675 impl Named for Method {
676     fn name(&self) -> Name {
677         match self.node {
678             MethDecl(i, _, _, _, _, _, _, _) => i.name,
679             MethMac(_) => panic!("encountered unexpanded method macro."),
680         }
681     }
682 }
683
684 pub trait FoldOps {
685     fn new_id(&self, id: NodeId) -> NodeId {
686         id
687     }
688     fn new_def_id(&self, def_id: DefId) -> DefId {
689         def_id
690     }
691     fn new_span(&self, span: Span) -> Span {
692         span
693     }
694 }
695
696 /// A Folder that updates IDs and Span's according to fold_ops.
697 struct IdAndSpanUpdater<F> {
698     fold_ops: F
699 }
700
701 impl<F: FoldOps> Folder for IdAndSpanUpdater<F> {
702     fn new_id(&mut self, id: NodeId) -> NodeId {
703         self.fold_ops.new_id(id)
704     }
705
706     fn new_span(&mut self, span: Span) -> Span {
707         self.fold_ops.new_span(span)
708     }
709 }
710
711 /// A Visitor that walks over an AST and collects Node's into an AST Map.
712 struct NodeCollector<'ast> {
713     map: Vec<MapEntry<'ast>>,
714     /// The node in which we are currently mapping (an item or a method).
715     parent: NodeId
716 }
717
718 impl<'ast> NodeCollector<'ast> {
719     fn insert_entry(&mut self, id: NodeId, entry: MapEntry<'ast>) {
720         debug!("ast_map: {} => {}", id, entry);
721         let len = self.map.len();
722         if id as uint >= len {
723             self.map.grow(id as uint - len + 1, NotPresent);
724         }
725         self.map[id as uint] = entry;
726     }
727
728     fn insert(&mut self, id: NodeId, node: Node<'ast>) {
729         let entry = MapEntry::from_node(self.parent, node);
730         self.insert_entry(id, entry);
731     }
732
733     fn visit_fn_decl(&mut self, decl: &'ast FnDecl) {
734         for a in decl.inputs.iter() {
735             self.insert(a.id, NodeArg(&*a.pat));
736         }
737     }
738 }
739
740 impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
741     fn visit_item(&mut self, i: &'ast Item) {
742         self.insert(i.id, NodeItem(i));
743         let parent = self.parent;
744         self.parent = i.id;
745         match i.node {
746             ItemImpl(_, _, _, ref impl_items) => {
747                 for impl_item in impl_items.iter() {
748                     match *impl_item {
749                         MethodImplItem(ref m) => {
750                             self.insert(m.id, NodeImplItem(impl_item));
751                         }
752                         TypeImplItem(ref t) => {
753                             self.insert(t.id, NodeImplItem(impl_item));
754                         }
755                     }
756                 }
757             }
758             ItemEnum(ref enum_definition, _) => {
759                 for v in enum_definition.variants.iter() {
760                     self.insert(v.node.id, NodeVariant(&**v));
761                 }
762             }
763             ItemForeignMod(ref nm) => {
764                 for nitem in nm.items.iter() {
765                     self.insert(nitem.id, NodeForeignItem(&**nitem));
766                 }
767             }
768             ItemStruct(ref struct_def, _) => {
769                 // If this is a tuple-like struct, register the constructor.
770                 match struct_def.ctor_id {
771                     Some(ctor_id) => {
772                         self.insert(ctor_id, NodeStructCtor(&**struct_def));
773                     }
774                     None => {}
775                 }
776             }
777             ItemTrait(_, _, ref bounds, ref trait_items) => {
778                 for b in bounds.iter() {
779                     if let TraitTyParamBound(ref t) = *b {
780                         self.insert(t.trait_ref.ref_id, NodeItem(i));
781                     }
782                 }
783
784                 for tm in trait_items.iter() {
785                     match *tm {
786                         RequiredMethod(ref m) => {
787                             self.insert(m.id, NodeTraitItem(tm));
788                         }
789                         ProvidedMethod(ref m) => {
790                             self.insert(m.id, NodeTraitItem(tm));
791                         }
792                         TypeTraitItem(ref typ) => {
793                             self.insert(typ.ty_param.id, NodeTraitItem(tm));
794                         }
795                     }
796                 }
797             }
798             _ => {}
799         }
800         visit::walk_item(self, i);
801         self.parent = parent;
802     }
803
804     fn visit_pat(&mut self, pat: &'ast Pat) {
805         self.insert(pat.id, match pat.node {
806             // Note: this is at least *potentially* a pattern...
807             PatIdent(..) => NodeLocal(pat),
808             _ => NodePat(pat)
809         });
810         visit::walk_pat(self, pat);
811     }
812
813     fn visit_expr(&mut self, expr: &'ast Expr) {
814         self.insert(expr.id, NodeExpr(expr));
815         visit::walk_expr(self, expr);
816     }
817
818     fn visit_stmt(&mut self, stmt: &'ast Stmt) {
819         self.insert(ast_util::stmt_id(stmt), NodeStmt(stmt));
820         visit::walk_stmt(self, stmt);
821     }
822
823     fn visit_ty_method(&mut self, m: &'ast TypeMethod) {
824         let parent = self.parent;
825         self.parent = m.id;
826         self.visit_fn_decl(&*m.decl);
827         visit::walk_ty_method(self, m);
828         self.parent = parent;
829     }
830
831     fn visit_fn(&mut self, fk: visit::FnKind<'ast>, fd: &'ast FnDecl,
832                 b: &'ast Block, s: Span, id: NodeId) {
833         match fk {
834             visit::FkMethod(..) => {
835                 let parent = self.parent;
836                 self.parent = id;
837                 self.visit_fn_decl(fd);
838                 visit::walk_fn(self, fk, fd, b, s);
839                 self.parent = parent;
840             }
841             _ => {
842                 self.visit_fn_decl(fd);
843                 visit::walk_fn(self, fk, fd, b, s);
844             }
845         }
846     }
847
848     fn visit_ty(&mut self, ty: &'ast Ty) {
849         match ty.node {
850             TyClosure(ref fd) | TyProc(ref fd) => {
851                 self.visit_fn_decl(&*fd.decl);
852             }
853             TyBareFn(ref fd) => {
854                 self.visit_fn_decl(&*fd.decl);
855             }
856             _ => {}
857         }
858         visit::walk_ty(self, ty);
859     }
860
861     fn visit_block(&mut self, block: &'ast Block) {
862         self.insert(block.id, NodeBlock(block));
863         visit::walk_block(self, block);
864     }
865
866     fn visit_lifetime_ref(&mut self, lifetime: &'ast Lifetime) {
867         self.insert(lifetime.id, NodeLifetime(lifetime));
868     }
869
870     fn visit_lifetime_def(&mut self, def: &'ast LifetimeDef) {
871         self.visit_lifetime_ref(&def.lifetime);
872     }
873 }
874
875 pub fn map_crate<'ast, F: FoldOps>(forest: &'ast mut Forest, fold_ops: F) -> Map<'ast> {
876     // Replace the crate with an empty one to take it out.
877     let krate = mem::replace(&mut forest.krate, Crate {
878         module: Mod {
879             inner: DUMMY_SP,
880             view_items: vec![],
881             items: vec![],
882         },
883         attrs: vec![],
884         config: vec![],
885         exported_macros: vec![],
886         span: DUMMY_SP
887     });
888     forest.krate = IdAndSpanUpdater { fold_ops: fold_ops }.fold_crate(krate);
889
890     let mut collector = NodeCollector {
891         map: vec![],
892         parent: CRATE_NODE_ID
893     };
894     collector.insert_entry(CRATE_NODE_ID, RootCrate);
895     visit::walk_crate(&mut collector, &forest.krate);
896     let map = collector.map;
897
898     if log_enabled!(::log::DEBUG) {
899         // This only makes sense for ordered stores; note the
900         // enumerate to count the number of entries.
901         let (entries_less_1, _) = map.iter().filter(|&x| {
902             match *x {
903                 NotPresent => false,
904                 _ => true
905             }
906         }).enumerate().last().expect("AST map was empty after folding?");
907
908         let entries = entries_less_1 + 1;
909         let vector_length = map.len();
910         debug!("The AST map has {} entries with a maximum of {}: occupancy {:.1}%",
911               entries, vector_length, (entries as f64 / vector_length as f64) * 100.);
912     }
913
914     Map {
915         forest: forest,
916         map: RefCell::new(map)
917     }
918 }
919
920 /// Used for items loaded from external crate that are being inlined into this
921 /// crate.  The `path` should be the path to the item but should not include
922 /// the item itself.
923 pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
924                                           path: Vec<PathElem>,
925                                           ii: InlinedItem,
926                                           fold_ops: F)
927                                           -> &'ast InlinedItem {
928     let mut fld = IdAndSpanUpdater { fold_ops: fold_ops };
929     let ii = match ii {
930         IIItem(i) => IIItem(fld.fold_item(i).expect_one("expected one item")),
931         IITraitItem(d, ti) => match ti {
932             ProvidedMethod(m) => {
933                 IITraitItem(fld.fold_ops.new_def_id(d),
934                             ProvidedMethod(fld.fold_method(m)
935                                               .expect_one("expected one method")))
936             }
937             RequiredMethod(ty_m) => {
938                 IITraitItem(fld.fold_ops.new_def_id(d),
939                             RequiredMethod(fld.fold_type_method(ty_m)))
940             }
941             TypeTraitItem(at) => {
942                 IITraitItem(
943                     fld.fold_ops.new_def_id(d),
944                     TypeTraitItem(P(fld.fold_associated_type((*at).clone()))))
945             }
946         },
947         IIImplItem(d, m) => match m {
948             MethodImplItem(m) => {
949                 IIImplItem(fld.fold_ops.new_def_id(d),
950                            MethodImplItem(fld.fold_method(m)
951                                              .expect_one("expected one method")))
952             }
953             TypeImplItem(t) => {
954                 IIImplItem(fld.fold_ops.new_def_id(d),
955                            TypeImplItem(P(fld.fold_typedef((*t).clone()))))
956             }
957         },
958         IIForeign(i) => IIForeign(fld.fold_foreign_item(i))
959     };
960
961     let ii_parent = map.forest.inlined_items.alloc(InlinedParent {
962         path: path,
963         ii: ii
964     });
965
966     let mut collector = NodeCollector {
967         map: mem::replace(&mut *map.map.borrow_mut(), vec![]),
968         parent: fld.new_id(DUMMY_NODE_ID)
969     };
970     let ii_parent_id = collector.parent;
971     collector.insert_entry(ii_parent_id, RootInlinedParent(ii_parent));
972     visit::walk_inlined_item(&mut collector, &ii_parent.ii);
973
974     // Methods get added to the AST map when their impl is visited.  Since we
975     // don't decode and instantiate the impl, but just the method, we have to
976     // add it to the table now. Likewise with foreign items.
977     match ii_parent.ii {
978         IIItem(_) => {}
979         IITraitItem(_, ref trait_item) => {
980             let trait_item_id = match *trait_item {
981                 ProvidedMethod(ref m) => m.id,
982                 RequiredMethod(ref m) => m.id,
983                 TypeTraitItem(ref ty) => ty.ty_param.id,
984             };
985
986             collector.insert(trait_item_id, NodeTraitItem(trait_item));
987         }
988         IIImplItem(_, ref impl_item) => {
989             let impl_item_id = match *impl_item {
990                 MethodImplItem(ref m) => m.id,
991                 TypeImplItem(ref ti) => ti.id,
992             };
993
994             collector.insert(impl_item_id, NodeImplItem(impl_item));
995         }
996         IIForeign(ref i) => {
997             collector.insert(i.id, NodeForeignItem(&**i));
998         }
999     }
1000     *map.map.borrow_mut() = collector.map;
1001     &ii_parent.ii
1002 }
1003
1004 pub trait NodePrinter {
1005     fn print_node(&mut self, node: &Node) -> IoResult<()>;
1006 }
1007
1008 impl<'a> NodePrinter for pprust::State<'a> {
1009     fn print_node(&mut self, node: &Node) -> IoResult<()> {
1010         match *node {
1011             NodeItem(a)        => self.print_item(&*a),
1012             NodeForeignItem(a) => self.print_foreign_item(&*a),
1013             NodeTraitItem(a)   => self.print_trait_method(&*a),
1014             NodeImplItem(a)    => self.print_impl_item(&*a),
1015             NodeVariant(a)     => self.print_variant(&*a),
1016             NodeExpr(a)        => self.print_expr(&*a),
1017             NodeStmt(a)        => self.print_stmt(&*a),
1018             NodePat(a)         => self.print_pat(&*a),
1019             NodeBlock(a)       => self.print_block(&*a),
1020             NodeLifetime(a)    => self.print_lifetime(&*a),
1021
1022             // these cases do not carry enough information in the
1023             // ast_map to reconstruct their full structure for pretty
1024             // printing.
1025             NodeLocal(_)       => panic!("cannot print isolated Local"),
1026             NodeArg(_)         => panic!("cannot print isolated Arg"),
1027             NodeStructCtor(_)  => panic!("cannot print isolated StructCtor"),
1028         }
1029     }
1030 }
1031
1032 fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
1033     let id_str = format!(" (id={})", id);
1034     let id_str = if include_id { id_str.as_slice() } else { "" };
1035
1036     match map.find(id) {
1037         Some(NodeItem(item)) => {
1038             let path_str = map.path_to_str_with_ident(id, item.ident);
1039             let item_str = match item.node {
1040                 ItemStatic(..) => "static",
1041                 ItemConst(..) => "const",
1042                 ItemFn(..) => "fn",
1043                 ItemMod(..) => "mod",
1044                 ItemForeignMod(..) => "foreign mod",
1045                 ItemTy(..) => "ty",
1046                 ItemEnum(..) => "enum",
1047                 ItemStruct(..) => "struct",
1048                 ItemTrait(..) => "trait",
1049                 ItemImpl(..) => "impl",
1050                 ItemMac(..) => "macro"
1051             };
1052             format!("{} {}{}", item_str, path_str, id_str)
1053         }
1054         Some(NodeForeignItem(item)) => {
1055             let path_str = map.path_to_str_with_ident(id, item.ident);
1056             format!("foreign item {}{}", path_str, id_str)
1057         }
1058         Some(NodeImplItem(ref ii)) => {
1059             match **ii {
1060                 MethodImplItem(ref m) => {
1061                     match m.node {
1062                         MethDecl(ident, _, _, _, _, _, _, _) =>
1063                             format!("method {} in {}{}",
1064                                     token::get_ident(ident),
1065                                     map.path_to_string(id), id_str),
1066                         MethMac(ref mac) =>
1067                             format!("method macro {}{}",
1068                                     pprust::mac_to_string(mac), id_str)
1069                     }
1070                 }
1071                 TypeImplItem(ref t) => {
1072                     format!("typedef {} in {}{}",
1073                             token::get_ident(t.ident),
1074                             map.path_to_string(id),
1075                             id_str)
1076                 }
1077             }
1078         }
1079         Some(NodeTraitItem(ref tm)) => {
1080             match **tm {
1081                 RequiredMethod(_) | ProvidedMethod(_) => {
1082                     let m = ast_util::trait_item_to_ty_method(&**tm);
1083                     format!("method {} in {}{}",
1084                             token::get_ident(m.ident),
1085                             map.path_to_string(id),
1086                             id_str)
1087                 }
1088                 TypeTraitItem(ref t) => {
1089                     format!("type item {} in {}{}",
1090                             token::get_ident(t.ty_param.ident),
1091                             map.path_to_string(id),
1092                             id_str)
1093                 }
1094             }
1095         }
1096         Some(NodeVariant(ref variant)) => {
1097             format!("variant {} in {}{}",
1098                     token::get_ident(variant.node.name),
1099                     map.path_to_string(id), id_str)
1100         }
1101         Some(NodeExpr(ref expr)) => {
1102             format!("expr {}{}", pprust::expr_to_string(&**expr), id_str)
1103         }
1104         Some(NodeStmt(ref stmt)) => {
1105             format!("stmt {}{}", pprust::stmt_to_string(&**stmt), id_str)
1106         }
1107         Some(NodeArg(ref pat)) => {
1108             format!("arg {}{}", pprust::pat_to_string(&**pat), id_str)
1109         }
1110         Some(NodeLocal(ref pat)) => {
1111             format!("local {}{}", pprust::pat_to_string(&**pat), id_str)
1112         }
1113         Some(NodePat(ref pat)) => {
1114             format!("pat {}{}", pprust::pat_to_string(&**pat), id_str)
1115         }
1116         Some(NodeBlock(ref block)) => {
1117             format!("block {}{}", pprust::block_to_string(&**block), id_str)
1118         }
1119         Some(NodeStructCtor(_)) => {
1120             format!("struct_ctor {}{}", map.path_to_string(id), id_str)
1121         }
1122         Some(NodeLifetime(ref l)) => {
1123             format!("lifetime {}{}",
1124                     pprust::lifetime_to_string(&**l), id_str)
1125         }
1126         None => {
1127             format!("unknown node{}", id_str)
1128         }
1129     }
1130 }