about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2011-11-23 20:57:34 +0100
committerMarijn Haverbeke <marijnh@gmail.com>2011-11-23 20:57:34 +0100
commite98286b5944c27cde4a5a268ff4ca926b40b8e76 (patch)
tree0c1f23fa08465a7048a87ff82336b101c4133f6e /src
parent03f6060e802e1acd8efe85b07bc98a97bf5caa7d (diff)
downloadrust-e98286b5944c27cde4a5a268ff4ca926b40b8e76.tar.gz
rust-e98286b5944c27cde4a5a268ff4ca926b40b8e76.zip
Allow import directives in any block
Closes #49
Diffstat (limited to 'src')
-rw-r--r--src/comp/front/config.rs3
-rw-r--r--src/comp/front/test.rs1
-rw-r--r--src/comp/middle/resolve.rs160
-rw-r--r--src/comp/syntax/ast.rs5
-rw-r--r--src/comp/syntax/ast_util.rs2
-rw-r--r--src/comp/syntax/fold.rs3
-rw-r--r--src/comp/syntax/parse/parser.rs7
-rw-r--r--src/comp/syntax/visit.rs3
-rw-r--r--src/test/run-pass/import-in-block.rs11
9 files changed, 113 insertions, 82 deletions
diff --git a/src/comp/front/config.rs b/src/comp/front/config.rs
index c227ca2c50f..955510864ea 100644
--- a/src/comp/front/config.rs
+++ b/src/comp/front/config.rs
@@ -70,7 +70,8 @@ fn fold_block(cfg: ast::crate_cfg, b: ast::blk_, fld: fold::ast_fold) ->
    ast::blk_ {
     let filter = bind filter_stmt(cfg, _);
     let filtered_stmts = vec::filter_map(filter, b.stmts);
-    ret {stmts: vec::map(fld.fold_stmt, filtered_stmts),
+    ret {view_items: b.view_items,
+         stmts: vec::map(fld.fold_stmt, filtered_stmts),
          expr: option::map(fld.fold_expr, b.expr),
          id: b.id,
          rules: b.rules};
diff --git a/src/comp/front/test.rs b/src/comp/front/test.rs
index 95c592eeada..d704045c990 100644
--- a/src/comp/front/test.rs
+++ b/src/comp/front/test.rs
@@ -348,6 +348,7 @@ fn mk_test_wrapper(cx: test_ctxt,
     };
 
     let wrapper_body: ast::blk = nospan({
+        view_items: [],
         stmts: [@call_stmt],
         expr: option::none,
         id: cx.next_node_id(),
diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs
index 5b1dca2a2f6..d5c70b35cef 100644
--- a/src/comp/middle/resolve.rs
+++ b/src/comp/middle/resolve.rs
@@ -37,7 +37,6 @@ tag scope {
     scope_fn(ast::fn_decl, ast::proto, [ast::ty_param]);
     scope_native_item(@ast::native_item);
     scope_loop(@ast::local); // there's only 1 decl per loop.
-
     scope_block(ast::blk, @mutable uint, @mutable uint);
     scope_arm(ast::arm);
 }
@@ -105,6 +104,7 @@ type env =
      ast_map: ast_map::map,
      imports: hashmap<ast::node_id, import_state>,
      mod_map: hashmap<ast::node_id, @indexed_mod>,
+     block_map: hashmap<ast::node_id, [glob_imp_def]>,
      ext_map: hashmap<def_id, [ident]>,
      ext_cache: ext_hash,
      used_imports: {mutable track: bool,
@@ -124,11 +124,12 @@ fn resolve_crate(sess: session, amap: ast_map::map, crate: @ast::crate) ->
    {def_map: def_map, ext_map: ext_map} {
     let e =
         @{cstore: sess.get_cstore(),
-          def_map: new_int_hash::<def>(),
+          def_map: new_int_hash(),
           ast_map: amap,
-          imports: new_int_hash::<import_state>(),
-          mod_map: new_int_hash::<@indexed_mod>(),
-          ext_map: new_def_hash::<[ident]>(),
+          imports: new_int_hash(),
+          mod_map: new_int_hash(),
+          block_map: new_int_hash(),
+          ext_map: new_def_hash(),
           ext_cache: new_ext_hash(),
           used_imports: {mutable track: false, mutable data:  []},
           mutable reported: [],
@@ -149,14 +150,14 @@ fn resolve_crate(sess: session, amap: ast_map::map, crate: @ast::crate) ->
 // 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, _, _, _)
-             with *visit::default_visitor::<scopes>()};
+          visit_item: bind index_i(e, _, _, _),
+          visit_block: visit_block_with_scope
+          with *visit::default_visitor::<scopes>()};
     visit::visit_crate(*c, cons(scope_crate, @nil), visit::mk_vt(v_map_mod));
-    // Register the top-level mod
 
+    // Register the top-level mod
     e.mod_map.insert(-1,
                      @{m: some(c.node.module),
                        index: index_mod(c.node.module),
@@ -200,38 +201,36 @@ fn map_crate(e: @env, c: @ast::crate) {
           _ { }
         }
     }
-    // Next, assemble the links for globbed imports.
 
+    // 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: visit_item_with_scope
-             with *visit::default_visitor::<scopes>()};
+          with *visit::default_visitor::<scopes>()};
     visit::visit_crate(*c, cons(scope_crate, @nil),
                        visit::mk_vt(v_link_glob));
     fn link_glob(e: @env, vi: @ast::view_item, sc: scopes, _v: vt<scopes>) {
-        fn find_mod(e: @env, sc: scopes) -> @indexed_mod {
-            alt sc {
-              cons(scope_item(i), tl) {
-                alt i.node {
-                  ast::item_mod(_) | ast::item_native_mod(_) {
-                    ret e.mod_map.get(i.id);
-                  }
-                  _ { be find_mod(e, *tl); }
-                }
-              }
-              _ {
-                ret e.mod_map.get(-1); //top-level
-
-              }
-            }
-        }
         alt vi.node {
           //if it really is a glob import, that is
           ast::view_item_import_glob(path, _) {
             let imp = follow_import(*e, sc, path, vi.span);
             if option::is_some(imp) {
-                find_mod(e, sc).glob_imports +=
-                    [{def: option::get(imp), item: vi}];
+                let glob = {def: option::get(imp), item: vi};;
+                alt sc {
+                  cons(scope_item(i), _) {
+                    e.mod_map.get(i.id).glob_imports += [glob];
+                  }
+                  cons(scope_block(b, _, _), _) {
+                    let globs = alt e.block_map.find(b.node.id) {
+                      some(globs) { globs + [glob] } none. { [glob] }
+                    };
+                    e.block_map.insert(b.node.id, globs);
+                  }
+                  nil. {
+                    e.mod_map.get(-1).glob_imports += [glob];
+                  }
+                }
             }
           }
           _ { }
@@ -370,6 +369,7 @@ fn visit_fn_with_scope(e: @env, f: ast::_fn, tp: [ast::ty_param], sp: span,
 fn visit_block_with_scope(b: ast::blk, sc: scopes, v: vt<scopes>) {
     let pos = @mutable 0u, loc = @mutable 0u;
     let block_sc = cons(scope_block(b, pos, loc), @sc);
+    for vi in b.node.view_items { v.visit_view_item(vi, block_sc, v); }
     for stmt in b.node.stmts {
         v.visit_stmt(stmt, block_sc, v);;
         *pos += 1u;;
@@ -426,9 +426,8 @@ fn follow_import(e: env, sc: scopes, path: [ident], sp: span) ->
         alt option::get(dcur) {
           ast::def_mod(_) | ast::def_native_mod(_) { ret dcur; }
           _ {
-            e.sess.span_err(sp,
-                            str::connect(path, "::") +
-                                " does not name a module.");
+            e.sess.span_err(sp, str::connect(path, "::") +
+                            " does not name a module.");
             ret none;
           }
         }
@@ -678,7 +677,7 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace)
             }
           }
           scope_block(b, pos, loc) {
-            ret lookup_in_block(name, b.node, *pos, *loc, ns);
+            ret lookup_in_block(e, name, sp, b.node, *pos, *loc, ns);
           }
           scope_arm(a) {
             if ns == ns_value {
@@ -793,8 +792,8 @@ fn lookup_in_obj(name: ident, ob: ast::_obj, ty_params: [ast::ty_param],
     }
 }
 
-fn lookup_in_block(name: ident, b: ast::blk_, pos: uint, loc_pos: uint,
-                   ns: namespace) -> option::t<def> {
+fn lookup_in_block(e: env, name: ident, sp: span, b: ast::blk_, pos: uint,
+                   loc_pos: uint, ns: namespace) -> option::t<def> {
     let i = vec::len(b.stmts);
     while i > 0u {
         i -= 1u;
@@ -849,7 +848,30 @@ fn lookup_in_block(name: ident, b: ast::blk_, pos: uint, loc_pos: uint,
           _ { }
         }
     }
-    ret none::<def>;
+    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_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; }
+              }
+              _ {}
+            }
+          }
+        }
+    }
+    ret none;
 }
 
 fn found_def_item(i: @ast::item, ns: namespace) -> option::t<def> {
@@ -991,57 +1013,51 @@ fn lookup_in_local_mod(e: env, node_id: node_id, sp: span, id: ident,
         }
       }
     }
-
     // not local or explicitly imported; try globs:
     ret lookup_glob_in_mod(e, info, sp, id, ns, outside);
 }
 
