Browse Source

to_pattern cleanup and support for dynamic input

Simon Krajewski 12 years ago
parent
commit
90ce029f2e
1 changed files with 156 additions and 142 deletions
  1. 156 142
      matcher.ml

+ 156 - 142
matcher.ml

@@ -233,78 +233,136 @@ let unify_enum_field en pl ef t =
 (* Transform an expression to a pattern *)
 (* TODO: sanity check this *)
 let to_pattern ctx e t =
+	let perror p = error "Unrecognized pattern" p in
 	let verror n p = error ("Variable " ^ n ^ " must appear exactly once in each sub-pattern") p in
-	let rec loop tctx e t = match e,follow t with
-	| (EParenthesis(e),_),t ->
-		loop tctx e t
-	| ((EField ((EConst (String s),_),"code"),p),t) ->
-		if UTF8.length s <> 1 then error "String must be a single UTF8 char" p;
-		let c = TInt (Int32.of_int (UChar.code (UTF8.get s 0))) in
-		mk_con_pat (CConst c) [] t p
-	| (ECall(ec,el),p),(TEnum(en,pl) as t) ->
-		let ec = type_expr_with_type ctx ec (Some t) false in
-		let ef = match ec.eexpr with
-			| TEnumField(en2,s)
-			| TClosure ({ eexpr = TTypeExpr (TEnumDecl en2) },s) when en == en2 -> PMap.find s en.e_constrs
-			| _ -> error ("Expected constructor for enum " ^ (s_type_path en.e_path)) p
-		in
-		(try unify_enum_field en pl ef t with Unify_error l -> error (error_msg (Unify l)) p);
-		let tl = match ef.ef_type with
-			| TFun(args,_) -> List.map (fun (_,_,t) -> t) args
-			| _ -> error "Arguments expected" p
-		in
-		let rec loop2 acc el tl = match el,tl with
-			| (EConst(Ident "_"),_) as e :: [], t :: tl ->
-				let pat = loop tctx e t_dynamic in
-				(ExtList.List.make ((List.length tl) + 1) pat) @ acc
-			| e :: el, t :: tl ->
-				let pat = loop tctx e (apply_params en.e_types pl (apply_params ef.ef_params (List.map (fun _ -> mk_mono()) ef.ef_params) t)) in
-				loop2 (pat :: acc) el tl
-			| e :: _, [] ->
-				error "Too many arguments" (pos e);
-			| [],_ :: _ ->
-				error "Not enough arguments" p;
-			| [],[] ->
-				acc
-		in
-		mk_con_pat (CEnum(en,ef)) (List.rev (loop2 [] el tl)) t p
-	| (EConst(Ident "null"),p),_ ->
-		error "null-patterns are not allowed" p
-	| (EConst((Ident ("false" | "true") | Int _ | String _ | Float _) as c),p),t ->
-		let e = Codegen.type_constant ctx.com c p in
-		unify ctx e.etype t p;
-		let c = match e.eexpr with TConst c -> c | _ -> assert false in
-		mk_con_pat (CConst c) [] t p
-	| (EConst(Ident "_"),p),t ->
-		{
-			pdef = PatAny;
-			ptype = t;
-			ppos = p;
-		}
-	| (EField _,p),t ->
-		let e = type_expr_with_type ctx e (Some t) false in
-		(match e.eexpr with
-		| TConst c -> mk_con_pat (CConst c) [] t p
-		| TTypeExpr mt -> mk_con_pat (CType mt) [] t p
-		| _ -> error "Constant expression expected" p)
-	| ((EConst(Ident s),p) as ec),t -> (try
-		(* HACK so type_ident via type_field does not cause display errors *)
-		ctx.untyped <- true;
-		let ec = try type_expr_with_type ctx ec (Some t) true with _ -> raise Not_found in
-		ctx.untyped <- false;
-		(* we might have found the wrong thing entirely *)
-		(try unify_raise ctx t ec.etype ec.epos with Error (Unify _,_) -> raise Not_found);
-		(match ec.eexpr with
-			| TEnumField(en,s)
-			| TField ({ eexpr = TTypeExpr (TEnumDecl en) },s) ->
-				let ef = PMap.find s en.e_constrs in
-				(* TODO: do we have to call unify_enum_field here? *)
-				mk_con_pat (CEnum(en,ef)) [] t p
-			| TTypeExpr mt ->
-				mk_con_pat (CType mt) [] t p
+	let rec loop tctx e t = match e with
+		| EParenthesis(e),_ ->
+			loop tctx e t
+		| ECall(ec,el),p ->
+			let ec = type_expr_with_type ctx ec (Some t) false in
+			(match follow ec.etype with
+			| TAnon a -> (match !(a.a_status) with
+				| Statics c when has_meta ":extractor" c.cl_meta ->
+					let cf = try PMap.find "unapply" c.cl_statics with Not_found -> error "Missing extractor method unapply" c.cl_pos in
+					let tcf = apply_params cf.cf_params (List.map (fun _ -> mk_mono()) cf.cf_params) (follow cf.cf_type) in
+					(match tcf,el with
+					| TFun([(_,_,ta)],r),[e] ->
+						unify ctx t ta p;
+						error ("Extractors are not supported yet") p;
+					| TFun (_),[e] ->
+						error "Method unapply must accept exactly 1 argument." cf.cf_pos;
+					| TFun _,_ ->
+						error "Invalid number of arguments to extractor, must be exactly 1" p
+					| _ ->
+						error "Invalid type for method unapply" cf.cf_pos)			
+				| _ -> perror p)				
+			| TEnum(en,pl)
+			| TFun(_,TEnum(en,pl)) ->
+				let ef = match ec.eexpr with
+					| TEnumField(_,s)
+					| TClosure ({ eexpr = TTypeExpr (TEnumDecl _) },s) -> PMap.find s en.e_constrs
+					| _ -> error ("Expected constructor for enum " ^ (s_type_path en.e_path)) p
+				in
+				(try unify_enum_field en pl ef t with Unify_error l -> error (error_msg (Unify l)) p);
+				let tl = match ef.ef_type with
+					| TFun(args,_) -> List.map (fun (_,_,t) -> t) args
+					| _ -> error "Arguments expected" p
+				in
+				let rec loop2 acc el tl = match el,tl with
+					| (EConst(Ident "_"),_) as e :: [], t :: tl ->
+						let pat = loop tctx e t_dynamic in
+						(ExtList.List.make ((List.length tl) + 1) pat) @ acc
+					| e :: el, t :: tl ->
+						let pat = loop tctx e (apply_params en.e_types pl (apply_params ef.ef_params (List.map (fun _ -> mk_mono()) ef.ef_params) t)) in
+						loop2 (pat :: acc) el tl
+					| e :: _, [] ->
+						error "Too many arguments" (pos e);
+					| [],_ :: _ ->
+						error "Not enough arguments" p;
+					| [],[] ->
+						acc
+				in
+				mk_con_pat (CEnum(en,ef)) (List.rev (loop2 [] el tl)) t p
+			| _ -> perror p)
+		| (EConst(Ident "null"),p) ->
+			error "null-patterns are not allowed" p
+		| (EConst((Ident ("false" | "true") | Int _ | String _ | Float _) as c),p) ->
+			let e = Codegen.type_constant ctx.com c p in
+			unify ctx e.etype t p;
+			let c = match e.eexpr with TConst c -> c | _ -> assert false in
+			mk_con_pat (CConst c) [] t p
+		| (EConst(Ident "_"),p) ->
+			{
+				pdef = PatAny;
+				ptype = t;
+				ppos = p;
+			}
+		| (EField _,p) ->
+			let e = type_expr_with_type ctx e (Some t) false in
+			(match e.eexpr with
+			| TConst c -> mk_con_pat (CConst c) [] t p
+			| TTypeExpr mt -> mk_con_pat (CType mt) [] t p
+			| _ -> error "Constant expression expected" p)
+		| ((EConst(Ident s),p) as ec) -> (try
+				(* HACK so type_ident via type_field does not cause display errors *)
+				ctx.untyped <- true;
+				let ec = try type_expr_with_type ctx ec (Some t) true with _ -> raise Not_found in
+				ctx.untyped <- false;
+				(* we might have found the wrong thing entirely *)
+				(try unify_raise ctx t ec.etype ec.epos with Error (Unify _,_) -> raise Not_found);
+				(match ec.eexpr with
+					| TEnumField(en,s)
+					| TField ({ eexpr = TTypeExpr (TEnumDecl en) },s) ->
+						let ef = PMap.find s en.e_constrs in
+						unify_enum_field en (List.map (fun _ -> mk_mono()) en.e_types) ef t;
+						mk_con_pat (CEnum(en,ef)) [] t p
+					| TTypeExpr mt ->
+						mk_con_pat (CType mt) [] t p
+					| _ ->
+						raise Not_found);
+			with Not_found ->
+				let v = match tctx.pc_sub_vars with
+					| Some vmap -> (try PMap.find s vmap with Not_found -> verror s p)
+					| None -> alloc_var s t
+				in
+				unify ctx t v.v_type p;
+				if PMap.mem s tctx.pc_locals then verror s p;
+				tctx.pc_locals <- PMap.add s v tctx.pc_locals;
+				{
+					pdef = PatVar(SVar v,p);
+					ptype = t;
+					ppos = p;
+				})
+		| ((EObjectDecl fl),p) ->
+			(match follow t with
+			| TAnon {a_fields = fields}
+			| TInst({cl_fields = fields},_) ->
+				List.iter (fun (n,(_,p)) -> if not (PMap.mem n fields) then error (unify_error_msg (print_context()) (has_extra_field t n)) p) fl;
+				let fl,pl,i = PMap.foldi (fun n cf (sl,pl,i) ->
+					let pat = try loop tctx (List.assoc n fl) cf.cf_type with Not_found -> (mk_any cf.cf_type p) in
+					(n,cf) :: sl,pat :: pl,i + 1
+				) fields ([],[],0) in
+				mk_con_pat (CAnon (i,fl)) pl t p;
+			| t ->
+				error ("Invalid pattern, expected something matching " ^ (s_type (print_context()) t)) p)
+		| (ECast(e1,Some t2),p) ->
+			let t2 = Typeload.load_complex_type ctx p t2 in
+			unify ctx t t2 p;
+			loop tctx e1 t2
+		| (ECast(e1,None),p) ->
+			loop tctx e1 t_dynamic
+		| (EArrayDecl [],p) ->
+			mk_con_pat (CArray 0) [] t p
+		| (EArrayDecl el,p) ->
+			(match t with
+			| TInst({cl_path=[],"Array"},[t2]) ->
+				let pl = List.map (fun e -> loop tctx e t2) el in
+				mk_con_pat (CArray (List.length el)) pl t p
 			| _ ->
-				raise Not_found);
-		with Not_found ->
+				error ((s_type (print_context()) t) ^ " should be Array") p)
+		| (EBinop(OpOr,(EBinop(OpOr,e1,e2),p2),e3),p1) ->
+			loop tctx (EBinop(OpOr,e1,(EBinop(OpOr,e2,e3),p2)),p1) t
+		| (EBinop(OpAssign,(EConst(Ident s),_),e1),p) ->
 			let v = match tctx.pc_sub_vars with
 				| Some vmap -> (try PMap.find s vmap with Not_found -> verror s p)
 				| None -> alloc_var s t
@@ -312,74 +370,30 @@ let to_pattern ctx e t =
 			unify ctx t v.v_type p;
 			if PMap.mem s tctx.pc_locals then verror s p;
 			tctx.pc_locals <- PMap.add s v tctx.pc_locals;
+			let pat1 = loop tctx e1 t in
 			{
-				pdef = PatVar(SVar v,p);
+				pdef = PatBind(v,pat1);
 				ptype = t;
 				ppos = p;
-			})
-	| ((EObjectDecl fl),p),t ->
-		(match t with
-		| TAnon {a_fields = fields}
-		| TInst({cl_fields = fields},_) ->
-			List.iter (fun (n,(_,p)) -> if not (PMap.mem n fields) then error (unify_error_msg (print_context()) (has_extra_field t n)) p) fl;
-			let fl,pl,i = PMap.foldi (fun n cf (sl,pl,i) ->
-				try
-					let e = List.assoc n fl in
-					(n,cf) :: sl,(loop tctx e cf.cf_type) :: pl,i + 1
-				with Not_found ->
-					(n,cf) :: sl,(mk_any cf.cf_type p) :: pl,i + 1
-			) fields ([],[],0) in
-			mk_con_pat (CAnon (i,fl)) pl t p;
-		| t ->
-			error ("Invalid pattern, expected something matching " ^ (s_type (print_context()) t)) p)
-	| (EBinop(OpOr,(EBinop(OpOr,e1,e2),p2),e3),p1),t ->
-		loop tctx (EBinop(OpOr,e1,(EBinop(OpOr,e2,e3),p2)),p1) t
-	| (EBinop(OpAssign,(EConst(Ident s),_),e1),p),t ->
-		let v = match tctx.pc_sub_vars with
-			| Some vmap -> (try PMap.find s vmap with Not_found -> verror s p)
-			| None -> alloc_var s t
-		in
-		unify ctx t v.v_type p;
-		if PMap.mem s tctx.pc_locals then verror s p;
-		tctx.pc_locals <- PMap.add s v tctx.pc_locals;
-		let pat1 = loop tctx e1 t in
-		{
-			pdef = PatBind(v,pat1);
-			ptype = t;
-			ppos = p;
-		};
-	| (EBinop(OpOr,e1,e2),p),t ->
-		let old = tctx.pc_locals in
-		let pat1 = loop tctx e1 t in
-		let tctx2 = {
-			pc_sub_vars = Some tctx.pc_locals;
-			pc_locals = old;
-		} in
-		let pat2 = loop tctx2 e2 t in
-		PMap.iter (fun s _ -> if not (PMap.mem s tctx2.pc_locals) then verror s p) tctx.pc_locals;
-		unify ctx pat1.ptype pat2.ptype pat1.ppos;
-		{
-			pdef = PatOr(pat1,pat2);
-			ptype = pat2.ptype;
-			ppos = punion pat1.ppos pat2.ppos;
-		}
-
-	| (ECast(e1,Some t2),p),t ->
-		let t2 = Typeload.load_complex_type ctx p t2 in
-		unify ctx t t2 p;
-		loop tctx e1 t2
-	| (EArrayDecl [],p),t ->
-		mk_con_pat (CArray 0) [] t p
-	| (EArrayDecl el,p),t ->
-		(match t with
-		| TInst({cl_path=[],"Array"},[t2]) ->
-			let pl = List.map (fun e -> loop tctx e t2) el in
-			mk_con_pat (CArray (List.length el)) pl t p
-		| _ ->
-			error ((s_type (print_context()) t) ^ " should be Array") p)
-	| (_,p),_ ->
-		ctx.com.warning "Unrecognized pattern, falling back to normal switch" p;
-		raise Exit
+			};
+		| (EBinop(OpOr,e1,e2),p) ->
+			let old = tctx.pc_locals in
+			let pat1 = loop tctx e1 t in
+			let tctx2 = {
+				pc_sub_vars = Some tctx.pc_locals;
+				pc_locals = old;
+			} in
+			let pat2 = loop tctx2 e2 t in
+			PMap.iter (fun s _ -> if not (PMap.mem s tctx2.pc_locals) then verror s p) tctx.pc_locals;
+			unify ctx pat1.ptype pat2.ptype pat1.ppos;
+			{
+				pdef = PatOr(pat1,pat2);
+				ptype = pat2.ptype;
+				ppos = punion pat1.ppos pat2.ppos;
+			}
+		| (_,p) ->
+			ctx.com.warning "Unrecognized pattern, falling back to normal switch" p;
+			raise Exit
 	in
 	let tctx = {
 		pc_locals = PMap.empty;
@@ -533,10 +547,10 @@ let all_ctors t =
 		true
 	| TEnum(en,pl) ->
 		PMap.iter (fun _ ef ->
-				try unify_enum_field en pl ef t;
-					h := PMap.add (CEnum(en,ef)) ef.ef_pos !h
-				with Unify_error _ ->
-					()
+			try unify_enum_field en pl ef t;
+				h := PMap.add (CEnum(en,ef)) ef.ef_pos !h
+			with Unify_error _ ->
+				()
 		) en.e_constrs;
 		false
 	| TAnon {a_fields = fields}
@@ -573,7 +587,7 @@ let rec compile mctx (stl : subterm list) (n : int) (pmat : pattern_matrix) = ma
 			let st_head,st_tail = match stl with st :: stl -> st,stl | _ -> assert false in
 			let sigma,t = column_sigma mctx st_head pmat in
 			let c_all,inf = all_ctors t in
-			let cases = List.map (fun (c,g) ->
+			let cases = List.rev_map (fun (c,g) ->
 				let a = arity c in
 				if not g then c_all := PMap.remove (fst c) !c_all;
 				let pmat_spec = spec mctx c pmat in
@@ -756,7 +770,7 @@ and to_typed_ast ctx need_val (dt : decision_tree) : texpr =
 		mk (TBlock [
 			mk (TVars vl) t_dynamic p;
 			e;
-		]) e.etype p		
+		]) e.etype p
 	| Switch(st,t,cases) ->
 		match follow t with
 		| TEnum(en,pl) ->
@@ -796,7 +810,7 @@ let match_expr ctx e cases def need_val with_type p =
 					raise Exit
 				| TDynamic _
 				| TMono _ ->
-					raise Exit
+					true
 				| TAbstract({a_path=[],"Bool"},_) ->
 					false
 				| TInst({cl_path=[],"String"},_)