about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2012-02-17 23:05:20 -0800
committerGraydon Hoare <graydon@mozilla.com>2012-02-17 23:05:20 -0800
commitef6f6285893ca2546d740771b4c8046bfa68f668 (patch)
tree78c00965b1b06d7920ab4a64097bbf9c8b635b78
parent6f708968549b346611e8172b02612f3c32ca4feb (diff)
downloadrust-ef6f6285893ca2546d740771b4c8046bfa68f668.tar.gz
rust-ef6f6285893ca2546d740771b4c8046bfa68f668.zip
Refactor view_path to parse (but not yet process) export globs, unify code paths.
-rw-r--r--src/comp/front/core_inject.rs3
-rw-r--r--src/comp/middle/resolve.rs438
-rw-r--r--src/comp/syntax/ast.rs32
-rw-r--r--src/comp/syntax/ast_util.rs63
-rw-r--r--src/comp/syntax/parse/parser.rs183
-rw-r--r--src/comp/syntax/print/pprust.rs89
-rw-r--r--src/test/compile-fail/import-from-none.rs8
-rw-r--r--src/test/compile-fail/import-from-path.rs2
-rw-r--r--src/test/compile-fail/import-from-rename.rs2
-rw-r--r--src/test/compile-fail/import-glob-path.rs2
-rw-r--r--src/test/compile-fail/import-glob-rename.rs2
11 files changed, 423 insertions, 401 deletions
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<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); }
+                  _ {}
+                }
+              }
             }
           }
         }
-      }
-      _ {}
     }
 }
 
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<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 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),
 
-type import_ident = spanned<import_ident_>;
+    // 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
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<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 {
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::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");
-            }
+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::EQ {
+        // x = foo::bar
+        p.bump();
+        path = [parse_ident(p)];
+        while p.token == token::MOD_SEP {
             p.bump();
-          }
-          _ { p.fatal("expecting '::' or ';'"); }
+            let id = parse_ident(p);
+            path += [id];
         }
-        alt p.token {
-          token::IDENT(_, _) { identifiers += [parse_ident(p)]; }
-
-
-
-
+        let hi = p.span.hi;
+        ret @spanned(lo, hi,
+                     ast::view_path_simple(first_ident,
+                                           @path, p.get_id()));
+      }
 
-          //the lexer can't tell the different kinds of stars apart ) :
-          token::BINOP(token::STAR) {
-            glob = true;
+      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()));
+              }
 
-          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");
+              _ { break; }
             }
-            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());
         }
       }
+      _ { }
     }
+    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_full_import_name(p: parser, def_ident: ast::ident) ->
-   ast::view_item_ {
-    alt p.token {
-      token::IDENT(i, _) {
+fn parse_view_paths(p: parser) -> [@ast::view_path] {
+    let vp = [parse_view_path(p)];
+    while p.token == token::COMMA {
         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 {
-            p.bump();
-            ret parse_full_import_name(p, p.get_str(i));
-          }
-          _ { ret parse_rest_import_name(p, p.get_str(i), none); }
-        }
-      }
-      _ { p.fatal("expecting an identifier"); }
-    }
-}
-
-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());
-       }
+        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, _) {
-        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);
-        }
-      }
-      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, _) {
+
+      ast::view_item_import(vps) {
         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, "::*");
+        print_view_paths(s, vps);
       }
-      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::*;