[/] [trunk/] [src/] [maketest/] [clockexpression.sml] - Blame information for rev 35

Line No. Rev Author Line
1 4 tbourke
(* $Id: clockexpression.sml 35 2008-04-01 02:55:38Z tbourke $ *)
2
 
3
structure ClockExpression :> CLOCK_EXPRESSION =
4
let structure E = Expression
5
          and Env = Environment
6
          and ECVT = ExpressionCvt
7
in struct
8
 
9
  exception NonClockTerm
10
 
11
  type symbol    = Atom.atom
12
   and symbolset = AtomSet.set
13
   and var       = Expression.var
14
 
15
  datatype clockrel = Lt | Leq | Eq | Geq | Gt
16
 
17
  datatype clockval = Simple of int
18
                    | Complex of E.expr
19
 
20
  datatype clockterm = NonClock of E.expr
21
                     | CRel of E.var * clockrel * clockval
22
                     | CDiff of E.var * var * clockrel * clockval
23
 
24
  datatype t = Term of clockterm
25
             | And of t * t
26
             | Or  of t * t
27
 
28 31 tbourke
  val trueExpr = Term (NonClock E.trueExpr)
29
  val falseExpr = Term (NonClock E.falseExpr)
30
 
31 4 tbourke
  (* shortcuts over Atom and AtomSet *)
32 18 tbourke
  infix <+ <- ++ <\ \ =:= ; open Symbol
33 4 tbourke
 
34
  local (*{{{1*)
35
    (* TODO: fix smlnj-lib and replace with:
36
             fun pad n = Iterate.iterate (fn s=> "    " ^ s) n ""*)
37
    fun pad n = let fun iter (s, 0) = s
38
                      | iter (s, n) = iter (s ^ "    ", n - 1)
39
                in iter ("", n) end
40
 
41
    fun clkRelToStr Lt  = " < " | clkRelToStr Leq = " <= "
42
      | clkRelToStr Eq  = " = " | clkRelToStr Geq = " >= "
43
      | clkRelToStr Gt  = " > "
44
 
45
    fun clkValToStr (Simple i)  = Int.toString i
46
      | clkValToStr (Complex e) = "#" ^ ECVT.Expr.toString e ^ "#"
47
 
48
    fun clkTermToStr (NonClock e)             = "#" ^ ECVT.Expr.toString e ^ "#"
49
      | clkTermToStr (CRel (s, rel, v))       = ECVT.Var.toString s ^
50
                                                clkRelToStr rel ^
51
                                                clkValToStr v
52
      | clkTermToStr (CDiff (s1, s2, rel, v)) = ECVT.Var.toString s1 ^
53
                                                " - " ^
54
                                                ECVT.Var.toString s2 ^
55
                                                clkRelToStr rel ^
56
                                                clkValToStr v
57
  in (*}}}1*)
58
  fun clkToStr (n, Term t)       = pad n ^ clkTermToStr t
59
    | clkToStr (n, And (c1, c2)) = clkEToStr (n, "&&", c1, c2)
60
    | clkToStr (n, Or (c1, c2))  = clkEToStr (n, "||", c1, c2)
61
 
62
  and clkEToStr (n, s, c1, c2) = clkToStr (n + 1, c1)
63
                               ^ "\n" ^ pad n ^ s ^ "\n"
64
                               ^ clkToStr (n + 1, c2)
65
  fun toString t = clkToStr (0, t)
66
  end (* local *)
67
 
68
  local (*{{{1*)
69
    fun negRel Lt  = Geq
70
      | negRel Leq = Gt
71
      | negRel Geq = Lt
72
      | negRel Gt  = Leq
73
      | negRel Eq  = raise Fail "ClockExpression.negRel: Cannot negate Eq"
74
 
75
    fun negT (NonClock e) = Term (NonClock (E.negate e))
76
 
77
      | negT (CRel (c, Eq, e))       = Or (Term (CRel (c, Lt, e)),
78
                                           Term (CRel (c, Gt, e)))
79
      | negT (CDiff (c1, c2, Eq, e)) = Or (Term (CDiff (c1, c2, Lt, e)),
80
                                           Term (CDiff (c1, c2, Gt, e)))
81
 
82
      | negT (CRel (c, rel, e))       = Term (CRel (c, negRel rel, e))
83
      | negT (CDiff (c1, c2, rel, e)) = Term (CDiff (c1, c2, negRel rel, e))
84
  in (*}}}1*)
