module Language.Drasil.Code.Imperative.FunctionCalls (
  genAllInputCalls, genAllInputCallsProc, genInputCall, genInputCallProc,
  genDerivedCall, genDerivedCallProc, genConstraintCall, genConstraintCallProc,
  genCalcCall, genCalcCallProc, genOutputCall, genOutputCallProc
) where

import Data.List ((\\), intersect)
import qualified Data.Map as Map (lookup)
import Data.Maybe (catMaybes)
import Control.Applicative ((<|>))
import Control.Monad.State (get)

import Drasil.Code.CodeVar (CodeIdea(codeName), CodeVarChunk, quantvar)
import Language.Drasil.Code.Imperative.GenerateGOOL (fApp, fAppProc, fAppInOut,
  fAppInOutProc)
import Language.Drasil.Code.Imperative.Helpers (convScope)
import Language.Drasil.Code.Imperative.Import (codeType, mkVal, mkValProc,
  mkVar, mkVarProc)
import Language.Drasil.Code.Imperative.Parameters (getCalcParams,
  getConstraintParams, getDerivedIns, getDerivedOuts, getInputFormatIns,
  getInputFormatOuts, getOutputParams)
import Language.Drasil.Code.Imperative.DrasilState (GenState, DrasilState(..),
  genICName)
import Language.Drasil.Chunk.CodeDefinition (CodeDefinition)
import Language.Drasil.Mod (Name)
import Language.Drasil.Choices (InternalConcept(..))

import Drasil.GOOL (MS, VS, TypeSym(..), OOTypeSym, ScopeSym, ValueSym,
  OOVariableSym, VariableValue(..), ValueStatement(valStmt), DeclStatement(..),
  convType, convTypeOO, FuncAppStatement, TypeElim, VariableSym,
  VariableElim, Argument, Set, ValueExpression, Comparison, BooleanExpression,
  MathConstant, List, SelfSym, OOFuncAppStatement, InternalValueExp, Literal,
  OOValueExpression)
import Drasil.GProc (NativeVector, Reference, NumericExpression)

-- | Generates calls to all of the input-related functions. First is the call to
-- the function for reading inputs, then the function for calculating derived
-- inputs, then the function for checking input constraints.
genAllInputCalls
  ::
    ( ValueSym r val typ
    , Argument r val
    , Literal r val typ
    , MathConstant r val
    , TypeSym r typ
    , OOTypeSym r typ
    , VariableSym r var typ
    , OOVariableSym r var val typ
    , VariableValue r var val
    , BooleanExpression r val
    , Comparison r val
    , NumericExpression r val
    , ValueExpression r var val binder typ
    , SelfSym r var
    , InternalValueExp r var val typ
    , OOValueExpression r var val typ
    , List r val
    , Reference r val
    , Set r val
    , ValueStatement r stmt val
    , FuncAppStatement r stmt var val
    , OOFuncAppStatement r stmt var val
    , TypeElim r typ
    , VariableElim r var typ
    )
  => GenState [MS (r stmt)]
genAllInputCalls :: forall {k} (r :: k -> *) (val :: k) (typ :: k) (var :: k)
       (binder :: k) (stmt :: k).
(ValueSym r val typ, Argument r val, Literal r val typ,
 MathConstant r val, TypeSym r typ, OOTypeSym r typ,
 VariableSym r var typ, OOVariableSym r var val typ,
 VariableValue r var val, BooleanExpression r val, Comparison r val,
 NumericExpression r val, ValueExpression r var val binder typ,
 SelfSym r var, InternalValueExp r var val typ,
 OOValueExpression r var val typ, List r val, Reference r val,
 Set r val, ValueStatement r stmt val,
 FuncAppStatement r stmt var val, OOFuncAppStatement r stmt var val,
 TypeElim r typ, VariableElim r var typ) =>
