Refactor view_path to parse (but not yet process) export globs, unify code paths.
This commit is contained in:
parent
6f70896854
commit
ef6f628589
@ -31,7 +31,8 @@ fn inject_libcore_ref(sess: session,
|
||||
let n2 = sess.next_node_id();
|
||||
|
||||
let vi1 = spanned(ast::view_item_use("core", [], n1));
|
||||
let vi2 = spanned(ast::view_item_import_glob(@["core"], n2));
|
||||
let vp = spanned(ast::view_path_glob(@["core"], n2));
|
||||
let vi2 = spanned(ast::view_item_import([vp]));
|
||||
|
||||
let vis = [vi1, vi2] + crate.node.module.view_items;
|
||||
|
||||
|
@ -100,8 +100,8 @@ enum mod_index_entry {
|
||||
|
||||
type mod_index = hashmap<ident, list<mod_index_entry>>;
|
||||
|
||||
// A tuple of an imported def and the import stmt that brung it
|
||||
type glob_imp_def = {def: def, item: @ast::view_item};
|
||||
// A tuple of an imported def and the view_path from its originating import
|
||||
type glob_imp_def = {def: def, path: @ast::view_path};
|
||||
|
||||
type indexed_mod = {
|
||||
m: option<ast::_mod>,
|
||||
@ -200,43 +200,53 @@ fn create_env(sess: session, amap: ast_map::map) -> @env {
|
||||
sess: sess}
|
||||
}
|
||||
|
||||
fn iter_import_paths(vi: ast::view_item, f: fn(vp: @ast::view_path)) {
|
||||
alt vi.node {
|
||||
ast::view_item_import(vps) {
|
||||
for vp in vps {
|
||||
f(vp);
|
||||
}
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
|
||||
fn iter_export_paths(vi: ast::view_item, f: fn(vp: @ast::view_path)) {
|
||||
alt vi.node {
|
||||
ast::view_item_export(vps) {
|
||||
for vp in vps {
|
||||
f(vp);
|
||||
}
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
|
||||
// Locate all modules and imports and index them, so that the next passes can
|
||||
// resolve through them.
|
||||
fn map_crate(e: @env, c: @ast::crate) {
|
||||
// First, find all the modules, and index the names that they contain
|
||||
let v_map_mod =
|
||||
@{visit_view_item: bind index_vi(e, _, _, _),
|
||||
visit_item: bind index_i(e, _, _, _),
|
||||
visit_block: visit_block_with_scope
|
||||
with *visit::default_visitor::<scopes>()};
|
||||
visit::visit_crate(*c, top_scope(), visit::mk_vt(v_map_mod));
|
||||
|
||||
// Register the top-level mod
|
||||
e.mod_map.insert(ast::crate_node_id,
|
||||
@{m: some(c.node.module),
|
||||
index: index_mod(c.node.module),
|
||||
mutable glob_imports: [],
|
||||
glob_imported_names: new_str_hash(),
|
||||
path: ""});
|
||||
fn index_vi(e: @env, i: @ast::view_item, sc: scopes, _v: vt<scopes>) {
|
||||
alt i.node {
|
||||
ast::view_item_import(name, ids, id) {
|
||||
e.imports.insert(id, todo(id, name, ids, i.span, sc));
|
||||
}
|
||||
ast::view_item_import_from(mod_path, idents, id) {
|
||||
for ident in idents {
|
||||
e.imports.insert(ident.node.id,
|
||||
todo(ident.node.id, ident.node.name,
|
||||
@(*mod_path + [ident.node.name]),
|
||||
ident.span, sc));
|
||||
iter_import_paths(*i) { |vp|
|
||||
alt vp.node {
|
||||
ast::view_path_simple(name, path, id) {
|
||||
e.imports.insert(id, todo(id, name, path, vp.span, sc));
|
||||
}
|
||||
ast::view_path_glob(path, id) {
|
||||
e.imports.insert(id, is_glob(path, sc, vp.span));
|
||||
}
|
||||
ast::view_path_list(mod_path, idents, _) {
|
||||
for ident in idents {
|
||||
let t = todo(ident.node.id, ident.node.name,
|
||||
@(*mod_path + [ident.node.name]),
|
||||
ident.span, sc);
|
||||
e.imports.insert(ident.node.id, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::view_item_import_glob(pth, id) {
|
||||
e.imports.insert(id, is_glob(pth, sc, i.span));
|
||||
}
|
||||
_ { }
|
||||
}
|
||||
}
|
||||
|
||||
fn path_from_scope(sc: scopes, n: str) -> str {
|
||||
let path = n + "::";
|
||||
list::iter(sc) {|s|
|
||||
@ -247,6 +257,7 @@ fn map_crate(e: @env, c: @ast::crate) {
|
||||
}
|
||||
path
|
||||
}
|
||||
|
||||
fn index_i(e: @env, i: @ast::item, sc: scopes, v: vt<scopes>) {
|
||||
visit_item_with_scope(e, i, sc, v);
|
||||
alt i.node {
|
||||
@ -270,20 +281,14 @@ fn map_crate(e: @env, c: @ast::crate) {
|
||||
}
|
||||
}
|
||||
|
||||
// Next, assemble the links for globbed imports.
|
||||
let v_link_glob =
|
||||
@{visit_view_item: bind link_glob(e, _, _, _),
|
||||
visit_block: visit_block_with_scope,
|
||||
visit_item: bind visit_item_with_scope(e, _, _, _)
|
||||
with *visit::default_visitor::<scopes>()};
|
||||
visit::visit_crate(*c, top_scope(), visit::mk_vt(v_link_glob));
|
||||
fn link_glob(e: @env, vi: @ast::view_item, sc: scopes, _v: vt<scopes>) {
|
||||
alt vi.node {
|
||||
//if it really is a glob import, that is
|
||||
ast::view_item_import_glob(path, _) {
|
||||
alt follow_import(*e, sc, *path, vi.span) {
|
||||
some(imp) {
|
||||
let glob = {def: imp, item: vi};
|
||||
iter_import_paths(*vi) { |vp|
|
||||
//if it really is a glob import, that is
|
||||
alt vp.node {
|
||||
ast::view_path_glob(path, _) {
|
||||
alt follow_import(*e, sc, *path, vp.span) {
|
||||
some(imp) {
|
||||
let glob = {def: imp, path: vp};
|
||||
check list::is_not_empty(sc);
|
||||
alt list::head(sc) {
|
||||
scope_item(i) {
|
||||
@ -291,7 +296,8 @@ fn map_crate(e: @env, c: @ast::crate) {
|
||||
}
|
||||
scope_block(b, _, _) {
|
||||
let globs = alt e.block_map.find(b.node.id) {
|
||||
some(globs) { globs + [glob] } none { [glob] }
|
||||
some(globs) { globs + [glob] }
|
||||
none { [glob] }
|
||||
};
|
||||
e.block_map.insert(b.node.id, globs);
|
||||
}
|
||||
@ -300,15 +306,41 @@ fn map_crate(e: @env, c: @ast::crate) {
|
||||
+= [glob];
|
||||
}
|
||||
_ { e.sess.span_bug(vi.span, "Unexpected scope in a \
|
||||
glob import"); }
|
||||
}
|
||||
glob import"); }
|
||||
}
|
||||
}
|
||||
_ { }
|
||||
}
|
||||
_ { }
|
||||
}
|
||||
}
|
||||
_ { }
|
||||
}
|
||||
_ { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// First, find all the modules, and index the names that they contain
|
||||
let v_map_mod =
|
||||
@{visit_view_item: bind index_vi(e, _, _, _),
|
||||
visit_item: bind index_i(e, _, _, _),
|
||||
visit_block: visit_block_with_scope
|
||||
with *visit::default_visitor::<scopes>()};
|
||||
visit::visit_crate(*c, top_scope(), visit::mk_vt(v_map_mod));
|
||||
|
||||
// Register the top-level mod
|
||||
e.mod_map.insert(ast::crate_node_id,
|
||||
@{m: some(c.node.module),
|
||||
index: index_mod(c.node.module),
|
||||
mutable glob_imports: [],
|
||||
glob_imported_names: new_str_hash(),
|
||||
path: ""});
|
||||
|
||||
// Next, assemble the links for globbed imports.
|
||||
let v_link_glob =
|
||||
@{visit_view_item: bind link_glob(e, _, _, _),
|
||||
visit_block: visit_block_with_scope,
|
||||
visit_item: bind visit_item_with_scope(e, _, _, _)
|
||||
with *visit::default_visitor::<scopes>()};
|
||||
visit::visit_crate(*c, top_scope(), visit::mk_vt(v_link_glob));
|
||||
|
||||
}
|
||||
|
||||
fn resolve_imports(e: env) {
|
||||
@ -674,18 +706,20 @@ fn resolve_import(e: env, defid: ast::def_id, name: ast::ident,
|
||||
fn lst(my_id: node_id, vis: [@view_item]) -> [node_id] {
|
||||
let imports = [], found = false;
|
||||
for vi in vis {
|
||||
alt vi.node {
|
||||
view_item_import(_, _, id) | view_item_import_glob(_, id) {
|
||||
if id == my_id { found = true; }
|
||||
if found { imports += [id]; }
|
||||
}
|
||||
view_item_import_from(_, ids, _) {
|
||||
for id in ids {
|
||||
if id.node.id == my_id { found = true; }
|
||||
if found { imports += [id.node.id]; }
|
||||
iter_import_paths(*vi) {|vp|
|
||||
alt vp.node {
|
||||
view_path_simple(_, _, id)
|
||||
| view_path_glob(_, id) {
|
||||
if id == my_id { found = true; }
|
||||
if found { imports += [id]; }
|
||||
}
|
||||
view_path_list(_, ids, _) {
|
||||
for id in ids {
|
||||
if id.node.id == my_id { found = true; }
|
||||
if found { imports += [id.node.id]; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
imports
|
||||
@ -1177,25 +1211,38 @@ fn lookup_in_block(e: env, name: ident, sp: span, b: ast::blk_, pos: uint,
|
||||
}
|
||||
for vi in b.view_items {
|
||||
alt vi.node {
|
||||
ast::view_item_import(ident, _, id) {
|
||||
if name == ident { ret lookup_import(e, local_def(id), ns); }
|
||||
}
|
||||
ast::view_item_import_from(mod_path, idents, id) {
|
||||
for ident in idents {
|
||||
if name == ident.node.name {
|
||||
ret lookup_import(e, local_def(ident.node.id), ns);
|
||||
|
||||
ast::view_item_import(vps) {
|
||||
for vp in vps {
|
||||
alt vp.node {
|
||||
ast::view_path_simple(ident, _, id) {
|
||||
if name == ident {
|
||||
ret lookup_import(e, local_def(id), ns);
|
||||
}
|
||||
}
|
||||
|
||||
ast::view_path_list(path, idents, _) {
|
||||
for ident in idents {
|
||||
if name == ident.node.name {
|
||||
let def = local_def(ident.node.id);
|
||||
ret lookup_import(e, def, ns);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ast::view_path_glob(_, _) {
|
||||
alt e.block_map.find(b.id) {
|
||||
some(globs) {
|
||||
let found = lookup_in_globs(e, globs, sp, name,
|
||||
ns, inside);
|
||||
if found != none { ret found; }
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::view_item_import_glob(_, _) {
|
||||
alt e.block_map.find(b.id) {
|
||||
some(globs) {
|
||||
let found = lookup_in_globs(e, globs, sp, name, ns, inside);
|
||||
if found != none { ret found; }
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
_ { e.sess.span_bug(vi.span, "Unexpected view_item in block"); }
|
||||
}
|
||||
}
|
||||
@ -1363,16 +1410,18 @@ fn lookup_in_globs(e: env, globs: [glob_imp_def], sp: span, id: ident,
|
||||
ns: namespace, dr: dir) -> option<def> {
|
||||
fn lookup_in_mod_(e: env, def: glob_imp_def, sp: span, name: ident,
|
||||
ns: namespace, dr: dir) -> option<glob_imp_def> {
|
||||
alt def.item.node {
|
||||
ast::view_item_import_glob(_, id) {
|
||||
alt def.path.node {
|
||||
|
||||
ast::view_path_glob(_, id) {
|
||||
if vec::contains(e.ignored_imports, id) { ret none; }
|
||||
}
|
||||
|
||||
_ {
|
||||
e.sess.span_bug(sp, "lookup_in_globs: not a glob");
|
||||
}
|
||||
}
|
||||
alt lookup_in_mod(e, def.def, sp, name, ns, dr) {
|
||||
some(d) { option::some({def: d, item: def.item}) }
|
||||
some(d) { option::some({def: d, path: def.path}) }
|
||||
none { none }
|
||||
}
|
||||
}
|
||||
@ -1385,7 +1434,7 @@ fn lookup_in_globs(e: env, globs: [glob_imp_def], sp: span, id: ident,
|
||||
ret some(matches[0].def);
|
||||
} else {
|
||||
for match: glob_imp_def in matches {
|
||||
let sp = match.item.span;
|
||||
let sp = match.path.span;
|
||||
e.sess.span_note(sp, #fmt["'%s' is imported here", id]);
|
||||
}
|
||||
e.sess.span_fatal(sp, "'" + id + "' is glob-imported from" +
|
||||
@ -1476,28 +1525,41 @@ fn add_to_index(index: hashmap<ident, list<mod_index_entry>>, id: ident,
|
||||
}
|
||||
}
|
||||
|
||||
fn index_mod(md: ast::_mod) -> mod_index {
|
||||
let index = new_str_hash::<list<mod_index_entry>>();
|
||||
for it: @ast::view_item in md.view_items {
|
||||
alt it.node {
|
||||
fn index_view_items(view_items: [@ast::view_item],
|
||||
index: hashmap<ident, list<mod_index_entry>>) {
|
||||
for vi in view_items {
|
||||
alt vi.node {
|
||||
ast::view_item_use(ident, _, id) {
|
||||
add_to_index(index, ident, mie_view_item(ident, id, it.span));
|
||||
add_to_index(index, ident, mie_view_item(ident, id, vi.span));
|
||||
}
|
||||
ast::view_item_import(ident, _, id) {
|
||||
add_to_index(index, ident, mie_import_ident(id, it.span));
|
||||
}
|
||||
ast::view_item_import_from(_, idents, _) {
|
||||
for ident in idents {
|
||||
add_to_index(index, ident.node.name,
|
||||
mie_import_ident(ident.node.id, ident.span));
|
||||
}
|
||||
}
|
||||
//globbed imports have to be resolved lazily.
|
||||
ast::view_item_import_glob(_, _) | ast::view_item_export(_, _) {}
|
||||
// exports: ignore
|
||||
_ {}
|
||||
}
|
||||
|
||||
iter_import_paths(*vi) {|vp|
|
||||
alt vp.node {
|
||||
ast::view_path_simple(ident, _, id) {
|
||||
add_to_index(index, ident, mie_import_ident(id, vp.span));
|
||||
}
|
||||
ast::view_path_list(_, idents, _) {
|
||||
for ident in idents {
|
||||
add_to_index(index, ident.node.name,
|
||||
mie_import_ident(ident.node.id,
|
||||
ident.span));
|
||||
}
|
||||
}
|
||||
|
||||
// globbed imports have to be resolved lazily.
|
||||
ast::view_path_glob(_, _) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn index_mod(md: ast::_mod) -> mod_index {
|
||||
let index = new_str_hash::<list<mod_index_entry>>();
|
||||
|
||||
index_view_items(md.view_items, index);
|
||||
|
||||
for it: @ast::item in md.items {
|
||||
alt it.node {
|
||||
ast::item_const(_, _) | ast::item_fn(_, _, _) | ast::item_mod(_) |
|
||||
@ -1537,27 +1599,12 @@ fn index_mod(md: ast::_mod) -> mod_index {
|
||||
ret index;
|
||||
}
|
||||
|
||||
|
||||
fn index_nmod(md: ast::native_mod) -> mod_index {
|
||||
let index = new_str_hash::<list<mod_index_entry>>();
|
||||
for it: @ast::view_item in md.view_items {
|
||||
alt it.node {
|
||||
ast::view_item_use(ident, _, id) {
|
||||
add_to_index(index, ident, mie_view_item(ident, id,
|
||||
it.span));
|
||||
}
|
||||
ast::view_item_import(ident, _, id) {
|
||||
add_to_index(index, ident, mie_import_ident(id, it.span));
|
||||
}
|
||||
ast::view_item_import_from(_, idents, _) {
|
||||
for ident in idents {
|
||||
add_to_index(index, ident.node.name,
|
||||
mie_import_ident(ident.node.id, ident.span));
|
||||
}
|
||||
}
|
||||
ast::view_item_import_glob(_, _) | ast::view_item_export(_, _) { }
|
||||
_ { /* tag exports */ }
|
||||
}
|
||||
}
|
||||
|
||||
index_view_items(md.view_items, index);
|
||||
|
||||
for it: @ast::native_item in md.items {
|
||||
add_to_index(index, it.ident, mie_native_item(it));
|
||||
}
|
||||
@ -1912,55 +1959,72 @@ fn check_exports(e: @env) {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_export_enum_list(e: @env, val: @indexed_mod,
|
||||
span: codemap::span, id: ast::ident,
|
||||
ids: [ast::path_list_ident]) {
|
||||
if vec::len(ids) == 0u {
|
||||
let _ = check_enum_ok(e, span, id, val);
|
||||
} else {
|
||||
let parent_id = check_enum_ok(e, span, id, val);
|
||||
for variant_id in ids {
|
||||
alt val.index.find(variant_id.node.name) {
|
||||
some(ms) {
|
||||
list::iter(ms) {|m|
|
||||
alt m {
|
||||
mie_enum_variant(_, _, actual_parent_id, _) {
|
||||
if actual_parent_id != parent_id {
|
||||
let msg = #fmt("variant %s \
|
||||
doesn't belong to enum %s",
|
||||
variant_id.node.name,
|
||||
id);
|
||||
e.sess.span_err(span, msg);
|
||||
}
|
||||
}
|
||||
_ {
|
||||
e.sess.span_err(span,
|
||||
#fmt("%s is not a variant",
|
||||
variant_id.node.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ {
|
||||
e.sess.span_err(span,
|
||||
#fmt("%s is not a variant",
|
||||
variant_id.node.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
e.mod_map.values {|val|
|
||||
alt val.m {
|
||||
some(m) {
|
||||
for vi in m.view_items {
|
||||
alt vi.node {
|
||||
ast::view_item_export(idents, _) {
|
||||
for ident in idents {
|
||||
iter_export_paths(*vi) { |vp|
|
||||
alt vp.node {
|
||||
ast::view_path_simple(ident, _, _) {
|
||||
check_export(e, ident, val, vi);
|
||||
}
|
||||
}
|
||||
ast::view_item_export_enum_none(id, _) {
|
||||
let _ = check_enum_ok(e, vi.span, id, val);
|
||||
}
|
||||
ast::view_item_export_enum_some(id, ids, _) {
|
||||
// Check that it's an enum and all the given variants
|
||||
// belong to it
|
||||
let parent_id = check_enum_ok(e, vi.span, id, val);
|
||||
for variant_id in ids {
|
||||
alt val.index.find(variant_id.node.name) {
|
||||
some(ms) {
|
||||
list::iter(ms) {|m|
|
||||
alt m {
|
||||
mie_enum_variant(_, _, actual_parent_id,
|
||||
_) {
|
||||
if actual_parent_id != parent_id {
|
||||
e.sess.span_err(vi.span,
|
||||
#fmt("variant %s \
|
||||
doesn't belong to enum %s",
|
||||
variant_id.node.name,
|
||||
id));
|
||||
}
|
||||
}
|
||||
_ { e.sess.span_err(vi.span,
|
||||
#fmt("%s is not a \
|
||||
variant", variant_id.node.name)); }
|
||||
}}
|
||||
}
|
||||
_ { e.sess.span_err(vi.span, #fmt("%s is not a\
|
||||
variant", variant_id.node.name)); }
|
||||
}
|
||||
}
|
||||
}
|
||||
_ { }
|
||||
ast::view_path_list(path, ids, _) {
|
||||
let id = if vec::len(*path) == 1u {
|
||||
path[0]
|
||||
} else {
|
||||
e.sess.span_fatal(vp.span,
|
||||
#fmt("bad export name-list"))
|
||||
};
|
||||
check_export_enum_list(e, val, vp.span, id, ids);
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
none { }
|
||||
}
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
||||
// Impl resolution
|
||||
|
||||
@ -1993,43 +2057,47 @@ fn find_impls_in_view_item(e: env, vi: @ast::view_item,
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
alt vi.node {
|
||||
ast::view_item_import(name, pt, id) {
|
||||
let found = [];
|
||||
if vec::len(*pt) == 1u {
|
||||
option::may(sc) {|sc|
|
||||
list::iter(sc) {|level|
|
||||
if vec::len(found) > 0u { ret; }
|
||||
for imp in *level {
|
||||
if imp.ident == pt[0] {
|
||||
found += [@{ident: name with *imp}];
|
||||
|
||||
iter_import_paths(*vi) { |vp|
|
||||
alt vp.node {
|
||||
ast::view_path_simple(name, pt, id) {
|
||||
let found = [];
|
||||
if vec::len(*pt) == 1u {
|
||||
option::may(sc) {|sc|
|
||||
list::iter(sc) {|level|
|
||||
if vec::len(found) > 0u { ret; }
|
||||
for imp in *level {
|
||||
if imp.ident == pt[0] {
|
||||
found += [@{ident: name with *imp}];
|
||||
}
|
||||
}
|
||||
if vec::len(found) > 0u { impls += found; }
|
||||
}
|
||||
if vec::len(found) > 0u { impls += found; }
|
||||
}
|
||||
} else {
|
||||
lookup_imported_impls(e, id) {|is|
|
||||
for i in *is { impls += [@{ident: name with *i}]; }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lookup_imported_impls(e, id) {|is|
|
||||
for i in *is { impls += [@{ident: name with *i}]; }
|
||||
}
|
||||
|
||||
ast::view_path_list(base, names, _) {
|
||||
for nm in names {
|
||||
lookup_imported_impls(e, nm.node.id) {|is| impls += *is; }
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::view_item_import_from(base, names, _) {
|
||||
for nm in names {
|
||||
lookup_imported_impls(e, nm.node.id) {|is| impls += *is; }
|
||||
}
|
||||
}
|
||||
ast::view_item_import_glob(ids, id) {
|
||||
alt check e.imports.get(id) {
|
||||
is_glob(path, sc, sp) {
|
||||
alt follow_import(e, sc, *path, sp) {
|
||||
some(def) { find_impls_in_mod(e, def, impls, none); }
|
||||
_ {}
|
||||
}
|
||||
|
||||
ast::view_path_glob(ids, id) {
|
||||
alt check e.imports.get(id) {
|
||||
is_glob(path, sc, sp) {
|
||||
alt follow_import(e, sc, *path, sp) {
|
||||
some(def) { find_impls_in_mod(e, def, impls, none); }
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -441,26 +441,36 @@ type variant_ = {name: ident, attrs: [attribute], args: [variant_arg],
|
||||
|
||||
type variant = spanned<variant_>;
|
||||
|
||||
type view_item = spanned<view_item_>;
|
||||
|
||||
// FIXME: May want to just use path here, which would allow things like
|
||||
// 'import ::foo'
|
||||
type simple_path = [ident];
|
||||
|
||||
type import_ident_ = {name: ident, id: node_id};
|
||||
type path_list_ident_ = {name: ident, id: node_id};
|
||||
type path_list_ident = spanned<path_list_ident_>;
|
||||
|
||||
type import_ident = spanned<import_ident_>;
|
||||
type view_path = spanned<view_path_>;
|
||||
enum view_path_ {
|
||||
|
||||
// quux = foo::bar::baz
|
||||
//
|
||||
// or just
|
||||
//
|
||||
// foo::bar::baz (with 'baz =' implicitly on the left)
|
||||
view_path_simple(ident, @simple_path, node_id),
|
||||
|
||||
// foo::bar::*
|
||||
view_path_glob(@simple_path, node_id),
|
||||
|
||||
// foo::bar::{a,b,c}
|
||||
view_path_list(@simple_path, [path_list_ident], node_id)
|
||||
}
|
||||
|
||||
type view_item = spanned<view_item_>;
|
||||
enum view_item_ {
|
||||
view_item_use(ident, [@meta_item], node_id),
|
||||
view_item_import(ident, @simple_path, node_id),
|
||||
view_item_import_glob(@simple_path, node_id),
|
||||
view_item_import_from(@simple_path, [import_ident], node_id),
|
||||
view_item_export([ident], node_id),
|
||||
// export foo::{}
|
||||
view_item_export_enum_none(ident, node_id),
|
||||
// export foo::{bar, baz, blat}
|
||||
view_item_export_enum_some(ident, [import_ident], node_id)
|
||||
view_item_import([@view_path]),
|
||||
view_item_export([@view_path])
|
||||
}
|
||||
|
||||
// Meta-data associated with an item
|
||||
|
@ -116,56 +116,63 @@ fn float_ty_to_str(t: float_ty) -> str {
|
||||
}
|
||||
|
||||
fn is_exported(i: ident, m: _mod) -> bool {
|
||||
let nonlocal = true;
|
||||
let local = false;
|
||||
let parent_enum : option<ident> = none;
|
||||
for it: @item in m.items {
|
||||
if it.ident == i { nonlocal = false; }
|
||||
if it.ident == i { local = true; }
|
||||
alt it.node {
|
||||
item_enum(variants, _) {
|
||||
for v: variant in variants {
|
||||
if v.node.name == i {
|
||||
nonlocal = false;
|
||||
local = true;
|
||||
parent_enum = some(it.ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ { }
|
||||
}
|
||||
if !nonlocal { break; }
|
||||
if local { break; }
|
||||
}
|
||||
let count = 0u;
|
||||
let has_explicit_exports = false;
|
||||
for vi: @view_item in m.view_items {
|
||||
alt vi.node {
|
||||
view_item_export(ids, _) {
|
||||
// If any of ids is a enum, we want to consider
|
||||
// all the variants to be exported
|
||||
for id in ids {
|
||||
if str::eq(i, id) { ret true; }
|
||||
alt parent_enum {
|
||||
some(parent_enum_id) {
|
||||
if str::eq(id, parent_enum_id) { ret true; }
|
||||
view_item_export(vps) {
|
||||
has_explicit_exports = true;
|
||||
for vp in vps {
|
||||
alt vp.node {
|
||||
ast::view_path_simple(id, _, _) {
|
||||
if id == i { ret true; }
|
||||
alt parent_enum {
|
||||
some(parent_enum_id) {
|
||||
if id == parent_enum_id { ret true; }
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
_ { }
|
||||
}
|
||||
}
|
||||
|
||||
ast::view_path_list(path, ids, _) {
|
||||
if vec::len(*path) == 1u {
|
||||
if i == path[0] { ret true; }
|
||||
for id in ids {
|
||||
if id.node.name == i { ret true; }
|
||||
}
|
||||
} else {
|
||||
fail "export of path-qualified list";
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: glob-exports aren't supported yet.
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
count += 1u;
|
||||
}
|
||||
view_item_export_enum_none(id, _) {
|
||||
if str::eq(i, id) { ret true; }
|
||||
count += 1u;
|
||||
}
|
||||
view_item_export_enum_some(id, ids, _) {
|
||||
if str::eq(i, id) { ret true; }
|
||||
for id in ids { if str::eq(i, id.node.name) { ret true; } }
|
||||
count += 1u;
|
||||
}
|
||||
_ {/* fall through */ }
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
// If there are no declared exports then
|
||||
// everything not imported is exported
|
||||
// even if it's nonlocal (since it's explicit)
|
||||
ret count == 0u && !nonlocal;
|
||||
// even if it's local (since it's explicit)
|
||||
ret !has_explicit_exports && local;
|
||||
}
|
||||
|
||||
pure fn is_call_expr(e: @expr) -> bool {
|
||||
|
@ -202,7 +202,7 @@ fn parse_ident(p: parser) -> ast::ident {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_import_ident(p: parser) -> ast::import_ident {
|
||||
fn parse_path_list_ident(p: parser) -> ast::path_list_ident {
|
||||
let lo = p.span.lo;
|
||||
let ident = parse_ident(p);
|
||||
let hi = p.span.hi;
|
||||
@ -2421,139 +2421,80 @@ fn parse_use(p: parser) -> ast::view_item_ {
|
||||
ret ast::view_item_use(ident, metadata, p.get_id());
|
||||
}
|
||||
|
||||
fn parse_rest_import_name(p: parser, first: ast::ident,
|
||||
def_ident: option<ast::ident>) ->
|
||||
ast::view_item_ {
|
||||
let identifiers: [ast::ident] = [first];
|
||||
let glob: bool = false;
|
||||
let from_idents = option::none::<[ast::import_ident]>;
|
||||
while true {
|
||||
alt p.token {
|
||||
token::SEMI { break; }
|
||||
token::MOD_SEP {
|
||||
if glob { p.fatal("cannot path into a glob"); }
|
||||
if option::is_some(from_idents) {
|
||||
p.fatal("cannot path into import list");
|
||||
}
|
||||
p.bump();
|
||||
}
|
||||
_ { p.fatal("expecting '::' or ';'"); }
|
||||
}
|
||||
alt p.token {
|
||||
token::IDENT(_, _) { identifiers += [parse_ident(p)]; }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//the lexer can't tell the different kinds of stars apart ) :
|
||||
token::BINOP(token::STAR) {
|
||||
glob = true;
|
||||
p.bump();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
token::LBRACE {
|
||||
let from_idents_ =
|
||||
parse_seq(token::LBRACE, token::RBRACE, seq_sep(token::COMMA),
|
||||
parse_import_ident, p).node;
|
||||
if vec::is_empty(from_idents_) {
|
||||
p.fatal("at least one import is required");
|
||||
}
|
||||
from_idents = some(from_idents_);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_ {
|
||||
p.fatal("expecting an identifier, or '*'");
|
||||
}
|
||||
}
|
||||
}
|
||||
alt def_ident {
|
||||
some(i) {
|
||||
if glob { p.fatal("globbed imports can't be renamed"); }
|
||||
if option::is_some(from_idents) {
|
||||
p.fatal("can't rename import list");
|
||||
}
|
||||
ret ast::view_item_import(i, @identifiers, p.get_id());
|
||||
}
|
||||
_ {
|
||||
if glob {
|
||||
ret ast::view_item_import_glob(@identifiers, p.get_id());
|
||||
} else if option::is_some(from_idents) {
|
||||
ret ast::view_item_import_from(@identifiers,
|
||||
option::get(from_idents),
|
||||
p.get_id());
|
||||
} else {
|
||||
let len = vec::len(identifiers);
|
||||
ret ast::view_item_import(identifiers[len - 1u], @identifiers,
|
||||
p.get_id());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_full_import_name(p: parser, def_ident: ast::ident) ->
|
||||
ast::view_item_ {
|
||||
fn parse_view_path(p: parser) -> @ast::view_path {
|
||||
let lo = p.span.lo;
|
||||
let first_ident = parse_ident(p);
|
||||
let path = [first_ident];
|
||||
#debug("parsed view_path: %s", first_ident);
|
||||
alt p.token {
|
||||
token::IDENT(i, _) {
|
||||
token::EQ {
|
||||
// x = foo::bar
|
||||
p.bump();
|
||||
ret parse_rest_import_name(p, p.get_str(i), some(def_ident));
|
||||
}
|
||||
_ { p.fatal("expecting an identifier"); }
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_import(p: parser) -> ast::view_item_ {
|
||||
alt p.token {
|
||||
token::IDENT(i, _) {
|
||||
p.bump();
|
||||
alt p.token {
|
||||
token::EQ {
|
||||
path = [parse_ident(p)];
|
||||
while p.token == token::MOD_SEP {
|
||||
p.bump();
|
||||
ret parse_full_import_name(p, p.get_str(i));
|
||||
}
|
||||
_ { ret parse_rest_import_name(p, p.get_str(i), none); }
|
||||
let id = parse_ident(p);
|
||||
path += [id];
|
||||
}
|
||||
let hi = p.span.hi;
|
||||
ret @spanned(lo, hi,
|
||||
ast::view_path_simple(first_ident,
|
||||
@path, p.get_id()));
|
||||
}
|
||||
|
||||
token::MOD_SEP {
|
||||
// foo::bar or foo::{a,b,c} or foo::*
|
||||
while p.token == token::MOD_SEP {
|
||||
p.bump();
|
||||
|
||||
alt p.token {
|
||||
|
||||
token::IDENT(i, _) {
|
||||
p.bump();
|
||||
path += [p.get_str(i)];
|
||||
}
|
||||
|
||||
// foo::bar::{a,b,c}
|
||||
token::LBRACE {
|
||||
let idents =
|
||||
parse_seq(token::LBRACE, token::RBRACE,
|
||||
seq_sep(token::COMMA),
|
||||
parse_path_list_ident, p).node;
|
||||
let hi = p.span.hi;
|
||||
ret @spanned(lo, hi,
|
||||
ast::view_path_list(@path, idents,
|
||||
p.get_id()));
|
||||
}
|
||||
|
||||
// foo::bar::*
|
||||
token::BINOP(token::STAR) {
|
||||
p.bump();
|
||||
let hi = p.span.hi;
|
||||
ret @spanned(lo, hi,
|
||||
ast::view_path_glob(@path,
|
||||
p.get_id()));
|
||||
}
|
||||
|
||||
_ { break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
_ { p.fatal("expecting an identifier"); }
|
||||
_ { }
|
||||
}
|
||||
let hi = p.span.hi;
|
||||
let last = path[vec::len(path) - 1u];
|
||||
ret @spanned(lo, hi,
|
||||
ast::view_path_simple(last, @path,
|
||||
p.get_id()));
|
||||
}
|
||||
|
||||
fn parse_enum_export(p:parser, tyname:ast::ident) -> ast::view_item_ {
|
||||
let enumnames:[ast::import_ident] =
|
||||
parse_seq(token::LBRACE, token::RBRACE,
|
||||
seq_sep(token::COMMA), {|p| parse_import_ident(p) }, p).node;
|
||||
let id = p.get_id();
|
||||
if vec::is_empty(enumnames) {
|
||||
ret ast::view_item_export_enum_none(tyname, id);
|
||||
}
|
||||
else {
|
||||
ret ast::view_item_export_enum_some(tyname, enumnames, id);
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_export(p: parser) -> ast::view_item_ {
|
||||
let first = parse_ident(p);
|
||||
alt p.token {
|
||||
token::MOD_SEP {
|
||||
p.bump();
|
||||
ret parse_enum_export(p, first);
|
||||
}
|
||||
t {
|
||||
if t == token::COMMA { p.bump(); }
|
||||
let ids =
|
||||
parse_seq_to_before_end(token::SEMI, seq_sep(token::COMMA),
|
||||
parse_ident, p);
|
||||
ret ast::view_item_export(vec::concat([[first], ids]), p.get_id());
|
||||
}
|
||||
fn parse_view_paths(p: parser) -> [@ast::view_path] {
|
||||
let vp = [parse_view_path(p)];
|
||||
while p.token == token::COMMA {
|
||||
p.bump();
|
||||
vp += [parse_view_path(p)];
|
||||
}
|
||||
ret vp;
|
||||
}
|
||||
|
||||
fn parse_view_item(p: parser) -> @ast::view_item {
|
||||
@ -2562,8 +2503,12 @@ fn parse_view_item(p: parser) -> @ast::view_item {
|
||||
if eat_word(p, "use") {
|
||||
parse_use(p)
|
||||
} else if eat_word(p, "import") {
|
||||
parse_import(p)
|
||||
} else if eat_word(p, "export") { parse_export(p) } else { fail };
|
||||
ast::view_item_import(parse_view_paths(p))
|
||||
} else if eat_word(p, "export") {
|
||||
ast::view_item_export(parse_view_paths(p))
|
||||
} else {
|
||||
fail
|
||||
};
|
||||
let hi = p.span.lo;
|
||||
expect(p, token::SEMI);
|
||||
ret @spanned(lo, hi, the_item);
|
||||
|
@ -1333,6 +1333,44 @@ fn print_meta_item(s: ps, &&item: @ast::meta_item) {
|
||||
end(s);
|
||||
}
|
||||
|
||||
fn print_simple_path(s: ps, path: ast::simple_path) {
|
||||
let first = true;
|
||||
for id in path {
|
||||
if first { first = false; } else { word(s.s, "::"); }
|
||||
word(s.s, id);
|
||||
}
|
||||
}
|
||||
|
||||
fn print_view_path(s: ps, &&vp: @ast::view_path) {
|
||||
alt vp.node {
|
||||
ast::view_path_simple(ident, path, _) {
|
||||
if path[vec::len(*path)-1u] != ident {
|
||||
word_space(s, ident);
|
||||
word_space(s, "=");
|
||||
}
|
||||
print_simple_path(s, *path);
|
||||
}
|
||||
|
||||
ast::view_path_glob(path, _) {
|
||||
print_simple_path(s, *path);
|
||||
word(s.s, "::*");
|
||||
}
|
||||
|
||||
ast::view_path_list(path, idents, _) {
|
||||
print_simple_path(s, *path);
|
||||
word(s.s, "::{");
|
||||
commasep(s, inconsistent, idents) {|s, w|
|
||||
word(s.s, w.node.name)
|
||||
}
|
||||
word(s.s, "}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn print_view_paths(s: ps, vps: [@ast::view_path]) {
|
||||
commasep(s, inconsistent, vps, print_view_path);
|
||||
}
|
||||
|
||||
fn print_view_item(s: ps, item: @ast::view_item) {
|
||||
hardbreak_if_not_bol(s);
|
||||
maybe_print_comment(s, item.span.lo);
|
||||
@ -1346,59 +1384,20 @@ fn print_view_item(s: ps, item: @ast::view_item) {
|
||||
pclose(s);
|
||||
}
|
||||
}
|
||||
ast::view_item_import(id, ids, _) {
|
||||
|
||||
ast::view_item_import(vps) {
|
||||
head(s, "import");
|
||||
if !str::eq(id, ids[vec::len(*ids) - 1u]) {
|
||||
word_space(s, id);
|
||||
word_space(s, "=");
|
||||
}
|
||||
let first = true;
|
||||
for elt: ast::ident in *ids {
|
||||
if first { first = false; } else { word(s.s, "::"); }
|
||||
word(s.s, elt);
|
||||
}
|
||||
print_view_paths(s, vps);
|
||||
}
|
||||
ast::view_item_import_from(mod_path, idents, _) {
|
||||
head(s, "import");
|
||||
for elt: ast::ident in *mod_path { word(s.s, elt); word(s.s, "::"); }
|
||||
word(s.s, "{");
|
||||
commasep(s, inconsistent, idents,
|
||||
fn@(s: ps, w: ast::import_ident) { word(s.s, w.node.name) });
|
||||
word(s.s, "}");
|
||||
}
|
||||
ast::view_item_import_glob(ids, _) {
|
||||
head(s, "import");
|
||||
let first = true;
|
||||
for elt: ast::ident in *ids {
|
||||
if first { first = false; } else { word(s.s, "::"); }
|
||||
word(s.s, elt);
|
||||
}
|
||||
word(s.s, "::*");
|
||||
}
|
||||
ast::view_item_export(ids, _) {
|
||||
|
||||
ast::view_item_export(vps) {
|
||||
head(s, "export");
|
||||
commasep(s, inconsistent, ids,
|
||||
fn@(s: ps, &&w: ast::ident) { word(s.s, w) });
|
||||
}
|
||||
ast::view_item_export_enum_none(id, _) {
|
||||
head(s, "export");
|
||||
word(s.s, id);
|
||||
word(s.s, "::{}");
|
||||
}
|
||||
ast::view_item_export_enum_some(id, ids, _) {
|
||||
head(s, "export");
|
||||
word(s.s, id);
|
||||
word(s.s, "::{");
|
||||
commasep(s, inconsistent, ids, fn@(s:ps, &&w: ast::import_ident) {
|
||||
word(s.s, w.node.name) });
|
||||
word(s.s, "}");
|
||||
print_view_paths(s, vps);
|
||||
}
|
||||
}
|
||||
word(s.s, ";");
|
||||
end(s); // end inner head-block
|
||||
|
||||
end(s); // end outer head-block
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,8 +0,0 @@
|
||||
// error-pattern:at least one import is required
|
||||
import spam::{};
|
||||
|
||||
mod spam {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
@ -1,2 +1,2 @@
|
||||
// error-pattern:cannot path into import list
|
||||
// error-pattern:expecting
|
||||
import foo::{bar}::baz
|
@ -1,4 +1,4 @@
|
||||
// error-pattern:can't rename import list
|
||||
// error-pattern:expecting
|
||||
|
||||
import baz = foo::{bar};
|
||||
|
||||
|
@ -1,2 +1,2 @@
|
||||
// error-pattern:cannot path into a glob
|
||||
// error-pattern:expecting
|
||||
import foo::*::bar
|
@ -1,4 +1,4 @@
|
||||
// error-pattern:globbed imports can't be renamed
|
||||
// error-pattern:expecting
|
||||
|
||||
import baz = foo::*;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user