Browse Source

fixed block_vars

Nicolas Cannasse 17 years ago
parent
commit
27d8e6d49c
11 changed files with 373 additions and 108 deletions
  1. 226 72
      codegen.ml
  2. 1 0
      doc/CHANGES.txt
  3. 3 4
      genjs.ml
  4. 3 4
      genswf8.ml
  5. 4 4
      genswf9.ml
  6. 1 0
      main.ml
  7. 5 0
      tests/unit/Test.hx
  8. 128 0
      tests/unit/TestLocals.hx
  9. 0 22
      tests/unit/TestMisc.hx
  10. 0 1
      tests/unit/unit.hxml
  11. 2 1
      tests/unit/unit.hxp

+ 226 - 72
codegen.ml

@@ -41,6 +41,15 @@ let binop op a b t p =
 let index com e index t p =
 let index com e index t p =
 	mk (TArray (e,mk (TConst (TInt (Int32.of_int index))) com.type_api.tint p)) t p
 	mk (TArray (e,mk (TConst (TInt (Int32.of_int index))) com.type_api.tint p)) t p
 
 
+let concat e1 e2 =
+	let e = (match e1.eexpr, e2.eexpr with
+		| TBlock el1, TBlock el2 -> TBlock (el1@el2)
+		| TBlock el, _ -> TBlock (el @ [e2])
+		| _, TBlock el -> TBlock (e1 :: el)
+		| _ , _ -> TBlock [e1;e2]
+	) in
+	mk e e2.etype (punion e1.epos e2.epos)
+
 (* -------------------------------------------------------------------------- *)
 (* -------------------------------------------------------------------------- *)
 (* REMOTING PROXYS *)
 (* REMOTING PROXYS *)
 
 
@@ -302,6 +311,66 @@ let on_generate ctx t =
 	| _ ->
 	| _ ->
 		()
 		()
 
 
+(* -------------------------------------------------------------------------- *)
+(* LOCAL VARIABLES USAGE *)
+
+type usage =
+	| Block of ((usage -> unit) -> unit)
+	| Loop of ((usage -> unit) -> unit)
+	| Function of ((usage -> unit) -> unit)
+	| Declare of string * t
+	| Use of string
+
+let rec local_usage f e =
+	match e.eexpr with
+	| TLocal v ->
+		f (Use v)
+	| TVars l ->
+		List.iter (fun (v,t,e) ->
+			(match e with None -> () | Some e -> local_usage f e);
+			f (Declare (v,t));
+		) l
+	| TFunction tf ->
+		let cc f =
+			List.iter (fun (n,_,t) -> f (Declare (n,t))) tf.tf_args;
+			local_usage f tf.tf_expr;
+		in
+		f (Function cc)		
+	| TBlock l ->
+		f (Block (fun f -> List.iter (local_usage f) l))		
+	| TFor (v,t,it,e) ->
+		local_usage f it;
+		f (Loop (fun f ->
+			f (Declare (v,t));
+			local_usage f e;
+		))
+	| TWhile _ ->
+		f (Loop (fun f ->
+			iter (local_usage f) e
+		))
+	| TTry (e,catchs) ->
+		local_usage f e;
+		List.iter (fun (v,t,e) ->
+			f (Block (fun f ->
+				f (Declare (v,t));
+				local_usage f e;
+			))
+		) catchs;
+	| TMatch (e,_,cases,def) ->
+		local_usage f e;
+		List.iter (fun (_,vars,e) ->
+			let cc f = 
+				(match vars with
+				| None -> ()
+				| Some l ->	List.iter (fun (vo,t) -> match vo with None -> () | Some v -> f (Declare (v,t))) l);
+				local_usage f e;
+			in
+			f (Block cc)
+		) cases;
+		(match def with None -> () | Some e -> local_usage f e);
+	| _ ->
+		iter (local_usage f) e
+
 (* -------------------------------------------------------------------------- *)
 (* -------------------------------------------------------------------------- *)
 (* PER-BLOCK VARIABLES *)
 (* PER-BLOCK VARIABLES *)
 
 
