]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ast_map.rs
auto merge of #13049 : alexcrichton/rust/io-fill, r=huonw
[rust.git] / src / libsyntax / ast_map.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 use abi::AbiSet;
12 use ast::*;
13 use ast_util;
14 use codemap::Span;
15 use fold::Folder;
16 use fold;
17 use parse::token;
18 use print::pprust;
19 use util::small_vector::SmallVector;
20
21 use std::cell::RefCell;
22 use std::iter;
23 use std::slice;
24 use std::fmt;
25
26 #[deriving(Clone, Eq)]
27 pub enum PathElem {
28     PathMod(Name),
29     PathName(Name)
30 }
31
32 impl PathElem {
33     pub fn name(&self) -> Name {
34         match *self {
35             PathMod(name) | PathName(name) => name
36         }
37     }
38 }
39
40 impl fmt::Show for PathElem {
41     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
42         let slot = token::get_name(self.name());
43         write!(f.buf, "{}", slot)
44     }
45 }
46
47 #[deriving(Clone)]
48 struct LinkedPathNode<'a> {
49     node: PathElem,
50     next: LinkedPath<'a>,
51 }
52
53 type LinkedPath<'a> = Option<&'a LinkedPathNode<'a>>;
54
55 impl<'a> Iterator<PathElem> for LinkedPath<'a> {
56     fn next(&mut self) -> Option<PathElem> {
57         match *self {
58             Some(node) => {
59                 *self = node.next;
60                 Some(node.node)
61             }
62             None => None
63         }
64     }
65 }
66
67 // HACK(eddyb) move this into libstd (value wrapper for slice::Items).
68 #[deriving(Clone)]
69 pub struct Values<'a, T>(slice::Items<'a, T>);
70
71 impl<'a, T: Pod> Iterator<T> for Values<'a, T> {
72     fn next(&mut self) -> Option<T> {
73         let &Values(ref mut items) = self;
74         items.next().map(|&x| x)
75     }
76 }
77
78 /// The type of the iterator used by with_path.
79 pub type PathElems<'a, 'b> = iter::Chain<Values<'a, PathElem>, LinkedPath<'b>>;
80
81 pub fn path_to_str<PI: Iterator<PathElem>>(mut path: PI) -> ~str {
82     let itr = token::get_ident_interner();
83
84     path.fold(~"", |mut s, e| {
85         let e = itr.get(e.name());
86         if !s.is_empty() {
87             s.push_str("::");
88         }
89         s.push_str(e.as_slice());
90         s
91     })
92 }
93
94 #[deriving(Clone)]
95 pub enum Node {
96     NodeItem(@Item),
97     NodeForeignItem(@ForeignItem),
98     NodeTraitMethod(@TraitMethod),
99     NodeMethod(@Method),
100     NodeVariant(P<Variant>),
101     NodeExpr(@Expr),
102     NodeStmt(@Stmt),
103     NodeArg(@Pat),
104     NodeLocal(@Pat),
105     NodeBlock(P<Block>),
106
107     /// NodeStructCtor represents a tuple struct.
108     NodeStructCtor(@StructDef),
109 }
110
111 // The odd layout is to bring down the total size.
112 #[deriving(Clone)]
113 enum MapEntry {
114     // Placeholder for holes in the map.
115     NotPresent,
116
117     // All the node types, with a parent ID.
118     EntryItem(NodeId, @Item),
119     EntryForeignItem(NodeId, @ForeignItem),
120     EntryTraitMethod(NodeId, @TraitMethod),
121     EntryMethod(NodeId, @Method),
122     EntryVariant(NodeId, P<Variant>),
123     EntryExpr(NodeId, @Expr),
124     EntryStmt(NodeId, @Stmt),
125     EntryArg(NodeId, @Pat),
126     EntryLocal(NodeId, @Pat),
127     EntryBlock(NodeId, P<Block>),
128     EntryStructCtor(NodeId, @StructDef),
129
130     // Roots for node trees.
131     RootCrate,
132     RootInlinedParent(P<InlinedParent>)
133 }
134
135 struct InlinedParent {
136     path: Vec<PathElem> ,
137     // Required by NodeTraitMethod and NodeMethod.
138     def_id: DefId
139 }
140
141 impl MapEntry {
142     fn parent(&self) -> Option<NodeId> {
143         Some(match *self {
144             EntryItem(id, _) => id,
145             EntryForeignItem(id, _) => id,
146             EntryTraitMethod(id, _) => id,
147             EntryMethod(id, _) => id,
148             EntryVariant(id, _) => id,
149             EntryExpr(id, _) => id,
150             EntryStmt(id, _) => id,
151             EntryArg(id, _) => id,
152             EntryLocal(id, _) => id,
153             EntryBlock(id, _) => id,
154             EntryStructCtor(id, _) => id,
155             _ => return None
156         })
157     }
158
159     fn to_node(&self) -> Option<Node> {
160         Some(match *self {
161             EntryItem(_, p) => NodeItem(p),
162             EntryForeignItem(_, p) => NodeForeignItem(p),
163             EntryTraitMethod(_, p) => NodeTraitMethod(p),
164             EntryMethod(_, p) => NodeMethod(p),
165             EntryVariant(_, p) => NodeVariant(p),
166             EntryExpr(_, p) => NodeExpr(p),
167             EntryStmt(_, p) => NodeStmt(p),
168             EntryArg(_, p) => NodeArg(p),
169             EntryLocal(_, p) => NodeLocal(p),
170             EntryBlock(_, p) => NodeBlock(p),
171             EntryStructCtor(_, p) => NodeStructCtor(p),
172             _ => return None
173         })
174     }
175 }
176
177 pub struct Map {
178     /// NodeIds are sequential integers from 0, so we can be
179     /// super-compact by storing them in a vector. Not everything with
180     /// a NodeId is in the map, but empirically the occupancy is about
181     /// 75-80%, so there's not too much overhead (certainly less than
182     /// a hashmap, since they (at the time of writing) have a maximum
183     /// of 75% occupancy).
184     ///
185     /// Also, indexing is pretty quick when you've got a vector and
186     /// plain old integers.
187     priv map: RefCell<Vec<MapEntry> >
188 }
189
190 impl Map {
191     fn find_entry(&self, id: NodeId) -> Option<MapEntry> {
192         let map = self.map.borrow();
193         if map.len() > id as uint {
194             Some(*map.get(id as uint))
195         } else {
196             None
197         }
198     }
199
200     /// Retrieve the Node corresponding to `id`, failing if it cannot
201     /// be found.
202     pub fn get(&self, id: NodeId) -> Node {
203         match self.find(id) {
204             Some(node) => node,
205             None => fail!("couldn't find node id {} in the AST map", id)
206         }
207     }
208
209     /// Retrieve the Node corresponding to `id`, returning None if
210     /// cannot be found.
211     pub fn find(&self, id: NodeId) -> Option<Node> {
212         self.find_entry(id).and_then(|x| x.to_node())
213     }
214
215     pub fn get_parent(&self, id: NodeId) -> NodeId {
216         self.find_entry(id).and_then(|x| x.parent()).unwrap_or(id)
217     }
218
219     pub fn get_parent_did(&self, id: NodeId) -> DefId {
220         let parent = self.get_parent(id);
221         match self.find_entry(parent) {
222             Some(RootInlinedParent(data)) => data.def_id,
223             _ => ast_util::local_def(parent)
224         }
225     }
226
227     pub fn get_foreign_abis(&self, id: NodeId) -> AbiSet {
228         let parent = self.get_parent(id);
229         let abis = match self.find_entry(parent) {
230             Some(EntryItem(_, i)) => match i.node {
231                 ItemForeignMod(ref nm) => Some(nm.abis),
232                 _ => None
233             },
234             // Wrong but OK, because the only inlined foreign items are intrinsics.
235             Some(RootInlinedParent(_)) => Some(AbiSet::Intrinsic()),
236             _ => None
237         };
238         match abis {
239             Some(abis) => abis,
240             None => fail!("expected foreign mod or inlined parent, found {}",
241                           self.node_to_str(parent))
242         }
243     }
244
245     pub fn get_foreign_vis(&self, id: NodeId) -> Visibility {
246         let vis = self.expect_foreign_item(id).vis;
247         match self.find(self.get_parent(id)) {
248             Some(NodeItem(i)) => vis.inherit_from(i.vis),
249             _ => vis
250         }
251     }
252
253     pub fn expect_item(&self, id: NodeId) -> @Item {
254         match self.find(id) {
255             Some(NodeItem(item)) => item,
256             _ => fail!("expected item, found {}", self.node_to_str(id))
257         }
258     }
259
260     pub fn expect_foreign_item(&self, id: NodeId) -> @ForeignItem {
261         match self.find(id) {
262             Some(NodeForeignItem(item)) => item,
263             _ => fail!("expected foreign item, found {}", self.node_to_str(id))
264         }
265     }
266
267     pub fn get_path_elem(&self, id: NodeId) -> PathElem {
268         match self.get(id) {
269             NodeItem(item) => {
270                 match item.node {
271                     ItemMod(_) | ItemForeignMod(_) => {
272                         PathMod(item.ident.name)
273                     }
274                     _ => PathName(item.ident.name)
275                 }
276             }
277             NodeForeignItem(i) => PathName(i.ident.name),
278             NodeMethod(m) => PathName(m.ident.name),
279             NodeTraitMethod(tm) => match *tm {
280                 Required(ref m) => PathName(m.ident.name),
281                 Provided(ref m) => PathName(m.ident.name)
282             },
283             NodeVariant(v) => PathName(v.node.name.name),
284             node => fail!("no path elem for {:?}", node)
285         }
286     }
287
288     pub fn with_path<T>(&self, id: NodeId, f: |PathElems| -> T) -> T {
289         self.with_path_next(id, None, f)
290     }
291
292     pub fn path_to_str(&self, id: NodeId) -> ~str {
293         self.with_path(id, |path| path_to_str(path))
294     }
295
296     fn path_to_str_with_ident(&self, id: NodeId, i: Ident) -> ~str {
297         self.with_path(id, |path| {
298             path_to_str(path.chain(Some(PathName(i.name)).move_iter()))
299         })
300     }
301
302     fn with_path_next<T>(&self, id: NodeId, next: LinkedPath, f: |PathElems| -> T) -> T {
303         let parent = self.get_parent(id);
304         let parent = match self.find_entry(id) {
305             Some(EntryForeignItem(..)) | Some(EntryVariant(..)) => {
306                 // Anonymous extern items, enum variants and struct ctors
307                 // go in the parent scope.
308                 self.get_parent(parent)
309             }
310             // But tuple struct ctors don't have names, so use the path of its
311             // parent, the struct item. Similarly with closure expressions.
312             Some(EntryStructCtor(..)) | Some(EntryExpr(..)) => {
313                 return self.with_path_next(parent, next, f);
314             }
315             _ => parent
316         };
317         if parent == id {
318             match self.find_entry(id) {
319                 Some(RootInlinedParent(data)) => {
320                     f(Values(data.path.iter()).chain(next))
321                 }
322                 _ => f(Values([].iter()).chain(next))
323             }
324         } else {
325             self.with_path_next(parent, Some(&LinkedPathNode {
326                 node: self.get_path_elem(id),
327                 next: next
328             }), f)
329         }
330     }
331
332     pub fn with_attrs<T>(&self, id: NodeId, f: |Option<&[Attribute]>| -> T) -> T {
333         let attrs = match self.get(id) {
334             NodeItem(i) => Some(i.attrs.as_slice()),
335             NodeForeignItem(fi) => Some(fi.attrs.as_slice()),
336             NodeTraitMethod(tm) => match *tm {
337                 Required(ref type_m) => Some(type_m.attrs.as_slice()),
338                 Provided(m) => Some(m.attrs.as_slice())
339             },
340             NodeMethod(m) => Some(m.attrs.as_slice()),
341             NodeVariant(ref v) => Some(v.node.attrs.as_slice()),
342             // unit/tuple structs take the attributes straight from
343             // the struct definition.
344             // FIXME(eddyb) make this work again (requires access to the map).
345             NodeStructCtor(_) => {
346                 return self.with_attrs(self.get_parent(id), f);
347             }
348             _ => None
349         };
350         f(attrs)
351     }
352
353     pub fn span(&self, id: NodeId) -> Span {
354         match self.find(id) {
355             Some(NodeItem(item)) => item.span,
356             Some(NodeForeignItem(foreign_item)) => foreign_item.span,
357             Some(NodeTraitMethod(trait_method)) => {
358                 match *trait_method {
359                     Required(ref type_method) => type_method.span,
360                     Provided(ref method) => method.span,
361                 }
362             }
363             Some(NodeMethod(method)) => method.span,
364             Some(NodeVariant(variant)) => variant.span,
365             Some(NodeExpr(expr)) => expr.span,
366             Some(NodeStmt(stmt)) => stmt.span,
367             Some(NodeArg(pat)) | Some(NodeLocal(pat)) => pat.span,
368             Some(NodeBlock(block)) => block.span,
369             Some(NodeStructCtor(_)) => self.expect_item(self.get_parent(id)).span,
370             _ => fail!("node_span: could not find span for id {}", id),
371         }
372     }
373
374     pub fn node_to_str(&self, id: NodeId) -> ~str {
375         node_id_to_str(self, id)
376     }
377 }
378
379 pub trait FoldOps {
380     fn new_id(&self, id: NodeId) -> NodeId {
381         id
382     }
383     fn new_span(&self, span: Span) -> Span {
384         span
385     }
386 }
387
388 pub struct Ctx<'a, F> {
389     map: &'a Map,
390     // The node in which we are currently mapping (an item or a method).
391     // When equal to DUMMY_NODE_ID, the next mapped node becomes the parent.
392     parent: NodeId,
393     fold_ops: F
394 }
395
396 impl<'a, F> Ctx<'a, F> {
397     fn insert(&self, id: NodeId, entry: MapEntry) {
398         (*self.map.map.borrow_mut()).grow_set(id as uint, &NotPresent, entry);
399     }
400 }
401
402 impl<'a, F: FoldOps> Folder for Ctx<'a, F> {
403     fn new_id(&mut self, id: NodeId) -> NodeId {
404         let id = self.fold_ops.new_id(id);
405         if self.parent == DUMMY_NODE_ID {
406             self.parent = id;
407         }
408         id
409     }
410
411     fn new_span(&mut self, span: Span) -> Span {
412         self.fold_ops.new_span(span)
413     }
414
415     fn fold_item(&mut self, i: @Item) -> SmallVector<@Item> {
416         let parent = self.parent;
417         self.parent = DUMMY_NODE_ID;
418
419         let i = fold::noop_fold_item(i, self).expect_one("expected one item");
420         assert_eq!(self.parent, i.id);
421
422         match i.node {
423             ItemImpl(_, _, _, ref ms) => {
424                 for &m in ms.iter() {
425                     self.insert(m.id, EntryMethod(self.parent, m));
426                 }
427             }
428             ItemEnum(ref enum_definition, _) => {
429                 for &v in enum_definition.variants.iter() {
430                     self.insert(v.node.id, EntryVariant(self.parent, v));
431                 }
432             }
433             ItemForeignMod(ref nm) => {
434                 for &nitem in nm.items.iter() {
435                     self.insert(nitem.id, EntryForeignItem(self.parent, nitem));
436                 }
437             }
438             ItemStruct(struct_def, _) => {
439                 // If this is a tuple-like struct, register the constructor.
440                 match struct_def.ctor_id {
441                     Some(ctor_id) => {
442                         self.insert(ctor_id, EntryStructCtor(self.parent,
443                                                              struct_def));
444                     }
445                     None => {}
446                 }
447             }
448             ItemTrait(_, ref traits, ref methods) => {
449                 for t in traits.iter() {
450                     self.insert(t.ref_id, EntryItem(self.parent, i));
451                 }
452
453                 for tm in methods.iter() {
454                     match *tm {
455                         Required(ref m) => {
456                             self.insert(m.id, EntryTraitMethod(self.parent,
457                                                                @(*tm).clone()));
458                         }
459                         Provided(m) => {
460                             self.insert(m.id, EntryTraitMethod(self.parent,
461                                                                @Provided(m)));
462                         }
463                     }
464                 }
465             }
466             _ => {}
467         }
468
469         self.parent = parent;
470         self.insert(i.id, EntryItem(self.parent, i));
471
472         SmallVector::one(i)
473     }
474
475     fn fold_pat(&mut self, pat: @Pat) -> @Pat {
476         let pat = fold::noop_fold_pat(pat, self);
477         match pat.node {
478             PatIdent(..) => {
479                 // Note: this is at least *potentially* a pattern...
480                 self.insert(pat.id, EntryLocal(self.parent, pat));
481             }
482             _ => {}
483         }
484
485         pat
486     }
487
488     fn fold_expr(&mut self, expr: @Expr) -> @Expr {
489         let expr = fold::noop_fold_expr(expr, self);
490
491         self.insert(expr.id, EntryExpr(self.parent, expr));
492
493         expr
494     }
495
496     fn fold_stmt(&mut self, stmt: &Stmt) -> SmallVector<@Stmt> {
497         let stmt = fold::noop_fold_stmt(stmt, self).expect_one("expected one statement");
498         self.insert(ast_util::stmt_id(stmt), EntryStmt(self.parent, stmt));
499         SmallVector::one(stmt)
500     }
501
502     fn fold_method(&mut self, m: @Method) -> @Method {
503         let parent = self.parent;
504         self.parent = DUMMY_NODE_ID;
505         let m = fold::noop_fold_method(m, self);
506         assert_eq!(self.parent, m.id);
507         self.parent = parent;
508         m
509     }
510
511     fn fold_fn_decl(&mut self, decl: &FnDecl) -> P<FnDecl> {
512         let decl = fold::noop_fold_fn_decl(decl, self);
513         for a in decl.inputs.iter() {
514             self.insert(a.id, EntryArg(self.parent, a.pat));
515         }
516         decl
517     }
518
519     fn fold_block(&mut self, block: P<Block>) -> P<Block> {
520         let block = fold::noop_fold_block(block, self);
521         self.insert(block.id, EntryBlock(self.parent, block));
522         block
523     }
524 }
525
526 pub fn map_crate<F: FoldOps>(krate: Crate, fold_ops: F) -> (Crate, Map) {
527     let map = Map { map: RefCell::new(Vec::new()) };
528     let krate = {
529         let mut cx = Ctx {
530             map: &map,
531             parent: CRATE_NODE_ID,
532             fold_ops: fold_ops
533         };
534         cx.insert(CRATE_NODE_ID, RootCrate);
535         cx.fold_crate(krate)
536     };
537
538     if log_enabled!(::log::DEBUG) {
539         let map = map.map.borrow();
540         // This only makes sense for ordered stores; note the
541         // enumerate to count the number of entries.
542         let (entries_less_1, _) = (*map).iter().filter(|&x| {
543             match *x {
544                 NotPresent => false,
545                 _ => true
546             }
547         }).enumerate().last().expect("AST map was empty after folding?");
548
549         let entries = entries_less_1 + 1;
550         let vector_length = (*map).len();
551         debug!("The AST map has {} entries with a maximum of {}: occupancy {:.1}%",
552               entries, vector_length, (entries as f64 / vector_length as f64) * 100.);
553     }
554
555     (krate, map)
556 }
557
558 // Used for items loaded from external crate that are being inlined into this
559 // crate.  The `path` should be the path to the item but should not include
560 // the item itself.
561 pub fn map_decoded_item<F: FoldOps>(map: &Map,
562                                     path: Vec<PathElem> ,
563                                     fold_ops: F,
564                                     fold: |&mut Ctx<F>| -> InlinedItem)
565                                     -> InlinedItem {
566     let mut cx = Ctx {
567         map: map,
568         parent: DUMMY_NODE_ID,
569         fold_ops: fold_ops
570     };
571
572     // Generate a NodeId for the RootInlinedParent inserted below.
573     cx.new_id(DUMMY_NODE_ID);
574
575     // Methods get added to the AST map when their impl is visited.  Since we
576     // don't decode and instantiate the impl, but just the method, we have to
577     // add it to the table now. Likewise with foreign items.
578     let mut def_id = DefId { krate: LOCAL_CRATE, node: DUMMY_NODE_ID };
579     let ii = fold(&mut cx);
580     match ii {
581         IIItem(_) => {}
582         IIMethod(impl_did, is_provided, m) => {
583             let entry = if is_provided {
584                 EntryTraitMethod(cx.parent, @Provided(m))
585             } else {
586                 EntryMethod(cx.parent, m)
587             };
588             cx.insert(m.id, entry);
589             def_id = impl_did;
590         }
591         IIForeign(i) => {
592             cx.insert(i.id, EntryForeignItem(cx.parent, i));
593         }
594     }
595
596     cx.insert(cx.parent, RootInlinedParent(P(InlinedParent {
597         path: path,
598         def_id: def_id
599     })));
600
601     ii
602 }
603
604 fn node_id_to_str(map: &Map, id: NodeId) -> ~str {
605     match map.find(id) {
606         Some(NodeItem(item)) => {
607             let path_str = map.path_to_str_with_ident(id, item.ident);
608             let item_str = match item.node {
609                 ItemStatic(..) => "static",
610                 ItemFn(..) => "fn",
611                 ItemMod(..) => "mod",
612                 ItemForeignMod(..) => "foreign mod",
613                 ItemTy(..) => "ty",
614                 ItemEnum(..) => "enum",
615                 ItemStruct(..) => "struct",
616                 ItemTrait(..) => "trait",
617                 ItemImpl(..) => "impl",
618                 ItemMac(..) => "macro"
619             };
620             format!("{} {} (id={})", item_str, path_str, id)
621         }
622         Some(NodeForeignItem(item)) => {
623             let path_str = map.path_to_str_with_ident(id, item.ident);
624             format!("foreign item {} (id={})", path_str, id)
625         }
626         Some(NodeMethod(m)) => {
627             format!("method {} in {} (id={})",
628                     token::get_ident(m.ident),
629                     map.path_to_str(id), id)
630         }
631         Some(NodeTraitMethod(ref tm)) => {
632             let m = ast_util::trait_method_to_ty_method(&**tm);
633             format!("method {} in {} (id={})",
634                     token::get_ident(m.ident),
635                     map.path_to_str(id), id)
636         }
637         Some(NodeVariant(ref variant)) => {
638             format!("variant {} in {} (id={})",
639                     token::get_ident(variant.node.name),
640                     map.path_to_str(id), id)
641         }
642         Some(NodeExpr(expr)) => {
643             format!("expr {} (id={})", pprust::expr_to_str(expr), id)
644         }
645         Some(NodeStmt(stmt)) => {
646             format!("stmt {} (id={})", pprust::stmt_to_str(stmt), id)
647         }
648         Some(NodeArg(pat)) => {
649             format!("arg {} (id={})", pprust::pat_to_str(pat), id)
650         }
651         Some(NodeLocal(pat)) => {
652             format!("local {} (id={})", pprust::pat_to_str(pat), id)
653         }
654         Some(NodeBlock(block)) => {
655             format!("block {} (id={})", pprust::block_to_str(block), id)
656         }
657         Some(NodeStructCtor(_)) => {
658             format!("struct_ctor {} (id={})", map.path_to_str(id), id)
659         }
660         None => {
661             format!("unknown node (id={})", id)
662         }
663     }
664 }