85
    fun negate (Term t)       = negT t
86
      | negate (And (e1, e2)) = Or  (negate e1, negate e2)
87
      | negate (Or  (e1, e2)) = And (negate e1, negate e2)
88
  end
89
 
90
  fun getValFree (Simple _)  = emptyset
91
    | getValFree (Complex e) = E.getFreeNames e
92
 
93
  val getVarFree = E.getFreeNames o E.VarExpr
94
 
95 19 tbourke
  fun getTermFree (NonClock e)            = E.getFreeNames e
96
    | getTermFree (CRel (s, _, cv))       = getVarFree s ++ getValFree cv
97
    | getTermFree (CDiff (s1, s2, _, cv)) = getVarFree s1 ++ getVarFree s2
98
                                                          ++ getValFree cv
99
 
100 4 tbourke
  fun getFree (And (c1, c2))                 = getFree c1 ++ getFree c2
101
    | getFree (Or (c1, c2))                  = getFree c1 ++ getFree c2
102 19 tbourke
    | getFree (Term t)                       = getTermFree t
103 4 tbourke
 
104
  local (*{{{1*)
105
    fun isClk (env, v) = case Env.findVarExprType env v
106
                         of SOME (E.CLOCK) => true
107
                          | NONE           => raise NonClockTerm
108
                          | _              => false
109
 
110
    fun isClkVar (env, E.VarExpr v) = isClk (env, v)
111
      | isClkVar _                  = false
112
 
113 29 tbourke
    fun containsClocks (env, expr) =
114 26 tbourke
        not (List.null (Env.filter (fn (env',e)=>isClkVar (env', e)) env expr))
115 4 tbourke
 
116
    fun notClk (env, e) = if containsClocks (env, e)
117
                          then raise NonClockTerm
118
                          else Term (NonClock e)
119
 
120
    fun toRel E.LtOp = Lt  | toRel E.LeOp = Leq
121
      | toRel E.EqOp = Eq  | toRel E.NeOp = raise NonClockTerm
122
      | toRel E.GeOp = Geq | toRel E.GtOp = Gt
123
 
124
    fun flipRel Lt  = Gt | flipRel Leq = Geq
125
      | flipRel Eq  = Eq | flipRel Geq = Leq
126
      | flipRel Gt  = Lt
127
 
128
    val toFlipRel = flipRel o toRel
129
 
130
    fun toVal (E.IntCExpr i) = Simple i
131
      | toVal e              = Complex e
132
 
133
    fun toVar (E.VarExpr v) = v
134
      | toVar _             = raise Fail "toVar: bad call"
135
 
136
  in (*}}}1*)
137
 
138 35 tbourke
  fun rename (r, clockexpr) = let
139
      fun rCVar v = let val E.VarExpr v' = E.renameVar (r, E.VarExpr v)
140
                    in v' end
141
 
142
      fun rCVal (s as Simple _) = s
143
        | rCVal (Complex e)     = Complex (E.renameVar (r, e))
144
 
145
      fun rCTerm (NonClock e)              = NonClock (E.renameVar (r, e))
146
        | rCTerm (CRel (s, rel, cv))       = CRel (rCVar s, rel, rCVal cv)
147
        | rCTerm (CDiff (s1, s2, rel, cv)) = CDiff (rCVar s1, rCVar s2,
148
                                                    rel, rCVal cv)
149
 
150
      fun ren (Term t)       = Term (rCTerm t)
151
        | ren (And (c1, c2)) = And  (ren c1, ren c2)
152
        | ren (Or  (c1, c2)) = Or   (ren c1, ren c2)
153
 
154
    in ren clockexpr end
155
 
156
  local
157
    fun addNameTypes xs = let
158
        fun add ((n, _), s) = s <+ n
159
      in foldl add emptyset xs end
160
  in
161
  fun ensureNoBindingConflict (rb, re) (b, e) = let
162
      val rbn = addNameTypes rb
163
      val bn  = addNameTypes b
164
 
165
      fun checkName ((n, ty), (bs, e, used)) =
166
          if n <- rbn
167
          then let val n' = getNewName (n, used)