@@ -310,96 +379,181 @@ let on_generate ctx t =
 	by value. It transforms the following expression :
 	by value. It transforms the following expression :
 
 
 	for( x in array )
 	for( x in array )
-		funs.push(function() return x);
+		funs.push(function() return x++);	
 
 
 	Into the following :
 	Into the following :
 
 
-	for( x in array )
-		funs.push(function(x) { function() return x; }(x));
+	for( _x in array ) {
+		var x = [_x];
+		funs.push(function(x) { function() return x[0]++; }(x));
+	}
 
 
-	This way, each value is captured independantly.	
+	This way, each value is captured independantly.
 *)
 *)
 
 
-let block_vars e =
-	let add_var map v d = map := PMap.add v d (!map) in
-	let wrap e used =
-		match PMap.foldi (fun v _ acc -> v :: acc) used [] with
-		| [] -> e
-		| vars ->
-			mk (TCall (
-				(mk (TFunction {
-					tf_args = List.map (fun v -> v , false, t_dynamic) vars;
-					tf_type = t_dynamic;
-					tf_expr = mk (TReturn (Some e)) t_dynamic e.epos;
-				}) t_dynamic e.epos),
-				List.map (fun v -> mk (TLocal v) t_dynamic e.epos) vars)
-			) t_dynamic e.epos
+let block_vars ctx e =
+
+	let uid = ref 0 in
+	let gen_unique() =
+		incr uid;
+		"$t" ^ string_of_int !uid;
 	in
 	in
-	let rec in_fun vars depth used_locals e =
-		match e.eexpr with
-		| TLocal v ->
-			(try
-				if PMap.find v vars = depth then add_var used_locals v depth;				
-			with
-				Not_found -> ())
-		| _ ->
-			iter (in_fun vars depth used_locals) e
 
 
-	and in_loop vars depth e =
+	let t = ctx.type_api in
+
+	let rec mk_init v vt vtmp pos =
+		let at = t.tarray vt in
+		mk (TVars [v,at,Some (mk (TArrayDecl [mk (TLocal vtmp) vt pos]) at pos)]) t.tvoid pos
+
+	and wrap used e =
 		match e.eexpr with
 		match e.eexpr with
