소스 검색

Merge branch 'match_refactor' into development

Simon Krajewski 12 년 전
부모
커밋
ba9713112f
21개의 변경된 파일733개의 추가작업 그리고 995개의 파일을 삭제
  1. 2 0
      ast.ml
  2. 171 36
      codegen.ml
  3. 14 0
      common.ml
  4. 7 51
      genas3.ml
  5. 29 49
      gencommon.ml
  6. 24 67
      gencpp.ml
  7. 4 3
      gencs.ml
  8. 5 4
      genjava.ml
  9. 7 60
      genjs.ml
  10. 77 56
      genneko.ml
  11. 8 52
      genphp.ml
  12. 6 2
      genswf8.ml
  13. 10 3
      genswf9.ml
  14. 4 2
      interp.ml
  15. 219 375
      matcher.ml
  16. 14 9
      optimizer.ml
  17. 1 1
      tests/unit/Test.hx
  18. 88 34
      type.ml
  19. 2 1
      typecore.ml
  20. 12 4
      typeload.ml
  21. 29 186
      typer.ml

+ 2 - 0
ast.ml

@@ -54,6 +54,7 @@ module Meta = struct
 		| DynamicObject
 		| DynamicObject
 		| Enum
 		| Enum
 		| EnumConstructorParam
 		| EnumConstructorParam
+		| Exhaustive
 		| Expose
 		| Expose
 		| Extern
 		| Extern
 		| FakeEnum
 		| FakeEnum
@@ -84,6 +85,7 @@ module Meta = struct
 		| Meta
 		| Meta
 		| Macro
 		| Macro
 		| MaybeUsed
 		| MaybeUsed
+		| MatchAny
 		| MultiType
 		| MultiType
 		| Native
 		| Native
 		| NativeGen
 		| NativeGen

+ 171 - 36
codegen.ml

@@ -851,18 +851,32 @@ let rec local_usage f e =
 				local_usage f e;
 				local_usage f e;
 			))
 			))
 		) catchs;
 		) 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 (function None -> () | Some v -> f (Declare v)) l);
+	| TPatMatch dt ->
+		List.iter (fun (v,eo) ->
+			f (Declare v);
+			match eo with None -> () | Some e -> local_usage f e
+		) dt.dt_var_init;
+		let rec fdt dt = match dt with
+			| DTBind(bl,dt) ->
+				List.iter (fun ((v,_),e) ->
+					f (Declare v);
+					local_usage f e
+				) bl;
+				fdt dt
+			| DTExpr e -> local_usage f e
+			| DTGuard(e,dt1,dt2) ->
 				local_usage f e;
 				local_usage f e;
-			in
-			f (Block cc)
-		) cases;
-		(match def with None -> () | Some e -> local_usage f e);
+				fdt dt1;
+				(match dt2 with None -> () | Some dt -> fdt dt)
+			| DTSwitch(e,cl) ->
+				local_usage f e;
+				List.iter (fun (e,dt) ->
+					local_usage f e;
+					fdt dt
+				) cl
+			| DTGoto _ -> ()
+		in
+		Array.iter fdt dt.dt_dt_lookup
 	| _ ->
 	| _ ->
 		iter (local_usage f) e
 		iter (local_usage f) e
 
 
@@ -924,7 +938,8 @@ let captured_vars com e =
 					v, e
 					v, e
 			) catchs in
 			) catchs in
 			mk (TTry (wrap used expr,catchs)) e.etype e.epos
 			mk (TTry (wrap used expr,catchs)) e.etype e.epos
-		| TMatch (expr,enum,cases,def) ->
+		(* TODO: find out this does *)
+(* 		| TMatch (expr,enum,cases,def) ->
 			let cases = List.map (fun (il,vars,e) ->
 			let cases = List.map (fun (il,vars,e) ->
 				let pos = e.epos in
 				let pos = e.epos in
 				let e = ref (wrap used e) in
 				let e = ref (wrap used e) in
@@ -943,7 +958,7 @@ let captured_vars com e =
 				il, vars, !e
 				il, vars, !e
 			) cases in
 			) cases in
 			let def = match def with None -> None | Some e -> Some (wrap used e) in
 			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
+			mk (TMatch (wrap used expr,enum,cases,def)) e.etype e.epos *)
 		| TFunction f ->
 		| TFunction f ->
 			(*
 			(*
 				list variables that are marked as used, but also used in that
 				list variables that are marked as used, but also used in that
@@ -1176,17 +1191,29 @@ let rename_local_vars com e =
 				loop e;
 				loop e;
 				old()
 				old()
 			) catchs;
 			) catchs;
-		| TMatch (e,_,cases,def) ->
-			loop e;
-			List.iter (fun (_,vars,e) ->
-				let old = save() in
-				(match vars with
-				| None -> ()
-				| Some l ->	List.iter (function None -> () | Some v -> declare v e.epos) l);
-				loop e;
-				old();
-			) cases;
-			(match def with None -> () | Some e -> loop e);
+		| TPatMatch dt ->
+			let rec fdt dt = match dt with
+				| DTSwitch(e,cl) ->
+					loop e;
+					List.iter (fun (_,dt) ->
+						let old = save() in
+						fdt dt;
+						old();
+					) cl;
+				| DTBind(bl,dt) ->
+					List.iter (fun ((v,p),e) ->
+						declare v e.epos
+					) bl;
+					fdt dt
+				| DTExpr e -> loop e;
+				| DTGuard(e,dt1,dt2) ->
+					loop e;
+					fdt dt1;
+					(match dt2 with None -> () | Some dt -> fdt dt)
+				| DTGoto _ ->
+					()
+			in
+			Array.iter fdt dt.dt_dt_lookup
 		| TTypeExpr t ->
 		| TTypeExpr t ->
 			check t
 			check t
 		| TNew (c,_,_) ->
 		| TNew (c,_,_) ->
@@ -1289,21 +1316,34 @@ let check_local_vars_init e =
 				v
 				v
 			) cases in
 			) cases in
 			(match def with
 			(match def with
+			| None when (match e.eexpr with TMeta((Meta.Exhaustive,_,_),_) | TParenthesis({eexpr = TMeta((Meta.Exhaustive,_,_),_)}) -> true | _ -> false) ->
+				(match cvars with
+				| cv :: cvars ->
+					PMap.iter (fun i b -> if b then vars := PMap.add i b !vars) cv;
+					join vars cvars
+				| [] -> ())
 			| None -> ()
 			| None -> ()
 			| Some e ->
 			| Some e ->
 				loop vars e;
 				loop vars e;
 				join vars cvars)
 				join vars cvars)
-		| TMatch (e,_,cases,def) ->
-			loop vars e;
-			let old = !vars in
-			let cvars = List.map (fun (_,vl,e) ->
-				vars := old;
-				loop vars e;
-				restore vars old [];
-				!vars
-			) cases in
-			(match def with None -> () | Some e -> vars := old; loop vars e);
-			join vars cvars
+		| TPatMatch dt ->
+			let cvars = ref [] in
+			let rec fdt dt = match dt with
+				| DTExpr e ->
+					let old = !vars in
+					loop vars e;
+					restore vars old [];
+					cvars := !vars :: !cvars
+				| DTSwitch(e,cl) ->
+					loop vars e;
+					List.iter (fun (_,dt) -> fdt dt) cl
+				| DTGuard(e,dt1,dt2) ->
+					fdt dt1;
+					(match dt2 with None -> () | Some dt -> fdt dt)
+				| DTBind(_,dt) -> fdt dt
+				| DTGoto _ -> ()
+			in
+			join vars !cvars
 		(* mark all reachable vars as initialized, since we don't exit the block  *)
 		(* mark all reachable vars as initialized, since we don't exit the block  *)
 		| TBreak | TContinue | TReturn None ->
 		| TBreak | TContinue | TReturn None ->
 			vars := PMap.map (fun _ -> true) !vars
 			vars := PMap.map (fun _ -> true) !vars
@@ -1531,6 +1571,101 @@ module Abstract = struct
 	let handle_abstract_casts ctx e =
 	let handle_abstract_casts ctx e =
 		loop ctx e
 		loop ctx e
 end
 end
+
+module PatternMatchConversion = struct
+
+ 	type cctx = {
+		ctx : typer;
+		mutable eval_stack : ((tvar * pos) * texpr) list list;
+		dt_lookup : dt array;
+	}
+
+	let replace_locals stack e =
+		let replace v =
+			let rec loop vl = match vl with
+				| vl :: vll -> (try snd (List.find (fun ((v2,_),st) -> v2 == v) vl) with Not_found -> loop vll)
+				| [] -> raise Not_found
+			in
+			loop stack
+		in
+		let rec loop e = match e.eexpr with
+			| TLocal v ->
+				begin try
+					let e2 = replace v in
+					Type.unify e.etype e2.etype;
+					e2
+				with Not_found -> e end
+			| _ -> Type.map_expr loop e
+		in
+		loop e
+
+	let group_cases cases =
+		let dt_eq dt1 dt2 = match dt1,dt2 with
+			| DTGoto i1, DTGoto i2 when i1 = i2 -> true
+			(* TODO equal bindings *)
+			| _ -> false
+		in
+		match List.rev cases with
+		| [] -> []
+		| [con,dt] -> [[con],dt]
+		| (con,dt) :: cases ->
+			let tmp,ldt,cases = List.fold_left (fun (tmp,ldt,acc) (con,dt) ->
+				if dt_eq dt ldt then
+					(con :: tmp,dt,acc)
+				else
+					([con],dt,(tmp,ldt) :: acc)
+			) ([con],dt,[]) cases in
+			match tmp with
+			| [] -> cases
+			| tmp -> ((tmp,ldt) :: cases)
+
+	let rec convert_dt cctx dt =
+		match dt with
+		| DTBind (bl,dt) ->
+			cctx.eval_stack <- bl :: cctx.eval_stack;
+			let e = convert_dt cctx dt in
+			cctx.eval_stack <- List.tl cctx.eval_stack;
+			e
+		| DTGoto i ->
+			convert_dt cctx (cctx.dt_lookup.(i))
+		| DTExpr e ->
+			replace_locals cctx.eval_stack e
+		| DTGuard(e,dt1,dt2) ->
+			let ethen = convert_dt cctx dt1 in
+			mk (TIf(replace_locals cctx.eval_stack e,ethen,match dt2 with None -> None | Some dt -> Some (convert_dt cctx dt))) ethen.etype (punion e.epos ethen.epos)
+		| DTSwitch(e_st,cl) ->
+			let def = ref None in
+			let cases = List.filter (fun (e,dt) ->
+ 				match e.eexpr with
+ 				| TMeta((Meta.MatchAny,_,_),_) ->
+					def := Some (convert_dt cctx dt);
+					false
+				| _ ->
+					true
+			) cl in
+			let cases = group_cases cases in
+			let cases = List.map (fun (cl,dt) -> cl,convert_dt cctx dt) cases in
+			mk (TSwitch(e_st,cases,!def)) (mk_mono()) e_st.epos
+
+	let to_typed_ast ctx dt p =
+		let first = dt.dt_dt_lookup.(dt.dt_first) in
+		let cctx = {
+			ctx = ctx;
+			dt_lookup = dt.dt_dt_lookup;
+			eval_stack = [];
+		} in
+		let e = convert_dt cctx first in
+		let e = { e with epos = p; etype = dt.dt_type} in
+		if dt.dt_var_init = [] then
+			e
+		else begin
+			mk (TBlock [
+				mk (TVars dt.dt_var_init) t_dynamic e.epos;
+				e;
+			]) dt.dt_type e.epos
+		end
+end
+
 (* -------------------------------------------------------------------------- *)
 (* -------------------------------------------------------------------------- *)
 (* USAGE *)
 (* USAGE *)
 
 
@@ -1854,7 +1989,7 @@ let rec constructor_side_effects e =
 		true
 		true
 	| TField (_,FEnum _) ->
 	| TField (_,FEnum _) ->
 		false
 		false
-	| TUnop _ | TArray _ | TField _ | TCall _ | TNew _ | TFor _ | TWhile _ | TSwitch _ | TMatch _ | TReturn _ | TThrow _ ->
+	| TUnop _ | TArray _ | TField _ | TEnumParameter _ | TCall _ | TNew _ | TFor _ | TWhile _ | TSwitch _ | TPatMatch _ | TReturn _ | TThrow _ ->
 		true
 		true
 	| TBinop _ | TTry _ | TIf _ | TBlock _ | TVars _
 	| TBinop _ | TTry _ | TIf _ | TBlock _ | TVars _
 	| TFunction _ | TArrayDecl _ | TObjectDecl _
 	| TFunction _ | TArrayDecl _ | TObjectDecl _

+ 14 - 0
common.ml

@@ -93,6 +93,8 @@ type platform_config = {
 	pf_add_final_return : bool;
 	pf_add_final_return : bool;
 	(** does the platform natively support overloaded functions *)
 	(** does the platform natively support overloaded functions *)
 	pf_overload : bool;
 	pf_overload : bool;
+	(** does the platform generator handle pattern matching *)
+	pf_pattern_matching : bool;
 }
 }
 
 
 type context = {
 type context = {
@@ -311,6 +313,7 @@ module MetaInfo = struct
 		| DynamicObject -> ":dynamicObject",("Used internally to identify the Dynamic Object implementation",[Platforms [Java;Cs]; UsedOn TClass; Internal])
 		| DynamicObject -> ":dynamicObject",("Used internally to identify the Dynamic Object implementation",[Platforms [Java;Cs]; UsedOn TClass; Internal])
 		| Enum -> ":enum",("Used internally to annotate a class that was generated from an enum",[Platforms [Java;Cs]; UsedOn TClass; Internal])
 		| Enum -> ":enum",("Used internally to annotate a class that was generated from an enum",[Platforms [Java;Cs]; UsedOn TClass; Internal])
 		| EnumConstructorParam -> ":enumConstructorParam",("Used internally to annotate GADT type parameters",[UsedOn TClass; Internal])
 		| EnumConstructorParam -> ":enumConstructorParam",("Used internally to annotate GADT type parameters",[UsedOn TClass; Internal])
+		| Exhaustive -> ":exhaustive",("",[Internal])
 		| Expose -> ":expose",("Makes the class available on the window object",[HasParam "?Name=Class path";UsedOn TClass;Platform Js])
 		| Expose -> ":expose",("Makes the class available on the window object",[HasParam "?Name=Class path";UsedOn TClass;Platform Js])
 		| Extern -> ":extern",("Marks the field as extern so it is not generated",[UsedOn TClassField])
 		| Extern -> ":extern",("Marks the field as extern so it is not generated",[UsedOn TClassField])
 		| FakeEnum -> ":fakeEnum",("Treat enum as collection of values of the specified type",[HasParam "Type name";UsedOn TEnum])
 		| FakeEnum -> ":fakeEnum",("Treat enum as collection of values of the specified type",[HasParam "Type name";UsedOn TEnum])
@@ -341,6 +344,7 @@ module MetaInfo = struct
 		| Meta -> ":meta",("Internally used to mark a class field as being the metadata field",[])
 		| Meta -> ":meta",("Internally used to mark a class field as being the metadata field",[])
 		| Macro -> ":macro",("(deprecated)",[])
 		| Macro -> ":macro",("(deprecated)",[])
 		| MaybeUsed -> ":maybeUsed",("Internally used by DCE to mark fields that might be kept",[Internal])
 		| MaybeUsed -> ":maybeUsed",("Internally used by DCE to mark fields that might be kept",[Internal])
+		| MatchAny -> ":matchAny",("Internally used to mark the default case when pattern matching",[Internal])
 		| MultiType -> ":multiType",("Specifies that an abstract chooses its this-type from its @:to functions",[UsedOn TAbstract])
 		| MultiType -> ":multiType",("Specifies that an abstract chooses its this-type from its @:to functions",[UsedOn TAbstract])
 		| Native -> ":native",("Rewrites the path of a class or enum during generation",[HasParam "Output type path";UsedOnEither [TClass;TEnum]])
 		| Native -> ":native",("Rewrites the path of a class or enum during generation",[HasParam "Output type path";UsedOnEither [TClass;TEnum]])
 		| NativeGen -> ":nativeGen",("Annotates that a type should be treated as if it were an extern definition - platform native",[Platforms [Java;Cs]; UsedOnEither[TClass;TEnum]])
 		| NativeGen -> ":nativeGen",("Annotates that a type should be treated as if it were an extern definition - platform native",[Platforms [Java;Cs]; UsedOnEither[TClass;TEnum]])
@@ -432,6 +436,7 @@ let default_config =
 		pf_pad_nulls = false;
 		pf_pad_nulls = false;
 		pf_add_final_return = false;
 		pf_add_final_return = false;
 		pf_overload = false;
 		pf_overload = false;
+		pf_pattern_matching = false;
 	}
 	}
 
 
 let get_config com =
 let get_config com =
@@ -451,6 +456,7 @@ let get_config com =
 			pf_pad_nulls = false;
 			pf_pad_nulls = false;
 			pf_add_final_return = false;
 			pf_add_final_return = false;
 			pf_overload = false;
 			pf_overload = false;
+			pf_pattern_matching = false;
 		}
 		}
 	| Js ->
 	| Js ->
 		{
 		{
@@ -464,6 +470,7 @@ let get_config com =
 			pf_pad_nulls = false;
 			pf_pad_nulls = false;
 			pf_add_final_return = false;
 			pf_add_final_return = false;
 			pf_overload = false;
 			pf_overload = false;
+			pf_pattern_matching = false;
 		}
 		}
 	| Neko ->
 	| Neko ->
 		{
 		{
@@ -477,6 +484,7 @@ let get_config com =
 			pf_pad_nulls = true;
 			pf_pad_nulls = true;
 			pf_add_final_return = false;
 			pf_add_final_return = false;
 			pf_overload = false;
 			pf_overload = false;
+			pf_pattern_matching = false;
 		}
 		}
 	| Flash when defined Define.As3 ->
 	| Flash when defined Define.As3 ->
 		{
 		{
@@ -490,6 +498,7 @@ let get_config com =
 			pf_pad_nulls = false;
 			pf_pad_nulls = false;
 			pf_add_final_return = true;
 			pf_add_final_return = true;
 			pf_overload = false;
 			pf_overload = false;
+			pf_pattern_matching = false;
 		}
 		}
 	| Flash ->
 	| Flash ->
 		{
 		{
@@ -503,6 +512,7 @@ let get_config com =
 			pf_pad_nulls = false;
 			pf_pad_nulls = false;
 			pf_add_final_return = false;
 			pf_add_final_return = false;
 			pf_overload = false;
 			pf_overload = false;
+			pf_pattern_matching = false;
 		}
 		}
 	| Php ->
 	| Php ->
 		{
 		{
@@ -521,6 +531,7 @@ let get_config com =
 			pf_pad_nulls = true;
 			pf_pad_nulls = true;
 			pf_add_final_return = false;
 			pf_add_final_return = false;
 			pf_overload = false;
 			pf_overload = false;
+			pf_pattern_matching = false;
 		}
 		}
 	| Cpp ->
 	| Cpp ->
 		{
 		{
@@ -534,6 +545,7 @@ let get_config com =
 			pf_pad_nulls = true;
 			pf_pad_nulls = true;
 			pf_add_final_return = true;
 			pf_add_final_return = true;
 			pf_overload = false;
 			pf_overload = false;
+			pf_pattern_matching = false;
 		}
 		}
 	| Cs ->
 	| Cs ->
 		{
 		{
@@ -547,6 +559,7 @@ let get_config com =
 			pf_pad_nulls = true;
 			pf_pad_nulls = true;
 			pf_add_final_return = false;
 			pf_add_final_return = false;
 			pf_overload = true;
 			pf_overload = true;
+			pf_pattern_matching = false;
 		}
 		}
 	| Java ->
 	| Java ->
 		{
 		{
@@ -560,6 +573,7 @@ let get_config com =
 			pf_pad_nulls = true;
 			pf_pad_nulls = true;
 			pf_add_final_return = false;
 			pf_add_final_return = false;
 			pf_overload = true;
 			pf_overload = true;
+			pf_pattern_matching = false;
 		}
 		}
 
 
 let create v args =
 let create v args =

+ 7 - 51
genas3.ml

@@ -276,7 +276,7 @@ let rec type_str ctx t p =
 let rec iter_switch_break in_switch e =
 let rec iter_switch_break in_switch e =
 	match e.eexpr with
 	match e.eexpr with
 	| TFunction _ | TWhile _ | TFor _ -> ()
 	| TFunction _ | TWhile _ | TFor _ -> ()
-	| TSwitch _ | TMatch _ when not in_switch -> iter_switch_break true e
+	| TSwitch _ | TPatMatch _ when not in_switch -> iter_switch_break true e
 	| TBreak when in_switch -> raise Exit
 	| TBreak when in_switch -> raise Exit
 	| _ -> iter (iter_switch_break in_switch) e
 	| _ -> iter (iter_switch_break in_switch) e
 
 
@@ -580,6 +580,9 @@ and gen_expr ctx e =
 		gen_expr ctx e1;
 		gen_expr ctx e1;
 		spr ctx ")";
 		spr ctx ")";
 		gen_field_access ctx e1.etype (field_name s)
 		gen_field_access ctx e1.etype (field_name s)
