comparison src/iflow.sml @ 1697:cb0f05bdc183

Refactor SQL parsing code from Iflow to Sql, add querydml parser.
author Edward Z. Yang <ezyang@mit.edu>
date Mon, 12 Mar 2012 12:00:23 -0700
parents 0577be31a435
children c1e3805e604e
comparison
equal deleted inserted replaced
1696:177547450bb9 1697:cb0f05bdc183
26 *) 26 *)
27 27
28 structure Iflow :> IFLOW = struct 28 structure Iflow :> IFLOW = struct
29 29
30 open Mono 30 open Mono
31 open Sql
31 32
32 structure IS = IntBinarySet 33 structure IS = IntBinarySet
33 structure IM = IntBinaryMap 34 structure IM = IntBinaryMap
34 35
35 structure SK = struct 36 structure SK = struct
54 "urlifyString_w", 55 "urlifyString_w",
55 "urlifyBool_w", 56 "urlifyBool_w",
56 "set_cookie"] 57 "set_cookie"]
57 58
58 val writers = SS.addList (SS.empty, writers) 59 val writers = SS.addList (SS.empty, writers)
59
60 type lvar = int
61
62 datatype func =
63 DtCon0 of string
64 | DtCon1 of string
65 | UnCon of string
66 | Other of string
67
68 datatype exp =
69 Const of Prim.t
70 | Var of int
71 | Lvar of lvar
72 | Func of func * exp list
73 | Recd of (string * exp) list
74 | Proj of exp * string
75
76 datatype reln =
77 Known
78 | Sql of string
79 | PCon0 of string
80 | PCon1 of string
81 | Eq
82 | Ne
83 | Lt
84 | Le
85 | Gt
86 | Ge
87
88 datatype prop =
89 True
90 | False
91 | Unknown
92 | And of prop * prop
93 | Or of prop * prop
94 | Reln of reln * exp list
95 | Cond of exp * prop
96 60
97 local 61 local
98 open Print 62 open Print
99 val string = PD.string 63 val string = PD.string
100 in 64 in
224 fun p_atom a = 188 fun p_atom a =
225 p_prop (case a of 189 p_prop (case a of
226 AReln x => Reln x 190 AReln x => Reln x
227 | ACond x => Cond x) 191 | ACond x => Cond x)
228 192
229 val debug = ref false
230
231 (* Congruence closure *) 193 (* Congruence closure *)
232 structure Cc :> sig 194 structure Cc :> sig
233 type database 195 type database
234 196
235 exception Contradiction 197 exception Contradiction
826 fun patCon pc = 788 fun patCon pc =
827 case pc of 789 case pc of
828 PConVar n => "C" ^ Int.toString n 790 PConVar n => "C" ^ Int.toString n
829 | PConFfi {mod = m, datatyp = d, con = c, ...} => m ^ "." ^ d ^ "." ^ c 791 | PConFfi {mod = m, datatyp = d, con = c, ...} => m ^ "." ^ d ^ "." ^ c
830 792
831 datatype chunk =
832 String of string
833 | Exp of Mono.exp
834
835 fun chunkify e =
836 case #1 e of
837 EPrim (Prim.String s) => [String s]
838 | EStrcat (e1, e2) =>
839 let
840 val chs1 = chunkify e1
841 val chs2 = chunkify e2
842 in
843 case chs2 of
844 String s2 :: chs2' =>
845 (case List.last chs1 of
846 String s1 => List.take (chs1, length chs1 - 1) @ String (s1 ^ s2) :: chs2'
847 | _ => chs1 @ chs2)
848 | _ => chs1 @ chs2
849 end
850 | _ => [Exp e]
851
852 type 'a parser = chunk list -> ('a * chunk list) option
853
854 fun always v chs = SOME (v, chs)
855
856 fun parse p s =
857 case p (chunkify s) of
858 SOME (v, []) => SOME v
859 | _ => NONE
860
861 fun const s chs =
862 case chs of
863 String s' :: chs => if String.isPrefix s s' then
864 SOME ((), if size s = size s' then
865 chs
866 else
867 String (String.extract (s', size s, NONE)) :: chs)
868 else
869 NONE
870 | _ => NONE
871
872 fun follow p1 p2 chs =
873 case p1 chs of
874 NONE => NONE
875 | SOME (v1, chs) =>
876 case p2 chs of
877 NONE => NONE
878 | SOME (v2, chs) => SOME ((v1, v2), chs)
879
880 fun wrap p f chs =
881 case p chs of
882 NONE => NONE
883 | SOME (v, chs) => SOME (f v, chs)
884
885 fun wrapP p f chs =
886 case p chs of
887 NONE => NONE
888 | SOME (v, chs) =>
889 case f v of
890 NONE => NONE
891 | SOME r => SOME (r, chs)
892
893 fun alt p1 p2 chs =
894 case p1 chs of
895 NONE => p2 chs
896 | v => v
897
898 fun altL ps =
899 case rev ps of
900 [] => (fn _ => NONE)
901 | p :: ps =>
902 foldl (fn (p1, p2) => alt p1 p2) p ps
903
904 fun opt p chs =
905 case p chs of
906 NONE => SOME (NONE, chs)
907 | SOME (v, chs) => SOME (SOME v, chs)
908
909 fun skip cp chs =
910 case chs of
911 String "" :: chs => skip cp chs
912 | String s :: chs' => if cp (String.sub (s, 0)) then
913 skip cp (String (String.extract (s, 1, NONE)) :: chs')
914 else
915 SOME ((), chs)
916 | _ => SOME ((), chs)
917
918 fun keep cp chs =
919 case chs of
920 String "" :: chs => keep cp chs
921 | String s :: chs' =>
922 let
923 val (befor, after) = Substring.splitl cp (Substring.full s)
924 in
925 if Substring.isEmpty befor then
926 NONE
927 else
928 SOME (Substring.string befor,
929 if Substring.isEmpty after then
930 chs'
931 else
932 String (Substring.string after) :: chs')
933 end
934 | _ => NONE
935
936 fun ws p = wrap (follow (skip (fn ch => ch = #" "))
937 (follow p (skip (fn ch => ch = #" ")))) (#1 o #2)
938
939 fun log name p chs =
940 (if !debug then
941 (print (name ^ ": ");
942 app (fn String s => print s
943 | _ => print "???") chs;
944 print "\n")
945 else
946 ();
947 p chs)
948
949 fun list p chs =
950 altL [wrap (follow p (follow (ws (const ",")) (list p)))
951 (fn (v, ((), ls)) => v :: ls),
952 wrap (ws p) (fn v => [v]),
953 always []] chs
954
955 val ident = keep (fn ch => Char.isAlphaNum ch orelse ch = #"_")
956
957 val t_ident = wrapP ident (fn s => if String.isPrefix "T_" s then
958 SOME (String.extract (s, 2, NONE))
959 else
960 NONE)
961 val uw_ident = wrapP ident (fn s => if String.isPrefix "uw_" s andalso size s >= 4 then
962 SOME (str (Char.toUpper (String.sub (s, 3)))
963 ^ String.extract (s, 4, NONE))
964 else
965 NONE)
966
967 val field = wrap (follow t_ident
968 (follow (const ".")
969 uw_ident))
970 (fn (t, ((), f)) => (t, f))
971
972 datatype Rel =
973 Exps of exp * exp -> prop
974 | Props of prop * prop -> prop
975
976 datatype sqexp =
977 SqConst of Prim.t
978 | SqTrue
979 | SqFalse
980 | SqNot of sqexp
981 | Field of string * string
982 | Computed of string
983 | Binop of Rel * sqexp * sqexp
984 | SqKnown of sqexp
985 | Inj of Mono.exp
986 | SqFunc of string * sqexp
987 | Unmodeled
988 | Null
989
990 fun cmp s r = wrap (const s) (fn () => Exps (fn (e1, e2) => Reln (r, [e1, e2])))
991
992 val sqbrel = altL [cmp "=" Eq,
993 cmp "<>" Ne,
994 cmp "<=" Le,
995 cmp "<" Lt,
996 cmp ">=" Ge,
997 cmp ">" Gt,
998 wrap (const "AND") (fn () => Props And),
999 wrap (const "OR") (fn () => Props Or)]
1000
1001 datatype ('a, 'b) sum = inl of 'a | inr of 'b
1002
1003 fun string chs =
1004 case chs of
1005 String s :: chs =>
1006 if size s >= 2 andalso String.sub (s, 0) = #"'" then
1007 let
1008 fun loop (cs, acc) =
1009 case cs of
1010 [] => NONE
1011 | c :: cs =>
1012 if c = #"'" then
1013 SOME (String.implode (rev acc), cs)
1014 else if c = #"\\" then
1015 case cs of
1016 c :: cs => loop (cs, c :: acc)
1017 | _ => raise Fail "Iflow.string: Unmatched backslash escape"
1018 else
1019 loop (cs, c :: acc)
1020 in
1021 case loop (String.explode (String.extract (s, 1, NONE)), []) of
1022 NONE => NONE
1023 | SOME (s, []) => SOME (s, chs)
1024 | SOME (s, cs) => SOME (s, String (String.implode cs) :: chs)
1025 end
1026 else
1027 NONE
1028 | _ => NONE
1029
1030 val prim =
1031 altL [wrap (follow (wrapP (follow (keep Char.isDigit) (follow (const ".") (keep Char.isDigit)))
1032 (fn (x, ((), y)) => Option.map Prim.Float (Real64.fromString (x ^ "." ^ y))))
1033 (opt (const "::float8"))) #1,
1034 wrap (follow (wrapP (keep Char.isDigit)
1035 (Option.map Prim.Int o Int64.fromString))
1036 (opt (const "::int8"))) #1,
1037 wrap (follow (opt (const "E")) (follow string (opt (const "::text"))))
1038 (Prim.String o #1 o #2)]
1039
1040 fun known' chs =
1041 case chs of
1042 Exp (EFfi ("Basis", "sql_known"), _) :: chs => SOME ((), chs)
1043 | _ => NONE
1044
1045 fun sqlify chs =
1046 case chs of
1047 Exp (EFfiApp ("Basis", f, [(e, _)]), _) :: chs =>
1048 if String.isPrefix "sqlify" f then
1049 SOME (e, chs)
1050 else
1051 NONE
1052 | Exp (ECase (e, [((PCon (_, PConFfi {mod = "Basis", con = "True", ...}, NONE), _),
1053 (EPrim (Prim.String "TRUE"), _)),
1054 ((PCon (_, PConFfi {mod = "Basis", con = "False", ...}, NONE), _),
1055 (EPrim (Prim.String "FALSE"), _))], _), _) :: chs =>
1056 SOME (e, chs)
1057
1058 | _ => NONE
1059
1060 fun constK s = wrap (const s) (fn () => s)
1061
1062 val funcName = altL [constK "COUNT",
1063 constK "MIN",
1064 constK "MAX",
1065 constK "SUM",
1066 constK "AVG"]
1067
1068 val unmodeled = altL [const "COUNT(*)",
1069 const "CURRENT_TIMESTAMP"]
1070
1071 fun sqexp chs =
1072 log "sqexp"
1073 (altL [wrap prim SqConst,
1074 wrap (const "TRUE") (fn () => SqTrue),
1075 wrap (const "FALSE") (fn () => SqFalse),
1076 wrap (const "NULL") (fn () => Null),
1077 wrap field Field,
1078 wrap uw_ident Computed,
1079 wrap known SqKnown,
1080 wrap func SqFunc,
1081 wrap unmodeled (fn () => Unmodeled),
1082 wrap sqlify Inj,
1083 wrap (follow (const "COALESCE(") (follow sqexp (follow (const ",")
1084 (follow (keep (fn ch => ch <> #")")) (const ")")))))
1085 (fn ((), (e, _)) => e),
1086 wrap (follow (const "(NOT ") (follow sqexp (const ")")))
1087 (fn ((), (e, _)) => SqNot e),
1088 wrap (follow (ws (const "("))
1089 (follow (wrap
1090 (follow sqexp
1091 (alt
1092 (wrap
1093 (follow (ws sqbrel)
1094 (ws sqexp))
1095 inl)
1096 (always (inr ()))))
1097 (fn (e1, sm) =>
1098 case sm of
1099 inl (bo, e2) => Binop (bo, e1, e2)
1100 | inr () => e1))
1101 (const ")")))
1102 (fn ((), (e, ())) => e)])
1103 chs
1104
1105 and known chs = wrap (follow known' (follow (const "(") (follow sqexp (const ")"))))
1106 (fn ((), ((), (e, ()))) => e) chs
1107
1108 and func chs = wrap (follow funcName (follow (const "(") (follow sqexp (const ")"))))
1109 (fn (f, ((), (e, ()))) => (f, e)) chs
1110
1111 datatype sitem =
1112 SqField of string * string
1113 | SqExp of sqexp * string
1114
1115 val sitem = alt (wrap (follow sqexp (follow (const " AS ") uw_ident))
1116 (fn (e, ((), s)) => SqExp (e, s)))
1117 (wrap field SqField)
1118
1119 val select = log "select"
1120 (wrap (follow (const "SELECT ") (list sitem))
1121 (fn ((), ls) => ls))
1122
1123 val fitem = wrap (follow uw_ident
1124 (follow (const " AS ")
1125 t_ident))
1126 (fn (t, ((), f)) => (t, f))
1127
1128 val from = log "from"
1129 (wrap (follow (const "FROM ") (list fitem))
1130 (fn ((), ls) => ls))
1131
1132 val wher = wrap (follow (ws (const "WHERE ")) sqexp)
1133 (fn ((), ls) => ls)
1134
1135 type query1 = {Select : sitem list,
1136 From : (string * string) list,
1137 Where : sqexp option}
1138
1139 val query1 = log "query1"
1140 (wrap (follow (follow select from) (opt wher))
1141 (fn ((fs, ts), wher) => {Select = fs, From = ts, Where = wher}))
1142
1143 datatype query =
1144 Query1 of query1
1145 | Union of query * query
1146
1147 val orderby = log "orderby"
1148 (wrap (follow (ws (const "ORDER BY "))
1149 (follow (list sqexp)
1150 (opt (ws (const "DESC")))))
1151 ignore)
1152
1153 fun query chs = log "query"
1154 (wrap
1155 (follow
1156 (alt (wrap (follow (const "((")
1157 (follow query
1158 (follow (const ") UNION (")
1159 (follow query (const "))")))))
1160 (fn ((), (q1, ((), (q2, ())))) => Union (q1, q2)))
1161 (wrap query1 Query1))
1162 (opt orderby))
1163 #1)
1164 chs
1165
1166 datatype dml =
1167 Insert of string * (string * sqexp) list
1168 | Delete of string * sqexp
1169 | Update of string * (string * sqexp) list * sqexp
1170
1171 val insert = log "insert"
1172 (wrapP (follow (const "INSERT INTO ")
1173 (follow uw_ident
1174 (follow (const " (")
1175 (follow (list uw_ident)
1176 (follow (const ") VALUES (")
1177 (follow (list sqexp)
1178 (const ")")))))))
1179 (fn ((), (tab, ((), (fs, ((), (es, ())))))) =>
1180 (SOME (tab, ListPair.zipEq (fs, es)))
1181 handle ListPair.UnequalLengths => NONE))
1182
1183 val delete = log "delete"
1184 (wrap (follow (const "DELETE FROM ")
1185 (follow uw_ident
1186 (follow (const " AS T_T WHERE ")
1187 sqexp)))
1188 (fn ((), (tab, ((), es))) => (tab, es)))
1189
1190 val setting = log "setting"
1191 (wrap (follow uw_ident (follow (const " = ") sqexp))
1192 (fn (f, ((), e)) => (f, e)))
1193
1194 val update = log "update"
1195 (wrap (follow (const "UPDATE ")
1196 (follow uw_ident
1197 (follow (const " AS T_T SET ")
1198 (follow (list setting)
1199 (follow (ws (const "WHERE "))
1200 sqexp)))))
1201 (fn ((), (tab, ((), (fs, ((), e))))) =>
1202 (tab, fs, e)))
1203
1204 val dml = log "dml"
1205 (altL [wrap insert Insert,
1206 wrap delete Delete,
1207 wrap update Update])
1208
1209 type check = exp * ErrorMsg.span 793 type check = exp * ErrorMsg.span
1210 794
1211 structure St :> sig 795 structure St :> sig
1212 val reset : unit -> unit 796 val reset : unit -> unit
1213 797