root/trunk/CspCASL/StatAnaCSP.hs @ 11231

Revision 11231, 31.2 kB (checked in by csliam, 11 months ago)

Static analysis of CspCASL now adds channel names and process names to the collected symbols (stored in the CASL signature)

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