Merge branch 'master' of git://github.com/graydon/rust
Conflicts: src/boot/fe/ast.ml
This commit is contained in:
commit
4467d7683d
@ -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>
|
||||
|
@ -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 \
|
||||
|
@ -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;
|
||||
}
|
||||
;;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 =
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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:*
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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]();
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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();
|
||||
|
15
src/test/run-pass/int-lib.rs
Normal file
15
src/test/run-pass/int-lib.rs
Normal 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();
|
||||
}
|
22
src/test/run-pass/integral-indexing.rs
Normal file
22
src/test/run-pass/integral-indexing.rs
Normal 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);
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
16
src/test/run-pass/str-lib.rs
Normal file
16
src/test/run-pass/str-lib.rs
Normal 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();
|
||||
}
|
Loading…
Reference in New Issue
Block a user