comparison src/iflow.sml @ 1211:1d4d65245dd3

About to try removing Select predicate
author Adam Chlipala <adamc@hcoop.net>
date Tue, 06 Apr 2010 13:59:16 -0400
parents c5bd970e77a5
children fc33072c4d33
comparison
equal deleted inserted replaced
1210:c5bd970e77a5 1211:1d4d65245dd3
65 | Finish 65 | Finish
66 66
67 datatype reln = 67 datatype reln =
68 Known 68 Known
69 | Sql of string 69 | Sql of string
70 | DtCon of string
70 | Eq 71 | Eq
71 | Ne 72 | Ne
72 | Lt 73 | Lt
73 | Le 74 | Le
74 | Gt 75 | Gt
125 string ")"] 126 string ")"]
126 | _ => raise Fail "Iflow.p_reln: Known") 127 | _ => raise Fail "Iflow.p_reln: Known")
127 | Sql s => box [string (s ^ "("), 128 | Sql s => box [string (s ^ "("),
128 p_list p_exp es, 129 p_list p_exp es,
129 string ")"] 130 string ")"]
131 | DtCon s => box [string (s ^ "("),
132 p_list p_exp es,
133 string ")"]
130 | Eq => p_bop "=" es 134 | Eq => p_bop "=" es
131 | Ne => p_bop "<>" es 135 | Ne => p_bop "<>" es
132 | Lt => p_bop "<" es 136 | Lt => p_bop "<" es
133 | Le => p_bop "<=" es 137 | Le => p_bop "<=" es
134 | Gt => p_bop ">" es 138 | Gt => p_bop ">" es
239 NONE => e 243 NONE => e
240 | SOME e => simplify e) 244 | SOME e => simplify e)
241 | Func (f, es) => 245 | Func (f, es) =>
242 let 246 let
243 val es = map simplify es 247 val es = map simplify es
248
249 fun default () = Func (f, es)
244 in 250 in
245 if List.exists isFinish es then 251 if List.exists isFinish es then
246 Finish 252 Finish
253 else if String.isPrefix "un" f then
254 case es of
255 [Func (f', [e])] => if f' = String.extract (f, 2, NONE) then
256 e
257 else
258 default ()
259 | _ => default ()
247 else 260 else
248 Func (f, es) 261 default ()
249 end 262 end
250 | Recd xes => 263 | Recd xes =>
251 let 264 let
252 val xes = map (fn (x, e) => (x, simplify e)) xes 265 val xes = map (fn (x, e) => (x, simplify e)) xes
253 in 266 in
349 else 362 else
350 (restore saved; 363 (restore saved;
351 false) 364 false)
352 end 365 end
353 366
354 exception Imply of prop * prop
355
356 val debug = ref false 367 val debug = ref false
357 368
369 fun eeq (e1, e2) =
370 case (e1, e2) of
371 (Const p1, Const p2) => Prim.equal (p1, p2)
372 | (Var n1, Var n2) => n1 = n2
373 | (Lvar n1, Lvar n2) => n1 = n2
374 | (Func (f1, es1), Func (f2, es2)) => f1 = f2 andalso ListPair.allEq eeq (es1, es2)
375 | (Recd xes1, Recd xes2) => length xes1 = length xes2 andalso
376 List.all (fn (x2, e2) =>
377 List.exists (fn (x1, e1) => x1 = x2 andalso eeq (e1, e2)) xes2) xes1
378 | (Proj (e1, x1), Proj (e2, x2)) => eeq (e1, e2) andalso x1 = x2
379 | (Finish, Finish) => true
380 | _ => false
381
358 (* Congruence closure *) 382 (* Congruence closure *)
359 structure Cc :> sig 383 structure Cc :> sig
360 type t 384 type t
361 val empty : t 385 val empty : t
362 val assert : t * exp * exp -> t 386 val assert : t * exp * exp -> t
363 val query : t * exp * exp -> bool 387 val query : t * exp * exp -> bool
364 val allPeers : t * exp -> exp list 388 val allPeers : t * exp -> exp list
365 end = struct 389 end = struct
366 390
367 fun eq' (e1, e2) = 391 fun eq (e1, e2) = eeq (simplify e1, simplify e2)
368 case (e1, e2) of
369 (Const p1, Const p2) => Prim.equal (p1, p2)
370 | (Var n1, Var n2) => n1 = n2
371 | (Lvar n1, Lvar n2) => n1 = n2
372 | (Func (f1, es1), Func (f2, es2)) => f1 = f2 andalso ListPair.allEq eq' (es1, es2)
373 | (Recd xes1, Recd xes2) => length xes1 = length xes2 andalso
374 List.all (fn (x2, e2) =>
375 List.exists (fn (x1, e1) => x1 = x2 andalso eq' (e1, e2)) xes2) xes1
376 | (Proj (e1, x1), Proj (e2, x2)) => eq' (e1, e2) andalso x1 = x2
377 | (Finish, Finish) => true
378 | _ => false
379
380 fun eq (e1, e2) = eq' (simplify e1, simplify e2)
381 392
382 type t = (exp * exp) list 393 type t = (exp * exp) list
383 394
384 val empty = [] 395 val empty = []
385 396
473 let 484 let
474 fun matches e = 485 fun matches e =
475 case e of 486 case e of
476 Var v' => v' = v 487 Var v' => v' = v
477 | Proj (e, _) => matches e 488 | Proj (e, _) => matches e
489 | Func (f, [e]) => String.isPrefix "un" f andalso matches e
478 | _ => false 490 | _ => false
479 in 491 in
480 List.exists matches (Cc.allPeers (cc, e2)) 492 List.exists matches (Cc.allPeers (cc, e2))
481 end 493 end
482 | _ => false) 494 | _ => false)
526 (Eq, [e1, e2]) => Cc.query (cc, e1, e2) 538 (Eq, [e1, e2]) => Cc.query (cc, e1, e2)
527 | _ => false) 539 | _ => false)
528 orelse hps hyps 540 orelse hps hyps
529 end 541 end
530 in 542 in
531 gls goals (fn () => false) 543 if List.exists (fn (DtCon c1, [e]) =>
544 List.exists (fn (DtCon c2, [e']) =>
545 c1 <> c2 andalso
546 Cc.query (cc, e, e')
547 | _ => false) hyps
548 orelse List.exists (fn Func (c2, []) => c1 <> c2
549 | Finish => true
550 | _ => false)
551 (Cc.allPeers (cc, e))
552 | _ => false) hyps
553 orelse gls goals (fn () => false) then
554 true
555 else
556 (Print.prefaces "Can't prove"
557 [("hyps", Print.p_list (fn x => p_prop (Reln x)) hyps),
558 ("goals", Print.p_list (fn x => p_prop (Reln x)) goals)];
559 false)
532 end)) 560 end))
533 in 561 in
534 reset (); 562 reset ();
535 doOne false; 563 doOne false;
536 doOne true 564 doOne true
666 wrap (ws p) (fn v => [v]), 694 wrap (ws p) (fn v => [v]),
667 always []] chs 695 always []] chs
668 696
669 val ident = keep (fn ch => Char.isAlphaNum ch orelse ch = #"_") 697 val ident = keep (fn ch => Char.isAlphaNum ch orelse ch = #"_")
670 698
671 val t_ident = wrap ident (fn s => if String.isPrefix "T_" s then 699 val t_ident = wrapP ident (fn s => if String.isPrefix "T_" s then
672 String.extract (s, 2, NONE) 700 SOME (String.extract (s, 2, NONE))
673 else
674 raise Fail "Iflow: Bad table variable")
675 val uw_ident = wrap ident (fn s => if String.isPrefix "uw_" s andalso size s >= 4 then
676 str (Char.toUpper (String.sub (s, 3)))
677 ^ String.extract (s, 4, NONE)
678 else 701 else
679 raise Fail "Iflow: Bad uw_* variable") 702 NONE)
680 703 val uw_ident = wrapP ident (fn s => if String.isPrefix "uw_" s andalso size s >= 4 then
681 val sitem = wrap (follow t_ident 704 SOME (str (Char.toUpper (String.sub (s, 3)))
705 ^ String.extract (s, 4, NONE))
706 else
707 NONE)
708
709 val field = wrap (follow t_ident
682 (follow (const ".") 710 (follow (const ".")
683 uw_ident)) 711 uw_ident))
684 (fn (t, ((), f)) => (t, f)) 712 (fn (t, ((), f)) => (t, f))
685 713
686 datatype Rel = 714 datatype Rel =
691 SqConst of Prim.t 719 SqConst of Prim.t
692 | Field of string * string 720 | Field of string * string
693 | Binop of Rel * sqexp * sqexp 721 | Binop of Rel * sqexp * sqexp
694 | SqKnown of sqexp 722 | SqKnown of sqexp
695 | Inj of Mono.exp 723 | Inj of Mono.exp
724 | SqFunc of string * sqexp
725 | Count
696 726
697 fun cmp s r = wrap (const s) (fn () => Exps (fn (e1, e2) => Reln (r, [e1, e2]))) 727 fun cmp s r = wrap (const s) (fn () => Exps (fn (e1, e2) => Reln (r, [e1, e2])))
698 728
699 val sqbrel = altL [cmp "=" Eq, 729 val sqbrel = altL [cmp "=" Eq,
700 cmp "<>" Ne, 730 cmp "<>" Ne,
756 SOME (e, chs) 786 SOME (e, chs)
757 else 787 else
758 NONE 788 NONE
759 | _ => NONE 789 | _ => NONE
760 790
791 fun constK s = wrap (const s) (fn () => s)
792
793 val funcName = altL [constK "COUNT",
794 constK "MIN",
795 constK "MAX",
796 constK "SUM",
797 constK "AVG"]
798
761 fun sqexp chs = 799 fun sqexp chs =
762 log "sqexp" 800 log "sqexp"
763 (altL [wrap prim SqConst, 801 (altL [wrap prim SqConst,
764 wrap sitem Field, 802 wrap field Field,
765 wrap known SqKnown, 803 wrap known SqKnown,
804 wrap func SqFunc,
805 wrap (const "COUNT(*)") (fn () => Count),
766 wrap sqlify Inj, 806 wrap sqlify Inj,
807 wrap (follow (const "COALESCE(") (follow sqexp (follow (const ",")
808 (follow (keep (fn ch => ch <> #")")) (const ")")))))
809 (fn ((), (e, _)) => e),
767 wrap (follow (ws (const "(")) 810 wrap (follow (ws (const "("))
768 (follow (wrap 811 (follow (wrap
769 (follow sqexp 812 (follow sqexp
770 (alt 813 (alt
771 (wrap 814 (wrap
780 (const ")"))) 823 (const ")")))
781 (fn ((), (e, ())) => e)]) 824 (fn ((), (e, ())) => e)])
782 chs 825 chs
783 826
784 and known chs = wrap (follow known' (follow (const "(") (follow sqexp (const ")")))) 827 and known chs = wrap (follow known' (follow (const "(") (follow sqexp (const ")"))))
785 (fn ((), ((), (e, ()))) => e) chs 828 (fn ((), ((), (e, ()))) => e) chs
829
830 and func chs = wrap (follow funcName (follow (const "(") (follow sqexp (const ")"))))
831 (fn (f, ((), (e, ()))) => (f, e)) chs
832
833 datatype sitem =
834 SqField of string * string
835 | SqExp of sqexp * string
836
837 val sitem = alt (wrap field SqField)
838 (wrap (follow sqexp (follow (const " AS ") uw_ident))
839 (fn (e, ((), s)) => SqExp (e, s)))
786 840
787 val select = log "select" 841 val select = log "select"
788 (wrap (follow (const "SELECT ") (list sitem)) 842 (wrap (follow (const "SELECT ") (list sitem))
789 (fn ((), ls) => ls)) 843 (fn ((), ls) => ls))
790 844
801 (fn ((), ls) => ls) 855 (fn ((), ls) => ls)
802 856
803 val query = log "query" 857 val query = log "query"
804 (wrap (follow (follow select from) (opt wher)) 858 (wrap (follow (follow select from) (opt wher))
805 (fn ((fs, ts), wher) => {Select = fs, From = ts, Where = wher})) 859 (fn ((fs, ts), wher) => {Select = fs, From = ts, Where = wher}))
860
861 fun removeDups ls =
862 case ls of
863 [] => []
864 | x :: ls =>
865 let
866 val ls = removeDups ls
867 in
868 if List.exists (fn x' => x' = x) ls then
869 ls
870 else
871 x :: ls
872 end
806 873
807 fun queryProp env rv oe e = 874 fun queryProp env rv oe e =
808 case parse query e of 875 case parse query e of
809 NONE => (print ("Warning: Information flow checker can't parse SQL query at " 876 NONE => (print ("Warning: Information flow checker can't parse SQL query at "
810 ^ ErrorMsg.spanToString (#2 e) ^ "\n"); 877 ^ ErrorMsg.spanToString (#2 e) ^ "\n");
811 (Unknown, [])) 878 (Unknown, []))
812 | SOME r => 879 | SOME r =>
813 let 880 let
881 fun usedFields e =
882 case e of
883 SqConst _ => []
884 | Field (v, f) => [(v, f)]
885 | Binop (_, e1, e2) => removeDups (usedFields e1 @ usedFields e2)
886 | SqKnown _ => []
887 | Inj _ => []
888 | SqFunc (_, e) => usedFields e
889 | Count => []
890
891 val allUsed = removeDups (List.mapPartial (fn SqField x => SOME x | _ => NONE) (#Select r)
892 @ (case #Where r of
893 NONE => []
894 | SOME e => usedFields e))
895
814 val p = 896 val p =
815 foldl (fn ((t, v), p) => 897 foldl (fn ((t, v), p) =>
816 And (p, 898 And (p,
817 Reln (Sql t, 899 Reln (Sql t,
818 [Recd (foldl (fn ((v', f), fs) => 900 [Recd (foldl (fn ((v', f), fs) =>
819 if v' = v then 901 if v' = v then
820 (f, Proj (Proj (Lvar rv, v), f)) :: fs 902 (f, Proj (Proj (Lvar rv, v), f)) :: fs
821 else 903 else
822 fs) [] (#Select r))]))) 904 fs) [] allUsed)])))
823 True (#From r) 905 True (#From r)
824 906
825 fun expIn e = 907 fun expIn e =
826 case e of 908 case e of
827 SqConst p => inl (Const p) 909 SqConst p => inl (Const p)
843 | EField (e, f) => Proj (deinj e, f) 925 | EField (e, f) => Proj (deinj e, f)
844 | _ => raise Fail "Iflow: non-variable injected into query" 926 | _ => raise Fail "Iflow: non-variable injected into query"
845 in 927 in
846 inl (deinj e) 928 inl (deinj e)
847 end 929 end
848 930 | SqFunc (f, e) =>
849 fun usedFields e = 931 inl (case expIn e of
850 case e of 932 inl e => Func (f, [e])
851 SqConst _ => [] 933 | _ => raise Fail ("Iflow: non-expresion passed to function " ^ f))
852 | Field (v, f) => [Proj (Proj (Lvar rv, v), f)] 934 | Count => inl (Func ("COUNT", []))
853 | Binop (_, e1, e2) => usedFields e1 @ usedFields e2
854 | SqKnown _ => []
855 | Inj _ => []
856 935
857 val p = case #Where r of 936 val p = case #Where r of
858 NONE => p 937 NONE => p
859 | SOME e => 938 | SOME e =>
860 case expIn e of 939 case expIn e of
862 | _ => p 941 | _ => p
863 in 942 in
864 (case oe of 943 (case oe of
865 NONE => p 944 NONE => p
866 | SOME oe => 945 | SOME oe =>
867 And (p, foldl (fn ((v, f), p) => 946 And (p, foldl (fn (si, p) =>
868 Or (p, 947 let
869 Reln (Eq, [oe, Proj (Proj (Lvar rv, v), f)]))) 948 val p' = case si of
949 SqField (v, f) => Reln (Eq, [oe, Proj (Proj (Lvar rv, v), f)])
950 | SqExp (e, f) =>
951 case expIn e of
952 inr _ => Unknown
953 | inl e => Reln (Eq, [oe, e])
954 in
955 Or (p, p')
956 end)
870 False (#Select r)), 957 False (#Select r)),
871 958
872 case #Where r of 959 case #Where r of
873 NONE => [] 960 NONE => []
874 | SOME e => usedFields e) 961 | SOME e => map (fn (v, f) => Proj (Proj (Lvar rv, v), f)) (usedFields e))
875 end 962 end
963
964 fun evalPat env e (pt, _) =
965 case pt of
966 PWild => (env, True)
967 | PVar _ => (e :: env, True)
968 | PPrim _ => (env, True)
969 | PCon (_, pc, NONE) => (env, Reln (DtCon (patCon pc), [e]))
970 | PCon (_, pc, SOME pt) =>
971 let
972 val (env, p) = evalPat env (Func ("un" ^ patCon pc, [e])) pt
973 in
974 (env, And (p, Reln (DtCon (patCon pc), [e])))
975 end
976 | PRecord xpts =>
977 foldl (fn ((x, pt, _), (env, p)) =>
978 let
979 val (env, p') = evalPat env (Proj (e, x)) pt
980 in
981 (env, And (p', p))
982 end) (env, True) xpts
983 | PNone _ => (env, Reln (DtCon "None", [e]))
984 | PSome (_, pt) =>
985 let
986 val (env, p) = evalPat env (Func ("unSome", [e])) pt
987 in
988 (env, And (p, Reln (DtCon "Some", [e])))
989 end
990
991 fun peq (p1, p2) =
992 case (p1, p2) of
993 (True, True) => true
994 | (False, False) => true
995 | (Unknown, Unknown) => true
996 | (And (x1, y1), And (x2, y2)) => peq (x1, x2) andalso peq (y1, y2)
997 | (Or (x1, y1), Or (x2, y2)) => peq (x1, x2) andalso peq (y1, y2)
998 | (Reln (r1, es1), Reln (r2, es2)) => r1 = r2 andalso ListPair.allEq eeq (es1, es2)
999 | (Select (n1, n2, n3, p1, e1), Select (n1', n2', n3', p2, e2)) =>
1000 n1 = n1' andalso n2 = n2' andalso n3 = n3'
1001 andalso peq (p1, p2) andalso eeq (e1, e2)
1002 | _ => false
1003
1004 fun removeRedundant p1 =
1005 let
1006 fun rr p2 =
1007 if peq (p1, p2) then
1008 True
1009 else
1010 case p2 of
1011 And (x, y) => And (rr x, rr y)
1012 | Or (x, y) => Or (rr x, rr y)
1013 | Select (n1, n2, n3, p, e) => Select (n1, n2, n3, rr p, e)
1014 | _ => p2
1015 in
1016 rr
1017 end
876 1018
877 fun evalExp env (e as (_, loc), st as (nv, p, sent)) = 1019 fun evalExp env (e as (_, loc), st as (nv, p, sent)) =
878 let 1020 let
879 fun default () = 1021 fun default () =
880 (Var nv, (nv+1, p, sent)) 1022 (Var nv, (nv+1, p, sent))
949 let 1091 let
950 val (e, st) = evalExp env (e, st) 1092 val (e, st) = evalExp env (e, st)
951 in 1093 in
952 (Proj (e, s), st) 1094 (Proj (e, s), st)
953 end 1095 end
954 | ECase _ => default () 1096 | ECase (e, pes, _) =>
1097 let
1098 val (e, st) = evalExp env (e, st)
1099 val r = #1 st
1100 val st = (r + 1, #2 st, #3 st)
1101 val orig = #2 st
1102
1103 val st = foldl (fn ((pt, pe), st) =>
1104 let
1105 val (env, pp) = evalPat env e pt
1106 val (pe, st') = evalExp env (pe, (#1 st, And (orig, pp), #3 st))
1107
1108 val this = And (removeRedundant orig (#2 st'), Reln (Eq, [Var r, pe]))
1109 in
1110 (#1 st', Or (#2 st, this), #3 st')
1111 end) (#1 st, False, #3 st) pes
1112 in
1113 (Var r, (#1 st, And (orig, #2 st), #3 st))
1114 end
955 | EStrcat (e1, e2) => 1115 | EStrcat (e1, e2) =>
956 let 1116 let
957 val (e1, st) = evalExp env (e1, st) 1117 val (e1, st) = evalExp env (e1, st)
958 val (e2, st) = evalExp env (e2, st) 1118 val (e2, st) = evalExp env (e2, st)
959 in 1119 in