GenState [MS (r stmt)]
genAllInputCalls = do
  gi <- GenState (Maybe (MS (r stmt)))
forall {k} (r :: k -> *) (typ :: k) (var :: k) (val :: k)
       (stmt :: k).
(TypeSym r typ, OOTypeSym r typ, VariableSym r var typ,
 OOVariableSym r var val typ, VariableValue r var val,
 SelfSym r var, FuncAppStatement r stmt var val,
 OOFuncAppStatement r stmt var val, VariableElim r var typ) =>
GenState (Maybe (MS (r stmt)))
genInputCall
  dv <- genDerivedCall
  ic <- genConstraintCall
  pure $ catMaybes [gi, dv, ic]

-- | Generates a call to the function for reading inputs from a file.
genInputCall
  ::
    ( TypeSym r typ
    , OOTypeSym r typ
    , VariableSym r var typ
    , OOVariableSym r var val typ
    , VariableValue r var val
    , SelfSym r var
    , FuncAppStatement r stmt var val
    , OOFuncAppStatement r stmt var val
    , VariableElim r var typ
    )
  => GenState (Maybe (MS (r stmt)))
genInputCall :: forall {k} (r :: k -> *) (typ :: k) (var :: k) (val :: k)
       (stmt :: k).
(TypeSym r typ, OOTypeSym r typ, VariableSym r var typ,
 OOVariableSym r var val typ, VariableValue r var val,
 SelfSym r var, FuncAppStatement r stmt var val,
 OOFuncAppStatement r stmt var val, VariableElim r var typ) =>
GenState (Maybe (MS (r stmt)))
genInputCall = do
  giName <- InternalConcept -> GenState String
genICName InternalConcept
GetInput
  genInOutCall giName getInputFormatIns getInputFormatOuts

-- | Generates a call to the function for calculating derived inputs.
genDerivedCall
  ::
    ( TypeSym r typ
    , OOTypeSym r typ
    , VariableSym r var typ
    , OOVariableSym r var val typ
    , VariableValue r var val
    , SelfSym r var
    , FuncAppStatement r stmt var val
    , OOFuncAppStatement r stmt var val
    , VariableElim r var typ
    )
  => GenState (Maybe (MS (r stmt)))
genDerivedCall :: forall {k} (r :: k -> *) (typ :: k) (var :: k) (val :: k)
       (stmt :: k).
(TypeSym r typ, OOTypeSym r typ, VariableSym r var typ,
 OOVariableSym r var val typ, VariableValue r var val,
 SelfSym r var, FuncAppStatement r stmt var val,
 OOFuncAppStatement r stmt var val, VariableElim r var typ) =>
GenState (Maybe (MS (r stmt)))
genDerivedCall = do
  dvName <- InternalConcept -> GenState String
genICName InternalConcept
DerivedValuesFn
  genInOutCall dvName getDerivedIns getDerivedOuts

-- | Generates a call to the function for checking constraints on the input.
genConstraintCall
  ::
    ( ValueSym r val typ
    , Argument r val
    , Literal r val typ
    , MathConstant r val
    , TypeSym r typ
    , OOTypeSym r typ
    , VariableSym r var typ
    , OOVariableSym r var val typ
    , VariableValue r var val
    , BooleanExpression r val
    , Comparison r val
    , NumericExpression r val
    , ValueExpression r var val binder typ
    , SelfSym r var
    , InternalValueExp r var val typ
    , OOValueExpression r var val typ
    , List r val
    , Reference r val
    , Set r val
    , ValueStatement r stmt val
    , TypeElim r typ
    , VariableElim r var typ
    )
  => GenState (Maybe (MS (r stmt)))
genConstraintCall :: forall {k} (r :: k -> *) (val :: k) (typ :: k) (var :: k)
       (binder :: k) (stmt :: k).
