root/trunk/CspCASL/StatAnaCSP.hs @ 11224

Revision 11224, 30.7 kB (checked in by csliam, 11 months ago)

Improved pretty printing of CspCASL signatures

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