annotate src/iflow.sml @ 1209:775357041e48

Parsing float and string SQL literals
author Adam Chlipala <adamc@hcoop.net>
date Tue, 06 Apr 2010 11:07:19 -0400
parents b5a4c5407ae0
children c5bd970e77a5
rev   line source
adamc@1200 1 (* Copyright (c) 2010, Adam Chlipala
adamc@1200 2 * All rights reserved.
adamc@1200 3 *
adamc@1200 4 * Redistribution and use in source and binary forms, with or without
adamc@1200 5 * modification, are permitted provided that the following conditions are met:
adamc@1200 6 *
adamc@1200 7 * - Redistributions of source code must retain the above copyright notice,
adamc@1200 8 * this list of conditions and the following disclaimer.
adamc@1200 9 * - Redistributions in binary form must reproduce the above copyright notice,
adamc@1200 10 * this list of conditions and the following disclaimer in the documentation
adamc@1200 11 * and/or other materials provided with the distribution.
adamc@1200 12 * - The names of contributors may not be used to endorse or promote products
adamc@1200 13 * derived from this software without specific prior written permission.
adamc@1200 14 *
adamc@1200 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
adamc@1200 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
adamc@1200 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
adamc@1200 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
adamc@1200 19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
adamc@1200 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
adamc@1200 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
adamc@1200 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
adamc@1200 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
adamc@1200 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
adamc@1200 25 * POSSIBILITY OF SUCH DAMAGE.
adamc@1200 26 *)
adamc@1200 27
adamc@1200 28 structure Iflow :> IFLOW = struct
adamc@1200 29
adamc@1200 30 open Mono
adamc@1200 31
adamc@1207 32 structure IS = IntBinarySet
adamc@1202 33 structure IM = IntBinaryMap
adamc@1202 34
adamc@1200 35 structure SS = BinarySetFn(struct
adamc@1200 36 type ord_key = string
adamc@1200 37 val compare = String.compare
adamc@1200 38 end)
adamc@1200 39
adamc@1200 40 val writers = ["htmlifyInt_w",
adamc@1200 41 "htmlifyFloat_w",
adamc@1200 42 "htmlifyString_w",
adamc@1200 43 "htmlifyBool_w",
adamc@1200 44 "htmlifyTime_w",
adamc@1200 45 "attrifyInt_w",
adamc@1200 46 "attrifyFloat_w",
adamc@1200 47 "attrifyString_w",
adamc@1200 48 "attrifyChar_w",
adamc@1200 49 "urlifyInt_w",
adamc@1200 50 "urlifyFloat_w",
adamc@1200 51 "urlifyString_w",
adamc@1200 52 "urlifyBool_w"]
adamc@1200 53
adamc@1200 54 val writers = SS.addList (SS.empty, writers)
adamc@1200 55
adamc@1200 56 type lvar = int
adamc@1200 57
adamc@1200 58 datatype exp =
adamc@1200 59 Const of Prim.t
adamc@1200 60 | Var of int
adamc@1200 61 | Lvar of lvar
adamc@1200 62 | Func of string * exp list
adamc@1200 63 | Recd of (string * exp) list
adamc@1200 64 | Proj of exp * string
adamc@1200 65 | Finish
adamc@1200 66
adamc@1200 67 datatype reln =
adamc@1207 68 Known
adamc@1207 69 | Sql of string
adamc@1200 70 | Eq
adamc@1200 71
adamc@1200 72 datatype prop =
adamc@1200 73 True
adamc@1200 74 | False
adamc@1200 75 | Unknown
adamc@1200 76 | And of prop * prop
adamc@1200 77 | Or of prop * prop
adamc@1200 78 | Reln of reln * exp list
adamc@1200 79 | Select of int * lvar * lvar * prop * exp
adamc@1200 80
adamc@1200 81 local
adamc@1207 82 open Print
adamc@1207 83 val string = PD.string
adamc@1207 84 in
adamc@1207 85
adamc@1207 86 fun p_exp e =
adamc@1207 87 case e of
adamc@1207 88 Const p => Prim.p_t p
adamc@1207 89 | Var n => string ("x" ^ Int.toString n)
adamc@1207 90 | Lvar n => string ("X" ^ Int.toString n)
adamc@1207 91 | Func (f, es) => box [string (f ^ "("),
adamc@1207 92 p_list p_exp es,
adamc@1207 93 string ")"]
adamc@1207 94 | Recd xes => box [string "{",
adamc@1207 95 p_list (fn (x, e) => box [string "x",
adamc@1207 96 space,
adamc@1207 97 string "=",
adamc@1207 98 space,
adamc@1207 99 p_exp e]) xes,
adamc@1207 100 string "}"]
adamc@1207 101 | Proj (e, x) => box [p_exp e,
adamc@1207 102 string ("." ^ x)]
adamc@1207 103 | Finish => string "FINISH"
adamc@1207 104
adamc@1207 105 fun p_reln r es =
adamc@1207 106 case r of
adamc@1207 107 Known =>
adamc@1207 108 (case es of
adamc@1207 109 [e] => box [string "known(",
adamc@1207 110 p_exp e,
adamc@1207 111 string ")"]
adamc@1207 112 | _ => raise Fail "Iflow.p_reln: Known")
adamc@1207 113 | Sql s => box [string (s ^ "("),
adamc@1207 114 p_list p_exp es,
adamc@1207 115 string ")"]
adamc@1207 116 | Eq =>
adamc@1207 117 (case es of
adamc@1207 118 [e1, e2] => box [p_exp e1,
adamc@1207 119 space,
adamc@1207 120 string "=",
adamc@1207 121 space,
adamc@1207 122 p_exp e2]
adamc@1207 123 | _ => raise Fail "Iflow.p_reln: Eq")
adamc@1207 124
adamc@1207 125 fun p_prop p =
adamc@1207 126 case p of
adamc@1207 127 True => string "True"
adamc@1207 128 | False => string "False"
adamc@1207 129 | Unknown => string "??"
adamc@1207 130 | And (p1, p2) => box [string "(",
adamc@1207 131 p_prop p1,
adamc@1207 132 string ")",
adamc@1207 133 space,
adamc@1207 134 string "&&",
adamc@1207 135 space,
adamc@1207 136 string "(",
adamc@1207 137 p_prop p2,
adamc@1207 138 string ")"]
adamc@1207 139 | Or (p1, p2) => box [string "(",
adamc@1207 140 p_prop p1,
adamc@1207 141 string ")",
adamc@1207 142 space,
adamc@1207 143 string "||",
adamc@1207 144 space,
adamc@1207 145 string "(",
adamc@1207 146 p_prop p2,
adamc@1207 147 string ")"]
adamc@1207 148 | Reln (r, es) => p_reln r es
adamc@1207 149 | Select (n1, n2, n3, p, e) => box [string ("select(x" ^ Int.toString n1
adamc@1207 150 ^ ",X" ^ Int.toString n2
adamc@1207 151 ^ ",X" ^ Int.toString n3
adamc@1207 152 ^ "){"),
adamc@1207 153 p_prop p,
adamc@1207 154 string "}{",
adamc@1207 155 p_exp e,
adamc@1207 156 string "}"]
adamc@1207 157
adamc@1207 158 end
adamc@1207 159
adamc@1207 160 local
adamc@1202 161 val count = ref 1
adamc@1200 162 in
adamc@1200 163 fun newLvar () =
adamc@1200 164 let
adamc@1200 165 val n = !count
adamc@1200 166 in
adamc@1200 167 count := n + 1;
adamc@1200 168 n
adamc@1200 169 end
adamc@1200 170 end
adamc@1200 171
adamc@1200 172 fun subExp (v, lv) =
adamc@1200 173 let
adamc@1200 174 fun sub e =
adamc@1200 175 case e of
adamc@1200 176 Const _ => e
adamc@1200 177 | Var v' => if v' = v then Lvar lv else e
adamc@1200 178 | Lvar _ => e
adamc@1200 179 | Func (f, es) => Func (f, map sub es)
adamc@1200 180 | Recd xes => Recd (map (fn (x, e) => (x, sub e)) xes)
adamc@1200 181 | Proj (e, s) => Proj (sub e, s)
adamc@1200 182 | Finish => Finish
adamc@1200 183 in
adamc@1200 184 sub
adamc@1200 185 end
adamc@1200 186
adamc@1200 187 fun subProp (v, lv) =
adamc@1200 188 let
adamc@1200 189 fun sub p =
adamc@1200 190 case p of
adamc@1200 191 True => p
adamc@1200 192 | False => p
adamc@1200 193 | Unknown => p
adamc@1200 194 | And (p1, p2) => And (sub p1, sub p2)
adamc@1200 195 | Or (p1, p2) => Or (sub p1, sub p2)
adamc@1200 196 | Reln (r, es) => Reln (r, map (subExp (v, lv)) es)
adamc@1200 197 | Select (v1, lv1, lv2, p, e) => Select (v1, lv1, lv2, sub p, subExp (v, lv) e)
adamc@1200 198 in
adamc@1200 199 sub
adamc@1200 200 end
adamc@1200 201
adamc@1200 202 fun isKnown e =
adamc@1200 203 case e of
adamc@1200 204 Const _ => true
adamc@1200 205 | Func (_, es) => List.all isKnown es
adamc@1200 206 | Recd xes => List.all (isKnown o #2) xes
adamc@1200 207 | Proj (e, _) => isKnown e
adamc@1200 208 | _ => false
adamc@1200 209
adamc@1200 210 fun isFinish e =
adamc@1200 211 case e of
adamc@1200 212 Finish => true
adamc@1200 213 | _ => false
adamc@1200 214
adamc@1208 215 val unif = ref (IM.empty : exp IM.map)
adamc@1208 216
adamc@1208 217 fun reset () = unif := IM.empty
adamc@1208 218 fun save () = !unif
adamc@1208 219 fun restore x = unif := x
adamc@1208 220
adamc@1200 221 fun simplify e =
adamc@1200 222 case e of
adamc@1200 223 Const _ => e
adamc@1200 224 | Var _ => e
adamc@1208 225 | Lvar n =>
adamc@1208 226 (case IM.find (!unif, n) of
adamc@1208 227 NONE => e
adamc@1208 228 | SOME e => simplify e)
adamc@1200 229 | Func (f, es) =>
adamc@1200 230 let
adamc@1200 231 val es = map simplify es
adamc@1200 232 in
adamc@1200 233 if List.exists isFinish es then
adamc@1200 234 Finish
adamc@1200 235 else
adamc@1200 236 Func (f, es)
adamc@1200 237 end
adamc@1200 238 | Recd xes =>
adamc@1200 239 let
adamc@1200 240 val xes = map (fn (x, e) => (x, simplify e)) xes
adamc@1200 241 in
adamc@1200 242 if List.exists (isFinish o #2) xes then
adamc@1200 243 Finish
adamc@1200 244 else
adamc@1200 245 Recd xes
adamc@1200 246 end
adamc@1200 247 | Proj (e, s) =>
adamc@1200 248 (case simplify e of
adamc@1200 249 Recd xes =>
adamc@1200 250 getOpt (ListUtil.search (fn (x, e') => if x = s then SOME e' else NONE) xes, Recd xes)
adamc@1200 251 | e' =>
adamc@1200 252 if isFinish e' then
adamc@1200 253 Finish
adamc@1200 254 else
adamc@1200 255 Proj (e', s))
adamc@1200 256 | Finish => Finish
adamc@1200 257
adamc@1202 258 fun decomp fals or =
adamc@1200 259 let
adamc@1200 260 fun decomp p k =
adamc@1200 261 case p of
adamc@1200 262 True => k []
adamc@1202 263 | False => fals
adamc@1200 264 | Unknown => k []
adamc@1200 265 | And (p1, p2) =>
adamc@1200 266 decomp p1 (fn ps1 =>
adamc@1200 267 decomp p2 (fn ps2 =>
adamc@1200 268 k (ps1 @ ps2)))
adamc@1200 269 | Or (p1, p2) =>
adamc@1200 270 or (decomp p1 k, fn () => decomp p2 k)
adamc@1200 271 | Reln x => k [x]
adamc@1200 272 | Select _ => k []
adamc@1200 273 in
adamc@1200 274 decomp
adamc@1200 275 end
adamc@1200 276
adamc@1202 277 fun lvarIn lv =
adamc@1202 278 let
adamc@1202 279 fun lvi e =
adamc@1202 280 case e of
adamc@1202 281 Const _ => false
adamc@1202 282 | Var _ => false
adamc@1202 283 | Lvar lv' => lv' = lv
adamc@1202 284 | Func (_, es) => List.exists lvi es
adamc@1202 285 | Recd xes => List.exists (lvi o #2) xes
adamc@1202 286 | Proj (e, _) => lvi e
adamc@1202 287 | Finish => false
adamc@1202 288 in
adamc@1202 289 lvi
adamc@1202 290 end
adamc@1202 291
adamc@1202 292 fun eq' (e1, e2) =
adamc@1202 293 case (e1, e2) of
adamc@1202 294 (Const p1, Const p2) => Prim.equal (p1, p2)
adamc@1202 295 | (Var n1, Var n2) => n1 = n2
adamc@1202 296
adamc@1202 297 | (Lvar n1, _) =>
adamc@1202 298 (case IM.find (!unif, n1) of
adamc@1202 299 SOME e1 => eq' (e1, e2)
adamc@1202 300 | NONE =>
adamc@1202 301 case e2 of
adamc@1202 302 Lvar n2 =>
adamc@1202 303 (case IM.find (!unif, n2) of
adamc@1202 304 SOME e2 => eq' (e1, e2)
adamc@1202 305 | NONE => n1 = n2
adamc@1208 306 orelse (unif := IM.insert (!unif, n2, e1);
adamc@1202 307 true))
adamc@1202 308 | _ =>
adamc@1202 309 if lvarIn n1 e2 then
adamc@1202 310 false
adamc@1202 311 else
adamc@1202 312 (unif := IM.insert (!unif, n1, e2);
adamc@1202 313 true))
adamc@1202 314
adamc@1202 315 | (_, Lvar n2) =>
adamc@1202 316 (case IM.find (!unif, n2) of
adamc@1202 317 SOME e2 => eq' (e1, e2)
adamc@1202 318 | NONE =>
adamc@1202 319 if lvarIn n2 e1 then
adamc@1202 320 false
adamc@1202 321 else
adamc@1202 322 (unif := IM.insert (!unif, n2, e1);
adamc@1202 323 true))
adamc@1202 324
adamc@1202 325 | (Func (f1, es1), Func (f2, es2)) => f1 = f2 andalso ListPair.allEq eq' (es1, es2)
adamc@1202 326 | (Recd xes1, Recd xes2) => ListPair.allEq (fn ((x1, e1), (x2, e2)) => x1 = x2 andalso eq' (e1, e2)) (xes1, xes2)
adamc@1202 327 | (Proj (e1, s1), Proj (e2, s2)) => eq' (e1, e2) andalso s1 = s2
adamc@1202 328 | (Finish, Finish) => true
adamc@1202 329 | _ => false
adamc@1202 330
adamc@1202 331 fun eq (e1, e2) =
adamc@1202 332 let
adamc@1203 333 val saved = save ()
adamc@1202 334 in
adamc@1202 335 if eq' (simplify e1, simplify e2) then
adamc@1202 336 true
adamc@1202 337 else
adamc@1203 338 (restore saved;
adamc@1202 339 false)
adamc@1202 340 end
adamc@1202 341
adamc@1202 342 exception Imply of prop * prop
adamc@1202 343
adamc@1208 344 val debug = ref false
adamc@1208 345
adamc@1208 346 (* Congruence closure *)
adamc@1208 347 structure Cc :> sig
adamc@1208 348 type t
adamc@1208 349 val empty : t
adamc@1208 350 val assert : t * exp * exp -> t
adamc@1208 351 val query : t * exp * exp -> bool
adamc@1208 352 val allPeers : t * exp -> exp list
adamc@1208 353 end = struct
adamc@1208 354
adamc@1208 355 fun eq' (e1, e2) =
adamc@1208 356 case (e1, e2) of
adamc@1208 357 (Const p1, Const p2) => Prim.equal (p1, p2)
adamc@1208 358 | (Var n1, Var n2) => n1 = n2
adamc@1208 359 | (Lvar n1, Lvar n2) => n1 = n2
adamc@1208 360 | (Func (f1, es1), Func (f2, es2)) => f1 = f2 andalso ListPair.allEq eq' (es1, es2)
adamc@1208 361 | (Recd xes1, Recd xes2) => length xes1 = length xes2 andalso
adamc@1208 362 List.all (fn (x2, e2) =>
adamc@1208 363 List.exists (fn (x1, e1) => x1 = x2 andalso eq' (e1, e2)) xes2) xes1
adamc@1208 364 | (Proj (e1, x1), Proj (e2, x2)) => eq' (e1, e2) andalso x1 = x2
adamc@1208 365 | (Finish, Finish) => true
adamc@1208 366 | _ => false
adamc@1208 367
adamc@1208 368 fun eq (e1, e2) = eq' (simplify e1, simplify e2)
adamc@1208 369
adamc@1208 370 type t = (exp * exp) list
adamc@1208 371
adamc@1208 372 val empty = []
adamc@1208 373
adamc@1208 374 fun lookup (t, e) =
adamc@1208 375 case List.find (fn (e', _) => eq (e', e)) t of
adamc@1208 376 NONE => e
adamc@1208 377 | SOME (_, e2) => lookup (t, e2)
adamc@1208 378
adamc@1208 379 fun assert (t, e1, e2) =
adamc@1208 380 let
adamc@1208 381 val r1 = lookup (t, e1)
adamc@1208 382 val r2 = lookup (t, e2)
adamc@1208 383 in
adamc@1208 384 if eq (r1, r2) then
adamc@1208 385 t
adamc@1208 386 else
adamc@1208 387 (r1, r2) :: t
adamc@1208 388 end
adamc@1208 389
adamc@1208 390 open Print
adamc@1208 391
adamc@1208 392 fun query (t, e1, e2) =
adamc@1208 393 (if !debug then
adamc@1208 394 prefaces "CC query" [("e1", p_exp (simplify e1)),
adamc@1208 395 ("e2", p_exp (simplify e2)),
adamc@1208 396 ("t", p_list (fn (e1, e2) => box [p_exp (simplify e1),
adamc@1208 397 space,
adamc@1208 398 PD.string "->",
adamc@1208 399 space,
adamc@1208 400 p_exp (simplify e2)]) t)]
adamc@1208 401 else
adamc@1208 402 ();
adamc@1208 403 eq (lookup (t, e1), lookup (t, e2)))
adamc@1208 404
adamc@1208 405 fun allPeers (t, e) =
adamc@1208 406 let
adamc@1208 407 val r = lookup (t, e)
adamc@1208 408 in
adamc@1208 409 r :: List.mapPartial (fn (e1, e2) =>
adamc@1208 410 let
adamc@1208 411 val r' = lookup (t, e2)
adamc@1208 412 in
adamc@1208 413 if eq (r, r') then
adamc@1208 414 SOME e1
adamc@1208 415 else
adamc@1208 416 NONE
adamc@1208 417 end) t
adamc@1208 418 end
adamc@1208 419
adamc@1208 420 end
adamc@1208 421
adamc@1208 422 fun rimp cc ((r1, es1), (r2, es2)) =
adamc@1202 423 case (r1, r2) of
adamc@1202 424 (Sql r1', Sql r2') =>
adamc@1202 425 r1' = r2' andalso
adamc@1202 426 (case (es1, es2) of
adamc@1202 427 ([Recd xes1], [Recd xes2]) =>
adamc@1202 428 let
adamc@1203 429 val saved = save ()
adamc@1202 430 in
adamc@1202 431 if List.all (fn (f, e2) =>
adamc@1203 432 case ListUtil.search (fn (f', e1) => if f' = f then SOME e1 else NONE) xes1 of
adamc@1203 433 NONE => true
adamc@1203 434 | SOME e1 => eq (e1, e2)) xes2 then
adamc@1202 435 true
adamc@1202 436 else
adamc@1203 437 (restore saved;
adamc@1202 438 false)
adamc@1202 439 end
adamc@1202 440 | _ => false)
adamc@1202 441 | (Eq, Eq) =>
adamc@1202 442 (case (es1, es2) of
adamc@1202 443 ([x1, y1], [x2, y2]) =>
adamc@1202 444 let
adamc@1203 445 val saved = save ()
adamc@1202 446 in
adamc@1202 447 if eq (x1, x2) andalso eq (y1, y2) then
adamc@1202 448 true
adamc@1202 449 else
adamc@1203 450 (restore saved;
adamc@1208 451 if eq (x1, y2) andalso eq (y1, x2) then
adamc@1208 452 true
adamc@1208 453 else
adamc@1208 454 (restore saved;
adamc@1208 455 false))
adamc@1202 456 end
adamc@1202 457 | _ => false)
adamc@1207 458 | (Known, Known) =>
adamc@1207 459 (case (es1, es2) of
adamc@1208 460 ([Var v], [e2]) =>
adamc@1207 461 let
adamc@1208 462 fun matches e =
adamc@1208 463 case e of
adamc@1208 464 Var v' => v' = v
adamc@1208 465 | Proj (e, _) => matches e
adamc@1207 466 | _ => false
adamc@1207 467 in
adamc@1208 468 List.exists matches (Cc.allPeers (cc, e2))
adamc@1207 469 end
adamc@1207 470 | _ => false)
adamc@1202 471 | _ => false
adamc@1202 472
adamc@1202 473 fun imply (p1, p2) =
adamc@1208 474 let
adamc@1208 475 fun doOne doKnown =
adamc@1208 476 decomp true (fn (e1, e2) => e1 andalso e2 ()) p1
adamc@1208 477 (fn hyps =>
adamc@1208 478 decomp false (fn (e1, e2) => e1 orelse e2 ()) p2
adamc@1208 479 (fn goals =>
adamc@1208 480 let
adamc@1208 481 val cc = foldl (fn (p, cc) =>
adamc@1208 482 case p of
adamc@1208 483 (Eq, [e1, e2]) => Cc.assert (cc, e1, e2)
adamc@1208 484 | _ => cc) Cc.empty hyps
adamc@1202 485
adamc@1208 486 fun gls goals onFail =
adamc@1208 487 case goals of
adamc@1208 488 [] => true
adamc@1208 489 | g :: goals =>
adamc@1208 490 case (doKnown, g) of
adamc@1208 491 (false, (Known, _)) => gls goals onFail
adamc@1208 492 | _ =>
adamc@1208 493 let
adamc@1208 494 fun hps hyps =
adamc@1208 495 case hyps of
adamc@1208 496 [] => onFail ()
adamc@1208 497 | h :: hyps =>
adamc@1208 498 let
adamc@1208 499 val saved = save ()
adamc@1208 500 in
adamc@1208 501 if rimp cc (h, g) then
adamc@1208 502 let
adamc@1208 503 val changed = IM.numItems (!unif)
adamc@1208 504 <> IM.numItems saved
adamc@1208 505 in
adamc@1208 506 gls goals (fn () => (restore saved;
adamc@1208 507 changed andalso hps hyps))
adamc@1208 508 end
adamc@1208 509 else
adamc@1208 510 hps hyps
adamc@1208 511 end
adamc@1208 512 in
adamc@1208 513 (case g of
adamc@1208 514 (Eq, [e1, e2]) => Cc.query (cc, e1, e2)
adamc@1208 515 | _ => false)
adamc@1208 516 orelse hps hyps
adamc@1208 517 end
adamc@1208 518 in
adamc@1208 519 gls goals (fn () => false)
adamc@1208 520 end))
adamc@1208 521 in
adamc@1208 522 reset ();
adamc@1208 523 doOne false;
adamc@1208 524 doOne true
adamc@1208 525 end
adamc@1200 526
adamc@1200 527 fun patCon pc =
adamc@1200 528 case pc of
adamc@1200 529 PConVar n => "C" ^ Int.toString n
adamc@1200 530 | PConFfi {mod = m, datatyp = d, con = c, ...} => m ^ "." ^ d ^ "." ^ c
adamc@1200 531
adamc@1202 532
adamc@1200 533
adamc@1200 534 datatype chunk =
adamc@1200 535 String of string
adamc@1200 536 | Exp of Mono.exp
adamc@1200 537
adamc@1200 538 fun chunkify e =
adamc@1200 539 case #1 e of
adamc@1200 540 EPrim (Prim.String s) => [String s]
adamc@1207 541 | EStrcat (e1, e2) =>
adamc@1207 542 let
adamc@1207 543 val chs1 = chunkify e1
adamc@1207 544 val chs2 = chunkify e2
adamc@1207 545 in
adamc@1207 546 case chs2 of
adamc@1207 547 String s2 :: chs2' =>
adamc@1207 548 (case List.last chs1 of
adamc@1207 549 String s1 => List.take (chs1, length chs1 - 1) @ String (s1 ^ s2) :: chs2'
adamc@1207 550 | _ => chs1 @ chs2)
adamc@1207 551 | _ => chs1 @ chs2
adamc@1207 552 end
adamc@1200 553 | _ => [Exp e]
adamc@1200 554
adamc@1201 555 type 'a parser = chunk list -> ('a * chunk list) option
adamc@1201 556
adamc@1201 557 fun always v chs = SOME (v, chs)
adamc@1201 558
adamc@1202 559 fun parse p s =
adamc@1202 560 case p (chunkify s) of
adamc@1201 561 SOME (v, []) => SOME v
adamc@1201 562 | _ => NONE
adamc@1201 563
adamc@1201 564 fun const s chs =
adamc@1201 565 case chs of
adamc@1201 566 String s' :: chs => if String.isPrefix s s' then
adamc@1201 567 SOME ((), if size s = size s' then
adamc@1201 568 chs
adamc@1201 569 else
adamc@1201 570 String (String.extract (s', size s, NONE)) :: chs)
adamc@1201 571 else
adamc@1201 572 NONE
adamc@1201 573 | _ => NONE
adamc@1201 574
adamc@1201 575 fun follow p1 p2 chs =
adamc@1201 576 case p1 chs of
adamc@1201 577 NONE => NONE
adamc@1201 578 | SOME (v1, chs) =>
adamc@1201 579 case p2 chs of
adamc@1201 580 NONE => NONE
adamc@1201 581 | SOME (v2, chs) => SOME ((v1, v2), chs)
adamc@1201 582
adamc@1201 583 fun wrap p f chs =
adamc@1201 584 case p chs of
adamc@1201 585 NONE => NONE
adamc@1201 586 | SOME (v, chs) => SOME (f v, chs)
adamc@1201 587
adamc@1209 588 fun wrapP p f chs =
adamc@1209 589 case p chs of
adamc@1209 590 NONE => NONE
adamc@1209 591 | SOME (v, chs) =>
adamc@1209 592 case f v of
adamc@1209 593 NONE => NONE
adamc@1209 594 | SOME r => SOME (r, chs)
adamc@1209 595
adamc@1201 596 fun alt p1 p2 chs =
adamc@1201 597 case p1 chs of
adamc@1201 598 NONE => p2 chs
adamc@1201 599 | v => v
adamc@1201 600
adamc@1207 601 fun altL ps =
adamc@1207 602 case rev ps of
adamc@1207 603 [] => (fn _ => NONE)
adamc@1207 604 | p :: ps =>
adamc@1207 605 foldl (fn (p1, p2) => alt p1 p2) p ps
adamc@1207 606
adamc@1204 607 fun opt p chs =
adamc@1204 608 case p chs of
adamc@1204 609 NONE => SOME (NONE, chs)
adamc@1204 610 | SOME (v, chs) => SOME (SOME v, chs)
adamc@1204 611
adamc@1201 612 fun skip cp chs =
adamc@1201 613 case chs of
adamc@1201 614 String "" :: chs => skip cp chs
adamc@1201 615 | String s :: chs' => if cp (String.sub (s, 0)) then
adamc@1201 616 skip cp (String (String.extract (s, 1, NONE)) :: chs')
adamc@1201 617 else
adamc@1201 618 SOME ((), chs)
adamc@1201 619 | _ => SOME ((), chs)
adamc@1201 620
adamc@1201 621 fun keep cp chs =
adamc@1201 622 case chs of
adamc@1201 623 String "" :: chs => keep cp chs
adamc@1201 624 | String s :: chs' =>
adamc@1201 625 let
adamc@1201 626 val (befor, after) = Substring.splitl cp (Substring.full s)
adamc@1201 627 in
adamc@1201 628 if Substring.isEmpty befor then
adamc@1201 629 NONE
adamc@1201 630 else
adamc@1201 631 SOME (Substring.string befor,
adamc@1201 632 if Substring.isEmpty after then
adamc@1201 633 chs'
adamc@1201 634 else
adamc@1201 635 String (Substring.string after) :: chs')
adamc@1201 636 end
adamc@1201 637 | _ => NONE
adamc@1201 638
adamc@1204 639 fun ws p = wrap (follow (skip (fn ch => ch = #" "))
adamc@1204 640 (follow p (skip (fn ch => ch = #" ")))) (#1 o #2)
adamc@1204 641
adamc@1204 642 fun log name p chs =
adamc@1206 643 (if !debug then
adamc@1206 644 case chs of
adamc@1207 645 String s :: _ => print (name ^ ": " ^ s ^ "\n")
adamc@1206 646 | _ => print (name ^ ": blocked!\n")
adamc@1206 647 else
adamc@1206 648 ();
adamc@1204 649 p chs)
adamc@1201 650
adamc@1201 651 fun list p chs =
adamc@1207 652 altL [wrap (follow p (follow (ws (const ",")) (list p)))
adamc@1207 653 (fn (v, ((), ls)) => v :: ls),
adamc@1207 654 wrap (ws p) (fn v => [v]),
adamc@1207 655 always []] chs
adamc@1201 656
adamc@1201 657 val ident = keep (fn ch => Char.isAlphaNum ch orelse ch = #"_")
adamc@1201 658
adamc@1201 659 val t_ident = wrap ident (fn s => if String.isPrefix "T_" s then
adamc@1201 660 String.extract (s, 2, NONE)
adamc@1201 661 else
adamc@1201 662 raise Fail "Iflow: Bad table variable")
adamc@1201 663 val uw_ident = wrap ident (fn s => if String.isPrefix "uw_" s then
adamc@1201 664 String.extract (s, 3, NONE)
adamc@1201 665 else
adamc@1201 666 raise Fail "Iflow: Bad uw_* variable")
adamc@1201 667
adamc@1201 668 val sitem = wrap (follow t_ident
adamc@1201 669 (follow (const ".")
adamc@1201 670 uw_ident))
adamc@1201 671 (fn (t, ((), f)) => (t, f))
adamc@1201 672
adamc@1206 673 datatype Rel =
adamc@1206 674 Exps of exp * exp -> prop
adamc@1206 675 | Props of prop * prop -> prop
adamc@1206 676
adamc@1204 677 datatype sqexp =
adamc@1206 678 SqConst of Prim.t
adamc@1206 679 | Field of string * string
adamc@1206 680 | Binop of Rel * sqexp * sqexp
adamc@1207 681 | SqKnown of sqexp
adamc@1207 682 | Inj of Mono.exp
adamc@1204 683
adamc@1207 684 val sqbrel = altL [wrap (const "=") (fn () => Exps (fn (e1, e2) => Reln (Eq, [e1, e2]))),
adamc@1207 685 wrap (const "AND") (fn () => Props And),
adamc@1207 686 wrap (const "OR") (fn () => Props Or)]
adamc@1204 687
adamc@1204 688 datatype ('a, 'b) sum = inl of 'a | inr of 'b
adamc@1204 689
adamc@1209 690 fun string chs =
adamc@1206 691 case chs of
adamc@1209 692 String s :: chs =>
adamc@1209 693 if size s >= 2 andalso String.sub (s, 0) = #"'" then
adamc@1209 694 let
adamc@1209 695 fun loop (cs, acc) =
adamc@1209 696 case cs of
adamc@1209 697 [] => NONE
adamc@1209 698 | c :: cs =>
adamc@1209 699 if c = #"'" then
adamc@1209 700 SOME (String.implode (rev acc), cs)
adamc@1209 701 else if c = #"\\" then
adamc@1209 702 case cs of
adamc@1209 703 c :: cs => loop (cs, c :: acc)
adamc@1209 704 | _ => raise Fail "Iflow.string: Unmatched backslash escape"
adamc@1209 705 else
adamc@1209 706 loop (cs, c :: acc)
adamc@1209 707 in
adamc@1209 708 case loop (String.explode (String.extract (s, 1, NONE)), []) of
adamc@1209 709 NONE => NONE
adamc@1209 710 | SOME (s, []) => SOME (s, chs)
adamc@1209 711 | SOME (s, cs) => SOME (s, String (String.implode cs) :: chs)
adamc@1209 712 end
adamc@1209 713 else
adamc@1209 714 NONE
adamc@1209 715 | _ => NONE
adamc@1206 716
adamc@1209 717 val prim =
adamc@1209 718 altL [wrap (follow (wrapP (follow (keep Char.isDigit) (follow (const ".") (keep Char.isDigit)))
adamc@1209 719 (fn (x, ((), y)) => Option.map Prim.Float (Real64.fromString (x ^ "." ^ y))))
adamc@1209 720 (opt (const "::float8"))) #1,
adamc@1209 721 wrap (follow (wrapP (keep Char.isDigit)
adamc@1209 722 (Option.map Prim.Int o Int64.fromString))
adamc@1209 723 (opt (const "::int8"))) #1,
adamc@1209 724 wrap (follow (opt (const "E")) (follow string (opt (const "::text"))))
adamc@1209 725 (Prim.String o #1 o #2)]
adamc@1206 726
adamc@1207 727 fun known' chs =
adamc@1207 728 case chs of
adamc@1207 729 Exp (EFfi ("Basis", "sql_known"), _) :: chs => SOME ((), chs)
adamc@1207 730 | _ => NONE
adamc@1207 731
adamc@1207 732 fun sqlify chs =
adamc@1207 733 case chs of
adamc@1207 734 Exp (EFfiApp ("Basis", f, [e]), _) :: chs =>
adamc@1207 735 if String.isPrefix "sqlify" f then
adamc@1207 736 SOME (e, chs)
adamc@1207 737 else
adamc@1207 738 NONE
adamc@1207 739 | _ => NONE
adamc@1207 740
adamc@1204 741 fun sqexp chs =
adamc@1206 742 log "sqexp"
adamc@1207 743 (altL [wrap prim SqConst,
adamc@1207 744 wrap sitem Field,
adamc@1207 745 wrap known SqKnown,
adamc@1207 746 wrap sqlify Inj,
adamc@1207 747 wrap (follow (ws (const "("))
adamc@1207 748 (follow (wrap
adamc@1207 749 (follow sqexp
adamc@1207 750 (alt
adamc@1207 751 (wrap
adamc@1207 752 (follow (ws sqbrel)
adamc@1207 753 (ws sqexp))
adamc@1207 754 inl)
adamc@1207 755 (always (inr ()))))
adamc@1207 756 (fn (e1, sm) =>
adamc@1207 757 case sm of
adamc@1207 758 inl (bo, e2) => Binop (bo, e1, e2)
adamc@1207 759 | inr () => e1))
adamc@1207 760 (const ")")))
adamc@1207 761 (fn ((), (e, ())) => e)])
adamc@1207 762 chs
adamc@1206 763
adamc@1207 764 and known chs = wrap (follow known' (follow (const "(") (follow sqexp (const ")"))))
adamc@1207 765 (fn ((), ((), (e, ()))) => e) chs
adamc@1207 766
adamc@1207 767 val select = log "select"
adamc@1207 768 (wrap (follow (const "SELECT ") (list sitem))
adamc@1207 769 (fn ((), ls) => ls))
adamc@1201 770
adamc@1201 771 val fitem = wrap (follow uw_ident
adamc@1201 772 (follow (const " AS ")
adamc@1201 773 t_ident))
adamc@1201 774 (fn (t, ((), f)) => (t, f))
adamc@1201 775
adamc@1207 776 val from = log "from"
adamc@1207 777 (wrap (follow (const "FROM ") (list fitem))
adamc@1207 778 (fn ((), ls) => ls))
adamc@1201 779
adamc@1204 780 val wher = wrap (follow (ws (const "WHERE ")) sqexp)
adamc@1204 781 (fn ((), ls) => ls)
adamc@1204 782
adamc@1207 783 val query = log "query"
adamc@1207 784 (wrap (follow (follow select from) (opt wher))
adamc@1207 785 (fn ((fs, ts), wher) => {Select = fs, From = ts, Where = wher}))
adamc@1201 786
adamc@1207 787 fun queryProp env rv oe e =
adamc@1202 788 case parse query e of
adamc@1207 789 NONE => (print ("Warning: Information flow checker can't parse SQL query at "
adamc@1207 790 ^ ErrorMsg.spanToString (#2 e) ^ "\n");
adamc@1207 791 Unknown)
adamc@1201 792 | SOME r =>
adamc@1202 793 let
adamc@1202 794 val p =
adamc@1202 795 foldl (fn ((t, v), p) =>
adamc@1202 796 And (p,
adamc@1202 797 Reln (Sql t,
adamc@1202 798 [Recd (foldl (fn ((v', f), fs) =>
adamc@1202 799 if v' = v then
adamc@1202 800 (f, Proj (Proj (Lvar rv, v), f)) :: fs
adamc@1202 801 else
adamc@1202 802 fs) [] (#Select r))])))
adamc@1202 803 True (#From r)
adamc@1205 804
adamc@1205 805 fun expIn e =
adamc@1205 806 case e of
adamc@1206 807 SqConst p => inl (Const p)
adamc@1206 808 | Field (v, f) => inl (Proj (Proj (Lvar rv, v), f))
adamc@1205 809 | Binop (bo, e1, e2) =>
adamc@1206 810 inr (case (bo, expIn e1, expIn e2) of
adamc@1206 811 (Exps f, inl e1, inl e2) => f (e1, e2)
adamc@1206 812 | (Props f, inr p1, inr p2) => f (p1, p2)
adamc@1206 813 | _ => Unknown)
adamc@1207 814 | SqKnown e =>
adamc@1207 815 inr (case expIn e of
adamc@1207 816 inl e => Reln (Known, [e])
adamc@1207 817 | _ => Unknown)
adamc@1207 818 | Inj e =>
adamc@1207 819 let
adamc@1207 820 fun deinj (e, _) =
adamc@1207 821 case e of
adamc@1207 822 ERel n => List.nth (env, n)
adamc@1207 823 | EField (e, f) => Proj (deinj e, f)
adamc@1207 824 | _ => raise Fail "Iflow: non-variable injected into query"
adamc@1207 825 in
adamc@1207 826 inl (deinj e)
adamc@1207 827 end
adamc@1205 828
adamc@1205 829 val p = case #Where r of
adamc@1205 830 NONE => p
adamc@1205 831 | SOME e =>
adamc@1205 832 case expIn e of
adamc@1205 833 inr p' => And (p, p')
adamc@1205 834 | _ => p
adamc@1202 835 in
adamc@1202 836 case oe of
adamc@1202 837 NONE => p
adamc@1202 838 | SOME oe =>
adamc@1205 839 And (p, foldl (fn ((v, f), p) =>
adamc@1205 840 Or (p,
adamc@1205 841 Reln (Eq, [oe, Proj (Proj (Lvar rv, v), f)])))
adamc@1205 842 False (#Select r))
adamc@1202 843 end
adamc@1200 844
adamc@1202 845 fun evalExp env (e as (_, loc), st as (nv, p, sent)) =
adamc@1200 846 let
adamc@1200 847 fun default () =
adamc@1200 848 (Var nv, (nv+1, p, sent))
adamc@1200 849
adamc@1200 850 fun addSent (p, e, sent) =
adamc@1200 851 if isKnown e then
adamc@1200 852 sent
adamc@1200 853 else
adamc@1202 854 (loc, e, p) :: sent
adamc@1200 855 in
adamc@1200 856 case #1 e of
adamc@1200 857 EPrim p => (Const p, st)
adamc@1200 858 | ERel n => (List.nth (env, n), st)
adamc@1200 859 | ENamed _ => default ()
adamc@1200 860 | ECon (_, pc, NONE) => (Func (patCon pc, []), st)
adamc@1200 861 | ECon (_, pc, SOME e) =>
adamc@1200 862 let
adamc@1200 863 val (e, st) = evalExp env (e, st)
adamc@1200 864 in
adamc@1200 865 (Func (patCon pc, [e]), st)
adamc@1200 866 end
adamc@1200 867 | ENone _ => (Func ("None", []), st)
adamc@1200 868 | ESome (_, e) =>
adamc@1200 869 let
adamc@1200 870 val (e, st) = evalExp env (e, st)
adamc@1200 871 in
adamc@1200 872 (Func ("Some", [e]), st)
adamc@1200 873 end
adamc@1200 874 | EFfi _ => default ()
adamc@1200 875 | EFfiApp (m, s, es) =>
adamc@1200 876 if m = "Basis" andalso SS.member (writers, s) then
adamc@1200 877 let
adamc@1200 878 val (es, st) = ListUtil.foldlMap (evalExp env) st es
adamc@1200 879 in
adamc@1200 880 (Func ("unit", []), (#1 st, p, foldl (fn (e, sent) => addSent (#2 st, e, sent)) sent es))
adamc@1200 881 end
adamc@1200 882 else if Settings.isEffectful (m, s) andalso not (Settings.isBenignEffectful (m, s)) then
adamc@1200 883 default ()
adamc@1200 884 else
adamc@1200 885 let
adamc@1200 886 val (es, st) = ListUtil.foldlMap (evalExp env) st es
adamc@1200 887 in
adamc@1200 888 (Func (m ^ "." ^ s, es), st)
adamc@1200 889 end
adamc@1200 890 | EApp _ => default ()
adamc@1200 891 | EAbs _ => default ()
adamc@1200 892 | EUnop (s, e1) =>
adamc@1200 893 let
adamc@1200 894 val (e1, st) = evalExp env (e1, st)
adamc@1200 895 in
adamc@1200 896 (Func (s, [e1]), st)
adamc@1200 897 end
adamc@1200 898 | EBinop (s, e1, e2) =>
adamc@1200 899 let
adamc@1200 900 val (e1, st) = evalExp env (e1, st)
adamc@1200 901 val (e2, st) = evalExp env (e2, st)
adamc@1200 902 in
adamc@1200 903 (Func (s, [e1, e2]), st)
adamc@1200 904 end
adamc@1200 905 | ERecord xets =>
adamc@1200 906 let
adamc@1200 907 val (xes, st) = ListUtil.foldlMap (fn ((x, e, _), st) =>
adamc@1200 908 let
adamc@1200 909 val (e, st) = evalExp env (e, st)
adamc@1200 910 in
adamc@1200 911 ((x, e), st)
adamc@1200 912 end) st xets
adamc@1200 913 in
adamc@1200 914 (Recd xes, st)
adamc@1200 915 end
adamc@1200 916 | EField (e, s) =>
adamc@1200 917 let
adamc@1200 918 val (e, st) = evalExp env (e, st)
adamc@1200 919 in
adamc@1200 920 (Proj (e, s), st)
adamc@1200 921 end
adamc@1200 922 | ECase _ => default ()
adamc@1200 923 | EStrcat (e1, e2) =>
adamc@1200 924 let
adamc@1200 925 val (e1, st) = evalExp env (e1, st)
adamc@1200 926 val (e2, st) = evalExp env (e2, st)
adamc@1200 927 in
adamc@1200 928 (Func ("cat", [e1, e2]), st)
adamc@1200 929 end
adamc@1200 930 | EError _ => (Finish, st)
adamc@1200 931 | EReturnBlob {blob = b, mimeType = m, ...} =>
adamc@1200 932 let
adamc@1200 933 val (b, st) = evalExp env (b, st)
adamc@1200 934 val (m, st) = evalExp env (m, st)
adamc@1200 935 in
adamc@1200 936 (Finish, (#1 st, p, addSent (#2 st, b, addSent (#2 st, m, sent))))
adamc@1200 937 end
adamc@1200 938 | ERedirect (e, _) =>
adamc@1200 939 let
adamc@1200 940 val (e, st) = evalExp env (e, st)
adamc@1200 941 in
adamc@1200 942 (Finish, (#1 st, p, addSent (#2 st, e, sent)))
adamc@1200 943 end
adamc@1200 944 | EWrite e =>
adamc@1200 945 let
adamc@1200 946 val (e, st) = evalExp env (e, st)
adamc@1200 947 in
adamc@1200 948 (Func ("unit", []), (#1 st, p, addSent (#2 st, e, sent)))
adamc@1200 949 end
adamc@1200 950 | ESeq (e1, e2) =>
adamc@1200 951 let
adamc@1200 952 val (_, st) = evalExp env (e1, st)
adamc@1200 953 in
adamc@1200 954 evalExp env (e2, st)
adamc@1200 955 end
adamc@1200 956 | ELet (_, _, e1, e2) =>
adamc@1200 957 let
adamc@1200 958 val (e1, st) = evalExp env (e1, st)
adamc@1200 959 in
adamc@1200 960 evalExp (e1 :: env) (e2, st)
adamc@1200 961 end
adamc@1200 962 | EClosure (n, es) =>
adamc@1200 963 let
adamc@1200 964 val (es, st) = ListUtil.foldlMap (evalExp env) st es
adamc@1200 965 in
adamc@1200 966 (Func ("Cl" ^ Int.toString n, es), st)
adamc@1200 967 end
adamc@1200 968
adamc@1200 969 | EQuery {query = q, body = b, initial = i, ...} =>
adamc@1200 970 let
adamc@1200 971 val (_, st) = evalExp env (q, st)
adamc@1200 972 val (i, st) = evalExp env (i, st)
adamc@1200 973
adamc@1200 974 val r = #1 st
adamc@1200 975 val acc = #1 st + 1
adamc@1200 976 val st' = (#1 st + 2, #2 st, #3 st)
adamc@1200 977
adamc@1200 978 val (b, st') = evalExp (Var acc :: Var r :: env) (b, st')
adamc@1200 979
adamc@1200 980 val r' = newLvar ()
adamc@1200 981 val acc' = newLvar ()
adamc@1207 982 val qp = queryProp env r' NONE q
adamc@1200 983
adamc@1200 984 val doSubExp = subExp (r, r') o subExp (acc, acc')
adamc@1200 985 val doSubProp = subProp (r, r') o subProp (acc, acc')
adamc@1200 986
adamc@1200 987 val p = doSubProp (#2 st')
adamc@1200 988 val p = And (p, qp)
adamc@1200 989 val p = Select (r, r', acc', p, doSubExp b)
adamc@1200 990 in
adamc@1202 991 (Var r, (#1 st + 1, And (#2 st, p), map (fn (loc, e, p) => (loc,
adamc@1202 992 doSubExp e,
adamc@1202 993 And (qp, doSubProp p))) (#3 st')))
adamc@1200 994 end
adamc@1200 995 | EDml _ => default ()
adamc@1200 996 | ENextval _ => default ()
adamc@1200 997 | ESetval _ => default ()
adamc@1200 998
adamc@1200 999 | EUnurlify _ => default ()
adamc@1200 1000 | EJavaScript _ => default ()
adamc@1200 1001 | ESignalReturn _ => default ()
adamc@1200 1002 | ESignalBind _ => default ()
adamc@1200 1003 | ESignalSource _ => default ()
adamc@1200 1004 | EServerCall _ => default ()
adamc@1200 1005 | ERecv _ => default ()
adamc@1200 1006 | ESleep _ => default ()
adamc@1200 1007 | ESpawn _ => default ()
adamc@1200 1008 end
adamc@1200 1009
adamc@1200 1010 fun check file =
adamc@1200 1011 let
adamc@1207 1012 val exptd = foldl (fn ((d, _), exptd) =>
adamc@1207 1013 case d of
adamc@1207 1014 DExport (_, _, n, _, _, _) => IS.add (exptd, n)
adamc@1207 1015 | _ => exptd) IS.empty file
adamc@1207 1016
adamc@1202 1017 fun decl ((d, _), (vals, pols)) =
adamc@1200 1018 case d of
adamc@1207 1019 DVal (_, n, _, e, _) =>
adamc@1200 1020 let
adamc@1207 1021 val isExptd = IS.member (exptd, n)
adamc@1207 1022
adamc@1207 1023 fun deAbs (e, env, nv, p) =
adamc@1200 1024 case #1 e of
adamc@1207 1025 EAbs (_, _, _, e) => deAbs (e, Var nv :: env, nv + 1,
adamc@1207 1026 if isExptd then
adamc@1207 1027 And (p, Reln (Known, [Var nv]))
adamc@1207 1028 else
adamc@1207 1029 p)
adamc@1207 1030 | _ => (e, env, nv, p)
adamc@1200 1031
adamc@1207 1032 val (e, env, nv, p) = deAbs (e, [], 1, True)
adamc@1200 1033
adamc@1207 1034 val (e, (_, p, sent)) = evalExp env (e, (nv, p, []))
adamc@1200 1035 in
adamc@1207 1036 (sent @ vals, pols)
adamc@1200 1037 end
adamc@1202 1038
adamc@1207 1039 | DPolicy (PolQuery e) => (vals, queryProp [] 0 (SOME (Var 0)) e :: pols)
adamc@1202 1040
adamc@1202 1041 | _ => (vals, pols)
adamc@1202 1042
adamc@1203 1043 val () = reset ()
adamc@1202 1044
adamc@1202 1045 val (vals, pols) = foldl decl ([], []) file
adamc@1200 1046 in
adamc@1207 1047 app (fn (loc, e, p) =>
adamc@1207 1048 let
adamc@1207 1049 val p = And (p, Reln (Eq, [Var 0, e]))
adamc@1207 1050 in
adamc@1208 1051 if List.exists (fn pol => if imply (p, pol) then
adamc@1208 1052 (if !debug then
adamc@1208 1053 Print.prefaces "Match"
adamc@1208 1054 [("Hyp", p_prop p),
adamc@1208 1055 ("Goal", p_prop pol)]
adamc@1208 1056 else
adamc@1208 1057 ();
adamc@1208 1058 true)
adamc@1208 1059 else
adamc@1208 1060 false) pols then
adamc@1207 1061 ()
adamc@1207 1062 else
adamc@1207 1063 (ErrorMsg.errorAt loc "The information flow policy may be violated here.";
adamc@1207 1064 Print.preface ("The state satisifes this predicate:", p_prop p))
adamc@1207 1065 end) vals
adamc@1200 1066 end
adamc@1200 1067
adamc@1200 1068 end