(ValueSym r val typ, Argument r val, Literal r val typ,
 MathConstant r val, TypeSym r typ, OOTypeSym r typ,
 VariableSym r var typ, OOVariableSym r var val typ,
 VariableValue r var val, BooleanExpression r val, Comparison r val,
 NumericExpression r val, ValueExpression r var val binder typ,
 SelfSym r var, InternalValueExp r var val typ,
 OOValueExpression r var val typ, List r val, Reference r val,
 Set r val, ValueStatement r stmt val, TypeElim r typ,
 VariableElim r var typ) =>
GenState (Maybe (MS (r stmt)))
genConstraintCall = do
  icName <- InternalConcept -> GenState String
genICName InternalConcept
InputConstraintsFn
  val <- genFuncCall icName void getConstraintParams
  pure $ valStmt <$> val

-- | Generates a call to a calculation function, given the 'CodeDefinition' for the
-- value being calculated.
genCalcCall
  ::
    ( ValueSym r val typ
    , Argument r val
    , Literal r val typ
    , MathConstant r val
    , TypeSym r typ
    , OOTypeSym r typ
    , VariableSym r var typ
    , OOVariableSym r var val typ
    , ScopeSym r scope
    , VariableValue r var val
    , BooleanExpression r val
    , Comparison r val
    , NumericExpression r val
    , ValueExpression r var val binder typ
    , SelfSym r var
    , InternalValueExp r var val typ
    , OOValueExpression r var val typ
    , List r val
    , Reference r val
    , Set r val
    , DeclStatement r bod stmt var scope val
    , TypeElim r typ
    , VariableElim r var typ
    )
  => CodeDefinition -> GenState (Maybe (MS (r stmt)))
genCalcCall :: forall {k} (r :: k -> *) (val :: k) (typ :: k) (var :: k)
       (scope :: k) (binder :: k) (bod :: k) (stmt :: k).
(ValueSym r val typ, Argument r val, Literal r val typ,
 MathConstant r val, TypeSym r typ, OOTypeSym r typ,
 VariableSym r var typ, OOVariableSym r var val typ,
 ScopeSym r scope, VariableValue r var val, BooleanExpression r val,
 Comparison r val, NumericExpression r val,
 ValueExpression r var val binder typ, SelfSym r var,
 InternalValueExp r var val typ, OOValueExpression r var val typ,
 List r val, Reference r val, Set r val,
 DeclStatement r bod stmt var scope val, TypeElim r typ,
 VariableElim r var typ) =>
CodeDefinition -> GenState (Maybe (MS (r stmt)))
genCalcCall CodeDefinition
c = do
  g <- StateT DrasilState Identity DrasilState
forall s (m :: * -> *). MonadState s m => m s
get
  let scp = ScopeType -> r scope
forall {k} (r :: k -> *) (scope :: k).
ScopeSym r scope =>
ScopeType -> r scope
convScope (ScopeType -> r scope) -> ScopeType -> r scope
forall a b. (a -> b) -> a -> b
$ DrasilState -> ScopeType
currentScope DrasilState
g
  t <- codeType c
  val <- genFuncCall (codeName c) (convTypeOO t) (getCalcParams c)
  v <- mkVar (quantvar c)
  pure $ varDecDef v scp <$> val

-- | Generates a call to the function for printing outputs.
genOutputCall
  ::
    ( ValueSym r val typ
    , Argument r val
    , Literal r val typ
    , MathConstant r val
    , TypeSym r typ
    , OOTypeSym r typ
    , VariableSym r var typ
    , OOVariableSym r var val typ
    , VariableValue r var val
    , BooleanExpression r val
    , Comparison r val
    , NumericExpression r val
    , ValueExpression r var val binder typ
    , SelfSym r var
    , InternalValueExp r var val typ
    , OOValueExpression r var val typ
    , List r val
    , Reference r val
    , Set r val
    , ValueStatement r stmt val
    , TypeElim r typ
    , VariableElim r var typ
    )
  => GenState (Maybe (MS (r stmt)))
