mirror of https://github.com/rust-lang/rust.git
Reformat source tree (minus a couple tests that are still grumpy).
This commit is contained in:
parent
8d381823e2
commit
ce72993488
|
@ -1,101 +1,136 @@
|
|||
// FIXME: Most of these should be uints.
|
||||
|
||||
|
||||
|
||||
// FIXME: Most of these should be uints.
|
||||
const int rc_base_field_refcnt = 0;
|
||||
|
||||
|
||||
// FIXME: import from std::dbg when imported consts work.
|
||||
const uint const_refcount = 0x7bad_face_u;
|
||||
|
||||
const int task_field_refcnt = 0;
|
||||
|
||||
const int task_field_stk = 2;
|
||||
|
||||
const int task_field_runtime_sp = 3;
|
||||
|
||||
const int task_field_rust_sp = 4;
|
||||
|
||||
const int task_field_gc_alloc_chain = 5;
|
||||
|
||||
const int task_field_dom = 6;
|
||||
|
||||
const int n_visible_task_fields = 7;
|
||||
|
||||
const int dom_field_interrupt_flag = 1;
|
||||
|
||||
const int frame_glue_fns_field_mark = 0;
|
||||
|
||||
const int frame_glue_fns_field_drop = 1;
|
||||
|
||||
const int frame_glue_fns_field_reloc = 2;
|
||||
|
||||
const int box_rc_field_refcnt = 0;
|
||||
|
||||
const int box_rc_field_body = 1;
|
||||
|
||||
const int general_code_alignment = 16;
|
||||
|
||||
const int vec_elt_rc = 0;
|
||||
|
||||
const int vec_elt_alloc = 1;
|
||||
|
||||
const int vec_elt_fill = 2;
|
||||
|
||||
const int vec_elt_pad = 3;
|
||||
|
||||
const int vec_elt_data = 4;
|
||||
|
||||
const int tydesc_field_first_param = 0;
|
||||
|
||||
const int tydesc_field_size = 1;
|
||||
|
||||
const int tydesc_field_align = 2;
|
||||
|
||||
const int tydesc_field_take_glue = 3;
|
||||
|
||||
const int tydesc_field_drop_glue = 4;
|
||||
|
||||
const int tydesc_field_free_glue = 5;
|
||||
|
||||
const int tydesc_field_sever_glue = 6;
|
||||
|
||||
const int tydesc_field_mark_glue = 7;
|
||||
|
||||
|
||||
// FIXME no longer used in rustc, drop when rustboot is gone
|
||||
const int tydesc_field_obj_drop_glue = 8;
|
||||
|
||||
const int tydesc_field_is_stateful = 9;
|
||||
|
||||
const int tydesc_field_cmp_glue = 10;
|
||||
|
||||
const int n_tydesc_fields = 11;
|
||||
|
||||
const uint cmp_glue_op_eq = 0u;
|
||||
|
||||
const uint cmp_glue_op_lt = 1u;
|
||||
|
||||
const uint cmp_glue_op_le = 2u;
|
||||
|
||||
|
||||
const int obj_field_vtbl = 0;
|
||||
|
||||
const int obj_field_box = 1;
|
||||
|
||||
const int obj_body_elt_tydesc = 0;
|
||||
const int obj_body_elt_typarams = 1;
|
||||
const int obj_body_elt_fields = 2;
|
||||
const int obj_body_elt_with_obj = 3; /* The base object to which an anonymous
|
||||
* object is attached */
|
||||
|
||||
const int fn_field_code = 0;
|
||||
const int obj_body_elt_typarams = 1;
|
||||
|
||||
const int obj_body_elt_fields = 2;
|
||||
|
||||
const int obj_body_elt_with_obj = 3;
|
||||
|
||||
/* The base object to which an anonymous
|
||||
* object is attached */
|
||||
const int fn_field_code = 0;
|
||||
|
||||
const int fn_field_box = 1;
|
||||
|
||||
const int closure_elt_tydesc = 0;
|
||||
|
||||
const int closure_elt_target = 1;
|
||||
|
||||
const int closure_elt_bindings = 2;
|
||||
|
||||
const int closure_elt_ty_params = 3;
|
||||
|
||||
const uint ivec_default_length = 8u;
|
||||
|
||||
const uint ivec_elt_len = 0u;
|
||||
const uint ivec_elt_alen = 1u;
|
||||
const uint ivec_elt_elems = 2u;
|
||||
const uint ivec_heap_stub_elt_zero = 0u;
|
||||
const uint ivec_heap_stub_elt_alen = 1u;
|
||||
const uint ivec_heap_stub_elt_ptr = 2u;
|
||||
const uint ivec_heap_elt_len = 0u;
|
||||
const uint ivec_heap_elt_elems = 1u;
|
||||
|
||||
const uint ivec_elt_alen = 1u;
|
||||
|
||||
const uint ivec_elt_elems = 2u;
|
||||
|
||||
const uint ivec_heap_stub_elt_zero = 0u;
|
||||
|
||||
const uint ivec_heap_stub_elt_alen = 1u;
|
||||
|
||||
const uint ivec_heap_stub_elt_ptr = 2u;
|
||||
|
||||
const uint ivec_heap_elt_len = 0u;
|
||||
|
||||
const uint ivec_heap_elt_elems = 1u;
|
||||
|
||||
const int worst_case_glue_call_args = 7;
|
||||
|
||||
fn memcpy_glue_name() -> str {
|
||||
ret "rust_memcpy_glue";
|
||||
}
|
||||
fn memcpy_glue_name() -> str { ret "rust_memcpy_glue"; }
|
||||
|
||||
fn bzero_glue_name() -> str {
|
||||
ret "rust_bzero_glue";
|
||||
}
|
||||
fn bzero_glue_name() -> str { ret "rust_bzero_glue"; }
|
||||
|
||||
fn yield_glue_name() -> str {
|
||||
ret "rust_yield_glue";
|
||||
}
|
||||
|
||||
fn no_op_type_glue_name() -> str {
|
||||
ret "rust_no_op_type_glue";
|
||||
}
|
||||
fn yield_glue_name() -> str { ret "rust_yield_glue"; }
|
||||
|
||||
fn no_op_type_glue_name() -> str { ret "rust_no_op_type_glue"; }
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
import driver::session;
|
||||
import lib::llvm::llvm;
|
||||
import middle::trans;
|
||||
|
@ -13,7 +14,6 @@ import std::sha1::sha1;
|
|||
import std::sort;
|
||||
import trans::crate_ctxt;
|
||||
import front::ast;
|
||||
|
||||
import lib::llvm::llvm::ModuleRef;
|
||||
import lib::llvm::llvm::ValueRef;
|
||||
import lib::llvm::mk_pass_manager;
|
||||
|
@ -32,11 +32,9 @@ tag output_type {
|
|||
|
||||
fn llvm_err(session::session sess, str msg) {
|
||||
auto buf = llvm::LLVMRustGetLastError();
|
||||
if ((buf as uint) == 0u) {
|
||||
if (buf as uint == 0u) {
|
||||
sess.err(msg);
|
||||
} else {
|
||||
sess.err(msg + ": " + str::str_from_cstr(buf));
|
||||
}
|
||||
} else { sess.err(msg + ": " + str::str_from_cstr(buf)); }
|
||||
fail;
|
||||
}
|
||||
|
||||
|
@ -44,22 +42,18 @@ fn link_intrinsics(session::session sess, ModuleRef llmod) {
|
|||
auto path = fs::connect(sess.get_opts().sysroot, "intrinsics.bc");
|
||||
auto membuf =
|
||||
llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(str::buf(path));
|
||||
if ((membuf as uint) == 0u) {
|
||||
if (membuf as uint == 0u) {
|
||||
llvm_err(sess, "installation problem: couldn't open " + path);
|
||||
fail;
|
||||
}
|
||||
|
||||
auto llintrinsicsmod = llvm::LLVMRustParseBitcode(membuf);
|
||||
llvm::LLVMDisposeMemoryBuffer(membuf);
|
||||
|
||||
if ((llintrinsicsmod as uint) == 0u) {
|
||||
if (llintrinsicsmod as uint == 0u) {
|
||||
llvm_err(sess, "installation problem: couldn't parse intrinsics.bc");
|
||||
fail;
|
||||
}
|
||||
|
||||
auto linkres = llvm::LLVMLinkModules(llmod, llintrinsicsmod);
|
||||
llvm::LLVMDisposeModule(llintrinsicsmod);
|
||||
|
||||
if (linkres == False) {
|
||||
llvm_err(sess, "couldn't link the module with the intrinsics");
|
||||
fail;
|
||||
|
@ -68,9 +62,8 @@ fn link_intrinsics(session::session sess, ModuleRef llmod) {
|
|||
|
||||
mod write {
|
||||
fn is_object_or_assembly_or_exe(output_type ot) -> bool {
|
||||
if ( (ot == output_type_assembly) ||
|
||||
(ot == output_type_object) ||
|
||||
(ot == output_type_exe) ) {
|
||||
if (ot == output_type_assembly || ot == output_type_object ||
|
||||
ot == output_type_exe) {
|
||||
ret true;
|
||||
}
|
||||
ret false;
|
||||
|
@ -83,39 +76,30 @@ mod write {
|
|||
auto stem;
|
||||
if (dot_pos < 0) {
|
||||
stem = output_path;
|
||||
} else {
|
||||
stem = str::substr(output_path, 0u, dot_pos as uint);
|
||||
}
|
||||
} else { stem = str::substr(output_path, 0u, dot_pos as uint); }
|
||||
ret stem + "." + extension;
|
||||
}
|
||||
|
||||
fn run_passes(session::session sess, ModuleRef llmod, str output) {
|
||||
|
||||
auto opts = sess.get_opts();
|
||||
|
||||
if (opts.time_llvm_passes) {
|
||||
llvm::LLVMRustEnableTimePasses();
|
||||
}
|
||||
|
||||
if (opts.time_llvm_passes) { llvm::LLVMRustEnableTimePasses(); }
|
||||
link_intrinsics(sess, llmod);
|
||||
|
||||
auto pm = mk_pass_manager();
|
||||
auto td = mk_target_data(x86::get_data_layout());
|
||||
llvm::LLVMAddTargetData(td.lltd, pm.llpm);
|
||||
|
||||
// TODO: run the linter here also, once there are llvm-c bindings for
|
||||
// it.
|
||||
|
||||
// Generate a pre-optimization intermediate file if -save-temps was
|
||||
// specified.
|
||||
|
||||
if (opts.save_temps) {
|
||||
alt (opts.output_type) {
|
||||
case (output_type_bitcode) {
|
||||
if (opts.optimize != 0u) {
|
||||
auto filename = mk_intermediate_name(output,
|
||||
"no-opt.bc");
|
||||
auto filename =
|
||||
mk_intermediate_name(output, "no-opt.bc");
|
||||
llvm::LLVMWriteBitcodeToFile(llmod,
|
||||
str::buf(filename));
|
||||
str::buf(filename));
|
||||
}
|
||||
}
|
||||
case (_) {
|
||||
|
@ -124,109 +108,95 @@ mod write {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.verify) {
|
||||
llvm::LLVMAddVerifierPass(pm.llpm);
|
||||
}
|
||||
|
||||
if (opts.verify) { llvm::LLVMAddVerifierPass(pm.llpm); }
|
||||
// FIXME: This is mostly a copy of the bits of opt's -O2 that are
|
||||
// available in the C api.
|
||||
// FIXME2: We might want to add optimization levels like -O1, -O2,
|
||||
// -Os, etc
|
||||
// FIXME3: Should we expose and use the pass lists used by the opt
|
||||
// tool?
|
||||
|
||||
if (opts.optimize != 0u) {
|
||||
auto fpm = mk_pass_manager();
|
||||
llvm::LLVMAddTargetData(td.lltd, fpm.llpm);
|
||||
llvm::LLVMAddStandardFunctionPasses(fpm.llpm, 2u);
|
||||
llvm::LLVMRunPassManager(fpm.llpm, llmod);
|
||||
|
||||
let uint threshold = 225u;
|
||||
if (opts.optimize == 3u) {
|
||||
threshold = 275u;
|
||||
}
|
||||
|
||||
if (opts.optimize == 3u) { threshold = 275u; }
|
||||
llvm::LLVMAddStandardModulePasses(pm.llpm,
|
||||
// optimization level
|
||||
opts.optimize,
|
||||
False, // optimize for size
|
||||
True, // unit-at-a-time
|
||||
True, // unroll loops
|
||||
True, // simplify lib calls
|
||||
threshold); // inline threshold
|
||||
}
|
||||
True, // unit-at-a-time
|
||||
True, // unroll loops
|
||||
True, // simplify lib calls
|
||||
threshold); // inline threshold
|
||||
|
||||
if (opts.verify) {
|
||||
llvm::LLVMAddVerifierPass(pm.llpm);
|
||||
}
|
||||
|
||||
if (opts.verify) { llvm::LLVMAddVerifierPass(pm.llpm); }
|
||||
if (is_object_or_assembly_or_exe(opts.output_type)) {
|
||||
let int LLVMAssemblyFile = 0;
|
||||
let int LLVMObjectFile = 1;
|
||||
let int LLVMNullFile = 2;
|
||||
auto FileType;
|
||||
if ((opts.output_type == output_type_object) ||
|
||||
(opts.output_type == output_type_exe)) {
|
||||
if (opts.output_type == output_type_object ||
|
||||
opts.output_type == output_type_exe) {
|
||||
FileType = LLVMObjectFile;
|
||||
} else {
|
||||
FileType = LLVMAssemblyFile;
|
||||
}
|
||||
|
||||
} else { FileType = LLVMAssemblyFile; }
|
||||
// Write optimized bitcode if --save-temps was on.
|
||||
if (opts.save_temps) {
|
||||
|
||||
if (opts.save_temps) {
|
||||
// Always output the bitcode file with --save-temps
|
||||
|
||||
auto filename = mk_intermediate_name(output, "opt.bc");
|
||||
llvm::LLVMRunPassManager(pm.llpm, llmod);
|
||||
llvm::LLVMWriteBitcodeToFile(llmod, str::buf(filename));
|
||||
pm = mk_pass_manager();
|
||||
|
||||
// Save the assembly file if -S is used
|
||||
|
||||
if (opts.output_type == output_type_assembly) {
|
||||
llvm::LLVMRustWriteOutputFile(pm.llpm, llmod,
|
||||
str::buf(x86::get_target_triple()),
|
||||
str::buf(output), LLVMAssemblyFile);
|
||||
auto triple = x86::get_target_triple();
|
||||
llvm::LLVMRustWriteOutputFile(pm.llpm, llmod,
|
||||
str::buf(triple),
|
||||
str::buf(output),
|
||||
LLVMAssemblyFile);
|
||||
}
|
||||
|
||||
// Save the object file for -c or --save-temps alone
|
||||
// This .o is needed when an exe is built
|
||||
if ((opts.output_type == output_type_object) ||
|
||||
(opts.output_type == output_type_exe)) {
|
||||
llvm::LLVMRustWriteOutputFile(pm.llpm, llmod,
|
||||
str::buf(x86::get_target_triple()),
|
||||
str::buf(output), LLVMObjectFile);
|
||||
}
|
||||
if (opts.output_type == output_type_object ||
|
||||
opts.output_type == output_type_exe) {
|
||||
auto triple = x86::get_target_triple();
|
||||
llvm::LLVMRustWriteOutputFile(pm.llpm, llmod,
|
||||
str::buf(triple),
|
||||
str::buf(output),
|
||||
LLVMObjectFile);
|
||||
}
|
||||
} else {
|
||||
|
||||
// If we aren't saving temps then just output the file
|
||||
// type corresponding to the '-c' or '-S' flag used
|
||||
auto triple = x86::get_target_triple();
|
||||
llvm::LLVMRustWriteOutputFile(pm.llpm, llmod,
|
||||
str::buf(x86::get_target_triple()),
|
||||
str::buf(output),
|
||||
FileType);
|
||||
str::buf(triple),
|
||||
str::buf(output), FileType);
|
||||
}
|
||||
|
||||
// Clean up and return
|
||||
|
||||
llvm::LLVMDisposeModule(llmod);
|
||||
if (opts.time_llvm_passes) {
|
||||
llvm::LLVMRustPrintPassTimings();
|
||||
}
|
||||
if (opts.time_llvm_passes) { llvm::LLVMRustPrintPassTimings(); }
|
||||
ret;
|
||||
}
|
||||
|
||||
// If only a bitcode file is asked for by using the '--emit-llvm'
|
||||
// flag, then output it here
|
||||
llvm::LLVMRunPassManager(pm.llpm, llmod);
|
||||
|
||||
llvm::LLVMRunPassManager(pm.llpm, llmod);
|
||||
llvm::LLVMWriteBitcodeToFile(llmod, str::buf(output));
|
||||
llvm::LLVMDisposeModule(llmod);
|
||||
|
||||
if (opts.time_llvm_passes) {
|
||||
llvm::LLVMRustPrintPassTimings();
|
||||
}
|
||||
if (opts.time_llvm_passes) { llvm::LLVMRustPrintPassTimings(); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Name mangling and its relationship to metadata. This is complex. Read
|
||||
* carefully.
|
||||
|
@ -277,81 +247,63 @@ mod write {
|
|||
* system linkers understand.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
iter crate_export_metas(&ast::crate c) -> @ast::meta_item {
|
||||
for (@ast::crate_directive cdir in c.node.directives) {
|
||||
alt (cdir.node) {
|
||||
case (ast::cdir_meta(?v, ?mis)) {
|
||||
if (v == ast::export_meta) {
|
||||
for (@ast::meta_item mi in mis) {
|
||||
put mi;
|
||||
}
|
||||
for (@ast::meta_item mi in mis) { put mi; }
|
||||
}
|
||||
}
|
||||
case (_) {}
|
||||
case (_) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
iter crate_local_metas(&ast::crate c) -> @ast::meta_item {
|
||||
for (@ast::crate_directive cdir in c.node.directives) {
|
||||
alt (cdir.node) {
|
||||
case (ast::cdir_meta(?v, ?mis)) {
|
||||
if (v == ast::local_meta) {
|
||||
for (@ast::meta_item mi in mis) {
|
||||
put mi;
|
||||
}
|
||||
for (@ast::meta_item mi in mis) { put mi; }
|
||||
}
|
||||
}
|
||||
case (_) {}
|
||||
case (_) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn get_crate_meta_export(&session::session sess,
|
||||
&ast::crate c, str k, str default,
|
||||
bool warn_default) -> str {
|
||||
fn get_crate_meta_export(&session::session sess, &ast::crate c, str k,
|
||||
str default, bool warn_default) -> str {
|
||||
let vec[@ast::meta_item] v = [];
|
||||
for each (@ast::meta_item mi in crate_export_metas(c)) {
|
||||
if (mi.node.key == k) {
|
||||
v += [mi];
|
||||
}
|
||||
if (mi.node.key == k) { v += [mi]; }
|
||||
}
|
||||
alt (vec::len(v)) {
|
||||
case (0u) {
|
||||
if (warn_default) {
|
||||
sess.warn(#fmt("missing meta '%s', using '%s' as default",
|
||||
k, default));
|
||||
sess.warn(#fmt("missing meta '%s', using '%s' as default", k,
|
||||
default));
|
||||
}
|
||||
ret default;
|
||||
}
|
||||
case (1u) {
|
||||
ret v.(0).node.value;
|
||||
}
|
||||
case (1u) { ret v.(0).node.value; }
|
||||
case (_) {
|
||||
sess.span_err(v.(1).span, #fmt("duplicate meta '%s'", k));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This calculates CMH as defined above
|
||||
fn crate_meta_extras_hash(sha1 sha, &ast::crate crate) -> str {
|
||||
fn lteq(&@ast::meta_item ma,
|
||||
&@ast::meta_item mb) -> bool {
|
||||
fn lteq(&@ast::meta_item ma, &@ast::meta_item mb) -> bool {
|
||||
ret ma.node.key <= mb.node.key;
|
||||
}
|
||||
|
||||
fn len_and_str(&str s) -> str {
|
||||
ret #fmt("%u_%s", str::byte_len(s), s);
|
||||
}
|
||||
|
||||
let vec[mutable @ast::meta_item] v = [mutable];
|
||||
fn len_and_str(&str s) -> str { ret #fmt("%u_%s", str::byte_len(s), s); }
|
||||
let vec[mutable @ast::meta_item] v = [mutable ];
|
||||
for each (@ast::meta_item mi in crate_export_metas(crate)) {
|
||||
if (mi.node.key != "name" &&
|
||||
mi.node.key != "vers") {
|
||||
if (mi.node.key != "name" && mi.node.key != "vers") {
|
||||
v += [mutable mi];
|
||||
}
|
||||
}
|
||||
|
@ -365,10 +317,10 @@ fn crate_meta_extras_hash(sha1 sha, &ast::crate crate) -> str {
|
|||
ret truncated_sha1_result(sha);
|
||||
}
|
||||
|
||||
fn crate_meta_name(&session::session sess, &ast::crate crate,
|
||||
&str output) -> str {
|
||||
fn crate_meta_name(&session::session sess, &ast::crate crate, &str output) ->
|
||||
str {
|
||||
auto os = str::split(fs::basename(output), '.' as u8);
|
||||
assert vec::len(os) >= 2u;
|
||||
assert (vec::len(os) >= 2u);
|
||||
vec::pop(os);
|
||||
ret get_crate_meta_export(sess, crate, "name", str::connect(os, "."),
|
||||
sess.get_opts().shared);
|
||||
|
@ -384,15 +336,16 @@ fn truncated_sha1_result(sha1 sha) -> str {
|
|||
}
|
||||
|
||||
|
||||
|
||||
// This calculates STH for a symbol, as defined above
|
||||
fn symbol_hash(ty::ctxt tcx, sha1 sha, &ty::t t,
|
||||
str crate_meta_name,
|
||||
fn symbol_hash(ty::ctxt tcx, sha1 sha, &ty::t t, str crate_meta_name,
|
||||
str crate_meta_extras_hash) -> str {
|
||||
// NB: do *not* use abbrevs here as we want the symbol names
|
||||
// to be independent of one another in the crate.
|
||||
auto cx = @rec(ds=metadata::def_to_str, tcx=tcx,
|
||||
abbrevs=metadata::ac_no_abbrevs);
|
||||
|
||||
auto cx =
|
||||
@rec(ds=metadata::def_to_str,
|
||||
tcx=tcx,
|
||||
abbrevs=metadata::ac_no_abbrevs);
|
||||
sha.reset();
|
||||
sha.input_str(crate_meta_name);
|
||||
sha.input_str("-");
|
||||
|
@ -401,6 +354,7 @@ fn symbol_hash(ty::ctxt tcx, sha1 sha, &ty::t t,
|
|||
sha.input_str(metadata::Encode::ty_str(cx, t));
|
||||
auto hash = truncated_sha1_result(sha);
|
||||
// Prefix with _ so that it never blends into adjacent digits
|
||||
|
||||
ret "_" + hash;
|
||||
}
|
||||
|
||||
|
@ -409,54 +363,49 @@ fn get_symbol_hash(&@crate_ctxt ccx, &ty::t t) -> str {
|
|||
alt (ccx.type_sha1s.find(t)) {
|
||||
case (some(?h)) { hash = h; }
|
||||
case (none) {
|
||||
hash = symbol_hash(ccx.tcx, ccx.sha, t,
|
||||
ccx.crate_meta_name,
|
||||
ccx.crate_meta_extras_hash);
|
||||
hash =
|
||||
symbol_hash(ccx.tcx, ccx.sha, t, ccx.crate_meta_name,
|
||||
ccx.crate_meta_extras_hash);
|
||||
ccx.type_sha1s.insert(t, hash);
|
||||
}
|
||||
}
|
||||
ret hash;
|
||||
}
|
||||
|
||||
|
||||
fn mangle(&vec[str] ss) -> str {
|
||||
|
||||
// Follow C++ namespace-mangling style
|
||||
|
||||
auto n = "_ZN"; // Begin name-sequence.
|
||||
|
||||
for (str s in ss) {
|
||||
n += #fmt("%u%s", str::byte_len(s), s);
|
||||
}
|
||||
|
||||
for (str s in ss) { n += #fmt("%u%s", str::byte_len(s), s); }
|
||||
n += "E"; // End name-sequence.
|
||||
|
||||
ret n;
|
||||
}
|
||||
|
||||
|
||||
fn exported_name(&vec[str] path, &str hash, &str vers) -> str {
|
||||
// FIXME: versioning isn't working yet
|
||||
|
||||
ret mangle(path + [hash]); // + "@" + vers;
|
||||
|
||||
}
|
||||
|
||||
fn mangle_exported_name(&@crate_ctxt ccx, &vec[str] path,
|
||||
&ty::t t) -> str {
|
||||
fn mangle_exported_name(&@crate_ctxt ccx, &vec[str] path, &ty::t t) -> str {
|
||||
auto hash = get_symbol_hash(ccx, t);
|
||||
ret exported_name(path, hash, ccx.crate_meta_vers);
|
||||
}
|
||||
|
||||
fn mangle_internal_name_by_type_only(&@crate_ctxt ccx, &ty::t t,
|
||||
&str name) -> str {
|
||||
fn mangle_internal_name_by_type_only(&@crate_ctxt ccx, &ty::t t, &str name) ->
|
||||
str {
|
||||
auto f = metadata::def_to_str;
|
||||
auto cx = @rec(ds=f, tcx=ccx.tcx, abbrevs=metadata::ac_no_abbrevs);
|
||||
auto s = pretty::ppaux::ty_to_short_str(ccx.tcx, t);
|
||||
|
||||
auto hash = get_symbol_hash(ccx, t);
|
||||
ret mangle([name, s, hash]);
|
||||
}
|
||||
|
||||
fn mangle_internal_name_by_path_and_seq(&@crate_ctxt ccx, &vec[str] path,
|
||||
&str flav) -> str {
|
||||
&str flav) -> str {
|
||||
ret mangle(path + [ccx.names.next(flav)]);
|
||||
}
|
||||
|
||||
|
@ -467,7 +416,6 @@ fn mangle_internal_name_by_path(&@crate_ctxt ccx, &vec[str] path) -> str {
|
|||
fn mangle_internal_name_by_seq(&@crate_ctxt ccx, &str flav) -> str {
|
||||
ret ccx.names.next(flav);
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
|
||||
import middle::trans;
|
||||
|
||||
import trans::decl_cdecl_fn;
|
||||
|
||||
import trans::T_f32;
|
||||
import trans::T_f64;
|
||||
import trans::T_fn;
|
||||
|
@ -20,49 +19,47 @@ import trans::T_str;
|
|||
import trans::T_taskptr;
|
||||
import trans::T_tydesc;
|
||||
import trans::T_void;
|
||||
|
||||
import lib::llvm::type_names;
|
||||
import lib::llvm::llvm::ModuleRef;
|
||||
import lib::llvm::llvm::ValueRef;
|
||||
import lib::llvm::llvm::TypeRef;
|
||||
|
||||
type upcalls = rec(
|
||||
ValueRef grow_task,
|
||||
ValueRef log_int,
|
||||
ValueRef log_float,
|
||||
ValueRef log_double,
|
||||
ValueRef log_str,
|
||||
ValueRef trace_word,
|
||||
ValueRef trace_str,
|
||||
ValueRef new_port,
|
||||
ValueRef del_port,
|
||||
ValueRef new_chan,
|
||||
ValueRef flush_chan,
|
||||
ValueRef del_chan,
|
||||
ValueRef clone_chan,
|
||||
ValueRef _yield,
|
||||
ValueRef sleep,
|
||||
ValueRef _join,
|
||||
ValueRef send,
|
||||
ValueRef recv,
|
||||
ValueRef _fail,
|
||||
ValueRef kill,
|
||||
ValueRef exit,
|
||||
ValueRef malloc,
|
||||
ValueRef free,
|
||||
ValueRef mark,
|
||||
ValueRef new_str,
|
||||
ValueRef new_vec,
|
||||
ValueRef vec_grow,
|
||||
ValueRef vec_append,
|
||||
ValueRef get_type_desc,
|
||||
ValueRef new_task,
|
||||
ValueRef start_task,
|
||||
ValueRef new_thread,
|
||||
ValueRef start_thread,
|
||||
ValueRef ivec_resize,
|
||||
ValueRef ivec_spill
|
||||
);
|
||||
type upcalls =
|
||||
rec(ValueRef grow_task,
|
||||
ValueRef log_int,
|
||||
ValueRef log_float,
|
||||
ValueRef log_double,
|
||||
ValueRef log_str,
|
||||
ValueRef trace_word,
|
||||
ValueRef trace_str,
|
||||
ValueRef new_port,
|
||||
ValueRef del_port,
|
||||
ValueRef new_chan,
|
||||
ValueRef flush_chan,
|
||||
ValueRef del_chan,
|
||||
ValueRef clone_chan,
|
||||
ValueRef _yield,
|
||||
ValueRef sleep,
|
||||
ValueRef _join,
|
||||
ValueRef send,
|
||||
ValueRef recv,
|
||||
ValueRef _fail,
|
||||
ValueRef kill,
|
||||
ValueRef exit,
|
||||
ValueRef malloc,
|
||||
ValueRef free,
|
||||
ValueRef mark,
|
||||
ValueRef new_str,
|
||||
ValueRef new_vec,
|
||||
ValueRef vec_grow,
|
||||
ValueRef vec_append,
|
||||
ValueRef get_type_desc,
|
||||
ValueRef new_task,
|
||||
ValueRef start_task,
|
||||
ValueRef new_thread,
|
||||
ValueRef start_thread,
|
||||
ValueRef ivec_resize,
|
||||
ValueRef ivec_spill);
|
||||
|
||||
fn declare_upcalls(type_names tn, ModuleRef llmod) -> @upcalls {
|
||||
fn decl(type_names tn, ModuleRef llmod, str name, vec[TypeRef] tys,
|
||||
|
@ -72,69 +69,67 @@ fn declare_upcalls(type_names tn, ModuleRef llmod) -> @upcalls {
|
|||
auto fn_ty = T_fn(arg_tys, rv);
|
||||
ret trans::decl_cdecl_fn(llmod, "upcall_" + name, fn_ty);
|
||||
}
|
||||
|
||||
auto dv = bind decl(tn, llmod, _, _, T_void());
|
||||
auto d = bind decl(tn, llmod, _, _, _);
|
||||
|
||||
// FIXME: Sigh:.. remove this when I fix the typechecker pushdown.
|
||||
// --pcwalton
|
||||
|
||||
let vec[TypeRef] empty_vec = [];
|
||||
|
||||
ret @rec(
|
||||
grow_task=dv("grow_task", [T_size_t()]),
|
||||
log_int=dv("log_int", [T_i32(), T_i32()]),
|
||||
log_float=dv("log_float", [T_i32(), T_f32()]),
|
||||
log_double=dv("log_double", [T_i32(), T_ptr(T_f64())]),
|
||||
log_str=dv("log_str", [T_i32(), T_ptr(T_str())]),
|
||||
trace_word=dv("trace_word", [T_int()]),
|
||||
trace_str=dv("trace_str", [T_ptr(T_i8())]),
|
||||
new_port=d("new_port", [T_size_t()], T_opaque_port_ptr()),
|
||||
del_port=dv("del_port", [T_opaque_port_ptr()]),
|
||||
new_chan=d("new_chan", [T_opaque_port_ptr()], T_opaque_chan_ptr()),
|
||||
flush_chan=dv("flush_chan", [T_opaque_chan_ptr()]),
|
||||
del_chan=dv("del_chan", [T_opaque_chan_ptr()]),
|
||||
clone_chan=d("clone_chan", [T_taskptr(tn), T_opaque_chan_ptr()],
|
||||
T_opaque_chan_ptr()),
|
||||
_yield=dv("yield", empty_vec),
|
||||
sleep=dv("sleep", [T_size_t()]),
|
||||
_join=dv("join", [T_taskptr(tn)]),
|
||||
send=dv("send", [T_opaque_chan_ptr(), T_ptr(T_i8())]),
|
||||
recv=dv("recv", [T_ptr(T_ptr(T_i8())), T_opaque_port_ptr()]),
|
||||
_fail=dv("fail", [T_ptr(T_i8()), T_ptr(T_i8()), T_size_t()]),
|
||||
kill=dv("kill", [T_taskptr(tn)]),
|
||||
exit=dv("exit", empty_vec),
|
||||
malloc=d("malloc", [T_size_t(), T_ptr(T_tydesc(tn))],
|
||||
T_ptr(T_i8())),
|
||||
free=dv("free", [T_ptr(T_i8()), T_int()]),
|
||||
mark=d("mark", [T_ptr(T_i8())], T_int()),
|
||||
new_str=d("new_str", [T_ptr(T_i8()), T_size_t()], T_ptr(T_str())),
|
||||
new_vec=d("new_vec", [T_size_t(), T_ptr(T_tydesc(tn))],
|
||||
T_opaque_vec_ptr()),
|
||||
vec_grow=d("vec_grow", [T_opaque_vec_ptr(), T_size_t(),
|
||||
T_ptr(T_int()), T_ptr(T_tydesc(tn))],
|
||||
T_opaque_vec_ptr()),
|
||||
vec_append=d("vec_append", [T_ptr(T_tydesc(tn)), T_ptr(T_tydesc(tn)),
|
||||
T_ptr(T_opaque_vec_ptr()),
|
||||
T_opaque_vec_ptr(), T_bool()], T_void()),
|
||||
get_type_desc=d("get_type_desc",
|
||||
[T_ptr(T_nil()), T_size_t(), T_size_t(),
|
||||
T_size_t(), T_ptr(T_ptr(T_tydesc(tn)))],
|
||||
T_ptr(T_tydesc(tn))),
|
||||
new_task=d("new_task", [T_ptr(T_str())], T_taskptr(tn)),
|
||||
start_task=d("start_task", [T_taskptr(tn),
|
||||
T_int(), T_int(), T_size_t()],
|
||||
T_taskptr(tn)),
|
||||
new_thread=d("new_thread", [T_ptr(T_i8())], T_taskptr(tn)),
|
||||
start_thread=d("start_thread", [T_taskptr(tn), T_int(), T_int(),
|
||||
T_int(), T_size_t()],
|
||||
T_taskptr(tn)),
|
||||
ivec_resize=d("ivec_resize", [T_ptr(T_opaque_ivec()), T_int()],
|
||||
T_void()),
|
||||
ivec_spill=d("ivec_spill", [T_ptr(T_opaque_ivec()), T_int()],
|
||||
T_void())
|
||||
);
|
||||
ret @rec(grow_task=dv("grow_task", [T_size_t()]),
|
||||
log_int=dv("log_int", [T_i32(), T_i32()]),
|
||||
log_float=dv("log_float", [T_i32(), T_f32()]),
|
||||
log_double=dv("log_double", [T_i32(), T_ptr(T_f64())]),
|
||||
log_str=dv("log_str", [T_i32(), T_ptr(T_str())]),
|
||||
trace_word=dv("trace_word", [T_int()]),
|
||||
trace_str=dv("trace_str", [T_ptr(T_i8())]),
|
||||
new_port=d("new_port", [T_size_t()], T_opaque_port_ptr()),
|
||||
del_port=dv("del_port", [T_opaque_port_ptr()]),
|
||||
new_chan=d("new_chan", [T_opaque_port_ptr()],
|
||||
T_opaque_chan_ptr()),
|
||||
flush_chan=dv("flush_chan", [T_opaque_chan_ptr()]),
|
||||
del_chan=dv("del_chan", [T_opaque_chan_ptr()]),
|
||||
clone_chan=d("clone_chan", [T_taskptr(tn), T_opaque_chan_ptr()],
|
||||
T_opaque_chan_ptr()),
|
||||
_yield=dv("yield", empty_vec),
|
||||
sleep=dv("sleep", [T_size_t()]),
|
||||
_join=dv("join", [T_taskptr(tn)]),
|
||||
send=dv("send", [T_opaque_chan_ptr(), T_ptr(T_i8())]),
|
||||
recv=dv("recv", [T_ptr(T_ptr(T_i8())), T_opaque_port_ptr()]),
|
||||
_fail=dv("fail", [T_ptr(T_i8()), T_ptr(T_i8()), T_size_t()]),
|
||||
kill=dv("kill", [T_taskptr(tn)]),
|
||||
exit=dv("exit", empty_vec),
|
||||
malloc=d("malloc", [T_size_t(), T_ptr(T_tydesc(tn))],
|
||||
T_ptr(T_i8())),
|
||||
free=dv("free", [T_ptr(T_i8()), T_int()]),
|
||||
mark=d("mark", [T_ptr(T_i8())], T_int()),
|
||||
new_str=d("new_str", [T_ptr(T_i8()), T_size_t()],
|
||||
T_ptr(T_str())),
|
||||
new_vec=d("new_vec", [T_size_t(), T_ptr(T_tydesc(tn))],
|
||||
T_opaque_vec_ptr()),
|
||||
vec_grow=d("vec_grow",
|
||||
[T_opaque_vec_ptr(), T_size_t(), T_ptr(T_int()),
|
||||
T_ptr(T_tydesc(tn))], T_opaque_vec_ptr()),
|
||||
vec_append=d("vec_append",
|
||||
[T_ptr(T_tydesc(tn)), T_ptr(T_tydesc(tn)),
|
||||
T_ptr(T_opaque_vec_ptr()), T_opaque_vec_ptr(),
|
||||
T_bool()], T_void()),
|
||||
get_type_desc=d("get_type_desc",
|
||||
[T_ptr(T_nil()), T_size_t(), T_size_t(),
|
||||
T_size_t(), T_ptr(T_ptr(T_tydesc(tn)))],
|
||||
T_ptr(T_tydesc(tn))),
|
||||
new_task=d("new_task", [T_ptr(T_str())], T_taskptr(tn)),
|
||||
start_task=d("start_task",
|
||||
[T_taskptr(tn), T_int(), T_int(), T_size_t()],
|
||||
T_taskptr(tn)),
|
||||
new_thread=d("new_thread", [T_ptr(T_i8())], T_taskptr(tn)),
|
||||
start_thread=d("start_thread",
|
||||
[T_taskptr(tn), T_int(), T_int(), T_int(),
|
||||
T_size_t()], T_taskptr(tn)),
|
||||
ivec_resize=d("ivec_resize", [T_ptr(T_opaque_ivec()), T_int()],
|
||||
T_void()),
|
||||
ivec_spill=d("ivec_spill", [T_ptr(T_opaque_ivec()), T_int()],
|
||||
T_void()));
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
import lib::llvm::llvm;
|
||||
import lib::llvm::llvm::ModuleRef;
|
||||
import std::str;
|
||||
|
@ -5,43 +6,33 @@ import std::vec;
|
|||
import std::os::target_os;
|
||||
import util::common::istr;
|
||||
|
||||
fn get_module_asm() -> str {
|
||||
ret "";
|
||||
}
|
||||
fn get_module_asm() -> str { ret ""; }
|
||||
|
||||
fn get_meta_sect_name() -> str {
|
||||
if (str::eq(target_os(), "macos")) {
|
||||
ret "__DATA,__note.rustc";
|
||||
}
|
||||
if (str::eq(target_os(), "win32")) {
|
||||
ret ".note.rustc";
|
||||
}
|
||||
if (str::eq(target_os(), "macos")) { ret "__DATA,__note.rustc"; }
|
||||
if (str::eq(target_os(), "win32")) { ret ".note.rustc"; }
|
||||
ret ".note.rustc";
|
||||
}
|
||||
|
||||
fn get_data_layout() -> str {
|
||||
if (str::eq(target_os(), "macos")) {
|
||||
ret "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64" +
|
||||
"-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" +
|
||||
"-n8:16:32";
|
||||
ret "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16"
|
||||
+ "-i32:32:32-i64:32:64"
|
||||
+ "-f32:32:32-f64:32:64-v64:64:64"
|
||||
+ "-v128:128:128-a0:0:64-f80:128:128"
|
||||
+ "-n8:16:32";
|
||||
}
|
||||
if (str::eq(target_os(), "win32")) {
|
||||
ret "e-p:32:32-f64:64:64-i64:64:64-f80:32:32-n8:16:32";
|
||||
ret "e-p:32:32-f64:64:64-i64:64:64-f80:32:32-n8:16:32";
|
||||
}
|
||||
ret "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32";
|
||||
}
|
||||
|
||||
fn get_target_triple() -> str {
|
||||
if (str::eq(target_os(), "macos")) {
|
||||
ret "i686-apple-darwin";
|
||||
}
|
||||
if (str::eq(target_os(), "win32")) {
|
||||
ret "i686-pc-mingw32";
|
||||
}
|
||||
if (str::eq(target_os(), "macos")) { ret "i686-apple-darwin"; }
|
||||
if (str::eq(target_os(), "win32")) { ret "i686-pc-mingw32"; }
|
||||
ret "i686-unknown-linux-gnu";
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// -*- rust -*-
|
||||
|
||||
|
||||
// -*- rust -*-
|
||||
import front::creader;
|
||||
import front::parser;
|
||||
import front::token;
|
||||
|
@ -15,7 +16,6 @@ import pretty::ppaux;
|
|||
import back::link;
|
||||
import lib::llvm;
|
||||
import util::common;
|
||||
|
||||
import std::fs;
|
||||
import std::map::mk_hashmap;
|
||||
import std::option;
|
||||
|
@ -25,99 +25,78 @@ import std::str;
|
|||
import std::vec;
|
||||
import std::io;
|
||||
import std::run;
|
||||
|
||||
import std::getopts;
|
||||
import std::getopts::optopt;
|
||||
import std::getopts::optmulti;
|
||||
import std::getopts::optflag;
|
||||
import std::getopts::optflagopt;
|
||||
import std::getopts::opt_present;
|
||||
|
||||
import back::link::output_type;
|
||||
|
||||
tag pp_mode {
|
||||
ppm_normal;
|
||||
ppm_typed;
|
||||
ppm_identified;
|
||||
}
|
||||
tag pp_mode { ppm_normal; ppm_typed; ppm_identified; }
|
||||
|
||||
fn default_environment(session::session sess,
|
||||
str argv0,
|
||||
str input) -> eval::env {
|
||||
|
||||
auto libc = alt (sess.get_targ_cfg().os) {
|
||||
case (session::os_win32) { "msvcrt.dll" }
|
||||
case (session::os_macos) { "libc.dylib" }
|
||||
case (session::os_linux) { "libc.so.6" }
|
||||
case (_) { "libc.so" }
|
||||
};
|
||||
|
||||
ret [// Target bindings.
|
||||
fn default_environment(session::session sess, str argv0, str input) ->
|
||||
eval::env {
|
||||
auto libc =
|
||||
alt (sess.get_targ_cfg().os) {
|
||||
case (session::os_win32) { "msvcrt.dll" }
|
||||
case (session::os_macos) { "libc.dylib" }
|
||||
case (session::os_linux) { "libc.so.6" }
|
||||
case (_) { "libc.so" }
|
||||
};
|
||||
ret [ // Target bindings.
|
||||
tup("target_os", eval::val_str(std::os::target_os())),
|
||||
tup("target_arch", eval::val_str("x86")),
|
||||
tup("target_libc", eval::val_str(libc)),
|
||||
|
||||
// Build bindings.
|
||||
tup("build_compiler", eval::val_str(argv0)),
|
||||
tup("build_input", eval::val_str(input))
|
||||
];
|
||||
tup("build_input", eval::val_str(input))];
|
||||
}
|
||||
|
||||
fn parse_input(session::session sess,
|
||||
parser::parser p,
|
||||
str input) -> @ast::crate {
|
||||
fn parse_input(session::session sess, parser::parser p, str input) ->
|
||||
@ast::crate {
|
||||
ret if (str::ends_with(input, ".rc")) {
|
||||
parser::parse_crate_from_crate_file(p)
|
||||
} else if (str::ends_with(input, ".rs")) {
|
||||
parser::parse_crate_from_source_file(p)
|
||||
} else {
|
||||
sess.err("unknown input file type: " + input);
|
||||
fail
|
||||
};
|
||||
parser::parse_crate_from_crate_file(p)
|
||||
} else if (str::ends_with(input, ".rs")) {
|
||||
parser::parse_crate_from_source_file(p)
|
||||
} else { sess.err("unknown input file type: " + input); fail };
|
||||
}
|
||||
|
||||
fn time[T](bool do_it, str what, fn()->T thunk) -> T {
|
||||
fn time[T](bool do_it, str what, fn() -> T thunk) -> T {
|
||||
if (!do_it) { ret thunk(); }
|
||||
|
||||
auto start = std::time::get_time();
|
||||
auto rv = thunk();
|
||||
auto end = std::time::get_time();
|
||||
|
||||
// FIXME: Actually do timeval math.
|
||||
log_err #fmt("time: %s took %u s", what, (end.sec - start.sec) as uint);
|
||||
|
||||
log_err #fmt("time: %s took %u s", what, end.sec - start.sec as uint);
|
||||
ret rv;
|
||||
}
|
||||
|
||||
fn compile_input(session::session sess,
|
||||
eval::env env,
|
||||
str input, str output) {
|
||||
fn compile_input(session::session sess, eval::env env, str input,
|
||||
str output) {
|
||||
auto time_passes = sess.get_opts().time_passes;
|
||||
auto def = tup(ast::local_crate, 0);
|
||||
auto p = parser::new_parser(sess, env, def, input, 0u, 0u);
|
||||
auto crate = time(time_passes, "parsing",
|
||||
bind parse_input(sess, p, input));
|
||||
if (sess.get_opts().output_type == link::output_type_none) {ret;}
|
||||
|
||||
auto def_map = time(time_passes, "resolution",
|
||||
bind resolve::resolve_crate(sess, crate));
|
||||
|
||||
auto crate =
|
||||
time(time_passes, "parsing", bind parse_input(sess, p, input));
|
||||
if (sess.get_opts().output_type == link::output_type_none) { ret; }
|
||||
auto def_map =
|
||||
time(time_passes, "resolution",
|
||||
bind resolve::resolve_crate(sess, crate));
|
||||
auto ty_cx = ty::mk_ctxt(sess, def_map);
|
||||
time[()](time_passes, "typechecking",
|
||||
bind typeck::check_crate(ty_cx, crate));
|
||||
|
||||
if (sess.get_opts().run_typestate) {
|
||||
time(time_passes, "typestate checking",
|
||||
bind middle::tstate::ck::check_crate(ty_cx, crate));
|
||||
}
|
||||
|
||||
time(time_passes, "alias checking",
|
||||
bind middle::alias::check_crate(@ty_cx, def_map, crate));
|
||||
|
||||
auto llmod =
|
||||
time[llvm::llvm::ModuleRef](time_passes, "translation",
|
||||
bind trans::trans_crate(sess, crate,
|
||||
ty_cx, output));
|
||||
|
||||
time[()](time_passes, "LLVM passes",
|
||||
bind link::write::run_passes(sess, llmod, output));
|
||||
}
|
||||
|
@ -127,7 +106,6 @@ fn pretty_print_input(session::session sess, eval::env env, str input,
|
|||
auto def = tup(ast::local_crate, 0);
|
||||
auto p = front::parser::new_parser(sess, env, def, input, 0u, 0u);
|
||||
auto crate = parse_input(sess, p, input);
|
||||
|
||||
auto mode;
|
||||
alt (ppm) {
|
||||
case (ppm_typed) {
|
||||
|
@ -139,7 +117,6 @@ fn pretty_print_input(session::session sess, eval::env env, str input,
|
|||
case (ppm_normal) { mode = ppaux::mo_untyped; }
|
||||
case (ppm_identified) { mode = ppaux::mo_identified; }
|
||||
}
|
||||
|
||||
pprust::print_file(sess, crate.node.module, input, std::io::stdout(),
|
||||
mode);
|
||||
}
|
||||
|
@ -147,14 +124,13 @@ fn pretty_print_input(session::session sess, eval::env env, str input,
|
|||
fn version(str argv0) {
|
||||
auto vers = "unknown version";
|
||||
auto env_vers = #env("CFG_VERSION");
|
||||
if (str::byte_len(env_vers) != 0u) {
|
||||
vers = env_vers;
|
||||
}
|
||||
if (str::byte_len(env_vers) != 0u) { vers = env_vers; }
|
||||
io::stdout().write_str(#fmt("%s %s\n", argv0, vers));
|
||||
}
|
||||
|
||||
fn usage(str argv0) {
|
||||
io::stdout().write_str(#fmt("usage: %s [options] <input>\n", argv0) + "
|
||||
io::stdout().write_str(#fmt("usage: %s [options] <input>\n", argv0) +
|
||||
"
|
||||
options:
|
||||
|
||||
-h --help display this message
|
||||
|
@ -185,35 +161,27 @@ options:
|
|||
|
||||
fn get_os(str triple) -> session::os {
|
||||
ret if (str::find(triple, "win32") >= 0 ||
|
||||
str::find(triple, "mingw32") >= 0 ) {
|
||||
session::os_win32
|
||||
} else if (str::find(triple, "darwin") >= 0) {
|
||||
session::os_macos
|
||||
} else if (str::find(triple, "linux") >= 0) {
|
||||
session::os_linux
|
||||
} else {
|
||||
log_err "Unknown operating system!";
|
||||
fail
|
||||
};
|
||||
str::find(triple, "mingw32") >= 0) {
|
||||
session::os_win32
|
||||
} else if (str::find(triple, "darwin") >= 0) {
|
||||
session::os_macos
|
||||
} else if (str::find(triple, "linux") >= 0) {
|
||||
session::os_linux
|
||||
} else { log_err "Unknown operating system!"; fail };
|
||||
}
|
||||
|
||||
fn get_arch(str triple) -> session::arch {
|
||||
ret if (str::find(triple, "i386") >= 0 ||
|
||||
str::find(triple, "i486") >= 0 ||
|
||||
str::find(triple, "i586") >= 0 ||
|
||||
str::find(triple, "i686") >= 0 ||
|
||||
str::find(triple, "i786") >= 0 ) {
|
||||
session::arch_x86
|
||||
} else if (str::find(triple, "x86_64") >= 0) {
|
||||
session::arch_x64
|
||||
} else if (str::find(triple, "arm") >= 0 ||
|
||||
str::find(triple, "xscale") >= 0 ) {
|
||||
session::arch_arm
|
||||
}
|
||||
else {
|
||||
log_err ("Unknown architecture! " + triple);
|
||||
fail
|
||||
};
|
||||
ret if (str::find(triple, "i386") >= 0 || str::find(triple, "i486") >= 0
|
||||
|| str::find(triple, "i586") >= 0 ||
|
||||
str::find(triple, "i686") >= 0 ||
|
||||
str::find(triple, "i786") >= 0) {
|
||||
session::arch_x86
|
||||
} else if (str::find(triple, "x86_64") >= 0) {
|
||||
session::arch_x64
|
||||
} else if (str::find(triple, "arm") >= 0 ||
|
||||
str::find(triple, "xscale") >= 0) {
|
||||
session::arch_arm
|
||||
} else { log_err "Unknown architecture! " + triple; fail };
|
||||
}
|
||||
|
||||
fn get_default_sysroot(str binary) -> str {
|
||||
|
@ -225,34 +193,29 @@ fn get_default_sysroot(str binary) -> str {
|
|||
fn build_target_config() -> @session::config {
|
||||
let str triple =
|
||||
std::str::rustrt::str_from_cstr(llvm::llvm::LLVMRustGetHostTriple());
|
||||
|
||||
let @session::config target_cfg =
|
||||
@rec(os = get_os(triple),
|
||||
arch = get_arch(triple),
|
||||
int_type = common::ty_i32,
|
||||
uint_type = common::ty_u32,
|
||||
float_type = common::ty_f64);
|
||||
|
||||
@rec(os=get_os(triple),
|
||||
arch=get_arch(triple),
|
||||
int_type=common::ty_i32,
|
||||
uint_type=common::ty_u32,
|
||||
float_type=common::ty_f64);
|
||||
ret target_cfg;
|
||||
}
|
||||
|
||||
fn build_session_options(str binary, getopts::match match)
|
||||
-> @session::options {
|
||||
fn build_session_options(str binary, getopts::match match) ->
|
||||
@session::options {
|
||||
auto shared = opt_present(match, "shared");
|
||||
auto library_search_paths = getopts::opt_strs(match, "L");
|
||||
|
||||
auto output_type = if (opt_present(match, "parse-only")) {
|
||||
link::output_type_none
|
||||
} else if (opt_present(match, "S")) {
|
||||
link::output_type_assembly
|
||||
} else if (opt_present(match, "c")) {
|
||||
link::output_type_object
|
||||
} else if (opt_present(match, "emit-llvm")) {
|
||||
link::output_type_bitcode
|
||||
} else {
|
||||
link::output_type_exe
|
||||
};
|
||||
|
||||
auto output_type =
|
||||
if (opt_present(match, "parse-only")) {
|
||||
link::output_type_none
|
||||
} else if (opt_present(match, "S")) {
|
||||
link::output_type_assembly
|
||||
} else if (opt_present(match, "c")) {
|
||||
link::output_type_object
|
||||
} else if (opt_present(match, "emit-llvm")) {
|
||||
link::output_type_bitcode
|
||||
} else { link::output_type_exe };
|
||||
auto verify = !opt_present(match, "noverify");
|
||||
auto save_temps = opt_present(match, "save-temps");
|
||||
auto debuginfo = opt_present(match, "g");
|
||||
|
@ -261,47 +224,44 @@ fn build_session_options(str binary, getopts::match match)
|
|||
auto time_llvm_passes = opt_present(match, "time-llvm-passes");
|
||||
auto run_typestate = !opt_present(match, "no-typestate");
|
||||
auto sysroot_opt = getopts::opt_maybe_str(match, "sysroot");
|
||||
|
||||
let uint opt_level = if (opt_present(match, "O")) {
|
||||
if (opt_present(match, "OptLevel")) {
|
||||
log_err "error: -O and --OptLevel both provided";
|
||||
fail;
|
||||
}
|
||||
2u
|
||||
} else if (opt_present(match, "OptLevel")) {
|
||||
alt (getopts::opt_str(match, "OptLevel")) {
|
||||
case ("0") { 0u }
|
||||
case ("1") { 1u }
|
||||
case ("2") { 2u }
|
||||
case ("3") { 3u }
|
||||
case (_) {
|
||||
log_err "error: optimization level needs to be between 0-3";
|
||||
fail
|
||||
let uint opt_level =
|
||||
if (opt_present(match, "O")) {
|
||||
if (opt_present(match, "OptLevel")) {
|
||||
log_err "error: -O and --OptLevel both provided";
|
||||
fail;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
0u
|
||||
};
|
||||
|
||||
auto sysroot = alt (sysroot_opt) {
|
||||
case (none) { get_default_sysroot(binary) }
|
||||
case (some(?s)) { s }
|
||||
};
|
||||
|
||||
2u
|
||||
} else if (opt_present(match, "OptLevel")) {
|
||||
alt (getopts::opt_str(match, "OptLevel")) {
|
||||
case ("0") { 0u }
|
||||
case ("1") { 1u }
|
||||
case ("2") { 2u }
|
||||
case ("3") { 3u }
|
||||
case (_) {
|
||||
log_err "error: optimization level needs " +
|
||||
"to be between 0-3";
|
||||
fail
|
||||
}
|
||||
}
|
||||
} else { 0u };
|
||||
auto sysroot =
|
||||
alt (sysroot_opt) {
|
||||
case (none) { get_default_sysroot(binary) }
|
||||
case (some(?s)) { s }
|
||||
};
|
||||
let @session::options sopts =
|
||||
@rec(shared = shared,
|
||||
optimize = opt_level,
|
||||
debuginfo = debuginfo,
|
||||
verify = verify,
|
||||
run_typestate = run_typestate,
|
||||
save_temps = save_temps,
|
||||
stats = stats,
|
||||
time_passes = time_passes,
|
||||
time_llvm_passes = time_llvm_passes,
|
||||
output_type = output_type,
|
||||
library_search_paths = library_search_paths,
|
||||
sysroot = sysroot);
|
||||
|
||||
@rec(shared=shared,
|
||||
optimize=opt_level,
|
||||
debuginfo=debuginfo,
|
||||
verify=verify,
|
||||
run_typestate=run_typestate,
|
||||
save_temps=save_temps,
|
||||
stats=stats,
|
||||
time_passes=time_passes,
|
||||
time_llvm_passes=time_llvm_passes,
|
||||
output_type=output_type,
|
||||
library_search_paths=library_search_paths,
|
||||
sysroot=sysroot);
|
||||
ret sopts;
|
||||
}
|
||||
|
||||
|
@ -311,61 +271,51 @@ fn build_session(@session::options sopts) -> session::session {
|
|||
auto target_crate_num = 0;
|
||||
let vec[@ast::meta_item] md = [];
|
||||
auto sess =
|
||||
session::session(target_crate_num, target_cfg, sopts,
|
||||
crate_cache, md, front::codemap::new_codemap());
|
||||
session::session(target_crate_num, target_cfg, sopts, crate_cache, md,
|
||||
front::codemap::new_codemap());
|
||||
ret sess;
|
||||
}
|
||||
|
||||
fn parse_pretty(session::session sess, &str name) -> pp_mode {
|
||||
if (str::eq(name, "normal")) { ret ppm_normal; }
|
||||
else if (str::eq(name, "typed")) { ret ppm_typed; }
|
||||
else if (str::eq(name, "identified")) { ret ppm_identified; }
|
||||
|
||||
if (str::eq(name, "normal")) {
|
||||
ret ppm_normal;
|
||||
} else if (str::eq(name, "typed")) {
|
||||
ret ppm_typed;
|
||||
} else if (str::eq(name, "identified")) { ret ppm_identified; }
|
||||
sess.err("argument to `pretty` must be one of `normal`, `typed`, or " +
|
||||
"`identified`");
|
||||
"`identified`");
|
||||
}
|
||||
|
||||
fn main(vec[str] args) {
|
||||
|
||||
auto opts = [optflag("h"), optflag("help"),
|
||||
optflag("v"), optflag("version"),
|
||||
optflag("glue"), optflag("emit-llvm"),
|
||||
optflagopt("pretty"),
|
||||
optflag("ls"), optflag("parse-only"),
|
||||
optflag("O"), optopt("OptLevel"),
|
||||
optflag("shared"), optmulti("L"),
|
||||
optflag("S"), optflag("c"), optopt("o"), optflag("g"),
|
||||
optflag("save-temps"), optopt("sysroot"),
|
||||
optflag("stats"),
|
||||
optflag("time-passes"), optflag("time-llvm-passes"),
|
||||
optflag("no-typestate"), optflag("noverify")];
|
||||
|
||||
auto opts =
|
||||
[optflag("h"), optflag("help"), optflag("v"), optflag("version"),
|
||||
optflag("glue"), optflag("emit-llvm"), optflagopt("pretty"),
|
||||
optflag("ls"), optflag("parse-only"), optflag("O"),
|
||||
optopt("OptLevel"), optflag("shared"), optmulti("L"), optflag("S"),
|
||||
optflag("c"), optopt("o"), optflag("g"), optflag("save-temps"),
|
||||
optopt("sysroot"), optflag("stats"), optflag("time-passes"),
|
||||
optflag("time-llvm-passes"), optflag("no-typestate"),
|
||||
optflag("noverify")];
|
||||
auto binary = vec::shift[str](args);
|
||||
auto match = alt (getopts::getopts(args, opts)) {
|
||||
case (getopts::success(?m)) { m }
|
||||
case (getopts::failure(?f)) {
|
||||
log_err #fmt("error: %s", getopts::fail_str(f));
|
||||
fail
|
||||
}
|
||||
};
|
||||
|
||||
if (opt_present(match, "h") ||
|
||||
opt_present(match, "help")) {
|
||||
auto match =
|
||||
alt (getopts::getopts(args, opts)) {
|
||||
case (getopts::success(?m)) { m }
|
||||
case (getopts::failure(?f)) {
|
||||
log_err #fmt("error: %s", getopts::fail_str(f));
|
||||
fail
|
||||
}
|
||||
};
|
||||
if (opt_present(match, "h") || opt_present(match, "help")) {
|
||||
usage(binary);
|
||||
ret;
|
||||
}
|
||||
|
||||
if (opt_present(match, "v") ||
|
||||
opt_present(match, "version")) {
|
||||
if (opt_present(match, "v") || opt_present(match, "version")) {
|
||||
version(binary);
|
||||
ret;
|
||||
}
|
||||
|
||||
auto sopts = build_session_options(binary, match);
|
||||
auto sess = build_session(sopts);
|
||||
|
||||
auto n_inputs = vec::len[str](match.free);
|
||||
|
||||
auto output_file = getopts::opt_maybe_str(match, "o");
|
||||
auto glue = opt_present(match, "glue");
|
||||
if (glue) {
|
||||
|
@ -376,33 +326,30 @@ fn main(vec[str] args) {
|
|||
middle::trans::make_common_glue(sess, out);
|
||||
ret;
|
||||
}
|
||||
|
||||
if (n_inputs == 0u) {
|
||||
sess.err("No input filename given.");
|
||||
} else if (n_inputs > 1u) {
|
||||
sess.err("Multiple input filenames provided.");
|
||||
}
|
||||
|
||||
auto ifile = match.free.(0);
|
||||
let str saved_out_filename = "";
|
||||
auto env = default_environment(sess, binary, ifile);
|
||||
auto pretty = option::map[str,pp_mode](bind parse_pretty(sess, _),
|
||||
getopts::opt_default(match, "pretty", "normal"));
|
||||
auto pretty =
|
||||
option::map[str,
|
||||
pp_mode](bind parse_pretty(sess, _),
|
||||
getopts::opt_default(match, "pretty", "normal"));
|
||||
auto ls = opt_present(match, "ls");
|
||||
|
||||
alt (pretty) {
|
||||
case (some[pp_mode](?ppm)) {
|
||||
pretty_print_input(sess, env, ifile, ppm);
|
||||
ret;
|
||||
}
|
||||
case (none[pp_mode]) { /* continue */ }
|
||||
case (none[pp_mode]) {/* continue */ }
|
||||
}
|
||||
|
||||
if (ls) {
|
||||
front::creader::list_file_metadata(ifile, std::io::stdout());
|
||||
ret;
|
||||
}
|
||||
|
||||
alt (output_file) {
|
||||
case (none) {
|
||||
let vec[str] parts = str::split(ifile, '.' as u8);
|
||||
|
@ -412,9 +359,11 @@ fn main(vec[str] args) {
|
|||
case (link::output_type_none) { parts += ["pp"]; }
|
||||
case (link::output_type_bitcode) { parts += ["bc"]; }
|
||||
case (link::output_type_assembly) { parts += ["s"]; }
|
||||
|
||||
// Object and exe output both use the '.o' extension here
|
||||
case (link::output_type_object) { parts += ["o"]; }
|
||||
case (
|
||||
// Object and exe output both use the '.o' extension here
|
||||
link::output_type_object) {
|
||||
parts += ["o"];
|
||||
}
|
||||
case (link::output_type_exe) { parts += ["o"]; }
|
||||
}
|
||||
auto ofile = str::connect(parts, ".");
|
||||
|
@ -422,18 +371,17 @@ fn main(vec[str] args) {
|
|||
}
|
||||
case (some(?ofile)) {
|
||||
// FIXME: what about windows? This will create a foo.exe.o.
|
||||
|
||||
saved_out_filename = ofile;
|
||||
auto temp_filename;
|
||||
alt (sopts.output_type) {
|
||||
case (link::output_type_exe) {
|
||||
// FIXME: what about shared?
|
||||
|
||||
temp_filename = ofile + ".o";
|
||||
}
|
||||
case (_) {
|
||||
temp_filename = ofile;
|
||||
}
|
||||
case (_) { temp_filename = ofile; }
|
||||
}
|
||||
|
||||
compile_input(sess, env, ifile, temp_filename);
|
||||
}
|
||||
}
|
||||
|
@ -449,41 +397,42 @@ fn main(vec[str] args) {
|
|||
let str stage = "-L" + binary_dir;
|
||||
let vec[str] gcc_args;
|
||||
let str prog = "gcc";
|
||||
|
||||
// The invocations of gcc share some flags across platforms
|
||||
let vec[str] common_cflags = ["-fno-strict-aliasing", "-fPIC",
|
||||
"-Wall", "-fno-rtti", "-fno-exceptions", "-g"];
|
||||
let vec[str] common_libs = [stage, "-Lrustllvm", "-Lrt",
|
||||
"-lrustrt", "-lrustllvm", "-lstd", "-lm"];
|
||||
|
||||
let vec[str] common_cflags =
|
||||
["-fno-strict-aliasing", "-fPIC", "-Wall", "-fno-rtti",
|
||||
"-fno-exceptions", "-g"];
|
||||
let vec[str] common_libs =
|
||||
[stage, "-Lrustllvm", "-Lrt", "-lrustrt", "-lrustllvm", "-lstd",
|
||||
"-lm"];
|
||||
alt (sess.get_targ_cfg().os) {
|
||||
case (session::os_win32) {
|
||||
gcc_args = common_cflags + [
|
||||
"-march=i686", "-O2",
|
||||
glu, main, "-o",
|
||||
saved_out_filename,
|
||||
saved_out_filename + ".o"] + common_libs;
|
||||
gcc_args =
|
||||
common_cflags +
|
||||
["-march=i686", "-O2", glu, main, "-o",
|
||||
saved_out_filename, saved_out_filename + ".o"] +
|
||||
common_libs;
|
||||
}
|
||||
case (session::os_macos) {
|
||||
gcc_args = common_cflags + [
|
||||
"-arch i386", "-O0", "-m32",
|
||||
glu, main, "-o",
|
||||
saved_out_filename,
|
||||
saved_out_filename + ".o"] + common_libs;
|
||||
gcc_args =
|
||||
common_cflags +
|
||||
["-arch i386", "-O0", "-m32", glu, main, "-o",
|
||||
saved_out_filename, saved_out_filename + ".o"] +
|
||||
common_libs;
|
||||
}
|
||||
case (session::os_linux) {
|
||||
gcc_args = common_cflags + [
|
||||
"-march=i686", "-O2", "-m32",
|
||||
glu, main, "-o",
|
||||
saved_out_filename,
|
||||
saved_out_filename + ".o"] + common_libs;
|
||||
gcc_args =
|
||||
common_cflags +
|
||||
["-march=i686", "-O2", "-m32", glu, main, "-o",
|
||||
saved_out_filename, saved_out_filename + ".o"] +
|
||||
common_libs;
|
||||
}
|
||||
}
|
||||
|
||||
// We run 'gcc' here
|
||||
run::run_program(prog, gcc_args);
|
||||
|
||||
run::run_program(prog, gcc_args);
|
||||
// Clean up on Darwin
|
||||
|
||||
if (sess.get_targ_cfg().os == session::os_macos) {
|
||||
run::run_program("dsymutil", [saved_out_filename]);
|
||||
}
|
||||
|
@ -494,7 +443,6 @@ fn main(vec[str] args) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
// fill-column: 78;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
import front::ast;
|
||||
import front::codemap;
|
||||
import util::common::span;
|
||||
|
@ -10,163 +11,112 @@ import std::option;
|
|||
import std::option::some;
|
||||
import std::option::none;
|
||||
|
||||
tag os {
|
||||
os_win32;
|
||||
os_macos;
|
||||
os_linux;
|
||||
}
|
||||
tag os { os_win32; os_macos; os_linux; }
|
||||
|
||||
tag arch {
|
||||
arch_x86;
|
||||
arch_x64;
|
||||
arch_arm;
|
||||
}
|
||||
tag arch { arch_x86; arch_x64; arch_arm; }
|
||||
|
||||
type config = rec(os os,
|
||||
arch arch,
|
||||
ty_mach int_type,
|
||||
ty_mach uint_type,
|
||||
ty_mach float_type);
|
||||
type config =
|
||||
rec(os os,
|
||||
arch arch,
|
||||
ty_mach int_type,
|
||||
ty_mach uint_type,
|
||||
ty_mach float_type);
|
||||
|
||||
type options = rec(bool shared,
|
||||
uint optimize,
|
||||
bool debuginfo,
|
||||
bool verify,
|
||||
bool run_typestate,
|
||||
bool save_temps,
|
||||
bool stats,
|
||||
bool time_passes,
|
||||
bool time_llvm_passes,
|
||||
back::link::output_type output_type,
|
||||
vec[str] library_search_paths,
|
||||
str sysroot);
|
||||
type options =
|
||||
rec(bool shared,
|
||||
uint optimize,
|
||||
bool debuginfo,
|
||||
bool verify,
|
||||
bool run_typestate,
|
||||
bool save_temps,
|
||||
bool stats,
|
||||
bool time_passes,
|
||||
bool time_llvm_passes,
|
||||
back::link::output_type output_type,
|
||||
vec[str] library_search_paths,
|
||||
str sysroot);
|
||||
|
||||
type crate_metadata = rec(str name,
|
||||
vec[u8] data);
|
||||
type crate_metadata = rec(str name, vec[u8] data);
|
||||
|
||||
fn span_to_str(span sp, codemap::codemap cm) -> str {
|
||||
auto lo = codemap::lookup_pos(cm, sp.lo);
|
||||
auto hi = codemap::lookup_pos(cm, sp.hi);
|
||||
ret (#fmt("%s:%u:%u:%u:%u", lo.filename, lo.line,
|
||||
lo.col, hi.line, hi.col));
|
||||
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::codemap cm) {
|
||||
auto ss = "<input>:0:0:0:0";
|
||||
alt (sp) {
|
||||
case (some(?ssp)) {
|
||||
ss = span_to_str(ssp, cm);
|
||||
}
|
||||
case (none) {}
|
||||
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));
|
||||
}
|
||||
|
||||
state obj session(ast::crate_num cnum,
|
||||
@config targ_cfg, @options opts,
|
||||
map::hashmap[int, crate_metadata] crates,
|
||||
mutable vec[@ast::meta_item] metadata,
|
||||
codemap::codemap cm) {
|
||||
|
||||
fn get_targ_cfg() -> @config {
|
||||
ret targ_cfg;
|
||||
}
|
||||
|
||||
fn get_opts() -> @options {
|
||||
ret opts;
|
||||
}
|
||||
|
||||
fn get_targ_crate_num() -> ast::crate_num {
|
||||
ret cnum;
|
||||
}
|
||||
|
||||
obj session(ast::crate_num cnum,
|
||||
@config targ_cfg,
|
||||
@options opts,
|
||||
map::hashmap[int, crate_metadata] crates,
|
||||
mutable vec[@ast::meta_item] metadata,
|
||||
codemap::codemap cm) {
|
||||
fn get_targ_cfg() -> @config { ret targ_cfg; }
|
||||
fn get_opts() -> @options { ret opts; }
|
||||
fn get_targ_crate_num() -> ast::crate_num { ret cnum; }
|
||||
fn span_err(span sp, str msg) -> ! {
|
||||
// FIXME: Use constants, but rustboot doesn't know how to export them.
|
||||
|
||||
emit_diagnostic(some(sp), msg, "error", 9u8, cm);
|
||||
fail;
|
||||
}
|
||||
|
||||
fn err(str msg) -> ! {
|
||||
emit_diagnostic(none[span], msg, "error", 9u8, cm);
|
||||
fail;
|
||||
}
|
||||
|
||||
fn add_metadata(vec[@ast::meta_item] data) {
|
||||
metadata = metadata + data;
|
||||
}
|
||||
fn get_metadata() -> vec[@ast::meta_item] {
|
||||
ret metadata;
|
||||
}
|
||||
|
||||
fn add_metadata(vec[@ast::meta_item] data) { metadata = metadata + data; }
|
||||
fn get_metadata() -> vec[@ast::meta_item] { ret metadata; }
|
||||
fn span_warn(span sp, str msg) {
|
||||
// FIXME: Use constants, but rustboot doesn't know how to export them.
|
||||
|
||||
emit_diagnostic(some(sp), msg, "warning", 11u8, cm);
|
||||
}
|
||||
|
||||
fn warn(str msg) {
|
||||
emit_diagnostic(none[span], msg, "warning", 11u8, cm);
|
||||
}
|
||||
|
||||
fn span_note(span sp, str msg) {
|
||||
// FIXME: Use constants, but rustboot doesn't know how to export them.
|
||||
|
||||
emit_diagnostic(some(sp), msg, "note", 10u8, cm);
|
||||
}
|
||||
|
||||
fn span_bug(span sp, str msg) -> ! {
|
||||
self.span_err(sp, #fmt("internal compiler error %s", msg));
|
||||
}
|
||||
|
||||
fn bug(str msg) -> ! {
|
||||
self.err(#fmt("internal compiler error %s", msg));
|
||||
}
|
||||
|
||||
fn span_unimpl(span sp, str msg) -> ! {
|
||||
self.span_bug(sp, "unimplemented " + msg);
|
||||
}
|
||||
|
||||
fn unimpl(str msg) -> ! {
|
||||
self.bug("unimplemented " + msg);
|
||||
}
|
||||
|
||||
fn get_external_crate(int num) -> crate_metadata {
|
||||
ret crates.get(num);
|
||||
}
|
||||
|
||||
fn unimpl(str msg) -> ! { self.bug("unimplemented " + msg); }
|
||||
fn get_external_crate(int num) -> crate_metadata { ret crates.get(num); }
|
||||
fn set_external_crate(int num, &crate_metadata metadata) {
|
||||
crates.insert(num, metadata);
|
||||
}
|
||||
|
||||
fn has_external_crate(int num) -> bool {
|
||||
ret crates.contains_key(num);
|
||||
}
|
||||
|
||||
fn get_codemap() -> codemap::codemap {
|
||||
ret cm;
|
||||
}
|
||||
|
||||
fn has_external_crate(int num) -> bool { ret crates.contains_key(num); }
|
||||
fn get_codemap() -> codemap::codemap { ret cm; }
|
||||
fn lookup_pos(uint pos) -> codemap::loc {
|
||||
ret codemap::lookup_pos(cm, pos);
|
||||
}
|
||||
|
||||
fn span_str(span sp) -> str {
|
||||
ret span_to_str(sp, self.get_codemap());
|
||||
}
|
||||
fn span_str(span sp) -> str { ret span_to_str(sp, self.get_codemap()); }
|
||||
}
|
||||
|
||||
|
||||
// Local Variables:
|
||||
// fill-column: 78;
|
||||
// indent-tabs-mode: nil
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
import std::option;
|
||||
import std::str;
|
||||
import std::vec;
|
||||
|
@ -9,15 +10,17 @@ import util::common::filename;
|
|||
type ident = str;
|
||||
|
||||
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, "::");
|
||||
}
|
||||
fn path_name(&path p) -> str { ret str::connect(p.node.idents, "::"); }
|
||||
|
||||
type crate_num = int;
|
||||
|
||||
const crate_num local_crate = 0;
|
||||
|
||||
type def_num = int;
|
||||
|
||||
type def_id = tup(crate_num, def_num);
|
||||
|
||||
type ty_param = ident;
|
||||
|
@ -33,7 +36,9 @@ tag def {
|
|||
def_const(def_id);
|
||||
def_arg(def_id);
|
||||
def_local(def_id);
|
||||
def_variant(def_id /* tag */, def_id /* variant */);
|
||||
def_variant(def_id, /* tag */def_id);
|
||||
|
||||
/* variant */
|
||||
def_ty(def_id);
|
||||
def_ty_arg(uint);
|
||||
def_binding(def_id);
|
||||
|
@ -44,9 +49,7 @@ tag def {
|
|||
|
||||
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);
|
||||
}
|
||||
case (def_variant(?tag_id, ?var_id)) { ret tup(tag_id, var_id); }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,16 +75,14 @@ fn def_id_of_def(def d) -> def_id {
|
|||
}
|
||||
|
||||
type crate = spanned[crate_];
|
||||
type crate_ = rec(vec[@crate_directive] directives,
|
||||
_mod module);
|
||||
|
||||
tag meta_visibility {
|
||||
export_meta;
|
||||
local_meta;
|
||||
}
|
||||
type crate_ = rec(vec[@crate_directive] directives, _mod module);
|
||||
|
||||
tag meta_visibility { export_meta; local_meta; }
|
||||
|
||||
tag crate_directive_ {
|
||||
cdir_expr(@expr);
|
||||
|
||||
// FIXME: cdir_let should be eliminated
|
||||
// and redirected to the use of const stmt_decls inside
|
||||
// crate directive blocks.
|
||||
|
@ -93,18 +94,19 @@ tag crate_directive_ {
|
|||
cdir_syntax(path);
|
||||
cdir_auth(path, _auth);
|
||||
}
|
||||
|
||||
type crate_directive = spanned[crate_directive_];
|
||||
|
||||
|
||||
type meta_item = spanned[meta_item_];
|
||||
|
||||
type meta_item_ = rec(ident key, str value);
|
||||
|
||||
type block = spanned[block_];
|
||||
type block_ = rec(vec[@stmt] stmts,
|
||||
option::t[@expr] expr,
|
||||
ann a);
|
||||
|
||||
type block_ = rec(vec[@stmt] stmts, option::t[@expr] expr, ann a);
|
||||
|
||||
type pat = spanned[pat_];
|
||||
|
||||
tag pat_ {
|
||||
pat_wild(ann);
|
||||
pat_bind(ident, def_id, ann);
|
||||
|
@ -112,26 +114,13 @@ tag pat_ {
|
|||
pat_tag(path, vec[@pat], ann);
|
||||
}
|
||||
|
||||
tag mutability {
|
||||
mut;
|
||||
imm;
|
||||
maybe_mut;
|
||||
}
|
||||
tag mutability { mut; imm; maybe_mut; }
|
||||
|
||||
tag layer {
|
||||
layer_value;
|
||||
layer_state;
|
||||
layer_gc;
|
||||
}
|
||||
tag layer { layer_value; layer_state; layer_gc; }
|
||||
|
||||
tag _auth {
|
||||
auth_unsafe;
|
||||
}
|
||||
tag _auth { auth_unsafe; }
|
||||
|
||||
tag proto {
|
||||
proto_iter;
|
||||
proto_fn;
|
||||
}
|
||||
tag proto { proto_iter; proto_fn; }
|
||||
|
||||
tag binop {
|
||||
add;
|
||||
|
@ -157,102 +146,85 @@ tag binop {
|
|||
|
||||
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 ">";}
|
||||
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 ">"; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
tag unop {
|
||||
box(mutability);
|
||||
deref;
|
||||
not;
|
||||
neg;
|
||||
}
|
||||
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 "-";}
|
||||
case (box(?mt)) { if (mt == mut) { ret "@mutable "; } ret "@"; }
|
||||
case (deref) { ret "*"; }
|
||||
case (not) { ret "!"; }
|
||||
case (neg) { ret "-"; }
|
||||
}
|
||||
}
|
||||
|
||||
tag mode {
|
||||
val;
|
||||
alias(bool);
|
||||
}
|
||||
tag mode { val; alias(bool); }
|
||||
|
||||
type stmt = spanned[stmt_];
|
||||
|
||||
tag stmt_ {
|
||||
stmt_decl(@decl, ann);
|
||||
stmt_expr(@expr, ann);
|
||||
|
||||
// These only exist in crate-level blocks.
|
||||
stmt_crate_directive(@crate_directive);
|
||||
}
|
||||
|
||||
tag init_op {
|
||||
init_assign;
|
||||
init_recv;
|
||||
init_move;
|
||||
}
|
||||
tag init_op { init_assign; init_recv; init_move; }
|
||||
|
||||
type initializer = rec(init_op op,
|
||||
@expr expr);
|
||||
type initializer = rec(init_op op, @expr expr);
|
||||
|
||||
type local_ =
|
||||
rec(option::t[@ty] ty,
|
||||
bool infer,
|
||||
ident ident,
|
||||
option::t[initializer] init,
|
||||
def_id id,
|
||||
ann ann);
|
||||
|
||||
type local_ = rec(option::t[@ty] ty,
|
||||
bool infer,
|
||||
ident ident,
|
||||
option::t[initializer] init,
|
||||
def_id id,
|
||||
ann ann);
|
||||
type local = spanned[@local_];
|
||||
|
||||
type decl = spanned[decl_];
|
||||
tag decl_ {
|
||||
decl_local(@local_);
|
||||
decl_item(@item);
|
||||
}
|
||||
|
||||
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 spawn_dom { dom_implicit; dom_thread; }
|
||||
|
||||
|
||||
// FIXME: temporary
|
||||
tag seq_kind {
|
||||
sk_unique;
|
||||
sk_rc;
|
||||
}
|
||||
tag seq_kind { sk_unique; sk_rc; }
|
||||
|
||||
type expr = spanned[expr_];
|
||||
|
||||
tag expr_ {
|
||||
expr_vec(vec[@expr], mutability, seq_kind, ann);
|
||||
expr_tup(vec[elt], ann);
|
||||
|
@ -273,11 +245,11 @@ tag expr_ {
|
|||
expr_alt(@expr, vec[arm], ann);
|
||||
expr_fn(_fn, ann);
|
||||
expr_block(block, ann);
|
||||
expr_move(@expr /* TODO: @expr|is_lval */, @expr, ann);
|
||||
expr_assign(@expr /* TODO: @expr|is_lval */, @expr, ann);
|
||||
expr_assign_op(binop, @expr /* TODO: @expr|is_lval */, @expr, ann);
|
||||
expr_send(@expr /* TODO: @expr|is_lval */, @expr, ann);
|
||||
expr_recv(@expr /* TODO: @expr|is_lval */, @expr, ann);
|
||||
expr_move(@expr, /* TODO: @expr|is_lval */@expr, ann);
|
||||
expr_assign(@expr, /* TODO: @expr|is_lval */@expr, ann);
|
||||
expr_assign_op(binop, @expr, /* TODO: @expr|is_lval */@expr, ann);
|
||||
expr_send(@expr, /* TODO: @expr|is_lval */@expr, ann);
|
||||
expr_recv(@expr, /* TODO: @expr|is_lval */@expr, ann);
|
||||
expr_field(@expr, ident, ann);
|
||||
expr_index(@expr, @expr, ann);
|
||||
expr_path(path, ann);
|
||||
|
@ -289,9 +261,11 @@ tag expr_ {
|
|||
expr_put(option::t[@expr], ann);
|
||||
expr_be(@expr, ann);
|
||||
expr_log(int, @expr, ann);
|
||||
/* just an assert, no significance to typestate */
|
||||
|
||||
/* just an assert, no significance to typestate */
|
||||
expr_assert(@expr, ann);
|
||||
/* preds that typestate is aware of */
|
||||
|
||||
/* preds that typestate is aware of */
|
||||
expr_check(@expr, ann);
|
||||
expr_port(ann);
|
||||
expr_chan(@expr, ann);
|
||||
|
@ -299,6 +273,7 @@ tag expr_ {
|
|||
}
|
||||
|
||||
type lit = spanned[lit_];
|
||||
|
||||
tag lit_ {
|
||||
lit_str(str, seq_kind);
|
||||
lit_char(char);
|
||||
|
@ -311,39 +286,53 @@ tag lit_ {
|
|||
lit_bool(bool);
|
||||
}
|
||||
|
||||
|
||||
// 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_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_];
|
||||
|
||||
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;
|
||||
|
||||
/* 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(util::common::ty_mach);
|
||||
ty_char;
|
||||
ty_str;
|
||||
ty_istr; // interior string
|
||||
ty_istr; // interior string
|
||||
|
||||
ty_box(mt);
|
||||
ty_vec(mt);
|
||||
ty_ivec(mt); // interior vector
|
||||
ty_ivec(mt); // interior vector
|
||||
|
||||
ty_ptr(mt);
|
||||
ty_task;
|
||||
ty_port(@ty);
|
||||
|
@ -357,6 +346,7 @@ tag ty_ {
|
|||
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
|
||||
|
@ -365,62 +355,69 @@ 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);
|
||||
}
|
||||
tag constr_arg_general_[T] { carg_base; carg_ident(T); carg_lit(@lit); }
|
||||
|
||||
type constr_arg = constr_arg_general[uint];
|
||||
|
||||
type constr_arg_use = constr_arg_general[ident];
|
||||
|
||||
type constr_arg_general[T] = spanned[constr_arg_general_[T]];
|
||||
|
||||
|
||||
// The ann field is there so that using the def_map in the type
|
||||
// context, we can get the def_id for the path.
|
||||
type constr_general[T] = rec(path path,
|
||||
vec[@constr_arg_general[T]] args,
|
||||
ann ann);
|
||||
type constr_general[T] =
|
||||
rec(path path, vec[@constr_arg_general[T]] args, ann ann);
|
||||
|
||||
type constr = spanned[constr_general[uint]];
|
||||
|
||||
type constr_use = spanned[constr_general[ident]];
|
||||
|
||||
type arg = rec(mode mode, @ty ty, ident ident, def_id id);
|
||||
type fn_decl = rec(vec[arg] inputs,
|
||||
@ty output,
|
||||
purity purity,
|
||||
controlflow cf,
|
||||
vec[@constr] constraints);
|
||||
|
||||
type fn_decl =
|
||||
rec(vec[arg] inputs,
|
||||
@ty output,
|
||||
purity purity,
|
||||
controlflow cf,
|
||||
vec[@constr] constraints);
|
||||
|
||||
tag purity {
|
||||
pure_fn; // declared with "pred"
|
||||
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
|
||||
|
||||
return; // everything else
|
||||
|
||||
}
|
||||
|
||||
type _fn = rec(fn_decl decl,
|
||||
proto proto,
|
||||
block body);
|
||||
type _fn = rec(fn_decl decl, proto proto, block body);
|
||||
|
||||
type method_ = rec(ident ident, _fn meth, def_id id, ann ann);
|
||||
|
||||
type method = spanned[method_];
|
||||
|
||||
type obj_field = rec(mutability mut, @ty ty, ident ident, def_id id, ann ann);
|
||||
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[obj_field]] fields,
|
||||
vec[@method] methods,
|
||||
// with_obj: the original object being extended, if it exists.
|
||||
option::t[@expr] with_obj);
|
||||
type _obj =
|
||||
rec(vec[obj_field] fields, vec[@method] methods, option::t[@method] dtor);
|
||||
|
||||
type _mod = rec(vec[@view_item] view_items,
|
||||
vec[@item] items);
|
||||
type anon_obj =
|
||||
rec(
|
||||
// New fields and methods, if they exist.
|
||||
option::t[vec[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;
|
||||
|
@ -429,16 +426,20 @@ tag native_abi {
|
|||
native_abi_rust_intrinsic;
|
||||
}
|
||||
|
||||
type native_mod = rec(str native_name,
|
||||
native_abi abi,
|
||||
vec[@view_item] view_items,
|
||||
vec[@native_item] items);
|
||||
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, def_id id);
|
||||
|
||||
type variant_ = rec(str name, vec[variant_arg] args, def_id id, ann ann);
|
||||
|
||||
type variant = spanned[variant_];
|
||||
|
||||
type view_item = spanned[view_item_];
|
||||
|
||||
tag view_item_ {
|
||||
view_item_use(ident, vec[@meta_item], def_id, ann);
|
||||
view_item_import(ident, vec[ident], def_id);
|
||||
|
@ -452,18 +453,16 @@ type obj_def_ids = rec(def_id ty, def_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;
|
||||
}
|
||||
tag attr_style { attr_outer; attr_inner; }
|
||||
|
||||
type attribute_ = rec(attr_style style,
|
||||
meta_item value);
|
||||
type attribute_ = rec(attr_style style, meta_item value);
|
||||
|
||||
type item = spanned[item_];
|
||||
|
||||
tag item_ {
|
||||
item_const(ident, @ty, @expr, vec[attribute], def_id, ann);
|
||||
item_fn(ident, _fn, vec[ty_param], vec[attribute], def_id, ann);
|
||||
|
@ -476,97 +475,79 @@ tag item_ {
|
|||
|
||||
fn item_ident(@item it) -> ident {
|
||||
ret alt (it.node) {
|
||||
case (item_const(?ident, _, _, _, _, _)) { ident }
|
||||
case (item_fn(?ident, _, _, _, _, _)) { ident }
|
||||
case (item_mod(?ident, _, _, _)) { ident }
|
||||
case (item_native_mod(?ident, _, _, _)) { ident }
|
||||
case (item_ty(?ident, _, _, _, _, _)) { ident }
|
||||
case (item_tag(?ident, _, _, _, _, _)) { ident }
|
||||
case (item_obj(?ident, _, _, _, _, _)) { ident }
|
||||
}
|
||||
case (item_const(?ident, _, _, _, _, _)) { ident }
|
||||
case (item_fn(?ident, _, _, _, _, _)) { ident }
|
||||
case (item_mod(?ident, _, _, _)) { ident }
|
||||
case (item_native_mod(?ident, _, _, _)) { ident }
|
||||
case (item_ty(?ident, _, _, _, _, _)) { ident }
|
||||
case (item_tag(?ident, _, _, _, _, _)) { ident }
|
||||
case (item_obj(?ident, _, _, _, _, _)) { ident }
|
||||
}
|
||||
}
|
||||
|
||||
type native_item = spanned[native_item_];
|
||||
|
||||
tag native_item_ {
|
||||
native_item_ty(ident, def_id);
|
||||
native_item_fn(ident, option::t[str],
|
||||
fn_decl, vec[ty_param], def_id, ann);
|
||||
native_item_fn(ident,
|
||||
option::t[str],
|
||||
fn_decl,
|
||||
vec[ty_param],
|
||||
def_id,
|
||||
ann);
|
||||
}
|
||||
|
||||
fn is_exported(ident i, _mod m) -> bool {
|
||||
auto nonlocal = true;
|
||||
for (@ast::item it in m.items) {
|
||||
if (item_ident(it) == i) {
|
||||
nonlocal = false;
|
||||
}
|
||||
if (item_ident(it) == i) { nonlocal = false; }
|
||||
alt (it.node) {
|
||||
case (item_tag(_, ?variants, _, _, _, _)) {
|
||||
for (variant v in variants) {
|
||||
if (v.node.name == i) {
|
||||
nonlocal = false;
|
||||
}
|
||||
if (v.node.name == i) { nonlocal = false; }
|
||||
}
|
||||
}
|
||||
case (_) {}
|
||||
case (_) { }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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 */ }
|
||||
case (_) {/* fall through */ }
|
||||
}
|
||||
}
|
||||
|
||||
// If there are no declared exports then
|
||||
// everything not imported is exported
|
||||
if (count == 0u && !nonlocal) {
|
||||
ret true;
|
||||
} else {
|
||||
ret false;
|
||||
}
|
||||
if (count == 0u && !nonlocal) { ret true; } else { ret false; }
|
||||
}
|
||||
|
||||
fn is_call_expr(@expr e) -> bool {
|
||||
alt (e.node) {
|
||||
case (expr_call(_, _, _)) {
|
||||
ret true;
|
||||
}
|
||||
case (_) {
|
||||
ret false;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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 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; }
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
|
||||
import std::vec;
|
||||
|
||||
|
||||
/* 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(str name, uint start_pos, mutable vec[uint] lines);
|
||||
|
||||
type filemap = @rec(str name,
|
||||
uint start_pos,
|
||||
mutable vec[uint] lines);
|
||||
type codemap = @rec(mutable vec[filemap] files);
|
||||
|
||||
type loc = rec(str filename, uint line, uint col);
|
||||
|
||||
fn new_codemap() -> codemap {
|
||||
|
@ -18,34 +19,27 @@ fn new_codemap() -> codemap {
|
|||
}
|
||||
|
||||
fn new_filemap(str filename, uint start_pos) -> filemap {
|
||||
ret @rec(name=filename,
|
||||
start_pos=start_pos,
|
||||
mutable lines=[0u]);
|
||||
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 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);
|
||||
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; }
|
||||
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);
|
||||
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; }
|
||||
if (f.lines.(m) > pos) { b = m; } else { a = m; }
|
||||
}
|
||||
ret rec(filename=f.name,
|
||||
line=a + 1u,
|
||||
col=pos - f.lines.(a));
|
||||
ret rec(filename=f.name, line=a + 1u, col=pos - f.lines.(a));
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// -*- rust -*-
|
||||
|
||||
|
||||
// -*- rust -*-
|
||||
import driver::session;
|
||||
import front::ast;
|
||||
import lib::llvm::False;
|
||||
|
@ -18,7 +19,6 @@ import util::common::respan;
|
|||
import util::common::a_bang;
|
||||
import util::common::a_ty;
|
||||
import util::common::may_begin_ident;
|
||||
|
||||
import std::str;
|
||||
import std::uint;
|
||||
import std::vec;
|
||||
|
@ -40,16 +40,15 @@ import std::map::hashmap;
|
|||
// contain pipe characters.
|
||||
|
||||
// Callback to translate defs to strs or back:
|
||||
type str_def = fn(str) -> ast::def_id;
|
||||
type str_def = fn(str) -> ast::def_id ;
|
||||
|
||||
type pstate = rec(vec[u8] data, int crate,
|
||||
mutable uint pos, uint len, ty::ctxt tcx);
|
||||
type pstate =
|
||||
rec(vec[u8] data, int crate, mutable uint pos, uint len, ty::ctxt tcx);
|
||||
|
||||
type ty_or_bang = util::common::ty_or_bang[ty::t];
|
||||
|
||||
fn peek(@pstate st) -> u8 {
|
||||
ret st.data.(st.pos);
|
||||
}
|
||||
fn peek(@pstate st) -> u8 { ret st.data.(st.pos); }
|
||||
|
||||
fn next(@pstate st) -> u8 {
|
||||
auto ch = st.data.(st.pos);
|
||||
st.pos = st.pos + 1u;
|
||||
|
@ -64,10 +63,10 @@ fn parse_ident(@pstate st, str_def sd, char last) -> ast::ident {
|
|||
ret res;
|
||||
}
|
||||
|
||||
fn parse_ty_data(vec[u8] data, int crate_num, uint pos, uint len,
|
||||
str_def sd, ty::ctxt tcx) -> ty::t {
|
||||
auto st = @rec(data=data, crate=crate_num,
|
||||
mutable pos=pos, len=len, tcx=tcx);
|
||||
fn parse_ty_data(vec[u8] data, int crate_num, uint pos, uint len, str_def sd,
|
||||
ty::ctxt tcx) -> ty::t {
|
||||
auto st =
|
||||
@rec(data=data, crate=crate_num, mutable pos=pos, len=len, tcx=tcx);
|
||||
auto result = parse_ty(st, sd);
|
||||
ret result;
|
||||
}
|
||||
|
@ -75,7 +74,7 @@ fn parse_ty_data(vec[u8] data, int crate_num, uint pos, uint len,
|
|||
fn parse_ty_or_bang(@pstate st, str_def sd) -> ty_or_bang {
|
||||
alt (peek(st) as char) {
|
||||
case ('!') { auto ignore = next(st); ret a_bang[ty::t]; }
|
||||
case (_) { ret a_ty[ty::t](parse_ty(st, sd)); }
|
||||
case (_) { ret a_ty[ty::t](parse_ty(st, sd)); }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,19 +82,18 @@ fn parse_constrs(@pstate st, str_def sd) -> vec[@ast::constr] {
|
|||
let vec[@ast::constr] res = [];
|
||||
alt (peek(st) as char) {
|
||||
case (':') {
|
||||
do {
|
||||
do {
|
||||
auto ignore = next(st);
|
||||
vec::push(res, parse_constr(st, sd));
|
||||
} while (peek(st) as char == ',')
|
||||
}
|
||||
case (_) {}
|
||||
case (_) { }
|
||||
}
|
||||
ret res;
|
||||
}
|
||||
|
||||
fn parse_constr(@pstate st, str_def sd) -> @ast::constr {
|
||||
st.tcx.sess.unimpl("Reading constraints "
|
||||
+ " isn't implemented");
|
||||
st.tcx.sess.unimpl("Reading constraints " + " isn't implemented");
|
||||
/*
|
||||
let vec[@ast::constr_arg] args = [];
|
||||
auto sp = rec(lo=0u,hi=0u); // FIXME
|
||||
|
@ -137,6 +135,7 @@ fn parse_constr(@pstate st, str_def sd) -> @ast::constr {
|
|||
} while (next(st) as char == ',');
|
||||
ignore = next(st) as char;
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
fn parse_ty(@pstate st, str_def sd) -> ty::t {
|
||||
|
@ -168,9 +167,7 @@ fn parse_ty(@pstate st, str_def sd) -> ty::t {
|
|||
assert (next(st) as char == '[');
|
||||
auto def = parse_def(st, sd);
|
||||
let vec[ty::t] params = [];
|
||||
while (peek(st) as char != ']') {
|
||||
params += [parse_ty(st, sd)];
|
||||
}
|
||||
while (peek(st) as char != ']') { params += [parse_ty(st, sd)]; }
|
||||
st.pos = st.pos + 1u;
|
||||
ret ty::mk_tag(st.tcx, def, params);
|
||||
}
|
||||
|
@ -185,9 +182,7 @@ fn parse_ty(@pstate st, str_def sd) -> ty::t {
|
|||
case ('T') {
|
||||
assert (next(st) as char == '[');
|
||||
let vec[ty::mt] params = [];
|
||||
while (peek(st) as char != ']') {
|
||||
params += [parse_mt(st, sd)];
|
||||
}
|
||||
while (peek(st) as char != ']') { params += [parse_mt(st, sd)]; }
|
||||
st.pos = st.pos + 1u;
|
||||
ret ty::mk_tup(st.tcx, params);
|
||||
}
|
||||
|
@ -207,13 +202,13 @@ fn parse_ty(@pstate st, str_def sd) -> ty::t {
|
|||
}
|
||||
case ('F') {
|
||||
auto func = parse_ty_fn(st, sd);
|
||||
ret ty::mk_fn(st.tcx, ast::proto_fn, func._0,
|
||||
func._1, func._2, func._3);
|
||||
ret ty::mk_fn(st.tcx, ast::proto_fn, func._0, func._1, func._2,
|
||||
func._3);
|
||||
}
|
||||
case ('W') {
|
||||
auto func = parse_ty_fn(st, sd);
|
||||
ret ty::mk_fn(st.tcx, ast::proto_iter, func._0,
|
||||
func._1, func._2, func._3);
|
||||
ret ty::mk_fn(st.tcx, ast::proto_iter, func._0, func._1, func._2,
|
||||
func._3);
|
||||
}
|
||||
case ('N') {
|
||||
auto abi;
|
||||
|
@ -224,7 +219,7 @@ fn parse_ty(@pstate st, str_def sd) -> ty::t {
|
|||
case ('l') { abi = ast::native_abi_llvm; }
|
||||
}
|
||||
auto func = parse_ty_fn(st, sd);
|
||||
ret ty::mk_native_fn(st.tcx,abi,func._0,func._1);
|
||||
ret ty::mk_native_fn(st.tcx, abi, func._0, func._1);
|
||||
}
|
||||
case ('O') {
|
||||
assert (next(st) as char == '[');
|
||||
|
@ -232,20 +227,21 @@ fn parse_ty(@pstate st, str_def sd) -> ty::t {
|
|||
while (peek(st) as char != ']') {
|
||||
auto proto;
|
||||
alt (next(st) as char) {
|
||||
case ('W') {proto = ast::proto_iter;}
|
||||
case ('F') {proto = ast::proto_fn;}
|
||||
case ('W') { proto = ast::proto_iter; }
|
||||
case ('F') { proto = ast::proto_fn; }
|
||||
}
|
||||
auto name = "";
|
||||
while (peek(st) as char != '[') {
|
||||
name += str::unsafe_from_byte(next(st));
|
||||
}
|
||||
auto func = parse_ty_fn(st, sd);
|
||||
methods += [rec(proto=proto,
|
||||
ident=name,
|
||||
inputs=func._0,
|
||||
output=func._1,
|
||||
cf=func._2,
|
||||
constrs=func._3)];
|
||||
methods +=
|
||||
[rec(proto=proto,
|
||||
ident=name,
|
||||
inputs=func._0,
|
||||
output=func._1,
|
||||
cf=func._2,
|
||||
constrs=func._3)];
|
||||
}
|
||||
st.pos += 1u;
|
||||
ret ty::mk_obj(st.tcx, methods);
|
||||
|
@ -258,12 +254,12 @@ fn parse_ty(@pstate st, str_def sd) -> ty::t {
|
|||
assert (next(st) as char == ':');
|
||||
auto len = parse_hex(st);
|
||||
assert (next(st) as char == '#');
|
||||
alt (st.tcx.rcache.find(tup(st.crate,pos,len))) {
|
||||
alt (st.tcx.rcache.find(tup(st.crate, pos, len))) {
|
||||
case (some(?tt)) { ret tt; }
|
||||
case (none) {
|
||||
auto ps = @rec(pos=pos, len=len with *st);
|
||||
auto tt = parse_ty(ps, sd);
|
||||
st.tcx.rcache.insert(tup(st.crate,pos,len), tt);
|
||||
st.tcx.rcache.insert(tup(st.crate, pos, len), tt);
|
||||
ret tt;
|
||||
}
|
||||
}
|
||||
|
@ -279,9 +275,9 @@ fn parse_ty(@pstate st, str_def sd) -> ty::t {
|
|||
fn parse_mt(@pstate st, str_def sd) -> ty::mt {
|
||||
auto mut;
|
||||
alt (peek(st) as char) {
|
||||
case ('m') {next(st); mut = ast::mut;}
|
||||
case ('?') {next(st); mut = ast::maybe_mut;}
|
||||
case (_) {mut=ast::imm;}
|
||||
case ('m') { next(st); mut = ast::mut; }
|
||||
case ('?') { next(st); mut = ast::maybe_mut; }
|
||||
case (_) { mut = ast::imm; }
|
||||
}
|
||||
ret rec(ty=parse_ty(st, sd), mut=mut);
|
||||
}
|
||||
|
@ -299,7 +295,7 @@ fn parse_int(@pstate st) -> int {
|
|||
auto n = 0;
|
||||
while (true) {
|
||||
auto cur = peek(st) as char;
|
||||
if (cur < '0' || cur > '9') {break;}
|
||||
if (cur < '0' || cur > '9') { break; }
|
||||
st.pos = st.pos + 1u;
|
||||
n *= 10;
|
||||
n += (cur as int) - ('0' as int);
|
||||
|
@ -311,22 +307,18 @@ fn parse_hex(@pstate st) -> uint {
|
|||
auto n = 0u;
|
||||
while (true) {
|
||||
auto cur = peek(st) as char;
|
||||
if ((cur < '0' || cur > '9') &&
|
||||
(cur < 'a' || cur > 'f')) {break;}
|
||||
if ((cur < '0' || cur > '9') && (cur < 'a' || cur > 'f')) { break; }
|
||||
st.pos = st.pos + 1u;
|
||||
n *= 16u;
|
||||
if ('0' <= cur && cur <= '9') {
|
||||
n += (cur as uint) - ('0' as uint);
|
||||
} else {
|
||||
n += (10u + (cur as uint) - ('a' as uint));
|
||||
}
|
||||
} else { n += 10u + (cur as uint) - ('a' as uint); }
|
||||
}
|
||||
ret n;
|
||||
}
|
||||
|
||||
fn parse_ty_fn(@pstate st, str_def sd) -> tup(vec[ty::arg], ty::t,
|
||||
ast::controlflow,
|
||||
vec[@ast::constr]) {
|
||||
fn parse_ty_fn(@pstate st, str_def sd) ->
|
||||
tup(vec[ty::arg], ty::t, ast::controlflow, vec[@ast::constr]) {
|
||||
assert (next(st) as char == '[');
|
||||
let vec[ty::arg] inputs = [];
|
||||
while (peek(st) as char != ']') {
|
||||
|
@ -342,33 +334,28 @@ fn parse_ty_fn(@pstate st, str_def sd) -> tup(vec[ty::arg], ty::t,
|
|||
inputs += [rec(mode=mode, ty=parse_ty(st, sd))];
|
||||
}
|
||||
st.pos = st.pos + 1u;
|
||||
auto cs = parse_constrs(st, sd);
|
||||
auto cs = parse_constrs(st, sd);
|
||||
auto res = parse_ty_or_bang(st, sd);
|
||||
alt (res) {
|
||||
case (a_bang) {
|
||||
ret tup(inputs, ty::mk_bot(st.tcx), ast::noreturn, cs);
|
||||
}
|
||||
case (a_ty(?t)) {
|
||||
ret tup(inputs, t, ast::return, cs);
|
||||
}
|
||||
case (a_ty(?t)) { ret tup(inputs, t, ast::return, cs); }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Rust metadata parsing
|
||||
|
||||
fn parse_def_id(vec[u8] buf) -> ast::def_id {
|
||||
auto colon_idx = 0u;
|
||||
auto len = vec::len[u8](buf);
|
||||
while (colon_idx < len && buf.(colon_idx) != (':' as u8)) {
|
||||
while (colon_idx < len && buf.(colon_idx) != ':' as u8) {
|
||||
colon_idx += 1u;
|
||||
}
|
||||
if (colon_idx == len) {
|
||||
log_err "didn't find ':' when parsing def id";
|
||||
fail;
|
||||
}
|
||||
|
||||
auto crate_part = vec::slice[u8](buf, 0u, colon_idx);
|
||||
auto def_part = vec::slice[u8](buf, colon_idx + 1u, len);
|
||||
auto crate_num = uint::parse_buf(crate_part, 10u) as int;
|
||||
|
@ -376,26 +363,27 @@ fn parse_def_id(vec[u8] buf) -> ast::def_id {
|
|||
ret tup(crate_num, def_num);
|
||||
}
|
||||
|
||||
fn lookup_hash(&ebml::doc d, fn(vec[u8]) -> bool eq_fn, uint hash)
|
||||
-> vec[ebml::doc] {
|
||||
fn lookup_hash(&ebml::doc d, fn(vec[u8]) -> bool eq_fn, uint hash) ->
|
||||
vec[ebml::doc] {
|
||||
auto index = ebml::get_doc(d, metadata::tag_index);
|
||||
auto table = ebml::get_doc(index, metadata::tag_index_table);
|
||||
|
||||
auto hash_pos = table.start + (hash % 256u) * 4u;
|
||||
auto hash_pos = table.start + hash % 256u * 4u;
|
||||
auto pos = ebml::be_uint_from_bytes(d.data, hash_pos, 4u);
|
||||
auto bucket = ebml::doc_at(d.data, pos);
|
||||
// Awkward logic because we can't ret from foreach yet
|
||||
|
||||
let vec[ebml::doc] result = [];
|
||||
auto belt = metadata::tag_index_buckets_bucket_elt;
|
||||
for each (ebml::doc elt in ebml::tagged_docs(bucket, belt)) {
|
||||
auto pos = ebml::be_uint_from_bytes(elt.data, elt.start, 4u);
|
||||
if (eq_fn(vec::slice[u8](elt.data, elt.start+4u, elt.end))) {
|
||||
if (eq_fn(vec::slice[u8](elt.data, elt.start + 4u, elt.end))) {
|
||||
vec::push(result, ebml::doc_at(d.data, pos));
|
||||
}
|
||||
}
|
||||
ret result;
|
||||
}
|
||||
|
||||
|
||||
// Given a path and serialized crate metadata, returns the ID of the
|
||||
// definition the path refers to.
|
||||
fn resolve_path(vec[ast::ident] path, vec[u8] data) -> vec[ast::def_id] {
|
||||
|
@ -422,15 +410,14 @@ fn maybe_find_item(int item_id, &ebml::doc items) -> option::t[ebml::doc] {
|
|||
auto found = lookup_hash(items, eqer, metadata::hash_def_num(item_id));
|
||||
if (vec::len(found) == 0u) {
|
||||
ret option::none[ebml::doc];
|
||||
} else {
|
||||
ret option::some[ebml::doc](found.(0));
|
||||
}
|
||||
} else { ret option::some[ebml::doc](found.(0)); }
|
||||
}
|
||||
|
||||
fn find_item(int item_id, &ebml::doc items) -> ebml::doc {
|
||||
ret option::get(maybe_find_item(item_id, items));
|
||||
}
|
||||
|
||||
|
||||
// Looks up an item in the given metadata and returns an ebml doc pointing
|
||||
// to the item data.
|
||||
fn lookup_item(int item_id, vec[u8] data) -> ebml::doc {
|
||||
|
@ -459,11 +446,11 @@ fn item_type(&ebml::doc item, int this_cnum, ty::ctxt tcx) -> ty::t {
|
|||
// that, in turn, links against another crate. We need a mapping
|
||||
// from crate ID to crate "meta" attributes as part of the crate
|
||||
// metadata:
|
||||
|
||||
auto buf = str::bytes(s);
|
||||
auto external_def_id = parse_def_id(buf);
|
||||
ret tup(this_cnum, external_def_id._1);
|
||||
}
|
||||
|
||||
auto tp = ebml::get_doc(item, metadata::tag_items_data_item_type);
|
||||
auto s = str::unsafe_from_bytes(ebml::doc_data(tp));
|
||||
ret parse_ty_data(item.data, this_cnum, tp.start, tp.end - tp.start,
|
||||
|
@ -490,9 +477,10 @@ fn tag_variant_ids(&ebml::doc item, int this_cnum) -> vec[ast::def_id] {
|
|||
}
|
||||
|
||||
fn get_metadata_section(str filename) -> option::t[vec[u8]] {
|
||||
auto mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile
|
||||
(str::buf(filename));
|
||||
if (mb as int == 0) {ret option::none[vec[u8]];}
|
||||
auto b = str::buf(filename);
|
||||
auto mb =
|
||||
llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(b);
|
||||
if (mb as int == 0) { ret option::none[vec[u8]]; }
|
||||
auto of = mk_object_file(mb);
|
||||
auto si = mk_section_iter(of.llof);
|
||||
while (llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False) {
|
||||
|
@ -509,73 +497,60 @@ fn get_metadata_section(str filename) -> option::t[vec[u8]] {
|
|||
ret option::none[vec[u8]];
|
||||
}
|
||||
|
||||
fn get_exported_metadata(&session::session sess,
|
||||
&str path,
|
||||
&vec[u8] data) -> hashmap[str,str] {
|
||||
auto meta_items = ebml::get_doc(ebml::new_doc(data),
|
||||
metadata::tag_meta_export);
|
||||
fn get_exported_metadata(&session::session sess, &str path, &vec[u8] data) ->
|
||||
hashmap[str, str] {
|
||||
auto meta_items =
|
||||
ebml::get_doc(ebml::new_doc(data), metadata::tag_meta_export);
|
||||
auto mm = common::new_str_hash[str]();
|
||||
|
||||
for each (ebml::doc m in ebml::tagged_docs(meta_items,
|
||||
metadata::tag_meta_item)) {
|
||||
|
||||
for each (ebml::doc m in
|
||||
ebml::tagged_docs(meta_items, metadata::tag_meta_item)) {
|
||||
auto kd = ebml::get_doc(m, metadata::tag_meta_item_key);
|
||||
auto vd = ebml::get_doc(m, metadata::tag_meta_item_value);
|
||||
|
||||
auto k = str::unsafe_from_bytes(ebml::doc_data(kd));
|
||||
auto v = str::unsafe_from_bytes(ebml::doc_data(vd));
|
||||
|
||||
log #fmt("metadata in %s: %s = %s", path, k, v);
|
||||
|
||||
if (!mm.insert(k,v)) {
|
||||
if (!mm.insert(k, v)) {
|
||||
sess.warn(#fmt("Duplicate metadata item in %s: %s", path, k));
|
||||
}
|
||||
}
|
||||
ret mm;
|
||||
}
|
||||
|
||||
fn metadata_matches(hashmap[str,str] mm,
|
||||
&vec[@ast::meta_item] metas) -> bool {
|
||||
fn metadata_matches(hashmap[str, str] mm, &vec[@ast::meta_item] metas) ->
|
||||
bool {
|
||||
log #fmt("matching %u metadata requirements against %u metadata items",
|
||||
vec::len(metas), mm.size());
|
||||
for (@ast::meta_item mi in metas) {
|
||||
alt (mm.find(mi.node.key)) {
|
||||
case (some(?v)) {
|
||||
if (v == mi.node.value) {
|
||||
log #fmt("matched '%s': '%s'",
|
||||
mi.node.key, mi.node.value);
|
||||
log #fmt("matched '%s': '%s'", mi.node.key,
|
||||
mi.node.value);
|
||||
} else {
|
||||
log #fmt("missing '%s': '%s' (got '%s')",
|
||||
mi.node.key, mi.node.value, v);
|
||||
log #fmt("missing '%s': '%s' (got '%s')", mi.node.key,
|
||||
mi.node.value, v);
|
||||
ret false;
|
||||
}
|
||||
}
|
||||
case (none) {
|
||||
log #fmt("missing '%s': '%s'",
|
||||
mi.node.key, mi.node.value);
|
||||
ret false;
|
||||
log #fmt("missing '%s': '%s'", mi.node.key, mi.node.value);
|
||||
ret false;
|
||||
}
|
||||
}
|
||||
}
|
||||
ret true;
|
||||
}
|
||||
|
||||
fn find_library_crate(&session::session sess,
|
||||
&ast::ident ident,
|
||||
fn find_library_crate(&session::session sess, &ast::ident ident,
|
||||
&vec[@ast::meta_item] metas,
|
||||
&vec[str] library_search_paths)
|
||||
-> option::t[tup(str, vec[u8])] {
|
||||
|
||||
&vec[str] library_search_paths) ->
|
||||
option::t[tup(str, vec[u8])] {
|
||||
let str crate_name = ident;
|
||||
for (@ast::meta_item mi in metas) {
|
||||
if (mi.node.key == "name") {
|
||||
crate_name = mi.node.value;
|
||||
break;
|
||||
}
|
||||
if (mi.node.key == "name") { crate_name = mi.node.value; break; }
|
||||
}
|
||||
auto nn = parser::default_native_lib_naming(sess);
|
||||
let str prefix = nn.prefix + crate_name;
|
||||
|
||||
// FIXME: we could probably use a 'glob' function in std::fs but it will
|
||||
// be much easier to write once the unsafe module knows more about FFI
|
||||
// tricks. Currently the glob(3) interface is a bit more than we can
|
||||
|
@ -583,17 +558,14 @@ fn find_library_crate(&session::session sess,
|
|||
// manually filtering fs::list_dir here.
|
||||
|
||||
for (str library_search_path in library_search_paths) {
|
||||
|
||||
for (str path in fs::list_dir(library_search_path)) {
|
||||
|
||||
let str f = fs::basename(path);
|
||||
if (! (str::starts_with(f, prefix) &&
|
||||
str::ends_with(f, nn.suffix))) {
|
||||
log #fmt("skipping %s, doesn't look like %s*%s",
|
||||
path, prefix, nn.suffix);
|
||||
if (!(str::starts_with(f, prefix) &&
|
||||
str::ends_with(f, nn.suffix))) {
|
||||
log #fmt("skipping %s, doesn't look like %s*%s", path, prefix,
|
||||
nn.suffix);
|
||||
cont;
|
||||
}
|
||||
|
||||
alt (get_metadata_section(path)) {
|
||||
case (option::some(?cvec)) {
|
||||
auto mm = get_exported_metadata(sess, path, cvec);
|
||||
|
@ -604,37 +576,33 @@ fn find_library_crate(&session::session sess,
|
|||
log #fmt("found %s with matching metadata", path);
|
||||
ret some(tup(path, cvec));
|
||||
}
|
||||
case (_) {}
|
||||
case (_) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
ret none;
|
||||
}
|
||||
|
||||
fn load_library_crate(&session::session sess,
|
||||
&int cnum,
|
||||
&ast::ident ident,
|
||||
fn load_library_crate(&session::session sess, &int cnum, &ast::ident ident,
|
||||
&vec[@ast::meta_item] metas,
|
||||
&vec[str] library_search_paths) {
|
||||
alt (find_library_crate(sess, ident, metas, library_search_paths)) {
|
||||
case (some(?t)) {
|
||||
sess.set_external_crate(cnum, rec(name=ident,
|
||||
data=t._1));
|
||||
sess.set_external_crate(cnum, rec(name=ident, data=t._1));
|
||||
ret;
|
||||
}
|
||||
case (_) {}
|
||||
case (_) { }
|
||||
}
|
||||
log_err #fmt("can't find crate for '%s'", ident);
|
||||
fail;
|
||||
}
|
||||
|
||||
type env = @rec(
|
||||
session::session sess,
|
||||
resolve::crate_map crate_map,
|
||||
@hashmap[str, int] crate_cache,
|
||||
vec[str] library_search_paths,
|
||||
mutable int next_crate_num
|
||||
);
|
||||
type env =
|
||||
@rec(session::session sess,
|
||||
resolve::crate_map crate_map,
|
||||
@hashmap[str, int] crate_cache,
|
||||
vec[str] library_search_paths,
|
||||
mutable int next_crate_num);
|
||||
|
||||
fn visit_view_item(env e, &@ast::view_item i) {
|
||||
alt (i.node) {
|
||||
|
@ -646,9 +614,7 @@ fn visit_view_item(env e, &@ast::view_item i) {
|
|||
e.library_search_paths);
|
||||
e.crate_cache.insert(ident, e.next_crate_num);
|
||||
e.next_crate_num += 1;
|
||||
} else {
|
||||
cnum = e.crate_cache.get(ident);
|
||||
}
|
||||
} else { cnum = e.crate_cache.get(ident); }
|
||||
e.crate_map.insert(ann.id, cnum);
|
||||
}
|
||||
case (_) { }
|
||||
|
@ -657,66 +623,70 @@ fn visit_view_item(env e, &@ast::view_item i) {
|
|||
|
||||
|
||||
// Reads external crates referenced by "use" directives.
|
||||
fn read_crates(session::session sess,
|
||||
resolve::crate_map crate_map,
|
||||
fn read_crates(session::session sess, resolve::crate_map crate_map,
|
||||
&ast::crate crate) {
|
||||
auto e = @rec(
|
||||
sess=sess,
|
||||
crate_map=crate_map,
|
||||
crate_cache=@common::new_str_hash[int](),
|
||||
library_search_paths=sess.get_opts().library_search_paths,
|
||||
mutable next_crate_num=1
|
||||
);
|
||||
|
||||
auto v = rec(visit_view_item_pre=bind visit_view_item(e, _)
|
||||
with walk::default_visitor());
|
||||
auto e =
|
||||
@rec(sess=sess,
|
||||
crate_map=crate_map,
|
||||
crate_cache=@common::new_str_hash[int](),
|
||||
library_search_paths=sess.get_opts().library_search_paths,
|
||||
mutable next_crate_num=1);
|
||||
auto v =
|
||||
rec(visit_view_item_pre=bind visit_view_item(e, _)
|
||||
with walk::default_visitor());
|
||||
walk::walk_crate(v, crate);
|
||||
}
|
||||
|
||||
|
||||
fn kind_has_type_params(u8 kind_ch) -> bool {
|
||||
ret alt (kind_ch as char) {
|
||||
case ('c') { false } case ('f') { true } case ('F') { true }
|
||||
case ('y') { true } case ('o') { true } case ('t') { true }
|
||||
case ('T') { false } case ('m') { false } case ('n') { false }
|
||||
case ('v') { true }
|
||||
};
|
||||
case ('c') { false }
|
||||
case ('f') { true }
|
||||
case ('F') { true }
|
||||
case ('y') { true }
|
||||
case ('o') { true }
|
||||
case ('t') { true }
|
||||
case ('T') { false }
|
||||
case ('m') { false }
|
||||
case ('n') { false }
|
||||
case ('v') { true }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// Crate metadata queries
|
||||
|
||||
fn lookup_defs(session::session sess, int cnum, vec[ast::ident] path)
|
||||
-> vec[ast::def] {
|
||||
fn lookup_defs(session::session sess, int cnum, vec[ast::ident] path) ->
|
||||
vec[ast::def] {
|
||||
auto data = sess.get_external_crate(cnum).data;
|
||||
|
||||
ret vec::map(bind lookup_def(cnum, data, _),
|
||||
resolve_path(path, data));
|
||||
ret vec::map(bind lookup_def(cnum, data, _), resolve_path(path, data));
|
||||
}
|
||||
|
||||
|
||||
// FIXME doesn't yet handle re-exported externals
|
||||
fn lookup_def(int cnum, vec[u8] data, &ast::def_id did_) -> ast::def {
|
||||
auto item = lookup_item(did_._1, data);
|
||||
auto kind_ch = item_kind(item);
|
||||
|
||||
auto did = tup(cnum, did_._1);
|
||||
|
||||
auto def = alt (kind_ch as char) {
|
||||
case ('c') { ast::def_const(did) }
|
||||
case ('f') { ast::def_fn(did) }
|
||||
case ('F') { ast::def_native_fn(did) }
|
||||
case ('y') { ast::def_ty(did) }
|
||||
case ('o') { ast::def_obj(did) }
|
||||
case ('T') { ast::def_native_ty(did) }
|
||||
// We treat references to tags as references to types.
|
||||
case ('t') { ast::def_ty(did) }
|
||||
case ('m') { ast::def_mod(did) }
|
||||
case ('n') { ast::def_native_mod(did) }
|
||||
case ('v') {
|
||||
auto tid = variant_tag_id(item);
|
||||
tid = tup(cnum, tid._1);
|
||||
ast::def_variant(tid, did)
|
||||
}
|
||||
};
|
||||
auto def =
|
||||
alt (kind_ch as char) {
|
||||
case ('c') { ast::def_const(did) }
|
||||
case ('f') { ast::def_fn(did) }
|
||||
case ('F') { ast::def_native_fn(did) }
|
||||
case ('y') { ast::def_ty(did) }
|
||||
case ('o') { ast::def_obj(did) }
|
||||
case ('T') { ast::def_native_ty(did) }
|
||||
case (
|
||||
// We treat references to tags as references to types.
|
||||
't') {
|
||||
ast::def_ty(did)
|
||||
}
|
||||
case ('m') { ast::def_mod(did) }
|
||||
case ('n') { ast::def_native_mod(did) }
|
||||
case ('v') {
|
||||
auto tid = variant_tag_id(item);
|
||||
tid = tup(cnum, tid._1);
|
||||
ast::def_variant(tid, did)
|
||||
}
|
||||
};
|
||||
ret def;
|
||||
}
|
||||
|
||||
|
@ -725,16 +695,12 @@ fn get_type(ty::ctxt tcx, ast::def_id def) -> ty::ty_param_count_and_ty {
|
|||
auto data = tcx.sess.get_external_crate(external_crate_id).data;
|
||||
auto item = lookup_item(def._1, data);
|
||||
auto t = item_type(item, external_crate_id, tcx);
|
||||
|
||||
auto tp_count;
|
||||
auto kind_ch = item_kind(item);
|
||||
auto has_ty_params = kind_has_type_params(kind_ch);
|
||||
if (has_ty_params) {
|
||||
tp_count = item_ty_param_count(item, external_crate_id);
|
||||
} else {
|
||||
tp_count = 0u;
|
||||
}
|
||||
|
||||
} else { tp_count = 0u; }
|
||||
ret tup(tp_count, t);
|
||||
}
|
||||
|
||||
|
@ -744,13 +710,11 @@ fn get_symbol(session::session sess, ast::def_id def) -> str {
|
|||
ret item_symbol(lookup_item(def._1, data));
|
||||
}
|
||||
|
||||
fn get_tag_variants(ty::ctxt tcx, ast::def_id def)
|
||||
-> vec[ty::variant_info] {
|
||||
fn get_tag_variants(ty::ctxt tcx, ast::def_id def) -> vec[ty::variant_info] {
|
||||
auto external_crate_id = def._0;
|
||||
auto data = tcx.sess.get_external_crate(external_crate_id).data;
|
||||
auto items = ebml::get_doc(ebml::new_doc(data), metadata::tag_items);
|
||||
auto item = find_item(def._1, items);
|
||||
|
||||
let vec[ty::variant_info] infos = [];
|
||||
auto variant_ids = tag_variant_ids(item, external_crate_id);
|
||||
for (ast::def_id did in variant_ids) {
|
||||
|
@ -759,25 +723,21 @@ fn get_tag_variants(ty::ctxt tcx, ast::def_id def)
|
|||
let vec[ty::t] arg_tys = [];
|
||||
alt (ty::struct(tcx, ctor_ty)) {
|
||||
case (ty::ty_fn(_, ?args, _, _, _)) {
|
||||
for (ty::arg a in args) {
|
||||
arg_tys += [a.ty];
|
||||
}
|
||||
for (ty::arg a in args) { arg_tys += [a.ty]; }
|
||||
}
|
||||
case (_) {
|
||||
// Nullary tag variant.
|
||||
|
||||
}
|
||||
}
|
||||
infos += [rec(args=arg_tys, ctor_ty=ctor_ty, id=did)];
|
||||
}
|
||||
|
||||
ret infos;
|
||||
}
|
||||
|
||||
fn list_file_metadata(str path, io::writer out) {
|
||||
alt (get_metadata_section(path)) {
|
||||
case (option::some(?bytes)) {
|
||||
list_crate_metadata(bytes, out);
|
||||
}
|
||||
case (option::some(?bytes)) { list_crate_metadata(bytes, out); }
|
||||
case (option::none) {
|
||||
out.write_str("Could not find metadata in " + path + ".\n");
|
||||
}
|
||||
|
@ -799,7 +759,7 @@ fn list_crate_metadata(vec[u8] bytes, io::writer out) {
|
|||
auto index = ebml::get_doc(paths, metadata::tag_index);
|
||||
auto bs = ebml::get_doc(index, metadata::tag_index_buckets);
|
||||
for each (ebml::doc bucket in
|
||||
ebml::tagged_docs(bs, metadata::tag_index_buckets_bucket)) {
|
||||
ebml::tagged_docs(bs, metadata::tag_index_buckets_bucket)) {
|
||||
auto et = metadata::tag_index_buckets_bucket_elt;
|
||||
for each (ebml::doc elt in ebml::tagged_docs(bucket, et)) {
|
||||
auto data = read_path(elt);
|
||||
|
@ -819,19 +779,18 @@ fn describe_def(&ebml::doc items, ast::def_id id) -> str {
|
|||
|
||||
fn item_kind_to_str(u8 kind) -> str {
|
||||
alt (kind as char) {
|
||||
case ('c') {ret "const";}
|
||||
case ('f') {ret "fn";}
|
||||
case ('F') {ret "native fn";}
|
||||
case ('y') {ret "type";}
|
||||
case ('o') {ret "obj";}
|
||||
case ('T') {ret "native type";}
|
||||
case ('t') {ret "type";}
|
||||
case ('m') {ret "mod";}
|
||||
case ('n') {ret "native mod";}
|
||||
case ('v') {ret "tag";}
|
||||
case ('c') { ret "const"; }
|
||||
case ('f') { ret "fn"; }
|
||||
case ('F') { ret "native fn"; }
|
||||
case ('y') { ret "type"; }
|
||||
case ('o') { ret "obj"; }
|
||||
case ('T') { ret "native type"; }
|
||||
case ('t') { ret "type"; }
|
||||
case ('m') { ret "mod"; }
|
||||
case ('n') { ret "native mod"; }
|
||||
case ('v') { ret "tag"; }
|
||||
}
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
// fill-column: 78;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
|
||||
import std::vec;
|
||||
import std::str;
|
||||
import std::option;
|
||||
import std::option::some;
|
||||
import std::option::none;
|
||||
import std::map::hashmap;
|
||||
|
||||
import driver::session;
|
||||
import ast::ident;
|
||||
import front::parser::parser;
|
||||
|
@ -18,76 +18,49 @@ import util::common::new_str_hash;
|
|||
|
||||
|
||||
// Simple dynamic-typed value type for eval_expr.
|
||||
tag val {
|
||||
val_bool(bool);
|
||||
val_int(int);
|
||||
val_str(str);
|
||||
}
|
||||
tag val { val_bool(bool); val_int(int); val_str(str); }
|
||||
|
||||
tag eval_mode {
|
||||
mode_depend;
|
||||
mode_parse;
|
||||
}
|
||||
tag eval_mode { mode_depend; mode_parse; }
|
||||
|
||||
type env = vec[tup(ident, val)];
|
||||
type ctx = @rec(parser p,
|
||||
eval_mode mode,
|
||||
mutable vec[str] deps,
|
||||
session::session sess,
|
||||
mutable uint chpos,
|
||||
mutable uint next_ann);
|
||||
|
||||
fn mk_env() -> env {
|
||||
ret [];
|
||||
}
|
||||
type ctx =
|
||||
@rec(parser p,
|
||||
eval_mode mode,
|
||||
mutable vec[str] deps,
|
||||
session::session sess,
|
||||
mutable uint chpos,
|
||||
mutable uint next_ann);
|
||||
|
||||
fn mk_env() -> env { ret []; }
|
||||
|
||||
fn val_is_bool(val v) -> bool {
|
||||
alt (v) {
|
||||
case (val_bool(_)) { true }
|
||||
case (_) { false }
|
||||
}
|
||||
alt (v) { case (val_bool(_)) { true } case (_) { false } }
|
||||
}
|
||||
|
||||
fn val_is_int(val v) -> bool {
|
||||
alt (v) {
|
||||
case (val_int(_)) { true }
|
||||
case (_) { false }
|
||||
}
|
||||
alt (v) { case (val_int(_)) { true } case (_) { false } }
|
||||
}
|
||||
|
||||
fn val_is_str(val v) -> bool {
|
||||
alt (v) {
|
||||
case (val_str(_)) { true }
|
||||
case (_) { false }
|
||||
}
|
||||
alt (v) { case (val_str(_)) { true } case (_) { false } }
|
||||
}
|
||||
|
||||
fn val_as_bool(val v) -> bool {
|
||||
alt (v) {
|
||||
case (val_bool(?b)) { b }
|
||||
case (_) { fail }
|
||||
}
|
||||
alt (v) { case (val_bool(?b)) { b } case (_) { fail } }
|
||||
}
|
||||
|
||||
fn val_as_int(val v) -> int {
|
||||
alt (v) {
|
||||
case (val_int(?i)) { i }
|
||||
case (_) { fail }
|
||||
}
|
||||
alt (v) { case (val_int(?i)) { i } case (_) { fail } }
|
||||
}
|
||||
|
||||
fn val_as_str(val v) -> str {
|
||||
alt (v) {
|
||||
case (val_str(?s)) { s }
|
||||
case (_) { fail }
|
||||
}
|
||||
alt (v) { case (val_str(?s)) { s } case (_) { fail } }
|
||||
}
|
||||
|
||||
fn lookup(session::session sess, env e, span sp, ident i) -> val {
|
||||
for (tup(ident, val) pair in e) {
|
||||
if (str::eq(i, pair._0)) {
|
||||
ret pair._1;
|
||||
}
|
||||
if (str::eq(i, pair._0)) { ret pair._1; }
|
||||
}
|
||||
sess.span_err(sp, "unknown variable: " + i)
|
||||
}
|
||||
|
@ -96,10 +69,8 @@ fn eval_lit(ctx cx, span sp, @ast::lit lit) -> val {
|
|||
alt (lit.node) {
|
||||
case (ast::lit_bool(?b)) { val_bool(b) }
|
||||
case (ast::lit_int(?i)) { val_int(i) }
|
||||
case (ast::lit_str(?s,_)) { val_str(s) }
|
||||
case (_) {
|
||||
cx.sess.span_err(sp, "evaluating unsupported literal")
|
||||
}
|
||||
case (ast::lit_str(?s, _)) { val_str(s) }
|
||||
case (_) { cx.sess.span_err(sp, "evaluating unsupported literal") }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,23 +78,17 @@ fn eval_expr(ctx cx, env e, @ast::expr x) -> val {
|
|||
alt (x.node) {
|
||||
case (ast::expr_path(?pth, _)) {
|
||||
if (vec::len[ident](pth.node.idents) == 1u &&
|
||||
vec::len[@ast::ty](pth.node.types) == 0u) {
|
||||
vec::len[@ast::ty](pth.node.types) == 0u) {
|
||||
ret lookup(cx.sess, e, x.span, pth.node.idents.(0));
|
||||
}
|
||||
cx.sess.span_err(x.span, "evaluating structured path-name");
|
||||
}
|
||||
|
||||
case (ast::expr_lit(?lit, _)) {
|
||||
ret eval_lit(cx, x.span, lit);
|
||||
}
|
||||
|
||||
case (ast::expr_lit(?lit, _)) { ret eval_lit(cx, x.span, lit); }
|
||||
case (ast::expr_unary(?op, ?a, _)) {
|
||||
auto av = eval_expr(cx, e, a);
|
||||
alt (op) {
|
||||
case (ast::not) {
|
||||
if (val_is_bool(av)) {
|
||||
ret val_bool(!val_as_bool(av));
|
||||
}
|
||||
if (val_is_bool(av)) { ret val_bool(!val_as_bool(av)); }
|
||||
cx.sess.span_err(x.span, "bad types in '!' expression");
|
||||
}
|
||||
case (_) {
|
||||
|
@ -131,7 +96,6 @@ fn eval_expr(ctx cx, env e, @ast::expr x) -> val {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
case (ast::expr_binary(?op, ?a, ?b, _)) {
|
||||
auto av = eval_expr(cx, e, a);
|
||||
auto bv = eval_expr(cx, e, b);
|
||||
|
@ -145,57 +109,48 @@ fn eval_expr(ctx cx, env e, @ast::expr x) -> val {
|
|||
}
|
||||
cx.sess.span_err(x.span, "bad types in '+' expression");
|
||||
}
|
||||
|
||||
case (ast::sub) {
|
||||
if (val_is_int(av) && val_is_int(bv)) {
|
||||
ret val_int(val_as_int(av) - val_as_int(bv));
|
||||
}
|
||||
cx.sess.span_err(x.span, "bad types in '-' expression");
|
||||
}
|
||||
|
||||
case (ast::mul) {
|
||||
if (val_is_int(av) && val_is_int(bv)) {
|
||||
ret val_int(val_as_int(av) * val_as_int(bv));
|
||||
}
|
||||
cx.sess.span_err(x.span, "bad types in '*' expression");
|
||||
}
|
||||
|
||||
case (ast::div) {
|
||||
if (val_is_int(av) && val_is_int(bv)) {
|
||||
ret val_int(val_as_int(av) / val_as_int(bv));
|
||||
}
|
||||
cx.sess.span_err(x.span, "bad types in '/' expression");
|
||||
}
|
||||
|
||||
case (ast::rem) {
|
||||
if (val_is_int(av) && val_is_int(bv)) {
|
||||
ret val_int(val_as_int(av) % val_as_int(bv));
|
||||
}
|
||||
cx.sess.span_err(x.span, "bad types in '%' expression");
|
||||
}
|
||||
|
||||
case (ast::and) {
|
||||
if (val_is_bool(av) && val_is_bool(bv)) {
|
||||
ret val_bool(val_as_bool(av) && val_as_bool(bv));
|
||||
}
|
||||
cx.sess.span_err(x.span, "bad types in '&&' expression");
|
||||
}
|
||||
|
||||
case (ast::or) {
|
||||
if (val_is_bool(av) && val_is_bool(bv)) {
|
||||
ret val_bool(val_as_bool(av) || val_as_bool(bv));
|
||||
}
|
||||
cx.sess.span_err(x.span, "bad types in '||' expression");
|
||||
}
|
||||
|
||||
case (ast::eq) {
|
||||
ret val_bool(val_eq(cx.sess, x.span, av, bv));
|
||||
}
|
||||
|
||||
case (ast::ne) {
|
||||
ret val_bool(! val_eq(cx.sess, x.span, av, bv));
|
||||
ret val_bool(!val_eq(cx.sess, x.span, av, bv));
|
||||
}
|
||||
|
||||
case (_) {
|
||||
cx.sess.span_err(x.span, "evaluating unsupported binop");
|
||||
}
|
||||
|
@ -214,52 +169,34 @@ fn val_eq(session::session sess, span sp, val av, val bv) -> bool {
|
|||
} else if (val_is_int(av) && val_is_int(bv)) {
|
||||
val_as_int(av) == val_as_int(bv)
|
||||
} else if (val_is_str(av) && val_is_str(bv)) {
|
||||
str::eq(val_as_str(av),
|
||||
val_as_str(bv))
|
||||
} else {
|
||||
sess.span_err(sp, "bad types in comparison")
|
||||
}
|
||||
str::eq(val_as_str(av), val_as_str(bv))
|
||||
} else { sess.span_err(sp, "bad types in comparison") }
|
||||
}
|
||||
|
||||
fn eval_crate_directives(ctx cx,
|
||||
env e,
|
||||
vec[@ast::crate_directive] cdirs,
|
||||
str prefix,
|
||||
&mutable vec[@ast::view_item] view_items,
|
||||
&mutable vec[@ast::item] items) {
|
||||
|
||||
fn eval_crate_directives(ctx cx, env e, 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, e, sub_cdir, prefix,
|
||||
view_items, items);
|
||||
eval_crate_directive(cx, e, sub_cdir, prefix, view_items, items);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn eval_crate_directives_to_mod(ctx cx, env e,
|
||||
vec[@ast::crate_directive] cdirs,
|
||||
str prefix) -> ast::_mod {
|
||||
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, e, cdirs, prefix,
|
||||
view_items, items);
|
||||
|
||||
eval_crate_directives(cx, e, cdirs, prefix, view_items, items);
|
||||
ret rec(view_items=view_items, items=items);
|
||||
}
|
||||
|
||||
|
||||
fn eval_crate_directive_block(ctx cx,
|
||||
env e,
|
||||
&ast::block blk,
|
||||
str prefix,
|
||||
&mutable vec[@ast::view_item] view_items,
|
||||
&mutable vec[@ast::item] items) {
|
||||
|
||||
fn eval_crate_directive_block(ctx cx, env e, &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, e, cdir, prefix,
|
||||
view_items, items);
|
||||
eval_crate_directive(cx, e, cdir, prefix, view_items, items);
|
||||
}
|
||||
case (_) {
|
||||
cx.sess.span_err(s.span,
|
||||
|
@ -269,25 +206,19 @@ fn eval_crate_directive_block(ctx cx,
|
|||
}
|
||||
}
|
||||
|
||||
fn eval_crate_directive_expr(ctx cx,
|
||||
env e,
|
||||
@ast::expr x,
|
||||
str prefix,
|
||||
&mutable vec[@ast::view_item] view_items,
|
||||
&mutable vec[@ast::item] items) {
|
||||
fn eval_crate_directive_expr(ctx cx, env e, @ast::expr x, str prefix,
|
||||
&mutable vec[@ast::view_item] view_items,
|
||||
&mutable vec[@ast::item] items) {
|
||||
alt (x.node) {
|
||||
|
||||
case (ast::expr_if(?cond, ?thn, ?elopt, _)) {
|
||||
auto cv = eval_expr(cx, e, cond);
|
||||
if (!val_is_bool(cv)) {
|
||||
cx.sess.span_err(x.span, "bad cond type in 'if'");
|
||||
}
|
||||
|
||||
if (val_as_bool(cv)) {
|
||||
ret eval_crate_directive_block(cx, e, thn, prefix,
|
||||
view_items, items);
|
||||
ret eval_crate_directive_block(cx, e, thn, prefix, view_items,
|
||||
items);
|
||||
}
|
||||
|
||||
alt (elopt) {
|
||||
case (some(?els)) {
|
||||
ret eval_crate_directive_expr(cx, e, els, prefix,
|
||||
|
@ -295,10 +226,10 @@ fn eval_crate_directive_expr(ctx cx,
|
|||
}
|
||||
case (_) {
|
||||
// Absent-else is ok.
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case (ast::expr_alt(?v, ?arms, _)) {
|
||||
auto vv = eval_expr(cx, e, v);
|
||||
for (ast::arm arm in arms) {
|
||||
|
@ -306,14 +237,15 @@ fn eval_crate_directive_expr(ctx cx,
|
|||
case (ast::pat_lit(?lit, _)) {
|
||||
auto pv = eval_lit(cx, arm.pat.span, lit);
|
||||
if (val_eq(cx.sess, arm.pat.span, vv, pv)) {
|
||||
ret eval_crate_directive_block
|
||||
(cx, e, arm.block, prefix, view_items, items);
|
||||
ret eval_crate_directive_block(cx, e, arm.block,
|
||||
prefix, view_items,
|
||||
items);
|
||||
}
|
||||
}
|
||||
case (ast::pat_wild(_)) {
|
||||
ret eval_crate_directive_block
|
||||
(cx, e, arm.block, prefix,
|
||||
view_items, items);
|
||||
ret eval_crate_directive_block(cx, e, arm.block,
|
||||
prefix, view_items,
|
||||
items);
|
||||
}
|
||||
case (_) {
|
||||
cx.sess.span_err(arm.pat.span,
|
||||
|
@ -323,61 +255,42 @@ fn eval_crate_directive_expr(ctx cx,
|
|||
}
|
||||
cx.sess.span_err(x.span, "no cases matched in 'alt'");
|
||||
}
|
||||
|
||||
case (ast::expr_block(?block, _)) {
|
||||
ret eval_crate_directive_block(cx, e, block, prefix,
|
||||
view_items, items);
|
||||
}
|
||||
|
||||
case (_) {
|
||||
cx.sess.span_err(x.span, "unsupported expr type");
|
||||
ret eval_crate_directive_block(cx, e, block, prefix, view_items,
|
||||
items);
|
||||
}
|
||||
case (_) { cx.sess.span_err(x.span, "unsupported expr type"); }
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_crate_directive(ctx cx,
|
||||
env e,
|
||||
@ast::crate_directive cdir,
|
||||
str prefix,
|
||||
&mutable vec[@ast::view_item] view_items,
|
||||
&mutable vec[@ast::item] items) {
|
||||
fn eval_crate_directive(ctx cx, env e, @ast::crate_directive cdir, str prefix,
|
||||
&mutable vec[@ast::view_item] view_items,
|
||||
&mutable vec[@ast::item] items) {
|
||||
alt (cdir.node) {
|
||||
|
||||
case (ast::cdir_let(?id, ?x, ?cdirs)) {
|
||||
auto v = eval_expr(cx, e, x);
|
||||
auto e0 = [tup(id, v)] + e;
|
||||
eval_crate_directives(cx, e0, cdirs, prefix,
|
||||
view_items, items);
|
||||
eval_crate_directives(cx, e0, cdirs, prefix, view_items, items);
|
||||
}
|
||||
|
||||
case (ast::cdir_expr(?x)) {
|
||||
eval_crate_directive_expr(cx, e, x, prefix,
|
||||
view_items, items);
|
||||
eval_crate_directive_expr(cx, e, x, prefix, view_items, items);
|
||||
}
|
||||
|
||||
case (ast::cdir_src_mod(?id, ?file_opt)) {
|
||||
|
||||
auto file_path = id + ".rs";
|
||||
alt (file_opt) {
|
||||
case (some(?f)) {
|
||||
file_path = f;
|
||||
}
|
||||
case (none) {}
|
||||
case (some(?f)) { file_path = f; }
|
||||
case (none) { }
|
||||
}
|
||||
|
||||
auto full_path = prefix + std::fs::path_sep() + file_path;
|
||||
|
||||
if (cx.mode == mode_depend) {
|
||||
cx.deps += [full_path];
|
||||
ret;
|
||||
}
|
||||
|
||||
if (cx.mode == mode_depend) { cx.deps += [full_path]; ret; }
|
||||
auto start_id = cx.p.next_def_id();
|
||||
auto p0 = new_parser(cx.sess, e, start_id, full_path, cx.chpos,
|
||||
cx.next_ann);
|
||||
auto p0 =
|
||||
new_parser(cx.sess, e, start_id, full_path, cx.chpos,
|
||||
cx.next_ann);
|
||||
auto m0 = parse_mod_items(p0, token::EOF);
|
||||
auto next_id = p0.next_def_id();
|
||||
// Thread defids and chpos through the parsers
|
||||
|
||||
cx.p.set_def(next_id._1);
|
||||
cx.chpos = p0.get_chpos();
|
||||
cx.next_ann = p0.next_ann_num();
|
||||
|
@ -385,40 +298,25 @@ fn eval_crate_directive(ctx cx,
|
|||
auto i = @spanned(cdir.span.lo, cdir.span.hi, im);
|
||||
vec::push[@ast::item](items, i);
|
||||
}
|
||||
|
||||
case (ast::cdir_dir_mod(?id, ?dir_opt, ?cdirs)) {
|
||||
|
||||
auto path = id;
|
||||
alt (dir_opt) {
|
||||
case (some(?d)) {
|
||||
path = d;
|
||||
}
|
||||
case (none) {}
|
||||
}
|
||||
|
||||
alt (dir_opt) { case (some(?d)) { path = d; } case (none) { } }
|
||||
auto full_path = prefix + std::fs::path_sep() + path;
|
||||
auto m0 = eval_crate_directives_to_mod(cx, e, cdirs, full_path);
|
||||
auto im = ast::item_mod(id, m0, [], cx.p.next_def_id());
|
||||
auto i = @spanned(cdir.span.lo, cdir.span.hi, im);
|
||||
vec::push[@ast::item](items, i);
|
||||
}
|
||||
|
||||
case (ast::cdir_view_item(?vi)) {
|
||||
vec::push[@ast::view_item](view_items, vi);
|
||||
}
|
||||
|
||||
case (ast::cdir_meta(?vi, ?mi)) {
|
||||
if (vi == ast::export_meta) {
|
||||
cx.sess.add_metadata(mi);
|
||||
}
|
||||
if (vi == ast::export_meta) { cx.sess.add_metadata(mi); }
|
||||
}
|
||||
|
||||
case (ast::cdir_syntax(?pth)) {}
|
||||
case (ast::cdir_auth(?pth, ?eff)) {}
|
||||
case (ast::cdir_syntax(?pth)) { }
|
||||
case (ast::cdir_auth(?pth, ?eff)) { }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
|
||||
import std::option;
|
||||
import std::map::hashmap;
|
||||
|
||||
import driver::session::session;
|
||||
import front::parser::parser;
|
||||
import util::common::span;
|
||||
import util::common::new_str_hash;
|
||||
|
||||
type syntax_expander = fn(&ext_ctxt, span,
|
||||
&vec[@ast::expr],
|
||||
option::t[str]) -> @ast::expr;
|
||||
type syntax_expander =
|
||||
fn(&ext_ctxt, span, &vec[@ast::expr], option::t[str]) -> @ast::expr ;
|
||||
|
||||
|
||||
// Temporary: to introduce a tag in order to make a recursive type work
|
||||
tag syntax_extension {
|
||||
x(syntax_expander);
|
||||
}
|
||||
tag syntax_extension { x(syntax_expander); }
|
||||
|
||||
|
||||
// A temporary hard-coded map of methods for expanding syntax extension
|
||||
// AST nodes into full ASTs
|
||||
|
@ -24,36 +23,32 @@ fn syntax_expander_table() -> hashmap[str, syntax_extension] {
|
|||
ret syntax_expanders;
|
||||
}
|
||||
|
||||
type span_msg_fn = fn (span sp, str msg) -> !;
|
||||
type next_ann_fn = fn () -> ast::ann;
|
||||
type span_msg_fn = fn(span, str) -> ! ;
|
||||
|
||||
type next_ann_fn = fn() -> ast::ann ;
|
||||
|
||||
|
||||
// Provides a limited set of services necessary for syntax extensions
|
||||
// to do their thing
|
||||
type ext_ctxt = rec(span_msg_fn span_err,
|
||||
span_msg_fn span_unimpl,
|
||||
next_ann_fn next_ann);
|
||||
type ext_ctxt =
|
||||
rec(span_msg_fn span_err, span_msg_fn span_unimpl, next_ann_fn next_ann);
|
||||
|
||||
fn mk_ctxt(parser parser) -> ext_ctxt {
|
||||
auto sess = parser.get_session();
|
||||
|
||||
fn ext_span_err_(session sess, span sp, str msg) -> ! {
|
||||
sess.span_err(sp, msg);
|
||||
}
|
||||
auto ext_span_err = bind ext_span_err_(sess, _, _);
|
||||
|
||||
fn ext_span_unimpl_(session sess, span sp, str msg) -> ! {
|
||||
sess.span_unimpl(sp, msg);
|
||||
}
|
||||
auto ext_span_unimpl = bind ext_span_unimpl_(sess, _, _);
|
||||
|
||||
fn ext_next_ann_(parser parser) -> ast::ann { parser.get_ann() }
|
||||
auto ext_next_ann = bind ext_next_ann_(parser);
|
||||
|
||||
ret rec(span_err = ext_span_err,
|
||||
span_unimpl = ext_span_unimpl,
|
||||
next_ann = ext_next_ann);
|
||||
ret rec(span_err=ext_span_err,
|
||||
span_unimpl=ext_span_unimpl,
|
||||
next_ann=ext_next_ann);
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
|
|
@ -1,50 +1,40 @@
|
|||
|
||||
|
||||
/*
|
||||
* The compiler code necessary to support the #env extension. Eventually this
|
||||
* should all get sucked into either the compiler syntax extension plugin
|
||||
* interface.
|
||||
*/
|
||||
|
||||
import util::common;
|
||||
|
||||
import std::str;
|
||||
import std::vec;
|
||||
import std::option;
|
||||
import std::generic_os;
|
||||
|
||||
import ext::*;
|
||||
|
||||
export expand_syntax_ext;
|
||||
|
||||
fn expand_syntax_ext(&ext_ctxt cx,
|
||||
common::span sp,
|
||||
&vec[@ast::expr] args,
|
||||
fn expand_syntax_ext(&ext_ctxt cx, common::span sp, &vec[@ast::expr] args,
|
||||
option::t[str] body) -> @ast::expr {
|
||||
|
||||
if (vec::len[@ast::expr](args) != 1u) {
|
||||
cx.span_err(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));
|
||||
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);
|
||||
}
|
||||
case (option::none) { ret make_new_str(cx, sp, ""); }
|
||||
case (option::some(?s)) { ret make_new_str(cx, sp, s); }
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: duplicate code copied from extfmt:
|
||||
|
||||
// FIXME: duplicate code copied from extfmt:
|
||||
fn expr_to_str(&ext_ctxt cx, @ast::expr expr) -> str {
|
||||
alt (expr.node) {
|
||||
case (ast::expr_lit(?l, _)) {
|
||||
alt (l.node) {
|
||||
case (ast::lit_str(?s,_)) { ret s; }
|
||||
case (ast::lit_str(?s, _)) { ret s; }
|
||||
case (_) { cx.span_err(l.span, "malformed #env call"); }
|
||||
}
|
||||
}
|
||||
|
@ -52,8 +42,7 @@ fn expr_to_str(&ext_ctxt cx, @ast::expr expr) -> str {
|
|||
}
|
||||
}
|
||||
|
||||
fn make_new_lit(&ext_ctxt cx, common::span sp, ast::lit_ lit)
|
||||
-> @ast::expr {
|
||||
fn make_new_lit(&ext_ctxt cx, common::span sp, ast::lit_ lit) -> @ast::expr {
|
||||
auto sp_lit = @rec(node=lit, span=sp);
|
||||
auto expr = ast::expr_lit(sp_lit, cx.next_ann());
|
||||
ret @rec(node=expr, span=sp);
|
||||
|
@ -62,7 +51,6 @@ fn make_new_lit(&ext_ctxt cx, common::span sp, ast::lit_ lit)
|
|||
fn make_new_str(&ext_ctxt cx, common::span sp, str s) -> @ast::expr {
|
||||
ret make_new_lit(cx, sp, ast::lit_str(s, ast::sk_rc));
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
|
|
@ -1,42 +1,32 @@
|
|||
|
||||
|
||||
/*
|
||||
* 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 util::common;
|
||||
|
||||
import std::str;
|
||||
import std::vec;
|
||||
import std::option;
|
||||
import std::option::none;
|
||||
import std::option::some;
|
||||
|
||||
import std::extfmt::ct::*;
|
||||
|
||||
import ext::*;
|
||||
|
||||
export expand_syntax_ext;
|
||||
|
||||
fn expand_syntax_ext(&ext_ctxt cx,
|
||||
common::span sp,
|
||||
&vec[@ast::expr] args,
|
||||
fn expand_syntax_ext(&ext_ctxt cx, common::span sp, &vec[@ast::expr] args,
|
||||
option::t[str] body) -> @ast::expr {
|
||||
|
||||
if (vec::len[@ast::expr](args) == 0u) {
|
||||
cx.span_err(sp, "#fmt requires a format string");
|
||||
}
|
||||
|
||||
auto fmt = expr_to_str(cx, args.(0));
|
||||
auto fmtspan = args.(0).span;
|
||||
|
||||
log "Format string:";
|
||||
log fmt;
|
||||
|
||||
fn parse_fmt_err_(&ext_ctxt cx, common::span sp, str msg) -> ! {
|
||||
cx.span_err(sp, msg);
|
||||
}
|
||||
|
||||
auto parse_fmt_err = bind parse_fmt_err_(cx, fmtspan, _);
|
||||
auto pieces = parse_fmt_string(fmt, parse_fmt_err);
|
||||
auto args_len = vec::len[@ast::expr](args);
|
||||
|
@ -49,52 +39,45 @@ fn expr_to_str(&ext_ctxt cx, @ast::expr expr) -> str {
|
|||
alt (expr.node) {
|
||||
case (ast::expr_lit(?l, _)) {
|
||||
alt (l.node) {
|
||||
case (ast::lit_str(?s,_)) { ret s; }
|
||||
case (ast::lit_str(?s, _)) { ret s; }
|
||||
case (_) { cx.span_err(l.span, err_msg); }
|
||||
}
|
||||
}
|
||||
case (_) {
|
||||
cx.span_err(expr.span, err_msg);
|
||||
}
|
||||
case (_) { cx.span_err(expr.span, err_msg); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 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, common::span sp,
|
||||
vec[piece] pieces, vec[@ast::expr] args) -> @ast::expr {
|
||||
|
||||
fn make_new_lit(&ext_ctxt cx,
|
||||
common::span sp, ast::lit_ lit) -> @ast::expr {
|
||||
fn pieces_to_expr(&ext_ctxt cx, common::span sp, vec[piece] pieces,
|
||||
vec[@ast::expr] args) -> @ast::expr {
|
||||
fn make_new_lit(&ext_ctxt cx, common::span sp, ast::lit_ lit) ->
|
||||
@ast::expr {
|
||||
auto sp_lit = @rec(node=lit, span=sp);
|
||||
auto expr = ast::expr_lit(sp_lit, cx.next_ann());
|
||||
ret @rec(node=expr, span=sp);
|
||||
}
|
||||
|
||||
fn make_new_str(&ext_ctxt cx, common::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, common::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, common::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, common::span sp,
|
||||
@ast::expr lhs, @ast::expr rhs) -> @ast::expr {
|
||||
fn make_add_expr(&ext_ctxt cx, common::span sp, @ast::expr lhs,
|
||||
@ast::expr rhs) -> @ast::expr {
|
||||
auto binexpr = ast::expr_binary(ast::add, lhs, rhs, cx.next_ann());
|
||||
ret @rec(node=binexpr, span=sp);
|
||||
}
|
||||
|
||||
fn make_path_expr(&ext_ctxt cx, common::span sp, vec[ast::ident] idents)
|
||||
-> @ast::expr {
|
||||
-> @ast::expr {
|
||||
let vec[@ast::ty] types = [];
|
||||
auto path = rec(idents=idents, types=types);
|
||||
auto sp_path = rec(node=path, span=sp);
|
||||
|
@ -102,15 +85,13 @@ fn pieces_to_expr(&ext_ctxt cx, common::span sp,
|
|||
auto sp_pathexpr = @rec(node=pathexpr, span=sp);
|
||||
ret sp_pathexpr;
|
||||
}
|
||||
|
||||
fn make_vec_expr(&ext_ctxt cx, common::span sp, vec[@ast::expr] exprs)
|
||||
-> @ast::expr {
|
||||
auto vecexpr = ast::expr_vec(exprs, ast::imm, ast::sk_rc,
|
||||
cx.next_ann());
|
||||
fn make_vec_expr(&ext_ctxt cx, common::span sp, vec[@ast::expr] exprs) ->
|
||||
@ast::expr {
|
||||
auto vecexpr =
|
||||
ast::expr_vec(exprs, ast::imm, ast::sk_rc, cx.next_ann());
|
||||
auto sp_vecexpr = @rec(node=vecexpr, span=sp);
|
||||
ret sp_vecexpr;
|
||||
}
|
||||
|
||||
fn make_call(&ext_ctxt cx, common::span sp, vec[ast::ident] fn_path,
|
||||
vec[@ast::expr] args) -> @ast::expr {
|
||||
auto pathexpr = make_path_expr(cx, sp, fn_path);
|
||||
|
@ -118,80 +99,64 @@ fn pieces_to_expr(&ext_ctxt cx, common::span sp,
|
|||
auto sp_callexpr = @rec(node=callexpr, span=sp);
|
||||
ret sp_callexpr;
|
||||
}
|
||||
|
||||
fn make_rec_expr(&ext_ctxt cx, common::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);
|
||||
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],
|
||||
cx.next_ann());
|
||||
auto recexpr =
|
||||
ast::expr_rec(astfields, option::none[@ast::expr], cx.next_ann());
|
||||
auto sp_recexpr = @rec(node=recexpr, span=sp);
|
||||
ret sp_recexpr;
|
||||
}
|
||||
|
||||
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,
|
||||
common::span sp, str ident) -> @ast::expr {
|
||||
fn make_rt_path_expr(&ext_ctxt cx, common::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,
|
||||
common::span sp, &conv cnv) -> @ast::expr {
|
||||
|
||||
fn make_flags(&ext_ctxt cx, common::span sp, vec[flag] flags)
|
||||
-> @ast::expr {
|
||||
fn make_rt_conv_expr(&ext_ctxt cx, common::span sp, &conv cnv) ->
|
||||
@ast::expr {
|
||||
fn make_flags(&ext_ctxt cx, common::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_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";
|
||||
}
|
||||
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,
|
||||
common::span sp, &count cnt) -> @ast::expr {
|
||||
fn make_count(&ext_ctxt cx, common::span sp, &count cnt) ->
|
||||
@ast::expr {
|
||||
alt (cnt) {
|
||||
case (count_implied) {
|
||||
ret make_rt_path_expr(cx, sp, "count_implied");
|
||||
|
@ -207,143 +172,96 @@ fn pieces_to_expr(&ext_ctxt cx, common::span sp,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn make_ty(&ext_ctxt cx, common::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 (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";
|
||||
}
|
||||
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,
|
||||
common::span sp,
|
||||
@ast::expr flags_expr,
|
||||
@ast::expr width_expr,
|
||||
@ast::expr precision_expr,
|
||||
fn make_conv_rec(&ext_ctxt cx, common::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)]);
|
||||
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);
|
||||
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, common::span sp, str conv_type,
|
||||
&conv cnv, @ast::expr arg) -> @ast::expr {
|
||||
fn make_conv_call(&ext_ctxt cx, common::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, common::span sp,
|
||||
conv cnv, @ast::expr arg) -> @ast::expr {
|
||||
|
||||
fn make_new_conv(&ext_ctxt cx, common::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 (signed) { ret true; }
|
||||
case (unsigned) { ret false; }
|
||||
}
|
||||
}
|
||||
case (_) {
|
||||
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);
|
||||
}
|
||||
case (option::none) { }
|
||||
case (_) { cx.span_unimpl(sp, unsupported); }
|
||||
}
|
||||
|
||||
for (flag f in cnv.flags) {
|
||||
alt (f) {
|
||||
case (flag_left_justify) {
|
||||
}
|
||||
case (flag_left_justify) { }
|
||||
case (flag_sign_always) {
|
||||
if (!is_signed_type(cnv)) {
|
||||
cx.span_err(sp, "+ flag only valid in "
|
||||
+ "signed #fmt conversion");
|
||||
cx.span_err(sp,
|
||||
"+ flag only valid in " +
|
||||
"signed #fmt conversion");
|
||||
}
|
||||
}
|
||||
case (flag_space_for_sign) {
|
||||
if (!is_signed_type(cnv)) {
|
||||
cx.span_err(sp, "space flag only valid in "
|
||||
+ "signed #fmt conversions");
|
||||
cx.span_err(sp,
|
||||
"space flag only valid in " +
|
||||
"signed #fmt conversions");
|
||||
}
|
||||
}
|
||||
case (flag_left_zero_pad) {
|
||||
}
|
||||
case (_) {
|
||||
cx.span_unimpl(sp, unsupported);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
|
@ -373,38 +291,21 @@ fn pieces_to_expr(&ext_ctxt cx, common::span sp,
|
|||
case (ty_octal) {
|
||||
ret make_conv_call(cx, arg.span, "uint", cnv, arg);
|
||||
}
|
||||
case (_) {
|
||||
cx.span_unimpl(sp, unsupported);
|
||||
}
|
||||
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";
|
||||
}
|
||||
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";
|
||||
}
|
||||
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) {
|
||||
|
@ -414,12 +315,8 @@ fn pieces_to_expr(&ext_ctxt cx, common::span sp,
|
|||
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";
|
||||
}
|
||||
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)) {
|
||||
|
@ -428,57 +325,33 @@ fn pieces_to_expr(&ext_ctxt cx, common::span sp,
|
|||
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";
|
||||
}
|
||||
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_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 (signed) { log "type: signed"; }
|
||||
case (unsigned) { log "type: unsigned"; }
|
||||
}
|
||||
}
|
||||
case (ty_bits) {
|
||||
log "type: bits";
|
||||
}
|
||||
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 (case_upper) { log "type: uhex"; }
|
||||
case (case_lower) { log "type: lhex"; }
|
||||
}
|
||||
}
|
||||
case (ty_octal) {
|
||||
log "type: octal";
|
||||
}
|
||||
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)) {
|
||||
|
@ -487,32 +360,28 @@ fn pieces_to_expr(&ext_ctxt cx, common::span sp,
|
|||
}
|
||||
case (piece_conv(?conv)) {
|
||||
n += 1u;
|
||||
|
||||
if (n >= nargs) {
|
||||
cx.span_err(sp, "not enough arguments to #fmt "
|
||||
+ "for the given format string");
|
||||
cx.span_err(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_err(sp,
|
||||
#fmt("too many arguments to #fmt. found %u, expected %u",
|
||||
nargs, expected_nargs));
|
||||
}
|
||||
|
||||
ret tmp_expr;
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
import std::io;
|
||||
import std::str;
|
||||
import std::vec;
|
||||
|
@ -11,59 +12,49 @@ import driver::session::session;
|
|||
import util::common;
|
||||
import util::common::*;
|
||||
import util::data::interner;
|
||||
import util::data::interner::intern;
|
||||
|
||||
state type reader = state 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 m);
|
||||
};
|
||||
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(session sess, io::reader rdr,
|
||||
codemap::filemap filemap,
|
||||
fn new_reader(session sess, io::reader rdr, codemap::filemap filemap,
|
||||
@interner::interner[str] itr) -> reader {
|
||||
|
||||
state obj reader(session sess,
|
||||
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;
|
||||
}
|
||||
|
||||
obj reader(session sess,
|
||||
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_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 curr() -> char { ret ch; }
|
||||
fn next() -> char {
|
||||
if (pos < len) {ret str::char_at(file, pos);}
|
||||
else {ret -1 as 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);
|
||||
|
@ -71,80 +62,47 @@ fn new_reader(session sess, io::reader rdr,
|
|||
ch = next._0;
|
||||
}
|
||||
}
|
||||
|
||||
fn bump() {
|
||||
if (pos < len) {
|
||||
col += 1u;
|
||||
chpos += 1u;
|
||||
if (ch == '\n') {
|
||||
codemap::next_line(fm, chpos);
|
||||
col = 0u;
|
||||
}
|
||||
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;
|
||||
}
|
||||
} 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) {
|
||||
sess.span_err(rec(lo=chpos, hi=chpos), m);
|
||||
}
|
||||
fn get_col() -> uint { ret col; }
|
||||
fn get_filemap() -> codemap::filemap { ret fm; }
|
||||
fn err(str m) { sess.span_err(rec(lo=chpos, hi=chpos), m); }
|
||||
}
|
||||
auto file = str::unsafe_from_bytes(rdr.read_whole_stream());
|
||||
let vec[str] strs = [];
|
||||
auto rd = reader(sess, file, str::byte_len(file), 0u, 0u,
|
||||
-1 as char, filemap.start_pos, filemap.start_pos,
|
||||
strs, filemap, itr);
|
||||
auto rd =
|
||||
reader(sess, 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 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;
|
||||
}
|
||||
|
||||
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 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 consume_whitespace_and_comments(&reader rdr) {
|
||||
while (is_whitespace(rdr.curr())) {
|
||||
rdr.bump();
|
||||
}
|
||||
while (is_whitespace(rdr.curr())) { rdr.bump(); }
|
||||
be consume_any_line_comment(rdr);
|
||||
}
|
||||
|
||||
|
@ -152,10 +110,9 @@ fn consume_any_line_comment(&reader rdr) {
|
|||
if (rdr.curr() == '/') {
|
||||
alt (rdr.next()) {
|
||||
case ('/') {
|
||||
while (rdr.curr() != '\n' && !rdr.is_eof()) {
|
||||
rdr.bump();
|
||||
}
|
||||
while (rdr.curr() != '\n' && !rdr.is_eof()) { rdr.bump(); }
|
||||
// Restart whitespace munch.
|
||||
|
||||
be consume_whitespace_and_comments(rdr);
|
||||
}
|
||||
case ('*') {
|
||||
|
@ -163,21 +120,15 @@ fn consume_any_line_comment(&reader rdr) {
|
|||
rdr.bump();
|
||||
be consume_block_comment(rdr);
|
||||
}
|
||||
case (_) {
|
||||
ret;
|
||||
}
|
||||
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.is_eof()) { rdr.err("unterminated block comment"); fail; }
|
||||
if (rdr.curr() == '/' && rdr.next() == '*') {
|
||||
rdr.bump();
|
||||
rdr.bump();
|
||||
|
@ -187,32 +138,27 @@ fn consume_block_comment(&reader rdr) {
|
|||
rdr.bump();
|
||||
rdr.bump();
|
||||
level -= 1;
|
||||
} else {
|
||||
rdr.bump();
|
||||
}
|
||||
} else { rdr.bump(); }
|
||||
}
|
||||
}
|
||||
// restart whitespace munch.
|
||||
|
||||
be consume_whitespace_and_comments(rdr);
|
||||
}
|
||||
|
||||
fn digits_to_string(str s) -> int {
|
||||
|
||||
let int accum_int = 0;
|
||||
let int i = 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 res = "";
|
||||
|
||||
if (c == 'e' || c == 'E') {
|
||||
res += str::from_bytes([c as u8]);
|
||||
rdr.bump();
|
||||
|
@ -223,31 +169,19 @@ fn scan_exponent(&reader rdr) -> option::t[str] {
|
|||
}
|
||||
auto exponent = scan_dec_digits(rdr);
|
||||
if (str::byte_len(exponent) > 0u) {
|
||||
ret(some(res + exponent));
|
||||
}
|
||||
else {
|
||||
rdr.err("scan_exponent: bad fp literal");
|
||||
fail;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ret none[str];
|
||||
}
|
||||
ret some(res + 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 res = "";
|
||||
|
||||
while (is_dec_digit (c) || c == '_') {
|
||||
if (c != '_') {
|
||||
res += str::from_bytes([c as u8]);
|
||||
}
|
||||
while (is_dec_digit(c) || c == '_') {
|
||||
if (c != '_') { res += str::from_bytes([c as u8]); }
|
||||
rdr.bump();
|
||||
c = rdr.curr();
|
||||
}
|
||||
|
||||
ret res;
|
||||
}
|
||||
|
||||
|
@ -256,16 +190,12 @@ fn scan_number(char c, &reader rdr) -> token::token {
|
|||
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);
|
||||
}
|
||||
if (c != '_') { accum_int *= 16; accum_int += hex_digit_val(c); }
|
||||
rdr.bump();
|
||||
c = rdr.curr();
|
||||
}
|
||||
|
@ -274,125 +204,100 @@ fn scan_number(char c, &reader rdr) -> token::token {
|
|||
rdr.bump();
|
||||
c = rdr.curr();
|
||||
while (is_bin_digit(c) || c == '_') {
|
||||
if (c != '_') {
|
||||
accum_int *= 2;
|
||||
accum_int += bin_digit_value(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);
|
||||
}
|
||||
|
||||
} 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');
|
||||
let bool signed = c == 'i';
|
||||
rdr.bump();
|
||||
c = rdr.curr();
|
||||
if (c == '8') {
|
||||
rdr.bump();
|
||||
if (signed) {
|
||||
ret token::LIT_MACH_INT(common::ty_i8, accum_int);
|
||||
} else {
|
||||
ret token::LIT_MACH_INT(common::ty_u8, accum_int);
|
||||
}
|
||||
} else { ret token::LIT_MACH_INT(common::ty_u8, accum_int); }
|
||||
}
|
||||
|
||||
n = rdr.next();
|
||||
if (c == '1' && n == '6') {
|
||||
rdr.bump();
|
||||
rdr.bump();
|
||||
if (signed) {
|
||||
ret token::LIT_MACH_INT(common::ty_i16, accum_int);
|
||||
} else {
|
||||
ret token::LIT_MACH_INT(common::ty_u16, accum_int);
|
||||
}
|
||||
} else { ret token::LIT_MACH_INT(common::ty_u16, accum_int); }
|
||||
}
|
||||
if (c == '3' && n == '2') {
|
||||
rdr.bump();
|
||||
rdr.bump();
|
||||
if (signed) {
|
||||
ret token::LIT_MACH_INT(common::ty_i32, accum_int);
|
||||
} else {
|
||||
ret token::LIT_MACH_INT(common::ty_u32, accum_int);
|
||||
}
|
||||
} else { ret token::LIT_MACH_INT(common::ty_u32, accum_int); }
|
||||
}
|
||||
|
||||
if (c == '6' && n == '4') {
|
||||
rdr.bump();
|
||||
rdr.bump();
|
||||
if (signed) {
|
||||
ret token::LIT_MACH_INT(common::ty_i64, accum_int);
|
||||
} else {
|
||||
ret token::LIT_MACH_INT(common::ty_u64, accum_int);
|
||||
}
|
||||
} else { ret token::LIT_MACH_INT(common::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) {
|
||||
}
|
||||
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();
|
||||
rdr.bump();
|
||||
rdr.bump();
|
||||
ret token::LIT_MACH_FLOAT(util::common::ty_f32,
|
||||
interner::intern[str](*rdr.get_interner(), float_str));
|
||||
}
|
||||
else if (c == '6' && n == '4') {
|
||||
rdr.bump(); rdr.bump();
|
||||
intern(*rdr.get_interner(),
|
||||
float_str));
|
||||
} else if (c == '6' && n == '4') {
|
||||
rdr.bump();
|
||||
rdr.bump();
|
||||
ret token::LIT_MACH_FLOAT(util::common::ty_f64,
|
||||
interner::intern[str](*rdr.get_interner(), float_str));
|
||||
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 {
|
||||
} 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)) {
|
||||
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);
|
||||
}
|
||||
case (none) { ret token::LIT_INT(accum_int); }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -412,50 +317,38 @@ fn scan_numeric_escape(&reader rdr, uint n_hex_digits) -> char {
|
|||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
} else { ret token::BINOP(op); }
|
||||
}
|
||||
|
||||
alt (c) {
|
||||
// One-byte tokens.
|
||||
case ('?') { rdr.bump(); ret token::QUES; }
|
||||
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; }
|
||||
|
@ -473,80 +366,47 @@ fn next_token(&reader rdr) -> token::token {
|
|||
if (rdr.curr() == ':') {
|
||||
rdr.bump();
|
||||
ret token::MOD_SEP;
|
||||
}
|
||||
else {
|
||||
ret token::COLON;
|
||||
};
|
||||
} else { ret token::COLON; }
|
||||
}
|
||||
|
||||
// Multi-byte tokens.
|
||||
case ('=') {
|
||||
case (
|
||||
// Multi-byte tokens.
|
||||
'=') {
|
||||
rdr.bump();
|
||||
if (rdr.curr() == '=') {
|
||||
rdr.bump();
|
||||
ret token::EQEQ;
|
||||
} else {
|
||||
ret token::EQ;
|
||||
}
|
||||
} else { ret token::EQ; }
|
||||
}
|
||||
|
||||
case ('!') {
|
||||
rdr.bump();
|
||||
if (rdr.curr() == '=') {
|
||||
rdr.bump();
|
||||
ret token::NE;
|
||||
} else {
|
||||
ret token::NOT;
|
||||
}
|
||||
} 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::LARROW;
|
||||
}
|
||||
case ('|') {
|
||||
rdr.bump();
|
||||
ret token::SEND;
|
||||
}
|
||||
case (_) {
|
||||
ret token::LT;
|
||||
}
|
||||
case ('=') { rdr.bump(); ret token::LE; }
|
||||
case ('<') { ret binop(rdr, token::LSL); }
|
||||
case ('-') { rdr.bump(); ret token::LARROW; }
|
||||
case ('|') { rdr.bump(); ret token::SEND; }
|
||||
case (_) { ret token::LT; }
|
||||
}
|
||||
}
|
||||
|
||||
case ('>') {
|
||||
rdr.bump();
|
||||
alt (rdr.curr()) {
|
||||
case ('=') {
|
||||
rdr.bump();
|
||||
ret token::GE;
|
||||
}
|
||||
|
||||
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;
|
||||
} else { ret binop(rdr, token::LSR); }
|
||||
}
|
||||
case (_) { ret token::GT; }
|
||||
}
|
||||
}
|
||||
|
||||
case ('\'') {
|
||||
rdr.bump();
|
||||
auto c2 = rdr.curr();
|
||||
|
@ -560,11 +420,9 @@ fn next_token(&reader rdr) -> token::token {
|
|||
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));
|
||||
|
@ -572,15 +430,14 @@ fn next_token(&reader rdr) -> token::token {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
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() != '"') {
|
||||
|
@ -606,25 +463,19 @@ fn next_token(&reader rdr) -> token::token {
|
|||
case ('"') {
|
||||
str::push_byte(accum_str, '"' as u8);
|
||||
}
|
||||
case ('\n') {
|
||||
consume_whitespace(rdr);
|
||||
}
|
||||
|
||||
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));
|
||||
|
@ -632,88 +483,54 @@ fn next_token(&reader rdr) -> token::token {
|
|||
}
|
||||
}
|
||||
}
|
||||
case (_) {
|
||||
str::push_char(accum_str, ch);
|
||||
}
|
||||
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);
|
||||
}
|
||||
} else { ret binop(rdr, token::MINUS); }
|
||||
}
|
||||
|
||||
case ('&') {
|
||||
if (rdr.next() == '&') {
|
||||
rdr.bump();
|
||||
rdr.bump();
|
||||
ret token::ANDAND;
|
||||
} else {
|
||||
ret binop(rdr, token::AND);
|
||||
}
|
||||
} 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 ('|') { 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 ('+') { 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
|
||||
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
|
||||
|
||||
}
|
||||
|
||||
type cmnt = rec(cmnt_style style, vec[str] lines, uint pos);
|
||||
|
@ -724,80 +541,64 @@ fn read_to_eol(&reader rdr) -> str {
|
|||
str::push_char(val, rdr.curr());
|
||||
rdr.bump();
|
||||
}
|
||||
if (rdr.curr() == '\n') {
|
||||
rdr.bump();
|
||||
} else {
|
||||
assert rdr.is_eof();
|
||||
}
|
||||
if (rdr.curr() == '\n') { rdr.bump(); } else { assert (rdr.is_eof()); }
|
||||
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);
|
||||
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();
|
||||
}
|
||||
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()) {
|
||||
while (is_whitespace(rdr.curr()) && rdr.curr() != '\n' && !rdr.is_eof()) {
|
||||
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);
|
||||
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,
|
||||
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;
|
||||
}
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
} else { s1 = ""; }
|
||||
} else { s1 = s; }
|
||||
log "pushing line: " + s1;
|
||||
lines += [s1];
|
||||
}
|
||||
|
||||
fn read_block_comment(&reader rdr,
|
||||
bool code_to_the_left) -> cmnt {
|
||||
fn read_block_comment(&reader rdr, bool code_to_the_left) -> cmnt {
|
||||
log ">>> block comment";
|
||||
auto p = rdr.get_chpos();
|
||||
let vec[str] lines = [];
|
||||
|
@ -808,10 +609,7 @@ fn read_block_comment(&reader rdr,
|
|||
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.is_eof()) { rdr.err("unterminated block comment"); fail; }
|
||||
if (rdr.curr() == '\n') {
|
||||
trim_whitespace_prefix_and_push_line(lines, curr_line, col);
|
||||
curr_line = "";
|
||||
|
@ -829,63 +627,56 @@ fn read_block_comment(&reader rdr,
|
|||
rdr.bump();
|
||||
curr_line += "/";
|
||||
level -= 1;
|
||||
} else {
|
||||
rdr.bump();
|
||||
}
|
||||
} 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) {
|
||||
if (!rdr.is_eof() && rdr.curr() != '\n' && vec::len(lines) == 1u) {
|
||||
style = mixed;
|
||||
}
|
||||
log "<<< block comment";
|
||||
ret rec(style = style, lines = lines, pos=p);
|
||||
ret rec(style=style, lines=lines, pos=p);
|
||||
}
|
||||
|
||||
fn peeking_at_comment(&reader rdr) -> bool {
|
||||
ret (rdr.curr() == '/' && rdr.next() == '/') ||
|
||||
(rdr.curr() == '/' && rdr.next() == '*');
|
||||
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));
|
||||
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));
|
||||
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 }
|
||||
}
|
||||
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(session sess, str path)
|
||||
-> rec(vec[cmnt] cmnts, vec[lit] lits) {
|
||||
fn gather_comments_and_literals(session sess, 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(sess, srdr, codemap::new_filemap(path, 0u), itr);
|
||||
|
@ -907,15 +698,14 @@ fn gather_comments_and_literals(session sess, str path)
|
|||
break;
|
||||
}
|
||||
if (is_lit(next_token(rdr))) {
|
||||
vec::push[lit](literals, rec(lit=rdr.get_mark_str(),
|
||||
pos=rdr.get_mark_chpos()));
|
||||
vec::push[lit](literals,
|
||||
rec(lit=rdr.get_mark_str(),
|
||||
pos=rdr.get_mark_chpos()));
|
||||
}
|
||||
first_read = false;
|
||||
}
|
||||
ret rec(cmnts=comments, lits=literals);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,3 +1,4 @@
|
|||
|
||||
import util::common::ty_mach;
|
||||
import util::common::ty_mach_to_str;
|
||||
import util::common::new_str_hash;
|
||||
|
@ -23,6 +24,7 @@ tag binop {
|
|||
}
|
||||
|
||||
tag token {
|
||||
|
||||
/* Expression-operator symbols. */
|
||||
EQ;
|
||||
LT;
|
||||
|
@ -35,7 +37,6 @@ tag token {
|
|||
OROR;
|
||||
NOT;
|
||||
TILDE;
|
||||
|
||||
BINOP(binop);
|
||||
BINOPEQ(binop);
|
||||
|
||||
|
@ -57,7 +58,6 @@ tag token {
|
|||
RBRACKET;
|
||||
LBRACE;
|
||||
RBRACE;
|
||||
|
||||
POUND;
|
||||
|
||||
/* Literals */
|
||||
|
@ -74,7 +74,6 @@ tag token {
|
|||
IDENT(str_num, bool);
|
||||
IDX(int);
|
||||
UNDERSCORE;
|
||||
|
||||
BRACEQUOTE(str_num);
|
||||
EOF;
|
||||
}
|
||||
|
@ -97,7 +96,6 @@ fn binop_to_str(binop o) -> str {
|
|||
|
||||
fn to_str(lexer::reader r, token t) -> str {
|
||||
alt (t) {
|
||||
|
||||
case (EQ) { ret "="; }
|
||||
case (LT) { ret "<"; }
|
||||
case (LE) { ret "<="; }
|
||||
|
@ -109,12 +107,13 @@ fn to_str(lexer::reader r, token t) -> str {
|
|||
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) + "="; }
|
||||
|
||||
/* Structural symbols */
|
||||
case (AT) { ret "@"; }
|
||||
case (
|
||||
/* Structural symbols */
|
||||
AT) {
|
||||
ret "@";
|
||||
}
|
||||
case (DOT) { ret "."; }
|
||||
case (COMMA) { ret ","; }
|
||||
case (SEMI) { ret ";"; }
|
||||
|
@ -131,49 +130,46 @@ fn to_str(lexer::reader r, token t) -> str {
|
|||
case (RBRACKET) { ret "]"; }
|
||||
case (LBRACE) { ret "{"; }
|
||||
case (RBRACE) { ret "}"; }
|
||||
|
||||
case (POUND) { ret "#"; }
|
||||
|
||||
/* Literals */
|
||||
case (LIT_INT(?i)) { ret int::to_str(i, 10u); }
|
||||
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);
|
||||
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);
|
||||
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 (LIT_BOOL(?b)) { if (b) { ret "true"; } else { ret "false"; } }
|
||||
case (
|
||||
/* Name components */
|
||||
IDENT(?s, _)) {
|
||||
ret interner::get[str](*r.get_interner(), s);
|
||||
}
|
||||
|
||||
/* Name components */
|
||||
case (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>"; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Local Variables:
|
||||
// fill-column: 78;
|
||||
// indent-tabs-mode: nil
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
import front::ast;
|
||||
import front::ast::ident;
|
||||
import front::ast::def_num;
|
||||
|
@ -10,6 +11,7 @@ import std::option::some;
|
|||
import std::option::none;
|
||||
import std::option::is_none;
|
||||
|
||||
|
||||
// This is not an alias-analyser (though it would merit from becoming one, or
|
||||
// at getting input from one, to be more precise). It is a pass that checks
|
||||
// whether aliases are used in a safe way. Beyond that, though it doesn't have
|
||||
|
@ -17,40 +19,38 @@ import std::option::is_none;
|
|||
// (using an lval, which is actually mutable), since it already has all the
|
||||
// information needed to do that (and the typechecker, which would be a
|
||||
// logical place for such a check, doesn't).
|
||||
tag valid { valid; overwritten(span, ast::path); val_taken(span, ast::path); }
|
||||
|
||||
tag valid {
|
||||
valid;
|
||||
overwritten(span, ast::path);
|
||||
val_taken(span, ast::path);
|
||||
}
|
||||
type restrict =
|
||||
@rec(vec[def_num] root_vars,
|
||||
def_num block_defnum,
|
||||
vec[def_num] bindings,
|
||||
vec[ty::t] tys,
|
||||
vec[uint] depends_on,
|
||||
mutable valid ok);
|
||||
|
||||
type restrict = @rec(vec[def_num] root_vars,
|
||||
def_num block_defnum,
|
||||
vec[def_num] bindings,
|
||||
vec[ty::t] tys,
|
||||
vec[uint] depends_on,
|
||||
mutable valid ok);
|
||||
type scope = vec[restrict];
|
||||
|
||||
tag local_info {
|
||||
arg(ast::mode);
|
||||
objfield(ast::mutability);
|
||||
}
|
||||
tag local_info { arg(ast::mode); objfield(ast::mutability); }
|
||||
|
||||
type ctx = rec(@ty::ctxt tcx,
|
||||
resolve::def_map dm,
|
||||
std::map::hashmap[def_num,local_info] local_map);
|
||||
type ctx =
|
||||
rec(@ty::ctxt tcx,
|
||||
resolve::def_map dm,
|
||||
std::map::hashmap[def_num, local_info] local_map);
|
||||
|
||||
fn check_crate(@ty::ctxt tcx, resolve::def_map dm, &@ast::crate crate) {
|
||||
auto cx = @rec(tcx = tcx,
|
||||
dm = dm,
|
||||
// Stores information about object fields and function
|
||||
// arguments that's otherwise not easily available.
|
||||
local_map = util::common::new_int_hash());
|
||||
auto v = @rec(visit_fn = bind visit_fn(cx, _, _, _, _, _, _, _, _),
|
||||
visit_item = bind visit_item(cx, _, _, _),
|
||||
visit_expr = bind visit_expr(cx, _, _, _)
|
||||
with *visit::default_visitor[scope]());
|
||||
auto cx =
|
||||
@rec(tcx=tcx,
|
||||
dm=dm,
|
||||
|
||||
// Stores information about object fields and function
|
||||
// arguments that's otherwise not easily available.
|
||||
local_map=util::common::new_int_hash());
|
||||
auto v =
|
||||
@rec(visit_fn=bind visit_fn(cx, _, _, _, _, _, _, _, _),
|
||||
visit_item=bind visit_item(cx, _, _, _),
|
||||
visit_expr=bind visit_expr(cx, _, _, _)
|
||||
with *visit::default_visitor[scope]());
|
||||
visit::visit_crate(*crate, [], visit::vtor(v));
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,7 @@ fn visit_item(@ctx cx, &@ast::item i, &scope sc, &vt[scope] v) {
|
|||
cx.local_map.insert(f.id._1, objfield(f.mut));
|
||||
}
|
||||
}
|
||||
case (_) {}
|
||||
case (_) { }
|
||||
}
|
||||
visit::visit_item(i, sc, v);
|
||||
}
|
||||
|
@ -79,9 +79,7 @@ fn visit_item(@ctx cx, &@ast::item i, &scope sc, &vt[scope] v) {
|
|||
fn visit_expr(@ctx cx, &@ast::expr ex, &scope sc, &vt[scope] v) {
|
||||
auto handled = false;
|
||||
alt (ex.node) {
|
||||
case (ast::expr_call(?f, ?args, _)) {
|
||||
check_call(*cx, f, args, sc);
|
||||
}
|
||||
case (ast::expr_call(?f, ?args, _)) { check_call(*cx, f, args, sc); }
|
||||
case (ast::expr_alt(?input, ?arms, _)) {
|
||||
check_alt(*cx, input, arms, sc, v);
|
||||
handled = true;
|
||||
|
@ -91,13 +89,13 @@ fn visit_expr(@ctx cx, &@ast::expr ex, &scope sc, &vt[scope] v) {
|
|||
case (some(?ex)) {
|
||||
auto root = expr_root(*cx, ex, false);
|
||||
if (mut_field(root.ds)) {
|
||||
cx.tcx.sess.span_err
|
||||
(ex.span,
|
||||
"result of put must be immutably rooted");
|
||||
cx.tcx.sess.span_err(ex.span,
|
||||
"result of put must be"
|
||||
+ " immutably rooted");
|
||||
}
|
||||
visit_expr(cx, ex, sc, v);
|
||||
}
|
||||
case (_) {}
|
||||
case (_) { }
|
||||
}
|
||||
handled = true;
|
||||
}
|
||||
|
@ -109,7 +107,6 @@ fn visit_expr(@ctx cx, &@ast::expr ex, &scope sc, &vt[scope] v) {
|
|||
check_for(*cx, decl, seq, block, sc, v);
|
||||
handled = true;
|
||||
}
|
||||
|
||||
case (ast::expr_path(?pt, ?ann)) {
|
||||
check_var(*cx, ex, pt, ann, false, sc);
|
||||
}
|
||||
|
@ -125,25 +122,23 @@ fn visit_expr(@ctx cx, &@ast::expr ex, &scope sc, &vt[scope] v) {
|
|||
check_assign(cx, dest, src, sc, v);
|
||||
handled = true;
|
||||
}
|
||||
|
||||
case (_) {}
|
||||
case (_) { }
|
||||
}
|
||||
if (!handled) { visit::visit_expr(ex, sc, v); }
|
||||
}
|
||||
|
||||
fn check_call(&ctx cx, &@ast::expr f, &vec[@ast::expr] args, &scope sc)
|
||||
-> rec(vec[def_num] root_vars, vec[ty::t] unsafe_ts) {
|
||||
fn check_call(&ctx cx, &@ast::expr f, &vec[@ast::expr] args, &scope sc) ->
|
||||
rec(vec[def_num] root_vars, vec[ty::t] unsafe_ts) {
|
||||
auto fty = ty::expr_ty(*cx.tcx, f);
|
||||
auto arg_ts = alt (ty::struct(*cx.tcx, fty)) {
|
||||
case (ty::ty_fn(_, ?args, _, _, _)) { args }
|
||||
case (ty::ty_native_fn(_, ?args, _)) { args }
|
||||
};
|
||||
|
||||
auto arg_ts =
|
||||
alt (ty::struct(*cx.tcx, fty)) {
|
||||
case (ty::ty_fn(_, ?args, _, _, _)) { args }
|
||||
case (ty::ty_native_fn(_, ?args, _)) { args }
|
||||
};
|
||||
let vec[def_num] roots = [];
|
||||
let vec[tup(uint, def_num)] mut_roots = [];
|
||||
let vec[ty::t] unsafe_ts = [];
|
||||
let vec[uint] unsafe_t_offsets = [];
|
||||
|
||||
auto i = 0u;
|
||||
for (ty::arg arg_t in arg_ts) {
|
||||
if (arg_t.mode != ty::mo_val) {
|
||||
|
@ -156,39 +151,38 @@ fn check_call(&ctx cx, &@ast::expr f, &vec[@ast::expr] args, &scope sc)
|
|||
}
|
||||
case (_) {
|
||||
if (!mut_field(root.ds)) {
|
||||
cx.tcx.sess.span_err
|
||||
(arg.span, "passing a temporary value or \
|
||||
immutable field by mutable alias");
|
||||
auto m = "passing a temporary value or \
|
||||
immutable field by mutable alias";
|
||||
cx.tcx.sess.span_err(arg.span, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
alt (path_def_id(cx, root.ex)) {
|
||||
case (some(?did)) { vec::push(roots, did._1); }
|
||||
case (_) {}
|
||||
case (_) { }
|
||||
}
|
||||
alt (inner_mut(root.ds)) {
|
||||
case (some(?t)) {
|
||||
vec::push(unsafe_ts, t);
|
||||
vec::push(unsafe_t_offsets, i);
|
||||
}
|
||||
case (_) {}
|
||||
case (_) { }
|
||||
}
|
||||
}
|
||||
i += 1u;
|
||||
}
|
||||
|
||||
if (vec::len(unsafe_ts) > 0u) {
|
||||
alt (f.node) {
|
||||
case (ast::expr_path(_, ?ann)) {
|
||||
if (def_is_local(cx.dm.get(ann.id))) {
|
||||
cx.tcx.sess.span_err
|
||||
(f.span, #fmt("function may alias with argument \
|
||||
%u, which is not immutably rooted",
|
||||
unsafe_t_offsets.(0)));
|
||||
cx.tcx.sess.span_err(f.span,
|
||||
#fmt("function may alias with \
|
||||
argument %u, which is not immutably rooted",
|
||||
unsafe_t_offsets.(0)));
|
||||
}
|
||||
}
|
||||
case (_) {}
|
||||
case (_) { }
|
||||
}
|
||||
}
|
||||
auto j = 0u;
|
||||
|
@ -199,16 +193,18 @@ fn check_call(&ctx cx, &@ast::expr f, &vec[@ast::expr] args, &scope sc)
|
|||
for (ty::arg arg_t in arg_ts) {
|
||||
auto mut_alias = arg_t.mode == ty::mo_alias(true);
|
||||
if (i != offset &&
|
||||
ty_can_unsafely_include(cx, unsafe, arg_t.ty, mut_alias)) {
|
||||
cx.tcx.sess.span_err
|
||||
(args.(i).span, #fmt("argument %u may alias with \
|
||||
argument %u, which is not immutably rooted", i, offset));
|
||||
ty_can_unsafely_include(cx, unsafe, arg_t.ty, mut_alias))
|
||||
{
|
||||
cx.tcx.sess.span_err(args.(i).span,
|
||||
#fmt("argument %u may alias with \
|
||||
argument %u, which is not immutably rooted",
|
||||
i, offset));
|
||||
}
|
||||
i += 1u;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure we're not passing a root by mutable alias.
|
||||
|
||||
for (tup(uint, def_num) root in mut_roots) {
|
||||
auto mut_alias_to_root = vec::count(root._1, roots) > 1u;
|
||||
for (restrict r in sc) {
|
||||
|
@ -217,38 +213,37 @@ fn check_call(&ctx cx, &@ast::expr f, &vec[@ast::expr] args, &scope sc)
|
|||
}
|
||||
}
|
||||
if (mut_alias_to_root) {
|
||||
cx.tcx.sess.span_err
|
||||
(args.(root._0).span, "passing a mutable alias to a \
|
||||
cx.tcx.sess.span_err(args.(root._0).span,
|
||||
"passing a mutable alias to a \
|
||||
variable that roots another alias");
|
||||
}
|
||||
}
|
||||
|
||||
ret rec(root_vars = roots, unsafe_ts = unsafe_ts);
|
||||
ret rec(root_vars=roots, unsafe_ts=unsafe_ts);
|
||||
}
|
||||
|
||||
fn check_alt(&ctx cx, &@ast::expr input, &vec[ast::arm] arms,
|
||||
&scope sc, &vt[scope] v) {
|
||||
fn check_alt(&ctx cx, &@ast::expr input, &vec[ast::arm] arms, &scope sc,
|
||||
&vt[scope] v) {
|
||||
visit::visit_expr(input, sc, v);
|
||||
auto root = expr_root(cx, input, true);
|
||||
auto roots = alt (path_def_id(cx, root.ex)) {
|
||||
case (some(?did)) { [did._1] }
|
||||
case (_) { [] }
|
||||
};
|
||||
let vec[ty::t] forbidden_tp = alt (inner_mut(root.ds)) {
|
||||
case (some(?t)) { [t] }
|
||||
case (_) { [] }
|
||||
};
|
||||
|
||||
auto roots =
|
||||
alt (path_def_id(cx, root.ex)) {
|
||||
case (some(?did)) { [did._1] }
|
||||
case (_) { [] }
|
||||
};
|
||||
let vec[ty::t] forbidden_tp =
|
||||
alt (inner_mut(root.ds)) { case (some(?t)) { [t] } case (_) { [] } };
|
||||
for (ast::arm a in arms) {
|
||||
auto dnums = arm_defnums(a);
|
||||
auto new_sc = sc;
|
||||
if (vec::len(dnums) > 0u) {
|
||||
new_sc = sc + [@rec(root_vars=roots,
|
||||
block_defnum=dnums.(0),
|
||||
bindings=dnums,
|
||||
tys=forbidden_tp,
|
||||
depends_on=deps(sc, roots),
|
||||
mutable ok=valid)];
|
||||
new_sc =
|
||||
sc +
|
||||
[@rec(root_vars=roots,
|
||||
block_defnum=dnums.(0),
|
||||
bindings=dnums,
|
||||
tys=forbidden_tp,
|
||||
depends_on=deps(sc, roots),
|
||||
mutable ok=valid)];
|
||||
}
|
||||
visit::visit_arm(a, new_sc, v);
|
||||
}
|
||||
|
@ -258,15 +253,11 @@ fn arm_defnums(&ast::arm arm) -> vec[def_num] {
|
|||
auto dnums = [];
|
||||
fn walk_pat(&mutable vec[def_num] found, &@ast::pat p) {
|
||||
alt (p.node) {
|
||||
case (ast::pat_bind(_, ?did, _)) {
|
||||
vec::push(found, did._1);
|
||||
}
|
||||
case (ast::pat_bind(_, ?did, _)) { vec::push(found, did._1); }
|
||||
case (ast::pat_tag(_, ?children, _)) {
|
||||
for (@ast::pat child in children) {
|
||||
walk_pat(found, child);
|
||||
}
|
||||
for (@ast::pat child in children) { walk_pat(found, child); }
|
||||
}
|
||||
case (_) {}
|
||||
case (_) { }
|
||||
}
|
||||
}
|
||||
walk_pat(dnums, arm.pat);
|
||||
|
@ -280,47 +271,46 @@ fn check_for_each(&ctx cx, &@ast::local local, &@ast::expr call,
|
|||
case (ast::expr_call(?f, ?args, _)) {
|
||||
auto data = check_call(cx, f, args, sc);
|
||||
auto defnum = local.node.id._1;
|
||||
|
||||
auto new_sc = @rec(root_vars=data.root_vars,
|
||||
block_defnum=defnum,
|
||||
bindings=[defnum],
|
||||
tys=data.unsafe_ts,
|
||||
depends_on=deps(sc, data.root_vars),
|
||||
mutable ok=valid);
|
||||
auto new_sc =
|
||||
@rec(root_vars=data.root_vars,
|
||||
block_defnum=defnum,
|
||||
bindings=[defnum],
|
||||
tys=data.unsafe_ts,
|
||||
depends_on=deps(sc, data.root_vars),
|
||||
mutable ok=valid);
|
||||
visit::visit_block(block, sc + [new_sc], v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_for(&ctx cx, &@ast::local local, &@ast::expr seq,
|
||||
&ast::block block, &scope sc, &vt[scope] v) {
|
||||
fn check_for(&ctx cx, &@ast::local local, &@ast::expr seq, &ast::block block,
|
||||
&scope sc, &vt[scope] v) {
|
||||
visit::visit_expr(seq, sc, v);
|
||||
auto defnum = local.node.id._1;
|
||||
|
||||
auto root = expr_root(cx, seq, false);
|
||||
auto root_def = alt (path_def_id(cx, root.ex)) {
|
||||
case (some(?did)) { [did._1] }
|
||||
case (_) { [] }
|
||||
};
|
||||
auto unsafe = alt (inner_mut(root.ds)) {
|
||||
case (some(?t)) { [t] }
|
||||
case (_) { [] }
|
||||
};
|
||||
auto root_def =
|
||||
alt (path_def_id(cx, root.ex)) {
|
||||
case (some(?did)) { [did._1] }
|
||||
case (_) { [] }
|
||||
};
|
||||
auto unsafe =
|
||||
alt (inner_mut(root.ds)) { case (some(?t)) { [t] } case (_) { [] } };
|
||||
// If this is a mutable vector, don't allow it to be touched.
|
||||
|
||||
auto seq_t = ty::expr_ty(*cx.tcx, seq);
|
||||
alt (ty::struct(*cx.tcx, seq_t)) {
|
||||
case (ty::ty_vec(?mt)) {
|
||||
if (mt.mut != ast::imm) { unsafe = [seq_t]; }
|
||||
}
|
||||
case (ty::ty_str) {}
|
||||
case (ty::ty_str) { }
|
||||
}
|
||||
|
||||
auto new_sc = @rec(root_vars=root_def,
|
||||
block_defnum=defnum,
|
||||
bindings=[defnum],
|
||||
tys=unsafe,
|
||||
depends_on=deps(sc, root_def),
|
||||
mutable ok=valid);
|
||||
auto new_sc =
|
||||
@rec(root_vars=root_def,
|
||||
block_defnum=defnum,
|
||||
bindings=[defnum],
|
||||
tys=unsafe,
|
||||
depends_on=deps(sc, root_def),
|
||||
mutable ok=valid);
|
||||
visit::visit_block(block, sc + [new_sc], v);
|
||||
}
|
||||
|
||||
|
@ -331,6 +321,7 @@ fn check_var(&ctx cx, &@ast::expr ex, &ast::path p, ast::ann ann, bool assign,
|
|||
auto my_defnum = ast::def_id_of_def(def)._1;
|
||||
auto var_t = ty::expr_ty(*cx.tcx, ex);
|
||||
for (restrict r in sc) {
|
||||
|
||||
// excludes variables introduced since the alias was made
|
||||
if (my_defnum < r.block_defnum) {
|
||||
for (ty::t t in r.tys) {
|
||||
|
@ -344,22 +335,21 @@ fn check_var(&ctx cx, &@ast::expr ex, &ast::path p, ast::ann ann, bool assign,
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME does not catch assigning to immutable object fields yet
|
||||
fn check_assign(&@ctx cx, &@ast::expr dest, &@ast::expr src,
|
||||
&scope sc, &vt[scope] v) {
|
||||
visit_expr(cx, src, sc, v);
|
||||
|
||||
// FIXME does not catch assigning to immutable object fields yet
|
||||
fn check_assign(&@ctx cx, &@ast::expr dest, &@ast::expr src, &scope sc,
|
||||
&vt[scope] v) {
|
||||
visit_expr(cx, src, sc, v);
|
||||
alt (dest.node) {
|
||||
case (ast::expr_path(?p, ?ann)) {
|
||||
auto dnum = ast::def_id_of_def(cx.dm.get(ann.id))._1;
|
||||
if (is_immutable_alias(cx, sc, dnum)) {
|
||||
cx.tcx.sess.span_err
|
||||
(dest.span, "assigning to immutable alias");
|
||||
cx.tcx.sess.span_err(dest.span,
|
||||
"assigning to immutable alias");
|
||||
} else if (is_immutable_objfield(cx, dnum)) {
|
||||
cx.tcx.sess.span_err
|
||||
(dest.span, "assigning to immutable obj field");
|
||||
cx.tcx.sess.span_err(dest.span,
|
||||
"assigning to immutable obj field");
|
||||
}
|
||||
|
||||
auto var_t = ty::expr_ty(*cx.tcx, dest);
|
||||
for (restrict r in sc) {
|
||||
if (vec::member(dnum, r.root_vars)) {
|
||||
|
@ -373,13 +363,14 @@ fn check_assign(&@ctx cx, &@ast::expr dest, &@ast::expr src,
|
|||
if (vec::len(root.ds) == 0u) {
|
||||
cx.tcx.sess.span_err(dest.span, "assignment to non-lvalue");
|
||||
} else if (!root.ds.(0).mut) {
|
||||
auto name = alt (root.ds.(0).kind) {
|
||||
case (unbox) { "box" }
|
||||
case (field) { "field" }
|
||||
case (index) { "vec content" }
|
||||
};
|
||||
cx.tcx.sess.span_err
|
||||
(dest.span, "assignment to immutable " + name);
|
||||
auto name =
|
||||
alt (root.ds.(0).kind) {
|
||||
case (unbox) { "box" }
|
||||
case (field) { "field" }
|
||||
case (index) { "vec content" }
|
||||
};
|
||||
cx.tcx.sess.span_err(dest.span,
|
||||
"assignment to immutable " + name);
|
||||
}
|
||||
visit_expr(cx, dest, sc, v);
|
||||
}
|
||||
|
@ -389,13 +380,14 @@ fn check_assign(&@ctx cx, &@ast::expr dest, &@ast::expr src,
|
|||
fn is_immutable_alias(&@ctx cx, &scope sc, def_num dnum) -> bool {
|
||||
alt (cx.local_map.find(dnum)) {
|
||||
case (some(arg(ast::alias(false)))) { ret true; }
|
||||
case (_) {}
|
||||
case (_) { }
|
||||
}
|
||||
for (restrict r in sc) {
|
||||
if (vec::member(dnum, r.bindings)) { ret true; }
|
||||
}
|
||||
ret false;
|
||||
}
|
||||
|
||||
fn is_immutable_objfield(&@ctx cx, def_num dnum) -> bool {
|
||||
ret cx.local_map.find(dnum) == some(objfield(ast::imm));
|
||||
}
|
||||
|
@ -407,17 +399,18 @@ fn test_scope(&ctx cx, &scope sc, &restrict r, &ast::path p) {
|
|||
prob = sc.(dep).ok;
|
||||
}
|
||||
if (prob != valid) {
|
||||
auto msg = alt (prob) {
|
||||
case (overwritten(?sp, ?wpt)) {
|
||||
tup(sp, "overwriting " + ast::path_name(wpt))
|
||||
}
|
||||
case (val_taken(?sp, ?vpt)) {
|
||||
tup(sp, "taking the value of " + ast::path_name(vpt))
|
||||
}
|
||||
};
|
||||
cx.tcx.sess.span_err
|
||||
(msg._0, msg._1 + " will invalidate alias " +
|
||||
ast::path_name(p) + ", which is still used");
|
||||
auto msg =
|
||||
alt (prob) {
|
||||
case (overwritten(?sp, ?wpt)) {
|
||||
tup(sp, "overwriting " + ast::path_name(wpt))
|
||||
}
|
||||
case (val_taken(?sp, ?vpt)) {
|
||||
tup(sp, "taking the value of " + ast::path_name(vpt))
|
||||
}
|
||||
};
|
||||
cx.tcx.sess.span_err(msg._0,
|
||||
msg._1 + " will invalidate alias " +
|
||||
ast::path_name(p) + ", which is still used");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -426,55 +419,45 @@ fn deps(&scope sc, vec[def_num] roots) -> vec[uint] {
|
|||
auto result = [];
|
||||
for (restrict r in sc) {
|
||||
for (def_num dn in roots) {
|
||||
if (vec::member(dn, r.bindings)) {
|
||||
vec::push(result, i);
|
||||
}
|
||||
if (vec::member(dn, r.bindings)) { vec::push(result, i); }
|
||||
}
|
||||
i += 1u;
|
||||
}
|
||||
ret result;
|
||||
}
|
||||
|
||||
tag deref_t {
|
||||
unbox;
|
||||
field;
|
||||
index;
|
||||
}
|
||||
tag deref_t { unbox; field; index; }
|
||||
|
||||
type deref = rec(bool mut, deref_t kind, ty::t outer_t);
|
||||
|
||||
|
||||
// Finds the root (the thing that is dereferenced) for the given expr, and a
|
||||
// vec of dereferences that were used on this root. Note that, in this vec,
|
||||
// the inner derefs come in front, so foo.bar.baz becomes rec(ex=foo,
|
||||
// ds=[field(baz),field(bar)])
|
||||
fn expr_root(&ctx cx, @ast::expr ex, bool autoderef)
|
||||
-> rec(@ast::expr ex, vec[deref] ds) {
|
||||
|
||||
fn maybe_auto_unbox(&ctx cx, &ty::t t)
|
||||
-> rec(ty::t t, option::t[deref] d) {
|
||||
fn expr_root(&ctx cx, @ast::expr ex, bool autoderef) ->
|
||||
rec(@ast::expr ex, vec[deref] ds) {
|
||||
fn maybe_auto_unbox(&ctx cx, &ty::t t) ->
|
||||
rec(ty::t t, option::t[deref] d) {
|
||||
alt (ty::struct(*cx.tcx, t)) {
|
||||
case (ty::ty_box(?mt)) {
|
||||
ret rec(t=mt.ty, d=some(rec(mut=mt.mut != ast::imm,
|
||||
kind=unbox,
|
||||
outer_t=t)));
|
||||
}
|
||||
case (_) {
|
||||
ret rec(t=t, d=none);
|
||||
ret rec(t=mt.ty,
|
||||
d=some(rec(mut=mt.mut != ast::imm,
|
||||
kind=unbox,
|
||||
outer_t=t)));
|
||||
}
|
||||
case (_) { ret rec(t=t, d=none); }
|
||||
}
|
||||
}
|
||||
fn maybe_push_auto_unbox(&option::t[deref] d, &mutable vec[deref] ds) {
|
||||
alt (d) {
|
||||
case (some(?d)) { vec::push(ds, d); }
|
||||
case (none) {}
|
||||
}
|
||||
alt (d) { case (some(?d)) { vec::push(ds, d); } case (none) { } }
|
||||
}
|
||||
|
||||
let vec[deref] ds = [];
|
||||
while (true) {
|
||||
alt ({ex.node}) {
|
||||
alt ({ ex.node }) {
|
||||
case (ast::expr_field(?base, ?ident, _)) {
|
||||
auto auto_unbox = maybe_auto_unbox
|
||||
(cx, ty::expr_ty(*cx.tcx, base));
|
||||
auto auto_unbox =
|
||||
maybe_auto_unbox(cx, ty::expr_ty(*cx.tcx, base));
|
||||
auto mut = false;
|
||||
alt (ty::struct(*cx.tcx, auto_unbox.t)) {
|
||||
case (ty::ty_tup(?fields)) {
|
||||
|
@ -489,22 +472,21 @@ fn expr_root(&ctx cx, @ast::expr ex, bool autoderef)
|
|||
}
|
||||
}
|
||||
}
|
||||
case (ty::ty_obj(_)) {}
|
||||
case (ty::ty_obj(_)) { }
|
||||
}
|
||||
vec::push(ds, rec(mut=mut,
|
||||
kind=field,
|
||||
outer_t=auto_unbox.t));
|
||||
vec::push(ds, rec(mut=mut, kind=field, outer_t=auto_unbox.t));
|
||||
maybe_push_auto_unbox(auto_unbox.d, ds);
|
||||
ex = base;
|
||||
}
|
||||
case (ast::expr_index(?base, _, _)) {
|
||||
auto auto_unbox = maybe_auto_unbox
|
||||
(cx, ty::expr_ty(*cx.tcx, base));
|
||||
auto auto_unbox =
|
||||
maybe_auto_unbox(cx, ty::expr_ty(*cx.tcx, base));
|
||||
alt (ty::struct(*cx.tcx, auto_unbox.t)) {
|
||||
case (ty::ty_vec(?mt)) {
|
||||
vec::push(ds, rec(mut=mt.mut != ast::imm,
|
||||
kind=index,
|
||||
outer_t=auto_unbox.t));
|
||||
vec::push(ds,
|
||||
rec(mut=mt.mut != ast::imm,
|
||||
kind=index,
|
||||
outer_t=auto_unbox.t));
|
||||
}
|
||||
}
|
||||
maybe_push_auto_unbox(auto_unbox.d, ds);
|
||||
|
@ -515,15 +497,14 @@ fn expr_root(&ctx cx, @ast::expr ex, bool autoderef)
|
|||
auto base_t = ty::expr_ty(*cx.tcx, base);
|
||||
alt (ty::struct(*cx.tcx, base_t)) {
|
||||
case (ty::ty_box(?mt)) {
|
||||
vec::push(ds, rec(mut=mt.mut != ast::imm,
|
||||
kind=unbox,
|
||||
outer_t=base_t));
|
||||
vec::push(ds,
|
||||
rec(mut=mt.mut != ast::imm,
|
||||
kind=unbox,
|
||||
outer_t=base_t));
|
||||
}
|
||||
}
|
||||
ex = base;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else { break; }
|
||||
}
|
||||
case (_) { break; }
|
||||
}
|
||||
|
@ -536,16 +517,12 @@ fn expr_root(&ctx cx, @ast::expr ex, bool autoderef)
|
|||
}
|
||||
|
||||
fn mut_field(&vec[deref] ds) -> bool {
|
||||
for (deref d in ds) {
|
||||
if (d.mut) { ret true; }
|
||||
}
|
||||
for (deref d in ds) { if (d.mut) { ret true; } }
|
||||
ret false;
|
||||
}
|
||||
|
||||
fn inner_mut(&vec[deref] ds) -> option::t[ty::t] {
|
||||
for (deref d in ds) {
|
||||
if (d.mut) { ret some(d.outer_t); }
|
||||
}
|
||||
for (deref d in ds) { if (d.mut) { ret some(d.outer_t); } }
|
||||
ret none;
|
||||
}
|
||||
|
||||
|
@ -554,14 +531,12 @@ fn path_def_id(&ctx cx, &@ast::expr ex) -> option::t[ast::def_id] {
|
|||
case (ast::expr_path(_, ?ann)) {
|
||||
ret some(ast::def_id_of_def(cx.dm.get(ann.id)));
|
||||
}
|
||||
case (_) {
|
||||
ret none;
|
||||
}
|
||||
case (_) { ret none; }
|
||||
}
|
||||
}
|
||||
|
||||
fn ty_can_unsafely_include(&ctx cx, ty::t needle, ty::t haystack, bool mut)
|
||||
-> bool {
|
||||
fn ty_can_unsafely_include(&ctx cx, ty::t needle, ty::t haystack, bool mut) ->
|
||||
bool {
|
||||
fn get_mut(bool cur, &ty::mt mt) -> bool {
|
||||
ret cur || mt.mut != ast::imm;
|
||||
}
|
||||
|
@ -599,13 +574,20 @@ fn ty_can_unsafely_include(&ctx cx, ty::t needle, ty::t haystack, bool mut)
|
|||
}
|
||||
ret false;
|
||||
}
|
||||
// These may contain anything.
|
||||
case (ty::ty_fn(_, _, _, _, _)) { ret true; }
|
||||
case (
|
||||
// These may contain anything.
|
||||
ty::ty_fn(_, _, _, _, _)) {
|
||||
ret true;
|
||||
}
|
||||
case (ty::ty_obj(_)) { ret true; }
|
||||
// A type param may include everything, but can only be treated as
|
||||
// opaque downstream, and is thus safe unless we saw mutable
|
||||
// fields, in which case the whole thing can be overwritten.
|
||||
case (ty::ty_param(_)) { ret mut; }
|
||||
case (
|
||||
// A type param may include everything, but can only be
|
||||
// treated as opaque downstream, and is thus safe unless we
|
||||
// saw mutable fields, in which case the whole thing can be
|
||||
// overwritten.
|
||||
ty::ty_param(_)) {
|
||||
ret mut;
|
||||
}
|
||||
case (_) { ret false; }
|
||||
}
|
||||
}
|
||||
|
@ -614,14 +596,13 @@ fn ty_can_unsafely_include(&ctx cx, ty::t needle, ty::t haystack, bool mut)
|
|||
|
||||
fn def_is_local(&ast::def d) -> bool {
|
||||
ret alt (d) {
|
||||
case (ast::def_local(_)) { true }
|
||||
case (ast::def_arg(_)) { true }
|
||||
case (ast::def_obj_field(_)) { true }
|
||||
case (ast::def_binding(_)) { true }
|
||||
case (_) { false }
|
||||
};
|
||||
case (ast::def_local(_)) { true }
|
||||
case (ast::def_arg(_)) { true }
|
||||
case (ast::def_obj_field(_)) { true }
|
||||
case (ast::def_binding(_)) { true }
|
||||
case (_) { false }
|
||||
};
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
// fill-column: 78;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
import std::str;
|
||||
import std::uint;
|
||||
import std::vec;
|
||||
|
@ -7,7 +8,6 @@ import std::io;
|
|||
import std::option;
|
||||
import std::option::some;
|
||||
import std::option::none;
|
||||
|
||||
import front::ast;
|
||||
import front::ast::*;
|
||||
import middle::trans;
|
||||
|
@ -17,77 +17,90 @@ import back::x86;
|
|||
import back::link;
|
||||
import util::common;
|
||||
import pretty::ppaux::lit_to_str;
|
||||
|
||||
import lib::llvm::llvm;
|
||||
import lib::llvm::llvm::ValueRef;
|
||||
import lib::llvm::False;
|
||||
|
||||
const uint tag_paths = 0x01u;
|
||||
|
||||
const uint tag_items = 0x02u;
|
||||
|
||||
const uint tag_paths_data = 0x03u;
|
||||
|
||||
const uint tag_paths_data_name = 0x04u;
|
||||
|
||||
const uint tag_paths_data_item = 0x05u;
|
||||
|
||||
const uint tag_paths_data_mod = 0x06u;
|
||||
|
||||
const uint tag_def_id = 0x07u;
|
||||
|
||||
const uint tag_items_data = 0x08u;
|
||||
|
||||
const uint tag_items_data_item = 0x09u;
|
||||
|
||||
const uint tag_items_data_item_kind = 0x0au;
|
||||
|
||||
const uint tag_items_data_item_ty_param_count = 0x0bu;
|
||||
|
||||
const uint tag_items_data_item_type = 0x0cu;
|
||||
|
||||
const uint tag_items_data_item_symbol = 0x0du;
|
||||
|
||||
const uint tag_items_data_item_variant = 0x0eu;
|
||||
|
||||
const uint tag_items_data_item_tag_id = 0x0fu;
|
||||
|
||||
const uint tag_index = 0x11u;
|
||||
|
||||
const uint tag_index_buckets = 0x12u;
|
||||
|
||||
const uint tag_index_buckets_bucket = 0x13u;
|
||||
|
||||
const uint tag_index_buckets_bucket_elt = 0x14u;
|
||||
|
||||
const uint tag_index_table = 0x15u;
|
||||
|
||||
const uint tag_meta_export = 0x16u;
|
||||
|
||||
const uint tag_meta_local = 0x17u;
|
||||
|
||||
const uint tag_meta_item = 0x18u;
|
||||
|
||||
const uint tag_meta_item_key = 0x19u;
|
||||
|
||||
const uint tag_meta_item_value = 0x20u;
|
||||
|
||||
|
||||
// Type encoding
|
||||
|
||||
// Compact string representation for ty.t values. API ty_str & parse_from_str.
|
||||
// Extra parameters are for converting to/from def_ids in the string rep.
|
||||
// Whatever format you choose should not contain pipe characters.
|
||||
|
||||
type ty_abbrev = rec(uint pos, uint len, str s);
|
||||
|
||||
tag abbrev_ctxt {
|
||||
ac_no_abbrevs;
|
||||
ac_use_abbrevs(hashmap[ty::t, ty_abbrev]);
|
||||
}
|
||||
tag abbrev_ctxt { ac_no_abbrevs; ac_use_abbrevs(hashmap[ty::t, ty_abbrev]); }
|
||||
|
||||
mod Encode {
|
||||
type ctxt =
|
||||
rec(fn(&ast::def_id) -> str ds, // Def -> str Callback:
|
||||
|
||||
type ctxt = rec(
|
||||
fn(&ast::def_id) -> str ds, // Def -> str Callback:
|
||||
ty::ctxt tcx, // The type context.
|
||||
abbrev_ctxt abbrevs
|
||||
);
|
||||
ty::ctxt tcx, // The type context.
|
||||
|
||||
abbrev_ctxt abbrevs);
|
||||
|
||||
fn cx_uses_abbrevs(&@ctxt cx) -> bool {
|
||||
alt (cx.abbrevs) {
|
||||
case (ac_no_abbrevs) { ret false; }
|
||||
case (ac_no_abbrevs) { ret false; }
|
||||
case (ac_use_abbrevs(_)) { ret true; }
|
||||
}
|
||||
}
|
||||
|
||||
fn ty_str(&@ctxt cx, &ty::t t) -> str {
|
||||
assert (!cx_uses_abbrevs(cx));
|
||||
auto sw = io::string_writer();
|
||||
enc_ty(sw.get_writer(), cx, t);
|
||||
ret sw.get_str();
|
||||
}
|
||||
|
||||
fn enc_ty(&io::writer w, &@ctxt cx, &ty::t t) {
|
||||
alt (cx.abbrevs) {
|
||||
case (ac_no_abbrevs) {
|
||||
|
@ -105,32 +118,26 @@ mod Encode {
|
|||
}
|
||||
case (ac_use_abbrevs(?abbrevs)) {
|
||||
alt (abbrevs.find(t)) {
|
||||
case (some(?a)) {
|
||||
w.write_str(a.s);
|
||||
ret;
|
||||
}
|
||||
case (some(?a)) { w.write_str(a.s); ret; }
|
||||
case (none) {
|
||||
auto pos = w.get_buf_writer().tell();
|
||||
auto ss = enc_sty(w, cx, ty::struct(cx.tcx, t));
|
||||
auto end = w.get_buf_writer().tell();
|
||||
auto len = end-pos;
|
||||
auto len = end - pos;
|
||||
fn estimate_sz(uint u) -> uint {
|
||||
auto n = u;
|
||||
auto len = 0u;
|
||||
while (n != 0u) {
|
||||
len += 1u;
|
||||
n = n >> 4u;
|
||||
}
|
||||
while (n != 0u) { len += 1u; n = n >> 4u; }
|
||||
ret len;
|
||||
}
|
||||
auto abbrev_len =
|
||||
3u + estimate_sz(pos) + estimate_sz(len);
|
||||
|
||||
if (abbrev_len < len) {
|
||||
// I.e. it's actually an abbreviation.
|
||||
auto s = ("#"
|
||||
+ uint::to_str(pos, 16u) + ":"
|
||||
+ uint::to_str(len, 16u) + "#");
|
||||
|
||||
auto s =
|
||||
"#" + uint::to_str(pos, 16u) + ":" +
|
||||
uint::to_str(len, 16u) + "#";
|
||||
auto a = rec(pos=pos, len=len, s=s);
|
||||
abbrevs.insert(t, a);
|
||||
}
|
||||
|
@ -140,16 +147,14 @@ mod Encode {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn enc_mt(&io::writer w, &@ctxt cx, &ty::mt mt) {
|
||||
alt (mt.mut) {
|
||||
case (ast::imm) { }
|
||||
case (ast::mut) { w.write_char('m'); }
|
||||
case (ast::imm) { }
|
||||
case (ast::mut) { w.write_char('m'); }
|
||||
case (ast::maybe_mut) { w.write_char('?'); }
|
||||
}
|
||||
enc_ty(w, cx, mt.ty);
|
||||
}
|
||||
|
||||
fn enc_sty(&io::writer w, &@ctxt cx, &ty::sty st) {
|
||||
alt (st) {
|
||||
case (ty::ty_nil) { w.write_char('n'); }
|
||||
|
@ -172,29 +177,25 @@ mod Encode {
|
|||
case (common::ty_f64) { w.write_str("MF"); }
|
||||
}
|
||||
}
|
||||
case (ty::ty_char) {w.write_char('c');}
|
||||
case (ty::ty_str) {w.write_char('s');}
|
||||
case (ty::ty_istr) {w.write_char('S');}
|
||||
case (ty::ty_tag(?def,?tys)) {
|
||||
case (ty::ty_char) { w.write_char('c'); }
|
||||
case (ty::ty_str) { w.write_char('s'); }
|
||||
case (ty::ty_istr) { w.write_char('S'); }
|
||||
case (ty::ty_tag(?def, ?tys)) {
|
||||
w.write_str("t[");
|
||||
w.write_str(cx.ds(def));
|
||||
w.write_char('|');
|
||||
for (ty::t t in tys) {
|
||||
enc_ty(w, cx, t);
|
||||
}
|
||||
for (ty::t t in tys) { enc_ty(w, cx, t); }
|
||||
w.write_char(']');
|
||||
}
|
||||
case (ty::ty_box(?mt)) {w.write_char('@'); enc_mt(w, cx, mt); }
|
||||
case (ty::ty_ptr(?mt)) {w.write_char('*'); enc_mt(w, cx, mt); }
|
||||
case (ty::ty_vec(?mt)) {w.write_char('V'); enc_mt(w, cx, mt); }
|
||||
case (ty::ty_ivec(?mt)) {w.write_char('I'); enc_mt(w, cx, mt); }
|
||||
case (ty::ty_port(?t)) {w.write_char('P'); enc_ty(w, cx, t); }
|
||||
case (ty::ty_chan(?t)) {w.write_char('C'); enc_ty(w, cx, t); }
|
||||
case (ty::ty_box(?mt)) { w.write_char('@'); enc_mt(w, cx, mt); }
|
||||
case (ty::ty_ptr(?mt)) { w.write_char('*'); enc_mt(w, cx, mt); }
|
||||
case (ty::ty_vec(?mt)) { w.write_char('V'); enc_mt(w, cx, mt); }
|
||||
case (ty::ty_ivec(?mt)) { w.write_char('I'); enc_mt(w, cx, mt); }
|
||||
case (ty::ty_port(?t)) { w.write_char('P'); enc_ty(w, cx, t); }
|
||||
case (ty::ty_chan(?t)) { w.write_char('C'); enc_ty(w, cx, t); }
|
||||
case (ty::ty_tup(?mts)) {
|
||||
w.write_str("T[");
|
||||
for (ty::mt mt in mts) {
|
||||
enc_mt(w, cx, mt);
|
||||
}
|
||||
for (ty::mt mt in mts) { enc_mt(w, cx, mt); }
|
||||
w.write_char(']');
|
||||
}
|
||||
case (ty::ty_rec(?fields)) {
|
||||
|
@ -206,11 +207,11 @@ mod Encode {
|
|||
}
|
||||
w.write_char(']');
|
||||
}
|
||||
case (ty::ty_fn(?proto,?args,?out,?cf,?constrs)) {
|
||||
case (ty::ty_fn(?proto, ?args, ?out, ?cf, ?constrs)) {
|
||||
enc_proto(w, proto);
|
||||
enc_ty_fn(w, cx, args, out, cf, constrs);
|
||||
}
|
||||
case (ty::ty_native_fn(?abi,?args,?out)) {
|
||||
case (ty::ty_native_fn(?abi, ?args, ?out)) {
|
||||
w.write_char('N');
|
||||
alt (abi) {
|
||||
case (ast::native_abi_rust) { w.write_char('r'); }
|
||||
|
@ -236,23 +237,21 @@ mod Encode {
|
|||
w.write_char('X');
|
||||
w.write_str(common::istr(id));
|
||||
}
|
||||
case (ty::ty_native) {w.write_char('E');}
|
||||
case (ty::ty_native) { w.write_char('E'); }
|
||||
case (ty::ty_param(?id)) {
|
||||
w.write_char('p');
|
||||
w.write_str(common::uistr(id));
|
||||
}
|
||||
case (ty::ty_type) {w.write_char('Y');}
|
||||
case (ty::ty_task) {w.write_char('a');}
|
||||
case (ty::ty_type) { w.write_char('Y'); }
|
||||
case (ty::ty_task) { w.write_char('a'); }
|
||||
}
|
||||
}
|
||||
|
||||
fn enc_proto(&io::writer w, ast::proto proto) {
|
||||
alt (proto) {
|
||||
case (ast::proto_iter) { w.write_char('W'); }
|
||||
case (ast::proto_fn) { w.write_char('F'); }
|
||||
}
|
||||
}
|
||||
|
||||
fn enc_ty_fn(&io::writer w, &@ctxt cx, &vec[ty::arg] args, &ty::t out,
|
||||
&ast::controlflow cf, &vec[@ast::constr] constrs) {
|
||||
w.write_char('[');
|
||||
|
@ -262,54 +261,40 @@ mod Encode {
|
|||
w.write_char('&');
|
||||
if (mut) { w.write_char('m'); }
|
||||
}
|
||||
case (ty::mo_val) {}
|
||||
case (ty::mo_val) { }
|
||||
}
|
||||
enc_ty(w, cx, arg.ty);
|
||||
}
|
||||
w.write_char(']');
|
||||
alt (cf) {
|
||||
case (ast::noreturn) {
|
||||
w.write_char('!');
|
||||
}
|
||||
case (_) {
|
||||
enc_ty(w, cx, out);
|
||||
}
|
||||
case (ast::noreturn) { w.write_char('!'); }
|
||||
case (_) { enc_ty(w, cx, out); }
|
||||
}
|
||||
auto colon = true;
|
||||
for (@ast::constr c in constrs) {
|
||||
if (colon) { w.write_char(':'); colon = false; }
|
||||
else { w.write_char(','); }
|
||||
if (colon) {
|
||||
w.write_char(':');
|
||||
colon = false;
|
||||
} else { w.write_char(','); }
|
||||
enc_constr(w, cx, c);
|
||||
}
|
||||
}
|
||||
|
||||
fn enc_constr(&io::writer w, &@ctxt cx, &@ast::constr c) {
|
||||
w.write_str(path_to_str(c.node.path));
|
||||
w.write_char('(');
|
||||
// FIXME
|
||||
// w.write_str(cx.ds(c.node.id));
|
||||
|
||||
auto comma = false;
|
||||
for (@constr_arg a in c.node.args) {
|
||||
if (comma) {
|
||||
w.write_char(',');
|
||||
}
|
||||
else {
|
||||
comma = true;
|
||||
}
|
||||
if (comma) { w.write_char(','); } else { comma = true; }
|
||||
alt (a.node) {
|
||||
case (carg_base) {
|
||||
w.write_char('*');
|
||||
}
|
||||
case (carg_ident(?i)) {
|
||||
w.write_uint(i);
|
||||
}
|
||||
case (carg_lit(?l)) {
|
||||
w.write_str(lit_to_str(l));
|
||||
}
|
||||
case (carg_base) { w.write_char('*'); }
|
||||
case (carg_ident(?i)) { w.write_uint(i); }
|
||||
case (carg_lit(?l)) { w.write_str(lit_to_str(l)); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -320,7 +305,6 @@ fn C_postr(&str s) -> ValueRef {
|
|||
|
||||
|
||||
// Path table encoding
|
||||
|
||||
fn encode_name(&ebml::writer ebml_w, &str name) {
|
||||
ebml::start_tag(ebml_w, tag_paths_data_name);
|
||||
ebml_w.writer.write(str::bytes(name));
|
||||
|
@ -333,8 +317,7 @@ fn encode_def_id(&ebml::writer ebml_w, &ast::def_id id) {
|
|||
ebml::end_tag(ebml_w);
|
||||
}
|
||||
|
||||
fn encode_tag_variant_paths(&ebml::writer ebml_w,
|
||||
&vec[ast::variant] variants,
|
||||
fn encode_tag_variant_paths(&ebml::writer ebml_w, &vec[ast::variant] variants,
|
||||
&vec[str] path,
|
||||
&mutable vec[tup(str, uint)] index) {
|
||||
for (ast::variant variant in variants) {
|
||||
|
@ -346,17 +329,14 @@ fn encode_tag_variant_paths(&ebml::writer ebml_w,
|
|||
}
|
||||
}
|
||||
|
||||
fn add_to_index(&ebml::writer ebml_w,
|
||||
&vec[str] path,
|
||||
&mutable vec[tup(str, uint)] index,
|
||||
&str name) {
|
||||
fn add_to_index(&ebml::writer ebml_w, &vec[str] path,
|
||||
&mutable vec[tup(str, uint)] index, &str name) {
|
||||
auto full_path = path + [name];
|
||||
index += [tup(str::connect(full_path, "::"), ebml_w.writer.tell())];
|
||||
}
|
||||
|
||||
fn encode_native_module_item_paths(&ebml::writer ebml_w,
|
||||
&ast::native_mod nmod,
|
||||
&vec[str] path,
|
||||
&ast::native_mod nmod, &vec[str] path,
|
||||
&mutable vec[tup(str, uint)] index) {
|
||||
for (@ast::native_item nitem in nmod.items) {
|
||||
alt (nitem.node) {
|
||||
|
@ -378,15 +358,11 @@ fn encode_native_module_item_paths(&ebml::writer ebml_w,
|
|||
}
|
||||
}
|
||||
|
||||
fn encode_module_item_paths(&ebml::writer ebml_w,
|
||||
&ast::_mod module,
|
||||
fn encode_module_item_paths(&ebml::writer ebml_w, &ast::_mod module,
|
||||
&vec[str] path,
|
||||
&mutable vec[tup(str, uint)] index) {
|
||||
for (@ast::item it in module.items) {
|
||||
if (!ast::is_exported(ast::item_ident(it), module)) {
|
||||
cont;
|
||||
}
|
||||
|
||||
if (!ast::is_exported(ast::item_ident(it), module)) { cont; }
|
||||
alt (it.node) {
|
||||
case (ast::item_const(?id, _, ?tps, _, ?did, ?ann)) {
|
||||
add_to_index(ebml_w, path, index, id);
|
||||
|
@ -432,7 +408,6 @@ fn encode_module_item_paths(&ebml::writer ebml_w,
|
|||
encode_name(ebml_w, id);
|
||||
encode_def_id(ebml_w, did);
|
||||
ebml::end_tag(ebml_w);
|
||||
|
||||
encode_tag_variant_paths(ebml_w, variants, path, index);
|
||||
}
|
||||
case (ast::item_obj(?id, _, ?tps, _, ?odid, ?ann)) {
|
||||
|
@ -441,7 +416,6 @@ fn encode_module_item_paths(&ebml::writer ebml_w,
|
|||
encode_name(ebml_w, id);
|
||||
encode_def_id(ebml_w, odid.ctor);
|
||||
ebml::end_tag(ebml_w);
|
||||
|
||||
add_to_index(ebml_w, path, index, id);
|
||||
ebml::start_tag(ebml_w, tag_paths_data_item);
|
||||
encode_name(ebml_w, id);
|
||||
|
@ -452,8 +426,8 @@ fn encode_module_item_paths(&ebml::writer ebml_w,
|
|||
}
|
||||
}
|
||||
|
||||
fn encode_item_paths(&ebml::writer ebml_w, &@ast::crate crate)
|
||||
-> vec[tup(str, uint)] {
|
||||
fn encode_item_paths(&ebml::writer ebml_w, &@ast::crate crate) ->
|
||||
vec[tup(str, uint)] {
|
||||
let vec[tup(str, uint)] index = [];
|
||||
let vec[str] path = [];
|
||||
ebml::start_tag(ebml_w, tag_paths);
|
||||
|
@ -464,16 +438,13 @@ fn encode_item_paths(&ebml::writer ebml_w, &@ast::crate crate)
|
|||
|
||||
|
||||
// Item info table encoding
|
||||
|
||||
fn encode_kind(&ebml::writer ebml_w, u8 c) {
|
||||
ebml::start_tag(ebml_w, tag_items_data_item_kind);
|
||||
ebml_w.writer.write([c]);
|
||||
ebml::end_tag(ebml_w);
|
||||
}
|
||||
|
||||
fn def_to_str(&ast::def_id did) -> str {
|
||||
ret #fmt("%d:%d", did._0, did._1);
|
||||
}
|
||||
fn def_to_str(&ast::def_id did) -> str { ret #fmt("%d:%d", did._0, did._1); }
|
||||
|
||||
fn encode_type_param_count(&ebml::writer ebml_w, &vec[ast::ty_param] tps) {
|
||||
ebml::start_tag(ebml_w, tag_items_data_item_ty_param_count);
|
||||
|
@ -489,10 +460,9 @@ fn encode_variant_id(&ebml::writer ebml_w, &ast::def_id vid) {
|
|||
|
||||
fn encode_type(&@trans::crate_ctxt cx, &ebml::writer ebml_w, &ty::t typ) {
|
||||
ebml::start_tag(ebml_w, tag_items_data_item_type);
|
||||
|
||||
auto f = def_to_str;
|
||||
auto ty_str_ctxt = @rec(ds=f, tcx=cx.tcx,
|
||||
abbrevs=ac_use_abbrevs(cx.type_abbrevs));
|
||||
auto ty_str_ctxt =
|
||||
@rec(ds=f, tcx=cx.tcx, abbrevs=ac_use_abbrevs(cx.type_abbrevs));
|
||||
Encode::enc_ty(io::new_writer_(ebml_w.writer), ty_str_ctxt, typ);
|
||||
ebml::end_tag(ebml_w);
|
||||
}
|
||||
|
@ -517,15 +487,12 @@ fn encode_tag_id(&ebml::writer ebml_w, &ast::def_id id) {
|
|||
ebml::end_tag(ebml_w);
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn encode_tag_variant_info(&@trans::crate_ctxt cx, &ebml::writer ebml_w,
|
||||
&ast::def_id did, &vec[ast::variant] variants,
|
||||
&mutable vec[tup(int, uint)] index,
|
||||
&vec[ast::ty_param] ty_params) {
|
||||
for (ast::variant variant in variants) {
|
||||
index += [tup(variant.node.id._1, ebml_w.writer.tell())];
|
||||
|
||||
ebml::start_tag(ebml_w, tag_items_data_item);
|
||||
encode_def_id(ebml_w, variant.node.id);
|
||||
encode_kind(ebml_w, 'v' as u8);
|
||||
|
@ -590,7 +557,6 @@ fn encode_info_for_item(@trans::crate_ctxt cx, &ebml::writer ebml_w,
|
|||
encode_variant_id(ebml_w, v.node.id);
|
||||
}
|
||||
ebml::end_tag(ebml_w);
|
||||
|
||||
encode_tag_variant_info(cx, ebml_w, did, variants, index, tps);
|
||||
}
|
||||
case (ast::item_obj(?id, _, ?tps, _, ?odid, ?ann)) {
|
||||
|
@ -602,7 +568,6 @@ fn encode_info_for_item(@trans::crate_ctxt cx, &ebml::writer ebml_w,
|
|||
encode_type(cx, ebml_w, fn_ty);
|
||||
encode_symbol(cx, ebml_w, odid.ctor);
|
||||
ebml::end_tag(ebml_w);
|
||||
|
||||
index += [tup(odid.ty._1, ebml_w.writer.tell())];
|
||||
ebml::start_tag(ebml_w, tag_items_data_item);
|
||||
encode_def_id(ebml_w, odid.ty);
|
||||
|
@ -634,22 +599,20 @@ fn encode_info_for_native_item(&@trans::crate_ctxt cx, &ebml::writer ebml_w,
|
|||
ebml::end_tag(ebml_w);
|
||||
}
|
||||
|
||||
fn encode_info_for_items(&@trans::crate_ctxt cx, &ebml::writer ebml_w)
|
||||
-> vec[tup(int, uint)] {
|
||||
fn encode_info_for_items(&@trans::crate_ctxt cx, &ebml::writer ebml_w) ->
|
||||
vec[tup(int, uint)] {
|
||||
let vec[tup(int, uint)] index = [];
|
||||
|
||||
ebml::start_tag(ebml_w, tag_items_data);
|
||||
for each (@tup(ast::def_id, @ast::item) kvp in cx.items.items()) {
|
||||
index += [tup(kvp._0._1, ebml_w.writer.tell())];
|
||||
encode_info_for_item(cx, ebml_w, kvp._1, index);
|
||||
}
|
||||
for each (@tup(ast::def_id, @ast::native_item) kvp in
|
||||
cx.native_items.items()) {
|
||||
cx.native_items.items()) {
|
||||
index += [tup(kvp._0._1, ebml_w.writer.tell())];
|
||||
encode_info_for_native_item(cx, ebml_w, kvp._1);
|
||||
}
|
||||
ebml::end_tag(ebml_w);
|
||||
|
||||
ret index;
|
||||
}
|
||||
|
||||
|
@ -657,46 +620,33 @@ fn encode_info_for_items(&@trans::crate_ctxt cx, &ebml::writer ebml_w)
|
|||
// Path and definition ID indexing
|
||||
|
||||
// djb's cdb hashes.
|
||||
|
||||
fn hash_def_num(&int def_num) -> uint {
|
||||
ret 177573u ^ (def_num as uint);
|
||||
}
|
||||
fn hash_def_num(&int def_num) -> uint { ret 177573u ^ (def_num as uint); }
|
||||
|
||||
fn hash_path(&str s) -> uint {
|
||||
auto h = 5381u;
|
||||
for (u8 ch in str::bytes(s)) {
|
||||
h = ((h << 5u) + h) ^ (ch as uint);
|
||||
}
|
||||
for (u8 ch in str::bytes(s)) { h = (h << 5u) + h ^ (ch as uint); }
|
||||
ret h;
|
||||
}
|
||||
|
||||
fn create_index[T](&vec[tup(T, uint)] index, fn(&T) -> uint hash_fn)
|
||||
-> vec[vec[tup(T, uint)]] {
|
||||
fn create_index[T](&vec[tup(T, uint)] index, fn(&T) -> uint hash_fn) ->
|
||||
vec[vec[tup(T, uint)]] {
|
||||
let vec[mutable vec[tup(T, uint)]] buckets = vec::empty_mut();
|
||||
for each (uint i in uint::range(0u, 256u)) {
|
||||
buckets += [mutable []];
|
||||
}
|
||||
|
||||
for each (uint i in uint::range(0u, 256u)) { buckets += [mutable []]; }
|
||||
for (tup(T, uint) elt in index) {
|
||||
auto h = hash_fn(elt._0);
|
||||
buckets.(h % 256u) += [elt];
|
||||
}
|
||||
|
||||
ret vec::freeze(buckets);
|
||||
}
|
||||
|
||||
fn encode_index[T](&ebml::writer ebml_w,
|
||||
&vec[vec[tup(T, uint)]] buckets,
|
||||
fn(&io::writer, &T) write_fn) {
|
||||
fn encode_index[T](&ebml::writer ebml_w, &vec[vec[tup(T, uint)]] buckets,
|
||||
fn(&io::writer, &T) write_fn) {
|
||||
auto writer = io::new_writer_(ebml_w.writer);
|
||||
|
||||
ebml::start_tag(ebml_w, tag_index);
|
||||
|
||||
let vec[uint] bucket_locs = [];
|
||||
ebml::start_tag(ebml_w, tag_index_buckets);
|
||||
for (vec[tup(T, uint)] bucket in buckets) {
|
||||
bucket_locs += [ebml_w.writer.tell()];
|
||||
|
||||
ebml::start_tag(ebml_w, tag_index_buckets_bucket);
|
||||
for (tup(T, uint) elt in bucket) {
|
||||
ebml::start_tag(ebml_w, tag_index_buckets_bucket_elt);
|
||||
|
@ -707,27 +657,19 @@ fn encode_index[T](&ebml::writer ebml_w,
|
|||
ebml::end_tag(ebml_w);
|
||||
}
|
||||
ebml::end_tag(ebml_w);
|
||||
|
||||
ebml::start_tag(ebml_w, tag_index_table);
|
||||
for (uint pos in bucket_locs) {
|
||||
writer.write_be_uint(pos, 4u);
|
||||
}
|
||||
for (uint pos in bucket_locs) { writer.write_be_uint(pos, 4u); }
|
||||
ebml::end_tag(ebml_w);
|
||||
|
||||
ebml::end_tag(ebml_w);
|
||||
}
|
||||
|
||||
fn write_str(&io::writer writer, &str s) {
|
||||
writer.write_str(s);
|
||||
}
|
||||
fn write_str(&io::writer writer, &str s) { writer.write_str(s); }
|
||||
|
||||
fn write_int(&io::writer writer, &int n) {
|
||||
writer.write_be_uint(n as uint, 4u);
|
||||
}
|
||||
|
||||
|
||||
fn encode_meta_items(&ebml::writer ebml_w, &ast::crate crate) {
|
||||
|
||||
fn encode_meta_item(&ebml::writer ebml_w, &ast::meta_item mi) {
|
||||
ebml::start_tag(ebml_w, tag_meta_item);
|
||||
ebml::start_tag(ebml_w, tag_meta_item_key);
|
||||
|
@ -738,13 +680,11 @@ fn encode_meta_items(&ebml::writer ebml_w, &ast::crate crate) {
|
|||
ebml::end_tag(ebml_w);
|
||||
ebml::end_tag(ebml_w);
|
||||
}
|
||||
|
||||
ebml::start_tag(ebml_w, tag_meta_export);
|
||||
for each (@ast::meta_item mi in link::crate_export_metas(crate)) {
|
||||
encode_meta_item(ebml_w, *mi);
|
||||
}
|
||||
ebml::end_tag(ebml_w);
|
||||
|
||||
ebml::start_tag(ebml_w, tag_meta_local);
|
||||
for each (@ast::meta_item mi in link::crate_local_metas(crate)) {
|
||||
encode_meta_item(ebml_w, *mi);
|
||||
|
@ -752,16 +692,15 @@ fn encode_meta_items(&ebml::writer ebml_w, &ast::crate crate) {
|
|||
ebml::end_tag(ebml_w);
|
||||
}
|
||||
|
||||
fn encode_metadata(&@trans::crate_ctxt cx, &@ast::crate crate)
|
||||
-> ValueRef {
|
||||
fn encode_metadata(&@trans::crate_ctxt cx, &@ast::crate crate) -> ValueRef {
|
||||
auto string_w = io::string_writer();
|
||||
auto buf_w = string_w.get_writer().get_buf_writer();
|
||||
auto ebml_w = ebml::create_writer(buf_w);
|
||||
|
||||
// Encode the meta items
|
||||
encode_meta_items(ebml_w, *crate);
|
||||
|
||||
encode_meta_items(ebml_w, *crate);
|
||||
// Encode and index the paths.
|
||||
|
||||
ebml::start_tag(ebml_w, tag_paths);
|
||||
auto paths_index = encode_item_paths(ebml_w, crate);
|
||||
auto str_writer = write_str;
|
||||
|
@ -769,8 +708,8 @@ fn encode_metadata(&@trans::crate_ctxt cx, &@ast::crate crate)
|
|||
auto paths_buckets = create_index[str](paths_index, path_hasher);
|
||||
encode_index[str](ebml_w, paths_buckets, str_writer);
|
||||
ebml::end_tag(ebml_w);
|
||||
|
||||
// Encode and index the items.
|
||||
|
||||
ebml::start_tag(ebml_w, tag_items);
|
||||
auto items_index = encode_info_for_items(cx, ebml_w);
|
||||
auto int_writer = write_int;
|
||||
|
@ -778,27 +717,23 @@ fn encode_metadata(&@trans::crate_ctxt cx, &@ast::crate crate)
|
|||
auto items_buckets = create_index[int](items_index, item_hasher);
|
||||
encode_index[int](ebml_w, items_buckets, int_writer);
|
||||
ebml::end_tag(ebml_w);
|
||||
|
||||
// Pad this, since something (LLVM, presumably) is cutting off the
|
||||
// remaining % 4 bytes.
|
||||
buf_w.write([0u8, 0u8, 0u8, 0u8]);
|
||||
|
||||
buf_w.write([0u8, 0u8, 0u8, 0u8]);
|
||||
ret C_postr(string_w.get_str());
|
||||
}
|
||||
|
||||
fn write_metadata(&@trans::crate_ctxt cx, &@ast::crate crate) {
|
||||
if (!cx.sess.get_opts().shared) {
|
||||
ret;
|
||||
}
|
||||
|
||||
if (!cx.sess.get_opts().shared) { ret; }
|
||||
auto llmeta = encode_metadata(cx, crate);
|
||||
auto llconst = trans::C_struct([llmeta]);
|
||||
auto llglobal = llvm::LLVMAddGlobal(cx.llmod, trans::val_ty(llconst),
|
||||
str::buf("rust_metadata"));
|
||||
auto llglobal =
|
||||
llvm::LLVMAddGlobal(cx.llmod, trans::val_ty(llconst),
|
||||
str::buf("rust_metadata"));
|
||||
llvm::LLVMSetInitializer(llglobal, llconst);
|
||||
llvm::LLVMSetSection(llglobal, str::buf(x86::get_meta_sect_name()));
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,160 +1,169 @@
|
|||
|
||||
import front::ast::ident;
|
||||
import std::vec;
|
||||
import std::bitv;
|
||||
|
||||
|
||||
/*
|
||||
This says: this expression requires the idents in <pre> to be initialized,
|
||||
and given the precondition, it guarantees that the idents in <post> are
|
||||
initialized.
|
||||
*/
|
||||
type precond = bitv::t; /* 1 means "this variable must be initialized"
|
||||
0 means "don't care about this variable" */
|
||||
type postcond = bitv::t; /* 1 means "this variable is initialized"
|
||||
0 means "don't know about this variable */
|
||||
type precond = bitv::t;
|
||||
|
||||
type prestate = bitv::t; /* 1 means "this variable is definitely initialized"
|
||||
0 means "don't know whether this variable is
|
||||
initialized" */
|
||||
type poststate = bitv::t; /* 1 means "this variable is definitely initialized"
|
||||
0 means "don't know whether this variable is
|
||||
initialized" */
|
||||
/* 1 means "this variable must be initialized"
|
||||
0 means "don't care about this variable" */
|
||||
type postcond = bitv::t;
|
||||
|
||||
/* named thus so as not to confuse with prestate and poststate */
|
||||
/* 1 means "this variable is initialized"
|
||||
0 means "don't know about this variable */
|
||||
type prestate = bitv::t;
|
||||
|
||||
/* 1 means "this variable is definitely initialized"
|
||||
0 means "don't know whether this variable is
|
||||
initialized" */
|
||||
type poststate = bitv::t;
|
||||
|
||||
/* 1 means "this variable is definitely initialized"
|
||||
0 means "don't know whether this variable is
|
||||
initialized" */
|
||||
/* named thus so as not to confuse with prestate and poststate */
|
||||
type pre_and_post = @rec(precond precondition, postcond postcondition);
|
||||
/* FIXME: once it's implemented: */
|
||||
// : ((*.precondition).nbits == (*.postcondition).nbits);
|
||||
|
||||
|
||||
/* FIXME: once it's implemented: */
|
||||
|
||||
// : ((*.precondition).nbits == (*.postcondition).nbits);
|
||||
type pre_and_post_state = rec(prestate prestate, poststate poststate);
|
||||
|
||||
type ts_ann = @rec(pre_and_post conditions, pre_and_post_state states);
|
||||
|
||||
fn true_precond(uint num_vars) -> precond {
|
||||
be bitv::create(num_vars, false);
|
||||
be bitv::create(num_vars, false);
|
||||
}
|
||||
|
||||
fn true_postcond(uint num_vars) -> postcond {
|
||||
be true_precond(num_vars);
|
||||
}
|
||||
fn true_postcond(uint num_vars) -> postcond { be true_precond(num_vars); }
|
||||
|
||||
fn empty_prestate(uint num_vars) -> prestate {
|
||||
be true_precond(num_vars);
|
||||
}
|
||||
fn empty_prestate(uint num_vars) -> prestate { be true_precond(num_vars); }
|
||||
|
||||
fn empty_poststate(uint num_vars) -> poststate {
|
||||
be true_precond(num_vars);
|
||||
}
|
||||
fn empty_poststate(uint num_vars) -> poststate { be true_precond(num_vars); }
|
||||
|
||||
fn false_postcond(uint num_vars) -> postcond {
|
||||
be bitv::create(num_vars, true);
|
||||
}
|
||||
|
||||
fn empty_pre_post(uint num_vars) -> pre_and_post {
|
||||
ret(@rec(precondition=empty_prestate(num_vars),
|
||||
postcondition=empty_poststate(num_vars)));
|
||||
ret @rec(precondition=empty_prestate(num_vars),
|
||||
postcondition=empty_poststate(num_vars));
|
||||
}
|
||||
|
||||
fn empty_states(uint num_vars) -> pre_and_post_state {
|
||||
ret(rec(prestate=true_precond(num_vars),
|
||||
poststate=true_postcond(num_vars)));
|
||||
ret rec(prestate=true_precond(num_vars),
|
||||
poststate=true_postcond(num_vars));
|
||||
}
|
||||
|
||||
fn empty_ann(uint num_vars) -> ts_ann {
|
||||
ret(@rec(conditions=empty_pre_post(num_vars),
|
||||
states=empty_states(num_vars)));
|
||||
ret @rec(conditions=empty_pre_post(num_vars),
|
||||
states=empty_states(num_vars));
|
||||
}
|
||||
|
||||
fn get_pre(&pre_and_post p) -> precond {
|
||||
ret p.precondition;
|
||||
}
|
||||
fn get_pre(&pre_and_post p) -> precond { ret p.precondition; }
|
||||
|
||||
fn get_post(&pre_and_post p) -> postcond {
|
||||
ret p.postcondition;
|
||||
}
|
||||
fn get_post(&pre_and_post p) -> postcond { ret p.postcondition; }
|
||||
|
||||
fn difference(&precond p1, &precond p2) -> bool {
|
||||
be bitv::difference(p1, p2);
|
||||
be bitv::difference(p1, p2);
|
||||
}
|
||||
|
||||
fn union(&precond p1, &precond p2) -> bool {
|
||||
be bitv::union(p1, p2);
|
||||
}
|
||||
fn union(&precond p1, &precond p2) -> bool { be bitv::union(p1, p2); }
|
||||
|
||||
fn intersect(&precond p1, &precond p2) -> bool {
|
||||
be bitv::intersect(p1, p2);
|
||||
}
|
||||
fn intersect(&precond p1, &precond p2) -> bool { be bitv::intersect(p1, p2); }
|
||||
|
||||
fn pps_len(&pre_and_post p) -> uint {
|
||||
// gratuitous check
|
||||
assert (p.precondition.nbits == p.postcondition.nbits);
|
||||
ret p.precondition.nbits;
|
||||
// gratuitous check
|
||||
|
||||
assert (p.precondition.nbits == p.postcondition.nbits);
|
||||
ret p.precondition.nbits;
|
||||
}
|
||||
|
||||
fn require(uint i, &pre_and_post p) -> () {
|
||||
// sets the ith bit in p's pre
|
||||
bitv::set(p.precondition, i, true);
|
||||
fn require(uint i, &pre_and_post p) {
|
||||
// sets the ith bit in p's pre
|
||||
|
||||
bitv::set(p.precondition, i, true);
|
||||
}
|
||||
|
||||
fn require_and_preserve(uint i, &pre_and_post p) -> () {
|
||||
// sets the ith bit in p's pre and post
|
||||
bitv::set(p.precondition, i, true);
|
||||
bitv::set(p.postcondition, i, true);
|
||||
fn require_and_preserve(uint i, &pre_and_post p) {
|
||||
// sets the ith bit in p's pre and post
|
||||
|
||||
bitv::set(p.precondition, i, true);
|
||||
bitv::set(p.postcondition, i, true);
|
||||
}
|
||||
|
||||
fn set_in_postcond(uint i, &pre_and_post p) -> bool {
|
||||
// sets the ith bit in p's post
|
||||
auto was_set = bitv::get(p.postcondition, i);
|
||||
bitv::set(p.postcondition, i, true);
|
||||
ret !was_set;
|
||||
// sets the ith bit in p's post
|
||||
|
||||
auto was_set = bitv::get(p.postcondition, i);
|
||||
bitv::set(p.postcondition, i, true);
|
||||
ret !was_set;
|
||||
}
|
||||
|
||||
fn set_in_poststate(uint i, &pre_and_post_state s) -> bool {
|
||||
// sets the ith bit in p's post
|
||||
auto was_set = bitv::get(s.poststate, i);
|
||||
bitv::set(s.poststate, i, true);
|
||||
ret !was_set;
|
||||
// sets the ith bit in p's post
|
||||
|
||||
auto was_set = bitv::get(s.poststate, i);
|
||||
bitv::set(s.poststate, i, true);
|
||||
ret !was_set;
|
||||
}
|
||||
|
||||
fn clear_in_poststate(uint i, &pre_and_post_state s) -> bool {
|
||||
// sets the ith bit in p's post
|
||||
auto was_set = bitv::get(s.poststate, i);
|
||||
bitv::set(s.poststate, i, false);
|
||||
ret was_set;
|
||||
// sets the ith bit in p's post
|
||||
|
||||
auto was_set = bitv::get(s.poststate, i);
|
||||
bitv::set(s.poststate, i, false);
|
||||
ret was_set;
|
||||
}
|
||||
|
||||
|
||||
// Sets all the bits in a's precondition to equal the
|
||||
// corresponding bit in p's precondition.
|
||||
fn set_precondition(ts_ann a, &precond p) -> () {
|
||||
bitv::copy(a.conditions.precondition, p);
|
||||
fn set_precondition(ts_ann a, &precond p) {
|
||||
bitv::copy(a.conditions.precondition, p);
|
||||
}
|
||||
|
||||
|
||||
// Sets all the bits in a's postcondition to equal the
|
||||
// corresponding bit in p's postcondition.
|
||||
fn set_postcondition(ts_ann a, &postcond p) -> () {
|
||||
bitv::copy(a.conditions.postcondition, p);
|
||||
fn set_postcondition(ts_ann a, &postcond p) {
|
||||
bitv::copy(a.conditions.postcondition, p);
|
||||
}
|
||||
|
||||
|
||||
// Sets all the bits in a's prestate to equal the
|
||||
// corresponding bit in p's prestate.
|
||||
fn set_prestate(ts_ann a, &prestate p) -> bool {
|
||||
ret bitv::copy(a.states.prestate, p);
|
||||
ret bitv::copy(a.states.prestate, p);
|
||||
}
|
||||
|
||||
|
||||
// Sets all the bits in a's postcondition to equal the
|
||||
// corresponding bit in p's postcondition.
|
||||
fn set_poststate(ts_ann a, &poststate p) -> bool {
|
||||
ret bitv::copy(a.states.poststate, p);
|
||||
ret bitv::copy(a.states.poststate, p);
|
||||
}
|
||||
|
||||
|
||||
// Set all the bits in p that are set in new
|
||||
fn extend_prestate(&prestate p, &poststate new) -> bool {
|
||||
ret bitv::union(p, new);
|
||||
ret bitv::union(p, new);
|
||||
}
|
||||
|
||||
|
||||
// Set all the bits in p that are set in new
|
||||
fn extend_poststate(&poststate p, &poststate new) -> bool {
|
||||
ret bitv::union(p, new);
|
||||
ret bitv::union(p, new);
|
||||
}
|
||||
|
||||
|
||||
// Clears the given bit in p
|
||||
fn relax_prestate(uint i, &prestate p) -> bool {
|
||||
auto was_set = bitv::get(p, i);
|
||||
|
@ -162,46 +171,36 @@ fn relax_prestate(uint i, &prestate p) -> bool {
|
|||
ret was_set;
|
||||
}
|
||||
|
||||
|
||||
// Clears all the bits in p
|
||||
fn clear(&precond p) -> () {
|
||||
bitv::clear(p);
|
||||
}
|
||||
fn clear(&precond p) { bitv::clear(p); }
|
||||
|
||||
|
||||
// Sets all the bits in p
|
||||
fn set(&precond p) -> () {
|
||||
bitv::set_all(p);
|
||||
}
|
||||
fn set(&precond p) { bitv::set_all(p); }
|
||||
|
||||
fn ann_precond(&ts_ann a) -> precond {
|
||||
ret a.conditions.precondition;
|
||||
}
|
||||
fn ann_precond(&ts_ann a) -> precond { ret a.conditions.precondition; }
|
||||
|
||||
fn ann_prestate(&ts_ann a) -> prestate {
|
||||
ret a.states.prestate;
|
||||
}
|
||||
fn ann_prestate(&ts_ann a) -> prestate { ret a.states.prestate; }
|
||||
|
||||
fn ann_poststate(&ts_ann a) -> poststate {
|
||||
ret a.states.poststate;
|
||||
}
|
||||
fn ann_poststate(&ts_ann a) -> poststate { ret a.states.poststate; }
|
||||
|
||||
fn pp_clone(&pre_and_post p) -> pre_and_post {
|
||||
ret @rec(precondition=clone(p.precondition),
|
||||
postcondition=clone(p.postcondition));
|
||||
ret @rec(precondition=clone(p.precondition),
|
||||
postcondition=clone(p.postcondition));
|
||||
}
|
||||
|
||||
fn clone(prestate p) -> prestate {
|
||||
ret bitv::clone(p);
|
||||
}
|
||||
fn clone(prestate p) -> prestate { ret bitv::clone(p); }
|
||||
|
||||
|
||||
// returns true if a implies b
|
||||
// that is, returns true except if for some bits c and d,
|
||||
// c = 1 and d = 0
|
||||
fn implies(bitv::t a, bitv::t b) -> bool {
|
||||
auto tmp = bitv::clone(b);
|
||||
bitv::difference(tmp, a);
|
||||
ret bitv::is_false(tmp);
|
||||
auto tmp = bitv::clone(b);
|
||||
bitv::difference(tmp, a);
|
||||
ret bitv::is_false(tmp);
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
|
||||
import std::vec;
|
||||
import std::option;
|
||||
import std::option::some;
|
||||
import std::option::none;
|
||||
|
||||
import front::ast::*;
|
||||
import middle::ty::expr_ann;
|
||||
|
||||
import util::common::uistr;
|
||||
import util::common::span;
|
||||
import util::common::new_str_hash;
|
||||
|
@ -16,7 +15,6 @@ import util::common::log_stmt_err;
|
|||
import util::common::log_expr;
|
||||
import util::common::log_block;
|
||||
import util::common::log_stmt;
|
||||
|
||||
import aux::fn_info;
|
||||
import aux::fn_info_map;
|
||||
import aux::num_constraints;
|
||||
|
@ -25,75 +23,72 @@ import aux::crate_ctxt;
|
|||
import aux::add_node;
|
||||
import middle::tstate::ann::empty_ann;
|
||||
|
||||
fn collect_ids_expr(&@expr e, @mutable vec[uint] res) -> () {
|
||||
vec::push(*res, (expr_ann(e)).id);
|
||||
fn collect_ids_expr(&@expr e, @mutable vec[uint] res) {
|
||||
vec::push(*res, expr_ann(e).id);
|
||||
}
|
||||
fn collect_ids_block(&block b, @mutable vec[uint] res) -> () {
|
||||
|
||||
fn collect_ids_block(&block b, @mutable vec[uint] res) {
|
||||
vec::push(*res, b.node.a.id);
|
||||
}
|
||||
|
||||
fn collect_ids_stmt(&@stmt s, @mutable vec[uint] res) -> () {
|
||||
fn collect_ids_stmt(&@stmt s, @mutable vec[uint] res) {
|
||||
alt (s.node) {
|
||||
case (stmt_decl(_,?a)) {
|
||||
log("node_id " + uistr(a.id));
|
||||
case (stmt_decl(_, ?a)) {
|
||||
log "node_id " + uistr(a.id);
|
||||
log_stmt(*s);
|
||||
|
||||
vec::push(*res, a.id);
|
||||
}
|
||||
case (stmt_expr(_,?a)) {
|
||||
log("node_id " + uistr(a.id));
|
||||
case (stmt_expr(_, ?a)) {
|
||||
log "node_id " + uistr(a.id);
|
||||
log_stmt(*s);
|
||||
|
||||
vec::push(*res, a.id);
|
||||
}
|
||||
case (_) {}
|
||||
case (_) { }
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_ids_local(&@local l, @mutable vec[uint] res) -> () {
|
||||
fn collect_ids_local(&@local l, @mutable vec[uint] res) {
|
||||
vec::push(*res, l.node.ann.id);
|
||||
}
|
||||
|
||||
fn node_ids_in_fn(&_fn f, &span sp, &ident i, &def_id d, &ann a,
|
||||
@mutable vec[uint] res) -> () {
|
||||
@mutable vec[uint] res) {
|
||||
auto collect_ids = walk::default_visitor();
|
||||
collect_ids = rec(visit_expr_pre = bind collect_ids_expr(_,res),
|
||||
visit_block_pre = bind collect_ids_block(_,res),
|
||||
visit_stmt_pre = bind collect_ids_stmt(_,res),
|
||||
visit_local_pre = bind collect_ids_local(_,res)
|
||||
with collect_ids);
|
||||
collect_ids =
|
||||
rec(visit_expr_pre=bind collect_ids_expr(_, res),
|
||||
visit_block_pre=bind collect_ids_block(_, res),
|
||||
visit_stmt_pre=bind collect_ids_stmt(_, res),
|
||||
visit_local_pre=bind collect_ids_local(_, res) with collect_ids);
|
||||
walk::walk_fn(collect_ids, f, sp, i, d, a);
|
||||
}
|
||||
|
||||
fn init_vecs(&crate_ctxt ccx, &vec[uint] node_ids, uint len) -> () {
|
||||
fn init_vecs(&crate_ctxt ccx, &vec[uint] node_ids, uint len) {
|
||||
for (uint i in node_ids) {
|
||||
log(uistr(i) + " |-> " + uistr(len));
|
||||
log uistr(i) + " |-> " + uistr(len);
|
||||
add_node(ccx, i, empty_ann(len));
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_fn(&crate_ctxt ccx, uint num_constraints, &_fn f,
|
||||
&span sp, &ident i, &def_id d, &ann a) -> () {
|
||||
fn visit_fn(&crate_ctxt ccx, uint num_constraints, &_fn f, &span sp, &ident i,
|
||||
&def_id d, &ann a) {
|
||||
let @mutable vec[uint] node_ids = @mutable [];
|
||||
node_ids_in_fn(f, sp, i, d, a, node_ids);
|
||||
auto node_id_vec = *node_ids;
|
||||
init_vecs(ccx, node_id_vec, num_constraints);
|
||||
}
|
||||
|
||||
fn annotate_in_fn(&crate_ctxt ccx, &_fn f, &span sp, &ident i,
|
||||
&def_id f_id, &ann a)
|
||||
-> () {
|
||||
fn annotate_in_fn(&crate_ctxt ccx, &_fn f, &span sp, &ident i, &def_id f_id,
|
||||
&ann a) {
|
||||
auto f_info = get_fn_info(ccx, f_id);
|
||||
visit_fn(ccx, num_constraints(f_info), f, sp, i, f_id, a);
|
||||
}
|
||||
|
||||
fn annotate_crate(&crate_ctxt ccx, &crate crate) -> () {
|
||||
fn annotate_crate(&crate_ctxt ccx, &crate crate) {
|
||||
auto do_ann = walk::default_visitor();
|
||||
do_ann = rec(visit_fn_pre = bind annotate_in_fn(ccx,_,_,_,_,_)
|
||||
with do_ann);
|
||||
do_ann =
|
||||
rec(visit_fn_pre=bind annotate_in_fn(ccx, _, _, _, _, _) with do_ann);
|
||||
walk::walk_crate(do_ann, crate);
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
import std::bitv;
|
||||
import std::vec;
|
||||
import std::vec::len;
|
||||
|
@ -7,12 +8,9 @@ import std::option;
|
|||
import std::option::none;
|
||||
import std::option::some;
|
||||
import std::option::maybe;
|
||||
|
||||
import front::ast;
|
||||
import front::ast::*;
|
||||
|
||||
import middle::ty::expr_ann;
|
||||
|
||||
import util::common;
|
||||
import util::common::span;
|
||||
import util::common::respan;
|
||||
|
@ -23,7 +21,6 @@ import util::common::log_expr_err;
|
|||
import util::common::uistr;
|
||||
import util::common::lit_eq;
|
||||
import pretty::pprust::path_to_str;
|
||||
|
||||
import tstate::ann::pre_and_post;
|
||||
import tstate::ann::pre_and_post_state;
|
||||
import tstate::ann::empty_ann;
|
||||
|
@ -40,37 +37,23 @@ import tstate::ann::extend_poststate;
|
|||
import tstate::ann::set_precondition;
|
||||
import tstate::ann::set_postcondition;
|
||||
import tstate::ann::ts_ann;
|
||||
|
||||
import util::common::istr;
|
||||
import pretty::ppaux::constr_args_to_str;
|
||||
import pretty::ppaux::lit_to_str;
|
||||
|
||||
/* logging funs */
|
||||
|
||||
fn def_id_to_str(def_id d) -> str {
|
||||
ret (istr(d._0) + "," + istr(d._1));
|
||||
}
|
||||
/* logging funs */
|
||||
fn def_id_to_str(def_id d) -> str { ret istr(d._0) + "," + istr(d._1); }
|
||||
|
||||
fn comma_str(vec[@constr_arg_use] args) -> str {
|
||||
auto res = "";
|
||||
auto comma = false;
|
||||
for (@constr_arg_use a in args) {
|
||||
if (comma) {
|
||||
res += ", ";
|
||||
}
|
||||
else {
|
||||
comma = true;
|
||||
}
|
||||
if (comma) { res += ", "; } else { comma = true; }
|
||||
alt (a.node) {
|
||||
case (carg_base) {
|
||||
res += "*";
|
||||
}
|
||||
case (carg_ident(?i)) {
|
||||
res += i;
|
||||
}
|
||||
case (carg_lit(?l)) {
|
||||
res += lit_to_str(l);
|
||||
}
|
||||
case (carg_base) { res += "*"; }
|
||||
case (carg_ident(?i)) { res += i; }
|
||||
case (carg_lit(?l)) { res += lit_to_str(l); }
|
||||
}
|
||||
}
|
||||
ret res;
|
||||
|
@ -82,132 +65,112 @@ fn constraint_to_str(&ty::ctxt tcx, &constr c) -> str {
|
|||
ret "init(" + i + " [" + tcx.sess.span_str(c.span) + "])";
|
||||
}
|
||||
case (npred(?p, ?args)) {
|
||||
ret path_to_str(p) + "(" + comma_str(args) + ")"
|
||||
+ "[" + tcx.sess.span_str(c.span) + "]";
|
||||
ret path_to_str(p) + "(" + comma_str(args) + ")" + "[" +
|
||||
tcx.sess.span_str(c.span) + "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn bitv_to_str(fn_ctxt fcx, bitv::t v) -> str {
|
||||
auto s = "";
|
||||
auto comma = false;
|
||||
|
||||
for (norm_constraint p in constraints(fcx)) {
|
||||
if (bitv::get(v, p.bit_num)) {
|
||||
s += (if (comma) { ", " } else { comma = true; "" })
|
||||
+ aux::constraint_to_str(fcx.ccx.tcx, p.c);
|
||||
}
|
||||
}
|
||||
ret s;
|
||||
auto s = "";
|
||||
auto comma = false;
|
||||
for (norm_constraint p in constraints(fcx)) {
|
||||
if (bitv::get(v, p.bit_num)) {
|
||||
s +=
|
||||
if (comma) { ", " } else { comma = true; "" } +
|
||||
aux::constraint_to_str(fcx.ccx.tcx, p.c);
|
||||
}
|
||||
}
|
||||
ret s;
|
||||
}
|
||||
|
||||
fn log_bitv(&fn_ctxt fcx, &bitv::t v) {
|
||||
log(bitv_to_str(fcx, v));
|
||||
}
|
||||
fn log_bitv(&fn_ctxt fcx, &bitv::t v) { log bitv_to_str(fcx, v); }
|
||||
|
||||
fn first_difference_string(&fn_ctxt fcx, &bitv::t expected,
|
||||
&bitv::t actual) -> str {
|
||||
fn first_difference_string(&fn_ctxt fcx, &bitv::t expected, &bitv::t actual)
|
||||
-> str {
|
||||
let str s = "";
|
||||
auto done = false;
|
||||
for (norm_constraint c in constraints(fcx)) {
|
||||
if (!done) {
|
||||
if (bitv::get(expected, c.bit_num) &&
|
||||
!bitv::get(actual, c.bit_num)) {
|
||||
!bitv::get(actual, c.bit_num)) {
|
||||
/*
|
||||
FIXME
|
||||
for fun, try either:
|
||||
* "ret s" after the assignment to s
|
||||
or
|
||||
* using break here
|
||||
*/
|
||||
|
||||
/*
|
||||
FIXME
|
||||
for fun, try either:
|
||||
* "ret s" after the assignment to s
|
||||
or
|
||||
* using break here
|
||||
*/
|
||||
s = constraint_to_str(fcx.ccx.tcx, c.c);
|
||||
|
||||
done = true;
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
ret s;
|
||||
}
|
||||
|
||||
fn log_bitv_err(fn_ctxt fcx, bitv::t v) {
|
||||
log_err(bitv_to_str(fcx, v));
|
||||
fn log_bitv_err(fn_ctxt fcx, bitv::t v) { log_err bitv_to_str(fcx, v); }
|
||||
|
||||
fn tos(vec[uint] v) -> str {
|
||||
auto res = "";
|
||||
for (uint i in v) { if (i == 0u) { res += "0"; } else { res += "1"; } }
|
||||
ret res;
|
||||
}
|
||||
|
||||
fn tos (vec[uint] v) -> str {
|
||||
auto res = "";
|
||||
for (uint i in v) {
|
||||
if (i == 0u) {
|
||||
res += "0";
|
||||
}
|
||||
else {
|
||||
res += "1";
|
||||
}
|
||||
}
|
||||
ret res;
|
||||
fn log_cond(vec[uint] v) { log tos(v); }
|
||||
|
||||
fn log_cond_err(vec[uint] v) { log_err tos(v); }
|
||||
|
||||
fn log_pp(&pre_and_post pp) {
|
||||
auto p1 = bitv::to_vec(pp.precondition);
|
||||
auto p2 = bitv::to_vec(pp.postcondition);
|
||||
log "pre:";
|
||||
log_cond(p1);
|
||||
log "post:";
|
||||
log_cond(p2);
|
||||
}
|
||||
|
||||
fn log_cond(vec[uint] v) -> () {
|
||||
log(tos(v));
|
||||
}
|
||||
fn log_cond_err(vec[uint] v) -> () {
|
||||
log_err(tos(v));
|
||||
fn log_pp_err(&pre_and_post pp) {
|
||||
auto p1 = bitv::to_vec(pp.precondition);
|
||||
auto p2 = bitv::to_vec(pp.postcondition);
|
||||
log_err "pre:";
|
||||
log_cond_err(p1);
|
||||
log_err "post:";
|
||||
log_cond_err(p2);
|
||||
}
|
||||
|
||||
fn log_pp(&pre_and_post pp) -> () {
|
||||
auto p1 = bitv::to_vec(pp.precondition);
|
||||
auto p2 = bitv::to_vec(pp.postcondition);
|
||||
log("pre:");
|
||||
log_cond(p1);
|
||||
log("post:");
|
||||
log_cond(p2);
|
||||
fn log_states(&pre_and_post_state pp) {
|
||||
auto p1 = bitv::to_vec(pp.prestate);
|
||||
auto p2 = bitv::to_vec(pp.poststate);
|
||||
log "prestate:";
|
||||
log_cond(p1);
|
||||
log "poststate:";
|
||||
log_cond(p2);
|
||||
}
|
||||
|
||||
fn log_pp_err(&pre_and_post pp) -> () {
|
||||
auto p1 = bitv::to_vec(pp.precondition);
|
||||
auto p2 = bitv::to_vec(pp.postcondition);
|
||||
log_err("pre:");
|
||||
log_cond_err(p1);
|
||||
log_err("post:");
|
||||
log_cond_err(p2);
|
||||
fn log_states_err(&pre_and_post_state pp) {
|
||||
auto p1 = bitv::to_vec(pp.prestate);
|
||||
auto p2 = bitv::to_vec(pp.poststate);
|
||||
log_err "prestate:";
|
||||
log_cond_err(p1);
|
||||
log_err "poststate:";
|
||||
log_cond_err(p2);
|
||||
}
|
||||
|
||||
fn log_states(&pre_and_post_state pp) -> () {
|
||||
auto p1 = bitv::to_vec(pp.prestate);
|
||||
auto p2 = bitv::to_vec(pp.poststate);
|
||||
log("prestate:");
|
||||
log_cond(p1);
|
||||
log("poststate:");
|
||||
log_cond(p2);
|
||||
}
|
||||
fn print_ident(&ident i) { log " " + i + " "; }
|
||||
|
||||
fn log_states_err(&pre_and_post_state pp) -> () {
|
||||
auto p1 = bitv::to_vec(pp.prestate);
|
||||
auto p2 = bitv::to_vec(pp.poststate);
|
||||
log_err("prestate:");
|
||||
log_cond_err(p1);
|
||||
log_err("poststate:");
|
||||
log_cond_err(p2);
|
||||
}
|
||||
|
||||
fn print_ident(&ident i) -> () {
|
||||
log(" " + i + " ");
|
||||
}
|
||||
|
||||
fn print_idents(vec[ident] idents) -> () {
|
||||
if (len[ident](idents) == 0u) {
|
||||
ret;
|
||||
}
|
||||
else {
|
||||
log("an ident: " + pop[ident](idents));
|
||||
print_idents(idents);
|
||||
}
|
||||
fn print_idents(vec[ident] idents) {
|
||||
if (len[ident](idents) == 0u) {
|
||||
ret;
|
||||
} else { log "an ident: " + pop[ident](idents); print_idents(idents); }
|
||||
}
|
||||
|
||||
|
||||
/* data structures */
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/* Two different data structures represent constraints in different
|
||||
contexts: constraint and norm_constraint.
|
||||
|
||||
|
@ -234,116 +197,108 @@ to represent predicate *arguments* however. This type
|
|||
|
||||
Both types store an ident and span, for error-logging purposes.
|
||||
*/
|
||||
type pred_desc_ = rec(vec[@constr_arg_use] args, uint bit_num);
|
||||
|
||||
type pred_desc_ = rec(vec[@constr_arg_use] args,
|
||||
uint bit_num);
|
||||
type pred_desc = spanned[pred_desc_];
|
||||
|
||||
tag constraint {
|
||||
cinit(uint, span, ident);
|
||||
cpred(path, @mutable vec[pred_desc]);
|
||||
}
|
||||
tag constr__ {
|
||||
ninit(ident);
|
||||
npred(path, vec[@constr_arg_use]);
|
||||
}
|
||||
|
||||
tag constr__ { ninit(ident); npred(path, vec[@constr_arg_use]); }
|
||||
|
||||
type constr_ = rec(def_id id, constr__ c);
|
||||
|
||||
type constr = spanned[constr_];
|
||||
type norm_constraint = rec(uint bit_num,
|
||||
constr c);
|
||||
|
||||
type norm_constraint = rec(uint bit_num, constr c);
|
||||
|
||||
type constr_map = @std::map::hashmap[def_id, constraint];
|
||||
|
||||
type fn_info = rec(constr_map constrs, uint num_constraints, controlflow cf);
|
||||
type fn_info = rec(constr_map constrs, uint num_constraints, controlflow cf);
|
||||
|
||||
|
||||
/* mapping from node ID to typestate annotation */
|
||||
type node_ann_table = @mutable vec[mutable ts_ann];
|
||||
|
||||
|
||||
/* mapping from function name to fn_info map */
|
||||
type fn_info_map = @std::map::hashmap[def_id, fn_info];
|
||||
|
||||
type fn_ctxt = rec(fn_info enclosing,
|
||||
def_id id,
|
||||
ident name,
|
||||
crate_ctxt ccx);
|
||||
type fn_ctxt = rec(fn_info enclosing, def_id id, ident name, crate_ctxt ccx);
|
||||
|
||||
type crate_ctxt = rec(ty::ctxt tcx,
|
||||
node_ann_table node_anns,
|
||||
fn_info_map fm);
|
||||
type crate_ctxt = rec(ty::ctxt tcx, node_ann_table node_anns, fn_info_map fm);
|
||||
|
||||
fn get_fn_info(&crate_ctxt ccx, def_id did) -> fn_info {
|
||||
assert (ccx.fm.contains_key(did));
|
||||
ret ccx.fm.get(did);
|
||||
}
|
||||
|
||||
fn add_node(&crate_ctxt ccx, uint i, &ts_ann a) -> () {
|
||||
auto sz = len(*(ccx.node_anns));
|
||||
if (sz <= i) {
|
||||
grow(*(ccx.node_anns), (i - sz) + 1u, empty_ann(0u));
|
||||
}
|
||||
fn add_node(&crate_ctxt ccx, uint i, &ts_ann a) {
|
||||
auto sz = len(*ccx.node_anns);
|
||||
if (sz <= i) { grow(*ccx.node_anns, i - sz + 1u, empty_ann(0u)); }
|
||||
ccx.node_anns.(i) = a;
|
||||
}
|
||||
|
||||
fn get_ts_ann(&crate_ctxt ccx, uint i) -> option::t[ts_ann] {
|
||||
if (i < len(*(ccx.node_anns))) {
|
||||
if (i < len(*ccx.node_anns)) {
|
||||
ret some[ts_ann](ccx.node_anns.(i));
|
||||
}
|
||||
else {
|
||||
ret none[ts_ann];
|
||||
}
|
||||
} else { ret none[ts_ann]; }
|
||||
}
|
||||
/********* utils ********/
|
||||
|
||||
|
||||
/********* utils ********/
|
||||
fn ann_to_ts_ann(&crate_ctxt ccx, &ann a) -> ts_ann {
|
||||
alt (get_ts_ann(ccx, a.id)) {
|
||||
case (none) {
|
||||
log_err ("ann_to_ts_ann: no ts_ann for node_id "
|
||||
+ uistr(a.id));
|
||||
case (none) {
|
||||
log_err "ann_to_ts_ann: no ts_ann for node_id " + uistr(a.id);
|
||||
fail;
|
||||
}
|
||||
case (some(?t)) { ret t; }
|
||||
case (some(?t)) { ret t; }
|
||||
}
|
||||
}
|
||||
|
||||
fn ann_to_poststate(&crate_ctxt ccx, ann a) -> poststate {
|
||||
log "ann_to_poststate";
|
||||
ret (ann_to_ts_ann(ccx, a)).states.poststate;
|
||||
ret ann_to_ts_ann(ccx, a).states.poststate;
|
||||
}
|
||||
|
||||
fn stmt_to_ann(&crate_ctxt ccx, &stmt s) -> ts_ann {
|
||||
log "stmt_to_ann";
|
||||
alt (s.node) {
|
||||
case (stmt_decl(_,?a)) {
|
||||
ret ann_to_ts_ann(ccx, a);
|
||||
alt (s.node) {
|
||||
case (stmt_decl(_, ?a)) { ret ann_to_ts_ann(ccx, a); }
|
||||
case (stmt_expr(_, ?a)) { ret ann_to_ts_ann(ccx, a); }
|
||||
case (stmt_crate_directive(_)) {
|
||||
log_err "expecting an annotated statement here";
|
||||
fail;
|
||||
}
|
||||
}
|
||||
case (stmt_expr(_,?a)) {
|
||||
ret ann_to_ts_ann(ccx, a);
|
||||
}
|
||||
case (stmt_crate_directive(_)) {
|
||||
log_err "expecting an annotated statement here";
|
||||
fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* fails if e has no annotation */
|
||||
fn expr_states(&crate_ctxt ccx, @expr e) -> pre_and_post_state {
|
||||
log "expr_states";
|
||||
ret (ann_to_ts_ann(ccx, expr_ann(e)).states);
|
||||
ret ann_to_ts_ann(ccx, expr_ann(e)).states;
|
||||
}
|
||||
|
||||
|
||||
/* fails if e has no annotation */
|
||||
fn expr_pp(&crate_ctxt ccx, @expr e) -> pre_and_post {
|
||||
log "expr_pp";
|
||||
ret (ann_to_ts_ann(ccx, expr_ann(e)).conditions);
|
||||
ret ann_to_ts_ann(ccx, expr_ann(e)).conditions;
|
||||
}
|
||||
|
||||
fn stmt_pp(&crate_ctxt ccx, &stmt s) -> pre_and_post {
|
||||
ret (stmt_to_ann(ccx, s).conditions);
|
||||
ret stmt_to_ann(ccx, s).conditions;
|
||||
}
|
||||
|
||||
|
||||
/* fails if b has no annotation */
|
||||
fn block_pp(&crate_ctxt ccx, &block b) -> pre_and_post {
|
||||
log "block_pp";
|
||||
ret (ann_to_ts_ann(ccx, b.node.a).conditions);
|
||||
ret ann_to_ts_ann(ccx, b.node.a).conditions;
|
||||
}
|
||||
|
||||
fn clear_pp(pre_and_post pp) {
|
||||
|
@ -358,61 +313,61 @@ fn clear_precond(&crate_ctxt ccx, &ann a) {
|
|||
|
||||
fn block_states(&crate_ctxt ccx, &block b) -> pre_and_post_state {
|
||||
log "block_states";
|
||||
ret (ann_to_ts_ann(ccx, b.node.a).states);
|
||||
ret ann_to_ts_ann(ccx, b.node.a).states;
|
||||
}
|
||||
|
||||
fn stmt_states(&crate_ctxt ccx, &stmt s) -> pre_and_post_state {
|
||||
ret (stmt_to_ann(ccx, s)).states;
|
||||
ret stmt_to_ann(ccx, s).states;
|
||||
}
|
||||
|
||||
fn expr_precond(&crate_ctxt ccx, @expr e) -> precond {
|
||||
ret (expr_pp(ccx, e)).precondition;
|
||||
ret expr_pp(ccx, e).precondition;
|
||||
}
|
||||
|
||||
fn expr_postcond(&crate_ctxt ccx, @expr e) -> postcond {
|
||||
ret (expr_pp(ccx, e)).postcondition;
|
||||
ret expr_pp(ccx, e).postcondition;
|
||||
}
|
||||
|
||||
fn expr_prestate(&crate_ctxt ccx, @expr e) -> prestate {
|
||||
ret (expr_states(ccx, e)).prestate;
|
||||
ret expr_states(ccx, e).prestate;
|
||||
}
|
||||
|
||||
fn expr_poststate(&crate_ctxt ccx, @expr e) -> poststate {
|
||||
ret (expr_states(ccx, e)).poststate;
|
||||
ret expr_states(ccx, e).poststate;
|
||||
}
|
||||
|
||||
fn stmt_precond(&crate_ctxt ccx, &stmt s) -> precond {
|
||||
ret (stmt_pp(ccx, s)).precondition;
|
||||
ret stmt_pp(ccx, s).precondition;
|
||||
}
|
||||
|
||||
fn stmt_postcond(&crate_ctxt ccx, &stmt s) -> postcond {
|
||||
ret (stmt_pp(ccx, s)).postcondition;
|
||||
ret stmt_pp(ccx, s).postcondition;
|
||||
}
|
||||
|
||||
fn states_to_poststate(&pre_and_post_state ss) -> poststate {
|
||||
ret ss.poststate;
|
||||
ret ss.poststate;
|
||||
}
|
||||
|
||||
fn stmt_prestate(&crate_ctxt ccx, &stmt s) -> prestate {
|
||||
ret (stmt_states(ccx, s)).prestate;
|
||||
ret stmt_states(ccx, s).prestate;
|
||||
}
|
||||
|
||||
fn stmt_poststate(&crate_ctxt ccx, &stmt s) -> poststate {
|
||||
ret (stmt_states(ccx, s)).poststate;
|
||||
ret stmt_states(ccx, s).poststate;
|
||||
}
|
||||
|
||||
fn block_postcond(&crate_ctxt ccx, &block b) -> postcond {
|
||||
ret (block_pp(ccx, b)).postcondition;
|
||||
ret block_pp(ccx, b).postcondition;
|
||||
}
|
||||
|
||||
fn block_poststate(&crate_ctxt ccx, &block b) -> poststate {
|
||||
ret (block_states(ccx, b)).poststate;
|
||||
ret block_states(ccx, b).poststate;
|
||||
}
|
||||
|
||||
|
||||
/* sets the pre_and_post for an ann */
|
||||
fn with_pp(&crate_ctxt ccx, &ann a, pre_and_post p) {
|
||||
add_node(ccx, a.id, @rec(conditions=p,
|
||||
states=empty_states(pps_len(p))));
|
||||
add_node(ccx, a.id, @rec(conditions=p, states=empty_states(pps_len(p))));
|
||||
}
|
||||
|
||||
fn set_prestate_ann(&crate_ctxt ccx, &ann a, &prestate pre) -> bool {
|
||||
|
@ -420,7 +375,6 @@ fn set_prestate_ann(&crate_ctxt ccx, &ann a, &prestate pre) -> bool {
|
|||
ret set_prestate(ann_to_ts_ann(ccx, a), pre);
|
||||
}
|
||||
|
||||
|
||||
fn extend_prestate_ann(&crate_ctxt ccx, &ann a, &prestate pre) -> bool {
|
||||
log "extend_prestate_ann";
|
||||
ret extend_prestate(ann_to_ts_ann(ccx, a).states.prestate, pre);
|
||||
|
@ -436,15 +390,14 @@ fn extend_poststate_ann(&crate_ctxt ccx, &ann a, &poststate post) -> bool {
|
|||
ret extend_poststate(ann_to_ts_ann(ccx, a).states.poststate, post);
|
||||
}
|
||||
|
||||
fn set_pre_and_post(&crate_ctxt ccx, &ann a,
|
||||
&precond pre, &postcond post) -> () {
|
||||
fn set_pre_and_post(&crate_ctxt ccx, &ann a, &precond pre, &postcond post) {
|
||||
log "set_pre_and_post";
|
||||
auto t = ann_to_ts_ann(ccx, a);
|
||||
set_precondition(t, pre);
|
||||
set_postcondition(t, post);
|
||||
}
|
||||
|
||||
fn copy_pre_post(&crate_ctxt ccx, &ann a, &@expr sub) -> () {
|
||||
fn copy_pre_post(&crate_ctxt ccx, &ann a, &@expr sub) {
|
||||
log "set_pre_and_post";
|
||||
auto p = expr_pp(ccx, sub);
|
||||
auto t = ann_to_ts_ann(ccx, a);
|
||||
|
@ -460,29 +413,25 @@ fn set_postcond_false(&crate_ctxt ccx, &ann a) {
|
|||
}
|
||||
|
||||
fn pure_exp(&crate_ctxt ccx, &ann a, &prestate p) -> bool {
|
||||
auto changed = false;
|
||||
changed = extend_prestate_ann(ccx, a, p) || changed;
|
||||
changed = extend_poststate_ann(ccx, a, p) || changed;
|
||||
ret changed;
|
||||
auto changed = false;
|
||||
changed = extend_prestate_ann(ccx, a, p) || changed;
|
||||
changed = extend_poststate_ann(ccx, a, p) || changed;
|
||||
ret changed;
|
||||
}
|
||||
|
||||
fn fixed_point_states(&fn_ctxt fcx,
|
||||
fn (&fn_ctxt, &_fn) -> bool f, &_fn start) -> () {
|
||||
fn fixed_point_states(&fn_ctxt fcx, fn(&fn_ctxt, &_fn) -> bool f,
|
||||
&_fn start) {
|
||||
auto changed = f(fcx, start);
|
||||
if (changed) {
|
||||
ret fixed_point_states(fcx, f, start);
|
||||
} else {
|
||||
// we're done!
|
||||
|
||||
auto changed = f(fcx, start);
|
||||
|
||||
if (changed) {
|
||||
ret fixed_point_states(fcx, f, start);
|
||||
}
|
||||
else {
|
||||
// we're done!
|
||||
ret;
|
||||
}
|
||||
ret;
|
||||
}
|
||||
}
|
||||
|
||||
fn num_constraints(fn_info m) -> uint {
|
||||
ret m.num_constraints;
|
||||
}
|
||||
fn num_constraints(fn_info m) -> uint { ret m.num_constraints; }
|
||||
|
||||
fn new_crate_ctxt(ty::ctxt cx) -> crate_ctxt {
|
||||
let vec[mutable ts_ann] na = vec::empty_mut();
|
||||
|
@ -492,40 +441,32 @@ fn new_crate_ctxt(ty::ctxt cx) -> crate_ctxt {
|
|||
fn controlflow_def_id(&crate_ctxt ccx, &def_id d) -> controlflow {
|
||||
alt (ccx.fm.find(d)) {
|
||||
case (some(?fi)) { ret fi.cf; }
|
||||
case (none) { ret return; }
|
||||
case (none) { ret return; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Use e's type to determine whether it returns.
|
||||
If it has a function type with a ! annotation,
|
||||
the answer is noreturn. */
|
||||
fn controlflow_expr(&crate_ctxt ccx, @expr e) -> controlflow {
|
||||
alt (ty::struct(ccx.tcx, ty::ann_to_type(ccx.tcx,
|
||||
expr_ann(e)))) {
|
||||
case (ty::ty_fn(_,_,_,?cf,_)) {
|
||||
ret cf;
|
||||
}
|
||||
case (_) {
|
||||
ret return;
|
||||
}
|
||||
alt (ty::struct(ccx.tcx, ty::ann_to_type(ccx.tcx, expr_ann(e)))) {
|
||||
case (ty::ty_fn(_, _, _, ?cf, _)) { ret cf; }
|
||||
case (_) { ret return; }
|
||||
}
|
||||
}
|
||||
|
||||
fn constraints_expr(&ty::ctxt cx, @expr e) -> vec[@ast::constr] {
|
||||
alt (ty::struct(cx, ty::ann_to_type(cx, expr_ann(e)))) {
|
||||
case (ty::ty_fn(_,_,_,_,?cs)) {
|
||||
ret cs;
|
||||
}
|
||||
case (_) {
|
||||
ret [];
|
||||
}
|
||||
case (ty::ty_fn(_, _, _, _, ?cs)) { ret cs; }
|
||||
case (_) { ret []; }
|
||||
}
|
||||
}
|
||||
|
||||
fn ann_to_def_strict(&ty::ctxt cx, &ann a) -> def {
|
||||
alt (cx.def_map.find(a.id)) {
|
||||
case (none) {
|
||||
log_err("ann_to_def: node_id " + uistr(a.id) + " has no def");
|
||||
log_err "ann_to_def: node_id " + uistr(a.id) + " has no def";
|
||||
fail;
|
||||
}
|
||||
case (some(?d)) { ret d; }
|
||||
|
@ -544,37 +485,38 @@ fn norm_a_constraint(&def_id id, &constraint c) -> vec[norm_constraint] {
|
|||
case (cpred(?p, ?descs)) {
|
||||
let vec[norm_constraint] res = [];
|
||||
for (pred_desc pd in *descs) {
|
||||
vec::push(res, rec(bit_num=pd.node.bit_num,
|
||||
c=respan(pd.span, rec(id=id, c=npred(p, pd.node.args)))));
|
||||
vec::push(res,
|
||||
rec(bit_num=pd.node.bit_num,
|
||||
c=respan(pd.span,
|
||||
rec(id=id,
|
||||
c=npred(p, pd.node.args)))));
|
||||
}
|
||||
ret res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Tried to write this as an iterator, but I got a
|
||||
// non-exhaustive match in trans.
|
||||
fn constraints(&fn_ctxt fcx) -> vec[norm_constraint] {
|
||||
let vec[norm_constraint] res = [];
|
||||
for each (@tup(def_id, constraint) p in
|
||||
fcx.enclosing.constrs.items()) {
|
||||
for each (@tup(def_id, constraint) p in fcx.enclosing.constrs.items()) {
|
||||
res += norm_a_constraint(p._0, p._1);
|
||||
}
|
||||
ret res;
|
||||
}
|
||||
|
||||
|
||||
// FIXME:
|
||||
// this probably doesn't handle name shadowing well (or at all)
|
||||
// variables should really always be id'd by def_id and not ident
|
||||
fn match_args(&fn_ctxt fcx, vec[pred_desc] occs,
|
||||
vec[@constr_arg_use] occ) -> uint {
|
||||
log ("match_args: looking at " +
|
||||
pretty::ppaux::constr_args_to_str_1(occ));
|
||||
fn match_args(&fn_ctxt fcx, vec[pred_desc] occs, vec[@constr_arg_use] occ) ->
|
||||
uint {
|
||||
log "match_args: looking at " + pretty::ppaux::constr_args_to_str_1(occ);
|
||||
for (pred_desc pd in occs) {
|
||||
log ("match_args: candidate " + pred_desc_to_str(pd));
|
||||
if (ty::args_eq(str::eq, pd.node.args, occ)) {
|
||||
ret pd.node.bit_num;
|
||||
}
|
||||
log "match_args: candidate " + pred_desc_to_str(pd);
|
||||
if (ty::args_eq(str::eq, pd.node.args, occ)) { ret pd.node.bit_num; }
|
||||
}
|
||||
fcx.ccx.tcx.sess.bug("match_args: no match for occurring args");
|
||||
}
|
||||
|
@ -583,10 +525,8 @@ fn def_id_for_constr(ty::ctxt tcx, uint t) -> def_id {
|
|||
alt (tcx.def_map.find(t)) {
|
||||
case (none) {
|
||||
tcx.sess.bug("def_id_for_constr: bad node_id " + uistr(t));
|
||||
}
|
||||
case (some(def_fn(?i))) {
|
||||
ret i;
|
||||
}
|
||||
case (some(def_fn(?i))) { ret i; }
|
||||
case (_) {
|
||||
tcx.sess.bug("def_id_for_constr: pred is not a function");
|
||||
}
|
||||
|
@ -598,60 +538,59 @@ fn expr_to_constr_arg(ty::ctxt tcx, &@expr e) -> @constr_arg_use {
|
|||
case (expr_path(?p, _)) {
|
||||
if (vec::len(p.node.idents) == 1u) {
|
||||
ret @respan(p.span, carg_ident[ident](p.node.idents.(0)));
|
||||
}
|
||||
else {
|
||||
tcx.sess.bug("exprs_to_constr_args: non-local variable "
|
||||
+ "as pred arg");
|
||||
} else {
|
||||
tcx.sess.bug("exprs_to_constr_args: non-local variable " +
|
||||
"as pred arg");
|
||||
}
|
||||
}
|
||||
case (expr_lit(?l, _)) {
|
||||
ret @respan(e.span, carg_lit(l));
|
||||
}
|
||||
case (expr_lit(?l, _)) { ret @respan(e.span, carg_lit(l)); }
|
||||
case (_) {
|
||||
tcx.sess.bug("exprs_to_constr_args: ill-formed pred arg");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn exprs_to_constr_args(ty::ctxt tcx, vec[@expr] args)
|
||||
-> vec[@constr_arg_use] {
|
||||
fn exprs_to_constr_args(ty::ctxt tcx, vec[@expr] args) ->
|
||||
vec[@constr_arg_use] {
|
||||
auto f = bind expr_to_constr_arg(tcx, _);
|
||||
ret vec::map(f, args);
|
||||
}
|
||||
|
||||
fn expr_to_constr(ty::ctxt tcx, &@expr e) -> constr {
|
||||
alt (e.node) {
|
||||
// FIXME
|
||||
// change the first pattern to expr_path to test a typechecker bug
|
||||
case (expr_call(?operator, ?args, _)) {
|
||||
case (
|
||||
// FIXME change the first pattern to expr_path to test a
|
||||
// typechecker bug
|
||||
expr_call(?operator, ?args, _)) {
|
||||
alt (operator.node) {
|
||||
case (expr_path(?p, ?a)) {
|
||||
ret respan(e.span,
|
||||
rec(id=def_id_for_constr(tcx, a.id),
|
||||
c=npred(p,
|
||||
exprs_to_constr_args(tcx, args))));
|
||||
rec(id=def_id_for_constr(tcx, a.id),
|
||||
c=npred(p,
|
||||
exprs_to_constr_args(tcx, args))));
|
||||
}
|
||||
case (_) {
|
||||
tcx.sess.span_err(operator.span, "Internal error: " +
|
||||
" ill-formed operator in predicate");
|
||||
tcx.sess.span_err(operator.span,
|
||||
"Internal error: " +
|
||||
" ill-formed operator \
|
||||
in predicate");
|
||||
}
|
||||
}
|
||||
}
|
||||
case (_) {
|
||||
tcx.sess.span_err(e.span, "Internal error: " +
|
||||
" ill-formed predicate");
|
||||
tcx.sess.span_err(e.span,
|
||||
"Internal error: " + " ill-formed predicate");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn pred_desc_to_str(&pred_desc p) -> str {
|
||||
ret ("<" + uistr(p.node.bit_num) + ", " +
|
||||
pretty::ppaux::constr_args_to_str_1(p.node.args) + ">");
|
||||
ret "<" + uistr(p.node.bit_num) + ", " +
|
||||
pretty::ppaux::constr_args_to_str_1(p.node.args) + ">";
|
||||
}
|
||||
|
||||
fn substitute_constr_args(&ty::ctxt cx,
|
||||
&vec[@expr] actuals, &@ast::constr c)
|
||||
-> constr__ {
|
||||
fn substitute_constr_args(&ty::ctxt cx, &vec[@expr] actuals, &@ast::constr c)
|
||||
-> constr__ {
|
||||
let vec[@constr_arg_use] res = [];
|
||||
for (@constr_arg a in c.node.args) {
|
||||
res += [substitute_arg(cx, actuals, a)];
|
||||
|
@ -661,31 +600,26 @@ fn substitute_constr_args(&ty::ctxt cx,
|
|||
|
||||
type subst = vec[tup(arg, @expr)];
|
||||
|
||||
fn substitute_arg(&ty::ctxt cx, &vec[@expr] actuals, @ast::constr_arg a)
|
||||
-> @constr_arg_use {
|
||||
fn substitute_arg(&ty::ctxt cx, &vec[@expr] actuals, @ast::constr_arg a) ->
|
||||
@constr_arg_use {
|
||||
auto num_actuals = vec::len(actuals);
|
||||
alt (a.node) {
|
||||
case (carg_ident(?i)) {
|
||||
if (i < num_actuals) {
|
||||
ret expr_to_constr_arg(cx, actuals.(i));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
cx.sess.span_err(a.span, "Constraint argument out of bounds");
|
||||
}
|
||||
}
|
||||
case (carg_base) { ret @respan(a.span, carg_base); }
|
||||
case (carg_lit(?l)) { ret @respan(a.span, carg_lit(l)); }
|
||||
case (carg_lit(?l)) { ret @respan(a.span, carg_lit(l)); }
|
||||
}
|
||||
}
|
||||
|
||||
fn path_to_ident(&ty::ctxt cx, &path p) -> ident {
|
||||
alt (vec::last(p.node.idents)) {
|
||||
case (none) {
|
||||
cx.sess.span_err(p.span, "Malformed path");
|
||||
}
|
||||
case (some(?i)) {
|
||||
ret i;
|
||||
}
|
||||
case (none) { cx.sess.span_err(p.span, "Malformed path"); }
|
||||
case (some(?i)) { ret i; }
|
||||
}
|
||||
}
|
||||
//
|
||||
|
@ -698,4 +632,3 @@ fn path_to_ident(&ty::ctxt cx, &path p) -> ident {
|
|||
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
|
||||
// End:
|
||||
//
|
||||
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
|
||||
import std::bitv;
|
||||
import std::vec;
|
||||
import std::vec::len;
|
||||
import std::vec::slice;
|
||||
|
||||
import front::ast::*;
|
||||
|
||||
import aux::fn_ctxt;
|
||||
import aux::fn_info;
|
||||
import aux::log_bitv;
|
||||
|
@ -16,7 +15,6 @@ import aux::npred;
|
|||
import aux::pred_desc;
|
||||
import aux::match_args;
|
||||
import aux::constr_;
|
||||
|
||||
import tstate::aux::ann_to_ts_ann;
|
||||
import tstate::ann::pre_and_post;
|
||||
import tstate::ann::precond;
|
||||
|
@ -41,23 +39,19 @@ fn bit_num(&fn_ctxt fcx, &constr_ c) -> uint {
|
|||
alt (c.c) {
|
||||
case (ninit(_)) {
|
||||
alt (res) {
|
||||
case (cinit(?n,_,_)) {
|
||||
ret n;
|
||||
}
|
||||
case (cinit(?n, _, _)) { ret n; }
|
||||
case (_) {
|
||||
fcx.ccx.tcx.sess.bug("bit_num: asked for init constraint,"
|
||||
+ " found a pred constraint");
|
||||
+ " found a pred constraint");
|
||||
}
|
||||
}
|
||||
}
|
||||
case (npred(_, ?args)) {
|
||||
alt (res) {
|
||||
case (cpred(_, ?descs)) {
|
||||
ret match_args(fcx, *descs, args);
|
||||
}
|
||||
case (cpred(_, ?descs)) { ret match_args(fcx, *descs, args); }
|
||||
case (_) {
|
||||
fcx.ccx.tcx.sess.bug("bit_num: asked for pred constraint,"
|
||||
+ " found an init constraint");
|
||||
+ " found an init constraint");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,84 +62,75 @@ fn promises(&fn_ctxt fcx, &poststate p, &constr_ c) -> bool {
|
|||
ret bitv::get(p, bit_num(fcx, c));
|
||||
}
|
||||
|
||||
|
||||
// Given a list of pres and posts for exprs e0 ... en,
|
||||
// return the precondition for evaluating each expr in order.
|
||||
// So, if e0's post is {x} and e1's pre is {x, y, z}, the entire
|
||||
// precondition shouldn't include x.
|
||||
fn seq_preconds(fn_ctxt fcx, vec[pre_and_post] pps) -> precond {
|
||||
let uint sz = len[pre_and_post](pps);
|
||||
let uint num_vars = num_constraints(fcx.enclosing);
|
||||
|
||||
if (sz >= 1u) {
|
||||
auto first = pps.(0);
|
||||
assert (pps_len(first) == num_vars);
|
||||
let precond rest = seq_preconds(fcx,
|
||||
slice[pre_and_post](pps, 1u, sz));
|
||||
difference(rest, first.postcondition);
|
||||
auto res = clone(first.precondition);
|
||||
union(res, rest);
|
||||
|
||||
log("seq_preconds:");
|
||||
log("first.postcondition =");
|
||||
log_bitv(fcx, first.postcondition);
|
||||
log("rest =");
|
||||
log_bitv(fcx, rest);
|
||||
log("returning");
|
||||
log_bitv(fcx, res);
|
||||
|
||||
ret res;
|
||||
}
|
||||
else {
|
||||
ret true_precond(num_vars);
|
||||
}
|
||||
let uint sz = len[pre_and_post](pps);
|
||||
let uint num_vars = num_constraints(fcx.enclosing);
|
||||
if (sz >= 1u) {
|
||||
auto first = pps.(0);
|
||||
assert (pps_len(first) == num_vars);
|
||||
let precond rest =
|
||||
seq_preconds(fcx, slice[pre_and_post](pps, 1u, sz));
|
||||
difference(rest, first.postcondition);
|
||||
auto res = clone(first.precondition);
|
||||
union(res, rest);
|
||||
log "seq_preconds:";
|
||||
log "first.postcondition =";
|
||||
log_bitv(fcx, first.postcondition);
|
||||
log "rest =";
|
||||
log_bitv(fcx, rest);
|
||||
log "returning";
|
||||
log_bitv(fcx, res);
|
||||
ret res;
|
||||
} else { ret true_precond(num_vars); }
|
||||
}
|
||||
|
||||
|
||||
/* works on either postconds or preconds
|
||||
should probably rethink the whole type synonym situation */
|
||||
fn union_postconds_go(&postcond first, &vec[postcond] rest) -> postcond {
|
||||
auto sz = vec::len[postcond](rest);
|
||||
|
||||
if (sz > 0u) {
|
||||
auto other = rest.(0);
|
||||
union(first, other);
|
||||
union_postconds_go(first, slice[postcond](rest, 1u, len[postcond](rest)));
|
||||
}
|
||||
|
||||
ret first;
|
||||
auto sz = vec::len[postcond](rest);
|
||||
if (sz > 0u) {
|
||||
auto other = rest.(0);
|
||||
union(first, other);
|
||||
union_postconds_go(first,
|
||||
slice[postcond](rest, 1u, len[postcond](rest)));
|
||||
}
|
||||
ret first;
|
||||
}
|
||||
|
||||
fn union_postconds(uint nv, &vec[postcond] pcs) -> postcond {
|
||||
if (len[postcond](pcs) > 0u) {
|
||||
ret union_postconds_go(bitv::clone(pcs.(0)), pcs);
|
||||
}
|
||||
else {
|
||||
ret empty_prestate(nv);
|
||||
}
|
||||
if (len[postcond](pcs) > 0u) {
|
||||
ret union_postconds_go(bitv::clone(pcs.(0)), pcs);
|
||||
} else { ret empty_prestate(nv); }
|
||||
}
|
||||
|
||||
|
||||
/* Gee, maybe we could use foldl or something */
|
||||
fn intersect_postconds_go(&postcond first, &vec[postcond] rest) -> postcond {
|
||||
auto sz = vec::len[postcond](rest);
|
||||
|
||||
if (sz > 0u) {
|
||||
auto other = rest.(0);
|
||||
intersect(first, other);
|
||||
intersect_postconds_go(first, slice[postcond](rest, 1u,
|
||||
len[postcond](rest)));
|
||||
}
|
||||
|
||||
ret first;
|
||||
auto sz = vec::len[postcond](rest);
|
||||
if (sz > 0u) {
|
||||
auto other = rest.(0);
|
||||
intersect(first, other);
|
||||
intersect_postconds_go(first,
|
||||
slice[postcond](rest, 1u,
|
||||
len[postcond](rest)));
|
||||
}
|
||||
ret first;
|
||||
}
|
||||
|
||||
fn intersect_postconds(&vec[postcond] pcs) -> postcond {
|
||||
assert (len[postcond](pcs) > 0u);
|
||||
|
||||
ret intersect_postconds_go(bitv::clone(pcs.(0)), pcs);
|
||||
assert (len[postcond](pcs) > 0u);
|
||||
ret intersect_postconds_go(bitv::clone(pcs.(0)), pcs);
|
||||
}
|
||||
|
||||
fn gen(&fn_ctxt fcx, &ann a, &constr_ c) -> bool {
|
||||
ret set_in_postcond(bit_num(fcx, c),
|
||||
(ann_to_ts_ann(fcx.ccx, a)).conditions);
|
||||
ret set_in_postcond(bit_num(fcx, c),
|
||||
ann_to_ts_ann(fcx.ccx, a).conditions);
|
||||
}
|
||||
|
||||
fn declare_var(&fn_ctxt fcx, &constr_ c, prestate pre) -> prestate {
|
||||
|
@ -155,17 +140,14 @@ fn declare_var(&fn_ctxt fcx, &constr_ c, prestate pre) -> prestate {
|
|||
}
|
||||
|
||||
fn gen_poststate(&fn_ctxt fcx, &ann a, &constr_ c) -> bool {
|
||||
log "gen_poststate";
|
||||
ret set_in_poststate(bit_num(fcx, c),
|
||||
(ann_to_ts_ann(fcx.ccx, a)).states);
|
||||
log "gen_poststate";
|
||||
ret set_in_poststate(bit_num(fcx, c), ann_to_ts_ann(fcx.ccx, a).states);
|
||||
}
|
||||
|
||||
fn kill_poststate(&fn_ctxt fcx, &ann a, &constr_ c) -> bool {
|
||||
log "kill_poststate";
|
||||
ret clear_in_poststate(bit_num(fcx, c),
|
||||
(ann_to_ts_ann(fcx.ccx, a)).states);
|
||||
log "kill_poststate";
|
||||
ret clear_in_poststate(bit_num(fcx, c), ann_to_ts_ann(fcx.ccx, a).states);
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
import front::ast;
|
||||
import front::ast::method;
|
||||
import front::ast::ann;
|
||||
|
@ -13,7 +14,6 @@ import front::ast::ty_param;
|
|||
import front::ast::crate;
|
||||
import front::ast::return;
|
||||
import front::ast::noreturn;
|
||||
|
||||
import front::ast::expr;
|
||||
import middle::ty::type_is_nil;
|
||||
import middle::ty::ret_ty_of_fn;
|
||||
|
@ -36,12 +36,10 @@ import std::vec::slice;
|
|||
import std::vec::unzip;
|
||||
import std::vec::plus_option;
|
||||
import std::vec::cat_options;
|
||||
|
||||
import std::option;
|
||||
import std::option::t;
|
||||
import std::option::some;
|
||||
import std::option::none;
|
||||
|
||||
import aux::fn_ctxt;
|
||||
import aux::crate_ctxt;
|
||||
import aux::new_crate_ctxt;
|
||||
|
@ -54,39 +52,37 @@ import aux::num_constraints;
|
|||
import aux::fixed_point_states;
|
||||
import aux::bitv_to_str;
|
||||
import aux::first_difference_string;
|
||||
|
||||
import pretty::pprust::ty_to_str;
|
||||
import util::common::log_stmt_err;
|
||||
import aux::log_bitv_err;
|
||||
import bitvectors::promises;
|
||||
|
||||
import annotate::annotate_crate;
|
||||
import collect_locals::mk_f_to_fn_info;
|
||||
import pre_post_conditions::fn_pre_post;
|
||||
import states::find_pre_post_state_fn;
|
||||
|
||||
fn check_states_expr(&fn_ctxt fcx, @expr e) -> () {
|
||||
let precond prec = expr_precond(fcx.ccx, e);
|
||||
fn check_states_expr(&fn_ctxt fcx, @expr e) {
|
||||
let precond prec = expr_precond(fcx.ccx, e);
|
||||
let prestate pres = expr_prestate(fcx.ccx, e);
|
||||
|
||||
if (!implies(pres, prec)) {
|
||||
auto s = "";
|
||||
auto diff = first_difference_string(fcx, prec, pres);
|
||||
s += ("Unsatisfied precondition constraint (for example, "
|
||||
+ diff + ") for expression:\n");
|
||||
s +=
|
||||
"Unsatisfied precondition constraint (for example, " + diff +
|
||||
") for expression:\n";
|
||||
s += pretty::pprust::expr_to_str(e);
|
||||
s += ("\nPrecondition:\n");
|
||||
s += "\nPrecondition:\n";
|
||||
s += bitv_to_str(fcx, prec);
|
||||
s += ("\nPrestate:\n");
|
||||
s += "\nPrestate:\n";
|
||||
s += bitv_to_str(fcx, pres);
|
||||
fcx.ccx.tcx.sess.span_err(e.span, s);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_states_stmt(&fn_ctxt fcx, &stmt s) -> () {
|
||||
fn check_states_stmt(&fn_ctxt fcx, &stmt s) {
|
||||
auto a = stmt_to_ann(fcx.ccx, s);
|
||||
let precond prec = ann_precond(a);
|
||||
let prestate pres = ann_prestate(a);
|
||||
let precond prec = ann_precond(a);
|
||||
let prestate pres = ann_prestate(a);
|
||||
|
||||
/*
|
||||
log_err("check_states_stmt:");
|
||||
|
@ -96,113 +92,109 @@ fn check_states_stmt(&fn_ctxt fcx, &stmt s) -> () {
|
|||
log_err("pres = ");
|
||||
log_bitv_err(fcx.enclosing, pres);
|
||||
*/
|
||||
|
||||
if (!implies(pres, prec)) {
|
||||
auto ss = "";
|
||||
auto diff = first_difference_string(fcx, prec, pres);
|
||||
ss += ("Unsatisfied precondition constraint (for example, "
|
||||
+ diff + ") for statement:\n");
|
||||
ss +=
|
||||
"Unsatisfied precondition constraint (for example, " + diff +
|
||||
") for statement:\n";
|
||||
ss += pretty::pprust::stmt_to_str(s);
|
||||
ss += ("\nPrecondition:\n");
|
||||
ss += "\nPrecondition:\n";
|
||||
ss += bitv_to_str(fcx, prec);
|
||||
ss += ("\nPrestate: \n");
|
||||
ss += "\nPrestate: \n";
|
||||
ss += bitv_to_str(fcx, pres);
|
||||
fcx.ccx.tcx.sess.span_err(s.span, ss);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_states_against_conditions(&fn_ctxt fcx, &_fn f, &ann a) -> () {
|
||||
fn check_states_against_conditions(&fn_ctxt fcx, &_fn f, &ann a) {
|
||||
auto enclosing = fcx.enclosing;
|
||||
auto nv = num_constraints(enclosing);
|
||||
auto nv = num_constraints(enclosing);
|
||||
auto post = @mutable empty_poststate(nv);
|
||||
|
||||
fn do_one_(fn_ctxt fcx, &@stmt s, @mutable poststate post) -> () {
|
||||
fn do_one_(fn_ctxt fcx, &@stmt s, @mutable poststate post) {
|
||||
check_states_stmt(fcx, *s);
|
||||
*post = stmt_poststate(fcx.ccx, *s);
|
||||
}
|
||||
|
||||
auto do_one = bind do_one_(fcx, _, post);
|
||||
|
||||
vec::map[@stmt, ()](do_one, f.body.node.stmts);
|
||||
fn do_inner_(fn_ctxt fcx, &@expr e, @mutable poststate post) -> () {
|
||||
fn do_inner_(fn_ctxt fcx, &@expr e, @mutable poststate post) {
|
||||
check_states_expr(fcx, e);
|
||||
*post = expr_poststate(fcx.ccx, e);
|
||||
}
|
||||
auto do_inner = bind do_inner_(fcx, _, post);
|
||||
option::map[@expr, ()](do_inner, f.body.node.expr);
|
||||
|
||||
auto cf = fcx.enclosing.cf;
|
||||
/* Finally, check that the return value is initialized */
|
||||
|
||||
let aux::constr_ ret_c = rec(id=fcx.id, c=aux::ninit(fcx.name));
|
||||
if (f.proto == ast::proto_fn
|
||||
&& ! promises(fcx, {*post}, ret_c)
|
||||
&& ! type_is_nil(fcx.ccx.tcx,
|
||||
ret_ty_of_fn(fcx.ccx.tcx, a))
|
||||
&& cf == return) {
|
||||
fcx.ccx.tcx.sess.span_note(f.body.span, "In function " + fcx.name +
|
||||
", not all control paths return a value");
|
||||
if (f.proto == ast::proto_fn && !promises(fcx, { *post }, ret_c) &&
|
||||
!type_is_nil(fcx.ccx.tcx, ret_ty_of_fn(fcx.ccx.tcx, a)) &&
|
||||
cf == return) {
|
||||
fcx.ccx.tcx.sess.span_note(f.body.span,
|
||||
"In function " + fcx.name +
|
||||
", not all control paths \
|
||||
return a value");
|
||||
fcx.ccx.tcx.sess.span_err(f.decl.output.span,
|
||||
"see declared return type of '" + ty_to_str(*f.decl.output) +
|
||||
"'");
|
||||
}
|
||||
else if (cf == noreturn) {
|
||||
"see declared return type of '" +
|
||||
ty_to_str(*f.decl.output) + "'");
|
||||
} else if (cf == noreturn) {
|
||||
|
||||
// check that this really always fails
|
||||
// the fcx.id bit means "returns" for a returning fn,
|
||||
// "diverges" for a non-returning fn
|
||||
if (! promises(fcx, {*post}, ret_c)) {
|
||||
if (!promises(fcx, { *post }, ret_c)) {
|
||||
fcx.ccx.tcx.sess.span_err(f.body.span,
|
||||
"In non-returning function " + fcx.name +
|
||||
", some control paths may return to the caller");
|
||||
"In non-returning function " + fcx.name
|
||||
+ ", some control paths may \
|
||||
return to the caller");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn check_fn_states(&fn_ctxt fcx, &_fn f, &ann a) -> () {
|
||||
fn check_fn_states(&fn_ctxt fcx, &_fn f, &ann a) {
|
||||
/* Compute the pre- and post-states for this function */
|
||||
|
||||
auto g = find_pre_post_state_fn;
|
||||
fixed_point_states(fcx, g, f);
|
||||
|
||||
/* Now compare each expr's pre-state to its precondition
|
||||
and post-state to its postcondition */
|
||||
|
||||
check_states_against_conditions(fcx, f, a);
|
||||
}
|
||||
|
||||
fn fn_states(&crate_ctxt ccx, &_fn f, &span sp, &ident i,
|
||||
&def_id id, &ann a) -> () {
|
||||
fn fn_states(&crate_ctxt ccx, &_fn f, &span sp, &ident i, &def_id id,
|
||||
&ann a) {
|
||||
/* Look up the var-to-bit-num map for this function */
|
||||
|
||||
assert (ccx.fm.contains_key(id));
|
||||
auto f_info = ccx.fm.get(id);
|
||||
|
||||
auto fcx = rec(enclosing=f_info, id=id, name=i, ccx=ccx);
|
||||
check_fn_states(fcx, f, a);
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn check_crate(ty::ctxt cx, @crate crate) -> () {
|
||||
fn check_crate(ty::ctxt cx, @crate crate) {
|
||||
let crate_ctxt ccx = new_crate_ctxt(cx);
|
||||
|
||||
/* Build the global map from function id to var-to-bit-num-map */
|
||||
|
||||
mk_f_to_fn_info(ccx, crate);
|
||||
|
||||
/* Add a blank ts_ann for every statement (and expression) */
|
||||
|
||||
annotate_crate(ccx, *crate);
|
||||
|
||||
/* Compute the pre and postcondition for every subexpression */
|
||||
auto do_pre_post = walk::default_visitor();
|
||||
do_pre_post = rec(visit_fn_pre = bind fn_pre_post(ccx,_,_,_,_,_)
|
||||
with do_pre_post);
|
||||
walk::walk_crate(do_pre_post, *crate);
|
||||
|
||||
auto do_pre_post = walk::default_visitor();
|
||||
do_pre_post =
|
||||
rec(visit_fn_pre=bind fn_pre_post(ccx, _, _, _, _, _)
|
||||
with do_pre_post);
|
||||
walk::walk_crate(do_pre_post, *crate);
|
||||
/* Check the pre- and postcondition against the pre- and poststate
|
||||
for every expression */
|
||||
|
||||
auto do_states = walk::default_visitor();
|
||||
do_states = rec(visit_fn_pre = bind fn_states(ccx,_,_,_,_,_)
|
||||
with do_states);
|
||||
do_states =
|
||||
rec(visit_fn_pre=bind fn_states(ccx, _, _, _, _, _) with do_states);
|
||||
walk::walk_crate(do_states, *crate);
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
|
||||
import std::vec;
|
||||
import std::vec::plus_option;
|
||||
|
||||
import front::ast;
|
||||
import front::ast::*;
|
||||
import option::*;
|
||||
|
||||
import middle::walk::walk_crate;
|
||||
import middle::walk::walk_fn;
|
||||
import middle::walk::ast_visitor;
|
||||
|
||||
import aux::cinit;
|
||||
import aux::ninit;
|
||||
import aux::npred;
|
||||
|
@ -21,7 +19,6 @@ import aux::constr_map;
|
|||
import aux::expr_to_constr;
|
||||
import aux::constraints_expr;
|
||||
import aux::ann_to_def_strict;
|
||||
|
||||
import util::common::new_def_hash;
|
||||
import util::common::uistr;
|
||||
import util::common::span;
|
||||
|
@ -29,28 +26,31 @@ import util::common::respan;
|
|||
|
||||
type ctxt = rec(@mutable vec[aux::constr] cs, ty::ctxt tcx);
|
||||
|
||||
fn collect_local(&ctxt cx, &@local loc) -> () {
|
||||
log("collect_local: pushing " + loc.node.ident);
|
||||
vec::push(*cx.cs, respan(loc.span,
|
||||
rec(id=loc.node.id,
|
||||
c=ninit(loc.node.ident))));
|
||||
fn collect_local(&ctxt cx, &@local loc) {
|
||||
log "collect_local: pushing " + loc.node.ident;
|
||||
vec::push(*cx.cs,
|
||||
respan(loc.span, rec(id=loc.node.id, c=ninit(loc.node.ident))));
|
||||
}
|
||||
|
||||
fn collect_pred(&ctxt cx, &@expr e) -> () {
|
||||
fn collect_pred(&ctxt cx, &@expr e) {
|
||||
alt (e.node) {
|
||||
case (expr_check(?e, _)) {
|
||||
vec::push(*cx.cs, expr_to_constr(cx.tcx, e));
|
||||
}
|
||||
// If it's a call, generate appropriate instances of the
|
||||
// call's constraints.
|
||||
case (expr_call(?operator, ?operands, ?a)) {
|
||||
case (
|
||||
// If it's a call, generate appropriate instances of the
|
||||
// call's constraints.
|
||||
expr_call(?operator, ?operands, ?a)) {
|
||||
for (@ast::constr c in constraints_expr(cx.tcx, operator)) {
|
||||
auto d_id = ann_to_def_strict(cx.tcx, c.node.ann);
|
||||
alt (d_id) {
|
||||
case (def_fn(?an_id)) {
|
||||
let aux::constr ct = respan(c.span,
|
||||
rec(id=an_id, c=aux::substitute_constr_args(cx.tcx,
|
||||
operands, c)));
|
||||
let aux::constr ct =
|
||||
respan(c.span,
|
||||
rec(id=an_id,
|
||||
c=aux::substitute_constr_args(cx.tcx,
|
||||
operands,
|
||||
c)));
|
||||
vec::push(*cx.cs, ct);
|
||||
}
|
||||
case (_) {
|
||||
|
@ -60,64 +60,64 @@ fn collect_pred(&ctxt cx, &@expr e) -> () {
|
|||
}
|
||||
}
|
||||
// FIXME: constraints on result type
|
||||
|
||||
}
|
||||
case (_) { }
|
||||
}
|
||||
}
|
||||
|
||||
fn find_locals(&ty::ctxt tcx, &_fn f, &span sp, &ident i, &def_id d, &ann a)
|
||||
-> ctxt {
|
||||
-> ctxt {
|
||||
let ctxt cx = rec(cs=@mutable vec::alloc(0u), tcx=tcx);
|
||||
auto visitor = walk::default_visitor();
|
||||
visitor = rec(visit_local_pre=bind collect_local(cx,_),
|
||||
visit_expr_pre=bind collect_pred(cx,_)
|
||||
with visitor);
|
||||
visitor =
|
||||
rec(visit_local_pre=bind collect_local(cx, _),
|
||||
visit_expr_pre=bind collect_pred(cx, _) with visitor);
|
||||
walk_fn(visitor, f, sp, i, d, a);
|
||||
ret cx;
|
||||
}
|
||||
|
||||
fn add_constraint(&ty::ctxt tcx, aux::constr c, uint next, constr_map tbl)
|
||||
-> uint {
|
||||
log(aux::constraint_to_str(tcx, c) + " |-> "
|
||||
+ util::common::uistr(next));
|
||||
fn add_constraint(&ty::ctxt tcx, aux::constr c, uint next, constr_map tbl) ->
|
||||
uint {
|
||||
log aux::constraint_to_str(tcx, c) + " |-> " + util::common::uistr(next);
|
||||
alt (c.node.c) {
|
||||
case (ninit(?i)) {
|
||||
tbl.insert(c.node.id, cinit(next, c.span, i));
|
||||
}
|
||||
case (ninit(?i)) { tbl.insert(c.node.id, cinit(next, c.span, i)); }
|
||||
case (npred(?p, ?args)) {
|
||||
alt (tbl.find(c.node.id)) {
|
||||
case (some(?ct)) {
|
||||
alt (ct) {
|
||||
case (cinit(_,_,_)) {
|
||||
tcx.sess.bug("add_constraint: same def_id used"
|
||||
+ " as a variable and a pred");
|
||||
case (cinit(_, _, _)) {
|
||||
tcx.sess.bug("add_constraint: same def_id used" +
|
||||
" as a variable and a pred");
|
||||
}
|
||||
case (cpred(_, ?pds)) {
|
||||
vec::push(*pds, respan(c.span,
|
||||
rec(args=args, bit_num=next)));
|
||||
vec::push(*pds,
|
||||
respan(c.span,
|
||||
rec(args=args, bit_num=next)));
|
||||
}
|
||||
}
|
||||
}
|
||||
case (none) {
|
||||
tbl.insert(c.node.id, cpred(p,
|
||||
@mutable [respan(c.span, rec(args=args,
|
||||
bit_num=next))]));
|
||||
tbl.insert(c.node.id,
|
||||
cpred(p,
|
||||
@mutable [respan(c.span,
|
||||
rec(args=args,
|
||||
bit_num=next))]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ret (next + 1u);
|
||||
ret next + 1u;
|
||||
}
|
||||
|
||||
|
||||
/* builds a table mapping each local var defined in f
|
||||
to a bit number in the precondition/postcondition vectors */
|
||||
fn mk_fn_info(&crate_ctxt ccx, &_fn f, &span f_sp,
|
||||
&ident f_name, &def_id f_id, &ann a)
|
||||
-> () {
|
||||
fn mk_fn_info(&crate_ctxt ccx, &_fn f, &span f_sp, &ident f_name,
|
||||
&def_id f_id, &ann a) {
|
||||
auto res_map = @new_def_hash[constraint]();
|
||||
let uint next = 0u;
|
||||
let vec[arg] f_args = f.decl.inputs;
|
||||
|
||||
/* ignore args, which we know are initialized;
|
||||
just collect locally declared vars */
|
||||
|
||||
|
@ -125,35 +125,33 @@ fn mk_fn_info(&crate_ctxt ccx, &_fn f, &span f_sp,
|
|||
/* now we have to add bit nums for both the constraints
|
||||
and the variables... */
|
||||
|
||||
for (aux::constr c in {*cx.cs}) {
|
||||
for (aux::constr c in { *cx.cs }) {
|
||||
next = add_constraint(cx.tcx, c, next, res_map);
|
||||
}
|
||||
/* add a pseudo-entry for the function's return value
|
||||
we can safely use the function's name itself for this purpose */
|
||||
|
||||
add_constraint(cx.tcx, respan(f_sp, rec(id=f_id, c=ninit(f_name))), next,
|
||||
res_map);
|
||||
|
||||
auto res = rec(constrs=res_map,
|
||||
num_constraints=vec::len(*cx.cs) + 1u,
|
||||
cf=f.decl.cf);
|
||||
|
||||
auto res =
|
||||
rec(constrs=res_map,
|
||||
num_constraints=vec::len(*cx.cs) + 1u,
|
||||
cf=f.decl.cf);
|
||||
ccx.fm.insert(f_id, res);
|
||||
|
||||
log(f_name + " has " + uistr(num_constraints(res)) + " constraints");
|
||||
|
||||
log f_name + " has " + uistr(num_constraints(res)) + " constraints";
|
||||
}
|
||||
|
||||
|
||||
/* initializes the global fn_info_map (mapping each function ID, including
|
||||
nested locally defined functions, onto a mapping from local variable name
|
||||
to bit number) */
|
||||
fn mk_f_to_fn_info(&crate_ctxt ccx, @crate c) -> () {
|
||||
let ast_visitor vars_visitor = walk::default_visitor();
|
||||
vars_visitor = rec(visit_fn_pre=bind mk_fn_info(ccx,_,_,_,_,_)
|
||||
with vars_visitor);
|
||||
|
||||
walk_crate(vars_visitor, *c);
|
||||
fn mk_f_to_fn_info(&crate_ctxt ccx, @crate c) {
|
||||
let ast_visitor vars_visitor = walk::default_visitor();
|
||||
vars_visitor =
|
||||
rec(visit_fn_pre=bind mk_fn_info(ccx, _, _, _, _, _)
|
||||
with vars_visitor);
|
||||
walk_crate(vars_visitor, *c);
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
@ -164,4 +162,3 @@ fn mk_f_to_fn_info(&crate_ctxt ccx, @crate c) -> () {
|
|||
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
|
||||
// End:
|
||||
//
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
import std::vec;
|
||||
import std::vec::plus_option;
|
||||
import std::option;
|
||||
|
@ -44,24 +45,21 @@ import aux::ann_to_ts_ann;
|
|||
import aux::set_postcond_false;
|
||||
import aux::controlflow_expr;
|
||||
import aux::expr_to_constr;
|
||||
|
||||
//import aux::constr_to_constr_occ;
|
||||
import aux::constraints_expr;
|
||||
import aux::substitute_constr_args;
|
||||
import aux::ninit;
|
||||
import aux::npred;
|
||||
import aux::path_to_ident;
|
||||
|
||||
import bitvectors::seq_preconds;
|
||||
import bitvectors::union_postconds;
|
||||
import bitvectors::intersect_postconds;
|
||||
import bitvectors::declare_var;
|
||||
import bitvectors::bit_num;
|
||||
import bitvectors::gen;
|
||||
|
||||
import front::ast::*;
|
||||
|
||||
import middle::ty::expr_ann;
|
||||
|
||||
import util::common::new_def_hash;
|
||||
import util::common::decl_lhs;
|
||||
import util::common::uistr;
|
||||
|
@ -77,169 +75,165 @@ import util::common::log_block;
|
|||
import util::common::span;
|
||||
|
||||
fn find_pre_post_mod(&_mod m) -> _mod {
|
||||
log("implement find_pre_post_mod!");
|
||||
log "implement find_pre_post_mod!";
|
||||
fail;
|
||||
}
|
||||
|
||||
fn find_pre_post_native_mod(&native_mod m) -> native_mod {
|
||||
log("implement find_pre_post_native_mod");
|
||||
log "implement find_pre_post_native_mod";
|
||||
fail;
|
||||
}
|
||||
|
||||
|
||||
fn find_pre_post_obj(&crate_ctxt ccx, _obj o) -> () {
|
||||
fn do_a_method(crate_ctxt ccx, &@method m) -> () {
|
||||
fn find_pre_post_obj(&crate_ctxt ccx, _obj o) {
|
||||
fn do_a_method(crate_ctxt ccx, &@method m) {
|
||||
assert (ccx.fm.contains_key(m.node.id));
|
||||
let fn_ctxt fcx = rec(enclosing=ccx.fm.get(m.node.id),
|
||||
id=m.node.id, name=m.node.ident, ccx=ccx);
|
||||
let fn_ctxt fcx =
|
||||
rec(enclosing=ccx.fm.get(m.node.id),
|
||||
id=m.node.id,
|
||||
name=m.node.ident,
|
||||
ccx=ccx);
|
||||
find_pre_post_fn(fcx, m.node.meth);
|
||||
}
|
||||
auto f = bind do_a_method(ccx,_);
|
||||
auto f = bind do_a_method(ccx, _);
|
||||
vec::map[@method, ()](f, o.methods);
|
||||
option::map[@method, ()](f, o.dtor);
|
||||
}
|
||||
|
||||
fn find_pre_post_item(&crate_ctxt ccx, &item i) -> () {
|
||||
fn find_pre_post_item(&crate_ctxt ccx, &item i) {
|
||||
alt (i.node) {
|
||||
case (item_const(?id, ?t, ?e, _, ?di, ?a)) {
|
||||
// make a fake fcx
|
||||
auto fake_fcx = rec(enclosing=
|
||||
rec(constrs=@new_def_hash[constraint](),
|
||||
num_constraints=0u,
|
||||
cf=return),
|
||||
id=tup(0,0),
|
||||
name="",
|
||||
ccx=ccx);
|
||||
|
||||
auto fake_fcx =
|
||||
rec(enclosing=rec(constrs=@new_def_hash[constraint](),
|
||||
num_constraints=0u,
|
||||
cf=return),
|
||||
id=tup(0, 0),
|
||||
name="",
|
||||
ccx=ccx);
|
||||
find_pre_post_expr(fake_fcx, e);
|
||||
}
|
||||
case (item_fn(?id, ?f, ?ps, _, ?di, ?a)) {
|
||||
assert (ccx.fm.contains_key(di));
|
||||
auto fcx = rec(enclosing=ccx.fm.get(di),
|
||||
id=di, name=id, ccx=ccx);
|
||||
auto fcx = rec(enclosing=ccx.fm.get(di), id=di, name=id, ccx=ccx);
|
||||
find_pre_post_fn(fcx, f);
|
||||
}
|
||||
case (item_mod(?id, ?m, _, ?di)) {
|
||||
find_pre_post_mod(m);
|
||||
}
|
||||
case (item_mod(?id, ?m, _, ?di)) { find_pre_post_mod(m); }
|
||||
case (item_native_mod(?id, ?nm, _, ?di)) {
|
||||
find_pre_post_native_mod(nm);
|
||||
}
|
||||
case (item_ty(_,_,_,_,_,_)) {
|
||||
ret;
|
||||
}
|
||||
case (item_tag(_,_,_,_,_,_)) {
|
||||
ret;
|
||||
}
|
||||
case (item_ty(_, _, _, _, _, _)) { ret; }
|
||||
case (item_tag(_, _, _, _, _, _)) { ret; }
|
||||
case (item_obj(?id, ?o, ?ps, _, ?di, ?a)) {
|
||||
find_pre_post_obj(ccx, o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Finds the pre and postcondition for each expr in <args>;
|
||||
sets the precondition in a to be the result of combining
|
||||
the preconditions for <args>, and the postcondition in a to
|
||||
be the union of all postconditions for <args> */
|
||||
fn find_pre_post_exprs(&fn_ctxt fcx, &vec[@expr] args, ann a) {
|
||||
if (vec::len[@expr](args) > 0u) {
|
||||
log ("find_pre_post_exprs: oper =");
|
||||
log_expr(*(args.(0)));
|
||||
log "find_pre_post_exprs: oper =";
|
||||
log_expr(*args.(0));
|
||||
}
|
||||
|
||||
auto enclosing = fcx.enclosing;
|
||||
auto fm = fcx.ccx.fm;
|
||||
auto nv = num_constraints(enclosing);
|
||||
|
||||
fn do_one(fn_ctxt fcx, &@expr e) -> () {
|
||||
find_pre_post_expr(fcx, e);
|
||||
}
|
||||
auto fm = fcx.ccx.fm;
|
||||
auto nv = num_constraints(enclosing);
|
||||
fn do_one(fn_ctxt fcx, &@expr e) { find_pre_post_expr(fcx, e); }
|
||||
auto f = bind do_one(fcx, _);
|
||||
|
||||
vec::map[@expr, ()](f, args);
|
||||
|
||||
fn get_pp(crate_ctxt ccx, &@expr e) -> pre_and_post {
|
||||
ret expr_pp(ccx, e);
|
||||
}
|
||||
|
||||
auto g = bind get_pp(fcx.ccx, _);
|
||||
auto pps = vec::map[@expr, pre_and_post](g, args);
|
||||
auto h = get_post;
|
||||
|
||||
set_pre_and_post(fcx.ccx, a, seq_preconds(fcx, pps),
|
||||
union_postconds
|
||||
(nv, (vec::map[pre_and_post, postcond](h, pps))));
|
||||
union_postconds(nv,
|
||||
vec::map[pre_and_post,
|
||||
postcond](h, pps)));
|
||||
}
|
||||
|
||||
fn find_pre_post_loop(&fn_ctxt fcx, &@local l, &@expr index,
|
||||
&block body, &ann a) -> () {
|
||||
fn find_pre_post_loop(&fn_ctxt fcx, &@local l, &@expr index, &block body,
|
||||
&ann a) {
|
||||
find_pre_post_expr(fcx, index);
|
||||
find_pre_post_block(fcx, body);
|
||||
auto loop_precond = declare_var(fcx, rec(id=l.node.id,
|
||||
c=ninit(l.node.ident)),
|
||||
seq_preconds(fcx, [expr_pp(fcx.ccx, index), block_pp(fcx.ccx, body)]));
|
||||
auto loop_postcond = intersect_postconds
|
||||
([expr_postcond(fcx.ccx, index), block_postcond(fcx.ccx, body)]);
|
||||
auto loop_precond =
|
||||
declare_var(fcx, rec(id=l.node.id, c=ninit(l.node.ident)),
|
||||
seq_preconds(fcx,
|
||||
[expr_pp(fcx.ccx, index),
|
||||
block_pp(fcx.ccx, body)]));
|
||||
auto loop_postcond =
|
||||
intersect_postconds([expr_postcond(fcx.ccx, index),
|
||||
block_postcond(fcx.ccx, body)]);
|
||||
set_pre_and_post(fcx.ccx, a, loop_precond, loop_postcond);
|
||||
}
|
||||
|
||||
fn gen_if_local(&fn_ctxt fcx, @expr lhs, @expr rhs,
|
||||
&ann larger_ann, &ann new_var, &path pth) -> () {
|
||||
alt (ann_to_def(fcx.ccx, new_var)) {
|
||||
case (some(?d)) {
|
||||
alt (d) {
|
||||
case (def_local(?d_id)) {
|
||||
find_pre_post_expr(fcx, rhs);
|
||||
auto p = expr_pp(fcx.ccx, rhs);
|
||||
set_pre_and_post(fcx.ccx, larger_ann,
|
||||
p.precondition, p.postcondition);
|
||||
gen(fcx, larger_ann, rec(id=d_id,
|
||||
c=ninit(path_to_ident(fcx.ccx.tcx, pth))));
|
||||
}
|
||||
case (_) { find_pre_post_exprs(fcx, [lhs, rhs], larger_ann); }
|
||||
}
|
||||
}
|
||||
case (_) { find_pre_post_exprs(fcx, [lhs, rhs], larger_ann); }
|
||||
}
|
||||
fn gen_if_local(&fn_ctxt fcx, @expr lhs, @expr rhs, &ann larger_ann,
|
||||
&ann new_var, &path pth) {
|
||||
alt (ann_to_def(fcx.ccx, new_var)) {
|
||||
case (some(?d)) {
|
||||
alt (d) {
|
||||
case (def_local(?d_id)) {
|
||||
find_pre_post_expr(fcx, rhs);
|
||||
auto p = expr_pp(fcx.ccx, rhs);
|
||||
set_pre_and_post(fcx.ccx, larger_ann, p.precondition,
|
||||
p.postcondition);
|
||||
gen(fcx, larger_ann,
|
||||
rec(id=d_id,
|
||||
c=ninit(path_to_ident(fcx.ccx.tcx, pth))));
|
||||
}
|
||||
case (_) { find_pre_post_exprs(fcx, [lhs, rhs], larger_ann); }
|
||||
}
|
||||
}
|
||||
case (_) { find_pre_post_exprs(fcx, [lhs, rhs], larger_ann); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Fills in annotations as a side effect. Does not rebuild the expr */
|
||||
fn find_pre_post_expr(&fn_ctxt fcx, @expr e) -> () {
|
||||
auto enclosing = fcx.enclosing;
|
||||
fn find_pre_post_expr(&fn_ctxt fcx, @expr e) {
|
||||
auto enclosing = fcx.enclosing;
|
||||
auto num_local_vars = num_constraints(enclosing);
|
||||
|
||||
fn do_rand_(fn_ctxt fcx, &@expr e) -> () {
|
||||
find_pre_post_expr(fcx, e);
|
||||
}
|
||||
|
||||
log("find_pre_post_expr (num_constraints =" +
|
||||
uistr(num_local_vars) + "):");
|
||||
fn do_rand_(fn_ctxt fcx, &@expr e) { find_pre_post_expr(fcx, e); }
|
||||
log "find_pre_post_expr (num_constraints =" + uistr(num_local_vars) +
|
||||
"):";
|
||||
log_expr(*e);
|
||||
|
||||
alt (e.node) {
|
||||
case (expr_call(?operator, ?operands, ?a)) {
|
||||
auto args = vec::clone[@expr](operands);
|
||||
vec::push[@expr](args, operator);
|
||||
find_pre_post_exprs(fcx, args, a);
|
||||
|
||||
/* should test higher-order constrained functions */
|
||||
|
||||
/* FIXME */
|
||||
|
||||
/* see if the call has any constraints on its in type */
|
||||
log("a function: " );
|
||||
|
||||
log "a function: ";
|
||||
log_expr(*operator);
|
||||
auto pp = expr_pp(fcx.ccx, e);
|
||||
for (@constr c in constraints_expr(fcx.ccx.tcx, operator)) {
|
||||
auto id = ann_to_def(fcx.ccx, c.node.ann);
|
||||
alt (id) {
|
||||
case (some(def_fn(?d_id))) {
|
||||
auto i = bit_num(fcx, rec(id=d_id,
|
||||
c=substitute_constr_args(fcx.ccx.tcx,
|
||||
operands, c)));
|
||||
auto i =
|
||||
bit_num(fcx,
|
||||
rec(id=d_id,
|
||||
c=substitute_constr_args(fcx.ccx.tcx,
|
||||
operands,
|
||||
c)));
|
||||
require(i, pp);
|
||||
}
|
||||
case (_) {
|
||||
fcx.ccx.tcx.sess.span_err(c.span, "Unbound pred "
|
||||
+ " or pred that's not bound to a function");
|
||||
fcx.ccx.tcx.sess.span_err(c.span,
|
||||
"Unbound pred " +
|
||||
" or pred that's not \
|
||||
bound to a function");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -248,9 +242,7 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) -> () {
|
|||
|
||||
/* if this is a failing call, its postcondition sets everything */
|
||||
alt (controlflow_expr(fcx.ccx, operator)) {
|
||||
case (noreturn) {
|
||||
set_postcond_false(fcx.ccx, a);
|
||||
}
|
||||
case (noreturn) { set_postcond_false(fcx.ccx, a); }
|
||||
case (_) { }
|
||||
}
|
||||
}
|
||||
|
@ -268,21 +260,20 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) -> () {
|
|||
case (expr_path(?p, ?a)) {
|
||||
auto res = expr_pp(fcx.ccx, e);
|
||||
clear_pp(res);
|
||||
|
||||
auto df = ann_to_def_strict(fcx.ccx.tcx, a);
|
||||
alt (df) {
|
||||
case (def_local(?d_id)) {
|
||||
auto i = bit_num(fcx, rec(id=d_id,
|
||||
c=ninit(path_to_ident(fcx.ccx.tcx, p))));
|
||||
auto i =
|
||||
bit_num(fcx,
|
||||
rec(id=d_id,
|
||||
c=ninit(path_to_ident(fcx.ccx.tcx, p))));
|
||||
require_and_preserve(i, res);
|
||||
}
|
||||
case (_) { /* nothing to check */ }
|
||||
case (_) {/* nothing to check */ }
|
||||
}
|
||||
}
|
||||
case (expr_self_method(?v, ?a)) {
|
||||
clear_pp(expr_pp(fcx.ccx, e));
|
||||
}
|
||||
case(expr_log(_, ?arg, ?a)) {
|
||||
case (expr_self_method(?v, ?a)) { clear_pp(expr_pp(fcx.ccx, e)); }
|
||||
case (expr_log(_, ?arg, ?a)) {
|
||||
find_pre_post_expr(fcx, arg);
|
||||
copy_pre_post(fcx.ccx, a, arg);
|
||||
}
|
||||
|
@ -290,19 +281,18 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) -> () {
|
|||
find_pre_post_expr(fcx, arg);
|
||||
copy_pre_post(fcx.ccx, a, arg);
|
||||
}
|
||||
case(expr_put(?opt, ?a)) {
|
||||
case (expr_put(?opt, ?a)) {
|
||||
alt (opt) {
|
||||
case (some(?arg)) {
|
||||
find_pre_post_expr(fcx, arg);
|
||||
copy_pre_post(fcx.ccx, a, arg);
|
||||
}
|
||||
case (none) {
|
||||
clear_pp(expr_pp(fcx.ccx, e));
|
||||
}
|
||||
case (none) { clear_pp(expr_pp(fcx.ccx, e)); }
|
||||
}
|
||||
}
|
||||
// FIXME this was just put in here as a placeholder
|
||||
case (expr_fn(?f, ?a)) {
|
||||
case (
|
||||
// FIXME this was just put in here as a placeholder
|
||||
expr_fn(?f, ?a)) {
|
||||
clear_pp(expr_pp(fcx.ccx, e));
|
||||
}
|
||||
case (expr_block(?b, ?a)) {
|
||||
|
@ -310,20 +300,19 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) -> () {
|
|||
auto p = block_pp(fcx.ccx, b);
|
||||
set_pre_and_post(fcx.ccx, a, p.precondition, p.postcondition);
|
||||
}
|
||||
case (expr_rec(?fields,?maybe_base,?a)) {
|
||||
case (expr_rec(?fields, ?maybe_base, ?a)) {
|
||||
auto es = field_exprs(fields);
|
||||
vec::plus_option[@expr](es, maybe_base);
|
||||
find_pre_post_exprs(fcx, es, a);
|
||||
}
|
||||
case (expr_move(?lhs, ?rhs, ?a)) {
|
||||
|
||||
// FIXME: this needs to deinitialize the rhs
|
||||
alt (lhs.node) {
|
||||
case (expr_path(?p, ?a_lhs)) {
|
||||
gen_if_local(fcx, lhs, rhs, a, a_lhs, p);
|
||||
}
|
||||
case (_) {
|
||||
find_pre_post_exprs(fcx, [lhs, rhs], a);
|
||||
}
|
||||
case (_) { find_pre_post_exprs(fcx, [lhs, rhs], a); }
|
||||
}
|
||||
}
|
||||
case (expr_assign(?lhs, ?rhs, ?a)) {
|
||||
|
@ -331,9 +320,7 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) -> () {
|
|||
case (expr_path(?p, ?a_lhs)) {
|
||||
gen_if_local(fcx, lhs, rhs, a, a_lhs, p);
|
||||
}
|
||||
case (_) {
|
||||
find_pre_post_exprs(fcx, [lhs, rhs], a);
|
||||
}
|
||||
case (_) { find_pre_post_exprs(fcx, [lhs, rhs], a); }
|
||||
}
|
||||
}
|
||||
case (expr_recv(?lhs, ?rhs, ?a)) {
|
||||
|
@ -344,6 +331,7 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) -> () {
|
|||
case (_) {
|
||||
// doesn't check that lhs is an lval, but
|
||||
// that's probably ok
|
||||
|
||||
find_pre_post_exprs(fcx, [lhs, rhs], a);
|
||||
}
|
||||
}
|
||||
|
@ -351,11 +339,10 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) -> () {
|
|||
case (expr_assign_op(_, ?lhs, ?rhs, ?a)) {
|
||||
/* Different from expr_assign in that the lhs *must*
|
||||
already be initialized */
|
||||
|
||||
find_pre_post_exprs(fcx, [lhs, rhs], a);
|
||||
}
|
||||
case (expr_lit(_,?a)) {
|
||||
clear_pp(expr_pp(fcx.ccx, e));
|
||||
}
|
||||
case (expr_lit(_, ?a)) { clear_pp(expr_pp(fcx.ccx, e)); }
|
||||
case (expr_ret(?maybe_val, ?a)) {
|
||||
alt (maybe_val) {
|
||||
case (none) {
|
||||
|
@ -372,9 +359,8 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) -> () {
|
|||
}
|
||||
case (expr_be(?e, ?a)) {
|
||||
find_pre_post_expr(fcx, e);
|
||||
set_pre_and_post(fcx.ccx, a,
|
||||
expr_prestate(fcx.ccx, e),
|
||||
false_postcond(num_local_vars));
|
||||
set_pre_and_post(fcx.ccx, a, expr_prestate(fcx.ccx, e),
|
||||
false_postcond(num_local_vars));
|
||||
}
|
||||
case (expr_if(?antec, ?conseq, ?maybe_alt, ?a)) {
|
||||
find_pre_post_expr(fcx, antec);
|
||||
|
@ -382,9 +368,10 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) -> () {
|
|||
alt (maybe_alt) {
|
||||
case (none) {
|
||||
log "333";
|
||||
auto precond_res = seq_preconds(fcx,
|
||||
[expr_pp(fcx.ccx, antec),
|
||||
block_pp(fcx.ccx, conseq)]);
|
||||
auto precond_res =
|
||||
seq_preconds(fcx,
|
||||
[expr_pp(fcx.ccx, antec),
|
||||
block_pp(fcx.ccx, conseq)]);
|
||||
set_pre_and_post(fcx.ccx, a, precond_res,
|
||||
expr_poststate(fcx.ccx, antec));
|
||||
}
|
||||
|
@ -392,38 +379,41 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) -> () {
|
|||
find_pre_post_expr(fcx, altern);
|
||||
log "444";
|
||||
auto precond_true_case =
|
||||
seq_preconds(fcx, [expr_pp(fcx.ccx, antec),
|
||||
block_pp(fcx.ccx, conseq)]);
|
||||
auto postcond_true_case = union_postconds
|
||||
(num_local_vars,
|
||||
[expr_postcond(fcx.ccx, antec),
|
||||
block_postcond(fcx.ccx, conseq)]);
|
||||
seq_preconds(fcx,
|
||||
[expr_pp(fcx.ccx, antec),
|
||||
block_pp(fcx.ccx, conseq)]);
|
||||
auto postcond_true_case =
|
||||
union_postconds(num_local_vars,
|
||||
[expr_postcond(fcx.ccx, antec),
|
||||
block_postcond(fcx.ccx, conseq)]);
|
||||
log "555";
|
||||
auto precond_false_case = seq_preconds
|
||||
(fcx, [expr_pp(fcx.ccx, antec),
|
||||
expr_pp(fcx.ccx, altern)]);
|
||||
auto postcond_false_case = union_postconds
|
||||
(num_local_vars,
|
||||
[expr_postcond(fcx.ccx, antec),
|
||||
expr_postcond(fcx.ccx, altern)]);
|
||||
auto precond_res = union_postconds
|
||||
(num_local_vars,
|
||||
[precond_true_case, precond_false_case]);
|
||||
auto postcond_res = intersect_postconds
|
||||
([postcond_true_case, postcond_false_case]);
|
||||
auto precond_false_case =
|
||||
seq_preconds(fcx,
|
||||
[expr_pp(fcx.ccx, antec),
|
||||
expr_pp(fcx.ccx, altern)]);
|
||||
auto postcond_false_case =
|
||||
union_postconds(num_local_vars,
|
||||
[expr_postcond(fcx.ccx, antec),
|
||||
expr_postcond(fcx.ccx, altern)]);
|
||||
auto precond_res =
|
||||
union_postconds(num_local_vars,
|
||||
[precond_true_case,
|
||||
precond_false_case]);
|
||||
auto postcond_res =
|
||||
intersect_postconds([postcond_true_case,
|
||||
postcond_false_case]);
|
||||
set_pre_and_post(fcx.ccx, a, precond_res, postcond_res);
|
||||
}
|
||||
}
|
||||
}
|
||||
case (expr_binary(?bop,?l,?r,?a)) {
|
||||
case (expr_binary(?bop, ?l, ?r, ?a)) {
|
||||
/* *unless* bop is lazy (e.g. and, or)?
|
||||
FIXME */
|
||||
|
||||
find_pre_post_exprs(fcx, [l, r], a);
|
||||
}
|
||||
case (expr_send(?l, ?r, ?a)) {
|
||||
find_pre_post_exprs(fcx, [l, r], a);
|
||||
}
|
||||
case (expr_unary(_,?operand,?a)) {
|
||||
case (expr_send(?l, ?r, ?a)) { find_pre_post_exprs(fcx, [l, r], a); }
|
||||
case (expr_unary(_, ?operand, ?a)) {
|
||||
find_pre_post_expr(fcx, operand);
|
||||
copy_pre_post(fcx.ccx, a, operand);
|
||||
}
|
||||
|
@ -437,26 +427,28 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) -> () {
|
|||
log "666";
|
||||
set_pre_and_post(fcx.ccx, a,
|
||||
seq_preconds(fcx,
|
||||
[expr_pp(fcx.ccx, test),
|
||||
block_pp(fcx.ccx, body)]),
|
||||
intersect_postconds([expr_postcond(fcx.ccx, test),
|
||||
block_postcond(fcx.ccx, body)]));
|
||||
[expr_pp(fcx.ccx, test),
|
||||
block_pp(fcx.ccx, body)]),
|
||||
intersect_postconds([expr_postcond(fcx.ccx,
|
||||
test),
|
||||
block_postcond(fcx.ccx,
|
||||
body)]));
|
||||
}
|
||||
case (expr_do_while(?body, ?test, ?a)) {
|
||||
find_pre_post_block(fcx, body);
|
||||
find_pre_post_expr(fcx, test);
|
||||
|
||||
auto loop_postcond = union_postconds(num_local_vars,
|
||||
[block_postcond(fcx.ccx, body),
|
||||
expr_postcond(fcx.ccx, test)]);
|
||||
auto loop_postcond =
|
||||
union_postconds(num_local_vars,
|
||||
[block_postcond(fcx.ccx, body),
|
||||
expr_postcond(fcx.ccx, test)]);
|
||||
/* conservative approximination: if the body
|
||||
could break or cont, the test may never be executed */
|
||||
|
||||
if (has_nonlocal_exits(body)) {
|
||||
loop_postcond = empty_poststate(num_local_vars);
|
||||
}
|
||||
|
||||
|
||||
set_pre_and_post(fcx.ccx, a, seq_preconds(fcx,
|
||||
set_pre_and_post(fcx.ccx, a,
|
||||
seq_preconds(fcx,
|
||||
[block_pp(fcx.ccx, body),
|
||||
expr_pp(fcx.ccx, test)]),
|
||||
loop_postcond);
|
||||
|
@ -486,13 +478,12 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) -> () {
|
|||
ret pp;
|
||||
}
|
||||
auto antec_pp = pp_clone(expr_pp(fcx.ccx, ex));
|
||||
auto e_pp = @rec(precondition=empty_prestate(num_local_vars),
|
||||
postcondition=false_postcond(num_local_vars));
|
||||
auto e_pp =
|
||||
@rec(precondition=empty_prestate(num_local_vars),
|
||||
postcondition=false_postcond(num_local_vars));
|
||||
auto g = bind combine_pp(antec_pp, fcx, _, _);
|
||||
|
||||
auto alts_overall_pp = vec::foldl[pre_and_post, pre_and_post]
|
||||
(g, e_pp, alt_pps);
|
||||
|
||||
auto alts_overall_pp =
|
||||
vec::foldl[pre_and_post, pre_and_post](g, e_pp, alt_pps);
|
||||
set_pre_and_post(fcx.ccx, a, alts_overall_pp.precondition,
|
||||
alts_overall_pp.postcondition);
|
||||
}
|
||||
|
@ -504,8 +495,8 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) -> () {
|
|||
set_pre_and_post(fcx.ccx, a,
|
||||
/* if execution continues after fail,
|
||||
then everything is true! */
|
||||
empty_prestate(num_local_vars),
|
||||
false_postcond(num_local_vars));
|
||||
empty_prestate(num_local_vars),
|
||||
false_postcond(num_local_vars));
|
||||
}
|
||||
case (expr_assert(?p, ?a)) {
|
||||
find_pre_post_expr(fcx, p);
|
||||
|
@ -514,26 +505,23 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) -> () {
|
|||
case (expr_check(?p, ?a)) {
|
||||
/* FIXME: Can we bypass this by having a
|
||||
node-id-to-constr_occ table? */
|
||||
|
||||
find_pre_post_expr(fcx, p);
|
||||
copy_pre_post(fcx.ccx, a, p);
|
||||
/* predicate p holds after this expression executes */
|
||||
|
||||
let aux::constr c = expr_to_constr(fcx.ccx.tcx, p);
|
||||
gen(fcx, a, c.node);
|
||||
}
|
||||
case(expr_bind(?operator, ?maybe_args, ?a)) {
|
||||
case (expr_bind(?operator, ?maybe_args, ?a)) {
|
||||
auto args = vec::cat_options[@expr](maybe_args);
|
||||
vec::push[@expr](args, operator); /* ??? order of eval? */
|
||||
|
||||
find_pre_post_exprs(fcx, args, a);
|
||||
}
|
||||
case (expr_break(?a)) {
|
||||
clear_pp(expr_pp(fcx.ccx, e));
|
||||
}
|
||||
case (expr_cont(?a)) {
|
||||
clear_pp(expr_pp(fcx.ccx, e));
|
||||
}
|
||||
case (expr_port(?a)) {
|
||||
clear_pp(expr_pp(fcx.ccx, e));
|
||||
}
|
||||
case (expr_break(?a)) { clear_pp(expr_pp(fcx.ccx, e)); }
|
||||
case (expr_cont(?a)) { clear_pp(expr_pp(fcx.ccx, e)); }
|
||||
case (expr_port(?a)) { clear_pp(expr_pp(fcx.ccx, e)); }
|
||||
case (expr_ext(_, _, _, ?expanded, ?a)) {
|
||||
find_pre_post_expr(fcx, expanded);
|
||||
copy_pre_post(fcx.ccx, a, expanded);
|
||||
|
@ -544,58 +532,53 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) -> () {
|
|||
find_pre_post_expr(fcx, ex);
|
||||
copy_pre_post(fcx.ccx, a, ex);
|
||||
}
|
||||
case (none) {
|
||||
clear_pp(expr_pp(fcx.ccx, e));
|
||||
}
|
||||
case (none) { clear_pp(expr_pp(fcx.ccx, e)); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn find_pre_post_stmt(&fn_ctxt fcx, &stmt s)
|
||||
-> () {
|
||||
log("stmt =");
|
||||
fn find_pre_post_stmt(&fn_ctxt fcx, &stmt s) {
|
||||
log "stmt =";
|
||||
log_stmt(s);
|
||||
|
||||
auto enclosing = fcx.enclosing;
|
||||
auto enclosing = fcx.enclosing;
|
||||
auto num_local_vars = num_constraints(enclosing);
|
||||
alt(s.node) {
|
||||
case(stmt_decl(?adecl, ?a)) {
|
||||
alt(adecl.node) {
|
||||
case(decl_local(?alocal)) {
|
||||
alt(alocal.init) {
|
||||
case(some(?an_init)) {
|
||||
alt (s.node) {
|
||||
case (stmt_decl(?adecl, ?a)) {
|
||||
alt (adecl.node) {
|
||||
case (decl_local(?alocal)) {
|
||||
alt (alocal.init) {
|
||||
case (some(?an_init)) {
|
||||
find_pre_post_expr(fcx, an_init.expr);
|
||||
copy_pre_post(fcx.ccx, alocal.ann, an_init.expr);
|
||||
|
||||
/* Inherit ann from initializer, and add var being
|
||||
initialized to the postcondition */
|
||||
|
||||
copy_pre_post(fcx.ccx, a, an_init.expr);
|
||||
gen(fcx, a, rec(id=alocal.id,
|
||||
c=ninit(alocal.ident)));
|
||||
gen(fcx, a,
|
||||
rec(id=alocal.id, c=ninit(alocal.ident)));
|
||||
}
|
||||
case(none) {
|
||||
case (none) {
|
||||
clear_pp(ann_to_ts_ann(fcx.ccx,
|
||||
alocal.ann).conditions);
|
||||
clear_pp(ann_to_ts_ann(fcx.ccx, a).conditions);
|
||||
}
|
||||
}
|
||||
}
|
||||
case(decl_item(?anitem)) {
|
||||
case (decl_item(?anitem)) {
|
||||
clear_pp(ann_to_ts_ann(fcx.ccx, a).conditions);
|
||||
find_pre_post_item(fcx.ccx, *anitem);
|
||||
}
|
||||
}
|
||||
}
|
||||
case(stmt_expr(?e,?a)) {
|
||||
case (stmt_expr(?e, ?a)) {
|
||||
find_pre_post_expr(fcx, e);
|
||||
copy_pre_post(fcx.ccx, a, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn find_pre_post_block(&fn_ctxt fcx, block b) -> () {
|
||||
fn find_pre_post_block(&fn_ctxt fcx, block b) {
|
||||
/* Want to say that if there is a break or cont in this
|
||||
block, then that invalidates the poststate upheld by
|
||||
any of the stmts after it.
|
||||
|
@ -612,54 +595,50 @@ fn find_pre_post_block(&fn_ctxt fcx, block b) -> () {
|
|||
|
||||
won't have a postcondition that says x is initialized, but that's ok.
|
||||
*/
|
||||
auto nv = num_constraints(fcx.enclosing);
|
||||
|
||||
fn do_one_(fn_ctxt fcx, &@stmt s) -> () {
|
||||
auto nv = num_constraints(fcx.enclosing);
|
||||
fn do_one_(fn_ctxt fcx, &@stmt s) {
|
||||
find_pre_post_stmt(fcx, *s);
|
||||
log("pre_post for stmt:");
|
||||
log "pre_post for stmt:";
|
||||
log_stmt(*s);
|
||||
log("is:");
|
||||
log "is:";
|
||||
log_pp(stmt_pp(fcx.ccx, *s));
|
||||
}
|
||||
auto do_one = bind do_one_(fcx, _);
|
||||
|
||||
vec::map[@stmt, ()](do_one, b.node.stmts);
|
||||
fn do_inner_(fn_ctxt fcx, &@expr e) -> () {
|
||||
find_pre_post_expr(fcx, e);
|
||||
}
|
||||
fn do_inner_(fn_ctxt fcx, &@expr e) { find_pre_post_expr(fcx, e); }
|
||||
auto do_inner = bind do_inner_(fcx, _);
|
||||
option::map[@expr, ()](do_inner, b.node.expr);
|
||||
|
||||
let vec[pre_and_post] pps = [];
|
||||
|
||||
fn get_pp_stmt(crate_ctxt ccx, &@stmt s) -> pre_and_post {
|
||||
ret stmt_pp(ccx, *s);
|
||||
}
|
||||
auto f = bind get_pp_stmt(fcx.ccx,_);
|
||||
auto f = bind get_pp_stmt(fcx.ccx, _);
|
||||
pps += vec::map[@stmt, pre_and_post](f, b.node.stmts);
|
||||
fn get_pp_expr(crate_ctxt ccx, &@expr e) -> pre_and_post {
|
||||
ret expr_pp(ccx, e);
|
||||
}
|
||||
auto g = bind get_pp_expr(fcx.ccx, _);
|
||||
plus_option[pre_and_post](pps,
|
||||
option::map[@expr, pre_and_post](g, b.node.expr));
|
||||
|
||||
auto block_precond = seq_preconds(fcx, pps);
|
||||
option::map[@expr,
|
||||
pre_and_post](g, b.node.expr));
|
||||
auto block_precond = seq_preconds(fcx, pps);
|
||||
auto h = get_post;
|
||||
auto postconds = vec::map[pre_and_post, postcond](h, pps);
|
||||
auto postconds = vec::map[pre_and_post, postcond](h, pps);
|
||||
/* A block may be empty, so this next line ensures that the postconds
|
||||
vector is non-empty. */
|
||||
|
||||
vec::push[postcond](postconds, block_precond);
|
||||
auto block_postcond = empty_poststate(nv);
|
||||
/* conservative approximation */
|
||||
if (! has_nonlocal_exits(b)) {
|
||||
|
||||
if (!has_nonlocal_exits(b)) {
|
||||
block_postcond = union_postconds(nv, postconds);
|
||||
}
|
||||
|
||||
set_pre_and_post(fcx.ccx, b.node.a, block_precond, block_postcond);
|
||||
}
|
||||
|
||||
fn find_pre_post_fn(&fn_ctxt fcx, &_fn f) -> () {
|
||||
fn find_pre_post_fn(&fn_ctxt fcx, &_fn f) {
|
||||
find_pre_post_block(fcx, f.body);
|
||||
|
||||
// Treat the tail expression as a return statement
|
||||
|
@ -668,18 +647,16 @@ fn find_pre_post_fn(&fn_ctxt fcx, &_fn f) -> () {
|
|||
auto tailann = expr_ann(tailexpr);
|
||||
set_postcond_false(fcx.ccx, tailann);
|
||||
}
|
||||
case (none) { /* fallthrough */ }
|
||||
case (none) {/* fallthrough */ }
|
||||
}
|
||||
}
|
||||
|
||||
fn fn_pre_post(crate_ctxt ccx, &_fn f, &span sp, &ident i, &def_id id,
|
||||
&ann a) -> () {
|
||||
&ann a) {
|
||||
assert (ccx.fm.contains_key(id));
|
||||
auto fcx = rec(enclosing=ccx.fm.get(id),
|
||||
id=id, name=i, ccx=ccx);
|
||||
auto fcx = rec(enclosing=ccx.fm.get(id), id=id, name=i, ccx=ccx);
|
||||
find_pre_post_fn(fcx, f);
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,3 +1,4 @@
|
|||
|
||||
import front::ast::*;
|
||||
import std::option;
|
||||
import std::option::some;
|
||||
|
@ -5,6 +6,7 @@ import std::option::none;
|
|||
import util::common::span;
|
||||
import util::common::respan;
|
||||
|
||||
|
||||
// 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
|
||||
|
@ -15,42 +17,41 @@ import util::common::respan;
|
|||
// 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; } }
|
||||
}
|
||||
|
||||
fn vt[E](&vt[E] x) -> visitor[E] { alt (x) { case (vtor(?v)) { ret v; } } }
|
||||
|
||||
type visitor[E] =
|
||||
@rec(fn(&_mod m, &span sp, &E e, &vt[E] v) visit_mod,
|
||||
fn(&@view_item v, &E e, &vt[E] v) visit_view_item,
|
||||
fn(&@native_item i, &E e, &vt[E] v) visit_native_item,
|
||||
fn(&@item i, &E e, &vt[E] v) visit_item,
|
||||
fn(&@local l, &E e, &vt[E] v) visit_local,
|
||||
fn(&block b, &E e, &vt[E] v) visit_block,
|
||||
fn(&@stmt s, &E e, &vt[E] v) visit_stmt,
|
||||
fn(&arm a, &E e, &vt[E] v) visit_arm,
|
||||
fn(&@pat p, &E e, &vt[E] v) visit_pat,
|
||||
fn(&@decl d, &E e, &vt[E] v) visit_decl,
|
||||
fn(&@expr ex, &E e, &vt[E] v) visit_expr,
|
||||
fn(&@ty t, &E e, &vt[E] v) visit_ty,
|
||||
fn(&@constr c, &E e, &vt[E] v) visit_constr,
|
||||
fn(&_fn f, &vec[ty_param] tp, &span sp, &ident name, &def_id d_id,
|
||||
&ann a, &E e, &vt[E] v) visit_fn);
|
||||
@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, &ident, &def_id, &ann, &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](_, _, _, _, _, _, _, _));
|
||||
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) {
|
||||
|
@ -65,39 +66,33 @@ fn visit_crate_directive[E](&@crate_directive cd, &E e, &vt[E] v) {
|
|||
visit_crate_directive(cdir, e, v);
|
||||
}
|
||||
}
|
||||
case (cdir_src_mod(_, _)) {}
|
||||
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_meta(_,_)) {}
|
||||
case (cdir_syntax(_)) {}
|
||||
case (cdir_auth(_, _)) {}
|
||||
case (cdir_view_item(?vi)) { vt(v).visit_view_item(vi, e, v); }
|
||||
case (cdir_meta(_, _)) { }
|
||||
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);
|
||||
}
|
||||
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_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 (none) { }
|
||||
case (some(?t)) { vt(v).visit_ty(t, e, v); }
|
||||
}
|
||||
alt (loc.node.init) {
|
||||
case (none) {}
|
||||
case (none) { }
|
||||
case (some(?i)) { vt(v).visit_expr(i.expr, e, v); }
|
||||
}
|
||||
}
|
||||
|
@ -111,9 +106,7 @@ fn visit_item[E](&@item i, &E e, &vt[E] v) {
|
|||
case (item_fn(?nm, ?f, ?tp, _, ?d, ?a)) {
|
||||
vt(v).visit_fn(f, tp, i.span, nm, d, a, e, v);
|
||||
}
|
||||
case (item_mod(_, ?m, _, _)) {
|
||||
vt(v).visit_mod(m, i.span, 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);
|
||||
|
@ -122,9 +115,7 @@ fn visit_item[E](&@item i, &E e, &vt[E] v) {
|
|||
vt(v).visit_native_item(ni, e, v);
|
||||
}
|
||||
}
|
||||
case (item_ty(_, ?t, _, _, _, _)) {
|
||||
vt(v).visit_ty(t, e, v);
|
||||
}
|
||||
case (item_ty(_, ?t, _, _, _, _)) { vt(v).visit_ty(t, e, v); }
|
||||
case (item_tag(_, ?variants, _, _, _, _)) {
|
||||
for (variant vr in variants) {
|
||||
for (variant_arg va in vr.node.args) {
|
||||
|
@ -133,22 +124,19 @@ fn visit_item[E](&@item i, &E e, &vt[E] v) {
|
|||
}
|
||||
}
|
||||
case (item_obj(_, ?ob, _, _, _, _)) {
|
||||
for (obj_field f in ob.fields) {
|
||||
vt(v).visit_ty(f.ty, e, v);
|
||||
}
|
||||
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, m.node.ident,
|
||||
m.node.id, m.node.ann, e, v);
|
||||
}
|
||||
alt (ob.dtor) {
|
||||
case (none) {}
|
||||
case (none) { }
|
||||
case (some(?m)) {
|
||||
vt(v).visit_fn(m.node.meth, [], m.span, m.node.ident,
|
||||
m.node.id, m.node.ann, e, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,22 +148,14 @@ fn visit_ty[E](&@ty t, &E e, &vt[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_tup(?mts)) {
|
||||
for (mt mt in mts) {
|
||||
vt(v).visit_ty(mt.ty, e, v);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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)) {
|
||||
|
@ -187,17 +167,16 @@ fn visit_ty[E](&@ty t, &E e, &vt[E] v) {
|
|||
}
|
||||
}
|
||||
case (ty_path(?p, _)) {
|
||||
for (@ty tp in p.node.types) {
|
||||
vt(v).visit_ty(tp, e, v);
|
||||
}
|
||||
for (@ty tp in p.node.types) { vt(v).visit_ty(tp, e, v); }
|
||||
}
|
||||
case (ty_constr(?t, _)) { vt(v).visit_ty(t, e, v); }
|
||||
case (_) {}
|
||||
case (_) { }
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_constr[E](&@constr c, &E e, &vt[E] v) {
|
||||
// default
|
||||
|
||||
}
|
||||
|
||||
fn visit_pat[E](&@pat p, &E e, &vt[E] v) {
|
||||
|
@ -206,26 +185,20 @@ fn visit_pat[E](&@pat p, &E e, &vt[E] v) {
|
|||
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 (_) {}
|
||||
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(_, _)) {}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -259,9 +232,8 @@ fn visit_decl[E](&@decl d, &E e, &vt[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);
|
||||
}
|
||||
case (none) { }
|
||||
case (some(?ex)) { vt(v).visit_expr(ex, e, v); }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -271,9 +243,7 @@ fn visit_exprs[E](vec[@expr] exprs, &E e, &vt[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_vec(?es, _, _, _)) { visit_exprs(es, e, v); }
|
||||
case (expr_tup(?elts, _)) {
|
||||
for (elt el in elts) { vt(v).visit_expr(el.expr, e, v); }
|
||||
}
|
||||
|
@ -298,9 +268,7 @@ fn visit_expr[E](&@expr ex, &E e, &vt[E] v) {
|
|||
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_unary(_, ?a, _)) { vt(v).visit_expr(a, e, v); }
|
||||
case (expr_lit(_, _)) { }
|
||||
case (expr_cast(?x, ?t, _)) {
|
||||
vt(v).visit_expr(x, e, v);
|
||||
|
@ -331,17 +299,13 @@ fn visit_expr[E](&@expr ex, &E e, &vt[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);
|
||||
}
|
||||
for (arm a in arms) { vt(v).visit_arm(a, e, v); }
|
||||
}
|
||||
case (expr_fn(?f, _)) {
|
||||
visit_fn_decl(f.decl, e, v);
|
||||
vt(v).visit_block(f.body, e, v);
|
||||
}
|
||||
case (expr_block(?b, _)) {
|
||||
vt(v).visit_block(b, 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);
|
||||
|
@ -362,17 +326,13 @@ fn visit_expr[E](&@expr ex, &E e, &vt[E] v) {
|
|||
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_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);
|
||||
}
|
||||
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);
|
||||
|
@ -380,30 +340,15 @@ fn visit_expr[E](&@expr ex, &E e, &vt[E] v) {
|
|||
case (expr_fail(_, _)) { }
|
||||
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_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,_,_,_)) {
|
||||
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)) {
|
||||
|
@ -414,9 +359,7 @@ fn visit_expr[E](&@expr ex, &E e, &vt[E] v) {
|
|||
}
|
||||
alt (anon_obj.with_obj) {
|
||||
case (none) { }
|
||||
case (some(?ex)) {
|
||||
vt(v).visit_expr(ex, e, v);
|
||||
}
|
||||
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, m.node.ident,
|
||||
|
@ -430,7 +373,6 @@ 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;
|
||||
|
|
|
@ -1,49 +1,49 @@
|
|||
import front::ast;
|
||||
|
||||
import front::ast;
|
||||
import std::option;
|
||||
import std::option::some;
|
||||
import std::option::none;
|
||||
|
||||
import util::common::span;
|
||||
import util::common::respan;
|
||||
|
||||
|
||||
// FIXME: Should visit patterns as well.
|
||||
type ast_visitor =
|
||||
rec(fn () -> bool keep_going,
|
||||
fn () -> bool want_crate_directives,
|
||||
fn (&ast::crate c) visit_crate_pre,
|
||||
fn (&ast::crate c) visit_crate_post,
|
||||
fn (&@ast::crate_directive cd) visit_crate_directive_pre,
|
||||
fn (&@ast::crate_directive cd) visit_crate_directive_post,
|
||||
fn (&@ast::view_item i) visit_view_item_pre,
|
||||
fn (&@ast::view_item i) visit_view_item_post,
|
||||
fn (&@ast::native_item i) visit_native_item_pre,
|
||||
fn (&@ast::native_item i) visit_native_item_post,
|
||||
fn (&@ast::item i) visit_item_pre,
|
||||
fn (&@ast::item i) visit_item_post,
|
||||
fn (&@ast::method m) visit_method_pre,
|
||||
fn (&@ast::method m) visit_method_post,
|
||||
fn (&ast::block b) visit_block_pre,
|
||||
fn (&ast::block b) visit_block_post,
|
||||
fn (&@ast::stmt s) visit_stmt_pre,
|
||||
fn (&@ast::stmt s) visit_stmt_post,
|
||||
fn (&ast::arm a) visit_arm_pre,
|
||||
fn (&ast::arm a) visit_arm_post,
|
||||
fn (&@ast::pat p) visit_pat_pre,
|
||||
fn (&@ast::pat p) visit_pat_post,
|
||||
fn (&@ast::decl d) visit_decl_pre,
|
||||
fn (&@ast::decl d) visit_decl_post,
|
||||
fn (&@ast::local l) visit_local_pre,
|
||||
fn (&@ast::local l) visit_local_post,
|
||||
fn (&@ast::expr e) visit_expr_pre,
|
||||
fn (&@ast::expr e) visit_expr_post,
|
||||
fn (&@ast::ty t) visit_ty_pre,
|
||||
fn (&@ast::ty t) visit_ty_post,
|
||||
fn (&@ast::constr c) visit_constr,
|
||||
fn (&ast::_fn f, &span sp, &ast::ident name,
|
||||
&ast::def_id d_id, &ast::ann a) visit_fn_pre,
|
||||
fn (&ast::_fn f, &span sp, &ast::ident name,
|
||||
&ast::def_id d_id, &ast::ann a) visit_fn_post);
|
||||
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, &span, &ast::ident, &ast::def_id, &ast::ann)
|
||||
visit_fn_pre,
|
||||
fn(&ast::_fn, &span, &ast::ident, &ast::def_id, &ast::ann)
|
||||
visit_fn_post);
|
||||
|
||||
fn walk_crate(&ast_visitor v, &ast::crate c) {
|
||||
if (!v.keep_going()) { ret; }
|
||||
|
@ -63,30 +63,24 @@ fn walk_crate_directive(&ast_visitor v, @ast::crate_directive cd) {
|
|||
walk_crate_directive(v, cdir);
|
||||
}
|
||||
}
|
||||
case (ast::cdir_src_mod(_, _)) {}
|
||||
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_meta(_,_)) {}
|
||||
case (ast::cdir_syntax(_)) {}
|
||||
case (ast::cdir_auth(_, _)) {}
|
||||
case (ast::cdir_view_item(?vi)) { walk_view_item(v, vi); }
|
||||
case (ast::cdir_meta(_, _)) { }
|
||||
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);
|
||||
}
|
||||
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) {
|
||||
|
@ -97,15 +91,10 @@ fn walk_view_item(&ast_visitor v, @ast::view_item 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.ty) { case (none) { } case (some(?t)) { walk_ty(v, t); } }
|
||||
alt (loc.node.init) {
|
||||
case (none) {}
|
||||
case (some(?i)) {
|
||||
walk_expr(v, i.expr);
|
||||
}
|
||||
case (none) { }
|
||||
case (some(?i)) { walk_expr(v, i.expr); }
|
||||
}
|
||||
v.visit_local_post(loc);
|
||||
}
|
||||
|
@ -121,15 +110,9 @@ fn walk_item(&ast_visitor v, @ast::item i) {
|
|||
case (ast::item_fn(?nm, ?f, _, _, ?d, ?a)) {
|
||||
walk_fn(v, f, i.span, nm, d, a);
|
||||
}
|
||||
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_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_tag(_, ?variants, _, _, _, _)) {
|
||||
for (ast::variant vr in variants) {
|
||||
for (ast::variant_arg va in vr.node.args) {
|
||||
|
@ -138,24 +121,21 @@ fn walk_item(&ast_visitor v, @ast::item i) {
|
|||
}
|
||||
}
|
||||
case (ast::item_obj(_, ?ob, _, _, _, _)) {
|
||||
for (ast::obj_field f in ob.fields) {
|
||||
walk_ty(v, f.ty);
|
||||
}
|
||||
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);
|
||||
walk_fn(v, m.node.meth, m.span,
|
||||
m.node.ident, m.node.id, m.node.ann);
|
||||
walk_fn(v, m.node.meth, m.span, m.node.ident, m.node.id,
|
||||
m.node.ann);
|
||||
v.visit_method_post(m);
|
||||
}
|
||||
alt (ob.dtor) {
|
||||
case (none) {}
|
||||
case (none) { }
|
||||
case (some(?m)) {
|
||||
walk_fn(v, m.node.meth, m.span, m.node.ident, m.node.id,
|
||||
m.node.ann);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
v.visit_item_post(i);
|
||||
}
|
||||
|
@ -164,40 +144,32 @@ 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_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_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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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)) {
|
||||
|
@ -209,11 +181,9 @@ fn walk_ty(&ast_visitor v, @ast::ty t) {
|
|||
}
|
||||
}
|
||||
case (ast::ty_path(?p, _)) {
|
||||
for (@ast::ty tp in p.node.types) {
|
||||
walk_ty(v, tp);
|
||||
}
|
||||
for (@ast::ty tp in p.node.types) { walk_ty(v, tp); }
|
||||
}
|
||||
case (ast::ty_type) {}
|
||||
case (ast::ty_type) { }
|
||||
case (ast::ty_constr(?t, _)) { walk_ty(v, t); }
|
||||
}
|
||||
v.visit_ty_post(t);
|
||||
|
@ -223,26 +193,18 @@ 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);
|
||||
}
|
||||
for (@ast::ty tp in path.node.types) { walk_ty(v, tp); }
|
||||
for (@ast::pat child in children) { walk_pat(v, child); }
|
||||
}
|
||||
case (_) {}
|
||||
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);
|
||||
}
|
||||
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) {
|
||||
|
@ -252,19 +214,14 @@ fn walk_native_item(&ast_visitor v, @ast::native_item ni) {
|
|||
case (ast::native_item_fn(_, _, ?fd, _, _, _)) {
|
||||
walk_fn_decl(v, fd);
|
||||
}
|
||||
case (ast::native_item_ty(_, _)) {
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -280,9 +237,7 @@ fn walk_fn(&ast_visitor v, &ast::_fn f, &span sp, &ast::ident i,
|
|||
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);
|
||||
}
|
||||
for (@ast::stmt s in b.node.stmts) { walk_stmt(v, s); }
|
||||
walk_expr_opt(v, b.node.expr);
|
||||
v.visit_block_post(b);
|
||||
}
|
||||
|
@ -291,12 +246,8 @@ 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_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);
|
||||
}
|
||||
|
@ -308,47 +259,30 @@ 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, @respan(d.span, loc));
|
||||
}
|
||||
case (ast::decl_item(?it)) {
|
||||
walk_item(v, it);
|
||||
}
|
||||
case (ast::decl_local(?loc)) { walk_local(v, @respan(d.span, 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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
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_vec(?es, _, _, _)) { walk_exprs(v, es); }
|
||||
case (ast::expr_tup(?elts, _)) {
|
||||
for (ast::elt e in elts) {
|
||||
walk_expr(v, e.expr);
|
||||
}
|
||||
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);
|
||||
}
|
||||
for (ast::field f in flds) { walk_expr(v, f.node.expr); }
|
||||
walk_expr_opt(v, base);
|
||||
}
|
||||
case (ast::expr_call(?callee, ?args, _)) {
|
||||
|
@ -358,9 +292,7 @@ fn walk_expr(&ast_visitor v, @ast::expr e) {
|
|||
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);
|
||||
}
|
||||
for (option::t[@ast::expr] eo in args) { walk_expr_opt(v, eo); }
|
||||
}
|
||||
case (ast::expr_spawn(_, _, ?callee, ?args, _)) {
|
||||
walk_expr(v, callee);
|
||||
|
@ -370,14 +302,9 @@ fn walk_expr(&ast_visitor v, @ast::expr e) {
|
|||
walk_expr(v, a);
|
||||
walk_expr(v, b);
|
||||
}
|
||||
case (ast::expr_unary(_, ?a, _)) {
|
||||
walk_expr(v, a);
|
||||
}
|
||||
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_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);
|
||||
|
@ -414,102 +341,67 @@ fn walk_expr(&ast_visitor v, @ast::expr e) {
|
|||
walk_fn_decl(v, f.decl);
|
||||
walk_block(v, f.body);
|
||||
}
|
||||
case (ast::expr_block(?b, _)) {
|
||||
walk_block(v, b);
|
||||
}
|
||||
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_move(?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_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);
|
||||
}
|
||||
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(_, _)) { }
|
||||
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_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,_,_,_)) {
|
||||
|
||||
case (ast::expr_chan(?x, _)) { walk_expr(v, x); }
|
||||
case (ast::expr_anon_obj(?anon_obj, _, _, _)) {
|
||||
// Fields
|
||||
let option::t[vec[ast::obj_field]] fields
|
||||
= none[vec[ast::obj_field]];
|
||||
|
||||
let option::t[vec[ast::obj_field]] fields =
|
||||
none[vec[ast::obj_field]];
|
||||
alt (anon_obj.fields) {
|
||||
case (none) { }
|
||||
case (some(?fields)) {
|
||||
for (ast::obj_field f in fields) {
|
||||
walk_ty(v, f.ty);
|
||||
}
|
||||
for (ast::obj_field f in fields) { walk_ty(v, f.ty); }
|
||||
}
|
||||
}
|
||||
|
||||
// with_obj
|
||||
|
||||
let option::t[@ast::expr] with_obj = none[@ast::expr];
|
||||
alt (anon_obj.with_obj) {
|
||||
case (none) { }
|
||||
case (some(?e)) {
|
||||
walk_expr(v, e);
|
||||
}
|
||||
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, m.node.ident,
|
||||
m.node.id, m.node.ann);
|
||||
walk_fn(v, m.node.meth, m.span, m.node.ident, m.node.id,
|
||||
m.node.ann);
|
||||
v.visit_method_post(m);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -517,24 +409,42 @@ fn walk_expr(&ast_visitor v, @ast::expr 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, &span sp, &ast::ident i, &ast::def_id d,
|
||||
&ast::ann a) { }
|
||||
&ast::ann a) {
|
||||
}
|
||||
|
||||
fn default_visitor() -> ast_visitor {
|
||||
ret rec(keep_going=def_keep_going,
|
||||
|
@ -571,7 +481,6 @@ fn default_visitor() -> ast_visitor {
|
|||
visit_fn_pre=def_visit_fn,
|
||||
visit_fn_post=def_visit_fn);
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
|
||||
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
|
||||
|
@ -54,19 +56,13 @@ import std::str;
|
|||
* 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;
|
||||
}
|
||||
|
||||
tag token { STRING(str, int); BREAK(break_t); BEGIN(begin_t); END; EOF; }
|
||||
|
||||
fn tok_str(token t) -> str {
|
||||
alt (t) {
|
||||
|
@ -78,18 +74,16 @@ fn tok_str(token t) -> str {
|
|||
}
|
||||
}
|
||||
|
||||
fn buf_str(vec[mutable token] toks, vec[mutable int] szs,
|
||||
uint left, uint right, uint lim) -> str {
|
||||
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);
|
||||
assert (n == vec::len(szs));
|
||||
auto i = left;
|
||||
auto L = lim;
|
||||
auto s = "[";
|
||||
while (i != right && L != 0u) {
|
||||
L -= 1u;
|
||||
if (i != left) {
|
||||
s += ", ";
|
||||
}
|
||||
if (i != left) { s += ", "; }
|
||||
s += #fmt("%d=%s", szs.(i), tok_str(toks.(i)));
|
||||
i += 1u;
|
||||
i %= n;
|
||||
|
@ -98,43 +92,35 @@ fn buf_str(vec[mutable token] toks, vec[mutable int] szs,
|
|||
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);
|
||||
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.
|
||||
|
@ -212,43 +198,46 @@ fn mk_printer(io::writer out, uint linewidth) -> printer {
|
|||
* 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 int margin, // width of lines we're constrained to
|
||||
|
||||
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"
|
||||
mutable int space, // number of spaces left on line
|
||||
|
||||
// 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 uint left, // index of left side of input stream
|
||||
|
||||
mutable vec[mutable uint] scan_stack,
|
||||
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 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
|
||||
) {
|
||||
|
||||
|
||||
mutable int pending_indentation) {
|
||||
fn pretty_print(token t) {
|
||||
|
||||
log #fmt("pp [%u,%u]", left, right);
|
||||
alt (t) {
|
||||
|
||||
case (EOF) {
|
||||
if (!scan_stack_empty) {
|
||||
self.check_stack(0);
|
||||
|
@ -256,22 +245,18 @@ obj printer(io::writer out,
|
|||
}
|
||||
self.indent(0);
|
||||
}
|
||||
|
||||
case (BEGIN(?b)) {
|
||||
if (scan_stack_empty) {
|
||||
left_total = 1;
|
||||
right_total = 1;
|
||||
left = 0u;
|
||||
right = 0u;
|
||||
} else {
|
||||
self.advance_right();
|
||||
}
|
||||
} 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);
|
||||
|
@ -284,16 +269,13 @@ obj printer(io::writer out,
|
|||
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();
|
||||
}
|
||||
} else { self.advance_right(); }
|
||||
log #fmt("pp BREAK/buffer [%u,%u]", left, right);
|
||||
self.check_stack(0);
|
||||
self.scan_push(right);
|
||||
|
@ -301,7 +283,6 @@ obj printer(io::writer out,
|
|||
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);
|
||||
|
@ -317,13 +298,12 @@ obj printer(io::writer out,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_stream() {
|
||||
log #fmt("check_stream [%u, %u] with left_total=%d, right_total=%d",
|
||||
left, right, left_total, right_total);;
|
||||
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);
|
||||
right_total - left_total, space);
|
||||
if (!scan_stack_empty) {
|
||||
if (left == scan_stack.(bottom)) {
|
||||
log #fmt("setting %u to infinity and popping", left);
|
||||
|
@ -331,72 +311,52 @@ obj printer(io::writer out,
|
|||
}
|
||||
}
|
||||
self.advance_left(token.(left), size.(left));
|
||||
if (left != right) {
|
||||
self.check_stream();
|
||||
}
|
||||
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;
|
||||
}
|
||||
} else { top += 1u; top %= buf_len; assert (top != bottom); }
|
||||
scan_stack.(top) = x;
|
||||
}
|
||||
|
||||
fn scan_pop() -> uint {
|
||||
assert !scan_stack_empty;
|
||||
assert (!scan_stack_empty);
|
||||
auto x = scan_stack.(top);
|
||||
if (top == bottom) {
|
||||
scan_stack_empty = true;
|
||||
} else {
|
||||
top += (buf_len - 1u);
|
||||
top %= buf_len;
|
||||
}
|
||||
} else { top += buf_len - 1u; top %= buf_len; }
|
||||
ret x;
|
||||
}
|
||||
|
||||
fn scan_top() -> uint {
|
||||
assert !scan_stack_empty;
|
||||
assert (!scan_stack_empty);
|
||||
ret scan_stack.(top);
|
||||
}
|
||||
|
||||
fn scan_pop_bottom() -> uint {
|
||||
assert !scan_stack_empty;
|
||||
assert (!scan_stack_empty);
|
||||
auto x = scan_stack.(bottom);
|
||||
if (top == bottom) {
|
||||
scan_stack_empty = true;
|
||||
} else {
|
||||
bottom += 1u;
|
||||
bottom %= buf_len;
|
||||
}
|
||||
} else { bottom += 1u; bottom %= buf_len; }
|
||||
ret x;
|
||||
}
|
||||
|
||||
fn advance_right() {
|
||||
right += 1u;
|
||||
right %= buf_len;
|
||||
assert right != left;
|
||||
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 (BREAK(?b)) { left_total += b.blank_space; }
|
||||
case (STRING(_, ?len)) {
|
||||
assert len == L;
|
||||
assert (len == L);
|
||||
left_total += len;
|
||||
}
|
||||
case (_) {}
|
||||
case (_) { }
|
||||
}
|
||||
if (left != right) {
|
||||
left += 1u;
|
||||
|
@ -405,7 +365,6 @@ obj printer(io::writer out,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_stack(int k) {
|
||||
if (!scan_stack_empty) {
|
||||
auto x = self.scan_top();
|
||||
|
@ -418,41 +377,33 @@ obj printer(io::writer out,
|
|||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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(" ");
|
||||
|
@ -460,51 +411,41 @@ obj printer(io::writer out,
|
|||
}
|
||||
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 #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;
|
||||
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)));
|
||||
rec(offset=col, pbreak=broken(b.breaks)));
|
||||
} else {
|
||||
log "print BEGIN -> push fitting block";
|
||||
vec::push(print_stack,
|
||||
rec(offset = 0,
|
||||
pbreak = fits));
|
||||
vec::push(print_stack, rec(offset=0, pbreak=fits));
|
||||
}
|
||||
}
|
||||
|
||||
case (END) {
|
||||
log "print END -> pop END";
|
||||
assert vec::len(print_stack) != 0u;
|
||||
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";
|
||||
|
@ -518,17 +459,17 @@ obj printer(io::writer out,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
case (STRING(?s, ?len)) {
|
||||
log "print STRING";
|
||||
assert L == len;
|
||||
assert (L == len);
|
||||
// assert L <= space;
|
||||
|
||||
space -= len;
|
||||
self.write_str(s);
|
||||
}
|
||||
|
||||
case (EOF) {
|
||||
// EOF should never get here.
|
||||
|
||||
fail;
|
||||
}
|
||||
}
|
||||
|
@ -537,45 +478,37 @@ obj printer(io::writer out,
|
|||
|
||||
|
||||
// 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)));
|
||||
p.pretty_print(BEGIN(rec(offset=indent as int, breaks=b)));
|
||||
}
|
||||
|
||||
fn ibox(printer p, uint indent) { box(p, indent, inconsistent); }
|
||||
|
||||
fn ibox(printer p, uint indent) {
|
||||
box(p, indent, inconsistent);
|
||||
}
|
||||
|
||||
fn cbox(printer p, uint indent) {
|
||||
box(p, indent, consistent);
|
||||
}
|
||||
|
||||
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)));
|
||||
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, 0xffff));
|
||||
}
|
||||
fn zero_word(printer p, str wrd) {
|
||||
p.pretty_print(STRING(wrd, 0));
|
||||
}
|
||||
|
||||
fn huge_word(printer p, str wrd) { p.pretty_print(STRING(wrd, 0xffff)); }
|
||||
|
||||
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, 0xffffu); }
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
import std::io;
|
||||
import middle::ty::*;
|
||||
import front::ast::constr_arg;
|
||||
|
@ -10,169 +11,122 @@ import front::codemap;
|
|||
import front::codemap::codemap;
|
||||
|
||||
fn ty_to_str(&ctxt cx, &t typ) -> str {
|
||||
|
||||
fn fn_input_to_str(&ctxt cx,
|
||||
&rec(middle::ty::mode mode, t ty) input) -> str {
|
||||
auto s = alt (input.mode) {
|
||||
case (mo_val) { "" }
|
||||
case (mo_alias(false)) { "&" }
|
||||
case (mo_alias(true)) { "&mutable " }
|
||||
};
|
||||
|
||||
fn fn_input_to_str(&ctxt cx, &rec(middle::ty::mode mode, t ty) input) ->
|
||||
str {
|
||||
auto s =
|
||||
alt (input.mode) {
|
||||
case (mo_val) { "" }
|
||||
case (mo_alias(false)) { "&" }
|
||||
case (mo_alias(true)) { "&mutable " }
|
||||
};
|
||||
ret s + ty_to_str(cx, input.ty);
|
||||
}
|
||||
|
||||
fn fn_to_str(&ctxt cx,
|
||||
ast::proto proto,
|
||||
option::t[ast::ident] ident,
|
||||
fn fn_to_str(&ctxt cx, ast::proto proto, option::t[ast::ident] ident,
|
||||
vec[arg] inputs, t output, ast::controlflow cf,
|
||||
&vec[@ast::constr] constrs) -> str {
|
||||
auto f = bind fn_input_to_str(cx, _);
|
||||
|
||||
auto s;
|
||||
alt (proto) {
|
||||
case (ast::proto_iter) {
|
||||
s = "iter";
|
||||
}
|
||||
case (ast::proto_fn) {
|
||||
s = "fn";
|
||||
}
|
||||
auto f = bind fn_input_to_str(cx, _);
|
||||
auto s;
|
||||
alt (proto) {
|
||||
case (ast::proto_iter) { s = "iter"; }
|
||||
case (ast::proto_fn) { s = "fn"; }
|
||||
}
|
||||
alt (ident) { case (some(?i)) { s += " "; s += i; } case (_) { } }
|
||||
s += "(";
|
||||
s += str::connect(vec::map[arg, str](f, inputs), ", ");
|
||||
s += ")";
|
||||
if (struct(cx, output) != ty_nil) {
|
||||
alt (cf) {
|
||||
case (ast::noreturn) { s += " -> !"; }
|
||||
case (ast::return) { s += " -> " + ty_to_str(cx, output); }
|
||||
}
|
||||
|
||||
alt (ident) {
|
||||
case (some(?i)) {
|
||||
s += " ";
|
||||
s += i;
|
||||
}
|
||||
case (_) { }
|
||||
}
|
||||
|
||||
s += "(";
|
||||
s += str::connect(vec::map[arg,str](f, inputs), ", ");
|
||||
s += ")";
|
||||
|
||||
if (struct(cx, output) != ty_nil) {
|
||||
alt (cf) {
|
||||
case (ast::noreturn) {
|
||||
s += " -> !";
|
||||
}
|
||||
case (ast::return) {
|
||||
s += " -> " + ty_to_str(cx, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s += constrs_str(constrs);
|
||||
ret s;
|
||||
}
|
||||
s += constrs_str(constrs);
|
||||
ret s;
|
||||
}
|
||||
|
||||
fn method_to_str(&ctxt cx, &method m) -> str {
|
||||
ret fn_to_str(cx, m.proto, some[ast::ident](m.ident),
|
||||
m.inputs, m.output, m.cf, m.constrs) + ";";
|
||||
ret fn_to_str(cx, m.proto, some[ast::ident](m.ident), m.inputs,
|
||||
m.output, m.cf, m.constrs) + ";";
|
||||
}
|
||||
|
||||
fn field_to_str(&ctxt cx, &field f) -> str {
|
||||
ret mt_to_str(cx, f.mt) + " " + f.ident;
|
||||
}
|
||||
|
||||
fn mt_to_str(&ctxt cx, &mt m) -> str {
|
||||
auto mstr;
|
||||
alt (m.mut) {
|
||||
case (ast::mut) { mstr = "mutable "; }
|
||||
case (ast::imm) { mstr = ""; }
|
||||
case (ast::mut) { mstr = "mutable "; }
|
||||
case (ast::imm) { mstr = ""; }
|
||||
case (ast::maybe_mut) { mstr = "mutable? "; }
|
||||
}
|
||||
|
||||
ret mstr + ty_to_str(cx, m.ty);
|
||||
}
|
||||
|
||||
alt (cname(cx, typ)) {
|
||||
case (some(?cs)) {
|
||||
ret cs;
|
||||
}
|
||||
case (_) { }
|
||||
}
|
||||
|
||||
alt (cname(cx, typ)) { case (some(?cs)) { ret cs; } case (_) { } }
|
||||
auto s = "";
|
||||
|
||||
alt (struct(cx, typ)) {
|
||||
case (ty_native) { s += "native"; }
|
||||
case (ty_nil) { s += "()"; }
|
||||
case (ty_bot) { s += "_|_"; }
|
||||
case (ty_bool) { s += "bool"; }
|
||||
case (ty_int) { s += "int"; }
|
||||
case (ty_float) { s += "float"; }
|
||||
case (ty_uint) { s += "uint"; }
|
||||
case (ty_machine(?tm)) { s += common::ty_mach_to_str(tm); }
|
||||
case (ty_char) { s += "char"; }
|
||||
case (ty_str) { s += "str"; }
|
||||
case (ty_istr) { s += "istr"; }
|
||||
case (ty_box(?tm)) { s += "@" + mt_to_str(cx, tm); }
|
||||
case (ty_vec(?tm)) { s += "vec[" + mt_to_str(cx, tm) + "]"; }
|
||||
case (ty_ivec(?tm)) { s += "ivec[" + mt_to_str(cx, tm) + "]"; }
|
||||
case (ty_port(?t)) { s += "port[" + ty_to_str(cx, t) + "]"; }
|
||||
case (ty_chan(?t)) { s += "chan[" + ty_to_str(cx, t) + "]"; }
|
||||
case (ty_type) { s += "type"; }
|
||||
case (ty_task) { s += "task"; }
|
||||
|
||||
case (ty_native) { s += "native"; }
|
||||
case (ty_nil) { s += "()"; }
|
||||
case (ty_bot) { s += "_|_"; }
|
||||
case (ty_bool) { s += "bool"; }
|
||||
case (ty_int) { s += "int"; }
|
||||
case (ty_float) { s += "float"; }
|
||||
case (ty_uint) { s += "uint"; }
|
||||
case (ty_machine(?tm)) { s += common::ty_mach_to_str(tm); }
|
||||
case (ty_char) { s += "char"; }
|
||||
case (ty_str) { s += "str"; }
|
||||
case (ty_istr) { s += "istr"; }
|
||||
case (ty_box(?tm)) { s += "@" + mt_to_str(cx, tm); }
|
||||
case (ty_vec(?tm)) { s += "vec[" + mt_to_str(cx, tm) + "]"; }
|
||||
case (ty_ivec(?tm)) { s += "ivec[" + mt_to_str(cx, tm) + "]"; }
|
||||
case (ty_port(?t)) { s += "port[" + ty_to_str(cx, t) + "]"; }
|
||||
case (ty_chan(?t)) { s += "chan[" + ty_to_str(cx, t) + "]"; }
|
||||
case (ty_type) { s += "type"; }
|
||||
case (ty_task) { s += "task"; }
|
||||
case (ty_tup(?elems)) {
|
||||
auto f = bind mt_to_str(cx, _);
|
||||
auto strs = vec::map[mt,str](f, elems);
|
||||
auto strs = vec::map[mt, str](f, elems);
|
||||
s += "tup(" + str::connect(strs, ",") + ")";
|
||||
}
|
||||
|
||||
case (ty_rec(?elems)) {
|
||||
auto f = bind field_to_str(cx, _);
|
||||
auto strs = vec::map[field,str](f, elems);
|
||||
auto strs = vec::map[field, str](f, elems);
|
||||
s += "rec(" + str::connect(strs, ",") + ")";
|
||||
}
|
||||
|
||||
case (ty_tag(?id, ?tps)) {
|
||||
// The user should never see this if the cname is set properly!
|
||||
s += "<tag#" + util::common::istr(id._0) + ":" +
|
||||
util::common::istr(id._1) + ">";
|
||||
|
||||
s +=
|
||||
"<tag#" + util::common::istr(id._0) + ":" +
|
||||
util::common::istr(id._1) + ">";
|
||||
if (vec::len[t](tps) > 0u) {
|
||||
auto f = bind ty_to_str(cx, _);
|
||||
auto strs = vec::map[t,str](f, tps);
|
||||
auto strs = vec::map[t, str](f, tps);
|
||||
s += "[" + str::connect(strs, ",") + "]";
|
||||
}
|
||||
}
|
||||
|
||||
case (ty_fn(?proto, ?inputs, ?output, ?cf, ?constrs)) {
|
||||
s += fn_to_str(cx, proto, none[ast::ident], inputs, output, cf,
|
||||
constrs);
|
||||
s +=
|
||||
fn_to_str(cx, proto, none[ast::ident], inputs, output, cf,
|
||||
constrs);
|
||||
}
|
||||
|
||||
case (ty_native_fn(_, ?inputs, ?output)) {
|
||||
let vec[@ast::constr] constrs = [];
|
||||
s += fn_to_str(cx, ast::proto_fn, none[ast::ident],
|
||||
inputs, output, ast::return, constrs);
|
||||
let vec[@ast::constr] constrs = [];
|
||||
s +=
|
||||
fn_to_str(cx, ast::proto_fn, none[ast::ident], inputs, output,
|
||||
ast::return, constrs);
|
||||
}
|
||||
|
||||
case (ty_obj(?meths)) {
|
||||
auto f = bind method_to_str(cx, _);
|
||||
auto m = vec::map[method,str](f, meths);
|
||||
auto m = vec::map[method, str](f, meths);
|
||||
s += "obj {\n\t" + str::connect(m, "\n\t") + "\n}";
|
||||
}
|
||||
|
||||
case (ty_var(?v)) {
|
||||
s += "<T" + util::common::istr(v) + ">";
|
||||
}
|
||||
|
||||
case (ty_var(?v)) { s += "<T" + util::common::istr(v) + ">"; }
|
||||
case (ty_param(?id)) {
|
||||
s += "'" + str::unsafe_from_bytes([('a' as u8) + (id as u8)]);
|
||||
}
|
||||
|
||||
case (_) {
|
||||
s += ty_to_short_str(cx, typ);
|
||||
}
|
||||
|
||||
case (_) { s += ty_to_short_str(cx, typ); }
|
||||
}
|
||||
|
||||
ret s;
|
||||
}
|
||||
|
||||
|
||||
fn ty_to_short_str(&ctxt cx, t typ) -> str {
|
||||
auto f = def_to_str;
|
||||
auto ecx = @rec(ds=f, tcx=cx, abbrevs=metadata::ac_no_abbrevs);
|
||||
|
@ -181,46 +135,29 @@ fn ty_to_short_str(&ctxt cx, t typ) -> str {
|
|||
ret s;
|
||||
}
|
||||
|
||||
fn constr_arg_to_str[T](fn (&T) -> str f,
|
||||
&ast::constr_arg_general_[T] c) -> str {
|
||||
fn constr_arg_to_str[T](fn(&T) -> str f, &ast::constr_arg_general_[T] c) ->
|
||||
str {
|
||||
alt (c) {
|
||||
case (ast::carg_base) {
|
||||
ret "*";
|
||||
}
|
||||
case (ast::carg_ident(?i)) {
|
||||
ret f(i);
|
||||
}
|
||||
case (ast::carg_lit(?l)) {
|
||||
ret lit_to_str(l);
|
||||
}
|
||||
case (ast::carg_base) { ret "*"; }
|
||||
case (ast::carg_ident(?i)) { ret f(i); }
|
||||
case (ast::carg_lit(?l)) { ret lit_to_str(l); }
|
||||
}
|
||||
}
|
||||
|
||||
fn constr_arg_to_str_1(&ast::constr_arg_general_[str] c) -> str {
|
||||
alt (c) {
|
||||
case (ast::carg_base) {
|
||||
ret "*";
|
||||
}
|
||||
case (ast::carg_ident(?i)) {
|
||||
ret i;
|
||||
}
|
||||
case (ast::carg_lit(?l)) {
|
||||
ret lit_to_str(l);
|
||||
}
|
||||
case (ast::carg_base) { ret "*"; }
|
||||
case (ast::carg_ident(?i)) { ret i; }
|
||||
case (ast::carg_lit(?l)) { ret lit_to_str(l); }
|
||||
}
|
||||
}
|
||||
|
||||
fn constr_args_to_str[T](fn (&T) -> str f,
|
||||
fn constr_args_to_str[T](fn(&T) -> str f,
|
||||
&vec[@ast::constr_arg_general[T]] args) -> str {
|
||||
auto comma = false;
|
||||
auto s = "(";
|
||||
auto s = "(";
|
||||
for (@ast::constr_arg_general[T] a in args) {
|
||||
if (comma) {
|
||||
s += ", ";
|
||||
}
|
||||
else {
|
||||
comma = true;
|
||||
}
|
||||
if (comma) { s += ", "; } else { comma = true; }
|
||||
s += constr_arg_to_str[T](f, a.node);
|
||||
}
|
||||
s += ")";
|
||||
|
@ -229,14 +166,9 @@ fn constr_args_to_str[T](fn (&T) -> str f,
|
|||
|
||||
fn constr_args_to_str_1(&vec[@ast::constr_arg_use] args) -> str {
|
||||
auto comma = false;
|
||||
auto s = "(";
|
||||
auto s = "(";
|
||||
for (@ast::constr_arg_use a in args) {
|
||||
if (comma) {
|
||||
s += ", ";
|
||||
}
|
||||
else {
|
||||
comma = true;
|
||||
}
|
||||
if (comma) { s += ", "; } else { comma = true; }
|
||||
s += constr_arg_to_str_1(a.node);
|
||||
}
|
||||
s += ")";
|
||||
|
@ -245,7 +177,6 @@ fn constr_args_to_str_1(&vec[@ast::constr_arg_use] args) -> str {
|
|||
|
||||
fn print_literal(&ps s, &@ast::lit lit) {
|
||||
maybe_print_comment(s, lit.span.lo);
|
||||
|
||||
alt (next_lit(s)) {
|
||||
case (some(?lt)) {
|
||||
if (lt.pos == lit.span.lo) {
|
||||
|
@ -254,39 +185,33 @@ fn print_literal(&ps s, &@ast::lit lit) {
|
|||
ret;
|
||||
}
|
||||
}
|
||||
case (_) {}
|
||||
case (_) { }
|
||||
}
|
||||
|
||||
alt (lit.node) {
|
||||
case (ast::lit_str(?st,?kind)) {
|
||||
case (ast::lit_str(?st, ?kind)) {
|
||||
if (kind == ast::sk_unique) { word(s.s, "~"); }
|
||||
print_string(s, st);
|
||||
}
|
||||
case (ast::lit_char(?ch)) {
|
||||
word(s.s, "'" + escape_str(str::from_bytes([ch as u8]), '\'')
|
||||
+ "'");
|
||||
word(s.s,
|
||||
"'" + escape_str(str::from_bytes([ch as u8]), '\'') + "'");
|
||||
}
|
||||
case (ast::lit_int(?val)) {
|
||||
word(s.s, common::istr(val));
|
||||
}
|
||||
case (ast::lit_uint(?val)) {
|
||||
word(s.s, common::uistr(val) + "u");
|
||||
}
|
||||
case (ast::lit_float(?fstr)) {
|
||||
word(s.s, fstr);
|
||||
}
|
||||
case (ast::lit_mach_int(?mach,?val)) {
|
||||
case (ast::lit_int(?val)) { word(s.s, common::istr(val)); }
|
||||
case (ast::lit_uint(?val)) { word(s.s, common::uistr(val) + "u"); }
|
||||
case (ast::lit_float(?fstr)) { word(s.s, fstr); }
|
||||
case (ast::lit_mach_int(?mach, ?val)) {
|
||||
word(s.s, common::istr(val as int));
|
||||
word(s.s, common::ty_mach_to_str(mach));
|
||||
}
|
||||
case (ast::lit_mach_float(?mach,?val)) {
|
||||
case (ast::lit_mach_float(?mach, ?val)) {
|
||||
// val is already a str
|
||||
|
||||
word(s.s, val);
|
||||
word(s.s, common::ty_mach_to_str(mach));
|
||||
}
|
||||
case (ast::lit_nil) {word(s.s, "()");}
|
||||
case (ast::lit_nil) { word(s.s, "()"); }
|
||||
case (ast::lit_bool(?val)) {
|
||||
if (val) {word(s.s, "true");} else {word(s.s, "false");}
|
||||
if (val) { word(s.s, "true"); } else { word(s.s, "false"); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -298,9 +223,9 @@ fn next_lit(&ps s) -> option::t[lexer::lit] {
|
|||
case (some(?lits)) {
|
||||
if (s.cur_lit < vec::len(lits)) {
|
||||
ret some(lits.(s.cur_lit));
|
||||
} else {ret none[lexer::lit];}
|
||||
} else { ret none[lexer::lit]; }
|
||||
}
|
||||
case (_) {ret none[lexer::lit];}
|
||||
case (_) { ret none[lexer::lit]; }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -313,31 +238,25 @@ fn maybe_print_comment(&ps s, uint pos) {
|
|||
s.cur_cmnt += 1u;
|
||||
} else { break; }
|
||||
}
|
||||
case (_) {break;}
|
||||
case (_) { break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn print_comment(&ps s, lexer::cmnt cmnt) {
|
||||
alt (cmnt.style) {
|
||||
case (lexer::mixed) {
|
||||
assert vec::len(cmnt.lines) == 1u;
|
||||
assert (vec::len(cmnt.lines) == 1u);
|
||||
zerobreak(s.s);
|
||||
word(s.s, cmnt.lines.(0));
|
||||
zerobreak(s.s);
|
||||
}
|
||||
|
||||
case (lexer::isolated) {
|
||||
hardbreak(s.s);
|
||||
ibox(s, 0u);
|
||||
for (str line in cmnt.lines) {
|
||||
word(s.s, line);
|
||||
hardbreak(s.s);
|
||||
}
|
||||
for (str line in cmnt.lines) { word(s.s, line); hardbreak(s.s); }
|
||||
end(s);
|
||||
}
|
||||
|
||||
case (lexer::trailing) {
|
||||
word(s.s, " ");
|
||||
if (vec::len(cmnt.lines) == 1u) {
|
||||
|
@ -356,23 +275,25 @@ fn print_comment(&ps s, lexer::cmnt cmnt) {
|
|||
}
|
||||
|
||||
fn print_string(&ps s, &str st) {
|
||||
word(s.s, "\""); word(s.s, escape_str(st, '"')); word(s.s, "\"");
|
||||
word(s.s, "\"");
|
||||
word(s.s, escape_str(st, '"'));
|
||||
word(s.s, "\"");
|
||||
}
|
||||
|
||||
|
||||
fn escape_str(str st, char to_escape) -> str {
|
||||
let str out = "";
|
||||
auto len = str::byte_len(st);
|
||||
auto i = 0u;
|
||||
while (i < len) {
|
||||
alt (st.(i) as char) {
|
||||
case ('\n') {out += "\\n";}
|
||||
case ('\t') {out += "\\t";}
|
||||
case ('\r') {out += "\\r";}
|
||||
case ('\\') {out += "\\\\";}
|
||||
case ('\n') { out += "\\n"; }
|
||||
case ('\t') { out += "\\t"; }
|
||||
case ('\r') { out += "\\r"; }
|
||||
case ('\\') { out += "\\\\"; }
|
||||
case (?cur) {
|
||||
if (cur == to_escape) {out += "\\";}
|
||||
if (cur == to_escape) { out += "\\"; }
|
||||
// FIXME some (or all?) non-ascii things should be escaped
|
||||
|
||||
str::push_char(out, cur);
|
||||
}
|
||||
}
|
||||
|
@ -381,7 +302,7 @@ fn escape_str(str st, char to_escape) -> str {
|
|||
ret out;
|
||||
}
|
||||
|
||||
fn to_str[T](&T t, fn(&ps s, &T s) f) -> str {
|
||||
fn to_str[T](&T t, fn(&ps, &T) f) -> str {
|
||||
auto writer = io::string_writer();
|
||||
auto s = rust_printer(writer.get_writer());
|
||||
f(s, t);
|
||||
|
@ -389,42 +310,35 @@ fn to_str[T](&T t, fn(&ps s, &T s) f) -> str {
|
|||
ret writer.get_str();
|
||||
}
|
||||
|
||||
|
||||
fn next_comment(&ps s) -> option::t[lexer::cmnt] {
|
||||
alt (s.comments) {
|
||||
case (some(?cmnts)) {
|
||||
if (s.cur_cmnt < vec::len(cmnts)) {
|
||||
ret some(cmnts.(s.cur_cmnt));
|
||||
} else {ret none[lexer::cmnt];}
|
||||
} else { ret none[lexer::cmnt]; }
|
||||
}
|
||||
case (_) {ret none[lexer::cmnt];}
|
||||
case (_) { ret none[lexer::cmnt]; }
|
||||
}
|
||||
}
|
||||
|
||||
type ps = @rec(pp::printer s,
|
||||
option::t[codemap] cm,
|
||||
option::t[vec[lexer::cmnt]] comments,
|
||||
option::t[vec[lexer::lit]] literals,
|
||||
mutable uint cur_cmnt,
|
||||
mutable uint cur_lit,
|
||||
mutable vec[pp::breaks] boxes,
|
||||
mode mode);
|
||||
type ps =
|
||||
@rec(pp::printer s,
|
||||
option::t[codemap] cm,
|
||||
option::t[vec[lexer::cmnt]] comments,
|
||||
option::t[vec[lexer::lit]] literals,
|
||||
mutable uint cur_cmnt,
|
||||
mutable uint cur_lit,
|
||||
mutable vec[pp::breaks] boxes,
|
||||
mode mode);
|
||||
|
||||
fn ibox(&ps s, uint u) {
|
||||
vec::push(s.boxes, pp::inconsistent);
|
||||
pp::ibox(s.s, u);
|
||||
}
|
||||
|
||||
fn end(&ps s) {
|
||||
vec::pop(s.boxes);
|
||||
pp::end(s.s);
|
||||
}
|
||||
fn end(&ps s) { vec::pop(s.boxes); pp::end(s.s); }
|
||||
|
||||
tag mode {
|
||||
mo_untyped;
|
||||
mo_typed(ctxt);
|
||||
mo_identified;
|
||||
}
|
||||
tag mode { mo_untyped; mo_typed(ctxt); mo_identified; }
|
||||
|
||||
fn rust_printer(io::writer writer) -> ps {
|
||||
let vec[pp::breaks] boxes = [];
|
||||
|
@ -439,36 +353,29 @@ fn rust_printer(io::writer writer) -> ps {
|
|||
}
|
||||
|
||||
const uint indent_unit = 4u;
|
||||
|
||||
const uint default_columns = 78u;
|
||||
|
||||
|
||||
// needed b/c constr_args_to_str needs
|
||||
// something that takes an alias
|
||||
// (argh)
|
||||
fn uint_to_str(&uint i) -> str {
|
||||
ret util::common::uistr(i);
|
||||
}
|
||||
fn uint_to_str(&uint i) -> str { ret util::common::uistr(i); }
|
||||
|
||||
fn constr_to_str(&@ast::constr c) -> str {
|
||||
ret path_to_str(c.node.path)
|
||||
+ constr_args_to_str(uint_to_str, c.node.args);
|
||||
ret path_to_str(c.node.path) +
|
||||
constr_args_to_str(uint_to_str, c.node.args);
|
||||
}
|
||||
|
||||
fn constrs_str(&vec[@ast::constr] constrs) -> str {
|
||||
auto s = "";
|
||||
auto colon = true;
|
||||
for (@ast::constr c in constrs) {
|
||||
if (colon) {
|
||||
s += " : ";
|
||||
colon = false;
|
||||
auto s = "";
|
||||
auto colon = true;
|
||||
for (@ast::constr c in constrs) {
|
||||
if (colon) { s += " : "; colon = false; } else { s += ", "; }
|
||||
s += constr_to_str(c);
|
||||
}
|
||||
else {
|
||||
s += ", ";
|
||||
}
|
||||
s += constr_to_str(c);
|
||||
}
|
||||
ret s;
|
||||
ret s;
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,3 +1,4 @@
|
|||
|
||||
import std::map;
|
||||
import std::map::hashmap;
|
||||
import std::uint;
|
||||
|
@ -12,7 +13,6 @@ import front::codemap::codemap;
|
|||
import front::ast::lit;
|
||||
import front::ast::path;
|
||||
import middle::walk;
|
||||
|
||||
import std::io::stdout;
|
||||
import std::io::str_writer;
|
||||
import std::io::string_writer;
|
||||
|
@ -28,8 +28,11 @@ import pretty::ppaux::mo_untyped;
|
|||
import pretty::pp::mk_printer;
|
||||
|
||||
type filename = str;
|
||||
|
||||
type span = rec(uint lo, uint hi);
|
||||
|
||||
type spanned[T] = rec(T node, span span);
|
||||
|
||||
type flag = hashmap[str, ()];
|
||||
|
||||
tag ty_mach {
|
||||
|
@ -37,20 +40,15 @@ tag ty_mach {
|
|||
ty_i16;
|
||||
ty_i32;
|
||||
ty_i64;
|
||||
|
||||
ty_u8;
|
||||
ty_u16;
|
||||
ty_u32;
|
||||
ty_u64;
|
||||
|
||||
ty_f32;
|
||||
ty_f64;
|
||||
}
|
||||
|
||||
tag ty_or_bang[T] {
|
||||
a_ty(T);
|
||||
a_bang;
|
||||
}
|
||||
tag ty_or_bang[T] { a_ty(T); a_bang; }
|
||||
|
||||
fn ty_mach_to_str(ty_mach tm) -> str {
|
||||
alt (tm) {
|
||||
|
@ -58,21 +56,19 @@ fn ty_mach_to_str(ty_mach tm) -> str {
|
|||
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"; }
|
||||
}
|
||||
}
|
||||
|
||||
fn new_str_hash[V]() -> std::map::hashmap[str,V] {
|
||||
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);
|
||||
ret std::map::mk_hashmap[str, V](hasher, eqer);
|
||||
}
|
||||
|
||||
fn def_eq(&ast::def_id a, &ast::def_id b) -> bool {
|
||||
|
@ -81,40 +77,36 @@ fn def_eq(&ast::def_id a, &ast::def_id b) -> bool {
|
|||
|
||||
fn hash_def(&ast::def_id d) -> uint {
|
||||
auto h = 5381u;
|
||||
h = ((h << 5u) + h) ^ (d._0 as uint);
|
||||
h = ((h << 5u) + h) ^ (d._1 as uint);
|
||||
h = (h << 5u) + h ^ (d._0 as uint);
|
||||
h = (h << 5u) + h ^ (d._1 as uint);
|
||||
ret h;
|
||||
}
|
||||
|
||||
fn new_def_hash[V]() -> std::map::hashmap[ast::def_id,V] {
|
||||
fn new_def_hash[V]() -> std::map::hashmap[ast::def_id, V] {
|
||||
let std::map::hashfn[ast::def_id] hasher = hash_def;
|
||||
let std::map::eqfn[ast::def_id] eqer = def_eq;
|
||||
ret std::map::mk_hashmap[ast::def_id,V](hasher, eqer);
|
||||
ret std::map::mk_hashmap[ast::def_id, V](hasher, eqer);
|
||||
}
|
||||
|
||||
fn new_int_hash[V]() -> std::map::hashmap[int,V] {
|
||||
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);
|
||||
ret std::map::mk_hashmap[int, V](hasher, eqer);
|
||||
}
|
||||
|
||||
fn new_uint_hash[V]() -> std::map::hashmap[uint,V] {
|
||||
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);
|
||||
ret std::map::mk_hashmap[uint, V](hasher, eqer);
|
||||
}
|
||||
|
||||
fn istr(int i) -> str {
|
||||
ret int::to_str(i, 10u);
|
||||
}
|
||||
fn istr(int i) -> str { ret int::to_str(i, 10u); }
|
||||
|
||||
fn uistr(uint i) -> str {
|
||||
ret uint::to_str(i, 10u);
|
||||
}
|
||||
fn uistr(uint i) -> str { ret uint::to_str(i, 10u); }
|
||||
|
||||
fn elt_expr(&ast::elt e) -> @ast::expr { ret e.expr; }
|
||||
|
||||
|
@ -125,82 +117,51 @@ fn elt_exprs(&vec[ast::elt] elts) -> vec[@ast::expr] {
|
|||
|
||||
fn field_expr(&ast::field f) -> @ast::expr { ret f.node.expr; }
|
||||
|
||||
fn field_exprs(vec[ast::field] fields) -> vec [@ast::expr] {
|
||||
fn field_exprs(vec[ast::field] fields) -> vec[@ast::expr] {
|
||||
auto f = field_expr;
|
||||
ret vec::map[ast::field, @ast::expr](f, fields);
|
||||
}
|
||||
|
||||
fn log_expr(&ast::expr e) -> () {
|
||||
log(pretty::pprust::expr_to_str(@e));
|
||||
fn log_expr(&ast::expr e) { log pretty::pprust::expr_to_str(@e); }
|
||||
|
||||
fn log_expr_err(&ast::expr e) { log_err pretty::pprust::expr_to_str(@e); }
|
||||
|
||||
fn log_ty_err(&ty t) { log_err pretty::pprust::ty_to_str(t); }
|
||||
|
||||
fn log_pat_err(&@pat p) { log_err pretty::pprust::pat_to_str(p); }
|
||||
|
||||
fn log_block(&ast::block b) { log pretty::pprust::block_to_str(b); }
|
||||
|
||||
fn log_block_err(&ast::block b) { log_err pretty::pprust::block_to_str(b); }
|
||||
|
||||
fn log_item_err(&@ast::item i) { log_err pretty::pprust::item_to_str(i); }
|
||||
|
||||
fn log_fn(&ast::_fn f, str name, vec[ast::ty_param] params) {
|
||||
log pretty::pprust::fun_to_str(f, name, params);
|
||||
}
|
||||
|
||||
fn log_expr_err(&ast::expr e) -> () {
|
||||
log_err(pretty::pprust::expr_to_str(@e));
|
||||
fn log_fn_err(&ast::_fn f, str name, vec[ast::ty_param] params) {
|
||||
log_err pretty::pprust::fun_to_str(f, name, params);
|
||||
}
|
||||
|
||||
fn log_ty_err(&ty t) -> () {
|
||||
log_err(pretty::pprust::ty_to_str(t));
|
||||
}
|
||||
fn log_stmt(&ast::stmt st) { log pretty::pprust::stmt_to_str(st); }
|
||||
|
||||
fn log_pat_err(&@pat p) -> () {
|
||||
log_err(pretty::pprust::pat_to_str(p));
|
||||
}
|
||||
|
||||
fn log_block(&ast::block b) -> () {
|
||||
log(pretty::pprust::block_to_str(b));
|
||||
}
|
||||
|
||||
fn log_block_err(&ast::block b) -> () {
|
||||
log_err(pretty::pprust::block_to_str(b));
|
||||
}
|
||||
|
||||
fn log_item_err(&@ast::item i) -> () {
|
||||
log_err(pretty::pprust::item_to_str(i));
|
||||
}
|
||||
|
||||
fn log_fn(&ast::_fn f, str name, vec[ast::ty_param] params) -> () {
|
||||
log(pretty::pprust::fun_to_str(f, name, params));
|
||||
}
|
||||
|
||||
fn log_fn_err(&ast::_fn f, str name, vec[ast::ty_param] params) -> () {
|
||||
log_err(pretty::pprust::fun_to_str(f, name, params));
|
||||
}
|
||||
|
||||
fn log_stmt(&ast::stmt st) -> () {
|
||||
log(pretty::pprust::stmt_to_str(st));
|
||||
}
|
||||
|
||||
fn log_stmt_err(&ast::stmt st) -> () {
|
||||
log_err(pretty::pprust::stmt_to_str(st));
|
||||
}
|
||||
fn log_stmt_err(&ast::stmt st) { log_err pretty::pprust::stmt_to_str(st); }
|
||||
|
||||
fn decl_lhs(@ast::decl d) -> ast::def_id {
|
||||
alt (d.node) {
|
||||
case (ast::decl_local(?l)) {
|
||||
ret l.id;
|
||||
}
|
||||
case (ast::decl_local(?l)) { ret l.id; }
|
||||
case (ast::decl_item(?an_item)) {
|
||||
alt (an_item.node) {
|
||||
case (ast::item_const(_,_,_,_,?d,_)) {
|
||||
ret d;
|
||||
}
|
||||
case (ast::item_fn(_,_,_,_,?d,_)) {
|
||||
ret d;
|
||||
}
|
||||
case (ast::item_mod(_,_,_,?d)) {
|
||||
ret d;
|
||||
}
|
||||
case (ast::item_native_mod(_,_,_,?d)) {
|
||||
ret d;
|
||||
}
|
||||
case (ast::item_ty(_,_,_,_,?d,_)) {
|
||||
ret d;
|
||||
}
|
||||
case (ast::item_tag(_,_,_,_,?d,_)) {
|
||||
ret d;
|
||||
}
|
||||
case (ast::item_obj(_,_,_,_,?d,_)) {
|
||||
case (ast::item_const(_, _, _, _, ?d, _)) { ret d; }
|
||||
case (ast::item_fn(_, _, _, _, ?d, _)) { ret d; }
|
||||
case (ast::item_mod(_, _, _, ?d)) { ret d; }
|
||||
case (ast::item_native_mod(_, _, _, ?d)) { ret d; }
|
||||
case (ast::item_ty(_, _, _, _, ?d, _)) { ret d; }
|
||||
case (ast::item_tag(_, _, _, _, ?d, _)) { ret d; }
|
||||
case (ast::item_obj(_, _, _, _, ?d, _)) {
|
||||
ret d.ctor; /* This doesn't really make sense */
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -208,18 +169,17 @@ fn decl_lhs(@ast::decl d) -> ast::def_id {
|
|||
}
|
||||
|
||||
fn has_nonlocal_exits(&ast::block b) -> bool {
|
||||
auto has_exits = @mutable false;
|
||||
|
||||
fn visit_expr(@mutable bool flag, &@ast::expr e) {
|
||||
alt (e.node) {
|
||||
case (ast::expr_break(_)) { *flag = true; }
|
||||
case (ast::expr_cont(_)) { *flag = true; }
|
||||
case (_) { }
|
||||
}
|
||||
}
|
||||
|
||||
auto v = rec(visit_expr_pre=bind visit_expr(has_exits, _)
|
||||
with walk::default_visitor());
|
||||
auto has_exits = @mutable false;
|
||||
fn visit_expr(@mutable bool flag, &@ast::expr e) {
|
||||
alt (e.node) {
|
||||
case (ast::expr_break(_)) { *flag = true; }
|
||||
case (ast::expr_cont(_)) { *flag = true; }
|
||||
case (_) { }
|
||||
}
|
||||
}
|
||||
auto v =
|
||||
rec(visit_expr_pre=bind visit_expr(has_exits, _)
|
||||
with walk::default_visitor());
|
||||
walk::walk_block(v, b);
|
||||
ret *has_exits;
|
||||
}
|
||||
|
@ -233,100 +193,85 @@ fn local_rhs_span(&@ast::local_ l, &span def) -> span {
|
|||
|
||||
fn lit_eq(&@ast::lit l, &@ast::lit m) -> bool {
|
||||
alt (l.node) {
|
||||
case (ast::lit_str(?s,?kind_s)) {
|
||||
case (ast::lit_str(?s, ?kind_s)) {
|
||||
alt (m.node) {
|
||||
case (ast::lit_str(?t,?kind_t)) {
|
||||
case (ast::lit_str(?t, ?kind_t)) {
|
||||
ret s == t && kind_s == kind_t;
|
||||
}
|
||||
case (_) { ret false; }
|
||||
case (_) { ret false; }
|
||||
}
|
||||
}
|
||||
case (ast::lit_char(?c)) {
|
||||
alt (m.node) {
|
||||
case (ast::lit_char(?d)) { ret c == d; }
|
||||
case (_) { ret false; }
|
||||
case (_) { ret false; }
|
||||
}
|
||||
}
|
||||
case (ast::lit_int(?i)) {
|
||||
alt (m.node) {
|
||||
case (ast::lit_int(?j)) { ret i == j; }
|
||||
case (_) { ret false; }
|
||||
case (_) { ret false; }
|
||||
}
|
||||
}
|
||||
case (ast::lit_uint(?i)) {
|
||||
alt (m.node) {
|
||||
case (ast::lit_uint(?j)) { ret i == j; }
|
||||
case (_) { ret false; }
|
||||
case (_) { ret false; }
|
||||
}
|
||||
}
|
||||
case (ast::lit_mach_int(_, ?i)) {
|
||||
alt (m.node) {
|
||||
case (ast::lit_mach_int(_, ?j)) { ret i == j; }
|
||||
case (_) { ret false; }
|
||||
case (_) { ret false; }
|
||||
}
|
||||
}
|
||||
case (ast::lit_float(?s)) {
|
||||
alt (m.node) {
|
||||
case (ast::lit_float(?t)) { ret s == t; }
|
||||
case (_) { ret false; }
|
||||
case (_) { ret false; }
|
||||
}
|
||||
}
|
||||
case (ast::lit_mach_float(_,?s)) {
|
||||
case (ast::lit_mach_float(_, ?s)) {
|
||||
alt (m.node) {
|
||||
case (ast::lit_mach_float(_,?t)) { ret s == t; }
|
||||
case (_) { ret false; }
|
||||
case (ast::lit_mach_float(_, ?t)) { ret s == t; }
|
||||
case (_) { ret false; }
|
||||
}
|
||||
}
|
||||
case (ast::lit_nil) {
|
||||
alt (m.node) {
|
||||
case (ast::lit_nil) { ret true; }
|
||||
case (_) { ret false; }
|
||||
case (_) { ret false; }
|
||||
}
|
||||
}
|
||||
case (ast::lit_bool(?b)) {
|
||||
alt (m.node) {
|
||||
case (ast::lit_bool(?c)) { ret b == c; }
|
||||
case (_) { ret false; }
|
||||
case (_) { ret false; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn respan[T](&span sp, &T t) -> spanned[T] {
|
||||
ret rec(node=t, span=sp);
|
||||
}
|
||||
fn respan[T](&span sp, &T t) -> spanned[T] { ret rec(node=t, span=sp); }
|
||||
|
||||
fn may_begin_ident(char c) -> bool {
|
||||
ret (is_alpha(c) || c == '_');
|
||||
}
|
||||
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 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');
|
||||
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_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_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';
|
||||
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'; }
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
|
||||
|
||||
// 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;
|
||||
|
@ -12,19 +13,17 @@ import std::option::none;
|
|||
import std::option::some;
|
||||
|
||||
mod interner {
|
||||
type interner[T] = rec(
|
||||
hashmap[T,uint] map,
|
||||
mutable vec[T] vect,
|
||||
hashfn[T] hasher,
|
||||
eqfn[T] eqer
|
||||
);
|
||||
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);
|
||||
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; }
|
||||
|
@ -36,9 +35,5 @@ mod interner {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get[T](&interner[T] itr, uint idx) -> T {
|
||||
ret itr.vect.(idx);
|
||||
}
|
||||
fn get[T](&interner[T] itr, uint idx) -> T { ret itr.vect.(idx); }
|
||||
}
|
||||
|
||||
|
|
114
src/lib/bitv.rs
114
src/lib/bitv.rs
|
@ -1,3 +1,4 @@
|
|||
|
||||
export t;
|
||||
export create;
|
||||
export union;
|
||||
|
@ -17,6 +18,7 @@ export to_vec;
|
|||
export to_str;
|
||||
export eq_vec;
|
||||
|
||||
|
||||
// FIXME: With recursive object types, we could implement binary methods like
|
||||
// union, intersection, and difference. At that point, we could write
|
||||
// an optimizing version of this module that produces a different obj
|
||||
|
@ -24,98 +26,71 @@ export eq_vec;
|
|||
|
||||
// FIXME: Almost all the functions in this module should be state fns, but the
|
||||
// effect system isn't currently working correctly.
|
||||
state type t = rec(vec[mutable uint] storage, uint nbits);
|
||||
type t = rec(vec[mutable uint] storage, uint nbits);
|
||||
|
||||
|
||||
// FIXME: this should be a constant once they work
|
||||
fn uint_bits() -> uint {
|
||||
ret 32u + ((1u << 32u) >> 27u);
|
||||
}
|
||||
fn uint_bits() -> uint { ret 32u + (1u << 32u >> 27u); }
|
||||
|
||||
fn create(uint nbits, bool init) -> t {
|
||||
auto elt = if (init) { !0u } else { 0u };
|
||||
|
||||
auto storage = vec::init_elt_mut[uint](elt, nbits / uint_bits() + 1u);
|
||||
ret rec(storage = storage, nbits = nbits);
|
||||
ret rec(storage=storage, nbits=nbits);
|
||||
}
|
||||
|
||||
fn process(&fn(uint, uint) -> uint op, &t v0, &t v1) -> bool {
|
||||
fn process(&fn(uint, uint) -> uint op, &t v0, &t v1) -> bool {
|
||||
auto len = vec::len(v1.storage);
|
||||
|
||||
assert (vec::len(v0.storage) == len);
|
||||
assert (v0.nbits == v1.nbits);
|
||||
|
||||
auto changed = false;
|
||||
|
||||
for each (uint i in uint::range(0u, len)) {
|
||||
auto w0 = v0.storage.(i);
|
||||
auto w1 = v1.storage.(i);
|
||||
|
||||
auto w = op(w0, w1);
|
||||
if (w0 != w) {
|
||||
changed = true;
|
||||
v0.storage.(i) = w;
|
||||
}
|
||||
if (w0 != w) { changed = true; v0.storage.(i) = w; }
|
||||
}
|
||||
|
||||
ret changed;
|
||||
}
|
||||
|
||||
fn lor(uint w0, uint w1) -> uint {
|
||||
ret w0 | w1;
|
||||
}
|
||||
fn lor(uint w0, uint w1) -> uint { ret w0 | w1; }
|
||||
|
||||
fn union(&t v0, &t v1) -> bool {
|
||||
auto sub = lor;
|
||||
ret process(sub, v0, v1);
|
||||
}
|
||||
fn union(&t v0, &t v1) -> bool { auto sub = lor; ret process(sub, v0, v1); }
|
||||
|
||||
fn land(uint w0, uint w1) -> uint {
|
||||
ret w0 & w1;
|
||||
}
|
||||
fn land(uint w0, uint w1) -> uint { ret w0 & w1; }
|
||||
|
||||
fn intersect(&t v0, &t v1) -> bool {
|
||||
auto sub = land;
|
||||
ret process(sub, v0, v1);
|
||||
}
|
||||
|
||||
fn right(uint w0, uint w1) -> uint {
|
||||
ret w1;
|
||||
}
|
||||
fn right(uint w0, uint w1) -> uint { ret w1; }
|
||||
|
||||
fn copy(&t v0, t v1) -> bool {
|
||||
auto sub = right;
|
||||
ret process(sub, v0, v1);
|
||||
}
|
||||
fn copy(&t v0, t v1) -> bool { auto sub = right; ret process(sub, v0, v1); }
|
||||
|
||||
fn clone(t v) -> t {
|
||||
auto storage = vec::init_elt_mut[uint](0u, v.nbits / uint_bits() + 1u);
|
||||
auto len = vec::len(v.storage);
|
||||
for each (uint i in uint::range(0u, len)) {
|
||||
storage.(i) = v.storage.(i);
|
||||
}
|
||||
ret rec(storage = storage, nbits = v.nbits);
|
||||
for each (uint i in uint::range(0u, len)) { storage.(i) = v.storage.(i); }
|
||||
ret rec(storage=storage, nbits=v.nbits);
|
||||
}
|
||||
|
||||
fn get(&t v, uint i) -> bool {
|
||||
assert (i < v.nbits);
|
||||
|
||||
auto bits = uint_bits();
|
||||
|
||||
auto w = i / bits;
|
||||
auto b = i % bits;
|
||||
auto x = 1u & (v.storage.(w) >> b);
|
||||
auto x = 1u & v.storage.(w) >> b;
|
||||
ret x == 1u;
|
||||
}
|
||||
|
||||
fn equal(&t v0, &t v1) -> bool {
|
||||
// FIXME: when we can break or return from inside an iterator loop,
|
||||
// we can eliminate this painful while-loop
|
||||
|
||||
auto len = vec::len(v1.storage);
|
||||
auto i = 0u;
|
||||
while (i < len) {
|
||||
if (v0.storage.(i) != v1.storage.(i)) {
|
||||
ret false;
|
||||
}
|
||||
if (v0.storage.(i) != v1.storage.(i)) { ret false; }
|
||||
i = i + 1u;
|
||||
}
|
||||
ret true;
|
||||
|
@ -128,9 +103,7 @@ fn clear(&t v) {
|
|||
}
|
||||
|
||||
fn set_all(&t v) {
|
||||
for each (uint i in uint::range(0u, v.nbits)) {
|
||||
set(v, i, true);
|
||||
}
|
||||
for each (uint i in uint::range(0u, v.nbits)) { set(v, i, true); }
|
||||
}
|
||||
|
||||
fn invert(&t v) {
|
||||
|
@ -139,6 +112,7 @@ fn invert(&t v) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* v0 = v0 - v1 */
|
||||
fn difference(&t v0, &t v1) -> bool {
|
||||
invert(v1);
|
||||
|
@ -149,49 +123,30 @@ fn difference(&t v0, &t v1) -> bool {
|
|||
|
||||
fn set(&t v, uint i, bool x) {
|
||||
assert (i < v.nbits);
|
||||
|
||||
auto bits = uint_bits();
|
||||
|
||||
auto w = i / bits;
|
||||
auto b = i % bits;
|
||||
auto w0 = v.storage.(w);
|
||||
auto flag = 1u << b;
|
||||
v.storage.(w) = if (x) {
|
||||
v.storage.(w) | flag
|
||||
} else {
|
||||
v.storage.(w) & !flag
|
||||
};
|
||||
v.storage.(w) =
|
||||
if (x) { v.storage.(w) | flag } else { v.storage.(w) & !flag };
|
||||
}
|
||||
|
||||
|
||||
/* true if all bits are 1 */
|
||||
fn is_true(&t v) -> bool {
|
||||
for (uint i in to_vec(v)) {
|
||||
if (i != 1u) {
|
||||
ret false;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint i in to_vec(v)) { if (i != 1u) { ret false; } }
|
||||
ret true;
|
||||
}
|
||||
|
||||
|
||||
/* true if all bits are non-1 */
|
||||
fn is_false(&t v) -> bool {
|
||||
for (uint i in to_vec(v)) {
|
||||
if (i == 1u) {
|
||||
ret false;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint i in to_vec(v)) { if (i == 1u) { ret false; } }
|
||||
ret true;
|
||||
}
|
||||
|
||||
fn init_to_vec(t v, uint i) -> uint {
|
||||
ret if (get(v, i)) {
|
||||
1u
|
||||
} else {
|
||||
0u
|
||||
};
|
||||
}
|
||||
fn init_to_vec(t v, uint i) -> uint { ret if (get(v, i)) { 1u } else { 0u }; }
|
||||
|
||||
fn to_vec(&t v) -> vec[uint] {
|
||||
auto sub = bind init_to_vec(v, _);
|
||||
|
@ -200,19 +155,13 @@ fn to_vec(&t v) -> vec[uint] {
|
|||
|
||||
fn to_str(&t v) -> str {
|
||||
auto res = "";
|
||||
|
||||
for (uint i in bitv::to_vec(v)) {
|
||||
if (i == 1u) {
|
||||
res += "1";
|
||||
}
|
||||
else {
|
||||
res += "0";
|
||||
}
|
||||
if (i == 1u) { res += "1"; } else { res += "0"; }
|
||||
}
|
||||
|
||||
ret res;
|
||||
}
|
||||
|
||||
|
||||
// FIXME: can we just use structural equality on to_vec?
|
||||
fn eq_vec(&t v0, &vec[uint] v1) -> bool {
|
||||
assert (v0.nbits == vec::len[uint](v1));
|
||||
|
@ -221,14 +170,11 @@ fn eq_vec(&t v0, &vec[uint] v1) -> bool {
|
|||
while (i < len) {
|
||||
auto w0 = get(v0, i);
|
||||
auto w1 = v1.(i);
|
||||
if ((!w0 && w1 != 0u) || (w0 && w1 == 0u)) {
|
||||
ret false;
|
||||
}
|
||||
if (!w0 && w1 != 0u || w0 && w1 == 0u) { ret false; }
|
||||
i = i + 1u;
|
||||
}
|
||||
ret true;
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
export ptr_eq;
|
||||
|
||||
native "rust" mod rustrt {
|
||||
|
@ -5,4 +6,3 @@ native "rust" mod rustrt {
|
|||
}
|
||||
|
||||
fn ptr_eq[T](@T a, @T b) -> bool { ret rustrt::rust_ptr_eq[T](a, b) != 0; }
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
|
||||
|
||||
|
||||
/**
|
||||
* Unsafe debugging functions for inspecting values.
|
||||
*
|
||||
|
@ -19,25 +22,16 @@ native "rust" mod rustrt {
|
|||
fn debug_trap(str msg);
|
||||
}
|
||||
|
||||
fn debug_vec[T](vec[T] v) {
|
||||
vec::print_debug_info[T](v);
|
||||
}
|
||||
fn debug_vec[T](vec[T] v) { vec::print_debug_info[T](v); }
|
||||
|
||||
fn debug_tydesc[T]() {
|
||||
rustrt::debug_tydesc[T]();
|
||||
}
|
||||
fn debug_tydesc[T]() { rustrt::debug_tydesc[T](); }
|
||||
|
||||
fn debug_opaque[T](&T x) {
|
||||
rustrt::debug_opaque[T](x);
|
||||
}
|
||||
fn debug_opaque[T](&T x) { rustrt::debug_opaque[T](x); }
|
||||
|
||||
fn debug_box[T](@T x) {
|
||||
rustrt::debug_box[T](x);
|
||||
}
|
||||
fn debug_box[T](@T x) { rustrt::debug_box[T](x); }
|
||||
|
||||
fn debug_tag[T](&T x) { rustrt::debug_tag[T](x); }
|
||||
|
||||
fn debug_tag[T](&T x) {
|
||||
rustrt::debug_tag[T](x);
|
||||
}
|
||||
|
||||
/**
|
||||
* `nmethods` is the number of methods we expect the object to have. The
|
||||
|
@ -52,18 +46,11 @@ fn debug_obj[T](&T x, uint nmethods, uint nbytes) {
|
|||
rustrt::debug_obj[T](x, nmethods, nbytes);
|
||||
}
|
||||
|
||||
fn debug_fn[T](&T x) {
|
||||
rustrt::debug_fn[T](x);
|
||||
}
|
||||
fn debug_fn[T](&T x) { rustrt::debug_fn[T](x); }
|
||||
|
||||
fn ptr_cast[T, U](@T x) -> @U {
|
||||
ret rustrt::debug_ptrcast[T, U](x);
|
||||
}
|
||||
|
||||
fn trap(str s) {
|
||||
rustrt::debug_trap(s);
|
||||
}
|
||||
fn ptr_cast[T, U](@T x) -> @U { ret rustrt::debug_ptrcast[T, U](x); }
|
||||
|
||||
fn trap(str s) { rustrt::debug_trap(s); }
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
|
|
192
src/lib/deque.rs
192
src/lib/deque.rs
|
@ -1,142 +1,112 @@
|
|||
|
||||
|
||||
|
||||
/**
|
||||
* A deque, for fun. Untested as of yet. Likely buggy.
|
||||
*/
|
||||
|
||||
type t[T] = obj {
|
||||
fn size() -> uint;
|
||||
|
||||
fn add_front(&T t);
|
||||
fn add_back(&T t);
|
||||
|
||||
fn pop_front() -> T;
|
||||
fn pop_back() -> T;
|
||||
|
||||
fn peek_front() -> T;
|
||||
fn peek_back() -> T;
|
||||
|
||||
fn get(int i) -> T;
|
||||
};
|
||||
type t[T] =
|
||||
obj {
|
||||
fn size() -> uint ;
|
||||
fn add_front(&T) ;
|
||||
fn add_back(&T) ;
|
||||
fn pop_front() -> T ;
|
||||
fn pop_back() -> T ;
|
||||
fn peek_front() -> T ;
|
||||
fn peek_back() -> T ;
|
||||
fn get(int) -> T ;
|
||||
};
|
||||
|
||||
fn create[T]() -> t[T] {
|
||||
|
||||
type cell[T] = option::t[T];
|
||||
|
||||
let uint initial_capacity = 32u; // 2^5
|
||||
/**
|
||||
* Grow is only called on full elts, so nelts is also len(elts), unlike
|
||||
* elsewhere.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Grow is only called on full elts, so nelts is also len(elts), unlike
|
||||
* elsewhere.
|
||||
*/
|
||||
fn grow[T](uint nelts, uint lo, vec[mutable cell[T]] elts)
|
||||
-> vec[mutable cell[T]] {
|
||||
fn grow[T](uint nelts, uint lo, vec[mutable cell[T]] elts) ->
|
||||
vec[mutable cell[T]] {
|
||||
assert (nelts == vec::len(elts));
|
||||
|
||||
// FIXME: Making the vector argument an alias is a workaround for
|
||||
// issue #375
|
||||
fn fill[T](uint i, uint nelts, uint lo,
|
||||
&vec[mutable cell[T]] old) -> cell[T] {
|
||||
ret if (i < nelts) {
|
||||
old.((lo + i) % nelts)
|
||||
} else {
|
||||
option::none
|
||||
};
|
||||
}
|
||||
|
||||
fn fill[T](uint i, uint nelts, uint lo, &vec[mutable cell[T]] old) ->
|
||||
cell[T] {
|
||||
ret if (i < nelts) {
|
||||
old.((lo + i) % nelts)
|
||||
} else { option::none };
|
||||
}
|
||||
let uint nalloc = uint::next_power_of_two(nelts + 1u);
|
||||
let vec::init_op[cell[T]] copy_op = bind fill[T](_, nelts, lo, elts);
|
||||
ret vec::init_fn_mut[cell[T]](copy_op, nalloc);
|
||||
}
|
||||
|
||||
fn get[T](vec[mutable cell[T]] elts, uint i) -> T {
|
||||
ret alt (elts.(i)) {
|
||||
case (option::some(?t)) { t }
|
||||
case (_) { fail }
|
||||
};
|
||||
case (option::some(?t)) { t }
|
||||
case (_) { fail }
|
||||
};
|
||||
}
|
||||
|
||||
obj deque[T](mutable uint nelts,
|
||||
mutable uint lo,
|
||||
mutable uint hi,
|
||||
mutable vec[mutable cell[T]] elts)
|
||||
{
|
||||
fn size() -> uint { ret nelts; }
|
||||
|
||||
fn add_front(&T t) {
|
||||
let uint oldlo = lo;
|
||||
|
||||
if (lo == 0u) {
|
||||
lo = vec::len[cell[T]](elts) - 1u;
|
||||
} else {
|
||||
lo -= 1u;
|
||||
}
|
||||
|
||||
if (lo == hi) {
|
||||
elts = grow[T](nelts, oldlo, elts);
|
||||
lo = vec::len[cell[T]](elts) - 1u;
|
||||
hi = nelts;
|
||||
}
|
||||
|
||||
elts.(lo) = option::some[T](t);
|
||||
nelts += 1u;
|
||||
mutable vec[mutable cell[T]] elts) {
|
||||
fn size() -> uint { ret nelts; }
|
||||
fn add_front(&T t) {
|
||||
let uint oldlo = lo;
|
||||
if (lo == 0u) {
|
||||
lo = vec::len[cell[T]](elts) - 1u;
|
||||
} else { lo -= 1u; }
|
||||
if (lo == hi) {
|
||||
elts = grow[T](nelts, oldlo, elts);
|
||||
lo = vec::len[cell[T]](elts) - 1u;
|
||||
hi = nelts;
|
||||
}
|
||||
|
||||
fn add_back(&T t) {
|
||||
if (lo == hi && nelts != 0u) {
|
||||
elts = grow[T](nelts, lo, elts);
|
||||
lo = 0u;
|
||||
hi = nelts;
|
||||
}
|
||||
|
||||
elts.(hi) = option::some[T](t);
|
||||
hi = (hi + 1u) % vec::len[cell[T]](elts);
|
||||
nelts += 1u;
|
||||
}
|
||||
|
||||
/**
|
||||
* We actually release (turn to none()) the T we're popping so
|
||||
* that we don't keep anyone's refcount up unexpectedly.
|
||||
*/
|
||||
fn pop_front() -> T {
|
||||
let T t = get[T](elts, lo);
|
||||
elts.(lo) = option::none[T];
|
||||
lo = (lo + 1u) % vec::len[cell[T]](elts);
|
||||
nelts -= 1u;
|
||||
ret t;
|
||||
}
|
||||
|
||||
fn pop_back() -> T {
|
||||
if (hi == 0u) {
|
||||
hi = vec::len[cell[T]](elts) - 1u;
|
||||
} else {
|
||||
hi -= 1u;
|
||||
}
|
||||
|
||||
let T t = get[T](elts, hi);
|
||||
elts.(hi) = option::none[T];
|
||||
nelts -= 1u;
|
||||
ret t;
|
||||
}
|
||||
|
||||
fn peek_front() -> T {
|
||||
ret get[T](elts, lo);
|
||||
}
|
||||
|
||||
fn peek_back() -> T {
|
||||
ret get[T](elts, hi - 1u);
|
||||
}
|
||||
|
||||
fn get(int i) -> T {
|
||||
let uint idx = (lo + (i as uint)) % vec::len[cell[T]](elts);
|
||||
ret get[T](elts, idx);
|
||||
}
|
||||
|
||||
elts.(lo) = option::some[T](t);
|
||||
nelts += 1u;
|
||||
}
|
||||
fn add_back(&T t) {
|
||||
if (lo == hi && nelts != 0u) {
|
||||
elts = grow[T](nelts, lo, elts);
|
||||
lo = 0u;
|
||||
hi = nelts;
|
||||
}
|
||||
elts.(hi) = option::some[T](t);
|
||||
hi = (hi + 1u) % vec::len[cell[T]](elts);
|
||||
nelts += 1u;
|
||||
}
|
||||
let vec[mutable cell[T]] v = vec::init_elt_mut(option::none,
|
||||
initial_capacity);
|
||||
|
||||
/**
|
||||
* We actually release (turn to none()) the T we're popping so
|
||||
* that we don't keep anyone's refcount up unexpectedly.
|
||||
*/
|
||||
fn pop_front() -> T {
|
||||
let T t = get[T](elts, lo);
|
||||
elts.(lo) = option::none[T];
|
||||
lo = (lo + 1u) % vec::len[cell[T]](elts);
|
||||
nelts -= 1u;
|
||||
ret t;
|
||||
}
|
||||
fn pop_back() -> T {
|
||||
if (hi == 0u) {
|
||||
hi = vec::len[cell[T]](elts) - 1u;
|
||||
} else { hi -= 1u; }
|
||||
let T t = get[T](elts, hi);
|
||||
elts.(hi) = option::none[T];
|
||||
nelts -= 1u;
|
||||
ret t;
|
||||
}
|
||||
fn peek_front() -> T { ret get[T](elts, lo); }
|
||||
fn peek_back() -> T { ret get[T](elts, hi - 1u); }
|
||||
fn get(int i) -> T {
|
||||
let uint idx = (lo + (i as uint)) % vec::len[cell[T]](elts);
|
||||
ret get[T](elts, idx);
|
||||
}
|
||||
}
|
||||
let vec[mutable cell[T]] v =
|
||||
vec::init_elt_mut(option::none, initial_capacity);
|
||||
ret deque[T](0u, 0u, 0u, v);
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
|
|
|
@ -1,40 +1,38 @@
|
|||
|
||||
|
||||
// Simple Extensible Binary Markup Language (ebml) reader and writer on a
|
||||
// cursor model. See the specification here:
|
||||
// http://www.matroska.org/technical/specs/rfc/index.html
|
||||
|
||||
import option::none;
|
||||
import option::some;
|
||||
|
||||
type ebml_tag = rec(uint id, uint size);
|
||||
|
||||
type ebml_state = rec(ebml_tag ebml_tag, uint tag_pos, uint data_pos);
|
||||
|
||||
|
||||
// TODO: When we have module renaming, make "reader" and "writer" separate
|
||||
// modules within this file.
|
||||
|
||||
// ebml reading
|
||||
|
||||
type doc = rec(vec[u8] data,
|
||||
uint start,
|
||||
uint end);
|
||||
type doc = rec(vec[u8] data, uint start, uint end);
|
||||
|
||||
fn vint_at(vec[u8] data, uint start) -> tup(uint, uint) {
|
||||
auto a = data.(start);
|
||||
if (a & 0x80u8 != 0u8) { ret tup((a & 0x7fu8) as uint, start + 1u); }
|
||||
if (a & 0x80u8 != 0u8) { ret tup(a & 0x7fu8 as uint, start + 1u); }
|
||||
if (a & 0x40u8 != 0u8) {
|
||||
ret tup((((a & 0x3fu8) as uint) << 8u) | (data.(start + 1u) as uint),
|
||||
ret tup((a & 0x3fu8 as uint) << 8u | (data.(start + 1u) as uint),
|
||||
start + 2u);
|
||||
} else if (a & 0x20u8 != 0u8) {
|
||||
ret tup((((a & 0x1fu8) as uint) << 16u) |
|
||||
((data.(start + 1u) as uint) << 8u) |
|
||||
(data.(start + 2u) as uint), start + 3u);
|
||||
ret tup((a & 0x1fu8 as uint) << 16u |
|
||||
(data.(start + 1u) as uint) << 8u |
|
||||
(data.(start + 2u) as uint), start + 3u);
|
||||
} else if (a & 0x10u8 != 0u8) {
|
||||
ret tup((((a & 0x0fu8) as uint) << 24u) |
|
||||
((data.(start + 1u) as uint) << 16u) |
|
||||
((data.(start + 2u) as uint) << 8u) |
|
||||
(data.(start + 3u) as uint), start + 4u);
|
||||
} else {
|
||||
log_err "vint too big"; fail;
|
||||
}
|
||||
ret tup((a & 0x0fu8 as uint) << 24u |
|
||||
(data.(start + 1u) as uint) << 16u |
|
||||
(data.(start + 2u) as uint) << 8u |
|
||||
(data.(start + 3u) as uint), start + 4u);
|
||||
} else { log_err "vint too big"; fail; }
|
||||
}
|
||||
|
||||
fn new_doc(vec[u8] data) -> doc {
|
||||
|
@ -63,7 +61,7 @@ fn maybe_get_doc(doc d, uint tg) -> option::t[doc] {
|
|||
|
||||
fn get_doc(doc d, uint tg) -> doc {
|
||||
alt (maybe_get_doc(d, tg)) {
|
||||
case (some(?d)) {ret d;}
|
||||
case (some(?d)) { ret d; }
|
||||
case (none) {
|
||||
log_err "failed to find block with tag " + uint::to_str(tg, 10u);
|
||||
fail;
|
||||
|
@ -93,9 +91,7 @@ iter tagged_docs(doc d, uint tg) -> doc {
|
|||
}
|
||||
}
|
||||
|
||||
fn doc_data(doc d) -> vec[u8] {
|
||||
ret vec::slice[u8](d.data, d.start, d.end);
|
||||
}
|
||||
fn doc_data(doc d) -> vec[u8] { ret vec::slice[u8](d.data, d.start, d.end); }
|
||||
|
||||
fn be_uint_from_bytes(vec[u8] data, uint start, uint size) -> uint {
|
||||
auto sz = size;
|
||||
|
@ -104,7 +100,7 @@ fn be_uint_from_bytes(vec[u8] data, uint start, uint size) -> uint {
|
|||
auto pos = start;
|
||||
while (sz > 0u) {
|
||||
sz -= 1u;
|
||||
val += (data.(pos) as uint) << (sz * 8u);
|
||||
val += (data.(pos) as uint) << sz * 8u;
|
||||
pos += 1u;
|
||||
}
|
||||
ret val;
|
||||
|
@ -114,45 +110,35 @@ fn doc_as_uint(doc d) -> uint {
|
|||
ret be_uint_from_bytes(d.data, d.start, d.end - d.start);
|
||||
}
|
||||
|
||||
// ebml writing
|
||||
|
||||
// ebml writing
|
||||
type writer = rec(io::buf_writer writer, mutable vec[uint] size_positions);
|
||||
|
||||
fn write_sized_vint(&io::buf_writer w, uint n, uint size) {
|
||||
let vec[u8] buf;
|
||||
alt (size) {
|
||||
case (1u) {
|
||||
buf = [0x80u8 | (n as u8)];
|
||||
}
|
||||
case (2u) {
|
||||
buf = [0x40u8 | ((n >> 8u) as u8),
|
||||
(n & 0xffu) as u8];
|
||||
}
|
||||
case (1u) { buf = [0x80u8 | (n as u8)]; }
|
||||
case (2u) { buf = [0x40u8 | (n >> 8u as u8), n & 0xffu as u8]; }
|
||||
case (3u) {
|
||||
buf = [0x20u8 | ((n >> 16u) as u8),
|
||||
((n >> 8u) & 0xffu) as u8,
|
||||
(n & 0xffu) as u8];
|
||||
buf =
|
||||
[0x20u8 | (n >> 16u as u8), n >> 8u & 0xffu as u8,
|
||||
n & 0xffu as u8];
|
||||
}
|
||||
case (4u) {
|
||||
buf = [0x10u8 | ((n >> 24u) as u8),
|
||||
((n >> 16u) & 0xffu) as u8,
|
||||
((n >> 8u) & 0xffu) as u8,
|
||||
(n & 0xffu) as u8];
|
||||
}
|
||||
case (_) {
|
||||
log_err "vint to write too big";
|
||||
fail;
|
||||
buf =
|
||||
[0x10u8 | (n >> 24u as u8), n >> 16u & 0xffu as u8,
|
||||
n >> 8u & 0xffu as u8, n & 0xffu as u8];
|
||||
}
|
||||
case (_) { log_err "vint to write too big"; fail; }
|
||||
}
|
||||
|
||||
w.write(buf);
|
||||
}
|
||||
|
||||
fn write_vint(&io::buf_writer w, uint n) {
|
||||
if (n < 0x7fu) { write_sized_vint(w, n, 1u); ret; }
|
||||
if (n < 0x4000u) { write_sized_vint(w, n, 2u); ret; }
|
||||
if (n < 0x200000u) { write_sized_vint(w, n, 3u); ret; }
|
||||
if (n < 0x10000000u) { write_sized_vint(w, n, 4u); ret; }
|
||||
if (n < 0x7fu) { write_sized_vint(w, n, 1u); ret; }
|
||||
if (n < 0x4000u) { write_sized_vint(w, n, 2u); ret; }
|
||||
if (n < 0x200000u) { write_sized_vint(w, n, 3u); ret; }
|
||||
if (n < 0x10000000u) { write_sized_vint(w, n, 4u); ret; }
|
||||
log_err "vint to write too big";
|
||||
fail;
|
||||
}
|
||||
|
@ -162,13 +148,14 @@ fn create_writer(&io::buf_writer w) -> writer {
|
|||
ret rec(writer=w, mutable size_positions=size_positions);
|
||||
}
|
||||
|
||||
// TODO: Provide a function to write the standard ebml header.
|
||||
|
||||
// TODO: Provide a function to write the standard ebml header.
|
||||
fn start_tag(&writer w, uint tag_id) {
|
||||
// Write the tag ID:
|
||||
write_vint(w.writer, tag_id);
|
||||
|
||||
write_vint(w.writer, tag_id);
|
||||
// Write a placeholder four-byte size.
|
||||
|
||||
w.size_positions += [w.writer.tell()];
|
||||
let vec[u8] zeroes = [0u8, 0u8, 0u8, 0u8];
|
||||
w.writer.write(zeroes);
|
||||
|
@ -181,6 +168,5 @@ fn end_tag(&writer w) {
|
|||
write_sized_vint(w.writer, cur_pos - last_size_pos - 4u, 4u);
|
||||
w.writer.seek(cur_pos as int, io::seek_set);
|
||||
}
|
||||
|
||||
// TODO: optionally perform "relaxations" on end_tag to more efficiently
|
||||
// encode sizes; this is a fixed point iteration
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
|
||||
|
||||
/* The 'fmt' extension is modeled on the posix printf system.
|
||||
*
|
||||
* A posix conversion ostensibly looks like this:
|
||||
|
@ -12,10 +14,10 @@
|
|||
* we also only support translating-to-rust a tiny subset of the possible
|
||||
* combinations at the moment.
|
||||
*/
|
||||
|
||||
import option::none;
|
||||
import option::some;
|
||||
|
||||
|
||||
/*
|
||||
* We have a 'ct' (compile-time) module that parses format strings into a
|
||||
* sequence of conversions. From those conversions AST fragments are built
|
||||
|
@ -29,16 +31,8 @@ import option::some;
|
|||
|
||||
// Functions used by the fmt extension at compile time
|
||||
mod ct {
|
||||
tag signedness {
|
||||
signed;
|
||||
unsigned;
|
||||
}
|
||||
|
||||
tag caseness {
|
||||
case_upper;
|
||||
case_lower;
|
||||
}
|
||||
|
||||
tag signedness { signed; unsigned; }
|
||||
tag caseness { case_upper; case_lower; }
|
||||
tag ty {
|
||||
ty_bool;
|
||||
ty_str;
|
||||
|
@ -48,8 +42,8 @@ mod ct {
|
|||
ty_hex(caseness);
|
||||
ty_octal;
|
||||
// FIXME: More types
|
||||
}
|
||||
|
||||
}
|
||||
tag flag {
|
||||
flag_left_justify;
|
||||
flag_left_zero_pad;
|
||||
|
@ -57,7 +51,6 @@ mod ct {
|
|||
flag_sign_always;
|
||||
flag_alternate;
|
||||
}
|
||||
|
||||
tag count {
|
||||
count_is(int);
|
||||
count_is_param(int);
|
||||
|
@ -66,25 +59,22 @@ mod ct {
|
|||
}
|
||||
|
||||
// A formatted conversion from an expression to a string
|
||||
type conv = rec(option::t[int] param,
|
||||
vec[flag] flags,
|
||||
count width,
|
||||
count precision,
|
||||
ty ty);
|
||||
type conv =
|
||||
rec(option::t[int] param,
|
||||
vec[flag] flags,
|
||||
count width,
|
||||
count precision,
|
||||
ty ty);
|
||||
|
||||
|
||||
// A fragment of the output sequence
|
||||
tag piece {
|
||||
piece_string(str);
|
||||
piece_conv(conv);
|
||||
}
|
||||
|
||||
type error_fn = fn (str) -> !;
|
||||
tag piece { piece_string(str); piece_conv(conv); }
|
||||
type error_fn = fn(str) -> ! ;
|
||||
|
||||
fn parse_fmt_string(str s, error_fn error) -> vec[piece] {
|
||||
let vec[piece] pieces = [];
|
||||
auto lim = str::byte_len(s);
|
||||
auto buf = "";
|
||||
|
||||
fn flush_buf(str buf, &mutable vec[piece] pieces) -> str {
|
||||
if (str::byte_len(buf) > 0u) {
|
||||
auto piece = piece_string(buf);
|
||||
|
@ -92,7 +82,6 @@ mod ct {
|
|||
}
|
||||
ret "";
|
||||
}
|
||||
|
||||
auto i = 0u;
|
||||
while (i < lim) {
|
||||
auto curr = str::substr(s, i, 1u);
|
||||
|
@ -110,83 +99,57 @@ mod ct {
|
|||
pieces += [res._0];
|
||||
i = res._1;
|
||||
}
|
||||
} else {
|
||||
buf += curr;
|
||||
i += 1u;
|
||||
}
|
||||
} else { buf += curr; i += 1u; }
|
||||
}
|
||||
buf = flush_buf(buf, pieces);
|
||||
ret pieces;
|
||||
}
|
||||
|
||||
fn peek_num(str s, uint i, uint lim) -> option::t[tup(uint, uint)] {
|
||||
if (i >= lim) {
|
||||
ret none[tup(uint, uint)];
|
||||
}
|
||||
|
||||
if (i >= lim) { ret none[tup(uint, uint)]; }
|
||||
auto c = s.(i);
|
||||
if (!('0' as u8 <= c && c <= '9' as u8)) {
|
||||
ret option::none[tup(uint, uint)];
|
||||
}
|
||||
|
||||
auto n = (c - ('0' as u8)) as uint;
|
||||
auto n = c - ('0' as u8) as uint;
|
||||
ret alt (peek_num(s, i + 1u, lim)) {
|
||||
case (none) {
|
||||
some[tup(uint, uint)](tup(n, i + 1u))
|
||||
}
|
||||
case (some(?next)) {
|
||||
auto m = next._0;
|
||||
auto j = next._1;
|
||||
some[tup(uint, uint)](tup(n * 10u + m, j))
|
||||
}
|
||||
};
|
||||
case (none) { some[tup(uint, uint)](tup(n, i + 1u)) }
|
||||
case (some(?next)) {
|
||||
auto m = next._0;
|
||||
auto j = next._1;
|
||||
some[tup(uint, uint)](tup(n * 10u + m, j))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn parse_conversion(str s, uint i, uint lim,
|
||||
error_fn error) -> tup(piece, uint) {
|
||||
fn parse_conversion(str s, uint i, uint lim, error_fn error) ->
|
||||
tup(piece, uint) {
|
||||
auto parm = parse_parameter(s, i, lim);
|
||||
auto flags = parse_flags(s, parm._1, lim);
|
||||
auto width = parse_count(s, flags._1, lim);
|
||||
auto prec = parse_precision(s, width._1, lim);
|
||||
auto ty = parse_type(s, prec._1, lim, error);
|
||||
ret tup(piece_conv(rec(param = parm._0,
|
||||
flags = flags._0,
|
||||
width = width._0,
|
||||
precision = prec._0,
|
||||
ty = ty._0)),
|
||||
ty._1);
|
||||
ret tup(piece_conv(rec(param=parm._0,
|
||||
flags=flags._0,
|
||||
width=width._0,
|
||||
precision=prec._0,
|
||||
ty=ty._0)), ty._1);
|
||||
}
|
||||
|
||||
fn parse_parameter(str s, uint i, uint lim) -> tup(option::t[int], uint) {
|
||||
if (i >= lim) {
|
||||
ret tup(none[int], i);
|
||||
}
|
||||
|
||||
if (i >= lim) { ret tup(none[int], i); }
|
||||
auto num = peek_num(s, i, lim);
|
||||
ret alt (num) {
|
||||
case (none) {
|
||||
tup(none[int], i)
|
||||
}
|
||||
case (some(?t)) {
|
||||
auto n = t._0;
|
||||
auto j = t._1;
|
||||
if (j < lim && s.(j) == '$' as u8) {
|
||||
tup(some[int](n as int), j + 1u)
|
||||
case (none) { tup(none[int], i) }
|
||||
case (some(?t)) {
|
||||
auto n = t._0;
|
||||
auto j = t._1;
|
||||
if (j < lim && s.(j) == '$' as u8) {
|
||||
tup(some[int](n as int), j + 1u)
|
||||
} else { tup(none[int], i) }
|
||||
}
|
||||
else {
|
||||
tup(none[int], i)
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
fn parse_flags(str s, uint i, uint lim) -> tup(vec[flag], uint) {
|
||||
let vec[flag] noflags = [];
|
||||
|
||||
if (i >= lim) {
|
||||
ret tup(noflags, i);
|
||||
}
|
||||
|
||||
if (i >= lim) { ret tup(noflags, i); }
|
||||
fn more_(flag f, str s, uint i, uint lim) -> tup(vec[flag], uint) {
|
||||
auto next = parse_flags(s, i + 1u, lim);
|
||||
auto rest = next._0;
|
||||
|
@ -194,144 +157,106 @@ mod ct {
|
|||
let vec[flag] curr = [f];
|
||||
ret tup(curr + rest, j);
|
||||
}
|
||||
|
||||
auto more = bind more_(_, s, i, lim);
|
||||
|
||||
auto f = s.(i);
|
||||
ret if (f == ('-' as u8)) {
|
||||
more(flag_left_justify)
|
||||
} else if (f == ('0' as u8)) {
|
||||
more(flag_left_zero_pad)
|
||||
} else if (f == (' ' as u8)) {
|
||||
more(flag_space_for_sign)
|
||||
} else if (f == ('+' as u8)) {
|
||||
more(flag_sign_always)
|
||||
} else if (f == ('#' as u8)) {
|
||||
more(flag_alternate)
|
||||
} else {
|
||||
tup(noflags, i)
|
||||
};
|
||||
ret if (f == '-' as u8) {
|
||||
more(flag_left_justify)
|
||||
} else if (f == '0' as u8) {
|
||||
more(flag_left_zero_pad)
|
||||
} else if (f == ' ' as u8) {
|
||||
more(flag_space_for_sign)
|
||||
} else if (f == '+' as u8) {
|
||||
more(flag_sign_always)
|
||||
} else if (f == '#' as u8) {
|
||||
more(flag_alternate)
|
||||
} else { tup(noflags, i) };
|
||||
}
|
||||
|
||||
fn parse_count(str s, uint i, uint lim) -> tup(count, uint) {
|
||||
ret if (i >= lim) {
|
||||
tup(count_implied, i)
|
||||
} else if (s.(i) == ('*' as u8)) {
|
||||
auto param = parse_parameter(s, i + 1u, lim);
|
||||
auto j = param._1;
|
||||
alt (param._0) {
|
||||
case (none) {
|
||||
tup(count_is_next_param, j)
|
||||
tup(count_implied, i)
|
||||
} else if (s.(i) == '*' as u8) {
|
||||
auto param = parse_parameter(s, i + 1u, lim);
|
||||
auto j = param._1;
|
||||
alt (param._0) {
|
||||
case (none) { tup(count_is_next_param, j) }
|
||||
case (some(?n)) { tup(count_is_param(n), j) }
|
||||
}
|
||||
case (some(?n)) {
|
||||
tup(count_is_param(n), j)
|
||||
} else {
|
||||
auto num = peek_num(s, i, lim);
|
||||
alt (num) {
|
||||
case (none) { tup(count_implied, i) }
|
||||
case (some(?num)) { tup(count_is(num._0 as int), num._1) }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
auto num = peek_num(s, i, lim);
|
||||
alt (num) {
|
||||
case (none) {
|
||||
tup(count_implied, i)
|
||||
}
|
||||
case (some(?num)) {
|
||||
tup(count_is(num._0 as int), num._1)
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
fn parse_precision(str s, uint i, uint lim) -> tup(count, uint) {
|
||||
ret if (i >= lim) {
|
||||
tup(count_implied, i)
|
||||
} else if (s.(i) == '.' as u8) {
|
||||
auto count = parse_count(s, i + 1u, lim);
|
||||
// If there were no digits specified, i.e. the precision
|
||||
// was ".", then the precision is 0
|
||||
alt (count._0) {
|
||||
case (count_implied) {
|
||||
tup(count_is(0), count._1)
|
||||
tup(count_implied, i)
|
||||
} else if (s.(i) == '.' as u8) {
|
||||
auto count = parse_count(s, i + 1u, lim);
|
||||
|
||||
// If there were no digits specified, i.e. the precision
|
||||
// was ".", then the precision is 0
|
||||
alt (count._0) {
|
||||
case (count_implied) { tup(count_is(0), count._1) }
|
||||
case (_) { count }
|
||||
}
|
||||
case (_) {
|
||||
count
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tup(count_implied, i)
|
||||
};
|
||||
} else { tup(count_implied, i) };
|
||||
}
|
||||
|
||||
fn parse_type(str s, uint i, uint lim, error_fn error) -> tup(ty, uint) {
|
||||
if (i >= lim) {
|
||||
error("missing type in conversion");
|
||||
}
|
||||
|
||||
if (i >= lim) { error("missing type in conversion"); }
|
||||
auto tstr = str::substr(s, i, 1u);
|
||||
auto t = if (str::eq(tstr, "b")) {
|
||||
ty_bool
|
||||
} else if (str::eq(tstr, "s")) {
|
||||
ty_str
|
||||
} else if (str::eq(tstr, "c")) {
|
||||
ty_char
|
||||
} else if (str::eq(tstr, "d")
|
||||
|| str::eq(tstr, "i")) {
|
||||
// TODO: Do we really want two signed types here?
|
||||
// How important is it to be printf compatible?
|
||||
ty_int(signed)
|
||||
} else if (str::eq(tstr, "u")) {
|
||||
ty_int(unsigned)
|
||||
} else if (str::eq(tstr, "x")) {
|
||||
ty_hex(case_lower)
|
||||
} else if (str::eq(tstr, "X")) {
|
||||
ty_hex(case_upper)
|
||||
} else if (str::eq(tstr, "t")) {
|
||||
ty_bits
|
||||
} else if (str::eq(tstr, "o")) {
|
||||
ty_octal
|
||||
} else {
|
||||
error("unknown type in conversion: " + tstr)
|
||||
};
|
||||
auto t =
|
||||
if (str::eq(tstr, "b")) {
|
||||
ty_bool
|
||||
} else if (str::eq(tstr, "s")) {
|
||||
ty_str
|
||||
} else if (str::eq(tstr, "c")) {
|
||||
ty_char
|
||||
} else if (str::eq(tstr, "d") || str::eq(tstr, "i")) {
|
||||
|
||||
// TODO: Do we really want two signed types here?
|
||||
// How important is it to be printf compatible?
|
||||
ty_int(signed)
|
||||
} else if (str::eq(tstr, "u")) {
|
||||
ty_int(unsigned)
|
||||
} else if (str::eq(tstr, "x")) {
|
||||
ty_hex(case_lower)
|
||||
} else if (str::eq(tstr, "X")) {
|
||||
ty_hex(case_upper)
|
||||
} else if (str::eq(tstr, "t")) {
|
||||
ty_bits
|
||||
} else if (str::eq(tstr, "o")) {
|
||||
ty_octal
|
||||
} else { error("unknown type in conversion: " + tstr) };
|
||||
ret tup(t, i + 1u);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Functions used by the fmt extension at runtime. For now there are a lot of
|
||||
// decisions made a runtime. If it proves worthwhile then some of these
|
||||
// conditions can be evaluated at compile-time. For now though it's cleaner to
|
||||
// implement it this way, I think.
|
||||
mod rt {
|
||||
|
||||
tag flag {
|
||||
flag_left_justify;
|
||||
flag_left_zero_pad;
|
||||
flag_space_for_sign;
|
||||
flag_sign_always;
|
||||
flag_alternate;
|
||||
|
||||
// FIXME: This is a hack to avoid creating 0-length vec exprs,
|
||||
// which have some difficulty typechecking currently. See
|
||||
// comments in front::extfmt::make_flags
|
||||
flag_none;
|
||||
}
|
||||
|
||||
tag count {
|
||||
count_is(int);
|
||||
count_implied;
|
||||
}
|
||||
|
||||
tag ty {
|
||||
ty_default;
|
||||
ty_bits;
|
||||
ty_hex_upper;
|
||||
ty_hex_lower;
|
||||
ty_octal;
|
||||
}
|
||||
tag count { count_is(int); count_implied; }
|
||||
tag ty { ty_default; ty_bits; ty_hex_upper; ty_hex_lower; ty_octal; }
|
||||
|
||||
// FIXME: May not want to use a vector here for flags;
|
||||
// instead just use a bool per flag
|
||||
type conv = rec(vec[flag] flags,
|
||||
count width,
|
||||
count precision,
|
||||
ty ty);
|
||||
type conv = rec(vec[flag] flags, count width, count precision, ty ty);
|
||||
|
||||
fn conv_int(&conv cv, int i) -> str {
|
||||
auto radix = 10u;
|
||||
|
@ -346,59 +271,45 @@ mod rt {
|
|||
}
|
||||
ret pad(cv, s, pad_signed);
|
||||
}
|
||||
|
||||
fn conv_uint(&conv cv, uint u) -> str {
|
||||
auto prec = get_int_precision(cv);
|
||||
auto res = alt (cv.ty) {
|
||||
case (ty_default) {
|
||||
uint_to_str_prec(u, 10u, prec)
|
||||
}
|
||||
case (ty_hex_lower) {
|
||||
uint_to_str_prec(u, 16u, prec)
|
||||
}
|
||||
case (ty_hex_upper) {
|
||||
str::to_upper(uint_to_str_prec(u, 16u, prec))
|
||||
}
|
||||
case (ty_bits) {
|
||||
uint_to_str_prec(u, 2u, prec)
|
||||
}
|
||||
case (ty_octal) {
|
||||
uint_to_str_prec(u, 8u, prec)
|
||||
}
|
||||
};
|
||||
auto res =
|
||||
alt (cv.ty) {
|
||||
case (ty_default) { uint_to_str_prec(u, 10u, prec) }
|
||||
case (ty_hex_lower) { uint_to_str_prec(u, 16u, prec) }
|
||||
case (ty_hex_upper) {
|
||||
str::to_upper(uint_to_str_prec(u, 16u, prec))
|
||||
}
|
||||
case (ty_bits) { uint_to_str_prec(u, 2u, prec) }
|
||||
case (ty_octal) { uint_to_str_prec(u, 8u, prec) }
|
||||
};
|
||||
ret pad(cv, res, pad_unsigned);
|
||||
}
|
||||
|
||||
fn conv_bool(&conv cv, bool b) -> str {
|
||||
auto s = if (b) {
|
||||
"true"
|
||||
} else {
|
||||
"false"
|
||||
};
|
||||
auto s = if (b) { "true" } else { "false" };
|
||||
// run the boolean conversion through the string conversion logic,
|
||||
// giving it the same rules for precision, etc.
|
||||
|
||||
ret conv_str(cv, s);
|
||||
}
|
||||
|
||||
fn conv_char(&conv cv, char c) -> str {
|
||||
ret pad(cv, str::from_char(c), pad_nozero);
|
||||
}
|
||||
|
||||
fn conv_str(&conv cv, str s) -> str {
|
||||
auto unpadded = alt (cv.precision) {
|
||||
case (count_implied) {
|
||||
s
|
||||
}
|
||||
case (count_is(?max)) {
|
||||
// For strings, precision is the maximum characters displayed
|
||||
if (max as uint < str::char_len(s)) {
|
||||
// FIXME: substr works on bytes, not chars!
|
||||
str::substr(s, 0u, max as uint)
|
||||
} else {
|
||||
s
|
||||
auto unpadded =
|
||||
alt (cv.precision) {
|
||||
case (count_implied) { s }
|
||||
case (count_is(?max)) {
|
||||
|
||||
// For strings, precision is the maximum characters
|
||||
// displayed
|
||||
if (max as uint < str::char_len(s)) {
|
||||
|
||||
// FIXME: substr works on bytes, not chars!
|
||||
str::substr(s, 0u, max as uint)
|
||||
} else { s }
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
ret pad(cv, unpadded, pad_nozero);
|
||||
}
|
||||
|
||||
|
@ -406,10 +317,8 @@ mod rt {
|
|||
// 0 and num is 0 then the result is the empty string.
|
||||
fn int_to_str_prec(int num, uint radix, uint prec) -> str {
|
||||
ret if (num < 0) {
|
||||
"-" + uint_to_str_prec((-num) as uint, radix, prec)
|
||||
} else {
|
||||
uint_to_str_prec(num as uint, radix, prec)
|
||||
};
|
||||
"-" + uint_to_str_prec(-num as uint, radix, prec)
|
||||
} else { uint_to_str_prec(num as uint, radix, prec) };
|
||||
}
|
||||
|
||||
// Convert a uint to string with a minimum number of digits. If precision
|
||||
|
@ -417,29 +326,22 @@ mod rt {
|
|||
// to uint: but it doesn't seem all that useful.
|
||||
fn uint_to_str_prec(uint num, uint radix, uint prec) -> str {
|
||||
ret if (prec == 0u && num == 0u) {
|
||||
""
|
||||
} else {
|
||||
auto s = uint::to_str(num, radix);
|
||||
auto len = str::char_len(s);
|
||||
if (len < prec) {
|
||||
auto diff = prec - len;
|
||||
auto pad = str_init_elt('0', diff);
|
||||
pad + s
|
||||
""
|
||||
} else {
|
||||
s
|
||||
}
|
||||
};
|
||||
auto s = uint::to_str(num, radix);
|
||||
auto len = str::char_len(s);
|
||||
if (len < prec) {
|
||||
auto diff = prec - len;
|
||||
auto pad = str_init_elt('0', diff);
|
||||
pad + s
|
||||
} else { s }
|
||||
};
|
||||
}
|
||||
|
||||
fn get_int_precision(&conv cv) -> uint {
|
||||
ret alt (cv.precision) {
|
||||
case (count_is(?c)) {
|
||||
c as uint
|
||||
}
|
||||
case (count_implied) {
|
||||
1u
|
||||
}
|
||||
};
|
||||
case (count_is(?c)) { c as uint }
|
||||
case (count_implied) { 1u }
|
||||
};
|
||||
}
|
||||
|
||||
// FIXME: This might be useful in str: but needs to be utf8 safe first
|
||||
|
@ -447,90 +349,59 @@ mod rt {
|
|||
auto svec = vec::init_elt[u8](c as u8, n_elts);
|
||||
// FIXME: Using unsafe_from_bytes because rustboot
|
||||
// can't figure out the is_utf8 predicate on from_bytes?
|
||||
|
||||
ret str::unsafe_from_bytes(svec);
|
||||
}
|
||||
|
||||
tag pad_mode {
|
||||
pad_signed;
|
||||
pad_unsigned;
|
||||
pad_nozero;
|
||||
}
|
||||
|
||||
tag pad_mode { pad_signed; pad_unsigned; pad_nozero; }
|
||||
fn pad(&conv cv, str s, pad_mode mode) -> str {
|
||||
auto uwidth;
|
||||
alt (cv.width) {
|
||||
case (count_implied) {
|
||||
ret s;
|
||||
}
|
||||
case (count_implied) { ret s; }
|
||||
case (count_is(?width)) {
|
||||
// FIXME: Maybe width should be uint
|
||||
|
||||
uwidth = width as uint;
|
||||
}
|
||||
}
|
||||
|
||||
auto strlen = str::char_len(s);
|
||||
if (uwidth <= strlen) {
|
||||
ret s;
|
||||
}
|
||||
|
||||
if (uwidth <= strlen) { ret s; }
|
||||
auto padchar = ' ';
|
||||
auto diff = uwidth - strlen;
|
||||
if (have_flag(cv.flags, flag_left_justify)) {
|
||||
auto padstr = str_init_elt(padchar, diff);
|
||||
ret s + padstr;
|
||||
}
|
||||
|
||||
auto might_zero_pad = false;
|
||||
auto signed = false;
|
||||
|
||||
alt (mode) {
|
||||
case (pad_nozero) {
|
||||
// fallthrough
|
||||
}
|
||||
case (pad_signed) {
|
||||
might_zero_pad = true;
|
||||
signed = true;
|
||||
}
|
||||
case (pad_unsigned) {
|
||||
might_zero_pad = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
case (pad_signed) { might_zero_pad = true; signed = true; }
|
||||
case (pad_unsigned) { might_zero_pad = true; }
|
||||
}
|
||||
fn have_precision(&conv cv) -> bool {
|
||||
ret alt (cv.precision) {
|
||||
case (count_implied) {
|
||||
false
|
||||
}
|
||||
case (_) {
|
||||
true
|
||||
}
|
||||
};
|
||||
case (count_implied) { false }
|
||||
case (_) { true }
|
||||
};
|
||||
}
|
||||
|
||||
auto zero_padding = false;
|
||||
if (might_zero_pad
|
||||
&& have_flag(cv.flags, flag_left_zero_pad)
|
||||
&& !have_precision(cv)) {
|
||||
|
||||
if (might_zero_pad && have_flag(cv.flags, flag_left_zero_pad) &&
|
||||
!have_precision(cv)) {
|
||||
padchar = '0';
|
||||
zero_padding = true;
|
||||
}
|
||||
|
||||
auto padstr = str_init_elt(padchar, diff);
|
||||
|
||||
// This is completely heinous. If we have a signed value then
|
||||
// potentially rip apart the intermediate result and insert some
|
||||
// zeros. It may make sense to convert zero padding to a precision
|
||||
// instead.
|
||||
if (signed
|
||||
&& zero_padding
|
||||
&& str::byte_len(s) > 0u) {
|
||||
|
||||
if (signed && zero_padding && str::byte_len(s) > 0u) {
|
||||
auto head = s.(0);
|
||||
if (head == '+' as u8
|
||||
|| head == '-' as u8
|
||||
|| head == ' ' as u8) {
|
||||
|
||||
if (head == '+' as u8 || head == '-' as u8 || head == ' ' as u8) {
|
||||
auto headstr = str::unsafe_from_bytes([head]);
|
||||
auto bytelen = str::byte_len(s);
|
||||
auto numpart = str::substr(s, 1u, bytelen - 1u);
|
||||
|
@ -539,18 +410,11 @@ mod rt {
|
|||
}
|
||||
ret padstr + s;
|
||||
}
|
||||
|
||||
fn have_flag(vec[flag] flags, flag f) -> bool {
|
||||
for (flag candidate in flags) {
|
||||
if (candidate == f) {
|
||||
ret true;
|
||||
}
|
||||
}
|
||||
for (flag candidate in flags) { if (candidate == f) { ret true; } }
|
||||
ret false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
|
||||
|
||||
native "rust" mod rustrt {
|
||||
fn rust_file_is_dir(str path) -> int;
|
||||
fn rust_file_is_dir(str path) -> int;
|
||||
}
|
||||
|
||||
fn path_sep() -> str {
|
||||
ret str::from_char(os_fs::path_sep);
|
||||
}
|
||||
fn path_sep() -> str { ret str::from_char(os_fs::path_sep); }
|
||||
|
||||
type path = str;
|
||||
|
||||
|
@ -12,9 +12,7 @@ fn dirname(path p) -> path {
|
|||
let int i = str::rindex(p, os_fs::path_sep as u8);
|
||||
if (i == -1) {
|
||||
i = str::rindex(p, os_fs::alt_path_sep as u8);
|
||||
if (i == -1) {
|
||||
ret p;
|
||||
}
|
||||
if (i == -1) { ret p; }
|
||||
}
|
||||
ret str::substr(p, 0u, i as uint);
|
||||
}
|
||||
|
@ -23,45 +21,40 @@ fn basename(path p) -> path {
|
|||
let int i = str::rindex(p, os_fs::path_sep as u8);
|
||||
if (i == -1) {
|
||||
i = str::rindex(p, os_fs::alt_path_sep as u8);
|
||||
if (i == -1) {
|
||||
ret p;
|
||||
}
|
||||
if (i == -1) { ret p; }
|
||||
}
|
||||
auto len = str::byte_len(p);
|
||||
if ((i+1) as uint >= len) { ret p; }
|
||||
|
||||
ret str::slice(p, i+1 as uint, len);
|
||||
if (i + 1 as uint >= len) { ret p; }
|
||||
ret str::slice(p, i + 1 as uint, len);
|
||||
}
|
||||
|
||||
|
||||
// FIXME: Need some typestate to avoid bounds check when len(pre) == 0
|
||||
fn connect(path pre, path post) -> path {
|
||||
auto len = str::byte_len(pre);
|
||||
ret if (pre.(len - 1u) == (os_fs::path_sep as u8)) { // Trailing '/'?
|
||||
pre + post
|
||||
} else {
|
||||
pre + path_sep() + post
|
||||
};
|
||||
ret if (pre.(len - 1u) == os_fs::path_sep as u8) {
|
||||
// Trailing '/'?
|
||||
pre + post
|
||||
} else { pre + path_sep() + post };
|
||||
}
|
||||
|
||||
fn file_is_dir(path p) -> bool {
|
||||
ret rustrt::rust_file_is_dir(p) != 0;
|
||||
}
|
||||
fn file_is_dir(path p) -> bool { ret rustrt::rust_file_is_dir(p) != 0; }
|
||||
|
||||
fn list_dir(path p) -> vec[str] {
|
||||
auto pl = str::byte_len(p);
|
||||
if (pl == 0u || p.(pl - 1u) as char != os_fs::path_sep) {
|
||||
p += path_sep();
|
||||
}
|
||||
let vec[str] full_paths = [];
|
||||
for (str filename in os_fs::list_dir(p)) {
|
||||
if (!str::eq(filename, ".")) {if (!str::eq(filename, "..")) {
|
||||
vec::push[str](full_paths, p + filename);
|
||||
}}
|
||||
}
|
||||
ret full_paths;
|
||||
auto pl = str::byte_len(p);
|
||||
if (pl == 0u || p.(pl - 1u) as char != os_fs::path_sep) {
|
||||
p += path_sep();
|
||||
}
|
||||
let vec[str] full_paths = [];
|
||||
for (str filename in os_fs::list_dir(p)) {
|
||||
if (!str::eq(filename, ".")) {
|
||||
if (!str::eq(filename, "..")) {
|
||||
vec::push[str](full_paths, p + filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
ret full_paths;
|
||||
}
|
||||
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
fn getenv(str n) -> option::t[str] {
|
||||
auto s = os::libc::getenv(str::buf(n));
|
||||
ret if ((s as int) == 0) {
|
||||
option::none[str]
|
||||
} else {
|
||||
option::some[str](str::str_from_cstr(s))
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
fn getenv(str n) -> option::t[str] {
|
||||
auto s = os::libc::getenv(str::buf(n));
|
||||
ret if (s as int == 0) {
|
||||
option::none[str]
|
||||
} else { option::some[str](str::str_from_cstr(s)) };
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
|
||||
|
||||
/* Simple getopt alternative. Construct a vector of options, either by using
|
||||
* reqopt, optopt, and optflag or by building them from components yourself,
|
||||
* and pass them to getopts, along with a vector of actual arguments (not
|
||||
|
@ -6,29 +8,21 @@
|
|||
* is what you expect. Use opt_* accessors (bottom of the file) to get
|
||||
* argument values out of the match object.
|
||||
*/
|
||||
|
||||
import option::some;
|
||||
import option::none;
|
||||
|
||||
export opt;
|
||||
|
||||
export reqopt;
|
||||
export optopt;
|
||||
export optflag;
|
||||
export optflagopt;
|
||||
export optmulti;
|
||||
|
||||
export getopts;
|
||||
|
||||
export result;
|
||||
export success;
|
||||
export failure;
|
||||
|
||||
export match;
|
||||
|
||||
export fail_;
|
||||
export fail_str;
|
||||
|
||||
export opt_present;
|
||||
export opt_str;
|
||||
export opt_strs;
|
||||
|
@ -36,63 +30,68 @@ export opt_maybe_str;
|
|||
export opt_default;
|
||||
|
||||
tag name { long(str); short(char); }
|
||||
|
||||
tag hasarg { yes; no; maybe; }
|
||||
|
||||
tag occur { req; optional; multi; }
|
||||
|
||||
type opt = rec(name name, hasarg hasarg, occur occur);
|
||||
|
||||
fn mkname(str nm) -> name {
|
||||
ret if (str::char_len(nm) == 1u) {
|
||||
short(str::char_at(nm, 0u))
|
||||
} else {
|
||||
long(nm)
|
||||
};
|
||||
short(str::char_at(nm, 0u))
|
||||
} else { long(nm) };
|
||||
}
|
||||
|
||||
fn reqopt(str name) -> opt {
|
||||
ret rec(name=mkname(name), hasarg=yes, occur=req);
|
||||
}
|
||||
|
||||
fn optopt(str name) -> opt {
|
||||
ret rec(name=mkname(name), hasarg=yes, occur=optional);
|
||||
}
|
||||
|
||||
fn optflag(str name) -> opt {
|
||||
ret rec(name=mkname(name), hasarg=no, occur=optional);
|
||||
}
|
||||
|
||||
fn optflagopt(str name) -> opt {
|
||||
ret rec(name=mkname(name), hasarg=maybe, occur=optional);
|
||||
}
|
||||
|
||||
fn optmulti(str name) -> opt {
|
||||
ret rec(name=mkname(name), hasarg=yes, occur=multi);
|
||||
}
|
||||
|
||||
tag optval {
|
||||
val(str);
|
||||
given;
|
||||
}
|
||||
tag optval { val(str); given; }
|
||||
|
||||
type match = rec(vec[opt] opts, vec[mutable vec[optval]] vals, vec[str] free);
|
||||
|
||||
fn is_arg(str arg) -> bool {
|
||||
ret str::byte_len(arg) > 1u && arg.(0) == '-' as u8;
|
||||
}
|
||||
|
||||
fn name_str(name nm) -> str {
|
||||
ret alt (nm) {
|
||||
case (short(?ch)) {str::from_char(ch)}
|
||||
case (long(?s)) {s}
|
||||
};
|
||||
case (short(?ch)) { str::from_char(ch) }
|
||||
case (long(?s)) { s }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// FIXME rustboot workaround
|
||||
fn name_eq(name a, name b) -> bool {
|
||||
ret alt (a) {
|
||||
case (long(?a)) {
|
||||
alt (b) {
|
||||
case (long(?b)) { str::eq(a, b) }
|
||||
case (_) { false }
|
||||
case (long(?a)) {
|
||||
alt (b) {
|
||||
case (long(?b)) { str::eq(a, b) }
|
||||
case (_) { false }
|
||||
}
|
||||
}
|
||||
}
|
||||
case (_) { if (a == b) { true } else { false } }
|
||||
};
|
||||
case (_) { if (a == b) { true } else { false } }
|
||||
};
|
||||
}
|
||||
|
||||
fn find_opt(vec[opt] opts, name nm) -> option::t[uint] {
|
||||
auto i = 0u;
|
||||
auto l = vec::len[opt](opts);
|
||||
|
@ -113,36 +112,32 @@ tag fail_ {
|
|||
|
||||
fn fail_str(fail_ f) -> str {
|
||||
ret alt (f) {
|
||||
case (argument_missing(?nm)) {
|
||||
"Argument to option '" + nm + "' missing."
|
||||
}
|
||||
case (unrecognized_option(?nm)) {
|
||||
"Unrecognized option: '" + nm + "'."
|
||||
}
|
||||
case (option_missing(?nm)) {
|
||||
"Required option '" + nm + "' missing."
|
||||
}
|
||||
case (option_duplicated(?nm)) {
|
||||
"Option '" + nm + "' given more than once."
|
||||
}
|
||||
case (unexpected_argument(?nm)) {
|
||||
"Option " + nm + " does not take an argument."
|
||||
}
|
||||
};
|
||||
case (argument_missing(?nm)) {
|
||||
"Argument to option '" + nm + "' missing."
|
||||
}
|
||||
case (unrecognized_option(?nm)) {
|
||||
"Unrecognized option: '" + nm + "'."
|
||||
}
|
||||
case (option_missing(?nm)) {
|
||||
"Required option '" + nm + "' missing."
|
||||
}
|
||||
case (option_duplicated(?nm)) {
|
||||
"Option '" + nm + "' given more than once."
|
||||
}
|
||||
case (unexpected_argument(?nm)) {
|
||||
"Option " + nm + " does not take an argument."
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
tag result {
|
||||
success(match);
|
||||
failure(fail_);
|
||||
}
|
||||
tag result { success(match); failure(fail_); }
|
||||
|
||||
fn getopts(vec[str] args, vec[opt] opts) -> result {
|
||||
auto n_opts = vec::len[opt](opts);
|
||||
fn empty_(uint x) -> vec[optval]{ret vec::empty[optval]();}
|
||||
fn empty_(uint x) -> vec[optval] { ret vec::empty[optval](); }
|
||||
auto f = empty_;
|
||||
auto vals = vec::init_fn_mut[vec[optval]](f, n_opts);
|
||||
let vec[str] free = [];
|
||||
|
||||
auto l = vec::len[str](args);
|
||||
auto i = 0u;
|
||||
while (i < l) {
|
||||
|
@ -163,8 +158,9 @@ fn getopts(vec[str] args, vec[opt] opts) -> result {
|
|||
names = [long(tail)];
|
||||
} else {
|
||||
names = [long(str::slice(tail, 0u, eq as uint))];
|
||||
i_arg = option::some[str]
|
||||
(str::slice(tail, (eq as uint) + 1u, curlen - 2u));
|
||||
i_arg =
|
||||
option::some[str](str::slice(tail, (eq as uint) + 1u,
|
||||
curlen - 2u));
|
||||
}
|
||||
} else {
|
||||
auto j = 1u;
|
||||
|
@ -180,7 +176,7 @@ fn getopts(vec[str] args, vec[opt] opts) -> result {
|
|||
name_pos += 1u;
|
||||
auto optid;
|
||||
alt (find_opt(opts, nm)) {
|
||||
case (some(?id)) {optid = id;}
|
||||
case (some(?id)) { optid = id; }
|
||||
case (none) {
|
||||
ret failure(unrecognized_option(name_str(nm)));
|
||||
}
|
||||
|
@ -197,7 +193,7 @@ fn getopts(vec[str] args, vec[opt] opts) -> result {
|
|||
vec::push[optval](vals.(optid),
|
||||
val(option::get[str](i_arg)));
|
||||
} else if (name_pos < vec::len[name](names) ||
|
||||
i + 1u == l || is_arg(args.(i + 1u))) {
|
||||
i + 1u == l || is_arg(args.(i + 1u))) {
|
||||
vec::push[optval](vals.(optid), given);
|
||||
} else {
|
||||
i += 1u;
|
||||
|
@ -220,63 +216,60 @@ fn getopts(vec[str] args, vec[opt] opts) -> result {
|
|||
}
|
||||
i += 1u;
|
||||
}
|
||||
|
||||
i = 0u;
|
||||
while (i < n_opts) {
|
||||
auto n = vec::len[optval](vals.(i));
|
||||
auto occ = opts.(i).occur;
|
||||
if (occ == req) {if (n == 0u) {
|
||||
ret failure(option_missing(name_str(opts.(i).name)));
|
||||
}}
|
||||
if (occ != multi) {if (n > 1u) {
|
||||
ret failure(option_duplicated(name_str(opts.(i).name)));
|
||||
}}
|
||||
if (occ == req) {
|
||||
if (n == 0u) {
|
||||
ret failure(option_missing(name_str(opts.(i).name)));
|
||||
}
|
||||
}
|
||||
if (occ != multi) {
|
||||
if (n > 1u) {
|
||||
ret failure(option_duplicated(name_str(opts.(i).name)));
|
||||
}
|
||||
}
|
||||
i += 1u;
|
||||
}
|
||||
|
||||
ret success(rec(opts=opts, vals=vals, free=free));
|
||||
}
|
||||
|
||||
fn opt_vals(match m, str nm) -> vec[optval] {
|
||||
ret alt (find_opt(m.opts, mkname(nm))) {
|
||||
case (some(?id)) { m.vals.(id) }
|
||||
case (none) {
|
||||
log_err "No option '" + nm + "' defined.";
|
||||
fail
|
||||
}
|
||||
};
|
||||
}
|
||||
fn opt_val(match m, str nm) -> optval {
|
||||
ret opt_vals(m, nm).(0);
|
||||
case (some(?id)) { m.vals.(id) }
|
||||
case (none) { log_err "No option '" + nm + "' defined."; fail }
|
||||
};
|
||||
}
|
||||
|
||||
fn opt_val(match m, str nm) -> optval { ret opt_vals(m, nm).(0); }
|
||||
|
||||
fn opt_present(match m, str nm) -> bool {
|
||||
ret vec::len[optval](opt_vals(m, nm)) > 0u;
|
||||
}
|
||||
|
||||
fn opt_str(match m, str nm) -> str {
|
||||
ret alt (opt_val(m, nm)) {
|
||||
case (val(?s)) { s }
|
||||
case (_) { fail }
|
||||
};
|
||||
ret alt (opt_val(m, nm)) { case (val(?s)) { s } case (_) { fail } };
|
||||
}
|
||||
|
||||
fn opt_strs(match m, str nm) -> vec[str] {
|
||||
let vec[str] acc = [];
|
||||
for (optval v in opt_vals(m, nm)) {
|
||||
alt (v) {
|
||||
case (val(?s)) { vec::push[str](acc, s); }
|
||||
case (_) {}
|
||||
}
|
||||
alt (v) { case (val(?s)) { vec::push[str](acc, s); } case (_) { } }
|
||||
}
|
||||
ret acc;
|
||||
}
|
||||
|
||||
fn opt_maybe_str(match m, str nm) -> option::t[str] {
|
||||
auto vals = opt_vals(m, nm);
|
||||
if (vec::len[optval](vals) == 0u) { ret none[str]; }
|
||||
ret alt (vals.(0)) {
|
||||
case (val(?s)) { some[str](s) }
|
||||
case (_) { none[str] }
|
||||
};
|
||||
case (val(?s)) { some[str](s) }
|
||||
case (_) { none[str] }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// Returns none if the option was not present, `def` if the option was
|
||||
/// present but no argument was provided, and the argument if the option was
|
||||
/// present and an argument was provided.
|
||||
|
@ -284,11 +277,10 @@ fn opt_default(match m, str nm, str def) -> option::t[str] {
|
|||
auto vals = opt_vals(m, nm);
|
||||
if (vec::len[optval](vals) == 0u) { ret none[str]; }
|
||||
ret alt (vals.(0)) {
|
||||
case (val(?s)) { some[str](s) }
|
||||
case (_) { some[str](def) }
|
||||
}
|
||||
case (val(?s)) { some[str](s) }
|
||||
case (_) { some[str](def) }
|
||||
}
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
|
|
|
@ -1,61 +1,65 @@
|
|||
|
||||
|
||||
fn add(int x, int y) -> int { ret x + y; }
|
||||
|
||||
fn sub(int x, int y) -> int { ret x - y; }
|
||||
|
||||
fn mul(int x, int y) -> int { ret x * y; }
|
||||
|
||||
fn div(int x, int y) -> int { ret x / y; }
|
||||
|
||||
fn rem(int x, int y) -> int { ret x % y; }
|
||||
|
||||
fn lt(int x, int y) -> bool { ret x < y; }
|
||||
|
||||
fn le(int x, int y) -> bool { ret x <= y; }
|
||||
|
||||
fn eq(int x, int y) -> bool { ret x == y; }
|
||||
|
||||
fn ne(int x, int y) -> bool { ret x != y; }
|
||||
|
||||
fn ge(int x, int y) -> bool { ret x >= y; }
|
||||
|
||||
fn gt(int x, int y) -> bool { ret x > y; }
|
||||
|
||||
fn positive(int x) -> bool { ret x > 0; }
|
||||
|
||||
fn negative(int x) -> bool { ret x < 0; }
|
||||
|
||||
fn nonpositive(int x) -> bool { ret x <= 0; }
|
||||
|
||||
fn nonnegative(int x) -> bool { ret x >= 0; }
|
||||
|
||||
|
||||
// FIXME: Make sure this works with negative integers.
|
||||
fn hash(&int x) -> uint { ret x as uint; }
|
||||
|
||||
fn eq_alias(&int x, &int y) -> bool { ret x == y; }
|
||||
|
||||
iter range(int lo, int hi) -> int {
|
||||
let int lo_ = lo;
|
||||
while (lo_ < hi) {
|
||||
put lo_;
|
||||
lo_ += 1;
|
||||
}
|
||||
while (lo_ < hi) { put lo_; lo_ += 1; }
|
||||
}
|
||||
|
||||
fn to_str(int n, uint radix) -> str
|
||||
{
|
||||
fn to_str(int n, uint radix) -> str {
|
||||
assert (0u < radix && radix <= 16u);
|
||||
ret if (n < 0) {
|
||||
"-" + uint::to_str((-n) as uint, radix)
|
||||
} else {
|
||||
uint::to_str(n as uint, radix)
|
||||
};
|
||||
"-" + uint::to_str(-n as uint, radix)
|
||||
} else { uint::to_str(n as uint, radix) };
|
||||
}
|
||||
|
||||
fn pow(int base, uint exponent) -> int {
|
||||
|
||||
ret if (exponent == 0u) {
|
||||
1
|
||||
} else if (base == 0) {
|
||||
0
|
||||
} else {
|
||||
auto accum = base;
|
||||
auto count = exponent;
|
||||
while (count > 1u) {
|
||||
accum *= base;
|
||||
count -= 1u;
|
||||
}
|
||||
accum
|
||||
};
|
||||
1
|
||||
} else if (base == 0) {
|
||||
0
|
||||
} else {
|
||||
auto accum = base;
|
||||
auto count = exponent;
|
||||
while (count > 1u) { accum *= base; count -= 1u; }
|
||||
accum
|
||||
};
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
|
|
367
src/lib/io.rs
367
src/lib/io.rs
|
@ -1,132 +1,123 @@
|
|||
|
||||
import os::libc;
|
||||
|
||||
native "rust" mod rustrt {
|
||||
fn rust_get_stdin() -> os::libc::FILE;
|
||||
fn rust_get_stdout() -> os::libc::FILE;
|
||||
fn rust_get_stdin() -> os::libc::FILE;
|
||||
fn rust_get_stdout() -> os::libc::FILE;
|
||||
}
|
||||
|
||||
|
||||
// Reading
|
||||
|
||||
// FIXME This is all buffered. We might need an unbuffered variant as well
|
||||
tag seek_style { seek_set; seek_end; seek_cur; }
|
||||
|
||||
tag seek_style {seek_set; seek_end; seek_cur;}
|
||||
|
||||
// The raw underlying reader class. All readers must implement this.
|
||||
type buf_reader =
|
||||
state obj {
|
||||
fn read(uint len) -> vec[u8];
|
||||
fn read_byte() -> int;
|
||||
fn unread_byte(int byte);
|
||||
fn eof() -> bool;
|
||||
obj {
|
||||
fn read(uint) -> vec[u8] ;
|
||||
fn read_byte() -> int ;
|
||||
fn unread_byte(int) ;
|
||||
fn eof() -> bool ;
|
||||
|
||||
// FIXME: Seekable really should be orthogonal. We will need
|
||||
// inheritance.
|
||||
fn seek(int offset, seek_style whence);
|
||||
fn tell() -> uint;
|
||||
// FIXME: Seekable really should be orthogonal. We will need
|
||||
// inheritance.
|
||||
fn seek(int, seek_style) ;
|
||||
fn tell() -> uint ;
|
||||
};
|
||||
|
||||
|
||||
// Convenience methods for reading.
|
||||
type reader =
|
||||
state obj {
|
||||
// FIXME: This should inherit from buf_reader.
|
||||
fn get_buf_reader() -> buf_reader;
|
||||
obj {
|
||||
|
||||
fn read_byte() -> int;
|
||||
fn unread_byte(int byte);
|
||||
fn read_bytes(uint len) -> vec[u8];
|
||||
fn read_char() -> char;
|
||||
fn eof() -> bool;
|
||||
fn read_line() -> str;
|
||||
fn read_c_str() -> str;
|
||||
fn read_le_uint(uint size) -> uint;
|
||||
fn read_le_int(uint size) -> int;
|
||||
fn read_be_uint(uint size) -> uint;
|
||||
fn read_whole_stream() -> vec[u8];
|
||||
// FIXME: This should inherit from buf_reader.
|
||||
fn get_buf_reader() -> buf_reader ;
|
||||
fn read_byte() -> int ;
|
||||
fn unread_byte(int) ;
|
||||
fn read_bytes(uint) -> vec[u8] ;
|
||||
fn read_char() -> char ;
|
||||
fn eof() -> bool ;
|
||||
fn read_line() -> str ;
|
||||
fn read_c_str() -> str ;
|
||||
fn read_le_uint(uint) -> uint ;
|
||||
fn read_le_int(uint) -> int ;
|
||||
fn read_be_uint(uint) -> uint ;
|
||||
fn read_whole_stream() -> vec[u8] ;
|
||||
fn seek(int, seek_style) ;
|
||||
fn tell() -> uint ; // FIXME: eventually u64
|
||||
|
||||
fn seek(int offset, seek_style whence);
|
||||
fn tell() -> uint; // FIXME: eventually u64
|
||||
};
|
||||
|
||||
fn convert_whence(seek_style whence) -> int {
|
||||
ret alt (whence) {
|
||||
case (seek_set) {0}
|
||||
case (seek_cur) {1}
|
||||
case (seek_end) {2}
|
||||
};
|
||||
case (seek_set) { 0 }
|
||||
case (seek_cur) { 1 }
|
||||
case (seek_end) { 2 }
|
||||
};
|
||||
}
|
||||
|
||||
state obj FILE_buf_reader(os::libc::FILE f, bool must_close) {
|
||||
obj FILE_buf_reader(os::libc::FILE f, bool must_close) {
|
||||
fn read(uint len) -> vec[u8] {
|
||||
auto buf = vec::alloc[u8](len);
|
||||
auto read = os::libc::fread(vec::buf[u8](buf), 1u, len, f);
|
||||
vec::len_set[u8](buf, read);
|
||||
ret buf;
|
||||
}
|
||||
fn read_byte() -> int {
|
||||
ret os::libc::fgetc(f);
|
||||
}
|
||||
fn unread_byte(int byte) {
|
||||
os::libc::ungetc(byte, f);
|
||||
}
|
||||
fn eof() -> bool {
|
||||
ret os::libc::feof(f) != 0;
|
||||
}
|
||||
fn read_byte() -> int { ret os::libc::fgetc(f); }
|
||||
fn unread_byte(int byte) { os::libc::ungetc(byte, f); }
|
||||
fn eof() -> bool { ret os::libc::feof(f) != 0; }
|
||||
fn seek(int offset, seek_style whence) {
|
||||
assert (os::libc::fseek(f, offset, convert_whence(whence)) == 0);
|
||||
}
|
||||
fn tell() -> uint {
|
||||
ret os::libc::ftell(f) as uint;
|
||||
}
|
||||
drop {
|
||||
if (must_close) { os::libc::fclose(f); }
|
||||
}
|
||||
}drop { if (must_close) { os::libc::fclose(f); } }
|
||||
}
|
||||
|
||||
|
||||
// FIXME: Convert this into pseudomethods on buf_reader.
|
||||
state obj new_reader(buf_reader rdr) {
|
||||
fn get_buf_reader() -> buf_reader {
|
||||
ret rdr;
|
||||
}
|
||||
fn read_byte() -> int {
|
||||
ret rdr.read_byte();
|
||||
}
|
||||
fn unread_byte(int byte) {
|
||||
ret rdr.unread_byte(byte);
|
||||
}
|
||||
fn read_bytes(uint len) -> vec[u8] {
|
||||
ret rdr.read(len);
|
||||
}
|
||||
obj new_reader(buf_reader rdr) {
|
||||
fn get_buf_reader() -> buf_reader { ret rdr; }
|
||||
fn read_byte() -> int { ret rdr.read_byte(); }
|
||||
fn unread_byte(int byte) { ret rdr.unread_byte(byte); }
|
||||
fn read_bytes(uint len) -> vec[u8] { ret rdr.read(len); }
|
||||
fn read_char() -> char {
|
||||
auto c0 = rdr.read_byte();
|
||||
if (c0 == -1) {ret -1 as char;} // FIXME will this stay valid?
|
||||
if (c0 == -1) {
|
||||
ret -1 as char; // FIXME will this stay valid?
|
||||
|
||||
}
|
||||
auto b0 = c0 as u8;
|
||||
auto w = str::utf8_char_width(b0);
|
||||
assert (w > 0u);
|
||||
if (w == 1u) {ret b0 as char;}
|
||||
if (w == 1u) { ret b0 as char; }
|
||||
auto val = 0u;
|
||||
while (w > 1u) {
|
||||
w -= 1u;
|
||||
auto next = rdr.read_byte();
|
||||
assert (next > -1);
|
||||
assert (next & 0xc0 == 0x80);
|
||||
assert (next & 192 == 128);
|
||||
val <<= 6u;
|
||||
val += (next & 0x3f) as uint;
|
||||
val += next & 63 as uint;
|
||||
}
|
||||
// See str::char_at
|
||||
val += ((b0 << ((w + 1u) as u8)) as uint) << ((w - 1u) * 6u - w - 1u);
|
||||
|
||||
val += (b0 << (w + 1u as u8) as uint) << (w - 1u) * 6u - w - 1u;
|
||||
ret val as char;
|
||||
}
|
||||
fn eof() -> bool {
|
||||
ret rdr.eof();
|
||||
}
|
||||
fn eof() -> bool { ret rdr.eof(); }
|
||||
fn read_line() -> str {
|
||||
let vec[u8] buf = [];
|
||||
// No break yet in rustc
|
||||
|
||||
auto go_on = true;
|
||||
while (go_on) {
|
||||
auto ch = rdr.read_byte();
|
||||
if (ch == -1 || ch == 10) {go_on = false;}
|
||||
else {vec::push[u8](buf, ch as u8);}
|
||||
if (ch == -1 || ch == 10) {
|
||||
go_on = false;
|
||||
} else { vec::push[u8](buf, ch as u8); }
|
||||
}
|
||||
ret str::unsafe_from_bytes(buf);
|
||||
}
|
||||
|
@ -135,11 +126,13 @@ state obj new_reader(buf_reader rdr) {
|
|||
auto go_on = true;
|
||||
while (go_on) {
|
||||
auto ch = rdr.read_byte();
|
||||
if (ch < 1) {go_on = false;}
|
||||
else {vec::push[u8](buf, ch as u8);}
|
||||
if (ch < 1) {
|
||||
go_on = false;
|
||||
} else { vec::push[u8](buf, ch as u8); }
|
||||
}
|
||||
ret str::unsafe_from_bytes(buf);
|
||||
}
|
||||
|
||||
// FIXME deal with eof?
|
||||
fn read_le_uint(uint size) -> uint {
|
||||
auto val = 0u;
|
||||
|
@ -161,29 +154,25 @@ state obj new_reader(buf_reader rdr) {
|
|||
}
|
||||
ret val as int;
|
||||
}
|
||||
|
||||
// FIXME deal with eof?
|
||||
fn read_be_uint(uint size) -> uint {
|
||||
auto val = 0u;
|
||||
auto sz = size; // FIXME: trans::ml bug workaround
|
||||
|
||||
while (sz > 0u) {
|
||||
sz -= 1u;
|
||||
val += (rdr.read_byte() as uint) << (sz * 8u);
|
||||
val += (rdr.read_byte() as uint) << sz * 8u;
|
||||
}
|
||||
ret val;
|
||||
}
|
||||
fn read_whole_stream() -> vec[u8] {
|
||||
let vec[u8] buf = [];
|
||||
while (!rdr.eof()) {
|
||||
buf += rdr.read(2048u);
|
||||
}
|
||||
while (!rdr.eof()) { buf += rdr.read(2048u); }
|
||||
ret buf;
|
||||
}
|
||||
fn seek(int offset, seek_style whence) {
|
||||
ret rdr.seek(offset, whence);
|
||||
}
|
||||
fn tell() -> uint {
|
||||
ret rdr.tell();
|
||||
}
|
||||
fn seek(int offset, seek_style whence) { ret rdr.seek(offset, whence); }
|
||||
fn tell() -> uint { ret rdr.tell(); }
|
||||
}
|
||||
|
||||
fn stdin() -> reader {
|
||||
|
@ -192,17 +181,13 @@ fn stdin() -> reader {
|
|||
|
||||
fn file_reader(str path) -> reader {
|
||||
auto f = os::libc::fopen(str::buf(path), str::buf("r"));
|
||||
if (f as uint == 0u) {
|
||||
log_err "error opening " + path;
|
||||
fail;
|
||||
}
|
||||
if (f as uint == 0u) { log_err "error opening " + path; fail; }
|
||||
ret new_reader(FILE_buf_reader(f, true));
|
||||
}
|
||||
|
||||
|
||||
// FIXME: Remove me once objects are exported.
|
||||
fn new_reader_(buf_reader bufr) -> reader {
|
||||
ret new_reader(bufr);
|
||||
}
|
||||
fn new_reader_(buf_reader bufr) -> reader { ret new_reader(bufr); }
|
||||
|
||||
|
||||
// Byte buffer readers
|
||||
|
@ -210,39 +195,28 @@ fn new_reader_(buf_reader bufr) -> reader {
|
|||
// TODO: mutable? u8, but this fails with rustboot.
|
||||
type byte_buf = @rec(vec[u8] buf, mutable uint pos);
|
||||
|
||||
state obj byte_buf_reader(byte_buf bbuf) {
|
||||
obj byte_buf_reader(byte_buf bbuf) {
|
||||
fn read(uint len) -> vec[u8] {
|
||||
auto rest = vec::len[u8](bbuf.buf) - bbuf.pos;
|
||||
auto to_read = len;
|
||||
if (rest < to_read) {
|
||||
to_read = rest;
|
||||
}
|
||||
if (rest < to_read) { to_read = rest; }
|
||||
auto range = vec::slice[u8](bbuf.buf, bbuf.pos, bbuf.pos + to_read);
|
||||
bbuf.pos += to_read;
|
||||
ret range;
|
||||
}
|
||||
fn read_byte() -> int {
|
||||
if (bbuf.pos == vec::len[u8](bbuf.buf)) {ret -1;}
|
||||
if (bbuf.pos == vec::len[u8](bbuf.buf)) { ret -1; }
|
||||
auto b = bbuf.buf.(bbuf.pos);
|
||||
bbuf.pos += 1u;
|
||||
ret b as int;
|
||||
}
|
||||
|
||||
fn unread_byte(int byte) {
|
||||
log_err "TODO: unread_byte";
|
||||
fail;
|
||||
}
|
||||
|
||||
fn eof() -> bool {
|
||||
ret bbuf.pos == vec::len[u8](bbuf.buf);
|
||||
}
|
||||
|
||||
fn unread_byte(int byte) { log_err "TODO: unread_byte"; fail; }
|
||||
fn eof() -> bool { ret bbuf.pos == vec::len[u8](bbuf.buf); }
|
||||
fn seek(int offset, seek_style whence) {
|
||||
auto pos = bbuf.pos;
|
||||
auto len = vec::len[u8](bbuf.buf);
|
||||
bbuf.pos = seek_in_buf(offset, pos, len, whence);
|
||||
}
|
||||
|
||||
fn tell() -> uint { ret bbuf.pos; }
|
||||
}
|
||||
|
||||
|
@ -252,46 +226,35 @@ fn new_byte_buf_reader(vec[u8] buf) -> byte_buf_reader {
|
|||
|
||||
|
||||
// Writing
|
||||
tag fileflag { append; create; truncate; none; }
|
||||
|
||||
tag fileflag {
|
||||
append;
|
||||
create;
|
||||
truncate;
|
||||
none;
|
||||
}
|
||||
type buf_writer =
|
||||
obj {
|
||||
fn write(vec[u8]) ;
|
||||
|
||||
type buf_writer = state obj {
|
||||
fn write(vec[u8] v);
|
||||
// FIXME: Seekable really should be orthogonal. We will need
|
||||
// inheritance.
|
||||
fn seek(int, seek_style) ;
|
||||
fn tell() -> uint ; // FIXME: eventually u64
|
||||
|
||||
// FIXME: Seekable really should be orthogonal. We will need inheritance.
|
||||
fn seek(int offset, seek_style whence);
|
||||
fn tell() -> uint; // FIXME: eventually u64
|
||||
};
|
||||
};
|
||||
|
||||
state obj FILE_writer(os::libc::FILE f, bool must_close) {
|
||||
obj FILE_writer(os::libc::FILE f, bool must_close) {
|
||||
fn write(vec[u8] v) {
|
||||
auto len = vec::len[u8](v);
|
||||
auto vbuf = vec::buf[u8](v);
|
||||
auto nout = os::libc::fwrite(vbuf, len, 1u, f);
|
||||
if (nout < 1u) {
|
||||
log_err "error dumping buffer";
|
||||
}
|
||||
if (nout < 1u) { log_err "error dumping buffer"; }
|
||||
}
|
||||
|
||||
fn seek(int offset, seek_style whence) {
|
||||
assert (os::libc::fseek(f, offset, convert_whence(whence)) == 0);
|
||||
}
|
||||
|
||||
fn tell() -> uint {
|
||||
ret os::libc::ftell(f) as uint;
|
||||
}
|
||||
|
||||
drop {
|
||||
if (must_close) {os::libc::fclose(f);}
|
||||
}
|
||||
}drop { if (must_close) { os::libc::fclose(f); } }
|
||||
}
|
||||
|
||||
state obj fd_buf_writer(int fd, bool must_close) {
|
||||
obj fd_buf_writer(int fd, bool must_close) {
|
||||
fn write(vec[u8] v) {
|
||||
auto len = vec::len[u8](v);
|
||||
auto count = 0u;
|
||||
|
@ -307,41 +270,31 @@ state obj fd_buf_writer(int fd, bool must_close) {
|
|||
count += nout as uint;
|
||||
}
|
||||
}
|
||||
|
||||
fn seek(int offset, seek_style whence) {
|
||||
log_err "need 64-bit native calls for seek, sorry";
|
||||
fail;
|
||||
}
|
||||
|
||||
fn tell() -> uint {
|
||||
log_err "need 64-bit native calls for tell, sorry";
|
||||
fail;
|
||||
}
|
||||
|
||||
drop {
|
||||
if (must_close) {os::libc::close(fd);}
|
||||
}
|
||||
}drop { if (must_close) { os::libc::close(fd); } }
|
||||
}
|
||||
|
||||
fn file_buf_writer(str path, vec[fileflag] flags) -> buf_writer {
|
||||
let int fflags =
|
||||
os::libc_constants::O_WRONLY() |
|
||||
os::libc_constants::O_BINARY();
|
||||
|
||||
os::libc_constants::O_WRONLY() | os::libc_constants::O_BINARY();
|
||||
for (fileflag f in flags) {
|
||||
alt (f) {
|
||||
case (append) { fflags |= os::libc_constants::O_APPEND(); }
|
||||
case (create) { fflags |= os::libc_constants::O_CREAT(); }
|
||||
case (append) { fflags |= os::libc_constants::O_APPEND(); }
|
||||
case (create) { fflags |= os::libc_constants::O_CREAT(); }
|
||||
case (truncate) { fflags |= os::libc_constants::O_TRUNC(); }
|
||||
case (none) {}
|
||||
case (none) { }
|
||||
}
|
||||
}
|
||||
|
||||
auto fd = os::libc::open(str::buf(path),
|
||||
fflags,
|
||||
os::libc_constants::S_IRUSR() |
|
||||
auto fd =
|
||||
os::libc::open(str::buf(path), fflags,
|
||||
os::libc_constants::S_IRUSR() |
|
||||
os::libc_constants::S_IWUSR());
|
||||
|
||||
if (fd < 0) {
|
||||
log_err "error opening file for writing";
|
||||
log_err sys::rustrt::last_os_error();
|
||||
|
@ -351,65 +304,50 @@ fn file_buf_writer(str path, vec[fileflag] flags) -> buf_writer {
|
|||
}
|
||||
|
||||
type writer =
|
||||
state obj {
|
||||
fn get_buf_writer() -> buf_writer;
|
||||
// write_str will continue to do utf-8 output only. an alternative
|
||||
// function will be provided for general encoded string output
|
||||
fn write_str(str s);
|
||||
fn write_line(str s);
|
||||
fn write_char(char ch);
|
||||
fn write_int(int n);
|
||||
fn write_uint(uint n);
|
||||
fn write_bytes(vec[u8] bytes);
|
||||
fn write_le_uint(uint n, uint size);
|
||||
fn write_le_int(int n, uint size);
|
||||
fn write_be_uint(uint n, uint size);
|
||||
obj {
|
||||
fn get_buf_writer() -> buf_writer ;
|
||||
|
||||
// write_str will continue to do utf-8 output only. an alternative
|
||||
// function will be provided for general encoded string output
|
||||
fn write_str(str) ;
|
||||
fn write_line(str) ;
|
||||
fn write_char(char) ;
|
||||
fn write_int(int) ;
|
||||
fn write_uint(uint) ;
|
||||
fn write_bytes(vec[u8]) ;
|
||||
fn write_le_uint(uint, uint) ;
|
||||
fn write_le_int(int, uint) ;
|
||||
fn write_be_uint(uint, uint) ;
|
||||
};
|
||||
|
||||
fn uint_to_le_bytes(uint n, uint size) -> vec[u8] {
|
||||
let vec[u8] bytes = [];
|
||||
while (size > 0u) {
|
||||
bytes += [(n & 255u) as u8];
|
||||
n >>= 8u;
|
||||
size -= 1u;
|
||||
}
|
||||
while (size > 0u) { bytes += [n & 255u as u8]; n >>= 8u; size -= 1u; }
|
||||
ret bytes;
|
||||
}
|
||||
|
||||
fn uint_to_be_bytes(uint n, uint size) -> vec[u8] {
|
||||
let vec[u8] bytes = [];
|
||||
auto i = (size - 1u) as int;
|
||||
while (i >= 0) {
|
||||
bytes += [((n >> ((i * 8) as uint)) & 255u) as u8];
|
||||
i -= 1;
|
||||
}
|
||||
auto i = size - 1u as int;
|
||||
while (i >= 0) { bytes += [n >> (i * 8 as uint) & 255u as u8]; i -= 1; }
|
||||
ret bytes;
|
||||
}
|
||||
|
||||
state obj new_writer(buf_writer out) {
|
||||
fn get_buf_writer() -> buf_writer {
|
||||
ret out;
|
||||
}
|
||||
fn write_str(str s) {
|
||||
out.write(str::bytes(s));
|
||||
}
|
||||
obj new_writer(buf_writer out) {
|
||||
fn get_buf_writer() -> buf_writer { ret out; }
|
||||
fn write_str(str s) { out.write(str::bytes(s)); }
|
||||
fn write_line(str s) {
|
||||
out.write(str::bytes(s));
|
||||
out.write(str::bytes("\n"));
|
||||
}
|
||||
fn write_char(char ch) {
|
||||
// FIXME needlessly consy
|
||||
|
||||
out.write(str::bytes(str::from_char(ch)));
|
||||
}
|
||||
fn write_int(int n) {
|
||||
out.write(str::bytes(int::to_str(n, 10u)));
|
||||
}
|
||||
fn write_uint(uint n) {
|
||||
out.write(str::bytes(uint::to_str(n, 10u)));
|
||||
}
|
||||
fn write_bytes(vec[u8] bytes) {
|
||||
out.write(bytes);
|
||||
}
|
||||
fn write_int(int n) { out.write(str::bytes(int::to_str(n, 10u))); }
|
||||
fn write_uint(uint n) { out.write(str::bytes(uint::to_str(n, 10u))); }
|
||||
fn write_bytes(vec[u8] bytes) { out.write(bytes); }
|
||||
fn write_le_uint(uint n, uint size) {
|
||||
out.write(uint_to_le_bytes(n, size));
|
||||
}
|
||||
|
@ -421,109 +359,94 @@ state obj new_writer(buf_writer out) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// FIXME: Remove me once objects are exported.
|
||||
fn new_writer_(buf_writer out) -> writer {
|
||||
ret new_writer(out);
|
||||
}
|
||||
fn new_writer_(buf_writer out) -> writer { ret new_writer(out); }
|
||||
|
||||
fn file_writer(str path, vec[fileflag] flags) -> writer {
|
||||
ret new_writer(file_buf_writer(path, flags));
|
||||
}
|
||||
|
||||
|
||||
// FIXME: fileflags
|
||||
fn buffered_file_buf_writer(str path) -> buf_writer {
|
||||
auto f = os::libc::fopen(str::buf(path), str::buf("w"));
|
||||
if (f as uint == 0u) {
|
||||
log_err "error opening " + path;
|
||||
fail;
|
||||
}
|
||||
if (f as uint == 0u) { log_err "error opening " + path; fail; }
|
||||
ret FILE_writer(f, true);
|
||||
}
|
||||
|
||||
|
||||
// FIXME it would be great if this could be a const
|
||||
fn stdout() -> writer {
|
||||
ret new_writer(fd_buf_writer(1, false));
|
||||
}
|
||||
fn stdout() -> writer { ret new_writer(fd_buf_writer(1, false)); }
|
||||
|
||||
type str_writer =
|
||||
state obj {
|
||||
fn get_writer() -> writer;
|
||||
fn get_str() -> str;
|
||||
obj {
|
||||
fn get_writer() -> writer ;
|
||||
fn get_str() -> str ;
|
||||
};
|
||||
|
||||
type mutable_byte_buf = @rec(mutable vec[mutable u8] buf, mutable uint pos);
|
||||
|
||||
state obj byte_buf_writer(mutable_byte_buf buf) {
|
||||
obj byte_buf_writer(mutable_byte_buf buf) {
|
||||
fn write(vec[u8] v) {
|
||||
// Fast path.
|
||||
|
||||
if (buf.pos == vec::len(buf.buf)) {
|
||||
// FIXME: Fix our type system. There's no reason you shouldn't be
|
||||
// able to add a mutable vector to an immutable one.
|
||||
|
||||
auto mv = vec::rustrt::unsafe_vec_to_mut[u8](v);
|
||||
buf.buf += mv;
|
||||
buf.pos += vec::len[u8](v);
|
||||
ret;
|
||||
}
|
||||
|
||||
// FIXME: Optimize: These should be unique pointers.
|
||||
|
||||
auto vlen = vec::len[u8](v);
|
||||
auto vpos = 0u;
|
||||
while (vpos < vlen) {
|
||||
auto b = v.(vpos);
|
||||
if (buf.pos == vec::len(buf.buf)) {
|
||||
buf.buf += [mutable b];
|
||||
} else {
|
||||
buf.buf.(buf.pos) = b;
|
||||
}
|
||||
} else { buf.buf.(buf.pos) = b; }
|
||||
buf.pos += 1u;
|
||||
vpos += 1u;
|
||||
}
|
||||
}
|
||||
|
||||
fn seek(int offset, seek_style whence) {
|
||||
auto pos = buf.pos;
|
||||
auto len = vec::len(buf.buf);
|
||||
buf.pos = seek_in_buf(offset, pos, len, whence);
|
||||
}
|
||||
|
||||
fn tell() -> uint { ret buf.pos; }
|
||||
}
|
||||
|
||||
fn string_writer() -> str_writer {
|
||||
// FIXME: yikes, this is bad. Needs fixing of mutable syntax.
|
||||
|
||||
let vec[mutable u8] b = [mutable 0u8];
|
||||
vec::pop(b);
|
||||
|
||||
let mutable_byte_buf buf = @rec(mutable buf = b, mutable pos = 0u);
|
||||
state obj str_writer_wrap(writer wr, mutable_byte_buf buf) {
|
||||
fn get_writer() -> writer {ret wr;}
|
||||
fn get_str() -> str {ret str::unsafe_from_bytes(buf.buf);}
|
||||
let mutable_byte_buf buf = @rec(mutable buf=b, mutable pos=0u);
|
||||
obj str_writer_wrap(writer wr, mutable_byte_buf buf) {
|
||||
fn get_writer() -> writer { ret wr; }
|
||||
fn get_str() -> str { ret str::unsafe_from_bytes(buf.buf); }
|
||||
}
|
||||
ret str_writer_wrap(new_writer(byte_buf_writer(buf)), buf);
|
||||
}
|
||||
|
||||
|
||||
// Utility functions
|
||||
|
||||
fn seek_in_buf(int offset, uint pos, uint len, seek_style whence) -> uint {
|
||||
auto bpos = pos as int;
|
||||
auto blen = len as int;
|
||||
alt (whence) {
|
||||
case (seek_set) { bpos = offset; }
|
||||
case (seek_cur) { bpos += offset; }
|
||||
case (seek_set) { bpos = offset; }
|
||||
case (seek_cur) { bpos += offset; }
|
||||
case (seek_end) { bpos = blen + offset; }
|
||||
}
|
||||
|
||||
if (bpos < 0) {
|
||||
bpos = 0;
|
||||
} else if (bpos > blen) {
|
||||
bpos = blen;
|
||||
}
|
||||
|
||||
if (bpos < 0) { bpos = 0; } else if (bpos > blen) { bpos = blen; }
|
||||
ret bpos as uint;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
|
||||
import str::sbuf;
|
||||
import vec::vbuf;
|
||||
|
||||
|
||||
// FIXME Somehow merge stuff duplicated here and macosx_os.rs. Made difficult
|
||||
// by https://github.com/graydon/rust/issues#issue/268
|
||||
|
||||
native mod libc = "libc.so.6" {
|
||||
|
||||
native "cdecl" mod libc {
|
||||
fn open(sbuf s, int flags, uint mode) -> int;
|
||||
fn read(int fd, vbuf buf, uint count) -> int;
|
||||
fn write(int fd, vbuf buf, uint count) -> int;
|
||||
fn close(int fd) -> int;
|
||||
|
||||
type FILE;
|
||||
fn fopen(sbuf path, sbuf mode) -> FILE;
|
||||
fn fdopen(int fd, sbuf mode) -> FILE;
|
||||
|
@ -22,47 +21,43 @@ native mod libc = "libc.so.6" {
|
|||
fn fwrite(vbuf buf, uint size, uint n, FILE f) -> uint;
|
||||
fn fseek(FILE f, int offset, int whence) -> int;
|
||||
fn ftell(FILE f) -> int;
|
||||
|
||||
type dir;
|
||||
fn opendir(sbuf d) -> dir;
|
||||
fn closedir(dir d) -> int;
|
||||
type dirent;
|
||||
fn readdir(dir d) -> dirent;
|
||||
|
||||
fn getenv(sbuf n) -> sbuf;
|
||||
fn setenv(sbuf n, sbuf v, int overwrite) -> int;
|
||||
fn unsetenv(sbuf n) -> int;
|
||||
|
||||
fn pipe(vbuf buf) -> int;
|
||||
fn waitpid(int pid, vbuf status, int options) -> int;
|
||||
}
|
||||
|
||||
mod libc_constants {
|
||||
fn O_RDONLY() -> int { ret 0x0000; }
|
||||
fn O_WRONLY() -> int { ret 0x0001; }
|
||||
fn O_RDWR() -> int { ret 0x0002; }
|
||||
fn O_APPEND() -> int { ret 0x0400; }
|
||||
fn O_CREAT() -> int { ret 0x0040; }
|
||||
fn O_EXCL() -> int { ret 0x0080; }
|
||||
fn O_TRUNC() -> int { ret 0x0200; }
|
||||
fn O_TEXT() -> int { ret 0x0000; } // nonexistent in linux libc
|
||||
fn O_BINARY() -> int { ret 0x0000; } // nonexistent in linux libc
|
||||
fn O_RDONLY() -> int { ret 0; }
|
||||
fn O_WRONLY() -> int { ret 1; }
|
||||
fn O_RDWR() -> int { ret 2; }
|
||||
fn O_APPEND() -> int { ret 1024; }
|
||||
fn O_CREAT() -> int { ret 64; }
|
||||
fn O_EXCL() -> int { ret 128; }
|
||||
fn O_TRUNC() -> int { ret 512; }
|
||||
fn O_TEXT() -> int {
|
||||
ret 0; // nonexistent in linux libc
|
||||
|
||||
fn S_IRUSR() -> uint { ret 0x0100u; }
|
||||
fn S_IWUSR() -> uint { ret 0x0080u; }
|
||||
}
|
||||
fn O_BINARY() -> int {
|
||||
ret 0; // nonexistent in linux libc
|
||||
|
||||
}
|
||||
fn S_IRUSR() -> uint { ret 256u; }
|
||||
fn S_IWUSR() -> uint { ret 128u; }
|
||||
}
|
||||
|
||||
fn exec_suffix() -> str {
|
||||
ret "";
|
||||
}
|
||||
fn exec_suffix() -> str { ret ""; }
|
||||
|
||||
fn target_os() -> str {
|
||||
ret "linux";
|
||||
}
|
||||
fn target_os() -> str { ret "linux"; }
|
||||
|
||||
fn dylib_filename(str base) -> str {
|
||||
ret "lib" + base + ".so";
|
||||
}
|
||||
fn dylib_filename(str base) -> str { ret "lib" + base + ".so"; }
|
||||
|
||||
fn pipe() -> tup(int, int) {
|
||||
let vec[mutable int] fds = [mutable 0, 0];
|
||||
|
@ -70,16 +65,13 @@ fn pipe() -> tup(int, int) {
|
|||
ret tup(fds.(0), fds.(1));
|
||||
}
|
||||
|
||||
fn fd_FILE(int fd) -> libc::FILE {
|
||||
ret libc::fdopen(fd, str::buf("r"));
|
||||
}
|
||||
fn fd_FILE(int fd) -> libc::FILE { ret libc::fdopen(fd, str::buf("r")); }
|
||||
|
||||
fn waitpid(int pid) -> int {
|
||||
let vec[mutable int] status = [mutable 0];
|
||||
assert (os::libc::waitpid(pid, vec::buf(status), 0) != -1);
|
||||
ret status.(0);
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
|
|
|
@ -1,102 +1,74 @@
|
|||
|
||||
import option::some;
|
||||
import option::none;
|
||||
|
||||
|
||||
// FIXME: It would probably be more appealing to define this as
|
||||
// type list[T] = rec(T hd, option[@list[T]] tl), but at the moment
|
||||
// our recursion rules do not permit that.
|
||||
|
||||
tag list[T] {
|
||||
cons(T, @list[T]);
|
||||
nil;
|
||||
}
|
||||
tag list[T] { cons(T, @list[T]); nil; }
|
||||
|
||||
fn from_vec[T](vec[T] v) -> list[T] {
|
||||
auto l = nil[T];
|
||||
// FIXME: This would be faster and more space efficient if it looped over
|
||||
// a reverse vector iterator. Unfortunately generic iterators seem not to
|
||||
// work yet.
|
||||
for (T item in vec::reversed(v)) {
|
||||
l = cons[T](item, @l);
|
||||
}
|
||||
|
||||
for (T item in vec::reversed(v)) { l = cons[T](item, @l); }
|
||||
ret l;
|
||||
}
|
||||
|
||||
fn foldl[T,U](&list[T] ls, &U u, fn(&T t, &U u) -> U f) -> U {
|
||||
alt(ls) {
|
||||
fn foldl[T, U](&list[T] ls, &U u, fn(&T, &U) -> U f) -> U {
|
||||
alt (ls) {
|
||||
case (cons(?hd, ?tl)) {
|
||||
auto u_ = f(hd, u);
|
||||
be foldl[T,U](*tl, u_, f);
|
||||
}
|
||||
case (nil) {
|
||||
ret u;
|
||||
be foldl[T, U](*tl, u_, f);
|
||||
}
|
||||
case (nil) { ret u; }
|
||||
}
|
||||
}
|
||||
|
||||
fn find[T,U](&list[T] ls,
|
||||
(fn(&T) -> option::t[U]) f) -> option::t[U] {
|
||||
alt(ls) {
|
||||
fn find[T, U](&list[T] ls, fn(&T) -> option::t[U] f) -> option::t[U] {
|
||||
alt (ls) {
|
||||
case (cons(?hd, ?tl)) {
|
||||
alt (f(hd)) {
|
||||
case (none) {
|
||||
be find[T,U](*tl, f);
|
||||
}
|
||||
case (some(?res)) {
|
||||
ret some[U](res);
|
||||
}
|
||||
case (none) { be find[T, U](*tl, f); }
|
||||
case (some(?res)) { ret some[U](res); }
|
||||
}
|
||||
}
|
||||
case (nil) {
|
||||
ret none[U];
|
||||
}
|
||||
case (nil) { ret none[U]; }
|
||||
}
|
||||
}
|
||||
|
||||
fn has[T](&list[T] ls, &T elt) -> bool {
|
||||
alt(ls) {
|
||||
alt (ls) {
|
||||
case (cons(?hd, ?tl)) {
|
||||
if (elt == hd) {
|
||||
ret true;
|
||||
} else {
|
||||
be has(*tl, elt);
|
||||
}
|
||||
if (elt == hd) { ret true; } else { be has(*tl, elt); }
|
||||
}
|
||||
case (nil) { ret false; }
|
||||
}
|
||||
}
|
||||
|
||||
fn length[T](&list[T] ls) -> uint {
|
||||
fn count[T](&T t, &uint u) -> uint {
|
||||
ret u + 1u;
|
||||
}
|
||||
ret foldl[T,uint](ls, 0u, bind count[T](_, _));
|
||||
fn count[T](&T t, &uint u) -> uint { ret u + 1u; }
|
||||
ret foldl[T, uint](ls, 0u, bind count[T](_, _));
|
||||
}
|
||||
|
||||
fn cdr[T](&list[T] ls) -> list[T] {
|
||||
alt (ls) {
|
||||
case (cons(_, ?tl)) {ret *tl;}
|
||||
}
|
||||
}
|
||||
fn car[T](&list[T] ls) -> T {
|
||||
alt (ls) {
|
||||
case (cons(?hd, _)) {ret hd;}
|
||||
}
|
||||
alt (ls) { case (cons(_, ?tl)) { ret *tl; } }
|
||||
}
|
||||
|
||||
fn car[T](&list[T] ls) -> T { alt (ls) { case (cons(?hd, _)) { ret hd; } } }
|
||||
|
||||
fn append[T](&list[T] l, &list[T] m) -> list[T] {
|
||||
alt (l) {
|
||||
case (nil) {
|
||||
ret m;
|
||||
}
|
||||
case (nil) { ret m; }
|
||||
case (cons(?x, ?xs)) {
|
||||
let list[T] rest = append[T](*xs, m);
|
||||
ret cons[T](x, @rest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
|
||||
import str::sbuf;
|
||||
import vec::vbuf;
|
||||
|
||||
native mod libc = "libc.dylib" {
|
||||
|
||||
native "cdecl" mod libc {
|
||||
fn open(sbuf s, int flags, uint mode) -> int;
|
||||
fn read(int fd, vbuf buf, uint count) -> int;
|
||||
fn write(int fd, vbuf buf, uint count) -> int;
|
||||
fn close(int fd) -> int;
|
||||
|
||||
type FILE;
|
||||
fn fopen(sbuf path, sbuf mode) -> FILE;
|
||||
fn fdopen(int fd, sbuf mode) -> FILE;
|
||||
|
@ -19,47 +18,43 @@ native mod libc = "libc.dylib" {
|
|||
fn fwrite(vbuf buf, uint size, uint n, FILE f) -> uint;
|
||||
fn fseek(FILE f, int offset, int whence) -> int;
|
||||
fn ftell(FILE f) -> int;
|
||||
|
||||
type dir;
|
||||
fn opendir(sbuf d) -> dir;
|
||||
fn closedir(dir d) -> int;
|
||||
type dirent;
|
||||
fn readdir(dir d) -> dirent;
|
||||
|
||||
fn getenv(sbuf n) -> sbuf;
|
||||
fn setenv(sbuf n, sbuf v, int overwrite) -> int;
|
||||
fn unsetenv(sbuf n) -> int;
|
||||
|
||||
fn pipe(vbuf buf) -> int;
|
||||
fn waitpid(int pid, vbuf status, int options) -> int;
|
||||
}
|
||||
|
||||
mod libc_constants {
|
||||
fn O_RDONLY() -> int { ret 0x0000; }
|
||||
fn O_WRONLY() -> int { ret 0x0001; }
|
||||
fn O_RDWR() -> int { ret 0x0002; }
|
||||
fn O_APPEND() -> int { ret 0x0008; }
|
||||
fn O_CREAT() -> int { ret 0x0200; }
|
||||
fn O_EXCL() -> int { ret 0x0800; }
|
||||
fn O_TRUNC() -> int { ret 0x0400; }
|
||||
fn O_TEXT() -> int { ret 0x0000; } // nonexistent in darwin libc
|
||||
fn O_BINARY() -> int { ret 0x0000; } // nonexistent in darwin libc
|
||||
fn O_RDONLY() -> int { ret 0; }
|
||||
fn O_WRONLY() -> int { ret 1; }
|
||||
fn O_RDWR() -> int { ret 2; }
|
||||
fn O_APPEND() -> int { ret 8; }
|
||||
fn O_CREAT() -> int { ret 512; }
|
||||
fn O_EXCL() -> int { ret 2048; }
|
||||
fn O_TRUNC() -> int { ret 1024; }
|
||||
fn O_TEXT() -> int {
|
||||
ret 0; // nonexistent in darwin libc
|
||||
|
||||
fn S_IRUSR() -> uint { ret 0x0400u; }
|
||||
fn S_IWUSR() -> uint { ret 0x0200u; }
|
||||
}
|
||||
fn O_BINARY() -> int {
|
||||
ret 0; // nonexistent in darwin libc
|
||||
|
||||
}
|
||||
fn S_IRUSR() -> uint { ret 1024u; }
|
||||
fn S_IWUSR() -> uint { ret 512u; }
|
||||
}
|
||||
|
||||
fn exec_suffix() -> str {
|
||||
ret "";
|
||||
}
|
||||
fn exec_suffix() -> str { ret ""; }
|
||||
|
||||
fn target_os() -> str {
|
||||
ret "macos";
|
||||
}
|
||||
fn target_os() -> str { ret "macos"; }
|
||||
|
||||
fn dylib_filename(str base) -> str {
|
||||
ret "lib" + base + ".dylib";
|
||||
}
|
||||
fn dylib_filename(str base) -> str { ret "lib" + base + ".dylib"; }
|
||||
|
||||
fn pipe() -> tup(int, int) {
|
||||
let vec[mutable int] fds = [mutable 0, 0];
|
||||
|
@ -67,16 +62,13 @@ fn pipe() -> tup(int, int) {
|
|||
ret tup(fds.(0), fds.(1));
|
||||
}
|
||||
|
||||
fn fd_FILE(int fd) -> libc::FILE {
|
||||
ret libc::fdopen(fd, str::buf("r"));
|
||||
}
|
||||
fn fd_FILE(int fd) -> libc::FILE { ret libc::fdopen(fd, str::buf("r")); }
|
||||
|
||||
fn waitpid(int pid) -> int {
|
||||
let vec[mutable int] status = [mutable 0];
|
||||
assert (os::libc::waitpid(pid, vec::buf(status), 0) != -1);
|
||||
ret status.(0);
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
|
|
327
src/lib/map.rs
327
src/lib/map.rs
|
@ -1,37 +1,34 @@
|
|||
|
||||
|
||||
|
||||
/**
|
||||
* At the moment, this is a partial hashmap implementation, not yet fit for
|
||||
* use, but useful as a stress test for rustboot.
|
||||
*/
|
||||
type hashfn[K] = fn(&K) -> uint ;
|
||||
|
||||
type hashfn[K] = fn(&K) -> uint;
|
||||
type eqfn[K] = fn(&K, &K) -> bool;
|
||||
type eqfn[K] = fn(&K, &K) -> bool ;
|
||||
|
||||
state type hashmap[K, V] = state obj {
|
||||
fn size() -> uint;
|
||||
fn insert(&K key, &V val) -> bool;
|
||||
fn contains_key(&K key) -> bool;
|
||||
fn get(&K key) -> V;
|
||||
fn find(&K key) -> option::t[V];
|
||||
fn remove(&K key) -> option::t[V];
|
||||
fn rehash();
|
||||
iter items() -> @tup(K,V);
|
||||
};
|
||||
type hashmap[K, V] =
|
||||
obj {
|
||||
fn size() -> uint ;
|
||||
fn insert(&K, &V) -> bool ;
|
||||
fn contains_key(&K) -> bool ;
|
||||
fn get(&K) -> V ;
|
||||
fn find(&K) -> option::t[V] ;
|
||||
fn remove(&K) -> option::t[V] ;
|
||||
fn rehash() ;
|
||||
iter items() -> @tup(K, V) ;
|
||||
};
|
||||
|
||||
fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] {
|
||||
|
||||
let uint initial_capacity = 32u; // 2^5
|
||||
|
||||
let util::rational load_factor = rec(num=3, den=4);
|
||||
|
||||
tag bucket[K, V] {
|
||||
nil;
|
||||
deleted;
|
||||
some(K, V);
|
||||
}
|
||||
|
||||
tag bucket[K, V] { nil; deleted; some(K, V); }
|
||||
fn make_buckets[K, V](uint nbkts) -> vec[mutable bucket[K, V]] {
|
||||
ret vec::init_elt_mut[bucket[K, V]](nil[K, V], nbkts);
|
||||
}
|
||||
|
||||
// Derive two hash functions from the one given by taking the upper
|
||||
// half and lower half of the uint bits. Our bucket probing
|
||||
// sequence is then defined by
|
||||
|
@ -46,199 +43,159 @@ fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] {
|
|||
// is always a power of 2), so that all buckets are probed for a
|
||||
// fixed key.
|
||||
|
||||
fn hashl(uint n, uint nbkts) -> uint {
|
||||
ret ((n >>> 16u) * 2u + 1u);
|
||||
}
|
||||
|
||||
fn hashr(uint n, uint nbkts) -> uint {
|
||||
ret (0x0000_ffff_u & n);
|
||||
}
|
||||
|
||||
fn hashl(uint n, uint nbkts) -> uint { ret (n >>> 16u) * 2u + 1u; }
|
||||
fn hashr(uint n, uint nbkts) -> uint { ret 0x0000_ffff_u & n; }
|
||||
fn hash(uint h, uint nbkts, uint i) -> uint {
|
||||
ret (hashl(h, nbkts) * i + hashr(h, nbkts)) % nbkts;
|
||||
}
|
||||
|
||||
/**
|
||||
* We attempt to never call this with a full table. If we do, it
|
||||
* will fail.
|
||||
*/
|
||||
fn insert_common[K, V](&hashfn[K] hasher,
|
||||
&eqfn[K] eqer,
|
||||
vec[mutable bucket[K, V]] bkts,
|
||||
uint nbkts,
|
||||
&K key,
|
||||
&V val)
|
||||
-> bool
|
||||
{
|
||||
|
||||
fn insert_common[K,
|
||||
V](&hashfn[K] hasher, &eqfn[K] eqer,
|
||||
vec[mutable bucket[K, V]] bkts, uint nbkts, &K key,
|
||||
&V val) -> bool {
|
||||
let uint i = 0u;
|
||||
let uint h = hasher(key);
|
||||
while (i < nbkts) {
|
||||
let uint j = hash(h, nbkts, i);
|
||||
alt (bkts.(j)) {
|
||||
case (some(?k, _)) {
|
||||
// Copy key to please alias analysis.
|
||||
|
||||
auto k_ = k;
|
||||
if (eqer(key, k_)) {
|
||||
bkts.(j) = some[K, V](k_, val);
|
||||
ret false;
|
||||
}
|
||||
i += 1u;
|
||||
}
|
||||
case (_) { bkts.(j) = some[K, V](key, val); ret true; }
|
||||
}
|
||||
}
|
||||
fail; // full table
|
||||
|
||||
}
|
||||
fn find_common[K,
|
||||
V](&hashfn[K] hasher, &eqfn[K] eqer,
|
||||
vec[mutable bucket[K, V]] bkts, uint nbkts, &K key) ->
|
||||
option::t[V] {
|
||||
let uint i = 0u;
|
||||
let uint h = hasher(key);
|
||||
while (i < nbkts) {
|
||||
let uint j = hash(h, nbkts, i);
|
||||
alt (bkts.(j)) {
|
||||
case (some(?k, ?v)) {
|
||||
// Copy to please alias analysis.
|
||||
|
||||
auto k_ = k;
|
||||
auto v_ = v;
|
||||
if (eqer(key, k_)) { ret option::some[V](v_); }
|
||||
}
|
||||
case (nil) { ret option::none[V]; }
|
||||
case (deleted[K, V]) { }
|
||||
}
|
||||
i += 1u;
|
||||
}
|
||||
ret option::none[V];
|
||||
}
|
||||
fn rehash[K,
|
||||
V](&hashfn[K] hasher, &eqfn[K] eqer,
|
||||
vec[mutable bucket[K, V]] oldbkts, uint noldbkts,
|
||||
vec[mutable bucket[K, V]] newbkts, uint nnewbkts) {
|
||||
for (bucket[K, V] b in oldbkts) {
|
||||
alt (b) {
|
||||
case (some(?k_, ?v_)) {
|
||||
auto k = k_;
|
||||
auto v = v_;
|
||||
insert_common[K,
|
||||
V](hasher, eqer, newbkts, nnewbkts, k, v);
|
||||
}
|
||||
case (_) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
obj hashmap[K,
|
||||
V](hashfn[K] hasher,
|
||||
eqfn[K] eqer,
|
||||
mutable vec[mutable bucket[K, V]] bkts,
|
||||
mutable uint nbkts,
|
||||
mutable uint nelts,
|
||||
util::rational lf) {
|
||||
fn size() -> uint { ret nelts; }
|
||||
fn insert(&K key, &V val) -> bool {
|
||||
let util::rational load =
|
||||
rec(num=nelts + 1u as int, den=nbkts as int);
|
||||
if (!util::rational_leq(load, lf)) {
|
||||
let uint nnewbkts = uint::next_power_of_two(nbkts + 1u);
|
||||
let vec[mutable bucket[K, V]] newbkts =
|
||||
make_buckets[K, V](nnewbkts);
|
||||
rehash[K, V](hasher, eqer, bkts, nbkts, newbkts, nnewbkts);
|
||||
bkts = newbkts;
|
||||
nbkts = nnewbkts;
|
||||
}
|
||||
if (insert_common[K, V](hasher, eqer, bkts, nbkts, key, val)) {
|
||||
nelts += 1u;
|
||||
ret true;
|
||||
}
|
||||
ret false;
|
||||
}
|
||||
fn contains_key(&K key) -> bool {
|
||||
ret alt (find_common[K, V](hasher, eqer, bkts, nbkts, key)) {
|
||||
case (option::some(_)) { true }
|
||||
case (_) { false }
|
||||
};
|
||||
}
|
||||
fn get(&K key) -> V {
|
||||
ret alt (find_common[K, V](hasher, eqer, bkts, nbkts, key)) {
|
||||
case (option::some(?val)) { val }
|
||||
case (_) { fail }
|
||||
};
|
||||
}
|
||||
fn find(&K key) -> option::t[V] {
|
||||
be find_common[K, V](hasher, eqer, bkts, nbkts, key);
|
||||
}
|
||||
fn remove(&K key) -> option::t[V] {
|
||||
let uint i = 0u;
|
||||
let uint h = hasher(key);
|
||||
while (i < nbkts) {
|
||||
let uint j = hash(h, nbkts, i);
|
||||
alt (bkts.(j)) {
|
||||
case (some(?k, _)) {
|
||||
// Copy key to please alias analysis.
|
||||
auto k_ = k;
|
||||
if (eqer(key, k_)) {
|
||||
bkts.(j) = some[K, V](k_, val);
|
||||
ret false;
|
||||
}
|
||||
i += 1u;
|
||||
}
|
||||
case (_) {
|
||||
bkts.(j) = some[K, V](key, val);
|
||||
ret true;
|
||||
}
|
||||
}
|
||||
}
|
||||
fail; // full table
|
||||
}
|
||||
|
||||
fn find_common[K, V](&hashfn[K] hasher,
|
||||
&eqfn[K] eqer,
|
||||
vec[mutable bucket[K, V]] bkts,
|
||||
uint nbkts,
|
||||
&K key)
|
||||
-> option::t[V]
|
||||
{
|
||||
let uint i = 0u;
|
||||
let uint h = hasher(key);
|
||||
while (i < nbkts) {
|
||||
let uint j = (hash(h, nbkts, i));
|
||||
alt (bkts.(j)) {
|
||||
case (some(?k, ?v)) {
|
||||
// Copy to please alias analysis.
|
||||
auto k_ = k;
|
||||
auto v_ = v;
|
||||
auto vo = option::some(v);
|
||||
if (eqer(key, k_)) {
|
||||
ret option::some[V](v_);
|
||||
bkts.(j) = deleted[K, V];
|
||||
nelts -= 1u;
|
||||
ret vo;
|
||||
}
|
||||
}
|
||||
case (nil) {
|
||||
ret option::none[V];
|
||||
}
|
||||
case (deleted[K, V]) { }
|
||||
case (deleted) { }
|
||||
case (nil) { ret option::none[V]; }
|
||||
}
|
||||
i += 1u;
|
||||
}
|
||||
ret option::none[V];
|
||||
}
|
||||
|
||||
|
||||
fn rehash[K, V](&hashfn[K] hasher,
|
||||
&eqfn[K] eqer,
|
||||
vec[mutable bucket[K, V]] oldbkts, uint noldbkts,
|
||||
vec[mutable bucket[K, V]] newbkts, uint nnewbkts)
|
||||
{
|
||||
for (bucket[K, V] b in oldbkts) {
|
||||
fn rehash() {
|
||||
let vec[mutable bucket[K, V]] newbkts = make_buckets[K, V](nbkts);
|
||||
rehash[K, V](hasher, eqer, bkts, nbkts, newbkts, nbkts);
|
||||
bkts = newbkts;
|
||||
}
|
||||
iter items() -> @tup(K, V) {
|
||||
for (bucket[K, V] b in bkts) {
|
||||
alt (b) {
|
||||
case (some(?k_, ?v_)) {
|
||||
auto k = k_; auto v = v_;
|
||||
insert_common[K, V](hasher, eqer, newbkts,
|
||||
nnewbkts, k, v);
|
||||
}
|
||||
case (some(?k, ?v)) { put @tup(k, v); }
|
||||
case (_) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state obj hashmap[K, V](hashfn[K] hasher,
|
||||
eqfn[K] eqer,
|
||||
mutable vec[mutable bucket[K, V]] bkts,
|
||||
mutable uint nbkts,
|
||||
mutable uint nelts,
|
||||
util::rational lf)
|
||||
{
|
||||
fn size() -> uint { ret nelts; }
|
||||
|
||||
fn insert(&K key, &V val) -> bool {
|
||||
let util::rational load = rec(num=(nelts + 1u) as int,
|
||||
den=nbkts as int);
|
||||
if (!util::rational_leq(load, lf)) {
|
||||
let uint nnewbkts = uint::next_power_of_two(nbkts + 1u);
|
||||
let vec[mutable bucket[K, V]] newbkts =
|
||||
make_buckets[K, V](nnewbkts);
|
||||
rehash[K, V](hasher, eqer, bkts, nbkts,
|
||||
newbkts, nnewbkts);
|
||||
bkts = newbkts;
|
||||
nbkts = nnewbkts;
|
||||
}
|
||||
|
||||
if (insert_common[K, V](hasher, eqer, bkts,
|
||||
nbkts, key, val)) {
|
||||
nelts += 1u;
|
||||
ret true;
|
||||
}
|
||||
ret false;
|
||||
}
|
||||
|
||||
fn contains_key(&K key) -> bool {
|
||||
ret alt (find_common[K, V](hasher, eqer, bkts, nbkts, key)) {
|
||||
case (option::some(_)) { true }
|
||||
case (_) { false }
|
||||
};
|
||||
}
|
||||
|
||||
fn get(&K key) -> V {
|
||||
ret alt (find_common[K, V](hasher, eqer, bkts, nbkts, key)) {
|
||||
case (option::some(?val)) { val }
|
||||
case (_) { fail }
|
||||
};
|
||||
}
|
||||
|
||||
fn find(&K key) -> option::t[V] {
|
||||
be find_common[K, V](hasher, eqer, bkts, nbkts, key);
|
||||
}
|
||||
|
||||
fn remove(&K key) -> option::t[V] {
|
||||
let uint i = 0u;
|
||||
let uint h = hasher(key);
|
||||
while (i < nbkts) {
|
||||
let uint j = (hash(h, nbkts, i));
|
||||
alt (bkts.(j)) {
|
||||
case (some(?k, ?v)) {
|
||||
auto k_ = k; auto vo = option::some(v);
|
||||
if (eqer(key, k_)) {
|
||||
bkts.(j) = deleted[K, V];
|
||||
nelts -= 1u;
|
||||
ret vo;
|
||||
}
|
||||
}
|
||||
case (deleted) { }
|
||||
case (nil) {
|
||||
ret option::none[V];
|
||||
}
|
||||
}
|
||||
i += 1u;
|
||||
}
|
||||
ret option::none[V];
|
||||
}
|
||||
|
||||
fn rehash() {
|
||||
let vec[mutable bucket[K, V]] newbkts =
|
||||
make_buckets[K, V](nbkts);
|
||||
rehash[K, V](hasher, eqer, bkts, nbkts, newbkts, nbkts);
|
||||
bkts = newbkts;
|
||||
}
|
||||
|
||||
iter items() -> @tup(K,V) {
|
||||
for (bucket[K,V] b in bkts) {
|
||||
alt (b) {
|
||||
case(some(?k,?v)) {
|
||||
put @tup(k,v);
|
||||
}
|
||||
case (_) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let vec[mutable bucket[K, V]] bkts =
|
||||
make_buckets[K, V](initial_capacity);
|
||||
|
||||
}
|
||||
let vec[mutable bucket[K, V]] bkts = make_buckets[K, V](initial_capacity);
|
||||
ret hashmap[K, V](hasher, eqer, bkts, initial_capacity, 0u, load_factor);
|
||||
}
|
||||
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
|
|
|
@ -1,39 +1,24 @@
|
|||
|
||||
|
||||
|
||||
// lib/option::rs
|
||||
tag t[T] { none; some(T); }
|
||||
|
||||
tag t[T] {
|
||||
none;
|
||||
some(T);
|
||||
}
|
||||
|
||||
type operator[T, U] = fn(&T) -> U;
|
||||
type operator[T, U] = fn(&T) -> U ;
|
||||
|
||||
fn get[T](&t[T] opt) -> T {
|
||||
ret alt (opt) {
|
||||
case (some(?x)) {
|
||||
x
|
||||
}
|
||||
case (none) {
|
||||
fail
|
||||
}
|
||||
};
|
||||
ret alt (opt) { case (some(?x)) { x } case (none) { fail } };
|
||||
}
|
||||
|
||||
fn map[T, U](&operator[T, U] f, &t[T] opt) -> t[U] {
|
||||
ret alt (opt) {
|
||||
case (some(?x)) {
|
||||
some[U](f(x))
|
||||
}
|
||||
case (none) {
|
||||
none[U]
|
||||
}
|
||||
};
|
||||
case (some(?x)) { some[U](f(x)) }
|
||||
case (none) { none[U] }
|
||||
};
|
||||
}
|
||||
|
||||
fn is_none[T](&t[T] opt) -> bool {
|
||||
ret alt (opt) {
|
||||
case (none) { true }
|
||||
case (some(_)) { false }
|
||||
};
|
||||
ret alt (opt) { case (none) { true } case (some(_)) { false } };
|
||||
}
|
||||
|
||||
fn from_maybe[T](&T def, &t[T] opt) -> T {
|
||||
|
@ -41,21 +26,15 @@ fn from_maybe[T](&T def, &t[T] opt) -> T {
|
|||
ret maybe[T, T](def, f, opt);
|
||||
}
|
||||
|
||||
fn maybe[T, U](&U def, fn(&T) -> U f, &t[T] opt) -> U {
|
||||
ret alt (opt) {
|
||||
case (none) { def }
|
||||
case (some(?t)) { f(t) }
|
||||
};
|
||||
fn maybe[T, U](&U def, fn(&T) -> U f, &t[T] opt) -> U {
|
||||
ret alt (opt) { case (none) { def } case (some(?t)) { f(t) } };
|
||||
}
|
||||
|
||||
|
||||
// Can be defined in terms of the above when/if we have const bind.
|
||||
fn may[T](fn(&T) f, &t[T] opt) {
|
||||
alt (opt) {
|
||||
case (none) { /* nothing */ }
|
||||
case (some(?t)) { f(t); }
|
||||
}
|
||||
fn may[T](fn(&T) f, &t[T] opt) {
|
||||
alt (opt) { case (none) {/* nothing */ } case (some(?t)) { f(t); } }
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
|
@ -64,4 +43,3 @@ fn may[T](fn(&T) f, &t[T] opt) {
|
|||
// buffer-file-coding-system: utf-8-unix
|
||||
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
|
||||
// End:
|
||||
|
||||
|
|
|
@ -1,38 +1,41 @@
|
|||
|
||||
|
||||
native "rust" mod rustrt {
|
||||
fn rust_list_files(str path) -> vec[str];
|
||||
fn rust_dirent_filename(os::libc::dirent ent) -> str;
|
||||
fn rust_list_files(str path) -> vec[str];
|
||||
fn rust_dirent_filename(os::libc::dirent ent) -> str;
|
||||
}
|
||||
|
||||
fn list_dir(str path) -> vec[str] {
|
||||
ret rustrt::rust_list_files(path);
|
||||
// TODO ensure this is always closed
|
||||
ret rustrt::rust_list_files(path);
|
||||
// TODO ensure this is always closed
|
||||
|
||||
// FIXME: No idea why, but this appears to corrupt memory on OSX. I suspect
|
||||
// it has to do with the tasking primitives somehow, or perhaps the
|
||||
// FFI. Worth investigating more when we're digging into the FFI and unsafe
|
||||
// mode in more detail; in the meantime we just call list_files above and
|
||||
// skip this code.
|
||||
// FIXME: No idea why, but this appears to corrupt memory on OSX. I
|
||||
// suspect it has to do with the tasking primitives somehow, or perhaps
|
||||
// the FFI. Worth investigating more when we're digging into the FFI and
|
||||
// unsafe mode in more detail; in the meantime we just call list_files
|
||||
// above and skip this code.
|
||||
|
||||
/*
|
||||
auto dir = os::libc::opendir(str::buf(path));
|
||||
assert (dir as uint != 0u);
|
||||
let vec[str] result = [];
|
||||
while (true) {
|
||||
auto ent = os::libc::readdir(dir);
|
||||
if (ent as int == 0) {
|
||||
os::libc::closedir(dir);
|
||||
ret result;
|
||||
}
|
||||
vec::push[str](result, rustrt::rust_dirent_filename(ent));
|
||||
}
|
||||
os::libc::closedir(dir);
|
||||
ret result;
|
||||
*/
|
||||
|
||||
/*
|
||||
auto dir = os::libc::opendir(str::buf(path));
|
||||
assert (dir as uint != 0u);
|
||||
let vec[str] result = [];
|
||||
while (true) {
|
||||
auto ent = os::libc::readdir(dir);
|
||||
if (ent as int == 0) {
|
||||
os::libc::closedir(dir);
|
||||
ret result;
|
||||
}
|
||||
vec::push[str](result, rustrt::rust_dirent_filename(ent));
|
||||
}
|
||||
os::libc::closedir(dir);
|
||||
ret result;
|
||||
*/
|
||||
}
|
||||
|
||||
const char path_sep = '/';
|
||||
const char alt_path_sep = '/';
|
||||
|
||||
const char alt_path_sep = '/';
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
|
||||
|
||||
|
||||
/**
|
||||
* Bindings the runtime's random number generator (ISAAC).
|
||||
*/
|
||||
|
||||
native "rust" mod rustrt {
|
||||
type rctx;
|
||||
fn rand_new() -> rctx;
|
||||
|
@ -9,21 +11,19 @@ native "rust" mod rustrt {
|
|||
fn rand_free(rctx c);
|
||||
}
|
||||
|
||||
type rng = obj { fn next() -> u32; };
|
||||
type rng =
|
||||
obj {
|
||||
fn next() -> u32 ;
|
||||
};
|
||||
|
||||
fn mk_rng() -> rng {
|
||||
obj rt_rng(rustrt::rctx c) {
|
||||
fn next() -> u32 {
|
||||
ret rustrt::rand_next(c);
|
||||
}
|
||||
drop {
|
||||
rustrt::rand_free(c);
|
||||
}
|
||||
}drop { rustrt::rand_free(c); }
|
||||
}
|
||||
|
||||
ret rt_rng(rustrt::rand_new());
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
import str::sbuf;
|
||||
import vec::vbuf;
|
||||
|
||||
|
@ -7,73 +8,62 @@ native "rust" mod rustrt {
|
|||
|
||||
fn arg_vec(str prog, vec[str] args) -> vec[sbuf] {
|
||||
auto argptrs = [str::buf(prog)];
|
||||
for (str arg in args) {
|
||||
vec::push[sbuf](argptrs, str::buf(arg));
|
||||
}
|
||||
for (str arg in args) { vec::push[sbuf](argptrs, str::buf(arg)); }
|
||||
vec::push[sbuf](argptrs, 0 as sbuf);
|
||||
ret argptrs;
|
||||
}
|
||||
|
||||
fn run_program(str prog, vec[str] args) -> int {
|
||||
auto pid = rustrt::rust_run_program(vec::buf[sbuf](arg_vec(prog, args)),
|
||||
0, 0, 0);
|
||||
auto pid =
|
||||
rustrt::rust_run_program(vec::buf[sbuf](arg_vec(prog, args)), 0, 0,
|
||||
0);
|
||||
ret os::waitpid(pid);
|
||||
}
|
||||
|
||||
type program =
|
||||
state obj {
|
||||
fn get_id() -> int;
|
||||
fn input() -> io::writer;
|
||||
fn output() -> io::reader;
|
||||
fn close_input();
|
||||
fn finish() -> int;
|
||||
obj {
|
||||
fn get_id() -> int ;
|
||||
fn input() -> io::writer ;
|
||||
fn output() -> io::reader ;
|
||||
fn close_input() ;
|
||||
fn finish() -> int ;
|
||||
};
|
||||
|
||||
fn start_program(str prog, vec[str] args) -> @program {
|
||||
auto pipe_input = os::pipe();
|
||||
auto pipe_output = os::pipe();
|
||||
auto pid = rustrt::rust_run_program
|
||||
(vec::buf[sbuf](arg_vec(prog, args)),
|
||||
pipe_input._0, pipe_output._1, 0);
|
||||
if (pid == -1) {fail;}
|
||||
auto pid =
|
||||
rustrt::rust_run_program(vec::buf[sbuf](arg_vec(prog, args)),
|
||||
pipe_input._0, pipe_output._1, 0);
|
||||
if (pid == -1) { fail; }
|
||||
os::libc::close(pipe_input._0);
|
||||
os::libc::close(pipe_output._1);
|
||||
|
||||
state obj new_program(int pid,
|
||||
int in_fd,
|
||||
os::libc::FILE out_file,
|
||||
mutable bool finished) {
|
||||
fn get_id() -> int {ret pid;}
|
||||
obj new_program(int pid,
|
||||
int in_fd,
|
||||
os::libc::FILE out_file,
|
||||
mutable bool finished) {
|
||||
fn get_id() -> int { ret pid; }
|
||||
fn input() -> io::writer {
|
||||
ret io::new_writer(io::fd_buf_writer(in_fd, false));
|
||||
}
|
||||
fn output() -> io::reader {
|
||||
ret io::new_reader(io::FILE_buf_reader(out_file, false));
|
||||
}
|
||||
fn close_input() {
|
||||
os::libc::close(in_fd);
|
||||
}
|
||||
fn close_input() { os::libc::close(in_fd); }
|
||||
fn finish() -> int {
|
||||
if (finished) {ret 0;}
|
||||
if (finished) { ret 0; }
|
||||
finished = true;
|
||||
os::libc::close(in_fd);
|
||||
ret os::waitpid(pid);
|
||||
}
|
||||
drop {
|
||||
if (!finished) {
|
||||
os::libc::close(in_fd);
|
||||
os::waitpid(pid);
|
||||
}
|
||||
os::libc::fclose(out_file);
|
||||
}
|
||||
}drop {
|
||||
if (!finished) { os::libc::close(in_fd); os::waitpid(pid); }
|
||||
os::libc::fclose(out_file);
|
||||
}
|
||||
}
|
||||
ret @new_program(pid, pipe_input._1,
|
||||
os::fd_FILE(pipe_output._0),
|
||||
false);
|
||||
ret @new_program(pid, pipe_input._1, os::fd_FILE(pipe_output._0), false);
|
||||
}
|
||||
|
||||
fn program_output(str prog, vec[str] args)
|
||||
-> rec(int status, str out) {
|
||||
fn program_output(str prog, vec[str] args) -> rec(int status, str out) {
|
||||
auto pr = start_program(prog, args);
|
||||
pr.close_input();
|
||||
auto out = pr.output();
|
||||
|
@ -84,8 +74,6 @@ fn program_output(str prog, vec[str] args)
|
|||
}
|
||||
ret rec(status=pr.finish(), out=buf);
|
||||
}
|
||||
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
// fill-column: 78;
|
||||
|
|
196
src/lib/sha1.rs
196
src/lib/sha1.rs
|
@ -1,116 +1,119 @@
|
|||
|
||||
|
||||
/*
|
||||
* A SHA-1 implementation derived from Paul E. Jones's reference
|
||||
* implementation, which is written for clarity, not speed. At some
|
||||
* point this will want to be rewritten.
|
||||
*/
|
||||
|
||||
export sha1;
|
||||
export mk_sha1;
|
||||
|
||||
state type sha1 = state obj {
|
||||
// Provide message input as bytes
|
||||
fn input(&vec[u8]);
|
||||
type sha1 =
|
||||
obj {
|
||||
|
||||
// Provide message input as string
|
||||
fn input_str(&str);
|
||||
// Provide message input as bytes
|
||||
fn input(&vec[u8]) ;
|
||||
|
||||
// Read the digest as a vector of 20 bytes. After
|
||||
// calling this no further input may provided
|
||||
// until reset is called
|
||||
fn result() -> vec[u8];
|
||||
// Provide message input as string
|
||||
fn input_str(&str) ;
|
||||
|
||||
// Same as above, just a hex-string version.
|
||||
fn result_str() -> str;
|
||||
// Read the digest as a vector of 20 bytes. After
|
||||
// calling this no further input may provided
|
||||
// until reset is called
|
||||
fn result() -> vec[u8] ;
|
||||
|
||||
// Same as above, just a hex-string version.
|
||||
fn result_str() -> str ;
|
||||
|
||||
// Reset the sha1 state for reuse. This is called
|
||||
// automatically during construction
|
||||
fn reset() ;
|
||||
};
|
||||
|
||||
// Reset the sha1 state for reuse. This is called
|
||||
// automatically during construction
|
||||
fn reset();
|
||||
};
|
||||
|
||||
// Some unexported constants
|
||||
const uint digest_buf_len = 5u;
|
||||
|
||||
const uint msg_block_len = 64u;
|
||||
|
||||
const uint work_buf_len = 80u;
|
||||
|
||||
const u32 k0 = 0x5A827999u32;
|
||||
|
||||
const u32 k1 = 0x6ED9EBA1u32;
|
||||
|
||||
const u32 k2 = 0x8F1BBCDCu32;
|
||||
|
||||
const u32 k3 = 0xCA62C1D6u32;
|
||||
|
||||
|
||||
// Builds a sha1 object
|
||||
fn mk_sha1() -> sha1 {
|
||||
|
||||
state type sha1state = rec(vec[mutable u32] h,
|
||||
mutable u32 len_low,
|
||||
mutable u32 len_high,
|
||||
vec[mutable u8] msg_block,
|
||||
mutable uint msg_block_idx,
|
||||
mutable bool computed,
|
||||
vec[mutable u32] work_buf);
|
||||
type sha1state =
|
||||
rec(vec[mutable u32] h,
|
||||
mutable u32 len_low,
|
||||
mutable u32 len_high,
|
||||
vec[mutable u8] msg_block,
|
||||
mutable uint msg_block_idx,
|
||||
mutable bool computed,
|
||||
vec[mutable u32] work_buf);
|
||||
|
||||
fn add_input(&sha1state st, &vec[u8] msg) {
|
||||
// FIXME: Should be typestate precondition
|
||||
assert (!st.computed);
|
||||
|
||||
assert (!st.computed);
|
||||
for (u8 element in msg) {
|
||||
st.msg_block.(st.msg_block_idx) = element;
|
||||
st.msg_block_idx += 1u;
|
||||
|
||||
st.len_low += 8u32;
|
||||
if (st.len_low == 0u32) {
|
||||
st.len_high += 1u32;
|
||||
if (st.len_high == 0u32) {
|
||||
// FIXME: Need better failure mode
|
||||
|
||||
fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (st.msg_block_idx == msg_block_len) {
|
||||
process_msg_block(st);
|
||||
}
|
||||
if (st.msg_block_idx == msg_block_len) { process_msg_block(st); }
|
||||
}
|
||||
}
|
||||
|
||||
fn process_msg_block(&sha1state st) {
|
||||
|
||||
// FIXME: Make precondition
|
||||
|
||||
assert (vec::len(st.h) == digest_buf_len);
|
||||
assert (vec::len(st.work_buf) == work_buf_len);
|
||||
|
||||
let int t; // Loop counter
|
||||
auto w = st.work_buf;
|
||||
|
||||
auto w = st.work_buf;
|
||||
// Initialize the first 16 words of the vector w
|
||||
|
||||
t = 0;
|
||||
while (t < 16) {
|
||||
auto tmp;
|
||||
tmp = (st.msg_block.(t * 4) as u32) << 24u32;
|
||||
tmp = tmp | ((st.msg_block.(t * 4 + 1) as u32) << 16u32);
|
||||
tmp = tmp | ((st.msg_block.(t * 4 + 2) as u32) << 8u32);
|
||||
tmp = tmp | (st.msg_block.(t * 4 + 1) as u32) << 16u32;
|
||||
tmp = tmp | (st.msg_block.(t * 4 + 2) as u32) << 8u32;
|
||||
tmp = tmp | (st.msg_block.(t * 4 + 3) as u32);
|
||||
w.(t) = tmp;
|
||||
t += 1;
|
||||
}
|
||||
|
||||
// Initialize the rest of vector w
|
||||
|
||||
while (t < 80) {
|
||||
auto val = w.(t-3) ^ w.(t-8) ^ w.(t-14) ^ w.(t-16);
|
||||
auto val = w.(t - 3) ^ w.(t - 8) ^ w.(t - 14) ^ w.(t - 16);
|
||||
w.(t) = circular_shift(1u32, val);
|
||||
t += 1;
|
||||
}
|
||||
|
||||
auto a = st.h.(0);
|
||||
auto b = st.h.(1);
|
||||
auto c = st.h.(2);
|
||||
auto d = st.h.(3);
|
||||
auto e = st.h.(4);
|
||||
|
||||
let u32 temp;
|
||||
|
||||
t = 0;
|
||||
while (t < 20) {
|
||||
temp = circular_shift(5u32, a)
|
||||
+ ((b & c) | ((!b) & d)) + e + w.(t) + k0;
|
||||
temp =
|
||||
circular_shift(5u32, a) + (b & c | !b & d) + e + w.(t) + k0;
|
||||
e = d;
|
||||
d = c;
|
||||
c = circular_shift(30u32, b);
|
||||
|
@ -118,10 +121,8 @@ fn mk_sha1() -> sha1 {
|
|||
a = temp;
|
||||
t += 1;
|
||||
}
|
||||
|
||||
while (t < 40) {
|
||||
temp = circular_shift(5u32, a)
|
||||
+ (b ^ c ^ d) + e + w.(t) + k1;
|
||||
temp = circular_shift(5u32, a) + (b ^ c ^ d) + e + w.(t) + k1;
|
||||
e = d;
|
||||
d = c;
|
||||
c = circular_shift(30u32, b);
|
||||
|
@ -129,10 +130,10 @@ fn mk_sha1() -> sha1 {
|
|||
a = temp;
|
||||
t += 1;
|
||||
}
|
||||
|
||||
while (t < 60) {
|
||||
temp = circular_shift(5u32, a)
|
||||
+ ((b & c) | (b & d) | (c & d)) + e + w.(t) + k2;
|
||||
temp =
|
||||
circular_shift(5u32, a) + (b & c | b & d | c & d) + e + w.(t)
|
||||
+ k2;
|
||||
e = d;
|
||||
d = c;
|
||||
c = circular_shift(30u32, b);
|
||||
|
@ -140,10 +141,8 @@ fn mk_sha1() -> sha1 {
|
|||
a = temp;
|
||||
t += 1;
|
||||
}
|
||||
|
||||
while (t < 80) {
|
||||
temp = circular_shift(5u32, a)
|
||||
+ (b ^ c ^ d) + e + w.(t) + k3;
|
||||
temp = circular_shift(5u32, a) + (b ^ c ^ d) + e + w.(t) + k3;
|
||||
e = d;
|
||||
d = c;
|
||||
c = circular_shift(30u32, b);
|
||||
|
@ -151,40 +150,32 @@ fn mk_sha1() -> sha1 {
|
|||
a = temp;
|
||||
t += 1;
|
||||
}
|
||||
|
||||
st.h.(0) = st.h.(0) + a;
|
||||
st.h.(1) = st.h.(1) + b;
|
||||
st.h.(2) = st.h.(2) + c;
|
||||
st.h.(3) = st.h.(3) + d;
|
||||
st.h.(4) = st.h.(4) + e;
|
||||
|
||||
st.msg_block_idx = 0u;
|
||||
}
|
||||
|
||||
fn circular_shift(u32 bits, u32 word) -> u32 {
|
||||
// FIXME: This is a workaround for a rustboot
|
||||
// "unrecognized quads" codegen bug
|
||||
|
||||
auto bits_hack = bits;
|
||||
ret (word << bits_hack) | (word >> (32u32 - bits));
|
||||
ret word << bits_hack | word >> 32u32 - bits;
|
||||
}
|
||||
|
||||
fn mk_result(&sha1state st) -> vec[u8] {
|
||||
if (!st.computed) {
|
||||
pad_msg(st);
|
||||
st.computed = true;
|
||||
}
|
||||
|
||||
if (!st.computed) { pad_msg(st); st.computed = true; }
|
||||
let vec[u8] res = [];
|
||||
for (u32 hpart in st.h) {
|
||||
auto a = (hpart >> 24u32) & 0xFFu32 as u8;
|
||||
auto b = (hpart >> 16u32) & 0xFFu32 as u8;
|
||||
auto c = (hpart >> 8u32) & 0xFFu32 as u8;
|
||||
auto d = (hpart & 0xFFu32 as u8);
|
||||
res += [a,b,c,d];
|
||||
auto a = hpart >> 24u32 & 0xFFu32 as u8;
|
||||
auto b = hpart >> 16u32 & 0xFFu32 as u8;
|
||||
auto c = hpart >> 8u32 & 0xFFu32 as u8;
|
||||
auto d = hpart & 0xFFu32 as u8;
|
||||
res += [a, b, c, d];
|
||||
}
|
||||
ret res;
|
||||
}
|
||||
|
||||
/*
|
||||
* According to the standard, the message must be padded to an even
|
||||
* 512 bits. The first padding bit must be a '1'. The last 64 bits
|
||||
|
@ -194,101 +185,82 @@ fn mk_sha1() -> sha1 {
|
|||
* call process_msg_block() appropriately. When it returns, it
|
||||
* can be assumed that the message digest has been computed.
|
||||
*/
|
||||
|
||||
fn pad_msg(&sha1state st) {
|
||||
// FIXME: Should be a precondition
|
||||
assert (vec::len(st.msg_block) == msg_block_len);
|
||||
|
||||
assert (vec::len(st.msg_block) == msg_block_len);
|
||||
/*
|
||||
* Check to see if the current message block is too small to hold
|
||||
* the initial padding bits and length. If so, we will pad the
|
||||
* block, process it, and then continue padding into a second block.
|
||||
*/
|
||||
|
||||
if (st.msg_block_idx > 55u) {
|
||||
st.msg_block.(st.msg_block_idx) = 0x80u8;
|
||||
st.msg_block_idx += 1u;
|
||||
|
||||
while (st.msg_block_idx < msg_block_len) {
|
||||
st.msg_block.(st.msg_block_idx) = 0u8;
|
||||
st.msg_block_idx += 1u;
|
||||
}
|
||||
|
||||
process_msg_block(st);
|
||||
} else {
|
||||
st.msg_block.(st.msg_block_idx) = 0x80u8;
|
||||
st.msg_block_idx += 1u;
|
||||
}
|
||||
|
||||
while (st.msg_block_idx < 56u) {
|
||||
st.msg_block.(st.msg_block_idx) = 0u8;
|
||||
st.msg_block_idx += 1u;
|
||||
}
|
||||
|
||||
// Store the message length as the last 8 octets
|
||||
st.msg_block.(56) = (st.len_high >> 24u32) & 0xFFu32 as u8;
|
||||
st.msg_block.(57) = (st.len_high >> 16u32) & 0xFFu32 as u8;
|
||||
st.msg_block.(58) = (st.len_high >> 8u32) & 0xFFu32 as u8;
|
||||
st.msg_block.(59) = st.len_high & 0xFFu32 as u8;
|
||||
st.msg_block.(60) = (st.len_low >> 24u32) & 0xFFu32 as u8;
|
||||
st.msg_block.(61) = (st.len_low >> 16u32) & 0xFFu32 as u8;
|
||||
st.msg_block.(62) = (st.len_low >> 8u32) & 0xFFu32 as u8;
|
||||
st.msg_block.(63) = st.len_low & 0xFFu32 as u8;
|
||||
|
||||
st.msg_block.(56) = st.len_high >> 24u32 & 0xFFu32 as u8;
|
||||
st.msg_block.(57) = st.len_high >> 16u32 & 0xFFu32 as u8;
|
||||
st.msg_block.(58) = st.len_high >> 8u32 & 0xFFu32 as u8;
|
||||
st.msg_block.(59) = st.len_high & 0xFFu32 as u8;
|
||||
st.msg_block.(60) = st.len_low >> 24u32 & 0xFFu32 as u8;
|
||||
st.msg_block.(61) = st.len_low >> 16u32 & 0xFFu32 as u8;
|
||||
st.msg_block.(62) = st.len_low >> 8u32 & 0xFFu32 as u8;
|
||||
st.msg_block.(63) = st.len_low & 0xFFu32 as u8;
|
||||
process_msg_block(st);
|
||||
}
|
||||
|
||||
state obj sha1(sha1state st) {
|
||||
|
||||
obj sha1(sha1state st) {
|
||||
fn reset() {
|
||||
// FIXME: Should be typestate precondition
|
||||
assert (vec::len(st.h) == digest_buf_len);
|
||||
|
||||
assert (vec::len(st.h) == digest_buf_len);
|
||||
st.len_low = 0u32;
|
||||
st.len_high = 0u32;
|
||||
st.msg_block_idx = 0u;
|
||||
|
||||
st.h.(0) = 0x67452301u32;
|
||||
st.h.(1) = 0xEFCDAB89u32;
|
||||
st.h.(2) = 0x98BADCFEu32;
|
||||
st.h.(3) = 0x10325476u32;
|
||||
st.h.(4) = 0xC3D2E1F0u32;
|
||||
|
||||
st.computed = false;
|
||||
}
|
||||
|
||||
fn input(&vec[u8] msg) {
|
||||
add_input(st, msg);
|
||||
}
|
||||
|
||||
fn input_str(&str msg) {
|
||||
add_input(st, str::bytes(msg));
|
||||
}
|
||||
|
||||
fn result() -> vec[u8] {
|
||||
ret mk_result(st);
|
||||
}
|
||||
|
||||
fn input(&vec[u8] msg) { add_input(st, msg); }
|
||||
fn input_str(&str msg) { add_input(st, str::bytes(msg)); }
|
||||
fn result() -> vec[u8] { ret mk_result(st); }
|
||||
fn result_str() -> str {
|
||||
auto r = mk_result(st);
|
||||
auto s = "";
|
||||
for (u8 b in r) {
|
||||
s += uint::to_str(b as uint, 16u);
|
||||
}
|
||||
for (u8 b in r) { s += uint::to_str(b as uint, 16u); }
|
||||
ret s;
|
||||
}
|
||||
}
|
||||
|
||||
auto st = rec(h = vec::init_elt_mut[u32](0u32, digest_buf_len),
|
||||
mutable len_low = 0u32,
|
||||
mutable len_high = 0u32,
|
||||
msg_block = vec::init_elt_mut[u8](0u8, msg_block_len),
|
||||
mutable msg_block_idx = 0u,
|
||||
mutable computed = false,
|
||||
work_buf = vec::init_elt_mut[u32](0u32, work_buf_len));
|
||||
auto st =
|
||||
rec(h=vec::init_elt_mut[u32](0u32, digest_buf_len),
|
||||
mutable len_low=0u32,
|
||||
mutable len_high=0u32,
|
||||
msg_block=vec::init_elt_mut[u8](0u8, msg_block_len),
|
||||
mutable msg_block_idx=0u,
|
||||
mutable computed=false,
|
||||
work_buf=vec::init_elt_mut[u32](0u32, work_buf_len));
|
||||
auto sh = sha1(st);
|
||||
sh.reset();
|
||||
ret sh;
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
|
||||
|
||||
/// A simple map based on a vector for small integer keys. Space requirements
|
||||
/// are O(highest integer key).
|
||||
|
||||
import option::none;
|
||||
import option::some;
|
||||
|
||||
type smallintmap[T] = rec(mutable vec[mutable option::t[T]] v);
|
||||
|
||||
fn mk[T]() -> smallintmap[T] {
|
||||
let vec[mutable option::t[T]] v = [mutable];
|
||||
let vec[mutable option::t[T]] v = [mutable ];
|
||||
ret rec(mutable v=v);
|
||||
}
|
||||
|
||||
|
@ -38,7 +39,4 @@ fn truncate[T](&smallintmap[T] m, uint len) {
|
|||
m.v = vec::slice_mut[option::t[T]](m.v, 0u, len);
|
||||
}
|
||||
|
||||
fn max_key[T](&smallintmap[T] m) -> uint {
|
||||
ret vec::len[option::t[T]](m.v);
|
||||
}
|
||||
|
||||
fn max_key[T](&smallintmap[T] m) -> uint { ret vec::len[option::t[T]](m.v); }
|
|
@ -1,15 +1,14 @@
|
|||
|
||||
import vec::len;
|
||||
import vec::slice;
|
||||
|
||||
export lteq;
|
||||
export merge_sort;
|
||||
export quick_sort;
|
||||
export quick_sort3;
|
||||
|
||||
type lteq[T] = fn(&T a, &T b) -> bool;
|
||||
type lteq[T] = fn(&T, &T) -> bool ;
|
||||
|
||||
fn merge_sort[T](lteq[T] le, vec[T] v) -> vec[T] {
|
||||
|
||||
fn merge[T](lteq[T] le, vec[T] a, vec[T] b) -> vec[T] {
|
||||
let vec[T] res = [];
|
||||
let uint a_len = len[T](a);
|
||||
|
@ -20,28 +19,18 @@ fn merge_sort[T](lteq[T] le, vec[T] v) -> vec[T] {
|
|||
if (le(a.(a_ix), b.(b_ix))) {
|
||||
res += [a.(a_ix)];
|
||||
a_ix += 1u;
|
||||
} else {
|
||||
res += [b.(b_ix)];
|
||||
b_ix += 1u;
|
||||
}
|
||||
} else { res += [b.(b_ix)]; b_ix += 1u; }
|
||||
}
|
||||
res += slice[T](a, a_ix, a_len);
|
||||
res += slice[T](b, b_ix, b_len);
|
||||
ret res;
|
||||
}
|
||||
|
||||
let uint v_len = len[T](v);
|
||||
|
||||
if (v_len <= 1u) {
|
||||
ret v;
|
||||
}
|
||||
|
||||
if (v_len <= 1u) { ret v; }
|
||||
let uint mid = v_len / 2u;
|
||||
let vec[T] a = slice[T](v, 0u, mid);
|
||||
let vec[T] b = slice[T](v, mid, v_len);
|
||||
ret merge[T](le,
|
||||
merge_sort[T](le, a),
|
||||
merge_sort[T](le, b));
|
||||
ret merge[T](le, merge_sort[T](le, a), merge_sort[T](le, b));
|
||||
}
|
||||
|
||||
fn swap[T](vec[mutable T] arr, uint x, uint y) {
|
||||
|
@ -50,17 +39,16 @@ fn swap[T](vec[mutable T] arr, uint x, uint y) {
|
|||
arr.(y) = a;
|
||||
}
|
||||
|
||||
fn part[T](lteq[T] compare_func, vec[mutable T] arr, uint left,
|
||||
uint right, uint pivot) -> uint {
|
||||
|
||||
fn part[T](lteq[T] compare_func, vec[mutable T] arr, uint left, uint right,
|
||||
uint pivot) -> uint {
|
||||
auto pivot_value = arr.(pivot);
|
||||
swap[T](arr, pivot, right);
|
||||
let uint storage_index = left;
|
||||
let uint i = left;
|
||||
while (i<right) {
|
||||
if (compare_func({arr.(i)}, pivot_value)) {
|
||||
swap[T](arr, i, storage_index);
|
||||
storage_index += 1u;
|
||||
while (i < right) {
|
||||
if (compare_func({ arr.(i) }, pivot_value)) {
|
||||
swap[T](arr, i, storage_index);
|
||||
storage_index += 1u;
|
||||
}
|
||||
i += 1u;
|
||||
}
|
||||
|
@ -68,26 +56,19 @@ fn part[T](lteq[T] compare_func, vec[mutable T] arr, uint left,
|
|||
ret storage_index;
|
||||
}
|
||||
|
||||
fn qsort[T](lteq[T] compare_func, vec[mutable T] arr, uint left,
|
||||
uint right) {
|
||||
|
||||
fn qsort[T](lteq[T] compare_func, vec[mutable T] arr, uint left, uint right) {
|
||||
if (right > left) {
|
||||
auto pivot = (left+right)/2u;
|
||||
auto pivot = (left + right) / 2u;
|
||||
auto new_pivot = part[T](compare_func, arr, left, right, pivot);
|
||||
if (new_pivot == 0u) {
|
||||
ret;
|
||||
}
|
||||
if (new_pivot == 0u) { ret; }
|
||||
qsort[T](compare_func, arr, left, new_pivot - 1u);
|
||||
qsort[T](compare_func, arr, new_pivot + 1u, right);
|
||||
}
|
||||
}
|
||||
|
||||
fn quick_sort[T](lteq[T] compare_func, vec[mutable T] arr) {
|
||||
|
||||
if (len[T](arr) == 0u) {
|
||||
ret;
|
||||
}
|
||||
qsort[T](compare_func, arr, 0u, (len[T](arr)) - 1u);
|
||||
if (len[T](arr) == 0u) { ret; }
|
||||
qsort[T](compare_func, arr, 0u, len[T](arr) - 1u);
|
||||
}
|
||||
|
||||
|
||||
|
@ -95,81 +76,60 @@ fn quick_sort[T](lteq[T] compare_func, vec[mutable T] arr) {
|
|||
// http://www.cs.princeton.edu/~rs/talks/QuicksortIsOptimal.pdf
|
||||
// According to these slides this is the algorithm of choice for
|
||||
// 'randomly ordered keys, abstract compare' & 'small number of key values'
|
||||
|
||||
fn qsort3[T](lteq[T] compare_func_lt, lteq[T] compare_func_eq,
|
||||
vec[mutable T] arr, int left, int right) {
|
||||
|
||||
if (right <= left) {
|
||||
ret;
|
||||
}
|
||||
|
||||
if (right <= left) { ret; }
|
||||
let T v = arr.(right);
|
||||
let int i = left - 1;
|
||||
let int j = right;
|
||||
let int p = i;
|
||||
let int q = j;
|
||||
|
||||
while (true) {
|
||||
i += 1;
|
||||
while (compare_func_lt({arr.(i)}, v)) {
|
||||
i += 1;
|
||||
}
|
||||
while (compare_func_lt({ arr.(i) }, v)) { i += 1; }
|
||||
j -= 1;
|
||||
while (compare_func_lt(v, {arr.(j)})) {
|
||||
if (j == left) {
|
||||
break;
|
||||
}
|
||||
while (compare_func_lt(v, { arr.(j) })) {
|
||||
if (j == left) { break; }
|
||||
j -= 1;
|
||||
}
|
||||
if (i >= j) {
|
||||
break;
|
||||
}
|
||||
if (i >= j) { break; }
|
||||
swap[T](arr, i as uint, j as uint);
|
||||
if (compare_func_eq({arr.(i)}, v)) {
|
||||
if (compare_func_eq({ arr.(i) }, v)) {
|
||||
p += 1;
|
||||
swap[T](arr, p as uint, i as uint);
|
||||
}
|
||||
if (compare_func_eq(v, {arr.(j)})) {
|
||||
if (compare_func_eq(v, { arr.(j) })) {
|
||||
q -= 1;
|
||||
swap[T](arr, j as uint, q as uint);
|
||||
}
|
||||
}
|
||||
}
|
||||
swap[T](arr, i as uint, right as uint);
|
||||
j = i - 1;
|
||||
i += 1;
|
||||
|
||||
let int k = left;
|
||||
while (k < p) {
|
||||
swap[T](arr, k as uint, j as uint);
|
||||
k += 1;
|
||||
j -= 1;
|
||||
if (k == vec::len[T](arr) as int) {
|
||||
break;
|
||||
}
|
||||
if (k == vec::len[T](arr) as int) { break; }
|
||||
}
|
||||
k = right - 1;
|
||||
while (k > q) {
|
||||
swap[T](arr, i as uint, k as uint);
|
||||
k -= 1;
|
||||
i += 1;
|
||||
if (k == 0) {
|
||||
break;
|
||||
}
|
||||
if (k == 0) { break; }
|
||||
}
|
||||
|
||||
qsort3[T](compare_func_lt, compare_func_eq, arr, left, j);
|
||||
qsort3[T](compare_func_lt, compare_func_eq, arr, i, right);
|
||||
}
|
||||
|
||||
fn quick_sort3[T](lteq[T] compare_func_lt, lteq[T] compare_func_eq,
|
||||
vec[mutable T] arr) {
|
||||
if (vec::len[T](arr) == 0u) {
|
||||
ret;
|
||||
}
|
||||
vec[mutable T] arr) {
|
||||
if (vec::len[T](arr) == 0u) { ret; }
|
||||
qsort3[T](compare_func_lt, compare_func_eq, arr, 0,
|
||||
(vec::len[T](arr) as int) - 1);
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
|
|
282
src/lib/str.rs
282
src/lib/str.rs
|
@ -1,7 +1,6 @@
|
|||
|
||||
import rustrt::sbuf;
|
||||
|
||||
import vec::rustrt::vbuf;
|
||||
|
||||
export sbuf;
|
||||
export rustrt;
|
||||
export eq;
|
||||
|
@ -63,16 +62,12 @@ native "rust" mod rustrt {
|
|||
|
||||
fn eq(&str a, &str b) -> bool {
|
||||
let uint i = byte_len(a);
|
||||
if (byte_len(b) != i) {
|
||||
ret false;
|
||||
}
|
||||
if (byte_len(b) != i) { ret false; }
|
||||
while (i > 0u) {
|
||||
i -= 1u;
|
||||
auto cha = a.(i);
|
||||
auto chb = b.(i);
|
||||
if (cha != chb) {
|
||||
ret false;
|
||||
}
|
||||
if (cha != chb) { ret false; }
|
||||
}
|
||||
ret true;
|
||||
}
|
||||
|
@ -81,62 +76,62 @@ fn lteq(&str a, &str b) -> bool {
|
|||
let uint i = byte_len(a);
|
||||
let uint j = byte_len(b);
|
||||
let uint n = i;
|
||||
if (j < n) {
|
||||
n = j;
|
||||
}
|
||||
|
||||
if (j < n) { n = j; }
|
||||
let uint x = 0u;
|
||||
while (x < n) {
|
||||
auto cha = a.(x);
|
||||
auto chb = b.(x);
|
||||
if (cha < chb) {
|
||||
ret true;
|
||||
}
|
||||
else if (cha > chb) {
|
||||
ret false;
|
||||
}
|
||||
if (cha < chb) { ret true; } else if (cha > chb) { ret false; }
|
||||
x += 1u;
|
||||
}
|
||||
|
||||
ret i <= j;
|
||||
}
|
||||
|
||||
|
||||
fn hash(&str s) -> uint {
|
||||
// djb hash.
|
||||
// FIXME: replace with murmur.
|
||||
|
||||
let uint u = 5381u;
|
||||
for (u8 c in s) {
|
||||
u *= 33u;
|
||||
u += (c as uint);
|
||||
}
|
||||
for (u8 c in s) { u *= 33u; u += c as uint; }
|
||||
ret u;
|
||||
}
|
||||
|
||||
|
||||
// UTF-8 tags and ranges
|
||||
const u8 tag_cont_u8 = 0x80_u8;
|
||||
const uint tag_cont = 0x80_u;
|
||||
const uint max_one_b = 0x80_u;
|
||||
const uint tag_two_b = 0xc0_u;
|
||||
const uint max_two_b = 0x800_u;
|
||||
const uint tag_three_b = 0xe0_u;
|
||||
const uint max_three_b = 0x10000_u;
|
||||
const uint tag_four_b = 0xf0_u;
|
||||
const uint max_four_b = 0x200000_u;
|
||||
const uint tag_five_b = 0xf8_u;
|
||||
const uint max_five_b = 0x4000000_u;
|
||||
const uint tag_six_b = 0xfc_u;
|
||||
const u8 tag_cont_u8 = 128u8;
|
||||
|
||||
const uint tag_cont = 128u;
|
||||
|
||||
const uint max_one_b = 128u;
|
||||
|
||||
const uint tag_two_b = 192u;
|
||||
|
||||
const uint max_two_b = 2048u;
|
||||
|
||||
const uint tag_three_b = 224u;
|
||||
|
||||
const uint max_three_b = 65536u;
|
||||
|
||||
const uint tag_four_b = 240u;
|
||||
|
||||
const uint max_four_b = 2097152u;
|
||||
|
||||
const uint tag_five_b = 248u;
|
||||
|
||||
const uint max_five_b = 67108864u;
|
||||
|
||||
const uint tag_six_b = 252u;
|
||||
|
||||
fn is_utf8(vec[u8] v) -> bool {
|
||||
auto i = 0u;
|
||||
auto total = vec::len[u8](v);
|
||||
while (i < total) {
|
||||
auto chsize = utf8_char_width(v.(i));
|
||||
if (chsize == 0u) {ret false;}
|
||||
if (i + chsize > total) {ret false;}
|
||||
if (chsize == 0u) { ret false; }
|
||||
if (i + chsize > total) { ret false; }
|
||||
i += 1u;
|
||||
while (chsize > 1u) {
|
||||
if (v.(i) & 0xc0_u8 != tag_cont_u8) {ret false;}
|
||||
if (v.(i) & 192u8 != tag_cont_u8) { ret false; }
|
||||
i += 1u;
|
||||
chsize -= 1u;
|
||||
}
|
||||
|
@ -146,52 +141,35 @@ fn is_utf8(vec[u8] v) -> bool {
|
|||
|
||||
fn is_ascii(str s) -> bool {
|
||||
let uint i = byte_len(s);
|
||||
while (i > 0u) {
|
||||
i -= 1u;
|
||||
if ((s.(i) & 0x80_u8) != 0u8) {
|
||||
ret false;
|
||||
}
|
||||
}
|
||||
while (i > 0u) { i -= 1u; if (s.(i) & 128u8 != 0u8) { ret false; } }
|
||||
ret true;
|
||||
}
|
||||
|
||||
fn alloc(uint n_bytes) -> str {
|
||||
ret rustrt::str_alloc(n_bytes);
|
||||
}
|
||||
fn alloc(uint n_bytes) -> str { ret rustrt::str_alloc(n_bytes); }
|
||||
|
||||
|
||||
// Returns the number of bytes (a.k.a. UTF-8 code units) in s.
|
||||
// Contrast with a function that would return the number of code
|
||||
// points (char's), combining character sequences, words, etc. See
|
||||
// http://icu-project.org/apiref/icu4c/classBreakIterator.html for a
|
||||
// way to implement those.
|
||||
fn byte_len(str s) -> uint {
|
||||
ret rustrt::str_byte_len(s);
|
||||
}
|
||||
fn byte_len(str s) -> uint { ret rustrt::str_byte_len(s); }
|
||||
|
||||
fn buf(str s) -> sbuf {
|
||||
ret rustrt::str_buf(s);
|
||||
}
|
||||
fn buf(str s) -> sbuf { ret rustrt::str_buf(s); }
|
||||
|
||||
fn bytes(str s) -> vec[u8] {
|
||||
ret rustrt::str_vec(s);
|
||||
}
|
||||
fn bytes(str s) -> vec[u8] { ret rustrt::str_vec(s); }
|
||||
|
||||
fn from_bytes(vec[u8] v) -> str { ret rustrt::str_from_vec(v); }
|
||||
|
||||
fn from_bytes(vec[u8] v) : is_utf8(v) -> str {
|
||||
ret rustrt::str_from_vec(v);
|
||||
}
|
||||
|
||||
// FIXME temp thing
|
||||
fn unsafe_from_bytes(vec[mutable? u8] v) -> str {
|
||||
ret rustrt::str_from_vec(v);
|
||||
}
|
||||
|
||||
fn unsafe_from_byte(u8 u) -> str {
|
||||
ret rustrt::str_from_vec([u]);
|
||||
}
|
||||
fn unsafe_from_byte(u8 u) -> str { ret rustrt::str_from_vec([u]); }
|
||||
|
||||
fn str_from_cstr(sbuf cstr) -> str {
|
||||
ret rustrt::str_from_cstr(cstr);
|
||||
}
|
||||
fn str_from_cstr(sbuf cstr) -> str { ret rustrt::str_from_cstr(cstr); }
|
||||
|
||||
fn str_from_buf(sbuf buf, uint len) -> str {
|
||||
ret rustrt::str_from_buf(buf, len);
|
||||
|
@ -202,30 +180,30 @@ fn push_utf8_bytes(&mutable str s, char ch) {
|
|||
if (code < max_one_b) {
|
||||
s = rustrt::str_push_byte(s, code);
|
||||
} else if (code < max_two_b) {
|
||||
s = rustrt::str_push_byte(s, ((code >> 6u) & 0x1f_u) | tag_two_b);
|
||||
s = rustrt::str_push_byte(s, (code & 0x3f_u) | tag_cont);
|
||||
s = rustrt::str_push_byte(s, code >> 6u & 31u | tag_two_b);
|
||||
s = rustrt::str_push_byte(s, code & 63u | tag_cont);
|
||||
} else if (code < max_three_b) {
|
||||
s = rustrt::str_push_byte(s, ((code >> 12u) & 0x0f_u) | tag_three_b);
|
||||
s = rustrt::str_push_byte(s, ((code >> 6u) & 0x3f_u) | tag_cont);
|
||||
s = rustrt::str_push_byte(s, (code & 0x3f_u) | tag_cont);
|
||||
s = rustrt::str_push_byte(s, code >> 12u & 15u | tag_three_b);
|
||||
s = rustrt::str_push_byte(s, code >> 6u & 63u | tag_cont);
|
||||
s = rustrt::str_push_byte(s, code & 63u | tag_cont);
|
||||
} else if (code < max_four_b) {
|
||||
s = rustrt::str_push_byte(s, ((code >> 18u) & 0x07_u) | tag_four_b);
|
||||
s = rustrt::str_push_byte(s, ((code >> 12u) & 0x3f_u) | tag_cont);
|
||||
s = rustrt::str_push_byte(s, ((code >> 6u) & 0x3f_u) | tag_cont);
|
||||
s = rustrt::str_push_byte(s, (code & 0x3f_u) | tag_cont);
|
||||
s = rustrt::str_push_byte(s, code >> 18u & 7u | tag_four_b);
|
||||
s = rustrt::str_push_byte(s, code >> 12u & 63u | tag_cont);
|
||||
s = rustrt::str_push_byte(s, code >> 6u & 63u | tag_cont);
|
||||
s = rustrt::str_push_byte(s, code & 63u | tag_cont);
|
||||
} else if (code < max_five_b) {
|
||||
s = rustrt::str_push_byte(s, ((code >> 24u) & 0x03_u) | tag_five_b);
|
||||
s = rustrt::str_push_byte(s, ((code >> 18u) & 0x3f_u) | tag_cont);
|
||||
s = rustrt::str_push_byte(s, ((code >> 12u) & 0x3f_u) | tag_cont);
|
||||
s = rustrt::str_push_byte(s, ((code >> 6u) & 0x3f_u) | tag_cont);
|
||||
s = rustrt::str_push_byte(s, (code & 0x3f_u) | tag_cont);
|
||||
s = rustrt::str_push_byte(s, code >> 24u & 3u | tag_five_b);
|
||||
s = rustrt::str_push_byte(s, code >> 18u & 63u | tag_cont);
|
||||
s = rustrt::str_push_byte(s, code >> 12u & 63u | tag_cont);
|
||||
s = rustrt::str_push_byte(s, code >> 6u & 63u | tag_cont);
|
||||
s = rustrt::str_push_byte(s, code & 63u | tag_cont);
|
||||
} else {
|
||||
s = rustrt::str_push_byte(s, ((code >> 30u) & 0x01_u) | tag_six_b);
|
||||
s = rustrt::str_push_byte(s, ((code >> 24u) & 0x3f_u) | tag_cont);
|
||||
s = rustrt::str_push_byte(s, ((code >> 18u) & 0x3f_u) | tag_cont);
|
||||
s = rustrt::str_push_byte(s, ((code >> 12u) & 0x3f_u) | tag_cont);
|
||||
s = rustrt::str_push_byte(s, ((code >> 6u) & 0x3f_u) | tag_cont);
|
||||
s = rustrt::str_push_byte(s, (code & 0x3f_u) | tag_cont);
|
||||
s = rustrt::str_push_byte(s, code >> 30u & 1u | tag_six_b);
|
||||
s = rustrt::str_push_byte(s, code >> 24u & 63u | tag_cont);
|
||||
s = rustrt::str_push_byte(s, code >> 18u & 63u | tag_cont);
|
||||
s = rustrt::str_push_byte(s, code >> 12u & 63u | tag_cont);
|
||||
s = rustrt::str_push_byte(s, code >> 6u & 63u | tag_cont);
|
||||
s = rustrt::str_push_byte(s, code & 63u | tag_cont);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,18 +215,21 @@ fn from_char(char ch) -> str {
|
|||
|
||||
fn from_chars(vec[char] chs) -> str {
|
||||
auto buf = "";
|
||||
for (char ch in chs) {push_utf8_bytes(buf, ch);}
|
||||
for (char ch in chs) { push_utf8_bytes(buf, ch); }
|
||||
ret buf;
|
||||
}
|
||||
|
||||
fn utf8_char_width(u8 b) -> uint {
|
||||
let uint byte = b as uint;
|
||||
if (byte < 0x80_u) {ret 1u;}
|
||||
if (byte < 0xc0_u) {ret 0u;} // Not a valid start byte
|
||||
if (byte < 0xe0_u) {ret 2u;}
|
||||
if (byte < 0xf0_u) {ret 3u;}
|
||||
if (byte < 0xf8_u) {ret 4u;}
|
||||
if (byte < 0xfc_u) {ret 5u;}
|
||||
if (byte < 128u) { ret 1u; }
|
||||
if (byte < 192u) {
|
||||
ret 0u; // Not a valid start byte
|
||||
|
||||
}
|
||||
if (byte < 224u) { ret 2u; }
|
||||
if (byte < 240u) { ret 3u; }
|
||||
if (byte < 248u) { ret 4u; }
|
||||
if (byte < 252u) { ret 5u; }
|
||||
ret 6u;
|
||||
}
|
||||
|
||||
|
@ -256,27 +237,26 @@ fn char_range_at(str s, uint i) -> tup(char, uint) {
|
|||
auto b0 = s.(i);
|
||||
auto w = utf8_char_width(b0);
|
||||
assert (w != 0u);
|
||||
if (w == 1u) {ret tup(b0 as char, i + 1u);}
|
||||
if (w == 1u) { ret tup(b0 as char, i + 1u); }
|
||||
auto val = 0u;
|
||||
auto end = i + w;
|
||||
i += 1u;
|
||||
while (i < end) {
|
||||
auto byte = s.(i);
|
||||
assert (byte & 0xc0_u8 == tag_cont_u8);
|
||||
assert (byte & 192u8 == tag_cont_u8);
|
||||
val <<= 6u;
|
||||
val += (byte & 0x3f_u8) as uint;
|
||||
val += byte & 63u8 as uint;
|
||||
i += 1u;
|
||||
}
|
||||
// Clunky way to get the right bits from the first byte. Uses two shifts,
|
||||
// the first to clip off the marker bits at the left of the byte, and then
|
||||
// a second (as uint) to get it to the right position.
|
||||
val += ((b0 << ((w + 1u) as u8)) as uint) << ((w - 1u) * 6u - w - 1u);
|
||||
|
||||
val += (b0 << (w + 1u as u8) as uint) << (w - 1u) * 6u - w - 1u;
|
||||
ret tup(val as char, i);
|
||||
}
|
||||
|
||||
fn char_at(str s, uint i) -> char {
|
||||
ret char_range_at(s, i)._0;
|
||||
}
|
||||
fn char_at(str s, uint i) -> char { ret char_range_at(s, i)._0; }
|
||||
|
||||
fn char_len(str s) -> uint {
|
||||
auto i = 0u;
|
||||
|
@ -304,13 +284,11 @@ fn to_chars(str s) -> vec[char] {
|
|||
ret buf;
|
||||
}
|
||||
|
||||
fn push_char(&mutable str s, char ch) {
|
||||
s += from_char(ch);
|
||||
}
|
||||
fn push_char(&mutable str s, char ch) { s += from_char(ch); }
|
||||
|
||||
fn pop_char(&mutable str s) -> char {
|
||||
auto end = byte_len(s);
|
||||
while (end > 0u && s.(end - 1u) & 0xc0_u8 == tag_cont_u8) {end -= 1u;}
|
||||
while (end > 0u && s.(end - 1u) & 192u8 == tag_cont_u8) { end -= 1u; }
|
||||
assert (end > 0u);
|
||||
auto ch = char_at(s, end - 1u);
|
||||
s = substr(s, 0u, end - 1u);
|
||||
|
@ -327,6 +305,7 @@ fn unshift_char(&mutable str s, char ch) {
|
|||
// Workaround for rustboot order-of-evaluation issue -- if I put s
|
||||
// directly after the +, the string ends up containing (only) the
|
||||
// character, twice.
|
||||
|
||||
auto x = s;
|
||||
s = from_char(ch) + x;
|
||||
}
|
||||
|
@ -338,76 +317,47 @@ fn refcount(str s) -> uint {
|
|||
} else {
|
||||
// -2 because calling this function and the native function both
|
||||
// incremented the refcount.
|
||||
ret r - 2u;
|
||||
|
||||
ret r - 2u;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Standard bits from the world of string libraries.
|
||||
|
||||
fn index(str s, u8 c) -> int {
|
||||
let int i = 0;
|
||||
for (u8 k in s) {
|
||||
if (k == c) {
|
||||
ret i;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
for (u8 k in s) { if (k == c) { ret i; } i += 1; }
|
||||
ret -1;
|
||||
}
|
||||
|
||||
fn rindex(str s, u8 c) -> int {
|
||||
let int n = str::byte_len(s) as int;
|
||||
while (n >= 0) {
|
||||
if (s.(n) == c) {
|
||||
ret n;
|
||||
}
|
||||
n -= 1;
|
||||
}
|
||||
while (n >= 0) { if (s.(n) == c) { ret n; } n -= 1; }
|
||||
ret n;
|
||||
}
|
||||
|
||||
fn find(str haystack, str needle) -> int {
|
||||
|
||||
let int haystack_len = byte_len(haystack) as int;
|
||||
let int needle_len = byte_len(needle) as int;
|
||||
|
||||
if (needle_len == 0) {
|
||||
ret 0;
|
||||
}
|
||||
|
||||
fn match_at(&str haystack,
|
||||
&str needle,
|
||||
int i) -> bool {
|
||||
if (needle_len == 0) { ret 0; }
|
||||
fn match_at(&str haystack, &str needle, int i) -> bool {
|
||||
let int j = i;
|
||||
for (u8 c in needle) {
|
||||
if (haystack.(j) != c) {
|
||||
ret false;
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
for (u8 c in needle) { if (haystack.(j) != c) { ret false; } j += 1; }
|
||||
ret true;
|
||||
}
|
||||
|
||||
let int i = 0;
|
||||
while (i <= haystack_len - needle_len) {
|
||||
if (match_at(haystack, needle, i)) {
|
||||
ret i;
|
||||
}
|
||||
if (match_at(haystack, needle, i)) { ret i; }
|
||||
i += 1;
|
||||
}
|
||||
ret -1;
|
||||
ret -1;
|
||||
}
|
||||
|
||||
fn starts_with(str haystack, str needle) -> bool {
|
||||
let uint haystack_len = byte_len(haystack);
|
||||
let uint needle_len = byte_len(needle);
|
||||
if (needle_len == 0u) {
|
||||
ret true;
|
||||
}
|
||||
if (needle_len > haystack_len) {
|
||||
ret false;
|
||||
}
|
||||
if (needle_len == 0u) { ret true; }
|
||||
if (needle_len > haystack_len) { ret false; }
|
||||
ret eq(substr(haystack, 0u, needle_len), needle);
|
||||
}
|
||||
|
||||
|
@ -415,15 +365,13 @@ fn ends_with(str haystack, str needle) -> bool {
|
|||
let uint haystack_len = byte_len(haystack);
|
||||
let uint needle_len = byte_len(needle);
|
||||
ret if (needle_len == 0u) {
|
||||
true
|
||||
} else if (needle_len > haystack_len) {
|
||||
false
|
||||
} else {
|
||||
eq(substr(haystack,
|
||||
haystack_len - needle_len,
|
||||
needle_len),
|
||||
needle)
|
||||
};
|
||||
true
|
||||
} else if (needle_len > haystack_len) {
|
||||
false
|
||||
} else {
|
||||
eq(substr(haystack, haystack_len - needle_len, needle_len),
|
||||
needle)
|
||||
};
|
||||
}
|
||||
|
||||
fn substr(str s, uint begin, uint len) -> str {
|
||||
|
@ -432,6 +380,7 @@ fn substr(str s, uint begin, uint len) -> str {
|
|||
|
||||
fn slice(str s, uint begin, uint end) -> str {
|
||||
// FIXME: Typestate precondition
|
||||
|
||||
assert (begin <= end);
|
||||
assert (end <= str::byte_len(s));
|
||||
ret rustrt::str_slice(s, begin, end);
|
||||
|
@ -473,23 +422,15 @@ fn split(str s, u8 sep) -> vec[str] {
|
|||
v += [accum];
|
||||
accum = "";
|
||||
ends_with_sep = true;
|
||||
} else {
|
||||
accum += unsafe_from_byte(c);
|
||||
ends_with_sep = false;
|
||||
}
|
||||
}
|
||||
if (str::byte_len(accum) != 0u ||
|
||||
ends_with_sep) {
|
||||
v += [accum];
|
||||
} else { accum += unsafe_from_byte(c); ends_with_sep = false; }
|
||||
}
|
||||
if (str::byte_len(accum) != 0u || ends_with_sep) { v += [accum]; }
|
||||
ret v;
|
||||
}
|
||||
|
||||
fn concat(vec[str] v) -> str {
|
||||
let str s = "";
|
||||
for (str ss in v) {
|
||||
s += ss;
|
||||
}
|
||||
for (str ss in v) { s += ss; }
|
||||
ret s;
|
||||
}
|
||||
|
||||
|
@ -497,16 +438,13 @@ fn connect(vec[str] v, str sep) -> str {
|
|||
let str s = "";
|
||||
let bool first = true;
|
||||
for (str ss in v) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
s += sep;
|
||||
}
|
||||
if (first) { first = false; } else { s += sep; }
|
||||
s += ss;
|
||||
}
|
||||
ret s;
|
||||
}
|
||||
|
||||
|
||||
// FIXME: This only handles ASCII
|
||||
fn to_upper(str s) -> str {
|
||||
auto outstr = "";
|
||||
|
@ -517,15 +455,11 @@ fn to_upper(str s) -> str {
|
|||
auto next;
|
||||
if (ascii_a <= byte && byte <= ascii_z) {
|
||||
next = byte - diff;
|
||||
} else {
|
||||
next = byte;
|
||||
}
|
||||
} else { next = byte; }
|
||||
push_byte(outstr, next);
|
||||
}
|
||||
ret outstr;
|
||||
}
|
||||
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
|
|
|
@ -1,25 +1,18 @@
|
|||
|
||||
export rustrt;
|
||||
|
||||
native "rust" mod rustrt {
|
||||
|
||||
// Explicitly re-export native stuff we want to be made
|
||||
// available outside this crate. Otherwise it's
|
||||
// visible-in-crate, but not re-exported.
|
||||
|
||||
export last_os_error;
|
||||
export size_of;
|
||||
export align_of;
|
||||
export refcount;
|
||||
export do_gc;
|
||||
|
||||
fn last_os_error() -> str;
|
||||
// Explicitly re-export native stuff we want to be made
|
||||
// available outside this crate. Otherwise it's
|
||||
// visible-in-crate, but not re-exported.
|
||||
fn last_os_error() -> str;
|
||||
fn size_of[T]() -> uint;
|
||||
fn align_of[T]() -> uint;
|
||||
fn refcount[T](@T t) -> uint;
|
||||
fn do_gc();
|
||||
fn unsupervise();
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
|
|
|
@ -1,29 +1,46 @@
|
|||
|
||||
|
||||
|
||||
// Simple ANSI color library.
|
||||
//
|
||||
// TODO: Windows support.
|
||||
|
||||
const u8 color_black = 0u8;
|
||||
|
||||
const u8 color_red = 1u8;
|
||||
|
||||
const u8 color_green = 2u8;
|
||||
|
||||
const u8 color_yellow = 3u8;
|
||||
|
||||
const u8 color_blue = 4u8;
|
||||
|
||||
const u8 color_magenta = 5u8;
|
||||
|
||||
const u8 color_cyan = 6u8;
|
||||
|
||||
const u8 color_light_gray = 7u8;
|
||||
|
||||
const u8 color_light_grey = 7u8;
|
||||
|
||||
const u8 color_dark_gray = 8u8;
|
||||
|
||||
const u8 color_dark_grey = 8u8;
|
||||
|
||||
const u8 color_bright_red = 9u8;
|
||||
|
||||
const u8 color_bright_green = 10u8;
|
||||
|
||||
const u8 color_bright_yellow = 11u8;
|
||||
|
||||
const u8 color_bright_blue = 12u8;
|
||||
|
||||
const u8 color_bright_magenta = 13u8;
|
||||
|
||||
const u8 color_bright_cyan = 14u8;
|
||||
|
||||
const u8 color_bright_white = 15u8;
|
||||
|
||||
fn esc(io::buf_writer writer) {
|
||||
writer.write([0x1bu8, '[' as u8]);
|
||||
}
|
||||
fn esc(io::buf_writer writer) { writer.write([0x1bu8, '[' as u8]); }
|
||||
|
||||
fn reset(io::buf_writer writer) {
|
||||
esc(writer);
|
||||
|
@ -36,12 +53,8 @@ fn color_supported() -> bool {
|
|||
|
||||
fn set_color(io::buf_writer writer, u8 first_char, u8 color) {
|
||||
assert (color < 16u8);
|
||||
|
||||
esc(writer);
|
||||
if (color >= 8u8) {
|
||||
writer.write(['1' as u8, ';' as u8]);
|
||||
color -= 8u8;
|
||||
}
|
||||
if (color >= 8u8) { writer.write(['1' as u8, ';' as u8]); color -= 8u8; }
|
||||
writer.write([first_char, ('0' as u8) + color, 'm' as u8]);
|
||||
}
|
||||
|
||||
|
@ -52,7 +65,5 @@ fn fg(io::buf_writer writer, u8 color) {
|
|||
fn bg(io::buf_writer writer, u8 color) {
|
||||
ret set_color(writer, '4' as u8, color);
|
||||
}
|
||||
|
||||
// export fg;
|
||||
// export bg;
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
|
||||
|
||||
native "rust" mod rustrt {
|
||||
fn get_time(&mutable u32 sec, &mutable u32 usec);
|
||||
}
|
||||
|
@ -5,8 +7,8 @@ native "rust" mod rustrt {
|
|||
type timeval = rec(u32 sec, u32 usec);
|
||||
|
||||
fn get_time() -> timeval {
|
||||
auto sec = 0u32; auto usec = 0u32;
|
||||
auto sec = 0u32;
|
||||
auto usec = 0u32;
|
||||
rustrt::get_time(sec, usec);
|
||||
ret rec(sec=sec, usec=usec);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,23 +1,28 @@
|
|||
|
||||
|
||||
fn add(u8 x, u8 y) -> u8 { ret x + y; }
|
||||
|
||||
fn sub(u8 x, u8 y) -> u8 { ret x - y; }
|
||||
|
||||
fn mul(u8 x, u8 y) -> u8 { ret x * y; }
|
||||
|
||||
fn div(u8 x, u8 y) -> u8 { ret x / y; }
|
||||
|
||||
fn rem(u8 x, u8 y) -> u8 { ret x % y; }
|
||||
|
||||
fn lt(u8 x, u8 y) -> bool { ret x < y; }
|
||||
|
||||
fn le(u8 x, u8 y) -> bool { ret x <= y; }
|
||||
|
||||
fn eq(u8 x, u8 y) -> bool { ret x == y; }
|
||||
|
||||
fn ne(u8 x, u8 y) -> bool { ret x != y; }
|
||||
|
||||
fn ge(u8 x, u8 y) -> bool { ret x >= y; }
|
||||
|
||||
fn gt(u8 x, u8 y) -> bool { ret x > y; }
|
||||
|
||||
iter range(u8 lo, u8 hi) -> u8 {
|
||||
while (lo < hi) {
|
||||
put lo;
|
||||
lo += 1u8;
|
||||
}
|
||||
}
|
||||
|
||||
iter range(u8 lo, u8 hi) -> u8 { while (lo < hi) { put lo; lo += 1u8; } }
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
|
||||
import option::none;
|
||||
import option::some;
|
||||
|
||||
|
||||
// A very naive implementation of union-find with unsigned integer nodes.
|
||||
// Maintains the invariant that the root of a node is always equal to or less
|
||||
// than the node itself.
|
||||
|
||||
type node = option::t[uint];
|
||||
|
||||
type ufind = rec(mutable vec[mutable node] nodes);
|
||||
|
||||
fn make() -> ufind {
|
||||
let vec[mutable node] v = [mutable none[uint]];
|
||||
vec::pop(v); // FIXME: botch
|
||||
vec::pop(v); // FIXME: botch
|
||||
|
||||
ret rec(mutable nodes=v);
|
||||
}
|
||||
|
||||
|
@ -20,6 +23,7 @@ fn make_set(&ufind ufnd) -> uint {
|
|||
ret idx;
|
||||
}
|
||||
|
||||
|
||||
/// Creates sets as necessary to ensure that least `n` sets are present in the
|
||||
/// data structure.
|
||||
fn grow(&ufind ufnd, uint n) {
|
||||
|
@ -38,22 +42,16 @@ fn union(&ufind ufnd, uint m, uint n) {
|
|||
auto n_root = find(ufnd, n);
|
||||
if (m_root < n_root) {
|
||||
ufnd.nodes.(n_root) = some[uint](m_root);
|
||||
} else if (m_root > n_root) {
|
||||
ufnd.nodes.(m_root) = some[uint](n_root);
|
||||
}
|
||||
} else if (m_root > n_root) { ufnd.nodes.(m_root) = some[uint](n_root); }
|
||||
}
|
||||
|
||||
fn set_count(&ufind ufnd) -> uint {
|
||||
ret vec::len[node](ufnd.nodes);
|
||||
}
|
||||
fn set_count(&ufind ufnd) -> uint { ret vec::len[node](ufnd.nodes); }
|
||||
|
||||
|
||||
// Removes all sets with IDs greater than or equal to the given value.
|
||||
fn prune(&ufind ufnd, uint n) {
|
||||
// TODO: Use "slice" once we get rid of "mutable?"
|
||||
auto len = vec::len[node](ufnd.nodes);
|
||||
while (len != n) {
|
||||
vec::pop[node](ufnd.nodes);
|
||||
len -= 1u;
|
||||
}
|
||||
}
|
||||
|
||||
auto len = vec::len[node](ufnd.nodes);
|
||||
while (len != n) { vec::pop[node](ufnd.nodes); len -= 1u; }
|
||||
}
|
|
@ -1,40 +1,42 @@
|
|||
|
||||
|
||||
fn add(uint x, uint y) -> uint { ret x + y; }
|
||||
|
||||
fn sub(uint x, uint y) -> uint { ret x - y; }
|
||||
|
||||
fn mul(uint x, uint y) -> uint { ret x * y; }
|
||||
|
||||
fn div(uint x, uint y) -> uint { ret x / y; }
|
||||
|
||||
fn rem(uint x, uint y) -> uint { ret x % y; }
|
||||
|
||||
fn lt(uint x, uint y) -> bool { ret x < y; }
|
||||
|
||||
fn le(uint x, uint y) -> bool { ret x <= y; }
|
||||
|
||||
fn eq(uint x, uint y) -> bool { ret x == y; }
|
||||
|
||||
fn ne(uint x, uint y) -> bool { ret x != y; }
|
||||
|
||||
fn ge(uint x, uint y) -> bool { ret x >= y; }
|
||||
|
||||
fn gt(uint x, uint y) -> bool { ret x > y; }
|
||||
|
||||
fn max(uint x, uint y) -> uint {
|
||||
if (x > y) { ret x; }
|
||||
ret y;
|
||||
}
|
||||
fn max(uint x, uint y) -> uint { if (x > y) { ret x; } ret y; }
|
||||
|
||||
iter range(uint lo, uint hi) -> uint {
|
||||
auto lo_ = lo;
|
||||
while (lo_ < hi) {
|
||||
put lo_;
|
||||
lo_ += 1u;
|
||||
}
|
||||
while (lo_ < hi) { put lo_; lo_ += 1u; }
|
||||
}
|
||||
|
||||
fn next_power_of_two(uint n) -> uint {
|
||||
// FIXME change |* uint(4)| below to |* uint(8) / uint(2)| and watch the
|
||||
// world explode.
|
||||
|
||||
let uint halfbits = sys::rustrt::size_of[uint]() * 4u;
|
||||
let uint tmp = n - 1u;
|
||||
let uint shift = 1u;
|
||||
while (shift <= halfbits) {
|
||||
tmp |= tmp >> shift;
|
||||
shift <<= 1u;
|
||||
}
|
||||
while (shift <= halfbits) { tmp |= tmp >> shift; shift <<= 1u; }
|
||||
ret tmp + 1u;
|
||||
}
|
||||
|
||||
|
@ -43,65 +45,53 @@ fn parse_buf(vec[u8] buf, uint radix) -> uint {
|
|||
log_err "parse_buf(): buf is empty";
|
||||
fail;
|
||||
}
|
||||
|
||||
auto i = vec::len[u8](buf) - 1u;
|
||||
auto power = 1u;
|
||||
auto n = 0u;
|
||||
while (true) {
|
||||
n += (((buf.(i)) - ('0' as u8)) as uint) * power;
|
||||
n += (buf.(i) - ('0' as u8) as uint) * power;
|
||||
power *= radix;
|
||||
if (i == 0u) { ret n; }
|
||||
i -= 1u;
|
||||
}
|
||||
|
||||
fail;
|
||||
}
|
||||
|
||||
fn to_str(uint num, uint radix) -> str
|
||||
{
|
||||
fn to_str(uint num, uint radix) -> str {
|
||||
auto n = num;
|
||||
|
||||
assert (0u < radix && radix <= 16u);
|
||||
fn digit(uint n) -> char {
|
||||
ret alt (n) {
|
||||
case (0u) { '0' }
|
||||
case (1u) { '1' }
|
||||
case (2u) { '2' }
|
||||
case (3u) { '3' }
|
||||
case (4u) { '4' }
|
||||
case (5u) { '5' }
|
||||
case (6u) { '6' }
|
||||
case (7u) { '7' }
|
||||
case (8u) { '8' }
|
||||
case (9u) { '9' }
|
||||
case (10u) { 'a' }
|
||||
case (11u) { 'b' }
|
||||
case (12u) { 'c' }
|
||||
case (13u) { 'd' }
|
||||
case (14u) { 'e' }
|
||||
case (15u) { 'f' }
|
||||
case (_) { fail }
|
||||
};
|
||||
case (0u) { '0' }
|
||||
case (1u) { '1' }
|
||||
case (2u) { '2' }
|
||||
case (3u) { '3' }
|
||||
case (4u) { '4' }
|
||||
case (5u) { '5' }
|
||||
case (6u) { '6' }
|
||||
case (7u) { '7' }
|
||||
case (8u) { '8' }
|
||||
case (9u) { '9' }
|
||||
case (10u) { 'a' }
|
||||
case (11u) { 'b' }
|
||||
case (12u) { 'c' }
|
||||
case (13u) { 'd' }
|
||||
case (14u) { 'e' }
|
||||
case (15u) { 'f' }
|
||||
case (_) { fail }
|
||||
};
|
||||
}
|
||||
|
||||
if (n == 0u) { ret "0"; }
|
||||
|
||||
let str s = "";
|
||||
while (n != 0u) {
|
||||
s += str::unsafe_from_byte(digit(n % radix) as u8);
|
||||
n /= radix;
|
||||
}
|
||||
|
||||
let str s1 = "";
|
||||
let uint len = str::byte_len(s);
|
||||
while (len != 0u) {
|
||||
len -= 1u;
|
||||
s1 += str::unsafe_from_byte(s.(len));
|
||||
}
|
||||
while (len != 0u) { len -= 1u; s1 += str::unsafe_from_byte(s.(len)); }
|
||||
ret s1;
|
||||
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
|
|
|
@ -1,28 +1,24 @@
|
|||
fn id[T](&T x) -> T {
|
||||
ret x;
|
||||
}
|
||||
|
||||
|
||||
fn id[T](&T x) -> T { ret x; }
|
||||
|
||||
|
||||
/* FIXME (issue #141): See test/run-pass/constrained-type.rs. Uncomment
|
||||
* the constraint once fixed. */
|
||||
type rational = rec(int num, int den); // : int::positive(*.den);
|
||||
type rational = rec(int num, int den);
|
||||
|
||||
// : int::positive(*.den);
|
||||
fn rational_leq(&rational x, &rational y) -> bool {
|
||||
// NB: Uses the fact that rationals have positive denominators WLOG:
|
||||
|
||||
ret x.num * y.den <= y.num * x.den;
|
||||
}
|
||||
|
||||
fn fst[T, U](&tup(T, U) x) -> T {
|
||||
ret x._0;
|
||||
}
|
||||
fn fst[T, U](&tup(T, U) x) -> T { ret x._0; }
|
||||
|
||||
fn snd[T, U](&tup(T, U) x) -> U {
|
||||
ret x._1;
|
||||
}
|
||||
|
||||
fn orb(&bool a, &bool b) -> bool {
|
||||
ret a || b;
|
||||
}
|
||||
fn snd[T, U](&tup(T, U) x) -> U { ret x._1; }
|
||||
|
||||
fn orb(&bool a, &bool b) -> bool { ret a || b; }
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
|
|
253
src/lib/vec.rs
253
src/lib/vec.rs
|
@ -1,39 +1,35 @@
|
|||
|
||||
import option::none;
|
||||
import option::some;
|
||||
import util::orb;
|
||||
|
||||
type vbuf = rustrt::vbuf;
|
||||
|
||||
type operator2[T,U,V] = fn(&T, &U) -> V;
|
||||
type operator2[T, U, V] = fn(&T, &U) -> V ;
|
||||
|
||||
type array[T] = vec[mutable? T];
|
||||
|
||||
native "rust" mod rustrt {
|
||||
type vbuf;
|
||||
|
||||
fn vec_buf[T](vec[T] v, uint offset) -> vbuf;
|
||||
|
||||
fn vec_len[T](vec[T] v) -> uint;
|
||||
/**
|
||||
* Sometimes we modify the vec internal data via vec_buf and need to
|
||||
* update the vec's fill length accordingly.
|
||||
*/
|
||||
fn vec_len_set[T](vec[T] v, uint n);
|
||||
|
||||
/**
|
||||
* The T in vec_alloc[T, U] is the type of the vec to allocate. The
|
||||
* U is the type of an element in the vec. So to allocate a vec[U] we
|
||||
* want to invoke this as vec_alloc[vec[U], U].
|
||||
*/
|
||||
fn vec_alloc[T, U](uint n_elts) -> vec[U];
|
||||
/**
|
||||
* Sometimes we modify the vec internal data via vec_buf and need to
|
||||
* update the vec's fill length accordingly.
|
||||
*/
|
||||
fn vec_len_set[T](vec[T] v, uint n);
|
||||
|
||||
/**
|
||||
* The T in vec_alloc[T, U] is the type of the vec to allocate. The
|
||||
* U is the type of an element in the vec. So to allocate a vec[U] we
|
||||
* want to invoke this as vec_alloc[vec[U], U].
|
||||
*/
|
||||
fn vec_alloc[T, U](uint n_elts) -> vec[U];
|
||||
fn vec_alloc_mut[T, U](uint n_elts) -> vec[mutable U];
|
||||
|
||||
fn refcount[T](vec[T] v) -> uint;
|
||||
|
||||
fn vec_print_debug_info[T](vec[T] v);
|
||||
|
||||
fn vec_from_vbuf[T](vbuf v, uint n_elts) -> vec[T];
|
||||
|
||||
fn unsafe_vec_to_mut[T](vec[T] v) -> vec[mutable T];
|
||||
}
|
||||
|
||||
|
@ -52,7 +48,8 @@ fn refcount[T](array[T] v) -> uint {
|
|||
} else {
|
||||
// -2 because calling this function and the native function both
|
||||
// incremented the refcount.
|
||||
ret r - 2u;
|
||||
|
||||
ret r - 2u;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,35 +57,27 @@ fn vec_from_vbuf[T](vbuf v, uint n_elts) -> vec[T] {
|
|||
ret rustrt::vec_from_vbuf[T](v, n_elts);
|
||||
}
|
||||
|
||||
// FIXME: Remove me; this is a botch to get around rustboot's bad typechecker.
|
||||
fn empty[T]() -> vec[T] {
|
||||
ret alloc[T](0u);
|
||||
}
|
||||
|
||||
// FIXME: Remove me; this is a botch to get around rustboot's bad typechecker.
|
||||
fn empty_mut[T]() -> vec[mutable T] {
|
||||
ret alloc_mut[T](0u);
|
||||
}
|
||||
fn empty[T]() -> vec[T] { ret alloc[T](0u); }
|
||||
|
||||
type init_op[T] = fn(uint i) -> T;
|
||||
|
||||
// FIXME: Remove me; this is a botch to get around rustboot's bad typechecker.
|
||||
fn empty_mut[T]() -> vec[mutable T] { ret alloc_mut[T](0u); }
|
||||
|
||||
type init_op[T] = fn(uint) -> T ;
|
||||
|
||||
fn init_fn[T](&init_op[T] op, uint n_elts) -> vec[T] {
|
||||
let vec[T] v = alloc[T](n_elts);
|
||||
let uint i = 0u;
|
||||
while (i < n_elts) {
|
||||
v += [op(i)];
|
||||
i += 1u;
|
||||
}
|
||||
while (i < n_elts) { v += [op(i)]; i += 1u; }
|
||||
ret v;
|
||||
}
|
||||
|
||||
fn init_fn_mut[T](&init_op[T] op, uint n_elts) -> vec[mutable T] {
|
||||
let vec[mutable T] v = alloc_mut[T](n_elts);
|
||||
let uint i = 0u;
|
||||
while (i < n_elts) {
|
||||
v += [mutable op(i)];
|
||||
i += 1u;
|
||||
}
|
||||
while (i < n_elts) { v += [mutable op(i)]; i += 1u; }
|
||||
ret v;
|
||||
}
|
||||
|
||||
|
@ -100,79 +89,60 @@ fn init_elt[T](&T t, uint n_elts) -> vec[T] {
|
|||
* let init_op[T] inner = bind elt_op[T](t, _);
|
||||
* ret init_fn[T](inner, n_elts);
|
||||
*/
|
||||
|
||||
let vec[T] v = alloc[T](n_elts);
|
||||
let uint i = n_elts;
|
||||
while (i > 0u) {
|
||||
i -= 1u;
|
||||
v += [t];
|
||||
}
|
||||
while (i > 0u) { i -= 1u; v += [t]; }
|
||||
ret v;
|
||||
}
|
||||
|
||||
fn init_elt_mut[T](&T t, uint n_elts) -> vec[mutable T] {
|
||||
let vec[mutable T] v = alloc_mut[T](n_elts);
|
||||
let uint i = n_elts;
|
||||
while (i > 0u) {
|
||||
i -= 1u;
|
||||
v += [mutable t];
|
||||
}
|
||||
while (i > 0u) { i -= 1u; v += [mutable t]; }
|
||||
ret v;
|
||||
}
|
||||
|
||||
fn buf[T](array[T] v) -> vbuf {
|
||||
ret rustrt::vec_buf[T](v, 0u);
|
||||
}
|
||||
fn buf[T](array[T] v) -> vbuf { ret rustrt::vec_buf[T](v, 0u); }
|
||||
|
||||
fn len[T](array[T] v) -> uint {
|
||||
ret rustrt::vec_len[T](v);
|
||||
}
|
||||
fn len[T](array[T] v) -> uint { ret rustrt::vec_len[T](v); }
|
||||
|
||||
fn len_set[T](array[T] v, uint n) {
|
||||
rustrt::vec_len_set[T](v, n);
|
||||
}
|
||||
fn len_set[T](array[T] v, uint n) { rustrt::vec_len_set[T](v, n); }
|
||||
|
||||
fn buf_off[T](array[T] v, uint offset) -> vbuf {
|
||||
assert (offset < len[T](v));
|
||||
assert (offset < len[T](v));
|
||||
ret rustrt::vec_buf[T](v, offset);
|
||||
}
|
||||
|
||||
fn print_debug_info[T](array[T] v) {
|
||||
rustrt::vec_print_debug_info[T](v);
|
||||
}
|
||||
fn print_debug_info[T](array[T] v) { rustrt::vec_print_debug_info[T](v); }
|
||||
|
||||
|
||||
// Returns the last element of v.
|
||||
fn last[T](array[T] v) -> option::t[T] {
|
||||
auto l = len[T](v);
|
||||
if (l == 0u) {
|
||||
ret none[T];
|
||||
}
|
||||
if (l == 0u) { ret none[T]; }
|
||||
ret some[T](v.(l - 1u));
|
||||
}
|
||||
|
||||
// Returns elements from [start..end) from v.
|
||||
|
||||
// Returns elements from [start..end) from v.
|
||||
fn slice[T](array[T] v, uint start, uint end) -> vec[T] {
|
||||
assert (start <= end);
|
||||
assert (end <= len[T](v));
|
||||
auto result = alloc[T](end - start);
|
||||
let uint i = start;
|
||||
while (i < end) {
|
||||
result += [v.(i)];
|
||||
i += 1u;
|
||||
}
|
||||
while (i < end) { result += [v.(i)]; i += 1u; }
|
||||
ret result;
|
||||
}
|
||||
|
||||
|
||||
// FIXME: Should go away eventually.
|
||||
fn slice_mut[T](array[T] v, uint start, uint end) -> vec[mutable T] {
|
||||
assert (start <= end);
|
||||
assert (end <= len[T](v));
|
||||
auto result = alloc_mut[T](end - start);
|
||||
let uint i = start;
|
||||
while (i < end) {
|
||||
result += [mutable v.(i)];
|
||||
i += 1u;
|
||||
}
|
||||
while (i < end) { result += [mutable v.(i)]; i += 1u; }
|
||||
ret result;
|
||||
}
|
||||
|
||||
|
@ -196,12 +166,10 @@ fn pop[T](&mutable array[T] v) -> T {
|
|||
fn top[T](&array[T] v) -> T {
|
||||
auto ln = len[T](v);
|
||||
assert (ln > 0u);
|
||||
ret v.(ln-1u);
|
||||
ret v.(ln - 1u);
|
||||
}
|
||||
|
||||
fn push[T](&mutable array[T] v, &T t) {
|
||||
v += [t];
|
||||
}
|
||||
fn push[T](&mutable array[T] v, &T t) { v += [t]; }
|
||||
|
||||
fn unshift[T](&mutable array[T] v, &T t) {
|
||||
auto res = alloc[T](len[T](v) + 1u);
|
||||
|
@ -212,132 +180,96 @@ fn unshift[T](&mutable array[T] v, &T t) {
|
|||
|
||||
fn grow[T](&mutable array[T] v, uint n, &T initval) {
|
||||
let uint i = n;
|
||||
while (i > 0u) {
|
||||
i -= 1u;
|
||||
v += [initval];
|
||||
}
|
||||
while (i > 0u) { i -= 1u; v += [initval]; }
|
||||
}
|
||||
|
||||
fn grow_set[T](&mutable vec[mutable T] v, uint index, &T initval, &T val) {
|
||||
auto length = vec::len(v);
|
||||
if (index >= length) {
|
||||
grow(v, index - length + 1u, initval);
|
||||
}
|
||||
if (index >= length) { grow(v, index - length + 1u, initval); }
|
||||
v.(index) = val;
|
||||
}
|
||||
|
||||
fn grow_init_fn[T](&mutable array[T] v, uint n, fn()->T init_fn) {
|
||||
fn grow_init_fn[T](&mutable array[T] v, uint n, fn() -> T init_fn) {
|
||||
let uint i = n;
|
||||
while (i > 0u) {
|
||||
i -= 1u;
|
||||
v += [init_fn()];
|
||||
}
|
||||
while (i > 0u) { i -= 1u; v += [init_fn()]; }
|
||||
}
|
||||
|
||||
fn grow_init_fn_set[T](&array[T] v, uint index, fn()->T init_fn, &T val) {
|
||||
fn grow_init_fn_set[T](&array[T] v, uint index, fn() -> T init_fn, &T val) {
|
||||
auto length = vec::len(v);
|
||||
if (index >= length) { grow_init_fn(v, index - length + 1u, init_fn); }
|
||||
v.(index) = val;
|
||||
}
|
||||
|
||||
|
||||
fn map[T, U](&fn(&T) -> U f, &vec[T] v) -> vec[U] {
|
||||
fn map[T, U](&fn(&T) -> U f, &vec[T] v) -> vec[U] {
|
||||
let vec[U] res = alloc[U](len[T](v));
|
||||
for (T ve in v) {
|
||||
res += [f(ve)];
|
||||
}
|
||||
for (T ve in v) { res += [f(ve)]; }
|
||||
ret res;
|
||||
}
|
||||
|
||||
fn filter_map[T, U](&fn(&T) -> option::t[U] f, &vec[T] v) -> vec[U] {
|
||||
fn filter_map[T, U](&fn(&T) -> option::t[U] f, &vec[T] v) -> vec[U] {
|
||||
let vec[U] res = [];
|
||||
for(T ve in v) {
|
||||
alt(f(ve)) {
|
||||
case (some(?elt)) { res += [elt]; }
|
||||
case (none) {}
|
||||
}
|
||||
for (T ve in v) {
|
||||
alt (f(ve)) { case (some(?elt)) { res += [elt]; } case (none) { } }
|
||||
}
|
||||
ret res;
|
||||
}
|
||||
|
||||
fn map2[T,U,V](&operator2[T,U,V] f, &vec[T] v0, &vec[U] v1) -> vec[V] {
|
||||
fn map2[T, U, V](&operator2[T, U, V] f, &vec[T] v0, &vec[U] v1) -> vec[V] {
|
||||
auto v0_len = len[T](v0);
|
||||
if (v0_len != len[U](v1)) {
|
||||
fail;
|
||||
}
|
||||
|
||||
if (v0_len != len[U](v1)) { fail; }
|
||||
let vec[V] u = alloc[V](v0_len);
|
||||
auto i = 0u;
|
||||
while (i < v0_len) {
|
||||
u += [f({v0.(i)}, {v1.(i)})];
|
||||
i += 1u;
|
||||
}
|
||||
|
||||
while (i < v0_len) { u += [f({ v0.(i) }, { v1.(i) })]; i += 1u; }
|
||||
ret u;
|
||||
}
|
||||
|
||||
fn find[T](fn (&T) -> bool f, &vec[T] v) -> option::t[T] {
|
||||
for (T elt in v) {
|
||||
if (f(elt)) {
|
||||
ret some[T](elt);
|
||||
}
|
||||
}
|
||||
|
||||
fn find[T](fn(&T) -> bool f, &vec[T] v) -> option::t[T] {
|
||||
for (T elt in v) { if (f(elt)) { ret some[T](elt); } }
|
||||
ret none[T];
|
||||
}
|
||||
|
||||
fn member[T](&T x, &array[T] v) -> bool {
|
||||
for (T elt in v) {
|
||||
if (x == elt) { ret true; }
|
||||
}
|
||||
for (T elt in v) { if (x == elt) { ret true; } }
|
||||
ret false;
|
||||
}
|
||||
|
||||
fn count[T](&T x, &array[T] v) -> uint {
|
||||
auto cnt = 0u;
|
||||
for (T elt in v) {
|
||||
if (x == elt) { cnt += 1u; }
|
||||
}
|
||||
for (T elt in v) { if (x == elt) { cnt += 1u; } }
|
||||
ret cnt;
|
||||
}
|
||||
|
||||
fn foldl[T, U](fn (&U, &T) -> U p, &U z, &vec[T] v) -> U {
|
||||
fn foldl[T, U](fn(&U, &T) -> U p, &U z, &vec[T] v) -> U {
|
||||
auto sz = len[T](v);
|
||||
|
||||
if (sz == 0u) {
|
||||
ret z;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
auto rest = slice[T](v, 1u, sz);
|
||||
|
||||
ret (p(foldl[T,U](p, z, rest), v.(0)));
|
||||
ret p(foldl[T, U](p, z, rest), v.(0));
|
||||
}
|
||||
}
|
||||
|
||||
fn unzip[T, U](&vec[tup(T, U)] v) -> tup(vec[T], vec[U]) {
|
||||
auto sz = len[tup(T, U)](v);
|
||||
|
||||
if (sz == 0u) {
|
||||
ret tup(alloc[T](0u), alloc[U](0u));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
auto rest = slice[tup(T, U)](v, 1u, sz);
|
||||
auto tl = unzip[T, U](rest);
|
||||
auto a = [v.(0)._0];
|
||||
auto b = [v.(0)._1];
|
||||
auto tl = unzip[T, U](rest);
|
||||
auto a = [v.(0)._0];
|
||||
auto b = [v.(0)._1];
|
||||
ret tup(a + tl._0, b + tl._1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// FIXME make the lengths being equal a constraint
|
||||
fn zip[T, U](&vec[T] v, &vec[U] u) -> vec[tup(T, U)] {
|
||||
auto sz = len[T](v);
|
||||
assert (sz == len[U](u));
|
||||
|
||||
if (sz == 0u) {
|
||||
ret alloc[tup(T, U)](0u);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
auto rest = zip[T, U](slice[T](v, 1u, sz), slice[U](u, 1u, sz));
|
||||
vec::push(rest, tup(v.(0), u.(0)));
|
||||
ret rest;
|
||||
|
@ -349,41 +281,29 @@ fn or(&vec[bool] v) -> bool {
|
|||
ret vec::foldl[bool, bool](f, false, v);
|
||||
}
|
||||
|
||||
fn clone[T](&vec[T] v) -> vec[T] {
|
||||
ret slice[T](v, 0u, len[T](v));
|
||||
}
|
||||
fn clone[T](&vec[T] v) -> vec[T] { ret slice[T](v, 0u, len[T](v)); }
|
||||
|
||||
fn plus_option[T](&mutable vec[T] v, &option::t[T] o) -> () {
|
||||
alt (o) {
|
||||
case (none) {}
|
||||
case (some(?x)) { v += [x]; }
|
||||
}
|
||||
fn plus_option[T](&mutable vec[T] v, &option::t[T] o) {
|
||||
alt (o) { case (none) { } case (some(?x)) { v += [x]; } }
|
||||
}
|
||||
|
||||
fn cat_options[T](&vec[option::t[T]] v) -> vec[T] {
|
||||
let vec[T] res = [];
|
||||
|
||||
for (option::t[T] o in v) {
|
||||
alt (o) {
|
||||
case (none) { }
|
||||
case (some(?t)) {
|
||||
res += [t];
|
||||
}
|
||||
}
|
||||
alt (o) { case (none) { } case (some(?t)) { res += [t]; } }
|
||||
}
|
||||
|
||||
ret res;
|
||||
}
|
||||
|
||||
|
||||
// TODO: Remove in favor of built-in "freeze" operation when it's implemented.
|
||||
fn freeze[T](vec[mutable T] v) -> vec[T] {
|
||||
let vec[T] result = [];
|
||||
for (T elem in v) {
|
||||
result += [elem];
|
||||
}
|
||||
for (T elem in v) { result += [elem]; }
|
||||
ret result;
|
||||
}
|
||||
|
||||
|
||||
// Swaps two elements in a vector
|
||||
fn swap[T](&vec[mutable T] v, uint a, uint b) {
|
||||
let T t = v.(a);
|
||||
|
@ -391,44 +311,31 @@ fn swap[T](&vec[mutable T] v, uint a, uint b) {
|
|||
v.(b) = t;
|
||||
}
|
||||
|
||||
|
||||
// In place vector reversal
|
||||
fn reverse[T](&vec[mutable T] v) -> () {
|
||||
fn reverse[T](&vec[mutable T] v) {
|
||||
let uint i = 0u;
|
||||
auto ln = len[T](v);
|
||||
|
||||
while(i < ln / 2u) {
|
||||
swap(v, i, ln - i - 1u);
|
||||
i += 1u;
|
||||
}
|
||||
while (i < ln / 2u) { swap(v, i, ln - i - 1u); i += 1u; }
|
||||
}
|
||||
|
||||
|
||||
// Functional vector reversal. Returns a reversed copy of v.
|
||||
fn reversed[T](vec[T] v) -> vec[T] {
|
||||
let vec[T] res = [];
|
||||
|
||||
auto i = len[T](v);
|
||||
if (i == 0u) {
|
||||
ret res;
|
||||
}
|
||||
else {
|
||||
i -= 1u;
|
||||
}
|
||||
|
||||
while(i != 0u) {
|
||||
push[T](res, v.(i));
|
||||
i -= 1u;
|
||||
}
|
||||
if (i == 0u) { ret res; } else { i -= 1u; }
|
||||
while (i != 0u) { push[T](res, v.(i)); i -= 1u; }
|
||||
push[T](res, v.(0));
|
||||
|
||||
ret res;
|
||||
}
|
||||
|
||||
|
||||
/// Truncates the vector to length `new_len`.
|
||||
/// FIXME: This relies on a typechecker bug (covariance vs. invariance).
|
||||
fn truncate[T](&mutable vec[mutable? T] v, uint new_len) {
|
||||
v = slice[T](v, 0u, new_len);
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
|
||||
|
||||
native "rust" mod rustrt {
|
||||
fn rust_list_files(str path) -> vec[str];
|
||||
fn rust_file_is_dir(str path) -> int;
|
||||
fn rust_list_files(str path) -> vec[str];
|
||||
fn rust_file_is_dir(str path) -> int;
|
||||
}
|
||||
|
||||
fn list_dir(str path) -> vec[str] {
|
||||
ret rustrt::rust_list_files(path+"*");
|
||||
}
|
||||
fn list_dir(str path) -> vec[str] { ret rustrt::rust_list_files(path + "*"); }
|
||||
|
||||
|
||||
/* FIXME: win32 path handling actually accepts '/' or '\' and has subtly
|
||||
* different semantics for each. Since we build on mingw, we are usually
|
||||
|
@ -14,8 +15,8 @@ fn list_dir(str path) -> vec[str] {
|
|||
* tag type.
|
||||
*/
|
||||
const char path_sep = '/';
|
||||
const char alt_path_sep = '\\';
|
||||
|
||||
const char alt_path_sep = '\\';
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
|
||||
import str::sbuf;
|
||||
import vec::vbuf;
|
||||
|
||||
native mod libc = "msvcrt.dll" {
|
||||
fn open(sbuf s, int flags, uint mode) -> int = "_open";
|
||||
fn read(int fd, vbuf buf, uint count) -> int = "_read";
|
||||
fn write(int fd, vbuf buf, uint count) -> int = "_write";
|
||||
fn close(int fd) -> int = "_close";
|
||||
|
||||
native "cdecl" mod libc {
|
||||
fn open(sbuf s, int flags, uint mode) -> int"_open";
|
||||
fn read(int fd, vbuf buf, uint count) -> int"_read";
|
||||
fn write(int fd, vbuf buf, uint count) -> int"_write";
|
||||
fn close(int fd) -> int"_close";
|
||||
type FILE;
|
||||
fn fopen(sbuf path, sbuf mode) -> FILE;
|
||||
fn _fdopen(int fd, sbuf mode) -> FILE;
|
||||
|
@ -18,58 +18,50 @@ native mod libc = "msvcrt.dll" {
|
|||
fn fwrite(vbuf buf, uint size, uint n, FILE f) -> uint;
|
||||
fn fseek(FILE f, int offset, int whence) -> int;
|
||||
fn ftell(FILE f) -> int;
|
||||
|
||||
fn getenv(sbuf n) -> sbuf;
|
||||
|
||||
fn _pipe(vbuf fds, uint size, int mode) -> int;
|
||||
}
|
||||
|
||||
mod libc_constants {
|
||||
fn O_RDONLY() -> int { ret 0x0000; }
|
||||
fn O_WRONLY() -> int { ret 0x0001; }
|
||||
fn O_RDWR() -> int { ret 0x0002; }
|
||||
fn O_APPEND() -> int { ret 0x0400; }
|
||||
fn O_CREAT() -> int { ret 0x0040; }
|
||||
fn O_EXCL() -> int { ret 0x0080; }
|
||||
fn O_TRUNC() -> int { ret 0x0200; }
|
||||
fn O_TEXT() -> int { ret 0x4000; }
|
||||
fn O_BINARY() -> int { ret 0x8000; }
|
||||
fn O_RDONLY() -> int { ret 0; }
|
||||
fn O_WRONLY() -> int { ret 1; }
|
||||
fn O_RDWR() -> int { ret 2; }
|
||||
fn O_APPEND() -> int { ret 1024; }
|
||||
fn O_CREAT() -> int { ret 64; }
|
||||
fn O_EXCL() -> int { ret 128; }
|
||||
fn O_TRUNC() -> int { ret 512; }
|
||||
fn O_TEXT() -> int { ret 16384; }
|
||||
fn O_BINARY() -> int { ret 32768; }
|
||||
fn S_IRUSR() -> uint {
|
||||
ret 256u; // really _S_IREAD in win32
|
||||
|
||||
fn S_IRUSR() -> uint { ret 0x0100u; } // really _S_IREAD in win32
|
||||
fn S_IWUSR() -> uint { ret 0x0080u; } // really _S_IWRITE in win32
|
||||
}
|
||||
fn S_IWUSR() -> uint {
|
||||
ret 128u; // really _S_IWRITE in win32
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fn exec_suffix() -> str {
|
||||
ret ".exe";
|
||||
}
|
||||
fn exec_suffix() -> str { ret ".exe"; }
|
||||
|
||||
fn target_os() -> str {
|
||||
ret "win32";
|
||||
}
|
||||
fn target_os() -> str { ret "win32"; }
|
||||
|
||||
fn dylib_filename(str base) -> str {
|
||||
ret base + ".dll";
|
||||
}
|
||||
fn dylib_filename(str base) -> str { ret base + ".dll"; }
|
||||
|
||||
fn pipe() -> tup(int, int) {
|
||||
let vec[mutable int] fds = [mutable 0, 0];
|
||||
assert (os::libc::_pipe(vec::buf(fds), 1024u,
|
||||
libc_constants::O_BINARY()) == 0);
|
||||
assert (os::libc::_pipe(vec::buf(fds), 1024u, libc_constants::O_BINARY())
|
||||
== 0);
|
||||
ret tup(fds.(0), fds.(1));
|
||||
}
|
||||
|
||||
fn fd_FILE(int fd) -> libc::FILE {
|
||||
ret libc::_fdopen(fd, str::buf("r"));
|
||||
}
|
||||
fn fd_FILE(int fd) -> libc::FILE { ret libc::_fdopen(fd, str::buf("r")); }
|
||||
|
||||
native "rust" mod rustrt {
|
||||
fn rust_process_wait(int handle) -> int;
|
||||
}
|
||||
|
||||
fn waitpid(int pid) -> int {
|
||||
ret rustrt::rust_process_wait(pid);
|
||||
}
|
||||
|
||||
fn waitpid(int pid) -> int { ret rustrt::rust_process_wait(pid); }
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
|
||||
|
||||
/* -*- mode::rust;indent-tabs-mode::nil -*-
|
||||
* Implementation of 99 Bottles of Beer
|
||||
* http://99-bottles-of-beer.net/
|
||||
|
@ -6,62 +8,48 @@ use std;
|
|||
import std::int;
|
||||
import std::str;
|
||||
|
||||
fn b1() -> str {
|
||||
ret "# of beer on the wall, # of beer.";
|
||||
}
|
||||
fn b1() -> str { ret "# of beer on the wall, # of beer."; }
|
||||
|
||||
fn b2() -> str {
|
||||
ret "Take one down and pass it around, # of beer on the wall.";
|
||||
ret "Take one down and pass it around, # of beer on the wall.";
|
||||
}
|
||||
|
||||
fn b7() ->str {
|
||||
ret "No more bottles of beer on the wall, no more bottles of beer.";
|
||||
fn b7() -> str {
|
||||
ret "No more bottles of beer on the wall, no more bottles of beer.";
|
||||
}
|
||||
|
||||
fn b8() -> str {
|
||||
ret "Go to the store and buy some more, # of beer on the wall.";
|
||||
ret "Go to the store and buy some more, # of beer on the wall.";
|
||||
}
|
||||
|
||||
fn sub(str t, int n) -> str {
|
||||
let str b = "";
|
||||
let uint i = 0u;
|
||||
let str ns;
|
||||
alt (n) {
|
||||
case (0) {
|
||||
ns = "no more bottles";
|
||||
let str b = "";
|
||||
let uint i = 0u;
|
||||
let str ns;
|
||||
alt (n) {
|
||||
case (0) { ns = "no more bottles"; }
|
||||
case (1) { ns = "1 bottle"; }
|
||||
case (_) { ns = int::to_str(n, 10u) + " bottles"; }
|
||||
}
|
||||
case (1) {
|
||||
ns = "1 bottle";
|
||||
}
|
||||
case (_) {
|
||||
ns = int::to_str(n, 10u) + " bottles";
|
||||
}
|
||||
}
|
||||
while (i < str::byte_len(t)) {
|
||||
if (t.(i) == ('#' as u8)) {
|
||||
b += ns;
|
||||
while (i < str::byte_len(t)) {
|
||||
if (t.(i) == '#' as u8) {
|
||||
b += ns;
|
||||
} else { str::push_byte(b, t.(i)); }
|
||||
i += 1u;
|
||||
}
|
||||
else {
|
||||
str::push_byte(b, t.(i));
|
||||
}
|
||||
i += 1u;
|
||||
}
|
||||
ret b;
|
||||
ret b;
|
||||
}
|
||||
|
||||
|
||||
/* Using an interator */
|
||||
iter ninetynine() -> int {
|
||||
let int n = 100;
|
||||
while (n > 1) {
|
||||
n -= 1;
|
||||
put n;
|
||||
}
|
||||
}
|
||||
fn main() {
|
||||
for each (int n in ninetynine()) {
|
||||
log sub(b1(), n);
|
||||
log sub(b2(), n-1);
|
||||
log "";
|
||||
}
|
||||
log b7();
|
||||
log b8();
|
||||
}
|
||||
iter ninetynine() -> int { let int n = 100; while (n > 1) { n -= 1; put n; } }
|
||||
|
||||
fn main() {
|
||||
for each (int n in ninetynine()) {
|
||||
log sub(b1(), n);
|
||||
log sub(b2(), n - 1);
|
||||
log "";
|
||||
}
|
||||
log b7();
|
||||
log b8();
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
|
||||
|
||||
/* -*- mode::rust;indent-tabs-mode::nil -*-
|
||||
* Implementation of 99 Bottles of Beer
|
||||
* http://99-bottles-of-beer.net/
|
||||
|
@ -6,70 +8,55 @@ use std;
|
|||
import std::int;
|
||||
import std::str;
|
||||
|
||||
tag bottle { none; dual; single; multiple(int);}
|
||||
tag bottle { none; dual; single; multiple(int); }
|
||||
|
||||
fn show(bottle b) {
|
||||
alt(b) {
|
||||
case (none) {
|
||||
log "No more bottles of beer on the wall, no more bottles of beer,";
|
||||
log "Go to the store and buy some more, "
|
||||
+"99 bottles of beer on the wall.";
|
||||
alt (b) {
|
||||
case (none) {
|
||||
log "No more bottles of beer on the wall, " +
|
||||
"no more bottles of beer,";
|
||||
log "Go to the store and buy some more, " +
|
||||
"99 bottles of beer on the wall.";
|
||||
}
|
||||
case (single) {
|
||||
log "1 bottle of beer on the wall, 1 bottle of beer,";
|
||||
log "Take one down and pass it around, " +
|
||||
"no more bottles of beer on the wall.";
|
||||
}
|
||||
case (dual) {
|
||||
log "2 bottles of beer on the wall, 2 bottles of beer,";
|
||||
log "Take one down and pass it around, " +
|
||||
"1 bottle of beer on the wall.";
|
||||
}
|
||||
case (multiple(?n)) {
|
||||
let str nb = int::to_str(n, 10u);
|
||||
let str mb = int::to_str(n - 1, 10u);
|
||||
log nb + " bottles of beer on the wall, " + nb +
|
||||
" bottles of beer,";
|
||||
log "Take one down and pass it around, " + mb +
|
||||
" bottles of beer on the wall.";
|
||||
}
|
||||
}
|
||||
case (single) {
|
||||
log "1 bottle of beer on the wall, 1 bottle of beer,";
|
||||
log "Take one down and pass it around, "
|
||||
+"no more bottles of beer on the wall.";
|
||||
}
|
||||
case (dual) {
|
||||
log "2 bottles of beer on the wall, 2 bottles of beer,";
|
||||
log "Take one down and pass it around, 1 bottle of beer on the wall.";
|
||||
}
|
||||
case (multiple(?n)) {
|
||||
let str nb = int::to_str(n, 10u);
|
||||
let str mb = int::to_str(n - 1, 10u);
|
||||
log nb + " bottles of beer on the wall, " + nb + " bottles of beer,";
|
||||
log "Take one down and pass it around, "
|
||||
+ mb + " bottles of beer on the wall.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn next(bottle b) -> bottle {
|
||||
alt(b) {
|
||||
case (none) {
|
||||
ret none;
|
||||
alt (b) {
|
||||
case (none) { ret none; }
|
||||
case (single) { ret none; }
|
||||
case (dual) { ret single; }
|
||||
case (multiple(3)) { ret dual; }
|
||||
case (multiple(?n)) { ret multiple(n - 1); }
|
||||
}
|
||||
case (single) {
|
||||
ret none;
|
||||
}
|
||||
case (dual) {
|
||||
ret single;
|
||||
}
|
||||
case (multiple(3)) {
|
||||
ret dual;
|
||||
}
|
||||
case (multiple(?n)) {
|
||||
ret multiple(n - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Won't need this when tags can be compared with ==
|
||||
fn more(bottle b) -> bool {
|
||||
alt(b) {
|
||||
case (none) {
|
||||
ret false;
|
||||
}
|
||||
case (_) {
|
||||
ret true;
|
||||
}
|
||||
}
|
||||
alt (b) { case (none) { ret false; } case (_) { ret true; } }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let bottle b = multiple(99);
|
||||
let bool running = true;
|
||||
while (running) {
|
||||
show(b);
|
||||
log "";
|
||||
running = more(b);
|
||||
b = next(b);
|
||||
}
|
||||
let bottle b = multiple(99);
|
||||
let bool running = true;
|
||||
while (running) { show(b); log ""; running = more(b); b = next(b); }
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
|
||||
|
||||
/* -*- mode::rust;indent-tabs-mode::nil -*-
|
||||
* Implementation of 99 Bottles of Beer
|
||||
* http://99-bottles-of-beer.net/
|
||||
|
@ -6,56 +8,43 @@ use std;
|
|||
import std::int;
|
||||
import std::str;
|
||||
|
||||
fn b1() -> str {
|
||||
ret "# of beer on the wall, # of beer.";
|
||||
}
|
||||
fn b1() -> str { ret "# of beer on the wall, # of beer."; }
|
||||
|
||||
fn b2() -> str {
|
||||
ret "Take one down and pass it around, # of beer on the wall.";
|
||||
ret "Take one down and pass it around, # of beer on the wall.";
|
||||
}
|
||||
fn b7() ->str {
|
||||
ret "No more bottles of beer on the wall, no more bottles of beer.";
|
||||
|
||||
fn b7() -> str {
|
||||
ret "No more bottles of beer on the wall, no more bottles of beer.";
|
||||
}
|
||||
|
||||
fn b8() -> str {
|
||||
ret "Go to the store and buy some more, # of beer on the wall.";
|
||||
ret "Go to the store and buy some more, # of beer on the wall.";
|
||||
}
|
||||
|
||||
fn sub(str t, int n) -> str {
|
||||
let str b = "";
|
||||
let uint i = 0u;
|
||||
let str ns;
|
||||
alt (n) {
|
||||
case (0) {
|
||||
ns = "no more bottles";
|
||||
let str b = "";
|
||||
let uint i = 0u;
|
||||
let str ns;
|
||||
alt (n) {
|
||||
case (0) { ns = "no more bottles"; }
|
||||
case (1) { ns = "1 bottle"; }
|
||||
case (_) { ns = int::to_str(n, 10u) + " bottles"; }
|
||||
}
|
||||
case (1) {
|
||||
ns = "1 bottle";
|
||||
}
|
||||
case (_) {
|
||||
ns = int::to_str(n, 10u) + " bottles";
|
||||
}
|
||||
}
|
||||
while (i < str::byte_len(t)) {
|
||||
if (t.(i) == ('#' as u8)) {
|
||||
b += ns;
|
||||
while (i < str::byte_len(t)) {
|
||||
if (t.(i) == '#' as u8) {
|
||||
b += ns;
|
||||
} else { str::push_byte(b, t.(i)); }
|
||||
i += 1u;
|
||||
}
|
||||
else {
|
||||
str::push_byte(b, t.(i));
|
||||
}
|
||||
i += 1u;
|
||||
}
|
||||
ret b;
|
||||
ret b;
|
||||
}
|
||||
|
||||
|
||||
/* Straightforward counter */
|
||||
fn main() {
|
||||
let int n=99;
|
||||
while (n > 0) {
|
||||
log sub(b1(), n);
|
||||
log sub(b2(), n - 1);
|
||||
log "";
|
||||
n -= 1;
|
||||
}
|
||||
log b7();
|
||||
log sub(b8(),99);
|
||||
let int n = 99;
|
||||
while (n > 0) { log sub(b1(), n); log sub(b2(), n - 1); log ""; n -= 1; }
|
||||
log b7();
|
||||
log sub(b8(), 99);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,37 +7,33 @@ import std::int;
|
|||
import std::str;
|
||||
|
||||
fn main() {
|
||||
fn multiple(int n) {
|
||||
let str nb = int::to_str(n, 10u);
|
||||
let str mb = int::to_str(n - 1, 10u);
|
||||
log nb + " bottles of beer on the wall, " + nb + " bottles of beer,";
|
||||
log "Take one down and pass it around, "
|
||||
+ mb + " bottles of beer on the wall.";
|
||||
log "";
|
||||
if (n > 3) {
|
||||
be multiple(n - 1);
|
||||
fn multiple(int n) {
|
||||
let str nb = int::to_str(n, 10u);
|
||||
let str mb = int::to_str(n - 1, 10u);
|
||||
log nb + " bottles of beer on the wall, " + nb + " bottles of beer,";
|
||||
log "Take one down and pass it around, " + mb +
|
||||
" bottles of beer on the wall.";
|
||||
log "";
|
||||
if (n > 3) { be multiple(n - 1); } else { be dual(); }
|
||||
}
|
||||
else {
|
||||
be dual();
|
||||
fn dual() {
|
||||
log "2 bottles of beer on the wall, 2 bottles of beer,";
|
||||
log "Take one down and pass it around, 1 bottle of beer on the wall.";
|
||||
log "";
|
||||
be single();
|
||||
}
|
||||
}
|
||||
fn dual() {
|
||||
log "2 bottles of beer on the wall, 2 bottles of beer,";
|
||||
log "Take one down and pass it around, 1 bottle of beer on the wall.";
|
||||
log "";
|
||||
be single();
|
||||
}
|
||||
fn single() {
|
||||
log "1 bottle of beer on the wall, 1 bottle of beer,";
|
||||
log "Take one down and pass it around, "
|
||||
+ "no more bottles of beer on the wall.";
|
||||
log "";
|
||||
be none();
|
||||
}
|
||||
fn none() {
|
||||
log "No more bottles of beer on the wall, no more bottles of beer,";
|
||||
log "Go to the store and buy some more, 99 bottles of beer on the wall.";
|
||||
log "";
|
||||
}
|
||||
multiple(99);
|
||||
fn single() {
|
||||
log "1 bottle of beer on the wall, 1 bottle of beer,";
|
||||
log "Take one down and pass it around, " +
|
||||
"no more bottles of beer on the wall.";
|
||||
log "";
|
||||
be none();
|
||||
}
|
||||
fn none() {
|
||||
log "No more bottles of beer on the wall, no more bottles of beer,";
|
||||
log "Go to the store and buy some more, " +
|
||||
"99 bottles of beer on the wall.";
|
||||
log "";
|
||||
}
|
||||
multiple(99);
|
||||
}
|
|
@ -1,25 +1,25 @@
|
|||
// -*- rust -*-
|
||||
|
||||
|
||||
|
||||
// -*- rust -*-
|
||||
fn ack(int m, int n) -> int {
|
||||
if (m == 0) {
|
||||
ret n+1;
|
||||
} else {
|
||||
if (n == 0) {
|
||||
ret ack(m-1, 1);
|
||||
if (m == 0) {
|
||||
ret n + 1;
|
||||
} else {
|
||||
ret ack(m-1, ack(m, n-1));
|
||||
if (n == 0) {
|
||||
ret ack(m - 1, 1);
|
||||
} else { ret ack(m - 1, ack(m, n - 1)); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert (ack(0,0) == 1);
|
||||
assert (ack(3,2) == 29);
|
||||
assert (ack(3,4) == 125);
|
||||
assert (ack(0, 0) == 1);
|
||||
assert (ack(3, 2) == 29);
|
||||
assert (ack(3, 4) == 125);
|
||||
// This takes a while; but a comparison may amuse: on win32 at least, the
|
||||
// posted C version of the 'benchmark' running ack(4,1) overruns its stack
|
||||
// segment and crashes. We just grow our stack (to 4mb) as we go.
|
||||
|
||||
// This takes a while; but a comparison may amuse: on win32 at least, the
|
||||
// posted C version of the 'benchmark' running ack(4,1) overruns its stack
|
||||
// segment and crashes. We just grow our stack (to 4mb) as we go.
|
||||
// assert (ack(4,1) == 65533);
|
||||
|
||||
// assert (ack(4,1) == 65533);
|
||||
}
|
|
@ -1,74 +1,53 @@
|
|||
use std;
|
||||
|
||||
use std;
|
||||
import std::int;
|
||||
|
||||
tag tree {
|
||||
nil;
|
||||
node(@tree, @tree, int);
|
||||
}
|
||||
tag tree { nil; node(@tree, @tree, int); }
|
||||
|
||||
fn item_check(@tree t) -> int {
|
||||
alt (*t) {
|
||||
case (nil) {
|
||||
ret 0;
|
||||
alt (*t) {
|
||||
case (nil) { ret 0; }
|
||||
case (node(?left, ?right, ?item)) {
|
||||
ret item + item_check(left) - item_check(right);
|
||||
}
|
||||
}
|
||||
case (node(?left, ?right, ?item)) {
|
||||
ret item + item_check(left) - item_check(right);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn bottom_up_tree(int item, int depth) -> @tree{
|
||||
if (depth > 0) {
|
||||
ret @node(bottom_up_tree(2 * item - 1, depth - 1),
|
||||
bottom_up_tree(2 * item, depth - 1),
|
||||
item);
|
||||
} else {
|
||||
ret @nil;
|
||||
}
|
||||
fn bottom_up_tree(int item, int depth) -> @tree {
|
||||
if (depth > 0) {
|
||||
ret @node(bottom_up_tree(2 * item - 1, depth - 1),
|
||||
bottom_up_tree(2 * item, depth - 1), item);
|
||||
} else { ret @nil; }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
||||
auto n = 8;
|
||||
auto min_depth = 4;
|
||||
auto max_depth;
|
||||
if (min_depth + 2 > n) {
|
||||
max_depth = min_depth + 2;
|
||||
} else {
|
||||
max_depth = n;
|
||||
}
|
||||
|
||||
auto stretch_depth = max_depth + 1;
|
||||
|
||||
auto stretch_tree = bottom_up_tree(0, stretch_depth);
|
||||
log #fmt("stretch tree of depth %d\t check: %d",
|
||||
stretch_depth, item_check(stretch_tree));
|
||||
|
||||
auto long_lived_tree = bottom_up_tree(0, max_depth);
|
||||
|
||||
auto depth = min_depth;
|
||||
while (depth <= max_depth) {
|
||||
auto iterations = int::pow(2, (max_depth - depth + min_depth) as uint);
|
||||
auto chk = 0;
|
||||
|
||||
auto i = 1;
|
||||
while (i <= iterations) {
|
||||
auto temp_tree = bottom_up_tree(i, depth);
|
||||
chk += item_check(temp_tree);
|
||||
|
||||
temp_tree = bottom_up_tree(-i, depth);
|
||||
chk += item_check(temp_tree);
|
||||
|
||||
i += 1;
|
||||
auto n = 8;
|
||||
auto min_depth = 4;
|
||||
auto max_depth;
|
||||
if (min_depth + 2 > n) {
|
||||
max_depth = min_depth + 2;
|
||||
} else { max_depth = n; }
|
||||
auto stretch_depth = max_depth + 1;
|
||||
auto stretch_tree = bottom_up_tree(0, stretch_depth);
|
||||
log #fmt("stretch tree of depth %d\t check: %d", stretch_depth,
|
||||
item_check(stretch_tree));
|
||||
auto long_lived_tree = bottom_up_tree(0, max_depth);
|
||||
auto depth = min_depth;
|
||||
while (depth <= max_depth) {
|
||||
auto iterations = int::pow(2, max_depth - depth + min_depth as uint);
|
||||
auto chk = 0;
|
||||
auto i = 1;
|
||||
while (i <= iterations) {
|
||||
auto temp_tree = bottom_up_tree(i, depth);
|
||||
chk += item_check(temp_tree);
|
||||
temp_tree = bottom_up_tree(-i, depth);
|
||||
chk += item_check(temp_tree);
|
||||
i += 1;
|
||||
}
|
||||
log #fmt("%d\t trees of depth %d\t check: %d", iterations * 2, depth,
|
||||
chk);
|
||||
depth += 2;
|
||||
}
|
||||
|
||||
log #fmt("%d\t trees of depth %d\t check: %d",
|
||||
iterations * 2, depth, chk);
|
||||
|
||||
depth += 2;
|
||||
}
|
||||
|
||||
log #fmt("long lived trees of depth %d\t check: %d",
|
||||
max_depth, item_check(long_lived_tree));
|
||||
log #fmt("long lived trees of depth %d\t check: %d", max_depth,
|
||||
item_check(long_lived_tree));
|
||||
}
|
|
@ -1,99 +1,64 @@
|
|||
|
||||
|
||||
// Based on Isaac Gouy's fannkuchredux.csharp
|
||||
|
||||
use std;
|
||||
|
||||
import std::int;
|
||||
import std::vec;
|
||||
|
||||
fn fannkuch(int n) -> int {
|
||||
fn perm1init(uint i) -> int { ret i as int; }
|
||||
auto perm1init_ = perm1init; // Rustboot workaround
|
||||
|
||||
fn perm1init(uint i) -> int {
|
||||
ret i as int;
|
||||
}
|
||||
auto perm1init_ = perm1init; // Rustboot workaround
|
||||
auto perm = vec::init_elt_mut(0, n as uint);
|
||||
auto perm1 = vec::init_fn_mut(perm1init_, n as uint);
|
||||
auto count = vec::init_elt_mut(0, n as uint);
|
||||
auto f = 0;
|
||||
auto i = 0;
|
||||
auto k = 0;
|
||||
auto r = 0;
|
||||
auto flips = 0;
|
||||
auto nperm = 0;
|
||||
auto checksum = 0;
|
||||
r = n;
|
||||
while (r > 0) {
|
||||
i = 0;
|
||||
while (r != 1) { count.(r - 1) = r; r -= 1; }
|
||||
while (i < n) { perm.(i) = perm1.(i); i += 1; }
|
||||
// Count flips and update max and checksum
|
||||
|
||||
auto perm = vec::init_elt_mut(0, n as uint);
|
||||
auto perm1 = vec::init_fn_mut(perm1init_, n as uint);
|
||||
auto count = vec::init_elt_mut(0, n as uint);
|
||||
f = 0;
|
||||
k = perm.(0);
|
||||
while (k != 0) {
|
||||
i = 0;
|
||||
while (2 * i < k) {
|
||||
auto t = perm.(i);
|
||||
perm.(i) = perm.(k - i);
|
||||
perm.(k - i) = t;
|
||||
i += 1;
|
||||
}
|
||||
k = perm.(0);
|
||||
f += 1;
|
||||
}
|
||||
if (f > flips) { flips = f; }
|
||||
if (nperm & 0x1 == 0) { checksum += f; } else { checksum -= f; }
|
||||
// Use incremental change to generate another permutation
|
||||
|
||||
auto f = 0;
|
||||
auto i = 0;
|
||||
auto k = 0;
|
||||
auto r = 0;
|
||||
auto flips = 0;
|
||||
auto nperm = 0;
|
||||
auto checksum = 0;
|
||||
|
||||
r = n;
|
||||
while (r > 0) {
|
||||
i = 0;
|
||||
|
||||
while (r != 1) {
|
||||
count.(r - 1) = r;
|
||||
r -=1;
|
||||
auto go = true;
|
||||
while (go) {
|
||||
if (r == n) { log checksum; ret flips; }
|
||||
auto p0 = perm1.(0);
|
||||
i = 0;
|
||||
while (i < r) { auto j = i + 1; perm1.(i) = perm1.(j); i = j; }
|
||||
perm1.(r) = p0;
|
||||
count.(r) -= 1;
|
||||
if (count.(r) > 0) { go = false; } else { r += 1; }
|
||||
}
|
||||
nperm += 1;
|
||||
}
|
||||
|
||||
while (i < n) {
|
||||
perm.(i) = perm1.(i);
|
||||
i += 1;
|
||||
}
|
||||
|
||||
// Count flips and update max and checksum
|
||||
f = 0;
|
||||
k = perm.(0);
|
||||
while (k != 0) {
|
||||
i = 0;
|
||||
while (2 * i < k) {
|
||||
auto t = perm.(i);
|
||||
perm.(i) = perm.(k - i);
|
||||
perm.(k - i) = t;
|
||||
i += 1;
|
||||
}
|
||||
k = perm.(0);
|
||||
f += 1;
|
||||
}
|
||||
|
||||
if (f > flips) {
|
||||
flips = f;
|
||||
}
|
||||
|
||||
if ((nperm & 0x1) == 0) {
|
||||
checksum += f;
|
||||
} else {
|
||||
checksum -= f;
|
||||
}
|
||||
|
||||
// Use incremental change to generate another permutation
|
||||
auto go = true;
|
||||
while (go) {
|
||||
if (r == n) {
|
||||
log checksum;
|
||||
ret flips;
|
||||
}
|
||||
auto p0 = perm1.(0);
|
||||
i = 0;
|
||||
while (i < r) {
|
||||
auto j = i + 1;
|
||||
perm1.(i) = perm1.(j);
|
||||
i = j;
|
||||
}
|
||||
perm1.(r) = p0;
|
||||
|
||||
count.(r) -= 1;
|
||||
if (count.(r) > 0) {
|
||||
go = false;
|
||||
} else {
|
||||
r += 1;
|
||||
}
|
||||
}
|
||||
|
||||
nperm += 1;
|
||||
}
|
||||
|
||||
ret flips;
|
||||
ret flips;
|
||||
}
|
||||
|
||||
fn main(vec[str] args) {
|
||||
auto n = 7;
|
||||
log #fmt("Pfannkuchen(%d) = %d", n, fannkuch(n));
|
||||
auto n = 7;
|
||||
log #fmt("Pfannkuchen(%d) = %d", n, fannkuch(n));
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
|
||||
|
||||
/* -*- mode: rust; indent-tabs-mode: nil -*-
|
||||
* Implementation of 'fasta' benchmark from
|
||||
* Computer Language Benchmarks Game
|
||||
|
@ -9,119 +11,80 @@ import std::str;
|
|||
import std::uint;
|
||||
import std::int;
|
||||
|
||||
fn LINE_LENGTH() -> uint {
|
||||
ret 60u;
|
||||
}
|
||||
fn LINE_LENGTH() -> uint { ret 60u; }
|
||||
|
||||
obj myrandom(mutable u32 last) {
|
||||
fn next(u32 mx) -> u32 {
|
||||
last = (last * 3877u32 + 29573u32) % 139968u32;
|
||||
auto ans = (mx*last) / 139968u32;
|
||||
ret ans;
|
||||
}
|
||||
fn next(u32 mx) -> u32 {
|
||||
last = (last * 3877u32 + 29573u32) % 139968u32;
|
||||
auto ans = mx * last / 139968u32;
|
||||
ret ans;
|
||||
}
|
||||
}
|
||||
|
||||
type aminoacids = tup(char, u32);
|
||||
|
||||
fn make_cumulative(vec[aminoacids] aa) -> vec[aminoacids] {
|
||||
let u32 cp = 0u32;
|
||||
let vec[aminoacids] ans = [];
|
||||
for (aminoacids a in aa) {
|
||||
cp += a._1;
|
||||
ans += [tup(a._0, cp)];
|
||||
}
|
||||
ret ans;
|
||||
let u32 cp = 0u32;
|
||||
let vec[aminoacids] ans = [];
|
||||
for (aminoacids a in aa) { cp += a._1; ans += [tup(a._0, cp)]; }
|
||||
ret ans;
|
||||
}
|
||||
|
||||
fn select_random(u32 r, vec[aminoacids] genelist) -> char {
|
||||
if (r < genelist.(0)._1) {
|
||||
ret genelist.(0)._0;
|
||||
}
|
||||
fn bisect(vec[aminoacids] v, uint lo, uint hi, u32 target) -> char {
|
||||
if (hi > (lo + 1u)) {
|
||||
let uint mid = lo + (hi - lo) / 2u;
|
||||
if (target < v.(mid)._1) {
|
||||
be bisect(v, lo, mid, target);
|
||||
}
|
||||
else {
|
||||
be bisect(v, mid, hi, target);
|
||||
}
|
||||
if (r < genelist.(0)._1) { ret genelist.(0)._0; }
|
||||
fn bisect(vec[aminoacids] v, uint lo, uint hi, u32 target) -> char {
|
||||
if (hi > lo + 1u) {
|
||||
let uint mid = lo + (hi - lo) / 2u;
|
||||
if (target < v.(mid)._1) {
|
||||
be bisect(v, lo, mid, target);
|
||||
} else { be bisect(v, mid, hi, target); }
|
||||
} else { ret v.(hi)._0; }
|
||||
}
|
||||
else {
|
||||
ret v.(hi)._0;
|
||||
}
|
||||
}
|
||||
ret bisect(genelist, 0u, vec::len[aminoacids](genelist) - 1u, r);
|
||||
ret bisect(genelist, 0u, vec::len[aminoacids](genelist) - 1u, r);
|
||||
}
|
||||
|
||||
fn make_random_fasta(str id, str desc, vec[aminoacids] genelist, int n) {
|
||||
log(">" + id + " " + desc);
|
||||
auto rng = myrandom(std::rand::mk_rng().next());
|
||||
let str op = "";
|
||||
for each (uint i in uint::range(0u, n as uint)) {
|
||||
str::push_byte(op, select_random(rng.next(100u32), genelist) as u8);
|
||||
if (str::byte_len(op) >= LINE_LENGTH()) {
|
||||
log(op);
|
||||
op = "";
|
||||
log ">" + id + " " + desc;
|
||||
auto rng = myrandom(std::rand::mk_rng().next());
|
||||
let str op = "";
|
||||
for each (uint i in uint::range(0u, n as uint)) {
|
||||
str::push_byte(op, select_random(rng.next(100u32), genelist) as u8);
|
||||
if (str::byte_len(op) >= LINE_LENGTH()) { log op; op = ""; }
|
||||
}
|
||||
}
|
||||
if (str::byte_len(op) > 0u) {
|
||||
log(op);
|
||||
}
|
||||
if (str::byte_len(op) > 0u) { log op; }
|
||||
}
|
||||
|
||||
fn make_repeat_fasta(str id, str desc, str s, int n) {
|
||||
log(">" + id + " " + desc);
|
||||
let str op = "";
|
||||
let uint sl = str::byte_len(s);
|
||||
for each (uint i in uint::range(0u, n as uint)) {
|
||||
|
||||
str::push_byte(op, s.(i % sl));
|
||||
if (str::byte_len(op) >= LINE_LENGTH()) {
|
||||
log(op);
|
||||
op = "";
|
||||
log ">" + id + " " + desc;
|
||||
let str op = "";
|
||||
let uint sl = str::byte_len(s);
|
||||
for each (uint i in uint::range(0u, n as uint)) {
|
||||
str::push_byte(op, s.(i % sl));
|
||||
if (str::byte_len(op) >= LINE_LENGTH()) { log op; op = ""; }
|
||||
}
|
||||
}
|
||||
if (str::byte_len(op) > 0u) {
|
||||
log(op);
|
||||
}
|
||||
if (str::byte_len(op) > 0u) { log op; }
|
||||
}
|
||||
|
||||
fn main(vec[str] args) {
|
||||
let vec[aminoacids] iub = make_cumulative([tup( 'a', 27u32 ),
|
||||
tup( 'c', 12u32 ),
|
||||
tup( 'g', 12u32 ),
|
||||
tup( 't', 27u32 ),
|
||||
|
||||
tup( 'B', 2u32 ),
|
||||
tup( 'D', 2u32 ),
|
||||
tup( 'H', 2u32 ),
|
||||
tup( 'K', 2u32 ),
|
||||
tup( 'M', 2u32 ),
|
||||
tup( 'N', 2u32 ),
|
||||
tup( 'R', 2u32 ),
|
||||
tup( 'S', 2u32 ),
|
||||
tup( 'V', 2u32 ),
|
||||
tup( 'W', 2u32 ),
|
||||
tup( 'Y', 2u32 )]);
|
||||
|
||||
let vec[aminoacids] homosapiens = make_cumulative([tup( 'a', 30u32 ),
|
||||
tup( 'c', 20u32 ),
|
||||
tup( 'g', 20u32 ),
|
||||
tup( 't', 30u32 )]);
|
||||
|
||||
let str alu =
|
||||
"GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG" +
|
||||
"GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA" +
|
||||
"CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT" +
|
||||
"ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA" +
|
||||
"GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG" +
|
||||
"AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC" +
|
||||
"AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA";
|
||||
|
||||
let int n = 512;
|
||||
|
||||
make_repeat_fasta ("ONE", "Homo sapiens alu", alu, n*2);
|
||||
make_random_fasta("TWO", "IUB ambiguity codes", iub, n*3);
|
||||
make_random_fasta ("THREE", "Homo sapiens frequency", homosapiens, n*5);
|
||||
let vec[aminoacids] iub =
|
||||
make_cumulative([tup('a', 27u32), tup('c', 12u32), tup('g', 12u32),
|
||||
tup('t', 27u32), tup('B', 2u32), tup('D', 2u32),
|
||||
tup('H', 2u32), tup('K', 2u32), tup('M', 2u32),
|
||||
tup('N', 2u32), tup('R', 2u32), tup('S', 2u32),
|
||||
tup('V', 2u32), tup('W', 2u32), tup('Y', 2u32)]);
|
||||
let vec[aminoacids] homosapiens =
|
||||
make_cumulative([tup('a', 30u32), tup('c', 20u32), tup('g', 20u32),
|
||||
tup('t', 30u32)]);
|
||||
let str alu =
|
||||
"GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG" +
|
||||
"GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA" +
|
||||
"CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT" +
|
||||
"ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA" +
|
||||
"GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG" +
|
||||
"AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC" +
|
||||
"AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA";
|
||||
let int n = 512;
|
||||
make_repeat_fasta("ONE", "Homo sapiens alu", alu, n * 2);
|
||||
make_random_fasta("TWO", "IUB ambiguity codes", iub, n * 3);
|
||||
make_random_fasta("THREE", "Homo sapiens frequency", homosapiens, n * 5);
|
||||
}
|
|
@ -1,22 +1,19 @@
|
|||
// -*- rust -*-
|
||||
|
||||
|
||||
|
||||
// -*- rust -*-
|
||||
fn fib(int n) -> int {
|
||||
// Several of the posted 'benchmark' versions of this compute the
|
||||
// wrong Fibonacci numbers, of course.
|
||||
if (n == 0) {
|
||||
ret 0;
|
||||
} else {
|
||||
if (n <= 2) {
|
||||
ret 1;
|
||||
} else {
|
||||
ret fib(n-1) + fib(n-2);
|
||||
}
|
||||
}
|
||||
|
||||
// Several of the posted 'benchmark' versions of this compute the
|
||||
// wrong Fibonacci numbers, of course.
|
||||
if (n == 0) {
|
||||
ret 0;
|
||||
} else { if (n <= 2) { ret 1; } else { ret fib(n - 1) + fib(n - 2); } }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert (fib(8) == 21);
|
||||
assert (fib(15) == 610);
|
||||
log fib(8);
|
||||
log fib(15);
|
||||
assert (fib(8) == 21);
|
||||
assert (fib(15) == 610);
|
||||
log fib(8);
|
||||
log fib(15);
|
||||
}
|
|
@ -1,18 +1,16 @@
|
|||
|
||||
|
||||
// error-pattern:explicit failure
|
||||
use std;
|
||||
import std::option::*;
|
||||
|
||||
fn foo(str s) {
|
||||
}
|
||||
fn foo(str s) { }
|
||||
|
||||
fn main() {
|
||||
auto i = alt (some[int](3)) {
|
||||
case (none[int]) {
|
||||
fail
|
||||
}
|
||||
case (some[int](_)) {
|
||||
fail
|
||||
}
|
||||
};
|
||||
foo(i);
|
||||
auto i =
|
||||
alt (some[int](3)) {
|
||||
case (none[int]) { fail }
|
||||
case (some[int](_)) { fail }
|
||||
};
|
||||
foo(i);
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// error-pattern:woooo
|
||||
|
||||
fn main() {
|
||||
fail "woooo";
|
||||
}
|
||||
|
||||
|
||||
// error-pattern:woooo
|
||||
fn main() { fail"woooo"; }
|
|
@ -1,5 +1,5 @@
|
|||
// error-pattern:explicit
|
||||
|
||||
fn main() {
|
||||
fail;
|
||||
}
|
||||
|
||||
|
||||
// error-pattern:explicit
|
||||
fn main() { fail; }
|
|
@ -1,19 +1,12 @@
|
|||
// error-pattern:explicit failure
|
||||
|
||||
|
||||
|
||||
// error-pattern:explicit failure
|
||||
fn f() -> ! { fail }
|
||||
|
||||
fn g() -> int {
|
||||
auto x = alt (true) {
|
||||
case (true) {
|
||||
f()
|
||||
}
|
||||
case (false) {
|
||||
10
|
||||
}
|
||||
};
|
||||
ret x;
|
||||
auto x = alt (true) { case (true) { f() } case (false) { 10 } };
|
||||
ret x;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
g();
|
||||
}
|
||||
fn main() { g(); }
|
|
@ -1,12 +1,5 @@
|
|||
// error-pattern:explicit failure
|
||||
|
||||
fn main() {
|
||||
auto x = alt(true) {
|
||||
case (false) {
|
||||
0
|
||||
}
|
||||
case (true) {
|
||||
fail
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// error-pattern:explicit failure
|
||||
fn main() { auto x = alt (true) { case (false) { 0 } case (true) { fail } }; }
|
|
@ -1,7 +1,7 @@
|
|||
// error-pattern:explicit failure
|
||||
|
||||
|
||||
|
||||
// error-pattern:explicit failure
|
||||
fn f() -> ! { fail }
|
||||
|
||||
fn main() {
|
||||
f();
|
||||
}
|
||||
fn main() { f(); }
|
|
@ -1,16 +1,9 @@
|
|||
// error-pattern:explicit failure
|
||||
|
||||
|
||||
|
||||
// error-pattern:explicit failure
|
||||
fn f() -> ! { fail }
|
||||
|
||||
fn g() -> int {
|
||||
auto x = if (true) {
|
||||
f()
|
||||
} else {
|
||||
10
|
||||
};
|
||||
ret x;
|
||||
}
|
||||
fn g() -> int { auto x = if (true) { f() } else { 10 }; ret x; }
|
||||
|
||||
fn main() {
|
||||
g();
|
||||
}
|
||||
fn main() { g(); }
|
|
@ -1,11 +1,5 @@
|
|||
// error-pattern:explicit failure
|
||||
|
||||
fn main() {
|
||||
auto x = if (false) {
|
||||
0
|
||||
} else if (true) {
|
||||
fail
|
||||
} else {
|
||||
10
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// error-pattern:explicit failure
|
||||
fn main() { auto x = if (false) { 0 } else if (true) { fail } else { 10 }; }
|
|
@ -1,5 +1,5 @@
|
|||
// error-pattern:1 == 2
|
||||
|
||||
fn main() {
|
||||
assert (1 == 2);
|
||||
}
|
||||
|
||||
|
||||
// error-pattern:1 == 2
|
||||
fn main() { assert (1 == 2); }
|
|
@ -1,15 +1,9 @@
|
|||
|
||||
|
||||
|
||||
// -*- rust -*-
|
||||
|
||||
// error-pattern:non-exhaustive match failure
|
||||
tag t { a; b; }
|
||||
|
||||
tag t {
|
||||
a;
|
||||
b;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
auto x = a;
|
||||
alt (x) {
|
||||
case (b) { }
|
||||
}
|
||||
}
|
||||
fn main() { auto x = a; alt (x) { case (b) { } } }
|
|
@ -1,17 +1,11 @@
|
|||
|
||||
|
||||
|
||||
// -*- rust -*-
|
||||
// xfail-stage0
|
||||
// error-pattern:Predicate lt(b, a) failed
|
||||
fn f(int a, int b) { }
|
||||
|
||||
fn f(int a, int b) : lt(a,b) {
|
||||
}
|
||||
pred lt(int a, int b) -> bool { ret a < b; }
|
||||
|
||||
pred lt(int a, int b) -> bool {
|
||||
ret a < b;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let int a = 10;
|
||||
let int b = 23;
|
||||
check lt(b,a);
|
||||
f(b,a);
|
||||
}
|
||||
fn main() { let int a = 10; let int b = 23; check (lt(b, a)); f(b, a); }
|
|
@ -1,10 +1,8 @@
|
|||
|
||||
|
||||
|
||||
// Tests that trans treats the rhs of pth's decl
|
||||
// as a _|_-typed thing, not a str-typed thing
|
||||
// xfail-stage0
|
||||
// error-pattern:bye
|
||||
fn main() {
|
||||
auto pth = fail "bye";
|
||||
|
||||
let rec(str t) res = rec(t=pth);
|
||||
|
||||
}
|
||||
fn main() { auto pth = fail"bye"; let rec(str t) res = rec(t=pth); }
|
|
@ -1,16 +1,18 @@
|
|||
|
||||
|
||||
|
||||
// -*- rust -*-
|
||||
|
||||
// error-pattern:bounds check
|
||||
|
||||
fn main() {
|
||||
let str s = "hello";
|
||||
let int x = 0;
|
||||
assert (s.(x) == (0x68 as u8));
|
||||
let str s = "hello";
|
||||
let int x = 0;
|
||||
assert (s.(x) == 0x68 as u8);
|
||||
// NB: at the moment a string always has a trailing NULL,
|
||||
// so the largest index value on the string above is 5, not
|
||||
// 4. Possibly change this.
|
||||
|
||||
// NB: at the moment a string always has a trailing NULL,
|
||||
// so the largest index value on the string above is 5, not
|
||||
// 4. Possibly change this.
|
||||
// Bounds-check failure.
|
||||
|
||||
// Bounds-check failure.
|
||||
assert (s.(x + 6) == (0x0 as u8));
|
||||
assert (s.(x + 6) == 0x0 as u8);
|
||||
}
|
|
@ -1,17 +1,18 @@
|
|||
|
||||
|
||||
|
||||
// xfail-stage0
|
||||
// xfail-stage1
|
||||
// xfail-stage2
|
||||
|
||||
/*
|
||||
This program should hang on the po |> r line.
|
||||
*/
|
||||
|
||||
fn main() {
|
||||
let port[int] po = port();
|
||||
let chan[int] ch = chan(po);
|
||||
|
||||
auto r; po |> r;
|
||||
|
||||
auto r;
|
||||
po |> r;
|
||||
ch <| 42;
|
||||
|
||||
log_err r;
|
||||
}
|
|
@ -1,11 +1,14 @@
|
|||
|
||||
|
||||
|
||||
// -*- rust -*-
|
||||
|
||||
// error-pattern:bounds check
|
||||
|
||||
fn main() {
|
||||
let vec[int] v = [10];
|
||||
let int x = 0;
|
||||
assert (v.(x) == 10);
|
||||
// Bounds-check failure.
|
||||
assert (v.(x + 2) == 20);
|
||||
let vec[int] v = [10];
|
||||
let int x = 0;
|
||||
assert (v.(x) == 10);
|
||||
// Bounds-check failure.
|
||||
|
||||
assert (v.(x + 2) == 20);
|
||||
}
|
|
@ -1,11 +1,14 @@
|
|||
|
||||
|
||||
|
||||
// -*- rust -*-
|
||||
|
||||
// error-pattern:bounds check
|
||||
|
||||
fn main() {
|
||||
let vec[int] v = [10, 20];
|
||||
let int x = 0;
|
||||
assert (v.(x) == 10);
|
||||
// Bounds-check failure.
|
||||
assert (v.(x-1) == 20);
|
||||
let vec[int] v = [10, 20];
|
||||
let int x = 0;
|
||||
assert (v.(x) == 10);
|
||||
// Bounds-check failure.
|
||||
|
||||
assert (v.(x - 1) == 20);
|
||||
}
|
|
@ -1,23 +1,16 @@
|
|||
// Regression test for issue #374
|
||||
|
||||
|
||||
// Regression test for issue #374
|
||||
use std;
|
||||
import std::option;
|
||||
import std::option::none;
|
||||
|
||||
tag sty {
|
||||
ty_nil;
|
||||
}
|
||||
tag sty { ty_nil; }
|
||||
|
||||
type raw_t = rec(sty struct,
|
||||
option::t[str] cname,
|
||||
uint hash);
|
||||
type raw_t = rec(sty struct, option::t[str] cname, uint hash);
|
||||
|
||||
fn mk_raw_ty(sty st, &option::t[str] cname) -> raw_t {
|
||||
ret rec(struct=st,
|
||||
cname=cname,
|
||||
hash=0u);
|
||||
ret rec(struct=st, cname=cname, hash=0u);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
mk_raw_ty(ty_nil, none[str]);
|
||||
}
|
||||
fn main() { mk_raw_ty(ty_nil, none[str]); }
|
|
@ -1,15 +1,14 @@
|
|||
|
||||
|
||||
// xfail-stage0
|
||||
use std;
|
||||
import std::option::*;
|
||||
|
||||
fn main() {
|
||||
let int i = alt (some[int](3)) {
|
||||
case (none[int]) {
|
||||
fail
|
||||
}
|
||||
case (some[int](_)) {
|
||||
5
|
||||
}
|
||||
};
|
||||
log i;
|
||||
let int i =
|
||||
alt (some[int](3)) {
|
||||
case (none[int]) { fail }
|
||||
case (some[int](_)) { 5 }
|
||||
};
|
||||
log i;
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
use std;
|
||||
import std::option;
|
||||
import std::option::t;
|
||||
|
@ -5,30 +6,17 @@ import std::option::none;
|
|||
import std::option::some;
|
||||
|
||||
fn foo[T](&option::t[T] y) {
|
||||
let int x;
|
||||
let int x;
|
||||
let vec[int] res = [];
|
||||
/* tests that x doesn't get put in the precondition for the
|
||||
entire if expression */
|
||||
|
||||
let vec[int] res = [];
|
||||
|
||||
/* tests that x doesn't get put in the precondition for the
|
||||
entire if expression */
|
||||
if (true) {
|
||||
}
|
||||
else {
|
||||
alt (y) {
|
||||
case (none[T]) {
|
||||
x = 17;
|
||||
}
|
||||
case (_) {
|
||||
x = 42;
|
||||
}
|
||||
if (true) {
|
||||
} else {
|
||||
alt (y) { case (none[T]) { x = 17; } case (_) { x = 42; } }
|
||||
res += [x];
|
||||
}
|
||||
res += [x];
|
||||
}
|
||||
|
||||
ret;
|
||||
ret;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
log("hello");
|
||||
foo[int](some[int](5));
|
||||
}
|
||||
fn main() { log "hello"; foo[int](some[int](5)); }
|
|
@ -1,14 +1,9 @@
|
|||
|
||||
|
||||
mod m1 {
|
||||
tag foo {
|
||||
foo1;
|
||||
foo2;
|
||||
}
|
||||
}
|
||||
fn bar(m1::foo x) {
|
||||
alt(x) {
|
||||
case (m1::foo1) {
|
||||
}
|
||||
}
|
||||
}
|
||||
fn main(vec[str] args) {
|
||||
tag foo { foo1; foo2; }
|
||||
}
|
||||
|
||||
fn bar(m1::foo x) { alt (x) { case (m1::foo1) { } } }
|
||||
|
||||
fn main(vec[str] args) { }
|
|
@ -1,32 +1,35 @@
|
|||
// -*- rust -*-
|
||||
|
||||
|
||||
// -*- rust -*-
|
||||
use std;
|
||||
import std::str;
|
||||
|
||||
|
||||
// FIXME: import std::dbg.const_refcount. Currently
|
||||
// cross-crate const references don't work.
|
||||
const uint const_refcount = 0x7bad_face_u;
|
||||
|
||||
tag t {
|
||||
make_t(str);
|
||||
clam;
|
||||
}
|
||||
tag t { make_t(str); clam; }
|
||||
|
||||
fn foo(str s) {
|
||||
let t x = make_t(s); // ref up
|
||||
let t x = make_t(s); // ref up
|
||||
|
||||
alt (x) {
|
||||
case (make_t(?y)) { log y; } // ref up then down
|
||||
case (_) { log "?"; fail; }
|
||||
}
|
||||
alt (x) {
|
||||
case (make_t(?y)) {
|
||||
log y; // ref up then down
|
||||
|
||||
log str::refcount(s);
|
||||
assert (str::refcount(s) == const_refcount);
|
||||
}
|
||||
case (_) { log "?"; fail; }
|
||||
}
|
||||
log str::refcount(s);
|
||||
assert (str::refcount(s) == const_refcount);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let str s = "hi"; // ref up
|
||||
foo(s); // ref up then down
|
||||
log str::refcount(s);
|
||||
assert (str::refcount(s) == const_refcount);
|
||||
let str s = "hi"; // ref up
|
||||
|
||||
foo(s); // ref up then down
|
||||
|
||||
log str::refcount(s);
|
||||
assert (str::refcount(s) == const_refcount);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue