-- | Implementations defined here are valid in some, but not all, language renderers
module Drasil.Shared.LanguageRenderer.Common (
  boolRender, bool, extVar, funcType, extFuncAppMixedArgs, listAccessFunc,
  forEach', varDecDef, listSize, increment
) where

import Prelude hiding (print, pi, (<>))
import Control.Lens.Zoom (zoom)
import Control.Monad.State (modify)
import Text.PrettyPrint.HughesPJ (text, empty, Doc)

import Drasil.Shared.CodeType (CodeType(..))
import Drasil.Shared.InterfaceCommon (Body, MixedCall, ValueSym, TypeSym(int),
  VariableElim(variableName), Label, Library, funcApp, getCodeType,
  EmptyStatement, AssignStatement, ValueExpression)
import Drasil.Shared.RendererClassesCommon (scopeData, call,
  RenderFunction(funcFromData), RenderVariable, RenderValue, ValueElim,
  RenderStatement, ScopeElim, InternalVarElim)
import Drasil.Shared.LanguageRenderer (access, intValue)
import qualified Drasil.Shared.LanguageRenderer as R (extVar, listAccessFunc,
  addAssign)
import Drasil.Shared.LanguageRenderer.Constructors(mkStmtNoEnd, mkStateVar,
  typeFromData)
import Drasil.Shared.State (MS, VS, lensMStoVS, useVarName, setVarScope)
import qualified Drasil.Shared.InterfaceCommon as IC
import Drasil.Shared.AST (ScopeData, TypeData, FuncData)

-- Swift and Julia --

boolRender :: String
boolRender :: String
boolRender = String
"Bool"

bool :: (Monad r) => VS (r TypeData)
bool :: forall (r :: * -> *). Monad r => VS (r TypeData)
bool = CodeType -> String -> Doc -> VS (r TypeData)
forall (r :: * -> *).
Monad r =>
CodeType -> String -> Doc -> VS (r TypeData)
typeFromData CodeType
Boolean String
boolRender (String -> Doc
text String
boolRender)

-- Python, Java, C#, and Julia --

extVar
  :: (RenderVariable r var typ)
  => Label -> Label -> VS (r typ) -> VS (r var)
extVar :: forall {k} (r :: k -> *) (var :: k) (typ :: k).
RenderVariable r var typ =>
String -> String -> VS (r typ) -> VS (r var)
extVar String
l String
n VS (r typ)
t = String -> VS (r typ) -> Doc -> VS (r var)
forall {k} (r :: k -> *) (var :: k) (typ :: k).
RenderVariable r var typ =>
String -> VS (r typ) -> Doc -> VS (r var)
mkStateVar (String
l String -> String -> String
`access` String
n) VS (r typ)
t (String -> String -> Doc
R.extVar String
l String
n)

-- Python, Java, and Julia --

funcType
  :: (Monad r, IC.TypeElim r TypeData)
  => [VS (r TypeData)] -> VS (r TypeData) -> VS (r TypeData)
funcType :: forall (r :: * -> *).
(Monad r, TypeElim r TypeData) =>
[VS (r TypeData)] -> VS (r TypeData) -> VS (r TypeData)
funcType [VS (r TypeData)]
ps' VS (r TypeData)
r' =  do
  ps <- [VS (r TypeData)] -> StateT ValueState Identity [r TypeData]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
forall (m :: * -> *) a. Monad m => [m a] -> m [a]
sequence [VS (r TypeData)]
ps'
  r <- r'
  typeFromData (Func (getCodeType <$> ps) (getCodeType r)) "" empty

-- Python, Java, C#, Swift, and Julia --
extFuncAppMixedArgs
  :: (RenderValue r var val typ)
  => Library -> MixedCall r var val typ
