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.
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.
19 use util::small_vector::SmallVector;
21 use std::cell::RefCell;
26 #[deriving(Clone, Eq)]
33 pub fn name(&self) -> Name {
35 PathMod(name) | PathName(name) => name
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)
48 struct LinkedPathNode<'a> {
53 type LinkedPath<'a> = Option<&'a LinkedPathNode<'a>>;
55 impl<'a> Iterator<PathElem> for LinkedPath<'a> {
56 fn next(&mut self) -> Option<PathElem> {
67 // HACK(eddyb) move this into libstd (value wrapper for slice::Items).
69 pub struct Values<'a, T>(slice::Items<'a, T>);
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)
78 /// The type of the iterator used by with_path.
79 pub type PathElems<'a, 'b> = iter::Chain<Values<'a, PathElem>, LinkedPath<'b>>;
81 pub fn path_to_str<PI: Iterator<PathElem>>(mut path: PI) -> ~str {
82 let itr = token::get_ident_interner();
84 path.fold(~"", |mut s, e| {
85 let e = itr.get(e.name());
89 s.push_str(e.as_slice());
97 NodeForeignItem(@ForeignItem),
98 NodeTraitMethod(@TraitMethod),
100 NodeVariant(P<Variant>),
107 /// NodeStructCtor represents a tuple struct.
108 NodeStructCtor(@StructDef),
111 // The odd layout is to bring down the total size.
114 // Placeholder for holes in the map.
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),
130 // Roots for node trees.
132 RootInlinedParent(P<InlinedParent>)
135 struct InlinedParent {
136 path: Vec<PathElem> ,
137 // Required by NodeTraitMethod and NodeMethod.
142 fn parent(&self) -> Option<NodeId> {
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,
159 fn to_node(&self) -> Option<Node> {
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),
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).
185 /// Also, indexing is pretty quick when you've got a vector and
186 /// plain old integers.
187 priv map: RefCell<Vec<MapEntry> >
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))
200 /// Retrieve the Node corresponding to `id`, failing if it cannot
202 pub fn get(&self, id: NodeId) -> Node {
203 match self.find(id) {
205 None => fail!("couldn't find node id {} in the AST map", id)
209 /// Retrieve the Node corresponding to `id`, returning None if
211 pub fn find(&self, id: NodeId) -> Option<Node> {
212 self.find_entry(id).and_then(|x| x.to_node())
215 pub fn get_parent(&self, id: NodeId) -> NodeId {
216 self.find_entry(id).and_then(|x| x.parent()).unwrap_or(id)
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)
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),
234 // Wrong but OK, because the only inlined foreign items are intrinsics.
235 Some(RootInlinedParent(_)) => Some(AbiSet::Intrinsic()),
240 None => fail!("expected foreign mod or inlined parent, found {}",
241 self.node_to_str(parent))
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),
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))
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))
267 pub fn get_path_elem(&self, id: NodeId) -> PathElem {
271 ItemMod(_) | ItemForeignMod(_) => {
272 PathMod(item.ident.name)
274 _ => PathName(item.ident.name)
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)
283 NodeVariant(v) => PathName(v.node.name.name),
284 node => fail!("no path elem for {:?}", node)
288 pub fn with_path<T>(&self, id: NodeId, f: |PathElems| -> T) -> T {
289 self.with_path_next(id, None, f)
292 pub fn path_to_str(&self, id: NodeId) -> ~str {
293 self.with_path(id, |path| path_to_str(path))
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()))
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)
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);
318 match self.find_entry(id) {
319 Some(RootInlinedParent(data)) => {
320 f(Values(data.path.iter()).chain(next))
322 _ => f(Values([].iter()).chain(next))
325 self.with_path_next(parent, Some(&LinkedPathNode {
326 node: self.get_path_elem(id),
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())
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);
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,
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),
374 pub fn node_to_str(&self, id: NodeId) -> ~str {
375 node_id_to_str(self, id)
380 fn new_id(&self, id: NodeId) -> NodeId {
383 fn new_span(&self, span: Span) -> Span {
388 pub struct Ctx<'a, F> {
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.
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);
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 {
411 fn new_span(&mut self, span: Span) -> Span {
412 self.fold_ops.new_span(span)
415 fn fold_item(&mut self, i: @Item) -> SmallVector<@Item> {
416 let parent = self.parent;
417 self.parent = DUMMY_NODE_ID;
419 let i = fold::noop_fold_item(i, self).expect_one("expected one item");
420 assert_eq!(self.parent, i.id);
423 ItemImpl(_, _, _, ref ms) => {
424 for &m in ms.iter() {
425 self.insert(m.id, EntryMethod(self.parent, m));
428 ItemEnum(ref enum_definition, _) => {
429 for &v in enum_definition.variants.iter() {
430 self.insert(v.node.id, EntryVariant(self.parent, v));
433 ItemForeignMod(ref nm) => {
434 for &nitem in nm.items.iter() {
435 self.insert(nitem.id, EntryForeignItem(self.parent, nitem));
438 ItemStruct(struct_def, _) => {
439 // If this is a tuple-like struct, register the constructor.
440 match struct_def.ctor_id {
442 self.insert(ctor_id, EntryStructCtor(self.parent,
448 ItemTrait(_, ref traits, ref methods) => {
449 for t in traits.iter() {
450 self.insert(t.ref_id, EntryItem(self.parent, i));
453 for tm in methods.iter() {
456 self.insert(m.id, EntryTraitMethod(self.parent,
460 self.insert(m.id, EntryTraitMethod(self.parent,
469 self.parent = parent;
470 self.insert(i.id, EntryItem(self.parent, i));
475 fn fold_pat(&mut self, pat: @Pat) -> @Pat {
476 let pat = fold::noop_fold_pat(pat, self);
479 // Note: this is at least *potentially* a pattern...
480 self.insert(pat.id, EntryLocal(self.parent, pat));
488 fn fold_expr(&mut self, expr: @Expr) -> @Expr {
489 let expr = fold::noop_fold_expr(expr, self);
491 self.insert(expr.id, EntryExpr(self.parent, expr));
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)
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;
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));
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));
526 pub fn map_crate<F: FoldOps>(krate: Crate, fold_ops: F) -> (Crate, Map) {
527 let map = Map { map: RefCell::new(Vec::new()) };
531 parent: CRATE_NODE_ID,
534 cx.insert(CRATE_NODE_ID, RootCrate);
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| {
547 }).enumerate().last().expect("AST map was empty after folding?");
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.);
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
561 pub fn map_decoded_item<F: FoldOps>(map: &Map,
562 path: Vec<PathElem> ,
564 fold: |&mut Ctx<F>| -> InlinedItem)
568 parent: DUMMY_NODE_ID,
572 // Generate a NodeId for the RootInlinedParent inserted below.
573 cx.new_id(DUMMY_NODE_ID);
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);
582 IIMethod(impl_did, is_provided, m) => {
583 let entry = if is_provided {
584 EntryTraitMethod(cx.parent, @Provided(m))
586 EntryMethod(cx.parent, m)
588 cx.insert(m.id, entry);
592 cx.insert(i.id, EntryForeignItem(cx.parent, i));
596 cx.insert(cx.parent, RootInlinedParent(P(InlinedParent {
604 fn node_id_to_str(map: &Map, id: NodeId) -> ~str {
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",
611 ItemMod(..) => "mod",
612 ItemForeignMod(..) => "foreign mod",
614 ItemEnum(..) => "enum",
615 ItemStruct(..) => "struct",
616 ItemTrait(..) => "trait",
617 ItemImpl(..) => "impl",
618 ItemMac(..) => "macro"
620 format!("{} {} (id={})", item_str, path_str, id)
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)
626 Some(NodeMethod(m)) => {
627 format!("method {} in {} (id={})",
628 token::get_ident(m.ident),
629 map.path_to_str(id), id)
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)
637 Some(NodeVariant(ref variant)) => {
638 format!("variant {} in {} (id={})",
639 token::get_ident(variant.node.name),
640 map.path_to_str(id), id)
642 Some(NodeExpr(expr)) => {
643 format!("expr {} (id={})", pprust::expr_to_str(expr), id)
645 Some(NodeStmt(stmt)) => {
646 format!("stmt {} (id={})", pprust::stmt_to_str(stmt), id)
648 Some(NodeArg(pat)) => {
649 format!("arg {} (id={})", pprust::pat_to_str(pat), id)
651 Some(NodeLocal(pat)) => {
652 format!("local {} (id={})", pprust::pat_to_str(pat), id)
654 Some(NodeBlock(block)) => {
655 format!("block {} (id={})", pprust::block_to_str(block), id)
657 Some(NodeStructCtor(_)) => {
658 format!("struct_ctor {} (id={})", map.path_to_str(id), id)
661 format!("unknown node (id={})", id)