Browse Source

add Codegen.handle_side_effects and apply it on the AST when compiling to CPP (closes #2217)

Simon Krajewski 12 years ago
parent
commit
8a8802243e
3 changed files with 121 additions and 0 deletions
  1. 99 0
      codegen.ml
  2. 1 0
      main.ml
  3. 21 0
      tests/unit/unitstd/EvaluationOrder.unit.hx

+ 99 - 0
codegen.ml

@@ -825,6 +825,105 @@ let promote_abstract_parameters ctx t = match t with
 	| _ ->
 		()
 
+(*
+	- wraps implicit blocks in TIf, TFor, TWhile, TFunction and TTry with real ones
+*)
+let rec blockify_ast e =
+	match e.eexpr with
+	| TIf(e1,e2,eo) ->
+		{e with eexpr = TIf(blockify_ast e1,mk_block (blockify_ast e2),match eo with None -> None | Some e -> Some (mk_block (blockify_ast e)))}
+	| TFor(v,e1,e2) ->
+		{e with eexpr = TFor(v,blockify_ast e1,mk_block (blockify_ast e2))}
+	| TWhile(e1,e2,flag) ->
+		{e with eexpr = TWhile(blockify_ast e1,mk_block (blockify_ast e2),flag)}
+	| TFunction tf ->
+		{e with eexpr = TFunction {tf with tf_expr = mk_block (blockify_ast tf.tf_expr)}}
+	| TTry(e1,cl) ->
+		{e with eexpr = TTry(blockify_ast e1,List.map (fun (v,e) -> v,mk_block (blockify_ast e)) cl)}
+	| _ ->
+		Type.map_expr blockify_ast e
+
+let handle_side_effects com gen_temp e =
+	let block_el = ref [] in
+	let push e = block_el := e :: !block_el in
+	let declare_temp t eo p =
+		let v = gen_temp t in
+		begin match follow t,eo with
+			| TAbstract({a_path=[],"Void"},_),Some e -> com.warning (s_expr (s_type (print_context())) e) p;
+			| _ -> ()
+		end;
+		let e = mk (TVars [v,eo]) com.basic.tvoid p in
+		push e;
+		mk (TLocal v) t p
+	in
+	let push_block () =
+		let cur = !block_el in
+		block_el := [];
+		fun () ->
+			let added = !block_el in
+			block_el := cur;
+			List.rev added
+	in
+	let rec block f el =
+		let close = push_block() in
+		List.iter (fun e ->
+			push (f e)
+		) el;
+		close()
+	in
+	let rec loop e =
+		match e.eexpr with
+		| TBlock el ->
+			{e with eexpr = TBlock (block loop el)}
+		| TCall(e1,el) ->
+			{e with eexpr = TCall(loop e1,ordered_list el)}
+		| TNew(c,tl,el) ->
+			{e with eexpr = TNew(c,tl,ordered_list el)}
+		| TArrayDecl el ->
+			{e with eexpr = TArrayDecl (ordered_list el)}
+		| TObjectDecl fl ->
+			let el = ordered_list (List.map snd fl) in
+			{e with eexpr = TObjectDecl (List.map2 (fun (n,_) e -> n,e) fl el)}
+		| _ ->
+			Type.map_expr loop e
+	and ordered_list el =
+		let had_side_effect = ref false in
+		let rec no_side_effect e = match e.eexpr with
+			| TNew _ | TCall _ | TArrayDecl _ | TObjectDecl _ | TBinop ((OpAssignOp _ | OpAssign),_,_) | TUnop ((Increment|Decrement),_,_) ->
+				if !had_side_effect then
+					declare_temp e.etype (Some (loop e)) e.epos
+				else begin
+					had_side_effect := true;
+					e
+				end
+			| TConst _ | TLocal _ | TTypeExpr _ | TFunction _
+			| TReturn _ | TBreak | TContinue | TThrow _ | TCast (_,Some _) ->
+				e
+			| TBlock _ ->
+				loop e
+			| _ ->
+				Type.map_expr no_side_effect e
+		in
+		let rec loop2 acc el = match el with
+			| e :: el ->
+				let e = no_side_effect e in
+				if !had_side_effect then
+					(List.map no_side_effect (List.rev el)) @ e :: acc
+				else
+					loop2 (e :: acc) el
+			| [] ->
+				acc
+		in
+		List.map loop (loop2 [] (List.rev el))
+	in
+	let e = blockify_ast e in
+	let e = loop e in
+	match !block_el with
+		| [] ->
+			e
+		| el ->
+			mk (TBlock (List.rev (e :: el))) e.etype e.epos
+
 (*
 	Pushes complex right-hand side expression inwards.
 

+ 1 - 0
main.ml

@@ -1216,6 +1216,7 @@ try
 		com.modules <- modules;
 		let filters = [
 			Codegen.Abstract.handle_abstract_casts tctx;
+			(match com.platform with Cpp -> Codegen.handle_side_effects com (Typecore.gen_local tctx) | _ -> fun e -> e);
 			Codegen.promote_complex_rhs com;
 			if com.foptimize then (fun e -> Optimizer.reduce_expression tctx (Optimizer.inline_constructors tctx e)) else Optimizer.sanitize tctx;
 			Codegen.check_local_vars_init;

+ 21 - 0
tests/unit/unitstd/EvaluationOrder.unit.hx

@@ -0,0 +1,21 @@
+function func(i1:Dynamic, i2:Dynamic, i3:Dynamic) {
+	return '$i1;$i2;$i3';
+}
+
+var i = 0;
+func(i++, i++, i++) == "0;1;2";
+
+var a = [i++, i++, i++];
+a.join(";") == "3;4;5";
+
+var obj = {
+	a: i++,
+	b: i++,
+	c: i++
+}
+
+obj.a = 6;
+obj.b = 7;
+obj.c = 8;
+
+func(i++, [i++, i++].join(";"), i++) == "9;10;11;12";