genOutputCall :: forall {k} (r :: k -> *) (val :: k) (typ :: k) (var :: k)
       (binder :: k) (stmt :: k).
(ValueSym r val typ, Argument r val, Literal r val typ,
 MathConstant r val, TypeSym r typ, OOTypeSym r typ,
 VariableSym r var typ, OOVariableSym r var val typ,
 VariableValue r var val, BooleanExpression r val, Comparison r val,
 NumericExpression r val, ValueExpression r var val binder typ,
 SelfSym r var, InternalValueExp r var val typ,
 OOValueExpression r var val typ, List r val, Reference r val,
 Set r val, ValueStatement r stmt val, TypeElim r typ,
 VariableElim r var typ) =>
GenState (Maybe (MS (r stmt)))
genOutputCall = do
  woName <- InternalConcept -> GenState String
genICName InternalConcept
WriteOutput
  val <- genFuncCall woName void getOutputParams
  pure $ valStmt <$> val

-- | Generates a function call given the name, return type, and arguments to
-- the function.
genFuncCall
  ::
    ( ValueSym r val typ
    , Argument r val
    , Literal r val typ
    , MathConstant r val
    , TypeSym r typ
    , OOTypeSym r typ
    , VariableSym r var typ
    , OOVariableSym r var val typ
    , VariableValue r var val
    , BooleanExpression r val
    , Comparison r val
    , NumericExpression r val
    , ValueExpression r var val binder typ
    , SelfSym r var
    , InternalValueExp r var val typ
    , OOValueExpression r var val typ
    , List r val
    , Reference r val
    , Set r val
    , TypeElim r typ
    , VariableElim r var typ
    )
  => Name
  -> VS (r typ)
  -> GenState [CodeVarChunk]
  -> GenState (Maybe (VS (r val)))
genFuncCall :: forall {k} (r :: k -> *) (val :: k) (typ :: k) (var :: k)
       (binder :: k).
(ValueSym r val typ, Argument r val, Literal r val typ,
 MathConstant r val, TypeSym r typ, OOTypeSym r typ,
 VariableSym r var typ, OOVariableSym r var val typ,
 VariableValue r var val, BooleanExpression r val, Comparison r val,
 NumericExpression r val, ValueExpression r var val binder typ,
 SelfSym r var, InternalValueExp r var val typ,
 OOValueExpression r var val typ, List r val, Reference r val,
 Set r val, TypeElim r typ, VariableElim r var typ) =>
String
-> VS (r typ)
-> GenState [CodeVarChunk]
-> GenState (Maybe (VS (r val)))
genFuncCall String
n VS (r typ)
t GenState [CodeVarChunk]
funcPs = do
  mm <- String -> GenState (Maybe String)
genCall String
n
  let genFuncCall' Maybe String
Nothing = Maybe (VS (r val))
-> StateT DrasilState Identity (Maybe (VS (r val)))
forall a. a -> StateT DrasilState Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe (VS (r val))
forall a. Maybe a
Nothing
      genFuncCall' (Just String
m) = do
        cs <- GenState [CodeVarChunk]
funcPs
        pvals <- mapM mkVal cs
        val <- fApp m n t pvals []
        pure $ Just val
  genFuncCall' mm

-- | Generates a function call given the name, inputs, and outputs for the
-- function.
genInOutCall
  ::
    ( TypeSym r typ
    , OOTypeSym r typ
    , VariableSym r var typ
    , OOVariableSym r var val typ
    , VariableValue r var val
    , SelfSym r var
    , FuncAppStatement r stmt var val
    , OOFuncAppStatement r stmt var val
    , VariableElim r var typ
    )
  => Name
  -> GenState [CodeVarChunk]
  -> GenState [CodeVarChunk]
  -> GenState (Maybe (MS (r stmt)))