168
               in ((n', ty)::bs,
169
                   rename ({old=n, new=n'}, e),
170
                   used <+ n')
171
               end
172
          else ((n, ty)::bs, e, used)
173
 
174
      val (b', e', _) = foldl checkName ([], e, rbn ++ bn) (rev b)
175
    in (b', e') end
176
  end (* local *)
177
 
178 4 tbourke
  (* raises NonClockTerm *)
179
  fun fromExpr (usednames, env, expr) = let
180
 
181
    val used = ref usednames
182
    val forallbindings = ref ([] : (symbol * E.ty) list)
183
 
184
    fun addForAllBinding (s, ty) = let
185
        val newName = getNewName (s, !used)
186
      in
187
        used := (!used <+ newName);
188
        forallbindings := (newName, ty) :: !forallbindings;
189
        newName
190
      end
191
 
192
    fun conv (env, e as E.BinBoolExpr {left, bop, right, ...}) = let
193
      (*{{{1*)
194
          val (l, r) = (conv (env, left), conv (env, right))
195
        in case (l, r, bop)
196
            of (Term (NonClock le), Term (NonClock re), _)=> Term (NonClock e)
197
             | (Term (NonClock le), _, E.ImplyOp)         => Or (negate l, r)
198
             | (_, _, E.ImplyOp)                          => raise NonClockTerm
199
             | (_, _, E.OrOp)                             => Or (l, r)
200
             | (_, _, E.AndOp)                            => And (l, r)
201
        end
202
 
203
      (* possibly: c1 - c2 {<,<=,==,>=,>} e *)
204
      | conv (env, e as E.RelExpr {left=E.BinIntExpr
205
                              {left=lclk, bop=E.MinusOp, right=rclk, ...},
206
                            rel, right, ...}) =
207
          if isClkVar (env, lclk) andalso isClkVar (env, rclk)
208
          then Term (CDiff (toVar lclk, toVar rclk, toRel rel, toVal right))
209
          else notClk (env, e)
210
 
211
      | conv (env, e as E.RelExpr {right=E.BinIntExpr
212
                              {left=lclk, bop=E.MinusOp, right=rclk, ...},
213
                            rel, left, ...})  =
214
          if isClkVar (env, lclk) andalso isClkVar (env, rclk)
215
          then Term (CDiff (toVar lclk, toVar rclk, toFlipRel rel, toVal left))
216
          else notClk (env, e)
217
 
218
      (* possibly: c {<,<=,==,>=,>} e *)
219
      | conv (env, e as E.RelExpr {left, rel, right, ...}) = let in
220
            case (isClkVar (env, left), isClkVar (env, right))
221
            of (true, true)   => raise NonClockTerm
222
             | (false, false) => Term (NonClock e)
223
             | (true, false)  => Term (CRel (toVar left,toRel rel,toVal right))
224
             | (false, true)  => Term (CRel (toVar right, toFlipRel rel,
225
                                             toVal left))
226
            end
227
 
228
      | conv (env, e as E.VarExpr v)    = if isClk (env, v) then raise NonClockTerm
229
                                                            else Term (NonClock e)
230
 
231
      (* Guard must be side-effect free *)
232
      | conv (env, E.UnaryModExpr _)    = raise NonClockTerm
233
      | conv (env, E.Deadlock _)        = raise NonClockTerm
234
 
235
      | conv (env, e as E.IntCExpr _)           = Term (NonClock e)
236
      | conv (env, e as E.BoolCExpr _)          = Term (NonClock e)
237
      | conv (env, e as E.AssignExpr _)         = notClk (env, e)
238
      | conv (env, e as E.NegExpr _)            = notClk (env, e)
239
      | conv (env, e as E.NotExpr _)            = notClk (env, e)
240
      | conv (env, e as E.BinIntExpr _)         = notClk (env, e)
241
      | conv (env, e as E.CallExpr {args, ...}) = notClk (env, e)
242
 
243
      (* tested in Uppaal 4.0.2: (i==1)?(x>2):(x>3)  //int i, clock x;
244
         gives: incompatible arguments to inline if *)
245
      | conv (env, e as E.CondExpr _)           = notClk (env, e)
246
      | conv (env, e as E.ForAllExpr {id,ty,expr,...}) = let
247
            val env' = Env.addId Env.BoundScope ((id, ty), env)
248
          in
249
            if containsClocks (env', expr)
250
            then let (* lift forall to top-level, i.e. make prenex
251
                        the usual proviso on names must be respected *)
252
                   val id' = addForAllBinding (id, ty)
253
                 in
254
                   conv (Env.addId Env.BoundScope ((id', ty), env),
255
                         E.renameVar ({old=id, new=id'}, expr))
256
                 end
257
            else Term (NonClock e)
258
          end
259
      | conv (env, e as E.ExistsExpr _)         = notClk (env, e)
260
    (*}}}1*)
261 26 tbourke
 
262 4 tbourke
  in (conv (env, expr), !forallbindings, !used) end
263
  end (* local *)
264
 
265
  local
266
    (*{{{1*)
267
    fun fromCRel Lt  = E.LtOp  | fromCRel Leq = E.LeOp
268
      | fromCRel Geq = E.GeOp  | fromCRel Gt  = E.GtOp
269
      | fromCRel Eq  = E.EqOp
270
 
271
    fun fromCVal (Simple i) = E.IntCExpr i
272
      | fromCVal (Complex e) = e
273
 
274
    fun fromClkT (NonClock e) = e
275
      | fromClkT (CRel (v, rel, cv)) = E.RelExpr {left=E.VarExpr v,
276
                                                  rel=fromCRel rel,
277
                                                  right=fromCVal cv,
278
                                                  pos=E.nopos}
279
      | fromClkT (CDiff (v1, v2, rel, cv)) = let
280
            val d = E.BinIntExpr {left=E.VarExpr v1,
281
                                  bop=E.MinusOp,
282
                                  right=E.VarExpr v2,
283
                                  pos=E.nopos}
284
          in
285
            E.RelExpr {left=d, rel=fromCRel rel,
286
                       right=fromCVal cv, pos=E.nopos}
287
          end
288
    (*}}}1*)
289
  in
290
  fun toExpr (t, fas) = let
291
      fun toE (Term ct)        = fromClkT ct
292
        | toE (And (ce1, ce2)) = E.BinBoolExpr {left=toE ce1, bop=E.AndOp,
293
                                                right=toE ce2, pos=E.nopos}
294
        | toE (Or (ce1, ce2))  = E.BinBoolExpr {left=toE ce1, bop=E.OrOp,
295
                                                right=toE ce2, pos=E.nopos}
296
      fun wrapForall ((s, ty), e)=E.ForAllExpr {id=s,ty=ty,expr=e,pos=E.nopos}
297
 
298
    in foldl wrapForall (toE t) fas end
299
  end (* local *)
300
 
301 19 tbourke
  (* see tech. report: canswap predicate *)
302
  fun conflictExists (sE, sA, psi) = let
303
      exception ConflictingQuantifiers
304 4 tbourke
 
305 19 tbourke
      fun termToPairs ct = let
306
          val f = getTermFree ct
307
          val e = AtomSet.intersection (f, sE)
308
          val a = AtomSet.intersection (f, sA)
309
        in
310
          if not (AtomSet.isEmpty e) andalso not (AtomSet.isEmpty a)
311
          then raise ConflictingQuantifiers else (e, a)
312
        end
313 4 tbourke
 
314 19 tbourke
      fun pairUnion ((e1,a1), (e2,a2)) = (e1 ++ e2, a1 ++ a2)
315
      val emptyPair = (emptyset, emptyset)
316 4 tbourke
 
317 19 tbourke
      fun findCommon ((e,a), (se,sa)) = let
318
          val ei = if AtomSet.isEmpty a then se ++ e else se
319
          val ai = if AtomSet.isEmpty e then sa ++ a else sa
320
        in (ei, ai) end
321 4 tbourke
 
322 19 tbourke
      val termPairs = map (fn cl=>map termToPairs cl) psi
323
        (* [ [(E,A), ..., (E,A)], ..., [(E,A), ..., (E,A)] ] *)
324
      val clausePairs = map (fn cl=>foldl pairUnion emptyPair cl) termPairs
325
        (* [ (E,A), ..., (E,A) ] *)
326
 
327
      val (sEf, sAf) = foldl findCommon emptyPair clausePairs
328
 
329
      fun conflict ([], _) = false
330
        | conflict ((e, a)::xs, (confE, confA)) =
331
            if (AtomSet.isSubset (e, sEf) andalso AtomSet.isEmpty (a))
332
               orelse (AtomSet.isSubset (a, sAf) andalso AtomSet.isEmpty (e))
333
            then conflict (xs, (confE, confA))
334
            else if not (AtomSet.isEmpty (AtomSet.intersection (e, confE)))
335
                 orelse not (AtomSet.isEmpty (AtomSet.intersection (a, confA)))
336
                 then true else conflict (xs, (confE ++ e, confA ++ a))
337
 
338
    in conflict (clausePairs, (sEf, sAf)) end
339
       handle ConflictingQuantifiers => true
340
 
341 4 tbourke
  local (*{{{1*)
342
    datatype termchoice =
343
            KeepLeft   (* M |- (l && r)  <=>  M |- l *)
344
          | KeepRight  (* M |- (l && r)  <=>  M |- r *)
345
          | MergeEqual (* M |- (le >= c && re <= c)  <=>  M |- (le = c) *)
346
          | Contra     (* M |- (l && r)  <==>  M |- false *)
347
          | KeepBoth   (* none of the above *)
348
 
349
    (* Guards are integer-valued, but the clocks themselves are real-valued. *)
350
    fun chooseFromSimpleRel ((Lt, i), r) = (case r
351
                      of (Lt , j) => if i <= j then KeepLeft   else KeepRight
352
                       | (Leq, j) => if i <= j then KeepLeft   else KeepRight
353
                       | (Eq , j) => if i > j  then KeepRight  else Contra
354
                       | (Geq, j) => if i > j  then KeepBoth   else Contra
355
                       | (Gt , j) => if i > j  then KeepBoth   else Contra
356
                      )
357
      | chooseFromSimpleRel ((Leq, i), r) = (case r                 (*{{{2*)
358
                      of (Lt , j) => if i < j  then KeepLeft   else KeepRight
359
                       | (Leq, j) => if i < j  then KeepLeft   else KeepRight
360
                       | (Eq , j) => if i >= j then KeepRight  else Contra
361
                       | (Geq, j) => if i = j  then MergeEqual else
362
                                     if i > j  then KeepBoth   else Contra
363
                       | (Gt , j) => if i > j  then KeepBoth   else Contra
364
                      )
365
      | chooseFromSimpleRel ((Eq , i), r) = (case r
366
                      of (Lt , j) => if i < j  then KeepLeft   else Contra
367
                       | (Leq, j) => if i <= j then KeepLeft   else Contra
368
                       | (Eq , j) => if i = j  then KeepLeft   else Contra
369
                       | (Geq, j) => if i >= j then KeepLeft   else Contra
370
                       | (Gt , j) => if i > j  then KeepLeft   else Contra
371
                      )
372
      | chooseFromSimpleRel ((Geq, i), r) = (case r
373
                      of (Lt , j) => if i < j  then KeepBoth   else Contra
374
                       | (Leq, j) => if i = j  then MergeEqual else
375
                                     if i < j  then KeepBoth   else Contra
376
                       | (Eq , j) => if i <= j then KeepRight  else Contra
377
                       | (Geq, j) => if i > j  then KeepLeft   else KeepRight
378
                       | (Gt , j) => if i > j  then KeepLeft   else KeepRight
379
                      )
380
      | chooseFromSimpleRel ((Gt , i), r) = (case r
381
                      of (Lt , j) => if i < j  then KeepBoth   else Contra
382
                       | (Leq, j) => if i < j  then KeepBoth   else Contra
383
                       | (Eq , j) => if i < j  then KeepRight  else Contra
384
                       | (Geq, j) => if i >= j then KeepLeft   else KeepRight
385
                       | (Gt , j) => if i >= j then KeepLeft   else KeepRight
386
        (*}}}2*)      )
387
 
388
    (* Handle ((el1 ~1 er1) && (el2 ~2 er2)) with el1=er1, er1=er2: *)
389
    fun chooseFromComplexRel (Lt , r) = (case r of Lt  => KeepLeft
390
                                                 | Leq => KeepLeft
391
                                                 | _   => Contra)
392
      | chooseFromComplexRel (Leq, r) = (case r of Geq => MergeEqual (*{{{2*)
393
                                                 | Gt  => Contra
394
                                                 | _   => KeepRight)
395
      | chooseFromComplexRel (Eq , r) = (case r of Lt  => Contra
396
                                                 | Gt  => Contra
397
                                                 | _   => KeepLeft)
398
      | chooseFromComplexRel (Geq, r) = (case r of Leq => MergeEqual
399
                                                 | Lt  => Contra
400
                                                 | _   => KeepRight)
401
      | chooseFromComplexRel (Gt , r) = (case r of Gt  => KeepLeft
402
                                                 | Geq => KeepLeft
403
      (*}}}2*)                                   | _   => Contra)
404
 
405
    fun chooseTerm (CRel (c1, rel1, Simple i1),
406
                    CRel (c2, rel2, Simple i2))
407
                   = if E.varequal (c1, c2)
408
                     then chooseFromSimpleRel ((rel1, i1), (rel2, i2))
409
                     else KeepBoth
410
        (*{{{2*)
411
      | chooseTerm (CRel (c1, rel1, Complex e1),
412
                    CRel (c2, rel2, Complex e2))
413
                   = if E.varequal (c1, c2) andalso E.equal (e1, e2)
414
                     then chooseFromComplexRel (rel1, rel2)
415
                     else KeepBoth
416
 
417
      | chooseTerm (CDiff (cl1, cr1, rel1, Simple i1),
418
                    CDiff (cl2, cr2, rel2, Simple i2))
419
                   = if E.varequal (cl1, cl2) andalso E.varequal (cr1, cr2)
420
                     then chooseFromSimpleRel ((rel1, i1), (rel2, i2))
421
                     else KeepBoth
422
 
423
      | chooseTerm (CDiff (cl1, cr1, rel1, Complex e1),
424
                    CDiff (cl2, cr2, rel2, Complex e2))
425
                   = if E.varequal (cl1, cl2) andalso E.varequal (cr1, cr2)
426
                        andalso E.equal (e1, e2)
427
                     then chooseFromComplexRel (rel1, rel2) else KeepBoth
428
 
429
      | chooseTerm (NonClock(E.BoolCExpr b),_)= if b then KeepRight else Contra
430
      | chooseTerm (_,NonClock(E.BoolCExpr b)) = if b then KeepLeft else Contra
431
 
432
      | chooseTerm (NonClock e1, NonClock e2)
433
                   = if E.isNegation (e1, e2) then Contra else KeepBoth
434
 
435
      | chooseTerm _ = KeepBoth
436
      (*}}}2*)
437
 
438
    exception Contradiction
439
 
440
    fun termAndConj (t, cs) = let
441
        fun mergeEqual (CRel (c, _, v))       = CRel (c, Eq, v)
442
          | mergeEqual (CDiff (c1, c2, _, v)) = CDiff (c1, c2, Eq, v)
443
 
444
        fun tandc (rs, t, [])    = t::rs
445
          | tandc (rs, t, x::xs) = case chooseTerm (t, x)
446
                of KeepLeft   => tandc (rs, t, xs)
447
                 | KeepRight  => List.revAppend (rs, x::xs)
448
                 | MergeEqual => List.revAppend (rs, mergeEqual t::xs)
449
                 | Contra     => raise Contradiction
450
                 | KeepBoth   => tandc (x::rs, t, xs)
451
      in tandc ([], t, cs) end
452
 
453
    fun conjAndConj and1 and2 = SOME (foldl termAndConj and2 and1)
454
                                  handle Contradiction => NONE
455
 
456
    fun andDNFLists (or1, or2) = let
457
        fun throughSecond andx = let
458
            val r = List.mapPartial (conjAndConj andx) or2
459
          in if null r then NONE else SOME r end
460
      in
461
        List.concat (List.mapPartial throughSecond or1)
462
      end
463
    (*}}}1*)
464
  in
465
    fun toDNF (Term ct)      = [[ct]]
466
      | toDNF (Or (e1, e2))  = toDNF e1 @ toDNF e2
467
      | toDNF (And (e1, e2)) = andDNFLists (toDNF e1, toDNF e2)
468
  end (* local *)
469
 
470
  fun fromDNF xxs = let
471
      fun combineAnd (t, e) = And (e, Term t)
472
      fun makeAnd []        = NONE
473
        | makeAnd (x::xs)   = SOME (foldl combineAnd (Term x) xs)
474
 
475
      fun combineOr (e1, e2) = Or (e2, e1)
476
      fun makeOr []      = Term (NonClock (E.falseExpr))
477
        | makeOr (x::xs) = foldl combineOr x xs
478
 
479
      fun trueExpr (Term (NonClock t)) = E.equal (t, E.trueExpr)
480
        | trueExpr _                   = false
481
 
482
      val andclauses = List.mapPartial makeAnd xxs
483
 
484
    in if List.exists trueExpr andclauses
485
       then Term (NonClock (E.trueExpr))
486
       else makeOr andclauses
487
    end
488
 
489
  fun andexpr (e1, e2) = fromDNF (toDNF (And (e1, e2)))
490
    (* exploit the simplification built into toDNF *)
491
 
492
end
493
end
494