+	| TEnumParameter (e,i) ->
+		gen_value ctx e;
+		print ctx ".params[%i]" i;
 	| TField (e,s) ->
 	| TField (e,s) ->
    		gen_value ctx e;
    		gen_value ctx e;
 		gen_field_access ctx e.etype (field_name s)
 		gen_field_access ctx e.etype (field_name s)
@@ -723,49 +726,7 @@ and gen_expr ctx e =
 			print ctx "catch( %s : %s )" (s_ident v.v_name) (type_str ctx v.v_type e.epos);
 			print ctx "catch( %s : %s )" (s_ident v.v_name) (type_str ctx v.v_type e.epos);
 			gen_expr ctx e;
 			gen_expr ctx e;
 		) catchs;
 		) catchs;
-	| TMatch (e,_,cases,def) ->
-		print ctx "{";
-		let bend = open_block ctx in
-		newline ctx;
-		let tmp = gen_local ctx "$e" in
-		print ctx "var %s : enum = " tmp;
-		gen_value ctx e;
-		newline ctx;
-		print ctx "switch( %s.index ) {" tmp;
-		List.iter (fun (cl,params,e) ->
-			List.iter (fun c ->
-				newline ctx;
-				print ctx "case %d:" c;
-			) cl;
-			(match params with
-			| None | Some [] -> ()
-			| Some l ->
-				let n = ref (-1) in
-				let l = List.fold_left (fun acc v -> incr n; match v with None -> acc | Some v -> (v,!n) :: acc) [] l in
-				match l with
-				| [] -> ()
-				| l ->
-					newline ctx;
-					spr ctx "var ";
-					concat ctx ", " (fun (v,n) ->
-						print ctx "%s : %s = %s.params[%d]" (s_ident v.v_name) (type_str ctx v.v_type e.epos) tmp n;
-					) l);
-			gen_block ctx e;
-			print ctx "break";
-		) cases;
-		(match def with
-		| None -> ()
-		| Some e ->
-			newline ctx;
-			spr ctx "default:";
-			gen_block ctx e;
-			print ctx "break";
-		);
-		newline ctx;
-		spr ctx "}";
-		bend();
-		newline ctx;
-		spr ctx "}";
+	| TPatMatch dt -> assert false
 	| TSwitch (e,cases,def) ->
 	| TSwitch (e,cases,def) ->
 		spr ctx "switch";
 		spr ctx "switch";
 		gen_value ctx (parent e);
 		gen_value ctx (parent e);
@@ -859,6 +820,7 @@ and gen_value ctx e =
 	| TArray _
 	| TArray _
 	| TBinop _
 	| TBinop _
 	| TField _
 	| TField _
+	| TEnumParameter _
 	| TTypeExpr _
 	| TTypeExpr _
 	| TParenthesis _
 	| TParenthesis _
 	| TMeta _
 	| TMeta _
@@ -927,13 +889,7 @@ and gen_value ctx e =
 			match def with None -> None | Some e -> Some (assign e)
 			match def with None -> None | Some e -> Some (assign e)
 		)) e.etype e.epos);
 		)) e.etype e.epos);
 		v()
 		v()
-	| TMatch (cond,enum,cases,def) ->
-		let v = value true in
-		gen_expr ctx (mk (TMatch (cond,enum,
-			List.map (fun (constr,params,e) -> (constr,params,assign e)) cases,
-			match def with None -> None | Some e -> Some (assign e)
-		)) e.etype e.epos);
-		v()
+	| TPatMatch dt -> assert false
 	| TTry (b,catchs) ->
 	| TTry (b,catchs) ->
 		let v = value true in
 		let v = value true in
 		gen_expr ctx (mk (TTry (block (assign b),
 		gen_expr ctx (mk (TTry (block (assign b),

+ 29 - 49
gencommon.ml

@@ -110,7 +110,7 @@ struct
   let mk_heexpr = function
   let mk_heexpr = function
     | TConst _ -> 0 | TLocal _ -> 1 | TArray _ -> 3 | TBinop _ -> 4 | TField _ -> 5 | TTypeExpr _ -> 7 | TParenthesis _ -> 8 | TObjectDecl _ -> 9
     | TConst _ -> 0 | TLocal _ -> 1 | TArray _ -> 3 | TBinop _ -> 4 | TField _ -> 5 | TTypeExpr _ -> 7 | TParenthesis _ -> 8 | TObjectDecl _ -> 9
     | TArrayDecl _ -> 10 | TCall _ -> 11 | TNew _ -> 12 | TUnop _ -> 13 | TFunction _ -> 14 | TVars _ -> 15 | TBlock _ -> 16 | TFor _ -> 17 | TIf _ -> 18 | TWhile _ -> 19
     | TArrayDecl _ -> 10 | TCall _ -> 11 | TNew _ -> 12 | TUnop _ -> 13 | TFunction _ -> 14 | TVars _ -> 15 | TBlock _ -> 16 | TFor _ -> 17 | TIf _ -> 18 | TWhile _ -> 19
-    | TSwitch _ -> 20 | TMatch _ -> 21 | TTry _ -> 22 | TReturn _ -> 23 | TBreak -> 24 | TContinue -> 25 | TThrow _ -> 26 | TCast _ -> 27 | TMeta _ -> 28
+    | TSwitch _ -> 20 | TPatMatch _ -> 21 | TTry _ -> 22 | TReturn _ -> 23 | TBreak -> 24 | TContinue -> 25 | TThrow _ -> 26 | TCast _ -> 27 | TMeta _ -> 28 | TEnumParameter _ -> 29
 
 
   let mk_heetype = function
   let mk_heetype = function
     | TMono _ -> 0 | TEnum _ -> 1 | TInst _ -> 2 | TType _ -> 3 | TFun _ -> 4
     | TMono _ -> 0 | TEnum _ -> 1 | TInst _ -> 2 | TType _ -> 3 | TFun _ -> 4
@@ -4602,8 +4602,8 @@ struct
         { expr with eexpr = TWhile(fn cond, block, flag) }
         { expr with eexpr = TWhile(fn cond, block, flag) }
       | TSwitch(cond, el_block_l, default) ->
       | TSwitch(cond, el_block_l, default) ->
         { expr with eexpr = TSwitch( fn cond, List.map (fun (el,block) -> (List.map fn el, block)) el_block_l, default ) }
         { expr with eexpr = TSwitch( fn cond, List.map (fun (el,block) -> (List.map fn el, block)) el_block_l, default ) }
-      | TMatch(cond, enum, cases, default) ->
-        { expr with eexpr = TMatch(fn cond, enum, cases, default) }
+(*       | TMatch(cond, enum, cases, default) ->
+        { expr with eexpr = TMatch(fn cond, enum, cases, default) } *)
       | TReturn(eopt) ->
       | TReturn(eopt) ->
         { expr with eexpr = TReturn(Option.map fn eopt) }
         { expr with eexpr = TReturn(Option.map fn eopt) }
       | TThrow (texpr) ->
       | TThrow (texpr) ->
@@ -4655,6 +4655,7 @@ struct
       | TArray _
       | TArray _
       | TBinop _
       | TBinop _
       | TField _
       | TField _
+      | TEnumParameter _
       | TTypeExpr _
       | TTypeExpr _
       | TObjectDecl _
       | TObjectDecl _
       | TArrayDecl _
       | TArrayDecl _
@@ -4669,7 +4670,7 @@ struct
       | TFor _
       | TFor _
       | TWhile _
       | TWhile _
       | TSwitch _
       | TSwitch _
-      | TMatch _
+      | TPatMatch _
       | TTry _
       | TTry _
       | TReturn _
       | TReturn _
       | TBreak
       | TBreak
@@ -4794,8 +4795,8 @@ struct
         { right with eexpr = TBlock(apply_assign_block assign_fun el) }
         { right with eexpr = TBlock(apply_assign_block assign_fun el) }
       | TSwitch (cond, elblock_l, default) ->
       | TSwitch (cond, elblock_l, default) ->
         { right with eexpr = TSwitch(cond, List.map (fun (el,block) -> (el, mk_get_block assign_fun block)) elblock_l, Option.map (mk_get_block assign_fun) default) }
         { right with eexpr = TSwitch(cond, List.map (fun (el,block) -> (el, mk_get_block assign_fun block)) elblock_l, Option.map (mk_get_block assign_fun) default) }
-      | TMatch (cond, ep, il_vlo_e_l, default) ->
-        { right with eexpr = TMatch(cond, ep, List.map (fun (il,vlo,e) -> (il,vlo,mk_get_block assign_fun e)) il_vlo_e_l, Option.map (mk_get_block assign_fun) default) }
+(*       | TMatch (cond, ep, il_vlo_e_l, default) ->
+        { right with eexpr = TMatch(cond, ep, List.map (fun (il,vlo,e) -> (il,vlo,mk_get_block assign_fun e)) il_vlo_e_l, Option.map (mk_get_block assign_fun) default) } *)
       | TTry (block, catches) ->
       | TTry (block, catches) ->
         { right with eexpr = TTry(mk_get_block assign_fun block, List.map (fun (v,block) -> (v,mk_get_block assign_fun block) ) catches) }
         { right with eexpr = TTry(mk_get_block assign_fun block, List.map (fun (v,block) -> (v,mk_get_block assign_fun block) ) catches) }
       | TIf (cond,eif,eelse) ->
       | TIf (cond,eif,eelse) ->
@@ -5102,8 +5103,8 @@ struct
           { e with eexpr = TBlock(block) }
           { e with eexpr = TBlock(block) }
         | TTry (block, catches) ->
         | TTry (block, catches) ->
           { e with eexpr = TTry(traverse (mk_block block), List.map (fun (v,block) -> (v, traverse (mk_block block))) catches) }
           { e with eexpr = TTry(traverse (mk_block block), List.map (fun (v,block) -> (v, traverse (mk_block block))) catches) }
-        | TMatch (cond,ep,il_vol_e_l,default) ->
-          { e with eexpr = TMatch(cond,ep,List.map (fun (il,vol,e) -> (il,vol,traverse (mk_block e))) il_vol_e_l, Option.map (fun e -> traverse (mk_block e)) default) }
+(*         | TMatch (cond,ep,il_vol_e_l,default) ->
+          { e with eexpr = TMatch(cond,ep,List.map (fun (il,vol,e) -> (il,vol,traverse (mk_block e))) il_vol_e_l, Option.map (fun e -> traverse (mk_block e)) default) } *)
         | TSwitch (cond,el_e_l, default) ->
         | TSwitch (cond,el_e_l, default) ->
           { e with eexpr = TSwitch(cond, List.map (fun (el,e) -> (el, traverse (mk_block e))) el_e_l, Option.map (fun e -> traverse (mk_block e)) default) }
           { e with eexpr = TSwitch(cond, List.map (fun (el,e) -> (el, traverse (mk_block e))) el_e_l, Option.map (fun e -> traverse (mk_block e)) default) }
         | TWhile (cond,block,flag) ->
         | TWhile (cond,block,flag) ->
@@ -6009,8 +6010,8 @@ struct
           { e with eexpr = TWhile (handle (run econd) gen.gcon.basic.tbool econd.etype, run (mk_block e1), flag) }
           { e with eexpr = TWhile (handle (run econd) gen.gcon.basic.tbool econd.etype, run (mk_block e1), flag) }
         | TSwitch (cond, el_e_l, edef) ->
         | TSwitch (cond, el_e_l, edef) ->
           { e with eexpr = TSwitch(run cond, List.map (fun (el,e) -> (List.map run el, run (mk_block e))) el_e_l, Option.map (fun e -> run (mk_block e)) edef) }
           { e with eexpr = TSwitch(run cond, List.map (fun (el,e) -> (List.map run el, run (mk_block e))) el_e_l, Option.map (fun e -> run (mk_block e)) edef) }
-        | TMatch (cond, en, il_vl_e_l, edef) ->
-          { e with eexpr = TMatch(run cond, en, List.map (fun (il, vl, e) -> (il, vl, run (mk_block e))) il_vl_e_l, Option.map (fun e -> run (mk_block e)) edef) }
+(*         | TMatch (cond, en, il_vl_e_l, edef) ->
+          { e with eexpr = TMatch(run cond, en, List.map (fun (il, vl, e) -> (il, vl, run (mk_block e))) il_vl_e_l, Option.map (fun e -> run (mk_block e)) edef) } *)
         | TFor (v,cond,e1) ->
         | TFor (v,cond,e1) ->
           { e with eexpr = TFor(v, run cond, run (mk_block e1)) }
           { e with eexpr = TFor(v, run cond, run (mk_block e1)) }
         | TTry (e, ve_l) ->
         | TTry (e, ve_l) ->
@@ -8583,43 +8584,22 @@ struct
     let traverse gen t opt_get_native_enum_tag =
     let traverse gen t opt_get_native_enum_tag =
       let rec run e =
       let rec run e =
         match e.eexpr with
         match e.eexpr with
-          | TMatch(cond,(en,eparams),cases,default) ->
-            let cond = run cond in (* being safe *)
+          | TEnumParameter(f, i) ->
+            let f = run f in
             (* check if en was converted to class *)
             (* check if en was converted to class *)
             (* if it was, switch on tag field and change cond type *)
             (* if it was, switch on tag field and change cond type *)
-            let exprs_before, cond_local, cond = try
+            let f = try
+              let en, eparams = match follow (gen.gfollow#run_f f.etype) with
+                | TEnum(en,p) -> en, p
+                | _ -> raise Not_found
+              in
               let cl = Hashtbl.find t.ec_tbl en.e_path in
               let cl = Hashtbl.find t.ec_tbl en.e_path in
-              let cond = { cond with etype = TInst(cl, eparams) } in
-              let exprs_before, new_cond = ensure_local gen cond in
-              exprs_before, new_cond, get_index gen new_cond cl eparams
+              { f with etype = TInst(cl, eparams) }
             with | Not_found ->
             with | Not_found ->
-              (*
-                if it's not a class, we'll either use get_native_enum_tag or in a last resource,
-                call Type.getEnumIndex
-              *)
-              match opt_get_native_enum_tag with
-                | Some get_native_etag ->
-                  [], cond, get_native_etag cond
-                | None ->
-                  [], cond, { eexpr = TCall(mk_static_field_access_infer gen.gclasses.cl_type "enumIndex" e.epos [], [cond]); etype = gen.gcon.basic.tint; epos = cond.epos }
+              f
             in
             in
-
-            (* for each case, change cases to expr int, and see if there is any var create *)
-            let change_case (il, params, expr) =
-              let expr = run expr in
-              (* if there are, set var with tarray *)
-              let exprs = tmatch_params_to_exprs gen params cond_local in
-              let expr = match expr.eexpr with
-                | TBlock(bl) -> { expr with eexpr = TBlock(exprs @ bl) }
-                | _ -> { expr with eexpr = TBlock ( exprs @ [expr] ) }
-              in
-              (List.map (fun i -> mk_int gen i e.epos) il, expr)
-            in
-
-            let tswitch = { e with eexpr = TSwitch(cond, List.map change_case cases, Option.map run default) } in
-            (match exprs_before with
-              | [] -> tswitch
-              | _ -> { e with eexpr = TBlock(exprs_before @ [tswitch]) })
+            let cond_array = { (mk_field_access gen f "params" f.epos) with etype = gen.gcon.basic.tarray t_empty } in
+            { e with eexpr = TArray(cond_array, mk_int gen i cond_array.epos); }
           | _ -> Type.map_expr run e
           | _ -> Type.map_expr run e
       in
       in
 
 
@@ -9333,7 +9313,7 @@ struct
 
 
           new_e
           new_e
         | TSwitch _
         | TSwitch _
-        | TMatch _ ->
+        | TPatMatch _ ->
           let last_switch = !in_switch in
           let last_switch = !in_switch in
           in_switch := true;
           in_switch := true;
 
 
@@ -9557,9 +9537,9 @@ struct
             (el, handle_case (e, ek))
             (el, handle_case (e, ek))
           ) el_e_l, Some def) } in
           ) el_e_l, Some def) } in
           ret, !k
           ret, !k
-        | TMatch(cond, ep, il_vopt_e_l, None) ->
-          { expr with eexpr = TMatch(cond, ep, List.map (fun (il, vopt, e) -> (il, vopt, handle_case (process_expr e))) il_vopt_e_l, None) }, Normal
-        | TMatch(cond, ep, il_vopt_e_l, Some def) ->
+(*         | TMatch(cond, ep, il_vopt_e_l, None) ->
+          { expr with eexpr = TMatch(cond, ep, List.map (fun (il, vopt, e) -> (il, vopt, handle_case (process_expr e))) il_vopt_e_l, None) }, Normal *)
+(*         | TMatch(cond, ep, il_vopt_e_l, Some def) ->
           let def, k = process_expr def in
           let def, k = process_expr def in
           let def = handle_case (def, k) in
           let def = handle_case (def, k) in
           let k = ref k in
           let k = ref k in
@@ -9568,7 +9548,7 @@ struct
             k := aggregate_kind !k ek;
             k := aggregate_kind !k ek;
             (il, vopt, handle_case (e, ek))
             (il, vopt, handle_case (e, ek))
           ) il_vopt_e_l, Some def) } in
           ) il_vopt_e_l, Some def) } in
-          ret, !k
+          ret, !k *)
         | TTry (e, catches) ->
         | TTry (e, catches) ->
           let e, k = process_expr e in
           let e, k = process_expr e in
           let k = ref k in
           let k = ref k in
@@ -9849,8 +9829,8 @@ struct
           { e with eexpr = TBlock bl }
           { e with eexpr = TBlock bl }
         | TTry (block, catches) ->
         | TTry (block, catches) ->
           { e with eexpr = TTry(traverse (mk_block block), List.map (fun (v,block) -> (v, traverse (mk_block block))) catches) }
           { e with eexpr = TTry(traverse (mk_block block), List.map (fun (v,block) -> (v, traverse (mk_block block))) catches) }
-        | TMatch (cond,ep,il_vol_e_l,default) ->
-          { e with eexpr = TMatch(cond,ep,List.map (fun (il,vol,e) -> (il,vol,traverse (mk_block e))) il_vol_e_l, Option.map (fun e -> traverse (mk_block e)) default) }
+(*         | TMatch (cond,ep,il_vol_e_l,default) ->
+          { e with eexpr = TMatch(cond,ep,List.map (fun (il,vol,e) -> (il,vol,traverse (mk_block e))) il_vol_e_l, Option.map (fun e -> traverse (mk_block e)) default) } *)
         | TSwitch (cond,el_e_l, default) ->
         | TSwitch (cond,el_e_l, default) ->
           { e with eexpr = TSwitch(cond, List.map (fun (el,e) -> (el, traverse (mk_block e))) el_e_l, Option.map (fun e -> traverse (mk_block e)) default) }
           { e with eexpr = TSwitch(cond, List.map (fun (el,e) -> (el, traverse (mk_block e))) el_e_l, Option.map (fun e -> traverse (mk_block e)) default) }
         | TWhile (cond,block,flag) ->
         | TWhile (cond,block,flag) ->

+ 24 - 67
gencpp.ml

@@ -758,6 +758,7 @@ let rec iter_retval f retval e =
 		f false e2;
 		f false e2;
 	| TThrow e
 	| TThrow e
 	| TField (e,_)
 	| TField (e,_)
+	| TEnumParameter (e,_)
 	| TUnop (_,_,e) ->
 	| TUnop (_,_,e) ->
 		f true e
 		f true e
 	| TParenthesis e | TMeta(_,e) ->
 	| TParenthesis e | TMeta(_,e) ->
@@ -790,10 +791,11 @@ let rec iter_retval f retval e =
 		f true e;
 		f true e;
 		List.iter (fun (el,e2) -> List.iter (f true) el; f retval e2) cases;
 		List.iter (fun (el,e2) -> List.iter (f true) el; f retval e2) cases;
 		(match def with None -> () | Some e -> f retval e)
 		(match def with None -> () | Some e -> f retval e)
-	| TMatch (e,_,cases,def) ->
+(* 	| TMatch (e,_,cases,def) ->
 		f true e;
 		f true e;
 		List.iter (fun (_,_,e) -> f false e) cases;
 		List.iter (fun (_,_,e) -> f false e) cases;
-		(match def with None -> () | Some e -> f false e)
+		(match def with None -> () | Some e -> f false e) *)
+	| TPatMatch dt -> assert false
 	| TTry (e,catches) ->
 	| TTry (e,catches) ->
 		f retval e;
 		f retval e;
 		List.iter (fun (_,e) -> f false e) catches
 		List.iter (fun (_,e) -> f false e) catches
@@ -893,7 +895,7 @@ let find_undeclared_variables_ctx ctx undeclared declarations this_suffix allow_
          let name = keyword_remap tvar.v_name in
          let name = keyword_remap tvar.v_name in
 			if  not (Hashtbl.mem declarations name) then
 			if  not (Hashtbl.mem declarations name) then
 				Hashtbl.replace undeclared name (type_string expression.etype)
 				Hashtbl.replace undeclared name (type_string expression.etype)
