module CSPM (
module CSPM.DataStructures.Names,
module CSPM.DataStructures.Syntax,
module CSPM.DataStructures.Types,
CSPMSession, newCSPMSession,
CSPMMonad,
getSession, setSession, handleWarnings,
withSession,
CSPM, unCSPM,
parseStringAsFile, parseFile, parseInteractiveStmt, parseExpression,
typeCheckFile, typeCheckInteractiveStmt, typeCheckExpression, ensureExpressionIsOfType,
dependenciesOfExp, typeOfExpression,
evaluateExp,
bindFile, bindDeclaration, getBoundNames,
getLibCSPMVersion
)
where
import Control.Monad.State
import Control.Monad.Trans
import Data.Version
import System.FilePath
import System.IO
import CSPM.DataStructures.Names
import CSPM.DataStructures.Syntax
import CSPM.DataStructures.Types
import qualified CSPM.Evaluator as EV
import CSPM.Evaluator.Values
import qualified CSPM.Parser as P
import qualified CSPM.TypeChecker as TC
import qualified CSPM.Desugar as DS
import Paths_libcspm (version)
import Util.Annotated
import Util.Exception
import Util.PrettyPrint
data CSPMSession = CSPMSession {
tcState :: TC.TypeInferenceState,
evState :: EV.EvaluationState
}
newCSPMSession :: MonadIO m => m CSPMSession
newCSPMSession = do
tcState <- liftIO $ TC.initTypeChecker
let evState = EV.initEvaluator
return $ CSPMSession tcState evState
class (MonadIO m) => CSPMMonad m where
getSession :: m CSPMSession
setSession :: CSPMSession -> m ()
handleWarnings :: [ErrorMessage] -> m ()
withSession :: CSPMMonad m => (CSPMSession -> m a) -> m a
withSession f = getSession >>= f
modifySession :: CSPMMonad m => (CSPMSession -> CSPMSession) -> m ()
modifySession f = do
s <- getSession
setSession (f s)
reportWarnings :: CSPMMonad m => m(a, [ErrorMessage]) -> m a
reportWarnings prog = withSession $ \ sess -> do
(v, ws) <- prog
if ws == [] then return ()
else handleWarnings ws
return v
type CSPM = StateT CSPMSession IO
unCSPM :: CSPMSession -> CSPM a -> IO (a, CSPMSession)
unCSPM = flip runStateT
instance CSPMMonad CSPM where
getSession = get
setSession = put
handleWarnings ms = liftIO $ putStrLn $ show $ prettyPrint ms
parse :: CSPMMonad m => FilePath -> P.ParseMonad a -> m a
parse dir p = liftIO $ P.runParser p dir
parseFile :: CSPMMonad m => FilePath -> m [PModule]
parseFile fp =
let (dir, fname) = splitFileName fp
in parse dir (P.parseFile fname)
parseStringAsFile :: CSPMMonad m => String -> m [PModule]
parseStringAsFile str = parse "" (P.parseStringAsFile str)
parseInteractiveStmt :: CSPMMonad m => String -> m PInteractiveStmt
parseInteractiveStmt str = parse "" (P.parseInteractiveStmt str)
parseExpression :: CSPMMonad m => String -> m PExp
parseExpression str = parse "" (P.parseExpression str)
runTypeCheckerInCurrentState :: CSPMMonad m => TC.TypeCheckMonad a -> m (a, [ErrorMessage])
runTypeCheckerInCurrentState p = withSession $ \s -> do
(a, ws, st) <- liftIO $ TC.runFromStateToState (tcState s) p
modifySession (\s -> s { tcState = st })
return (a, ws)
typeCheckFile :: CSPMMonad m => [PModule] -> m [TCModule]
typeCheckFile ms = reportWarnings $ runTypeCheckerInCurrentState $ do
TC.typeCheck ms
return $ DS.desugar ms
typeCheckInteractiveStmt :: CSPMMonad m => PInteractiveStmt -> m TCInteractiveStmt
typeCheckInteractiveStmt pstmt = reportWarnings $ runTypeCheckerInCurrentState $ do
TC.typeCheck pstmt
return $ DS.desugar pstmt
typeCheckExpression :: CSPMMonad m => PExp -> m TCExp
typeCheckExpression exp = reportWarnings $ runTypeCheckerInCurrentState $ do
TC.typeCheck exp
return $ DS.desugar exp
ensureExpressionIsOfType :: CSPMMonad m => Type -> PExp -> m TCExp
ensureExpressionIsOfType t exp = reportWarnings $ runTypeCheckerInCurrentState $ do
TC.typeCheckExpect t exp
return $ DS.desugar exp
typeOfExpression :: CSPMMonad m => PExp -> m Type
typeOfExpression exp =
reportWarnings $ runTypeCheckerInCurrentState (TC.typeOfExp exp)
dependenciesOfExp :: CSPMMonad m => TCExp -> m [Name]
dependenciesOfExp e =
reportWarnings $ runTypeCheckerInCurrentState (TC.dependenciesOfExp e)
runEvaluatorInCurrentState :: CSPMMonad m => EV.EvaluationMonad a -> m a
runEvaluatorInCurrentState p = withSession $ \s -> do
let (a, st) = EV.runFromStateToState (evState s) p
modifySession (\s -> s { evState = st })
return a
getBoundNames :: CSPMMonad m => m [Name]
getBoundNames = runEvaluatorInCurrentState EV.getBoundNames
bindDeclaration :: CSPMMonad m => TCDecl -> m ()
bindDeclaration d = withSession $ \s -> do
evSt <- runEvaluatorInCurrentState (EV.addToEnvironment (EV.evaluateDecl d))
modifySession (\s -> s { evState = evSt })
bindFile :: CSPMMonad m => [TCModule] -> m ()
bindFile ms = do
evSt <- runEvaluatorInCurrentState (EV.addToEnvironment (EV.evaluateFile ms))
modifySession (\s -> s { evState = evSt })
return ()
evaluateFile :: CSPMMonad m => [TCModule] -> m [(Name, Value)]
evaluateFile ms = runEvaluatorInCurrentState (EV.evaluateFile ms)
evaluateExp :: CSPMMonad m => TCExp -> m Value
evaluateExp e = runEvaluatorInCurrentState (EV.evaluateExp e)
getLibCSPMVersion :: Version
getLibCSPMVersion = version