rust/src/comp/syntax/visit.rs
Marijn Haverbeke 7114702496 Change the way block calls are parsed, mark them as block-calls.
This makes it possible to omit the semicolon after the block, and will
cause the pretty-printer to properly print such calls (if
pretty-printing of blocks wasn't so broken). Block calls (with the
block outside of the parentheses) can now only occur at statement
level, and their value can not be used. When calling a block-style
function that returns a useful value, the block must be put insde the
parentheses.

Issue #1054
2011-10-21 14:24:14 +02:00

463 lines
16 KiB
Rust

import ast::*;
import std::option;
import std::option::{none, some};
import codemap::span;
// Context-passing AST walker. Each overridden visit method has full control
// over what happens with its node, it can do its own traversal of the node's
// children (potentially passing in different contexts to each), call
// visit::visit_* to apply the default traversal algorithm (again, it can
// override the context), or prevent deeper traversal by doing nothing.
// Our typesystem doesn't do circular types, so the visitor record can not
// hold functions that take visitors. A vt tag is used to break the cycle.
tag vt<E> { mk_vt(visitor<E>); }
type visitor<E> =
// takes the components so that one function can be
// generic over constr and ty_constr
@{visit_mod: fn@(_mod, span, E, vt<E>),
visit_view_item: fn@(@view_item, E, vt<E>),
visit_native_item: fn@(@native_item, E, vt<E>),
visit_item: fn@(@item, E, vt<E>),
visit_local: fn@(@local, E, vt<E>),
visit_block: fn@(ast::blk, E, vt<E>),
visit_stmt: fn@(@stmt, E, vt<E>),
visit_arm: fn@(arm, E, vt<E>),
visit_pat: fn@(@pat, E, vt<E>),
visit_decl: fn@(@decl, E, vt<E>),
visit_expr: fn@(@expr, E, vt<E>),
visit_ty: fn@(@ty, E, vt<E>),
visit_constr: fn@(path, span, node_id, E, vt<E>),
visit_fn: fn@(_fn, [ty_param], span, fn_ident, node_id, E, vt<E>)};
fn default_visitor<E>() -> visitor<E> {
ret @{visit_mod: bind visit_mod::<E>(_, _, _, _),
visit_view_item: bind visit_view_item::<E>(_, _, _),
visit_native_item: bind visit_native_item::<E>(_, _, _),
visit_item: bind visit_item::<E>(_, _, _),
visit_local: bind visit_local::<E>(_, _, _),
visit_block: bind visit_block::<E>(_, _, _),
visit_stmt: bind visit_stmt::<E>(_, _, _),
visit_arm: bind visit_arm::<E>(_, _, _),
visit_pat: bind visit_pat::<E>(_, _, _),
visit_decl: bind visit_decl::<E>(_, _, _),
visit_expr: bind visit_expr::<E>(_, _, _),
visit_ty: bind visit_ty::<E>(_, _, _),
visit_constr: bind visit_constr::<E>(_, _, _, _, _),
visit_fn: bind visit_fn::<E>(_, _, _, _, _, _, _)};
}
fn visit_crate<E>(c: crate, e: E, v: vt<E>) {
v.visit_mod(c.node.module, c.span, e, v);
}
fn visit_crate_directive<E>(cd: @crate_directive, e: E, v: vt<E>) {
alt cd.node {
cdir_src_mod(_, _, _) { }
cdir_dir_mod(_, _, cdirs, _) {
for cdir: @crate_directive in cdirs {
visit_crate_directive(cdir, e, v);
}
}
cdir_view_item(vi) { v.visit_view_item(vi, e, v); }
cdir_syntax(_) { }
cdir_auth(_, _) { }
}
}
fn visit_mod<E>(m: _mod, _sp: span, e: E, v: vt<E>) {
for vi: @view_item in m.view_items { v.visit_view_item(vi, e, v); }
for i: @item in m.items { v.visit_item(i, e, v); }
}
fn visit_view_item<E>(_vi: @view_item, _e: E, _v: vt<E>) { }
fn visit_local<E>(loc: @local, e: E, v: vt<E>) {
v.visit_pat(loc.node.pat, e, v);
v.visit_ty(loc.node.ty, e, v);
alt loc.node.init { none. { } some(i) { v.visit_expr(i.expr, e, v); } }
}
fn visit_item<E>(i: @item, e: E, v: vt<E>) {
alt i.node {
item_const(t, ex) { v.visit_ty(t, e, v); v.visit_expr(ex, e, v); }
item_fn(f, tp) { v.visit_fn(f, tp, i.span, some(i.ident), i.id, e, v); }
item_mod(m) { v.visit_mod(m, i.span, e, v); }
item_native_mod(nm) {
for vi: @view_item in nm.view_items { v.visit_view_item(vi, e, v); }
for ni: @native_item in nm.items { v.visit_native_item(ni, e, v); }
}
item_ty(t, _) { v.visit_ty(t, e, v); }
item_res(f, dtor_id, tps, _) {
v.visit_fn(f, tps, i.span, some(i.ident), dtor_id, e, v);
}
item_tag(variants, _) {
for vr: variant in variants {
for va: variant_arg in vr.node.args { v.visit_ty(va.ty, e, v); }
}
}
item_obj(ob, _, _) {
for f: obj_field in ob.fields { v.visit_ty(f.ty, e, v); }
for m: @method in ob.methods {
v.visit_fn(m.node.meth, [], m.span, some(m.node.ident), m.node.id,
e, v);
}
}
}
}
fn visit_ty<E>(t: @ty, e: E, v: vt<E>) {
alt t.node {
ty_nil. {/* no-op */ }
ty_bot. {/* no-op */ }
ty_bool. {/* no-op */ }
ty_int. {/* no-op */ }
ty_float. {/* no-op */ }
ty_uint. {/* no-op */ }
ty_machine(_) {/* no-op */ }
ty_char. {/* no-op */ }
ty_str. {/* no-op */ }
ty_box(mt) { v.visit_ty(mt.ty, e, v); }
ty_uniq(mt) { v.visit_ty(mt.ty, e, v); }
ty_vec(mt) { v.visit_ty(mt.ty, e, v); }
ty_ptr(mt) { v.visit_ty(mt.ty, e, v); }
ty_port(t) { v.visit_ty(t, e, v); }
ty_chan(t) { v.visit_ty(t, e, v); }
ty_task. {/* no-op */ }
ty_rec(flds) {
for f: ty_field in flds { v.visit_ty(f.node.mt.ty, e, v); }
}
ty_tup(ts) { for tt in ts { v.visit_ty(tt, e, v); } }
ty_fn(_, args, out, _, constrs) {
for a: ty_arg in args { v.visit_ty(a.node.ty, e, v); }
for c: @constr in constrs {
v.visit_constr(c.node.path, c.span, c.node.id, e, v);
}
v.visit_ty(out, e, v);
}
ty_obj(tmeths) {
for m: ty_method in tmeths {
for a: ty_arg in m.node.inputs { v.visit_ty(a.node.ty, e, v); }
v.visit_ty(m.node.output, e, v);
}
}
ty_path(p, _) { for tp: @ty in p.node.types { v.visit_ty(tp, e, v); } }
ty_type. {/* no-op */ }
ty_constr(t, cs) {
v.visit_ty(t, e, v);
for tc: @spanned<constr_general_<path, node_id>> in cs {
v.visit_constr(tc.node.path, tc.span, tc.node.id, e, v);
}
}
ty_infer. {/* no-op */ }
}
}
fn visit_constr<E>(_operator: path, _sp: span, _id: node_id, _e: E,
_v: vt<E>) {
// default
}
fn visit_pat<E>(p: @pat, e: E, v: vt<E>) {
alt p.node {
pat_tag(path, children) {
for tp: @ty in path.node.types { v.visit_ty(tp, e, v); }
for child: @pat in children { v.visit_pat(child, e, v); }
}
pat_rec(fields, _) {
for f: field_pat in fields { v.visit_pat(f.pat, e, v); }
}
pat_tup(elts) { for elt in elts { v.visit_pat(elt, e, v); } }
pat_box(inner) { v.visit_pat(inner, e, v); }
pat_uniq(inner) { v.visit_pat(inner, e, v); }
_ { }
}
}
fn visit_native_item<E>(ni: @native_item, e: E, v: vt<E>) {
alt ni.node {
native_item_fn(_, fd, _) { visit_fn_decl(fd, e, v); }
native_item_ty. { }
}
}
fn visit_fn_decl<E>(fd: fn_decl, e: E, v: vt<E>) {
for a: arg in fd.inputs { v.visit_ty(a.ty, e, v); }
for c: @constr in fd.constraints {
v.visit_constr(c.node.path, c.span, c.node.id, e, v);
}
v.visit_ty(fd.output, e, v);
}
fn visit_fn<E>(f: _fn, _tp: [ty_param], _sp: span, _i: fn_ident, _id: node_id,
e: E, v: vt<E>) {
visit_fn_decl(f.decl, e, v);
v.visit_block(f.body, e, v);
}
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); }
visit_expr_opt(b.node.expr, e, v);
}
fn visit_stmt<E>(s: @stmt, e: E, v: vt<E>) {
alt s.node {
stmt_decl(d, _) { v.visit_decl(d, e, v); }
stmt_expr(ex, _) { v.visit_expr(ex, e, v); }
stmt_crate_directive(cd) { visit_crate_directive(cd, e, v); }
}
}
fn visit_decl<E>(d: @decl, e: E, v: vt<E>) {
alt d.node {
decl_local(locs) {
for (_, loc) in locs { v.visit_local(loc, e, v); }
}
decl_item(it) { v.visit_item(it, e, v); }
}
}
fn visit_expr_opt<E>(eo: option::t<@expr>, e: E, v: vt<E>) {
alt eo { none. { } some(ex) { v.visit_expr(ex, e, v); } }
}
fn visit_exprs<E>(exprs: [@expr], e: E, v: vt<E>) {
for ex: @expr in exprs { v.visit_expr(ex, e, v); }
}
fn visit_mac<E>(m: mac, e: E, v: vt<E>) {
alt m.node {
ast::mac_invoc(pth, arg, body) { visit_expr(arg, e, v); }
ast::mac_embed_type(ty) { v.visit_ty(ty, e, v); }
ast::mac_embed_block(blk) { v.visit_block(blk, e, v); }
ast::mac_ellipsis. { }
}
}
fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
alt ex.node {
expr_vec(es, _) { visit_exprs(es, e, v); }
expr_rec(flds, base) {
for f: field in flds { v.visit_expr(f.node.expr, e, v); }
visit_expr_opt(base, e, v);
}
expr_tup(elts) { for el in elts { v.visit_expr(el, e, v); } }
expr_call(callee, args, _) {
visit_exprs(args, e, v);
v.visit_expr(callee, e, v);
}
expr_self_method(_) { }
expr_bind(callee, args) {
v.visit_expr(callee, e, v);
for eo: option::t<@expr> in args { visit_expr_opt(eo, e, v); }
}
expr_binary(_, a, b) { v.visit_expr(a, e, v); v.visit_expr(b, e, v); }
expr_unary(_, a) { v.visit_expr(a, e, v); }
expr_lit(_) { }
expr_cast(x, t) { v.visit_expr(x, e, v); v.visit_ty(t, e, v); }
expr_if(x, b, eo) {
v.visit_expr(x, e, v);
v.visit_block(b, e, v);
visit_expr_opt(eo, e, v);
}
expr_if_check(x, b, eo) {
v.visit_expr(x, e, v);
v.visit_block(b, e, v);
visit_expr_opt(eo, e, v);
}
expr_ternary(c, t, el) {
v.visit_expr(c, e, v);
v.visit_expr(t, e, v);
v.visit_expr(el, e, v);
}
expr_while(x, b) { v.visit_expr(x, e, v); v.visit_block(b, e, v); }
expr_for(dcl, x, b) {
v.visit_local(dcl, e, v);
v.visit_expr(x, e, v);
v.visit_block(b, e, v);
}
expr_do_while(b, x) { v.visit_block(b, e, v); v.visit_expr(x, e, v); }
expr_alt(x, arms) {
v.visit_expr(x, e, v);
for a: arm in arms { v.visit_arm(a, e, v); }
}
expr_fn(f) { v.visit_fn(f, [], ex.span, none, ex.id, e, v); }
expr_block(b) { v.visit_block(b, e, v); }
expr_assign(a, b) { v.visit_expr(b, e, v); v.visit_expr(a, e, v); }
expr_copy(a) { v.visit_expr(a, e, v); }
expr_move(a, b) { v.visit_expr(b, e, v); v.visit_expr(a, e, v); }
expr_swap(a, b) { v.visit_expr(a, e, v); v.visit_expr(b, e, v); }
expr_assign_op(_, a, b) {
v.visit_expr(b, e, v);
v.visit_expr(a, e, v);
}
expr_field(x, _) { v.visit_expr(x, e, v); }
expr_index(a, b) { v.visit_expr(a, e, v); v.visit_expr(b, e, v); }
expr_path(p) { for tp: @ty in p.node.types { v.visit_ty(tp, e, v); } }
expr_fail(eo) { visit_expr_opt(eo, e, v); }
expr_break. { }
expr_cont. { }
expr_ret(eo) { visit_expr_opt(eo, e, v); }
expr_be(x) { v.visit_expr(x, e, v); }
expr_log(_, x) { v.visit_expr(x, e, v); }
expr_check(_, x) { v.visit_expr(x, e, v); }
expr_assert(x) { v.visit_expr(x, e, v); }
expr_anon_obj(anon_obj) {
alt anon_obj.fields {
none. { }
some(fields) {
for f: anon_obj_field in fields {
v.visit_ty(f.ty, e, v);
v.visit_expr(f.expr, e, v);
}
}
}
alt anon_obj.inner_obj {
none. { }
some(ex) { v.visit_expr(ex, e, v); }
}
for m: @method in anon_obj.methods {
v.visit_fn(m.node.meth, [], m.span, some(m.node.ident), m.node.id,
e, v);
}
}
expr_mac(mac) { visit_mac(mac, e, v); }
}
}
fn visit_arm<E>(a: arm, e: E, v: vt<E>) {
for p: @pat in a.pats { v.visit_pat(p, e, v); }
visit_expr_opt(a.guard, e, v);
v.visit_block(a.body, e, v);
}
// Simpler, non-context passing interface. Always walks the whole tree, simply
// calls the given functions on the nodes.
type simple_visitor =
// takes the components so that one function can be
// generic over constr and ty_constr
@{visit_mod: fn@(_mod, span),
visit_view_item: fn@(@view_item),
visit_native_item: fn@(@native_item),
visit_item: fn@(@item),
visit_local: fn@(@local),
visit_block: fn@(ast::blk),
visit_stmt: fn@(@stmt),
visit_arm: fn@(arm),
visit_pat: fn@(@pat),
visit_decl: fn@(@decl),
visit_expr: fn@(@expr),
visit_ty: fn@(@ty),
visit_constr: fn@(path, span, node_id),
visit_fn: fn@(_fn, [ty_param], span, fn_ident, node_id)};
fn default_simple_visitor() -> simple_visitor {
ret @{visit_mod: fn(_m: _mod, _sp: span) { },
visit_view_item: fn(_vi: @view_item) { },
visit_native_item: fn(_ni: @native_item) { },
visit_item: fn(_i: @item) { },
visit_local: fn(_l: @local) { },
visit_block: fn(_b: ast::blk) { },
visit_stmt: fn(_s: @stmt) { },
visit_arm: fn(_a: arm) { },
visit_pat: fn(_p: @pat) { },
visit_decl: fn(_d: @decl) { },
visit_expr: fn(_e: @expr) { },
visit_ty: fn(_t: @ty) { },
visit_constr: fn(_p: path, _sp: span, _id: node_id) { },
visit_fn:
fn(_f: _fn, _tps: [ty_param], _sp: span, _ident: fn_ident,
_id: node_id) {
}};
}
fn mk_simple_visitor(v: simple_visitor) -> vt<()> {
fn v_mod(f: fn@(_mod, span), m: _mod, sp: span, &&e: (), v: vt<()>) {
f(m, sp);
visit_mod(m, sp, e, v);
}
fn v_view_item(f: fn@(@view_item), vi: @view_item, &&e: (), v: vt<()>) {
f(vi);
visit_view_item(vi, e, v);
}
fn v_native_item(f: fn@(@native_item), ni: @native_item, &&e: (),
v: vt<()>) {
f(ni);
visit_native_item(ni, e, v);
}
fn v_item(f: fn@(@item), i: @item, &&e: (), v: vt<()>) {
f(i);
visit_item(i, e, v);
}
fn v_local(f: fn@(@local), l: @local, &&e: (), v: vt<()>) {
f(l);
visit_local(l, e, v);
}
fn v_block(f: fn@(ast::blk), bl: ast::blk, &&e: (), v: vt<()>) {
f(bl);
visit_block(bl, e, v);
}
fn v_stmt(f: fn@(@stmt), st: @stmt, &&e: (), v: vt<()>) {
f(st);
visit_stmt(st, e, v);
}
fn v_arm(f: fn@(arm), a: arm, &&e: (), v: vt<()>) {
f(a);
visit_arm(a, e, v);
}
fn v_pat(f: fn@(@pat), p: @pat, &&e: (), v: vt<()>) {
f(p);
visit_pat(p, e, v);
}
fn v_decl(f: fn@(@decl), d: @decl, &&e: (), v: vt<()>) {
f(d);
visit_decl(d, e, v);
}
fn v_expr(f: fn@(@expr), ex: @expr, &&e: (), v: vt<()>) {
f(ex);
visit_expr(ex, e, v);
}
fn v_ty(f: fn@(@ty), ty: @ty, &&e: (), v: vt<()>) {
f(ty);
visit_ty(ty, e, v);
}
fn v_constr(f: fn@(path, span, node_id), pt: path, sp: span, id: node_id,
&&e: (), v: vt<()>) {
f(pt, sp, id);
visit_constr(pt, sp, id, e, v);
}
fn v_fn(f: fn@(_fn, [ty_param], span, fn_ident, node_id), ff: _fn,
tps: [ty_param], sp: span, ident: fn_ident, id: node_id, &&e: (),
v: vt<()>) {
f(ff, tps, sp, ident, id);
visit_fn(ff, tps, sp, ident, id, e, v);
}
ret mk_vt(@{visit_mod: bind v_mod(v.visit_mod, _, _, _, _),
visit_view_item: bind v_view_item(v.visit_view_item, _, _, _),
visit_native_item:
bind v_native_item(v.visit_native_item, _, _, _),
visit_item: bind v_item(v.visit_item, _, _, _),
visit_local: bind v_local(v.visit_local, _, _, _),
visit_block: bind v_block(v.visit_block, _, _, _),
visit_stmt: bind v_stmt(v.visit_stmt, _, _, _),
visit_arm: bind v_arm(v.visit_arm, _, _, _),
visit_pat: bind v_pat(v.visit_pat, _, _, _),
visit_decl: bind v_decl(v.visit_decl, _, _, _),
visit_expr: bind v_expr(v.visit_expr, _, _, _),
visit_ty: bind v_ty(v.visit_ty, _, _, _),
visit_constr: bind v_constr(v.visit_constr, _, _, _, _, _),
visit_fn: bind v_fn(v.visit_fn, _, _, _, _, _, _, _)});
}
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End: