]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ast_map.rs
d2125cebb5e48cd6ee244cd55ee4bbdd0c5a166b
[rust.git] / src / libsyntax / ast_map.rs
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.
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;
14 use ast_util::{inlined_item_utils, stmt_id};
15 use ast_util;
16 use codemap;
17 use diagnostic::span_handler;
18 use parse::token::ident_interner;
19 use print::pprust;
20 use visit;
21
22 use core::hashmap::HashMap;
23
24 pub enum path_elt {
25     path_mod(ident),
26     path_name(ident)
27 }
28
29 impl cmp::Eq for path_elt {
30     fn eq(&self, other: &path_elt) -> bool {
31         match (*self) {
32             path_mod(e0a) => {
33                 match (*other) {
34                     path_mod(e0b) => e0a == e0b,
35                     _ => false
36                 }
37             }
38             path_name(e0a) => {
39                 match (*other) {
40                     path_name(e0b) => e0a == e0b,
41                     _ => false
42                 }
43             }
44         }
45     }
46     fn ne(&self, other: &path_elt) -> bool { !(*self).eq(other) }
47 }
48
49 pub type path = ~[path_elt];
50
51 pub fn path_to_str_with_sep(p: &[path_elt], sep: ~str, itr: @ident_interner)
52                          -> ~str {
53     let strs = do p.map |e| {
54         match *e {
55           path_mod(s) => copy *itr.get(s),
56           path_name(s) => copy *itr.get(s)
57         }
58     };
59     str::connect(strs, sep)
60 }
61
62 pub fn path_ident_to_str(p: path, i: ident, itr: @ident_interner) -> ~str {
63     if vec::is_empty(p) {
64         //FIXME /* FIXME (#2543) */ copy *i
65         copy *itr.get(i)
66     } else {
67         fmt!("%s::%s", path_to_str(p, itr), *itr.get(i))
68     }
69 }
70
71 pub fn path_to_str(p: &[path_elt], itr: @ident_interner) -> ~str {
72     path_to_str_with_sep(p, ~"::", itr)
73 }
74
75 pub fn path_elt_to_str(pe: path_elt, itr: @ident_interner) -> ~str {
76     match pe {
77         path_mod(s) => copy *itr.get(s),
78         path_name(s) => copy *itr.get(s)
79     }
80 }
81
82 pub enum ast_node {
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),
89     node_expr(@expr),
90     node_stmt(@stmt),
91     // Locals are numbered, because the alias analysis needs to know in which
92     // order they are introduced.
93     node_arg(arg, uint),
94     node_local(uint),
95     node_block(blk),
96     node_struct_ctor(@struct_def, @item, @path),
97 }
98
99 pub type map = @mut HashMap<node_id, ast_node>;
100
101 pub struct Ctx {
102     map: map,
103     path: path,
104     local_id: uint,
105     diag: @span_handler,
106 }
107
108 pub type vt = visit::vt<@mut Ctx>;
109
110 pub fn extend(cx: @mut Ctx, elt: ident) -> @path {
111     @(vec::append(copy cx.path, ~[path_name(elt)]))
112 }
113
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,
119         visit_fn: map_fn,
120         visit_local: map_local,
121         visit_arm: map_arm,
122         visit_block: map_block,
123         .. *visit::default_visitor()
124     });
125 }
126
127 pub fn map_crate(diag: @span_handler, c: @crate) -> map {
128     let cx = @mut Ctx {
129         map: @mut HashMap::new(),
130         path: ~[],
131         local_id: 0u,
132         diag: diag,
133     };
134     visit::visit_crate(c, cx, mk_ast_map_visitor());
135     cx.map
136 }
137
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
140 // the item itself.
141 pub fn map_decoded_item(diag: @span_handler,
142                         map: map,
143                         path: path,
144                         ii: &inlined_item) {
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).
151     let cx = @mut Ctx {
152         map: map,
153         path: copy path,
154         local_id: 0,
155         diag: diag,
156     };
157     let v = mk_ast_map_visitor();
158
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:
162     match *ii {
163       ii_item(*) => { /* fallthrough */ }
164       ii_foreign(i) => {
165         cx.map.insert(i.id, node_foreign_item(i,
166                                               AbiSet::Intrinsic(),
167                                               i.vis,    // Wrong but OK
168                                               @path));
169       }
170       ii_method(impl_did, m) => {
171         map_method(impl_did, @path, m, cx);
172       }
173     }
174
175     // visit the item / method contents and add those to the map:
176     ii.accept(cx, v);
177 }
178
179 pub fn map_fn(
180     fk: &visit::fn_kind,
181     decl: &fn_decl,
182     body: &blk,
183     sp: codemap::span,
184     id: node_id,
185     cx: @mut Ctx,
186     v: visit::vt<@mut Ctx>
187 ) {
188     for decl.inputs.each |a| {
189         cx.map.insert(a.id,
190                       node_arg(/* FIXME (#2543) */ copy *a, cx.local_id));
191         cx.local_id += 1u;
192     }
193     visit::visit_fn(fk, decl, body, sp, id, cx, v);
194 }
195
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);
199 }
200
201 pub fn number_pat(cx: @mut Ctx, pat: @pat) {
202     do ast_util::walk_pat(pat) |p| {
203         match p.node {
204           pat_ident(*) => {
205             cx.map.insert(p.id, node_local(cx.local_id));
206             cx.local_id += 1u;
207           }
208           _ => ()
209         }
210     };
211 }
212
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);
216 }
217
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);
221 }
222
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));
227     cx.local_id += 1u;
228 }
229
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));
233     match i.node {
234         item_impl(_, _, _, ref ms) => {
235             let impl_did = ast_util::local_def(i.id);
236             for ms.each |m| {
237                 map_method(impl_did, extend(cx, i.ident), *m, cx);
238             }
239         }
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)));
245             }
246         }
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 {
251                     public => public,
252                     private => private,
253                     inherited => i.vis
254                 };
255
256                 cx.map.insert(nitem.id,
257                     node_foreign_item(
258                         *nitem,
259                         nm.abis,
260                         visibility,
261                         // FIXME (#2543)
262                         if nm.sort == ast::named {
263                             extend(cx, i.ident)
264                         } else {
265                             // Anonymous extern mods go in the parent scope
266                             @copy cx.path
267                         }
268                     )
269                 );
270             }
271         }
272         item_struct(struct_def, _) => {
273             map_struct_def(
274                 struct_def,
275                 node_item(i, item_path),
276                 i.ident,
277                 cx,
278                 v
279             );
280         }
281         item_trait(_, ref traits, ref methods) => {
282             for traits.each |p| {
283                 cx.map.insert(p.ref_id, node_item(i, item_path));
284             }
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);
288                 cx.map.insert(
289                     id,
290                     node_trait_method(@copy *tm, d_id, item_path)
291                 );
292             }
293         }
294         _ => ()
295     }
296     match i.node {
297         item_mod(_) | item_foreign_mod(_) => {
298             cx.path.push(path_mod(i.ident));
299         }
300         _ => cx.path.push(path_name(i.ident))
301     }
302     visit::visit_item(i, cx, v);
303     cx.path.pop();
304 }
305
306 pub fn map_struct_def(
307     struct_def: @ast::struct_def,
308     parent_node: ast_node,
309     ident: ast::ident,
310     cx: @mut Ctx,
311     _v: visit::vt<@mut Ctx>
312 ) {
313     let p = extend(cx, ident);
314     // If this is a tuple-like struct, register the constructor.
315     match struct_def.ctor_id {
316         None => {}
317         Some(ctor_id) => {
318             match parent_node {
319                 node_item(item, _) => {
320                     cx.map.insert(ctor_id,
321                                   node_struct_ctor(struct_def, item, p));
322                 }
323                 _ => fail!(~"struct def parent wasn't an item")
324             }
325         }
326     }
327 }
328
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);
332 }
333
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);
337 }
338
339 pub fn node_id_to_str(map: map, id: node_id, itr: @ident_interner) -> ~str {
340     match map.find(&id) {
341       None => {
342         fmt!("unknown node (id=%d)", id)
343       }
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",
348           item_fn(*) => ~"fn",
349           item_mod(*) => ~"mod",
350           item_foreign_mod(*) => ~"foreign mod",
351           item_ty(*) => ~"ty",
352           item_enum(*) => ~"enum",
353           item_struct(*) => ~"struct",
354           item_trait(*) => ~"trait",
355           item_impl(*) => ~"impl",
356           item_mac(*) => ~"macro"
357         };
358         fmt!("%s %s (id=%?)", item_str, path_str, id)
359       }
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)
363       }
364       Some(&node_method(m, _, path)) => {
365         fmt!("method %s in %s (id=%?)",
366              *itr.get(m.ident), path_to_str(*path, itr), id)
367       }
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)
372       }
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)
376       }
377       Some(&node_expr(expr)) => {
378         fmt!("expr %s (id=%?)", pprust::expr_to_str(expr, itr), id)
379       }
380       Some(&node_stmt(stmt)) => {
381         fmt!("stmt %s (id=%?)",
382              pprust::stmt_to_str(stmt, itr), id)
383       }
384       Some(&node_arg(_, _)) => { // add more info here
385         fmt!("arg (id=%?)", id)
386       }
387       Some(&node_local(_)) => { // add more info here
388         fmt!("local (id=%?)", id)
389       }
390       Some(&node_block(_)) => {
391         fmt!("block")
392       }
393       Some(&node_struct_ctor(*)) => {
394         fmt!("struct_ctor")
395       }
396     }
397 }
398
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)
405     }
406 }
407
408 // Local Variables:
409 // mode: rust
410 // fill-column: 78;
411 // indent-tabs-mode: nil
412 // c-basic-offset: 4
413 // buffer-file-coding-system: utf-8-unix
414 // End: