Port freevars.rs from oldvisit to <V:Visitor> trait.

This commit is contained in:
Felix S. Klock II 2013-08-13 13:37:54 +02:00
parent 6986361776
commit 35b1fc5c8b

View file

@ -17,7 +17,10 @@ use middle::ty;
use std::hashmap::HashMap;
use syntax::codemap::span;
use syntax::{ast, ast_util, oldvisit};
use syntax::{ast, ast_util};
use syntax::visit;
use syntax::visit::Visitor;
use syntax::ast::{item};
// A vector of defs representing the free variables referred to in a function.
// (The def_upvar will already have been stripped).
@ -29,27 +32,27 @@ pub struct freevar_entry {
pub type freevar_info = @~[@freevar_entry];
pub type freevar_map = @mut HashMap<ast::NodeId, freevar_info>;
// Searches through part of the AST for all references to locals or
// upvars in this frame and returns the list of definition IDs thus found.
// Since we want to be able to collect upvars in some arbitrary piece
// of the AST, we take a walker function that we invoke with a visitor
// in order to start the search.
fn collect_freevars(def_map: resolve::DefMap, blk: &ast::Block)
-> freevar_info {
let seen = @mut HashMap::new();
let refs = @mut ~[];
struct CollectFreevarsVisitor {
seen: @mut HashMap<ast::NodeId, ()>,
refs: @mut ~[@freevar_entry],
def_map: resolve::DefMap,
}
fn ignore_item(_i: @ast::item, (_depth, _v): (int, oldvisit::vt<int>)) { }
impl Visitor<int> for CollectFreevarsVisitor {
fn visit_item(&mut self, _:@item, _:int) {
// ignore_item
}
fn visit_expr(&mut self, expr:@ast::expr, depth:int) {
let walk_expr: @fn(expr: @ast::expr, (int, oldvisit::vt<int>)) =
|expr, (depth, v)| {
match expr.node {
ast::expr_fn_block(*) => {
oldvisit::visit_expr(expr, (depth + 1, v))
visit::walk_expr(self, expr, depth + 1)
}
ast::expr_path(*) | ast::expr_self => {
let mut i = 0;
match def_map.find(&expr.id) {
match self.def_map.find(&expr.id) {
None => fail!("path not found"),
Some(&df) => {
let mut def = df;
@ -62,28 +65,58 @@ fn collect_freevars(def_map: resolve::DefMap, blk: &ast::Block)
}
if i == depth { // Made it to end of loop
let dnum = ast_util::def_id_of_def(def).node;
if !seen.contains_key(&dnum) {
refs.push(@freevar_entry {
if !self.seen.contains_key(&dnum) {
self.refs.push(@freevar_entry {
def: def,
span: expr.span,
});
seen.insert(dnum, ());
self.seen.insert(dnum, ());
}
}
}
}
}
_ => oldvisit::visit_expr(expr, (depth, v))
_ => visit::walk_expr(self, expr, depth)
}
};
}
let v = oldvisit::mk_vt(@oldvisit::Visitor {visit_item: ignore_item,
visit_expr: walk_expr,
.. *oldvisit::default_visitor()});
(v.visit_block)(blk, (1, v));
}
// Searches through part of the AST for all references to locals or
// upvars in this frame and returns the list of definition IDs thus found.
// Since we want to be able to collect upvars in some arbitrary piece
// of the AST, we take a walker function that we invoke with a visitor
// in order to start the search.
fn collect_freevars(def_map: resolve::DefMap, blk: &ast::Block)
-> freevar_info {
let seen = @mut HashMap::new();
let refs = @mut ~[];
let mut v = CollectFreevarsVisitor {
seen: seen,
refs: refs,
def_map: def_map,
};
v.visit_block(blk, 1);
return @(*refs).clone();
}
struct AnnotateFreevarsVisitor {
def_map: resolve::DefMap,
freevars: freevar_map,
}
impl Visitor<()> for AnnotateFreevarsVisitor {
fn visit_fn(&mut self, fk:&visit::fn_kind, fd:&ast::fn_decl,
blk:&ast::Block, s:span, nid:ast::NodeId, _:()) {
let vars = collect_freevars(self.def_map, blk);
self.freevars.insert(nid, vars);
visit::walk_fn(self, fk, fd, blk, s, nid, ());
}
}
// Build a map from every function and for-each body to a set of the
// freevars contained in it. The implementation is not particularly
// efficient as it fully recomputes the free variables at every
@ -93,20 +126,11 @@ pub fn annotate_freevars(def_map: resolve::DefMap, crate: &ast::Crate) ->
freevar_map {
let freevars = @mut HashMap::new();
let walk_fn: @fn(&oldvisit::fn_kind,
&ast::fn_decl,
&ast::Block,
span,
ast::NodeId) = |_, _, blk, _, nid| {
let vars = collect_freevars(def_map, blk);
freevars.insert(nid, vars);
let mut visitor = AnnotateFreevarsVisitor {
def_map: def_map,
freevars: freevars,
};
let visitor =
oldvisit::mk_simple_visitor(@oldvisit::SimpleVisitor {
visit_fn: walk_fn,
.. *oldvisit::default_simple_visitor()});
oldvisit::visit_crate(crate, ((), visitor));
visit::walk_crate(&mut visitor, crate, ());
return freevars;
}