-		| TVars l ->
-			{ e with eexpr = TVars (List.map (fun (v,t,e) ->
-				let e = (match e with None -> None | Some e -> Some (in_loop vars depth e)) in
-				add_var vars v depth;
-				v, t, e
-			) l) }
-		| TFor (v,t,i,e1) ->
-			let new_vars = PMap.add v depth (!vars) in
-			{ e with eexpr = TFor (v,t,in_loop vars depth i,in_loop (ref new_vars) depth e1) }
-		| TTry (e1,cases) ->
-			let e1 = in_loop vars depth e1 in
-			let cases = List.map (fun (v,t,e) ->
-				let new_vars = PMap.add v depth (!vars) in
-				v , t, in_loop (ref new_vars) depth e
-			) cases in
-			{ e with eexpr = TTry (e1,cases) }
-		| TMatch (e1,t,cases,def) ->
-			let e1 = in_loop vars depth e1 in
-			let cases = List.map (fun (cl,params,e) ->
-				let e = (match params with
-					| None -> in_loop vars depth e
+		| TVars vl ->
+			let vl = List.map (fun (v,vt,e) ->
+				if PMap.mem v used then begin
+					let vt = t.tarray vt in					
+					v, vt, (match e with None -> None | Some e -> Some (mk (TArrayDecl [wrap used e]) (t.tarray e.etype) e.epos))
+				end else
+					v, vt, (match e with None -> None | Some e -> Some (wrap used e))
+			) vl in
+			{ e with eexpr = TVars vl }
+		| TLocal v when PMap.mem v used ->
+			mk (TArray ({ e with etype = t.tarray e.etype },mk (TConst (TInt 0l)) t.tint e.epos)) e.etype e.epos
+		| TFor (v,vt,it,expr) when PMap.mem v used ->			
+			let vtmp = gen_unique() in
+			let it = wrap used it in
+			let expr = wrap used expr in
+			mk (TFor (vtmp,vt,it,concat (mk_init v vt vtmp e.epos) expr)) e.etype e.epos
+		| TTry (expr,catchs) ->
+			let catchs = List.map (fun (v,t,e) ->
+				let e = wrap used e in
+				if PMap.mem v used then
+					let vtmp = gen_unique()	in				
+					vtmp, t, concat (mk_init v t vtmp e.epos) e
+				else
+					v, t, e
+			) catchs in
+			mk (TTry (wrap used expr,catchs)) e.etype e.epos
+		| TMatch (expr,enum,cases,def) ->
+			let cases = List.map (fun (il,vars,e) ->
+				let pos = e.epos in
+				let e = ref (wrap used e) in
+				let vars = match vars with
+					| None -> None
 					| Some l ->
 					| Some l ->
-						let new_vars = List.fold_left (fun acc (v,t) ->
-							match v with
-							| None -> acc
-							| Some name -> PMap.add name depth acc
-						) (!vars) l in
-						in_loop (ref new_vars) depth e
-				) in
-				cl , params, e
+						Some (List.map (fun (vo,vt) ->
+							match vo with
+							| Some v when PMap.mem v used ->
+								let vtmp = gen_unique() in
+								e := concat (mk_init v vt vtmp pos) !e;
+								Some vtmp, vt
+							| _ -> vo, vt
+						) l)
+				in
+				il, vars, !e
 			) cases in
 			) cases in
-			let def = (match def with None -> None | Some e -> Some (in_loop vars depth e)) in
-			{ e with eexpr = TMatch (e1, t, cases, def) }
-		| TBlock l ->
-			let new_vars = (ref !vars) in
-			map_expr (in_loop new_vars depth) e
-		| TFunction _ ->
-			let new_vars = !vars in
-			let used = ref PMap.empty in
-			iter (in_fun new_vars depth used) e;
-			let e = wrap e (!used) in
-			let new_vars = ref (PMap.foldi (fun v _ acc -> PMap.remove v acc) (!used) new_vars) in
-			map_expr (in_loop new_vars (depth + 1)) e
+			let def = match def with None -> None | Some e -> Some (wrap used e) in
+			mk (TMatch (wrap used expr,enum,cases,def)) e.etype e.epos
+		| TFunction f ->
+			(* 
+				list variables that are marked as used, but also used in that
+				function and which are not declared inside it !
+			*)
+			let fused = ref PMap.empty in
+			let tmp_used = ref (PMap.foldi PMap.add used PMap.empty) in
+			let rec browse = function
+				| Block f | Loop f | Function f -> f browse
+				| Use v -> 
+					(try 
+						fused := PMap.add v (PMap.find v !tmp_used) !fused;
+					with Not_found ->
+						())
+				| Declare (v,_) ->
+					tmp_used := PMap.remove v !tmp_used
+			in
+			local_usage browse e;			
+			let vars = PMap.foldi (fun v vt acc -> (v,t.tarray vt) :: acc) !fused [] in
+			(* in case the variable has been marked as used in a parallel scope... *)
+			let fexpr = ref (wrap used f.tf_expr) in
+			let fargs = List.map (fun (v,o,vt) ->
+				if PMap.mem v used then
+					let vtmp = gen_unique() in
+					fexpr := concat (mk_init v vt vtmp e.epos) !fexpr;
+					vtmp, o, vt
+				else
+					v, o, vt
+			) f.tf_args in
+			let e = { e with eexpr = TFunction { f with tf_args = fargs; tf_expr = !fexpr } } in
+			let args = List.map (fun (v,t) -> v, false, t) vars in
+			mk (TCall (
+				(mk (TFunction {
+					tf_args = args;
+					tf_type = e.etype;
+					tf_expr = mk (TReturn (Some e)) e.etype e.epos;
+				}) (TFun (args,e.etype)) e.epos),
+				List.map (fun (v,t) -> mk (TLocal v) t e.epos) vars)
+			) e.etype e.epos
 		| _ ->
 		| _ ->