-		| TMatch (condition, enum, cases, default) ->
+(* 		| TMatch (condition, enum, cases, default) ->
 			find_undeclared_variables undeclared declarations this_suffix allow_this condition;
 			find_undeclared_variables undeclared declarations this_suffix allow_this condition;
 			List.iter (fun (case_ids,params,expression) ->
 			List.iter (fun (case_ids,params,expression) ->
 				let old_decs = Hashtbl.copy declarations in
 				let old_decs = Hashtbl.copy declarations in
@@ -909,7 +911,7 @@ let find_undeclared_variables_ctx ctx undeclared declarations this_suffix allow_
 			(match default with | None -> ()
 			(match default with | None -> ()
 			| Some expr ->
 			| Some expr ->
 				find_undeclared_variables undeclared declarations this_suffix allow_this expr;
 				find_undeclared_variables undeclared declarations this_suffix allow_this expr;
-			);
+			); *)
 		| TFor (tvar, init, loop) ->
 		| TFor (tvar, init, loop) ->
 			let old_decs = Hashtbl.copy declarations in
 			let old_decs = Hashtbl.copy declarations in
 			Hashtbl.add declarations (keyword_remap tvar.v_name) ();
 			Hashtbl.add declarations (keyword_remap tvar.v_name) ();
@@ -941,6 +943,8 @@ let rec is_dynamic_in_cpp ctx expr =
 	else begin
 	else begin
 		let result = (
 		let result = (
 		match expr.eexpr with
 		match expr.eexpr with
+ 		| TEnumParameter( obj, index ) ->
+			true (* TODO? *)
 		| TField( obj, field ) ->
 		| TField( obj, field ) ->
 			let name = field_name field in
 			let name = field_name field in
 			ctx.ctx_dbgout ("/* ?tfield "^name^" */");
 			ctx.ctx_dbgout ("/* ?tfield "^name^" */");
@@ -1246,7 +1250,7 @@ and find_local_functions_and_return_blocks_ctx ctx retval expression =
 			if (retval) then begin
 			if (retval) then begin
 				define_local_return_block_ctx ctx expression (next_anon_function_name ctx) true;
 				define_local_return_block_ctx ctx expression (next_anon_function_name ctx) true;
 			end  (* else we are done *)
 			end  (* else we are done *)
-		| TMatch (_, _, _, _)
+		| TPatMatch (_)
 		| TTry (_, _)
 		| TTry (_, _)
 		| TSwitch (_, _, _) when retval ->
 		| TSwitch (_, _, _) when retval ->
 				define_local_return_block_ctx ctx expression (next_anon_function_name ctx) true;
 				define_local_return_block_ctx ctx expression (next_anon_function_name ctx) true;
@@ -1266,13 +1270,13 @@ and find_local_functions_and_return_blocks_ctx ctx retval expression =
 			let func_name = next_anon_function_name ctx in
 			let func_name = next_anon_function_name ctx in
 			output "\n";
 			output "\n";
 			define_local_function_ctx ctx func_name func
 			define_local_function_ctx ctx func_name func
-		| TField (obj,_) when (is_null obj) -> ( )
+		| TField (obj,_) | TEnumParameter (obj,_) when (is_null obj) -> ( )
 		| TArray (obj,_) when (is_null obj) -> ( )
 		| TArray (obj,_) when (is_null obj) -> ( )
 		| TIf ( _ , _ , _ ) when retval -> (* ? operator style *)
 		| TIf ( _ , _ , _ ) when retval -> (* ? operator style *)
 		   iter_retval find_local_functions_and_return_blocks retval expression
 		   iter_retval find_local_functions_and_return_blocks retval expression
-		| TMatch (_, _, _, _)
+		| TPatMatch (_)
 		| TSwitch (_, _, _) when retval -> ( )
 		| TSwitch (_, _, _) when retval -> ( )
-		| TMatch ( cond , _, _, _)
+		(* | TMatch ( cond , _, _, _) *)
 		| TWhile ( cond , _, _ )
 		| TWhile ( cond , _, _ )
 		| TIf ( cond , _, _ )
 		| TIf ( cond , _, _ )
 		| TSwitch ( cond , _, _) -> iter_retval find_local_functions_and_return_blocks true cond
 		| TSwitch ( cond , _, _) -> iter_retval find_local_functions_and_return_blocks true cond
@@ -1478,7 +1482,7 @@ and gen_expression ctx retval expression =
 		   check_array_cast (Codegen.Abstract.get_underlying_type abs pl)
 		   check_array_cast (Codegen.Abstract.get_underlying_type abs pl)
       | _ -> ()
       | _ -> ()
    in
    in
-	
+
 	let rec gen_tfield field_object field =
 	let rec gen_tfield field_object field =
       let member = (field_name field) in
       let member = (field_name field) in
 		let remap_name = keyword_remap member in
 		let remap_name = keyword_remap member in
@@ -1577,7 +1581,7 @@ and gen_expression ctx retval expression =
       output ("(" ^ !arg_string ^ ");\n");
       output ("(" ^ !arg_string ^ ");\n");
 	| TCall (func, arg_list) ->
 	| TCall (func, arg_list) ->
 		let rec is_variable e = match e.eexpr with
 		let rec is_variable e = match e.eexpr with
-		| TField _ -> false
+		| TField _ | TEnumParameter _ -> false
 		| TLocal { v_name = "__global__" } -> false
 		| TLocal { v_name = "__global__" } -> false
 		| TParenthesis p | TMeta(_,p) -> is_variable p
 		| TParenthesis p | TMeta(_,p) -> is_variable p
 		| TCast (e,None) -> is_variable e
 		| TCast (e,None) -> is_variable e
@@ -1732,8 +1736,12 @@ and gen_expression ctx retval expression =
 		end
 		end
 	(* Get precidence matching haxe ? *)
 	(* Get precidence matching haxe ? *)
 	| TBinop (op,expr1,expr2) -> gen_bin_op op expr1 expr2
 	| TBinop (op,expr1,expr2) -> gen_bin_op op expr1 expr2
-	| TField (expr,name) when (is_null expr) -> output "Dynamic()"
-
+	| TField (expr,_) | TEnumParameter (expr,_) when (is_null expr) -> output "Dynamic()"
+	| TEnumParameter (expr,i) ->
+		let enum = match follow expr.etype with TEnum(enum,_) -> enum | _ -> assert false in
+		output (  "(::" ^ (join_class_path_remap enum.e_path "::") ^ "(");
+		gen_expression ctx true expr;
+		output ( "))->__Param(" ^ (string_of_int i) ^ ")")
 	| TField (field_object,field) ->
 	| TField (field_object,field) ->
 		gen_tfield field_object field
 		gen_tfield field_object field
 
 
@@ -1879,8 +1887,9 @@ and gen_expression ctx retval expression =
 	(* These have already been defined in find_local_return_blocks ... *)
 	(* These have already been defined in find_local_return_blocks ... *)
 	| TTry (_,_)
 	| TTry (_,_)
 	| TSwitch (_,_,_)
 	| TSwitch (_,_,_)
-	| TMatch (_, _, _, _) when (retval && (not return_from_internal_node) )->
+	| TPatMatch (_) when (retval && (not return_from_internal_node) )->
       gen_local_block_call()
       gen_local_block_call()
+    | TPatMatch dt -> assert false
 	| TSwitch (condition,cases,optional_default)  ->
 	| TSwitch (condition,cases,optional_default)  ->
 		let switch_on_int_constants = (only_int_cases cases) && (not (contains_break expression)) in
 		let switch_on_int_constants = (only_int_cases cases) && (not (contains_break expression)) in
 		if (switch_on_int_constants) then begin
 		if (switch_on_int_constants) then begin
@@ -1933,58 +1942,6 @@ and gen_expression ctx retval expression =
 				output ";\n";
 				output ";\n";
 			);
 			);
 		end
 		end
-	| TMatch (condition, enum, cases, default) ->
-		let tmp_var = get_switch_var ctx in
-		writer#begin_block;
-		output_i (  "::" ^ (join_class_path_remap (fst enum).e_path "::") ^ " " ^ tmp_var ^ " = " );
-		gen_expression ctx true condition;
-		output ";\n";
-
-		let use_if_statements = contains_break expression in
-		let dump_condition = if (use_if_statements) then begin
-			let tmp_name = get_switch_var ctx in
-			output_i ( "int " ^ tmp_name ^ " = (" ^ tmp_var ^ ")->GetIndex();" );
-			let elif = ref "if" in
-			( fun case_ids -> output (!elif ^ " (" ); elif := "else if";
-					output (String.concat "||"
-					(List.map (fun id -> (string_of_int id) ^ "==" ^ tmp_name ) case_ids ) );
-				output ") " )
-		end else begin
-			output_i ("switch((" ^ tmp_var ^ ")->GetIndex())");
-			( fun case_ids ->
-			List.iter (fun id -> output ("case " ^ (string_of_int id) ^ ": ") ) case_ids;
-			)
-		end in
-		writer#begin_block;
-		List.iter (fun (case_ids,params,expression) ->
-			output_i "";
-			dump_condition case_ids;
-			let has_params = match params with | Some _ -> true | _ -> false in
-			if (has_params) then begin
-				writer#begin_block;
-				List.iter (fun (name,vtype,id) -> output_i
-				((type_string vtype) ^ " " ^ (keyword_remap name) ^
-					" = " ^ tmp_var ^ "->__Param(" ^ (string_of_int id) ^ ");\n"))
-						(tmatch_params_to_args params);
-			end;
-			ctx.ctx_return_from_block <- return_from_internal_node;
-			gen_expression ctx false (to_block expression);
-			if (has_params) then writer#end_block;
-			if (not use_if_statements) then output_i ";break;\n";
-		) cases;
-		(match default with
-		| None -> ()
-		|  Some e ->
-			if (use_if_statements) then
-				output_i "else "
-			else
-				output_i "default: ";
-			ctx.ctx_return_from_block <- return_from_internal_node;
-			gen_expression ctx false (to_block e);
-		);
-		writer#end_block;
-		writer#end_block;
-
 	| TTry (expression, catch_list) ->
 	| TTry (expression, catch_list) ->
 		output "try";
 		output "try";
 		(* Move this "inside" the try call ... *)
 		(* Move this "inside" the try call ... *)
@@ -2357,12 +2314,12 @@ let find_referenced_types ctx obj super_deps constructor_deps header_only for_de
 				| TTry (e,catches) ->
 				| TTry (e,catches) ->
 					List.iter (fun (v,_) -> visit_type v.v_type) catches
 					List.iter (fun (v,_) -> visit_type v.v_type) catches
 				(* Must visit the enum param types, Type.iter will visit the rest ... *)
 				(* Must visit the enum param types, Type.iter will visit the rest ... *)
-				| TMatch (_,enum,cases,_) ->
+(* 				| TMatch (_,enum,cases,_) ->
 					add_type (fst enum).e_path;
 					add_type (fst enum).e_path;
 					List.iter (fun (case_ids,params,expression) ->
 					List.iter (fun (case_ids,params,expression) ->
 						(match params with
 						(match params with
 						| None -> ()
 						| None -> ()
-						| Some l -> List.iter (function None -> () | Some v -> visit_type v.v_type) l  ) ) cases;
+						| Some l -> List.iter (function None -> () | Some v -> visit_type v.v_type) l  ) ) cases; *)
 				(* Must visit type too, Type.iter will visit the expressions ... *)
 				(* Must visit type too, Type.iter will visit the expressions ... *)
             | TNew  (klass,params,_) -> begin
             | TNew  (klass,params,_) -> begin
                visit_type (TInst (klass,params));
                visit_type (TInst (klass,params));

+ 4 - 3
gencs.ml

@@ -850,7 +850,7 @@ let configure gen =
 
 
   let has_semicolon e =
   let has_semicolon e =
     match e.eexpr with
     match e.eexpr with
-      | TBlock _ | TFor _ | TSwitch _ | TMatch _ | TTry _ | TIf _ -> false
+      | TBlock _ | TFor _ | TSwitch _ | TPatMatch _ | TTry _ | TIf _ -> false
       | TWhile (_,_,flag) when flag = Ast.NormalWhile -> false
       | TWhile (_,_,flag) when flag = Ast.NormalWhile -> false
       | _ -> true
       | _ -> true
   in
   in
@@ -993,7 +993,7 @@ let configure gen =
         | TParenthesis e ->
         | TParenthesis e ->
           write w "("; expr_s w e; write w ")"
           write w "("; expr_s w e; write w ")"
         | TMeta (_,e) ->
         | TMeta (_,e) ->
-            expr_s w e 
+            expr_s w e
         | TArrayDecl el ->
         | TArrayDecl el ->
           print w "new %s" (t_s e.etype);
           print w "new %s" (t_s e.etype);
           write w "{";
           write w "{";
@@ -1263,7 +1263,8 @@ let configure gen =
           if !strict_mode then assert false
           if !strict_mode then assert false
         | TObjectDecl _ -> write w "[ obj decl not supported ]"; if !strict_mode then assert false
         | TObjectDecl _ -> write w "[ obj decl not supported ]"; if !strict_mode then assert false
         | TFunction _ -> write w "[ func decl not supported ]"; if !strict_mode then assert false
         | TFunction _ -> write w "[ func decl not supported ]"; if !strict_mode then assert false
-        | TMatch _ -> write w "[ match not supported ]"; if !strict_mode then assert false
+        | TPatMatch _ -> write w "[ match not supported ]"; if !strict_mode then assert false
+        | TEnumParameter _ -> write w "[ enum parameter not supported ]"; if !strict_mode then assert false
     )
     )
     and do_call w e el =
     and do_call w e el =
       let params, el = extract_tparams [] el in
       let params, el = extract_tparams [] el in

+ 5 - 4
genjava.ml

@@ -288,8 +288,8 @@ struct
       | TBlock bl -> is_final_return_block is_switch bl
       | TBlock bl -> is_final_return_block is_switch bl
       | TSwitch (_, el_e_l, edef) ->
       | TSwitch (_, el_e_l, edef) ->
         List.for_all (fun (_,e) -> is_final_return_expr e) el_e_l && Option.map_default is_final_return_expr false edef
         List.for_all (fun (_,e) -> is_final_return_expr e) el_e_l && Option.map_default is_final_return_expr false edef
-      | TMatch (_, _, il_vl_e_l, edef) ->
-        List.for_all (fun (_,_,e) -> is_final_return_expr e)il_vl_e_l && Option.map_default is_final_return_expr false edef
+(*       | TMatch (_, _, il_vl_e_l, edef) ->
+        List.for_all (fun (_,_,e) -> is_final_return_expr e)il_vl_e_l && Option.map_default is_final_return_expr false edef *)
       | TIf (_,eif, Some eelse) ->
       | TIf (_,eif, Some eelse) ->
         is_final_return_expr eif && is_final_return_expr eelse
         is_final_return_expr eif && is_final_return_expr eelse
       | TFor (_,_,e) ->
       | TFor (_,_,e) ->
@@ -1012,7 +1012,7 @@ let configure gen =
     match e.eexpr with
     match e.eexpr with
       | TLocal { v_name = "__fallback__" }
       | TLocal { v_name = "__fallback__" }
       | TCall ({ eexpr = TLocal( { v_name = "__label__" } ) }, [ { eexpr = TConst(TInt _) } ] ) -> false
       | TCall ({ eexpr = TLocal( { v_name = "__label__" } ) }, [ { eexpr = TConst(TInt _) } ] ) -> false
-      | TBlock _ | TFor _ | TSwitch _ | TMatch _ | TTry _ | TIf _ -> false
+      | TBlock _ | TFor _ | TSwitch _ | TPatMatch _ | TTry _ | TIf _ -> false
       | TWhile (_,_,flag) when flag = Ast.NormalWhile -> false
       | TWhile (_,_,flag) when flag = Ast.NormalWhile -> false
       | _ -> true
       | _ -> true
   in
   in
@@ -1390,7 +1390,8 @@ let configure gen =
           if !strict_mode then assert false
           if !strict_mode then assert false
         | TObjectDecl _ -> write w "[ obj decl not supported ]"; if !strict_mode then assert false
         | TObjectDecl _ -> write w "[ obj decl not supported ]"; if !strict_mode then assert false
         | TFunction _ -> write w "[ func decl not supported ]"; if !strict_mode then assert false
         | TFunction _ -> write w "[ func decl not supported ]"; if !strict_mode then assert false
-        | TMatch _ -> write w "[ match not supported ]"; if !strict_mode then assert false
+        | TPatMatch _ -> write w "[ match not supported ]"; if !strict_mode then assert false
+        | TEnumParameter _ -> write w "[ enum parameter not supported ]"; if !strict_mode then assert false
     in
     in
     expr_s w e
     expr_s w e
   in
   in

+ 7 - 60
genjs.ml

@@ -260,7 +260,7 @@ let rec has_return e =
 let rec iter_switch_break in_switch e =
 let rec iter_switch_break in_switch e =
 	match e.eexpr with
 	match e.eexpr with
 	| TFunction _ | TWhile _ | TFor _ -> ()
 	| TFunction _ | TWhile _ | TFor _ -> ()
-	| TSwitch _ | TMatch _ when not in_switch -> iter_switch_break true e
+	| TSwitch _ | TPatMatch _ when not in_switch -> iter_switch_break true e
 	| TBreak when in_switch -> raise Exit
 	| TBreak when in_switch -> raise Exit
 	| _ -> iter (iter_switch_break in_switch) e
 	| _ -> iter (iter_switch_break in_switch) e
 
 
@@ -449,6 +449,9 @@ and gen_expr ctx e =
 			print ctx "($_=";
 			print ctx "($_=";
 			gen_value ctx x;
 			gen_value ctx x;
 			print ctx ",$bind($_,$_%s))" (field f.cf_name))
 			print ctx ",$bind($_,$_%s))" (field f.cf_name))
+	| TEnumParameter (x,i) ->
+		gen_value ctx x;
+		print ctx "[%i]" (i + 2)
 	| TField (x,f) ->
 	| TField (x,f) ->
 		gen_value ctx x;
 		gen_value ctx x;
 		let name = field_name f in
 		let name = field_name f in
@@ -638,58 +641,7 @@ and gen_expr ctx e =
 		bend();
 		bend();
 		newline ctx;
 		newline ctx;
 		spr ctx "}";
 		spr ctx "}";
-	| TMatch (e,(estruct,_),cases,def) ->
-		let evar = (if List.for_all (fun (_,pl,_) -> pl = None) cases then begin
-			spr ctx "switch( ";
-			gen_value ctx (if Optimizer.need_parent e then Codegen.mk_parent e else e);
-			spr ctx "[1] ) {";
-			"???"
-		end else begin
-			let v = (match e.eexpr with
-				| TLocal v -> v.v_name
-				| _ ->
-					spr ctx "var $e = ";
-					gen_value ctx e;
-					newline ctx;
-					"$e"
-			) in
-			print ctx "switch( %s[1] ) {" v;
-			v
-		end) in
-		List.iter (fun (cl,params,e) ->
-			List.iter (fun c ->
-				newline ctx;
-				print ctx "case %d:" c;
-			) cl;
-			let bend = open_block ctx in
-			(match params with
-			| None -> ()
-			| Some l ->
-				let n = ref 1 in
-				let l = List.fold_left (fun acc v -> incr n; match v with None -> acc | Some v -> (v.v_name,!n) :: acc) [] l in
-				newline ctx;
-				spr ctx "var ";
-				concat ctx ", " (fun (v,n) ->
-					print ctx "%s = %s[%d]" (ident v) evar n;
-				) l);
-			gen_block ctx e;
-			if not (has_return e) then begin
-				newline ctx;
-				print ctx "break";
-			end;
-			bend();
-		) cases;
-		(match def with
-		| None -> ()
-		| Some e ->
-			newline ctx;
-			spr ctx "default:";
-			let bend = open_block ctx in
-			gen_block ctx e;
-			bend();
-		);
-		newline ctx;
-		spr ctx "}"
+	| TPatMatch dt -> assert false
 	| TSwitch (e,cases,def) ->
 	| TSwitch (e,cases,def) ->
 		spr ctx "switch";
 		spr ctx "switch";
 		gen_value ctx e;
 		gen_value ctx e;
@@ -786,6 +738,7 @@ and gen_value ctx e =
 	| TArray _
 	| TArray _
 	| TBinop _
 	| TBinop _
 	| TField _
 	| TField _
+	| TEnumParameter _
 	| TTypeExpr _
 	| TTypeExpr _
 	| TParenthesis _
 	| TParenthesis _
 	| TMeta _
 	| TMeta _
@@ -854,13 +807,7 @@ and gen_value ctx e =
 			match def with None -> None | Some e -> Some (assign e)
 			match def with None -> None | Some e -> Some (assign e)
 		)) e.etype e.epos);
 		)) e.etype e.epos);
 		v()
 		v()
-	| TMatch (cond,enum,cases,def) ->
-		let v = value() in
-		gen_expr ctx (mk (TMatch (cond,enum,
-			List.map (fun (constr,params,e) -> (constr,params,assign e)) cases,
-			match def with None -> None | Some e -> Some (assign e)
-		)) e.etype e.epos);
-		v()
+	| TPatMatch dt -> assert false
 	| TTry (b,catchs) ->
 	| TTry (b,catchs) ->
 		let v = value() in
 		let v = value() in
 		let block e = mk (TBlock [e]) e.etype e.epos in
 		let block e = mk (TBlock [e]) e.etype e.epos in

+ 77 - 56
genneko.ml

@@ -35,6 +35,7 @@ type context = {
 	mutable curclass : string;
 	mutable curclass : string;
 	mutable curmethod : string;
 	mutable curmethod : string;
 	mutable inits : (tclass * texpr) list;
 	mutable inits : (tclass * texpr) list;
+	mutable label_count : int;
 }
 }
 
 
 let files = Hashtbl.create 0
 let files = Hashtbl.create 0
