content: {- |
  Module      :  ./CSL/GuardedDependencies.hs
  Description :  Guarded Dependency Store
  Copyright   :  (c) Ewaryst Schulz, DFKI Bremen 2011
  License     :  GPLv2 or higher, see LICENSE.txt
  
  Maintainer  :  Ewaryst.Schulz@dfki.de
  Stability   :  experimental
  Portability :  portable
  
  Definition of guarded dependencies resulting from the use of extended
  parameters.
  
  -}
  
  
  module CSL.GuardedDependencies
      where
  
  import Common.AS_Annotation
  import Common.Doc
  import Common.DocUtils
  
  import CSL.AS_BASIC_CSL
  import CSL.ASUtils
  import CSL.Sign as Sign
  import CSL.EPRelation
  
  import Control.Monad
  import qualified Data.Set as Set
  import qualified Data.Map as Map
  
  -- ** Datatypes and guarded definitions
  
  
  {- | A guard consists of the guard range and the corresponding expression
  together with a name, a set of not propagated parameters and a set of
  constrained parameters (in the extended parameter specification) -}
  data Guard a = Guard { range :: a
                       , definition :: EXPRESSION
                       , assName :: String
                       , filtered :: Set.Set String
                       , constrained :: Set.Set String }
  
  
  prettyGuard :: (a -> Doc) -> Guard a -> Doc
  prettyGuard f g = f (range g) <+> text "-->" <+> pretty (definition g)
  
  instance Functor Guard where
      fmap f (Guard x e an fs ct) = Guard (f x) e an fs ct
  
  instance Pretty a => Pretty (Guard a) where
      pretty = prettyGuard pretty
  
  instance Pretty a => Show (Guard a) where
      show = show . pretty
  
  {- | A guarded constant consists of the argument list (for function definitions)
  and a list of guard-expressions -}
  data Guarded a = Guarded { argvars :: [String]
                           , guards :: [Guard a] }
  
  {- Comment it in if needed later
  
  undefinedGuard :: String -> a -> Guard a
  undefinedGuard s x = Guard { range = x
                             , definition = err
                             , assName = err
                             , filtered = err
                             , constrained = err }
      where err = error $ "undefinedGuard: " ++ s
  
  undefinedGuarded :: String -> a -> Guarded a
  undefinedGuarded s x = Guarded { argvars = []
                                 , guards = [undefinedGuard s x] }
  -}
  
  
  prettyGuarded :: (a -> Doc) -> Guarded a -> Doc
  prettyGuarded f grdd = vcat $ map (prettyGuard f) $ guards grdd
  
  instance Functor Guarded where
      fmap f grdd = grdd { guards = map (fmap f) $ guards grdd }
  
  instance Pretty a => Pretty (Guarded a) where
      pretty = prettyGuarded pretty
  
  instance Pretty a => Show (Guarded a) where
      show = show . pretty
  
  
  type GuardedMap a = Map.Map String (Guarded a)
  
  
  addAssignment :: String -> OpDecl -> EXPRESSION -> GuardedMap [EXTPARAM]
                -> GuardedMap [EXTPARAM]
  addAssignment n (OpDecl sc epl al _) def m =
      let combf x y | argvars x == argvars y = y { guards = guards y ++ guards x }
                    | otherwise =
                        error "addAssignment: the argument vars does not match."
          grd = Guarded (map varDeclName al) [uncurry (Guard epl def n)
                                                $ filteredConstrainedParams epl]
      in Map.insertWith combf (simpleName $ OpUser sc) grd m
  
  {- TODO:
      1. analysis for missing definitions and undeclared extparams
      2. Integrating extparam domain definitions
      3. check for each constant if the Guards exhaust the extparam domain (in splitAS)
  -}
  
  -- | Splits the Commands into the AssignmentStore and a program sequence
  splitAS :: [Named CMD] -> (GuardedMap [EXTPARAM], [Named CMD])
  splitAS cl =
      let f nc (m, l) = case sentence nc of
                         Ass c def -> (addAssignment (senAttr nc) c def m, l)
                         _ -> (m, nc : l)
      in foldr f (Map.empty, []) cl
  