-			map_expr (in_loop vars depth) e
+			map_expr (wrap used) e
+
 	and out_loop e =
 	and out_loop e =
 		match e.eexpr with
 		match e.eexpr with
 		| TFor _ | TWhile _ ->
 		| TFor _ | TWhile _ ->
-			in_loop (ref PMap.empty) 0 e
+			(*
+				collect variables that are declared in loop but used in subfunctions
+			*)
+			let vars = ref PMap.empty in
+			let used = ref PMap.empty in
+			let depth = ref 0 in
+			let rec collect_vars in_loop = function
+				| Block f ->
+					let old = !vars in
+					f (collect_vars in_loop);
+					vars := old;
+				| Loop f ->
+					let old = !vars in
+					f (collect_vars true);
+					vars := old;
+				| Function f ->
+					incr depth;
+					f (collect_vars false);
+					decr depth;
+				| Declare (v,t) ->
+					if in_loop then vars := PMap.add v (!depth,t) !vars;
+				| Use v ->
+					try
+						let d, t = PMap.find v (!vars) in
+						if d <> !depth then used := PMap.add v t !used;
+					with Not_found ->
+						()
+			in
+			local_usage (collect_vars false) e;
+			if PMap.is_empty !used then e else wrap !used e
 		| _ ->
 		| _ ->
 			map_expr out_loop e
 			map_expr out_loop e
 	in
 	in
-	out_loop e
+	match ctx.platform with
+	| Neko | Cross -> e
+	| _ -> out_loop e
+
+let post_process ctx =
+	List.iter (function
+		| TClassDecl c ->
+			let process_field f =
+				match f.cf_expr with
+				| None -> ()
+				| Some e -> f.cf_expr <- Some (block_vars ctx e)
+			in
+			List.iter process_field c.cl_ordered_fields;
+			List.iter process_field c.cl_ordered_statics;
+			(match c.cl_constructor with
+			| None -> ()
+			| Some f -> process_field f);
+			(match c.cl_init with
+			| None -> ()
+			| Some e -> c.cl_init <- Some (block_vars ctx e));
+		| TEnumDecl _ -> ()
+		| TTypeDecl _ -> ()
+	) ctx.types
 
 
 (* -------------------------------------------------------------------------- *)
 (* -------------------------------------------------------------------------- *)
 (* STACK MANAGEMENT EMULATION *)
 (* STACK MANAGEMENT EMULATION *)

+ 1 - 0
doc/CHANGES.txt

@@ -45,6 +45,7 @@ TODO inlining : substitute class+function type parameters in order to have fully
 	renamed haxe.rtti.Type to haxe.rtti.CType (with changes in prefix)
 	renamed haxe.rtti.Type to haxe.rtti.CType (with changes in prefix)
 	added haxe.TimerQueue, added haxe.Timer.delay, remove haxe.Timer.delayed
 	added haxe.TimerQueue, added haxe.Timer.delay, remove haxe.Timer.delayed
 	flash9 : bugfix, generated interfaces were empty
 	flash9 : bugfix, generated interfaces were empty
+	fixed bug while writing block-vars in flash/js
 
 
 2008-04-05: 1.19
 2008-04-05: 1.19
 	fixed flash9 Array.toString
 	fixed flash9 Array.toString

+ 3 - 4
genjs.ml