@@ -242,6 +243,8 @@ and gen_expr ctx e =
 					call p (ident p ("@closure" ^ string_of_int n)) [tmp;ident p "@fun"]
 					call p (ident p ("@closure" ^ string_of_int n)) [tmp;ident p "@fun"]
 			] , p
 			] , p
 		| _ -> assert false)
 		| _ -> assert false)
+	| TEnumParameter (e,i) ->
+		EArray (field p (gen_expr ctx e) "args",int p i),p
 	| TField (e,f) ->
 	| TField (e,f) ->
 		field p (gen_expr ctx e) (field_name f)
 		field p (gen_expr ctx e) (field_name f)
 	| TTypeExpr t ->
 	| TTypeExpr t ->
@@ -361,64 +364,81 @@ and gen_expr ctx e =
 		gen_expr ctx e
 		gen_expr ctx e
 	| TCast (e1,Some t) ->
 	| TCast (e1,Some t) ->
 		gen_expr ctx (Codegen.default_cast ~vtmp:"@tmp" ctx.com e1 t e.etype e.epos)
 		gen_expr ctx (Codegen.default_cast ~vtmp:"@tmp" ctx.com e1 t e.etype e.epos)
-	| TMatch (e,_,cases,eo) ->
-		let p = pos ctx e.epos in
-		let etmp = (EVars ["@tmp",Some (gen_expr ctx e)],p) in
-		let eindex = field p (ident p "@tmp") "index" in
-		let gen_params params e =
-			match params with
-			| None ->
-				gen_expr ctx e
-			| Some el ->
-				let count = ref (-1) in
-				let vars = List.fold_left (fun acc v ->
-					incr count;
-					match v with
-					| None ->
-						acc
-					| Some v ->
-						let e = (EArray (ident p "@tmp",int p (!count)),p) in
-						let e = (if v.v_capture then call p (builtin p "array") [e] else e) in
-						(v.v_name , Some e) :: acc
-				) [] el in
+ 	| TPatMatch dt ->
+		let num_labels = Array.length dt.dt_dt_lookup in
+		let lc = ctx.label_count in
+		ctx.label_count <- ctx.label_count + num_labels + 1;
+		let get_label i ="label_" ^ (string_of_int (lc + i)) in
+		let goto i = call p (builtin p "goto") [ident p (get_label i)] in
+		let state = Hashtbl.create 0 in
+		let v_name v = "v" ^ (string_of_int v.v_id) in
+		let get_locals e =
+			let locals = Hashtbl.create 0 in
+			let rec loop e = match e.eexpr with
+				| TLocal v -> Hashtbl.replace locals v true
+				| _ -> Type.iter loop e
+			in
+			loop e;
+			Hashtbl.fold (fun v _ l -> if Hashtbl.mem locals v then (v.v_name, Some (field p (ident p "@state") (v_name v))) :: l else l) state []
+		in
+		let rec loop d = match d with
+			| DTGoto i ->
+				goto i
+			| DTBind (bl,dt) ->
+				let block = List.map (fun ((v,_),est) ->
+					let est = gen_expr ctx est in
+					let field = field p (ident p "@state") (v_name v) in
+					Hashtbl.replace state v field;
+					(EBinop ("=",field,est),p)
+				) bl in
+				EBlock (block @ [loop dt]),p
+			| DTExpr e ->
+				let block = [
+					(EBinop ("=",ident p "@ret",gen_expr ctx e),p);
+					goto num_labels;
+				] in
+				(match get_locals e with [] -> EBlock block,p | el -> EBlock ((EVars(el),p) :: block),p)
+			| DTGuard (e,dt1,dt2) ->
+				let eg = match dt2 with
+ 					| None -> (EIf (gen_expr ctx e,loop dt1,None),p)
+					| Some dt -> (EIf (gen_expr ctx e,loop dt1,Some (loop dt)),p)
+				in
+				(match get_locals e with [] -> eg | el -> EBlock [(EVars(el),p);eg],p)
+			| DTSwitch (e,cl) ->
 				let e = gen_expr ctx e in
 				let e = gen_expr ctx e in
-				(EBlock [
-					(EVars ["@tmp",Some (field p (ident p "@tmp") "args")],p);
-					(match vars with [] -> null p | _ -> EVars vars,p);
-					e
-				],p)
+				let def = ref None in
+				let cases = ExtList.List.filter_map (fun (e,dt) ->
+					match e.eexpr with
+	 				| TMeta((Meta.MatchAny,_,_),_) ->
+						def := Some (loop dt);
+						None
+					| _ ->
+						Some (gen_expr ctx e,loop dt)
+				) cl in
+				EBlock [
+					(ESwitch (e,cases,!def),p);
+					goto num_labels;
+				],p
 		in
 		in
-		(try
-		  (EBlock [
-			etmp;
-			(ESwitch (
-				eindex,
-				List.map (fun (cl,params,e2) ->
-					let cond = match cl with
-						| [s] -> int p s
-						| _ -> raise Exit
-					in
-					cond , gen_params params e2
-				) cases,
-				(match eo with None -> None | Some e -> Some (gen_expr ctx e))
-			),p)
-		  ],p)
-		with
-			Exit ->
-				(EBlock [
-					etmp;
-					(EVars ["@index",Some eindex],p);
-					List.fold_left (fun acc (cl,params,e2) ->
-						let cond = (match cl with
-							| [] -> assert false
-							| c :: l ->
-								let eq c = (EBinop ("==",ident p "@index",int p c),p) in
-								List.fold_left (fun acc c -> (EBinop ("||",acc,eq c),p)) (eq c) l
-						) in
-						EIf (cond,gen_params params e2,Some acc),p
-					) (match eo with None -> null p | Some e -> (gen_expr ctx e)) (List.rev cases)
-				],p)
-		)
+		let acc = DynArray.create () in
+		for i = num_labels -1 downto 0 do
+			let e = loop dt.dt_dt_lookup.(i) in
+			DynArray.add acc (ELabel (get_label i),p);
+			DynArray.add acc e;
+		done;
+		DynArray.add acc (ELabel (get_label num_labels),p);
+		DynArray.add acc (ident p "@ret");
+		let el = DynArray.to_list acc in
+		let var_init = List.fold_left (fun acc (v,eo) -> (v.v_name,(match eo with None -> None | Some e -> Some (gen_expr ctx e))) :: acc) [] dt.dt_var_init in
+		let state_init = Hashtbl.fold (fun v _ l -> (v_name v,null p) :: l) state [] in
+		let init = match var_init,state_init with
+			| [], [] -> []
+			| el, [] -> el
+			| [], vl -> ["@state",Some (EObject vl,p)]
+			| el, vl -> ("@state",Some (EObject vl,p)) :: el
+		in
+		let el = match init with [] -> (goto dt.dt_first) :: el | _ -> (EVars init,p) :: (goto dt.dt_first) :: el in
+		EBlock el,p
 	| TSwitch (e,cases,eo) ->
 	| TSwitch (e,cases,eo) ->
 		let e = gen_expr ctx e in
 		let e = gen_expr ctx e in
 		let eo = (match eo with None -> None | Some e -> Some (gen_expr ctx e)) in
 		let eo = (match eo with None -> None | Some e -> Some (gen_expr ctx e)) in
@@ -765,6 +785,7 @@ let new_context com ver macros =
 		curclass = "$boot";
 		curclass = "$boot";
 		curmethod = "$init";
 		curmethod = "$init";
 		inits = [];
 		inits = [];
+		label_count = 0;
 	}
 	}
 
 
 let header() =
 let header() =

+ 8 - 52
genphp.ml

@@ -1226,6 +1226,9 @@ and gen_expr ctx e =
 			print ctx " %s " (Ast.s_binop op);
 			print ctx " %s " (Ast.s_binop op);
 			gen_value_op ctx e2;
 			gen_value_op ctx e2;
 		));
 		));
+	| TEnumParameter(e1,i) ->
+		gen_value ctx e1;
+		print ctx "->params[%d]" i;
 	| TField (e1,s) ->
 	| TField (e1,s) ->
 		gen_tfield ctx e e1 (field_name s)
 		gen_tfield ctx e e1 (field_name s)
 	| TTypeExpr t ->
 	| TTypeExpr t ->
@@ -1300,7 +1303,7 @@ and gen_expr ctx e =
 				| TThrow _
 				| TThrow _
 				| TWhile _
 				| TWhile _
 				| TFor _
 				| TFor _
-				| TMatch _
+				| TPatMatch _
 				| TTry _
 				| TTry _
 				| TBreak
 				| TBreak
 				| TBlock _ ->
 				| TBlock _ ->
@@ -1314,7 +1317,7 @@ and gen_expr ctx e =
 					| TThrow _
 					| TThrow _
 					| TWhile _
 					| TWhile _
 					| TFor _
 					| TFor _
-					| TMatch _
+					| TPatMatch _
 					| TTry _
 					| TTry _
 					| TBlock _ -> ()
 					| TBlock _ -> ()
 					| _ ->
 					| _ ->
@@ -1582,55 +1585,7 @@ and gen_expr ctx e =
 		bend();
 		bend();
 		newline ctx;
 		newline ctx;
 		spr ctx "}"
 		spr ctx "}"
-	| TMatch (e,_,cases,def) ->
-		let b = save_locals ctx in
-		let tmp = define_local ctx "__hx__t" in
-		print ctx "$%s = " tmp;
-		gen_value ctx e;
-		newline ctx;
-		print ctx "switch($%s->index) {" tmp;
-		let old_loop = ctx.in_loop in
-		ctx.in_loop <- false;
-		ctx.nested_loops <- ctx.nested_loops + 1;
-		newline ctx;
-		List.iter (fun (cl,params,e) ->
-			List.iter (fun c ->
-				print ctx "case %d:" c;
-				newline ctx;
-			) cl;
-			let b = save_locals ctx in
-			(match params with
-			| None | Some [] -> ()
-			| Some l ->
-				let n = ref (-1) in
-				let l = List.fold_left (fun acc v -> incr n; match v with None -> acc | Some v -> (v.v_name,v.v_type,!n) :: acc) [] l in
-				match l with
-				| [] -> ()
-				| l ->
-					concat ctx "; " (fun (v,t,n) ->
-						let v = define_local ctx v in
-						print ctx "$%s = $%s->params[%d]" v tmp n;
-					) l;
-					newline ctx);
-			restore_in_block ctx in_block;
-			gen_expr ctx (mk_block e);
-			print ctx "break";
-			newline ctx;
-			b()
-		) cases;
-		(match def with
-		| None -> ()
-		| Some e ->
-			spr ctx "default:";
-			restore_in_block ctx in_block;
-			gen_expr ctx (mk_block e);
-			print ctx "break";
-			newline ctx;
-		);
-		ctx.nested_loops <- ctx.nested_loops - 1;
-		ctx.in_loop <- old_loop;
-		spr ctx "}";
-		b()
+	| TPatMatch dt -> assert false
 	| TSwitch (e,cases,def) ->
 	| TSwitch (e,cases,def) ->
 		let old_loop = ctx.in_loop in
 		let old_loop = ctx.in_loop in
 		ctx.in_loop <- false;
 		ctx.in_loop <- false;
@@ -1767,6 +1722,7 @@ and gen_value ctx e =
 	| TLocal _
 	| TLocal _
 	| TArray _
 	| TArray _
 	| TBinop _
 	| TBinop _
+	| TEnumParameter _
 	| TField _
 	| TField _
 	| TParenthesis _
 	| TParenthesis _
 	| TMeta _
 	| TMeta _
@@ -1819,7 +1775,7 @@ and gen_value ctx e =
 	| TThrow _
 	| TThrow _
 	| TSwitch _
 	| TSwitch _
 	| TFor _
 	| TFor _
-	| TMatch _
+	| TPatMatch _
 	| TIf _
 	| TIf _
 	| TTry _ ->
 	| TTry _ ->
 		inline_block ctx e
 		inline_block ctx e

+ 6 - 2
genswf8.ml

@@ -588,6 +588,10 @@ let rec gen_access ?(read_write=false) ctx forcall e =
 		if read_write then assert false;
 		if read_write then assert false;
 		push ctx [VStr (f,is_protected ctx e.etype f)];
 		push ctx [VStr (f,is_protected ctx e.etype f)];
 		VarClosure
 		VarClosure
+	| TEnumParameter(e,i) ->
+		gen_expr ctx true e;
+		push ctx [VInt i];
+		VarObj
 	| TField (e2,f) ->
 	| TField (e2,f) ->
 		gen_expr ctx true e2;
 		gen_expr ctx true e2;
 		if read_write then write ctx ADup;
 		if read_write then write ctx ADup;
@@ -970,6 +974,7 @@ and gen_expr_2 ctx retval e =
 	match e.eexpr with
 	match e.eexpr with
 	| TConst TSuper
 	| TConst TSuper
 	| TConst TThis
 	| TConst TThis
+	| TEnumParameter _
 	| TField _
 	| TField _
 	| TArray _
 	| TArray _
 	| TLocal _
 	| TLocal _
@@ -1164,8 +1169,7 @@ and gen_expr_2 ctx retval e =
 		gen_expr ctx retval e
 		gen_expr ctx retval e
 	| TCast (e1,Some t) ->
 	| TCast (e1,Some t) ->
 		gen_expr ctx retval (Codegen.default_cast ctx.com e1 t e.etype e.epos)
 		gen_expr ctx retval (Codegen.default_cast ctx.com e1 t e.etype e.epos)
-	| TMatch (e,_,cases,def) ->
-		gen_match ctx retval e cases def
+	| TPatMatch dt -> assert false
 	| TFor (v,it,e) ->
 	| TFor (v,it,e) ->
 		gen_expr ctx true it;
 		gen_expr ctx true it;
 		let r = alloc_tmp ctx in
 		let r = alloc_tmp ctx in

+ 10 - 3
genswf9.ml

@@ -862,6 +862,11 @@ let rec gen_access ctx e (forset : 'a) : 'a access =
 		let id, _, _ = property ctx f e1.etype in
 		let id, _, _ = property ctx f e1.etype in
 		write ctx HThis;
 		write ctx HThis;
 		VSuper id
 		VSuper id
+	| TEnumParameter (e1,i) ->
+		gen_expr ctx true e1;
+		write ctx (HGetProp (ident "params"));
+		write ctx (HSmallInt i);
+		VArray
 	| TField (e1,f) ->
 	| TField (e1,f) ->
 		let f = field_name f in
 		let f = field_name f in
 		let id, k, closure = property ctx f e1.etype in
 		let id, k, closure = property ctx f e1.etype in
@@ -1033,6 +1038,7 @@ let rec gen_expr_content ctx retval e =
 		ctx.infos.icond <- true;
 		ctx.infos.icond <- true;
 		no_value ctx retval
 		no_value ctx retval
 	| TField _
 	| TField _
+	| TEnumParameter _
 	| TLocal _
 	| TLocal _
 	| TTypeExpr _ ->
 	| TTypeExpr _ ->
 		getvar ctx (gen_access ctx e Read)
 		getvar ctx (gen_access ctx e Read)
@@ -1273,7 +1279,7 @@ let rec gen_expr_content ctx retval e =
 		);
 		);
 		List.iter (fun j -> j()) jend;
 		List.iter (fun j -> j()) jend;
 		branch());
 		branch());
-	| TMatch (e0,_,cases,def) ->
+(* 	| TMatch (e0,_,cases,def) ->
 		let t = classify ctx e.etype in
 		let t = classify ctx e.etype in
 		let rparams = alloc_reg ctx (KType (type_path ctx ([],"Array"))) in
 		let rparams = alloc_reg ctx (KType (type_path ctx ([],"Array"))) in
 		let has_params = List.exists (fun (_,p,_) -> p <> None) cases in
 		let has_params = List.exists (fun (_,p,_) -> p <> None) cases in
@@ -1324,7 +1330,8 @@ let rec gen_expr_content ctx retval e =
 		) cases in
 		) cases in
 		switch();
 		switch();
 		List.iter (fun j -> j()) jends;
 		List.iter (fun j -> j()) jends;
-		free_reg ctx rparams
+		free_reg ctx rparams *)
+	| TPatMatch dt -> assert false
 	| TCast (e1,t) ->
 	| TCast (e1,t) ->
 		gen_expr ctx retval e1;
 		gen_expr ctx retval e1;
 		if retval then begin
 		if retval then begin
@@ -1699,7 +1706,7 @@ and generate_function ctx fdata stat =
 			| TReturn (Some e) ->
 			| TReturn (Some e) ->
 				let rec inner_loop e =
 				let rec inner_loop e =
 					match e.eexpr with
 					match e.eexpr with
-					| TSwitch _ | TMatch _ | TFor _ | TWhile _ | TTry _ -> false
+					| TSwitch _ | TPatMatch _ | TFor _ | TWhile _ | TTry _ -> false
 					| TIf _ -> loop e
 					| TIf _ -> loop e
 					| TParenthesis e | TMeta(_,e) -> inner_loop e
 					| TParenthesis e | TMeta(_,e) -> inner_loop e
 					| _ -> true
 					| _ -> true

+ 4 - 2
interp.ml

@@ -4470,6 +4470,7 @@ let rec make_ast e =
 	| TLocal v -> EConst (mk_ident v.v_name)
 	| TLocal v -> EConst (mk_ident v.v_name)
 	| TArray (e1,e2) -> EArray (make_ast e1,make_ast e2)
 	| TArray (e1,e2) -> EArray (make_ast e1,make_ast e2)
 	| TBinop (op,e1,e2) -> EBinop (op, make_ast e1, make_ast e2)
 	| TBinop (op,e1,e2) -> EBinop (op, make_ast e1, make_ast e2)
+	| TEnumParameter (e,i) -> assert false
 	| TField (e,f) -> EField (make_ast e, Type.field_name f)
 	| TField (e,f) -> EField (make_ast e, Type.field_name f)
 	| TTypeExpr t -> fst (mk_path (full_type_path t) e.epos)
 	| TTypeExpr t -> fst (mk_path (full_type_path t) e.epos)
 	| TParenthesis e -> EParenthesis (make_ast e)
 	| TParenthesis e -> EParenthesis (make_ast e)
@@ -4495,7 +4496,7 @@ let rec make_ast e =
 		) cases in
 		) cases in
 		let def = match eopt def with None -> None | Some (EBlock [],_) -> Some None | e -> Some e in
 		let def = match eopt def with None -> None | Some (EBlock [],_) -> Some None | e -> Some e in
 		ESwitch (make_ast e,cases,def)
 		ESwitch (make_ast e,cases,def)
-	| TMatch (e,(en,_),cases,def) ->
+(* 	| TMatch (e,(en,_),cases,def) ->
 		let scases (idx,args,e) =
 		let scases (idx,args,e) =
 			let p = e.epos in
 			let p = e.epos in
 			let unused = (EConst (Ident "_"),p) in
 			let unused = (EConst (Ident "_"),p) in
@@ -4517,7 +4518,8 @@ let rec make_ast e =
 			) idx, None, (match e.eexpr with TBlock [] -> None | _ -> Some (make_ast e))
 			) idx, None, (match e.eexpr with TBlock [] -> None | _ -> Some (make_ast e))
 		in
 		in
 		let def = match eopt def with None -> None | Some (EBlock [],_) -> Some None | e -> Some e in
 		let def = match eopt def with None -> None | Some (EBlock [],_) -> Some None | e -> Some e in
-		ESwitch (make_ast e,List.map scases cases,def)
+		ESwitch (make_ast e,List.map scases cases,def) *)
+	| TPatMatch dt -> assert false
 	| TTry (e,catches) -> ETry (make_ast e,List.map (fun (v,e) -> v.v_name, (try make_type v.v_type with Exit -> assert false), make_ast e) catches)
 	| TTry (e,catches) -> ETry (make_ast e,List.map (fun (v,e) -> v.v_name, (try make_type v.v_type with Exit -> assert false), make_ast e) catches)
 	| TReturn e -> EReturn (eopt e)
 	| TReturn e -> EReturn (eopt e)
 	| TBreak -> EBreak
 	| TBreak -> EBreak

+ 219 - 375
matcher.ml

@@ -25,6 +25,8 @@ open Common
 open Type
 open Type
 open Typecore
 open Typecore
 
 
+type pvar = tvar * pos
+
 type con_def =
 type con_def =
 	| CEnum of tenum * tenum_field
 	| CEnum of tenum * tenum_field
 	| CConst of tconstant
 	| CConst of tconstant
@@ -40,7 +42,27 @@ and con = {
 	c_pos : pos;
 	c_pos : pos;
 }
 }
 
 
-type pvar = tvar * pos
+and st_def =
+	| SVar of tvar
+	| SField of st * string
+	| SEnum of st * tenum_field * int
+	| SArray of st * int
+	| STuple of st * int * int
+
+and st = {
+	st_def : st_def;
+	st_type : t;
+	st_pos : pos;
+}
+
+and dt =
+	| Switch of st * (con * dt) list
+	| Bind of ((tvar * pos) * st) list * dt
+	| Goto of int
+	| Expr of texpr
+	| Guard of texpr * dt * dt option
+
+(* Pattern *)
 
 
 type pat_def =
 type pat_def =
 	| PAny
 	| PAny
@@ -56,19 +78,6 @@ and pat = {
 	p_pos : pos;
 	p_pos : pos;
 }
 }
 
 
