module Language.Drasil.Code.Imperative.GenerateGOOL (ClassType(..),
  genModuleWithImports, genModuleWithImportsProc, genModule, genModuleProc,
  genDoxConfig, genReadMe, primaryClass, auxClass, fApp, fAppProc, ctorCall,
  fAppInOut, fAppInOutProc
) where

import Data.Bifunctor (second)
import qualified Data.Map as Map (lookup)
import Data.Maybe (catMaybes)
import Control.Monad.State (get, modify)
import Control.Lens ((^.))

import Drasil.FileHandling (FileLayout)
import Drasil.GProc (ProcProg)
import qualified Drasil.GProc as Proc (FileSym(..), ModuleSym(..))
import Language.Drasil hiding (List)
import Language.Drasil.Code.Imperative.DrasilState (GenState, DrasilState(..),
  getDoxOutput, getSoftwareDossierFiles, HasChoices(..))
import Language.Drasil.SoftwareDossier.SoftwareDossierSym (SoftwareDossierSym(..),
  SoftwareDossierState)
import Language.Drasil.Code.Imperative.README.Core (ReadMeInfo(..))
import Language.Drasil.Choices (Comments(..), SoftwareDossierFile(..))
import Language.Drasil.Mod (Name, Description, Import)
import Drasil.Metadata (watermark)
import Drasil.System (HasSystemMeta(..))
import Drasil.SRS (HasSmithEtAlSRS(..))

import Drasil.GOOL (SVariable, SValue, Class, CSStateVar, NamedArgs, File,
  OOProg, CS, FS, MS, VS, TypeData, ValueSym(..), Argument(..),
  ValueExpression(..), OOValueExpression(..), SelfSym(..), VariableValue(..),
  FuncAppStatement(..), OOFuncAppStatement(..), ClassSym(..), CodeType(..),
  TypeElim(..), objMethodCallMixedArgs, OOStatement)
import qualified Drasil.GOOL as OO (FileSym(..), ModuleSym(..))

-- | Defines a GOOL module. If the user chose 'CommentMod', the module will have
-- Doxygen comments. If the user did not choose 'CommentMod' but did choose
-- 'CommentFunc', a module-level Doxygen comment is still created, though it only
-- documents the file name, because without this Doxygen will not find the
-- function-level comments in the file.
genModuleWithImports :: (OOProg r vis smt md svr att prg) => Name -> Description ->
  [Import] -> [GenState (Maybe (MS (r md)))] -> [GenState (Maybe (CS (r Class)))] ->
  GenState (FS (r File))
genModuleWithImports :: forall (r :: * -> *) vis smt md svr att prg.
OOProg r vis smt md svr att prg =>
Name
-> Name
-> [Name]
-> [GenState (Maybe (MS (r md)))]
-> [GenState (Maybe (CS (r Class)))]
-> GenState (FS (r File))
genModuleWithImports Name
n Name
desc [Name]
is [GenState (Maybe (MS (r md)))]
maybeMs [GenState (Maybe (CS (r Class)))]
maybeCs = do
  DrasilState
g <- StateT DrasilState Identity DrasilState
forall s (m :: * -> *). MonadState s m => m s
get
  (DrasilState -> DrasilState) -> StateT DrasilState Identity ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\DrasilState
s -> DrasilState
s { currentModule = n })
  let as :: [Name]
as = (Person -> Name) -> [Person] -> [Name]
forall a b. (a -> b) -> [a] -> [b]
map Person -> Name
forall n. HasName n => n -> Name
fullName (DrasilState
g DrasilState -> Getting [Person] DrasilState [Person] -> [Person]
forall s a. s -> Getting a s a -> a
^. Getting [Person] DrasilState [Person]
forall c. HasSystemMeta c => Lens' c [Person]
Lens' DrasilState [Person]
authors)
  [Maybe (CS (r Class))]
cs <- [GenState (Maybe (CS (r Class)))]
-> StateT DrasilState Identity [Maybe (CS (r Class))]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
forall (m :: * -> *) a. Monad m => [m a] -> m [a]
sequence [GenState (Maybe (CS (r Class)))]
maybeCs
  [Maybe (MS (r md))]
ms <- [GenState (Maybe (MS (r md)))]
-> StateT DrasilState Identity [Maybe (MS (r md))]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
forall (m :: * -> *) a. Monad m => [m a] -> m [a]
sequence [GenState (Maybe (MS (r md)))]
maybeMs
  let commMod :: FS (r File) -> FS (r File)