@@ -574,7 +574,6 @@ let gen_class_static_field ctx c f =
 		print ctx "%s%s = null" (s_path c.cl_path) (field f.cf_name);
 		print ctx "%s%s = null" (s_path c.cl_path) (field f.cf_name);
 		newline ctx
 		newline ctx
 	| Some e ->
 	| Some e ->
-		let e = Codegen.block_vars e in
 		match e.eexpr with
 		match e.eexpr with
 		| TFunction _ ->
 		| TFunction _ ->
 			ctx.curmethod <- (f.cf_name,false);
 			ctx.curmethod <- (f.cf_name,false);
@@ -592,7 +591,7 @@ let gen_class_field ctx c f =
 		newline ctx
 		newline ctx
 	| Some e ->
 	| Some e ->
 		ctx.curmethod <- (f.cf_name,false);
 		ctx.curmethod <- (f.cf_name,false);
-		gen_value ctx (Codegen.block_vars e);
+		gen_value ctx e;
 		newline ctx
 		newline ctx
 
 
 let generate_class ctx c =
 let generate_class ctx c =
@@ -603,7 +602,7 @@ let generate_class ctx c =
 	print ctx "%s = " p;
 	print ctx "%s = " p;
 	(match c.cl_constructor with
 	(match c.cl_constructor with
 	| Some { cf_expr = Some e } ->
 	| Some { cf_expr = Some e } ->
-		(match Codegen.block_vars e with
+		(match e with
 		| { eexpr = TFunction f } ->
 		| { eexpr = TFunction f } ->
 			let args  = List.map arg_name f.tf_args in
 			let args  = List.map arg_name f.tf_args in
 			let a, args = (match args with [] -> "p" , ["p"] | x :: _ -> x, args) in
 			let a, args = (match args with [] -> "p" , ["p"] | x :: _ -> x, args) in
@@ -665,7 +664,7 @@ let generate_type ctx = function
 	| TClassDecl c ->
 	| TClassDecl c ->
 		(match c.cl_init with
 		(match c.cl_init with
 		| None -> ()
 		| None -> ()
-		| Some e -> ctx.inits <- Codegen.block_vars e :: ctx.inits);
+		| Some e -> ctx.inits <- e :: ctx.inits);
 		if not c.cl_extern then generate_class ctx c
 		if not c.cl_extern then generate_class ctx c
 	| TEnumDecl e when e.e_extern ->
 	| TEnumDecl e when e.e_extern ->
 		()
 		()

+ 3 - 4
genswf8.ml

@@ -1115,7 +1115,6 @@ let gen_class_static_field ctx c flag f =
 		push ctx [VReg 0; VStr (f.cf_name,flag); VNull];
 		push ctx [VReg 0; VStr (f.cf_name,flag); VNull];
 		setvar ctx VarObj
 		setvar ctx VarObj
 	| Some e ->
 	| Some e ->
-		let e = Codegen.block_vars e in
 		match e.eexpr with
 		match e.eexpr with
 		| TFunction _ ->
 		| TFunction _ ->
 			push ctx [VReg 0; VStr (f.cf_name,flag)];
 			push ctx [VReg 0; VStr (f.cf_name,flag)];
@@ -1140,7 +1139,7 @@ let gen_class_field ctx flag f =
 		push ctx [VNull]
 		push ctx [VNull]
 	| Some e ->
 	| Some e ->
 		ctx.curmethod <- (f.cf_name,false);
 		ctx.curmethod <- (f.cf_name,false);
-		gen_expr ctx true (Codegen.block_vars e));
+		gen_expr ctx true e);
 	setvar ctx VarObj
 	setvar ctx VarObj
 
 
 let gen_enum_field ctx e f =
 let gen_enum_field ctx e f =
@@ -1237,7 +1236,7 @@ let gen_type_def ctx t =
 	| TClassDecl c ->
 	| TClassDecl c ->
 		(match c.cl_init with
 		(match c.cl_init with
 		| None -> ()
 		| None -> ()
-		| Some e -> ctx.inits <- Codegen.block_vars e :: ctx.inits);
+		| Some e -> ctx.inits <- e :: ctx.inits);
 		gen_package ctx c.cl_path c.cl_extern;
 		gen_package ctx c.cl_path c.cl_extern;
 		if c.cl_extern then
 		if c.cl_extern then
 			()
 			()
@@ -1260,7 +1259,7 @@ let gen_type_def ctx t =
 		| Some { cf_expr = Some e } ->
 		| Some { cf_expr = Some e } ->
 			have_constr := true;
 			have_constr := true;
 			ctx.curmethod <- ("new",false);
 			ctx.curmethod <- ("new",false);
-			gen_expr ctx true (Codegen.block_vars e)
+			gen_expr ctx true e
 		| _ ->
 		| _ ->
 			let f = begin_func ctx true false [] in
 			let f = begin_func ctx true false [] in
 			f());
 			f());

