{-# LANGUAGE TemplateHaskell #-}
module Language.Drasil.Chunk.CodeDefinition (
  CodeDefinition, DefinitionType(..), qtoc, qtov, odeDef, auxExprs, defType,
) where

import Language.Drasil
import Language.Drasil.Chunk.Code (quantvar, quantfunc)
import Language.Drasil.CodeExpr.Development (expr, CanGenCode(..))
import Language.Drasil.Data.ODEInfo (ODEInfo(..), ODEOptions(..))

import Control.Lens ((^.), makeLenses, view)

-- | The definition may be specialized to use ODEs.
data DefinitionType = Definition | ODE

-- | A chunk for pairing a mathematical definition with a 'CodeChunk'.
data CodeDefinition = CD { CodeDefinition -> CodeChunk
_cchunk   :: CodeChunk
                         , CodeDefinition -> CodeExpr
_def      :: CodeExpr
                         , CodeDefinition -> [CodeExpr]
_auxExprs :: [CodeExpr]
                         , CodeDefinition -> DefinitionType
_defType  :: DefinitionType
                         }
makeLenses ''CodeDefinition

-- | Finds the 'UID' of the 'CodeChunk' used to make the 'CodeDefinition'.
instance HasUID           CodeDefinition where uid :: Lens' CodeDefinition UID
uid = Lens' CodeDefinition CodeChunk
cchunk forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall c. HasUID c => Lens' c UID
uid
-- | Finds the term ('NP') of the 'CodeChunk' used to make the 'CodeDefinition'.
instance NamedIdea        CodeDefinition where term :: Lens' CodeDefinition NP
term = Lens' CodeDefinition CodeChunk
cchunk forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall c. NamedIdea c => Lens' c NP
term
-- | Finds the idea contained in the 'CodeChunk' used to make the 'CodeDefinition'.
instance Idea             CodeDefinition where getA :: CodeDefinition -> Maybe String
getA = forall c. Idea c => c -> Maybe String
getA forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Lens' CodeDefinition CodeChunk
cchunk
-- | Finds the 'Space' of the 'CodeChunk' used to make the 'CodeDefinition'.
instance HasSpace         CodeDefinition where typ :: Getter CodeDefinition Space
typ = Lens' CodeDefinition CodeChunk
cchunk forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall c. HasSpace c => Getter c Space
typ
-- | Finds the 'Stage' dependent 'Symbol' of the 'CodeChunk' used to make the 'CodeDefinition'.
instance HasSymbol        CodeDefinition where symbol :: CodeDefinition -> Stage -> Symbol
symbol CodeDefinition
c = forall c. HasSymbol c => c -> Stage -> Symbol
symbol (CodeDefinition
c forall s a. s -> Getting a s a -> a
^. Lens' CodeDefinition CodeChunk
cchunk)
-- | 'CodeDefinition's have a 'Quantity'.
instance Quantity         CodeDefinition
-- | Finds the code name of a 'CodeDefinition'.
-- 'Function' 'CodeDefinition's are named with the function prefix to distinguish
-- them from the corresponding variable version.
instance CodeIdea         CodeDefinition where
  codeName :: CodeDefinition -> String
codeName (CD c :: CodeChunk
c@(CodeC QuantityDict
_ VarOrFunc
Var) CodeExpr
_ [CodeExpr]
_ DefinitionType
_) = forall c. CodeIdea c => c -> String
codeName CodeChunk
c
  codeName (CD c :: CodeChunk
c@(CodeC QuantityDict
_ VarOrFunc
Func) CodeExpr
_ [CodeExpr]
_ DefinitionType
_) = String
funcPrefix forall a. [a] -> [a] -> [a]
++ forall c. CodeIdea c => c -> String
codeName CodeChunk
c
  codeChunk :: CodeDefinition -> CodeChunk
codeChunk = forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Lens' CodeDefinition CodeChunk
cchunk
-- | Equal if 'UID's are equal.
instance Eq               CodeDefinition where CodeDefinition
c1 == :: CodeDefinition -> CodeDefinition -> Bool
== CodeDefinition
c2 = (CodeDefinition
c1 forall s a. s -> Getting a s a -> a
^. forall c. HasUID c => Lens' c UID
uid) forall a. Eq a => a -> a -> Bool
== (CodeDefinition
c2 forall s a. s -> Getting a s a -> a
^. forall c. HasUID c => Lens' c UID
uid)
-- | Finds the units of the 'CodeChunk' used to make the 'CodeDefinition'.
instance MayHaveUnit      CodeDefinition where getUnit :: CodeDefinition -> Maybe UnitDefn
getUnit = forall u. MayHaveUnit u => u -> Maybe UnitDefn
getUnit forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Lens' CodeDefinition CodeChunk
cchunk
-- | Finds the defining expression of a CodeDefinition.
instance DefiningCodeExpr CodeDefinition where codeExpr :: Lens' CodeDefinition CodeExpr
codeExpr = Lens' CodeDefinition CodeExpr
def

-- NOTE: We'll eventually want extra smart constructors that allow for custom
--       CodeExprs inputs.

-- TODO: These below 3 functions that generate ``CodeDefinitions'' should be generalized
--       It _might_ be good to create make a ``CanGenCodeDefinition''-like typeclass

-- | Constructs a 'CodeDefinition' where the underlying 'CodeChunk' is for a function.
qtoc :: (Quantity (q Expr), MayHaveUnit (q Expr), DefiningExpr q) => q Expr -> CodeDefinition
qtoc :: forall (q :: * -> *).
(Quantity (q Expr), MayHaveUnit (q Expr), DefiningExpr q) =>
q Expr -> CodeDefinition
qtoc q Expr
q = CodeChunk
-> CodeExpr -> [CodeExpr] -> DefinitionType -> CodeDefinition
CD (forall c. CodeIdea c => c -> CodeChunk
codeChunk forall a b. (a -> b) -> a -> b
$ forall c. (Quantity c, MayHaveUnit c) => c -> CodeFuncChunk
quantfunc q Expr
q) (Expr -> CodeExpr
expr forall a b. (a -> b) -> a -> b
$ q Expr
q forall s a. s -> Getting a s a -> a
^. forall (c :: * -> *) e. DefiningExpr c => Lens' (c e) e
defnExpr) [] DefinitionType
Definition

-- | Constructs a 'CodeDefinition' where the underlying 'CodeChunk' is for a variable.
qtov :: CanGenCode e => QDefinition e -> CodeDefinition
qtov :: forall e. CanGenCode e => QDefinition e -> CodeDefinition
qtov QDefinition e
q = CodeChunk
-> CodeExpr -> [CodeExpr] -> DefinitionType -> CodeDefinition
CD (forall c. CodeIdea c => c -> CodeChunk
codeChunk forall a b. (a -> b) -> a -> b
$ forall c. (Quantity c, MayHaveUnit c) => c -> CodeVarChunk
quantvar QDefinition e
q) (forall e. CanGenCode e => e -> CodeExpr
toCodeExpr forall a b. (a -> b) -> a -> b
$ QDefinition e
q forall s a. s -> Getting a s a -> a
^. forall (c :: * -> *) e. DefiningExpr c => Lens' (c e) e
defnExpr) [] DefinitionType
Definition

-- | Constructs a 'CodeDefinition' for an ODE.
odeDef :: ODEInfo -> CodeDefinition
odeDef :: ODEInfo -> CodeDefinition
odeDef ODEInfo
info = CodeChunk
-> CodeExpr -> [CodeExpr] -> DefinitionType -> CodeDefinition
CD
  (forall c. CodeIdea c => c -> CodeChunk
codeChunk forall a b. (a -> b) -> a -> b
$ forall c. (Quantity c, MayHaveUnit c) => c -> CodeFuncChunk
quantfunc forall a b. (a -> b) -> a -> b
$ ODEInfo -> CodeVarChunk
depVar ODEInfo
info)
  (forall r. ExprC r => [[r]] -> r
matrix [ODEInfo -> [CodeExpr]
odeSyst ODEInfo
info])
  (forall r. ExprC r => [[r]] -> r
matrix [ODEInfo -> [CodeExpr]
initVal ODEInfo
info]forall a. a -> [a] -> [a]
:
    forall a b. (a -> b) -> [a] -> [b]
map (forall a b. (a -> b) -> a -> b
$ ODEInfo
info) [ODEInfo -> CodeExpr
tInit, ODEInfo -> CodeExpr
tFinal, ODEOptions -> CodeExpr
absTol forall b c a. (b -> c) -> (a -> b) -> a -> c
. ODEInfo -> ODEOptions
odeOpts, ODEOptions -> CodeExpr
relTol forall b c a. (b -> c) -> (a -> b) -> a -> c
. ODEInfo -> ODEOptions
odeOpts, ODEOptions -> CodeExpr
stepSize forall b c a. (b -> c) -> (a -> b) -> a -> c
. ODEInfo -> ODEOptions
odeOpts])
  DefinitionType
ODE