Browse Source

group Enum cases

Simon Krajewski 12 years ago
parent
commit
000059411e
1 changed files with 83 additions and 32 deletions
  1. 83 32
      matcher.ml

+ 83 - 32
matcher.ml

@@ -819,6 +819,22 @@ let replace_locals mctx out e =
 	Hashtbl.iter (fun _ p -> mctx.ctx.com.warning "This variable is unused" p) all_subterms;
 	Hashtbl.iter (fun _ p -> mctx.ctx.com.warning "This variable is unused" p) all_subterms;
 	e
 	e
 
 
+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
+	&& (out1.o_bindings = []
+		|| (List.length out1.o_bindings) = (List.length out2.o_bindings)
+		&& (ExtList.List.for_all2 (fun (_,st1) (_,st2) -> st_eq st1 st2) out1.o_bindings out2.o_bindings)
+	)
+
 let rec to_typed_ast mctx dt =
 let rec to_typed_ast mctx dt =
 	match dt with
 	match dt with
 	| Goto _ ->
 	| Goto _ ->
@@ -842,13 +858,6 @@ let rec to_typed_ast mctx dt =
 
 
 and group_cases mctx cases to_case =
 and group_cases mctx cases to_case =
 	let def = ref None in
 	let def = ref None in
-	let is_compatible out1 out2 =
-		out1.o_id = out2.o_id
-		&& out1.o_guard = None
-		&& (out1.o_bindings = []
-			|| (List.length out1.o_bindings) = (List.length out2.o_bindings)
-			&& (ExtList.List.for_all2 (fun ((v1,_),st1) ((v2,_),st2) -> v1.v_name = v2.v_name && (s_st st1) = (s_st st2)) out1.o_bindings out2.o_bindings))
-	in
 	let group,cases,dto = List.fold_left (fun (group,cases,dto) (con,dt) -> match con.c_def with
 	let group,cases,dto = List.fold_left (fun (group,cases,dto) (con,dt) -> match con.c_def with
 		| CConst TNull ->
 		| CConst TNull ->
 			let e = to_typed_ast mctx dt in
 			let e = to_typed_ast mctx dt in
@@ -877,34 +886,76 @@ and group_cases mctx cases to_case =
 and to_enum_switch mctx en pl st cases =
 and to_enum_switch mctx en pl st cases =
 	let eval = st_to_texpr mctx st in
 	let eval = st_to_texpr mctx st in
 	let et = monomorphs mctx.ctx.type_params (TEnum(en,pl)) in
 	let et = monomorphs mctx.ctx.type_params (TEnum(en,pl)) 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
+		let capture_vars = match dt with
+			| Bind(out,None) ->
+				Some out.o_bindings
+			| _ ->
+				None
+		in
+		(* TODO: this is horrible *)
+		let vl = match etf with
+			| TFun(args,r) ->
+				unify mctx.ctx r et p;
+				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
+	in
 	let def = ref None in
 	let def = ref None in
-	let rec loop cases = match cases with
-		| [] ->
-			[]
-		| (({c_def = CEnum(en,ef) }) as con,dt) :: cases ->
-			let save = save_locals mctx.ctx in
-			let etf = follow (monomorphs en.e_types (monomorphs ef.ef_params ef.ef_type)) in
-			let vl = match etf with
-				| TFun(args,r) ->
-					unify mctx.ctx r et con.c_pos;
-					let vl = ExtList.List.mapi (fun i (_,_,t) ->
-						let st = mk_st (SEnum(st,ef.ef_name,i)) t st.st_pos in
-						Some (match (st_to_texpr mctx st).eexpr with TLocal v -> v | _ -> assert false)
-					) args in
-					Some vl
-				| _ -> None
-			in
-			let e = to_typed_ast mctx dt in
-			save();
-			([ef.ef_index],vl,e) :: loop cases
-		| (({c_def = CConst TNull }),dt) :: cases ->
+	let group,cases,dto = List.fold_left (fun (group,cases,dto) (con,dt) -> match con.c_def with
+		| CConst TNull ->
 			let e = to_typed_ast mctx dt in
 			let e = to_typed_ast mctx dt in
 			def := Some e;
 			def := Some e;
-			loop cases
-		| (con,_) :: _ ->
-			error ("Unexpected") con.c_pos
-	in
-	let cases = loop cases in
+			(group,cases,dto)
+		| _ -> match dto with
+			| None -> ([to_case con],cases,Some dt)
+			| Some dt2 -> match dt,dt2 with
+				| Bind(out1,_),Bind(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
 	mk (TMatch(eval,(en,pl),cases,!def)) mctx.out_type eval.epos
 
 
 and to_value_switch mctx t st cases =
 and to_value_switch mctx t st cases =