Merge branch 'master' of git://github.com/graydon/rust

Conflicts:
	src/boot/fe/ast.ml
This commit is contained in:
Or Brostovski 2010-08-07 16:43:08 +03:00
commit 4467d7683d
21 changed files with 412 additions and 149 deletions

View File

@ -15,6 +15,7 @@ Jeff Mulzelaar <jmuizelaar@mozilla.com>
Jeffrey Yasskin <jyasskin@gmail.com>
Matt Brubeck <mbrubeck@limpet.net>
Michael Bebenita <mbebenita@mozilla.com>
Or Brostovski <tohava@gmail.com>
Patrick Walton <pwalton@mozilla.com>
Ralph Giles <giles@thaumas.net>
Roy Frostig <rfrostig@mozilla.com>

View File

@ -389,11 +389,13 @@ TEST_XFAILS_X86 := $(TASK_XFAILS) \
test/run-pass/child-outlives-parent.rs \
test/run-pass/clone-with-exterior.rs \
test/run-pass/constrained-type.rs \
test/run-pass/destructor-ordering.rs \
test/run-pass/obj-as.rs \
test/run-pass/vec-slice.rs \
test/run-pass/fn-lval.rs \
test/run-pass/generic-fn-infer.rs \
test/run-pass/generic-recursive-tag.rs \
test/run-pass/int-lib.rs \
test/run-pass/iter-ret.rs \
test/run-pass/lib-deque.rs \
test/run-pass/lib-map.rs \
@ -418,7 +420,6 @@ TEST_XFAILS_LLVM := $(TASK_XFAILS) \
alt-tag.rs \
arithmetic-interference.rs \
argv.rs \
auto-deref.rs \
autoderef-full-lval.rs \
autoderef-objfn.rs \
basic.rs \
@ -452,7 +453,6 @@ TEST_XFAILS_LLVM := $(TASK_XFAILS) \
generic-drop-glue.rs \
generic-exterior-box.rs \
generic-fn-infer.rs \
generic-fn-twice.rs \
generic-fn.rs \
generic-obj-with-derived-type.rs \
generic-obj.rs \
@ -464,6 +464,8 @@ TEST_XFAILS_LLVM := $(TASK_XFAILS) \
i8-incr.rs \
import.rs \
inner-module.rs \
integral-indexing.rs \
int-lib.rs \
iter-range.rs \
iter-ret.rs \
large-records.rs \
@ -481,8 +483,6 @@ TEST_XFAILS_LLVM := $(TASK_XFAILS) \
mutable-alias-vec.rs \
mutable-vec-drop.rs \
mutual-recursion-group.rs \
native-mod.rc \
native.rc \
obj-as.rs \
obj-drop.rs \
obj-dtor.rs \
@ -506,6 +506,7 @@ TEST_XFAILS_LLVM := $(TASK_XFAILS) \
str-append.rs \
str-concat.rs \
str-idx.rs \
str-lib.rs \
tag.rs \
tail-cps.rs \
tail-direct.rs \

View File

@ -695,7 +695,7 @@ type emitter = { mutable emit_pc: int;
emit_target_specific: (emitter -> quad -> unit);
mutable emit_quads: quads;
emit_annotations: (int,string) Hashtbl.t;
emit_size_cache: ((size,operand) Hashtbl.t) Stack.t;
emit_size_cache: (size,operand) Hashtbl.t;
emit_node: node_id option;
}
@ -722,7 +722,7 @@ let new_emitter
emit_target_specific = emit_target_specific;
emit_quads = Array.create 4 badq;
emit_annotations = Hashtbl.create 0;
emit_size_cache = Stack.create ();
emit_size_cache = Hashtbl.create 0;
emit_node = node;
}
;;

View File