commMod | Comments
CommentMod Comments -> [Comments] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` DrasilState
g DrasilState
-> Getting [Comments] DrasilState [Comments] -> [Comments]
forall s a. s -> Getting a s a -> a
^. Getting [Comments] DrasilState [Comments]
forall a. HasChoices a => Lens' a [Comments]
Lens' DrasilState [Comments]
commented                   = Name -> Name -> [Name] -> Name -> FS (r File) -> FS (r File)
forall (r :: * -> *) vis smt md svr att.
FileSym r vis smt md svr att =>
Name -> Name -> [Name] -> Name -> FS (r File) -> FS (r File)
OO.docMod Name
desc Name
watermark [Name]
as (DrasilState
g DrasilState -> Getting Name DrasilState Name -> Name
forall s a. s -> Getting a s a -> a
^. Getting Name DrasilState Name
forall a. HasChoices a => Lens' a Name
Lens' DrasilState Name
date)
              | Comments
CommentFunc Comments -> [Comments] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` DrasilState
g DrasilState
-> Getting [Comments] DrasilState [Comments] -> [Comments]
forall s a. s -> Getting a s a -> a
^. Getting [Comments] DrasilState [Comments]
forall a. HasChoices a => Lens' a [Comments]
Lens' DrasilState [Comments]
commented Bool -> Bool -> Bool
&& Bool -> Bool
not ([Maybe (MS (r md))] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Maybe (MS (r md))]
ms) = Name -> Name -> [Name] -> Name -> FS (r File) -> FS (r File)
forall (r :: * -> *) vis smt md svr att.
FileSym r vis smt md svr att =>
Name -> Name -> [Name] -> Name -> FS (r File) -> FS (r File)
OO.docMod Name
"" Name
watermark [] Name
""
              | Bool
otherwise                                          = FS (r File) -> FS (r File)
forall a. a -> a
id
  FS (r File) -> GenState (FS (r File))
forall a. a -> StateT DrasilState Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return (FS (r File) -> GenState (FS (r File)))
-> FS (r File) -> GenState (FS (r File))
forall a b. (a -> b) -> a -> b
$ FS (r File) -> FS (r File)
commMod (FS (r File) -> FS (r File)) -> FS (r File) -> FS (r File)
forall a b. (a -> b) -> a -> b
$ FS (r Module) -> FS (r File)
forall (r :: * -> *) vis smt md svr att.
FileSym r vis smt md svr att =>
FS (r Module) -> FS (r File)
OO.fileDoc (FS (r Module) -> FS (r File)) -> FS (r Module) -> FS (r File)
forall a b. (a -> b) -> a -> b
$ Name -> [Name] -> [MS (r md)] -> [CS (r Class)] -> FS (r Module)
forall (r :: * -> *) vis smt md svr att.
ModuleSym r vis smt md svr att =>
Name -> [Name] -> [MS (r md)] -> [CS (r Class)] -> FS (r Module)
OO.buildModule Name
n [Name]
is ([Maybe (MS (r md))] -> [MS (r md)]
forall a. [Maybe a] -> [a]
catMaybes [Maybe (MS (r md))]
ms) ([Maybe (CS (r Class))] -> [CS (r Class)]
forall a. [Maybe a] -> [a]
catMaybes [Maybe (CS (r Class))]
cs)

-- | Generates a module for when imports do not need to be explicitly stated.
genModule :: (OOProg r vis smt md svr att prg) => Name -> Description ->
  [GenState (Maybe (MS (r md)))] -> [GenState (Maybe (CS (r Class)))] ->
  GenState (FS (r File))
genModule :: forall (r :: * -> *) vis smt md svr att prg.
OOProg r vis smt md svr att prg =>
Name
-> Name
-> [GenState (Maybe (MS (r md)))]
-> [GenState (Maybe (CS (r Class)))]
-> GenState (FS (r File))
genModule Name
n Name
desc = Name
-> Name
-> [Name]
-> [GenState (Maybe (MS (r md)))]
-> [GenState (Maybe (CS (r Class)))]
-> GenState (FS (r File))
forall (r :: * -> *) vis smt md svr att prg.
OOProg r vis smt md svr att prg =>
Name
-> Name
-> [Name]
-> [GenState (Maybe (MS (r md)))]
-> [GenState (Maybe (CS (r Class)))]
-> GenState (FS (r File))
genModuleWithImports Name
n Name
desc []

-- | Generates a Doxygen configuration file if the user has comments enabled.
genDoxConfig :: (SoftwareDossierSym r) => SoftwareDossierState ->
  GenState (Maybe (r FileLayout))
genDoxConfig :: forall (r :: * -> *).
SoftwareDossierSym r =>
SoftwareDossierState -> GenState (Maybe (r FileLayout))
genDoxConfig SoftwareDossierState
s = do
  DrasilState
g <- StateT DrasilState Identity DrasilState
forall s (m :: * -> *). MonadState s m => m s
get
  let n :: Name
n = DrasilState
g DrasilState -> Getting Name DrasilState Name -> Name
forall s a. s -> Getting a s a -> a
^. Getting Name DrasilState Name
forall c. HasSmithEtAlSRS c => Lens' c Name
Lens' DrasilState Name
programName
      cms :: [Comments]
cms = DrasilState
g DrasilState
-> Getting [Comments] DrasilState [Comments] -> [Comments]
forall s a. s -> Getting a s a -> a
^. Getting [Comments] DrasilState [Comments]
forall a. HasChoices a => Lens' a [Comments]
Lens' DrasilState [Comments]
commented
      v :: Verbosity
v = DrasilState -> Verbosity
getDoxOutput DrasilState
g
  Maybe (r FileLayout) -> GenState (Maybe (r FileLayout))