genInOutCall :: forall {k} (r :: k -> *) (typ :: k) (var :: k) (val :: k)
       (stmt :: k).
(TypeSym r typ, OOTypeSym r typ, VariableSym r var typ,
 OOVariableSym r var val typ, VariableValue r var val,
 SelfSym r var, FuncAppStatement r stmt var val,
 OOFuncAppStatement r stmt var val, VariableElim r var typ) =>
String
-> GenState [CodeVarChunk]
-> GenState [CodeVarChunk]
-> GenState (Maybe (MS (r stmt)))
genInOutCall String
n GenState [CodeVarChunk]
inFunc GenState [CodeVarChunk]
outFunc = do
  mm <- String -> GenState (Maybe String)
genCall String
n
  let genInOutCall' Maybe String
Nothing = Maybe (MS (r stmt))
-> StateT DrasilState Identity (Maybe (MS (r stmt)))
forall a. a -> StateT DrasilState Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe (MS (r stmt))
forall a. Maybe a
Nothing
      genInOutCall' (Just String
m) = do
        ins' <- GenState [CodeVarChunk]
inFunc
        outs' <- outFunc
        ins <- mapM mkVar (ins' \\ outs')
        outs <- mapM mkVar (outs' \\ ins')
        both <- mapM mkVar (ins' `intersect` outs')
        stmt <- fAppInOut m n (valueOf <$> ins) outs both
        pure $ Just stmt
  genInOutCall' mm

-- | Gets the name of the module containing the function being called.
-- If the function is not in either the module export map or class definition map,
--   return 'Nothing'.
-- If the function is not in module export map but is in the class definition map,
-- that means it is a private function, so return 'Nothing' unless it is in the
-- current class.
genCall :: Name -> GenState (Maybe Name)
genCall :: String -> GenState (Maybe String)
genCall String
n = do
  g <- StateT DrasilState Identity DrasilState
forall s (m :: * -> *). MonadState s m => m s
get
  let currc = DrasilState -> String
currentClass DrasilState
g
      genCallExported Maybe String
Nothing = Maybe String -> GenState (Maybe String)
genCallInClass (String -> Map String String -> Maybe String
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup String
n (Map String String -> Maybe String)
-> Map String String -> Maybe String
forall a b. (a -> b) -> a -> b
$ DrasilState -> Map String String
clsMap DrasilState
g)
      genCallExported Maybe String
m = Maybe String -> GenState (Maybe String)
forall a. a -> StateT DrasilState Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe String
m
      genCallInClass Maybe String
Nothing = Maybe String -> GenState (Maybe String)
forall a. a -> StateT DrasilState Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe String
forall a. Maybe a
Nothing
      genCallInClass (Just String
c) = if String
c String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
currc then Maybe String -> GenState (Maybe String)
forall a. a -> StateT DrasilState Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe String -> GenState (Maybe String))
-> Maybe String -> GenState (Maybe String)
forall a b. (a -> b) -> a -> b
$ String -> Map String String -> Maybe String
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup String
c (DrasilState -> Map String String
eMap
        DrasilState
g) Maybe String -> Maybe String -> Maybe String
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> String -> Maybe String
forall a. HasCallStack => String -> a
error (String
c String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
" class missing from export map")
        else Maybe String -> GenState (Maybe String)
forall a. a -> StateT DrasilState Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe String
forall a. Maybe a
Nothing
  genCallExported $ Map.lookup n (eMap g)

-- Procedural Versions --

-- | Generates calls to all of the input-related functions. First is the call to
-- the function for reading inputs, then the function for calculating derived
-- inputs, then the function for checking input constraints.
genAllInputCallsProc
  ::
    ( TypeSym r typ
    , ValueSym r val typ
    , Literal r val typ
    , MathConstant r val
    , VariableSym r var typ
    , VariableValue r var val
    , BooleanExpression r val
    , Comparison r val
    , NumericExpression r val
    , ValueExpression r var val binder typ
    , NativeVector r val typ
    , FuncAppStatement r stmt var val
    , Argument r val
    , List r val
    , Reference r val
    , Set r val
    , ValueStatement r stmt val
    , TypeElim r typ
    )
  => GenState [MS (r stmt)]
