{-# 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 = (External -> External -> Bool)
-> [External] -> [External] -> [External]
forall a. (a -> a -> Bool) -> [a] -> [a] -> [a]
unionBy (\External
a External
b -> External -> String
extname External
a String -> String -> Bool
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  = ([External] -> [External] -> [External])
-> [External] -> [[External]] -> [External]
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr [External] -> [External] -> [External]
extunion [External]
forall a. Monoid a => a
mempty ([[External]] -> [External]) -> [[External]] -> [External]
forall a b. (a -> b) -> a -> b
$ (Stream -> [External]) -> [Stream] -> [[External]]
forall a b. (a -> b) -> [a] -> [b]
map Stream -> [External]
streamexts [Stream]
streams
  triggersexts :: [External]
triggersexts = ([External] -> [External] -> [External])
-> [External] -> [[External]] -> [External]
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr [External] -> [External] -> [External]
extunion [External]
forall a. Monoid a => a
mempty ([[External]] -> [External]) -> [[External]] -> [External]
forall a b. (a -> b) -> a -> b
$ (Trigger -> [External]) -> [Trigger] -> [[External]]
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
_) = Expr a -> [External]
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 = Expr Bool -> [External]
forall a. Expr a -> [External]
exprexts Expr Bool
guard
    argexts :: [External]
argexts   = [[External]] -> [External]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[External]] -> [External]) -> [[External]] -> [External]
forall a b. (a -> b) -> a -> b
$ (UExpr -> [External]) -> [UExpr] -> [[External]]
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) = Expr a -> [External]
forall a. Expr a -> [External]
exprexts Expr a
expr

  exprexts :: Expr a -> [External]
  exprexts :: Expr a -> [External]
exprexts Expr a
expr = let rec :: Expr a -> [External]
rec = Expr a -> [External]
forall a. Expr a -> [External]
exprexts in case Expr a
expr of
    Local Type a1
_ Type a
_ String
_ Expr a1
e1 Expr a
e2   -> Expr a1 -> [External]
forall a. Expr a -> [External]
rec Expr a1
e1 [External] -> [External] -> [External]
`extunion` Expr a -> [External]
forall a. Expr a -> [External]
rec Expr a
e2
    ExternVar Type a
ty String
name Maybe [a]
_ -> [String -> String -> Type a -> External
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             -> Expr a1 -> [External]
forall a. Expr a -> [External]
rec Expr a1
e
    Op2 Op2 a1 b a
_ Expr a1
e1 Expr b
e2         -> Expr a1 -> [External]
forall a. Expr a -> [External]
rec Expr a1
e1 [External] -> [External] -> [External]
`extunion` Expr b -> [External]
forall a. Expr a -> [External]
rec Expr b
e2
    Op3 Op3 a1 b c a
_ Expr a1
e1 Expr b
e2 Expr c
e3      -> Expr a1 -> [External]
forall a. Expr a -> [External]
rec Expr a1
e1 [External] -> [External] -> [External]
`extunion` Expr b -> [External]
forall a. Expr a -> [External]
rec Expr b
e2 [External] -> [External] -> [External]
`extunion` Expr c -> [External]
forall a. Expr a -> [External]
rec Expr c
e3
    Label Type a
_ String
_ Expr a
e         -> Expr a -> [External]
forall a. Expr a -> [External]
rec Expr a
e
    Expr a
_                   -> []