-fn lookup_glob_in_mod(e: env, info: @indexed_mod, sp: span, id: ident,
-                      wanted_ns: namespace, dr: dir) -> option::t<def> {
-    fn per_ns(e: env, info: @indexed_mod, sp: span, id: ident, ns: namespace,
-              dr: dir) -> option::t<def> {
-
-        fn lookup_in_mod_(e: env, def: glob_imp_def, sp: span, name: ident,
-                          ns: namespace, dr: dir) -> option::t<glob_imp_def> {
-            alt lookup_in_mod(e, def.def, sp, name, ns, dr) {
-              option::some(d) { option::some({def: d, item: def.item}) }
-              option::none. { option::none }
-            }
+fn lookup_in_globs(e: env, globs: [glob_imp_def], sp: span, id: ident,
+                   ns: namespace, dr: dir) -> option::t<def> {
+    fn lookup_in_mod_(e: env, def: glob_imp_def, sp: span, name: ident,
+                      ns: namespace, dr: dir) -> option::t<glob_imp_def> {
+        alt lookup_in_mod(e, def.def, sp, name, ns, dr) {
+          option::some(d) { option::some({def: d, item: def.item}) }
+          option::none. { option::none }
         }
-
-        let matches =
-            vec::filter_map(bind lookup_in_mod_(e, _, sp, id, ns, dr),
-                            { info.glob_imports });
-        if vec::len(matches) == 0u {
-            ret none;
-        } else if vec::len(matches) == 1u {
-            ret some(matches[0].def);
-        } else {
-            for match: glob_imp_def in matches {
-                let sp = match.item.span;
-                e.sess.span_note(sp, #fmt["'%s' is imported here", id]);
-            }
-            e.sess.span_fatal(sp,
-                              "'" + id + "' is glob-imported from" +
-                                  " multiple different modules.");
+    }
+    let matches =
+        vec::filter_map(bind lookup_in_mod_(e, _, sp, id, ns, dr),
+                        { globs });
+    if vec::len(matches) == 0u {
+        ret none;
+    } else if vec::len(matches) == 1u {
+        ret some(matches[0].def);
+    } else {
+        for match: glob_imp_def in matches {
+            let sp = match.item.span;
+            e.sess.span_note(sp, #fmt["'%s' is imported here", id]);
         }
+        e.sess.span_fatal(sp, "'" + id + "' is glob-imported from" +
+                          " multiple different modules.");
     }
+}
+
+fn lookup_glob_in_mod(e: env, info: @indexed_mod, sp: span, id: ident,
+                      wanted_ns: namespace, dr: dir) -> option::t<def> {
     // since we don't know what names we have in advance,
     // absence takes the place of todo()
-
     if !info.glob_imported_names.contains_key(id) {
         info.glob_imported_names.insert(id, resolving(sp));
-        let val = per_ns(e, info, sp, id, ns_value, dr);
-        let typ = per_ns(e, info, sp, id, ns_type, dr);
-        let md = per_ns(e, info, sp, id, ns_module, dr);
+        let val = lookup_in_globs(e, info.glob_imports, sp, id, ns_value, dr);
+        let typ = lookup_in_globs(e, info.glob_imports, sp, id, ns_type, dr);
+        let md = lookup_in_globs(e, info.glob_imports, sp, id, ns_module, dr);
         info.glob_imported_names.insert(id, resolved(val, typ, md, id, sp));
     }
     alt info.glob_imported_names.get(id) {
       todo(_, _, _, _, _) { e.sess.bug("Shouldn't've put a todo in."); }
-      resolving(sp) {
-        ret none::<def>; //circularity is okay in import globs
-
-      }
+      //circularity is okay in import globs
+      resolving(sp) { ret none::<def>; }
       resolved(val, typ, md, _, _) {
         ret alt wanted_ns {
               ns_value. { val }
diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs
index b1e1a16c6af..ecba4efceca 100644
--- a/src/comp/syntax/ast.rs
+++ b/src/comp/syntax/ast.rs
@@ -76,9 +76,8 @@ tag meta_item_ {
 
 type blk = spanned<blk_>;
 
-type blk_ =
-    {stmts: [@stmt], expr: option::t<@expr>, id: node_id,
-     rules: blk_check_mode};
+type blk_ = {view_items: [@view_item], stmts: [@stmt], expr: option::t<@expr>,
+             id: node_id, rules: blk_check_mode};
 
 type pat = {id: node_id, node: pat_, span: span};
 
diff --git a/src/comp/syntax/ast_util.rs b/src/comp/syntax/ast_util.rs
index 862d182b9fd..2b574ae1cbe 100644
--- a/src/comp/syntax/ast_util.rs
+++ b/src/comp/syntax/ast_util.rs
@@ -199,7 +199,7 @@ fn block_from_expr(e: @expr) -> blk {
 
 fn default_block(stmts1: [@stmt], expr1: option::t<@expr>, id1: node_id) ->
    blk_ {
-    ret {stmts: stmts1, expr: expr1, id: id1, rules: default_blk};
+    {view_items: [], stmts: stmts1, expr: expr1, id: id1, rules: default_blk}
 }
 
 fn obj_field_from_anon_obj_field(f: anon_obj_field) -> obj_field {
diff --git a/src/comp/syntax/fold.rs b/src/comp/syntax/fold.rs
index 956f9e538f0..f9c23b4de25 100644
--- a/src/comp/syntax/fold.rs
+++ b/src/comp/syntax/fold.rs
@@ -247,7 +247,8 @@ fn noop_fold_method(m: method_, fld: ast_fold) -> method_ {
 
 
 fn noop_fold_block(b: blk_, fld: ast_fold) -> blk_ {
-    ret {stmts: vec::map(fld.fold_stmt, b.stmts),
+    ret {view_items: vec::map(fld.fold_view_item, b.view_items),
+         stmts: vec::map(fld.fold_stmt, b.stmts),
          expr: option::map(fld.fold_expr, b.expr),
          id: b.id,
          rules: b.rules};
diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs
index 391d5eb8819..df769033028 100644
--- a/src/comp/syntax/parse/parser.rs
+++ b/src/comp/syntax/parse/parser.rs
@@ -1697,8 +1697,8 @@ fn parse_block_no_value(p: parser) -> ast::blk {
 // necessary, and this should take a qualifier.
 // some blocks start with "#{"...
 fn parse_block_tail(p: parser, lo: uint, s: ast::blk_check_mode) -> ast::blk {
-    let stmts: [@ast::stmt] = [];
-    let expr: option::t<@ast::expr> = none;
+    let view_items = [], stmts = [], expr = none;
+    while is_word(p, "import") { view_items += [parse_view_item(p)]; }
     while p.peek() != token::RBRACE {
         alt p.peek() {
           token::SEMI. {
@@ -1736,7 +1736,8 @@ fn parse_block_tail(p: parser, lo: uint, s: ast::blk_check_mode) -> ast::blk {
     }
     let hi = p.get_hi_pos();
     p.bump();
-    let bloc = {stmts: stmts, expr: expr, id: p.get_id(), rules: s};
+    let bloc = {view_items: view_items, stmts: stmts, expr: expr,
+                id: p.get_id(), rules: s};
     ret spanned(lo, hi, bloc);
 }
 
diff --git a/src/comp/syntax/visit.rs b/src/comp/syntax/visit.rs
index 7430c28b749..5273d16e544 100644
--- a/src/comp/syntax/visit.rs
+++ b/src/comp/syntax/visit.rs
@@ -200,7 +200,8 @@ fn visit_fn<E>(f: _fn, _tp: [ty_param], _sp: span, _i: fn_ident, _id: node_id,
 }
 
 fn visit_block<E>(b: ast::blk, e: E, v: vt<E>) {
-    for s: @stmt in b.node.stmts { v.visit_stmt(s, e, v); }
+    for vi in b.node.view_items { v.visit_view_item(vi, e, v); }
+    for s in b.node.stmts { v.visit_stmt(s, e, v); }
     visit_expr_opt(b.node.expr, e, v);
 }
 
diff --git a/src/test/run-pass/import-in-block.rs b/src/test/run-pass/import-in-block.rs
new file mode 100644
index 00000000000..fae30afa4ad
--- /dev/null
+++ b/src/test/run-pass/import-in-block.rs
@@ -0,0 +1,11 @@
+use std;
+
+fn main() {
+    import std::vec;
+    import vec::to_mut;
+    log vec::len(to_mut([1, 2]));
+    {
+        import vec::*;
+        log len([2]);
+    }
+}