extFuncAppMixedArgs :: forall {k} (r :: k -> *) (var :: k) (val :: k) (typ :: k).
RenderValue r var val typ =>
String -> MixedCall r var val typ
extFuncAppMixedArgs String
l = Maybe String -> Maybe Doc -> MixedCall r var val typ
forall {k} (r :: k -> *) (var :: k) (val :: k) (typ :: k).
RenderValue r var val typ =>
Maybe String -> Maybe Doc -> MixedCall r var val typ
call (String -> Maybe String
forall a. a -> Maybe a
Just String
l) Maybe Doc
forall a. Maybe a
Nothing

-- Python, C#, Swift, and Julia --

listAccessFunc
  ::
    ( RenderFunction r typ
    , IC.TypeElim r typ
    , ValueElim r val
    , ValueSym r val typ
    )
  => VS (r typ) -> VS (r val) -> VS (r FuncData)
listAccessFunc :: forall (r :: * -> *) typ val.
(RenderFunction r typ, TypeElim r typ, ValueElim r val,
 ValueSym r val typ) =>
VS (r typ) -> VS (r val) -> VS (r FuncData)
listAccessFunc VS (r typ)
t VS (r val)
v = VS (r val) -> VS (r val)
forall {k} (r :: k -> *) (typ :: k) (val :: k).
(TypeElim r typ, ValueSym r val typ) =>
VS (r val) -> VS (r val)
intValue VS (r val)
v VS (r val)
-> (r val -> StateT ValueState Identity (r FuncData))
-> StateT ValueState Identity (r FuncData)
forall a b.
StateT ValueState Identity a
-> (a -> StateT ValueState Identity b)
-> StateT ValueState Identity b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ((Doc -> VS (r typ) -> StateT ValueState Identity (r FuncData)
forall (r :: * -> *) typ.
RenderFunction r typ =>
Doc -> VS (r typ) -> VS (r FuncData)
`funcFromData` VS (r typ)
t) (Doc -> StateT ValueState Identity (r FuncData))
-> (r val -> Doc)
-> r val
-> StateT ValueState Identity (r FuncData)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. r val -> Doc
forall {k} (r :: k -> *) (val :: k).
ValueElim r val =>
r val -> Doc
R.listAccessFunc)

-- Python, Swift, and Julia --

forEach'
  :: (RenderStatement r stmt)
  => (r var -> r val -> r Body -> Doc)
  -> VS (r var)
  -> VS (r val)
  -> MS (r Body)
  -> MS (r stmt)
forEach' :: forall (r :: * -> *) stmt var val.
RenderStatement r stmt =>
(r var -> r val -> r Doc -> Doc)
-> VS (r var) -> VS (r val) -> MS (r Doc) -> MS (r stmt)
forEach' r var -> r val -> r Doc -> Doc
f VS (r var)
i' VS (r val)
v' MS (r Doc)
b' = do
  i <- LensLike'
  (Zoomed (StateT ValueState Identity) (r var))
  MethodState
  ValueState
-> VS (r var) -> StateT MethodState Identity (r var)
forall c.
LensLike'
  (Zoomed (StateT ValueState Identity) c) MethodState ValueState
-> StateT ValueState Identity c -> StateT MethodState Identity c
forall (m :: * -> *) (n :: * -> *) s t c.
Zoom m n s t =>
LensLike' (Zoomed m c) t s -> m c -> n c
zoom LensLike'
  (Zoomed (StateT ValueState Identity) (r var))
  MethodState
  ValueState
(ValueState -> Focusing Identity (r var) ValueState)
-> MethodState -> Focusing Identity (r var) MethodState
Lens' MethodState ValueState
lensMStoVS VS (r var)
i'
  v <- zoom lensMStoVS v'
  b <- b'
  mkStmtNoEnd (f i v b)

-- Python and Julia --

varDecDef
  ::
    ( EmptyStatement r stmt
    , AssignStatement r stmt var val
    , ScopeElim r ScopeData
    , VariableElim r var typ
    )
  => VS (r var) -> r ScopeData -> Maybe (VS (r val)) -> MS (r stmt)
varDecDef :: forall (r :: * -> *) stmt var val typ.
(EmptyStatement r stmt, AssignStatement r stmt var val,
 ScopeElim r ScopeData, VariableElim r var typ) =>
