egison-5.0.0: hs-src/Language/Egison/EvalState.hs
{-# LANGUAGE FlexibleInstances #-}
{- |
Module : Language.Egison.EvalState
Licence : MIT
This module defines the state during the evaluation.
-}
module Language.Egison.EvalState
( EvalState(..)
, initialEvalState
, MonadEval(..)
, mLabelFuncName
, InstanceEnv
, MethodDict
, ConstructorEnv
, ConstructorInfo(..)
, PatternConstructorEnv
) where
import Control.Monad.Except
import Control.Monad.Trans.Class (lift)
import Control.Monad.Trans.State.Strict
import qualified Data.HashMap.Strict as HashMap
import Data.HashMap.Strict (HashMap)
import Language.Egison.IExpr
import Language.Egison.Type.Types (Type, TypeScheme)
import Language.Egison.Type.Env (TypeEnv, ClassEnv, PatternTypeEnv, emptyEnv, emptyClassEnv, emptyPatternEnv, extendEnv)
-- | Instance environment: maps class name -> method name -> type -> implementation
-- The implementation is stored as a function reference (Var name)
type MethodDict = HashMap Type String -- Type -> implementation function name
type InstanceEnv = HashMap String (HashMap String MethodDict) -- ClassName -> MethodName -> Dict
-- | Constructor environment: maps constructor name -> constructor info
-- Used for type inference and pattern matching
data ConstructorInfo = ConstructorInfo
{ ctorTypeName :: String -- ^ The inductive type name, e.g., "Maybe"
, ctorArgTypes :: [Type] -- ^ Constructor argument types
, ctorTypeParams :: [String] -- ^ Type parameters of the inductive type, e.g., ["a"]
} deriving (Show, Eq)
type ConstructorEnv = HashMap String ConstructorInfo
-- | Pattern constructor environment: maps pattern constructor name -> type scheme
-- This uses the same format as PatternTypeEnv for consistency
type PatternConstructorEnv = PatternTypeEnv
data EvalState = EvalState
{ funcNameStack :: [Var] -- ^ Names of called functions for improved error message
, instanceEnv :: InstanceEnv -- ^ Type class instance environment (runtime dispatch)
, constructorEnv :: ConstructorEnv -- ^ Inductive data constructor environment
, typeEnv :: TypeEnv -- ^ Type environment (for type inference)
, classEnv :: ClassEnv -- ^ Class environment (for type inference)
, patternEnv :: PatternTypeEnv -- ^ Pattern constructor environment (for type inference)
, patternFuncEnv :: PatternTypeEnv -- ^ Pattern function environment (for disambiguation)
}
initialEvalState :: EvalState
initialEvalState = EvalState
{ funcNameStack = []
, instanceEnv = HashMap.empty
, constructorEnv = HashMap.empty
, typeEnv = emptyEnv
, classEnv = emptyClassEnv
, patternEnv = emptyPatternEnv
, patternFuncEnv = emptyPatternEnv
}
class (Applicative m, Monad m) => MonadEval m where
pushFuncName :: Var -> m ()
topFuncName :: m Var
popFuncName :: m ()
getFuncNameStack :: m [Var]
-- Instance environment operations
getInstanceEnv :: m InstanceEnv
registerInstance :: String -> String -> Type -> String -> m ()
lookupInstance :: String -> String -> Type -> m (Maybe String)
-- Constructor environment operations
getConstructorEnv :: m ConstructorEnv
registerConstructor :: String -> ConstructorInfo -> m ()
lookupConstructor :: String -> m (Maybe ConstructorInfo)
-- Type environment operations
getTypeEnv :: m TypeEnv
setTypeEnv :: TypeEnv -> m ()
extendTypeEnv :: Var -> TypeScheme -> m ()
-- Class environment operations
getClassEnv :: m ClassEnv
setClassEnv :: ClassEnv -> m ()
-- Pattern environment operations
getPatternEnv :: m PatternTypeEnv
setPatternEnv :: PatternTypeEnv -> m ()
-- Pattern function environment operations
getPatternFuncEnv :: m PatternTypeEnv
setPatternFuncEnv :: PatternTypeEnv -> m ()
instance Monad m => MonadEval (StateT EvalState m) where
pushFuncName name = do
st <- get
put $ st { funcNameStack = name : funcNameStack st }
return ()
topFuncName = head . funcNameStack <$> get
popFuncName = do
st <- get
put $ st { funcNameStack = tail $ funcNameStack st }
return ()
getFuncNameStack = funcNameStack <$> get
getInstanceEnv = instanceEnv <$> get
registerInstance className methodName ty implName = do
st <- get
let env = instanceEnv st
classDict = HashMap.lookupDefault HashMap.empty className env
methodDict = HashMap.lookupDefault HashMap.empty methodName classDict
methodDict' = HashMap.insert ty implName methodDict
classDict' = HashMap.insert methodName methodDict' classDict
env' = HashMap.insert className classDict' env
put $ st { instanceEnv = env' }
lookupInstance className methodName ty = do
env <- instanceEnv <$> get
return $ do
classDict <- HashMap.lookup className env
methodDict <- HashMap.lookup methodName classDict
HashMap.lookup ty methodDict
getConstructorEnv = constructorEnv <$> get
registerConstructor ctorName info = do
st <- get
let env = constructorEnv st
env' = HashMap.insert ctorName info env
put $ st { constructorEnv = env' }
lookupConstructor ctorName = do
env <- constructorEnv <$> get
return $ HashMap.lookup ctorName env
getTypeEnv = typeEnv <$> get
setTypeEnv env = do
st <- get
put $ st { typeEnv = env }
extendTypeEnv name scheme = do
st <- get
let env' = extendEnv name scheme (typeEnv st)
put $ st { typeEnv = env' }
getClassEnv = classEnv <$> get
setClassEnv env = do
st <- get
put $ st { classEnv = env }
getPatternEnv = patternEnv <$> get
setPatternEnv env = do
st <- get
put $ st { patternEnv = env }
getPatternFuncEnv = patternFuncEnv <$> get
setPatternFuncEnv env = do
st <- get
put $ st { patternFuncEnv = env }
instance (MonadEval m) => MonadEval (ExceptT e m) where
pushFuncName name = lift $ pushFuncName name
topFuncName = lift topFuncName
popFuncName = lift popFuncName
getFuncNameStack = lift getFuncNameStack
getInstanceEnv = lift getInstanceEnv
registerInstance cn mn t i = lift $ registerInstance cn mn t i
lookupInstance cn mn t = lift $ lookupInstance cn mn t
getConstructorEnv = lift getConstructorEnv
registerConstructor cn info = lift $ registerConstructor cn info
lookupConstructor cn = lift $ lookupConstructor cn
getTypeEnv = lift getTypeEnv
setTypeEnv = lift . setTypeEnv
extendTypeEnv name scheme = lift $ extendTypeEnv name scheme
getClassEnv = lift getClassEnv
setClassEnv = lift . setClassEnv
getPatternEnv = lift getPatternEnv
setPatternEnv = lift . setPatternEnv
getPatternFuncEnv = lift getPatternFuncEnv
setPatternFuncEnv = lift . setPatternFuncEnv
mLabelFuncName :: MonadEval m => Maybe Var -> m a -> m a
mLabelFuncName Nothing m = m
mLabelFuncName (Just name) m = do
pushFuncName name
v <- m
popFuncName
return v