genAllInputCallsProc :: forall {k} (r :: k -> *) (typ :: k) (val :: k) (var :: k)
       (binder :: k) (stmt :: k).
(TypeSym r typ, ValueSym r val typ, Literal r val typ,
 MathConstant r val, VariableSym r var typ, VariableValue r var val,
 BooleanExpression r val, Comparison r val, NumericExpression r val,
 ValueExpression r var val binder typ, NativeVector r val typ,
 FuncAppStatement r stmt var val, Argument r val, List r val,
 Reference r val, Set r val, ValueStatement r stmt val,
 TypeElim r typ) =>
GenState [MS (r stmt)]
genAllInputCallsProc = do
  gi <- GenState (Maybe (MS (r stmt)))
forall {k} (r :: k -> *) (stmt :: k) (var :: k) (val :: k)
       (typ :: k).
(FuncAppStatement r stmt var val, TypeSym r typ,
 VariableSym r var typ, VariableValue r var val) =>
GenState (Maybe (MS (r stmt)))
genInputCallProc
  dv <- genDerivedCallProc
  ic <- genConstraintCallProc
  pure $ catMaybes [gi, dv, ic]

-- | Generates a call to the function for reading inputs from a file.
genInputCallProc
  ::
    ( FuncAppStatement r stmt var val
    , TypeSym r typ
    , VariableSym r var typ
    , VariableValue r var val
    )
  => GenState (Maybe (MS (r stmt)))
genInputCallProc :: forall {k} (r :: k -> *) (stmt :: k) (var :: k) (val :: k)
       (typ :: k).
(FuncAppStatement r stmt var val, TypeSym r typ,
 VariableSym r var typ, VariableValue r var val) =>
GenState (Maybe (MS (r stmt)))
genInputCallProc = do
  giName <- InternalConcept -> GenState String
genICName InternalConcept
GetInput
  genInOutCallProc giName getInputFormatIns getInputFormatOuts

-- | Generates a call to the function for calculating derived inputs.
genDerivedCallProc
  ::
    ( FuncAppStatement r stmt var val
    , TypeSym r typ
    , VariableSym r var typ
    , VariableValue r var val
    )
  => GenState (Maybe (MS (r stmt)))
genDerivedCallProc :: forall {k} (r :: k -> *) (stmt :: k) (var :: k) (val :: k)
       (typ :: k).
(FuncAppStatement r stmt var val, TypeSym r typ,
 VariableSym r var typ, VariableValue r var val) =>
GenState (Maybe (MS (r stmt)))
genDerivedCallProc = do
  dvName <- InternalConcept -> GenState String
genICName InternalConcept
DerivedValuesFn
  genInOutCallProc dvName getDerivedIns getDerivedOuts

-- | Generates a call to the function for checking constraints on the input.
genConstraintCallProc
  ::
    ( TypeSym r typ
    , ValueSym r val typ
    , Literal r val typ
    , MathConstant r val
    , VariableSym r var typ
    , VariableValue r var val
    , BooleanExpression r val
    , Comparison r val
    , NumericExpression r val
    , ValueExpression r var val binder typ
    , NativeVector r val typ
    , Argument r val
    , List r val
    , Reference r val
    , Set r val
    , ValueStatement r stmt val
    , TypeElim r typ
    )
  => GenState (Maybe (MS (r stmt)))
genConstraintCallProc :: forall {k} (r :: k -> *) (typ :: k) (val :: k) (var :: k)
       (binder :: k) (stmt :: k).