VS (r var) -> r ScopeData -> Maybe (VS (r val)) -> MS (r stmt)
varDecDef VS (r var)
v r ScopeData
scp Maybe (VS (r val))
e = do
  v' <- LensLike'
  (Zoomed (StateT ValueState Identity) (r var))
  MethodState
  ValueState
-> VS (r var) -> StateT MethodState Identity (r var)
forall c.
LensLike'
  (Zoomed (StateT ValueState Identity) c) MethodState ValueState
-> StateT ValueState Identity c -> StateT MethodState Identity c
forall (m :: * -> *) (n :: * -> *) s t c.
Zoom m n s t =>
LensLike' (Zoomed m c) t s -> m c -> n c
zoom LensLike'
  (Zoomed (StateT ValueState Identity) (r var))
  MethodState
  ValueState
(ValueState -> Focusing Identity (r var) ValueState)
-> MethodState -> Focusing Identity (r var) MethodState
Lens' MethodState ValueState
lensMStoVS VS (r var)
v
  modify $ useVarName (variableName v')
  modify $ setVarScope (variableName v') (scopeData scp)
  def e
  where
    def :: Maybe (VS (r val)) -> MS (r stmt)
def Maybe (VS (r val))
Nothing = MS (r stmt)
forall {k} (r :: k -> *) (stmt :: k).
EmptyStatement r stmt =>
MS (r stmt)
IC.emptyStmt
    def (Just VS (r val)
d) = VS (r var) -> VS (r val) -> MS (r stmt)
forall {k} (r :: k -> *) (stmt :: k) (var :: k) (val :: k).
AssignStatement r stmt var val =>
VS (r var) -> VS (r val) -> MS (r stmt)
IC.assign VS (r var)
v VS (r val)
d

-- Python and Swift --

increment
  :: (InternalVarElim r var, RenderStatement r stmt, ValueElim r val)
  => VS (r var) -> VS (r val) -> MS (r stmt)
increment :: forall {k} (r :: k -> *) (var :: k) (stmt :: k) (val :: k).
(InternalVarElim r var, RenderStatement r stmt, ValueElim r val) =>
VS (r var) -> VS (r val) -> MS (r stmt)
increment VS (r var)
vr' VS (r val)
v'= do
  vr <- LensLike'
  (Zoomed (StateT ValueState Identity) (r var))
  MethodState
  ValueState
-> VS (r var) -> StateT MethodState Identity (r var)
forall c.
LensLike'
  (Zoomed (StateT ValueState Identity) c) MethodState ValueState
-> StateT ValueState Identity c -> StateT MethodState Identity c
forall (m :: * -> *) (n :: * -> *) s t c.
Zoom m n s t =>
LensLike' (Zoomed m c) t s -> m c -> n c
zoom LensLike'
  (Zoomed (StateT ValueState Identity) (r var))
  MethodState
  ValueState
(ValueState -> Focusing Identity (r var) ValueState)
-> MethodState -> Focusing Identity (r var) MethodState
Lens' MethodState ValueState
lensMStoVS VS (r var)
vr'
  v <- zoom lensMStoVS v'
  mkStmtNoEnd $ R.addAssign vr v

-- Python, Julia, and MATLAB --

-- | Call to get the size of a list as a function call
listSize
  :: (TypeSym r typ, ValueExpression r var val binder typ)
  => String -> VS (r val) -> VS (r val)
listSize :: forall {k} (r :: k -> *) (typ :: k) (var :: k) (val :: k)
       (binder :: k).
(TypeSym r typ, ValueExpression r var val binder typ) =>
String -> VS (r val) -> VS (r val)
listSize String
fnName VS (r val)
list = PosCall r val typ
forall {k} (r :: k -> *) (var :: k) (val :: k) (binder :: k)
       (typ :: k).
ValueExpression r var val binder typ =>
PosCall r val typ
funcApp String
fnName VS (r typ)
forall {k} (r :: k -> *) (typ :: k). TypeSym r typ => VS (r typ)
int [VS (r val)
list]