{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE PostfixOperators #-}

-- | The logic to render C++ auxiliary files is contained in this module
module Language.Drasil.Code.Imperative.GOOL.LanguageRenderer.CppRenderer (
  CppProject(..)
) where

import Language.Drasil.Choices (ImplementationType(..))
import Language.Drasil.Code.Imperative.GOOL.ClassInterface (ReadMeInfo(..),
  PackageSym(..), AuxiliarySym(..))
import qualified
  Language.Drasil.Code.Imperative.GOOL.LanguageRenderer.LanguagePolymorphic as
  G (doxConfig, readMe, sampleInput, makefile, noRunIfLib, doxDocConfig,
  docIfEnabled)
import Language.Drasil.Code.Imperative.GOOL.Data (AuxData(..), ad,
  PackData(..), packD)
import Language.Drasil.Code.Imperative.Build.AST (BuildConfig, Runnable,
  asFragment, buildAll, cppCompiler, nativeBinary, executable, sharedLibrary)
import Language.Drasil.Code.Imperative.Doxygen.Import (no)

import GOOL.Drasil (onCodeList, cppName, cppVersion)

import Prelude hiding (break,print,(<>),sin,cos,tan,floor,const,log,exp)
import Text.PrettyPrint.HughesPJ (Doc)

-- | Holds a C++ project.
newtype CppProject a = CPPP {forall a. CppProject a -> a
unCPPP :: a}

instance Functor CppProject where
  fmap :: forall a b. (a -> b) -> CppProject a -> CppProject b
fmap a -> b
f (CPPP a
x) = forall a. a -> CppProject a
CPPP (a -> b
f a
x)

instance Applicative CppProject where
  pure :: forall a. a -> CppProject a
pure = forall a. a -> CppProject a
CPPP
  (CPPP a -> b
f) <*> :: forall a b. CppProject (a -> b) -> CppProject a -> CppProject b
<*> (CPPP a
x) = forall a. a -> CppProject a
CPPP (a -> b
f a
x)

instance Monad CppProject where
  CPPP a
x >>= :: forall a b. CppProject a -> (a -> CppProject b) -> CppProject b
>>= a -> CppProject b
f = a -> CppProject b
f a
x

instance PackageSym CppProject where
  type Package CppProject = PackData
  package :: ProgData
-> [CppProject (Auxiliary CppProject)]
-> CppProject (Package CppProject)
package ProgData
p = forall (m :: * -> *) a b. Monad m => ([a] -> b) -> [m a] -> m b
onCodeList (ProgData -> [AuxData] -> PackData
packD ProgData
p)

instance AuxiliarySym CppProject where
  type Auxiliary CppProject = AuxData
  type AuxHelper CppProject = Doc
  doxConfig :: String
-> GOOLState -> Verbosity -> CppProject (Auxiliary CppProject)
doxConfig = forall (r :: * -> *).
AuxiliarySym r =>
r (AuxHelper r)
-> String -> GOOLState -> Verbosity -> r (Auxiliary r)
G.doxConfig forall (r :: * -> *). AuxiliarySym r => r (AuxHelper r)
optimizeDox
  readMe :: ReadMeInfo -> CppProject (Auxiliary CppProject)
readMe ReadMeInfo
rmi =
    forall (r :: * -> *).
AuxiliarySym r =>
ReadMeInfo -> r (Auxiliary r)
G.readMe ReadMeInfo
rmi {
        langName :: String
langName = String
cppName,
        langVersion :: String
langVersion = String
cppVersion}
  sampleInput :: ChunkDB -> DataDesc -> [Expr] -> CppProject (Auxiliary CppProject)
sampleInput = forall (r :: * -> *).
AuxiliarySym r =>
ChunkDB -> DataDesc -> [Expr] -> r (Auxiliary r)
G.sampleInput

  optimizeDox :: CppProject (AuxHelper CppProject)
optimizeDox = forall (f :: * -> *) a. Applicative f => a -> f a
pure Doc
no

  makefile :: [String]
-> ImplementationType
-> [Comments]
-> GOOLState
-> ProgData
-> CppProject (Auxiliary CppProject)
makefile [String]
fs ImplementationType
it [Comments]
cms = forall (r :: * -> *).
AuxiliarySym r =>
Maybe BuildConfig
-> Maybe Runnable
-> Maybe DocConfig
-> GOOLState
-> ProgData
-> r (Auxiliary r)
G.makefile ([String] -> ImplementationType -> Maybe BuildConfig
cppBuildConfig [String]
fs ImplementationType
it) (ImplementationType -> Maybe Runnable -> Maybe Runnable
G.noRunIfLib ImplementationType
it Maybe Runnable
cppRunnable) ([Comments] -> DocConfig -> Maybe DocConfig
G.docIfEnabled [Comments]
cms DocConfig
G.doxDocConfig)

  auxHelperDoc :: CppProject (AuxHelper CppProject) -> Doc
auxHelperDoc = forall a. CppProject a -> a
unCPPP
  auxFromData :: String -> Doc -> CppProject (Auxiliary CppProject)
auxFromData String
fp Doc
d = forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ String -> Doc -> AuxData
ad String
fp Doc
d

-- helpers
-- | Create a build configuration for C++ files. Takes in 'FilePath's and the type of implementation.
cppBuildConfig :: [FilePath] -> ImplementationType -> Maybe BuildConfig
cppBuildConfig :: [String] -> ImplementationType -> Maybe BuildConfig
cppBuildConfig [String]
fs ImplementationType
it = ([CommandFragment] -> CommandFragment -> [[CommandFragment]])
-> BuildName -> Maybe BuildConfig
buildAll (\[CommandFragment]
i CommandFragment
o -> [CommandFragment
cppCompiler forall a. a -> [a] -> [a]
: [CommandFragment]
i forall a. [a] -> [a] -> [a]
++ forall a b. (a -> b) -> [a] -> [b]
map String -> CommandFragment
asFragment
  (String
"--std=c++11" forall a. a -> [a] -> [a]
: ImplementationType -> [String]
target ImplementationType
it forall a. [a] -> [a] -> [a]
++ [String
"-o"]) forall a. [a] -> [a] -> [a]
++ [CommandFragment
o] forall a. [a] -> [a] -> [a]
++ forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (\String
f -> forall a b. (a -> b) -> [a] -> [b]
map
  String -> CommandFragment
asFragment [String
"-I", String
f]) [String]
fs]) (ImplementationType -> BuildName
outName ImplementationType
it)
  where target :: ImplementationType -> [String]
target ImplementationType
Library = [String
"-shared", String
"-fPIC"]
        target ImplementationType
Program = []
        outName :: ImplementationType -> BuildName
outName ImplementationType
Library = BuildName
sharedLibrary
        outName ImplementationType
Program = BuildName
executable

-- | Default runnable information for C++ files.
cppRunnable :: Maybe Runnable
cppRunnable :: Maybe Runnable
cppRunnable = Maybe Runnable
nativeBinary