{-# OPTIONS_GHC -Wno-orphans #-}

-- | Defines chunk types for use in code generation.
module Language.Drasil.Chunk.Code (
  CodeIdea(..), CodeChunk(..), CodeVarChunk(..), CodeFuncChunk(..),
  VarOrFunc(..), obv, quantvar, quantfunc, ccObjVar, codevars, codevars',
  funcResolve, varResolve, listToArray, programName, funcPrefix,
  DefiningCodeExpr(..)
) where

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

import Language.Drasil
import Language.Drasil.Chunk.CodeBase
import Language.Drasil.Printers (symbolDoc)

import Text.PrettyPrint.HughesPJ (render)

-- | Finds the code name of a 'CodeChunk'.
instance CodeIdea    CodeChunk where
  codeName :: CodeChunk -> String
codeName = Doc -> String
render forall b c a. (b -> c) -> (a -> b) -> a -> c
. Symbol -> Doc
symbolDoc forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall q. HasSymbol q => q -> Symbol
codeSymb 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' CodeChunk QuantityDict
qc
  codeChunk :: CodeChunk -> CodeChunk
codeChunk = forall a. a -> a
id

-- | Finds the code name and 'CodeChunk' within a 'CodeVarChunk'.
instance CodeIdea    CodeVarChunk where
  codeName :: CodeVarChunk -> String
codeName = forall c. CodeIdea c => c -> String
codeName 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' CodeVarChunk CodeChunk
ccv
  codeChunk :: CodeVarChunk -> CodeChunk
codeChunk CodeVarChunk
c = QuantityDict -> VarOrFunc -> CodeChunk
CodeC (forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Lens' CodeChunk QuantityDict
qc forall a b. (a -> b) -> a -> b
$ forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Lens' CodeVarChunk CodeChunk
ccv CodeVarChunk
c) VarOrFunc
Var

-- | Finds the code name and 'CodeChunk' within a 'CodeFuncChunk'.
instance CodeIdea    CodeFuncChunk where
  codeName :: CodeFuncChunk -> String
codeName = forall c. CodeIdea c => c -> String
codeName forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Iso' CodeFuncChunk CodeChunk
ccf
  codeChunk :: CodeFuncChunk -> CodeChunk
codeChunk CodeFuncChunk
c = QuantityDict -> VarOrFunc -> CodeChunk
CodeC (forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Lens' CodeChunk QuantityDict
qc forall a b. (a -> b) -> a -> b
$ forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Iso' CodeFuncChunk CodeChunk
ccf CodeFuncChunk
c) VarOrFunc
Func

-- | Combine an Object-type 'CodeChunk' with another 'CodeChunk' to create a new
-- 'CodeChunk' which represents a field of the first. ex. @ccObjVar obj f = obj.f@.
ccObjVar :: CodeVarChunk -> CodeVarChunk -> CodeVarChunk
ccObjVar :: CodeVarChunk -> CodeVarChunk -> CodeVarChunk
ccObjVar CodeVarChunk
c1 CodeVarChunk
c2 = Space -> CodeVarChunk
checkObj (CodeVarChunk
c1 forall s a. s -> Getting a s a -> a
^. forall c. HasSpace c => Getter c Space
typ)
  where checkObj :: Space -> CodeVarChunk
checkObj (Actor String
_) = CodeChunk -> Maybe CodeChunk -> CodeVarChunk
CodeVC (forall c. CodeIdea c => c -> CodeChunk
codeChunk CodeVarChunk
c2) (forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall c. CodeIdea c => c -> CodeChunk
codeChunk CodeVarChunk
c1)
        checkObj Space
_ = forall a. HasCallStack => String -> a
error String
"First CodeChunk passed to ccObjVar must have Actor space"