module Copilot.Compile.C99.Util where

import Control.Monad.State

import Copilot.Core  (Id)
import qualified Language.C99.Simple.AST as C


type FunEnv = ([C.Decln], [C.Ident])

-- | `tell` equivalent for `State`.
statetell :: Monoid m => m -> State m ()
statetell :: m -> State m ()
statetell m
m = (m -> m) -> State m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (((m -> m -> m) -> m -> m -> m
forall a b c. (a -> b -> c) -> b -> a -> c
flip m -> m -> m
forall a. Monoid a => a -> a -> a
mappend) m
m)

-- | Generate fresh variable name based on a given one.
fresh :: String -> [String] -> String
fresh :: String -> [String] -> String
fresh String
name [String]
used = [String] -> String
forall a. [a] -> a
head ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ (String -> Bool) -> [String] -> [String]
forall a. (a -> Bool) -> [a] -> [a]
dropWhile ((String -> [String] -> Bool) -> [String] -> String -> Bool
forall a b c. (a -> b -> c) -> b -> a -> c
flip String -> [String] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem [String]
used) (String
nameString -> [String] -> [String]
forall a. a -> [a] -> [a]
:[String]
freshnames) where
  freshnames :: [String]
freshnames = (String
name String -> String -> String
forall a. [a] -> [a] -> [a]
++)(String -> String) -> (Integer -> String) -> Integer -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.Integer -> String
forall a. Show a => a -> String
show (Integer -> String) -> [Integer] -> [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Integer
0..]

-- | Collect all the names from a list of C99 declarations.
names :: [C.Decln] -> [String]
names :: [Decln] -> [String]
names [Decln]
ds = (Decln -> String) -> [Decln] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Decln -> String
match [Decln]
ds where
  match :: Decln -> String
match (C.VarDecln Maybe StorageSpec
_ Type
_ String
name Maybe Init
_) = String
name

-- | Turn a stream id into a suitable C variable name.
streamname :: Id -> String
streamname :: Id -> String
streamname Id
sid = String
"s" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Id -> String
forall a. Show a => a -> String
show Id
sid

-- | Turn a stream id into the global varname for indices.
indexname :: Id -> String
indexname :: Id -> String
indexname Id
sid = Id -> String
streamname Id
sid String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"_idx"

-- | Add a postfix for copies of external variables the name.
excpyname :: String -> String
excpyname :: String -> String
excpyname String
name = String
name String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"_cpy"

-- | Turn stream id into name of its generator function.
generatorname :: Id -> String
generatorname :: Id -> String
generatorname Id
sid = Id -> String
streamname Id
sid String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"_gen"

-- | Turn a the name of a trigger into a guard generator.
guardname :: String -> String
guardname :: String -> String
guardname String
name = String
name String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"_guard"

-- | Turn a trigger name into a an trigger argument name.
argname :: String -> Int -> String
argname :: String -> Id -> String
argname String
name Id
n = String
name String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"_arg" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Id -> String
forall a. Show a => a -> String
show Id
n

-- | Enumerate all argument names based on trigger name.
argnames :: String -> [String]
argnames :: String -> [String]
argnames String
base = [String
aname | Id
n <- [Id
0..], let aname :: String
aname = String -> Id -> String
argname String
base Id
n]

funcall :: C.Ident -> [C.Expr] -> C.Expr
funcall :: String -> [Expr] -> Expr
funcall String
name [Expr]
args = Expr -> [Expr] -> Expr
C.Funcall (String -> Expr
C.Ident String
name) [Expr]
args