Refactor view_path to parse (but not yet process) export globs, unify code paths.

This commit is contained in:
Graydon Hoare 2012-02-17 23:05:20 -08:00
parent 6f70896854
commit ef6f628589
11 changed files with 431 additions and 409 deletions

View file

@ -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;

View file

@ -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); }
_ {}
}
}
}
}
}
}
_ {}
}
}

View file

@ -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

View file

@ -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 {

View file

@ -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);

View file

@ -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
}

View file

@ -1,8 +0,0 @@
// error-pattern:at least one import is required
import spam::{};
mod spam {
}
fn main() {
}

View file

@ -1,2 +1,2 @@
// error-pattern:cannot path into import list
// error-pattern:expecting
import foo::{bar}::baz

View file

@ -1,4 +1,4 @@
// error-pattern:can't rename import list
// error-pattern:expecting
import baz = foo::{bar};

View file

@ -1,2 +1,2 @@
// error-pattern:cannot path into a glob
// error-pattern:expecting
import foo::*::bar

View file

@ -1,4 +1,4 @@
// error-pattern:globbed imports can't be renamed
// error-pattern:expecting
import baz = foo::*;