(TypeSym r typ, ValueSym r val typ, Literal r val typ,
 MathConstant r val, VariableSym r var typ, VariableValue r var val,
 BooleanExpression r val, Comparison r val, NumericExpression r val,
 ValueExpression r var val binder typ, NativeVector r val typ,
 Argument r val, List r val, Reference r val, Set r val,
 ValueStatement r stmt val, TypeElim r typ) =>
GenState (Maybe (MS (r stmt)))
genConstraintCallProc = do
  icName <- InternalConcept -> GenState String
genICName InternalConcept
InputConstraintsFn
  val <- genFuncCallProc icName void getConstraintParams
  pure $ valStmt <$> val

-- | Generates a call to a calculation function, given the 'CodeDefinition' for the
-- value being calculated.
genCalcCallProc
  ::
    ( TypeSym r typ
    , ValueSym r val typ
    , Literal r val typ
    , MathConstant r val
    , VariableValue r var val
    , BooleanExpression r val
    , Comparison r val
    , NumericExpression r val
    , VariableSym r var typ
    , ScopeSym r scope
    , ValueExpression r var val binder typ
    , DeclStatement r bod stmt var scope val
    , Argument r val
    , List r val
    , NativeVector r val typ
    , Reference r val
    , Set r val
    , TypeElim r typ
    )
  => CodeDefinition -> GenState (Maybe (MS (r stmt)))
genCalcCallProc :: forall {k} (r :: k -> *) (typ :: k) (val :: k) (var :: k)
       (scope :: k) (binder :: k) (bod :: k) (stmt :: k).
(TypeSym r typ, ValueSym r val typ, Literal r val typ,
 MathConstant r val, VariableValue r var val,
 BooleanExpression r val, Comparison r val, NumericExpression r val,
 VariableSym r var typ, ScopeSym r scope,
 ValueExpression r var val binder typ,
 DeclStatement r bod stmt var scope val, Argument r val, List r val,
 NativeVector r val typ, Reference r val, Set r val,
 TypeElim r typ) =>
CodeDefinition -> GenState (Maybe (MS (r stmt)))
genCalcCallProc CodeDefinition
c = do
  g <- StateT DrasilState Identity DrasilState
forall s (m :: * -> *). MonadState s m => m s
get
  let scp = ScopeType -> r scope
forall {k} (r :: k -> *) (scope :: k).
ScopeSym r scope =>
ScopeType -> r scope
convScope (ScopeType -> r scope) -> ScopeType -> r scope
forall a b. (a -> b) -> a -> b
$ DrasilState -> ScopeType
currentScope DrasilState
g
  t <- codeType c
  val <- genFuncCallProc (codeName c) (convType t) (getCalcParams c)
  v <- mkVarProc (quantvar c)
  pure $ (`varDecDef` scp) v <$> val

-- | Generates a call to the function for printing outputs.
genOutputCallProc
  ::
    ( TypeSym r typ
    , ValueSym r val typ
    , Literal r val typ
    , MathConstant r val
    , VariableSym r var typ
    , VariableValue r var val
    , BooleanExpression r val
    , Comparison r val
    , NumericExpression r val
    , ValueExpression r var val binder typ
    , Argument r val
    , List r val
    , NativeVector r val typ
    , Reference r val
    , Set r val
    , ValueStatement r stmt val
    , TypeElim r typ
    )
  => GenState (Maybe (MS (r stmt)))
genOutputCallProc :: forall {k} (r :: k -> *) (typ :: k) (val :: k) (var :: k)
       (binder :: k) (stmt :: k).
(TypeSym r typ, ValueSym r val typ, Literal r val typ,
 MathConstant r val, VariableSym r var typ, VariableValue r var val,
 BooleanExpression r val, Comparison r val, NumericExpression r val,
 ValueExpression r var val binder typ, Argument r val, List r val,
 NativeVector r val typ, Reference r val, Set r val,
 ValueStatement r stmt val, TypeElim r typ) =>