+ 4 - 4
genswf9.ml

@@ -1366,7 +1366,7 @@ and jump_expr ctx e jif =
 	jump_expr_gen ctx e jif (jump ctx)
 	jump_expr_gen ctx e jif (jump ctx)
 
 
 let generate_method ctx fdata stat =
 let generate_method ctx fdata stat =
-	generate_function ctx { fdata with tf_expr = Codegen.block_vars fdata.tf_expr } stat
+	generate_function ctx fdata stat
 
 
 let generate_construct ctx fdata c =
 let generate_construct ctx fdata c =
 	(* make all args optional to allow no-param constructor *)
 	(* make all args optional to allow no-param constructor *)
@@ -1391,7 +1391,7 @@ let generate_construct ctx fdata c =
 			write ctx (HInitProp id);
 			write ctx (HInitProp id);
 		| _ -> ()
 		| _ -> ()
 	) c.cl_fields;
 	) c.cl_fields;
-	gen_expr ctx false (Codegen.block_vars fdata.tf_expr);
+	gen_expr ctx false fdata.tf_expr;
 	write ctx HRetVoid;
 	write ctx HRetVoid;
 	f() , List.length fdata.tf_args
 	f() , List.length fdata.tf_args
 
 
@@ -1433,7 +1433,7 @@ let generate_class_statics ctx c =
 				first := false;
 				first := false;
 			end;
 			end;
 			write ctx (HReg r.rid);
 			write ctx (HReg r.rid);
-			gen_expr ctx true (Codegen.block_vars e);
+			gen_expr ctx true e;
 			write ctx (HSetSlot !nslot);
 			write ctx (HSetSlot !nslot);
 		| _ ->
 		| _ ->
 			incr nslot
 			incr nslot
