aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOr Brostovski <[email protected]>2010-08-07 16:43:08 +0300
committerOr Brostovski <[email protected]>2010-08-07 16:43:08 +0300
commit4467d7683dae87d6d4c55e446910f7a5b85abd13 (patch)
treee2578dbe8e2350eb4e82ae2941fc2efb7478253b
parentAdded AST pretty printing for communication alt statement, closes issue 19. (diff)
parentAdd Or to the AUTHORS file. (diff)
downloadrust-4467d7683dae87d6d4c55e446910f7a5b85abd13.tar.xz
rust-4467d7683dae87d6d4c55e446910f7a5b85abd13.zip
Merge branch 'master' of git://github.com/graydon/rust
Conflicts: src/boot/fe/ast.ml
-rw-r--r--AUTHORS.txt1
-rw-r--r--src/Makefile9
-rw-r--r--src/boot/be/il.ml4
-rw-r--r--src/boot/be/x86.ml61
-rw-r--r--src/boot/fe/item.ml5
-rw-r--r--src/boot/fe/pexp.ml50
-rw-r--r--src/boot/llvm/lltrans.ml39
-rw-r--r--src/boot/me/trans.ml59
-rw-r--r--src/boot/me/type.ml9
-rw-r--r--src/etc/x86.supp12
-rw-r--r--src/lib/_int.rs44
-rw-r--r--src/lib/_io.rs23
-rw-r--r--src/lib/_str.rs29
-rw-r--r--src/lib/deque.rs18
-rw-r--r--src/lib/map.rs12
-rw-r--r--src/rt/rust_builtin.cpp6
-rw-r--r--src/test/run-pass/destructor-ordering.rs117
-rw-r--r--src/test/run-pass/int-lib.rs15
-rw-r--r--src/test/run-pass/integral-indexing.rs22
-rw-r--r--src/test/run-pass/lib-map.rs6
-rw-r--r--src/test/run-pass/str-lib.rs16
21 files changed, 410 insertions, 147 deletions
diff --git a/AUTHORS.txt b/AUTHORS.txt
index 9a852ead..83a4fdb1 100644
--- a/AUTHORS.txt
+++ b/AUTHORS.txt
@@ -15,6 +15,7 @@ Jeff Mulzelaar <[email protected]>
Jeffrey Yasskin <[email protected]>
Matt Brubeck <[email protected]>
Michael Bebenita <[email protected]>
+Or Brostovski <[email protected]>
Patrick Walton <[email protected]>
Ralph Giles <[email protected]>
Roy Frostig <[email protected]>
diff --git a/src/Makefile b/src/Makefile
index 7236e02f..1d79a467 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -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 \
diff --git a/src/boot/be/il.ml b/src/boot/be/il.ml
index 792e83e2..172d8661 100644
--- a/src/boot/be/il.ml
+++ b/src/boot/be/il.ml
@@ -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;
}
;;
diff --git a/src/boot/be/x86.ml b/src/boot/be/x86.ml
index 217149c7..55b101bb 100644
--- a/src/boot/be/x86.ml
+++ b/src/boot/be/x86.ml
@@ -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
diff --git a/src/boot/fe/item.ml b/src/boot/fe/item.ml
index 69fe5fc2..82ec2faf 100644
--- a/src/boot/fe/item.ml
+++ b/src/boot/fe/item.ml
@@ -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
diff --git a/src/boot/fe/pexp.ml b/src/boot/fe/pexp.ml
index fb2d91a0..3e17e0e4 100644
--- a/src/boot/fe/pexp.ml
+++ b/src/boot/fe/pexp.ml
@@ -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
diff --git a/src/boot/llvm/lltrans.ml b/src/boot/llvm/lltrans.ml
index ee192725..c1ef49af 100644
--- a/src/boot/llvm/lltrans.ml
+++ b/src/boot/llvm/lltrans.ml
@@ -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 =
diff --git a/src/boot/me/trans.ml b/src/boot/me/trans.ml
index f2bb2287..b708bb26 100644
--- a/src/boot/me/trans.ml
+++ b/src/boot/me/trans.ml
@@ -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
diff --git a/src/boot/me/type.ml b/src/boot/me/type.ml
index 787855f0..23210ea1 100644
--- a/src/boot/me/type.ml
+++ b/src/boot/me/type.ml
@@ -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
diff --git a/src/etc/x86.supp b/src/etc/x86.supp
index f829f2ad..beb48223 100644
--- a/src/etc/x86.supp
+++ b/src/etc/x86.supp
@@ -11,4 +11,14 @@
Memcheck:Leak
fun:calloc
fun:_dl_allocate_tls
-} \ No newline at end of file
+}
+
+{
+ mac-dyld-oddity
+ Memcheck:Cond
+ fun:_ZN4dyld5_mainEPK12macho_headermiPPKcS5_S5_
+ fun:_ZN13dyldbootstrap5startEPK12macho_headeriPPKcl
+ fun:_dyld_start
+ obj:*
+}
+
diff --git a/src/lib/_int.rs b/src/lib/_int.rs
index 9b756675..e76c2bf5 100644
--- a/src/lib/_int.rs
+++ b/src/lib/_int.rs
@@ -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);
+ }
+}
diff --git a/src/lib/_io.rs b/src/lib/_io.rs
index 142f808a..93d06d41 100644
--- a/src/lib/_io.rs
+++ b/src/lib/_io.rs
@@ -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));
+}
diff --git a/src/lib/_str.rs b/src/lib/_str.rs
index 062d8bf1..a607c7d5 100644
--- a/src/lib/_str.rs
+++ b/src/lib/_str.rs
@@ -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));
+}
diff --git a/src/lib/deque.rs b/src/lib/deque.rs
index bd42d7cb..bf7acb53 100644
--- a/src/lib/deque.rs
+++ b/src/lib/deque.rs
@@ -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;
}
diff --git a/src/lib/map.rs b/src/lib/map.rs
index f9574176..ff7b4411 100644
--- a/src/lib/map.rs
+++ b/src/lib/map.rs
@@ -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]();
diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp
index 657109c6..d8d9b8d6 100644
--- a/src/rt/rust_builtin.cpp
+++ b/src/rt/rust_builtin.cpp
@@ -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)
{
diff --git a/src/test/run-pass/destructor-ordering.rs b/src/test/run-pass/destructor-ordering.rs
index 99479c55..f7f5b8c8 100644
--- a/src/test/run-pass/destructor-ordering.rs
+++ b/src/test/run-pass/destructor-ordering.rs
@@ -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");
+io fn test_decl_v_init() {
+ let port[order_info] tracker_p = port();
+ auto tracker = chan(tracker_p);
+ {
+ auto var1;
+ auto var2;
+ var2 = dorder(tracker, 0, "decl, not init");
+ var1 = dorder(tracker, 1, "decl, not init");
+ }
+ check_order(tracker_p);
}
-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_overwritten_obj() {
+ let port[order_info] tracker_p = port();
+ auto tracker = chan(tracker_p);
{
- dorder(tracker, 1, "overwritten object destroyed before end of scope");
+ 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();
diff --git a/src/test/run-pass/int-lib.rs b/src/test/run-pass/int-lib.rs
new file mode 100644
index 00000000..ce39de43
--- /dev/null
+++ b/src/test/run-pass/int-lib.rs
@@ -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();
+}
diff --git a/src/test/run-pass/integral-indexing.rs b/src/test/run-pass/integral-indexing.rs
new file mode 100644
index 00000000..fe7d147c
--- /dev/null
+++ b/src/test/run-pass/integral-indexing.rs
@@ -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);
+} \ No newline at end of file
diff --git a/src/test/run-pass/lib-map.rs b/src/test/run-pass/lib-map.rs
index 11101c84..058fb237 100644
--- a/src/test/run-pass/lib-map.rs
+++ b/src/test/run-pass/lib-map.rs
@@ -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();
-} \ No newline at end of file
+}
diff --git a/src/test/run-pass/str-lib.rs b/src/test/run-pass/str-lib.rs
new file mode 100644
index 00000000..585f9b8d
--- /dev/null
+++ b/src/test/run-pass/str-lib.rs
@@ -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();
+}