rust/src/comp/middle/tstate/annotate.rs

493 lines
16 KiB
Rust
Raw Normal View History

import std::_vec;
import std::option;
import std::option::some;
import std::option::none;
import front::ast;
import front::ast::ident;
import front::ast::def_id;
import front::ast::ann;
import front::ast::item;
import front::ast::_fn;
import front::ast::_mod;
import front::ast::crate;
import front::ast::_obj;
import front::ast::ty_param;
import front::ast::item_fn;
import front::ast::item_obj;
import front::ast::item_ty;
import front::ast::item_tag;
import front::ast::item_const;
import front::ast::item_mod;
import front::ast::item_native_mod;
import front::ast::expr;
import front::ast::elt;
import front::ast::field;
import front::ast::decl;
import front::ast::decl_local;
import front::ast::decl_item;
import front::ast::initializer;
import front::ast::local;
import front::ast::arm;
import front::ast::expr_call;
import front::ast::expr_vec;
import front::ast::expr_tup;
import front::ast::expr_path;
import front::ast::expr_field;
import front::ast::expr_index;
import front::ast::expr_log;
import front::ast::expr_block;
import front::ast::expr_rec;
import front::ast::expr_if;
import front::ast::expr_binary;
import front::ast::expr_unary;
import front::ast::expr_assign;
import front::ast::expr_assign_op;
import front::ast::expr_while;
import front::ast::expr_do_while;
import front::ast::expr_alt;
import front::ast::expr_lit;
import front::ast::expr_ret;
import front::ast::expr_self_method;
import front::ast::expr_bind;
import front::ast::expr_spawn;
import front::ast::expr_ext;
import front::ast::expr_fail;
import front::ast::expr_break;
import front::ast::expr_cont;
import front::ast::expr_send;
import front::ast::expr_recv;
import front::ast::expr_put;
import front::ast::expr_port;
import front::ast::expr_chan;
import front::ast::expr_be;
import front::ast::expr_check;
import front::ast::expr_assert;
import front::ast::expr_cast;
import front::ast::expr_for;
import front::ast::expr_for_each;
import front::ast::stmt;
import front::ast::stmt_decl;
import front::ast::stmt_expr;
import front::ast::block;
import front::ast::block_;
import front::ast::method;
import middle::fold;
import middle::fold::respan;
import middle::fold::new_identity_fold;
import middle::fold::fold_crate;
import middle::fold::fold_item;
import middle::fold::fold_method;
import util::common::uistr;
import util::common::span;
import util::common::new_str_hash;
import middle::tstate::aux::fn_info;
import middle::tstate::aux::fn_info_map;
import middle::tstate::aux::num_locals;
import middle::tstate::aux::init_ann;
import middle::tstate::aux::init_blank_ann;
import middle::tstate::aux::get_fn_info;
fn item_fn_anns(&fn_info_map fm, &span sp, ident i, &_fn f,
vec[ty_param] ty_params, def_id id, ann a) -> @item {
assert (fm.contains_key(id));
auto f_info = fm.get(id);
log(i + " has " + uistr(num_locals(f_info)) + " local vars");
auto fld0 = new_identity_fold[fn_info]();
fld0 = @rec(fold_ann = bind init_ann(_,_)
with *fld0);
ret fold_item[fn_info]
(f_info, fld0, @respan(sp, item_fn(i, f, ty_params, id, a)));
}
/* FIXME: rewrite this with walk instead of fold */
/* This is painstakingly written as an explicit recursion b/c the
standard ast.fold doesn't traverse in the correct order:
consider
fn foo() {
fn bar() {
auto x = 5;
log(x);
}
}
With fold, first bar() would be processed and its subexps would
correctly be annotated with length-1 bit vectors.
But then, the process would be repeated with (fn bar()...) as
a subexp of foo, which has 0 local variables -- so then
the body of bar() would be incorrectly annotated with length-0 bit
vectors. */
fn annotate_exprs(&fn_info_map fm, &vec[@expr] es) -> vec[@expr] {
fn one(fn_info_map fm, &@expr e) -> @expr {
ret annotate_expr(fm, e);
}
auto f = bind one(fm,_);
ret _vec::map[@expr, @expr](f, es);
}
fn annotate_elts(&fn_info_map fm, &vec[elt] es) -> vec[elt] {
fn one(fn_info_map fm, &elt e) -> elt {
ret rec(mut=e.mut,
expr=annotate_expr(fm, e.expr));
}
auto f = bind one(fm,_);
ret _vec::map[elt, elt](f, es);
}
fn annotate_fields(&fn_info_map fm, &vec[field] fs) -> vec[field] {
fn one(fn_info_map fm, &field f) -> field {
ret rec(mut=f.mut,
ident=f.ident,
expr=annotate_expr(fm, f.expr));
}
auto f = bind one(fm,_);
ret _vec::map[field, field](f, fs);
}
fn annotate_option_exp(&fn_info_map fm, &option::t[@expr] o)
-> option::t[@expr] {
fn one(fn_info_map fm, &@expr e) -> @expr {
ret annotate_expr(fm, e);
}
auto f = bind one(fm,_);
ret option::map[@expr, @expr](f, o);
}
fn annotate_option_exprs(&fn_info_map fm, &vec[option::t[@expr]] es)
-> vec[option::t[@expr]] {
fn one(fn_info_map fm, &option::t[@expr] o) -> option::t[@expr] {
ret annotate_option_exp(fm, o);
}
auto f = bind one(fm,_);
ret _vec::map[option::t[@expr], option::t[@expr]](f, es);
}
fn annotate_decl(&fn_info_map fm, &@decl d) -> @decl {
auto d1 = d.node;
alt (d.node) {
case (decl_local(?l)) {
alt(l.init) {
case (some[initializer](?init)) {
let option::t[initializer] an_i =
some[initializer]
(rec(expr=annotate_expr(fm, init.expr)
with init));
let @local new_l = @rec(init=an_i with *l);
d1 = decl_local(new_l);
}
case (_) { /* do nothing */ }
}
}
case (decl_item(?item)) {
d1 = decl_item(annotate_item(fm, item));
}
}
ret @respan(d.span, d1);
}
fn annotate_alts(&fn_info_map fm, &vec[arm] alts) -> vec[arm] {
fn one(fn_info_map fm, &arm a) -> arm {
ret rec(pat=a.pat,
block=annotate_block(fm, a.block));
}
auto f = bind one(fm,_);
ret _vec::map[arm, arm](f, alts);
}
fn annotate_expr(&fn_info_map fm, &@expr e) -> @expr {
auto e1 = e.node;
alt (e.node) {
case (expr_vec(?es, ?m, ?a)) {
e1 = expr_vec(annotate_exprs(fm, es), m, a);
}
case (expr_tup(?es, ?a)) {
e1 = expr_tup(annotate_elts(fm, es), a);
}
case (expr_rec(?fs, ?maybe_e, ?a)) {
e1 = expr_rec(annotate_fields(fm, fs),
annotate_option_exp(fm, maybe_e), a);
}
case (expr_call(?e, ?es, ?a)) {
e1 = expr_call(annotate_expr(fm, e),
annotate_exprs(fm, es), a);
}
case (expr_self_method(_,_)) {
// no change
}
case (expr_bind(?e, ?maybe_es, ?a)) {
e1 = expr_bind(annotate_expr(fm, e),
annotate_option_exprs(fm, maybe_es),
a);
}
case (expr_spawn(?s, ?maybe_s, ?e, ?es, ?a)) {
e1 = expr_spawn(s, maybe_s, annotate_expr(fm, e),
annotate_exprs(fm, es), a);
}
case (expr_binary(?bop, ?w, ?x, ?a)) {
e1 = expr_binary(bop, annotate_expr(fm, w),
annotate_expr(fm, x), a);
}
case (expr_unary(?uop, ?w, ?a)) {
e1 = expr_unary(uop, annotate_expr(fm, w), a);
}
case (expr_lit(_,_)) {
/* no change */
}
case (expr_cast(?e,?t,?a)) {
e1 = expr_cast(annotate_expr(fm, e), t, a);
}
case (expr_if(?e, ?b, ?maybe_e, ?a)) {
e1 = expr_if(annotate_expr(fm, e),
annotate_block(fm, b),
annotate_option_exp(fm, maybe_e), a);
}
case (expr_while(?e, ?b, ?a)) {
e1 = expr_while(annotate_expr(fm, e),
annotate_block(fm, b), a);
}
case (expr_for(?d, ?e, ?b, ?a)) {
e1 = expr_for(annotate_decl(fm, d),
annotate_expr(fm, e),
annotate_block(fm, b), a);
}
case (expr_for_each(?d, ?e, ?b, ?a)) {
e1 = expr_for_each(annotate_decl(fm, d),
annotate_expr(fm, e),
annotate_block(fm, b), a);
}
case (expr_do_while(?b, ?e, ?a)) {
e1 = expr_do_while(annotate_block(fm, b),
annotate_expr(fm, e), a);
}
case (expr_alt(?e, ?alts, ?a)) {
e1 = expr_alt(annotate_expr(fm, e),
annotate_alts(fm, alts), a);
}
case (expr_block(?b, ?a)) {
e1 = expr_block(annotate_block(fm, b), a);
}
case (expr_assign(?l, ?r, ?a)) {
e1 = expr_assign(annotate_expr(fm, l), annotate_expr(fm, r), a);
}
case (expr_assign_op(?bop, ?l, ?r, ?a)) {
e1 = expr_assign_op(bop,
annotate_expr(fm, l), annotate_expr(fm, r), a);
}
case (expr_send(?l, ?r, ?a)) {
e1 = expr_send(annotate_expr(fm, l),
annotate_expr(fm, r), a);
}
case (expr_recv(?l, ?r, ?a)) {
e1 = expr_recv(annotate_expr(fm, l),
annotate_expr(fm, r), a);
}
case (expr_field(?e, ?i, ?a)) {
e1 = expr_field(annotate_expr(fm, e),
i, a);
}
case (expr_index(?e, ?sub, ?a)) {
e1 = expr_index(annotate_expr(fm, e),
annotate_expr(fm, sub), a);
}
case (expr_path(_,_)) {
/* no change */
}
case (expr_ext(?p, ?es, ?s_opt, ?e, ?a)) {
e1 = expr_ext(p, annotate_exprs(fm, es),
s_opt,
annotate_expr(fm, e), a);
}
/* no change, next 3 cases */
case (expr_fail(_)) { }
case (expr_break(_)) { }
case (expr_cont(_)) { }
case (expr_ret(?maybe_e, ?a)) {
e1 = expr_ret(annotate_option_exp(fm, maybe_e), a);
}
case (expr_put(?maybe_e, ?a)) {
e1 = expr_put(annotate_option_exp(fm, maybe_e), a);
}
case (expr_be(?e, ?a)) {
e1 = expr_be(annotate_expr(fm, e), a);
}
case (expr_log(?n, ?e, ?a)) {
e1 = expr_log(n, annotate_expr(fm, e), a);
}
case (expr_assert(?e, ?a)) {
e1 = expr_assert(annotate_expr(fm, e), a);
}
case (expr_check(?e, ?a)) {
e1 = expr_check(annotate_expr(fm, e), a);
}
case (expr_port(_)) { /* no change */ }
case (expr_chan(?e, ?a)) {
e1 = expr_chan(annotate_expr(fm, e), a);
}
}
ret @respan(e.span, e1);
}
fn annotate_stmt(&fn_info_map fm, &@stmt s) -> @stmt {
alt (s.node) {
case (stmt_decl(?d, ?a)) {
ret @respan(s.span, stmt_decl(annotate_decl(fm, d), a));
}
case (stmt_expr(?e, ?a)) {
ret @respan(s.span, stmt_expr(annotate_expr(fm, e), a));
}
}
}
fn annotate_block(&fn_info_map fm, &block b) -> block {
let vec[@stmt] new_stmts = [];
for (@stmt s in b.node.stmts) {
auto new_s = annotate_stmt(fm, s);
_vec::push[@stmt](new_stmts, new_s);
}
fn ann_e(fn_info_map fm, &@expr e) -> @expr {
ret annotate_expr(fm, e);
}
auto f = bind ann_e(fm,_);
auto new_e = option::map[@expr, @expr](f, b.node.expr);
ret respan(b.span,
rec(stmts=new_stmts, expr=new_e with b.node));
}
fn annotate_fn(&fn_info_map fm, &_fn f) -> _fn {
// subexps have *already* been annotated based on
// f's number-of-locals
ret rec(body=annotate_block(fm, f.body) with f);
}
fn annotate_mod(&fn_info_map fm, &_mod m) -> _mod {
let vec[@item] new_items = [];
for (@item i in m.items) {
auto new_i = annotate_item(fm, i);
_vec::push[@item](new_items, new_i);
}
ret rec(items=new_items with m);
}
fn annotate_method(&fn_info_map fm, &@method m) -> @method {
auto f_info = get_fn_info(fm, m.node.id);
auto fld0 = new_identity_fold[fn_info]();
fld0 = @rec(fold_ann = bind init_ann(_,_)
with *fld0);
auto outer = fold_method[fn_info](f_info, fld0, m);
auto new_fn = annotate_fn(fm, outer.node.meth);
ret @respan(m.span,
rec(meth=new_fn with m.node));
}
fn annotate_obj(&fn_info_map fm, &_obj o) -> _obj {
fn one(fn_info_map fm, &@method m) -> @method {
ret annotate_method(fm, m);
}
auto f = bind one(fm,_);
auto new_methods = _vec::map[@method, @method](f, o.methods);
auto new_dtor = option::map[@method, @method](f, o.dtor);
ret rec(methods=new_methods, dtor=new_dtor with o);
}
// Only annotates the components of the item recursively.
fn annotate_item_inner(&fn_info_map fm, &@item item) -> @item {
alt (item.node) {
/* FIXME can't skip this case -- exprs contain blocks contain stmts,
which contain decls */
case (item_const(_,_,_,_,_)) {
// this has already been annotated by annotate_item
ret item;
}
case (item_fn(?ident, ?ff, ?tps, ?id, ?ann)) {
ret @respan(item.span,
item_fn(ident, annotate_fn(fm, ff), tps, id, ann));
}
case (item_mod(?ident, ?mm, ?id)) {
ret @respan(item.span,
item_mod(ident, annotate_mod(fm, mm), id));
}
case (item_native_mod(?ident, ?mm, ?id)) {
ret item;
}
case (item_ty(_,_,_,_,_)) {
ret item;
}
case (item_tag(_,_,_,_,_)) {
ret item;
}
case (item_obj(?ident, ?ob, ?tps, ?odid, ?ann)) {
ret @respan(item.span,
item_obj(ident, annotate_obj(fm, ob), tps, odid, ann));
}
}
}
fn annotate_item(&fn_info_map fm, &@item item) -> @item {
// Using a fold, recursively set all anns in this item
// to be blank.
// *Then*, call annotate_item recursively to do the right
// thing for any nested items inside this one.
alt (item.node) {
case (item_const(_,_,_,_,_)) {
auto fld0 = new_identity_fold[()]();
fld0 = @rec(fold_ann = bind init_blank_ann(_,_)
with *fld0);
ret fold_item[()]((), fld0, item);
}
case (item_fn(?i,?ff,?tps,?id,?ann)) {
auto f_info = get_fn_info(fm, id);
auto fld0 = new_identity_fold[fn_info]();
fld0 = @rec(fold_ann = bind init_ann(_,_)
with *fld0);
auto outer = fold_item[fn_info](f_info, fld0, item);
// now recurse into any nested items
ret annotate_item_inner(fm, outer);
}
case (item_mod(?i, ?mm, ?id)) {
auto fld0 = new_identity_fold[()]();
fld0 = @rec(fold_ann = bind init_blank_ann(_,_)
with *fld0);
auto outer = fold_item[()]((), fld0, item);
ret annotate_item_inner(fm, outer);
}
case (item_native_mod(?i, ?nm, ?id)) {
ret item;
}
case (item_ty(_,_,_,_,_)) {
ret item;
}
case (item_tag(_,_,_,_,_)) {
ret item;
}
case (item_obj(?i,?ob,?tps,?odid,?ann)) {
auto fld0 = new_identity_fold[()]();
fld0 = @rec(fold_ann = bind init_blank_ann(_,_)
with *fld0);
auto outer = fold_item[()]((), fld0, item);
ret annotate_item_inner(fm, outer);
}
}
}
fn annotate_module(&fn_info_map fm, &_mod module) -> _mod {
let vec[@item] new_items = [];
for (@item i in module.items) {
auto new_item = annotate_item(fm, i);
_vec::push[@item](new_items, new_item);
}
ret rec(items = new_items with module);
}
fn annotate_crate(&fn_info_map fm, &@crate crate) -> @crate {
ret @respan(crate.span,
rec(module = annotate_module(fm, crate.node.module)
with crate.node));
}