forall a. a -> StateT DrasilState Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (r FileLayout) -> GenState (Maybe (r FileLayout)))
-> Maybe (r FileLayout) -> GenState (Maybe (r FileLayout))
forall a b. (a -> b) -> a -> b
$ if Bool -> Bool
not ([Comments] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Comments]
cms) then Name -> SoftwareDossierState -> Verbosity -> Maybe (r FileLayout)
forall (r :: * -> *).
SoftwareDossierSym r =>
Name -> SoftwareDossierState -> Verbosity -> Maybe (r FileLayout)
doxConfig Name
n SoftwareDossierState
s Verbosity
v else Maybe (r FileLayout)
forall a. Maybe a
Nothing

-- | Generates a README file.
genReadMe :: (SoftwareDossierSym r) => ReadMeInfo -> GenState (Maybe (r FileLayout))
genReadMe :: forall (r :: * -> *).
SoftwareDossierSym r =>
ReadMeInfo -> GenState (Maybe (r FileLayout))
genReadMe ReadMeInfo
rmi = do
  DrasilState
g <- StateT DrasilState Identity DrasilState
forall s (m :: * -> *). MonadState s m => m s
get
  let n :: Name
n = DrasilState
g DrasilState -> Getting Name DrasilState Name -> Name
forall s a. s -> Getting a s a -> a
^. Getting Name DrasilState Name
forall c. HasSmithEtAlSRS c => Lens' c Name
Lens' DrasilState Name
programName
  Maybe (r FileLayout) -> GenState (Maybe (r FileLayout))
forall a. a -> StateT DrasilState Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (r FileLayout) -> GenState (Maybe (r FileLayout)))
-> Maybe (r FileLayout) -> GenState (Maybe (r FileLayout))
forall a b. (a -> b) -> a -> b
$ [SoftwareDossierFile] -> ReadMeInfo -> Maybe (r FileLayout)
forall (r :: * -> *).
SoftwareDossierSym r =>
[SoftwareDossierFile] -> ReadMeInfo -> Maybe (r FileLayout)
getReadMe (DrasilState -> [SoftwareDossierFile]
getSoftwareDossierFiles DrasilState
g) ReadMeInfo
rmi {caseName = n}

-- | Helper for generating a README file.
getReadMe :: (SoftwareDossierSym r) => [SoftwareDossierFile] -> ReadMeInfo -> Maybe (r FileLayout)
getReadMe :: forall (r :: * -> *).
SoftwareDossierSym r =>
[SoftwareDossierFile] -> ReadMeInfo -> Maybe (r FileLayout)
getReadMe [SoftwareDossierFile]
auxl ReadMeInfo
rmi = if SoftwareDossierFile
ReadME SoftwareDossierFile -> [SoftwareDossierFile] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [SoftwareDossierFile]
auxl then r FileLayout -> Maybe (r FileLayout)
forall a. a -> Maybe a
Just (ReadMeInfo -> r FileLayout
forall (r :: * -> *).
SoftwareDossierSym r =>
ReadMeInfo -> r FileLayout
readMe ReadMeInfo
rmi) else Maybe (r FileLayout)
forall a. Maybe a
Nothing

data ClassType = Primary | Auxiliary

-- | Generates a primary or auxiliary class with the given name, description,
-- state variables, and methods. The 'Maybe' 'Name' parameter is the name of the
-- interface the class implements, if applicable.
mkClass :: (ClassSym r vis smt md svr att) => ClassType -> Name -> Maybe Name ->
  Description -> [CSStateVar r svr] -> GenState [MS (r md)] ->
    GenState [MS (r md)] -> GenState (CS (r Class))
mkClass :: forall (r :: * -> *) vis smt md svr att.
ClassSym r vis smt md svr att =>
ClassType
-> Name
-> Maybe Name
-> Name
-> [CSStateVar r svr]
-> GenState [MS (r md)]
-> GenState [MS (r md)]
-> GenState (CS (r Class))
mkClass ClassType
s Name
n Maybe Name
l Name
desc [CSStateVar r svr]
vs GenState [MS (r md)]
cstrs GenState [MS (r md)]
mths = do
  DrasilState
g <- StateT DrasilState Identity DrasilState
forall s (m :: * -> *). MonadState s m => m s
get
  (DrasilState -> DrasilState) -> StateT DrasilState Identity ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\DrasilState
ds -> DrasilState
ds {currentClass = n})
  [MS (r md)]
cs <- GenState [MS (r md)]
cstrs
  [MS (r md)]
ms <- GenState [MS (r md)]
mths
  (DrasilState -> DrasilState) -> StateT DrasilState Identity ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\DrasilState
ds -> DrasilState
ds {currentClass = ""})
  let getFunc :: ClassType
-> [CSStateVar r svr] -> [MS (r md)] -> [MS (r md)] -> CS (r Class)
getFunc ClassType
Primary = Maybe Name
-> [CSStateVar r svr] -> [MS (r md)] -> [MS (r md)] -> CS (r Class)
forall {r :: * -> *} {vis} {smt} {md} {att} {svr}.
ClassSym r vis smt md svr att =>
Maybe Name
-> [CSStateVar r svr] -> [MS (r md)] -> [MS (r md)] -> CS (r Class)
getFunc' Maybe Name
l
      getFunc ClassType
