From 718c0b5963e6513337e4fee003b34423397c2d14 Mon Sep 17 00:00:00 2001 From: Roy Frostig Date: Wed, 4 Aug 2010 23:09:25 -0700 Subject: [PATCH 01/16] Add to std._io some formatter/type-specific-writer mechanism. Make a few type-specific buffered writers as wrappers of buf_writer. --- src/lib/_io.rs | 51 ++++++++++++++++++++++++++++++++++++ src/lib/_str.rs | 19 ++++++++++++++ src/test/run-pass/lib-map.rs | 6 ++++- 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/src/lib/_io.rs b/src/lib/_io.rs index 142f808a645..b0b0c313af8 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,50 @@ fn new_buf_writer(str path, vec[fileflag] flags) -> buf_writer { } ret fd_buf_writer(fd); } + +type formatter[T] = fn(&T x) -> vec[u8]; + +type writer[T] = unsafe obj { fn write(&T x); }; + +fn mk_writer[T](str path, + vec[fileflag] flags, + &formatter[T] fmt) + -> writer[T] +{ + unsafe obj w[T](buf_writer out, formatter[T] fmt) { + fn write(&T x) { + out.write(fmt(x)); + } + } + ret w[T](new_buf_writer(path, flags), fmt); +} + +/* TODO: int_writer, uint_writer, ... */ + +fn str_writer(str path, vec[fileflag] flags) -> writer[str] { + auto fmt = _str.bytes; // FIXME (issue #90) + ret mk_writer[str](path, flags, fmt); +} + +fn vec_writer[T](str path, + vec[fileflag] flags, + &formatter[T] inner) + -> writer[vec[T]] +{ + fn fmt[T](&vec[T] v, &formatter[T] inner) -> vec[u8] { + let vec[u8] res = _str.bytes("vec("); + auto first = true; + for (T x in v) { + if (!first) { + res += _str.bytes(", "); + } else { + first = false; + } + res += inner(x); + } + res += _str.bytes(")\n"); + ret res; + } + + ret mk_writer[vec[T]](path, flags, bind fmt[T](_, inner)); +} diff --git a/src/lib/_str.rs b/src/lib/_str.rs index 062d8bf146f..8eed9a38466 100644 --- a/src/lib/_str.rs +++ b/src/lib/_str.rs @@ -12,6 +12,18 @@ fn is_utf8(vec[u8] v) -> bool { fail; // FIXME } +fn is_ascii(str s) -> bool { + let uint i = len(s); + while (i > 0u) { + i -= 1u; + // FIXME (issue #94) + if ((s.(i as int) & 0x80u8) != 0u8) { + ret false; + } + } + ret true; +} + fn alloc(uint n_bytes) -> str { ret rustrt.str_alloc(n_bytes); } @@ -23,3 +35,10 @@ fn len(str s) -> uint { 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 as int); // FIXME (issue #94) + } + ret _vec.init_fn[u8](bind ith(s, _), _str.len(s)); +} diff --git a/src/test/run-pass/lib-map.rs b/src/test/run-pass/lib-map.rs index 11101c849b8..058fb2378f3 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 +} From 29987b56e1dafff4a850eef4e668a364340fc59b Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Thu, 5 Aug 2010 10:04:11 -0700 Subject: [PATCH 02/16] Move 'as' precedence up to just above relational; support indexing str and vec by all integral types. Closes #94. --- src/Makefile | 1 + src/boot/be/x86.ml | 19 ++++++---- src/boot/fe/pexp.ml | 50 +++++++++++++------------- src/boot/me/trans.ml | 3 +- src/boot/me/type.ml | 9 ++--- src/test/run-pass/integral-indexing.rs | 22 ++++++++++++ 6 files changed, 67 insertions(+), 37 deletions(-) create mode 100644 src/test/run-pass/integral-indexing.rs diff --git a/src/Makefile b/src/Makefile index 7236e02f874..0476240c3fc 100644 --- a/src/Makefile +++ b/src/Makefile @@ -464,6 +464,7 @@ TEST_XFAILS_LLVM := $(TASK_XFAILS) \ i8-incr.rs \ import.rs \ inner-module.rs \ + integral-indexing.rs \ iter-range.rs \ iter-ret.rs \ large-records.rs \ diff --git a/src/boot/be/x86.ml b/src/boot/be/x86.ml index 217149c74f3..2ec34890669 100644 --- a/src/boot/be/x86.ml +++ b/src/boot/be/x86.ml @@ -1936,15 +1936,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/pexp.ml b/src/boot/fe/pexp.ml index fb2d91a05ba..3e17e0e49e7 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/me/trans.ml b/src/boot/me/trans.ml index f2bb2287309..f54a5d653ba 100644 --- a/src/boot/me/trans.ml +++ b/src/boot/me/trans.ml @@ -914,7 +914,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 diff --git a/src/boot/me/type.ml b/src/boot/me/type.ml index 787855f0c1a..23210ea1ff8 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/test/run-pass/integral-indexing.rs b/src/test/run-pass/integral-indexing.rs new file mode 100644 index 00000000000..fe7d147c30c --- /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 From 935b4347e286b0022ae6f38b2875df6f05c55fa3 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Thu, 5 Aug 2010 10:10:39 -0700 Subject: [PATCH 03/16] Mop up workarounds in stdlib no longer required as issue #93 is closed. --- src/lib/_str.rs | 5 ++--- src/lib/deque.rs | 18 ++++++------------ src/lib/map.rs | 12 +++--------- 3 files changed, 11 insertions(+), 24 deletions(-) diff --git a/src/lib/_str.rs b/src/lib/_str.rs index 8eed9a38466..7d1a2dbdcd7 100644 --- a/src/lib/_str.rs +++ b/src/lib/_str.rs @@ -16,8 +16,7 @@ fn is_ascii(str s) -> bool { let uint i = len(s); while (i > 0u) { i -= 1u; - // FIXME (issue #94) - if ((s.(i as int) & 0x80u8) != 0u8) { + if ((s.(i) & 0x80u8) != 0u8) { ret false; } } @@ -38,7 +37,7 @@ fn buf(str s) -> sbuf { fn bytes(&str s) -> vec[u8] { fn ith(str s, uint i) -> u8 { - ret s.(i as int); // FIXME (issue #94) + ret s.(i); } ret _vec.init_fn[u8](bind ith(s, _), _str.len(s)); } diff --git a/src/lib/deque.rs b/src/lib/deque.rs index bd42d7cb2dc..bf7acb533bb 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 f95741761c0..ff7b441115b 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](); From 53b01dc0067827ddaf0b9dd13020acdb89fb7a17 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 5 Aug 2010 12:00:34 -0700 Subject: [PATCH 04/16] Add a valgrind suppression for Snow Leopard dyld --- src/etc/x86.supp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/etc/x86.supp b/src/etc/x86.supp index f829f2ad234..beb482237be 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:* +} + From 9da8101cc83116c3804393a1abe3eb5e1d0dc02a Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Thu, 5 Aug 2010 13:26:28 -0700 Subject: [PATCH 05/16] Something is wrong with the emitter size cache; disable for now, possibly put out flaming tinderboxes. --- src/boot/me/trans.ml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/boot/me/trans.ml b/src/boot/me/trans.ml index f54a5d653ba..8c280ebdb34 100644 --- a/src/boot/me/trans.ml +++ b/src/boot/me/trans.ml @@ -674,7 +674,9 @@ let trans_visitor (Printf.sprintf "calculated size %s is %s" (string_of_size size) (oper_str res))); - htab_put (emitter_size_cache()) size res; + + (* FIXME: this appears to be incorrect; investigate why.*) + (* htab_put (emitter_size_cache()) size res; *) res From db561b52fff4466ac4de4fc807ebc0c253c7cd73 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Thu, 5 Aug 2010 17:44:35 -0700 Subject: [PATCH 06/16] Degrade emitter size cache to just a flat hashtable with regular flushes (sigh) and re-introduce horrible bounce-off-spill hack for DIV, MUL, etc. --- src/boot/be/il.ml | 4 +-- src/boot/be/x86.ml | 42 ++++++++++++++++++++++++++----- src/boot/me/trans.ml | 60 ++++++++++++++++++++++++++------------------ 3 files changed, 73 insertions(+), 33 deletions(-) diff --git a/src/boot/be/il.ml b/src/boot/be/il.ml index 792e83e200a..172d8661430 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 2ec34890669..55b101bbd34 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 diff --git a/src/boot/me/trans.ml b/src/boot/me/trans.ml index 8c280ebdb34..b708bb268ff 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 @@ -674,9 +688,7 @@ let trans_visitor (Printf.sprintf "calculated size %s is %s" (string_of_size size) (oper_str res))); - - (* FIXME: this appears to be incorrect; investigate why.*) - (* htab_put (emitter_size_cache()) size res; *) + htab_put (emitter_size_cache()) size res; res @@ -1926,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()) @@ -1946,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 @@ -2078,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"; @@ -4398,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 From 514fb4b321d1d019a7bfcd64518d1162878cbf07 Mon Sep 17 00:00:00 2001 From: Roy Frostig Date: Fri, 6 Aug 2010 15:43:59 -0700 Subject: [PATCH 07/16] Accept uint literals as literal patterns. --- src/boot/fe/item.ml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/boot/fe/item.ml b/src/boot/fe/item.ml index 69fe5fc225d..82ec2fafc10 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 From 80a1cd3d1e5e39db00a68ad6c1dc5686b775a4ad Mon Sep 17 00:00:00 2001 From: Roy Frostig Date: Fri, 6 Aug 2010 15:48:23 -0700 Subject: [PATCH 08/16] Redo yesterday's buf_writer-wrapper in a less silly and convoluted way. Add integer stringifying functions to _int module. --- src/lib/_int.rs | 44 ++++++++++++++++++++++++++++++++++++++ src/lib/_io.rs | 56 +++++++++++++------------------------------------ 2 files changed, 58 insertions(+), 42 deletions(-) diff --git a/src/lib/_int.rs b/src/lib/_int.rs index 9b756675d88..03017259d52 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_string(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_string(mutable int n, uint radix) -> str +{ + check (0u < radix && radix <= 16u); + if (n < 0) { + ret "-" + uto_string((-n) as uint, radix); + } else { + ret uto_string(n as uint, radix); + } +} diff --git a/src/lib/_io.rs b/src/lib/_io.rs index b0b0c313af8..dbd60e63d6a 100644 --- a/src/lib/_io.rs +++ b/src/lib/_io.rs @@ -112,49 +112,21 @@ fn new_buf_writer(str path, vec[fileflag] flags) -> buf_writer { ret fd_buf_writer(fd); } -type formatter[T] = fn(&T x) -> vec[u8]; +type writer = + unsafe obj { + fn write_str(str s); + fn write_int(int n); + fn write_uint(uint n); + }; -type writer[T] = unsafe obj { fn write(&T x); }; - -fn mk_writer[T](str path, - vec[fileflag] flags, - &formatter[T] fmt) - -> writer[T] +fn file_writer(str path, + vec[fileflag] flags) + -> writer { - unsafe obj w[T](buf_writer out, formatter[T] fmt) { - fn write(&T x) { - out.write(fmt(x)); - } + 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_string(n, 10u))); } + fn write_uint(uint n) { out.write(_str.bytes(_int.uto_string(n, 10u))); } } - ret w[T](new_buf_writer(path, flags), fmt); -} - -/* TODO: int_writer, uint_writer, ... */ - -fn str_writer(str path, vec[fileflag] flags) -> writer[str] { - auto fmt = _str.bytes; // FIXME (issue #90) - ret mk_writer[str](path, flags, fmt); -} - -fn vec_writer[T](str path, - vec[fileflag] flags, - &formatter[T] inner) - -> writer[vec[T]] -{ - fn fmt[T](&vec[T] v, &formatter[T] inner) -> vec[u8] { - let vec[u8] res = _str.bytes("vec("); - auto first = true; - for (T x in v) { - if (!first) { - res += _str.bytes(", "); - } else { - first = false; - } - res += inner(x); - } - res += _str.bytes(")\n"); - ret res; - } - - ret mk_writer[vec[T]](path, flags, bind fmt[T](_, inner)); + ret fw(new_buf_writer(path, flags)); } From fdb842f9e6d28b51fa51935d66c77011f27a436b Mon Sep 17 00:00:00 2001 From: Jeffrey Yasskin Date: Fri, 23 Jul 2010 19:27:55 -0700 Subject: [PATCH 09/16] Fix LLVM translation of modules. --- src/Makefile | 4 ---- src/boot/llvm/lltrans.ml | 39 +++++++++++++++++++++++++++++---------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/Makefile b/src/Makefile index 0476240c3fc..280ccc6c7e3 100644 --- a/src/Makefile +++ b/src/Makefile @@ -418,7 +418,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 +451,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 \ @@ -482,8 +480,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 \ diff --git a/src/boot/llvm/lltrans.ml b/src/boot/llvm/lltrans.ml index ee1927257e8..c1ef49af0bf 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 = From 987589e94691a82a551677740d47444f6c9acfd5 Mon Sep 17 00:00:00 2001 From: Jeffrey Yasskin Date: Sat, 24 Jul 2010 12:33:29 -0700 Subject: [PATCH 10/16] Change the destructor-ordering test to use channels instead of a shared mutable object. This test used to take advantage of a hole in the type system that allows objects with destructors to refer to stateful objects. --- src/Makefile | 1 + src/test/run-pass/destructor-ordering.rs | 121 +++++++++++++++-------- 2 files changed, 81 insertions(+), 41 deletions(-) diff --git a/src/Makefile b/src/Makefile index 280ccc6c7e3..aaf2e94f68e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -389,6 +389,7 @@ 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 \ diff --git a/src/test/run-pass/destructor-ordering.rs b/src/test/run-pass/destructor-ordering.rs index 99479c55f93..f7f5b8c82c3 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"); -} - -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(); From 581a95a804f77259153c030d39f861282b468612 Mon Sep 17 00:00:00 2001 From: Jeffrey Yasskin Date: Sat, 24 Jul 2010 16:01:34 -0700 Subject: [PATCH 11/16] Add an int->str conversion function. The test currently fails because string equality isn't implemented. --- src/Makefile | 2 ++ src/lib/_int.rs | 20 ++++++++++---------- src/lib/_io.rs | 4 ++-- src/test/run-pass/int-lib.rs | 15 +++++++++++++++ 4 files changed, 29 insertions(+), 12 deletions(-) create mode 100644 src/test/run-pass/int-lib.rs diff --git a/src/Makefile b/src/Makefile index aaf2e94f68e..792eeec0a3b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -395,6 +395,7 @@ TEST_XFAILS_X86 := $(TASK_XFAILS) \ 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 \ @@ -464,6 +465,7 @@ TEST_XFAILS_LLVM := $(TASK_XFAILS) \ import.rs \ inner-module.rs \ integral-indexing.rs \ + int-lib.rs \ iter-range.rs \ iter-ret.rs \ large-records.rs \ diff --git a/src/lib/_int.rs b/src/lib/_int.rs index 03017259d52..e76c2bf5062 100644 --- a/src/lib/_int.rs +++ b/src/lib/_int.rs @@ -45,7 +45,7 @@ fn next_power_of_two(uint n) -> uint { ret tmp + 1u; } -fn uto_string(mutable uint n, uint radix) -> str +fn uto_str(mutable uint n, uint radix) -> str { check (0u < radix && radix <= 16u); fn digit(uint n) -> str { @@ -60,12 +60,12 @@ fn uto_string(mutable uint n, uint radix) -> str 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"; } + case (10u) { ret "a"; } + case (11u) { ret "b"; } + case (12u) { ret "c"; } + case (13u) { ret "d"; } + case (14u) { ret "e"; } + case (15u) { ret "f"; } } } @@ -79,12 +79,12 @@ fn uto_string(mutable uint n, uint radix) -> str ret s; } -fn to_string(mutable int n, uint radix) -> str +fn to_str(mutable int n, uint radix) -> str { check (0u < radix && radix <= 16u); if (n < 0) { - ret "-" + uto_string((-n) as uint, radix); + ret "-" + uto_str((-n) as uint, radix); } else { - ret uto_string(n as uint, radix); + ret uto_str(n as uint, radix); } } diff --git a/src/lib/_io.rs b/src/lib/_io.rs index dbd60e63d6a..93d06d416fb 100644 --- a/src/lib/_io.rs +++ b/src/lib/_io.rs @@ -125,8 +125,8 @@ fn file_writer(str path, { 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_string(n, 10u))); } - fn write_uint(uint n) { out.write(_str.bytes(_int.uto_string(n, 10u))); } + 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/test/run-pass/int-lib.rs b/src/test/run-pass/int-lib.rs new file mode 100644 index 00000000000..ce39de43921 --- /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(); +} From 3f6e8ffe64b57b0eaba6812208e94500422ca40c Mon Sep 17 00:00:00 2001 From: Jeffrey Yasskin Date: Sun, 25 Jul 2010 00:36:03 -0700 Subject: [PATCH 12/16] Implement _str.len() to return the number of bytes, rename it to byte_len(), and add a test. --- src/Makefile | 1 + src/lib/_str.rs | 15 ++++++++++----- src/rt/rust_builtin.cpp | 6 ++++++ src/test/run-pass/str-lib.rs | 16 ++++++++++++++++ 4 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 src/test/run-pass/str-lib.rs diff --git a/src/Makefile b/src/Makefile index 792eeec0a3b..1d79a46700a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -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/lib/_str.rs b/src/lib/_str.rs index 7d1a2dbdcd7..a607c7d5df5 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; } @@ -13,7 +13,7 @@ fn is_utf8(vec[u8] v) -> bool { } fn is_ascii(str s) -> bool { - let uint i = len(s); + let uint i = byte_len(s); while (i > 0u) { i -= 1u; if ((s.(i) & 0x80u8) != 0u8) { @@ -27,8 +27,13 @@ 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 { @@ -39,5 +44,5 @@ 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.len(s)); + ret _vec.init_fn[u8](bind ith(s, _), _str.byte_len(s)); } diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index 657109c6df2..d8d9b8d6eb4 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/str-lib.rs b/src/test/run-pass/str-lib.rs new file mode 100644 index 00000000000..585f9b8de5f --- /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(); +} From a0cc4817e952f1a022b1ad9c01793db1735a579e Mon Sep 17 00:00:00 2001 From: Or Brostovski Date: Thu, 5 Aug 2010 03:44:29 +0300 Subject: [PATCH 13/16] Added AST logging, and modified AST for consistent handling of alt stmts. - Modified the arm types, instead of a single arm type, there are now 2 (soon to be 3) arm types, one for each type of alt statement - Added AST logging for constrained type (see fmt_constrained) - Added AST logging for STMT_alt_type - Created a generic fmt_arm for use with all alt statements --- src/boot/fe/ast.ml | 75 ++++++++++++++++++++++++++++++++++----------- src/boot/me/dead.ml | 3 +- 2 files changed, 59 insertions(+), 19 deletions(-) diff --git a/src/boot/fe/ast.ml b/src/boot/fe/ast.ml index 651b1e653d7..d4ace045439 100644 --- a/src/boot/fe/ast.ml +++ b/src/boot/fe/ast.ml @@ -247,13 +247,13 @@ and stmt = stmt' identified and stmt_alt_tag = { alt_tag_lval: lval; - alt_tag_arms: arm array; + alt_tag_arms: tag_arm array; } and stmt_alt_type = { alt_type_lval: lval; - alt_type_arms: (ident * slot * stmt) array; + alt_type_arms: type_arm array; alt_type_else: stmt option; } @@ -318,8 +318,11 @@ and pat = | PAT_slot of ((slot identified) * ident) | PAT_wild -and arm' = pat * block -and arm = arm' identified +and tag_arm' = pat * block +and tag_arm = tag_arm' identified + +and type_arm' = ident * slot * block +and type_arm = type_arm' identified and atom = ATOM_literal of (lit identified) @@ -646,6 +649,16 @@ and fmt_iso (ff:Format.formatter) (tiso:ty_iso) : unit = done; fmt ff "@]]@]" +and fmt_constrained ff (ty, constrs) : unit = + fmt ff "@["; + fmt_ty ff ty; + fmt ff " : "; + fmt ff "@["; + fmt_constrs ff constrs; + fmt ff "@]"; + fmt ff "@]"; + + and fmt_ty (ff:Format.formatter) (t:ty) : unit = match t with TY_any -> fmt ff "any" @@ -687,7 +700,7 @@ and fmt_ty (ff:Format.formatter) (t:ty) : unit = | TY_tag ttag -> fmt_tag ff ttag | TY_iso tiso -> fmt_iso ff tiso | TY_idx idx -> fmt ff "" idx - | TY_constrained _ -> fmt ff "?constrained?" + | TY_constrained ctrd -> fmt_constrained ff ctrd | TY_obj (effect, fns) -> fmt_obox ff; @@ -707,7 +720,13 @@ and fmt_ty (ff:Format.formatter) (t:ty) : unit = and fmt_constrs (ff:Format.formatter) (cc:constr array) : unit = - Array.iter (fmt_constr ff) cc + for i = 0 to (Array.length cc) - 1 + do + if i != 0 + then fmt ff ",@ "; + fmt_constr ff cc.(i) + done; + (* Array.iter (fmt_constr ff) cc *) and fmt_decl_constrs (ff:Format.formatter) (cc:constr array) : unit = if Array.length cc = 0 @@ -1204,25 +1223,45 @@ and fmt_stmt_body (ff:Format.formatter) (s:stmt) : unit = fmt_lval ff at.alt_tag_lval; fmt ff ") "; fmt_obr ff; - Array.iter (fmt_arm ff) at.alt_tag_arms; + Array.iter (fmt_tag_arm ff) at.alt_tag_arms; fmt_cbb ff; - | STMT_alt_type _ -> fmt ff "?stmt_alt_type?" + | STMT_alt_type at -> + fmt_obox ff; + fmt ff "alt type ("; + fmt_lval ff at.alt_type_lval; + fmt ff ") "; + fmt_obr ff; + Array.iter (fmt_type_arm ff) at.alt_type_arms; + fmt_cbb ff; + | STMT_alt_port _ -> fmt ff "?stmt_alt_port?" | STMT_note _ -> fmt ff "?stmt_note?" | STMT_slice _ -> fmt ff "?stmt_slice?" end -and fmt_arm (ff:Format.formatter) (arm:arm) : unit = - let (pat, block) = arm.node in - fmt ff "@\n"; - fmt_obox ff; - fmt ff "case ("; - fmt_pat ff pat; - fmt ff ") "; - fmt_obr ff; - fmt_stmts ff block.node; - fmt_cbb ff; +and fmt_arm + (ff:Format.formatter) + (fmt_arm_case_expr : Format.formatter -> unit) + (block : block) + : unit = + fmt ff "@\n"; + fmt_obox ff; + fmt ff "case ("; + fmt_arm_case_expr ff; + fmt ff ") "; + fmt_obr ff; + fmt_stmts ff block.node; + fmt_cbb ff; + +and fmt_tag_arm (ff:Format.formatter) (tag_arm:tag_arm) : unit = + let (pat, block) = tag_arm.node in + fmt_arm ff (fun ff -> fmt_pat ff pat) block; + +and fmt_type_arm (ff:Format.formatter) (type_arm:type_arm) : unit = + let (_, slot, block) = type_arm.node in + fmt_arm ff (fun ff -> fmt_slot ff slot) block; + and fmt_pat (ff:Format.formatter) (pat:pat) : unit = match pat with diff --git a/src/boot/me/dead.ml b/src/boot/me/dead.ml index 61aa846a50c..7ef4bf8e3e3 100644 --- a/src/boot/me/dead.ml +++ b/src/boot/me/dead.ml @@ -70,7 +70,8 @@ let dead_code_visitor | Ast.STMT_alt_type { Ast.alt_type_arms = arms; Ast.alt_type_else = alt_type_else } -> - let arm_ids = Array.map (fun (_, _, block) -> block.id) arms in + let arm_ids = Array.map (fun { node = (_, _, block) } -> + block.id) arms in let else_ids = begin match alt_type_else with From 122ea68b12ec1587f0fe0bd4737ae866e2a56c39 Mon Sep 17 00:00:00 2001 From: Or Brostovski Date: Fri, 6 Aug 2010 16:11:15 +0300 Subject: [PATCH 14/16] Added AST pretty printing for slice expression --- src/boot/fe/ast.ml | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/boot/fe/ast.ml b/src/boot/fe/ast.ml index d4ace045439..9cad5ce539e 100644 --- a/src/boot/fe/ast.ml +++ b/src/boot/fe/ast.ml @@ -1237,7 +1237,13 @@ and fmt_stmt_body (ff:Format.formatter) (s:stmt) : unit = | STMT_alt_port _ -> fmt ff "?stmt_alt_port?" | STMT_note _ -> fmt ff "?stmt_note?" - | STMT_slice _ -> fmt ff "?stmt_slice?" + | STMT_slice (dst, src, slice) -> + fmt_lval ff dst; + fmt ff " = "; + fmt_lval ff src; + fmt ff "."; + fmt_slice ff slice; + fmt ff ";"; end and fmt_arm @@ -1275,6 +1281,27 @@ and fmt_pat (ff:Format.formatter) (pat:pat) : unit = | PAT_wild -> fmt ff "_" +and fmt_slice (ff:Format.formatter) (slice:slice) : unit = + let fmt_slice_start = (match slice.slice_start with + None -> (fun ff -> fmt ff "0") + | Some atom -> (fun ff -> fmt_atom ff atom)) in + fmt ff "(@["; + fmt_slice_start ff; + begin + match slice.slice_len with + None -> fmt ff "," + | Some slice_len -> + fmt ff ",@ @["; + fmt_slice_start ff; + fmt ff " +@ "; + fmt_atom ff slice_len; + fmt ff "@]"; + end; + fmt ff "@])"; + + + + and fmt_decl_param (ff:Format.formatter) (param:ty_param) : unit = let (ident, (i, e)) = param in fmt_effect ff e; From 459e86045707e39c692535e0e2394c143d08355e Mon Sep 17 00:00:00 2001 From: Or Brostovski Date: Fri, 6 Aug 2010 17:15:55 +0300 Subject: [PATCH 15/16] Added forgotten handling for alt_type_else, and also for stmt_note --- src/boot/fe/ast.ml | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/boot/fe/ast.ml b/src/boot/fe/ast.ml index 9cad5ce539e..efbd62ae202 100644 --- a/src/boot/fe/ast.ml +++ b/src/boot/fe/ast.ml @@ -254,7 +254,14 @@ and stmt_alt_type = { alt_type_lval: lval; alt_type_arms: type_arm array; - alt_type_else: stmt option; + alt_type_else: block option; + } + +and stmt_alt_port = + { + (* else lval is a timeout value. *) + alt_port_arms: (lval * lval) array; + alt_port_else: (lval * block) option; } and block' = stmt array @@ -264,12 +271,6 @@ and stmt_decl = DECL_mod_item of (ident * mod_item) | DECL_slot of (slot_key * (slot identified)) -and stmt_alt_port = - { - (* else lval is a timeout value. *) - alt_port_arms: (lval * lval) array; - alt_port_else: (lval * stmt) option; - } and stmt_while = { @@ -1233,10 +1234,25 @@ and fmt_stmt_body (ff:Format.formatter) (s:stmt) : unit = fmt ff ") "; fmt_obr ff; Array.iter (fmt_type_arm ff) at.alt_type_arms; + begin + match at.alt_type_else with + None -> () + | Some block -> + fmt ff "@\n"; + fmt_obox ff; + fmt ff "case (_) "; + fmt_obr ff; + fmt_stmts ff block.node; + fmt_cbb ff; + end; fmt_cbb ff; - | STMT_alt_port _ -> fmt ff "?stmt_alt_port?" - | STMT_note _ -> fmt ff "?stmt_note?" + | STMT_note at -> + begin + fmt ff "note "; + fmt_atom ff at; + fmt ff ";" + end | STMT_slice (dst, src, slice) -> fmt_lval ff dst; fmt ff " = "; @@ -1245,7 +1261,7 @@ and fmt_stmt_body (ff:Format.formatter) (s:stmt) : unit = fmt_slice ff slice; fmt ff ";"; end - + and fmt_arm (ff:Format.formatter) (fmt_arm_case_expr : Format.formatter -> unit) From bd7835effa42a37ddf647e9cbf132d601de4700d Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Fri, 6 Aug 2010 17:43:15 -0700 Subject: [PATCH 16/16] Add Or to the AUTHORS file. --- AUTHORS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.txt b/AUTHORS.txt index 9a852ead0d8..83a4fdb1b8d 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -15,6 +15,7 @@ Jeff Mulzelaar Jeffrey Yasskin Matt Brubeck Michael Bebenita +Or Brostovski Patrick Walton Ralph Giles Roy Frostig