-type st_def =
-	| SVar of tvar
-	| SField of st * string
-	| SEnum of st * string * int
-	| SArray of st * int
-	| STuple of st * int * int
-
-and st = {
-	st_def : st_def;
-	st_type : t;
-	st_pos : pos;
-}
-
 type out = {
 type out = {
 	o_expr : texpr;
 	o_expr : texpr;
 	o_guard : texpr option;
 	o_guard : texpr option;
@@ -79,28 +88,23 @@ type out = {
 type pat_vec = pat array * out
 type pat_vec = pat array * out
 type pat_matrix = pat_vec list
 type pat_matrix = pat_vec list
 
 
+(* Context *)
+
 type pattern_ctx = {
 type pattern_ctx = {
 	mutable pc_locals : (string, pvar) PMap.t;
 	mutable pc_locals : (string, pvar) PMap.t;
 	mutable pc_sub_vars : (string, pvar) PMap.t option;
 	mutable pc_sub_vars : (string, pvar) PMap.t option;
 	mutable pc_reify : bool;
 	mutable pc_reify : bool;
 }
 }
 
 
-type dt =
-	| Out of out * dt option
-	| Switch of st * (con * dt) list
-	| Bind of (pvar * st) list * dt
-	| Goto of int
-
 type matcher = {
 type matcher = {
 	ctx : typer;
 	ctx : typer;
-	stl : st list;
 	need_val : bool;
 	need_val : bool;
-	v_lookup : (string,tvar) Hashtbl.t;
+	dt_cache : (dt,int) Hashtbl.t;
+	dt_lut : dt DynArray.t;
+	mutable dt_count : int;
 	mutable outcomes : (pat list,out) PMap.t;
 	mutable outcomes : (pat list,out) PMap.t;
-	mutable out_type : Type.t;
 	mutable toplevel_or : bool;
 	mutable toplevel_or : bool;
 	mutable used_paths : (int,bool) Hashtbl.t;
 	mutable used_paths : (int,bool) Hashtbl.t;
-	mutable eval_stack : (pvar * st) list list;
 }
 }
 
 
 exception Not_exhaustive of pat * st
 exception Not_exhaustive of pat * st
@@ -168,16 +172,23 @@ let mk_subs st con =
 	let map = match follow st.st_type with
 	let map = match follow st.st_type with
 		| TInst(c,pl) -> apply_params c.cl_types pl
 		| TInst(c,pl) -> apply_params c.cl_types pl
 		| TEnum(en,pl) -> apply_params en.e_types pl
 		| TEnum(en,pl) -> apply_params en.e_types pl
+		| TAbstract(a,pl) -> apply_params a.a_types pl
 		| _ -> fun t -> t
 		| _ -> fun t -> t
 	in
 	in
 	match con.c_def with
 	match con.c_def with
 	| CFields (_,fl) -> List.map (fun (s,cf) -> mk_st (SField(st,s)) (map cf.cf_type) st.st_pos) fl
 	| CFields (_,fl) -> List.map (fun (s,cf) -> mk_st (SField(st,s)) (map cf.cf_type) st.st_pos) fl
 	| CEnum (en,({ef_type = TFun _} as ef)) ->
 	| CEnum (en,({ef_type = TFun _} as ef)) ->
-		let pl = match follow con.c_type with TEnum(_,pl) | TAbstract({a_this = TEnum(_)},pl)-> pl | TAbstract({a_path = [],"EnumValue"},[]) -> [] | _ -> [] in
+		let rec loop t = match follow t with
+			| TEnum(_,pl) -> pl
+			| TAbstract({a_path = [],"EnumValue"},[]) -> []
+			| TAbstract(a,pl) -> loop (Codegen.Abstract.get_underlying_type a pl)
+			| _ -> []
+		in
+		let pl = loop con.c_type in
 		begin match apply_params en.e_types pl (monomorphs ef.ef_params ef.ef_type) with
 		begin match apply_params en.e_types pl (monomorphs ef.ef_params ef.ef_type) with
 			| TFun(args,r) ->
 			| TFun(args,r) ->
 				ExtList.List.mapi (fun i (_,_,t) ->
 				ExtList.List.mapi (fun i (_,_,t) ->
-					mk_st (SEnum(st,ef.ef_name,i)) t st.st_pos
+					mk_st (SEnum(st,ef,i)) t st.st_pos
 				) args
 				) args
 			| _ ->
 			| _ ->
 				assert false
 				assert false
@@ -197,13 +208,7 @@ let get_tuple_types t = match t with
 
 
 let s_type = s_type (print_context())
 let s_type = s_type (print_context())
 
 
-let rec s_expr_small e = match e.eexpr with
-	| TLocal v -> v.v_name
-	| TField (e,s) -> s_expr_small e ^ "." ^ field_name s
-	| TBlock [] -> "{}"
-	| _ -> s_expr (s_type) e
-
-let s_con con = match con.c_def with
+let rec s_con con = match con.c_def with
 	| CEnum(_,ef) -> ef.ef_name
 	| CEnum(_,ef) -> ef.ef_name
 	| CAny -> "_"
 	| CAny -> "_"
 	| CConst c -> s_const c
 	| CConst c -> s_const c
@@ -221,42 +226,24 @@ let rec s_pat pat = match pat.p_def with
 	| PBind((v,_),pat) -> v.v_name ^ "=" ^ s_pat pat
 	| PBind((v,_),pat) -> v.v_name ^ "=" ^ s_pat pat
 	| PTuple pl -> "(" ^ (String.concat " " (Array.to_list (Array.map s_pat pl))) ^ ")"
 	| PTuple pl -> "(" ^ (String.concat " " (Array.to_list (Array.map s_pat pl))) ^ ")"
 
 
+let rec s_pat_vec pl =
+	String.concat " " (Array.to_list (Array.map s_pat pl))
+
+let rec s_pat_matrix pmat =
+	String.concat "\n" (List.map (fun (pl,out) -> (s_pat_vec pl) ^ "->" ^ "") pmat)
+
 let st_args l r v =
 let st_args l r v =
 	(if l > 0 then (String.concat "," (ExtList.List.make l "_")) ^ "," else "")
 	(if l > 0 then (String.concat "," (ExtList.List.make l "_")) ^ "," else "")
 	^ v ^
 	^ v ^
 	(if r > 0 then "," ^ (String.concat "," (ExtList.List.make r "_")) else "")
 	(if r > 0 then "," ^ (String.concat "," (ExtList.List.make r "_")) else "")
 
 
-let rec s_st st = (match st.st_def with
+let rec s_st st =
+	(match st.st_def with
 	| SVar v -> v.v_name
 	| SVar v -> v.v_name
-	| SEnum (st,n,i) -> s_st st ^ "." ^ n ^ "." ^ (string_of_int i)
+	| SEnum (st,ef,i) -> s_st st ^ "." ^ ef.ef_name ^ "." ^ (string_of_int i)
 	| SArray (st,i) -> s_st st ^ "[" ^ (string_of_int i) ^ "]"
 	| SArray (st,i) -> s_st st ^ "[" ^ (string_of_int i) ^ "]"
 	| STuple (st,i,a) -> "(" ^ (st_args i (a - i - 1) (s_st st)) ^ ")"
 	| STuple (st,i,a) -> "(" ^ (st_args i (a - i - 1) (s_st st)) ^ ")"
 	| SField (st,n) -> s_st st ^ "." ^ n)
 	| SField (st,n) -> s_st st ^ "." ^ n)
-	(* ^ ":" ^ (s_type st.st_type) *)
-
-let rec s_pat_vec pl =
-	String.concat " " (Array.to_list (Array.map s_pat pl))
-
-let s_out out = ""
-	(* ^ s_expr_small out.o_expr *)
-
-let rec s_pat_matrix pmat =
-	String.concat "\n" (List.map (fun (pl,out) -> (s_pat_vec pl) ^ "->" ^ (s_out out)) pmat)
-
-let rec s_dt tabs tree = tabs ^ match tree with
-	| Out(out,None)->
-		s_out out;
-	| Out(out,Some dt) ->
-		"if (" ^ (s_expr_small (match out.o_guard with Some e -> e | None -> assert false)) ^ ") " ^ (s_out out) ^ " else " ^ s_dt tabs dt
-	| Switch (st, cl) ->
-		"switch(" ^ (s_st st) ^ ") { \n" ^ tabs
-		^ (String.concat ("\n" ^ tabs) (List.map (fun (c,dt) ->
-			"case " ^ (s_con c) ^ ":\n" ^ (s_dt (tabs ^ "\t") dt)
-		) cl))
-		^ "\n" ^ (if String.length tabs = 0 then "" else (String.sub tabs 0 (String.length tabs - 1))) ^ "}"
-	| Bind (bl, dt) -> "bind " ^ (String.concat "," (List.map (fun ((v,_),st) -> v.v_name ^ "(" ^ (string_of_int v.v_id) ^ ") =" ^ (s_st st)) bl)) ^ "\n" ^ (s_dt tabs dt)
-	| Goto i ->
-		"goto " ^ (string_of_int i)
 
 
 (* Pattern parsing *)
 (* Pattern parsing *)
 
 
@@ -298,7 +285,7 @@ let rec matches_null ctx t = match t with
 		false
 		false
 	| TAbstract (a,_) -> not (Meta.has Meta.NotNull a.a_meta)
 	| TAbstract (a,_) -> not (Meta.has Meta.NotNull a.a_meta)
 	| _ ->
 	| _ ->
-		true	
+		true
 
 
 let to_pattern ctx e t =
 let to_pattern ctx e t =
 	let perror p = error "Unrecognized pattern" p in
 	let perror p = error "Unrecognized pattern" p in
@@ -737,37 +724,33 @@ let rec is_explicit_null = function
 	| _ ->
 	| _ ->
 		false
 		false
 
 
-let all_ctors mctx st =
+let rec all_ctors mctx t =
 	let h = ref PMap.empty in
 	let h = ref PMap.empty in
-	if is_explicit_null st.st_type then h := PMap.add (CConst TNull) Ast.null_pos !h;
-	let inf = match follow st.st_type with
+	if is_explicit_null t then h := PMap.add (CConst TNull) Ast.null_pos !h;
+	match follow t with
 	| TAbstract({a_path = [],"Bool"},_) ->
 	| TAbstract({a_path = [],"Bool"},_) ->
 		h := PMap.add (CConst(TBool true)) Ast.null_pos !h;
 		h := PMap.add (CConst(TBool true)) Ast.null_pos !h;
 		h := PMap.add (CConst(TBool false)) Ast.null_pos !h;
 		h := PMap.add (CConst(TBool false)) Ast.null_pos !h;
-		false
+		h,false
+	| TAbstract(a,pl) -> all_ctors mctx (Codegen.Abstract.get_underlying_type a pl)
 	| TInst({cl_path=[],"String"},_)
 	| TInst({cl_path=[],"String"},_)
-	| TInst({cl_path=[],"Array"},_)
-	| TAbstract _ ->
-		true
+	| TInst({cl_path=[],"Array"},_) ->
+		h,true
 	| TEnum(en,pl) ->
 	| TEnum(en,pl) ->
 		PMap.iter (fun _ ef ->
 		PMap.iter (fun _ ef ->
-			let tc = monomorphs mctx.ctx.type_params st.st_type in
+			let tc = monomorphs mctx.ctx.type_params t in
 			try unify_enum_field en pl ef tc;
 			try unify_enum_field en pl ef tc;
 				h := PMap.add (CEnum(en,ef)) ef.ef_pos !h
 				h := PMap.add (CEnum(en,ef)) ef.ef_pos !h
 			with Unify_error _ ->
 			with Unify_error _ ->
 				()
 				()
 		) en.e_constrs;
 		) en.e_constrs;
-		false
-	| TInst ({cl_kind = KTypeParameter _},_) ->
-		error "Unapplied type parameter" st.st_pos
+		h,false
 	| TAnon a ->
 	| TAnon a ->
-		true
+		h,true
 	| TInst(_,_) ->
 	| TInst(_,_) ->
-		false
+		h,false
 	| _ ->
 	| _ ->
-		true
-	in
-	h,inf
+		h,true
 
 
 let rec collapse_pattern pl = match pl with
 let rec collapse_pattern pl = match pl with
 	| pat :: [] ->
 	| pat :: [] ->
@@ -801,11 +784,27 @@ let bind_remaining out pv stl =
 	in
 	in
 	loop stl pv
 	loop stl pv
 
 
-let rec compile mctx stl pmat = match pmat with
+let get_cache mctx dt =
+	match dt with Goto _ -> dt | _ ->
+	try
+		let i = Hashtbl.find mctx.dt_cache dt in
+		Goto i
+	with Not_found ->
+		Hashtbl.replace mctx.dt_cache dt mctx.dt_count;
+		mctx.dt_count <- mctx.dt_count + 1;
+		DynArray.add mctx.dt_lut dt;
+		dt
+
+let rec compile mctx stl pmat =
+	let guard e dt1 dt2 = get_cache mctx (Guard(e,dt1,dt2)) in
+	let expr e = get_cache mctx (Expr e) in
+	let bind bl dt = get_cache mctx (Bind(bl,dt)) in
+	let switch st cl = get_cache mctx (Switch(st,cl)) in
+	get_cache mctx (match pmat with
 	| [] ->
 	| [] ->
 		(match stl with
 		(match stl with
 		| st :: stl ->
 		| st :: stl ->
-			let all,inf = all_ctors mctx st in
+			let all,inf = all_ctors mctx st.st_type in
 			let pl = PMap.foldi (fun cd p acc -> (mk_con_pat cd [] t_dynamic p) :: acc) !all [] in
 			let pl = PMap.foldi (fun cd p acc -> (mk_con_pat cd [] t_dynamic p) :: acc) !all [] in
 			begin match pl,inf with
 			begin match pl,inf with
 				| _,true
 				| _,true
@@ -823,12 +822,11 @@ let rec compile mctx stl pmat = match pmat with
 		if i = -1 then begin
 		if i = -1 then begin
 			Hashtbl.replace mctx.used_paths out.o_id true;
 			Hashtbl.replace mctx.used_paths out.o_id true;
 			let bl = bind_remaining out pv stl in
 			let bl = bind_remaining out pv stl in
-			let dt = if out.o_guard = None || match pl with [] -> true | _ -> false then
-				Out(out,None)
-			else
-				Out(out,Some (compile mctx stl pl))
+			let dt = match out.o_guard with
+				| None -> expr out.o_expr
+				| Some e -> guard e (expr out.o_expr) (match pl with [] -> None | _ -> Some (compile mctx stl pl))
 			in
 			in
-			if bl = [] then dt else Bind(bl,dt)
+			(if bl = [] then dt else bind bl dt)
 		end else if i > 0 then begin
 		end else if i > 0 then begin
 			let pmat = swap_pmat_columns i pmat in
 			let pmat = swap_pmat_columns i pmat in
 			let stls = swap_columns i stl in
 			let stls = swap_columns i stl in
@@ -836,7 +834,7 @@ let rec compile mctx stl pmat = match pmat with
 		end else begin
 		end else begin
 			let st_head,st_tail = match stl with st :: stl -> st,stl | _ -> assert false in
 			let st_head,st_tail = match stl with st :: stl -> st,stl | _ -> assert false in
 			let sigma,bl = column_sigma mctx st_head pmat in
 			let sigma,bl = column_sigma mctx st_head pmat in
-			let all,inf = all_ctors mctx st_head in
+			let all,inf = all_ctors mctx st_head.st_type in
 			let cases = List.map (fun (c,g) ->
 			let cases = List.map (fun (c,g) ->
 				if not g then all := PMap.remove c.c_def !all;
 				if not g then all := PMap.remove c.c_def !all;
 				let spec = spec mctx c pmat in
 				let spec = spec mctx c pmat in
@@ -850,9 +848,9 @@ let rec compile mctx stl pmat = match pmat with
  			| _,[{c_def = CFields _},dt] ->
  			| _,[{c_def = CFields _},dt] ->
 				dt
 				dt
 			| _ when not inf && PMap.is_empty !all ->
 			| _ when not inf && PMap.is_empty !all ->
-				Switch(st_head,cases)
+				switch st_head cases
 			| [],_ when inf && not mctx.need_val ->
 			| [],_ when inf && not mctx.need_val ->
-				Switch(st_head,cases)
+				switch st_head cases
 			| [],_ when inf ->
 			| [],_ when inf ->
 				raise (Not_exhaustive(any,st_head))
 				raise (Not_exhaustive(any,st_head))
 			| [],_ ->
 			| [],_ ->
@@ -863,12 +861,19 @@ let rec compile mctx stl pmat = match pmat with
 			| def,_ ->
 			| def,_ ->
 				let cdef = mk_con CAny t_dynamic st_head.st_pos in
 				let cdef = mk_con CAny t_dynamic st_head.st_pos in
 				let cases = cases @ [cdef,compile mctx st_tail def] in
 				let cases = cases @ [cdef,compile mctx st_tail def] in
-				Switch(st_head,cases)
+				switch st_head cases
 			in
 			in
-			if bl = [] then dt else Bind(bl,dt)
-		end
+			if bl = [] then dt else bind bl dt
+		end)
 
 
-(* Conversion to typed AST *)
+let rec collapse_case el = match el with
+	| e :: [] ->
+		e
+	| e :: el ->
+		let e2 = collapse_case el in
+		EBinop(OpOr,e,e2),punion (pos e) (pos e2)
+	| [] ->
+		assert false
 
 
 let mk_const ctx p = function
 let mk_const ctx p = function
 	| TString s -> mk (TConst (TString s)) ctx.com.basic.tstring p
 	| TString s -> mk (TConst (TString s)) ctx.com.basic.tstring p
@@ -878,260 +883,67 @@ let mk_const ctx p = function
 	| TNull -> mk (TConst TNull) (ctx.com.basic.tnull (mk_mono())) p
 	| TNull -> mk (TConst TNull) (ctx.com.basic.tnull (mk_mono())) p
 	| _ -> error "Unsupported constant" p
 	| _ -> error "Unsupported constant" p
 
 
-let rec st_to_unique_name ctx st = match st.st_def with
-	| SField(st,f) -> st_to_unique_name ctx st ^ "_f" ^ f
-	| SArray(st,i) -> st_to_unique_name ctx st ^ "_a" ^ (string_of_int i)
-	| SEnum(st,n,i) -> st_to_unique_name ctx st ^ "_e" ^ n ^ "_" ^ (string_of_int i)
-	| SVar v -> v.v_name
-	| STuple (st,_,_) -> st_to_unique_name ctx st
-
-let rec st_to_texpr mctx st = match st.st_def with
+let rec convert_st ctx st = match st.st_def with
 	| SVar v -> mk (TLocal v) v.v_type st.st_pos
 	| SVar v -> mk (TLocal v) v.v_type st.st_pos
 	| SField (sts,f) ->
 	| SField (sts,f) ->
-		let e = st_to_texpr mctx sts in
+		let e = convert_st ctx sts in
 		let fa = try quick_field e.etype f with Not_found -> FDynamic f in
 		let fa = try quick_field e.etype f with Not_found -> FDynamic f in
 		mk (TField(e,fa)) st.st_type st.st_pos
 		mk (TField(e,fa)) st.st_type st.st_pos
-	| SArray (sts,i) -> mk (TArray(st_to_texpr mctx sts,mk_const mctx.ctx st.st_pos (TInt (Int32.of_int i)))) st.st_type st.st_pos
-	| STuple (st,_,_) -> st_to_texpr mctx st
-	| SEnum _ ->
-		let n = st_to_unique_name mctx st in
-		let v = try	Hashtbl.find mctx.v_lookup n with Not_found ->
-			let v = alloc_var n st.st_type in
-			Hashtbl.add mctx.v_lookup n v;
-			v
-		in
-		mctx.ctx.locals <- PMap.add n v mctx.ctx.locals;
-		mk (TLocal v) v.v_type st.st_pos
-
-let rec st_eq st1 st2 = match st1.st_def,st2.st_def with
-	| STuple (st1,i1,_), STuple(st2,i2,_) -> i1 = i2 && st_eq st1 st2
-	| SEnum(st1,_,i1), SEnum(st2,_,i2) -> i1 = i2 && st_eq st1 st2
-	| SField(st1,f1),SField(st2,f2) -> f1 = f2 && st_eq st1 st2
-	| SArray(st1,i1),SArray(st2,i2) -> i1 = i1 && st_eq st1 st2
-	| SVar _, SVar _ -> true
-	| _ -> false
-
-let is_compatible out1 out2 =
-	out1.o_id = out2.o_id
-	&& out1.o_guard = None
-
-let replace_locals mctx out e =
-	let replace v =
-		let rec loop vl = match vl with
-			| vl :: vll -> (try snd (List.find (fun ((v2,_),st) -> v2 == v) vl) with Not_found -> loop vll)
-			| [] -> raise Not_found
-		in
-		loop mctx.eval_stack
-	in
-	let rec loop e = match e.eexpr with
-		| TLocal v ->
-			(try
-				let st = replace v in
-				unify mctx.ctx e.etype st.st_type e.epos;
-				st_to_texpr mctx st
-			with Not_found ->
-				e)
-		| _ ->
-			Type.map_expr loop e
-	in
-	let e = loop e in
-	(*      if not (Common.defined mctx.ctx.com Define.NoUnusedVarWarnings) then
-	Hashtbl.iter (fun _ (v,p) -> if (String.length v.v_name) > 0 && v.v_name.[0] <> '_' then mctx.ctx.com.warning "This variable is unused" p) all_subterms; *)
-	e
-
-let rec to_typed_ast mctx dt =
-	match dt with
-	| Goto _ ->
-		error "Not implemented yet" Ast.null_pos
-	| Out(out,dt) ->
-		replace_locals mctx out begin match out.o_guard,dt with
-			| Some eg,None ->
-				mk (TIf(eg,out.o_expr,None)) t_dynamic out.o_expr.epos
-			| Some eg,Some dt ->
-				let eelse = to_typed_ast mctx dt in
-				mk (TIf(eg,out.o_expr,Some eelse)) eelse.etype (punion out.o_expr.epos eelse.epos)
-			| _,None ->
-				out.o_expr
-			| _ -> assert false
-		end
-	| Bind (bl, dt) ->
-		List.iter (fun ((v,_),st) ->
-			let e = st_to_texpr mctx st in
-			begin match e.eexpr with
-				| TLocal v2 -> v2.v_name <- v.v_name
-				| _ -> ()
-			end;
-		) bl;
-		mctx.eval_stack <- bl :: mctx.eval_stack;
-		let e = to_typed_ast mctx dt in
-		mctx.eval_stack <- List.tl mctx.eval_stack;
-		e
-	| Switch(st,cases) ->
-		(* separate null-patterns: these are placed in an initial if (st == null) check to avoid null access issues *)
-		let null,cases = List.partition (fun (c,_) -> match c.c_def with CConst(TNull) -> true | _ -> false) cases in
-		let e = match follow st.st_type with
-		| TEnum(en,pl) | TAbstract({a_this = TEnum(en,_)},pl) -> to_enum_switch mctx en pl st cases
-		| TInst({cl_path = [],"Array"},[t]) -> to_array_switch mctx t st cases
-		| TAnon a -> to_structure_switch mctx a st cases
-		| t -> to_value_switch mctx t st cases
-		in
-		match null with
-		| [] -> e
-		| [_,dt] ->
-			let eval = st_to_texpr mctx st in
-			let ethen = to_typed_ast mctx dt in
-			let eif = mk (TBinop(OpEq,(mk (TConst TNull) st.st_type st.st_pos),eval)) mctx.ctx.t.tbool ethen.epos in
-			mk (TIf(eif,ethen,Some e)) ethen.etype ethen.epos
-		| _ ->
-			assert false	
-
-and group_cases mctx cases to_case =
-	let def = ref None in
-	let group,cases,dto = List.fold_left (fun (group,cases,dto) (con,dt) -> match con.c_def with
-		| CAny ->
-			let e = to_typed_ast mctx dt in
-			def := Some e;
-			(group,cases,dto)
-		| _ -> match dto with
-			| None -> ([to_case con],cases,Some dt)
-			| Some dt2 -> match dt,dt2 with
-				| Out(out1,_),Out(out2,_) when is_compatible out1 out2 ->
-					((to_case con) :: group,cases,dto)
-				| _ ->
-					let e = to_typed_ast mctx dt2 in
-					([to_case con],(List.rev group,e) :: cases, Some dt)
-	) ([],[],None) cases in
-	let cases = List.rev (match group,dto with
-		| [],None ->
-			cases
-		| group,Some dt ->
-			let e = to_typed_ast mctx dt in
-			(List.rev group,e) :: cases
-		| _ ->
-			assert false
-	) in
-	cases,def
-
-and to_enum_switch mctx en pl st cases =
-	let eval = st_to_texpr mctx st in
-	let to_case con = match con.c_def with
-		| CEnum(en,ef) -> en,ef
-		| _ ->
-			error ("Unexpected") con.c_pos
-	in
-	let type_case group dt p =
-		let group = List.rev group in
-		let en,ef = List.hd group in
-		let save = save_locals mctx.ctx in
-		let etf = follow (monomorphs en.e_types (monomorphs ef.ef_params ef.ef_type)) in
-		(* TODO: this is horrible !!! *)
-		let capture_vars = match dt with
-			| Out(out,None) ->
-				let vl = PMap.foldi (fun k v acc -> (k,v) :: acc) (List.fold_left (fun acc vl -> List.fold_left (fun acc (v,st) -> if PMap.mem v acc then acc else PMap.add v st acc) acc vl) PMap.empty mctx.eval_stack) [] in
-				Some vl
-			| _ ->
-				None
-		in
-		let vl = match etf with
-			| TFun(args,r) ->
-				let vl = ExtList.List.mapi (fun i (_,_,t) ->
-					let st = mk_st (SEnum(st,ef.ef_name,i)) t st.st_pos in
-					let mk_e () = Some (match (st_to_texpr mctx st).eexpr with TLocal v -> v | _ -> assert false) in
-					begin match capture_vars with
-						| Some cvl ->
-							let rec check st2 = st_eq st st2 || match st2.st_def with
-								| SEnum(st,_,_) | SArray(st,_) | STuple(st,_,_) | SField(st,_) -> check st
-								| SVar _ -> false
-							in
-							let rec loop cvl = match cvl with
-								| [] -> None
-								| (_,st2) :: cvl ->
-									if check st2 then mk_e() else loop cvl
-							in
-							loop cvl
-						| _ ->
-							mk_e()
-					end
-				) args in
-				if List.exists (fun e -> e <> None) vl then (Some vl) else None
-			| _ -> None
-		in
-		let e = to_typed_ast mctx dt in
-		save();
-		(List.map (fun (_,ef) -> ef.ef_index) group),vl,e
+	| SArray (sts,i) -> mk (TArray(convert_st ctx sts,mk_const ctx st.st_pos (TInt (Int32.of_int i)))) st.st_type st.st_pos
+	| STuple (st,_,_) -> convert_st ctx st
+	| SEnum(sts,ef,i) -> mk (TEnumParameter(convert_st ctx sts, i)) st.st_type st.st_pos
+
+let convert_con ctx con = match con.c_def with
+	| CConst c -> mk_const ctx con.c_pos c
+	| CType mt -> mk (TTypeExpr mt) t_dynamic con.c_pos
+	| CExpr e -> e
+	| CEnum(e,ef) -> mk_const ctx con.c_pos (TInt (Int32.of_int ef.ef_index))
+	| CArray i -> mk_const ctx con.c_pos (TInt (Int32.of_int i))
+	| CAny ->
+		let t = mk_mono() in
+		mk (TMeta((Meta.MatchAny,[],con.c_pos),mk (TConst (TNull)) t con.c_pos)) t con.c_pos
+	| CFields _ -> assert false
+
+let convert_switch ctx st cases loop =
+	let e_st = convert_st ctx st in
+	let p = e_st.epos in
+	let mk_index_call () =
+		let ttype = match follow (Typeload.load_instance ctx { tpackage = ["std"]; tname="Type"; tparams=[]; tsub = None} p true) with TInst(c,_) -> c | t -> assert false in
+		let cf = PMap.find "enumIndex" ttype.cl_statics in
+		let ec = (!type_module_type_ref) ctx (TClassDecl ttype) None p in
+		let ef = mk (TField(ec, FStatic(ttype,cf))) (tfun [e_st.etype] ctx.t.tint) p in
+		(* TODO: inlining this causes errors on flash 9 for whatever reason *)
+		if ctx.com.platform = Flash then mk (TCall (ef,[e_st])) ctx.t.tint p
+		else make_call ctx ef [e_st] ctx.t.tint p
 	in
 	in
-	let def = ref None in
-	let group,cases,dto = List.fold_left (fun (group,cases,dto) (con,dt) -> match con.c_def with
-		| CAny ->
-			let e = to_typed_ast mctx dt in
-			def := Some e;
-			(group,cases,dto)
-		| _ -> match dto with
-			| None -> ([to_case con],cases,Some dt)
-			| Some dt2 -> match dt,dt2 with
-				| Out(out1,_),Out(out2,_) when is_compatible out1 out2 ->
-					((to_case con) :: group,cases,dto)
-				| _ ->
-					let g = type_case group dt2 con.c_pos in
-					([to_case con],g :: cases, Some dt)
-	) ([],[],None) cases in
-	let cases = List.rev (match group,dto with
-		| [],None ->
-			cases
-		| group,Some dt ->
-			let g = type_case group dt eval.epos in
-			g :: cases
-		| _ ->
-			assert false
-	) in
-	mk (TMatch(eval,(en,pl),cases,!def)) mctx.out_type eval.epos
-
-and to_value_switch mctx t st cases =
-	let eval = st_to_texpr mctx st in
-	let to_case con = match con.c_def with
-		| CConst c ->
-			mk_const mctx.ctx con.c_pos c
-		| CType mt ->
-			Typer.type_module_type mctx.ctx mt None con.c_pos
-		| CExpr e ->
-			e
-		| _ ->
-			error ("Unexpected "  ^ (s_con con)) con.c_pos
-	in
-	let cases,def = group_cases mctx cases to_case in
-	mk (TSwitch(eval,cases,!def)) mctx.out_type eval.epos
-
-and to_structure_switch mctx t st cases =
-	match cases with
-	| ({c_def = CFields _},dt) :: cl ->
-		to_typed_ast mctx dt
-	| ({c_def = CAny},dt) :: [] ->
-		to_typed_ast mctx dt;
+	let e = match follow st.st_type with
+	| TEnum(_) ->
+		mk_index_call ()
+	| TAbstract(a,pl) when (match Codegen.Abstract.get_underlying_type a pl with TEnum(_) -> true | _ -> false) ->
+		mk_index_call ()
+	| TInst({cl_path = [],"Array"},_) as t ->
+		mk (TField (e_st,quick_field t "length")) ctx.t.tint p
 	| _ ->
 	| _ ->
-		assert false
-
-and to_array_switch mctx t st cases =
-	let to_case con = match con.c_def with
-		| CArray i ->
-			mk_const mctx.ctx con.c_pos (TInt (Int32.of_int i))
-		| _ ->
-			error ("Unexpected "  ^ (s_con con)) con.c_pos
+		e_st
 	in
 	in
-	let cases,def = group_cases mctx cases to_case in
-	let eval = st_to_texpr mctx st in
-	let eval = mk (TField(eval,quick_field eval.etype "length")) mctx.ctx.com.basic.tint st.st_pos in
-	mk (TSwitch(eval,cases,!def)) mctx.out_type eval.epos
+	let null = ref None in
+	let cases = List.filter (fun (con,dt) ->
+		match con.c_def with
+		| CConst TNull ->
+			null := Some (loop dt);
+			false
+		| _ ->
+			true
+	) cases in
+	let e = mk (TMeta((Meta.Exhaustive,[],p), e)) e.etype e.epos in
+	let dt = DTSwitch(e, List.map (fun (c,dt) -> convert_con ctx c, loop dt) cases) in
+	match !null with
+	| None -> dt
+	| Some dt_null ->
+		let econd = mk (TBinop(OpEq,e_st,mk (TConst TNull) (mk_mono()) p)) ctx.t.tbool p in
+		DTGuard(econd,dt_null,Some dt)
 
 
-(* Main *)
-
-let rec collapse_case el = match el with
-	| e :: [] ->
-		e
-	| e :: el ->
-		let e2 = collapse_case el in
-		EBinop(OpOr,e,e2),punion (pos e) (pos e2)
-	| [] ->
-		assert false
+(* Decision tree compilation *)
 
 
 let match_expr ctx e cases def with_type p =
 let match_expr ctx e cases def with_type p =
 	let need_val,with_type,tmono = match with_type with
 	let need_val,with_type,tmono = match with_type with
@@ -1163,6 +975,8 @@ let match_expr ctx e cases def with_type p =
 			begin match follow e.etype with
 			begin match follow e.etype with
 			| TEnum(en,_) when PMap.is_empty en.e_constrs || Meta.has Meta.FakeEnum en.e_meta ->
 			| TEnum(en,_) when PMap.is_empty en.e_constrs || Meta.has Meta.FakeEnum en.e_meta ->
 				raise Exit
 				raise Exit
+			| TAbstract({a_path=[],("Int" | "Float" | "Bool")},_) | TInst({cl_path = [],"String"},_) when (Common.defined ctx.com Common.Define.NoPatternMatching) ->
+				raise Exit;
 			| _ ->
 			| _ ->
 				()
 				()
 			end;
 			end;
@@ -1191,14 +1005,13 @@ let match_expr ctx e cases def with_type p =
 	(* create matcher context *)
 	(* create matcher context *)
 	let mctx = {
 	let mctx = {
 		ctx = ctx;
 		ctx = ctx;
-		stl = stl;
 		need_val = need_val;
 		need_val = need_val;
-		v_lookup = Hashtbl.create 0;
 		outcomes = PMap.empty;
 		outcomes = PMap.empty;
-		out_type = mk_mono();
 		toplevel_or = false;
 		toplevel_or = false;
 		used_paths = Hashtbl.create 0;
 		used_paths = Hashtbl.create 0;
-		eval_stack = [];
+		dt_cache = Hashtbl.create 0;
+		dt_lut = DynArray.create ();
+		dt_count = 0;
 	} in
 	} in
 	(* flatten cases *)
 	(* flatten cases *)
 	let cases = List.map (fun (el,eg,e) ->
 	let cases = List.map (fun (el,eg,e) ->
@@ -1302,36 +1115,9 @@ let match_expr ctx e cases def with_type p =
 			end;
 			end;
 		end) mctx.outcomes;
 		end) mctx.outcomes;
 	in
 	in
-	begin try
+	let dt = try
 		(* compile decision tree *)
 		(* compile decision tree *)
-		let dt = compile mctx stl pl in
-		(* check for unused patterns *)
-		check_unused();
-		(* determine type of switch statement *)
-		let t = if not need_val then
-			mk_mono()
-		else match with_type with
-			| WithType t | WithTypeResume t -> t
-			| _ -> try Typer.unify_min_raise ctx (List.rev_map (fun (_,out) -> out.o_expr) (List.rev pl)) with Error (Unify l,p) -> error (error_msg (Unify l)) p
-		in
-		(* unify with expected type if necessary *)
-		begin match tmono with
-			| None -> ()
-			| Some (WithType t2) -> unify ctx t2 t p
-			| Some (WithTypeResume t2) -> (try unify_raise ctx t2 t p with Error (Unify l,p) -> raise (Typer.WithTypeError (l,p)))
-			| _ -> assert false
-		end;
-		(* generate typed AST from decision tree *)
-		let e = to_typed_ast mctx dt in
-		let e = { e with epos = p; etype = t} in
-		if !var_inits = [] then
-			e
-		else begin
-			mk (TBlock [
-				mk (TVars (List.rev !var_inits)) t_dynamic e.epos;
-				e;
-			]) t e.epos
-		end
+		compile mctx stl pl
 	with Not_exhaustive(pat,st) ->
 	with Not_exhaustive(pat,st) ->
  		let rec s_st_r top pre st v = match st.st_def with
  		let rec s_st_r top pre st v = match st.st_def with
  			| SVar v1 ->
  			| SVar v1 ->
@@ -1346,18 +1132,76 @@ let match_expr ctx e cases def with_type p =
  				Printf.sprintf "[%s]" (st_args i r (s_st_r top false st v))
  				Printf.sprintf "[%s]" (st_args i r (s_st_r top false st v))
  			| SArray(st,i) ->
  			| SArray(st,i) ->
  				s_st_r false true st (Printf.sprintf "[%i]%s" i (if top then " = " ^ v else v))
  				s_st_r false true st (Printf.sprintf "[%i]%s" i (if top then " = " ^ v else v))
+ 			| SField({st_def = SVar v1},f) when v1.v_name.[0] = '`' ->
+ 				f ^ (if top then " = " ^ v else v)
   			| SField(st,f) ->
   			| SField(st,f) ->
  				s_st_r false true st (Printf.sprintf ".%s%s" f (if top then " = " ^ v else v))
  				s_st_r false true st (Printf.sprintf ".%s%s" f (if top then " = " ^ v else v))
- 			| SEnum(st,n,i) ->
-				let ef = match follow st.st_type with
- 					| TEnum(en,_) -> PMap.find n en.e_constrs
- 					| _ -> raise Not_found
- 				in
+ 			| SEnum(st,ef,i) ->
  				let len = match follow ef.ef_type with TFun(args,_) -> List.length args | _ -> 0 in
  				let len = match follow ef.ef_type with TFun(args,_) -> List.length args | _ -> 0 in
 				s_st_r false false st (Printf.sprintf "%s(%s)" ef.ef_name (st_args i (len - 1 - i) v))
 				s_st_r false false st (Printf.sprintf "%s(%s)" ef.ef_name (st_args i (len - 1 - i) v))
 		in
 		in
 		error ("Unmatched patterns: " ^ (s_st_r true false st (s_pat pat))) st.st_pos
 		error ("Unmatched patterns: " ^ (s_st_r true false st (s_pat pat))) st.st_pos
+	in
+	(* check for unused patterns *)
+	check_unused();
+	(* determine type of switch statement *)
+	let t = if not need_val then
+		mk_mono()
+	else match with_type with
+		| WithType t | WithTypeResume t -> t
+		| _ -> try Typer.unify_min_raise ctx (List.rev_map (fun (_,out) -> out.o_expr) (List.rev pl)) with Error (Unify l,p) -> error (error_msg (Unify l)) p
+	in
+	(* unify with expected type if necessary *)
+	begin match tmono with
+		| None -> ()
+		| Some (WithType t2) -> unify ctx t2 t p
+		| Some (WithTypeResume t2) -> (try unify_raise ctx t2 t p with Error (Unify l,p) -> raise (Typer.WithTypeError (l,p)))
+		| _ -> assert false
 	end;
 	end;
+	(* count usage *)
+	let usage = Array.make (DynArray.length mctx.dt_lut) 0 in
+	let first = (match dt with Goto i -> i | _ -> Hashtbl.find mctx.dt_cache dt) in
+	(* we always want to keep the first part *)
+	Array.set usage first 2;
+	let rec loop dt = match dt with
+		| Goto i -> Array.set usage i ((Array.get usage i) + 1)
+		| Switch(st,cl) -> List.iter (fun (_,dt) -> loop dt) cl
+		| Bind(bl,dt) -> loop dt
+		| Expr e -> ()
+		| Guard(e,dt1,dt2) ->
+			loop dt1;
+			match dt2 with None -> () | Some dt -> (loop dt)
+	in
+	DynArray.iter loop mctx.dt_lut;
+	(* filter parts that will be inlined and keep a map to them*)
+	let map = Array.make (DynArray.length mctx.dt_lut) 0 in
+	let lut = DynArray.create() in
+	let rec loop i c =
+		if c < DynArray.length mctx.dt_lut then begin
+			let i' = if usage.(c) > 1 then begin
+				DynArray.add lut (DynArray.get mctx.dt_lut c);
+				i + 1
+			end else i in
+			Array.set map c i;
+		 	loop i' (c + 1)
+		end
+	in
+	loop 0 0;
+	(* reindex *)
+	let rec loop dt = match dt with
+		| Goto i -> if usage.(i) > 1 then DTGoto (map.(i)) else loop (DynArray.get mctx.dt_lut i)
+		| Switch(st,cl) -> convert_switch ctx st cl loop
+		| Bind(bl,dt) -> DTBind(List.map (fun (v,st) -> v,convert_st ctx st) bl,loop dt)
+		| Expr e -> DTExpr e
+		| Guard(e,dt1,dt2) -> DTGuard(e,loop dt1, match dt2 with None -> None | Some dt -> Some (loop dt))
+	in
+	let lut = DynArray.map loop lut in
+	{
+		dt_first = map.(first);
+		dt_dt_lookup = DynArray.to_array lut;
+		dt_type = t;
+		dt_var_init = List.rev !var_inits;
+	}
 ;;
 ;;
 match_expr_ref := match_expr;
 match_expr_ref := match_expr;
 get_pattern_locals_ref := get_pattern_locals
 get_pattern_locals_ref := get_pattern_locals

+ 14 - 9
optimizer.ml

@@ -32,7 +32,7 @@ let has_side_effect e =
 	let rec loop e =
 	let rec loop e =
 		match e.eexpr with
 		match e.eexpr with
 		| TConst _ | TLocal _ | TField (_,FEnum _) | TTypeExpr _ | TFunction _ -> ()
 		| TConst _ | TLocal _ | TField (_,FEnum _) | TTypeExpr _ | TFunction _ -> ()
-		| TMatch _ | TNew _ | TCall _ | TField _ | TArray _ | TBinop ((OpAssignOp _ | OpAssign),_,_) | TUnop ((Increment|Decrement),_,_) -> raise Exit
+		| TPatMatch _ | TNew _ | TCall _ | TField _ | TEnumParameter _ | TArray _ | TBinop ((OpAssignOp _ | OpAssign),_,_) | TUnop ((Increment|Decrement),_,_) -> raise Exit
 		| TReturn _ | TBreak | TContinue | TThrow _ | TCast (_,Some _) -> raise Exit
 		| TReturn _ | TBreak | TContinue | TThrow _ | TCast (_,Some _) -> raise Exit
 		| TCast (_,None) | TBinop _ | TUnop _ | TParenthesis _ | TMeta _ | TWhile _ | TFor _ | TIf _ | TTry _ | TSwitch _ | TArrayDecl _ | TVars _ | TBlock _ | TObjectDecl _ -> Type.iter loop e
 		| TCast (_,None) | TBinop _ | TUnop _ | TParenthesis _ | TMeta _ | TWhile _ | TFor _ | TIf _ | TTry _ | TSwitch _ | TArrayDecl _ | TVars _ | TBlock _ | TObjectDecl _ -> Type.iter loop e
 	in
 	in
@@ -241,14 +241,17 @@ let rec type_inline ctx cf f ethis params tret config p force =
 			let eloop = map false eloop in
 			let eloop = map false eloop in
 			in_loop := old;
 			in_loop := old;
 			{ e with eexpr = TWhile (cond,eloop,flag) }
 			{ e with eexpr = TWhile (cond,eloop,flag) }
-		| TMatch (v,en,cases,def) ->
+(* 		| TMatch (v,en,cases,def) ->
 			let term = term && def <> None in
 			let term = term && def <> None in
 			let cases = List.map (fun (i,vl,e) ->
 			let cases = List.map (fun (i,vl,e) ->
 				let vl = opt (List.map (fun v -> opt (fun v -> (local v).i_subst) v)) vl in
 				let vl = opt (List.map (fun v -> opt (fun v -> (local v).i_subst) v)) vl in
 				i, vl, map term e
 				i, vl, map term e
 			) cases in
 			) cases in
 			let def = opt (map term) def in
 			let def = opt (map term) def in
-			{ e with eexpr = TMatch (map false v,en,cases,def); etype = if term && ret_val then unify_min ctx ((List.map (fun (_,_,e) -> e) cases) @ (match def with None -> [] | Some e -> [e])) else e.etype }
+			{ e with eexpr = TMatch (map false v,en,cases,def); etype = if term && ret_val then unify_min ctx ((List.map (fun (_,_,e) -> e) cases) @ (match def with None -> [] | Some e -> [e])) else e.etype } *)
+		| TPatMatch _ ->
+			cancel_inlining := true; (* TODO *)
+			e
 		| TSwitch (e1,cases,def) when term ->
 		| TSwitch (e1,cases,def) when term ->
 			let term = term && def <> None in
 			let term = term && def <> None in
 			let cases = List.map (fun (el,e) ->
 			let cases = List.map (fun (el,e) ->
@@ -332,7 +335,7 @@ let rec type_inline ctx cf f ethis params tret config p force =
 	in
 	in
 	let is_writable e =
 	let is_writable e =
 		match e.eexpr with
 		match e.eexpr with
-		| TField _ | TLocal _ | TArray _ -> true
+		| TField _ | TEnumParameter _ | TLocal _ | TArray _ -> true
 		| _  -> false
 		| _  -> false
 	in
 	in
 	let force = ref force in
 	let force = ref force in
@@ -600,9 +603,9 @@ let standard_precedence op =
 
 
 let rec need_parent e =
 let rec need_parent e =
 	match e.eexpr with
 	match e.eexpr with
-	| TConst _ | TLocal _ | TArray _ | TField _ | TParenthesis _ | TMeta _ | TCall _ | TNew _ | TTypeExpr _ | TObjectDecl _ | TArrayDecl _ -> false
+	| TConst _ | TLocal _ | TArray _ | TField _ | TEnumParameter _ | TParenthesis _ | TMeta _ | TCall _ | TNew _ | TTypeExpr _ | TObjectDecl _ | TArrayDecl _ -> false
 	| TCast (e,None) -> need_parent e
 	| TCast (e,None) -> need_parent e
-	| TCast _ | TThrow _ | TReturn _ | TTry _ | TMatch _ | TSwitch _ | TFor _ | TIf _ | TWhile _ | TBinop _ | TContinue | TBreak
+	| TCast _ | TThrow _ | TReturn _ | TTry _ | TPatMatch _ | TSwitch _ | TFor _ | TIf _ | TWhile _ | TBinop _ | TContinue | TBreak
 	| TBlock _ | TVars _ | TFunction _ | TUnop _ -> true
 	| TBlock _ | TVars _ | TFunction _ | TUnop _ -> true
 
 
 let rec add_final_return e t =
 let rec add_final_return e t =
@@ -644,7 +647,7 @@ let sanitize_expr com e =
 		match e.eexpr with
 		match e.eexpr with
 		| TVars _	(* needs to be put into blocks *)
 		| TVars _	(* needs to be put into blocks *)
 		| TFor _	(* a temp var is needed for holding iterator *)
 		| TFor _	(* a temp var is needed for holding iterator *)
-		| TMatch _	(* a temp var is needed for holding enum *)
+		| TPatMatch _	(* a temp var is needed for holding enum *)
 		| TCall ({ eexpr = TLocal { v_name = "__js__" } },_) (* we never know *)
 		| TCall ({ eexpr = TLocal { v_name = "__js__" } },_) (* we never know *)
 			-> block e
 			-> block e
 		| _ -> e
 		| _ -> e
@@ -714,6 +717,8 @@ let sanitize_expr com e =
 		{ e with eexpr = TFunction f }
 		{ e with eexpr = TFunction f }
 	| TCall (e2,args) ->
 	| TCall (e2,args) ->
 		if need_parent e2 then { e with eexpr = TCall(parent e2,args) } else e
 		if need_parent e2 then { e with eexpr = TCall(parent e2,args) } else e
+	| TEnumParameter (e2,i) ->
+		if need_parent e2 then { e with eexpr = TEnumParameter(parent e2,i) } else e
 	| TField (e2,f) ->
 	| TField (e2,f) ->
 		if need_parent e2 then { e with eexpr = TField(parent e2,f) } else e
 		if need_parent e2 then { e with eexpr = TField(parent e2,f) } else e
 	| TArray (e1,e2) ->
 	| TArray (e1,e2) ->
@@ -727,11 +732,11 @@ let sanitize_expr com e =
 		let cases = List.map (fun (el,e) -> el, complex e) cases in
 		let cases = List.map (fun (el,e) -> el, complex e) cases in
 		let def = (match def with None -> None | Some e -> Some (complex e)) in
 		let def = (match def with None -> None | Some e -> Some (complex e)) in
 		{ e with eexpr = TSwitch (e1,cases,def) }
 		{ e with eexpr = TSwitch (e1,cases,def) }
-	| TMatch (e1, en, cases, def) ->
+(* 	| TMatch (e1, en, cases, def) ->
 		let e1 = parent e1 in
 		let e1 = parent e1 in
 		let cases = List.map (fun (el,vars,e) -> el, vars, complex e) cases in
 		let cases = List.map (fun (el,vars,e) -> el, vars, complex e) cases in
 		let def = (match def with None -> None | Some e -> Some (complex e)) in
 		let def = (match def with None -> None | Some e -> Some (complex e)) in
-		{ e with eexpr = TMatch (e1,en,cases,def) }
+		{ e with eexpr = TMatch (e1,en,cases,def) } *)
 	| _ ->
 	| _ ->
 		e
 		e
 
 

+ 1 - 1
tests/unit/Test.hx

@@ -223,7 +223,7 @@ class Test #if swf_mark implements mt.Protect #end {
 		#end
 		#end
 		var classes = [
 		var classes = [
 			new TestOps(),
 			new TestOps(),
-			new TestBasetypes(),
+			//new TestBasetypes(),
 			new TestBytes(),
 			new TestBytes(),
 			new TestIO(),
 			new TestIO(),
 			new TestLocals(),
 			new TestLocals(),

+ 88 - 34
type.ml

@@ -119,7 +119,7 @@ and texpr_expr =
 	| TIf of texpr * texpr * texpr option
 	| TIf of texpr * texpr * texpr option
 	| TWhile of texpr * texpr * Ast.while_flag
 	| TWhile of texpr * texpr * Ast.while_flag
 	| TSwitch of texpr * (texpr list * texpr) list * texpr option
 	| TSwitch of texpr * (texpr list * texpr) list * texpr option
-	| TMatch of texpr * (tenum * tparams) * (int list * tvar option list option * texpr) list * texpr option
+	| TPatMatch of decision_tree
 	| TTry of texpr * (tvar * texpr) list
 	| TTry of texpr * (tvar * texpr) list
 	| TReturn of texpr option
 	| TReturn of texpr option
 	| TBreak
 	| TBreak
@@ -127,6 +127,7 @@ and texpr_expr =
 	| TThrow of texpr
 	| TThrow of texpr
 	| TCast of texpr * module_type option
 	| TCast of texpr * module_type option
 	| TMeta of metadata_entry * texpr
 	| TMeta of metadata_entry * texpr
+	| TEnumParameter of texpr * int
 
 
 and tfield_access =
 and tfield_access =
 	| FInstance of tclass * tclass_field
 	| FInstance of tclass * tclass_field
@@ -290,6 +291,20 @@ and module_kind =
 	| MMacro
 	| MMacro
 	| MFake
 	| MFake
 
 
+and dt =
+	| DTSwitch of texpr * (texpr * dt) list
+	| DTBind of ((tvar * pos) * texpr) list * dt
+	| DTGoto of int
+	| DTExpr of texpr
+	| DTGuard of texpr * dt * dt option
+
+and decision_tree = {
+	dt_dt_lookup : dt array;
+	dt_first : int;
+	dt_type : t;
+	dt_var_init : (tvar * texpr option) list;
+}
+
 let alloc_var =
 let alloc_var =
 	let uid = ref 0 in
 	let uid = ref 0 in
 	(fun n t -> incr uid; { v_name = n; v_type = t; v_id = !uid; v_capture = false; v_extra = None })
 	(fun n t -> incr uid; { v_name = n; v_type = t; v_id = !uid; v_capture = false; v_extra = None })
@@ -1269,6 +1284,14 @@ and unify_with_access t1 f2 =
 	(* read/write *)
 	(* read/write *)
 	| _ -> type_eq EqBothDynamic t1 f2.cf_type
 	| _ -> type_eq EqBothDynamic t1 f2.cf_type
 
 
+let iter_dt f dt = match dt with
+	| DTBind(_,dt) -> f dt
+	| DTSwitch(_,cl) -> List.iter (fun (_,dt) -> f dt) cl
+	| DTGuard(_,dt1,dt2) ->
+		f dt1;
+		(match dt2 with None -> () | Some dt -> f dt)
+	| DTGoto _ | DTExpr _ -> ()
+
 let iter f e =
 let iter f e =
 	match e.eexpr with
 	match e.eexpr with
 	| TConst _
 	| TConst _
@@ -1285,6 +1308,7 @@ let iter f e =
 		f e2;
 		f e2;
 	| TThrow e
 	| TThrow e
 	| TField (e,_)
 	| TField (e,_)
+	| TEnumParameter (e,_)
 	| TParenthesis e
 	| TParenthesis e
 	| TCast (e,_)
 	| TCast (e,_)
 	| TUnop (_,_,e)
 	| TUnop (_,_,e)
@@ -1311,10 +1335,24 @@ let iter f e =
 		f e;
 		f e;
 		List.iter (fun (el,e2) -> List.iter f el; f e2) cases;
 		List.iter (fun (el,e2) -> List.iter f el; f e2) cases;
 		(match def with None -> () | Some e -> f e)
 		(match def with None -> () | Some e -> f e)
-	| TMatch (e,_,cases,def) ->
-		f e;
-		List.iter (fun (_,_,e) -> f e) cases;
-		(match def with None -> () | Some e -> f e)
+	| TPatMatch dt ->
+		let rec loop dt = match dt with
+			| DTBind(_,dt) -> loop dt
+			| DTGoto _ -> ()
+			| DTSwitch(e,cl) ->
+				f e;
+				List.iter (fun (e,dt) ->
+					f e;
+					loop dt
+				) cl
+			| DTExpr e -> f e
+			| DTGuard(eg,dt1,dt2) ->
+				f eg;
+				loop dt1;
+				(match dt2 with None -> () | Some dt -> loop dt)
+		in
+		List.iter (fun (_,eo) -> match eo with None -> () | Some e -> f e) dt.dt_var_init;
+		Array.iter loop dt.dt_dt_lookup
 	| TTry (e,catches) ->
 	| TTry (e,catches) ->
 		f e;
 		f e;
 		List.iter (fun (_,e) -> f e) catches
 		List.iter (fun (_,e) -> f e) catches
@@ -1339,6 +1377,8 @@ let map_expr f e =
 		{ e with eexpr = TWhile (f e1,f e2,flag) }
 		{ e with eexpr = TWhile (f e1,f e2,flag) }
 	| TThrow e1 ->
 	| TThrow e1 ->
 		{ e with eexpr = TThrow (f e1) }
 		{ e with eexpr = TThrow (f e1) }
+	| TEnumParameter (e1,i) ->
+		 { e with eexpr = TEnumParameter(f e1,i) }
 	| TField (e1,v) ->
 	| TField (e1,v) ->
 		{ e with eexpr = TField (f e1,v) }
 		{ e with eexpr = TField (f e1,v) }
 	| TParenthesis e1 ->
 	| TParenthesis e1 ->
@@ -1363,8 +1403,16 @@ let map_expr f e =
 		{ e with eexpr = TIf (f ec,f e1,match e2 with None -> None | Some e -> Some (f e)) }
 		{ e with eexpr = TIf (f ec,f e1,match e2 with None -> None | Some e -> Some (f e)) }
 	| TSwitch (e1,cases,def) ->
 	| TSwitch (e1,cases,def) ->
 		{ e with eexpr = TSwitch (f e1, List.map (fun (el,e2) -> List.map f el, f e2) cases, match def with None -> None | Some e -> Some (f e)) }
 		{ e with eexpr = TSwitch (f e1, List.map (fun (el,e2) -> List.map f el, f e2) cases, match def with None -> None | Some e -> Some (f e)) }
-	| TMatch (e1,t,cases,def) ->
-		{ e with eexpr = TMatch (f e1, t, List.map (fun (cl,params,e) -> cl, params, f e) cases, match def with None -> None | Some e -> Some (f e)) }
+	| TPatMatch dt ->
+		let rec loop dt = match dt with
+			| DTBind(vl,dt) -> DTBind(vl, loop dt)
+			| DTGoto _ -> dt
+			| DTSwitch(e,cl) -> DTSwitch(f e, List.map (fun (e,dt) -> f e,loop dt) cl)
+			| DTExpr e -> DTExpr(f e)
+			| DTGuard(e,dt1,dt2) -> DTGuard(f e,loop dt1,match dt2 with None -> None | Some dt -> Some (loop dt))
+		in
+		let vi = List.map (fun (v,eo) -> v, match eo with None -> None | Some e -> Some(f e)) dt.dt_var_init in
+		{ e with eexpr = TPatMatch({dt with dt_dt_lookup = Array.map loop dt.dt_dt_lookup; dt_var_init = vi})}
 	| TTry (e1,catches) ->
 	| TTry (e1,catches) ->
 		{ e with eexpr = TTry (f e1, List.map (fun (v,e) -> v, f e) catches) }
 		{ e with eexpr = TTry (f e1, List.map (fun (v,e) -> v, f e) catches) }
 	| TReturn eo ->
 	| TReturn eo ->
@@ -1393,6 +1441,8 @@ let map_expr_type f ft fv e =
 		{ e with eexpr = TWhile (f e1,f e2,flag); etype = ft e.etype }
 		{ e with eexpr = TWhile (f e1,f e2,flag); etype = ft e.etype }
 	| TThrow e1 ->
 	| TThrow e1 ->
 		{ e with eexpr = TThrow (f e1); etype = ft e.etype }
 		{ e with eexpr = TThrow (f e1); etype = ft e.etype }
+	| TEnumParameter (e1,i) ->
+		{ e with eexpr = TEnumParameter(f e1,i); etype = ft e.etype }
 	| TField (e1,v) ->
 	| TField (e1,v) ->
 		{ e with eexpr = TField (f e1,v); etype = ft e.etype }
 		{ e with eexpr = TField (f e1,v); etype = ft e.etype }
 	| TParenthesis e1 ->
 	| TParenthesis e1 ->
@@ -1425,15 +1475,16 @@ let map_expr_type f ft fv e =
 		{ e with eexpr = TIf (f ec,f e1,match e2 with None -> None | Some e -> Some (f e)); etype = ft e.etype }
 		{ e with eexpr = TIf (f ec,f e1,match e2 with None -> None | Some e -> Some (f e)); etype = ft e.etype }
 	| TSwitch (e1,cases,def) ->
 	| TSwitch (e1,cases,def) ->
 		{ e with eexpr = TSwitch (f e1, List.map (fun (el,e2) -> List.map f el, f e2) cases, match def with None -> None | Some e -> Some (f e)); etype = ft e.etype }
 		{ e with eexpr = TSwitch (f e1, List.map (fun (el,e2) -> List.map f el, f e2) cases, match def with None -> None | Some e -> Some (f e)); etype = ft e.etype }
-	| TMatch (e1,(en,pl),cases,def) ->
-		let map_case (cl,params,e) =
-			let params = match params with
-				| None -> None
-				| Some l -> Some (List.map (function None -> None | Some v -> Some (fv v)) l)
-			in
-			cl, params, f e
+	| TPatMatch dt ->
+		let rec loop dt = match dt with
+			| DTBind(vl,dt) -> DTBind(vl, loop dt)
+			| DTGoto _ -> dt
+			| DTSwitch(e,cl) -> DTSwitch(f e, List.map (fun (e,dt) -> f e,loop dt) cl)
+			| DTExpr e -> DTExpr(f e)
+			| DTGuard (e,dt1,dt2) -> DTGuard(f e, loop dt, match dt2 with None -> None | Some dt -> Some (loop dt))
 		in
 		in
-		{ e with eexpr = TMatch (f e1, (en,List.map ft pl), List.map map_case cases, match def with None -> None | Some e -> Some (f e)); etype = ft e.etype }
+		let vi = List.map (fun (v,eo) -> v, match eo with None -> None | Some e -> Some(f e)) dt.dt_var_init in
+		{ e with eexpr = TPatMatch({dt with dt_dt_lookup = Array.map loop dt.dt_dt_lookup; dt_var_init = vi}); etype = ft e.etype}
 	| TTry (e1,catches) ->
 	| TTry (e1,catches) ->
 		{ e with eexpr = TTry (f e1, List.map (fun (v,e) -> fv v, f e) catches); etype = ft e.etype }
 		{ e with eexpr = TTry (f e1, List.map (fun (v,e) -> fv v, f e) catches); etype = ft e.etype }
 	| TReturn eo ->
 	| TReturn eo ->
@@ -1449,6 +1500,7 @@ let s_expr_kind e =
 	| TLocal _ -> "Local"
 	| TLocal _ -> "Local"
 	| TArray (_,_) -> "Array"
 	| TArray (_,_) -> "Array"
 	| TBinop (_,_,_) -> "Binop"
 	| TBinop (_,_,_) -> "Binop"
+	| TEnumParameter (_,_) -> "EnumParameter"
 	| TField (_,_) -> "Field"
 	| TField (_,_) -> "Field"
 	| TTypeExpr _ -> "TypeExpr"
 	| TTypeExpr _ -> "TypeExpr"
 	| TParenthesis _ -> "Parenthesis"
 	| TParenthesis _ -> "Parenthesis"
@@ -1464,7 +1516,7 @@ let s_expr_kind e =
 	| TIf (_,_,_) -> "If"
 	| TIf (_,_,_) -> "If"
 	| TWhile (_,_,_) -> "While"
 	| TWhile (_,_,_) -> "While"
 	| TSwitch (_,_,_) -> "Switch"
 	| TSwitch (_,_,_) -> "Switch"
-	| TMatch (_,_,_,_) -> "Match"
+	| TPatMatch _ -> "PatMatch"
 	| TTry (_,_) -> "Try"
 	| TTry (_,_) -> "Try"
 	| TReturn _ -> "Return"
 	| TReturn _ -> "Return"
 	| TBreak -> "Break"
 	| TBreak -> "Break"
@@ -1496,6 +1548,8 @@ let rec s_expr s_type e =
 		sprintf "%s[%s]" (loop e1) (loop e2)
 		sprintf "%s[%s]" (loop e1) (loop e2)
 	| TBinop (op,e1,e2) ->
 	| TBinop (op,e1,e2) ->
 		sprintf "(%s %s %s)" (loop e1) (s_binop op) (loop e2)
 		sprintf "(%s %s %s)" (loop e1) (s_binop op) (loop e2)
+	| TEnumParameter (e1,i) ->
+		sprintf "%s[%i]" (loop e1) i
 	| TField (e,f) ->
 	| TField (e,f) ->
 		let fstr = (match f with
 		let fstr = (match f with
 			| FStatic (c,f) -> "static(" ^ s_type_path c.cl_path ^ "." ^ f.cf_name ^ ")"
 			| FStatic (c,f) -> "static(" ^ s_type_path c.cl_path ^ "." ^ f.cf_name ^ ")"
@@ -1539,10 +1593,7 @@ let rec s_expr s_type e =
 		| DoWhile -> sprintf "DoWhile (%s,%s)" (loop e) (loop econd))
 		| DoWhile -> sprintf "DoWhile (%s,%s)" (loop e) (loop econd))
 	| TSwitch (e,cases,def) ->
 	| TSwitch (e,cases,def) ->
 		sprintf "Switch (%s,(%s)%s)" (loop e) (slist (fun (cl,e) -> sprintf "case %s: %s" (slist loop cl) (loop e)) cases) (match def with None -> "" | Some e -> "," ^ loop e)
 		sprintf "Switch (%s,(%s)%s)" (loop e) (slist (fun (cl,e) -> sprintf "case %s: %s" (slist loop cl) (loop e)) cases) (match def with None -> "" | Some e -> "," ^ loop e)
-	| TMatch (e,(en,tparams),cases,def) ->
-		let args vl = slist (function None -> "_" | Some v -> sprintf "%s : %s" (s_var v) (s_type v.v_type)) vl in
-		let cases = slist (fun (il,vl,e) -> sprintf "case %s%s : %s" (slist string_of_int il) (match vl with None -> "" | Some vl -> sprintf "(%s)" (args vl)) (loop e)) cases in
-		sprintf "Match %s (%s,(%s)%s)" (s_type (TEnum (en,tparams))) (loop e) cases (match def with None -> "" | Some e -> "," ^ loop e)
+	| TPatMatch dt -> s_dt "" (dt.dt_dt_lookup.(dt.dt_first))
 	| TTry (e,cl) ->
 	| TTry (e,cl) ->
 		sprintf "Try %s(%s) " (loop e) (slist (fun (v,e) -> sprintf "catch( %s : %s ) %s" (s_var v) (s_type v.v_type) (loop e)) cl)
 		sprintf "Try %s(%s) " (loop e) (slist (fun (v,e) -> sprintf "catch( %s : %s ) %s" (s_var v) (s_type v.v_type) (loop e)) cl)
 	| TReturn None ->
 	| TReturn None ->
@@ -1562,6 +1613,21 @@ let rec s_expr s_type e =
 	) in
 	) in
 	sprintf "(%s : %s)" str (s_type e.etype)
 	sprintf "(%s : %s)" str (s_type e.etype)
 
 
+and s_dt tabs tree =
+	let s_type = s_type (print_context()) in
+	tabs ^ match tree with
+	| DTSwitch (st, cl) ->
+		"switch(" ^ (s_expr s_type st) ^ ") { \n" ^ tabs
+		^ (String.concat ("\n" ^ tabs) (List.map (fun (c,dt) ->
+			"case " ^ (s_expr s_type c) ^ ":\n" ^ (s_dt (tabs ^ "\t") dt)
+		) cl))
+		^ "\n" ^ (if String.length tabs = 0 then "" else (String.sub tabs 0 (String.length tabs - 1))) ^ "}"
+	| DTBind (bl, dt) -> "bind " ^ (String.concat "," (List.map (fun ((v,_),st) -> v.v_name ^ "(" ^ (string_of_int v.v_id) ^ ") =" ^ (s_expr s_type st)) bl)) ^ "\n" ^ (s_dt tabs dt)
+	| DTGoto i ->
+		"goto " ^ (string_of_int i)
+	| DTExpr e -> s_expr s_type e
+	| DTGuard (e,dt1,dt2) -> "if(" ^ (s_expr s_type e) ^ ") " ^ (s_dt tabs dt1) ^ (match dt2 with None -> "" | Some dt -> " else " ^ (s_dt tabs dt))
+
 let rec s_expr_pretty tabs s_type e =
 let rec s_expr_pretty tabs s_type e =
 	let sprintf = Printf.sprintf in
 	let sprintf = Printf.sprintf in
 	let loop = s_expr_pretty tabs s_type in
 	let loop = s_expr_pretty tabs s_type in
@@ -1571,6 +1637,7 @@ let rec s_expr_pretty tabs s_type e =
 	| TLocal v -> v.v_name
 	| TLocal v -> v.v_name
 	| TArray (e1,e2) -> sprintf "%s[%s]" (loop e1) (loop e2)
 	| TArray (e1,e2) -> sprintf "%s[%s]" (loop e1) (loop e2)
 	| TBinop (op,e1,e2) -> sprintf "%s %s %s" (loop e1) (s_binop op) (loop e2)
 	| TBinop (op,e1,e2) -> sprintf "%s %s %s" (loop e1) (s_binop op) (loop e2)
+	| TEnumParameter (e1,i) -> sprintf "%s[%i]" (loop e1) i
 	| TField (e1,s) -> sprintf "%s.%s" (loop e1) (field_name s)
 	| TField (e1,s) -> sprintf "%s.%s" (loop e1) (field_name s)
 	| TTypeExpr mt -> (s_type_path (t_path mt))
 	| TTypeExpr mt -> (s_type_path (t_path mt))
 	| TParenthesis e1 -> sprintf "(%s)" (loop e1)
 	| TParenthesis e1 -> sprintf "(%s)" (loop e1)
@@ -1604,20 +1671,7 @@ let rec s_expr_pretty tabs s_type e =
 		let ntabs = tabs ^ "\t" in
 		let ntabs = tabs ^ "\t" in
 		let s = sprintf "switch (%s) {\n%s%s" (loop e) (slist (fun (cl,e) -> sprintf "%scase %s: %s\n" ntabs (slist loop cl) (s_expr_pretty ntabs s_type e)) cases) (match def with None -> "" | Some e -> ntabs ^ "default: " ^ (s_expr_pretty ntabs s_type e) ^ "\n") in
 		let s = sprintf "switch (%s) {\n%s%s" (loop e) (slist (fun (cl,e) -> sprintf "%scase %s: %s\n" ntabs (slist loop cl) (s_expr_pretty ntabs s_type e)) cases) (match def with None -> "" | Some e -> ntabs ^ "default: " ^ (s_expr_pretty ntabs s_type e) ^ "\n") in
 		s ^ tabs ^ "}"
 		s ^ tabs ^ "}"
-	| TMatch (e,(en,tparams),cases,def) ->
-		let ntabs = tabs ^ "\t" in
-		let cases = slist (fun (il,vl,e) ->
-			let ctor i = (PMap.find (List.nth en.e_names i) en.e_constrs).ef_name in
-			let ctors = String.concat "," (List.map ctor il) in
-			begin match vl with
-				| None ->
-					sprintf "%scase %s: %s\n" ntabs ctors (s_expr_pretty ntabs s_type e)
-				| Some vl ->
-					sprintf "%scase %s(%s): %s\n" ntabs ctors (String.concat "," (List.map (fun v -> match v with None -> "_" | Some v -> v.v_name) vl)) (s_expr_pretty ntabs s_type e)
-			end
-		) cases in
-		let s = sprintf "switch (%s) {\n%s%s" (loop e) cases (match def with None -> "" | Some e -> ntabs ^ "default: " ^ (s_expr_pretty ntabs s_type e) ^ "\n") in
-		s ^ tabs ^ "}"
+	| TPatMatch dt -> s_dt tabs (dt.dt_dt_lookup.(dt.dt_first))
 	| TTry (e,cl) ->
 	| TTry (e,cl) ->
 		sprintf "try %s%s" (loop e) (slist (fun (v,e) -> sprintf "catch( %s : %s ) %s" v.v_name (s_type v.v_type) (loop e)) cl)
 		sprintf "try %s%s" (loop e) (slist (fun (v,e) -> sprintf "catch( %s : %s ) %s" v.v_name (s_type v.v_type) (loop e)) cl)
 	| TReturn None ->
 	| TReturn None ->

+ 2 - 1
typecore.ml

@@ -138,8 +138,9 @@ exception DisplayPosition of Ast.pos list
 
 
 let make_call_ref : (typer -> texpr -> texpr list -> t -> pos -> texpr) ref = ref (fun _ _ _ _ _ -> assert false)
 let make_call_ref : (typer -> texpr -> texpr list -> t -> pos -> texpr) ref = ref (fun _ _ _ _ _ -> assert false)
 let type_expr_ref : (typer -> Ast.expr -> with_type -> texpr) ref = ref (fun _ _ _ -> assert false)
 let type_expr_ref : (typer -> Ast.expr -> with_type -> texpr) ref = ref (fun _ _ _ -> assert false)
+let type_module_type_ref : (typer -> module_type -> t list option -> pos -> texpr) ref = ref (fun _ _ _ _ -> assert false)
 let unify_min_ref : (typer -> texpr list -> t) ref = ref (fun _ _ -> assert false)
 let unify_min_ref : (typer -> texpr list -> t) ref = ref (fun _ _ -> assert false)
-let match_expr_ref : (typer -> Ast.expr -> (Ast.expr list * Ast.expr option * Ast.expr option) list -> Ast.expr option option -> with_type -> Ast.pos -> texpr) ref = ref (fun _ _ _ _ _ _ -> assert false)
+let match_expr_ref : (typer -> Ast.expr -> (Ast.expr list * Ast.expr option * Ast.expr option) list -> Ast.expr option option -> with_type -> Ast.pos -> decision_tree) ref = ref (fun _ _ _ _ _ _ -> assert false)
 let get_pattern_locals_ref : (typer -> Ast.expr -> Type.t -> (string, tvar) PMap.t) ref = ref (fun _ _ _ -> assert false)
 let get_pattern_locals_ref : (typer -> Ast.expr -> Type.t -> (string, tvar) PMap.t) ref = ref (fun _ _ _ -> assert false)
 let get_constructor_ref : (typer -> tclass -> t list -> Ast.pos -> (t * tclass_field)) ref = ref (fun _ _ _ _ -> assert false)
 let get_constructor_ref : (typer -> tclass -> t list -> Ast.pos -> (t * tclass_field)) ref = ref (fun _ _ _ _ -> assert false)
 let check_abstract_cast_ref : (typer -> t -> texpr -> Ast.pos -> texpr) ref = ref (fun _ _ _ _ -> assert false)
 let check_abstract_cast_ref : (typer -> t -> texpr -> Ast.pos -> texpr) ref = ref (fun _ _ _ _ -> assert false)

+ 12 - 4
typeload.ml

@@ -881,11 +881,19 @@ let rec return_flow ctx e =
 	| TSwitch (v,cases,Some e) ->
 	| TSwitch (v,cases,Some e) ->
 		List.iter (fun (_,e) -> return_flow e) cases;
 		List.iter (fun (_,e) -> return_flow e) cases;
 		return_flow e
 		return_flow e
-	| TSwitch (e,cases,None) when (match follow e.etype with TEnum _ -> true | _ -> false) ->
+	| TSwitch ({eexpr = TMeta((Meta.Exhaustive,_,_),_)},cases,None) ->
 		List.iter (fun (_,e) -> return_flow e) cases;
 		List.iter (fun (_,e) -> return_flow e) cases;
-	| TMatch (_,_,cases,def) ->
-		List.iter (fun (_,_,e) -> return_flow e) cases;
-		(match def with None -> () | Some e -> return_flow e)
+	| TPatMatch dt ->
+		let rec loop d = match d with
+			| DTExpr e -> return_flow e
+			| DTGuard(_,dt1,dt2) ->
+				loop dt1;
+				(match dt2 with None -> () | Some dt -> loop dt)
+			| DTBind (_,d) -> loop d
+			| DTSwitch (_,cl) -> List.iter (fun (_,dt) -> loop dt) cl
+			| DTGoto i -> loop (dt.dt_dt_lookup.(i))
+		in
+		loop (dt.dt_dt_lookup.(dt.dt_first))
 	| TTry (e,cases) ->
 	| TTry (e,cases) ->
 		return_flow e;
 		return_flow e;
 		List.iter (fun (_,e) -> return_flow e) cases;
 		List.iter (fun (_,e) -> return_flow e) cases;

+ 29 - 186
typer.ml

@@ -1881,102 +1881,6 @@ and type_unop ctx op flag e p =
 
 
 and type_switch_old ctx e cases def with_type p =
 and type_switch_old ctx e cases def with_type p =
 	let eval = type_expr ctx e Value in
 	let eval = type_expr ctx e Value in
-	let old_m = ctx.m in
-	let enum = ref None in
-	let used_cases = Hashtbl.create 0 in
-	let is_fake_enum e =
-		e.e_path = ([],"Bool") || Meta.has Meta.FakeEnum e.e_meta
-	in
-	(match follow eval.etype with
-	| TEnum (e,_) when is_fake_enum e -> ()
-	| TEnum (e,params) ->
-		enum := Some (Some (e,params));
-		(* hack to prioritize enum lookup *)
-		ctx.m <- { ctx.m with module_types = TEnumDecl e :: ctx.m.module_types }
-	| TMono _ ->
-		enum := Some None;
-	| t ->
-		if t == t_dynamic then enum := Some None
-	);
-	let case_expr c =
-		enum := None;
-		(* this inversion is needed *)
-		unify ctx eval.etype c.etype c.epos;
-		CExpr c
-	in
-	let type_match e en s pl =
-		let p = e.epos in
-		let params = (match !enum with
-			| None ->
-				assert false
-			| Some None when is_fake_enum en ->
-				raise Exit
-			| Some None ->
-				let params = List.map (fun _ -> mk_mono()) en.e_types in
-				enum := Some (Some (en,params));
-				unify ctx eval.etype (TEnum (en,params)) p;
-				params
-			| Some (Some (en2,params)) ->
-				if en != en2 then error ("This constructor is part of enum " ^ s_type_path en.e_path ^ " but is matched with enum " ^ s_type_path en2.e_path) p;
-				params
-		) in
-		if Hashtbl.mem used_cases s then error "This constructor has already been used" p;
-		Hashtbl.add used_cases s ();
-		let cst = (try PMap.find s en.e_constrs with Not_found -> assert false) in
-		let et = apply_params en.e_types params (monomorphs cst.ef_params cst.ef_type) in
-		let pl, rt = (match et with
-		| TFun (l,rt) ->
-			let pl = (if List.length l = List.length pl then pl else
-				match pl with
-				| [None] -> List.map (fun _ -> None) l
-				| _ -> error ("This constructor requires " ^ string_of_int (List.length l) ^ " arguments") p
-			) in
-			Some (List.map2 (fun p (_,_,t) -> match p with None -> None | Some p -> Some (p, t)) pl l), rt
-		| TEnum _ ->
-			if pl <> [] then error "This constructor does not require any argument" p;
-			None, et
-		| _ -> assert false
-		) in
-		unify ctx rt eval.etype p;
-		CMatch (cst,pl,p)
-	in
-	let type_case efull e pl p =
-		try
-			let e = (match !enum, e with
-			| None, _ -> raise Exit
-			| Some (Some (en,params)), (EConst (Ident i),p) ->
-				let ef = (try
-					PMap.find i en.e_constrs
-				with Not_found ->
-					display_error ctx ("This constructor is not part of the enum " ^ s_type_path en.e_path) p;
-					raise Exit
-				) in
-				mk (fast_enum_field en ef p) (apply_params en.e_types params ef.ef_type) (snd e)
-			| _ ->
-				type_expr ctx e Value
-			) in
-			let pl = List.map (fun e ->
-				match fst e with
-				| EConst (Ident "_") -> None
-				| EConst (Ident i) -> Some i
-				| _ -> raise Exit
-			) pl in
-			(match e.eexpr with
-			| TField (_,FEnum (en,c)) -> type_match e en c.ef_name pl
-			| _ -> if pl = [] then case_expr e else raise Exit)
-		with Exit ->
-			case_expr (type_expr ctx efull Value)
-	in
-	let cases = List.map (fun (el,eg,e2) ->
-		if el = [] then error "Case must match at least one expression" (punion_el el);
-		let el = List.map (fun e ->
-			match e with
-			| (ECall (c,pl),p) -> type_case e c pl p
-			| e -> type_case e e [] (snd e)
-		) el in
-		el, e2
-	) cases in
-	ctx.m <- old_m;
 	let el = ref [] in
 	let el = ref [] in
 	let type_case_code e =
 	let type_case_code e =
 		let e = (match e with
 		let e = (match e with
@@ -1986,6 +1890,23 @@ and type_switch_old ctx e cases def with_type p =
 		el := e :: !el;
 		el := e :: !el;
 		e
 		e
 	in
 	in
+	let consts = Hashtbl.create 0 in
+	let exprs (el,_,e) =
+		let el = List.map (fun e ->
+			match type_expr ctx e (WithType eval.etype) with
+			| { eexpr = TConst c } as e ->
+				if Hashtbl.mem consts c then error "Duplicate constant in switch" e.epos;
+				Hashtbl.add consts c true;
+				e
+			| e ->
+				e
+		) el in
+		let locals = save_locals ctx in
+		let e = type_case_code e in
+		locals();
+		el, e
+	in
+	let cases = List.map exprs cases in
 	let def() = (match def with
 	let def() = (match def with
 		| None -> None
 		| None -> None
 		| Some e ->
 		| Some e ->
@@ -1994,96 +1915,17 @@ and type_switch_old ctx e cases def with_type p =
 			locals();
 			locals();
 			Some e
 			Some e
 	) in
 	) in
-	match !enum with
-	| Some (Some (enum,enparams)) ->
-		let same_params p1 p2 =
-			let l1 = (match p1 with None -> [] | Some l -> l) in
-			let l2 = (match p2 with None -> [] | Some l -> l) in
-			let rec loop = function
-				| [] , [] -> true
-				| None :: l , [] | [] , None :: l -> loop (l,[])
-				| None :: l1, None :: l2 -> loop (l1,l2)
-				| Some (n1,t1) :: l1, Some (n2,t2) :: l2 ->
-					n1 = n2 && type_iseq t1 t2 && loop (l1,l2)
-				| _ -> false
-			in
-			loop (l1,l2)
-		in
-		let matchs (el,e) =
-			match el with
-			| CMatch (c,params,p1) :: l ->
-				let params = ref params in
-				let cl = List.map (fun c ->
-					match c with
-					| CMatch (c,p,p2) ->
-						if not (same_params p !params) then display_error ctx "Constructors parameters differs : should be same name, same type, and same position" p2;
-						if p <> None then params := p;
-						c
-					| _ -> assert false
-				) l in
-				let locals = save_locals ctx in
-				let params = (match !params with
-					| None -> None
-					| Some l ->
-						let has = ref false in
-						let l = List.map (fun v ->
-							match v with
-							| None -> None
-							| Some (v,t) -> has := true; Some (add_local ctx v t)
-						) l in
-						if !has then Some l else None
-				) in
-				let e = type_case_code e in
-				locals();
-				(c :: cl) , params, e
-			| _ ->
-				assert false
-		in
-		let indexes (el,vars,e) =
-			List.map (fun c -> c.ef_index) el, vars, e
-		in
-		let cases = List.map matchs cases in
-		let def = def() in
-		(match def with
-		| Some _ -> ()
-		| None ->
-			let tenum = TEnum(enum,enparams) in
-			let l = PMap.fold (fun c acc ->
-				let t = monomorphs enum.e_types (monomorphs c.ef_params (match c.ef_type with TFun (_,t) -> t | t -> t)) in
-				if Hashtbl.mem used_cases c.ef_name || not (try unify_raise ctx t tenum c.ef_pos; true with Error (Unify _,_) -> false) then acc else c.ef_name :: acc
-			) enum.e_constrs [] in
-			match l with
-			| [] -> ()
-			| _ -> display_error ctx ("Some constructors are not matched : " ^ String.concat "," l) p
-		);
-		let t = if with_type = NoValue then (mk_mono()) else unify_min ctx (List.rev !el) in
-		mk (TMatch (eval,(enum,enparams),List.map indexes cases,def)) t p
-	| _ ->
-		let consts = Hashtbl.create 0 in
-		let exprs (el,e) =
-			let el = List.map (fun c ->
-				match c with
-				| CExpr (({ eexpr = TConst c }) as e) ->
-					if Hashtbl.mem consts c then error "Duplicate constant in switch" e.epos;
-					Hashtbl.add consts c true;
-					e
-				| CExpr c -> c
-				| CMatch (_,_,p) -> error "You cannot use a normal switch on an enum constructor" p
-			) el in
-			let locals = save_locals ctx in
-			let e = type_case_code e in
-			locals();
-			el, e
-		in
-		let cases = List.map exprs cases in
-		let def = def() in
-		let t = if with_type = NoValue then (mk_mono()) else unify_min ctx (List.rev !el) in
-		mk (TSwitch (eval,cases,def)) t p
+	let def = def() in
+	let t = if with_type = NoValue then (mk_mono()) else unify_min ctx (List.rev !el) in
+	mk (TSwitch (eval,cases,def)) t p
 
 
-and type_switch ctx e cases def (with_type:with_type) p =
+and type_switch ctx e cases def with_type p =
 	try
 	try
-		if (Common.defined ctx.com Common.Define.NoPatternMatching) then raise Exit;
-		match_expr ctx e cases def with_type p
+		let dt = match_expr ctx e cases def with_type p in
+		if not ctx.in_macro && not (Common.defined ctx.com Define.Interp) && ctx.com.config.pf_pattern_matching then
+			mk (TPatMatch dt) dt.dt_type p
+		else
+			Codegen.PatternMatchConversion.to_typed_ast ctx dt p
 	with Exit ->
 	with Exit ->
 		type_switch_old ctx e cases def with_type p
 		type_switch_old ctx e cases def with_type p
 
 
@@ -3435,9 +3277,9 @@ let generate ctx =
 				end
 				end
 			in
 			in
 			loop c
 			loop c
-		| TMatch (_,(enum,_),_,_) ->
+(* 		| TMatch (_,(enum,_),_,_) ->
 			loop_enum p enum;
 			loop_enum p enum;
-			iter (walk_expr p) e
+			iter (walk_expr p) e *)
 		| TCall (f,_) ->
 		| TCall (f,_) ->
 			iter (walk_expr p) e;
 			iter (walk_expr p) e;
 			(* static call for initializing a variable *)
 			(* static call for initializing a variable *)
@@ -4163,3 +4005,4 @@ unify_min_ref := unify_min;
 make_call_ref := make_call;
 make_call_ref := make_call;
 get_constructor_ref := get_constructor;
 get_constructor_ref := get_constructor;
 check_abstract_cast_ref := Codegen.Abstract.check_cast;
 check_abstract_cast_ref := Codegen.Abstract.check_cast;
+type_module_type_ref := type_module_type;