Auxiliary = Name
-> Maybe Name
-> [CSStateVar r svr]
-> [MS (r md)]
-> [MS (r md)]
-> CS (r Class)
forall (r :: * -> *) vis smt md svr att.
ClassSym r vis smt md svr att =>
Name
-> Maybe Name
-> [CSStateVar r svr]
-> [MS (r md)]
-> [MS (r md)]
-> CS (r Class)
extraClass Name
n Maybe Name
forall a. Maybe a
Nothing
      getFunc' :: Maybe Name
-> [CSStateVar r svr] -> [MS (r md)] -> [MS (r md)] -> CS (r Class)
getFunc' Maybe Name
Nothing = Maybe Name
-> [CSStateVar r svr] -> [MS (r md)] -> [MS (r md)] -> CS (r Class)
forall (r :: * -> *) vis smt md svr att.
ClassSym r vis smt md svr att =>
Maybe Name
-> [CSStateVar r svr] -> [MS (r md)] -> [MS (r md)] -> CS (r Class)
buildClass Maybe Name
forall a. Maybe a
Nothing
      getFunc' (Just Name
intfc) = Name
-> [Name]
-> [CSStateVar r svr]
-> [MS (r md)]
-> [MS (r md)]
-> CS (r Class)
forall (r :: * -> *) vis smt md svr att.
ClassSym r vis smt md svr att =>
Name
-> [Name]
-> [CSStateVar r svr]
-> [MS (r md)]
-> [MS (r md)]
-> CS (r Class)
implementingClass Name
n [Name
intfc]
      c :: CS (r Class)
c = ClassType
-> [CSStateVar r svr] -> [MS (r md)] -> [MS (r md)] -> CS (r Class)
forall {r :: * -> *} {vis} {smt} {md} {att} {svr}.
ClassSym r vis smt md svr att =>
ClassType
-> [CSStateVar r svr] -> [MS (r md)] -> [MS (r md)] -> CS (r Class)
getFunc ClassType
s [CSStateVar r svr]
vs [MS (r md)]
cs [MS (r md)]
ms
  CS (r Class) -> GenState (CS (r Class))
