Browse Source

progressing on unit tests support

Nicolas Cannasse 9 years ago
parent
commit
83a4aa222e

+ 162 - 29
genhl.ml

@@ -1447,6 +1447,10 @@ and eval_expr ctx e =
 			op ctx (OCallClosure (ret, r, el)); (* if it's a value, it's a closure *)
 		);
 		unsafe_cast_to ctx ret (to_type ctx e.etype) e.epos
+	| TField (ec,FInstance({ cl_path = [],"Array" },[t],{ cf_name = "length" })) when to_type ctx t = HDyn ->
+		let r = alloc_tmp ctx HI32 in
+		op ctx (OCall1 (r,alloc_fun_path ctx (["hl";"types"],"ArrayDyn") "get_length", eval_null_check ctx ec));
+		r
 	| TField (ec,a) ->
 		let r = alloc_tmp ctx (to_type ctx (field_type ctx a e.epos)) in
 		(match get_access ctx e with
@@ -2759,6 +2763,7 @@ type value =
 
 and vabstract =
 	| AHashBytes of (string, value) Hashtbl.t
+	| AReg of regexp
 
 and vfunction =
 	| FFun of fundecl
@@ -2792,6 +2797,12 @@ and vfield =
 	| VFNone
 	| VFIndex of int
 
+and regexp = {
+	r : Str.regexp;
+	mutable r_string : string;
+	mutable r_groups : (int * int) option array;
+}
+
 exception Return of value
 
 let default t =
@@ -2833,6 +2844,8 @@ let rec is_compatible v t =
 	| VDynObj _, HDynObj -> true
 	| VVirtual v, HVirtual vt -> v.vtype == vt
 	| VRef (_,_,t1), HRef t2 -> tsame t1 t2
+	| VAbstract _, HAbstract _ -> true
+	| VEnum _, HEnum _ -> true
 	| _ -> false
 
 exception Runtime_error of string
@@ -2852,8 +2865,13 @@ let interp code =
 		try
 			Hashtbl.find cached_protos p.pname
 		with Not_found ->
-			let meths, fields = (match p.psuper with None -> [||],[||] | Some p -> let p,f = get_proto p in p.pmethods, f) in
-			let meths = Array.append meths (Array.map (fun f -> functions.(f)) p.pvirtuals) in
+			let fields = (match p.psuper with None -> [||] | Some p -> snd(get_proto p)) in
+			let meths = Array.map (fun f -> functions.(f)) p.pvirtuals in
+			Array.iter (fun f ->
+				match f.fvirtual with
+				| None -> ()
+				| Some v -> meths.(v) <- functions.(f.fmethod)
+			) p.pproto;
 			let fields = Array.append fields (Array.map (fun (_,_,t) -> t) p.pfields) in
 			let proto = ({ pclass = p; pmethods = meths },fields) in
 			Hashtbl.replace cached_protos p.pname proto;
@@ -2892,6 +2910,15 @@ let interp code =
 			VDyn (v,t)
 	in
 
+	let rec get_method p name =
+		let m = ref None in
+		Array.iter (fun p -> if p.fname = name then m := Some p.fmethod) p.pproto;
+		match !m , p.psuper with
+		| Some i, _ -> Some i
+		| None, Some s -> get_method s name
+		| None, None -> None
+	in
+
 	let rec vstr_d v =
 		match v with
 		| VNull -> "null"
@@ -2901,9 +2928,7 @@ let interp code =
 		| VDyn (v,t) -> "dyn(" ^ vstr_d v ^ ":" ^ tstr t ^ ")"
 		| VObj o ->
 			let p = "#" ^ o.oproto.pclass.pname in
-			let fid = ref None in
-			Array.iter (fun p -> if p.fname = "__string" then fid := Some p.fmethod) o.oproto.pclass.pproto;
-			(match !fid with
+			(match get_method o.oproto.pclass "__string" with
 			| None -> p
 			| Some f -> p ^ ":" ^ vstr_d (fcall (func f) [v]))
 		| VBytes b -> "bytes(" ^ (if String.length b > 0 && String.get b (String.length b - 1) = '\x00' then String.sub b 0 (String.length b - 1) else b) ^ ")"
@@ -2929,9 +2954,7 @@ let interp code =
 		| VDyn (v,t) ->
 			vstr v t
 		| VObj o ->
-			let fid = ref None in
-			Array.iter (fun p -> if p.fname = "__string" then fid := Some p.fmethod) o.oproto.pclass.pproto;
-			(match !fid with
+			(match get_method o.oproto.pclass "__string" with
 			| None -> "#" ^ o.oproto.pclass.pname
 			| Some f -> vstr (fcall (func f) [v]) HBytes)
 		| VBytes b -> (if String.length b > 0 && String.get b (String.length b - 1) = '\x00' then String.sub b 0 (String.length b - 1) else b)
@@ -2961,7 +2984,13 @@ let interp code =
 	and fcall f args =
 		match f with
 		| FFun f -> call f args
-		| FNativeFun (_,f,_) -> f args
+		| FNativeFun (_,f,_) ->
+			try
+				f args
+			with InterpThrow v ->
+				raise (InterpThrow v)
+			| e ->
+				error (Printexc.to_string e)
 
 	and dyn_set_field obj field v vt =
 		let v, vt = (match vt with
@@ -3099,9 +3128,7 @@ let interp code =
 		| _, VNull -> -1
 		| VObj oa, VObj ob ->
 			if oa == ob then 0 else
-			let fid = ref None in
-			Array.iter (fun p -> if p.fname = "__compare" then fid := Some p.fmethod) oa.oproto.pclass.pproto;
-			(match !fid with
+			(match get_method oa.oproto.pclass "__compare" with
 			| None -> 1
 			| Some f -> (match fcall (func f) [a;b] with VInt i -> Int32.to_int i | _ -> assert false));
 		| VDyn (v,t), _ ->
@@ -3113,13 +3140,15 @@ let interp code =
 
 
 	and call f args =
+		let regs = Array.create (Array.length f.regs) VUndef in
+		let pos = ref 1 in
+		stack := (f,pos) :: !stack;
 		let fret = (match f.ftype with
-			| HFun (fargs,fret) -> if List.length fargs <> List.length args then error "Invalid args"; fret
+			| HFun (fargs,fret) ->
+				if List.length fargs <> List.length args then error (Printf.sprintf "Invalid args: (%s) should be (%s)" (String.concat "," (List.map vstr_d args)) (String.concat "," (List.map tstr fargs)));
+				fret
 			| _ -> assert false
 		) in
-		let regs = Array.create (Array.length f.regs) VUndef in
-		let pos = ref 0 in
-		stack := (f,pos) :: !stack;
 		let rtype i = f.regs.(i) in
 		let check v t id =
 			if not (is_compatible v t) then error (Printf.sprintf "Can't set %s(%s) with %s" (id()) (tstr t) (vstr_d v));
@@ -3523,10 +3552,13 @@ let interp code =
 						set r v;
 						exec()
 		in
+		pos := 0;
 		exec()
 	in
 	let int = Int32.to_int in
+	let string s = String.sub s 0 (String.length s - 1) in (* chop last \0 which is not needed in ocaml *)
 	let load_native lib name t =
+		let unresolved() = (fun args -> error ("Unresolved native " ^ lib ^ "@" ^ name)) in
 		let f = (match lib with
 		| "std" ->
 			(match name with
@@ -3593,10 +3625,13 @@ let interp code =
 					let b = String.sub b start (String.length b - start) in
 					VInt (Int32.of_int (try UChar.code (UTF8.get b (int index)) with _ -> 0))
 				| _ -> assert false)
-			| "math_sqrt" ->
-				(function
-				| [VFloat f] -> VFloat (sqrt f)
-				| _ -> assert false)
+			| "math_round" -> (function [VFloat f] -> VInt (Int32.of_float (floor (f +. 0.5))) | _ -> assert false)
+			| "math_floor" -> (function [VFloat f] -> VInt (Int32.of_float (floor f)) | _ -> assert false)
+			| "math_ceil" -> (function [VFloat f] -> VInt (Int32.of_float (ceil f)) | _ -> assert false)
+			| "math_ffloor" -> (function [VFloat f] -> VFloat (floor f) | _ -> assert false)
+			| "math_fceil" -> (function [VFloat f] -> VFloat (ceil f) | _ -> assert false)
+			| "math_fround" -> (function [VFloat f] -> VFloat (floor (f +. 0.5)) | _ -> assert false)
+			| "math_sqrt" -> (function [VFloat f] -> VFloat (sqrt f) | _ -> assert false)
 			| "parse_int" ->
 				(function
 				| [VBytes str; VInt len] ->
@@ -3675,12 +3710,109 @@ let interp code =
 			| "bytes_find" ->
 				(function
 				| [VBytes src; VInt pos; VInt len; VBytes chk; VInt cpos; VInt clen; ] ->
-					VInt (Int32.of_int (try ExtString.String.find (String.sub src (int pos) (int len)) (String.sub chk (int cpos) (int clen)) with ExtString.Invalid_string -> -1))
+					VInt (Int32.of_int (try int pos + ExtString.String.find (String.sub src (int pos) (int len)) (String.sub chk (int cpos) (int clen)) with ExtString.Invalid_string -> -1))
 				| _ -> assert false)
 			| _ ->
-				(fun args -> error ("Unresolved native " ^ name)))
+				unresolved())
+		| "regexp" ->
+			(match name with
+			| "regexp_new_options" ->
+				(function
+				| [VBytes str; VBytes opt] ->
+					let case_sensitive = ref true in
+					List.iter (function
+						| 'm' -> () (* always ON ? *)
+						| 'i' -> case_sensitive := false
+						| c -> failwith ("Unsupported regexp option '" ^ String.make 1 c ^ "'")
+					) (ExtString.String.explode (string opt));
+					let buf = Buffer.create 0 in
+					let rec loop prev esc = function
+						| [] -> ()
+						| c :: l when esc ->
+							(match c with
+							| 'n' -> Buffer.add_char buf '\n'
+							| 'r' -> Buffer.add_char buf '\r'
+							| 't' -> Buffer.add_char buf '\t'
+							| 'd' -> Buffer.add_string buf "[0-9]"
+							| '\\' -> Buffer.add_string buf "\\\\"
+							| '(' | ')' -> Buffer.add_char buf c
+							| '1'..'9' | '+' | '$' | '^' | '*' | '?' | '.' | '[' | ']' ->
+								Buffer.add_char buf '\\';
+								Buffer.add_char buf c;
+							| _ -> failwith ("Unsupported escaped char '" ^ String.make 1 c ^ "'"));
+							loop c false l
+						| c :: l ->
+							match c with
+							| '\\' -> loop prev true l
+							| '(' | '|' | ')' ->
+								Buffer.add_char buf '\\';
+								Buffer.add_char buf c;
+								loop c false l
+							| '?' when prev = '(' && (match l with ':' :: _ -> true | _ -> false) ->
+								failwith "Non capturing groups '(?:' are not supported in macros"
+							| '?' when prev = '*' ->
+								failwith "Ungreedy *? are not supported in macros"
+							| _ ->
+								Buffer.add_char buf c;
+								loop c false l
+					in
+					loop '\000' false (ExtString.String.explode (string str));
+					let str = Buffer.contents buf in
+					let r = {
+						r = if !case_sensitive then Str.regexp str else Str.regexp_case_fold str;
+						r_string = "";
+						r_groups = [||];
+					} in
+					VAbstract (AReg r)
+				| _ ->
+					assert false);
+(*		"regexp_match", Fun4 (fun r str pos len ->
+			match r, str, pos, len with
+			| VAbstract (AReg r), VString str, VInt pos, VInt len ->
+				let nstr, npos, delta = (if len = String.length str - pos then str, pos, 0 else String.sub str pos len, 0, pos) in
+				(try
+					ignore(Str.search_forward r.r nstr npos);
+					let rec loop n =
+						if n = 9 then
+							[]
+						else try
+							(Some (Str.group_beginning n + delta, Str.group_end n + delta)) :: loop (n + 1)
+						with Not_found ->
+							None :: loop (n + 1)
+						| Invalid_argument _ ->
+							[]
+					in
+					r.r_string <- str;
+					r.r_groups <- Array.of_list (loop 0);
+					VBool true;
+				with Not_found ->
+					VBool false)
+			| _ -> error()
+		);
+		"regexp_matched", Fun2 (fun r n ->
+			match r, n with
+			| VAbstract (AReg r), VInt n ->
+				(match (try r.r_groups.(n) with _ -> failwith ("Invalid group " ^ string_of_int n)) with
+				| None -> VNull
+				| Some (pos,pend) -> VString (String.sub r.r_string pos (pend - pos)))
+			| _ -> error()
+		);
+		"regexp_matched_pos", Fun2 (fun r n ->
+			match r, n with
+			| VAbstract (AReg r), VInt n ->
+				(match (try r.r_groups.(n) with _ -> failwith ("Invalid group " ^ string_of_int n)) with
+				| None -> VNull
+				| Some (pos,pend) -> VObject (obj (hash_field (get_ctx())) ["pos",VInt pos;"len",VInt (pend - pos)]))
+			| _ -> error()
+		);
+		(* regexp_replace : not used by Haxe *)
+		(* regexp_replace_all : not used by Haxe *)
+		(* regexp_replace_fun : not used by Haxe *)
+	]*)
+			| _ ->
+				unresolved())
 		| _ ->
-			(fun args -> error ("Unresolved native " ^ name))
+			unresolved()
 		) in
 		FNativeFun (lib ^ "@" ^ name, f, t)
 	in
@@ -4165,23 +4297,24 @@ let generate com =
 		method_wrappers = PMap.empty;
 		cdebug_files = new_lookup();
 	} in
-	ignore(alloc_string ctx "");
-	ignore(class_type ctx ctx.base_class [] false);
 	let all_classes = Hashtbl.create 0 in
 	List.iter (fun t ->
 		match t with
 		| TClassDecl c ->
 			let rec loop p f =
 				match p with
-				| Some (p,_) when PMap.mem f.cf_name p.cl_fields ->
+				| Some (p,_) when PMap.mem f.cf_name p.cl_fields || loop p.cl_super f ->
 					Hashtbl.replace ctx.overrides (f.cf_name,p.cl_path) true;
-					loop p.cl_super f
-				| _ -> ()
+					true
+				| _ ->
+					false
 			in
-			List.iter (fun f -> loop c.cl_super f) c.cl_overrides;
+			List.iter (fun f -> ignore(loop c.cl_super f)) c.cl_overrides;
 			Hashtbl.add all_classes c.cl_path c
  		| _ -> ()
 	) com.types;
+	ignore(alloc_string ctx "");
+	ignore(class_type ctx ctx.base_class [] false);
 	List.iter (generate_type ctx) com.types;
 	let ep = generate_static_init ctx in
 	let code = {

+ 204 - 0
std/hl/_std/EReg.hx

@@ -0,0 +1,204 @@
+/*
+ * Copyright (C)2005-2012 Haxe Foundation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+private typedef ERegValue = hl.types.NativeAbstract<"ereg">;
+
+@:access(String)
+@:coreApi @:final class EReg {
+
+	var r : ERegValue;
+	var last : String;
+	var global : Bool;
+
+	public function new( r : String, opt : String ) : Void {
+		var a = opt.split("g");
+		global = a.length > 1;
+		if( global )
+			opt = a.join("");
+		this.r = regexp_new_options(r.bytes, opt.bytes);
+	}
+
+	public function match( s : String ) : Bool {
+		var p = regexp_match(r,s.bytes,0,s.size);
+		if( p )
+			last = s;
+		else
+			last = null;
+		return p;
+	}
+
+	public function matched( n : Int ) : String {
+		var size = 0;
+		var m = regexp_matched(r,n,new hl.types.Ref(size));
+		return m == null ? null : String.__alloc__(m,size,m.utf8Length(0,size));
+	}
+
+	public function matchedLeft() : String {
+		var size = 0;
+		var pos = regexp_matched_pos(r, 0, new hl.types.Ref(size));
+		return last.subBytes(0,pos);
+	}
+
+	public function matchedRight() : String {
+		var size = 0;
+		var pos = regexp_matched_pos(r, 0, new hl.types.Ref(size));
+		return last.subBytes(pos + size, last.size - (pos + size));
+	}
+
+	public function matchedPos() : { pos : Int, len : Int } {
+		var len = 0;
+		var pos = regexp_matched_pos(r,0,new hl.types.Ref(len));
+		return { pos : pos, len : len };
+	}
+
+	public function matchSub( s : String, pos : Int, len : Int = -1):Bool {
+		var p = regexp_match(r, s.bytes, pos, len < 0 ? s.length - pos : len);
+		if( p )
+			last = s;
+		else
+			last = null;
+		return p;
+	}
+
+	public function split( s : String ) : Array<String> {
+		/*var pos = 0;
+		var len = s.length;
+		var a = new Array();
+		var first = true;
+		do {
+			if( !regexp_match(r,s.__s,pos,len) )
+				break;
+			var p = regexp_matched_pos(r,0);
+			if( p.len == 0 && !first ) {
+				if( p.pos == s.length )
+					break;
+				p.pos += 1;
+			}
+			a.push(s.substr(pos,p.pos - pos));
+			var tot = p.pos + p.len - pos;
+			pos += tot;
+			len -= tot;
+			first = false;
+		} while( global );
+		a.push(s.substr(pos,len));
+		return a;*/
+		throw "TODO";
+		return null;
+	}
+
+	public function replace( s : String, by : String ) : String {
+		/*var b = new StringBuf();
+		var pos = 0;
+		var len = s.length;
+		var a = by.split("$");
+		var first = true;
+		do {
+			if( !regexp_match(r,s.__s,pos,len) )
+				break;
+			var p = regexp_matched_pos(r,0);
+			if( p.len == 0 && !first ) {
+				if( p.pos == s.length )
+					break;
+				p.pos += 1;
+			}
+			b.addSub(s,pos,p.pos-pos);
+			if( a.length > 0 )
+				b.add(a[0]);
+			var i = 1;
+			while( i < a.length ) {
+				var k = a[i];
+				var c = k.charCodeAt(0);
+				// 1...9
+				if( c >= 49 && c <= 57 ) {
+					var p = try regexp_matched_pos(r,Std.int(c)-48) catch( e : String ) null;
+					if( p == null ){
+						b.add("$");
+						b.add(k);
+					} else {
+						if( p.pos >= 0 ) b.addSub(s,p.pos,p.len);
+						b.addSub(k,1,k.length - 1);
+					}
+				} else if( c == null ) {
+					b.add("$");
+					i++;
+					var k2 = a[i];
+					if( k2 != null && k2.length > 0 )
+						b.add(k2);
+				} else
+					b.add("$"+k);
+				i++;
+			}
+			var tot = p.pos + p.len - pos;
+			pos += tot;
+			len -= tot;
+			first = false;
+		} while( global );
+		b.addSub(s,pos,len);
+		return b.toString();*/
+		throw "TODO";
+		return null;
+	}
+
+	public function map( s : String, f : EReg -> String ) : String {
+		/*
+		var offset = 0;
+		var buf = new StringBuf();
+		do {
+			if (offset >= s.length)
+				break;
+			else if (!matchSub(s, offset)) {
+				buf.add(s.substr(offset));
+				break;
+			}
+			var p = regexp_matched_pos(r,0);
+			buf.add(s.substr(offset, p.pos - offset));
+			buf.add(f(this));
+			if (p.len == 0) {
+				buf.add(s.substr(p.pos, 1));
+				offset = p.pos + 1;
+			}
+			else
+				offset = p.pos + p.len;
+		} while (global);
+		if (!global && offset > 0 && offset < s.length)
+			buf.add(s.substr(offset));
+		return buf.toString();*/
+		throw "TODO";
+		return null;
+	}
+
+	@:hlNative("regexp", "regexp_new_options") static function regexp_new_options( bytes : hl.types.Bytes, options : hl.types.Bytes ) : ERegValue {
+		return null;
+	}
+
+	@:hlNative("regexp", "regexp_match") static function regexp_match( r : ERegValue, str : hl.types.Bytes, pos : Int, size : Int ) : Bool {
+		return false;
+	}
+
+	@:hlNative("regexp", "regexp_matched") static function regexp_matched( r : ERegValue, n : Int, size : hl.types.Ref<Int> ) : hl.types.Bytes {
+		return null;
+	}
+
+	@:hlNative("regexp", "regexp_matched_pos") static function regexp_matched_pos( r : ERegValue, n : Int, size : hl.types.Ref<Int> ) : Int {
+		return 0;
+	}
+}

+ 3 - 3
std/hl/_std/Std.hx

@@ -42,13 +42,13 @@ class Std {
 	public static inline function int( v : Float ) : Int {
 		return untyped $int(v);
 	}
-	
+
 	public static function string( v : Dynamic ) : String {
 		var len = 0;
 		var bytes = hl.types.Bytes.ofValue(v,new hl.types.Ref(len));
 		return @:privateAccess String.__alloc__(bytes,len,bytes.utf8Length(0,len));
 	}
-	
+
 	public static function parseInt( s : String ) : Null<Int> {
 		return @:privateAccess s.bytes.parseInt(0, s.size);
 	}
@@ -58,7 +58,7 @@ class Std {
 	}
 
 	@:keep static function __add__( a : Dynamic, b : Dynamic ) : Dynamic {
-		throw "TODO";
+		trace("TODO");
 		return null;
 	}
 

+ 55 - 10
std/hl/_std/String.hx

@@ -35,20 +35,65 @@ class String {
 	}
 
 	public function indexOf( str : String, ?startIndex : Int ) : Int {
-		var startIndex : Int = startIndex;
-		if( startIndex < 0 ) startIndex = 0;
-		if( startIndex > size ) startIndex = size;
-		return bytes.find(startIndex,size - startIndex,str.bytes,0,str.size);
+		var startByte = 0;
+		if( startIndex != null && startIndex > 0 ) {
+			if( startIndex >= length )
+				return -1;
+			startByte = bytes.utf8Length(0, startIndex);
+		}
+		return bytes.find(startByte,size - startByte,str.bytes,0,str.size);
 	}
 
 	public function lastIndexOf( str : String, ?startIndex : Int ) : Int {
-		throw "TODO";
-		return -1;
+		var startByte = 0;
+		if( startIndex != null && startIndex > 0 ) {
+			if( startIndex >= length )
+				return -1;
+			startByte = bytes.utf8Length(0, startIndex);
+		}
+		var last = -1;
+		while( true ) {
+			var p = bytes.find(startByte, size - startByte, str.bytes, 0, str.size);
+			if( p < 0 ) break;
+			last = p;
+			startByte = p + 1;
+		}
+		return last;
 	}
 
 	public function split( delimiter : String ) : Array<String> {
-		throw "TODO";
-		return null;
+		var pos = 0;
+		var out = [];
+		if( size == 0 ) {
+			out.push("");
+			return out;
+		}
+		var dsize = delimiter.size;
+		if( dsize == 0 ) {
+			while( pos < size ) {
+				var p = bytes.utf8Pos(pos, 1);
+				out.push(subBytes(pos, p));
+				pos += p;
+			}
+			return out;
+		}
+		while( true ) {
+			var p = bytes.find(pos, size - pos, delimiter.bytes, 0, dsize);
+			if( p < 0 ) {
+				out.push(subBytes(pos, size-pos));
+				break;
+			}
+			out.push(subBytes(pos, pos - p));
+			pos = p + dsize;
+		}
+		return out;
+	}
+
+	function subBytes( pos : Int, size : Int ) : String {
+		var b = new hl.types.Bytes(size + 1);
+		b.blit(0, bytes, pos, size);
+		b[size] = 0;
+		return __alloc__(b, size, b.utf8Length(0, size));
 	}
 
 	public function substr( pos : Int, ?len : Int ) : String @:privateAccess {
@@ -74,8 +119,8 @@ class String {
 
 		var bytes = bytes;
 		var start = pos == 0 ? 0 : bytes.utf8Pos(0, pos);
-		var end = pos + len == sl ? size : bytes.utf8Pos(start, len);
-		var size = end - start;
+		var size = pos + len == sl ? size - start : bytes.utf8Pos(start, len);
+
 		var b = new hl.types.Bytes(size + 1);
 		b.blit(0, bytes, start, size);
 		b[size] = 0;

+ 18 - 2
std/hl/types/ArrayDyn.hx

@@ -1,5 +1,22 @@
 package hl.types;
 
+class ArrayDynIterator {
+	var a : ArrayBase;
+	var len : Int;
+	var pos : Int;
+	public function new(a) {
+		this.a = a;
+		this.len = a.length;
+		this.pos = 0;
+	}
+	public function hasNext() {
+		return pos < len;
+	}
+	public function next() {
+		return a.getDyn(pos++);
+	}
+}
+
 @:keep
 class ArrayDyn extends ArrayBase.ArrayAccess {
 
@@ -109,8 +126,7 @@ class ArrayDyn extends ArrayBase.ArrayAccess {
 	}
 
 	public function iterator() : Iterator<Dynamic> {
-		throw "TODO";
-		return null;
+		return new ArrayDynIterator(array);
 	}
 
 	public function map( f : Dynamic -> Dynamic ) : ArrayDyn {

+ 24 - 5
std/hl/types/ArrayObj.hx

@@ -58,8 +58,26 @@ class ArrayObj<T> extends ArrayBase {
 	}
 
 	public function splice( pos : Int, len : Int ) : ArrayObj<T> {
-		throw "TODO";
-		return null;
+		if( len < 0 ) return new ArrayObj();
+		if( pos < 0 ){
+			pos = this.length + pos;
+			if( pos < 0 ) pos = 0;
+		}
+		if( pos > this.length ) {
+			pos = 0;
+			len = 0;
+		} else if( pos + len > this.length ) {
+			len = this.length - pos;
+			if( len < 0 ) len = 0;
+		}
+		var a = this.array;
+		var ret : ArrayObj<T> = alloc(cast a.sub(pos,len));
+		var end = pos + len;
+		a.blit(pos,a,end,this.length-end);
+		this.length -= len;
+		while( --len >= 0 )
+			a[this.length + len] = null;
+		return ret;
 	}
 
 	override function toString() : String {
@@ -85,7 +103,7 @@ class ArrayObj<T> extends ArrayBase {
 		var i = indexOf(x);
 		if( i < 0 ) return false;
 		length--;
-		array.blit(i,array,i+1,length);
+		array.blit(i,array,i+1,length - i);
 		array[length] = null;
 		return true;
 	}
@@ -148,6 +166,7 @@ class ArrayObj<T> extends ArrayBase {
 			return null;
 		return array[pos];
 	}
+
 	override function setDyn( pos : Int, v : Dynamic ) {
 		var pos : UInt = pos;
 		if( pos >= length )
@@ -167,8 +186,8 @@ class ArrayObj<T> extends ArrayBase {
 	override function sortDyn( f : Dynamic -> Dynamic -> Int ) sort(f);
 	override function spliceDyn( pos : Int, len : Int ) return splice(pos, len);
 
-	public static function alloc( a : hl.types.NativeArray<Dynamic> ) {
-		var arr : ArrayObj<Dynamic> = untyped $new(ArrayObj);
+	public static function alloc<T>( a : hl.types.NativeArray<T> ) : ArrayObj<T> {
+		var arr : ArrayObj<T> = untyped $new(ArrayObj);
 		arr.array = a;
 		arr.length = a.length;
 		return arr;

+ 12 - 6
std/hl/types/Bytes.hx

@@ -57,18 +57,24 @@ package hl.types;
 	public function compare( pos : Int, bytes : Bytes, bytesPos : Int, size : Int ) : Int {
 		return 0;
 	}
-	
+
 	@:hlNative("std","bytes_find")
 	public function find( pos : Int, size : Int, bytes : Bytes, bytesPos : Int, bytesSize : Int ) : Int {
 		return 0;
 	}
-	
+
+	public function sub( pos : Int, size : Int ) {
+		var b = new Bytes(size);
+		b.blit(0, this, pos, size);
+		return b;
+	}
+
 
 	/**
 		Count the number of UTF8 chars into the given Bytes data.
 	**/
 	@:hlNative("std","utf8length")
-	function utf8Length( pos : Int, size : Int ) : Int {
+	public function utf8Length( pos : Int, size : Int ) : Int {
 		return 0;
 	}
 
@@ -79,7 +85,7 @@ package hl.types;
 	function bytesLength( pos : Int ) : Int {
 		return 0;
 	}
-	
+
 	@:hlNative("std","hash")
 	function hash() : Int {
 		return 0;
@@ -89,7 +95,7 @@ package hl.types;
 		Decode the utf8 char at the given position
 	**/
 	@:hlNative("std","utf8char")
-	function utf8Char( pos : Int, charPos : Int ) : Int {
+	public function utf8Char( pos : Int, charPos : Int ) : Int {
 		return 0;
 	}
 
@@ -97,7 +103,7 @@ package hl.types;
 		Gives the byte position for the utf8 char starting at pos.
 	**/
 	@:hlNative("std","utf8pos")
-	function utf8Pos( pos : Int, charPos : Int ) : Int {
+	public function utf8Pos( pos : Int, charPos : Int ) : Int {
 		return 0;
 	}
 

+ 6 - 0
std/hl/types/NativeArray.hx

@@ -41,6 +41,12 @@ package hl.types;
 		return value;
 	}
 
+	@:extern public inline function sub( pos : Int, len : Int ) {
+		var n = new NativeArray<T>(len);
+		n.blit(0, this, pos, len);
+		return n;
+	}
+
 	@:hlNative("std","atype") public function getType() : Type {
 		return null;
 	}

+ 3 - 3
std/hl/types/NativeBytesMap.hx

@@ -5,8 +5,8 @@ abstract NativeBytesMap(NativeAbstract<"BytesMap">) {
 	@:extern public inline function new() {
 		this = alloc();
 	}
-	
-	@:hlNative("std","hballoc") function alloc() : NativeAbstract<"BytesMap"> {
+
+	@:hlNative("std","hballoc") static function alloc() : NativeAbstract<"BytesMap"> {
 		return null;
 	}
 
@@ -18,7 +18,7 @@ abstract NativeBytesMap(NativeAbstract<"BytesMap">) {
 	public function exists( key : Bytes ) : Bool {
 		return false;
 	}
-	
+
 	@:hlNative("std","hbget")
 	public function get( key : Bytes ) : Dynamic {
 		return null;