1 // Copyright 2012 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.
14 use ast_util::{inlined_item_utils, stmt_id};
17 use diagnostic::span_handler;
18 use parse::token::ident_interner;
22 use core::hashmap::HashMap;
29 impl cmp::Eq for path_elt {
30 fn eq(&self, other: &path_elt) -> bool {
34 path_mod(e0b) => e0a == e0b,
40 path_name(e0b) => e0a == e0b,
46 fn ne(&self, other: &path_elt) -> bool { !(*self).eq(other) }
49 pub type path = ~[path_elt];
51 pub fn path_to_str_with_sep(p: &[path_elt], sep: ~str, itr: @ident_interner)
53 let strs = do p.map |e| {
55 path_mod(s) => copy *itr.get(s),
56 path_name(s) => copy *itr.get(s)
59 str::connect(strs, sep)
62 pub fn path_ident_to_str(p: path, i: ident, itr: @ident_interner) -> ~str {
64 //FIXME /* FIXME (#2543) */ copy *i
67 fmt!("%s::%s", path_to_str(p, itr), *itr.get(i))
71 pub fn path_to_str(p: &[path_elt], itr: @ident_interner) -> ~str {
72 path_to_str_with_sep(p, ~"::", itr)
75 pub fn path_elt_to_str(pe: path_elt, itr: @ident_interner) -> ~str {
77 path_mod(s) => copy *itr.get(s),
78 path_name(s) => copy *itr.get(s)
83 node_item(@item, @path),
84 node_foreign_item(@foreign_item, AbiSet, visibility, @path),
85 node_trait_method(@trait_method, def_id /* trait did */,
86 @path /* path to the trait */),
87 node_method(@method, def_id /* impl did */, @path /* path to the impl */),
88 node_variant(variant, @item, @path),
91 // Locals are numbered, because the alias analysis needs to know in which
92 // order they are introduced.
96 node_struct_ctor(@struct_def, @item, @path),
99 pub type map = @mut HashMap<node_id, ast_node>;
108 pub type vt = visit::vt<@mut Ctx>;
110 pub fn extend(cx: @mut Ctx, elt: ident) -> @path {
111 @(vec::append(copy cx.path, ~[path_name(elt)]))
114 pub fn mk_ast_map_visitor() -> vt {
115 return visit::mk_vt(@visit::Visitor {
116 visit_item: map_item,
117 visit_expr: map_expr,
118 visit_stmt: map_stmt,
120 visit_local: map_local,
122 visit_block: map_block,
123 .. *visit::default_visitor()
127 pub fn map_crate(diag: @span_handler, c: @crate) -> map {
129 map: @mut HashMap::new(),
134 visit::visit_crate(c, cx, mk_ast_map_visitor());
138 // Used for items loaded from external crate that are being inlined into this
139 // crate. The `path` should be the path to the item but should not include
141 pub fn map_decoded_item(diag: @span_handler,
145 // I believe it is ok for the local IDs of inlined items from other crates
146 // to overlap with the local ids from this crate, so just generate the ids
147 // starting from 0. (In particular, I think these ids are only used in
148 // alias analysis, which we will not be running on the inlined items, and
149 // even if we did I think it only needs an ordering between local
150 // variables that are simultaneously in scope).
157 let v = mk_ast_map_visitor();
159 // methods get added to the AST map when their impl is visited. Since we
160 // don't decode and instantiate the impl, but just the method, we have to
161 // add it to the table now:
163 ii_item(*) => { /* fallthrough */ }
165 cx.map.insert(i.id, node_foreign_item(i,
167 i.vis, // Wrong but OK
170 ii_method(impl_did, m) => {
171 map_method(impl_did, @path, m, cx);
175 // visit the item / method contents and add those to the map:
186 v: visit::vt<@mut Ctx>
188 for decl.inputs.each |a| {
190 node_arg(/* FIXME (#2543) */ copy *a, cx.local_id));
193 visit::visit_fn(fk, decl, body, sp, id, cx, v);
196 pub fn map_block(b: &blk, cx: @mut Ctx, v: visit::vt<@mut Ctx>) {
197 cx.map.insert(b.node.id, node_block(/* FIXME (#2543) */ copy *b));
198 visit::visit_block(b, cx, v);
201 pub fn number_pat(cx: @mut Ctx, pat: @pat) {
202 do ast_util::walk_pat(pat) |p| {
205 cx.map.insert(p.id, node_local(cx.local_id));
213 pub fn map_local(loc: @local, cx: @mut Ctx, v: visit::vt<@mut Ctx>) {
214 number_pat(cx, loc.node.pat);
215 visit::visit_local(loc, cx, v);
218 pub fn map_arm(arm: &arm, cx: @mut Ctx, v: visit::vt<@mut Ctx>) {
219 number_pat(cx, arm.pats[0]);
220 visit::visit_arm(arm, cx, v);
223 pub fn map_method(impl_did: def_id, impl_path: @path,
224 m: @method, cx: @mut Ctx) {
225 cx.map.insert(m.id, node_method(m, impl_did, impl_path));
226 cx.map.insert(m.self_id, node_local(cx.local_id));
230 pub fn map_item(i: @item, cx: @mut Ctx, v: visit::vt<@mut Ctx>) {
231 let item_path = @/* FIXME (#2543) */ copy cx.path;
232 cx.map.insert(i.id, node_item(i, item_path));
234 item_impl(_, _, _, ref ms) => {
235 let impl_did = ast_util::local_def(i.id);
237 map_method(impl_did, extend(cx, i.ident), *m, cx);
240 item_enum(ref enum_definition, _) => {
241 for (*enum_definition).variants.each |v| {
242 cx.map.insert(v.node.id, node_variant(
243 /* FIXME (#2543) */ copy *v, i,
244 extend(cx, i.ident)));
247 item_foreign_mod(ref nm) => {
248 for nm.items.each |nitem| {
249 // Compute the visibility for this native item.
250 let visibility = match nitem.vis {
256 cx.map.insert(nitem.id,
262 if nm.sort == ast::named {
265 // Anonymous extern mods go in the parent scope
272 item_struct(struct_def, _) => {
275 node_item(i, item_path),
281 item_trait(_, ref traits, ref methods) => {
282 for traits.each |p| {
283 cx.map.insert(p.ref_id, node_item(i, item_path));
285 for methods.each |tm| {
286 let id = ast_util::trait_method_to_ty_method(tm).id;
287 let d_id = ast_util::local_def(i.id);
290 node_trait_method(@copy *tm, d_id, item_path)
297 item_mod(_) | item_foreign_mod(_) => {
298 cx.path.push(path_mod(i.ident));
300 _ => cx.path.push(path_name(i.ident))
302 visit::visit_item(i, cx, v);
306 pub fn map_struct_def(
307 struct_def: @ast::struct_def,
308 parent_node: ast_node,
311 _v: visit::vt<@mut Ctx>
313 let p = extend(cx, ident);
314 // If this is a tuple-like struct, register the constructor.
315 match struct_def.ctor_id {
319 node_item(item, _) => {
320 cx.map.insert(ctor_id,
321 node_struct_ctor(struct_def, item, p));
323 _ => fail!(~"struct def parent wasn't an item")
329 pub fn map_expr(ex: @expr, cx: @mut Ctx, v: visit::vt<@mut Ctx>) {
330 cx.map.insert(ex.id, node_expr(ex));
331 visit::visit_expr(ex, cx, v);
334 pub fn map_stmt(stmt: @stmt, cx: @mut Ctx, v: visit::vt<@mut Ctx>) {
335 cx.map.insert(stmt_id(stmt), node_stmt(stmt));
336 visit::visit_stmt(stmt, cx, v);
339 pub fn node_id_to_str(map: map, id: node_id, itr: @ident_interner) -> ~str {
340 match map.find(&id) {
342 fmt!("unknown node (id=%d)", id)
344 Some(&node_item(item, path)) => {
345 let path_str = path_ident_to_str(*path, item.ident, itr);
346 let item_str = match item.node {
347 item_const(*) => ~"const",
349 item_mod(*) => ~"mod",
350 item_foreign_mod(*) => ~"foreign mod",
352 item_enum(*) => ~"enum",
353 item_struct(*) => ~"struct",
354 item_trait(*) => ~"trait",
355 item_impl(*) => ~"impl",
356 item_mac(*) => ~"macro"
358 fmt!("%s %s (id=%?)", item_str, path_str, id)
360 Some(&node_foreign_item(item, abi, _, path)) => {
361 fmt!("foreign item %s with abi %? (id=%?)",
362 path_ident_to_str(*path, item.ident, itr), abi, id)
364 Some(&node_method(m, _, path)) => {
365 fmt!("method %s in %s (id=%?)",
366 *itr.get(m.ident), path_to_str(*path, itr), id)
368 Some(&node_trait_method(ref tm, _, path)) => {
369 let m = ast_util::trait_method_to_ty_method(&**tm);
370 fmt!("method %s in %s (id=%?)",
371 *itr.get(m.ident), path_to_str(*path, itr), id)
373 Some(&node_variant(ref variant, _, path)) => {
374 fmt!("variant %s in %s (id=%?)",
375 *itr.get(variant.node.name), path_to_str(*path, itr), id)
377 Some(&node_expr(expr)) => {
378 fmt!("expr %s (id=%?)", pprust::expr_to_str(expr, itr), id)
380 Some(&node_stmt(stmt)) => {
381 fmt!("stmt %s (id=%?)",
382 pprust::stmt_to_str(stmt, itr), id)
384 Some(&node_arg(_, _)) => { // add more info here
385 fmt!("arg (id=%?)", id)
387 Some(&node_local(_)) => { // add more info here
388 fmt!("local (id=%?)", id)
390 Some(&node_block(_)) => {
393 Some(&node_struct_ctor(*)) => {
399 pub fn node_item_query<Result>(items: map, id: node_id,
400 query: &fn(@item) -> Result,
401 error_msg: ~str) -> Result {
402 match items.find(&id) {
403 Some(&node_item(it, _)) => query(it),
404 _ => fail!(error_msg)
411 // indent-tabs-mode: nil
413 // buffer-file-coding-system: utf-8-unix