forall a. a -> StateT DrasilState Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return (CS (r Class) -> GenState (CS (r Class)))
-> CS (r Class) -> GenState (CS (r Class))
forall a b. (a -> b) -> a -> b
$ if Comments
CommentClass Comments -> [Comments] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` DrasilState
g DrasilState
-> Getting [Comments] DrasilState [Comments] -> [Comments]
forall s a. s -> Getting a s a -> a
^. Getting [Comments] DrasilState [Comments]
forall a. HasChoices a => Lens' a [Comments]
Lens' DrasilState [Comments]
commented
    then Name -> CS (r Class) -> CS (r Class)
forall (r :: * -> *) vis smt md svr att.
ClassSym r vis smt md svr att =>
Name -> CS (r Class) -> CS (r Class)
docClass Name
desc CS (r Class)
c
    else CS (r Class)
c

-- | Generates a primary class.
primaryClass :: (ClassSym r vis smt md svr att) => Name -> Maybe Name -> Description ->
  [CSStateVar r svr] -> GenState [MS (r md)] -> GenState [MS (r md)] ->
  GenState (CS (r Class))
primaryClass :: forall (r :: * -> *) vis smt md svr att.
ClassSym r vis smt md svr att =>
Name
-> Maybe Name
-> Name
-> [CSStateVar r svr]
-> GenState [MS (r md)]
-> GenState [MS (r md)]
-> GenState (CS (r Class))
primaryClass = ClassType
-> Name
-> Maybe Name
-> Name
-> [CSStateVar r svr]
-> GenState [MS (r md)]
-> GenState [MS (r md)]
-> GenState (CS (r Class))
forall (r :: * -> *) vis smt md svr att.
ClassSym r vis smt md svr att =>
ClassType
-> Name
-> Maybe Name
-> Name
-> [CSStateVar r svr]
-> GenState [MS (r md)]
-> GenState [MS (r md)]
-> GenState (CS (r Class))
mkClass ClassType
Primary

-- | Generates an auxiliary class (for when a module contains multiple classes).
auxClass :: (ClassSym r vis smt md svr att) => Name -> Maybe Name -> Description ->
  [CSStateVar r svr] -> GenState [MS (r md)] -> GenState [MS (r md)] ->
  GenState (CS (r Class))
auxClass :: forall (r :: * -> *) vis smt md svr att.
ClassSym r vis smt md svr att =>
Name
-> Maybe Name
-> Name
-> [CSStateVar r svr]
-> GenState [MS (r md)]
-> GenState [MS (r md)]
-> GenState (CS (r Class))
auxClass = ClassType
-> Name
-> Maybe Name
-> Name
-> [CSStateVar r svr]
-> GenState [MS (r md)]
-> GenState [MS (r md)]
-> GenState (CS (r Class))
forall (r :: * -> *) vis smt md svr att.
ClassSym r vis smt md svr att =>
ClassType
-> Name
-> Maybe Name
-> Name
-> [CSStateVar r svr]
-> GenState [MS (r md)]
-> GenState [MS (r md)]
-> GenState (CS (r Class))
mkClass ClassType
Auxiliary

-- | Converts lists or objects to pointer arguments, since we use pointerParam
-- for list or object-type parameters.
mkArg :: (Argument r, TypeElim r) => SValue r -> SValue r
mkArg :: forall (r :: * -> *).
(Argument r, TypeElim r) =>
SValue r -> SValue r
mkArg SValue r
v = do
  r Value
vl <- SValue r
v
  let mkArg' :: CodeType -> SValue r -> SValue r
mkArg' (List CodeType
_) = SValue r -> SValue r
forall (r :: * -> *). Argument r => SValue r -> SValue r
pointerArg
      mkArg' (Object Name
_) = SValue r -> SValue r
forall (r :: * -> *). Argument r => SValue r -> SValue r
pointerArg
      mkArg' CodeType
_ = SValue r -> SValue r
forall a. a -> a
id
  CodeType -> SValue r -> SValue r
forall {r :: * -> *}.
Argument r =>
CodeType -> SValue r -> SValue r
mkArg' (r TypeData -> CodeType
forall (r :: * -> *). TypeElim r => r TypeData -> CodeType
getCodeType (r TypeData -> CodeType) -> r TypeData -> CodeType
forall a b. (a -> b) -> a -> b
$ r Value -> r TypeData
forall (r :: * -> *). ValueSym r => r Value -> r TypeData
valueType r Value
vl) (r Value -> SValue r
forall a. a -> StateT ValueState Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return r Value
vl)

-- | Gets the current module and calls mkArg on the arguments.
-- Called by more specific function call generators ('fApp' and 'ctorCall').
fCall :: (Argument r, TypeElim r) => (Name -> [SValue r] -> NamedArgs r ->
  SValue r) -> [SValue r] -> NamedArgs r -> GenState (SValue r)
fCall :: forall (r :: * -> *).
(Argument r, TypeElim r) =>
(Name -> [SValue r] -> NamedArgs r -> SValue r)
-> [SValue r] -> NamedArgs r -> GenState (SValue r)
fCall Name -> [SValue r] -> NamedArgs r -> SValue r
f [SValue r]
vl NamedArgs r
ns = do
  DrasilState
g <- StateT DrasilState Identity DrasilState
forall s (m :: * -> *). MonadState s m => m s
get
  let cm :: Name
cm = DrasilState -> Name
currentModule DrasilState
g
      args :: [SValue r]
args = (SValue r -> SValue r) -> [SValue r] -> [SValue r]
forall a b. (a -> b) -> [a] -> [b]
map SValue r -> SValue r
forall (r :: * -> *).
(Argument r, TypeElim r) =>
SValue r -> SValue r
mkArg [SValue r]
vl
      nargs :: NamedArgs r
nargs = ((SVariable r, SValue r) -> (SVariable r, SValue r))
-> NamedArgs r -> NamedArgs r
forall a b. (a -> b) -> [a] -> [b]
map ((SValue r -> SValue r)
-> (SVariable r, SValue r) -> (SVariable r, SValue r)
forall b c a. (b -> c) -> (a, b) -> (a, c)
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second SValue r -> SValue r
forall (r :: * -> *).
(Argument r, TypeElim r) =>
SValue r -> SValue r
mkArg) NamedArgs r
ns
  SValue r -> GenState (SValue r)
forall a. a -> StateT DrasilState Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return (SValue r -> GenState (SValue r))
-> SValue r -> GenState (SValue r)
forall a b. (a -> b) -> a -> b
$ Name -> [SValue r] -> NamedArgs r -> SValue r
f Name
cm [SValue r]
args NamedArgs r
nargs

-- | Function call generator.
-- The first parameter (@m@) is the module where the function is defined.
-- If @m@ is not the current module, use GOOL's function for calling functions from
--   external modules.
-- If @m@ is the current module and the function is in export map, use GOOL's basic
--   function for function applications.
-- If @m@ is the current module and function is not exported, use GOOL's function for
--   calling a method on self. This assumes all private methods are dynamic,
--   which is true for this generator.
fApp
  :: (OOStatement r smt, TypeElim r)
  => Name -> Name -> VS (r TypeData) -> [SValue r] -> NamedArgs r -> GenState (SValue r)
fApp :: forall (r :: * -> *) smt.
(OOStatement r smt, TypeElim r) =>
Name
-> Name
-> VS (r TypeData)
-> [SValue r]
-> NamedArgs r
-> GenState (SValue r)
fApp Name
m Name
s VS (r TypeData)
t [SValue r]
vl NamedArgs r
ns = do
  DrasilState
g <- StateT DrasilState Identity DrasilState
forall s (m :: * -> *). MonadState s m => m s
get
  (Name -> [SValue r] -> NamedArgs r -> SValue r)
-> [SValue r] -> NamedArgs r -> GenState (SValue r)
forall (r :: * -> *).
(Argument r, TypeElim r) =>
(Name -> [SValue r] -> NamedArgs r -> SValue r)
-> [SValue r] -> NamedArgs r -> GenState (SValue r)
fCall (\Name
cm [SValue r]
args NamedArgs r
nargs ->
    if Name
m Name -> Name -> Bool
forall a. Eq a => a -> a -> Bool
/= Name
cm then Name -> MixedCall r
forall (r :: * -> *). ValueExpression r => Name -> MixedCall r
extFuncAppMixedArgs Name
m Name
s VS (r TypeData)
t [SValue r]
args NamedArgs r
nargs else
      if Name -> Map Name Name -> Maybe Name
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Name
s (DrasilState -> Map Name Name
eMap DrasilState
g) Maybe Name -> Maybe Name -> Bool
forall a. Eq a => a -> a -> Bool
== Name -> Maybe Name
forall a. a -> Maybe a
Just Name
cm then MixedCall r
forall (r :: * -> *). ValueExpression r => MixedCall r
funcAppMixedArgs Name
s VS (r TypeData)
t [SValue r]
args NamedArgs r
nargs
      else VS (r TypeData)
-> SValue r -> Name -> [SValue r] -> NamedArgs r -> SValue r
forall (r :: * -> *).
InternalValueExp r =>
VS (r TypeData)
-> SValue r -> Name -> [SValue r] -> NamedArgs r -> SValue r
objMethodCallMixedArgs VS (r TypeData)
t (SVariable r -> SValue r
forall (r :: * -> *). VariableValue r => SVariable r -> SValue r
valueOf SVariable r
forall (r :: * -> *). SelfSym r => SVariable r
self) Name
s [SValue r]
args NamedArgs r
nargs) [SValue r]
vl NamedArgs r
ns

-- | Logic similar to 'fApp', but the self case is not required here
-- (because constructor will never be private). Calls 'newObjMixedArgs'.
ctorCall
  :: (OOStatement r smt, TypeElim r)
  => Name -> VS (r TypeData) -> [SValue r] -> NamedArgs r -> GenState (SValue r)
ctorCall :: forall (r :: * -> *) smt.
(OOStatement r smt, TypeElim r) =>
Name
-> VS (r TypeData)
-> [SValue r]
-> NamedArgs r
-> GenState (SValue r)
ctorCall Name
m VS (r TypeData)
t = (Name -> [SValue r] -> NamedArgs r -> SValue r)
-> [SValue r] -> NamedArgs r -> GenState (SValue r)
forall (r :: * -> *).
(Argument r, TypeElim r) =>
(Name -> [SValue r] -> NamedArgs r -> SValue r)
-> [SValue r] -> NamedArgs r -> GenState (SValue r)
fCall (\Name
cm [SValue r]
args NamedArgs r
nargs -> if Name
m Name -> Name -> Bool
forall a. Eq a => a -> a -> Bool
/= Name
cm then
  Name -> MixedCtorCall r
forall (r :: * -> *).
OOValueExpression r =>
Name -> MixedCtorCall r
extNewObjMixedArgs Name
m VS (r TypeData)
t [SValue r]
args NamedArgs r
nargs else MixedCtorCall r
forall (r :: * -> *). OOValueExpression r => MixedCtorCall r
newObjMixedArgs VS (r TypeData)
t [SValue r]
args NamedArgs r
nargs)

-- | Logic similar to 'fApp', but for In/Out calls.
fAppInOut :: (OOFuncAppStatement r smt) => Name -> Name -> [SValue r] ->
  [SVariable r] -> [SVariable r] -> GenState (MS (r smt))
fAppInOut :: forall (r :: * -> *) smt.
OOFuncAppStatement r smt =>
Name
-> Name
-> [SValue r]
-> [SVariable r]
-> [SVariable r]
-> GenState (MS (r smt))
fAppInOut Name
m Name
n [SValue r]
ins [SVariable r]
outs [SVariable r]
both = do
  DrasilState
g <- StateT DrasilState Identity DrasilState
forall s (m :: * -> *). MonadState s m => m s
get
  let cm :: Name
cm = DrasilState -> Name
currentModule DrasilState
g
  MS (r smt) -> GenState (MS (r smt))
forall a. a -> StateT DrasilState Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return (MS (r smt) -> GenState (MS (r smt)))
-> MS (r smt) -> GenState (MS (r smt))
forall a b. (a -> b) -> a -> b
$ if Name
m Name -> Name -> Bool
forall a. Eq a => a -> a -> Bool
/= Name
cm then Name -> InOutCall r smt
forall (r :: * -> *) smt.
FuncAppStatement r smt =>
Name -> InOutCall r smt
extInOutCall Name
m Name
n [SValue r]
ins [SVariable r]
outs [SVariable r]
both else if Name -> Map Name Name -> Maybe Name
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Name
n
    (DrasilState -> Map Name Name
eMap DrasilState
g) Maybe Name -> Maybe Name -> Bool
forall a. Eq a => a -> a -> Bool
== Name -> Maybe Name
forall a. a -> Maybe a
Just Name
cm then InOutCall r smt
forall (r :: * -> *) smt. FuncAppStatement r smt => InOutCall r smt
inOutCall Name
n [SValue r]
ins [SVariable r]
outs [SVariable r]
both else
    InOutCall r smt
forall (r :: * -> *) smt.
OOFuncAppStatement r smt =>
InOutCall r smt
selfInOutCall Name
n [SValue r]
ins [SVariable r]
outs [SVariable r]
both

-- Procedural Versions --

-- | Defines a GOOL module. If the user chose 'CommentMod', the module will have
-- Doxygen comments. If the user did not choose 'CommentMod' but did choose
-- 'CommentFunc', a module-level Doxygen comment is still created, though it only
-- documents the file name, because without this Doxygen will not find the
-- function-level comments in the file.
genModuleWithImportsProc :: (ProcProg r vis smt md prg) => Name -> Description ->
  [Import] -> [GenState (Maybe (MS (r md)))] -> GenState (FS (r File))
genModuleWithImportsProc :: forall (r :: * -> *) vis smt md prg.
ProcProg r vis smt md prg =>
Name
-> Name
-> [Name]
-> [GenState (Maybe (MS (r md)))]
-> GenState (FS (r File))
genModuleWithImportsProc Name
n Name
desc [Name]
is [GenState (Maybe (MS (r md)))]
maybeMs = do
  DrasilState
g <- StateT DrasilState Identity DrasilState
forall s (m :: * -> *). MonadState s m => m s
get
  (DrasilState -> DrasilState) -> StateT DrasilState Identity ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\DrasilState
s -> DrasilState
s { currentModule = n })
  let as :: [Name]
as = (Person -> Name) -> [Person] -> [Name]
forall a b. (a -> b) -> [a] -> [b]
map Person -> Name
forall n. HasName n => n -> Name
fullName (DrasilState
g DrasilState -> Getting [Person] DrasilState [Person] -> [Person]
forall s a. s -> Getting a s a -> a
^. Getting [Person] DrasilState [Person]
forall c. HasSystemMeta c => Lens' c [Person]
Lens' DrasilState [Person]
authors)
  [Maybe (MS (r md))]
ms <- [GenState (Maybe (MS (r md)))]
-> StateT DrasilState Identity [Maybe (MS (r md))]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
forall (m :: * -> *) a. Monad m => [m a] -> m [a]
sequence [GenState (Maybe (MS (r md)))]
maybeMs
  let commMod :: FS (r File) -> FS (r File)
commMod | Comments
CommentMod Comments -> [Comments] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` DrasilState
g DrasilState
-> Getting [Comments] DrasilState [Comments] -> [Comments]
forall s a. s -> Getting a s a -> a
^. Getting [Comments] DrasilState [Comments]
forall a. HasChoices a => Lens' a [Comments]
Lens' DrasilState [Comments]
commented                   = Name -> Name -> [Name] -> Name -> FS (r File) -> FS (r File)
forall (r :: * -> *) vis smt md.
FileSym r vis smt md =>
Name -> Name -> [Name] -> Name -> FS (r File) -> FS (r File)
Proc.docMod Name
desc Name
watermark [Name]
as (DrasilState
g DrasilState -> Getting Name DrasilState Name -> Name
forall s a. s -> Getting a s a -> a
^. Getting Name DrasilState Name
forall a. HasChoices a => Lens' a Name
Lens' DrasilState Name
date)
              | Comments
