| 1 |
4 |
tbourke |
(* $Id: ntautil.sml 19 2007-11-27 00:20:37Z tbourke $ *)
|
| 2 |
|
|
|
| 3 |
|
|
(* TODO:
|
| 4 |
|
|
* Make error handling more descriptive:
|
| 5 |
|
|
-catch the exception
|
| 6 |
|
|
-name the template and state
|
| 7 |
|
|
-show the bad transitions.
|
| 8 |
|
|
* Tidy this whole file up. Try to effect more structure and reuse.
|
| 9 |
|
|
Shift generic functions into xml/nta parse/parsed-nta.
|
| 10 |
|
|
|
| 11 |
|
|
*)
|
| 12 |
|
|
|
| 13 |
|
|
local structure P = ParsedNta
|
| 14 |
|
|
and E = UppaalParse.Expression
|
| 15 |
|
|
and ECvt = UppaalParse.ExpressionCvt
|
| 16 |
|
|
and Env = UppaalParse.Environment
|
| 17 |
|
|
in
|
| 18 |
|
|
|
| 19 |
|
|
structure NtaUtil : NTA_UTIL
|
| 20 |
|
|
=
|
| 21 |
|
|
struct
|
| 22 |
|
|
(* shortcuts over Atom and AtomSet *)
|
| 23 |
18 |
tbourke |
infix <+ <- ++ <\ \ =:= ; open Symbol
|
| 24 |
4 |
tbourke |
|
| 25 |
|
|
exception InvalidId of int
|
| 26 |
|
|
exception CannotSplitChannelArrays
|
| 27 |
|
|
|
| 28 |
17 |
tbourke |
fun actions (P.Template {transitions, ...}) = let
|
| 29 |
4 |
tbourke |
fun insert ((nm, dir), []) = [(nm, dir)]
|
| 30 |
|
|
| insert ((nm, dir), (x as (nm', dir'))::xs) =
|
| 31 |
|
|
if nm=:=nm' andalso dir=dir' then x::xs else x::insert ((nm, dir), xs)
|
| 32 |
|
|
|
| 33 |
17 |
tbourke |
fun addAct (P.Transition {sync=(NONE, _), ...}, l) = l
|
| 34 |
|
|
| addAct (P.Transition {sync=(SOME (nm, dir, _), _), ...}, l)
|
| 35 |
4 |
tbourke |
= insert ((nm, dir), l)
|
| 36 |
17 |
tbourke |
in foldl addAct [] transitions end
|
| 37 |
4 |
tbourke |
|
| 38 |
17 |
tbourke |
fun channelSet (P.Template {transitions, ...}) = let
|
| 39 |
|
|
fun addSync (P.Transition {sync=(NONE, _), ...} , s) = s
|
| 40 |
|
|
| addSync (P.Transition {sync=(SOME (c, _, _), _), ...}, s) = s <+ c
|
| 41 |
|
|
in foldl addSync AtomSet.empty transitions end
|
| 42 |
|
|
|
| 43 |
|
|
fun channels t = AtomSet.listItems (channelSet t)
|
| 44 |
|
|
|
| 45 |
4 |
tbourke |
fun warnIfCommitted t =
|
| 46 |
|
|
if List.exists P.Location.isCommitted (P.Template.selLocations t)
|
| 47 |
|
|
then Util.warn [P.Template.selName t,
|
| 48 |
|
|
" contains a committed location (not supported)."] else ()
|
| 49 |
|
|
|
| 50 |
|
|
fun warnOnChannels (t as P.Template {declaration=env,...}) = let
|
| 51 |
17 |
tbourke |
fun checkChannel nm = let
|
| 52 |
4 |
tbourke |
val pre = Atom.toString nm
|
| 53 |
|
|
in case Env.findVal env nm of
|
| 54 |
|
|
NONE => SOME [pre, " not in scope."]
|
| 55 |
|
|
| SOME (Env.VarEntry{ty,ref=r,...}) => (case #1 (E.stripArray ty) of
|
| 56 |
|
|
E.CHANNEL {broadcast,...} =>
|
| 57 |
|
|
if broadcast
|
| 58 |
|
|
then SOME [pre,"is broadcast (not supported)"]
|
| 59 |
|
|
else if r
|
| 60 |
|
|
then SOME [pre,"is passed by reference (not supported)"]
|
| 61 |
|
|
else NONE
|
| 62 |
|
|
| _ => NONE)
|
| 63 |
|
|
|
| 64 |
|
|
| _ => SOME [pre, " not a channel."]
|
| 65 |
|
|
end
|
| 66 |
17 |
tbourke |
in List.app Util.warn (List.mapPartial checkChannel (channels t)) end
|
| 67 |
4 |
tbourke |
|
| 68 |
|
|
local
|
| 69 |
|
|
structure PLoc = P.Location
|
| 70 |
|
|
and PTra = P.Transition
|
| 71 |
|
|
and PTem = P.Template
|
| 72 |
|
|
in
|
| 73 |
|
|
fun split (tplate as P.Template {transitions, locations, ...}, actmap) = let
|
| 74 |
|
|
fun addT (tp, ts) = PTem.addTransitions tp ts
|
| 75 |
|
|
|
| 76 |
|
|
fun findLoc l = List.find (fn (P.Location {id,...})=>id = l) locations
|
| 77 |
|
|
|
| 78 |
|
|
fun midPoint ((sx, sy), (tx, ty)) = ((sx + tx) div 2, (sy + ty) div 2)
|
| 79 |
|
|
|
| 80 |
|
|
fun findPos ((src, dst), []) = let
|
| 81 |
|
|
val sposo = Option.mapPartial PLoc.selPos (findLoc src)
|
| 82 |
|
|
val dposo = Option.mapPartial PLoc.selPos (findLoc dst)
|
| 83 |
|
|
in case (sposo, dposo) of
|
| 84 |
|
|
(SOME spos, SOME dpos) => (SOME (midPoint (spos,dpos)),[],[])
|
| 85 |
|
|
| _ => (NONE,[],[])
|
| 86 |
|
|
end
|
| 87 |
|
|
|
| 88 |
|
|
| findPos ((src, dst), nails) = let
|
| 89 |
|
|
val l = length nails
|
| 90 |
|
|
val m = (l + 1) div 2
|
| 91 |
|
|
in
|
| 92 |
|
|
if l mod 2 = 1
|
| 93 |
|
|
then (SOME (List.nth (nails, m-1)), List.take (nails, m-1),
|
| 94 |
|
|
List.drop (nails, m))
|
| 95 |
|
|
else (SOME (midPoint (List.nth (nails, m-1), List.nth (nails, m))),
|
| 96 |
|
|
List.take (nails, m), List.drop (nails, m))
|
| 97 |
|
|
end
|
| 98 |
|
|
|
| 99 |
|
|
fun spl (tr as P.Transition {sync=(NONE, _), ...}, tp) = addT (tp, [tr])
|
| 100 |
|
|
| spl (tr as P.Transition {sync=(SOME (nm,dir,[]), _),
|
| 101 |
|
|
source, target, nails, ...}, tp) = let in
|
| 102 |
|
|
case ActionMap.find (actmap, (nm, dir)) of
|
| 103 |
|
|
NONE => addT (tp, [tr])
|
| 104 |
|
|
| SOME (nm', dir') => let
|
| 105 |
|
|
val (mpos, preNs, postNs) = findPos ((source, target), nails)
|
| 106 |
|
|
|
| 107 |
|
|
val (tp', sloc) = PLoc.new tp ""
|
| 108 |
|
|
val slocId = PLoc.selId sloc
|
| 109 |
|
|
val tp' = PTem.updLocation tp'
|
| 110 |
|
|
(PLoc.updPos (PLoc.mkCommitted sloc) mpos)
|
| 111 |
|
|
|
| 112 |
|
|
val fromSloc = PTra.updSync
|
| 113 |
|
|
(PTra.new (slocId, target))
|
| 114 |
|
|
(SOME (nm', dir', []))
|
| 115 |
|
|
val fromSloc = PTra.updNails fromSloc postNs
|
| 116 |
|
|
in
|
| 117 |
|
|
addT (tp', [PTra.updNails
|
| 118 |
|
|
(PTra.updEndPoints tr (source,slocId)) preNs,
|
| 119 |
|
|
fromSloc])
|
| 120 |
|
|
end
|
| 121 |
|
|
end
|
| 122 |
|
|
| spl _ = raise CannotSplitChannelArrays
|
| 123 |
|
|
|
| 124 |
|
|
in foldl spl (PTem.updTransitions tplate []) transitions end
|
| 125 |
|
|
end (* local *)
|
| 126 |
|
|
|
| 127 |
|
|
local
|
| 128 |
|
|
structure IMap = IntBinaryMap
|
| 129 |
|
|
|
| 130 |
|
|
fun remap m i = case IMap.find (m, i) of
|
| 131 |
|
|
NONE => raise InvalidId i
|
| 132 |
|
|
| SOME ni => P.LocId ni
|
| 133 |
|
|
fun stripLocId (P.LocId i) = i
|
| 134 |
|
|
in
|
| 135 |
|
|
fun shiftTemplateIds (P.Template {name as (n,_), parameter, declaration,
|
| 136 |
|
|
initial, locations, transitions}, start) =
|
| 137 |
|
|
let
|
| 138 |
|
|
fun uLoc (P.Location {id=P.LocId i, position, color, name, invariant,
|
| 139 |
|
|
comments, urgent, committed}, (done, m, ni)) =
|
| 140 |
|
|
let
|
| 141 |
|
|
val nloc = P.Location {id=P.LocId ni, position=position,
|
| 142 |
|
|
color=color, name=name, invariant=invariant,
|
| 143 |
|
|
comments=comments, urgent=urgent,
|
| 144 |
|
|
committed=committed}
|
| 145 |
|
|
in (nloc::done, IMap.insert (m, i, ni), ni + 1) end
|
| 146 |
|
|
|
| 147 |
|
|
fun uTrans m (P.Transition {id, source=P.LocId si, target=P.LocId ti,
|
| 148 |
|
|
select, guard, sync, update, comments,
|
| 149 |
|
|
position, color, nails}, (done, ni)) =
|
| 150 |
|
|
let
|
| 151 |
|
|
val (nid, ni) = case id
|
| 152 |
|
|
of NONE => (NONE, ni)
|
| 153 |
|
|
| SOME (P.TransId i) => (SOME (P.TransId ni), ni + 1)
|
| 154 |
|
|
val ntr = P.Transition {id=nid,
|
| 155 |
|
|
source=remap m si,
|
| 156 |
|
|
target=remap m ti,
|
| 157 |
|
|
select=select, guard=guard,
|
| 158 |
|
|
sync=sync, update=update,
|
| 159 |
|
|
comments=comments, position=position,
|
| 160 |
|
|
color=color, nails=nails}
|
| 161 |
|
|
in (ntr::done, ni) end
|
| 162 |
|
|
|
| 163 |
|
|
val (nlocs, map, start') = foldl uLoc ([], IMap.empty, start) locations
|
| 164 |
|
|
|
| 165 |
|
|
val _ = Util.debugVeryDetailed (fn()=>let
|
| 166 |
|
|
fun s (f, t) = Int.toString f^"->"^
|
| 167 |
|
|
Int.toString t^" "
|
| 168 |
|
|
in "shiftTemplateIds (":: n:: ") "::
|
| 169 |
|
|
(List.map s (IMap.listItemsi map))
|
| 170 |
|
|
end)
|
| 171 |
|
|
|
| 172 |
|
|
val (ntrs, final) = foldl (uTrans map) ([], start') transitions
|
| 173 |
|
|
in
|
| 174 |
|
|
(P.Template {name=name, parameter=parameter,declaration=declaration,
|
| 175 |
|
|
initial=Option.map (remap map o stripLocId) initial,
|
| 176 |
|
|
locations=rev nlocs, transitions=rev ntrs}, final)
|
| 177 |
|
|
end
|
| 178 |
|
|
end
|
| 179 |
|
|
|
| 180 |
|
|
fun setTransId nid (tr as P.Transition {id, source, target, select, guard,
|
| 181 |
|
|
sync, update, comments, position, color, nails})
|
| 182 |
|
|
= let
|
| 183 |
|
|
val nochange = case (nid, id) of
|
| 184 |
|
|
(NONE, NONE) => true
|
| 185 |
|
|
| (SOME ni, SOME i) => (ni = i)
|
| 186 |
|
|
| _ => false
|
| 187 |
|
|
in
|
| 188 |
|
|
if nochange then tr
|
| 189 |
|
|
else (P.Transition {id=nid, source=source,
|
| 190 |
|
|
target=target, select=select,
|
| 191 |
|
|
guard=guard, sync=sync, update=update,
|
| 192 |
|
|
color=color, comments=comments,
|
| 193 |
|
|
position=position, nails=nails})
|
| 194 |
|
|
end
|
| 195 |
|
|
|
| 196 |
19 |
tbourke |
fun locsWithoutPositions (P.Template {locations,...}) = let
|
| 197 |
|
|
val add = IntBinarySet.add
|
| 198 |
|
|
fun f (P.Location {id=P.LocId i, position=NONE, ...}, s) = add (s, i)
|
| 199 |
|
|
| f (_, s) = s
|
| 200 |
|
|
val locs = foldl f IntBinarySet.empty locations
|
| 201 |
|
|
in fn (P.LocId i) => IntBinarySet.member (locs, i) end
|
| 202 |
|
|
|
| 203 |
4 |
tbourke |
fun stripTransitionIds (P.Template {name, parameter, declaration, initial,
|
| 204 |
|
|
locations, transitions}) =
|
| 205 |
|
|
P.Template {name=name, parameter=parameter, declaration=declaration,
|
| 206 |
|
|
initial=initial, locations=locations,
|
| 207 |
|
|
transitions=map (setTransId NONE) transitions}
|
| 208 |
|
|
|
| 209 |
|
|
fun addTransitionIds p (P.Template {name, parameter, declaration, initial,
|
| 210 |
|
|
locations, transitions}) =
|
| 211 |
|
|
let
|
| 212 |
|
|
fun biggest (P.Transition {id=NONE, ...}, i) = i
|
| 213 |
|
|
| biggest (P.Transition {id=SOME (P.TransId j), ...}, i) = Int.max (i, j)
|
| 214 |
|
|
val i = ref (foldl biggest 1 transitions)
|
| 215 |
|
|
|
| 216 |
|
|
fun f trans = if p trans then (setTransId (SOME (P.TransId (!i))) trans)
|
| 217 |
|
|
before i := (!i) + 1
|
| 218 |
|
|
else trans
|
| 219 |
|
|
in
|
| 220 |
|
|
P.Template {name=name, parameter=parameter, declaration=declaration,
|
| 221 |
|
|
initial=initial, locations=locations,
|
| 222 |
|
|
transitions=map f transitions}
|
| 223 |
|
|
end
|
| 224 |
|
|
|
| 225 |
|
|
fun addTransitions (t, newtrans) = P.Template.updTransitions t
|
| 226 |
|
|
(newtrans @ P.Template.selTransitions t)
|
| 227 |
|
|
|
| 228 |
|
|
fun expandUrgentLocs (t as P.Template {name, parameter, initial,
|
| 229 |
|
|
declaration=decls,
|
| 230 |
|
|
locations, transitions}) =
|
| 231 |
|
|
let
|
| 232 |
|
|
fun addUrgentIds (P.Location {id=P.LocId i, urgent, ...}, s) =
|
| 233 |
|
|
if urgent then IntBinarySet.add (s, i) else s
|
| 234 |
|
|
val urgentLocs = foldl addUrgentIds IntBinarySet.empty locations
|
| 235 |
|
|
in
|
| 236 |
|
|
if IntBinarySet.isEmpty urgentLocs then t
|
| 237 |
|
|
else let
|
| 238 |
|
|
val uclk = Env.newId (Atom.atom "c_u", decls)
|
| 239 |
|
|
val uclkvar = E.VarExpr (E.SimpleVar (uclk, E.nopos))
|
| 240 |
|
|
val uclkcons = E.RelExpr {left=uclkvar, rel=E.LeOp,
|
| 241 |
|
|
right=E.IntCExpr 0, pos=E.nopos}
|
| 242 |
|
|
val uclkrst = E.AssignExpr {var=uclkvar, aop=E.AssignOp,
|
| 243 |
|
|
expr=E.IntCExpr 0, pos=E.nopos}
|
| 244 |
|
|
|
| 245 |
|
|
val decls' = Env.addId Env.TemplateScope ((uclk, E.CLOCK), decls)
|
| 246 |
|
|
|
| 247 |
|
|
fun fromUrgent (P.Location {id, position, color, name,
|
| 248 |
|
|
invariant=(inv, invP), comments,
|
| 249 |
|
|
urgent=true, committed}) =
|
| 250 |
|
|
P.Location {id=id, position=position, color=color, name=name,
|
| 251 |
|
|
invariant=(E.andexpr (uclkcons, inv), invP),
|
| 252 |
|
|
comments=comments, urgent=false, committed=committed}
|
| 253 |
|
|
| fromUrgent l = l
|
| 254 |
|
|
|
| 255 |
|
|
fun addReset (t as P.Transition {target=target as P.LocId dst, id,
|
| 256 |
|
|
source, select, guard, sync,
|
| 257 |
|
|
update=(upd, updP),
|
| 258 |
|
|
comments, position, color, nails}) =
|
| 259 |
|
|
if IntBinarySet.member (urgentLocs, dst)
|
| 260 |
|
|
then P.Transition {id=id, source=source, target=target,
|
| 261 |
|
|
select=select, guard=guard, sync=sync,
|
| 262 |
|
|
update=(uclkrst::upd, updP),
|
| 263 |
|
|
comments=comments, position=position,
|
| 264 |
|
|
color=color, nails=nails}
|
| 265 |
|
|
else t
|
| 266 |
|
|
|
| 267 |
|
|
in
|
| 268 |
|
|
P.Template {name=name, parameter=parameter,
|
| 269 |
|
|
declaration=decls', initial=initial,
|
| 270 |
|
|
locations=map fromUrgent locations,
|
| 271 |
|
|
transitions=map addReset transitions}
|
| 272 |
|
|
end
|
| 273 |
|
|
end
|
| 274 |
|
|
|
| 275 |
|
|
fun makeInputEnabler (actionlist, env) = let
|
| 276 |
|
|
val l = P.LocId 1
|
| 277 |
|
|
|
| 278 |
|
|
fun newTrans (c, idtys, ids, tys, dir) = P.Transition {
|
| 279 |
|
|
id=NONE, source=l, target=l, select=(idtys, NONE),
|
| 280 |
|
|
guard=(E.trueExpr, NONE), sync=(SOME (c, dir, ids), NONE),
|
| 281 |
|
|
update=([], NONE), comments=(NONE, NONE),
|
| 282 |
|
|
position=NONE, color=NONE, nails=[]}
|
| 283 |
|
|
|
| 284 |
|
|
fun selfLoop (nm, dir) = let in
|
| 285 |
|
|
case Option.map E.stripArray (Env.findValType env nm) of
|
| 286 |
|
|
SOME (E.CHANNEL _, tys) => let
|
| 287 |
|
|
val ids = List.tabulate (length tys,
|
| 288 |
|
|
fn i=>Atom.atom ("s"^Int.toString i))
|
| 289 |
|
|
val sels = ListPair.map (fn (nm,t)=>E.BoundId (nm,t,E.nopos))
|
| 290 |
|
|
(ids, tys)
|
| 291 |
|
|
val eids = map (fn i=>E.VarExpr (E.SimpleVar (i,E.nopos))) ids
|
| 292 |
|
|
in
|
| 293 |
|
|
SOME (newTrans (nm, sels, eids, tys, dir))
|
| 294 |
|
|
end
|
| 295 |
|
|
|
| 296 |
|
|
| _ => (Util.warn ["channel ",Atom.toString nm,
|
| 297 |
|
|
" is invalid (skipped)"]; NONE)
|
| 298 |
|
|
end
|
| 299 |
|
|
|
| 300 |
|
|
in
|
| 301 |
|
|
P.Template {name=("AcceptAll", NONE),
|
| 302 |
|
|
parameter=([], NONE),
|
| 303 |
|
|
initial=SOME l,
|
| 304 |
|
|
declaration=env,
|
| 305 |
|
|
locations=[P.Location {
|
| 306 |
|
|
id=l,
|
| 307 |
|
|
position=SOME (0,0),
|
| 308 |
|
|
color=NONE,
|
| 309 |
|
|
name=(NONE, NONE),
|
| 310 |
|
|
invariant=(E.trueExpr, NONE),
|
| 311 |
|
|
comments=(NONE, NONE),
|
| 312 |
|
|
urgent=false,
|
| 313 |
|
|
committed=false}],
|
| 314 |
|
|
transitions=List.mapPartial selfLoop actionlist}
|
| 315 |
|
|
end
|
| 316 |
|
|
|
| 317 |
|
|
fun namesetToLocset (names, P.Template {locations, ...}) = let
|
| 318 |
|
|
fun f (P.Location {name=(NONE, _), ...}, s) = s
|
| 319 |
|
|
| f (P.Location {id=P.LocId i, name=(SOME name, _), ...}, s) =
|
| 320 |
|
|
if (Atom.atom name) <- names then IntBinarySet.add (s, i) else s
|
| 321 |
|
|
in
|
| 322 |
|
|
foldl f IntBinarySet.empty locations
|
| 323 |
|
|
end
|
| 324 |
|
|
end
|
| 325 |
|
|
end (* local *)
|
| 326 |
|
|
|