Allow import directives in any block

Closes #49
This commit is contained in:
Marijn Haverbeke 2011-11-23 20:57:34 +01:00
parent 03f6060e80
commit e98286b594
9 changed files with 114 additions and 83 deletions

View File

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

View File

@ -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(),

View File

@ -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 }
}
}
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.");
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),
{ 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 }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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