CommentFunc Comments -> [Comments] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` DrasilState
g DrasilState
-> Getting [Comments] DrasilState [Comments] -> [Comments]
forall s a. s -> Getting a s a -> a
^. Getting [Comments] DrasilState [Comments]
forall a. HasChoices a => Lens' a [Comments]
Lens' DrasilState [Comments]
commented Bool -> Bool -> Bool
&& Bool -> Bool
not ([Maybe (MS (r md))] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Maybe (MS (r md))]
ms) = Name -> Name -> [Name] -> Name -> FS (r File) -> FS (r File)
forall (r :: * -> *) vis smt md.
FileSym r vis smt md =>
Name -> Name -> [Name] -> Name -> FS (r File) -> FS (r File)
Proc.docMod Name
"" Name
watermark [] Name
""
              | Bool
otherwise                                          = FS (r File) -> FS (r File)
forall a. a -> a
id
  FS (r File) -> GenState (FS (r File))
forall a. a -> StateT DrasilState Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return (FS (r File) -> GenState (FS (r File)))
-> FS (r File) -> GenState (FS (r File))
forall a b. (a -> b) -> a -> b
$ FS (r File) -> FS (r File)
commMod (FS (r File) -> FS (r File)) -> FS (r File) -> FS (r File)
forall a b. (a -> b) -> a -> b
$ FS (r Module) -> FS (r File)
forall (r :: * -> *) vis smt md.
FileSym r vis smt md =>
FS (r Module) -> FS (r File)
Proc.fileDoc (FS (r Module) -> FS (r File)) -> FS (r Module) -> FS (r File)
forall a b. (a -> b) -> a -> b
$ Name -> [Name] -> [MS (r md)] -> FS (r Module)
forall (r :: * -> *) vis smt md.
ModuleSym r vis smt md =>
Name -> [Name] -> [MS (r md)] -> FS (r Module)
Proc.buildModule Name
n [Name]
is ([Maybe (MS (r md))] -> [MS (r md)]
forall a. [Maybe a] -> [a]
catMaybes [Maybe (MS (r md))]
ms)

-- | Generates a module for when imports do not need to be explicitly stated.
genModuleProc :: (ProcProg r vis smt md prg) => Name -> Description ->
  [GenState (Maybe (MS (r md)))] -> GenState (FS (r File))
genModuleProc :: forall (r :: * -> *) vis smt md prg.
ProcProg r vis smt md prg =>
Name
-> Name -> [GenState (Maybe (MS (r md)))] -> GenState (FS (r File))
genModuleProc Name
n Name
desc = Name
-> Name
-> [Name]
-> [GenState (Maybe (MS (r md)))]
-> GenState (FS (r File))
forall (r :: * -> *) vis smt md prg.
ProcProg r vis smt md prg =>
Name
-> Name
-> [Name]
-> [GenState (Maybe (MS (r md)))]
-> GenState (FS (r File))
genModuleWithImportsProc Name
n Name
desc []

-- | Function call generator.
-- The first parameter (@m@) is the module where the function is defined.
-- If @m@ is not the current module, use GOOL's function for calling functions from
--   external modules.
-- If @m@ is the current module and the function is in export map, use GOOL's basic
--   function for function applications.
-- If @m@ is the current module and function is not exported, use GOOL's function for
--   calling a method on self. This assumes all private methods are dynamic,
--   which is true for this generator.
fAppProc
  :: (Argument r, TypeElim r, ValueExpression r) => Name
  -> Name
  -> VS (r TypeData)
  -> [SValue r]
  -> NamedArgs r
  -> GenState (SValue r)
fAppProc :: forall (r :: * -> *).
(Argument r, TypeElim r, ValueExpression r) =>
Name
-> Name
-> VS (r TypeData)
-> [SValue r]
-> NamedArgs r
-> GenState (SValue r)
fAppProc Name
m Name
s VS (r TypeData)
t [SValue r]
vl NamedArgs r
ns = do
  DrasilState
g <- StateT DrasilState Identity DrasilState
forall s (m :: * -> *). MonadState s m => m s
get
  (Name -> [SValue r] -> NamedArgs r -> SValue r)
-> [SValue r] -> NamedArgs r -> GenState (SValue r)
forall (r :: * -> *).
(Argument r, TypeElim r) =>
(Name -> [SValue r] -> NamedArgs r -> SValue r)
-> [SValue r] -> NamedArgs r -> GenState (SValue r)
fCall (\Name
cm [SValue r]
args NamedArgs r
nargs ->
    if Name
m Name -> Name -> Bool
forall a. Eq a => a -> a -> Bool
/= Name
cm then Name -> MixedCall r
forall (r :: * -> *). ValueExpression r => Name -> MixedCall r
extFuncAppMixedArgs Name
m Name
s VS (r TypeData)
t [SValue r]
args NamedArgs r
nargs else
      if Name -> Map Name Name -> Maybe Name
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Name
s (DrasilState -> Map Name Name
eMap DrasilState
g) Maybe Name -> Maybe Name -> Bool
forall a. Eq a => a -> a -> Bool
== Name -> Maybe Name
forall a. a -> Maybe a
Just Name
cm then MixedCall r
forall (r :: * -> *). ValueExpression r => MixedCall r
funcAppMixedArgs Name
s VS (r TypeData)
t [SValue r]
args NamedArgs r
nargs
      else Name -> SValue r
forall a. HasCallStack => Name -> a
error Name
"fAppProc: Procedural languages do not support method calls.") [SValue r]
vl NamedArgs r
ns

-- | Logic similar to 'fApp', but for In/Out calls.
fAppInOutProc :: (FuncAppStatement r smt) => Name -> Name -> [SValue r] ->
  [SVariable r] -> [SVariable r] -> GenState (MS (r smt))
fAppInOutProc :: forall (r :: * -> *) smt.
FuncAppStatement r smt =>
Name
-> Name
-> [SValue r]
-> [SVariable r]
-> [SVariable r]
-> GenState (MS (r smt))
fAppInOutProc Name
m Name
n [SValue r]
ins [SVariable r]
outs [SVariable r]
both = do
  DrasilState
g <- StateT DrasilState Identity DrasilState
forall s (m :: * -> *). MonadState s m => m s
get
  let cm :: Name
cm = DrasilState -> Name
currentModule DrasilState
g
  MS (r smt) -> GenState (MS (r smt))
forall a. a -> StateT DrasilState Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return (MS (r smt) -> GenState (MS (r smt)))
-> MS (r smt) -> GenState (MS (r smt))
forall a b. (a -> b) -> a -> b
$ if Name
m Name -> Name -> Bool
forall a. Eq a => a -> a -> Bool
/= Name
cm then Name -> InOutCall r smt
forall (r :: * -> *) smt.
FuncAppStatement r smt =>
Name -> InOutCall r smt
extInOutCall Name
m Name
n [SValue r]
ins [SVariable r]
outs [SVariable r]
both else if Name -> Map Name Name -> Maybe Name
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Name
n
    (DrasilState -> Map Name Name
eMap DrasilState
g) Maybe Name -> Maybe Name -> Bool
forall a. Eq a => a -> a -> Bool
== Name -> Maybe Name
forall a. a -> Maybe a
Just Name
cm then InOutCall r smt
forall (r :: * -> *) smt. FuncAppStatement r smt => InOutCall r smt
inOutCall Name
n [SValue r]
ins [SVariable r]
outs [SVariable r]
both
    else Name -> MS (r smt)
forall a. HasCallStack => Name -> a
error Name
"fAppInOutProc: Procedural languages do not support method calls."