Move everything syntax-related to syntax/, break deps on rest of compiler
src/comp/syntax is currently just a sub-module of rustc, but it will, in the near future, be its own crate. This includes: - The AST data structure - The parser - The pretty-printer - Visit, walk, and fold - The syntax extension system - Some utility stuff that should be in the stdlib* *) Stdlib extensions currently require a snapshot before they can be used, and the win build is very broken right now. This is temporary and will be cleaned up when one of those problems goes away. A lot of code was moved by this patch, mostly towards a more organized layout. Some package paths did get longer, and I guess the new layout will take some getting used to. Sorry about that! Please try not to re-introduce any dependencies in syntax/ on any of the other src/comp/ subdirs.
This commit is contained in:
parent
c59ebf0f01
commit
6fd6fdea93
54 changed files with 1254 additions and 1203 deletions
29
src/comp/syntax/_std.rs
Normal file
29
src/comp/syntax/_std.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
// FIXME all this stuff should be in the standard lib, and in fact is,
|
||||
// but due to the way our snapshots currently work, rustc can't use it
|
||||
// until after the next snapshot.
|
||||
|
||||
fn new_str_hash[V]() -> std::map::hashmap[str, V] {
|
||||
let std::map::hashfn[str] hasher = std::str::hash;
|
||||
let std::map::eqfn[str] eqer = std::str::eq;
|
||||
ret std::map::mk_hashmap[str, V](hasher, eqer);
|
||||
}
|
||||
|
||||
fn new_int_hash[V]() -> std::map::hashmap[int, V] {
|
||||
fn hash_int(&int x) -> uint { ret x as uint; }
|
||||
fn eq_int(&int a, &int b) -> bool { ret a == b; }
|
||||
auto hasher = hash_int;
|
||||
auto eqer = eq_int;
|
||||
ret std::map::mk_hashmap[int, V](hasher, eqer);
|
||||
}
|
||||
|
||||
fn new_uint_hash[V]() -> std::map::hashmap[uint, V] {
|
||||
fn hash_uint(&uint x) -> uint { ret x; }
|
||||
fn eq_uint(&uint a, &uint b) -> bool { ret a == b; }
|
||||
auto hasher = hash_uint;
|
||||
auto eqer = eq_uint;
|
||||
ret std::map::mk_hashmap[uint, V](hasher, eqer);
|
||||
}
|
||||
|
||||
fn istr(int i) -> str { ret std::int::to_str(i, 10u); }
|
||||
|
||||
fn uistr(uint i) -> str { ret std::uint::to_str(i, 10u); }
|
||||
654
src/comp/syntax/ast.rs
Normal file
654
src/comp/syntax/ast.rs
Normal file
|
|
@ -0,0 +1,654 @@
|
|||
|
||||
import std::option;
|
||||
import std::str;
|
||||
import std::vec;
|
||||
import codemap::span;
|
||||
import codemap::filename;
|
||||
|
||||
type spanned[T] = rec(T node, span span);
|
||||
fn respan[T](&span sp, &T t) -> spanned[T] { ret rec(node=t, span=sp); }
|
||||
|
||||
type ident = str;
|
||||
// Functions may or may not have names.
|
||||
type fn_ident = option::t[ident];
|
||||
|
||||
// FIXME: with typestate constraint, could say
|
||||
// idents and types are the same length, and are
|
||||
// non-empty
|
||||
type path_ = rec(vec[ident] idents, vec[@ty] types);
|
||||
|
||||
type path = spanned[path_];
|
||||
|
||||
fn path_name(&path p) -> str { ret str::connect(p.node.idents, "::"); }
|
||||
|
||||
type crate_num = int;
|
||||
type node_id = int;
|
||||
type def_id = tup(crate_num, node_id);
|
||||
|
||||
const crate_num local_crate = 0;
|
||||
fn local_def(node_id id) -> def_id {
|
||||
ret tup(local_crate, id);
|
||||
}
|
||||
|
||||
type ty_param = ident;
|
||||
|
||||
tag def {
|
||||
def_fn(def_id, purity);
|
||||
def_obj_field(def_id);
|
||||
def_mod(def_id);
|
||||
def_native_mod(def_id);
|
||||
def_const(def_id);
|
||||
def_arg(def_id);
|
||||
def_local(def_id);
|
||||
def_variant(def_id, /* tag */def_id);
|
||||
|
||||
/* variant */
|
||||
def_ty(def_id);
|
||||
def_ty_arg(uint);
|
||||
def_binding(def_id);
|
||||
def_use(def_id);
|
||||
def_native_ty(def_id);
|
||||
def_native_fn(def_id);
|
||||
}
|
||||
|
||||
fn variant_def_ids(&def d) -> tup(def_id, def_id) {
|
||||
alt (d) {
|
||||
case (def_variant(?tag_id, ?var_id)) { ret tup(tag_id, var_id); }
|
||||
}
|
||||
}
|
||||
|
||||
fn def_id_of_def(def d) -> def_id {
|
||||
alt (d) {
|
||||
case (def_fn(?id,_)) { ret id; }
|
||||
case (def_obj_field(?id)) { ret id; }
|
||||
case (def_mod(?id)) { ret id; }
|
||||
case (def_native_mod(?id)) { ret id; }
|
||||
case (def_const(?id)) { ret id; }
|
||||
case (def_arg(?id)) { ret id; }
|
||||
case (def_local(?id)) { ret id; }
|
||||
case (def_variant(_, ?id)) { ret id; }
|
||||
case (def_ty(?id)) { ret id; }
|
||||
case (def_ty_arg(_)) { fail; }
|
||||
case (def_binding(?id)) { ret id; }
|
||||
case (def_use(?id)) { ret id; }
|
||||
case (def_native_ty(?id)) { ret id; }
|
||||
case (def_native_fn(?id)) { ret id; }
|
||||
}
|
||||
fail;
|
||||
}
|
||||
|
||||
// The set of meta_items that define the compilation environment of the crate,
|
||||
// used to drive conditional compilation
|
||||
type crate_cfg = vec[@meta_item];
|
||||
|
||||
type crate = spanned[crate_];
|
||||
|
||||
type crate_ = rec(vec[@crate_directive] directives,
|
||||
_mod module,
|
||||
vec[attribute] attrs,
|
||||
crate_cfg config);
|
||||
|
||||
tag crate_directive_ {
|
||||
cdir_src_mod(ident, option::t[filename], vec[attribute]);
|
||||
cdir_dir_mod(ident, option::t[filename],
|
||||
vec[@crate_directive], vec[attribute]);
|
||||
cdir_view_item(@view_item);
|
||||
cdir_syntax(path);
|
||||
cdir_auth(path, _auth);
|
||||
}
|
||||
|
||||
type crate_directive = spanned[crate_directive_];
|
||||
|
||||
type meta_item = spanned[meta_item_];
|
||||
|
||||
tag meta_item_ {
|
||||
meta_word(ident);
|
||||
meta_list(ident, vec[@meta_item]);
|
||||
meta_name_value(ident, str);
|
||||
}
|
||||
|
||||
type block = spanned[block_];
|
||||
|
||||
type block_ = rec(vec[@stmt] stmts, option::t[@expr] expr, node_id id);
|
||||
|
||||
type pat = rec(node_id id,
|
||||
pat_ node,
|
||||
span span);
|
||||
|
||||
tag pat_ {
|
||||
pat_wild;
|
||||
pat_bind(ident);
|
||||
pat_lit(@lit);
|
||||
pat_tag(path, vec[@pat]);
|
||||
}
|
||||
|
||||
tag mutability { mut; imm; maybe_mut; }
|
||||
|
||||
tag layer { layer_value; layer_state; layer_gc; }
|
||||
|
||||
tag _auth { auth_unsafe; }
|
||||
|
||||
tag proto { proto_iter; proto_fn; }
|
||||
|
||||
tag binop {
|
||||
add;
|
||||
sub;
|
||||
mul;
|
||||
div;
|
||||
rem;
|
||||
and;
|
||||
or;
|
||||
bitxor;
|
||||
bitand;
|
||||
bitor;
|
||||
lsl;
|
||||
lsr;
|
||||
asr;
|
||||
eq;
|
||||
lt;
|
||||
le;
|
||||
ne;
|
||||
ge;
|
||||
gt;
|
||||
}
|
||||
|
||||
fn binop_to_str(binop op) -> str {
|
||||
alt (op) {
|
||||
case (add) { ret "+"; }
|
||||
case (sub) { ret "-"; }
|
||||
case (mul) { ret "*"; }
|
||||
case (div) { ret "/"; }
|
||||
case (rem) { ret "%"; }
|
||||
case (and) { ret "&&"; }
|
||||
case (or) { ret "||"; }
|
||||
case (bitxor) { ret "^"; }
|
||||
case (bitand) { ret "&"; }
|
||||
case (bitor) { ret "|"; }
|
||||
case (lsl) { ret "<<"; }
|
||||
case (lsr) { ret ">>"; }
|
||||
case (asr) { ret ">>>"; }
|
||||
case (eq) { ret "=="; }
|
||||
case (lt) { ret "<"; }
|
||||
case (le) { ret "<="; }
|
||||
case (ne) { ret "!="; }
|
||||
case (ge) { ret ">="; }
|
||||
case (gt) { ret ">"; }
|
||||
}
|
||||
}
|
||||
|
||||
pred lazy_binop(binop b) -> bool {
|
||||
alt (b) {
|
||||
case (and) { true }
|
||||
case (or) { true }
|
||||
case (_) { false }
|
||||
}
|
||||
}
|
||||
|
||||
tag unop { box(mutability); deref; not; neg; }
|
||||
|
||||
fn unop_to_str(unop op) -> str {
|
||||
alt (op) {
|
||||
case (box(?mt)) { if (mt == mut) { ret "@mutable "; } ret "@"; }
|
||||
case (deref) { ret "*"; }
|
||||
case (not) { ret "!"; }
|
||||
case (neg) { ret "-"; }
|
||||
}
|
||||
}
|
||||
|
||||
tag mode { val; alias(bool); }
|
||||
|
||||
type stmt = spanned[stmt_];
|
||||
|
||||
tag stmt_ {
|
||||
stmt_decl(@decl, node_id);
|
||||
stmt_expr(@expr, node_id);
|
||||
|
||||
// These only exist in crate-level blocks.
|
||||
stmt_crate_directive(@crate_directive);
|
||||
}
|
||||
|
||||
tag init_op { init_assign; init_recv; init_move; }
|
||||
|
||||
type initializer = rec(init_op op, @expr expr);
|
||||
|
||||
type local_ =
|
||||
rec(option::t[@ty] ty,
|
||||
bool infer,
|
||||
ident ident,
|
||||
option::t[initializer] init,
|
||||
node_id id);
|
||||
|
||||
type local = spanned[local_];
|
||||
|
||||
type decl = spanned[decl_];
|
||||
|
||||
tag decl_ { decl_local(@local); decl_item(@item); }
|
||||
|
||||
type arm = rec(@pat pat, block block);
|
||||
|
||||
type elt = rec(mutability mut, @expr expr);
|
||||
|
||||
type field_ = rec(mutability mut, ident ident, @expr expr);
|
||||
|
||||
type field = spanned[field_];
|
||||
|
||||
tag spawn_dom { dom_implicit; dom_thread; }
|
||||
|
||||
tag check_mode { checked; unchecked; }
|
||||
|
||||
// FIXME: temporary
|
||||
tag seq_kind { sk_unique; sk_rc; }
|
||||
|
||||
type expr = rec(node_id id,
|
||||
expr_ node,
|
||||
span span);
|
||||
|
||||
tag expr_ {
|
||||
expr_vec(vec[@expr], mutability, seq_kind);
|
||||
expr_tup(vec[elt]);
|
||||
expr_rec(vec[field], option::t[@expr]);
|
||||
expr_call(@expr, vec[@expr]);
|
||||
expr_self_method(ident);
|
||||
expr_bind(@expr, vec[option::t[@expr]]);
|
||||
expr_spawn(spawn_dom, option::t[str], @expr, vec[@expr]);
|
||||
expr_binary(binop, @expr, @expr);
|
||||
expr_unary(unop, @expr);
|
||||
expr_lit(@lit);
|
||||
expr_cast(@expr, @ty);
|
||||
expr_if(@expr, block, option::t[@expr]);
|
||||
expr_ternary(@expr, @expr, @expr);
|
||||
expr_while(@expr, block);
|
||||
expr_for(@local, @expr, block);
|
||||
expr_for_each(@local, @expr, block);
|
||||
expr_do_while(block, @expr);
|
||||
expr_alt(@expr, vec[arm]);
|
||||
expr_fn(_fn);
|
||||
expr_block(block);
|
||||
/*
|
||||
* FIXME: many of these @exprs should be constrained with
|
||||
* is_lval once we have constrained types working.
|
||||
*/
|
||||
expr_move(@expr, @expr);
|
||||
expr_assign(@expr,@expr);
|
||||
expr_swap(@expr, @expr);
|
||||
expr_assign_op(binop, @expr, @expr);
|
||||
expr_send(@expr, @expr);
|
||||
expr_recv(@expr, @expr);
|
||||
expr_field(@expr, ident);
|
||||
expr_index(@expr, @expr);
|
||||
expr_path(path);
|
||||
expr_ext(path, vec[@expr], option::t[str], @expr);
|
||||
expr_fail(option::t[@expr]);
|
||||
expr_break;
|
||||
expr_cont;
|
||||
expr_ret(option::t[@expr]);
|
||||
expr_put(option::t[@expr]);
|
||||
expr_be(@expr);
|
||||
expr_log(int, @expr);
|
||||
|
||||
/* just an assert, no significance to typestate */
|
||||
expr_assert(@expr);
|
||||
|
||||
/* preds that typestate is aware of */
|
||||
expr_check(check_mode, @expr);
|
||||
/* FIXME Would be nice if expr_check desugared
|
||||
to expr_if_check. */
|
||||
expr_if_check(@expr, block, option::t[@expr]);
|
||||
expr_port(option::t[@ty]);
|
||||
expr_chan(@expr);
|
||||
expr_anon_obj(anon_obj, vec[ty_param], obj_def_ids);
|
||||
}
|
||||
|
||||
type lit = spanned[lit_];
|
||||
|
||||
tag lit_ {
|
||||
lit_str(str, seq_kind);
|
||||
lit_char(char);
|
||||
lit_int(int);
|
||||
lit_uint(uint);
|
||||
lit_mach_int(ty_mach, int);
|
||||
lit_float(str);
|
||||
lit_mach_float(ty_mach, str);
|
||||
lit_nil;
|
||||
lit_bool(bool);
|
||||
}
|
||||
|
||||
fn is_path(&@expr e) -> bool {
|
||||
ret alt (e.node) {
|
||||
case (expr_path(_)) { true }
|
||||
case (_) { false }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// NB: If you change this, you'll probably want to change the corresponding
|
||||
// type structure in middle/ty.rs as well.
|
||||
type mt = rec(@ty ty, mutability mut);
|
||||
|
||||
type ty_field_ = rec(ident ident, mt mt);
|
||||
|
||||
type ty_arg_ = rec(mode mode, @ty ty);
|
||||
|
||||
type ty_method_ =
|
||||
rec(proto proto,
|
||||
ident ident,
|
||||
vec[ty_arg] inputs,
|
||||
@ty output,
|
||||
controlflow cf,
|
||||
vec[@constr] constrs);
|
||||
|
||||
type ty_field = spanned[ty_field_];
|
||||
|
||||
type ty_arg = spanned[ty_arg_];
|
||||
|
||||
type ty_method = spanned[ty_method_];
|
||||
|
||||
tag ty_mach {
|
||||
ty_i8;
|
||||
ty_i16;
|
||||
ty_i32;
|
||||
ty_i64;
|
||||
ty_u8;
|
||||
ty_u16;
|
||||
ty_u32;
|
||||
ty_u64;
|
||||
ty_f32;
|
||||
ty_f64;
|
||||
}
|
||||
|
||||
fn ty_mach_to_str(ty_mach tm) -> str {
|
||||
alt (tm) {
|
||||
case (ty_u8) { ret "u8"; }
|
||||
case (ty_u16) { ret "u16"; }
|
||||
case (ty_u32) { ret "u32"; }
|
||||
case (ty_u64) { ret "u64"; }
|
||||
case (ty_i8) { ret "i8"; }
|
||||
case (ty_i16) { ret "i16"; }
|
||||
case (ty_i32) { ret "i32"; }
|
||||
case (ty_i64) { ret "i64"; }
|
||||
case (ty_f32) { ret "f32"; }
|
||||
case (ty_f64) { ret "f64"; }
|
||||
}
|
||||
}
|
||||
|
||||
type ty = spanned[ty_];
|
||||
|
||||
tag ty_ {
|
||||
ty_nil;
|
||||
ty_bot; /* return type of ! functions and type of
|
||||
ret/fail/break/cont. there is no syntax
|
||||
for this type. */
|
||||
|
||||
/* bot represents the value of functions that don't return a value
|
||||
locally to their context. in contrast, things like log that do
|
||||
return, but don't return a meaningful value, have result type nil. */
|
||||
ty_bool;
|
||||
ty_int;
|
||||
ty_uint;
|
||||
ty_float;
|
||||
ty_machine(ty_mach);
|
||||
ty_char;
|
||||
ty_str;
|
||||
ty_istr; // interior string
|
||||
|
||||
ty_box(mt);
|
||||
ty_vec(mt);
|
||||
ty_ivec(mt); // interior vector
|
||||
|
||||
ty_ptr(mt);
|
||||
ty_task;
|
||||
ty_port(@ty);
|
||||
ty_chan(@ty);
|
||||
ty_tup(vec[mt]);
|
||||
ty_rec(vec[ty_field]);
|
||||
ty_fn(proto, vec[ty_arg], @ty, controlflow, vec[@constr]);
|
||||
ty_obj(vec[ty_method]);
|
||||
ty_path(path, node_id);
|
||||
ty_type;
|
||||
ty_constr(@ty, vec[@constr]);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
A constraint arg that's a function argument is referred to by its position
|
||||
rather than name. This is so we could have higher-order functions that have
|
||||
constraints (potentially -- right now there's no way to write that), and also
|
||||
so that the typestate pass doesn't have to map a function name onto its decl.
|
||||
So, the constr_arg type is parameterized: it's instantiated with uint for
|
||||
declarations, and ident for uses.
|
||||
*/
|
||||
tag constr_arg_general_[T] { carg_base; carg_ident(T); carg_lit(@lit); }
|
||||
|
||||
type constr_arg = constr_arg_general[uint];
|
||||
|
||||
type constr_arg_general[T] = spanned[constr_arg_general_[T]];
|
||||
|
||||
type constr_ = rec(path path,
|
||||
vec[@constr_arg_general[uint]] args,
|
||||
node_id id);
|
||||
|
||||
type constr = spanned[constr_];
|
||||
|
||||
|
||||
/* The parser generates ast::constrs; resolve generates
|
||||
a mapping from each function to a list of ty::constr_defs,
|
||||
corresponding to these. */
|
||||
type arg = rec(mode mode, @ty ty, ident ident, node_id id);
|
||||
|
||||
type fn_decl =
|
||||
rec(vec[arg] inputs,
|
||||
@ty output,
|
||||
purity purity,
|
||||
controlflow cf,
|
||||
vec[@constr] constraints);
|
||||
|
||||
tag purity {
|
||||
pure_fn; // declared with "pred"
|
||||
|
||||
impure_fn; // declared with "fn"
|
||||
|
||||
}
|
||||
|
||||
tag controlflow {
|
||||
noreturn; // functions with return type _|_ that always
|
||||
// raise an error or exit (i.e. never return to the caller)
|
||||
|
||||
return; // everything else
|
||||
|
||||
}
|
||||
|
||||
type _fn = rec(fn_decl decl, proto proto, block body);
|
||||
|
||||
type method_ = rec(ident ident, _fn meth, node_id id);
|
||||
|
||||
type method = spanned[method_];
|
||||
|
||||
type obj_field = rec(mutability mut, @ty ty, ident ident, node_id id);
|
||||
type anon_obj_field = rec(mutability mut, @ty ty, @expr expr, ident ident,
|
||||
node_id id);
|
||||
|
||||
type _obj =
|
||||
rec(vec[obj_field] fields, vec[@method] methods, option::t[@method] dtor);
|
||||
|
||||
type anon_obj =
|
||||
rec(
|
||||
// New fields and methods, if they exist.
|
||||
option::t[vec[anon_obj_field]] fields,
|
||||
vec[@method] methods,
|
||||
|
||||
// with_obj: the original object being extended, if it exists.
|
||||
option::t[@expr] with_obj);
|
||||
|
||||
type _mod = rec(vec[@view_item] view_items, vec[@item] items);
|
||||
|
||||
tag native_abi {
|
||||
native_abi_rust;
|
||||
native_abi_cdecl;
|
||||
native_abi_llvm;
|
||||
native_abi_rust_intrinsic;
|
||||
}
|
||||
|
||||
type native_mod =
|
||||
rec(str native_name,
|
||||
native_abi abi,
|
||||
vec[@view_item] view_items,
|
||||
vec[@native_item] items);
|
||||
|
||||
type variant_arg = rec(@ty ty, node_id id);
|
||||
|
||||
type variant_ = rec(str name, vec[variant_arg] args, node_id id);
|
||||
|
||||
type variant = spanned[variant_];
|
||||
|
||||
type view_item = spanned[view_item_];
|
||||
|
||||
tag view_item_ {
|
||||
view_item_use(ident, vec[@meta_item], node_id);
|
||||
view_item_import(ident, vec[ident], node_id);
|
||||
view_item_import_glob(vec[ident], node_id);
|
||||
view_item_export(ident, node_id);
|
||||
}
|
||||
|
||||
type obj_def_ids = rec(node_id ty, node_id ctor);
|
||||
|
||||
|
||||
// Meta-data associated with an item
|
||||
type attribute = spanned[attribute_];
|
||||
|
||||
|
||||
// Distinguishes between attributes that decorate items and attributes that
|
||||
// are contained as statements within items. These two cases need to be
|
||||
// distinguished for pretty-printing.
|
||||
tag attr_style { attr_outer; attr_inner; }
|
||||
|
||||
type attribute_ = rec(attr_style style, meta_item value);
|
||||
|
||||
type item = rec(ident ident,
|
||||
vec[attribute] attrs,
|
||||
node_id id, // For objs and resources, this is the type def_id
|
||||
item_ node,
|
||||
span span);
|
||||
|
||||
tag item_ {
|
||||
item_const(@ty, @expr);
|
||||
item_fn(_fn, vec[ty_param]);
|
||||
item_mod(_mod);
|
||||
item_native_mod(native_mod);
|
||||
item_ty(@ty, vec[ty_param]);
|
||||
item_tag(vec[variant], vec[ty_param]);
|
||||
item_obj(_obj, vec[ty_param], node_id /* constructor id */);
|
||||
item_res(_fn /* dtor */, node_id /* dtor id */,
|
||||
vec[ty_param], node_id /* ctor id */);
|
||||
}
|
||||
|
||||
type native_item = rec(ident ident,
|
||||
native_item_ node,
|
||||
node_id id,
|
||||
span span);
|
||||
|
||||
tag native_item_ {
|
||||
native_item_ty;
|
||||
native_item_fn(option::t[str], fn_decl, vec[ty_param]);
|
||||
}
|
||||
|
||||
fn is_exported(ident i, _mod m) -> bool {
|
||||
auto nonlocal = true;
|
||||
for (@ast::item it in m.items) {
|
||||
if (it.ident == i) { nonlocal = false; }
|
||||
alt (it.node) {
|
||||
case (item_tag(?variants, _)) {
|
||||
for (variant v in variants) {
|
||||
if (v.node.name == i) { nonlocal = false; }
|
||||
}
|
||||
}
|
||||
case (_) { }
|
||||
}
|
||||
if (!nonlocal) { break; }
|
||||
}
|
||||
auto count = 0u;
|
||||
for (@ast::view_item vi in m.view_items) {
|
||||
alt (vi.node) {
|
||||
case (ast::view_item_export(?id, _)) {
|
||||
if (str::eq(i, id)) {
|
||||
// even if it's nonlocal (since it's explicit)
|
||||
|
||||
ret true;
|
||||
}
|
||||
count += 1u;
|
||||
}
|
||||
case (_) {/* fall through */ }
|
||||
}
|
||||
}
|
||||
// If there are no declared exports then
|
||||
// everything not imported is exported
|
||||
|
||||
ret count == 0u && !nonlocal;
|
||||
}
|
||||
|
||||
fn is_call_expr(@expr e) -> bool {
|
||||
alt (e.node) {
|
||||
case (expr_call(_, _)) { ret true; }
|
||||
case (_) { ret false; }
|
||||
}
|
||||
}
|
||||
|
||||
fn is_constraint_arg(@expr e) -> bool {
|
||||
alt (e.node) {
|
||||
case (expr_lit(_)) { ret true; }
|
||||
case (expr_path(_)) { ret true; }
|
||||
case (_) { ret false; }
|
||||
}
|
||||
}
|
||||
|
||||
fn eq_ty(&@ty a, &@ty b) -> bool { ret std::box::ptr_eq(a, b); }
|
||||
|
||||
fn hash_ty(&@ty t) -> uint { ret t.span.lo << 16u + t.span.hi; }
|
||||
|
||||
fn block_from_expr(@expr e) -> block {
|
||||
let block_ blk_ =
|
||||
rec(stmts=[],
|
||||
expr=option::some[@expr](e),
|
||||
id=e.id);
|
||||
ret rec(node=blk_, span=e.span);
|
||||
}
|
||||
|
||||
// This is a convenience function to transfor ternary expressions to if
|
||||
// expressions so that they can be treated the same
|
||||
fn ternary_to_if(&@expr e) -> @ast::expr {
|
||||
alt (e.node) {
|
||||
case (expr_ternary(?cond, ?then, ?els)) {
|
||||
auto then_blk = block_from_expr(then);
|
||||
auto els_blk = block_from_expr(els);
|
||||
auto els_expr = @rec(id=els.id, node=expr_block(els_blk),
|
||||
span=els.span);
|
||||
ret @rec(id=e.id,
|
||||
node=expr_if(cond, then_blk, option::some(els_expr)),
|
||||
span=e.span);
|
||||
}
|
||||
case (_) { fail; }
|
||||
}
|
||||
}
|
||||
|
||||
// Path stringification
|
||||
fn path_to_str(&ast::path pth) -> str {
|
||||
auto result = str::connect(pth.node.idents, "::");
|
||||
if (vec::len[@ast::ty](pth.node.types) > 0u) {
|
||||
fn f(&@ast::ty t) -> str { ret print::pprust::ty_to_str(*t); }
|
||||
result += "[";
|
||||
result += str::connect(vec::map(f, pth.node.types), ",");
|
||||
result += "]";
|
||||
}
|
||||
ret result;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 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:
|
||||
//
|
||||
96
src/comp/syntax/codemap.rs
Normal file
96
src/comp/syntax/codemap.rs
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
|
||||
import std::vec;
|
||||
import std::term;
|
||||
import std::io;
|
||||
import std::option;
|
||||
import std::option::some;
|
||||
import std::option::none;
|
||||
|
||||
type filename = str;
|
||||
|
||||
/* A codemap is a thing that maps uints to file/line/column positions
|
||||
* in a crate. This to make it possible to represent the positions
|
||||
* with single-word things, rather than passing records all over the
|
||||
* compiler.
|
||||
*/
|
||||
type filemap = @rec(filename name, uint start_pos, mutable vec[uint] lines);
|
||||
|
||||
type codemap = @rec(mutable vec[filemap] files);
|
||||
|
||||
type loc = rec(filename filename, uint line, uint col);
|
||||
|
||||
fn new_codemap() -> codemap {
|
||||
let vec[filemap] files = [];
|
||||
ret @rec(mutable files=files);
|
||||
}
|
||||
|
||||
fn new_filemap(filename filename, uint start_pos) -> filemap {
|
||||
ret @rec(name=filename, start_pos=start_pos, mutable lines=[0u]);
|
||||
}
|
||||
|
||||
fn next_line(filemap file, uint pos) { vec::push[uint](file.lines, pos); }
|
||||
|
||||
fn lookup_pos(codemap map, uint pos) -> loc {
|
||||
auto a = 0u;
|
||||
auto b = vec::len[filemap](map.files);
|
||||
while (b - a > 1u) {
|
||||
auto m = (a + b) / 2u;
|
||||
if (map.files.(m).start_pos > pos) { b = m; } else { a = m; }
|
||||
}
|
||||
auto f = map.files.(a);
|
||||
a = 0u;
|
||||
b = vec::len[uint](f.lines);
|
||||
while (b - a > 1u) {
|
||||
auto m = (a + b) / 2u;
|
||||
if (f.lines.(m) > pos) { b = m; } else { a = m; }
|
||||
}
|
||||
ret rec(filename=f.name, line=a + 1u, col=pos - f.lines.(a));
|
||||
}
|
||||
|
||||
type span = rec(uint lo, uint hi);
|
||||
|
||||
fn span_to_str(&span sp, &codemap cm) -> str {
|
||||
auto lo = lookup_pos(cm, sp.lo);
|
||||
auto hi = lookup_pos(cm, sp.hi);
|
||||
ret #fmt("%s:%u:%u:%u:%u", lo.filename, lo.line, lo.col, hi.line, hi.col);
|
||||
}
|
||||
|
||||
fn emit_diagnostic(&option::t[span] sp, &str msg, &str kind, u8 color,
|
||||
&codemap cm) {
|
||||
auto ss = "<input>:0:0:0:0";
|
||||
alt (sp) {
|
||||
case (some(?ssp)) { ss = span_to_str(ssp, cm); }
|
||||
case (none) { }
|
||||
}
|
||||
io::stdout().write_str(ss + ": ");
|
||||
if (term::color_supported()) {
|
||||
term::fg(io::stdout().get_buf_writer(), color);
|
||||
}
|
||||
io::stdout().write_str(#fmt("%s:", kind));
|
||||
if (term::color_supported()) {
|
||||
term::reset(io::stdout().get_buf_writer());
|
||||
}
|
||||
io::stdout().write_str(#fmt(" %s\n", msg));
|
||||
}
|
||||
|
||||
fn emit_warning(&option::t[span] sp, &str msg, &codemap cm) {
|
||||
emit_diagnostic(sp, msg, "warning", 11u8, cm);
|
||||
}
|
||||
fn emit_error(&option::t[span] sp, &str msg, &codemap cm) {
|
||||
emit_diagnostic(sp, msg, "error", 9u8, cm);
|
||||
}
|
||||
fn emit_note(&option::t[span] sp, &str msg, &codemap cm) {
|
||||
emit_diagnostic(sp, msg, "note", 10u8, cm);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 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:
|
||||
//
|
||||
98
src/comp/syntax/ext/base.rs
Normal file
98
src/comp/syntax/ext/base.rs
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
import std::vec;
|
||||
import std::option;
|
||||
import std::map::hashmap;
|
||||
import parse::parser::parse_sess;
|
||||
import codemap::span;
|
||||
import syntax::_std::new_str_hash;
|
||||
import codemap;
|
||||
|
||||
type syntax_expander =
|
||||
fn(&ext_ctxt, span, &vec[@ast::expr], option::t[str]) -> @ast::expr;
|
||||
type macro_definer = fn(&ext_ctxt, span, &vec[@ast::expr],
|
||||
option::t[str]) -> tup(str, syntax_extension);
|
||||
|
||||
tag syntax_extension {
|
||||
normal(syntax_expander);
|
||||
macro_defining(macro_definer);
|
||||
}
|
||||
|
||||
// A temporary hard-coded map of methods for expanding syntax extension
|
||||
// AST nodes into full ASTs
|
||||
fn syntax_expander_table() -> hashmap[str, syntax_extension] {
|
||||
auto syntax_expanders = new_str_hash[syntax_extension]();
|
||||
syntax_expanders.insert("fmt", normal(ext::fmt::expand_syntax_ext));
|
||||
syntax_expanders.insert("env", normal(ext::env::expand_syntax_ext));
|
||||
syntax_expanders.insert("macro",
|
||||
macro_defining(ext::simplext::add_new_extension));
|
||||
ret syntax_expanders;
|
||||
}
|
||||
|
||||
type span_msg_fn = fn(span, str) -> ! ;
|
||||
|
||||
type next_id_fn = fn() -> ast::node_id ;
|
||||
|
||||
|
||||
// Provides a limited set of services necessary for syntax extensions
|
||||
// to do their thing
|
||||
type ext_ctxt =
|
||||
rec(span_msg_fn span_fatal,
|
||||
span_msg_fn span_unimpl,
|
||||
next_id_fn next_id);
|
||||
|
||||
fn mk_ctxt(&parse_sess sess) -> ext_ctxt {
|
||||
fn ext_span_fatal_(&codemap::codemap cm, span sp, str msg) -> ! {
|
||||
codemap::emit_error(option::some(sp), msg, cm);
|
||||
fail;
|
||||
}
|
||||
auto ext_span_fatal = bind ext_span_fatal_(sess.cm, _, _);
|
||||
fn ext_span_unimpl_(&codemap::codemap cm, span sp, str msg) -> ! {
|
||||
codemap::emit_error(option::some(sp), "unimplemented " + msg, cm);
|
||||
fail;
|
||||
}
|
||||
auto ext_span_unimpl = bind ext_span_unimpl_(sess.cm, _, _);
|
||||
auto ext_next_id = bind parse::parser::next_node_id(sess);
|
||||
ret rec(span_fatal=ext_span_fatal,
|
||||
span_unimpl=ext_span_unimpl,
|
||||
next_id=ext_next_id);
|
||||
}
|
||||
|
||||
fn expr_to_str(&ext_ctxt cx, @ast::expr expr, str error) -> str {
|
||||
alt (expr.node) {
|
||||
case (ast::expr_lit(?l)) {
|
||||
alt (l.node) {
|
||||
case (ast::lit_str(?s, _)) { ret s; }
|
||||
case (_) { cx.span_fatal(l.span, error); }
|
||||
}
|
||||
}
|
||||
case (_) { cx.span_fatal(expr.span, error); }
|
||||
}
|
||||
}
|
||||
|
||||
fn expr_to_ident(&ext_ctxt cx, @ast::expr expr, str error) -> ast::ident {
|
||||
alt(expr.node) {
|
||||
case (ast::expr_path(?p)) {
|
||||
if (vec::len(p.node.types) > 0u
|
||||
|| vec::len(p.node.idents) != 1u) {
|
||||
cx.span_fatal(expr.span, error);
|
||||
} else {
|
||||
ret p.node.idents.(0);
|
||||
}
|
||||
}
|
||||
case (_) {
|
||||
cx.span_fatal(expr.span, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// 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:
|
||||
//
|
||||
47
src/comp/syntax/ext/env.rs
Normal file
47
src/comp/syntax/ext/env.rs
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
|
||||
|
||||
/*
|
||||
* The compiler code necessary to support the #env extension. Eventually this
|
||||
* should all get sucked into either the compiler syntax extension plugin
|
||||
* interface.
|
||||
*/
|
||||
import std::str;
|
||||
import std::vec;
|
||||
import std::option;
|
||||
import std::generic_os;
|
||||
import base::*;
|
||||
export expand_syntax_ext;
|
||||
|
||||
fn expand_syntax_ext(&ext_ctxt cx, codemap::span sp, &vec[@ast::expr] args,
|
||||
option::t[str] body) -> @ast::expr {
|
||||
if (vec::len[@ast::expr](args) != 1u) {
|
||||
cx.span_fatal(sp, "malformed #env call");
|
||||
}
|
||||
// FIXME: if this was more thorough it would manufacture an
|
||||
// option::t[str] rather than just an maybe-empty string.
|
||||
|
||||
auto var = expr_to_str(cx, args.(0), "#env requires a string");
|
||||
alt (generic_os::getenv(var)) {
|
||||
case (option::none) { ret make_new_str(cx, sp, ""); }
|
||||
case (option::some(?s)) { ret make_new_str(cx, sp, s); }
|
||||
}
|
||||
}
|
||||
|
||||
fn make_new_lit(&ext_ctxt cx, codemap::span sp, ast::lit_ lit) -> @ast::expr {
|
||||
auto sp_lit = @rec(node=lit, span=sp);
|
||||
ret @rec(id=cx.next_id(), node=ast::expr_lit(sp_lit), span=sp);
|
||||
}
|
||||
|
||||
fn make_new_str(&ext_ctxt cx, codemap::span sp, str s) -> @ast::expr {
|
||||
ret make_new_lit(cx, sp, ast::lit_str(s, ast::sk_rc));
|
||||
}
|
||||
//
|
||||
// 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:
|
||||
//
|
||||
372
src/comp/syntax/ext/fmt.rs
Normal file
372
src/comp/syntax/ext/fmt.rs
Normal file
|
|
@ -0,0 +1,372 @@
|
|||
|
||||
|
||||
/*
|
||||
* The compiler code necessary to support the #fmt extension. Eventually this
|
||||
* should all get sucked into either the standard library extfmt module or the
|
||||
* compiler syntax extension plugin interface.
|
||||
*/
|
||||
import std::str;
|
||||
import std::vec;
|
||||
import std::option;
|
||||
import std::option::none;
|
||||
import std::option::some;
|
||||
import std::extfmt::ct::*;
|
||||
import base::*;
|
||||
import codemap::span;
|
||||
export expand_syntax_ext;
|
||||
|
||||
fn expand_syntax_ext(&ext_ctxt cx, span sp, &vec[@ast::expr] args,
|
||||
option::t[str] body) -> @ast::expr {
|
||||
if (vec::len[@ast::expr](args) == 0u) {
|
||||
cx.span_fatal(sp, "#fmt requires a format string");
|
||||
}
|
||||
auto fmt = expr_to_str(cx, args.(0), "first argument to #fmt must be a "
|
||||
+ "string literal.");
|
||||
auto fmtspan = args.(0).span;
|
||||
log "Format string:";
|
||||
log fmt;
|
||||
fn parse_fmt_err_(&ext_ctxt cx, span sp, str msg) -> ! {
|
||||
cx.span_fatal(sp, msg);
|
||||
}
|
||||
auto parse_fmt_err = bind parse_fmt_err_(cx, fmtspan, _);
|
||||
auto pieces = parse_fmt_string(fmt, parse_fmt_err);
|
||||
ret pieces_to_expr(cx, sp, pieces, args);
|
||||
}
|
||||
|
||||
// FIXME: A lot of these functions for producing expressions can probably
|
||||
// be factored out in common with other code that builds expressions.
|
||||
// FIXME: Cleanup the naming of these functions
|
||||
fn pieces_to_expr(&ext_ctxt cx, span sp, vec[piece] pieces,
|
||||
vec[@ast::expr] args) -> @ast::expr {
|
||||
fn make_new_lit(&ext_ctxt cx, span sp, ast::lit_ lit) ->
|
||||
@ast::expr {
|
||||
auto sp_lit = @rec(node=lit, span=sp);
|
||||
ret @rec(id=cx.next_id(), node=ast::expr_lit(sp_lit), span=sp);
|
||||
}
|
||||
fn make_new_str(&ext_ctxt cx, span sp, str s) -> @ast::expr {
|
||||
auto lit = ast::lit_str(s, ast::sk_rc);
|
||||
ret make_new_lit(cx, sp, lit);
|
||||
}
|
||||
fn make_new_int(&ext_ctxt cx, span sp, int i) -> @ast::expr {
|
||||
auto lit = ast::lit_int(i);
|
||||
ret make_new_lit(cx, sp, lit);
|
||||
}
|
||||
fn make_new_uint(&ext_ctxt cx, span sp, uint u) -> @ast::expr {
|
||||
auto lit = ast::lit_uint(u);
|
||||
ret make_new_lit(cx, sp, lit);
|
||||
}
|
||||
fn make_add_expr(&ext_ctxt cx, span sp, @ast::expr lhs,
|
||||
@ast::expr rhs) -> @ast::expr {
|
||||
auto binexpr = ast::expr_binary(ast::add, lhs, rhs);
|
||||
ret @rec(id=cx.next_id(), node=binexpr, span=sp);
|
||||
}
|
||||
fn make_path_expr(&ext_ctxt cx, span sp, vec[ast::ident] idents)
|
||||
-> @ast::expr {
|
||||
let vec[@ast::ty] types = [];
|
||||
auto path = rec(idents=idents, types=types);
|
||||
auto sp_path = rec(node=path, span=sp);
|
||||
auto pathexpr = ast::expr_path(sp_path);
|
||||
ret @rec(id=cx.next_id(), node=pathexpr, span=sp);
|
||||
}
|
||||
fn make_vec_expr(&ext_ctxt cx, span sp, vec[@ast::expr] exprs) ->
|
||||
@ast::expr {
|
||||
auto vecexpr = ast::expr_vec(exprs, ast::imm, ast::sk_rc);
|
||||
ret @rec(id=cx.next_id(), node=vecexpr, span=sp);
|
||||
}
|
||||
fn make_call(&ext_ctxt cx, span sp, vec[ast::ident] fn_path,
|
||||
vec[@ast::expr] args) -> @ast::expr {
|
||||
auto pathexpr = make_path_expr(cx, sp, fn_path);
|
||||
auto callexpr = ast::expr_call(pathexpr, args);
|
||||
ret @rec(id=cx.next_id(), node=callexpr, span=sp);
|
||||
}
|
||||
fn make_rec_expr(&ext_ctxt cx, span sp,
|
||||
vec[tup(ast::ident, @ast::expr)] fields) -> @ast::expr {
|
||||
let vec[ast::field] astfields = [];
|
||||
for (tup(ast::ident, @ast::expr) field in fields) {
|
||||
auto ident = field._0;
|
||||
auto val = field._1;
|
||||
auto astfield =
|
||||
rec(node=rec(mut=ast::imm, ident=ident, expr=val), span=sp);
|
||||
astfields += [astfield];
|
||||
}
|
||||
auto recexpr = ast::expr_rec(astfields, option::none[@ast::expr]);
|
||||
ret @rec(id=cx.next_id(), node=recexpr, span=sp);
|
||||
}
|
||||
fn make_path_vec(str ident) -> vec[str] {
|
||||
// FIXME: #fmt can't currently be used from within std
|
||||
// because we're explicitly referencing the 'std' crate here
|
||||
|
||||
ret ["std", "extfmt", "rt", ident];
|
||||
}
|
||||
fn make_rt_path_expr(&ext_ctxt cx, span sp, str ident) ->
|
||||
@ast::expr {
|
||||
auto path = make_path_vec(ident);
|
||||
ret make_path_expr(cx, sp, path);
|
||||
}
|
||||
// Produces an AST expression that represents a RT::conv record,
|
||||
// which tells the RT::conv* functions how to perform the conversion
|
||||
|
||||
fn make_rt_conv_expr(&ext_ctxt cx, span sp, &conv cnv) ->
|
||||
@ast::expr {
|
||||
fn make_flags(&ext_ctxt cx, span sp, vec[flag] flags) ->
|
||||
@ast::expr {
|
||||
let vec[@ast::expr] flagexprs = [];
|
||||
for (flag f in flags) {
|
||||
auto fstr;
|
||||
alt (f) {
|
||||
case (flag_left_justify) { fstr = "flag_left_justify"; }
|
||||
case (flag_left_zero_pad) { fstr = "flag_left_zero_pad"; }
|
||||
case (flag_space_for_sign) {
|
||||
fstr = "flag_space_for_sign";
|
||||
}
|
||||
case (flag_sign_always) { fstr = "flag_sign_always"; }
|
||||
case (flag_alternate) { fstr = "flag_alternate"; }
|
||||
}
|
||||
flagexprs += [make_rt_path_expr(cx, sp, fstr)];
|
||||
}
|
||||
// FIXME: 0-length vectors can't have their type inferred
|
||||
// through the rec that these flags are a member of, so
|
||||
// this is a hack placeholder flag
|
||||
|
||||
if (vec::len[@ast::expr](flagexprs) == 0u) {
|
||||
flagexprs += [make_rt_path_expr(cx, sp, "flag_none")];
|
||||
}
|
||||
ret make_vec_expr(cx, sp, flagexprs);
|
||||
}
|
||||
fn make_count(&ext_ctxt cx, span sp, &count cnt) ->
|
||||
@ast::expr {
|
||||
alt (cnt) {
|
||||
case (count_implied) {
|
||||
ret make_rt_path_expr(cx, sp, "count_implied");
|
||||
}
|
||||
case (count_is(?c)) {
|
||||
auto count_lit = make_new_int(cx, sp, c);
|
||||
auto count_is_path = make_path_vec("count_is");
|
||||
auto count_is_args = [count_lit];
|
||||
ret make_call(cx, sp, count_is_path, count_is_args);
|
||||
}
|
||||
case (_) {
|
||||
cx.span_unimpl(sp, "unimplemented #fmt conversion");
|
||||
}
|
||||
}
|
||||
}
|
||||
fn make_ty(&ext_ctxt cx, span sp, &ty t) -> @ast::expr {
|
||||
auto rt_type;
|
||||
alt (t) {
|
||||
case (ty_hex(?c)) {
|
||||
alt (c) {
|
||||
case (case_upper) { rt_type = "ty_hex_upper"; }
|
||||
case (case_lower) { rt_type = "ty_hex_lower"; }
|
||||
}
|
||||
}
|
||||
case (ty_bits) { rt_type = "ty_bits"; }
|
||||
case (ty_octal) { rt_type = "ty_octal"; }
|
||||
case (_) { rt_type = "ty_default"; }
|
||||
}
|
||||
ret make_rt_path_expr(cx, sp, rt_type);
|
||||
}
|
||||
fn make_conv_rec(&ext_ctxt cx, span sp, @ast::expr flags_expr,
|
||||
@ast::expr width_expr, @ast::expr precision_expr,
|
||||
@ast::expr ty_expr) -> @ast::expr {
|
||||
ret make_rec_expr(cx, sp,
|
||||
[tup("flags", flags_expr),
|
||||
tup("width", width_expr),
|
||||
tup("precision", precision_expr),
|
||||
tup("ty", ty_expr)]);
|
||||
}
|
||||
auto rt_conv_flags = make_flags(cx, sp, cnv.flags);
|
||||
auto rt_conv_width = make_count(cx, sp, cnv.width);
|
||||
auto rt_conv_precision = make_count(cx, sp, cnv.precision);
|
||||
auto rt_conv_ty = make_ty(cx, sp, cnv.ty);
|
||||
ret make_conv_rec(cx, sp, rt_conv_flags, rt_conv_width,
|
||||
rt_conv_precision, rt_conv_ty);
|
||||
}
|
||||
fn make_conv_call(&ext_ctxt cx, span sp, str conv_type, &conv cnv,
|
||||
@ast::expr arg) -> @ast::expr {
|
||||
auto fname = "conv_" + conv_type;
|
||||
auto path = make_path_vec(fname);
|
||||
auto cnv_expr = make_rt_conv_expr(cx, sp, cnv);
|
||||
auto args = [cnv_expr, arg];
|
||||
ret make_call(cx, arg.span, path, args);
|
||||
}
|
||||
fn make_new_conv(&ext_ctxt cx, span sp, conv cnv, @ast::expr arg)
|
||||
-> @ast::expr {
|
||||
// FIXME: Extract all this validation into extfmt::ct
|
||||
|
||||
fn is_signed_type(conv cnv) -> bool {
|
||||
alt (cnv.ty) {
|
||||
case (ty_int(?s)) {
|
||||
alt (s) {
|
||||
case (signed) { ret true; }
|
||||
case (unsigned) { ret false; }
|
||||
}
|
||||
}
|
||||
case (_) { ret false; }
|
||||
}
|
||||
}
|
||||
auto unsupported = "conversion not supported in #fmt string";
|
||||
alt (cnv.param) {
|
||||
case (option::none) { }
|
||||
case (_) { cx.span_unimpl(sp, unsupported); }
|
||||
}
|
||||
for (flag f in cnv.flags) {
|
||||
alt (f) {
|
||||
case (flag_left_justify) { }
|
||||
case (flag_sign_always) {
|
||||
if (!is_signed_type(cnv)) {
|
||||
cx.span_fatal(sp,
|
||||
"+ flag only valid in " +
|
||||
"signed #fmt conversion");
|
||||
}
|
||||
}
|
||||
case (flag_space_for_sign) {
|
||||
if (!is_signed_type(cnv)) {
|
||||
cx.span_fatal(sp,
|
||||
"space flag only valid in " +
|
||||
"signed #fmt conversions");
|
||||
}
|
||||
}
|
||||
case (flag_left_zero_pad) { }
|
||||
case (_) { cx.span_unimpl(sp, unsupported); }
|
||||
}
|
||||
}
|
||||
alt (cnv.width) {
|
||||
case (count_implied) { }
|
||||
case (count_is(_)) { }
|
||||
case (_) { cx.span_unimpl(sp, unsupported); }
|
||||
}
|
||||
alt (cnv.precision) {
|
||||
case (count_implied) { }
|
||||
case (count_is(_)) { }
|
||||
case (_) { cx.span_unimpl(sp, unsupported); }
|
||||
}
|
||||
alt (cnv.ty) {
|
||||
case (ty_str) {
|
||||
ret make_conv_call(cx, arg.span, "str", cnv, arg);
|
||||
}
|
||||
case (ty_int(?sign)) {
|
||||
alt (sign) {
|
||||
case (signed) {
|
||||
ret make_conv_call(cx, arg.span, "int", cnv, arg);
|
||||
}
|
||||
case (unsigned) {
|
||||
ret make_conv_call(cx, arg.span, "uint", cnv, arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
case (ty_bool) {
|
||||
ret make_conv_call(cx, arg.span, "bool", cnv, arg);
|
||||
}
|
||||
case (ty_char) {
|
||||
ret make_conv_call(cx, arg.span, "char", cnv, arg);
|
||||
}
|
||||
case (ty_hex(_)) {
|
||||
ret make_conv_call(cx, arg.span, "uint", cnv, arg);
|
||||
}
|
||||
case (ty_bits) {
|
||||
ret make_conv_call(cx, arg.span, "uint", cnv, arg);
|
||||
}
|
||||
case (ty_octal) {
|
||||
ret make_conv_call(cx, arg.span, "uint", cnv, arg);
|
||||
}
|
||||
case (_) { cx.span_unimpl(sp, unsupported); }
|
||||
}
|
||||
}
|
||||
fn log_conv(conv c) {
|
||||
alt (c.param) {
|
||||
case (some(?p)) { log "param: " + std::int::to_str(p, 10u); }
|
||||
case (_) { log "param: none"; }
|
||||
}
|
||||
for (flag f in c.flags) {
|
||||
alt (f) {
|
||||
case (flag_left_justify) { log "flag: left justify"; }
|
||||
case (flag_left_zero_pad) { log "flag: left zero pad"; }
|
||||
case (flag_space_for_sign) { log "flag: left space pad"; }
|
||||
case (flag_sign_always) { log "flag: sign always"; }
|
||||
case (flag_alternate) { log "flag: alternate"; }
|
||||
}
|
||||
}
|
||||
alt (c.width) {
|
||||
case (count_is(?i)) {
|
||||
log "width: count is " + std::int::to_str(i, 10u);
|
||||
}
|
||||
case (count_is_param(?i)) {
|
||||
log "width: count is param " + std::int::to_str(i, 10u);
|
||||
}
|
||||
case (count_is_next_param) { log "width: count is next param"; }
|
||||
case (count_implied) { log "width: count is implied"; }
|
||||
}
|
||||
alt (c.precision) {
|
||||
case (count_is(?i)) {
|
||||
log "prec: count is " + std::int::to_str(i, 10u);
|
||||
}
|
||||
case (count_is_param(?i)) {
|
||||
log "prec: count is param " + std::int::to_str(i, 10u);
|
||||
}
|
||||
case (count_is_next_param) { log "prec: count is next param"; }
|
||||
case (count_implied) { log "prec: count is implied"; }
|
||||
}
|
||||
alt (c.ty) {
|
||||
case (ty_bool) { log "type: bool"; }
|
||||
case (ty_str) { log "type: str"; }
|
||||
case (ty_char) { log "type: char"; }
|
||||
case (ty_int(?s)) {
|
||||
alt (s) {
|
||||
case (signed) { log "type: signed"; }
|
||||
case (unsigned) { log "type: unsigned"; }
|
||||
}
|
||||
}
|
||||
case (ty_bits) { log "type: bits"; }
|
||||
case (ty_hex(?cs)) {
|
||||
alt (cs) {
|
||||
case (case_upper) { log "type: uhex"; }
|
||||
case (case_lower) { log "type: lhex"; }
|
||||
}
|
||||
}
|
||||
case (ty_octal) { log "type: octal"; }
|
||||
}
|
||||
}
|
||||
auto fmt_sp = args.(0).span;
|
||||
auto n = 0u;
|
||||
auto tmp_expr = make_new_str(cx, sp, "");
|
||||
auto nargs = vec::len[@ast::expr](args);
|
||||
for (piece pc in pieces) {
|
||||
alt (pc) {
|
||||
case (piece_string(?s)) {
|
||||
auto s_expr = make_new_str(cx, fmt_sp, s);
|
||||
tmp_expr = make_add_expr(cx, fmt_sp, tmp_expr, s_expr);
|
||||
}
|
||||
case (piece_conv(?conv)) {
|
||||
n += 1u;
|
||||
if (n >= nargs) {
|
||||
cx.span_fatal(sp,
|
||||
"not enough arguments to #fmt " +
|
||||
"for the given format string");
|
||||
}
|
||||
log "Building conversion:";
|
||||
log_conv(conv);
|
||||
auto arg_expr = args.(n);
|
||||
auto c_expr = make_new_conv(cx, fmt_sp, conv, arg_expr);
|
||||
tmp_expr = make_add_expr(cx, fmt_sp, tmp_expr, c_expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
auto expected_nargs = n + 1u; // n conversions + the fmt string
|
||||
|
||||
if (expected_nargs < nargs) {
|
||||
cx.span_fatal(sp,
|
||||
#fmt("too many arguments to #fmt. found %u, expected %u",
|
||||
nargs, expected_nargs));
|
||||
}
|
||||
ret tmp_expr;
|
||||
}
|
||||
//
|
||||
// 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:
|
||||
//
|
||||
144
src/comp/syntax/ext/simplext.rs
Normal file
144
src/comp/syntax/ext/simplext.rs
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
use std;
|
||||
|
||||
import codemap::span;
|
||||
import std::vec;
|
||||
import std::option;
|
||||
import vec::map;
|
||||
import vec::len;
|
||||
import option::some;
|
||||
import option::none;
|
||||
|
||||
import base::syntax_extension;
|
||||
import base::ext_ctxt;
|
||||
import base::normal;
|
||||
import base::expr_to_str;
|
||||
import base::expr_to_ident;
|
||||
|
||||
import fold::*;
|
||||
import ast::ident;
|
||||
import ast::path_;
|
||||
import ast::expr_path;
|
||||
|
||||
export add_new_extension;
|
||||
|
||||
|
||||
//temporary, until 'position' shows up in the snapshot
|
||||
fn position[T](&T x, &vec[T] v) -> option::t[uint] {
|
||||
let uint i = 0u;
|
||||
while (i < len(v)) {
|
||||
if (x == v.(i)) { ret some[uint](i); }
|
||||
i += 1u;
|
||||
}
|
||||
ret none[uint];
|
||||
}
|
||||
|
||||
// substitute, in a position that's required to be an ident
|
||||
fn subst_ident(&ext_ctxt cx, &vec[@ast::expr] args,
|
||||
@vec[ident] param_names, &ident i, ast_fold fld) -> ident {
|
||||
alt (position(i, *param_names)) {
|
||||
case (some[uint](?idx)) {
|
||||
ret expr_to_ident(cx, args.(idx),
|
||||
"This argument is expanded as an "
|
||||
+ "identifier; it must be one.");
|
||||
}
|
||||
case (none[uint]) {
|
||||
ret i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn subst_path(&ext_ctxt cx, &vec[@ast::expr] args,
|
||||
@vec[ident] param_names, &path_ p, ast_fold fld) -> path_ {
|
||||
// Don't substitute into qualified names.
|
||||
if (len(p.types) > 0u || len(p.idents) != 1u) { ret p; }
|
||||
alt (position(p.idents.(0), *param_names)) {
|
||||
case (some[uint](?idx)) {
|
||||
alt (args.(idx).node) {
|
||||
case (expr_path(?new_path)) {
|
||||
ret new_path.node;
|
||||
}
|
||||
case (_) {
|
||||
cx.span_fatal(args.(idx).span,
|
||||
"This argument is expanded as a path; "
|
||||
+ "it must be one.");
|
||||
}
|
||||
}
|
||||
}
|
||||
case (none[uint]) { ret p; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn subst_expr(&ext_ctxt cx, &vec[@ast::expr] args, @vec[ident] param_names,
|
||||
&ast::expr_ e, ast_fold fld,
|
||||
fn(&ast::expr_, ast_fold) -> ast::expr_ orig) -> ast::expr_ {
|
||||
ret alt(e) {
|
||||
case (expr_path(?p)){
|
||||
// Don't substitute into qualified names.
|
||||
if (len(p.node.types) > 0u || len(p.node.idents) != 1u) { e }
|
||||
alt (position(p.node.idents.(0), *param_names)) {
|
||||
case (some[uint](?idx)) {
|
||||
args.(idx).node
|
||||
}
|
||||
case (none[uint]) { e }
|
||||
}
|
||||
}
|
||||
case (_) { orig(e,fld) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn add_new_extension(&ext_ctxt cx, span sp, &vec[@ast::expr] args,
|
||||
option::t[str] body) -> tup(str, syntax_extension) {
|
||||
if (len(args) < 2u) {
|
||||
cx.span_fatal(sp, "malformed extension description");
|
||||
}
|
||||
|
||||
fn generic_extension(&ext_ctxt cx, span sp, &vec[@ast::expr] args,
|
||||
option::t[str] body, @vec[ident] param_names,
|
||||
@ast::expr dest_form) -> @ast::expr {
|
||||
if (len(args) != len(*param_names)) {
|
||||
cx.span_fatal(sp, #fmt("extension expects %u arguments, got %u",
|
||||
len(*param_names), len(args)));
|
||||
}
|
||||
|
||||
auto afp = default_ast_fold();
|
||||
auto f_pre =
|
||||
rec(fold_ident = bind subst_ident(cx, args, param_names, _, _),
|
||||
fold_path = bind subst_path(cx, args, param_names, _, _),
|
||||
fold_expr = bind subst_expr(cx, args, param_names, _, _,
|
||||
afp.fold_expr)
|
||||
with *afp);
|
||||
auto f = make_fold(f_pre);
|
||||
auto result = f.fold_expr(dest_form);
|
||||
dummy_out(f); //temporary: kill circular reference
|
||||
ret result;
|
||||
|
||||
}
|
||||
|
||||
let vec[ident] param_names = vec::empty[ident]();
|
||||
let uint idx = 1u;
|
||||
while(1u+idx < len(args)) {
|
||||
param_names +=
|
||||
[expr_to_ident(cx, args.(idx),
|
||||
"this parameter name must be an identifier.")];
|
||||
idx += 1u;
|
||||
}
|
||||
|
||||
ret tup(expr_to_str(cx, args.(0), "first arg must be a literal string."),
|
||||
normal(bind generic_extension(_,_,_,_,@param_names,
|
||||
args.(len(args)-1u))));
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// 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:
|
||||
//
|
||||
708
src/comp/syntax/fold.rs
Normal file
708
src/comp/syntax/fold.rs
Normal file
|
|
@ -0,0 +1,708 @@
|
|||
import syntax::codemap::span;
|
||||
import ast::*;
|
||||
|
||||
import std::vec;
|
||||
import std::option;
|
||||
import vec::map;
|
||||
|
||||
export ast_fold_precursor;
|
||||
export ast_fold;
|
||||
export default_ast_fold;
|
||||
export make_fold;
|
||||
export dummy_out;
|
||||
|
||||
type ast_fold = @mutable a_f;
|
||||
|
||||
// We may eventually want to be able to fold over type parameters, too
|
||||
|
||||
type ast_fold_precursor =
|
||||
rec(fn (&crate_ c, ast_fold) -> crate_ fold_crate,
|
||||
fn (&crate_directive_ cd, ast_fold) -> crate_directive_
|
||||
fold_crate_directive,
|
||||
fn (&view_item_ i, ast_fold) -> view_item_ fold_view_item,
|
||||
fn (&@native_item i, ast_fold) -> @native_item fold_native_item,
|
||||
fn (&@item i, ast_fold) -> @item fold_item,
|
||||
//unlike the others, item_ is non-trivial
|
||||
fn (&item_ i, ast_fold) -> item_ fold_item_underscore,
|
||||
fn (&method_ m, ast_fold) -> method_ fold_method,
|
||||
fn (&block_ b, ast_fold) -> block_ fold_block,
|
||||
fn (&stmt_ s, ast_fold) -> stmt_ fold_stmt,
|
||||
fn (&arm a, ast_fold) -> arm fold_arm,
|
||||
fn (&pat_ p, ast_fold) -> pat_ fold_pat,
|
||||
fn (&decl_ d, ast_fold) -> decl_ fold_decl,
|
||||
fn (&expr_ e, ast_fold) -> expr_ fold_expr,
|
||||
fn (&ty_ t, ast_fold) -> ty_ fold_ty,
|
||||
fn (&constr_ c, ast_fold) -> constr_ fold_constr,
|
||||
fn (&_fn f, ast_fold) -> _fn fold_fn,
|
||||
fn (&_mod m, ast_fold) -> _mod fold_mod,
|
||||
fn (&native_mod, ast_fold) -> native_mod fold_native_mod,
|
||||
fn (&variant_, ast_fold) -> variant_ fold_variant,
|
||||
fn (&ident, ast_fold) -> ident fold_ident,
|
||||
fn (&path_, ast_fold) -> path_ fold_path,
|
||||
fn (&local_, ast_fold) -> local_ fold_local
|
||||
);
|
||||
|
||||
type a_f =
|
||||
rec(fn (&crate c) -> crate fold_crate,
|
||||
fn (&@crate_directive cd) -> @crate_directive fold_crate_directive,
|
||||
fn (&@view_item i) -> @view_item fold_view_item,
|
||||
fn (&@native_item i) -> @native_item fold_native_item,
|
||||
fn (&@item i) -> @item fold_item,
|
||||
fn (&item_ i) -> item_ fold_item_underscore,
|
||||
fn (&@method m) -> @method fold_method,
|
||||
fn (&block b) -> block fold_block,
|
||||
fn (&@stmt s) -> @stmt fold_stmt,
|
||||
fn (&arm a) -> arm fold_arm,
|
||||
fn (&@pat p) -> @pat fold_pat,
|
||||
fn (&@decl d) -> @decl fold_decl,
|
||||
fn (&@expr e) -> @expr fold_expr,
|
||||
fn (&@ty t) -> @ty fold_ty,
|
||||
fn (&@constr c) -> @constr fold_constr,
|
||||
fn (&_fn f) -> _fn fold_fn,
|
||||
fn (&_mod m) -> _mod fold_mod,
|
||||
fn (&native_mod) -> native_mod fold_native_mod,
|
||||
fn (&variant) -> variant fold_variant,
|
||||
fn (&ident) -> ident fold_ident,
|
||||
fn (&path) -> path fold_path,
|
||||
fn (&@local) -> @local fold_local
|
||||
);
|
||||
|
||||
//fn nf_dummy[T](&T node) -> T { fail; }
|
||||
fn nf_crate_dummy(&crate c) -> crate { fail; }
|
||||
fn nf_crate_directive_dummy(&@crate_directive c)
|
||||
-> @crate_directive { fail; }
|
||||
fn nf_view_item_dummy(&@view_item v) -> @view_item { fail; }
|
||||
fn nf_native_item_dummy(&@native_item n) -> @native_item { fail; }
|
||||
fn nf_item_dummy(&@item i) -> @item { fail; }
|
||||
fn nf_item_underscore_dummy(&item_ i) -> item_ { fail; }
|
||||
fn nf_method_dummy(&@method m) -> @method { fail; }
|
||||
fn nf_block_dummy(&block b) -> block { fail; }
|
||||
fn nf_stmt_dummy(&@stmt s) -> @stmt { fail; }
|
||||
fn nf_arm_dummy(&arm a) -> arm { fail; }
|
||||
fn nf_pat_dummy(&@pat p) -> @pat { fail; }
|
||||
fn nf_decl_dummy(&@decl d) -> @decl { fail; }
|
||||
fn nf_expr_dummy(&@expr e) -> @expr { fail; }
|
||||
fn nf_ty_dummy(&@ty t) -> @ty { fail; }
|
||||
fn nf_constr_dummy(&@constr c) -> @constr { fail; }
|
||||
fn nf_fn_dummy(&_fn f) -> _fn { fail; }
|
||||
fn nf_mod_dummy(&_mod m) -> _mod { fail; }
|
||||
fn nf_native_mod_dummy(&native_mod n) -> native_mod { fail; }
|
||||
fn nf_variant_dummy(&variant v) -> variant { fail; }
|
||||
fn nf_ident_dummy(&ident i) -> ident { fail; }
|
||||
fn nf_path_dummy(&path p) -> path { fail; }
|
||||
fn nf_obj_field_dummy(&obj_field o) -> obj_field { fail; }
|
||||
fn nf_local_dummy(&@local o) -> @local { fail; }
|
||||
|
||||
/* some little folds that probably aren't useful to have in ast_fold itself*/
|
||||
|
||||
//used in noop_fold_item and noop_fold_crate and noop_fold_crate_directive
|
||||
fn fold_meta_item_(&@meta_item mi, ast_fold fld) -> @meta_item {
|
||||
ret @rec(node=
|
||||
alt (mi.node) {
|
||||
case (meta_word(?id)) { meta_word(fld.fold_ident(id)) }
|
||||
case (meta_list(?id, ?mis)) {
|
||||
auto fold_meta_item = bind fold_meta_item_(_,fld);
|
||||
meta_list(id, map(fold_meta_item, mis))
|
||||
}
|
||||
case (meta_name_value(?id,?s)) {
|
||||
meta_name_value(fld.fold_ident(id),s)
|
||||
}
|
||||
},
|
||||
span=mi.span);
|
||||
}
|
||||
//used in noop_fold_item and noop_fold_crate
|
||||
fn fold_attribute_(&attribute at, fn(&@meta_item) -> @meta_item fmi)
|
||||
-> attribute {
|
||||
ret rec(node=rec(style=at.node.style,
|
||||
value=*fmi(@at.node.value)),
|
||||
span=at.span);
|
||||
}
|
||||
//used in noop_fold_native_item and noop_fold_fn
|
||||
fn fold_arg_(&arg a, ast_fold fld) -> arg {
|
||||
ret rec(mode=a.mode, ty=fld.fold_ty(a.ty),
|
||||
ident=fld.fold_ident(a.ident), id=a.id);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
fn noop_fold_crate(&crate_ c, ast_fold fld) -> crate_ {
|
||||
auto fold_meta_item = bind fold_meta_item_(_,fld);
|
||||
auto fold_attribute = bind fold_attribute_(_,fold_meta_item);
|
||||
|
||||
ret rec(directives=map(fld.fold_crate_directive, c.directives),
|
||||
module=fld.fold_mod(c.module),
|
||||
attrs=map(fold_attribute, c.attrs),
|
||||
config=map(fold_meta_item, c.config));
|
||||
}
|
||||
|
||||
fn noop_fold_crate_directive(&crate_directive_ cd, ast_fold fld)
|
||||
-> crate_directive_ {
|
||||
ret alt(cd) {
|
||||
case(cdir_src_mod(?id,?fname,?attrs)) {
|
||||
cdir_src_mod(fld.fold_ident(id), fname, attrs)
|
||||
}
|
||||
case(cdir_dir_mod(?id,?fname,?cds,?attrs)) {
|
||||
cdir_dir_mod(fld.fold_ident(id),fname,
|
||||
map(fld.fold_crate_directive, cds), attrs)
|
||||
}
|
||||
case(cdir_view_item(?vi)) {
|
||||
cdir_view_item(fld.fold_view_item(vi))
|
||||
}
|
||||
case(cdir_syntax(_)) { cd }
|
||||
case(cdir_auth(_,_)) { cd }
|
||||
}
|
||||
}
|
||||
|
||||
fn noop_fold_view_item(&view_item_ vi, ast_fold fld) -> view_item_ {
|
||||
ret vi;
|
||||
}
|
||||
|
||||
|
||||
fn noop_fold_native_item(&@native_item ni, ast_fold fld) -> @native_item {
|
||||
auto fold_arg = bind fold_arg_(_, fld);
|
||||
|
||||
ret @rec(ident=fld.fold_ident(ni.ident),
|
||||
node=alt (ni.node) {
|
||||
case (native_item_ty) { native_item_ty }
|
||||
case (native_item_fn(?st, ?fdec, ?typms)) {
|
||||
native_item_fn(st,
|
||||
rec(inputs=map(fold_arg, fdec.inputs),
|
||||
output=fld.fold_ty(fdec.output),
|
||||
purity=fdec.purity, cf=fdec.cf,
|
||||
constraints=map(fld.fold_constr,
|
||||
fdec.constraints)),
|
||||
typms)
|
||||
}
|
||||
},
|
||||
id=ni.id,
|
||||
span=ni.span);
|
||||
}
|
||||
|
||||
fn noop_fold_item(&@item i, ast_fold fld) -> @item {
|
||||
auto fold_meta_item = bind fold_meta_item_(_,fld);
|
||||
auto fold_attribute = bind fold_attribute_(_,fold_meta_item);
|
||||
|
||||
ret @rec(ident=fld.fold_ident(i.ident),
|
||||
attrs=map(fold_attribute,i.attrs),
|
||||
id=i.id, node=fld.fold_item_underscore(i.node),
|
||||
span=i.span);
|
||||
}
|
||||
|
||||
fn noop_fold_item_underscore(&item_ i, ast_fold fld) -> item_ {
|
||||
fn fold_obj_field_(&obj_field of, ast_fold fld) -> obj_field {
|
||||
ret rec(mut=of.mut, ty=fld.fold_ty(of.ty),
|
||||
ident=fld.fold_ident(of.ident), id=of.id);
|
||||
}
|
||||
auto fold_obj_field = bind fold_obj_field_(_,fld);
|
||||
|
||||
ret alt(i) {
|
||||
case (item_const(?t, ?e)) {
|
||||
item_const(fld.fold_ty(t), fld.fold_expr(e))
|
||||
}
|
||||
case (item_fn(?f, ?typms)) {
|
||||
item_fn(fld.fold_fn(f), typms)
|
||||
}
|
||||
case (item_mod(?m)) { item_mod(fld.fold_mod(m)) }
|
||||
case (item_native_mod(?nm)) {
|
||||
item_native_mod(fld.fold_native_mod(nm))
|
||||
}
|
||||
case (item_ty(?t, ?typms)) {
|
||||
item_ty(fld.fold_ty(t), typms)
|
||||
}
|
||||
case (item_tag(?variants, ?typms)) {
|
||||
item_tag(map(fld.fold_variant, variants), typms)
|
||||
}
|
||||
case (item_obj(?o, ?typms, ?d)) {
|
||||
item_obj(rec(fields=map(fold_obj_field,o.fields),
|
||||
methods=map(fld.fold_method,o.methods),
|
||||
dtor=option::map(fld.fold_method,o.dtor)),
|
||||
typms, d)
|
||||
}
|
||||
case (item_res(?dtor, ?did, ?typms, ?cid)) {
|
||||
item_res(fld.fold_fn(dtor), did, typms, cid)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn noop_fold_method(&method_ m, ast_fold fld) -> method_ {
|
||||
ret rec(ident=fld.fold_ident(m.ident),
|
||||
meth=fld.fold_fn(m.meth), id=m.id);
|
||||
}
|
||||
|
||||
|
||||
fn noop_fold_block(&block_ b, ast_fold fld) -> block_ {
|
||||
ret rec(stmts=map(fld.fold_stmt, b.stmts),
|
||||
expr=option::map(fld.fold_expr, b.expr), id=b.id);
|
||||
}
|
||||
|
||||
fn noop_fold_stmt(&stmt_ s, ast_fold fld) -> stmt_ {
|
||||
ret alt(s) {
|
||||
case (stmt_decl(?d, ?nid)) { stmt_decl(fld.fold_decl(d), nid) }
|
||||
case (stmt_expr(?e, ?nid)) { stmt_expr(fld.fold_expr(e), nid) }
|
||||
case (stmt_crate_directive(?cd)) {
|
||||
stmt_crate_directive(fld.fold_crate_directive(cd))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn noop_fold_arm(&arm a, ast_fold fld) -> arm {
|
||||
ret rec(pat=fld.fold_pat(a.pat), block=fld.fold_block(a.block));
|
||||
}
|
||||
|
||||
fn noop_fold_pat(&pat_ p, ast_fold fld) -> pat_ {
|
||||
ret alt (p) {
|
||||
case (pat_wild) { p }
|
||||
case (pat_bind(?ident)) { pat_bind(fld.fold_ident(ident))}
|
||||
case (pat_lit(_)) { p }
|
||||
case (pat_tag(?pth, ?pats)) {
|
||||
pat_tag(fld.fold_path(pth), map(fld.fold_pat, pats))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn noop_fold_decl(&decl_ d, ast_fold fld) -> decl_ {
|
||||
ret alt (d) {
|
||||
// local really doesn't need its own fold...
|
||||
case (decl_local(?l)) {
|
||||
decl_local(fld.fold_local(l))
|
||||
}
|
||||
case (decl_item(?it)) { decl_item(fld.fold_item(it)) }
|
||||
}
|
||||
}
|
||||
|
||||
fn noop_fold_expr(&expr_ e, ast_fold fld) -> expr_ {
|
||||
fn fold_elt_(&elt elt, ast_fold fld) -> elt {
|
||||
ret rec(mut=elt.mut, expr=fld.fold_expr(elt.expr));
|
||||
}
|
||||
auto fold_elt = bind fold_elt_(_,fld);
|
||||
fn fold_field_(&field field, ast_fold fld) -> field {
|
||||
ret rec(node=rec(mut=field.node.mut,
|
||||
ident=fld.fold_ident(field.node.ident),
|
||||
expr=fld.fold_expr(field.node.expr)),
|
||||
span=field.span);
|
||||
}
|
||||
auto fold_field = bind fold_field_(_,fld);
|
||||
fn fold_anon_obj_(&anon_obj ao, ast_fold fld) -> anon_obj {
|
||||
fn fold_anon_obj_field_(&anon_obj_field aof, ast_fold fld)
|
||||
-> anon_obj_field {
|
||||
ret rec(mut=aof.mut, ty=fld.fold_ty(aof.ty),
|
||||
expr=fld.fold_expr(aof.expr),
|
||||
ident=fld.fold_ident(aof.ident), id=aof.id);
|
||||
}
|
||||
auto fold_anon_obj_field = bind fold_anon_obj_field_(_,fld);
|
||||
|
||||
ret rec(fields=alt(ao.fields) {
|
||||
case (option::none[vec[anon_obj_field]]) { ao.fields }
|
||||
case (option::some[vec[anon_obj_field]](?v)) {
|
||||
option::some[vec[anon_obj_field]]
|
||||
(map(fold_anon_obj_field, v))
|
||||
}},
|
||||
methods=map(fld.fold_method, ao.methods),
|
||||
with_obj=option::map(fld.fold_expr, ao.with_obj))
|
||||
}
|
||||
auto fold_anon_obj = bind fold_anon_obj_(_,fld);
|
||||
|
||||
|
||||
ret alt (e) {
|
||||
case (expr_vec(?exprs, ?mut, ?seq_kind)) {
|
||||
expr_vec(map(fld.fold_expr, exprs), mut, seq_kind)
|
||||
}
|
||||
case (expr_tup(?elts)) {
|
||||
expr_tup(map(fold_elt, elts))
|
||||
}
|
||||
case (expr_rec(?fields, ?maybe_expr)) {
|
||||
expr_rec(map(fold_field, fields),
|
||||
option::map(fld.fold_expr, maybe_expr))
|
||||
}
|
||||
case (expr_call(?f, ?args)) {
|
||||
expr_call(fld.fold_expr(f), map(fld.fold_expr, args))
|
||||
}
|
||||
case (expr_self_method(?id)) {
|
||||
expr_self_method(fld.fold_ident(id))
|
||||
}
|
||||
case (expr_bind(?f, ?args)) {
|
||||
auto opt_map_se = bind option::map(fld.fold_expr,_);
|
||||
expr_bind(fld.fold_expr(f), map(opt_map_se, args))
|
||||
}
|
||||
case (expr_spawn(?spawn_dom, ?name, ?f, ?args)) {
|
||||
expr_spawn(spawn_dom, name, fld.fold_expr(f),
|
||||
map(fld.fold_expr, args))
|
||||
}
|
||||
case (expr_binary(?binop, ?lhs, ?rhs)) {
|
||||
expr_binary(binop, fld.fold_expr(lhs), fld.fold_expr(rhs))
|
||||
}
|
||||
case (expr_unary(?binop, ?ohs)) {
|
||||
expr_unary(binop, fld.fold_expr(ohs))
|
||||
}
|
||||
case (expr_lit(_)) { e }
|
||||
case (expr_cast(?expr, ?ty)) {
|
||||
expr_cast(fld.fold_expr(expr), ty)
|
||||
}
|
||||
case (expr_if(?cond, ?tr, ?fl)) {
|
||||
expr_if(fld.fold_expr(cond), fld.fold_block(tr),
|
||||
option::map(fld.fold_expr, fl))
|
||||
}
|
||||
case (expr_ternary(?cond, ?tr, ?fl)) {
|
||||
expr_ternary(fld.fold_expr(cond),
|
||||
fld.fold_expr(tr),
|
||||
fld.fold_expr(fl))
|
||||
}
|
||||
case (expr_while(?cond, ?body)) {
|
||||
expr_while(fld.fold_expr(cond), fld.fold_block(body))
|
||||
}
|
||||
case (expr_for(?decl, ?expr, ?block)) {
|
||||
expr_for(fld.fold_local(decl), fld.fold_expr(expr),
|
||||
fld.fold_block(block))
|
||||
}
|
||||
case (expr_for_each(?decl, ?expr, ?block)) {
|
||||
expr_for_each(fld.fold_local(decl), fld.fold_expr(expr),
|
||||
fld.fold_block(block))
|
||||
}
|
||||
case (expr_do_while(?block, ?expr)) {
|
||||
expr_do_while(fld.fold_block(block), fld.fold_expr(expr))
|
||||
}
|
||||
case (expr_alt(?expr, ?arms)) {
|
||||
expr_alt(fld.fold_expr(expr), map(fld.fold_arm, arms))
|
||||
}
|
||||
case (expr_fn(?f)) {
|
||||
expr_fn(fld.fold_fn(f))
|
||||
}
|
||||
case (expr_block(?block)) {
|
||||
expr_block(fld.fold_block(block))
|
||||
}
|
||||
case (expr_move(?el, ?er)) {
|
||||
expr_move(fld.fold_expr(el), fld.fold_expr(er))
|
||||
}
|
||||
case (expr_assign(?el, ?er)) {
|
||||
expr_assign(fld.fold_expr(el), fld.fold_expr(er))
|
||||
}
|
||||
case (expr_swap(?el, ?er)) {
|
||||
expr_swap(fld.fold_expr(el), fld.fold_expr(er))
|
||||
}
|
||||
case (expr_assign_op(?op, ?el, ?er)) {
|
||||
expr_assign_op(op, fld.fold_expr(el), fld.fold_expr(er))
|
||||
}
|
||||
case (expr_send(?el, ?er)) {
|
||||
expr_send(fld.fold_expr(el), fld.fold_expr(er))
|
||||
}
|
||||
case (expr_recv(?el, ?er)) {
|
||||
expr_recv(fld.fold_expr(el), fld.fold_expr(er))
|
||||
}
|
||||
case (expr_field(?el, ?id)) {
|
||||
expr_field(fld.fold_expr(el), fld.fold_ident(id))
|
||||
}
|
||||
case (expr_index(?el, ?er)) {
|
||||
expr_index(fld.fold_expr(el), fld.fold_expr(er))
|
||||
}
|
||||
case (expr_path(?pth)) {
|
||||
expr_path(fld.fold_path(pth))
|
||||
}
|
||||
case (expr_ext(?pth, ?args, ?body, ?expanded)) {
|
||||
expr_ext(fld.fold_path(pth), map(fld.fold_expr, args),
|
||||
body, fld.fold_expr(expanded))
|
||||
}
|
||||
case (expr_fail(_)) { e }
|
||||
case (expr_break()) { e }
|
||||
case (expr_cont()) { e }
|
||||
case (expr_ret(?e)) {
|
||||
expr_ret(option::map(fld.fold_expr, e))
|
||||
}
|
||||
case (expr_put(?e)) {
|
||||
expr_put(option::map(fld.fold_expr, e))
|
||||
}
|
||||
case (expr_be(?e)) { expr_be(fld.fold_expr(e)) }
|
||||
case (expr_log(?lv, ?e)) { expr_log(lv, fld.fold_expr(e)) }
|
||||
case (expr_assert(?e)) { expr_assert(fld.fold_expr(e)) }
|
||||
case (expr_check(?m, ?e)) { expr_check(m, fld.fold_expr(e)) }
|
||||
case (expr_if_check(?cond, ?tr, ?fl)) {
|
||||
expr_if_check(fld.fold_expr(cond), fld.fold_block(tr),
|
||||
option::map(fld.fold_expr, fl))
|
||||
}
|
||||
case (expr_port(?ot)) {
|
||||
expr_port(alt(ot) {
|
||||
case (option::some(?t)) { option::some(fld.fold_ty(t)) }
|
||||
case (option::none) { option::none }
|
||||
})
|
||||
}
|
||||
case (expr_chan(?e)) { expr_chan(fld.fold_expr(e)) }
|
||||
case (expr_anon_obj(?ao, ?typms, ?odis)) {
|
||||
expr_anon_obj(fold_anon_obj(ao), typms, odis)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn noop_fold_ty(&ty_ t, ast_fold fld) -> ty_ {
|
||||
//drop in ty::fold_ty here if necessary
|
||||
ret t;
|
||||
}
|
||||
|
||||
fn noop_fold_constr(&constr_ c, ast_fold fld) -> constr_ {
|
||||
ret rec(path=fld.fold_path(c.path), args=c.args, id=c.id);
|
||||
}
|
||||
|
||||
// functions just don't get spans, for some reason
|
||||
fn noop_fold_fn(&_fn f, ast_fold fld) -> _fn {
|
||||
auto fold_arg = bind fold_arg_(_, fld);
|
||||
|
||||
ret rec(decl= rec(inputs=map(fold_arg, f.decl.inputs),
|
||||
output=fld.fold_ty(f.decl.output),
|
||||
purity=f.decl.purity,
|
||||
cf=f.decl.cf,
|
||||
constraints=map(fld.fold_constr, f.decl.constraints)),
|
||||
proto = f.proto,
|
||||
body = fld.fold_block(f.body));
|
||||
}
|
||||
|
||||
// ...nor do modules
|
||||
fn noop_fold_mod(&_mod m, ast_fold fld) -> _mod {
|
||||
ret rec(view_items=map(fld.fold_view_item, m.view_items),
|
||||
items=map(fld.fold_item, m.items));
|
||||
}
|
||||
|
||||
fn noop_fold_native_mod(&native_mod nm, ast_fold fld) -> native_mod {
|
||||
ret rec(native_name=nm.native_name,
|
||||
abi=nm.abi,
|
||||
view_items=map(fld.fold_view_item, nm.view_items),
|
||||
items=map(fld.fold_native_item, nm.items))
|
||||
}
|
||||
|
||||
fn noop_fold_variant(&variant_ v, ast_fold fld) -> variant_ {
|
||||
fn fold_variant_arg_(&variant_arg va, ast_fold fld) -> variant_arg {
|
||||
ret rec(ty=fld.fold_ty(va.ty), id=va.id);
|
||||
}
|
||||
auto fold_variant_arg = bind fold_variant_arg_(_,fld);
|
||||
ret rec(name=v.name,
|
||||
args=map(fold_variant_arg, v.args),
|
||||
id=v.id);
|
||||
}
|
||||
|
||||
fn noop_fold_ident(&ident i, ast_fold fld) -> ident {
|
||||
ret i;
|
||||
}
|
||||
|
||||
fn noop_fold_path(&path_ p, ast_fold fld) -> path_ {
|
||||
ret rec(idents=map(fld.fold_ident, p.idents),
|
||||
types=map(fld.fold_ty, p.types));
|
||||
}
|
||||
|
||||
fn noop_fold_local(&local_ l, ast_fold fld) -> local_ {
|
||||
ret rec(ty=option::map(fld.fold_ty,l.ty),
|
||||
infer=l.infer,
|
||||
ident=fld.fold_ident(l.ident),
|
||||
init=alt (l.init) {
|
||||
case (option::none[initializer]) { l.init }
|
||||
case (option::some[initializer](?init)) {
|
||||
option::some[initializer]
|
||||
(rec(op=init.op,
|
||||
expr=fld.fold_expr(init.expr)))
|
||||
}
|
||||
},
|
||||
id=l.id);
|
||||
}
|
||||
|
||||
|
||||
fn default_ast_fold() -> @ast_fold_precursor {
|
||||
ret @rec(fold_crate = noop_fold_crate,
|
||||
fold_crate_directive = noop_fold_crate_directive,
|
||||
fold_view_item = noop_fold_view_item,
|
||||
fold_native_item = noop_fold_native_item,
|
||||
fold_item = noop_fold_item,
|
||||
fold_item_underscore = noop_fold_item_underscore,
|
||||
fold_method = noop_fold_method,
|
||||
fold_block = noop_fold_block,
|
||||
fold_stmt = noop_fold_stmt,
|
||||
fold_arm = noop_fold_arm,
|
||||
fold_pat = noop_fold_pat,
|
||||
fold_decl = noop_fold_decl,
|
||||
fold_expr = noop_fold_expr,
|
||||
fold_ty = noop_fold_ty,
|
||||
fold_constr = noop_fold_constr,
|
||||
fold_fn = noop_fold_fn,
|
||||
fold_mod = noop_fold_mod,
|
||||
fold_native_mod = noop_fold_native_mod,
|
||||
fold_variant = noop_fold_variant,
|
||||
fold_ident = noop_fold_ident,
|
||||
fold_path = noop_fold_path,
|
||||
fold_local = noop_fold_local);
|
||||
}
|
||||
|
||||
fn dummy_out(ast_fold a) {
|
||||
*a = rec(fold_crate = nf_crate_dummy,
|
||||
fold_crate_directive = nf_crate_directive_dummy,
|
||||
fold_view_item = nf_view_item_dummy,
|
||||
fold_native_item = nf_native_item_dummy,
|
||||
fold_item = nf_item_dummy,
|
||||
fold_item_underscore = nf_item_underscore_dummy,
|
||||
fold_method = nf_method_dummy,
|
||||
fold_block = nf_block_dummy,
|
||||
fold_stmt = nf_stmt_dummy,
|
||||
fold_arm = nf_arm_dummy,
|
||||
fold_pat = nf_pat_dummy,
|
||||
fold_decl = nf_decl_dummy,
|
||||
fold_expr = nf_expr_dummy,
|
||||
fold_ty = nf_ty_dummy,
|
||||
fold_constr = nf_constr_dummy,
|
||||
fold_fn = nf_fn_dummy,
|
||||
fold_mod = nf_mod_dummy,
|
||||
fold_native_mod = nf_native_mod_dummy,
|
||||
fold_variant = nf_variant_dummy,
|
||||
fold_ident = nf_ident_dummy,
|
||||
fold_path = nf_path_dummy,
|
||||
fold_local = nf_local_dummy);
|
||||
}
|
||||
|
||||
|
||||
fn make_fold(&ast_fold_precursor afp) -> ast_fold {
|
||||
let ast_fold result =
|
||||
@mutable rec(fold_crate = nf_crate_dummy,
|
||||
fold_crate_directive = nf_crate_directive_dummy,
|
||||
fold_view_item = nf_view_item_dummy,
|
||||
fold_native_item = nf_native_item_dummy,
|
||||
fold_item = nf_item_dummy,
|
||||
fold_item_underscore = nf_item_underscore_dummy,
|
||||
fold_method = nf_method_dummy,
|
||||
fold_block = nf_block_dummy,
|
||||
fold_stmt = nf_stmt_dummy,
|
||||
fold_arm = nf_arm_dummy,
|
||||
fold_pat = nf_pat_dummy,
|
||||
fold_decl = nf_decl_dummy,
|
||||
fold_expr = nf_expr_dummy,
|
||||
fold_ty = nf_ty_dummy,
|
||||
fold_constr = nf_constr_dummy,
|
||||
fold_fn = nf_fn_dummy,
|
||||
fold_mod = nf_mod_dummy,
|
||||
fold_native_mod = nf_native_mod_dummy,
|
||||
fold_variant = nf_variant_dummy,
|
||||
fold_ident = nf_ident_dummy,
|
||||
fold_path = nf_path_dummy,
|
||||
fold_local = nf_local_dummy);
|
||||
|
||||
/* naturally, a macro to write these would be nice */
|
||||
fn f_crate(&ast_fold_precursor afp, ast_fold f, &crate c) -> crate {
|
||||
ret rec(node=afp.fold_crate(c.node, f),
|
||||
span=c.span);
|
||||
}
|
||||
fn f_crate_directive(&ast_fold_precursor afp, ast_fold f,
|
||||
&@crate_directive c) -> @crate_directive {
|
||||
ret @rec(node=afp.fold_crate_directive(c.node, f),
|
||||
span=c.span);
|
||||
}
|
||||
fn f_view_item(&ast_fold_precursor afp, ast_fold f, &@view_item x)
|
||||
-> @view_item {
|
||||
ret @rec(node=afp.fold_view_item(x.node, f), span=x.span);
|
||||
}
|
||||
fn f_native_item(&ast_fold_precursor afp, ast_fold f, &@native_item x)
|
||||
-> @native_item {
|
||||
ret afp.fold_native_item(x, f);
|
||||
}
|
||||
fn f_item(&ast_fold_precursor afp, ast_fold f, &@item i) -> @item {
|
||||
ret afp.fold_item(i, f);
|
||||
}
|
||||
fn f_item_underscore(&ast_fold_precursor afp, ast_fold f, &item_ i) ->
|
||||
item_ {
|
||||
ret afp.fold_item_underscore(i, f);
|
||||
}
|
||||
fn f_method(&ast_fold_precursor afp, ast_fold f, &@method x) -> @method {
|
||||
ret @rec(node=afp.fold_method(x.node, f), span=x.span);
|
||||
}
|
||||
fn f_block(&ast_fold_precursor afp, ast_fold f, &block x) -> block {
|
||||
ret rec(node=afp.fold_block(x.node, f), span=x.span);
|
||||
}
|
||||
fn f_stmt(&ast_fold_precursor afp, ast_fold f, &@stmt x) -> @stmt {
|
||||
ret @rec(node=afp.fold_stmt(x.node, f), span=x.span);
|
||||
}
|
||||
fn f_arm(&ast_fold_precursor afp, ast_fold f, &arm x) -> arm {
|
||||
ret afp.fold_arm(x, f);
|
||||
}
|
||||
fn f_pat(&ast_fold_precursor afp, ast_fold f, &@pat x) -> @pat {
|
||||
ret @rec(id=x.id, node=afp.fold_pat(x.node, f), span=x.span);
|
||||
}
|
||||
fn f_decl(&ast_fold_precursor afp, ast_fold f, &@decl x) -> @decl {
|
||||
ret @rec(node=afp.fold_decl(x.node, f), span=x.span);
|
||||
}
|
||||
fn f_expr(&ast_fold_precursor afp, ast_fold f, &@expr x) -> @expr {
|
||||
ret @rec(id=x.id, node=afp.fold_expr(x.node, f), span=x.span);
|
||||
}
|
||||
fn f_ty(&ast_fold_precursor afp, ast_fold f, &@ty x) -> @ty {
|
||||
ret @rec(node=afp.fold_ty(x.node, f), span=x.span);
|
||||
}
|
||||
fn f_constr(&ast_fold_precursor afp, ast_fold f, &@constr x) -> @constr {
|
||||
ret @rec(node=afp.fold_constr(x.node, f), span=x.span);
|
||||
}
|
||||
fn f_fn(&ast_fold_precursor afp, ast_fold f, &_fn x) -> _fn {
|
||||
ret afp.fold_fn(x, f);
|
||||
}
|
||||
fn f_mod(&ast_fold_precursor afp, ast_fold f, &_mod x) -> _mod {
|
||||
ret afp.fold_mod(x, f);
|
||||
}
|
||||
fn f_native_mod(&ast_fold_precursor afp, ast_fold f, &native_mod x) ->
|
||||
native_mod {
|
||||
ret afp.fold_native_mod(x, f);
|
||||
}
|
||||
fn f_variant(&ast_fold_precursor afp, ast_fold f, &variant x)
|
||||
-> variant {
|
||||
ret rec(node=afp.fold_variant(x.node, f), span=x.span);
|
||||
}
|
||||
fn f_ident(&ast_fold_precursor afp, ast_fold f, &ident x) -> ident {
|
||||
ret afp.fold_ident(x, f);
|
||||
}
|
||||
fn f_path(&ast_fold_precursor afp, ast_fold f, &path x) -> path {
|
||||
ret rec(node=afp.fold_path(x.node, f), span=x.span);
|
||||
}
|
||||
fn f_local(&ast_fold_precursor afp, ast_fold f, &@local x) -> @local {
|
||||
ret @rec(node=afp.fold_local(x.node, f), span=x.span);
|
||||
}
|
||||
|
||||
*result = rec(fold_crate = bind f_crate(afp,result,_),
|
||||
fold_crate_directive = bind f_crate_directive(afp,result,_),
|
||||
fold_view_item = bind f_view_item(afp,result,_),
|
||||
fold_native_item = bind f_native_item(afp,result,_),
|
||||
fold_item = bind f_item(afp,result,_),
|
||||
fold_item_underscore = bind f_item_underscore(afp,result,_),
|
||||
fold_method = bind f_method(afp,result,_),
|
||||
fold_block = bind f_block(afp,result,_),
|
||||
fold_stmt = bind f_stmt(afp,result,_),
|
||||
fold_arm = bind f_arm(afp, result, _),
|
||||
fold_pat = bind f_pat(afp,result,_),
|
||||
fold_decl = bind f_decl(afp,result,_),
|
||||
fold_expr = bind f_expr(afp,result,_),
|
||||
fold_ty = bind f_ty(afp,result,_),
|
||||
fold_constr = bind f_constr(afp,result,_),
|
||||
fold_fn = bind f_fn(afp,result,_),
|
||||
fold_mod = bind f_mod(afp,result,_),
|
||||
fold_native_mod = bind f_native_mod(afp,result,_),
|
||||
fold_variant = bind f_variant(afp,result,_),
|
||||
fold_ident = bind f_ident(afp,result,_),
|
||||
fold_path = bind f_path(afp,result,_),
|
||||
fold_local = bind f_local(afp,result,_));
|
||||
ret result;
|
||||
/*
|
||||
ret rec(fold_crate = noop_fold_crate,
|
||||
fold_crate_directive = noop_fold_crate_drective,
|
||||
fold_view_item = noop_fold_view_item,
|
||||
fold_native_item = noop_fold_native_item,
|
||||
fold_item = noop_fold_item,
|
||||
fold_method = noop_fold_method,
|
||||
fold_block = noop_fold_block,
|
||||
fold_stmt = noop_fold_stmt,
|
||||
fold_arm = noop_fold_arm,
|
||||
fold_pat = noop_fold_pat,
|
||||
fold_decl = noop_fold_decl,
|
||||
fold_expr = noop_fold_expr,
|
||||
fold_ty = noop_fold_ty,
|
||||
fold_constr = noop_fold_constr,
|
||||
fold_fn = noop_fold_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:
|
||||
//
|
||||
124
src/comp/syntax/parse/eval.rs
Normal file
124
src/comp/syntax/parse/eval.rs
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
|
||||
import std::vec;
|
||||
import std::str;
|
||||
import std::option;
|
||||
import std::option::some;
|
||||
import std::option::none;
|
||||
import syntax::ast;
|
||||
import syntax::parse::token;
|
||||
import syntax::parse::parser::parser;
|
||||
import syntax::parse::parser::new_parser;
|
||||
import syntax::parse::parser::parse_inner_attrs_and_next;
|
||||
import syntax::parse::parser::parse_mod_items;
|
||||
|
||||
export eval_crate_directives_to_mod;
|
||||
export mode_parse;
|
||||
|
||||
tag eval_mode { mode_depend; mode_parse; }
|
||||
|
||||
type ctx =
|
||||
@rec(parser p,
|
||||
eval_mode mode,
|
||||
mutable vec[str] deps,
|
||||
parser::parse_sess sess,
|
||||
mutable uint chpos,
|
||||
ast::crate_cfg cfg);
|
||||
|
||||
fn eval_crate_directives(ctx cx, vec[@ast::crate_directive] cdirs,
|
||||
str prefix, &mutable vec[@ast::view_item] view_items,
|
||||
&mutable vec[@ast::item] items) {
|
||||
for (@ast::crate_directive sub_cdir in cdirs) {
|
||||
eval_crate_directive(cx, sub_cdir, prefix, view_items, items);
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_crate_directives_to_mod(ctx cx,
|
||||
vec[@ast::crate_directive] cdirs, str prefix)
|
||||
-> ast::_mod {
|
||||
let vec[@ast::view_item] view_items = [];
|
||||
let vec[@ast::item] items = [];
|
||||
eval_crate_directives(cx, cdirs, prefix, view_items, items);
|
||||
ret rec(view_items=view_items, items=items);
|
||||
}
|
||||
|
||||
fn eval_crate_directive_block(ctx cx, &ast::block blk, str prefix,
|
||||
&mutable vec[@ast::view_item] view_items,
|
||||
&mutable vec[@ast::item] items) {
|
||||
for (@ast::stmt s in blk.node.stmts) {
|
||||
alt (s.node) {
|
||||
case (ast::stmt_crate_directive(?cdir)) {
|
||||
eval_crate_directive(cx, cdir, prefix, view_items, items);
|
||||
}
|
||||
case (_) {
|
||||
codemap::emit_warning
|
||||
(some(s.span), "unsupported stmt in crate-directive block",
|
||||
cx.sess.cm);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_crate_directive(ctx cx, @ast::crate_directive cdir, str prefix,
|
||||
&mutable vec[@ast::view_item] view_items,
|
||||
&mutable vec[@ast::item] items) {
|
||||
alt (cdir.node) {
|
||||
case (ast::cdir_src_mod(?id, ?file_opt, ?attrs)) {
|
||||
auto file_path = id + ".rs";
|
||||
alt (file_opt) {
|
||||
case (some(?f)) { file_path = f; }
|
||||
case (none) { }
|
||||
}
|
||||
auto full_path = if (std::fs::path_is_absolute(file_path)) {
|
||||
file_path
|
||||
} else {
|
||||
prefix + std::fs::path_sep() + file_path
|
||||
};
|
||||
if (cx.mode == mode_depend) { cx.deps += [full_path]; ret; }
|
||||
auto p0 =
|
||||
new_parser(cx.sess, cx.cfg, full_path, cx.chpos);
|
||||
auto inner_attrs = parse_inner_attrs_and_next(p0);
|
||||
auto mod_attrs = attrs + inner_attrs._0;
|
||||
auto first_item_outer_attrs = inner_attrs._1;
|
||||
auto m0 = parse_mod_items(p0, token::EOF, first_item_outer_attrs);
|
||||
|
||||
auto i = syntax::parse::parser::mk_item
|
||||
(p0, cdir.span.lo, cdir.span.hi, id, ast::item_mod(m0),
|
||||
mod_attrs);
|
||||
// Thread defids and chpos through the parsers
|
||||
cx.chpos = p0.get_chpos();
|
||||
vec::push[@ast::item](items, i);
|
||||
}
|
||||
case (ast::cdir_dir_mod(?id, ?dir_opt, ?cdirs, ?attrs)) {
|
||||
auto path = id;
|
||||
alt (dir_opt) { case (some(?d)) { path = d; } case (none) { } }
|
||||
auto full_path = if (std::fs::path_is_absolute(path)) {
|
||||
path
|
||||
} else {
|
||||
prefix + std::fs::path_sep() + path
|
||||
};
|
||||
auto m0 = eval_crate_directives_to_mod(cx, cdirs, full_path);
|
||||
auto i = @rec(ident=id,
|
||||
attrs=attrs,
|
||||
id=cx.sess.next_id,
|
||||
node=ast::item_mod(m0),
|
||||
span=cdir.span);
|
||||
cx.sess.next_id += 1;
|
||||
vec::push[@ast::item](items, i);
|
||||
}
|
||||
case (ast::cdir_view_item(?vi)) {
|
||||
vec::push[@ast::view_item](view_items, vi);
|
||||
}
|
||||
case (ast::cdir_syntax(?pth)) { }
|
||||
case (ast::cdir_auth(?pth, ?eff)) { }
|
||||
}
|
||||
}
|
||||
//
|
||||
// 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:
|
||||
//
|
||||
758
src/comp/syntax/parse/lexer.rs
Normal file
758
src/comp/syntax/parse/lexer.rs
Normal file
|
|
@ -0,0 +1,758 @@
|
|||
|
||||
import std::io;
|
||||
import std::str;
|
||||
import std::vec;
|
||||
import std::int;
|
||||
import std::map;
|
||||
import std::map::hashmap;
|
||||
import std::option;
|
||||
import std::option::some;
|
||||
import std::option::none;
|
||||
import util::interner;
|
||||
import util::interner::intern;
|
||||
import codemap;
|
||||
|
||||
type reader =
|
||||
obj {
|
||||
fn is_eof() -> bool ;
|
||||
fn curr() -> char ;
|
||||
fn next() -> char ;
|
||||
fn init() ;
|
||||
fn bump() ;
|
||||
fn mark() ;
|
||||
fn get_mark_chpos() -> uint ;
|
||||
fn get_mark_str() -> str ;
|
||||
fn get_interner() -> @interner::interner[str] ;
|
||||
fn get_chpos() -> uint ;
|
||||
fn get_col() -> uint ;
|
||||
fn get_filemap() -> codemap::filemap ;
|
||||
fn err(str) ;
|
||||
};
|
||||
|
||||
fn new_reader(&codemap::codemap cm, io::reader rdr, codemap::filemap filemap,
|
||||
@interner::interner[str] itr) -> reader {
|
||||
obj reader(codemap::codemap cm,
|
||||
str file,
|
||||
uint len,
|
||||
mutable uint col,
|
||||
mutable uint pos,
|
||||
mutable char ch,
|
||||
mutable uint mark_chpos,
|
||||
mutable uint chpos,
|
||||
mutable vec[str] strs,
|
||||
codemap::filemap fm,
|
||||
@interner::interner[str] itr) {
|
||||
fn is_eof() -> bool { ret ch == -1 as char; }
|
||||
fn mark() { mark_chpos = chpos; }
|
||||
fn get_mark_str() -> str { ret str::slice(file, mark_chpos, chpos); }
|
||||
fn get_mark_chpos() -> uint { ret mark_chpos; }
|
||||
fn get_chpos() -> uint { ret chpos; }
|
||||
fn curr() -> char { ret ch; }
|
||||
fn next() -> char {
|
||||
if (pos < len) {
|
||||
ret str::char_at(file, pos);
|
||||
} else { ret -1 as char; }
|
||||
}
|
||||
fn init() {
|
||||
if (pos < len) {
|
||||
auto next = str::char_range_at(file, pos);
|
||||
pos = next._1;
|
||||
ch = next._0;
|
||||
}
|
||||
}
|
||||
fn bump() {
|
||||
if (pos < len) {
|
||||
col += 1u;
|
||||
chpos += 1u;
|
||||
if (ch == '\n') { codemap::next_line(fm, chpos); col = 0u; }
|
||||
auto next = str::char_range_at(file, pos);
|
||||
pos = next._1;
|
||||
ch = next._0;
|
||||
} else { ch = -1 as char; }
|
||||
}
|
||||
fn get_interner() -> @interner::interner[str] { ret itr; }
|
||||
fn get_col() -> uint { ret col; }
|
||||
fn get_filemap() -> codemap::filemap { ret fm; }
|
||||
fn err(str m) {
|
||||
codemap::emit_error(some(rec(lo=chpos, hi=chpos)), m, cm);
|
||||
}
|
||||
}
|
||||
auto file = str::unsafe_from_bytes(rdr.read_whole_stream());
|
||||
let vec[str] strs = [];
|
||||
auto rd =
|
||||
reader(cm, file, str::byte_len(file), 0u, 0u, -1 as char,
|
||||
filemap.start_pos, filemap.start_pos, strs, filemap, itr);
|
||||
rd.init();
|
||||
ret rd;
|
||||
}
|
||||
|
||||
fn dec_digit_val(char c) -> int { ret (c as int) - ('0' as int); }
|
||||
|
||||
fn hex_digit_val(char c) -> int {
|
||||
if (in_range(c, '0', '9')) { ret (c as int) - ('0' as int); }
|
||||
if (in_range(c, 'a', 'f')) { ret (c as int) - ('a' as int) + 10; }
|
||||
if (in_range(c, 'A', 'F')) { ret (c as int) - ('A' as int) + 10; }
|
||||
fail;
|
||||
}
|
||||
|
||||
fn bin_digit_value(char c) -> int { if (c == '0') { ret 0; } ret 1; }
|
||||
|
||||
fn is_whitespace(char c) -> bool {
|
||||
ret c == ' ' || c == '\t' || c == '\r' || c == '\n';
|
||||
}
|
||||
|
||||
fn may_begin_ident(char c) -> bool { ret is_alpha(c) || c == '_'; }
|
||||
|
||||
fn in_range(char c, char lo, char hi) -> bool { ret lo <= c && c <= hi; }
|
||||
|
||||
fn is_alpha(char c) -> bool {
|
||||
ret in_range(c, 'a', 'z') || in_range(c, 'A', 'Z');
|
||||
}
|
||||
|
||||
fn is_dec_digit(char c) -> bool { ret in_range(c, '0', '9'); }
|
||||
|
||||
fn is_alnum(char c) -> bool { ret is_alpha(c) || is_dec_digit(c); }
|
||||
|
||||
fn is_hex_digit(char c) -> bool {
|
||||
ret in_range(c, '0', '9') || in_range(c, 'a', 'f') ||
|
||||
in_range(c, 'A', 'F');
|
||||
}
|
||||
|
||||
fn is_bin_digit(char c) -> bool { ret c == '0' || c == '1'; }
|
||||
|
||||
fn consume_whitespace_and_comments(&reader rdr) {
|
||||
while (is_whitespace(rdr.curr())) { rdr.bump(); }
|
||||
be consume_any_line_comment(rdr);
|
||||
}
|
||||
|
||||
fn consume_any_line_comment(&reader rdr) {
|
||||
if (rdr.curr() == '/') {
|
||||
alt (rdr.next()) {
|
||||
case ('/') {
|
||||
while (rdr.curr() != '\n' && !rdr.is_eof()) { rdr.bump(); }
|
||||
// Restart whitespace munch.
|
||||
|
||||
be consume_whitespace_and_comments(rdr);
|
||||
}
|
||||
case ('*') {
|
||||
rdr.bump();
|
||||
rdr.bump();
|
||||
be consume_block_comment(rdr);
|
||||
}
|
||||
case (_) { ret; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn consume_block_comment(&reader rdr) {
|
||||
let int level = 1;
|
||||
while (level > 0) {
|
||||
if (rdr.is_eof()) { rdr.err("unterminated block comment"); fail; }
|
||||
if (rdr.curr() == '/' && rdr.next() == '*') {
|
||||
rdr.bump();
|
||||
rdr.bump();
|
||||
level += 1;
|
||||
} else {
|
||||
if (rdr.curr() == '*' && rdr.next() == '/') {
|
||||
rdr.bump();
|
||||
rdr.bump();
|
||||
level -= 1;
|
||||
} else { rdr.bump(); }
|
||||
}
|
||||
}
|
||||
// restart whitespace munch.
|
||||
|
||||
be consume_whitespace_and_comments(rdr);
|
||||
}
|
||||
|
||||
fn digits_to_string(str s) -> int {
|
||||
let int accum_int = 0;
|
||||
for (u8 c in s) {
|
||||
accum_int *= 10;
|
||||
accum_int += dec_digit_val(c as char);
|
||||
}
|
||||
ret accum_int;
|
||||
}
|
||||
|
||||
fn scan_exponent(&reader rdr) -> option::t[str] {
|
||||
auto c = rdr.curr();
|
||||
auto rslt = "";
|
||||
if (c == 'e' || c == 'E') {
|
||||
rslt += str::from_bytes([c as u8]);
|
||||
rdr.bump();
|
||||
c = rdr.curr();
|
||||
if (c == '-' || c == '+') {
|
||||
rslt += str::from_bytes([c as u8]);
|
||||
rdr.bump();
|
||||
}
|
||||
auto exponent = scan_dec_digits(rdr);
|
||||
if (str::byte_len(exponent) > 0u) {
|
||||
ret some(rslt + exponent);
|
||||
} else { rdr.err("scan_exponent: bad fp literal"); fail; }
|
||||
} else { ret none[str]; }
|
||||
}
|
||||
|
||||
fn scan_dec_digits(&reader rdr) -> str {
|
||||
auto c = rdr.curr();
|
||||
let str rslt = "";
|
||||
while (is_dec_digit(c) || c == '_') {
|
||||
if (c != '_') { rslt += str::from_bytes([c as u8]); }
|
||||
rdr.bump();
|
||||
c = rdr.curr();
|
||||
}
|
||||
ret rslt;
|
||||
}
|
||||
|
||||
fn scan_number(char c, &reader rdr) -> token::token {
|
||||
auto accum_int = 0;
|
||||
let str dec_str = "";
|
||||
let bool is_dec_integer = false;
|
||||
auto n = rdr.next();
|
||||
if (c == '0' && n == 'x') {
|
||||
rdr.bump();
|
||||
rdr.bump();
|
||||
c = rdr.curr();
|
||||
while (is_hex_digit(c) || c == '_') {
|
||||
if (c != '_') { accum_int *= 16; accum_int += hex_digit_val(c); }
|
||||
rdr.bump();
|
||||
c = rdr.curr();
|
||||
}
|
||||
} else if (c == '0' && n == 'b') {
|
||||
rdr.bump();
|
||||
rdr.bump();
|
||||
c = rdr.curr();
|
||||
while (is_bin_digit(c) || c == '_') {
|
||||
if (c != '_') { accum_int *= 2; accum_int += bin_digit_value(c); }
|
||||
rdr.bump();
|
||||
c = rdr.curr();
|
||||
}
|
||||
} else { dec_str = scan_dec_digits(rdr); is_dec_integer = true; }
|
||||
if (is_dec_integer) { accum_int = digits_to_string(dec_str); }
|
||||
c = rdr.curr();
|
||||
n = rdr.next();
|
||||
if (c == 'u' || c == 'i') {
|
||||
let bool signed = c == 'i';
|
||||
rdr.bump();
|
||||
c = rdr.curr();
|
||||
if (c == '8') {
|
||||
rdr.bump();
|
||||
if (signed) {
|
||||
ret token::LIT_MACH_INT(ast::ty_i8, accum_int);
|
||||
} else { ret token::LIT_MACH_INT(ast::ty_u8, accum_int); }
|
||||
}
|
||||
n = rdr.next();
|
||||
if (c == '1' && n == '6') {
|
||||
rdr.bump();
|
||||
rdr.bump();
|
||||
if (signed) {
|
||||
ret token::LIT_MACH_INT(ast::ty_i16, accum_int);
|
||||
} else { ret token::LIT_MACH_INT(ast::ty_u16, accum_int); }
|
||||
}
|
||||
if (c == '3' && n == '2') {
|
||||
rdr.bump();
|
||||
rdr.bump();
|
||||
if (signed) {
|
||||
ret token::LIT_MACH_INT(ast::ty_i32, accum_int);
|
||||
} else { ret token::LIT_MACH_INT(ast::ty_u32, accum_int); }
|
||||
}
|
||||
if (c == '6' && n == '4') {
|
||||
rdr.bump();
|
||||
rdr.bump();
|
||||
if (signed) {
|
||||
ret token::LIT_MACH_INT(ast::ty_i64, accum_int);
|
||||
} else { ret token::LIT_MACH_INT(ast::ty_u64, accum_int); }
|
||||
}
|
||||
if (signed) {
|
||||
ret token::LIT_INT(accum_int);
|
||||
} else {
|
||||
// FIXME: should cast in the target bit-width.
|
||||
|
||||
ret token::LIT_UINT(accum_int as uint);
|
||||
}
|
||||
}
|
||||
c = rdr.curr();
|
||||
if (c == '.') {
|
||||
// Parse a floating-point number.
|
||||
|
||||
rdr.bump();
|
||||
auto dec_part = scan_dec_digits(rdr);
|
||||
auto float_str = dec_str + "." + dec_part;
|
||||
c = rdr.curr();
|
||||
auto exponent_str = scan_exponent(rdr);
|
||||
alt (exponent_str) {
|
||||
case (some(?s)) { float_str += s; }
|
||||
case (none) { }
|
||||
}
|
||||
c = rdr.curr();
|
||||
if (c == 'f') {
|
||||
rdr.bump();
|
||||
c = rdr.curr();
|
||||
n = rdr.next();
|
||||
if (c == '3' && n == '2') {
|
||||
rdr.bump();
|
||||
rdr.bump();
|
||||
ret token::LIT_MACH_FLOAT(ast::ty_f32,
|
||||
intern(*rdr.get_interner(),
|
||||
float_str));
|
||||
} else if (c == '6' && n == '4') {
|
||||
rdr.bump();
|
||||
rdr.bump();
|
||||
ret token::LIT_MACH_FLOAT(ast::ty_f64,
|
||||
intern(*rdr.get_interner(),
|
||||
float_str));
|
||||
/* FIXME: if this is out of range for either a 32-bit or
|
||||
64-bit float, it won't be noticed till the back-end */
|
||||
|
||||
}
|
||||
} else {
|
||||
ret token::LIT_FLOAT(interner::intern[str](*rdr.get_interner(),
|
||||
float_str));
|
||||
}
|
||||
}
|
||||
auto maybe_exponent = scan_exponent(rdr);
|
||||
alt (maybe_exponent) {
|
||||
case (some(?s)) {
|
||||
ret token::LIT_FLOAT(interner::intern[str](*rdr.get_interner(),
|
||||
dec_str + s));
|
||||
}
|
||||
case (none) { ret token::LIT_INT(accum_int); }
|
||||
}
|
||||
}
|
||||
|
||||
fn scan_numeric_escape(&reader rdr, uint n_hex_digits) -> char {
|
||||
auto accum_int = 0;
|
||||
while (n_hex_digits != 0u) {
|
||||
auto n = rdr.curr();
|
||||
rdr.bump();
|
||||
if (!is_hex_digit(n)) {
|
||||
rdr.err(#fmt("illegal numeric character escape: %d", n as int));
|
||||
fail;
|
||||
}
|
||||
accum_int *= 16;
|
||||
accum_int += hex_digit_val(n);
|
||||
n_hex_digits -= 1u;
|
||||
}
|
||||
ret accum_int as char;
|
||||
}
|
||||
|
||||
fn next_token(&reader rdr) -> token::token {
|
||||
auto accum_str = "";
|
||||
consume_whitespace_and_comments(rdr);
|
||||
if (rdr.is_eof()) { ret token::EOF; }
|
||||
rdr.mark();
|
||||
auto c = rdr.curr();
|
||||
if (is_alpha(c) || c == '_') {
|
||||
while (is_alnum(c) || c == '_') {
|
||||
str::push_char(accum_str, c);
|
||||
rdr.bump();
|
||||
c = rdr.curr();
|
||||
}
|
||||
if (str::eq(accum_str, "_")) { ret token::UNDERSCORE; }
|
||||
auto is_mod_name = c == ':' && rdr.next() == ':';
|
||||
ret token::IDENT(interner::intern[str](*rdr.get_interner(),
|
||||
accum_str), is_mod_name);
|
||||
}
|
||||
if (is_dec_digit(c)) { ret scan_number(c, rdr); }
|
||||
fn binop(&reader rdr, token::binop op) -> token::token {
|
||||
rdr.bump();
|
||||
if (rdr.curr() == '=') {
|
||||
rdr.bump();
|
||||
ret token::BINOPEQ(op);
|
||||
} else { ret token::BINOP(op); }
|
||||
}
|
||||
alt (c) {
|
||||
case (
|
||||
// One-byte tokens.
|
||||
'?') {
|
||||
rdr.bump();
|
||||
ret token::QUES;
|
||||
}
|
||||
case (';') { rdr.bump(); ret token::SEMI; }
|
||||
case (',') { rdr.bump(); ret token::COMMA; }
|
||||
case ('.') { rdr.bump(); ret token::DOT; }
|
||||
case ('(') { rdr.bump(); ret token::LPAREN; }
|
||||
case (')') { rdr.bump(); ret token::RPAREN; }
|
||||
case ('{') { rdr.bump(); ret token::LBRACE; }
|
||||
case ('}') { rdr.bump(); ret token::RBRACE; }
|
||||
case ('[') { rdr.bump(); ret token::LBRACKET; }
|
||||
case (']') { rdr.bump(); ret token::RBRACKET; }
|
||||
case ('@') { rdr.bump(); ret token::AT; }
|
||||
case ('#') { rdr.bump(); ret token::POUND; }
|
||||
case ('~') { rdr.bump(); ret token::TILDE; }
|
||||
case (':') {
|
||||
rdr.bump();
|
||||
if (rdr.curr() == ':') {
|
||||
rdr.bump();
|
||||
ret token::MOD_SEP;
|
||||
} else { ret token::COLON; }
|
||||
}
|
||||
case (
|
||||
// Multi-byte tokens.
|
||||
'=') {
|
||||
rdr.bump();
|
||||
if (rdr.curr() == '=') {
|
||||
rdr.bump();
|
||||
ret token::EQEQ;
|
||||
} else { ret token::EQ; }
|
||||
}
|
||||
case ('!') {
|
||||
rdr.bump();
|
||||
if (rdr.curr() == '=') {
|
||||
rdr.bump();
|
||||
ret token::NE;
|
||||
} else { ret token::NOT; }
|
||||
}
|
||||
case ('<') {
|
||||
rdr.bump();
|
||||
alt (rdr.curr()) {
|
||||
case ('=') { rdr.bump(); ret token::LE; }
|
||||
case ('<') { ret binop(rdr, token::LSL); }
|
||||
case ('|') { rdr.bump(); ret token::SEND; }
|
||||
case ('-') {
|
||||
rdr.bump();
|
||||
alt (rdr.curr()) {
|
||||
case ('>') { rdr.bump(); ret token::DARROW; }
|
||||
case (_) { ret token::LARROW; }
|
||||
}
|
||||
}
|
||||
case (_) { ret token::LT; }
|
||||
}
|
||||
}
|
||||
case ('>') {
|
||||
rdr.bump();
|
||||
alt (rdr.curr()) {
|
||||
case ('=') { rdr.bump(); ret token::GE; }
|
||||
case ('>') {
|
||||
if (rdr.next() == '>') {
|
||||
rdr.bump();
|
||||
ret binop(rdr, token::ASR);
|
||||
} else { ret binop(rdr, token::LSR); }
|
||||
}
|
||||
case (_) { ret token::GT; }
|
||||
}
|
||||
}
|
||||
case ('\'') {
|
||||
rdr.bump();
|
||||
auto c2 = rdr.curr();
|
||||
rdr.bump();
|
||||
if (c2 == '\\') {
|
||||
auto escaped = rdr.curr();
|
||||
rdr.bump();
|
||||
alt (escaped) {
|
||||
case ('n') { c2 = '\n'; }
|
||||
case ('r') { c2 = '\r'; }
|
||||
case ('t') { c2 = '\t'; }
|
||||
case ('\\') { c2 = '\\'; }
|
||||
case ('\'') { c2 = '\''; }
|
||||
case ('x') { c2 = scan_numeric_escape(rdr, 2u); }
|
||||
case ('u') { c2 = scan_numeric_escape(rdr, 4u); }
|
||||
case ('U') { c2 = scan_numeric_escape(rdr, 8u); }
|
||||
case (?c2) {
|
||||
rdr.err(#fmt("unknown character escape: %d",
|
||||
c2 as int));
|
||||
fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rdr.curr() != '\'') {
|
||||
rdr.err("unterminated character constant");
|
||||
fail;
|
||||
}
|
||||
rdr.bump(); // advance curr past token
|
||||
|
||||
ret token::LIT_CHAR(c2);
|
||||
}
|
||||
case ('"') {
|
||||
rdr.bump();
|
||||
while (rdr.curr() != '"') {
|
||||
auto ch = rdr.curr();
|
||||
rdr.bump();
|
||||
alt (ch) {
|
||||
case ('\\') {
|
||||
auto escaped = rdr.curr();
|
||||
rdr.bump();
|
||||
alt (escaped) {
|
||||
case ('n') {
|
||||
str::push_byte(accum_str, '\n' as u8);
|
||||
}
|
||||
case ('r') {
|
||||
str::push_byte(accum_str, '\r' as u8);
|
||||
}
|
||||
case ('t') {
|
||||
str::push_byte(accum_str, '\t' as u8);
|
||||
}
|
||||
case ('\\') {
|
||||
str::push_byte(accum_str, '\\' as u8);
|
||||
}
|
||||
case ('"') {
|
||||
str::push_byte(accum_str, '"' as u8);
|
||||
}
|
||||
case ('\n') { consume_whitespace(rdr); }
|
||||
case ('x') {
|
||||
str::push_char(accum_str,
|
||||
scan_numeric_escape(rdr, 2u));
|
||||
}
|
||||
case ('u') {
|
||||
str::push_char(accum_str,
|
||||
scan_numeric_escape(rdr, 4u));
|
||||
}
|
||||
case ('U') {
|
||||
str::push_char(accum_str,
|
||||
scan_numeric_escape(rdr, 8u));
|
||||
}
|
||||
case (?c2) {
|
||||
rdr.err(#fmt("unknown string escape: %d",
|
||||
c2 as int));
|
||||
fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
case (_) { str::push_char(accum_str, ch); }
|
||||
}
|
||||
}
|
||||
rdr.bump();
|
||||
ret token::LIT_STR(interner::intern[str](*rdr.get_interner(),
|
||||
accum_str));
|
||||
}
|
||||
case ('-') {
|
||||
if (rdr.next() == '>') {
|
||||
rdr.bump();
|
||||
rdr.bump();
|
||||
ret token::RARROW;
|
||||
} else { ret binop(rdr, token::MINUS); }
|
||||
}
|
||||
case ('&') {
|
||||
if (rdr.next() == '&') {
|
||||
rdr.bump();
|
||||
rdr.bump();
|
||||
ret token::ANDAND;
|
||||
} else { ret binop(rdr, token::AND); }
|
||||
}
|
||||
case ('|') {
|
||||
alt (rdr.next()) {
|
||||
case ('|') { rdr.bump(); rdr.bump(); ret token::OROR; }
|
||||
case ('>') { rdr.bump(); rdr.bump(); ret token::RECV; }
|
||||
case (_) { ret binop(rdr, token::OR); }
|
||||
}
|
||||
}
|
||||
case ('+') { ret binop(rdr, token::PLUS); }
|
||||
case ('*') { ret binop(rdr, token::STAR); }
|
||||
case ('/') { ret binop(rdr, token::SLASH); }
|
||||
case ('^') { ret binop(rdr, token::CARET); }
|
||||
case ('%') { ret binop(rdr, token::PERCENT); }
|
||||
case (?c) {
|
||||
rdr.err(#fmt("unkown start of token: %d", c as int));
|
||||
fail;
|
||||
}
|
||||
}
|
||||
fail;
|
||||
}
|
||||
|
||||
tag cmnt_style {
|
||||
isolated; // No code on either side of each line of the comment
|
||||
|
||||
trailing; // Code exists to the left of the comment
|
||||
|
||||
mixed; // Code before /* foo */ and after the comment
|
||||
|
||||
blank_line; // Just a manual blank linke "\n\n", for layout
|
||||
|
||||
}
|
||||
|
||||
type cmnt = rec(cmnt_style style, vec[str] lines, uint pos);
|
||||
|
||||
fn read_to_eol(&reader rdr) -> str {
|
||||
auto val = "";
|
||||
while (rdr.curr() != '\n' && !rdr.is_eof()) {
|
||||
str::push_char(val, rdr.curr());
|
||||
rdr.bump();
|
||||
}
|
||||
ret val;
|
||||
}
|
||||
|
||||
fn read_one_line_comment(&reader rdr) -> str {
|
||||
auto val = read_to_eol(rdr);
|
||||
assert (val.(0) == '/' as u8 && val.(1) == '/' as u8);
|
||||
ret val;
|
||||
}
|
||||
|
||||
fn consume_whitespace(&reader rdr) {
|
||||
while (is_whitespace(rdr.curr()) && !rdr.is_eof()) { rdr.bump(); }
|
||||
}
|
||||
|
||||
fn consume_non_eol_whitespace(&reader rdr) {
|
||||
while (is_whitespace(rdr.curr()) && rdr.curr() != '\n' && !rdr.is_eof()) {
|
||||
rdr.bump();
|
||||
}
|
||||
}
|
||||
|
||||
fn consume_whitespace_counting_blank_lines(&reader rdr,
|
||||
&mutable vec[cmnt] comments) {
|
||||
while (is_whitespace(rdr.curr()) && !rdr.is_eof()) {
|
||||
if (rdr.curr() == '\n' && rdr.next() == '\n') {
|
||||
log ">>> blank-line comment";
|
||||
let vec[str] v = [];
|
||||
comments += [rec(style=blank_line, lines=v,
|
||||
pos=rdr.get_chpos())];
|
||||
}
|
||||
rdr.bump();
|
||||
}
|
||||
}
|
||||
|
||||
fn read_line_comments(&reader rdr, bool code_to_the_left) -> cmnt {
|
||||
log ">>> line comments";
|
||||
auto p = rdr.get_chpos();
|
||||
let vec[str] lines = [];
|
||||
while (rdr.curr() == '/' && rdr.next() == '/') {
|
||||
auto line = read_one_line_comment(rdr);
|
||||
log line;
|
||||
lines += [line];
|
||||
consume_non_eol_whitespace(rdr);
|
||||
}
|
||||
log "<<< line comments";
|
||||
ret rec(style=if (code_to_the_left) { trailing } else { isolated },
|
||||
lines=lines,
|
||||
pos=p);
|
||||
}
|
||||
|
||||
fn all_whitespace(&str s, uint begin, uint end) -> bool {
|
||||
let uint i = begin;
|
||||
while (i != end) {
|
||||
if (!is_whitespace(s.(i) as char)) { ret false; }
|
||||
i += 1u;
|
||||
}
|
||||
ret true;
|
||||
}
|
||||
|
||||
fn trim_whitespace_prefix_and_push_line(&mutable vec[str] lines, &str s,
|
||||
uint col) {
|
||||
auto s1;
|
||||
if (all_whitespace(s, 0u, col)) {
|
||||
if (col < str::byte_len(s)) {
|
||||
s1 = str::slice(s, col, str::byte_len(s));
|
||||
} else { s1 = ""; }
|
||||
} else { s1 = s; }
|
||||
log "pushing line: " + s1;
|
||||
lines += [s1];
|
||||
}
|
||||
|
||||
fn read_block_comment(&reader rdr, bool code_to_the_left) -> cmnt {
|
||||
log ">>> block comment";
|
||||
auto p = rdr.get_chpos();
|
||||
let vec[str] lines = [];
|
||||
let uint col = rdr.get_col();
|
||||
rdr.bump();
|
||||
rdr.bump();
|
||||
auto curr_line = "/*";
|
||||
let int level = 1;
|
||||
while (level > 0) {
|
||||
log #fmt("=== block comment level %d", level);
|
||||
if (rdr.is_eof()) { rdr.err("unterminated block comment"); fail; }
|
||||
if (rdr.curr() == '\n') {
|
||||
trim_whitespace_prefix_and_push_line(lines, curr_line, col);
|
||||
curr_line = "";
|
||||
rdr.bump();
|
||||
} else {
|
||||
str::push_char(curr_line, rdr.curr());
|
||||
if (rdr.curr() == '/' && rdr.next() == '*') {
|
||||
rdr.bump();
|
||||
rdr.bump();
|
||||
curr_line += "*";
|
||||
level += 1;
|
||||
} else {
|
||||
if (rdr.curr() == '*' && rdr.next() == '/') {
|
||||
rdr.bump();
|
||||
rdr.bump();
|
||||
curr_line += "/";
|
||||
level -= 1;
|
||||
} else { rdr.bump(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
if (str::byte_len(curr_line) != 0u) {
|
||||
trim_whitespace_prefix_and_push_line(lines, curr_line, col);
|
||||
}
|
||||
auto style = if (code_to_the_left) { trailing } else { isolated };
|
||||
consume_non_eol_whitespace(rdr);
|
||||
if (!rdr.is_eof() && rdr.curr() != '\n' && vec::len(lines) == 1u) {
|
||||
style = mixed;
|
||||
}
|
||||
log "<<< block comment";
|
||||
ret rec(style=style, lines=lines, pos=p);
|
||||
}
|
||||
|
||||
fn peeking_at_comment(&reader rdr) -> bool {
|
||||
ret rdr.curr() == '/' && rdr.next() == '/' ||
|
||||
rdr.curr() == '/' && rdr.next() == '*';
|
||||
}
|
||||
|
||||
fn consume_comment(&reader rdr, bool code_to_the_left,
|
||||
&mutable vec[cmnt] comments) {
|
||||
log ">>> consume comment";
|
||||
if (rdr.curr() == '/' && rdr.next() == '/') {
|
||||
vec::push[cmnt](comments, read_line_comments(rdr, code_to_the_left));
|
||||
} else if (rdr.curr() == '/' && rdr.next() == '*') {
|
||||
vec::push[cmnt](comments, read_block_comment(rdr, code_to_the_left));
|
||||
} else { fail; }
|
||||
log "<<< consume comment";
|
||||
}
|
||||
|
||||
fn is_lit(&token::token t) -> bool {
|
||||
ret alt (t) {
|
||||
case (token::LIT_INT(_)) { true }
|
||||
case (token::LIT_UINT(_)) { true }
|
||||
case (token::LIT_MACH_INT(_, _)) { true }
|
||||
case (token::LIT_FLOAT(_)) { true }
|
||||
case (token::LIT_MACH_FLOAT(_, _)) { true }
|
||||
case (token::LIT_STR(_)) { true }
|
||||
case (token::LIT_CHAR(_)) { true }
|
||||
case (token::LIT_BOOL(_)) { true }
|
||||
case (_) { false }
|
||||
}
|
||||
}
|
||||
|
||||
type lit = rec(str lit, uint pos);
|
||||
|
||||
fn gather_comments_and_literals(&codemap::codemap cm, str path) ->
|
||||
rec(vec[cmnt] cmnts, vec[lit] lits) {
|
||||
auto srdr = io::file_reader(path);
|
||||
auto itr = @interner::mk[str](str::hash, str::eq);
|
||||
auto rdr = new_reader(cm, srdr, codemap::new_filemap(path, 0u), itr);
|
||||
let vec[cmnt] comments = [];
|
||||
let vec[lit] literals = [];
|
||||
let bool first_read = true;
|
||||
while (!rdr.is_eof()) {
|
||||
while (true) {
|
||||
auto code_to_the_left = !first_read;
|
||||
consume_non_eol_whitespace(rdr);
|
||||
if (rdr.curr() == '\n') {
|
||||
code_to_the_left = false;
|
||||
consume_whitespace_counting_blank_lines(rdr, comments);
|
||||
}
|
||||
while (peeking_at_comment(rdr)) {
|
||||
consume_comment(rdr, code_to_the_left, comments);
|
||||
consume_whitespace_counting_blank_lines(rdr, comments);
|
||||
}
|
||||
break;
|
||||
}
|
||||
auto tok = next_token(rdr);
|
||||
if (is_lit(tok)) {
|
||||
vec::push[lit](literals,
|
||||
rec(lit=rdr.get_mark_str(),
|
||||
pos=rdr.get_mark_chpos()));
|
||||
}
|
||||
log "tok: " + token::to_str(rdr, tok);
|
||||
first_read = false;
|
||||
}
|
||||
ret rec(cmnts=comments, lits=literals);
|
||||
}
|
||||
//
|
||||
// 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:
|
||||
//
|
||||
2468
src/comp/syntax/parse/parser.rs
Normal file
2468
src/comp/syntax/parse/parser.rs
Normal file
File diff suppressed because it is too large
Load diff
202
src/comp/syntax/parse/token.rs
Normal file
202
src/comp/syntax/parse/token.rs
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
|
||||
import ast::ty_mach;
|
||||
import ast::ty_mach_to_str;
|
||||
import _std::new_str_hash;
|
||||
import util::interner;
|
||||
import std::int;
|
||||
import std::uint;
|
||||
import std::str;
|
||||
|
||||
type str_num = uint;
|
||||
|
||||
tag binop {
|
||||
PLUS;
|
||||
MINUS;
|
||||
STAR;
|
||||
SLASH;
|
||||
PERCENT;
|
||||
CARET;
|
||||
AND;
|
||||
OR;
|
||||
LSL;
|
||||
LSR;
|
||||
ASR;
|
||||
}
|
||||
|
||||
tag token {
|
||||
|
||||
/* Expression-operator symbols. */
|
||||
EQ;
|
||||
LT;
|
||||
LE;
|
||||
EQEQ;
|
||||
NE;
|
||||
GE;
|
||||
GT;
|
||||
ANDAND;
|
||||
OROR;
|
||||
NOT;
|
||||
TILDE;
|
||||
BINOP(binop);
|
||||
BINOPEQ(binop);
|
||||
|
||||
/* Structural symbols */
|
||||
AT;
|
||||
DOT;
|
||||
COMMA;
|
||||
SEMI;
|
||||
COLON;
|
||||
MOD_SEP;
|
||||
QUES;
|
||||
RARROW;
|
||||
SEND;
|
||||
RECV;
|
||||
LARROW;
|
||||
DARROW;
|
||||
LPAREN;
|
||||
RPAREN;
|
||||
LBRACKET;
|
||||
RBRACKET;
|
||||
LBRACE;
|
||||
RBRACE;
|
||||
POUND;
|
||||
|
||||
/* Literals */
|
||||
LIT_INT(int);
|
||||
LIT_UINT(uint);
|
||||
LIT_MACH_INT(ty_mach, int);
|
||||
LIT_FLOAT(str_num);
|
||||
LIT_MACH_FLOAT(ty_mach, str_num);
|
||||
LIT_STR(str_num);
|
||||
LIT_CHAR(char);
|
||||
LIT_BOOL(bool);
|
||||
|
||||
/* Name components */
|
||||
IDENT(str_num, bool);
|
||||
IDX(int);
|
||||
UNDERSCORE;
|
||||
BRACEQUOTE(str_num);
|
||||
EOF;
|
||||
}
|
||||
|
||||
fn binop_to_str(binop o) -> str {
|
||||
alt (o) {
|
||||
case (PLUS) { ret "+"; }
|
||||
case (MINUS) { ret "-"; }
|
||||
case (STAR) { ret "*"; }
|
||||
case (SLASH) { ret "/"; }
|
||||
case (PERCENT) { ret "%"; }
|
||||
case (CARET) { ret "^"; }
|
||||
case (AND) { ret "&"; }
|
||||
case (OR) { ret "|"; }
|
||||
case (LSL) { ret "<<"; }
|
||||
case (LSR) { ret ">>"; }
|
||||
case (ASR) { ret ">>>"; }
|
||||
}
|
||||
}
|
||||
|
||||
fn to_str(lexer::reader r, token t) -> str {
|
||||
alt (t) {
|
||||
case (EQ) { ret "="; }
|
||||
case (LT) { ret "<"; }
|
||||
case (LE) { ret "<="; }
|
||||
case (EQEQ) { ret "=="; }
|
||||
case (NE) { ret "!="; }
|
||||
case (GE) { ret ">="; }
|
||||
case (GT) { ret ">"; }
|
||||
case (NOT) { ret "!"; }
|
||||
case (TILDE) { ret "~"; }
|
||||
case (OROR) { ret "||"; }
|
||||
case (ANDAND) { ret "&&"; }
|
||||
case (BINOP(?op)) { ret binop_to_str(op); }
|
||||
case (BINOPEQ(?op)) { ret binop_to_str(op) + "="; }
|
||||
case (
|
||||
/* Structural symbols */
|
||||
AT) {
|
||||
ret "@";
|
||||
}
|
||||
case (DOT) { ret "."; }
|
||||
case (COMMA) { ret ","; }
|
||||
case (SEMI) { ret ";"; }
|
||||
case (COLON) { ret ":"; }
|
||||
case (MOD_SEP) { ret "::"; }
|
||||
case (QUES) { ret "?"; }
|
||||
case (RARROW) { ret "->"; }
|
||||
case (SEND) { ret "<|"; }
|
||||
case (RECV) { ret "|>"; }
|
||||
case (LARROW) { ret "<-"; }
|
||||
case (DARROW) { ret "<->"; }
|
||||
case (LPAREN) { ret "("; }
|
||||
case (RPAREN) { ret ")"; }
|
||||
case (LBRACKET) { ret "["; }
|
||||
case (RBRACKET) { ret "]"; }
|
||||
case (LBRACE) { ret "{"; }
|
||||
case (RBRACE) { ret "}"; }
|
||||
case (POUND) { ret "#"; }
|
||||
case (
|
||||
/* Literals */
|
||||
LIT_INT(?i)) {
|
||||
ret int::to_str(i, 10u);
|
||||
}
|
||||
case (LIT_UINT(?u)) { ret uint::to_str(u, 10u); }
|
||||
case (LIT_MACH_INT(?tm, ?i)) {
|
||||
ret int::to_str(i, 10u) + "_" + ty_mach_to_str(tm);
|
||||
}
|
||||
case (LIT_MACH_FLOAT(?tm, ?s)) {
|
||||
ret interner::get[str](*r.get_interner(), s) + "_" +
|
||||
ty_mach_to_str(tm);
|
||||
}
|
||||
case (LIT_FLOAT(?s)) { ret interner::get[str](*r.get_interner(), s); }
|
||||
case (LIT_STR(?s)) {
|
||||
// FIXME: escape.
|
||||
|
||||
ret "\"" + interner::get[str](*r.get_interner(), s) + "\"";
|
||||
}
|
||||
case (LIT_CHAR(?c)) {
|
||||
// FIXME: escape.
|
||||
|
||||
auto tmp = "'";
|
||||
str::push_char(tmp, c);
|
||||
str::push_byte(tmp, '\'' as u8);
|
||||
ret tmp;
|
||||
}
|
||||
case (LIT_BOOL(?b)) { if (b) { ret "true"; } else { ret "false"; } }
|
||||
case (
|
||||
/* Name components */
|
||||
IDENT(?s, _)) {
|
||||
ret interner::get[str](*r.get_interner(), s);
|
||||
}
|
||||
case (IDX(?i)) { ret "_" + int::to_str(i, 10u); }
|
||||
case (UNDERSCORE) { ret "_"; }
|
||||
case (BRACEQUOTE(_)) { ret "<bracequote>"; }
|
||||
case (EOF) { ret "<eof>"; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pred can_begin_expr(token t) -> bool {
|
||||
alt (t) {
|
||||
case (LPAREN) { true }
|
||||
case (LBRACE) { true }
|
||||
case (IDENT(_,_)) { true }
|
||||
case (UNDERSCORE) { true }
|
||||
case (TILDE) { true }
|
||||
case (LIT_INT(_)) { true }
|
||||
case (LIT_UINT(_)) { true }
|
||||
case (LIT_MACH_INT(_,_)) { true }
|
||||
case (LIT_FLOAT(_)) { true }
|
||||
case (LIT_MACH_FLOAT(_,_)) { true }
|
||||
case (LIT_STR(_)) { true }
|
||||
case (LIT_CHAR(_)) { true }
|
||||
case (POUND) { true }
|
||||
case (AT) { true }
|
||||
case (_) { false }
|
||||
}
|
||||
}
|
||||
// Local Variables:
|
||||
// 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:
|
||||
532
src/comp/syntax/print/pp.rs
Normal file
532
src/comp/syntax/print/pp.rs
Normal file
|
|
@ -0,0 +1,532 @@
|
|||
|
||||
import std::io;
|
||||
import std::vec;
|
||||
import std::str;
|
||||
|
||||
|
||||
/*
|
||||
* This pretty-printer is a direct reimplementation of Philip Karlton's
|
||||
* Mesa pretty-printer, as described in appendix A of
|
||||
*
|
||||
* STAN-CS-79-770: "Pretty Printing", by Derek C. Oppen.
|
||||
* Stanford Department of Computer Science, 1979.
|
||||
*
|
||||
* The algorithm's aim is to break a stream into as few lines as possible
|
||||
* while respecting the indentation-consistency requirements of the enclosing
|
||||
* block, and avoiding breaking at silly places on block boundaries, for
|
||||
* example, between "x" and ")" in "x)".
|
||||
*
|
||||
* I am implementing this algorithm because it comes with 20 pages of
|
||||
* documentation explaining its theory, and because it addresses the set of
|
||||
* concerns I've seen other pretty-printers fall down on. Weirdly. Even though
|
||||
* it's 32 years old and not written in Haskell. What can I say?
|
||||
*
|
||||
* Despite some redundancies and quirks in the way it's implemented in that
|
||||
* paper, I've opted to keep the implementation here as similar as I can,
|
||||
* changing only what was blatantly wrong, a typo, or sufficiently
|
||||
* non-idiomatic rust that it really stuck out.
|
||||
*
|
||||
* In particular you'll see a certain amount of churn related to INTEGER vs.
|
||||
* CARDINAL in the Mesa implementation. Mesa apparently interconverts the two
|
||||
* somewhat readily? In any case, I've used uint for indices-in-buffers and
|
||||
* ints for character-sizes-and-indentation-offsets. This respects the need
|
||||
* for ints to "go negative" while carrying a pending-calculation balance, and
|
||||
* helps differentiate all the numbers flying around internally (slightly).
|
||||
*
|
||||
* I also inverted the indentation arithmetic used in the print stack, since
|
||||
* the Mesa implementation (somewhat randomly) stores the offset on the print
|
||||
* stack in terms of margin-col rather than col itself. I store col.
|
||||
*
|
||||
* I also implemented a small change in the STRING token, in that I store an
|
||||
* explicit length for the string. For most tokens this is just the length of
|
||||
* the accompanying string. But it's necessary to permit it to differ, for
|
||||
* encoding things that are supposed to "go on their own line" -- certain
|
||||
* classes of comment and blank-line -- where relying on adjacent
|
||||
* hardbreak-like BREAK tokens with long blankness indication doesn't actually
|
||||
* work. To see why, consider when there is a "thing that should be on its own
|
||||
* line" between two long blocks, say functions. If you put a hardbreak after
|
||||
* each function (or before each) and the breaking algorithm decides to break
|
||||
* there anyways (because the functions themselves are long) you wind up with
|
||||
* extra blank lines. If you don't put hardbreaks you can wind up with the
|
||||
* "thing which should be on its own line" not getting its own line in the
|
||||
* rare case of "really small functions" or such. This re-occurs with comments
|
||||
* and explicit blank lines. So in those cases we use a string with a payload
|
||||
* we want isolated to a line and an explicit length that's huge, surrounded
|
||||
* by two zero-length breaks. The algorithm will try its best to fit it on a
|
||||
* line (which it can't) and so naturally place the content on its own line to
|
||||
* avoid combining it with other lines and making matters even worse.
|
||||
*/
|
||||
tag breaks { consistent; inconsistent; }
|
||||
|
||||
type break_t = rec(int offset, int blank_space);
|
||||
|
||||
type begin_t = rec(int offset, breaks breaks);
|
||||
|
||||
tag token { STRING(str, int); BREAK(break_t); BEGIN(begin_t); END; EOF; }
|
||||
|
||||
fn tok_str(token t) -> str {
|
||||
alt (t) {
|
||||
case (STRING(?s, ?len)) { ret #fmt("STR(%s,%d)", s, len); }
|
||||
case (BREAK(_)) { ret "BREAK"; }
|
||||
case (BEGIN(_)) { ret "BEGIN"; }
|
||||
case (END) { ret "END"; }
|
||||
case (EOF) { ret "EOF"; }
|
||||
}
|
||||
}
|
||||
|
||||
fn buf_str(vec[mutable token] toks, vec[mutable int] szs, uint left,
|
||||
uint right, uint lim) -> str {
|
||||
auto n = vec::len(toks);
|
||||
assert (n == vec::len(szs));
|
||||
auto i = left;
|
||||
auto L = lim;
|
||||
auto s = "[";
|
||||
while (i != right && L != 0u) {
|
||||
L -= 1u;
|
||||
if (i != left) { s += ", "; }
|
||||
s += #fmt("%d=%s", szs.(i), tok_str(toks.(i)));
|
||||
i += 1u;
|
||||
i %= n;
|
||||
}
|
||||
s += "]";
|
||||
ret s;
|
||||
}
|
||||
|
||||
tag print_stack_break { fits; broken(breaks); }
|
||||
|
||||
type print_stack_elt = rec(int offset, print_stack_break pbreak);
|
||||
|
||||
const int size_infinity = 0xffff;
|
||||
|
||||
fn mk_printer(io::writer out, uint linewidth) -> printer {
|
||||
// Yes 3, it makes the ring buffers big enough to never
|
||||
// fall behind.
|
||||
|
||||
let uint n = 3u * linewidth;
|
||||
log #fmt("mk_printer %u", linewidth);
|
||||
let vec[mutable token] token = vec::init_elt_mut(EOF, n);
|
||||
let vec[mutable int] size = vec::init_elt_mut(0, n);
|
||||
let vec[mutable uint] scan_stack = vec::init_elt_mut(0u, n);
|
||||
let vec[print_stack_elt] print_stack = [];
|
||||
ret printer(out, n, linewidth as int, // margin
|
||||
linewidth as int, // space
|
||||
0u, // left
|
||||
0u, // right
|
||||
token, size, 0, // left_total
|
||||
0, // right_total
|
||||
scan_stack, true, // scan_stack_empty
|
||||
0u, // top
|
||||
0u, // bottom
|
||||
print_stack, 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* In case you do not have the paper, here is an explanation of what's going
|
||||
* on.
|
||||
*
|
||||
* There is a stream of input tokens flowing through this printer.
|
||||
*
|
||||
* The printer buffers up to 3N tokens inside itself, where N is linewidth.
|
||||
* Yes, linewidth is chars and tokens are multi-char, but in the worst
|
||||
* case every token worth buffering is 1 char long, so it's ok.
|
||||
*
|
||||
* Tokens are STRING, BREAK, and BEGIN/END to delimit blocks.
|
||||
*
|
||||
* BEGIN tokens can carry an offset, saying "how far to indent when you break
|
||||
* inside here", as well as a flag indicating "consistent" or "inconsistent"
|
||||
* breaking. Consistent breaking means that after the first break, no attempt
|
||||
* will be made to flow subsequent breaks together onto lines. Inconsistent
|
||||
* is the opposite. Inconsistent breaking example would be, say:
|
||||
*
|
||||
* foo(hello, there, good, friends)
|
||||
*
|
||||
* breaking inconsistently to become
|
||||
*
|
||||
* foo(hello, there
|
||||
* good, friends);
|
||||
*
|
||||
* whereas a consistent breaking would yield:
|
||||
*
|
||||
* foo(hello,
|
||||
* there
|
||||
* good,
|
||||
* friends);
|
||||
*
|
||||
* That is, in the consistent-break blocks we value vertical alignment
|
||||
* more than the ability to cram stuff onto a line. But in all cases if it
|
||||
* can make a block a one-liner, it'll do so.
|
||||
*
|
||||
* Carrying on with high-level logic:
|
||||
*
|
||||
* The buffered tokens go through a ring-buffer, 'tokens'. The 'left' and
|
||||
* 'right' indices denote the active portion of the ring buffer as well as
|
||||
* describing hypothetical points-in-the-infinite-stream at most 3N tokens
|
||||
* apart (i.e. "not wrapped to ring-buffer boundaries"). The paper will switch
|
||||
* between using 'left' and 'right' terms to denote the wrapepd-to-ring-buffer
|
||||
* and point-in-infinite-stream senses freely.
|
||||
*
|
||||
* There is a parallel ring buffer, 'size', that holds the calculated size of
|
||||
* each token. Why calculated? Because for BEGIN/END pairs, the "size"
|
||||
* includes everything betwen the pair. That is, the "size" of BEGIN is
|
||||
* actually the sum of the sizes of everything between BEGIN and the paired
|
||||
* END that follows. Since that is arbitrarily far in the future, 'size' is
|
||||
* being rewritten regularly while the printer runs; in fact most of the
|
||||
* machinery is here to work out 'size' entries on the fly (and give up when
|
||||
* they're so obviously over-long that "infinity" is a good enough
|
||||
* approximation for purposes of line breaking).
|
||||
*
|
||||
* The "input side" of the printer is managed as an abstract process called
|
||||
* SCAN, which uses 'scan_stack', 'scan_stack_empty', 'top' and 'bottom', to
|
||||
* manage calculating 'size'. SCAN is, in other words, the process of
|
||||
* calculating 'size' entries.
|
||||
*
|
||||
* The "output side" of the printer is managed by an abstract process called
|
||||
* PRINT, which uses 'print_stack', 'margin' and 'space' to figure out what to
|
||||
* do with each token/size pair it consumes as it goes. It's trying to consume
|
||||
* the entire buffered window, but can't output anything until the size is >=
|
||||
* 0 (sizes are set to negative while they're pending calculation).
|
||||
*
|
||||
* So SCAN takeks input and buffers tokens and pending calculations, while
|
||||
* PRINT gobbles up completed calculations and tokens from the buffer. The
|
||||
* theory is that the two can never get more than 3N tokens apart, because
|
||||
* once there's "obviously" too much data to fit on a line, in a size
|
||||
* calculation, SCAN will write "infinity" to the size and let PRINT consume
|
||||
* it.
|
||||
*
|
||||
* In this implementation (following the paper, again) the SCAN process is
|
||||
* the method called 'pretty_print', and the 'PRINT' process is the method
|
||||
* called 'print'.
|
||||
*/
|
||||
obj printer(io::writer out,
|
||||
uint buf_len,
|
||||
mutable int margin, // width of lines we're constrained to
|
||||
|
||||
mutable int space, // number of spaces left on line
|
||||
|
||||
mutable uint left, // index of left side of input stream
|
||||
|
||||
mutable uint right, // index of right side of input stream
|
||||
|
||||
mutable vec[mutable token] token,
|
||||
// ring-buffr stream goes through
|
||||
mutable vec[mutable int] size, // ring-buffer of calculated sizes
|
||||
|
||||
mutable int left_total, // running size of stream "...left"
|
||||
|
||||
mutable int right_total, // running size of stream "...right"
|
||||
|
||||
// pseudo-stack, really a ring too. Holds the
|
||||
// primary-ring-buffers index of the BEGIN that started the
|
||||
// current block, possibly with the most recent BREAK after that
|
||||
// BEGIN (if there is any) on top of it. Stuff is flushed off the
|
||||
// bottom as it becomes irrelevant due to the primary ring-buffer
|
||||
// advancing.
|
||||
mutable vec[mutable uint] scan_stack,
|
||||
mutable bool scan_stack_empty, // top==bottom disambiguator
|
||||
|
||||
mutable uint top, // index of top of scan_stack
|
||||
|
||||
mutable uint bottom, // index of bottom of scan_stack
|
||||
|
||||
// stack of blocks-in-progress being flushed by print
|
||||
mutable vec[print_stack_elt] print_stack,
|
||||
|
||||
// buffered indentation to avoid writing trailing whitespace
|
||||
mutable int pending_indentation) {
|
||||
|
||||
fn last_token() -> token {
|
||||
ret token.(right);
|
||||
}
|
||||
|
||||
fn pretty_print(token t) {
|
||||
log #fmt("pp [%u,%u]", left, right);
|
||||
alt (t) {
|
||||
case (EOF) {
|
||||
if (!scan_stack_empty) {
|
||||
self.check_stack(0);
|
||||
self.advance_left(token.(left), size.(left));
|
||||
}
|
||||
self.indent(0);
|
||||
}
|
||||
case (BEGIN(?b)) {
|
||||
if (scan_stack_empty) {
|
||||
left_total = 1;
|
||||
right_total = 1;
|
||||
left = 0u;
|
||||
right = 0u;
|
||||
} else { self.advance_right(); }
|
||||
log #fmt("pp BEGIN/buffer [%u,%u]", left, right);
|
||||
token.(right) = t;
|
||||
size.(right) = -right_total;
|
||||
self.scan_push(right);
|
||||
}
|
||||
case (END) {
|
||||
if (scan_stack_empty) {
|
||||
log #fmt("pp END/print [%u,%u]", left, right);
|
||||
self.print(t, 0);
|
||||
} else {
|
||||
log #fmt("pp END/buffer [%u,%u]", left, right);
|
||||
self.advance_right();
|
||||
token.(right) = t;
|
||||
size.(right) = -1;
|
||||
self.scan_push(right);
|
||||
}
|
||||
}
|
||||
case (BREAK(?b)) {
|
||||
if (scan_stack_empty) {
|
||||
left_total = 1;
|
||||
right_total = 1;
|
||||
left = 0u;
|
||||
right = 0u;
|
||||
} else { self.advance_right(); }
|
||||
log #fmt("pp BREAK/buffer [%u,%u]", left, right);
|
||||
self.check_stack(0);
|
||||
self.scan_push(right);
|
||||
token.(right) = t;
|
||||
size.(right) = -right_total;
|
||||
right_total += b.blank_space;
|
||||
}
|
||||
case (STRING(?s, ?len)) {
|
||||
if (scan_stack_empty) {
|
||||
log #fmt("pp STRING/print [%u,%u]", left, right);
|
||||
self.print(t, len);
|
||||
} else {
|
||||
log #fmt("pp STRING/buffer [%u,%u]", left, right);
|
||||
self.advance_right();
|
||||
token.(right) = t;
|
||||
size.(right) = len;
|
||||
right_total += len;
|
||||
self.check_stream();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fn check_stream() {
|
||||
log #fmt("check_stream [%u, %u] with left_total=%d, right_total=%d",
|
||||
left, right, left_total, right_total);
|
||||
if (right_total - left_total > space) {
|
||||
log #fmt("scan window is %d, longer than space on line (%d)",
|
||||
right_total - left_total, space);
|
||||
if (!scan_stack_empty) {
|
||||
if (left == scan_stack.(bottom)) {
|
||||
log #fmt("setting %u to infinity and popping", left);
|
||||
size.(self.scan_pop_bottom()) = size_infinity;
|
||||
}
|
||||
}
|
||||
self.advance_left(token.(left), size.(left));
|
||||
if (left != right) { self.check_stream(); }
|
||||
}
|
||||
}
|
||||
fn scan_push(uint x) {
|
||||
log #fmt("scan_push %u", x);
|
||||
if (scan_stack_empty) {
|
||||
scan_stack_empty = false;
|
||||
} else { top += 1u; top %= buf_len; assert (top != bottom); }
|
||||
scan_stack.(top) = x;
|
||||
}
|
||||
fn scan_pop() -> uint {
|
||||
assert (!scan_stack_empty);
|
||||
auto x = scan_stack.(top);
|
||||
if (top == bottom) {
|
||||
scan_stack_empty = true;
|
||||
} else { top += buf_len - 1u; top %= buf_len; }
|
||||
ret x;
|
||||
}
|
||||
fn scan_top() -> uint {
|
||||
assert (!scan_stack_empty);
|
||||
ret scan_stack.(top);
|
||||
}
|
||||
fn scan_pop_bottom() -> uint {
|
||||
assert (!scan_stack_empty);
|
||||
auto x = scan_stack.(bottom);
|
||||
if (top == bottom) {
|
||||
scan_stack_empty = true;
|
||||
} else { bottom += 1u; bottom %= buf_len; }
|
||||
ret x;
|
||||
}
|
||||
fn advance_right() {
|
||||
right += 1u;
|
||||
right %= buf_len;
|
||||
assert (right != left);
|
||||
}
|
||||
fn advance_left(token x, int L) {
|
||||
log #fmt("advnce_left [%u,%u], sizeof(%u)=%d", left, right, left, L);
|
||||
if (L >= 0) {
|
||||
self.print(x, L);
|
||||
alt (x) {
|
||||
case (BREAK(?b)) { left_total += b.blank_space; }
|
||||
case (STRING(_, ?len)) {
|
||||
assert (len == L);
|
||||
left_total += len;
|
||||
}
|
||||
case (_) { }
|
||||
}
|
||||
if (left != right) {
|
||||
left += 1u;
|
||||
left %= buf_len;
|
||||
self.advance_left(token.(left), size.(left));
|
||||
}
|
||||
}
|
||||
}
|
||||
fn check_stack(int k) {
|
||||
if (!scan_stack_empty) {
|
||||
auto x = self.scan_top();
|
||||
alt (token.(x)) {
|
||||
case (BEGIN(?b)) {
|
||||
if (k > 0) {
|
||||
size.(self.scan_pop()) = size.(x) + right_total;
|
||||
self.check_stack(k - 1);
|
||||
}
|
||||
}
|
||||
case (END) {
|
||||
// paper says + not =, but that makes no sense.
|
||||
|
||||
size.(self.scan_pop()) = 1;
|
||||
self.check_stack(k + 1);
|
||||
}
|
||||
case (_) {
|
||||
size.(self.scan_pop()) = size.(x) + right_total;
|
||||
if (k > 0) { self.check_stack(k); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fn print_newline(int amount) {
|
||||
log #fmt("NEWLINE %d", amount);
|
||||
out.write_str("\n");
|
||||
pending_indentation = 0;
|
||||
self.indent(amount);
|
||||
}
|
||||
fn indent(int amount) {
|
||||
log #fmt("INDENT %d", amount);
|
||||
pending_indentation += amount;
|
||||
}
|
||||
fn top() -> print_stack_elt {
|
||||
auto n = vec::len(print_stack);
|
||||
let print_stack_elt top = rec(offset=0, pbreak=broken(inconsistent));
|
||||
if (n != 0u) { top = print_stack.(n - 1u); }
|
||||
ret top;
|
||||
}
|
||||
fn write_str(str s) {
|
||||
while (pending_indentation > 0) {
|
||||
out.write_str(" ");
|
||||
pending_indentation -= 1;
|
||||
}
|
||||
out.write_str(s);
|
||||
}
|
||||
fn print(token x, int L) {
|
||||
log #fmt("print %s %d (remaining line space=%d)", tok_str(x), L,
|
||||
space);
|
||||
log buf_str(token, size, left, right, 6u);
|
||||
alt (x) {
|
||||
case (BEGIN(?b)) {
|
||||
if (L > space) {
|
||||
auto col = margin - space + b.offset;
|
||||
log #fmt("print BEGIN -> push broken block at col %d",
|
||||
col);
|
||||
vec::push(print_stack,
|
||||
rec(offset=col, pbreak=broken(b.breaks)));
|
||||
} else {
|
||||
log "print BEGIN -> push fitting block";
|
||||
vec::push(print_stack, rec(offset=0, pbreak=fits));
|
||||
}
|
||||
}
|
||||
case (END) {
|
||||
log "print END -> pop END";
|
||||
assert (vec::len(print_stack) != 0u);
|
||||
vec::pop(print_stack);
|
||||
}
|
||||
case (BREAK(?b)) {
|
||||
auto top = self.top();
|
||||
alt (top.pbreak) {
|
||||
case (fits) {
|
||||
log "print BREAK in fitting block";
|
||||
space -= b.blank_space;
|
||||
self.indent(b.blank_space);
|
||||
}
|
||||
case (broken(consistent)) {
|
||||
log "print BREAK in consistent block";
|
||||
self.print_newline(top.offset + b.offset);
|
||||
space = margin - (top.offset + b.offset);
|
||||
}
|
||||
case (broken(inconsistent)) {
|
||||
if (L > space) {
|
||||
log "print BREAK w/ newline in inconsistent";
|
||||
self.print_newline(top.offset + b.offset);
|
||||
space = margin - (top.offset + b.offset);
|
||||
} else {
|
||||
log "print BREAK w/o newline in inconsistent";
|
||||
self.indent(b.blank_space);
|
||||
space -= b.blank_space;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case (STRING(?s, ?len)) {
|
||||
log "print STRING";
|
||||
assert (L == len);
|
||||
// assert L <= space;
|
||||
|
||||
space -= len;
|
||||
self.write_str(s);
|
||||
}
|
||||
case (EOF) {
|
||||
// EOF should never get here.
|
||||
|
||||
fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Convenience functions to talk to the printer.
|
||||
fn box(printer p, uint indent, breaks b) {
|
||||
p.pretty_print(BEGIN(rec(offset=indent as int, breaks=b)));
|
||||
}
|
||||
|
||||
fn ibox(printer p, uint indent) { box(p, indent, inconsistent); }
|
||||
|
||||
fn cbox(printer p, uint indent) { box(p, indent, consistent); }
|
||||
|
||||
fn break_offset(printer p, uint n, int off) {
|
||||
p.pretty_print(BREAK(rec(offset=off, blank_space=n as int)));
|
||||
}
|
||||
|
||||
fn end(printer p) { p.pretty_print(END); }
|
||||
|
||||
fn eof(printer p) { p.pretty_print(EOF); }
|
||||
|
||||
fn word(printer p, str wrd) {
|
||||
p.pretty_print(STRING(wrd, str::char_len(wrd) as int));
|
||||
}
|
||||
|
||||
fn huge_word(printer p, str wrd) {
|
||||
p.pretty_print(STRING(wrd, size_infinity));
|
||||
}
|
||||
|
||||
fn zero_word(printer p, str wrd) { p.pretty_print(STRING(wrd, 0)); }
|
||||
|
||||
fn spaces(printer p, uint n) { break_offset(p, n, 0); }
|
||||
|
||||
fn zerobreak(printer p) { spaces(p, 0u); }
|
||||
|
||||
fn space(printer p) { spaces(p, 1u); }
|
||||
|
||||
fn hardbreak(printer p) { spaces(p, size_infinity as uint); }
|
||||
|
||||
fn hardbreak_tok() -> token {
|
||||
ret BREAK(rec(offset=0, blank_space=size_infinity));
|
||||
}
|
||||
|
||||
//
|
||||
// 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:
|
||||
//
|
||||
1473
src/comp/syntax/print/pprust.rs
Normal file
1473
src/comp/syntax/print/pprust.rs
Normal file
File diff suppressed because it is too large
Load diff
35
src/comp/syntax/util/interner.rs
Normal file
35
src/comp/syntax/util/interner.rs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
// An "interner" is a data structure that associates values with uint tags and
|
||||
// allows bidirectional lookup; i.e. given a value, one can easily find the
|
||||
// type, and vice versa.
|
||||
import std::vec;
|
||||
import std::map;
|
||||
import std::map::hashmap;
|
||||
import std::map::hashfn;
|
||||
import std::map::eqfn;
|
||||
import std::option;
|
||||
import std::option::none;
|
||||
import std::option::some;
|
||||
|
||||
type interner[T] =
|
||||
rec(hashmap[T, uint] map,
|
||||
mutable vec[T] vect,
|
||||
hashfn[T] hasher,
|
||||
eqfn[T] eqer);
|
||||
|
||||
fn mk[T](hashfn[T] hasher, eqfn[T] eqer) -> interner[T] {
|
||||
auto m = map::mk_hashmap[T, uint](hasher, eqer);
|
||||
let vec[T] vect = [];
|
||||
ret rec(map=m, mutable vect=vect, hasher=hasher, eqer=eqer);
|
||||
}
|
||||
fn intern[T](&interner[T] itr, &T val) -> uint {
|
||||
alt (itr.map.find(val)) {
|
||||
case (some(?idx)) { ret idx; }
|
||||
case (none) {
|
||||
auto new_idx = vec::len[T](itr.vect);
|
||||
itr.map.insert(val, new_idx);
|
||||
itr.vect += [val];
|
||||
ret new_idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
fn get[T](&interner[T] itr, uint idx) -> T { ret itr.vect.(idx); }
|
||||
407
src/comp/syntax/visit.rs
Normal file
407
src/comp/syntax/visit.rs
Normal file
|
|
@ -0,0 +1,407 @@
|
|||
|
||||
import ast::*;
|
||||
import std::option;
|
||||
import std::option::some;
|
||||
import std::option::none;
|
||||
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.
|
||||
|
||||
// Lots of redundant indirection and refcounting. 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] { vtor(visitor[E]); }
|
||||
|
||||
fn vt[E](&vt[E] x) -> visitor[E] { alt (x) { case (vtor(?v)) { ret v; } } }
|
||||
|
||||
type visitor[E] =
|
||||
@rec(fn(&_mod, &span, &E, &vt[E]) visit_mod,
|
||||
fn(&@view_item, &E, &vt[E]) visit_view_item,
|
||||
fn(&@native_item, &E, &vt[E]) visit_native_item,
|
||||
fn(&@item, &E, &vt[E]) visit_item,
|
||||
fn(&@local, &E, &vt[E]) visit_local,
|
||||
fn(&block, &E, &vt[E]) visit_block,
|
||||
fn(&@stmt, &E, &vt[E]) visit_stmt,
|
||||
fn(&arm, &E, &vt[E]) visit_arm,
|
||||
fn(&@pat, &E, &vt[E]) visit_pat,
|
||||
fn(&@decl, &E, &vt[E]) visit_decl,
|
||||
fn(&@expr, &E, &vt[E]) visit_expr,
|
||||
fn(&@ty, &E, &vt[E]) visit_ty,
|
||||
fn(&@constr, &E, &vt[E]) visit_constr,
|
||||
fn(&_fn, &vec[ty_param], &span, &fn_ident, node_id, &E, &vt[E])
|
||||
visit_fn);
|
||||
|
||||
fn default_visitor[E]() -> visitor[E] {
|
||||
ret @rec(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](&crate c, &E e, &vt[E] v) {
|
||||
vt(v).visit_mod(c.node.module, c.span, e, v);
|
||||
}
|
||||
|
||||
fn visit_crate_directive[E](&@crate_directive cd, &E e, &vt[E] v) {
|
||||
alt (cd.node) {
|
||||
case (cdir_src_mod(_, _, _)) { }
|
||||
case (cdir_dir_mod(_, _, ?cdirs, _)) {
|
||||
for (@crate_directive cdir in cdirs) {
|
||||
visit_crate_directive(cdir, e, v);
|
||||
}
|
||||
}
|
||||
case (cdir_view_item(?vi)) { vt(v).visit_view_item(vi, e, v); }
|
||||
case (cdir_syntax(_)) { }
|
||||
case (cdir_auth(_, _)) { }
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mod[E](&_mod m, &span sp, &E e, &vt[E] v) {
|
||||
for (@view_item vi in m.view_items) { vt(v).visit_view_item(vi, e, v); }
|
||||
for (@item i in m.items) { vt(v).visit_item(i, e, v); }
|
||||
}
|
||||
|
||||
fn visit_view_item[E](&@view_item vi, &E e, &vt[E] v) { }
|
||||
|
||||
fn visit_local[E](&@local loc, &E e, &vt[E] v) {
|
||||
alt (loc.node.ty) {
|
||||
case (none) { }
|
||||
case (some(?t)) { vt(v).visit_ty(t, e, v); }
|
||||
}
|
||||
alt (loc.node.init) {
|
||||
case (none) { }
|
||||
case (some(?i)) { vt(v).visit_expr(i.expr, e, v); }
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_item[E](&@item i, &E e, &vt[E] v) {
|
||||
alt (i.node) {
|
||||
case (item_const(?t, ?ex)) {
|
||||
vt(v).visit_ty(t, e, v);
|
||||
vt(v).visit_expr(ex, e, v);
|
||||
}
|
||||
case (item_fn(?f, ?tp)) {
|
||||
vt(v).visit_fn(f, tp, i.span, some(i.ident), i.id, e, v);
|
||||
}
|
||||
case (item_mod(?m)) { vt(v).visit_mod(m, i.span, e, v); }
|
||||
case (item_native_mod(?nm)) {
|
||||
for (@view_item vi in nm.view_items) {
|
||||
vt(v).visit_view_item(vi, e, v);
|
||||
}
|
||||
for (@native_item ni in nm.items) {
|
||||
vt(v).visit_native_item(ni, e, v);
|
||||
}
|
||||
}
|
||||
case (item_ty(?t, _)) { vt(v).visit_ty(t, e, v); }
|
||||
case (item_res(?f, ?dtor_id, ?tps, _)) {
|
||||
vt(v).visit_fn(f, tps, i.span, some(i.ident), dtor_id, e, v);
|
||||
}
|
||||
case (item_tag(?variants, _)) {
|
||||
for (variant vr in variants) {
|
||||
for (variant_arg va in vr.node.args) {
|
||||
vt(v).visit_ty(va.ty, e, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
case (item_obj(?ob, _, _)) {
|
||||
for (obj_field f in ob.fields) { vt(v).visit_ty(f.ty, e, v); }
|
||||
for (@method m in ob.methods) {
|
||||
vt(v).visit_fn(m.node.meth, [], m.span, some(m.node.ident),
|
||||
m.node.id, e, v);
|
||||
}
|
||||
alt (ob.dtor) {
|
||||
case (none) { }
|
||||
case (some(?m)) {
|
||||
vt(v).visit_fn(m.node.meth, [], m.span,
|
||||
some(m.node.ident),
|
||||
m.node.id, e, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_ty[E](&@ty t, &E e, &vt[E] v) {
|
||||
alt (t.node) {
|
||||
case (ty_nil) { /* no-op */ }
|
||||
case (ty_bot) { /* no-op */ }
|
||||
case (ty_bool) { /* no-op */ }
|
||||
case (ty_int) { /* no-op */ }
|
||||
case (ty_float) { /* no-op */ }
|
||||
case (ty_uint) { /* no-op */ }
|
||||
case (ty_machine(_)) { /* no-op */ }
|
||||
case (ty_char) { /* no-op */ }
|
||||
case (ty_str) { /* no-op */ }
|
||||
case (ty_istr) { /* no-op */ }
|
||||
case (ty_box(?mt)) { vt(v).visit_ty(mt.ty, e, v); }
|
||||
case (ty_vec(?mt)) { vt(v).visit_ty(mt.ty, e, v); }
|
||||
case (ty_ivec(?mt)) { vt(v).visit_ty(mt.ty, e, v); }
|
||||
case (ty_ptr(?mt)) { vt(v).visit_ty(mt.ty, e, v); }
|
||||
case (ty_port(?t)) { vt(v).visit_ty(t, e, v); }
|
||||
case (ty_chan(?t)) { vt(v).visit_ty(t, e, v); }
|
||||
case (ty_task) { /* no-op */ }
|
||||
case (ty_tup(?mts)) {
|
||||
for (mt mt in mts) { vt(v).visit_ty(mt.ty, e, v); }
|
||||
}
|
||||
case (ty_rec(?flds)) {
|
||||
for (ty_field f in flds) { vt(v).visit_ty(f.node.mt.ty, e, v); }
|
||||
}
|
||||
case (ty_fn(_, ?args, ?out, _, ?constrs)) {
|
||||
for (ty_arg a in args) { vt(v).visit_ty(a.node.ty, e, v); }
|
||||
for (@constr c in constrs) { vt(v).visit_constr(c, e, v); }
|
||||
vt(v).visit_ty(out, e, v);
|
||||
}
|
||||
case (ty_obj(?tmeths)) {
|
||||
for (ty_method m in tmeths) {
|
||||
for (ty_arg a in m.node.inputs) {
|
||||
vt(v).visit_ty(a.node.ty, e, v);
|
||||
}
|
||||
vt(v).visit_ty(m.node.output, e, v);
|
||||
}
|
||||
}
|
||||
case (ty_path(?p, _)) {
|
||||
for (@ty tp in p.node.types) { vt(v).visit_ty(tp, e, v); }
|
||||
}
|
||||
case (ty_type) { /* no-op */ }
|
||||
case (ty_constr(?t, _)) { vt(v).visit_ty(t, e, v); }
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_constr[E](&@constr c, &E e, &vt[E] v) {
|
||||
// default
|
||||
|
||||
}
|
||||
|
||||
fn visit_pat[E](&@pat p, &E e, &vt[E] v) {
|
||||
alt (p.node) {
|
||||
case (pat_tag(?path, ?children)) {
|
||||
for (@ty tp in path.node.types) { vt(v).visit_ty(tp, e, v); }
|
||||
for (@pat child in children) { vt(v).visit_pat(child, e, v); }
|
||||
}
|
||||
case (_) { }
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_native_item[E](&@native_item ni, &E e, &vt[E] v) {
|
||||
alt (ni.node) {
|
||||
case (native_item_fn(_, ?fd, _)) { visit_fn_decl(fd, e, v); }
|
||||
case (native_item_ty) { }
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_fn_decl[E](&fn_decl fd, &E e, &vt[E] v) {
|
||||
for (arg a in fd.inputs) { vt(v).visit_ty(a.ty, e, v); }
|
||||
for (@constr c in fd.constraints) { vt(v).visit_constr(c, e, v); }
|
||||
vt(v).visit_ty(fd.output, e, v);
|
||||
}
|
||||
|
||||
fn visit_fn[E](&_fn f, &vec[ty_param] tp, &span sp, &fn_ident i,
|
||||
node_id id, &E e, &vt[E] v) {
|
||||
visit_fn_decl(f.decl, e, v);
|
||||
vt(v).visit_block(f.body, e, v);
|
||||
}
|
||||
|
||||
fn visit_block[E](&block b, &E e, &vt[E] v) {
|
||||
for (@stmt s in b.node.stmts) { vt(v).visit_stmt(s, e, v); }
|
||||
visit_expr_opt(b.node.expr, e, v);
|
||||
}
|
||||
|
||||
fn visit_stmt[E](&@stmt s, &E e, &vt[E] v) {
|
||||
alt (s.node) {
|
||||
case (stmt_decl(?d, _)) { vt(v).visit_decl(d, e, v); }
|
||||
case (stmt_expr(?ex, _)) { vt(v).visit_expr(ex, e, v); }
|
||||
case (stmt_crate_directive(?cd)) { visit_crate_directive(cd, e, v); }
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_decl[E](&@decl d, &E e, &vt[E] v) {
|
||||
alt (d.node) {
|
||||
case (decl_local(?loc)) {
|
||||
vt(v).visit_local(loc, e, v);
|
||||
}
|
||||
case (decl_item(?it)) { vt(v).visit_item(it, e, v); }
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_expr_opt[E](option::t[@expr] eo, &E e, &vt[E] v) {
|
||||
alt (eo) {
|
||||
case (none) { }
|
||||
case (some(?ex)) { vt(v).visit_expr(ex, e, v); }
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_exprs[E](vec[@expr] exprs, &E e, &vt[E] v) {
|
||||
for (@expr ex in exprs) { vt(v).visit_expr(ex, e, v); }
|
||||
}
|
||||
|
||||
fn visit_expr[E](&@expr ex, &E e, &vt[E] v) {
|
||||
alt (ex.node) {
|
||||
case (expr_vec(?es, _, _)) { visit_exprs(es, e, v); }
|
||||
case (expr_tup(?elts)) {
|
||||
for (elt el in elts) { vt(v).visit_expr(el.expr, e, v); }
|
||||
}
|
||||
case (expr_rec(?flds, ?base)) {
|
||||
for (field f in flds) { vt(v).visit_expr(f.node.expr, e, v); }
|
||||
visit_expr_opt(base, e, v);
|
||||
}
|
||||
case (expr_call(?callee, ?args)) {
|
||||
vt(v).visit_expr(callee, e, v);
|
||||
visit_exprs(args, e, v);
|
||||
}
|
||||
case (expr_self_method(_)) { }
|
||||
case (expr_bind(?callee, ?args)) {
|
||||
vt(v).visit_expr(callee, e, v);
|
||||
for (option::t[@expr] eo in args) { visit_expr_opt(eo, e, v); }
|
||||
}
|
||||
case (expr_spawn(_, _, ?callee, ?args)) {
|
||||
vt(v).visit_expr(callee, e, v);
|
||||
visit_exprs(args, e, v);
|
||||
}
|
||||
case (expr_binary(_, ?a, ?b)) {
|
||||
vt(v).visit_expr(a, e, v);
|
||||
vt(v).visit_expr(b, e, v);
|
||||
}
|
||||
case (expr_unary(_, ?a)) { vt(v).visit_expr(a, e, v); }
|
||||
case (expr_lit(_)) { }
|
||||
case (expr_cast(?x, ?t)) {
|
||||
vt(v).visit_expr(x, e, v);
|
||||
vt(v).visit_ty(t, e, v);
|
||||
}
|
||||
case (expr_if(?x, ?b, ?eo)) {
|
||||
vt(v).visit_expr(x, e, v);
|
||||
vt(v).visit_block(b, e, v);
|
||||
visit_expr_opt(eo, e, v);
|
||||
}
|
||||
case (expr_if_check(?x, ?b, ?eo)) {
|
||||
vt(v).visit_expr(x, e, v);
|
||||
vt(v).visit_block(b, e, v);
|
||||
visit_expr_opt(eo, e, v);
|
||||
}
|
||||
case (expr_ternary(?c, ?t, ?el)) {
|
||||
vt(v).visit_expr(c, e, v);
|
||||
vt(v).visit_expr(t, e, v);
|
||||
vt(v).visit_expr(el, e, v);
|
||||
}
|
||||
case (expr_while(?x, ?b)) {
|
||||
vt(v).visit_expr(x, e, v);
|
||||
vt(v).visit_block(b, e, v);
|
||||
}
|
||||
case (expr_for(?dcl, ?x, ?b)) {
|
||||
vt(v).visit_local(dcl, e, v);
|
||||
vt(v).visit_expr(x, e, v);
|
||||
vt(v).visit_block(b, e, v);
|
||||
}
|
||||
case (expr_for_each(?dcl, ?x, ?b)) {
|
||||
vt(v).visit_local(dcl, e, v);
|
||||
vt(v).visit_expr(x, e, v);
|
||||
vt(v).visit_block(b, e, v);
|
||||
}
|
||||
case (expr_do_while(?b, ?x)) {
|
||||
vt(v).visit_block(b, e, v);
|
||||
vt(v).visit_expr(x, e, v);
|
||||
}
|
||||
case (expr_alt(?x, ?arms)) {
|
||||
vt(v).visit_expr(x, e, v);
|
||||
for (arm a in arms) { vt(v).visit_arm(a, e, v); }
|
||||
}
|
||||
case (expr_fn(?f)) {
|
||||
vt(v).visit_fn(f, [], ex.span, none, ex.id, e, v);
|
||||
}
|
||||
case (expr_block(?b)) { vt(v).visit_block(b, e, v); }
|
||||
case (expr_assign(?a, ?b)) {
|
||||
vt(v).visit_expr(b, e, v);
|
||||
vt(v).visit_expr(a, e, v);
|
||||
}
|
||||
case (expr_move(?a, ?b)) {
|
||||
vt(v).visit_expr(b, e, v);
|
||||
vt(v).visit_expr(a, e, v);
|
||||
}
|
||||
case (expr_swap(?a, ?b)) {
|
||||
vt(v).visit_expr(a, e, v);
|
||||
vt(v).visit_expr(b, e, v);
|
||||
}
|
||||
case (expr_assign_op(_, ?a, ?b)) {
|
||||
vt(v).visit_expr(b, e, v);
|
||||
vt(v).visit_expr(a, e, v);
|
||||
}
|
||||
case (expr_send(?a, ?b)) {
|
||||
vt(v).visit_expr(a, e, v);
|
||||
vt(v).visit_expr(b, e, v);
|
||||
}
|
||||
case (expr_recv(?a, ?b)) {
|
||||
vt(v).visit_expr(a, e, v);
|
||||
vt(v).visit_expr(b, e, v);
|
||||
}
|
||||
case (expr_field(?x, _)) { vt(v).visit_expr(x, e, v); }
|
||||
case (expr_index(?a, ?b)) {
|
||||
vt(v).visit_expr(a, e, v);
|
||||
vt(v).visit_expr(b, e, v);
|
||||
}
|
||||
case (expr_path(?p)) {
|
||||
for (@ty tp in p.node.types) { vt(v).visit_ty(tp, e, v); }
|
||||
}
|
||||
case (expr_ext(_, _, _, ?expansion)) {
|
||||
vt(v).visit_expr(expansion, e, v);
|
||||
}
|
||||
case (expr_fail(?eo)) {
|
||||
visit_expr_opt(eo, e, v);
|
||||
}
|
||||
case (expr_break) { }
|
||||
case (expr_cont) { }
|
||||
case (expr_ret(?eo)) { visit_expr_opt(eo, e, v); }
|
||||
case (expr_put(?eo)) { visit_expr_opt(eo, e, v); }
|
||||
case (expr_be(?x)) { vt(v).visit_expr(x, e, v); }
|
||||
case (expr_log(_, ?x)) { vt(v).visit_expr(x, e, v); }
|
||||
case (expr_check(_, ?x)) { vt(v).visit_expr(x, e, v); }
|
||||
case (expr_assert(?x)) { vt(v).visit_expr(x, e, v); }
|
||||
case (expr_port(_)) { }
|
||||
case (expr_chan(?x)) { vt(v).visit_expr(x, e, v); }
|
||||
case (expr_anon_obj(?anon_obj, _, _)) {
|
||||
alt (anon_obj.fields) {
|
||||
case (none) { }
|
||||
case (some(?fields)) {
|
||||
for (anon_obj_field f in fields) {
|
||||
vt(v).visit_ty(f.ty, e, v);
|
||||
vt(v).visit_expr(f.expr, e, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
alt (anon_obj.with_obj) {
|
||||
case (none) { }
|
||||
case (some(?ex)) { vt(v).visit_expr(ex, e, v); }
|
||||
}
|
||||
for (@method m in anon_obj.methods) {
|
||||
vt(v).visit_fn(m.node.meth, [], m.span, some(m.node.ident),
|
||||
m.node.id, e, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_arm[E](&arm a, &E e, &vt[E] v) {
|
||||
vt(v).visit_pat(a.pat, e, v);
|
||||
vt(v).visit_block(a.block, e, v);
|
||||
}
|
||||
// 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:
|
||||
495
src/comp/syntax/walk.rs
Normal file
495
src/comp/syntax/walk.rs
Normal file
|
|
@ -0,0 +1,495 @@
|
|||
|
||||
import ast;
|
||||
import ast::ty_param;
|
||||
import ast::respan;
|
||||
import std::option;
|
||||
import std::option::some;
|
||||
import std::option::none;
|
||||
import codemap::span;
|
||||
|
||||
type ast_visitor =
|
||||
rec(fn() -> bool keep_going,
|
||||
fn() -> bool want_crate_directives,
|
||||
fn(&ast::crate) visit_crate_pre,
|
||||
fn(&ast::crate) visit_crate_post,
|
||||
fn(&@ast::crate_directive) visit_crate_directive_pre,
|
||||
fn(&@ast::crate_directive) visit_crate_directive_post,
|
||||
fn(&@ast::view_item) visit_view_item_pre,
|
||||
fn(&@ast::view_item) visit_view_item_post,
|
||||
fn(&@ast::native_item) visit_native_item_pre,
|
||||
fn(&@ast::native_item) visit_native_item_post,
|
||||
fn(&@ast::item) visit_item_pre,
|
||||
fn(&@ast::item) visit_item_post,
|
||||
fn(&@ast::method) visit_method_pre,
|
||||
fn(&@ast::method) visit_method_post,
|
||||
fn(&ast::block) visit_block_pre,
|
||||
fn(&ast::block) visit_block_post,
|
||||
fn(&@ast::stmt) visit_stmt_pre,
|
||||
fn(&@ast::stmt) visit_stmt_post,
|
||||
fn(&ast::arm) visit_arm_pre,
|
||||
fn(&ast::arm) visit_arm_post,
|
||||
fn(&@ast::pat) visit_pat_pre,
|
||||
fn(&@ast::pat) visit_pat_post,
|
||||
fn(&@ast::decl) visit_decl_pre,
|
||||
fn(&@ast::decl) visit_decl_post,
|
||||
fn(&@ast::local) visit_local_pre,
|
||||
fn(&@ast::local) visit_local_post,
|
||||
fn(&@ast::expr) visit_expr_pre,
|
||||
fn(&@ast::expr) visit_expr_post,
|
||||
fn(&@ast::ty) visit_ty_pre,
|
||||
fn(&@ast::ty) visit_ty_post,
|
||||
fn(&@ast::constr) visit_constr,
|
||||
fn(&ast::_fn, &vec[ast::ty_param], &span, &ast::fn_ident,
|
||||
ast::node_id) visit_fn_pre,
|
||||
fn(&ast::_fn, &vec[ast::ty_param], &span, &ast::fn_ident,
|
||||
ast::node_id) visit_fn_post);
|
||||
|
||||
fn walk_crate(&ast_visitor v, &ast::crate c) {
|
||||
if (!v.keep_going()) { ret; }
|
||||
v.visit_crate_pre(c);
|
||||
walk_mod(v, c.node.module);
|
||||
v.visit_crate_post(c);
|
||||
}
|
||||
|
||||
fn walk_crate_directive(&ast_visitor v, @ast::crate_directive cd) {
|
||||
if (!v.keep_going()) { ret; }
|
||||
if (!v.want_crate_directives()) { ret; }
|
||||
v.visit_crate_directive_pre(cd);
|
||||
alt (cd.node) {
|
||||
case (ast::cdir_src_mod(_, _, _)) { }
|
||||
case (ast::cdir_dir_mod(_, _, ?cdirs, _)) {
|
||||
for (@ast::crate_directive cdir in cdirs) {
|
||||
walk_crate_directive(v, cdir);
|
||||
}
|
||||
}
|
||||
case (ast::cdir_view_item(?vi)) { walk_view_item(v, vi); }
|
||||
case (ast::cdir_syntax(_)) { }
|
||||
case (ast::cdir_auth(_, _)) { }
|
||||
}
|
||||
v.visit_crate_directive_post(cd);
|
||||
}
|
||||
|
||||
fn walk_mod(&ast_visitor v, &ast::_mod m) {
|
||||
if (!v.keep_going()) { ret; }
|
||||
for (@ast::view_item vi in m.view_items) { walk_view_item(v, vi); }
|
||||
for (@ast::item i in m.items) { walk_item(v, i); }
|
||||
}
|
||||
|
||||
fn walk_view_item(&ast_visitor v, @ast::view_item vi) {
|
||||
if (!v.keep_going()) { ret; }
|
||||
v.visit_view_item_pre(vi);
|
||||
v.visit_view_item_post(vi);
|
||||
}
|
||||
|
||||
fn walk_local(&ast_visitor v, @ast::local loc) {
|
||||
v.visit_local_pre(loc);
|
||||
alt (loc.node.ty) { case (none) { } case (some(?t)) { walk_ty(v, t); } }
|
||||
alt (loc.node.init) {
|
||||
case (none) { }
|
||||
case (some(?i)) { walk_expr(v, i.expr); }
|
||||
}
|
||||
v.visit_local_post(loc);
|
||||
}
|
||||
|
||||
fn walk_item(&ast_visitor v, @ast::item i) {
|
||||
if (!v.keep_going()) { ret; }
|
||||
v.visit_item_pre(i);
|
||||
alt (i.node) {
|
||||
case (ast::item_const(?t, ?e)) { walk_ty(v, t); walk_expr(v, e); }
|
||||
case (ast::item_fn(?f, ?tps)) {
|
||||
walk_fn(v, f, tps, i.span, some(i.ident), i.id);
|
||||
}
|
||||
case (ast::item_mod(?m)) { walk_mod(v, m); }
|
||||
case (ast::item_native_mod(?nm)) { walk_native_mod(v, nm); }
|
||||
case (ast::item_ty(?t, _)) { walk_ty(v, t); }
|
||||
case (ast::item_res(?f, ?dtor_id, ?tps, _)) {
|
||||
walk_fn(v, f, tps, i.span, some(i.ident), dtor_id);
|
||||
}
|
||||
case (ast::item_tag(?variants, _)) {
|
||||
for (ast::variant vr in variants) {
|
||||
for (ast::variant_arg va in vr.node.args) {
|
||||
walk_ty(v, va.ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
case (ast::item_obj(?ob, _, _)) {
|
||||
for (ast::obj_field f in ob.fields) { walk_ty(v, f.ty); }
|
||||
for (@ast::method m in ob.methods) {
|
||||
v.visit_method_pre(m);
|
||||
// Methods don't have ty params?
|
||||
walk_fn(v, m.node.meth, [], m.span,
|
||||
some(m.node.ident), m.node.id);
|
||||
v.visit_method_post(m);
|
||||
}
|
||||
alt (ob.dtor) {
|
||||
case (none) { }
|
||||
case (some(?m)) {
|
||||
walk_fn(v, m.node.meth, [], m.span,
|
||||
some(m.node.ident), m.node.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
v.visit_item_post(i);
|
||||
}
|
||||
|
||||
fn walk_ty(&ast_visitor v, @ast::ty t) {
|
||||
if (!v.keep_going()) { ret; }
|
||||
v.visit_ty_pre(t);
|
||||
alt (t.node) {
|
||||
case (ast::ty_nil) { }
|
||||
case (ast::ty_bot) { }
|
||||
case (ast::ty_bool) { }
|
||||
case (ast::ty_int) { }
|
||||
case (ast::ty_uint) { }
|
||||
case (ast::ty_float) { }
|
||||
case (ast::ty_machine(_)) { }
|
||||
case (ast::ty_char) { }
|
||||
case (ast::ty_str) { }
|
||||
case (ast::ty_istr) { }
|
||||
case (ast::ty_box(?mt)) { walk_ty(v, mt.ty); }
|
||||
case (ast::ty_vec(?mt)) { walk_ty(v, mt.ty); }
|
||||
case (ast::ty_ivec(?mt)) { walk_ty(v, mt.ty); }
|
||||
case (ast::ty_ptr(?mt)) { walk_ty(v, mt.ty); }
|
||||
case (ast::ty_task) { }
|
||||
case (ast::ty_port(?t)) { walk_ty(v, t); }
|
||||
case (ast::ty_chan(?t)) { walk_ty(v, t); }
|
||||
case (ast::ty_tup(?mts)) {
|
||||
for (ast::mt mt in mts) { walk_ty(v, mt.ty); }
|
||||
}
|
||||
case (ast::ty_rec(?flds)) {
|
||||
for (ast::ty_field f in flds) { walk_ty(v, f.node.mt.ty); }
|
||||
}
|
||||
case (ast::ty_fn(_, ?args, ?out, _, ?constrs)) {
|
||||
for (ast::ty_arg a in args) { walk_ty(v, a.node.ty); }
|
||||
for (@ast::constr c in constrs) { v.visit_constr(c); }
|
||||
walk_ty(v, out);
|
||||
}
|
||||
case (ast::ty_obj(?tmeths)) {
|
||||
for (ast::ty_method m in tmeths) {
|
||||
for (ast::ty_arg a in m.node.inputs) {
|
||||
walk_ty(v, a.node.ty);
|
||||
}
|
||||
walk_ty(v, m.node.output);
|
||||
}
|
||||
}
|
||||
case (ast::ty_path(?p, _)) {
|
||||
for (@ast::ty tp in p.node.types) { walk_ty(v, tp); }
|
||||
}
|
||||
case (ast::ty_type) { }
|
||||
case (ast::ty_constr(?t, _)) { walk_ty(v, t); }
|
||||
}
|
||||
v.visit_ty_post(t);
|
||||
}
|
||||
|
||||
fn walk_pat(&ast_visitor v, &@ast::pat p) {
|
||||
v.visit_pat_pre(p);
|
||||
alt (p.node) {
|
||||
case (ast::pat_tag(?path, ?children)) {
|
||||
for (@ast::ty tp in path.node.types) { walk_ty(v, tp); }
|
||||
for (@ast::pat child in children) { walk_pat(v, child); }
|
||||
}
|
||||
case (_) { }
|
||||
}
|
||||
v.visit_pat_post(p);
|
||||
}
|
||||
|
||||
fn walk_native_mod(&ast_visitor v, &ast::native_mod nm) {
|
||||
if (!v.keep_going()) { ret; }
|
||||
for (@ast::view_item vi in nm.view_items) { walk_view_item(v, vi); }
|
||||
for (@ast::native_item ni in nm.items) { walk_native_item(v, ni); }
|
||||
}
|
||||
|
||||
fn walk_native_item(&ast_visitor v, @ast::native_item ni) {
|
||||
if (!v.keep_going()) { ret; }
|
||||
v.visit_native_item_pre(ni);
|
||||
alt (ni.node) {
|
||||
case (ast::native_item_fn(_, ?fd, _)) {
|
||||
walk_fn_decl(v, fd);
|
||||
}
|
||||
case (ast::native_item_ty) { }
|
||||
}
|
||||
v.visit_native_item_post(ni);
|
||||
}
|
||||
|
||||
fn walk_fn_decl(&ast_visitor v, &ast::fn_decl fd) {
|
||||
for (ast::arg a in fd.inputs) { walk_ty(v, a.ty); }
|
||||
for (@ast::constr c in fd.constraints) { v.visit_constr(c); }
|
||||
walk_ty(v, fd.output);
|
||||
}
|
||||
|
||||
fn walk_fn(&ast_visitor v, &ast::_fn f, &vec[ast::ty_param] tps,
|
||||
&span sp, &ast::fn_ident i, ast::node_id d) {
|
||||
if (!v.keep_going()) { ret; }
|
||||
v.visit_fn_pre(f, tps, sp, i, d);
|
||||
walk_fn_decl(v, f.decl);
|
||||
walk_block(v, f.body);
|
||||
v.visit_fn_post(f, tps, sp, i, d);
|
||||
}
|
||||
|
||||
fn walk_block(&ast_visitor v, &ast::block b) {
|
||||
if (!v.keep_going()) { ret; }
|
||||
v.visit_block_pre(b);
|
||||
for (@ast::stmt s in b.node.stmts) { walk_stmt(v, s); }
|
||||
walk_expr_opt(v, b.node.expr);
|
||||
v.visit_block_post(b);
|
||||
}
|
||||
|
||||
fn walk_stmt(&ast_visitor v, @ast::stmt s) {
|
||||
if (!v.keep_going()) { ret; }
|
||||
v.visit_stmt_pre(s);
|
||||
alt (s.node) {
|
||||
case (ast::stmt_decl(?d, _)) { walk_decl(v, d); }
|
||||
case (ast::stmt_expr(?e, _)) { walk_expr(v, e); }
|
||||
case (ast::stmt_crate_directive(?cdir)) {
|
||||
walk_crate_directive(v, cdir);
|
||||
}
|
||||
}
|
||||
v.visit_stmt_post(s);
|
||||
}
|
||||
|
||||
fn walk_decl(&ast_visitor v, @ast::decl d) {
|
||||
if (!v.keep_going()) { ret; }
|
||||
v.visit_decl_pre(d);
|
||||
alt (d.node) {
|
||||
case (ast::decl_local(?loc)) { walk_local(v, loc); }
|
||||
case (ast::decl_item(?it)) { walk_item(v, it); }
|
||||
}
|
||||
v.visit_decl_post(d);
|
||||
}
|
||||
|
||||
fn walk_expr_opt(&ast_visitor v, option::t[@ast::expr] eo) {
|
||||
alt (eo) { case (none) { } case (some(?e)) { walk_expr(v, e); } }
|
||||
}
|
||||
|
||||
fn walk_exprs(&ast_visitor v, vec[@ast::expr] exprs) {
|
||||
for (@ast::expr e in exprs) { walk_expr(v, e); }
|
||||
}
|
||||
|
||||
fn walk_expr(&ast_visitor v, @ast::expr e) {
|
||||
if (!v.keep_going()) { ret; }
|
||||
v.visit_expr_pre(e);
|
||||
alt (e.node) {
|
||||
case (ast::expr_vec(?es, _, _)) { walk_exprs(v, es); }
|
||||
case (ast::expr_tup(?elts)) {
|
||||
for (ast::elt e in elts) { walk_expr(v, e.expr); }
|
||||
}
|
||||
case (ast::expr_rec(?flds, ?base)) {
|
||||
for (ast::field f in flds) { walk_expr(v, f.node.expr); }
|
||||
walk_expr_opt(v, base);
|
||||
}
|
||||
case (ast::expr_call(?callee, ?args)) {
|
||||
walk_expr(v, callee);
|
||||
walk_exprs(v, args);
|
||||
}
|
||||
case (ast::expr_self_method(_)) { }
|
||||
case (ast::expr_bind(?callee, ?args)) {
|
||||
walk_expr(v, callee);
|
||||
for (option::t[@ast::expr] eo in args) { walk_expr_opt(v, eo); }
|
||||
}
|
||||
case (ast::expr_spawn(_, _, ?callee, ?args)) {
|
||||
walk_expr(v, callee);
|
||||
walk_exprs(v, args);
|
||||
}
|
||||
case (ast::expr_binary(_, ?a, ?b)) {
|
||||
walk_expr(v, a);
|
||||
walk_expr(v, b);
|
||||
}
|
||||
case (ast::expr_unary(_, ?a)) { walk_expr(v, a); }
|
||||
case (ast::expr_lit(_)) { }
|
||||
case (ast::expr_cast(?x, ?t)) { walk_expr(v, x); walk_ty(v, t); }
|
||||
case (ast::expr_if(?x, ?b, ?eo)) {
|
||||
walk_expr(v, x);
|
||||
walk_block(v, b);
|
||||
walk_expr_opt(v, eo);
|
||||
}
|
||||
case (ast::expr_if_check(?x, ?b, ?eo)) {
|
||||
walk_expr(v, x);
|
||||
walk_block(v, b);
|
||||
walk_expr_opt(v, eo);
|
||||
}
|
||||
case (ast::expr_ternary(?c, ?t, ?e)) {
|
||||
walk_expr(v, c);
|
||||
walk_expr(v, t);
|
||||
walk_expr(v, e);
|
||||
}
|
||||
case (ast::expr_while(?x, ?b)) {
|
||||
walk_expr(v, x);
|
||||
walk_block(v, b);
|
||||
}
|
||||
case (ast::expr_for(?dcl, ?x, ?b)) {
|
||||
walk_local(v, dcl);
|
||||
walk_expr(v, x);
|
||||
walk_block(v, b);
|
||||
}
|
||||
case (ast::expr_for_each(?dcl, ?x, ?b)) {
|
||||
walk_local(v, dcl);
|
||||
walk_expr(v, x);
|
||||
walk_block(v, b);
|
||||
}
|
||||
case (ast::expr_do_while(?b, ?x)) {
|
||||
walk_block(v, b);
|
||||
walk_expr(v, x);
|
||||
}
|
||||
case (ast::expr_alt(?x, ?arms)) {
|
||||
walk_expr(v, x);
|
||||
for (ast::arm a in arms) {
|
||||
walk_pat(v, a.pat);
|
||||
v.visit_arm_pre(a);
|
||||
walk_block(v, a.block);
|
||||
v.visit_arm_post(a);
|
||||
}
|
||||
}
|
||||
case (ast::expr_fn(?f)) {
|
||||
walk_fn(v, f, [], e.span, none, e.id);
|
||||
}
|
||||
case (ast::expr_block(?b)) { walk_block(v, b); }
|
||||
case (ast::expr_assign(?a, ?b)) {
|
||||
walk_expr(v, a);
|
||||
walk_expr(v, b);
|
||||
}
|
||||
case (ast::expr_move(?a, ?b)) { walk_expr(v, a); walk_expr(v, b); }
|
||||
case (ast::expr_swap(?a, ?b)) { walk_expr(v, a); walk_expr(v, b); }
|
||||
case (ast::expr_assign_op(_, ?a, ?b)) {
|
||||
walk_expr(v, a);
|
||||
walk_expr(v, b);
|
||||
}
|
||||
case (ast::expr_send(?a, ?b)) { walk_expr(v, a); walk_expr(v, b); }
|
||||
case (ast::expr_recv(?a, ?b)) { walk_expr(v, a); walk_expr(v, b); }
|
||||
case (ast::expr_field(?x, _)) { walk_expr(v, x); }
|
||||
case (ast::expr_index(?a, ?b)) {
|
||||
walk_expr(v, a);
|
||||
walk_expr(v, b);
|
||||
}
|
||||
case (ast::expr_path(?p)) {
|
||||
for (@ast::ty tp in p.node.types) { walk_ty(v, tp); }
|
||||
}
|
||||
case (ast::expr_ext(_, ?args, ?body, ?expansion)) {
|
||||
// Only walk expansion, not args/body.
|
||||
|
||||
walk_expr(v, expansion);
|
||||
}
|
||||
case (ast::expr_fail(?eo)) { walk_expr_opt(v, eo); }
|
||||
case (ast::expr_break) { }
|
||||
case (ast::expr_cont) { }
|
||||
case (ast::expr_ret(?eo)) { walk_expr_opt(v, eo); }
|
||||
case (ast::expr_put(?eo)) { walk_expr_opt(v, eo); }
|
||||
case (ast::expr_be(?x)) { walk_expr(v, x); }
|
||||
case (ast::expr_log(_, ?x)) { walk_expr(v, x); }
|
||||
case (ast::expr_check(_, ?x)) { walk_expr(v, x); }
|
||||
case (ast::expr_assert(?x)) { walk_expr(v, x); }
|
||||
case (ast::expr_port(_)) { }
|
||||
case (ast::expr_chan(?x)) { walk_expr(v, x); }
|
||||
case (ast::expr_anon_obj(?anon_obj, _, _)) {
|
||||
// Fields
|
||||
|
||||
alt (anon_obj.fields) {
|
||||
case (none) { }
|
||||
case (some(?fields)) {
|
||||
for (ast::anon_obj_field f in fields) {
|
||||
walk_ty(v, f.ty);
|
||||
walk_expr(v, f.expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
// with_obj
|
||||
|
||||
alt (anon_obj.with_obj) {
|
||||
case (none) { }
|
||||
case (some(?e)) { walk_expr(v, e); }
|
||||
}
|
||||
|
||||
// Methods
|
||||
for (@ast::method m in anon_obj.methods) {
|
||||
v.visit_method_pre(m);
|
||||
walk_fn(v, m.node.meth, [], m.span, some(m.node.ident),
|
||||
m.node.id);
|
||||
v.visit_method_post(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
v.visit_expr_post(e);
|
||||
}
|
||||
|
||||
fn def_keep_going() -> bool { ret true; }
|
||||
|
||||
fn def_want_crate_directives() -> bool { ret false; }
|
||||
|
||||
fn def_visit_crate(&ast::crate c) { }
|
||||
|
||||
fn def_visit_crate_directive(&@ast::crate_directive c) { }
|
||||
|
||||
fn def_visit_view_item(&@ast::view_item vi) { }
|
||||
|
||||
fn def_visit_native_item(&@ast::native_item ni) { }
|
||||
|
||||
fn def_visit_item(&@ast::item i) { }
|
||||
|
||||
fn def_visit_method(&@ast::method m) { }
|
||||
|
||||
fn def_visit_block(&ast::block b) { }
|
||||
|
||||
fn def_visit_stmt(&@ast::stmt s) { }
|
||||
|
||||
fn def_visit_arm(&ast::arm a) { }
|
||||
|
||||
fn def_visit_pat(&@ast::pat p) { }
|
||||
|
||||
fn def_visit_decl(&@ast::decl d) { }
|
||||
|
||||
fn def_visit_local(&@ast::local l) { }
|
||||
|
||||
fn def_visit_expr(&@ast::expr e) { }
|
||||
|
||||
fn def_visit_ty(&@ast::ty t) { }
|
||||
|
||||
fn def_visit_constr(&@ast::constr c) { }
|
||||
|
||||
fn def_visit_fn(&ast::_fn f, &vec[ast::ty_param] tps,
|
||||
&span sp, &ast::fn_ident i, ast::node_id d) { }
|
||||
|
||||
fn default_visitor() -> ast_visitor {
|
||||
ret rec(keep_going=def_keep_going,
|
||||
want_crate_directives=def_want_crate_directives,
|
||||
visit_crate_pre=def_visit_crate,
|
||||
visit_crate_post=def_visit_crate,
|
||||
visit_crate_directive_pre=def_visit_crate_directive,
|
||||
visit_crate_directive_post=def_visit_crate_directive,
|
||||
visit_view_item_pre=def_visit_view_item,
|
||||
visit_view_item_post=def_visit_view_item,
|
||||
visit_native_item_pre=def_visit_native_item,
|
||||
visit_native_item_post=def_visit_native_item,
|
||||
visit_item_pre=def_visit_item,
|
||||
visit_item_post=def_visit_item,
|
||||
visit_method_pre=def_visit_method,
|
||||
visit_method_post=def_visit_method,
|
||||
visit_block_pre=def_visit_block,
|
||||
visit_block_post=def_visit_block,
|
||||
visit_stmt_pre=def_visit_stmt,
|
||||
visit_stmt_post=def_visit_stmt,
|
||||
visit_arm_pre=def_visit_arm,
|
||||
visit_arm_post=def_visit_arm,
|
||||
visit_pat_pre=def_visit_pat,
|
||||
visit_pat_post=def_visit_pat,
|
||||
visit_decl_pre=def_visit_decl,
|
||||
visit_decl_post=def_visit_decl,
|
||||
visit_local_pre=def_visit_local,
|
||||
visit_local_post=def_visit_local,
|
||||
visit_expr_pre=def_visit_expr,
|
||||
visit_expr_post=def_visit_expr,
|
||||
visit_ty_pre=def_visit_ty,
|
||||
visit_ty_post=def_visit_ty,
|
||||
visit_constr=def_visit_constr,
|
||||
visit_fn_pre=def_visit_fn,
|
||||
visit_fn_post=def_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:
|
||||
//
|
||||
Loading…
Add table
Add a link
Reference in a new issue