@@ -1746,7 +1746,7 @@ let generate_inits ctx types =
 		| TClassDecl c ->
 		| TClassDecl c ->
 			(match c.cl_init with
 			(match c.cl_init with
 			| None -> ()
 			| None -> ()
-			| Some e -> gen_expr ctx false (Codegen.block_vars e));
+			| Some e -> gen_expr ctx false e);
 		| _ -> ()
 		| _ -> ()
 	) types;
 	) types;
 	List.iter (fun (t,_) ->
 	List.iter (fun (t,_) ->

+ 1 - 0
main.ml

@@ -403,6 +403,7 @@ try
 		if !display then xml_out := None;		
 		if !display then xml_out := None;		
 		if !no_output then com.platform <- Cross;		
 		if !no_output then com.platform <- Cross;		
 		com.types <- Typer.types ctx com.main_class (!excludes);
 		com.types <- Typer.types ctx com.main_class (!excludes);
+		Codegen.post_process com;
 		(match com.platform with
 		(match com.platform with
 		| Cross ->
 		| Cross ->
 			()
 			()

+ 5 - 0
tests/unit/Test.hx

@@ -18,6 +18,10 @@ class Test #if swf_mark implements mt.Protect #end {
 		eq(v,false,pos);
 		eq(v,false,pos);
 	}
 	}
 
 
+	function assert( ?pos ) {
+		report("Assert",pos);
+	}
+
 	function exc( f : Void -> Void, ?pos ) {
 	function exc( f : Void -> Void, ?pos ) {
 		count++;
 		count++;
 		try {
 		try {
@@ -162,6 +166,7 @@ class Test #if swf_mark implements mt.Protect #end {
 			new TestBytes(),
 			new TestBytes(),
 			new TestInt32(),
 			new TestInt32(),
 			new TestIO(),
 			new TestIO(),
+			new TestLocals(),
 			new TestSerialize(),
 			new TestSerialize(),
 			new TestRemoting(),
 			new TestRemoting(),
 			new TestMisc(),
 			new TestMisc(),

+ 128 - 0
tests/unit/TestLocals.hx

@@ -0,0 +1,128 @@
+package unit;
+
+class TestLocals extends Test {
+
+	function testIncrDecr() {
+		var i = 5;
+		eq( i++, 5 );
+		eq( i, 6 );
+		eq( i--, 6 );
+		eq( i, 5 );
+		eq( ++i, 6 );
+		eq( i, 6 );
+		eq( --i, 5 );
+		eq( i, 5 );
+	}
+
+	function testScope() {
+		var x = 0;
+		eq(x,0);
+		// simple scope
+		{
+			var x = "hello";
+			eq(x,"hello");
+			{
+				var x = "";
+				eq(x,"");
+			}
+			eq(x,"hello");
+		}
+		eq(x,0);
+		// if
+		if( true ) {
+			var x = "hello";
+			eq(x,"hello");
+		}
+		eq(x,0);
+		// for
+		for( x in ["hello"] )
+			eq(x,"hello");
+		eq(x,0);
+		// switch
+		switch( MyEnum.D(MyEnum.A) ) {
+		case D(x):
+			eq(x,MyEnum.A);
+		default:
+			assert();
+		}
+		eq(x,0);
+		// try/catch
+		try {
+			throw "hello";
+		} catch( x : Dynamic ) {
+			eq(x,"hello");
+		}
+		eq(x,0);
+	}
+
+	function testCapture() {
+		// read
+		var funs = new Array();
+		for( i in 0...5 )
+			funs.push(function() return i);
+		for( k in 0...5 )
+			eq(funs[k](),k);
+
+		// write
+		funs = new Array();
+		var sum = 0;
+		for( i in 0...5 ) {
+			var k = 0;
+			funs.push(function() { k++; sum++; return k; });
+		}
+		for( i in 0...5 )
+			eq(funs[i](),1);
+		eq(sum,5);
+
+		// multiple
+		var accesses = new Array();
+		var sum = 0;
+		for( i in 0...5 ) {
+			var j = i;
+			accesses.push({
+				inc : function() { sum += j; j++; return j; },
+				dec : function() { j--; sum -= j; return j; },
+			});
+		}
+		for( i in 0...5 ) {
+			var a = accesses[i];
+			eq( a.inc(), i + 1 );
+			eq( sum, i );
+			eq( a.dec(), i );
+			eq( sum, 0 );
+		}
+	}
+
+	function testSubCapture() {
+		var funs = new Array();
+		for( i in 0...5 )
+			funs.push(function() {
+				var tmp = new Array();
+				for( j in 0...5 )
+					tmp.push(function() return i + j);
+				var sum = 0;
+				for( j in 0...5 )
+					sum += tmp[j]();
+				return sum;
+			});
+		for( i in 0...5 )
+			eq( funs[i](), i * 5 + 10 );
+	}
+
+	function testParallelCapture() {
+		var funs = new Array();
+		for( i in 0...5 ) {
+			if( true ) {
+				var j = i;
+				funs.push(function(k) return j);
+			}
+			if( true )
+				funs.push(function(j) return j);
+		}
+		for( k in 0...5 ) {
+			eq( funs[k*2](0), k );
+			eq( funs[k*2+1](k), k );
+		}
+	}
+
+}

+ 0 - 22
tests/unit/TestMisc.hx

@@ -23,28 +23,6 @@ class TestMisc extends Test {
 		eq( f(), 5 );
 		eq( f(), 5 );
 	}
 	}
 
 
-	function testBlockVars() {
-		var a = new Array();
-		for( i in 0...10 )
-			a.push(function() return i);
-		for( i in 0...10 )
-			eq( a[i](), i );
-	}
-
-	function testScopeVar() {
-		var x = 4;
-		{
-			var x = "hello";
-			eq(x,"hello");
-			switch( MyEnum.C(66,"") ) {
-			case C(x,_):
-				eq(x,66);
-			default:
-			}
-		}
-		eq(x,4);
-	}
-
 	function testMD5() {
 	function testMD5() {
 		eq( haxe.Md5.encode(""), "d41d8cd98f00b204e9800998ecf8427e" );
 		eq( haxe.Md5.encode(""), "d41d8cd98f00b204e9800998ecf8427e" );
 		eq( haxe.Md5.encode("hello"), "5d41402abc4b2a76b9719d911017c592" );
 		eq( haxe.Md5.encode("hello"), "5d41402abc4b2a76b9719d911017c592" );

+ 0 - 1
tests/unit/unit.hxml

@@ -16,7 +16,6 @@
 # JS
 # JS
 -js unit.js
 -js unit.js
 unit.Test
 unit.Test
--debug
 -cp ..
 -cp ..
 
 
 --next
 --next

+ 2 - 1
tests/unit/unit.hxp

@@ -1,7 +1,7 @@
 <haxe selected="0">
 <haxe selected="0">
   <output name="Flash" mode="swf" out="unit8.swf" class="unit.Test" lib="" cmd="http://dev.unit-tests/unit.html" main="True" debug="True">-cp ..</output>
   <output name="Flash" mode="swf" out="unit8.swf" class="unit.Test" lib="" cmd="http://dev.unit-tests/unit.html" main="True" debug="True">-cp ..</output>
   <output name="Flash9" mode="swf9" out="unit9.swf" class="unit.Test" lib="" cmd="" main="True" debug="True">-cp ..</output>
   <output name="Flash9" mode="swf9" out="unit9.swf" class="unit.Test" lib="" cmd="" main="True" debug="True">-cp ..</output>
-  <output name="JS" mode="js" out="unit.js" class="unit.Test" lib="" cmd="" main="False" debug="True">-cp ..</output>
+  <output name="JS" mode="js" out="unit.js" class="unit.Test" lib="" cmd="" main="False" debug="False">-cp ..</output>
   <output name="Neko" mode="neko" out="unit.n" class="unit.Test" lib="" cmd="" main="True" debug="True">-cp ..</output>
   <output name="Neko" mode="neko" out="unit.n" class="unit.Test" lib="" cmd="" main="True" debug="True">-cp ..</output>
   <output name="RemotingServer" mode="neko" out="remoting.n" class="unit.RemotingServer" lib="" cmd="" main="True" debug="False">-cp ..</output>
   <output name="RemotingServer" mode="neko" out="remoting.n" class="unit.RemotingServer" lib="" cmd="" main="True" debug="False">-cp ..</output>
   <files path="/">
   <files path="/">
@@ -14,6 +14,7 @@
     <file path="TestBytes.hx" />
     <file path="TestBytes.hx" />
     <file path="TestInt32.hx" />
     <file path="TestInt32.hx" />
     <file path="TestIO.hx" />
     <file path="TestIO.hx" />
+    <file path="TestLocals.hx" />
     <file path="TestMisc.hx" />
     <file path="TestMisc.hx" />
     <file path="TestReflect.hx" />
     <file path="TestReflect.hx" />
     <file path="TestRemoting.hx" />
     <file path="TestRemoting.hx" />