GenState (Maybe (MS (r stmt)))
genOutputCallProc = do
  woName <- InternalConcept -> GenState String
genICName InternalConcept
WriteOutput
  val <- genFuncCallProc woName void getOutputParams
  pure $ valStmt <$> val

-- | Generates a function call given the name, return type, and arguments to
-- the function.
genFuncCallProc
  ::
    ( TypeSym r typ
    , ValueSym r val typ
    , Literal r val typ
    , MathConstant r val
    , VariableSym r var typ
    , VariableValue r var val
    , BooleanExpression r val
    , Comparison r val
    , NumericExpression r val
    , ValueExpression r var val binder typ
    , Argument r val
    , List r val
    , NativeVector r val typ
    , Reference r val
    , Set r val
    , TypeElim r typ
    )
  => Name
  -> VS (r typ)
  -> GenState [CodeVarChunk]
  -> GenState (Maybe (VS (r val)))
genFuncCallProc :: forall {k} (r :: k -> *) (typ :: k) (val :: k) (var :: k)
       (binder :: k).
(TypeSym r typ, ValueSym r val typ, Literal r val typ,
 MathConstant r val, VariableSym r var typ, VariableValue r var val,
 BooleanExpression r val, Comparison r val, NumericExpression r val,
 ValueExpression r var val binder typ, Argument r val, List r val,
 NativeVector r val typ, Reference r val, Set r val,
 TypeElim r typ) =>
String
-> VS (r typ)
-> GenState [CodeVarChunk]
-> GenState (Maybe (VS (r val)))
genFuncCallProc String
n VS (r typ)
t GenState [CodeVarChunk]
funcPs = do
  mm <- String -> GenState (Maybe String)
genCall String
n
  let genFuncCall' Maybe String
Nothing = Maybe (VS (r val))
-> StateT DrasilState Identity (Maybe (VS (r val)))
forall a. a -> StateT DrasilState Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe (VS (r val))
forall a. Maybe a
Nothing
      genFuncCall' (Just String
m) = do
        cs <- GenState [CodeVarChunk]
funcPs
        pvals <- mapM mkValProc cs
        val <- fAppProc m n t pvals []
        pure $ Just val
  genFuncCall' mm

-- | Generates a function call given the name, inputs, and outputs for the
-- function.
genInOutCallProc
  ::
    ( FuncAppStatement r stmt var val
    , TypeSym r typ
    , VariableSym r var typ
    , VariableValue r var val
    )
  => Name
  -> GenState [CodeVarChunk]
  -> GenState [CodeVarChunk]
  -> GenState (Maybe (MS (r stmt)))
genInOutCallProc :: forall {k} (r :: k -> *) (stmt :: k) (var :: k) (val :: k)
       (typ :: k).
(FuncAppStatement r stmt var val, TypeSym r typ,
 VariableSym r var typ, VariableValue r var val) =>
String
-> GenState [CodeVarChunk]
-> GenState [CodeVarChunk]
-> GenState (Maybe (MS (r stmt)))
genInOutCallProc String
n GenState [CodeVarChunk]
inFunc GenState [CodeVarChunk]
outFunc = do
  mm <- String -> GenState (Maybe String)
genCall String
n
  let genInOutCall' Maybe String
Nothing = Maybe (MS (r stmt))
-> StateT DrasilState Identity (Maybe (MS (r stmt)))
forall a. a -> StateT DrasilState Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe (MS (r stmt))
forall a. Maybe a
Nothing
      genInOutCall' (Just String
m) = do
        ins' <- GenState [CodeVarChunk]
inFunc
        outs' <- outFunc
        ins <- mapM mkVarProc (ins' \\ outs')
        outs <- mapM mkVarProc (outs' \\ ins')
        both <- mapM mkVarProc (ins' `intersect` outs')
        stmt <- fAppInOutProc m n (valueOf <$> ins) outs both
        pure $ Just stmt
  genInOutCall' mm