diff --git a/src/comp/front/core_inject.rs b/src/comp/front/core_inject.rs index 07bb48b8b3e..b21967721c5 100644 --- a/src/comp/front/core_inject.rs +++ b/src/comp/front/core_inject.rs @@ -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; diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs index 7c93f7650f4..fca60dc3be7 100644 --- a/src/comp/middle/resolve.rs +++ b/src/comp/middle/resolve.rs @@ -100,8 +100,8 @@ enum mod_index_entry { type mod_index = hashmap>; -// 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, @@ -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::()}; - 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) { - 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) { 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::()}; - 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) { - 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::()}; + 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::()}; + 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 { fn lookup_in_mod_(e: env, def: glob_imp_def, sp: span, name: ident, ns: namespace, dr: dir) -> option { - 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>, id: ident, } } -fn index_mod(md: ast::_mod) -> mod_index { - let index = new_str_hash::>(); - for it: @ast::view_item in md.view_items { - alt it.node { +fn index_view_items(view_items: [@ast::view_item], + index: hashmap>) { + 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::>(); + + 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::>(); - 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); } + _ {} + } + } } } } - } - _ {} } } diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs index 3a365e58bbd..a76b6f9919f 100644 --- a/src/comp/syntax/ast.rs +++ b/src/comp/syntax/ast.rs @@ -441,26 +441,36 @@ type variant_ = {name: ident, attrs: [attribute], args: [variant_arg], type variant = spanned; -type view_item = spanned; // 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; -type import_ident = spanned; +type view_path = spanned; +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; 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 diff --git a/src/comp/syntax/ast_util.rs b/src/comp/syntax/ast_util.rs index cd508aae90b..09242f40c42 100644 --- a/src/comp/syntax/ast_util.rs +++ b/src/comp/syntax/ast_util.rs @@ -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 = 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 { diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index 1e21dff0b34..eb34fb4b89d 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -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::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); diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs index 343b4500a3d..3d0e8a579dc 100644 --- a/src/comp/syntax/print/pprust.rs +++ b/src/comp/syntax/print/pprust.rs @@ -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 - } diff --git a/src/test/compile-fail/import-from-none.rs b/src/test/compile-fail/import-from-none.rs deleted file mode 100644 index d80aa4f7ade..00000000000 --- a/src/test/compile-fail/import-from-none.rs +++ /dev/null @@ -1,8 +0,0 @@ -// error-pattern:at least one import is required -import spam::{}; - -mod spam { -} - -fn main() { -} \ No newline at end of file diff --git a/src/test/compile-fail/import-from-path.rs b/src/test/compile-fail/import-from-path.rs index 91ea6efdf2a..b8accfd0eb9 100644 --- a/src/test/compile-fail/import-from-path.rs +++ b/src/test/compile-fail/import-from-path.rs @@ -1,2 +1,2 @@ -// error-pattern:cannot path into import list +// error-pattern:expecting import foo::{bar}::baz \ No newline at end of file diff --git a/src/test/compile-fail/import-from-rename.rs b/src/test/compile-fail/import-from-rename.rs index e4aa78f6320..54a789cf902 100644 --- a/src/test/compile-fail/import-from-rename.rs +++ b/src/test/compile-fail/import-from-rename.rs @@ -1,4 +1,4 @@ -// error-pattern:can't rename import list +// error-pattern:expecting import baz = foo::{bar}; diff --git a/src/test/compile-fail/import-glob-path.rs b/src/test/compile-fail/import-glob-path.rs index 4a0c7582347..6204cc246c6 100644 --- a/src/test/compile-fail/import-glob-path.rs +++ b/src/test/compile-fail/import-glob-path.rs @@ -1,2 +1,2 @@ -// error-pattern:cannot path into a glob +// error-pattern:expecting import foo::*::bar \ No newline at end of file diff --git a/src/test/compile-fail/import-glob-rename.rs b/src/test/compile-fail/import-glob-rename.rs index e02f3bc84ab..9d08a0dad11 100644 --- a/src/test/compile-fail/import-glob-rename.rs +++ b/src/test/compile-fail/import-glob-rename.rs @@ -1,4 +1,4 @@ -// error-pattern:globbed imports can't be renamed +// error-pattern:expecting import baz = foo::*;