ae26b775b4
Module names no longer clash with type and value names. The tokenizer/parser still needs to be taught to be more careful in identifying keywords, so that we can use 'str' and 'vec' and so as module names.
959 lines
31 KiB
Rust
959 lines
31 KiB
Rust
import front::ast;
|
|
import front::ast::ident;
|
|
import front::ast::def;
|
|
import front::ast::def_id;
|
|
import front::ast::ann;
|
|
import front::creader;
|
|
import driver::session::session;
|
|
import util::common::new_def_hash;
|
|
import util::common::new_int_hash;
|
|
import util::common::new_uint_hash;
|
|
import util::common::new_str_hash;
|
|
import util::common::span;
|
|
import util::typestate_ann::ts_ann;
|
|
import std::map::hashmap;
|
|
import std::list::list;
|
|
import std::list::nil;
|
|
import std::list::cons;
|
|
import std::option;
|
|
import std::option::some;
|
|
import std::option::none;
|
|
import std::_str;
|
|
import std::_vec;
|
|
|
|
// Resolving happens in two passes. The first pass collects defids of all
|
|
// (internal) imports and modules, so that they can be looked up when needed,
|
|
// and then uses this information to resolve the imports. The second pass
|
|
// locates all names (in expressions, types, and alt patterns) and resolves
|
|
// them, storing the resulting def in the AST nodes.
|
|
|
|
// This module internally uses -1 as a def_id for the top_level module in a
|
|
// crate. The parser doesn't assign a def_id to this module.
|
|
// (FIXME See https://github.com/graydon/rust/issues/358 for the reason this
|
|
// isn't a const.)
|
|
|
|
tag scope {
|
|
scope_crate(@ast::crate);
|
|
scope_item(@ast::item);
|
|
scope_native_item(@ast::native_item);
|
|
scope_loop(@ast::decl); // there's only 1 decl per loop.
|
|
scope_block(ast::block);
|
|
scope_arm(ast::arm);
|
|
}
|
|
|
|
tag import_state {
|
|
todo(@ast::view_item, list[scope]);
|
|
resolving(span);
|
|
resolved(option::t[def] /* value */,
|
|
option::t[def] /* type */,
|
|
option::t[def] /* module */);
|
|
}
|
|
|
|
type ext_hash = hashmap[tup(def_id,str,namespace),def];
|
|
fn new_ext_hash() -> ext_hash {
|
|
fn hash(&tup(def_id,str,namespace) v) -> uint {
|
|
ret _str::hash(v._1) + util::common::hash_def(v._0) + (alt (v._2) {
|
|
case (ns_value) { 1u }
|
|
case (ns_type) { 2u }
|
|
case (ns_module) { 3u }
|
|
});
|
|
}
|
|
fn eq(&tup(def_id,str,namespace) v1,
|
|
&tup(def_id,str,namespace) v2) -> bool {
|
|
ret util::common::def_eq(v1._0, v2._0) &&
|
|
_str::eq(v1._1, v2._1) &&
|
|
v1._2 == v2._2;
|
|
}
|
|
ret std::map::mk_hashmap[tup(def_id,str,namespace),def](hash, eq);
|
|
}
|
|
|
|
tag mod_index_entry {
|
|
mie_view_item(@ast::view_item);
|
|
mie_item(@ast::item);
|
|
mie_tag_variant(@ast::item /* tag item */, uint /* variant index */);
|
|
}
|
|
type mod_index = hashmap[ident,list[mod_index_entry]];
|
|
type indexed_mod = rec(ast::_mod m, mod_index index);
|
|
|
|
tag nmod_index_entry {
|
|
nmie_view_item(@ast::view_item);
|
|
nmie_item(@ast::native_item);
|
|
}
|
|
type nmod_index = hashmap[ident,list[nmod_index_entry]];
|
|
type indexed_nmod = rec(ast::native_mod m, nmod_index index);
|
|
|
|
type def_map = hashmap[uint,def];
|
|
|
|
type env = rec(def_map def_map,
|
|
hashmap[ast::def_num,import_state] imports,
|
|
hashmap[ast::def_num,@indexed_mod] mod_map,
|
|
hashmap[ast::def_num,@indexed_nmod] nmod_map,
|
|
hashmap[def_id,vec[ident]] ext_map,
|
|
ext_hash ext_cache,
|
|
session sess);
|
|
|
|
// Used to distinguish between lookups from outside and from inside modules,
|
|
// since export restrictions should only be applied for the former.
|
|
tag dir { inside; outside; }
|
|
|
|
tag namespace {
|
|
ns_value;
|
|
ns_type;
|
|
ns_module;
|
|
}
|
|
|
|
fn resolve_crate(session sess, @ast::crate crate) -> def_map {
|
|
auto e = @rec(def_map = new_uint_hash[def](),
|
|
imports = new_int_hash[import_state](),
|
|
mod_map = new_int_hash[@indexed_mod](),
|
|
nmod_map = new_int_hash[@indexed_nmod](),
|
|
ext_map = new_def_hash[vec[ident]](),
|
|
ext_cache = new_ext_hash(),
|
|
sess = sess);
|
|
map_crate(e, *crate);
|
|
resolve_imports(*e);
|
|
resolve_names(e, *crate);
|
|
ret e.def_map;
|
|
}
|
|
|
|
// Locate all modules and imports and index them, so that the next passes can
|
|
// resolve through them.
|
|
|
|
fn map_crate(&@env e, &ast::crate c) {
|
|
auto cell = @mutable nil[scope];
|
|
auto v = rec(visit_crate_pre = bind push_env_for_crate(cell, _),
|
|
visit_crate_post = bind pop_env_for_crate(cell, _),
|
|
visit_view_item_pre = bind visit_view_item(e, cell, _),
|
|
visit_item_pre = bind visit_item(e, cell, _),
|
|
visit_item_post = bind pop_env_for_item(cell, _)
|
|
with walk::default_visitor());
|
|
// Register the top-level mod
|
|
e.mod_map.insert(-1, @rec(m=c.node.module,
|
|
index=index_mod(c.node.module)));
|
|
walk::walk_crate(v, c);
|
|
|
|
fn visit_view_item(@env e, @mutable list[scope] sc, &@ast::view_item i) {
|
|
alt (i.node) {
|
|
case (ast::view_item_import(_, ?ids, ?defid)) {
|
|
e.imports.insert(defid._1, todo(i, *sc));
|
|
}
|
|
case (_) {}
|
|
}
|
|
}
|
|
fn visit_item(@env e, @mutable list[scope] sc, &@ast::item i) {
|
|
push_env_for_item(sc, i);
|
|
alt (i.node) {
|
|
case (ast::item_mod(_, ?md, ?defid)) {
|
|
auto index = index_mod(md);
|
|
e.mod_map.insert(defid._1, @rec(m=md, index=index));
|
|
}
|
|
case (ast::item_native_mod(_, ?nmd, ?defid)) {
|
|
auto index = index_nmod(nmd);
|
|
e.nmod_map.insert(defid._1, @rec(m=nmd, index=index));
|
|
}
|
|
case (_) {}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn resolve_imports(&env e) {
|
|
for each (@tup(ast::def_num, import_state) it in e.imports.items()) {
|
|
alt (it._1) {
|
|
case (todo(?item, ?sc)) {
|
|
resolve_import(e, item, sc);
|
|
}
|
|
case (resolved(_, _, _)) {}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn resolve_names(&@env e, &ast::crate c) {
|
|
auto cell = @mutable nil[scope];
|
|
auto v = rec(visit_crate_pre = bind push_env_for_crate(cell, _),
|
|
visit_crate_post = bind pop_env_for_crate(cell, _),
|
|
visit_item_pre = bind push_env_for_item(cell, _),
|
|
visit_item_post = bind pop_env_for_item(cell, _),
|
|
visit_method_pre = bind push_env_for_method(cell, _),
|
|
visit_method_post = bind pop_env_for_method(cell, _),
|
|
visit_native_item_pre = bind push_env_for_n_item(cell, _),
|
|
visit_native_item_post = bind pop_env_for_n_item(cell, _),
|
|
visit_block_pre = bind push_env_for_block(cell, _),
|
|
visit_block_post = bind pop_env_for_block(cell, _),
|
|
visit_arm_pre = bind walk_arm(e, cell, _),
|
|
visit_arm_post = bind pop_env_for_arm(cell, _),
|
|
visit_expr_pre = bind walk_expr(e, cell, _),
|
|
visit_expr_post = bind pop_env_for_expr(cell, _),
|
|
visit_ty_pre = bind walk_ty(e, cell, _)
|
|
with walk::default_visitor());
|
|
walk::walk_crate(v, c);
|
|
|
|
fn walk_expr(@env e, @mutable list[scope] sc, &@ast::expr exp) {
|
|
push_env_for_expr(sc, exp);
|
|
alt (exp.node) {
|
|
case (ast::expr_path(?p, ?a)) {
|
|
auto df = lookup_path_strict(*e, *sc, exp.span, p.node.idents,
|
|
ns_value);
|
|
e.def_map.insert(ast::ann_tag(a), df);
|
|
}
|
|
case (_) {}
|
|
}
|
|
}
|
|
fn walk_ty(@env e, @mutable list[scope] sc, &@ast::ty t) {
|
|
alt (t.node) {
|
|
case (ast::ty_path(?p, ?a)) {
|
|
auto new_def = lookup_path_strict(*e, *sc, t.span,
|
|
p.node.idents, ns_type);
|
|
e.def_map.insert(ast::ann_tag(a), new_def);
|
|
}
|
|
case (_) {}
|
|
}
|
|
}
|
|
fn walk_arm(@env e, @mutable list[scope] sc, &ast::arm a) {
|
|
walk_pat(*e, *sc, a.pat);
|
|
push_env_for_arm(sc, a);
|
|
}
|
|
fn walk_pat(&env e, &list[scope] sc, &@ast::pat pat) {
|
|
alt (pat.node) {
|
|
case (ast::pat_tag(?p, ?children, ?a)) {
|
|
auto fnd = lookup_path_strict(e, sc, p.span, p.node.idents,
|
|
ns_value);
|
|
alt (fnd) {
|
|
case (ast::def_variant(?did, ?vid)) {
|
|
e.def_map.insert(ast::ann_tag(a), fnd);
|
|
}
|
|
case (_) {
|
|
e.sess.span_err(p.span, "not a tag variant: " +
|
|
_str::connect(p.node.idents, "::"));
|
|
fail;
|
|
}
|
|
}
|
|
for (@ast::pat child in children) {
|
|
walk_pat(e, sc, child);
|
|
}
|
|
}
|
|
case (_) {}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Helpers for tracking scope during a walk
|
|
|
|
fn push_env_for_crate(@mutable list[scope] sc, &ast::crate c) {
|
|
*sc = cons[scope](scope_crate(@c), @*sc);
|
|
}
|
|
fn pop_env_for_crate(@mutable list[scope] sc, &ast::crate c) {
|
|
*sc = std::list::cdr(*sc);
|
|
}
|
|
|
|
fn push_env_for_item(@mutable list[scope] sc, &@ast::item i) {
|
|
*sc = cons[scope](scope_item(i), @*sc);
|
|
}
|
|
fn pop_env_for_item(@mutable list[scope] sc, &@ast::item i) {
|
|
*sc = std::list::cdr(*sc);
|
|
}
|
|
|
|
fn push_env_for_method(@mutable list[scope] sc, &@ast::method m) {
|
|
let vec[ast::ty_param] tp = vec();
|
|
let @ast::item i = @rec(node=ast::item_fn(m.node.ident,
|
|
m.node.meth,
|
|
tp,
|
|
m.node.id,
|
|
m.node.ann),
|
|
span=m.span);
|
|
*sc = cons[scope](scope_item(i), @*sc);
|
|
}
|
|
fn pop_env_for_method(@mutable list[scope] sc, &@ast::method m) {
|
|
*sc = std::list::cdr(*sc);
|
|
}
|
|
|
|
fn push_env_for_n_item(@mutable list[scope] sc, &@ast::native_item i) {
|
|
*sc = cons[scope](scope_native_item(i), @*sc);
|
|
}
|
|
fn pop_env_for_n_item(@mutable list[scope] sc, &@ast::native_item i) {
|
|
*sc = std::list::cdr(*sc);
|
|
}
|
|
|
|
fn push_env_for_block(@mutable list[scope] sc, &ast::block b) {
|
|
*sc = cons[scope](scope_block(b), @*sc);
|
|
}
|
|
fn pop_env_for_block(@mutable list[scope] sc, &ast::block b) {
|
|
*sc = std::list::cdr(*sc);
|
|
}
|
|
|
|
fn push_env_for_expr(@mutable list[scope] sc, &@ast::expr x) {
|
|
alt (x.node) {
|
|
case (ast::expr_for(?d, _, _, _)) {
|
|
*sc = cons[scope](scope_loop(d), @*sc);
|
|
}
|
|
case (ast::expr_for_each(?d, _, _, _)) {
|
|
*sc = cons[scope](scope_loop(d), @*sc);
|
|
}
|
|
case (_) {}
|
|
}
|
|
}
|
|
fn pop_env_for_expr(@mutable list[scope] sc, &@ast::expr x) {
|
|
alt (x.node) {
|
|
case (ast::expr_for(?d, _, _, _)) {
|
|
*sc = std::list::cdr(*sc);
|
|
}
|
|
case (ast::expr_for_each(?d, _, _, _)) {
|
|
*sc = std::list::cdr(*sc);
|
|
}
|
|
case (_) {}
|
|
}
|
|
}
|
|
|
|
fn push_env_for_arm(@mutable list[scope] sc, &ast::arm p) {
|
|
*sc = cons[scope](scope_arm(p), @*sc);
|
|
}
|
|
fn pop_env_for_arm(@mutable list[scope] sc, &ast::arm p) {
|
|
*sc = std::list::cdr(*sc);
|
|
}
|
|
|
|
// Import resolution
|
|
|
|
fn resolve_import(&env e, &@ast::view_item it, &list[scope] sc) {
|
|
auto defid; auto ids;
|
|
alt (it.node) {
|
|
case (ast::view_item_import(_, ?_ids, ?_defid)) {
|
|
defid = _defid; ids = _ids;
|
|
}
|
|
}
|
|
e.imports.insert(defid._1, resolving(it.span));
|
|
|
|
auto n_idents = _vec::len(ids);
|
|
auto end_id = ids.(n_idents - 1u);
|
|
|
|
if (n_idents == 1u) {
|
|
register(e, defid, it.span, end_id,
|
|
lookup_in_scope(e, sc, it.span, end_id, ns_value),
|
|
lookup_in_scope(e, sc, it.span, end_id, ns_type),
|
|
lookup_in_scope(e, sc, it.span, end_id, ns_module));
|
|
} else {
|
|
auto dcur = lookup_in_scope_strict(e, sc, it.span, ids.(0),
|
|
ns_module);
|
|
auto i = 1u;
|
|
while (true) {
|
|
if (i == n_idents - 1u) {
|
|
register(e, defid, it.span, end_id,
|
|
lookup_in_mod(e, dcur, end_id, ns_value, outside),
|
|
lookup_in_mod(e, dcur, end_id, ns_type, outside),
|
|
lookup_in_mod(e, dcur, end_id, ns_module, outside));
|
|
break;
|
|
} else {
|
|
dcur = lookup_in_mod_strict(e, dcur, it.span, ids.(i),
|
|
ns_module, outside);
|
|
i += 1u;
|
|
}
|
|
}
|
|
}
|
|
|
|
fn register(&env e, def_id defid, &span sp, &ident id,
|
|
&option::t[def] val, &option::t[def] typ,
|
|
&option::t[def] md) {
|
|
if (option::is_none(val) && option::is_none(typ) &&
|
|
option::is_none(md)) {
|
|
unresolved(e, sp, id, "import");
|
|
}
|
|
e.imports.insert(defid._1, resolved(val, typ, md));
|
|
}
|
|
}
|
|
|
|
// Utilities
|
|
|
|
fn ns_name(namespace ns) -> str {
|
|
alt (ns) {
|
|
case (ns_type) { ret "typename"; }
|
|
case (ns_value) { ret "name"; }
|
|
case (ns_module) { ret "modulename"; }
|
|
}
|
|
}
|
|
|
|
fn unresolved(&env e, &span sp, &ident id, &str kind) {
|
|
e.sess.span_err(sp, "unresolved " + kind + ": " + id);
|
|
}
|
|
|
|
// Lookup helpers
|
|
|
|
fn lookup_path_strict(&env e, &list[scope] sc, &span sp, vec[ident] idents,
|
|
namespace ns) -> def {
|
|
auto n_idents = _vec::len(idents);
|
|
auto headns = if (n_idents == 1u) { ns } else { ns_module };
|
|
auto dcur = lookup_in_scope_strict(e, sc, sp, idents.(0), headns);
|
|
auto i = 1u;
|
|
while (i < n_idents) {
|
|
auto curns = if (n_idents == i + 1u) { ns } else { ns_module };
|
|
dcur = lookup_in_mod_strict(e, dcur, sp, idents.(i), curns, outside);
|
|
i += 1u;
|
|
}
|
|
ret dcur;
|
|
}
|
|
|
|
fn lookup_in_scope_strict(&env e, list[scope] sc, &span sp, &ident id,
|
|
namespace ns) -> def {
|
|
alt (lookup_in_scope(e, sc, sp, id, ns)) {
|
|
case (none[def]) {
|
|
unresolved(e, sp, id, ns_name(ns));
|
|
fail;
|
|
}
|
|
case (some[def](?d)) {
|
|
ret d;
|
|
}
|
|
}
|
|
}
|
|
|
|
fn scope_is_fn(&scope sc) -> bool {
|
|
ret alt (sc) {
|
|
case (scope_item(?it)) {
|
|
alt (it.node) {
|
|
case (ast::item_fn(_, _, _, _, _)) { true }
|
|
case (_) { false }
|
|
}
|
|
}
|
|
case (scope_native_item(_)) { true }
|
|
case (_) { false }
|
|
};
|
|
}
|
|
|
|
fn def_is_local(&def d) -> bool {
|
|
ret alt (d) {
|
|
case (ast::def_arg(_)) { true }
|
|
case (ast::def_local(_)) { true }
|
|
case (ast::def_binding(_)) { true }
|
|
case (_) { false }
|
|
};
|
|
}
|
|
fn def_is_obj_field(&def d) -> bool {
|
|
ret alt (d) {
|
|
case (ast::def_obj_field(_)) { true }
|
|
case (_) { false }
|
|
};
|
|
}
|
|
|
|
fn lookup_in_scope(&env e, list[scope] sc, &span sp, &ident id, namespace ns)
|
|
-> option::t[def] {
|
|
fn in_scope(&env e, &ident id, &scope s, namespace ns)
|
|
-> option::t[def] {
|
|
alt (s) {
|
|
case (scope_crate(?c)) {
|
|
auto defid = tup(ast::local_crate, -1);
|
|
ret lookup_in_regular_mod(e, defid, id, ns, inside);
|
|
}
|
|
case (scope_item(?it)) {
|
|
alt (it.node) {
|
|
case (ast::item_fn(_, ?f, ?ty_params, _, _)) {
|
|
ret lookup_in_fn(id, f.decl, ty_params, ns);
|
|
}
|
|
case (ast::item_obj(_, ?ob, ?ty_params, _, _)) {
|
|
ret lookup_in_obj(id, ob, ty_params, ns);
|
|
}
|
|
case (ast::item_tag(_, _, ?ty_params, _, _)) {
|
|
if (ns == ns_type) {
|
|
ret lookup_in_ty_params(id, ty_params);
|
|
}
|
|
}
|
|
case (ast::item_mod(_, _, ?defid)) {
|
|
ret lookup_in_regular_mod(e, defid, id, ns, inside);
|
|
}
|
|
case (ast::item_native_mod(_, ?m, ?defid)) {
|
|
ret lookup_in_native_mod(e, defid, id, ns);
|
|
}
|
|
case (ast::item_ty(_, _, ?ty_params, _, _)) {
|
|
if (ns == ns_type) {
|
|
ret lookup_in_ty_params(id, ty_params);
|
|
}
|
|
}
|
|
case (_) {}
|
|
}
|
|
}
|
|
case (scope_native_item(?it)) {
|
|
alt (it.node) {
|
|
case (ast::native_item_fn(_, _, ?decl, ?ty_params, _, _)){
|
|
ret lookup_in_fn(id, decl, ty_params, ns);
|
|
}
|
|
}
|
|
}
|
|
case (scope_loop(?d)) {
|
|
if (ns == ns_value) {
|
|
alt (d.node) {
|
|
case (ast::decl_local(?local)) {
|
|
if (_str::eq(local.ident, id)) {
|
|
ret some(ast::def_local(local.id));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
case (scope_block(?b)) {
|
|
ret lookup_in_block(id, b.node, ns);
|
|
}
|
|
case (scope_arm(?a)) {
|
|
if (ns == ns_value) {
|
|
ret lookup_in_pat(id, *a.pat);
|
|
}
|
|
}
|
|
}
|
|
ret none[def];
|
|
}
|
|
|
|
auto left_fn = false;
|
|
// Used to determine whether obj fields are in scope
|
|
auto left_fn_level2 = false;
|
|
while (true) {
|
|
alt (sc) {
|
|
case (nil[scope]) {
|
|
ret none[def];
|
|
}
|
|
case (cons[scope](?hd, ?tl)) {
|
|
auto fnd = in_scope(e, id, hd, ns);
|
|
if (!option::is_none(fnd)) {
|
|
auto df = option::get(fnd);
|
|
if ((left_fn && def_is_local(df)) ||
|
|
(left_fn_level2 && def_is_obj_field(df))) {
|
|
e.sess.span_err
|
|
(sp, "attempted dynamic environment-capture");
|
|
}
|
|
ret fnd;
|
|
}
|
|
if (left_fn) { left_fn_level2 = true; }
|
|
if (ns == ns_value && !left_fn) {
|
|
left_fn = scope_is_fn(hd);
|
|
}
|
|
sc = *tl;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn lookup_in_ty_params(&ident id, &vec[ast::ty_param] ty_params)
|
|
-> option::t[def] {
|
|
auto i = 0u;
|
|
for (ast::ty_param tp in ty_params) {
|
|
if (_str::eq(tp, id)) {
|
|
ret some(ast::def_ty_arg(i));
|
|
}
|
|
i += 1u;
|
|
}
|
|
ret none[def];
|
|
}
|
|
|
|
fn lookup_in_pat(&ident id, &ast::pat pat) -> option::t[def] {
|
|
alt (pat.node) {
|
|
case (ast::pat_bind(?name, ?defid, _)) {
|
|
if (_str::eq(name, id)) { ret some(ast::def_binding(defid)); }
|
|
}
|
|
case (ast::pat_wild(_)) {}
|
|
case (ast::pat_lit(_, _)) {}
|
|
case (ast::pat_tag(_, ?pats, _)) {
|
|
for (@ast::pat p in pats) {
|
|
auto found = lookup_in_pat(id, *p);
|
|
if (!option::is_none(found)) { ret found; }
|
|
}
|
|
}
|
|
}
|
|
ret none[def];
|
|
}
|
|
|
|
|
|
fn lookup_in_fn(&ident id, &ast::fn_decl decl, &vec[ast::ty_param] ty_params,
|
|
namespace ns) -> option::t[def] {
|
|
alt (ns) {
|
|
case (ns_value) {
|
|
for (ast::arg a in decl.inputs) {
|
|
if (_str::eq(a.ident, id)) {
|
|
ret some(ast::def_arg(a.id));
|
|
}
|
|
}
|
|
ret none[def];
|
|
}
|
|
case (ns_type) {
|
|
ret lookup_in_ty_params(id, ty_params);
|
|
}
|
|
case (_) { ret none[def]; }
|
|
}
|
|
}
|
|
|
|
fn lookup_in_obj(&ident id, &ast::_obj ob, &vec[ast::ty_param] ty_params,
|
|
namespace ns) -> option::t[def] {
|
|
alt (ns) {
|
|
case (ns_value) {
|
|
for (ast::obj_field f in ob.fields) {
|
|
if (_str::eq(f.ident, id)) {
|
|
ret some(ast::def_obj_field(f.id));
|
|
}
|
|
}
|
|
ret none[def];
|
|
}
|
|
case (ns_type) {
|
|
ret lookup_in_ty_params(id, ty_params);
|
|
}
|
|
case (_) { ret none[def]; }
|
|
}
|
|
}
|
|
|
|
fn lookup_in_block(&ident id, &ast::block_ b, namespace ns)
|
|
-> option::t[def] {
|
|
for (@ast::stmt st in b.stmts) {
|
|
alt (st.node) {
|
|
case (ast::stmt_decl(?d,_)) {
|
|
alt (d.node) {
|
|
case (ast::decl_local(?loc)) {
|
|
if (ns == ns_value && _str::eq(id, loc.ident)) {
|
|
ret some(ast::def_local(loc.id));
|
|
}
|
|
}
|
|
case (ast::decl_item(?it)) {
|
|
alt (it.node) {
|
|
case (ast::item_tag(?name, ?variants, _,
|
|
?defid, _)) {
|
|
if (ns == ns_type) {
|
|
if (_str::eq(name, id)) {
|
|
ret some(ast::def_ty(defid));
|
|
}
|
|
} else if (ns == ns_value) {
|
|
for (ast::variant v in variants) {
|
|
if (_str::eq(v.node.name, id)) {
|
|
ret some(ast::def_variant(
|
|
defid, v.node.id));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
case (_) {
|
|
if (_str::eq(ast::item_ident(it), id)) {
|
|
auto found = found_def_item(it, ns);
|
|
if (!option::is_none(found)) {ret found;}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
case (_) {}
|
|
}
|
|
}
|
|
ret none[def];
|
|
}
|
|
|
|
fn found_def_item(@ast::item i, namespace ns) -> option::t[def] {
|
|
alt (i.node) {
|
|
case (ast::item_const(_, _, _, ?defid, _)) {
|
|
if (ns == ns_value) { ret some(ast::def_const(defid)); }
|
|
}
|
|
case (ast::item_fn(_, _, _, ?defid, _)) {
|
|
if (ns == ns_value) { ret some(ast::def_fn(defid)); }
|
|
}
|
|
case (ast::item_mod(_, _, ?defid)) {
|
|
if (ns == ns_module) { ret some(ast::def_mod(defid)); }
|
|
}
|
|
case (ast::item_native_mod(_, _, ?defid)) {
|
|
if (ns == ns_module) { ret some(ast::def_native_mod(defid)); }
|
|
}
|
|
case (ast::item_ty(_, _, _, ?defid, _)) {
|
|
if (ns == ns_type) { ret some(ast::def_ty(defid)); }
|
|
}
|
|
case (ast::item_tag(_, _, _, ?defid, _)) {
|
|
if (ns == ns_type) { ret some(ast::def_ty(defid)); }
|
|
}
|
|
case (ast::item_obj(_, _, _, ?odid, _)) {
|
|
alt (ns) {
|
|
case (ns_value) { ret some(ast::def_obj(odid.ctor)); }
|
|
case (ns_type) { ret some(ast::def_obj(odid.ty)); }
|
|
case (_) { }
|
|
}
|
|
}
|
|
case (_) { }
|
|
}
|
|
ret none[def];
|
|
}
|
|
|
|
fn lookup_in_mod_strict(&env e, def m, &span sp, &ident id,
|
|
namespace ns, dir dr) -> def {
|
|
alt (lookup_in_mod(e, m, id, ns, dr)) {
|
|
case (none[def]) {
|
|
unresolved(e, sp, id, ns_name(ns));
|
|
fail;
|
|
}
|
|
case (some[def](?d)) {
|
|
ret d;
|
|
}
|
|
}
|
|
}
|
|
|
|
fn lookup_in_mod(&env e, def m, &ident id, namespace ns, dir dr)
|
|
-> option::t[def] {
|
|
auto defid = ast::def_id_of_def(m);
|
|
if (defid._0 != ast::local_crate) { // Not in this crate
|
|
auto cached = e.ext_cache.find(tup(defid,id,ns));
|
|
if (!option::is_none(cached)) { ret cached; }
|
|
auto path = vec(id);
|
|
if (defid._1 != -1) {
|
|
path = e.ext_map.get(defid) + path;
|
|
}
|
|
auto fnd = lookup_external(e, defid._0, path, ns);
|
|
if (!option::is_none(fnd)) {
|
|
e.ext_cache.insert(tup(defid,id,ns), option::get(fnd));
|
|
}
|
|
ret fnd;
|
|
}
|
|
alt (m) {
|
|
case (ast::def_mod(?defid)) {
|
|
ret lookup_in_regular_mod(e, defid, id, ns, dr);
|
|
}
|
|
case (ast::def_native_mod(?defid)) {
|
|
ret lookup_in_native_mod(e, defid, id, ns);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn found_view_item(&env e, @ast::view_item vi, namespace ns)
|
|
-> option::t[def] {
|
|
alt (vi.node) {
|
|
case (ast::view_item_use(_, _, _, ?cnum)) {
|
|
ret some(ast::def_mod(tup(option::get(cnum), -1)));
|
|
}
|
|
case (ast::view_item_import(_, _, ?defid)) {
|
|
ret lookup_import(e, defid, ns);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn lookup_import(&env e, def_id defid, namespace ns) -> option::t[def] {
|
|
alt (e.imports.get(defid._1)) {
|
|
case (todo(?item, ?sc)) {
|
|
resolve_import(e, item, sc);
|
|
ret lookup_import(e, defid, ns);
|
|
}
|
|
case (resolving(?sp)) {
|
|
e.sess.span_err(sp, "cyclic import");
|
|
}
|
|
case (resolved(?val, ?typ, ?md)) {
|
|
ret alt (ns) { case (ns_value) { val }
|
|
case (ns_type) { typ }
|
|
case (ns_module) { md } };
|
|
}
|
|
}
|
|
}
|
|
|
|
fn lookup_in_regular_mod(&env e, def_id defid, &ident id, namespace ns,
|
|
dir dr) -> option::t[def] {
|
|
auto info = e.mod_map.get(defid._1);
|
|
auto found = info.index.find(id);
|
|
if (option::is_none(found) ||
|
|
(dr == outside && !ast::is_exported(id, info.m))) {
|
|
ret none[def];
|
|
}
|
|
auto lst = option::get(found);
|
|
while (true) {
|
|
alt (lst) {
|
|
case (nil[mod_index_entry]) {
|
|
ret none[def];
|
|
}
|
|
case (cons[mod_index_entry](?hd, ?tl)) {
|
|
auto found = lookup_in_mie(e, hd, ns);
|
|
if (!option::is_none(found)) { ret found; }
|
|
lst = *tl;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn lookup_in_mie(&env e, &mod_index_entry mie, namespace ns)
|
|
-> option::t[def] {
|
|
alt (mie) {
|
|
case (mie_view_item(?view_item)) {
|
|
ret found_view_item(e, view_item, ns);
|
|
}
|
|
case (mie_item(?item)) {
|
|
ret found_def_item(item, ns);
|
|
}
|
|
case (mie_tag_variant(?item, ?variant_idx)) {
|
|
alt (item.node) {
|
|
case (ast::item_tag(_, ?variants, _, ?tid, _)) {
|
|
if (ns == ns_value) {
|
|
auto vid = variants.(variant_idx).node.id;
|
|
ret some(ast::def_variant(tid, vid));
|
|
} else {
|
|
ret none[def];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn lookup_in_native_mod(&env e, def_id defid, &ident id, namespace ns)
|
|
-> option::t[def] {
|
|
auto info = e.nmod_map.get(defid._1);
|
|
auto found = info.index.find(id);
|
|
if (option::is_none(found)) {
|
|
ret none[def];
|
|
}
|
|
auto lst = option::get(found);
|
|
while (true) {
|
|
alt (lst) {
|
|
case (nil[nmod_index_entry]) {
|
|
ret none[def];
|
|
}
|
|
case (cons[nmod_index_entry](?hd, ?tl)) {
|
|
auto found = lookup_in_nmie(e, hd, ns);
|
|
if (!option::is_none(found)) { ret found; }
|
|
lst = *tl;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn lookup_in_nmie(&env e, &nmod_index_entry nmie, namespace ns)
|
|
-> option::t[def] {
|
|
alt (nmie) {
|
|
case (nmie_view_item(?view_item)) {
|
|
ret found_view_item(e, view_item, ns);
|
|
}
|
|
case (nmie_item(?item)) {
|
|
alt (item.node) {
|
|
case (ast::native_item_ty(_, ?id)) {
|
|
if (ns == ns_type) {
|
|
ret some(ast::def_native_ty(id));
|
|
}
|
|
}
|
|
case (ast::native_item_fn(_, _, _, _, ?id, _)) {
|
|
if (ns == ns_value) {
|
|
ret some(ast::def_native_fn(id));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
case (_) {}
|
|
}
|
|
ret none[def];
|
|
}
|
|
|
|
// Module indexing
|
|
|
|
fn add_to_index[T](&hashmap[ident,list[T]] index, &ident id, &T ent) {
|
|
alt (index.find(id)) {
|
|
case (none[list[T]]) {
|
|
index.insert(id, cons(ent, @nil[T]));
|
|
}
|
|
case (some[list[T]](?prev)) {
|
|
index.insert(id, cons(ent, @prev));
|
|
}
|
|
}
|
|
}
|
|
|
|
fn index_mod(&ast::_mod md) -> mod_index {
|
|
auto index = new_str_hash[list[mod_index_entry]]();
|
|
|
|
for (@ast::view_item it in md.view_items) {
|
|
alt (it.node) {
|
|
case(ast::view_item_use(?id, _, _, _)) {
|
|
add_to_index(index, id, mie_view_item(it));
|
|
}
|
|
case(ast::view_item_import(?def_ident,_,_)) {
|
|
add_to_index(index, def_ident, mie_view_item(it));
|
|
}
|
|
case(ast::view_item_export(_)) {}
|
|
}
|
|
}
|
|
|
|
for (@ast::item it in md.items) {
|
|
alt (it.node) {
|
|
case (ast::item_const(?id, _, _, _, _)) {
|
|
add_to_index(index, id, mie_item(it));
|
|
}
|
|
case (ast::item_fn(?id, _, _, _, _)) {
|
|
add_to_index(index, id, mie_item(it));
|
|
}
|
|
case (ast::item_mod(?id, _, _)) {
|
|
add_to_index(index, id, mie_item(it));
|
|
}
|
|
case (ast::item_native_mod(?id, _, _)) {
|
|
add_to_index(index, id, mie_item(it));
|
|
}
|
|
case (ast::item_ty(?id, _, _, _, _)) {
|
|
add_to_index(index, id, mie_item(it));
|
|
}
|
|
case (ast::item_tag(?id, ?variants, _, _, _)) {
|
|
add_to_index(index, id, mie_item(it));
|
|
let uint variant_idx = 0u;
|
|
for (ast::variant v in variants) {
|
|
add_to_index(index, v.node.name,
|
|
mie_tag_variant(it, variant_idx));
|
|
variant_idx += 1u;
|
|
}
|
|
}
|
|
case (ast::item_obj(?id, _, _, _, _)) {
|
|
add_to_index(index, id, mie_item(it));
|
|
}
|
|
}
|
|
}
|
|
|
|
ret index;
|
|
}
|
|
|
|
fn index_nmod(&ast::native_mod md) -> nmod_index {
|
|
auto index = new_str_hash[list[nmod_index_entry]]();
|
|
|
|
for (@ast::view_item it in md.view_items) {
|
|
alt (it.node) {
|
|
case(ast::view_item_import(?def_ident,_,_)) {
|
|
add_to_index(index, def_ident, nmie_view_item(it));
|
|
}
|
|
case(ast::view_item_export(_)) {}
|
|
}
|
|
}
|
|
|
|
for (@ast::native_item it in md.items) {
|
|
alt (it.node) {
|
|
case (ast::native_item_ty(?id, _)) {
|
|
add_to_index(index, id, nmie_item(it));
|
|
}
|
|
case (ast::native_item_fn(?id, _, _, _, _, _)) {
|
|
add_to_index(index, id, nmie_item(it));
|
|
}
|
|
}
|
|
}
|
|
|
|
ret index;
|
|
}
|
|
|
|
// External lookups
|
|
|
|
fn ns_for_def(def d) -> namespace {
|
|
ret alt (d) {
|
|
case (ast::def_fn(?id)) { ns_value }
|
|
case (ast::def_obj(?id)) { ns_value }
|
|
case (ast::def_obj_field(?id)) { ns_value }
|
|
case (ast::def_mod(?id)) { ns_module }
|
|
case (ast::def_native_mod(?id)) { ns_module }
|
|
case (ast::def_const(?id)) { ns_value }
|
|
case (ast::def_arg(?id)) { ns_value }
|
|
case (ast::def_local(?id)) { ns_value }
|
|
case (ast::def_variant(_, ?id)) { ns_value }
|
|
case (ast::def_ty(?id)) { ns_type }
|
|
case (ast::def_binding(?id)) { ns_type }
|
|
case (ast::def_use(?id)) { ns_module }
|
|
case (ast::def_native_ty(?id)) { ns_type }
|
|
case (ast::def_native_fn(?id)) { ns_value }
|
|
};
|
|
}
|
|
|
|
fn lookup_external(&env e, int cnum, vec[ident] ids, namespace ns)
|
|
-> option::t[def] {
|
|
for (def d in creader::lookup_defs(e.sess, cnum, ids)) {
|
|
e.ext_map.insert(ast::def_id_of_def(d), ids);
|
|
if (ns == ns_for_def(d)) { ret some(d); }
|
|
}
|
|
ret none[def];
|
|
}
|
|
|
|
// Local Variables:
|
|
// mode: rust
|
|
// fill-column: 78;
|
|
// indent-tabs-mode: nil
|
|
// c-basic-offset: 4
|
|
// buffer-file-coding-system: utf-8-unix
|
|
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
|
|
// End:
|