comparison src/iflow.sml @ 1201:8793fd48968c

Generating a good Iflow condition for a test query
author Adam Chlipala <adamc@hcoop.net>
date Sun, 04 Apr 2010 15:17:57 -0400
parents 5eac14322548
children 509a6d7b60fb
comparison
equal deleted inserted replaced
1200:5eac14322548 1201:8793fd48968c
220 case #1 e of 220 case #1 e of
221 EPrim (Prim.String s) => [String s] 221 EPrim (Prim.String s) => [String s]
222 | EStrcat (e1, e2) => chunkify e1 @ chunkify e2 222 | EStrcat (e1, e2) => chunkify e1 @ chunkify e2
223 | _ => [Exp e] 223 | _ => [Exp e]
224 224
225 type 'a parser = chunk list -> ('a * chunk list) option
226
227 fun always v chs = SOME (v, chs)
228
229 fun parse p chs =
230 case p chs of
231 SOME (v, []) => SOME v
232 | _ => NONE
233
234 fun const s chs =
235 case chs of
236 String s' :: chs => if String.isPrefix s s' then
237 SOME ((), if size s = size s' then
238 chs
239 else
240 String (String.extract (s', size s, NONE)) :: chs)
241 else
242 NONE
243 | _ => NONE
244
245 fun follow p1 p2 chs =
246 case p1 chs of
247 NONE => NONE
248 | SOME (v1, chs) =>
249 case p2 chs of
250 NONE => NONE
251 | SOME (v2, chs) => SOME ((v1, v2), chs)
252
253 fun wrap p f chs =
254 case p chs of
255 NONE => NONE
256 | SOME (v, chs) => SOME (f v, chs)
257
258 fun alt p1 p2 chs =
259 case p1 chs of
260 NONE => p2 chs
261 | v => v
262
263 fun skip cp chs =
264 case chs of
265 String "" :: chs => skip cp chs
266 | String s :: chs' => if cp (String.sub (s, 0)) then
267 skip cp (String (String.extract (s, 1, NONE)) :: chs')
268 else
269 SOME ((), chs)
270 | _ => SOME ((), chs)
271
272 fun keep cp chs =
273 case chs of
274 String "" :: chs => keep cp chs
275 | String s :: chs' =>
276 let
277 val (befor, after) = Substring.splitl cp (Substring.full s)
278 in
279 if Substring.isEmpty befor then
280 NONE
281 else
282 SOME (Substring.string befor,
283 if Substring.isEmpty after then
284 chs'
285 else
286 String (Substring.string after) :: chs')
287 end
288 | _ => NONE
289
290 fun ws p = wrap (follow p (skip (fn ch => ch = #" "))) #1
291
292 fun list p chs =
293 (alt (wrap (follow p (follow (ws (const ",")) (list p)))
294 (fn (v, ((), ls)) => v :: ls))
295 (alt (wrap (ws p) (fn v => [v]))
296 (always []))) chs
297
298 val ident = keep (fn ch => Char.isAlphaNum ch orelse ch = #"_")
299
300 val t_ident = wrap ident (fn s => if String.isPrefix "T_" s then
301 String.extract (s, 2, NONE)
302 else
303 raise Fail "Iflow: Bad table variable")
304 val uw_ident = wrap ident (fn s => if String.isPrefix "uw_" s then
305 String.extract (s, 3, NONE)
306 else
307 raise Fail "Iflow: Bad uw_* variable")
308
309 val sitem = wrap (follow t_ident
310 (follow (const ".")
311 uw_ident))
312 (fn (t, ((), f)) => (t, f))
313
314 val select = wrap (follow (const "SELECT ") (list sitem))
315 (fn ((), ls) => ls)
316
317 val fitem = wrap (follow uw_ident
318 (follow (const " AS ")
319 t_ident))
320 (fn (t, ((), f)) => (t, f))
321
322 val from = wrap (follow (const "FROM ") (list fitem))
323 (fn ((), ls) => ls)
324
325 val query = wrap (follow select from)
326 (fn (fs, ts) => {Select = fs, From = ts})
327
225 fun queryProp rv e = 328 fun queryProp rv e =
226 let 329 case parse query (chunkify e) of
227 fun query chs = 330 NONE => Unknown
228 case chs of 331 | SOME r =>
229 [] => raise Fail "Iflow: Empty query" 332 foldl (fn ((t, v), p) =>
230 | Exp _ :: _ => Unknown 333 And (p,
231 | String "" :: chs => query chs 334 Reln (Sql t,
232 | String s :: chs => True 335 [Recd (foldl (fn ((v', f), fs) =>
233 in 336 if v' = v then
234 query (chunkify e) 337 (f, Proj (Proj (Lvar rv, v), f)) :: fs
235 end 338 else
339 fs) [] (#Select r))])))
340 True (#From r)
236 341
237 fun evalExp env (e : Mono.exp, st as (nv, p, sent)) = 342 fun evalExp env (e : Mono.exp, st as (nv, p, sent)) =
238 let 343 let
239 fun default () = 344 fun default () =
240 (Var nv, (nv+1, p, sent)) 345 (Var nv, (nv+1, p, sent))