about summary refs log tree commit diff
path: root/src/libsyntax/ast_map.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsyntax/ast_map.rs')
-rw-r--r--src/libsyntax/ast_map.rs309
1 files changed, 309 insertions, 0 deletions
diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs
new file mode 100644
index 00000000000..fbea5026b3c
--- /dev/null
+++ b/src/libsyntax/ast_map.rs
@@ -0,0 +1,309 @@
+import std::map;
+import std::map::hashmap;
+import ast::*;
+import print::pprust;
+import ast_util::path_to_ident;
+import ast_util::inlined_item_methods;
+import diagnostic::span_handler;
+
+enum path_elt { path_mod(str), path_name(str) }
+type path = [path_elt];
+
+fn path_to_str_with_sep(p: path, sep: str) -> str {
+    let strs = vec::map(p) {|e|
+        alt e {
+          path_mod(s) { s }
+          path_name(s) { s }
+        }
+    };
+    str::connect(strs, sep)
+}
+
+fn path_ident_to_str(p: path, i: ident) -> str {
+    if vec::is_empty(p) {
+        i
+    } else {
+        #fmt["%s::%s", path_to_str(p), i]
+    }
+}
+
+fn path_to_str(p: path) -> str {
+    path_to_str_with_sep(p, "::")
+}
+
+enum ast_node {
+    node_item(@item, @path),
+    node_native_item(@native_item, native_abi, @path),
+    node_method(@method, def_id /* impl did */, @path /* path to the impl */),
+    node_variant(variant, @item, @path),
+    node_expr(@expr),
+    node_export(@view_path, @path),
+    // Locals are numbered, because the alias analysis needs to know in which
+    // order they are introduced.
+    node_arg(arg, uint),
+    node_local(uint),
+    // Constructor for either a resource or a class
+    node_ctor(ident, [ty_param], a_ctor, @path),
+    // Destructor for a class
+    node_dtor([ty_param], @class_dtor, def_id, @path),
+    node_block(blk),
+}
+
+enum a_ctor {
+  res_ctor(fn_decl, node_id, codemap::span),
+  class_ctor(@class_ctor, def_id /* ID for parent class */),
+}
+
+type map = std::map::hashmap<node_id, ast_node>;
+type ctx = {map: map, mut path: path,
+            mut local_id: uint, diag: span_handler};
+type vt = visit::vt<ctx>;
+
+fn extend(cx: ctx, elt: str) -> @path {
+    @(cx.path + [path_name(elt)])
+}
+
+fn mk_ast_map_visitor() -> vt {
+    ret visit::mk_vt(@{
+        visit_item: map_item,
+        visit_expr: map_expr,
+        visit_fn: map_fn,
+        visit_local: map_local,
+        visit_arm: map_arm,
+        visit_view_item: map_view_item,
+        visit_block: map_block
+        with *visit::default_visitor()
+    });
+}
+
+fn map_crate(diag: span_handler, c: crate) -> map {
+    let cx = {map: std::map::int_hash(),
+              mut path: [],
+              mut local_id: 0u,
+              diag: diag};
+    visit::visit_crate(c, cx, mk_ast_map_visitor());
+    ret cx.map;
+}
+
+// Used for items loaded from external crate that are being inlined into this
+// crate.  The `path` should be the path to the item but should not include
+// the item itself.
+fn map_decoded_item(diag: span_handler,
+                    map: map, path: path, ii: inlined_item) {
+    // I believe it is ok for the local IDs of inlined items from other crates
+    // to overlap with the local ids from this crate, so just generate the ids
+    // starting from 0.  (In particular, I think these ids are only used in
+    // alias analysis, which we will not be running on the inlined items, and
+    // even if we did I think it only needs an ordering between local
+    // variables that are simultaneously in scope).
+    let cx = {map: map,
+              mut path: path,
+              mut local_id: 0u,
+              diag: diag};
+    let v = mk_ast_map_visitor();
+
+    // methods get added to the AST map when their impl is visited.  Since we
+    // don't decode and instantiate the impl, but just the method, we have to
+    // add it to the table now:
+    alt ii {
+      ii_item(_) | ii_ctor(_,_,_,_) { /* fallthrough */ }
+      ii_native(i) {
+        cx.map.insert(i.id, node_native_item(i, native_abi_rust_intrinsic,
+                                             @path));
+      }
+      ii_method(impl_did, m) {
+        map_method(impl_did, @path, m, cx);
+      }
+    }
+
+    // visit the item / method contents and add those to the map:
+    ii.accept(cx, v);
+}
+
+fn map_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
+          sp: codemap::span, id: node_id, cx: ctx, v: vt) {
+    for decl.inputs.each {|a|
+        cx.map.insert(a.id, node_arg(a, cx.local_id));
+        cx.local_id += 1u;
+    }
+    alt fk {
+      visit::fk_ctor(nm, tps, self_id, parent_id) {
+          let ct = @{node: {id: id, self_id: self_id,
+                           dec: decl, body: body},
+                    span: sp};
+          cx.map.insert(id, node_ctor(nm, tps, class_ctor(ct, parent_id),
+                                      @cx.path));
+       }
+      visit::fk_dtor(tps, self_id, parent_id) {
+          let dt = @{node: {id: id, self_id: self_id, body: body},
+                    span: sp};
+          cx.map.insert(id, node_dtor(tps, dt, parent_id, @cx.path));
+       }
+
+       _ {}
+    }
+    visit::visit_fn(fk, decl, body, sp, id, cx, v);
+}
+
+fn map_block(b: blk, cx: ctx, v: vt) {
+    cx.map.insert(b.node.id, node_block(b));
+    visit::visit_block(b, cx, v);
+}
+
+fn number_pat(cx: ctx, pat: @pat) {
+    ast_util::walk_pat(pat) {|p|
+        alt p.node {
+          pat_ident(_, _) {
+            cx.map.insert(p.id, node_local(cx.local_id));
+            cx.local_id += 1u;
+          }
+          _ {}
+        }
+    };
+}
+
+fn map_local(loc: @local, cx: ctx, v: vt) {
+    number_pat(cx, loc.node.pat);
+    visit::visit_local(loc, cx, v);
+}
+
+fn map_arm(arm: arm, cx: ctx, v: vt) {
+    number_pat(cx, arm.pats[0]);
+    visit::visit_arm(arm, cx, v);
+}
+
+fn map_method(impl_did: def_id, impl_path: @path,
+              m: @method, cx: ctx) {
+    cx.map.insert(m.id, node_method(m, impl_did, impl_path));
+    cx.map.insert(m.self_id, node_local(cx.local_id));
+    cx.local_id += 1u;
+}
+
+fn map_item(i: @item, cx: ctx, v: vt) {
+    let item_path = @cx.path;
+    cx.map.insert(i.id, node_item(i, item_path));
+    alt i.node {
+      item_impl(_, _, _, _, ms) {
+        let impl_did = ast_util::local_def(i.id);
+        for ms.each {|m|
+            map_method(impl_did, extend(cx, i.ident), m, cx);
+        }
+      }
+      item_res(decl, tps, _, dtor_id, ctor_id, _) {
+        cx.map.insert(ctor_id, node_ctor(i.ident, tps,
+                                         res_ctor(decl, ctor_id, i.span),
+                                         item_path));
+        cx.map.insert(dtor_id, node_item(i, item_path));
+      }
+      item_enum(vs, _, _) {
+        for vs.each {|v|
+            cx.map.insert(v.node.id, node_variant(
+                v, i, extend(cx, i.ident)));
+        }
+      }
+      item_native_mod(nm) {
+        let abi = alt attr::native_abi(i.attrs) {
+          either::left(msg) { cx.diag.span_fatal(i.span, msg); }
+          either::right(abi) { abi }
+        };
+        for nm.items.each {|nitem|
+            cx.map.insert(nitem.id, node_native_item(nitem, abi, @cx.path));
+        }
+      }
+      item_class(tps, ifces, items, ctor, dtor, _) {
+          let (_, ms) = ast_util::split_class_items(items);
+          // Map iface refs to their parent classes. This is
+          // so we can find the self_ty
+          vec::iter(ifces) {|p| cx.map.insert(p.id,
+                                  node_item(i, item_path)); };
+          let d_id = ast_util::local_def(i.id);
+          let p = extend(cx, i.ident);
+           // only need to handle methods
+          vec::iter(ms) {|m| map_method(d_id, p, m, cx); }
+      }
+      _ { }
+    }
+    alt i.node {
+      item_mod(_) | item_native_mod(_) {
+        cx.path += [path_mod(i.ident)];
+      }
+      _ { cx.path += [path_name(i.ident)]; }
+    }
+    visit::visit_item(i, cx, v);
+    vec::pop(cx.path);
+}
+
+fn map_view_item(vi: @view_item, cx: ctx, _v: vt) {
+    alt vi.node {
+      view_item_export(vps) {
+        for vps.each {|vp|
+            let (id, name) = alt vp.node {
+              view_path_simple(nm, _, id) { (id, nm) }
+              view_path_glob(pth, id) | view_path_list(pth, _, id) {
+                (id, path_to_ident(pth))
+              }
+            };
+            cx.map.insert(id, node_export(vp, extend(cx, name)));
+        }
+      }
+      _ {}
+    }
+}
+
+fn map_expr(ex: @expr, cx: ctx, v: vt) {
+    cx.map.insert(ex.id, node_expr(ex));
+    visit::visit_expr(ex, cx, v);
+}
+
+fn node_id_to_str(map: map, id: node_id) -> str {
+    alt map.find(id) {
+      none {
+        #fmt["unknown node (id=%d)", id]
+      }
+      some(node_item(item, path)) {
+        #fmt["item %s (id=%?)", path_ident_to_str(*path, item.ident), id]
+      }
+      some(node_native_item(item, abi, path)) {
+        #fmt["native item %s with abi %? (id=%?)",
+             path_ident_to_str(*path, item.ident), abi, id]
+      }
+      some(node_method(m, impl_did, path)) {
+        #fmt["method %s in %s (id=%?)",
+             m.ident, path_to_str(*path), id]
+      }
+      some(node_variant(variant, def_id, path)) {
+        #fmt["variant %s in %s (id=%?)",
+             variant.node.name, path_to_str(*path), id]
+      }
+      some(node_expr(expr)) {
+        #fmt["expr %s (id=%?)",
+             pprust::expr_to_str(expr), id]
+      }
+      some(node_export(_, path)) {
+        #fmt["export %s (id=%?)", // FIXME: add more info here
+             path_to_str(*path), id]
+      }
+      some(node_arg(_, _)) { // FIXME: add more info here
+        #fmt["arg (id=%?)", id]
+      }
+      some(node_local(_)) { // FIXME: add more info here
+        #fmt["local (id=%?)", id]
+      }
+      some(node_ctor(*)) { // FIXME: add more info here
+        #fmt["node_ctor (id=%?)", id]
+      }
+      some(node_dtor(*)) { // FIXME: add more info here
+        #fmt["node_dtor (id=%?)", id]
+      }
+      some(node_block(_)) {
+        #fmt["block"]
+      }
+    }
+}
+// Local Variables:
+// mode: rust
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End: