{-# LANGUAGE TemplateHaskell #-}
module Language.Drasil.Chunk.Parameter (
  PassBy(..), ParameterChunk(..), pcAuto, pcVal
) where

import Language.Drasil hiding (Ref, CodeIdea(..), CodeChunk)
import Language.Drasil.Chunk.Code (CodeIdea(..), CodeChunk)

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

-- | Determines whether a parameter is passed by value or by reference.
data PassBy = Val | Ref

-- | Chunk representing a parameter.
data ParameterChunk = PC {ParameterChunk -> CodeChunk
_pcc :: CodeChunk
                         , ParameterChunk -> PassBy
passBy :: PassBy}
makeLenses ''ParameterChunk

-- | Finds the 'UID' of the 'CodeChunk' used to make the 'ParameterChunk'.
instance HasUID      ParameterChunk where uid :: Getter ParameterChunk UID
uid = (CodeChunk -> f CodeChunk) -> ParameterChunk -> f ParameterChunk
Lens' ParameterChunk CodeChunk
pcc ((CodeChunk -> f CodeChunk) -> ParameterChunk -> f ParameterChunk)
-> ((UID -> f UID) -> CodeChunk -> f CodeChunk)
-> (UID -> f UID)
-> ParameterChunk
-> f ParameterChunk
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (UID -> f UID) -> CodeChunk -> f CodeChunk
forall c. HasUID c => Getter c UID
Getter CodeChunk UID
uid
-- | Finds the term ('NP') of the 'CodeChunk' used to make the 'ParameterChunk'.
instance NamedIdea   ParameterChunk where term :: Lens' ParameterChunk NP
term = (CodeChunk -> f CodeChunk) -> ParameterChunk -> f ParameterChunk
Lens' ParameterChunk CodeChunk
pcc ((CodeChunk -> f CodeChunk) -> ParameterChunk -> f ParameterChunk)
-> ((NP -> f NP) -> CodeChunk -> f CodeChunk)
-> (NP -> f NP)
-> ParameterChunk
-> f ParameterChunk
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (NP -> f NP) -> CodeChunk -> f CodeChunk
forall c. NamedIdea c => Lens' c NP
Lens' CodeChunk NP
term
-- | Finds the idea contained in the 'CodeChunk' used to make the 'ParameterChunk'.
instance Idea        ParameterChunk where getA :: ParameterChunk -> Maybe String
getA = CodeChunk -> Maybe String
forall c. Idea c => c -> Maybe String
getA (CodeChunk -> Maybe String)
-> (ParameterChunk -> CodeChunk) -> ParameterChunk -> Maybe String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Getting CodeChunk ParameterChunk CodeChunk
-> ParameterChunk -> CodeChunk
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting CodeChunk ParameterChunk CodeChunk
Lens' ParameterChunk CodeChunk
pcc
-- | Finds the 'Space' of the 'CodeChunk' used to make the 'ParameterChunk'.
instance HasSpace    ParameterChunk where typ :: Getter ParameterChunk Space
typ = (CodeChunk -> f CodeChunk) -> ParameterChunk -> f ParameterChunk
Lens' ParameterChunk CodeChunk
pcc ((CodeChunk -> f CodeChunk) -> ParameterChunk -> f ParameterChunk)
-> ((Space -> f Space) -> CodeChunk -> f CodeChunk)
-> (Space -> f Space)
-> ParameterChunk
-> f ParameterChunk
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Space -> f Space) -> CodeChunk -> f CodeChunk
forall c. HasSpace c => Getter c Space
Getter CodeChunk Space
typ
-- | Finds the 'Stage' dependent 'Symbol' of the 'CodeChunk' used to make the 'ParameterChunk'.
instance HasSymbol   ParameterChunk where symbol :: ParameterChunk -> Stage -> Symbol
symbol = CodeChunk -> Stage -> Symbol
forall c. HasSymbol c => c -> Stage -> Symbol
symbol (CodeChunk -> Stage -> Symbol)
-> (ParameterChunk -> CodeChunk)
-> ParameterChunk
-> Stage
-> Symbol
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Getting CodeChunk ParameterChunk CodeChunk
-> ParameterChunk -> CodeChunk
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting CodeChunk ParameterChunk CodeChunk
Lens' ParameterChunk CodeChunk
pcc
-- | 'ParameterChunk's have a 'Quantity'.
instance Quantity    ParameterChunk
-- | Finds the code name and 'CodeChunk' of a 'ParameterChunk'.
instance CodeIdea    ParameterChunk where
  codeName :: ParameterChunk -> String
codeName = CodeChunk -> String
forall c. CodeIdea c => c -> String
codeName (CodeChunk -> String)
-> (ParameterChunk -> CodeChunk) -> ParameterChunk -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Getting CodeChunk ParameterChunk CodeChunk
-> ParameterChunk -> CodeChunk
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting CodeChunk ParameterChunk CodeChunk
Lens' ParameterChunk CodeChunk
pcc
  codeChunk :: ParameterChunk -> CodeChunk
codeChunk = CodeChunk -> CodeChunk
forall c. CodeIdea c => c -> CodeChunk
codeChunk (CodeChunk -> CodeChunk)
-> (ParameterChunk -> CodeChunk) -> ParameterChunk -> CodeChunk
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Getting CodeChunk ParameterChunk CodeChunk
-> ParameterChunk -> CodeChunk
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting CodeChunk ParameterChunk CodeChunk
Lens' ParameterChunk CodeChunk
pcc
-- | Equal if 'UID's are equal.
instance Eq          ParameterChunk where ParameterChunk
c1 == :: ParameterChunk -> ParameterChunk -> Bool
== ParameterChunk
c2 = (ParameterChunk
c1 ParameterChunk -> Getting UID ParameterChunk UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID ParameterChunk UID
forall c. HasUID c => Getter c UID
Getter ParameterChunk UID
uid) UID -> UID -> Bool
forall a. Eq a => a -> a -> Bool
== (ParameterChunk
c2 ParameterChunk -> Getting UID ParameterChunk UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID ParameterChunk UID
forall c. HasUID c => Getter c UID
Getter ParameterChunk UID
uid)
-- | Finds the units of the 'CodeChunk' used to make the 'ParameterChunk'.
instance MayHaveUnit ParameterChunk where getUnit :: ParameterChunk -> Maybe UnitDefn
getUnit = CodeChunk -> Maybe UnitDefn
forall u. MayHaveUnit u => u -> Maybe UnitDefn
getUnit (CodeChunk -> Maybe UnitDefn)
-> (ParameterChunk -> CodeChunk)
-> ParameterChunk
-> Maybe UnitDefn
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Getting CodeChunk ParameterChunk CodeChunk
-> ParameterChunk -> CodeChunk
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting CodeChunk ParameterChunk CodeChunk
Lens' ParameterChunk CodeChunk
pcc

-- | Automatically chooses 'PassBy' based on 'Space' ('Vect'ors and 'Actor's passed by reference).
pcAuto :: (CodeIdea c) => c -> ParameterChunk
pcAuto :: forall c. CodeIdea c => c -> ParameterChunk
pcAuto c
c = CodeChunk -> PassBy -> ParameterChunk
PC CodeChunk
cdch (Space -> PassBy
choosePB (Space -> PassBy) -> Space -> PassBy
forall a b. (a -> b) -> a -> b
$ CodeChunk
cdch CodeChunk -> Getting Space CodeChunk Space -> Space
forall s a. s -> Getting a s a -> a
^. Getting Space CodeChunk Space
forall c. HasSpace c => Getter c Space
Getter CodeChunk Space
typ)
  where cdch :: CodeChunk
cdch = c -> CodeChunk
forall c. CodeIdea c => c -> CodeChunk
codeChunk c
c
        choosePB :: Space -> PassBy
choosePB (Vect Space
_) = PassBy
Ref
        choosePB (Actor String
_) = PassBy
Ref
        choosePB Space
_ = PassBy
Val

-- | Constructs a pass-by-value parameter.
pcVal :: (CodeIdea c) => c -> ParameterChunk
pcVal :: forall c. CodeIdea c => c -> ParameterChunk
pcVal c
c = CodeChunk -> PassBy -> ParameterChunk
PC (c -> CodeChunk
forall c. CodeIdea c => c -> CodeChunk
codeChunk c
c) PassBy
Val