root/trunk/CspCASL/StatAnaCSP.hs @ 11216

Revision 11216, 27.8 kB (checked in by maeder, 11 months ago)

extended symbol kinds i.e. for CspCASL

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1{- |
2Module      :  $Id$
3Description :  Static analysis of CspCASL
4Copyright   :  (c) Andy Gimblett, Markus Roggenbach, Swansea University 2008
5License     :  similar to LGPL, see HetCATS/LICENSE.txt or LIZENZ.txt
6
7Maintainer  :  a.m.gimblett@swansea.ac.uk
8Stability   :  provisional
9Portability :  portable
10
11Static analysis of CSP-CASL specifications, following "Tool Support
12for CSP-CASL", MPhil thesis by Andy Gimblett, 2008.
13<http://www.cs.swan.ac.uk/~csandy/mphil/>
14
15-}
16
17module CspCASL.StatAnaCSP where
18
19import qualified Control.Monad as Monad
20import qualified Data.Map as Map
21import qualified Data.Maybe as Maybe
22import qualified Data.Set as S
23-- liam added the following, they should be deleted from imports when
24-- liams temp code is removed: Op_name mkSimpleId mkInfix OP_SYMB(..),
25-- OP_TYPE(..)
26import CASL.AS_Basic_CASL (FORMULA(..), OpKind(..), SORT, TERM(..), VAR,
27                           VAR_DECL(..))
28import CASL.MixfixParser (emptyMix, Mix(..), makeRules, mkIdSets,
29                          resolveFormula, resolveMixfix, unite)
30import CASL.Overload (minExpFORMULA, oneExpTerm)
31import CASL.Sign
32import CASL.Morphism (RawSymbol)
33import CASL.StaticAna (allOpIds, allPredIds)
34import Common.AS_Annotation
35import Common.Result
36import Common.GlobalAnnotations
37import Common.ConvertGlobalAnnos
38import qualified Common.Lib.Rel as Rel
39import Common.Id (getRange, Id, simpleIdToId, nullRange)
40import Common.Lib.State
41import Common.ExtSign
42
43import CspCASL.AS_CspCASL
44import CspCASL.AS_CspCASL_Process
45import CspCASL.LocalTop (Obligation(..), unmetObs)
46import CspCASL.Print_CspCASL ()
47import CspCASL.SignCSP
48
49import qualified Data.Set as Set
50
51basicAnalysisCspCASL :: (CspBasicSpec, CspCASLSign, GlobalAnnos)
52        -> Result (CspBasicSpec, ExtSign CspCASLSign Symbol,
53                   [Named CspCASLSen])
54basicAnalysisCspCASL (cc, sigma, ga) =
55    let Result es mga = mergeGlobalAnnos ga $ globAnnos sigma
56        (_, accSig) = runState (ana_BASIC_CSP cc) $ case mga of
57              Nothing -> sigma
58              Just nga -> sigma { globAnnos = nga }
59        ds = reverse $ envDiags accSig
60        -- Extract process equations only.
61        ext = extendedInfo accSig
62        ccsents = reverse $ ccSentences ext
63        -- Clean signature here
64        cleanSig = accSig
65                   { extendedInfo = ext { ccSentences = []}}
66    in Result (es ++ ds) $
67      Just (cc, mkExtSign cleanSig, ccsents)
68
69ana_BASIC_CSP :: CspBasicSpec -> State CspCASLSign ()
70ana_BASIC_CSP cc = do checkLocalTops
71                      mapM anaChanDecl (channels cc)
72                      mapM anaProcItem (proc_items cc)
73                      return ()
74
75-- Analysis of local top elements
76
77-- | Check a CspCASL signature for local top elements in its subsort
78-- relation.
79checkLocalTops :: State CspCASLSign ()
80checkLocalTops = do
81    sig <- get
82    let obs = unmetObs $ Rel.toList $ Rel.transClosure $ sortRel sig
83    addDiags (map lteError obs)
84    return ()
85
86-- | Add diagnostic error message for every unmet local top element
87-- obligation.
88lteError :: Obligation SORT -> Diagnosis
89lteError (Obligation x y z) = mkDiag Error msg ()
90    where msg = ("local top element obligation ("
91                 ++ (show x) ++ "<" ++ (show y) ++ "," ++ (show z)
92                 ++ ") unfulfilled")
93
94-- Static analysis of channel declarations
95
96-- | Statically analyse a CspCASL channel declaration.
97anaChanDecl :: CHANNEL_DECL -> State CspCASLSign ()
98anaChanDecl (ChannelDecl chanNames chanSort) = do
99    checkSorts [chanSort] -- check channel sort is known
100    sig <- get
101    let ext = extendedInfo sig
102        oldChanMap = chans ext
103    newChanMap <- Monad.foldM (anaChannelName chanSort) oldChanMap chanNames
104    vds <- gets envDiags
105    put sig { extendedInfo = ext { chans = newChanMap }
106            , envDiags = vds
107            }
108    return ()
109
110-- | Statically analyse a CspCASL channel name.
111anaChannelName :: SORT -> ChanNameMap -> CHANNEL_NAME ->
112                    State CspCASLSign ChanNameMap
113anaChannelName s m chanName = do
114    sig <- get
115    if (show chanName) `S.member` (S.map show (sortSet sig))
116      then do let err = "channel name already in use as a sort name"
117              addDiags [mkDiag Error err chanName]
118              return m
119      else case Map.lookup chanName m of
120             Nothing -> return (Map.insert chanName s m) -- insert new.
121             Just e ->
122               if e == s
123                 then do let warn = "channel redeclared with same sort"
124                         addDiags [mkDiag Warning warn chanName]
125                         return m -- already declared with this sort.
126                 else do let err = "channel declared with multiple sorts"
127                         addDiags [mkDiag Error err chanName]
128                         return m
129
130-- Static analysis of process items
131
132-- | Statically analyse a CspCASL process item.
133anaProcItem :: PROC_ITEM -> State CspCASLSign ()
134anaProcItem procItem =
135    case procItem of
136      (Proc_Decl name argSorts alpha) -> anaProcDecl name argSorts alpha
137      (Proc_Eq parmProcName procTerm) -> anaProcEq parmProcName procTerm
138
139-- Static analysis of process declarations
140
141-- | Statically analyse a CspCASL process declaration.
142anaProcDecl :: PROCESS_NAME -> PROC_ARGS -> PROC_ALPHABET
143            -> State CspCASLSign ()
144anaProcDecl name argSorts (ProcAlphabet commTypes _) = do
145    sig <- get
146    let ext = extendedInfo sig
147        oldProcDecls = procSet ext
148    newProcDecls <-
149      if name `Map.member` oldProcDecls
150        then do -- duplicate process declaration
151                let err = "process name declared more than once"
152                addDiags [mkDiag Error err name]
153                return oldProcDecls
154        else do -- new process declation
155                checkSorts argSorts -- check argument sorts are known
156                -- build alphabet: set of CommType values
157                alpha <- Monad.foldM (anaCommType sig) S.empty commTypes
158                let profile = (ProcProfile argSorts alpha)
159                return (Map.insert name profile oldProcDecls)
160    vds <- gets envDiags
161    put sig { extendedInfo = ext {procSet = newProcDecls }
162            , envDiags = vds
163            }
164    return ()
165
166-- Static analysis of process equations
167
168-- | Statically analyse a CspCASL process equation.
169anaProcEq :: PARM_PROCNAME -> PROCESS -> State CspCASLSign ()
170anaProcEq (ParmProcname pn vs) proc = do
171    sig <- get
172    let ext = extendedInfo sig
173        ccsens = ccSentences ext
174        procDecls = procSet ext
175        prof = pn `Map.lookup` procDecls
176    case prof of
177         -- Only analyse a process if its name (and thus profile) is known
178         Just (ProcProfile procArgs procAlpha) ->
179             do  gVars <- anaProcVars pn procArgs vs -- compute global vars
180                 (termAlpha, fqProc) <- anaProcTerm proc (Map.fromList gVars) Map.empty
181                 checkCommAlphaSub termAlpha procAlpha proc "process equation"
182                 -- Save the diags from the checkCommAlphaSub
183                 vds <- gets envDiags
184                 -- put CspCASL Sentences back in to the state with new sentence
185                 put sig {envDiags = vds, extendedInfo =
186                          ext { ccSentences =
187                                -- BUG - What should the constituent
188                                -- alphabet be for this process?
189                                -- probably the same as the inner one!
190                                (makeNamed ("ProcHugo")
191                                               (ProcessEq pn gVars
192                                                          Set.empty
193                                                          fqProc)):ccsens
194                              }
195                         }
196                 return ()
197         Nothing ->
198             do addDiags [mkDiag Error "process equation for unknown process" pn]
199                return ()
200    return ()
201
202-- | Statically analyse a CspCASL process equation's global variable
203-- names.
204anaProcVars :: PROCESS_NAME -> [SORT] -> [VAR] -> State CspCASLSign ProcVarList
205anaProcVars pn ss vs = do
206    case (compare (length ss) (length vs)) of
207       LT -> do addDiags [mkDiag Error "too many process arguments" pn]
208                return []
209       GT -> do addDiags [mkDiag Error "not enough process arguments" pn]
210                return []
211       EQ -> Monad.foldM anaProcVar [] (zip vs ss)
212
213-- | Statically analyse a CspCASL process-global variable name.
214anaProcVar :: ProcVarList -> (VAR, SORT) -> State CspCASLSign ProcVarList
215anaProcVar old (v, s) = do
216    if v `elem` (map fst old)
217       then do addDiags [mkDiag Error "process argument declared more than once" v]
218               return old
219       else return (old ++ [(v, s)])
220
221-- Static analysis of process terms
222
223-- BUG in fucntion below
224-- not returing FQProcesses
225-- | Statically analyse a CspCASL process term.
226--   The process that is returned is a fully qualified process.
227anaProcTerm :: PROCESS -> ProcVarMap -> ProcVarMap ->
228               State CspCASLSign (CommAlpha, PROCESS)
229anaProcTerm proc gVars lVars = case proc of
230    NamedProcess name args range ->
231        do addDiags [mkDiag Debug "Named process" proc]
232           al <- anaNamedProc proc name args (lVars `Map.union` gVars)
233           return (al,
234                   FQProcess (NamedProcess name args range) al range)
235    Skip range ->
236        do addDiags [mkDiag Debug "Skip" proc]
237           return (S.empty,
238                   FQProcess (Skip range) S.empty range)
239    Stop range ->
240        do addDiags [mkDiag Debug "Stop" proc]
241           return (S.empty,
242                   FQProcess (Stop range) S.empty range)
243    Div range ->
244        do addDiags [mkDiag Debug "Div" proc]
245           return (S.empty,
246                   FQProcess (Div range) S.empty range)
247    Run es range ->
248        do addDiags [mkDiag Debug "Run" proc]
249           comms <- anaEventSet es
250           return (comms,
251                   FQProcess (Run es range) comms range)
252    Chaos es range ->
253        do addDiags [mkDiag Debug "Chaos" proc]
254           comms <- anaEventSet es
255           return (comms,
256                   FQProcess (Chaos es range) comms range)
257    PrefixProcess e p range ->
258        do addDiags [mkDiag Debug "Prefix" proc]
259           (evComms, rcvMap) <- anaEvent e (lVars `Map.union` gVars)
260           (comms, pFQTerm) <- anaProcTerm p gVars (rcvMap `Map.union` lVars)
261           return (comms `S.union` evComms,
262                   FQProcess (PrefixProcess e pFQTerm range) (comms `S.union` evComms) range)
263    InternalPrefixProcess v s p range ->
264        do addDiags [mkDiag Debug "Internal prefix" proc]
265           checkSorts [s] -- check sort is known
266           (comms, pFQTerm) <- anaProcTerm p gVars (Map.insert v s lVars)
267           return (S.insert (CommTypeSort s) comms,
268                   FQProcess (InternalPrefixProcess v s pFQTerm range) (S.insert (CommTypeSort s) comms) range)
269    ExternalPrefixProcess v s p range ->
270        do addDiags [mkDiag Debug "External prefix" proc]
271           checkSorts [s] -- check sort is known
272           (comms, pFQTerm) <- anaProcTerm p gVars (Map.insert v s lVars)
273           return (S.insert (CommTypeSort s) comms,
274                   FQProcess (ExternalPrefixProcess v s pFQTerm range) (S.insert (CommTypeSort s) comms) range)
275    Sequential p q range ->
276        do addDiags [mkDiag Debug "Sequential" proc]
277           (pComms, pFQTerm) <- anaProcTerm p gVars lVars
278           (qComms, qFQTerm) <- anaProcTerm q gVars Map.empty
279           return (pComms `S.union` qComms,
280                   FQProcess (Sequential pFQTerm qFQTerm range) (pComms `S.union` qComms) range)
281    InternalChoice p q range ->
282        do addDiags [mkDiag Debug "InternalChoice" proc]
283           (pComms, pFQTerm) <- anaProcTerm p gVars lVars
284           (qComms, qFQTerm) <- anaProcTerm q gVars lVars
285           return (pComms `S.union` qComms,
286                   FQProcess (InternalChoice pFQTerm qFQTerm range) (pComms `S.union` qComms) range)
287    ExternalChoice p q range ->
288        do addDiags [mkDiag Debug "ExternalChoice" proc]
289           (pComms, pFQTerm) <- anaProcTerm p gVars lVars
290           (qComms, qFQTerm) <- anaProcTerm q gVars lVars
291           return (pComms `S.union` qComms,
292                   FQProcess (ExternalChoice pFQTerm qFQTerm range) (pComms `S.union` qComms) range)
293    Interleaving p q range ->
294        do addDiags [mkDiag Debug "Interleaving" proc]
295           (pComms, pFQTerm) <- anaProcTerm p gVars lVars
296           (qComms, qFQTerm) <- anaProcTerm q gVars lVars
297           return (pComms `S.union` qComms,
298                   FQProcess (Interleaving pFQTerm qFQTerm range) (pComms `S.union` qComms) range)
299    SynchronousParallel p q range ->
300        do addDiags [mkDiag Debug "Synchronous" proc]
301           (pComms, pFQTerm) <- anaProcTerm p gVars lVars
302           (qComms, qFQTerm) <- anaProcTerm q gVars lVars
303           return (pComms `S.union` qComms,
304                   FQProcess (SynchronousParallel pFQTerm qFQTerm range) (pComms `S.union` qComms) range)
305    GeneralisedParallel p es q range ->
306        do addDiags [mkDiag Debug "Generalised parallel" proc]
307           (pComms, pFQTerm) <- anaProcTerm p gVars lVars
308           synComms <- anaEventSet es
309           (qComms, qFQTerm) <- anaProcTerm q gVars lVars
310           return (S.unions [pComms, qComms, synComms],
311                   FQProcess (GeneralisedParallel pFQTerm es qFQTerm range) (S.unions [pComms, qComms, synComms]) range)
312    AlphabetisedParallel p esp esq q range ->
313        do addDiags [mkDiag Debug "Alphabetised parallel" proc]
314           (pComms, pFQTerm) <- anaProcTerm p gVars lVars
315           pSynComms <- anaEventSet esp
316           checkCommAlphaSub pSynComms pComms proc
317                                 "alphabetised parallel, left"
318           qSynComms <- anaEventSet esq
319           (qComms, qFQTerm) <- anaProcTerm q gVars lVars
320           checkCommAlphaSub qSynComms qComms proc
321                                 "alphabetised parallel, right"
322           return (pComms `S.union` qComms,
323                   FQProcess (AlphabetisedParallel pFQTerm esp esq qFQTerm range) (pComms `S.union` qComms) range)
324    Hiding p es range ->
325        do addDiags [mkDiag Debug "Hiding" proc]
326           (pComms, pFQTerm) <- anaProcTerm p gVars lVars
327           hidComms <- anaEventSet es
328           return (pComms `S.union` hidComms,
329                   FQProcess (Hiding pFQTerm es range) (pComms `S.union` hidComms) range)
330    RenamingProcess p r range ->
331        do addDiags [mkDiag Debug "Renaming" proc]
332           (pComms, pFQTerm) <- anaProcTerm p gVars lVars
333           renAlpha <- anaRenaming r
334           return (pComms `S.union` renAlpha,
335                   FQProcess (RenamingProcess pFQTerm r range) (pComms `S.union` renAlpha) range)
336    ConditionalProcess f p q range ->
337        do addDiags [mkDiag Debug "Conditional" proc]
338           (pComms, pFQTerm) <- anaProcTerm p gVars lVars
339           (qComms, qFQTerm) <- anaProcTerm q gVars lVars
340           -- mfs is the fully qualified formula version of f
341           mfs <- anaFormulaCspCASL (gVars `Map.union` lVars) f
342           addDiags [mkDiag Debug "Formula" f]
343           addDiags [mkDiag Debug "FQFormula" (Maybe.fromJust mfs)]
344           let fComms = case mfs of
345                          Nothing -> S.empty
346                          Just fs -> formulaComms fs
347           return (S.unions [pComms, qComms, fComms],
348                   FQProcess (ConditionalProcess (Maybe.fromJust mfs) pFQTerm qFQTerm range)
349                                 (S.unions [pComms, qComms, fComms]) range)
350
351-- | Statically analyse a CspCASL "named process" term.
352anaNamedProc :: PROCESS -> PROCESS_NAME -> [TERM ()] -> ProcVarMap ->
353                State CspCASLSign CommAlpha
354anaNamedProc proc pn terms procVars = do
355    sig <- get
356    let ext = extendedInfo sig
357        procDecls = procSet ext
358        prof = pn `Map.lookup` procDecls
359    case prof of
360      Just (ProcProfile varSorts permAlpha) ->
361        if (length terms) == (length varSorts)
362          then do mapM (anaNamedProcTerm procVars) (zip terms varSorts)
363                  return permAlpha
364          else do let err = "wrong number of arguments in named process"
365                  addDiags [mkDiag Error err proc]
366                  return S.empty
367      Nothing ->
368        do addDiags [mkDiag Error "unknown process name" proc]
369           return S.empty
370
371-- | Statically analysis a CASL term occurring in a CspCASL "named
372-- process" term.
373anaNamedProcTerm :: ProcVarMap -> ((TERM ()), SORT) -> State CspCASLSign ()
374anaNamedProcTerm pm (t, expSort) = do
375    mt <- anaTermCspCASL pm t
376    case mt of
377      Nothing -> return () -- CASL term analysis failed
378      (Just at) -> do ccTermCast at expSort -- attempt cast; don't need result
379                      return ()
380
381-- Static analysis of event sets and communication types
382
383-- | Statically analyse a CspCASL event set.
384anaEventSet :: EVENT_SET -> State CspCASLSign CommAlpha
385anaEventSet (EventSet es _) = do
386  sig <- get
387  comms <- Monad.foldM (anaCommType sig) S.empty es
388  vds <- gets envDiags
389  put sig { envDiags = vds }
390  return comms
391
392-- | Statically analyse a CspCASL communication type.
393anaCommType :: CspCASLSign -> CommAlpha -> COMM_TYPE ->
394               State CspCASLSign CommAlpha
395anaCommType sig alpha ct =
396    if ctSort `S.member` (sortSet sig)
397      then -- ct is a sort name; insert sort into alpha
398        do return (S.insert (CommTypeSort ctSort) alpha)
399      else -- ct not a sort name, so should be a channel name
400        case Map.lookup ct (chans $ extendedInfo sig) of
401          Just s -> -- ct is a channel name; insert typed chan name into alpha
402                    return (S.insert (mkTypedChan ct s) alpha)
403          Nothing -> do let err = "not a sort or channel name"
404                        addDiags [mkDiag Error err ct]
405                        return alpha
406        where ctSort = simpleIdToId ct
407              mkTypedChan c s = CommTypeChan $ TypedChanName c s
408
409-- Static analysis of events
410
411-- | Statically analyse a CspCASL event.
412anaEvent :: EVENT -> ProcVarMap -> State CspCASLSign (CommAlpha, ProcVarMap)
413anaEvent e vars = case e of
414                    TermEvent t _ -> anaTermEvent t vars
415                    ChanSend c t _ -> anaChanSend c t vars
416                    ChanNonDetSend c v s _ -> anaChanBinding c v s
417                    ChanRecv c v s _ -> anaChanBinding c v s
418
419-- | Statically analyse a CspCASL term event.
420anaTermEvent :: (TERM ()) -> ProcVarMap ->
421                State CspCASLSign (CommAlpha, ProcVarMap)
422anaTermEvent t vars = do
423  mt <- anaTermCspCASL vars t
424  let alpha = case mt of
425                Just at -> [(CommTypeSort (sortOfTerm at))]
426                Nothing -> []
427  return (S.fromList alpha, Map.empty)
428
429-- | Statically analyse a CspCASL channel send event.
430anaChanSend :: CHANNEL_NAME -> (TERM ()) -> ProcVarMap ->
431                State CspCASLSign (CommAlpha, ProcVarMap)
432anaChanSend c t vars = do
433  sig <- get
434  let ext = extendedInfo sig
435  case c `Map.lookup` (chans ext) of
436    Nothing -> do
437      addDiags [mkDiag Error "unknown channel" c]
438      return (S.empty, Map.empty)
439    Just chanSort -> do
440      mt <- anaTermCspCASL vars t
441      case mt of
442        Nothing -> -- CASL analysis failed
443                   return (S.empty, Map.empty)
444        (Just at) ->
445            do mc <- ccTermCast at chanSort
446               case mc of
447                 Nothing -> -- cast failed
448                            return (S.empty, Map.empty)
449                 (Just ct) ->
450                     do let castSort = sortOfTerm ct
451                            alpha = [CommTypeSort castSort
452                                    ,CommTypeChan $ TypedChanName c castSort
453                                    ]
454                        return (S.fromList alpha, Map.empty)
455
456-- | Statically analyse a CspCASL "binding" channel event (which is
457-- either a channel nondeterministic send event or a channel receive
458-- event).
459anaChanBinding :: CHANNEL_NAME -> VAR -> SORT ->
460                   State CspCASLSign (CommAlpha, ProcVarMap)
461anaChanBinding c v s = do
462  checkSorts [s] -- check sort is known
463  sig <- get
464  let ext = extendedInfo sig
465  case c `Map.lookup` (chans ext) of
466    Nothing -> do
467      addDiags [mkDiag Error "unknown channel" c]
468      return (S.empty, Map.empty)
469    Just chanSort -> do
470      if s `S.member` (chanSort `S.insert` (subsorts chanSort))
471        then do let alpha = [CommTypeSort s
472                            ,CommTypeChan (TypedChanName c s)]
473                let binding = [(v, s)]
474                return (S.fromList alpha, Map.fromList binding)
475        else do let err = "sort not a subsort of channel's sort"
476                addDiags [mkDiag Error err s]
477                return (S.empty, Map.empty)
478            where subsorts = Rel.predecessors (sortRel sig)
479
480-- Static analysis of renaming and renaming items
481
482-- | Statically analyse a CspCASL renaming.
483anaRenaming :: RENAMING -> State CspCASLSign CommAlpha
484anaRenaming r = do al <- Monad.foldM anaRenamingItem S.empty r
485                   return al
486
487-- | Statically analyse a CspCASL renaming item.
488anaRenamingItem :: CommAlpha -> Id -> State CspCASLSign CommAlpha
489anaRenamingItem inAl ri = do
490    totOps <- getUnaryOpsById ri Total
491    if (not $ S.null totOps)
492      then return (inAl `S.union` totOps)
493      else do parOps <- getUnaryOpsById ri Partial
494              if (not $ S.null parOps)
495                then return (inAl `S.union` parOps)
496                else do preds <- getBinPredsById ri
497                        if (not $ S.null preds)
498                          then return (inAl `S.union` preds)
499                          else do let err = ("renaming item not a binary " ++
500                                             "operation or predicate name")
501                                  addDiags [mkDiag Error err ri]
502                                  return inAl
503
504-- | Given a CASL identifier and a `function kind' (total or partial),
505-- find all unary operations of that kind with that name in the CASL
506-- signature, and return a set of corresponding communication types
507-- for those operations.
508getUnaryOpsById :: Id -> OpKind -> State CspCASLSign (S.Set CommType)
509getUnaryOpsById ri kind = do
510    sig <- get
511    let opsWithId = Map.findWithDefault S.empty ri (opMap sig)
512        binOpsKind = S.filter (isBin kind) opsWithId
513        cts = S.map CommTypeSort $ S.fold opSorts S.empty binOpsKind
514    return cts
515      where isBin k ot = (k == opKind ot) && (1 == (length (opArgs ot)))
516            opSorts o inS = inS `S.union` (S.fromList ((opArgs o) ++ [opRes o]))
517
518-- | Given a CASL identifier find all binary predicates with that name
519-- in the CASL signature, and return a set of corresponding
520-- communication types for those predicates.
521getBinPredsById :: Id -> State CspCASLSign (S.Set CommType)
522getBinPredsById ri = do
523    sig <- get
524    let predsWithId = Map.findWithDefault S.empty ri (predMap sig)
525        binPreds = S.filter isBin predsWithId
526        cts = S.map CommTypeSort $ S.fold predSorts S.empty binPreds
527    return cts
528      where isBin ot = (2 == (length (predArgs ot)))
529            predSorts p inS = inS `S.union` (S.fromList (predArgs p))
530
531-- | Given two CspCASL communication alphabets, check that the first's
532-- subsort closure is a subset of the second's subsort closure.
533checkCommAlphaSub :: CommAlpha -> CommAlpha -> PROCESS -> String ->
534                     State CspCASLSign ()
535checkCommAlphaSub sub super proc context = do
536  sig <- get
537  let extras = ((closeCspCommAlpha sig sub) `S.difference`
538                (closeCspCommAlpha sig super))
539  if S.null extras
540    then do return ()
541    else do let err = ("Communication alphabet subset violations (" ++
542                       context ++ "): " ++ (show $ S.toList extras))
543            addDiags [mkDiag Error err proc]
544            return ()
545
546-- Static analysis of CASL terms occurring in CspCASL process terms.
547
548-- | Statically analyse a CASL term appearing in a CspCASL process;
549-- any in-scope process variables are added to the signature before
550-- performing the analysis.
551anaTermCspCASL :: ProcVarMap -> (TERM ()) ->
552                  State CspCASLSign (Maybe (TERM ()))
553anaTermCspCASL pm t = do
554    sig <- get
555    let newVars = Map.union pm (varMap sig)
556        sigext = sig { varMap = newVars }
557        Result ds mt = anaTermCspCASL' sigext t
558    addDiags ds
559    return mt
560
561-- | Statically analyse a CASL term in the context of a CspCASL
562-- signature.  If successful, returns a fully-qualified term.
563anaTermCspCASL' :: CspCASLSign -> TERM () -> Result (TERM ())
564anaTermCspCASL' sig trm = do
565    let allIds = unite [mkIdSets (allOpIds sig) $ allPredIds sig]
566        ga = globAnnos sig
567        mix = emptyMix { mixRules = makeRules ga allIds }
568    resT <- resolveMixfix (putParen mix) (mixResolve mix)
569                 ga (mixRules mix) trm
570    oneExpTerm (const return) sig resT
571
572-- | Attempt to cast a CASL term to a particular CASL sort.
573ccTermCast :: (TERM ()) -> SORT -> State CspCASLSign (Maybe (TERM ()))
574ccTermCast t cSort =
575    if termSort == (cSort)
576      then return (Just t)
577      else do sig <- get
578              if Rel.member termSort cSort (sortRel sig)
579                then do let err = "upcast term to " ++ (show cSort)
580                        addDiags [mkDiag Debug err t]
581                        return (Just (Sorted_term t cSort (getRange t)))
582                else if Rel.member cSort termSort (sortRel sig)
583                       then do let err = "downcast term to " ++ (show cSort)
584                               addDiags [mkDiag Debug err t]
585                               return (Just (Cast t cSort (getRange t)))
586                       else do let err = "can't cast term to sort " ++
587                                           (show cSort)
588                               addDiags [mkDiag Error err t]
589                               return Nothing
590        where termSort = (sortOfTerm t)
591
592-- Static analysis of CASL formulae occurring in CspCASL process
593-- terms.
594
595-- | Statically analyse a CASL formula appearing in a CspCASL process;
596-- any in-scope process variables are added to the signature before
597-- performing the analysis.
598anaFormulaCspCASL :: ProcVarMap -> (FORMULA ()) ->
599                     State CspCASLSign (Maybe (FORMULA ()))
600anaFormulaCspCASL pm f = do
601    addDiags [mkDiag Debug "anaFormulaCspCASL" ()]
602    sig <- get
603    let newVars = Map.union pm (varMap sig)
604        sigext = sig { varMap = newVars }
605        Result ds mt = anaFormulaCspCASL' sigext f
606    addDiags ds
607    return mt
608
609-- | Statically analyse a CASL formula in the context of a CspCASL
610-- signature.  If successful, returns a fully-qualified formula.
611anaFormulaCspCASL' :: CspCASLSign -> FORMULA () -> Result (FORMULA ())
612anaFormulaCspCASL' sig frm = do
613    let allIds = unite [mkIdSets (allOpIds sig) $ allPredIds sig]
614        ga = globAnnos sig
615        mix = emptyMix { mixRules = makeRules ga allIds }
616    resF <- resolveFormula (putParen mix) (mixResolve mix) ga (mixRules mix) frm
617    minExpFORMULA (const return) sig resF
618
619-- | Compute the communication alphabet arising from a formula
620-- occurring in a CspCASL process term.
621formulaComms :: (FORMULA ()) -> CommAlpha
622formulaComms f = case f of
623    Quantification _ varDecls f' _ ->
624        (formulaComms f') `S.union` S.fromList vdSorts
625            where vdSorts = (map (CommTypeSort . vdSort) varDecls)
626                  vdSort (Var_decl _ s _) = s
627    Conjunction fs _ -> S.unions (map formulaComms fs)
628    Disjunction fs _ -> S.unions (map formulaComms fs)
629    Implication f1 f2 _ _ -> (formulaComms f1) `S.union` (formulaComms f2)
630    Equivalence f1 f2 _ -> (formulaComms f1) `S.union` (formulaComms f2)
631    Negation f' _ -> formulaComms f'
632    True_atom _ -> S.empty
633    False_atom _ -> S.empty
634    Predication _ _ _ -> S.empty
635    Definedness t _ -> S.singleton (CommTypeSort (sortOfTerm t))
636    Existl_equation t1 t2 _ -> S.fromList [CommTypeSort (sortOfTerm t1),
637                                           CommTypeSort (sortOfTerm t2)]
638    Strong_equation t1 t2 _ -> S.fromList [CommTypeSort (sortOfTerm t1),
639                                           CommTypeSort (sortOfTerm t2)]
640    Membership t s _ -> S.fromList [CommTypeSort (sortOfTerm t),
641                                    CommTypeSort s]
642    Mixfix_formula t -> S.singleton (CommTypeSort (sortOfTerm t))
643    Unparsed_formula _ _ -> S.empty
644    Sort_gen_ax _ _ -> S.empty
645    ExtFORMULA _ -> S.empty
Note: See TracBrowser for help on using the browser.