@ -302,11 +302,41 @@ let emit_target_specific
| Il.IMOD | Il.UMOD ->
let dst_eax = hr_like_cell eax dst in
let lhs_eax = hr_like_op eax lhs in
let rhs_ecx = hr_like_op ecx lhs in
if lhs <> (Il.Cell lhs_eax)
then mov lhs_eax lhs;
if rhs <> (Il.Cell rhs_ecx)
then mov rhs_ecx rhs;
let rhs_ecx = hr_like_op ecx rhs in
(* Horrible: we bounce complex mul inputs off spill slots
* to ensure non-interference between the temporaries used
* during mem-base-reg reloads and the registers we're
* preparing. *)
let next_spill_like op =
Il.Mem (Il.next_spill_slot e
(Il.ScalarTy (Il.operand_scalar_ty op)))
in
let is_mem op =
match op with
Il.Cell (Il.Mem _) -> true
| _ -> false
in
let bounce_lhs = is_mem lhs in
let bounce_rhs = is_mem rhs in
let lhs_spill = next_spill_like lhs in
let rhs_spill = next_spill_like rhs in
if bounce_lhs
then mov lhs_spill lhs;
if bounce_rhs
then mov rhs_spill rhs;
mov lhs_eax
(if bounce_lhs
then (Il.Cell lhs_spill)
else lhs);
mov rhs_ecx
(if bounce_rhs
then (Il.Cell rhs_spill)
else rhs);
put (Il.Binary
{ b with
Il.binary_lhs = (Il.Cell lhs_eax);
@ -314,7 +344,7 @@ let emit_target_specific
Il.binary_dst = dst_eax; });
if dst <> dst_eax
then mov dst (Il.Cell dst_eax);
| _ when (Il.Cell dst) <> lhs ->
mov dst lhs;
put (Il.Binary
@ -1936,15 +1966,20 @@ let zero (dst:Il.cell) (count:Il.operand) : Asm.frag =
;;
let mov (signed:bool) (dst:Il.cell) (src:Il.operand) : Asm.frag =
if is_ty8 (Il.cell_scalar_ty dst) || is_ty8 (Il.operand_scalar_ty src)
if is_ty8 (Il.cell_scalar_ty dst)
then
begin
(match dst with
Il.Reg (Il.Hreg r, _)
-> assert (is_ok_r8 r) | _ -> ());
(match src with
Il.Cell (Il.Reg (Il.Hreg r, _))
-> assert (is_ok_r8 r) | _ -> ());
match dst with
Il.Reg (Il.Hreg r, _) -> assert (is_ok_r8 r)
| _ -> ()
end;
if is_ty8 (Il.operand_scalar_ty src)
then
begin
match src with
Il.Cell (Il.Reg (Il.Hreg r, _)) -> assert (is_ok_r8 r)
| _ -> ()
end;
match (signed, dst, src) with

View File

@ -253,7 +253,10 @@ and parse_stmts (ps:pstate) : Ast.stmt array =
let lv = name_to_lval apos bpos name in
Ast.PAT_tag (lv, paren_comma_list parse_pat ps)
| LIT_INT _ | LIT_CHAR _ | LIT_BOOL _ ->
| LIT_INT _
| LIT_UINT _
| LIT_CHAR _
| LIT_BOOL _ ->
Ast.PAT_lit (Pexp.parse_lit ps)
| UNDERSCORE -> bump ps; Ast.PAT_wild

View File

@ -817,11 +817,33 @@ and parse_or_pexp (ps:pstate) : pexp =
step lhs
and parse_as_pexp (ps:pstate) : pexp =
let apos = lexpos ps in
let pexp = ctxt "as pexp" parse_or_pexp ps in
let rec step accum =
match peek ps with
AS ->
bump ps;
let tapos = lexpos ps in
let t = parse_ty ps in
let bpos = lexpos ps in
let t = span ps tapos bpos t in
let node =
span ps apos bpos
(PEXP_unop ((Ast.UNOP_cast t), accum))
in
step node
| _ -> accum
in
step pexp
and parse_relational_pexp (ps:pstate) : pexp =
let name = "relational pexp" in
let apos = lexpos ps in
let lhs = ctxt (name ^ " lhs") parse_or_pexp ps in
let build = binop_build ps name apos parse_or_pexp in
let lhs = ctxt (name ^ " lhs") parse_as_pexp ps in
let build = binop_build ps name apos parse_as_pexp in
let rec step accum =
match peek ps with
LT -> build accum step Ast.BINOP_lt
@ -883,30 +905,8 @@ and parse_oror_pexp (ps:pstate) : pexp =
step lhs
and parse_as_pexp (ps:pstate) : pexp =
let apos = lexpos ps in
let pexp = ctxt "as pexp" parse_oror_pexp ps in
let rec step accum =
match peek ps with
AS ->
bump ps;
let tapos = lexpos ps in
let t = parse_ty ps in
let bpos = lexpos ps in
let t = span ps tapos bpos t in
let node =
span ps apos bpos
(PEXP_unop ((Ast.UNOP_cast t), accum))
in
step node
| _ -> accum
in
step pexp
and parse_pexp (ps:pstate) : pexp =
parse_as_pexp ps
parse_oror_pexp ps
and parse_mutable_and_pexp (ps:pstate) : (Ast.mutability * pexp) =
let mutability = parse_mutability ps in

View File

@ -588,7 +588,7 @@ let trans_crate
(* Maps a fn's or block's id to an LLVM metadata node (subprogram or
lexical block) representing it. *)
let (dbg_llscopes:(node_id, Llvm.llvalue) Hashtbl.t) = Hashtbl.create 0 in
let declare_mod_item
let rec declare_mod_item
(name:Ast.ident)
mod_item
: unit =
@ -616,9 +616,8 @@ let trans_crate
| Ast.MOD_ITEM_type _ ->
() (* Types get translated with their terms. *)
| Ast.MOD_ITEM_mod _ ->
() (* Modules simply contain other items that are translated
on their own. *)
| Ast.MOD_ITEM_mod (_, items) ->
Hashtbl.iter declare_mod_item items
| _ ->
Common.unimpl (Some id)
@ -807,6 +806,17 @@ let trans_crate
Ast.sprintf_lval lval)
in
let trans_callee (fn:Ast.lval) : (Llvm.llvalue * Ast.ty) =
let fty = Hashtbl.find sem_cx.ctxt_all_lval_types (lval_base_id fn) in
if lval_base_is_item sem_cx fn then
let fn_item = lval_item sem_cx fn in
let llfn = Hashtbl.find llitems (fn_item.id) in
(llfn, fty)
else
(* indirect call to computed slot *)
trans_lval fn
in
let trans_atom (atom:Ast.atom) : Llvm.llvalue =
iflog (fun _ -> log sem_cx "trans_atom: %a" Ast.sprintf_atom atom);
match atom with
@ -959,7 +969,7 @@ let trans_crate
| Ast.STMT_call (dest, fn, args) ->
let llargs = Array.map trans_atom args in
let (lldest, _) = trans_lval dest in
let (llfn, _) = trans_lval fn in
let (llfn, _) = trans_callee fn in
let llallargs = Array.append [| lldest; lltask |] llargs in
let llrv = build_call llfn llallargs "" llbuilder in
Llvm.set_instruction_call_conv Llvm.CallConv.c llrv;
@ -1072,13 +1082,22 @@ let trans_crate
ignore (Llvm.build_br llbodyblock llinitbuilder)
in
let trans_mod_item
(_:Ast.ident)
{ node = { Ast.decl_item = (item:Ast.mod_item') }; id = id }
let rec trans_mod_item
(name:Ast.ident)
mod_item
: unit =
let { node = { Ast.decl_item = (item:Ast.mod_item') }; id = id } =
mod_item in
match item with
Ast.MOD_ITEM_fn fn -> trans_fn fn id
| _ -> ()
Ast.MOD_ITEM_type _ ->
() (* Types get translated with their terms. *)
| Ast.MOD_ITEM_mod (_, items) ->
Hashtbl.iter trans_mod_item items
| Ast.MOD_ITEM_fn fn -> trans_fn fn id
| _ -> Common.unimpl (Some id)
"LLVM module declaration for: %a"
Ast.sprintf_mod_item (name, mod_item)
in
let exit_task_glue =

View File

@ -163,7 +163,6 @@ let trans_visitor
abi.Abi.abi_emit_target_specific
vregs_ok fnid
in
Stack.push (Hashtbl.create 0) e.Il.emit_size_cache;
Stack.push e emitters;
in
@ -172,16 +171,20 @@ let trans_visitor
let pop_emitter _ = ignore (Stack.pop emitters) in
let emitter _ = Stack.top emitters in
let emitter_size_cache _ = Stack.top (emitter()).Il.emit_size_cache in
let push_emitter_size_cache _ =
Stack.push
(Hashtbl.copy (emitter_size_cache()))
(emitter()).Il.emit_size_cache
let emitter_size_cache _ = (emitter()).Il.emit_size_cache in
let flush_emitter_size_cache _ =
Hashtbl.clear (emitter_size_cache())
in
let pop_emitter_size_cache _ =
ignore (Stack.pop (emitter()).Il.emit_size_cache)
let emit q =
begin
match q with
Il.Jmp _ -> flush_emitter_size_cache();
| _ -> ()
end;
Il.emit (emitter()) q
in
let emit q = Il.emit (emitter()) q in
let next_vreg _ = Il.next_vreg (emitter()) in
let next_vreg_cell t = Il.next_vreg_cell (emitter()) t in
let next_spill_cell t =
@ -190,12 +193,17 @@ let trans_visitor
let spill_ta = (spill_mem, Il.ScalarTy t) in
Il.Mem spill_ta
in
let mark _ : quad_idx = (emitter()).Il.emit_pc in
let mark _ : quad_idx =
flush_emitter_size_cache ();
(emitter()).Il.emit_pc
in
let patch_existing (jmp:quad_idx) (targ:quad_idx) : unit =
Il.patch_jump (emitter()) jmp targ
Il.patch_jump (emitter()) jmp targ;
flush_emitter_size_cache ();
in
let patch (i:quad_idx) : unit =
Il.patch_jump (emitter()) i (mark());
flush_emitter_size_cache ();
(* Insert a dead quad to ensure there's an otherwise-unused
* jump-target here.
*)
@ -583,7 +591,13 @@ let trans_visitor
(string_of_size size)));
let sub_sz = calculate_sz ty_params in
match htab_search (emitter_size_cache()) size with
Some op -> op
Some op ->
iflog (fun _ -> annotate
(Printf.sprintf "cached size %s is %s"
(string_of_size size)
(oper_str op)));
op
| _ ->
let res =
match size with
@ -914,7 +928,8 @@ let trans_visitor
let atop = trans_atom at in
let unit_sz = ty_sz_in_current_frame ty in
let idx = next_vreg_cell word_sty in
emit (Il.binary Il.UMUL idx atop unit_sz);
mov idx atop;
emit (Il.binary Il.UMUL idx (Il.Cell idx) unit_sz);
let elt_mem = trans_bounds_check (deref cell) (Il.Cell idx) in
(Il.Mem (elt_mem, referent_type abi ty), ty)
in
@ -1923,8 +1938,8 @@ let trans_visitor
: quad_idx list =
emit (Il.cmp (Il.Cell (Il.Reg (force_to_reg lhs))) rhs);
let jmp = mark() in
emit (Il.jmp cjmp Il.CodeNone);
[ jmp ]
emit (Il.jmp cjmp Il.CodeNone);
[ jmp ]
and trans_compare
?ty_params:(ty_params=get_ty_params_of_current_frame())
@ -1943,7 +1958,6 @@ let trans_visitor
| _ -> trans_compare_simple cjmp lhs rhs
and trans_cond (invert:bool) (expr:Ast.expr) : quad_idx list =
let anno _ =
iflog
begin
@ -2075,15 +2089,14 @@ let trans_visitor
trans_atom a
and trans_block (block:Ast.block) : unit =
flush_emitter_size_cache();
trace_str cx.ctxt_sess.Session.sess_trace_block
"entering block";
push_emitter_size_cache ();
emit (Il.Enter (Hashtbl.find cx.ctxt_block_fixups block.id));
Array.iter trans_stmt block.node;
trace_str cx.ctxt_sess.Session.sess_trace_block
"exiting block";
emit Il.Leave;
pop_emitter_size_cache ();
trace_str cx.ctxt_sess.Session.sess_trace_block
"exited block";
@ -4395,11 +4408,11 @@ let trans_visitor
let back_jmp =
trans_compare_simple Il.JB (Il.Cell dptr) (Il.Cell dlim)
in
List.iter
(fun j -> patch_existing j back_jmp_targ) back_jmp;
let v = next_vreg_cell word_sty in
mov v (Il.Cell src_fill);
add_to dst_fill (Il.Cell v);
List.iter
(fun j -> patch_existing j back_jmp_targ) back_jmp;
let v = next_vreg_cell word_sty in
mov v (Il.Cell src_fill);
add_to dst_fill (Il.Cell v);
| t ->
begin
bug () "unsupported vector-append type %a" Ast.sprintf_ty t

View File

@ -380,19 +380,20 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
sprintf_itype ()
| `Type (Ast.TY_vec ty_vec), Ast.COMP_atom atom ->
demand Ast.TY_int (check_atom atom);
demand_integer (check_atom atom);
LTYPE_mono ty_vec
| `Type (Ast.TY_vec _), _ ->
Common.err None "the vector type '%a' must be indexed via an int"
Common.err None
"the vector type '%a' must be indexed by an integral type"
sprintf_itype ()
| `Type Ast.TY_str, Ast.COMP_atom atom ->
demand Ast.TY_int (check_atom atom);
demand_integer (check_atom atom);
LTYPE_mono (Ast.TY_mach Common.TY_u8)
| `Type Ast.TY_str, _ ->
Common.err None "strings must be indexed via an int"
Common.err None "strings must be indexed by an integral type"
| `Type (Ast.TY_box ty_box), Ast.COMP_deref -> LTYPE_mono ty_box

View File

@ -11,4 +11,14 @@
Memcheck:Leak
fun:calloc
fun:_dl_allocate_tls
}
}
{
mac-dyld-oddity
Memcheck:Cond
fun:_ZN4dyld5_mainEPK12macho_headermiPPKcS5_S5_
fun:_ZN13dyldbootstrap5startEPK12macho_headeriPPKcl
fun:_dyld_start
obj:*
}

View File

@ -44,3 +44,47 @@ fn next_power_of_two(uint n) -> uint {
}
ret tmp + 1u;
}
fn uto_str(mutable uint n, uint radix) -> str
{
check (0u < radix && radix <= 16u);
fn digit(uint n) -> str {
alt (n) {
case (0u) { ret "0"; }
case (1u) { ret "1"; }
case (2u) { ret "2"; }
case (3u) { ret "3"; }
case (4u) { ret "4"; }
case (5u) { ret "5"; }
case (6u) { ret "6"; }
case (7u) { ret "7"; }
case (8u) { ret "8"; }
case (9u) { ret "9"; }
case (10u) { ret "a"; }
case (11u) { ret "b"; }
case (12u) { ret "c"; }
case (13u) { ret "d"; }
case (14u) { ret "e"; }
case (15u) { ret "f"; }
}
}
if (n == 0u) { ret "0"; }
let str s = "";
while (n > 0u) {
s = digit(n % radix) + s;
n /= radix;
}
ret s;
}
fn to_str(mutable int n, uint radix) -> str
{
check (0u < radix && radix <= 16u);
if (n < 0) {
ret "-" + uto_str((-n) as uint, radix);
} else {
ret uto_str(n as uint, radix);
}
}

View File

@ -1,3 +1,7 @@
import std.os;
import std._str;
import std._vec;
type buf_reader = unsafe obj {
fn read() -> vec[u8];
};
@ -107,3 +111,22 @@ fn new_buf_writer(str path, vec[fileflag] flags) -> buf_writer {
}
ret fd_buf_writer(fd);
}
type writer =
unsafe obj {
fn write_str(str s);
fn write_int(int n);
fn write_uint(uint n);
};
fn file_writer(str path,
vec[fileflag] flags)
-> writer
{
unsafe obj fw(buf_writer out) {
fn write_str(str s) { out.write(_str.bytes(s)); }
fn write_int(int n) { out.write(_str.bytes(_int.to_str(n, 10u))); }
fn write_uint(uint n) { out.write(_str.bytes(_int.uto_str(n, 10u))); }
}
ret fw(new_buf_writer(path, flags));
}

View File

@ -3,7 +3,7 @@ import rustrt.sbuf;
native "rust" mod rustrt {
type sbuf;
fn str_buf(str s) -> sbuf;
fn str_len(str s) -> uint;
fn str_byte_len(str s) -> uint;
fn str_alloc(uint n_bytes) -> str;
fn refcount[T](str s) -> uint;
}
@ -12,14 +12,37 @@ fn is_utf8(vec[u8] v) -> bool {
fail; // FIXME
}
fn is_ascii(str s) -> bool {
let uint i = byte_len(s);
while (i > 0u) {
i -= 1u;
if ((s.(i) & 0x80u8) != 0u8) {
ret false;
}
}
ret true;
}
fn alloc(uint n_bytes) -> str {
ret rustrt.str_alloc(n_bytes);
}
fn len(str s) -> uint {
ret rustrt.str_len(s);
// 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 buf(str s) -> sbuf {
ret rustrt.str_buf(s);
}
fn bytes(&str s) -> vec[u8] {
fn ith(str s, uint i) -> u8 {
ret s.(i);
}
ret _vec.init_fn[u8](bind ith(s, _), _str.byte_len(s));
}

View File

@ -36,7 +36,7 @@ fn create[T]() -> t[T] {
fn fill[T](uint i, uint nelts, uint lo, &vec[cell[T]] old) -> cell[T] {
if (i < nelts) {
ret old.(((lo + i) % nelts) as int);
ret old.((lo + i) % nelts);
} else {
ret util.none[T]();
}
@ -47,14 +47,8 @@ fn create[T]() -> t[T] {
ret _vec.init_fn[cell[T]](copy_op, nalloc);
}
/**
* FIXME (issue #94): We're converting to int every time we index into the
* vec, but we really want to index with the lo and hi uints that we have
* around.
*/
fn get[T](&vec[cell[T]] elts, uint i) -> T {
alt (elts.(i as int)) {
alt (elts.(i)) {
case (util.some[T](t)) { ret t; }
case (_) { fail; }
}
@ -82,7 +76,7 @@ fn create[T]() -> t[T] {
hi = nelts;
}
elts.(lo as int) = util.some[T](t);
elts.(lo) = util.some[T](t);
nelts += 1u;
}
@ -93,7 +87,7 @@ fn create[T]() -> t[T] {
hi = nelts;
}
elts.(hi as int) = util.some[T](t);
elts.(hi) = util.some[T](t);
hi = (hi + 1u) % _vec.len[cell[T]](elts);
nelts += 1u;
}
@ -104,7 +98,7 @@ fn create[T]() -> t[T] {
*/
fn pop_front() -> T {
let T t = get[T](elts, lo);
elts.(lo as int) = util.none[T]();
elts.(lo) = util.none[T]();
lo = (lo + 1u) % _vec.len[cell[T]](elts);
ret t;
}
@ -117,7 +111,7 @@ fn create[T]() -> t[T] {
}
let T t = get[T](elts, hi);
elts.(hi as int) = util.none[T]();
elts.(hi) = util.none[T]();
ret t;
}

View File

@ -75,8 +75,7 @@ fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] {
{
let uint i = 0u;
while (i < nbkts) {
// FIXME (issue #94): as in find_common()
let int j = (hash[K](hasher, nbkts, key, i)) as int;
let uint j = (hash[K](hasher, nbkts, key, i));
alt (bkts.(j)) {
case (some[K, V](k, _)) {
if (eqer(key, k)) {
@ -103,8 +102,7 @@ fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] {
{
let uint i = 0u;
while (i < nbkts) {
// FIXME (issue #94): Pending bugfix, remove uint coercion.
let int j = (hash[K](hasher, nbkts, key, i)) as int;
let uint j = (hash[K](hasher, nbkts, key, i));
alt (bkts.(j)) {
case (some[K, V](k, v)) {
if (eqer(key, k)) {
@ -149,9 +147,6 @@ fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] {
if (!util.rational_leq(load, lf)) {
let uint nnewbkts = _int.next_power_of_two(nbkts + 1u);
// FIXME (issue #94): Enforce our workaround to issue #94.
check ((nnewbkts as int) > 0);
let vec[mutable bucket[K, V]] newbkts = make_buckets[K, V](nnewbkts);
rehash[K, V](hasher, eqer, bkts, nbkts, newbkts, nnewbkts);
}
@ -183,8 +178,7 @@ fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] {
fn remove(&K key) -> util.option[V] {
let uint i = 0u;
while (i < nbkts) {
// FIXME (issue #94): as in find_common()
let int j = (hash[K](hasher, nbkts, key, i)) as int;
let uint j = (hash[K](hasher, nbkts, key, i));
alt (bkts.(j)) {
case (some[K, V](_, val)) {
bkts.(j) = deleted[K, V]();

View File

@ -115,6 +115,12 @@ str_buf(rust_task *task, rust_str *s)
return (char const *)&s->data[0];
}
extern "C" CDECL size_t
str_byte_len(rust_task *task, rust_str *s)
{
return s->fill - 1; // -1 for the '\0' terminator.
}
extern "C" CDECL void *
vec_buf(rust_task *task, type_desc *ty, rust_vec *v, size_t offset)
{

View File

@ -1,58 +1,93 @@
// We share an instance of this type among all the destructor-order
// checkers. It tracks how many destructors have run so far and
// 'fail's when one runs out of order.
// FIXME: Make it easier to collect a failure message.
state obj order_tracker(mutable int init) {
fn assert_order(int expected, str fail_message) {
if (expected != init) {
log expected;
// This test checks that destructors run in the right order. Because
// stateful objects can't have destructors, we have the destructors
// record their expected order into a channel when they execute (so
// the object becomes 'io' rather than 'state'). Then each test case
// asserts that the channel produces values in ascending order.
//
// FIXME: Write an int->str function and concatenate the whole failure
// message into a single log statement (or, even better, a print).
//
// FIXME: check_order should take only 1 line in a test, not 2+a block
// block. Since destructor-having objects can't refer to mutable state
// (like the port), we'd need a with-like construct to do the same for
// stateful objects within a scope.
//
// FIXME #21: Each test should execute in its own task, so it can fail
// independently, writing its error message to a channel that the
// parent task aggregates.
type order_info = rec(int order, str msg);
io fn check_order(port[order_info] expected_p) {
chan(expected_p) <| rec(order=-1, msg="");
let mutable int actual = 0;
auto expected <- expected_p; // FIXME #121: Workaround for while(true) bug.
auto done = -1; // FIXME: Workaround for typechecking bug.
while(expected.order != done) {
if (expected.order != actual) {
log expected.order;
log " != ";
log init;
log fail_message;
log actual;
log expected.msg;
fail;
}
init += 1;
actual += 1;
expected <- expected_p;
}
}
obj dorder(@order_tracker tracker, int order, str message) {
obj dorder(chan[order_info] expected, int order, str message) {
drop {
tracker.assert_order(order, message);
expected <| rec(order=order, msg=message);
}
}
fn test_simple() {
auto tracker = @order_tracker(0);
io fn test_simple() {
let port[order_info] tracker_p = port();
auto tracker = chan(tracker_p);
dorder(tracker, 1, "Reverse decl order");
dorder(tracker, 0, "Reverse decl order");
check_order(tracker_p);
}
fn test_block() {
auto tracker = @order_tracker(0);
dorder(tracker, 2, "Before block");
io fn test_block() {
let port[order_info] tracker_p = port();
auto tracker = chan(tracker_p);
{
dorder(tracker, 0, "Inside block");
dorder(tracker, 2, "Before block");
{
dorder(tracker, 0, "Inside block");
}
dorder(tracker, 1, "After block");
}
dorder(tracker, 1, "After block");
check_order(tracker_p);
}
fn test_decl_v_init() {
auto tracker = @order_tracker(0);
auto var1;
auto var2;
var2 = dorder(tracker, 0, "decl, not init");
var1 = dorder(tracker, 1, "decl, not init");
}
fn test_overwritten_obj() {
auto tracker = @order_tracker(0);
auto var1 = dorder(tracker, 0, "overwritten object destroyed first");
auto var2 = dorder(tracker, 2, "destroyed at end of scope");
var1 = dorder(tracker, 3, "overwriter deleted in rev decl order");
io fn test_decl_v_init() {
let port[order_info] tracker_p = port();
auto tracker = chan(tracker_p);
{
dorder(tracker, 1, "overwritten object destroyed before end of scope");
auto var1;
auto var2;
var2 = dorder(tracker, 0, "decl, not init");
var1 = dorder(tracker, 1, "decl, not init");
}
check_order(tracker_p);
}
io fn test_overwritten_obj() {
let port[order_info] tracker_p = port();
auto tracker = chan(tracker_p);
{
auto var1 = dorder(tracker, 0, "overwritten object destroyed first");
auto var2 = dorder(tracker, 2, "destroyed at end of scope");
var1 = dorder(tracker, 3, "overwriter deleted in rev decl order");
{
dorder(tracker, 1, "overwritten object destroyed before end of scope");
}
}
check_order(tracker_p);
}
// Used to embed dorder objects into an expression. Note that the
@ -60,17 +95,21 @@ fn test_overwritten_obj() {
fn combine_dorders(dorder d1, dorder d2) -> int {
ret 1;
}
fn test_expression_destroyed_right_to_left() {
auto tracker = @order_tracker(0);
combine_dorders(dorder(tracker, 4, ""), dorder(tracker, 3, ""))
/ combine_dorders(dorder(tracker, 2, ""), dorder(tracker, 1, ""));
io fn test_expression_destroyed_right_to_left() {
let port[order_info] tracker_p = port();
auto tracker = chan(tracker_p);
{
dorder(tracker, 0,
"expression objects live to end of block, not statement");
combine_dorders(dorder(tracker, 4, ""), dorder(tracker, 3, ""))
/ combine_dorders(dorder(tracker, 2, ""), dorder(tracker, 1, ""));
{
dorder(tracker, 0,
"expression objects live to end of block, not statement");
}
}
check_order(tracker_p);
}
fn main() {
io fn main() {
test_simple();
test_block();
test_decl_v_init();

View File

@ -0,0 +1,15 @@
use std;
import std._int;
fn test_to_str() {
check (_int.to_str(0, 10u) == "0");
check (_int.to_str(1, 10u) == "1");
check (_int.to_str(-1, 10u) == "-1");
check (_int.to_str(255, 16u) == "ff");
check (_int.to_str(-71, 36u) == "-1z");
}
fn main() {
test_to_str();
}

View File

@ -0,0 +1,22 @@
// This is a testcase for issue #94.
fn main() {
let vec[int] v = vec(0, 1, 2, 3, 4, 5);
let str s = "abcdef";
check (v.(3u) == 3);
check (v.(3u8) == 3);
check (v.(3i8) == 3);
check (v.(3u32) == 3);
check (v.(3i32) == 3);
log v.(3u8);
check (s.(3u) == 'd' as u8);
check (s.(3u8) == 'd' as u8);
check (s.(3i8) == 'd' as u8);
check (s.(3u32) == 'd' as u8);
check (s.(3i32) == 'd' as u8);
log s.(3u8);
}

View File

@ -4,13 +4,17 @@ use std;
import std.map;
fn test_simple() {
log "*** starting test_simple";
fn eq(&uint x, &uint y) -> bool { ret x == y; }
let map.hashfn[uint] hasher = std.util.id[uint];
let map.eqfn[uint] eqer = eq;
let map.hashmap[uint, uint] hm = map.mk_hashmap[uint, uint](hasher, eqer);
log "*** finished test_simple";
}
fn main() {
test_simple();
}
}

View File

@ -0,0 +1,16 @@
use std;
import std._str;
fn test_bytes_len() {
check (_str.byte_len("") == 0u);
check (_str.byte_len("hello world") == 11u);
check (_str.byte_len("\x63") == 1u);
check (_str.byte_len("\xa2") == 2u);
check (_str.byte_len("\u03c0") == 2u);
check (_str.byte_len("\u2620") == 3u);
check (_str.byte_len("\U0001d11e") == 4u);
}
fn main() {
test_bytes_len();
}