{-# LANGUAGE ExistentialQuantification #-}

-- | Represent information about externs needed in the generation of C99 code
-- for stream declarations and triggers.
module Copilot.Compile.C99.External where

import Data.List  (unionBy)

import Copilot.Core
import Copilot.Compile.C99.Util

-- | Representation of external variables.
data External = forall a. External
  { External -> String
extname    :: String
  , External -> String
extcpyname :: String
  , ()
exttype    :: Type a
  }

-- | Union over lists of External, we solely base the equality on the
-- extname's.
extunion :: [External] -> [External] -> [External]
extunion :: [External] -> [External] -> [External]
extunion = forall a. (a -> a -> Bool) -> [a] -> [a] -> [a]
unionBy (\External
a External
b -> External -> String
extname External
a forall a. Eq a => a -> a -> Bool
== External -> String
extname External
b)

-- | Collect all external variables from the streams and triggers.
--
-- Although Copilot specifications can contain also properties and theorems,
-- the C99 backend currently only generates code for streams and triggers.
gatherexts :: [Stream] -> [Trigger] -> [External]
gatherexts :: [Stream] -> [Trigger] -> [External]
gatherexts [Stream]
streams [Trigger]
triggers = [External]
streamsexts [External] -> [External] -> [External]
`extunion` [External]
triggersexts
  where
    streamsexts :: [External]
streamsexts  = forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr [External] -> [External] -> [External]
extunion forall a. Monoid a => a
mempty forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map Stream -> [External]
streamexts [Stream]
streams
    triggersexts :: [External]
triggersexts = forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr [External] -> [External] -> [External]
extunion forall a. Monoid a => a
mempty forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map Trigger -> [External]
triggerexts [Trigger]
triggers

    streamexts :: Stream -> [External]
    streamexts :: Stream -> [External]
streamexts (Stream Id
_ [a]
_ Expr a
expr Type a
_) = forall a. Expr a -> [External]
exprexts Expr a
expr

    triggerexts :: Trigger -> [External]
    triggerexts :: Trigger -> [External]
triggerexts (Trigger String
_ Expr Bool
guard [UExpr]
args) = [External]
guardexts [External] -> [External] -> [External]
`extunion` [External]
argexts
      where
        guardexts :: [External]
guardexts = forall a. Expr a -> [External]
exprexts Expr Bool
guard
        argexts :: [External]
argexts   = forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map UExpr -> [External]
uexprexts [UExpr]
args

    uexprexts :: UExpr -> [External]
    uexprexts :: UExpr -> [External]
uexprexts (UExpr Type a
_ Expr a
expr) = forall a. Expr a -> [External]
exprexts Expr a
expr

    exprexts :: Expr a -> [External]
    exprexts :: forall a. Expr a -> [External]
exprexts Expr a
expr = let rec :: Expr a -> [External]
rec = forall a. Expr a -> [External]
exprexts in case Expr a
expr of
      Local Type a1
_ Type a
_ String
_ Expr a1
e1 Expr a
e2   -> forall a. Expr a -> [External]
rec Expr a1
e1 [External] -> [External] -> [External]
`extunion` forall a. Expr a -> [External]
rec Expr a
e2
      ExternVar Type a
ty String
name Maybe [a]
_ -> [forall a. String -> String -> Type a -> External
External String
name (String -> String
excpyname String
name) Type a
ty]
      Op1 Op1 a1 a
_ Expr a1
e             -> forall a. Expr a -> [External]
rec Expr a1
e
      Op2 Op2 a1 b a
_ Expr a1
e1 Expr b
e2         -> forall a. Expr a -> [External]
rec Expr a1
e1 [External] -> [External] -> [External]
`extunion` forall a. Expr a -> [External]
rec Expr b
e2
      Op3 Op3 a1 b c a
_ Expr a1
e1 Expr b
e2 Expr c
e3      -> forall a. Expr a -> [External]
rec Expr a1
e1 [External] -> [External] -> [External]
`extunion` forall a. Expr a -> [External]
rec Expr b
e2 [External] -> [External] -> [External]
`extunion` forall a. Expr a -> [External]
rec Expr c
e3
      Label Type a
_ String
_ Expr a
e         -> forall a. Expr a -> [External]
rec Expr a
e
      Expr a
_                   -> []