egison-4.2.0: hs-src/Language/Egison/Eval.hs
{- |
Module : Language.Egison.Eval
Licence : MIT
This module provides interface for evaluating Egison expressions.
-}
module Language.Egison.Eval
(
-- * Eval Egison expressions
evalExpr
, evalTopExpr
, evalTopExprStr
, evalTopExprs
, evalTopExprsNoPrint
, runExpr
, runTopExpr
, runTopExprStr
, runTopExprs
-- * Load Egison files
, loadEgisonLibrary
, loadEgisonFile
) where
import Control.Monad (forM_, when)
import Control.Monad.Except (throwError)
import Control.Monad.Reader (ask, asks)
import Control.Monad.State
import Language.Egison.AST
import Language.Egison.CmdOptions
import Language.Egison.Core
import Language.Egison.Data
import Language.Egison.Desugar
import Language.Egison.EvalState (MonadEval (..))
import Language.Egison.IExpr
import Language.Egison.MathOutput (prettyMath)
import Language.Egison.Parser
-- | Evaluate an Egison expression.
evalExpr :: Env -> Expr -> EvalM EgisonValue
evalExpr env expr = desugarExpr expr >>= evalExprDeep env
-- | Evaluate an Egison top expression.
evalTopExpr :: Env -> TopExpr -> EvalM (Maybe EgisonValue, Env)
evalTopExpr env topExpr = do
topExpr <- desugarTopExpr topExpr
case topExpr of
Nothing -> return (Nothing, env)
Just topExpr -> evalTopExpr' env topExpr
-- | Evaluate an Egison top expression.
evalTopExprStr :: Env -> TopExpr -> EvalM (Maybe String, Env)
evalTopExprStr env topExpr = do
(val, env') <- evalTopExpr env topExpr
case val of
Nothing -> return (Nothing, env')
Just val -> do str <- valueToStr val
return (Just str, env')
valueToStr :: EgisonValue -> EvalM String
valueToStr val = do
mathExpr <- asks optMathExpr
case mathExpr of
Nothing -> return (show val)
Just lang -> return (prettyMath lang val)
-- | Evaluate Egison top expressions.
evalTopExprs :: Env -> [TopExpr] -> EvalM Env
evalTopExprs env exprs = do
exprs <- desugarTopExprs exprs
opts <- ask
(bindings, rest) <- collectDefs opts exprs
env <- recursiveBind env bindings
forM_ rest $ \expr -> do
(val, _) <- evalTopExpr' env expr
case val of
Nothing -> return ()
Just val -> valueToStr val >>= liftIO . putStrLn
return env
-- | Evaluate Egison top expressions.
evalTopExprsNoPrint :: Env -> [TopExpr] -> EvalM Env
evalTopExprsNoPrint env exprs = do
exprs <- desugarTopExprs exprs
opts <- ask
(bindings, rest) <- collectDefs opts exprs
env <- recursiveBind env bindings
forM_ rest $ evalTopExpr' env
return env
-- | Evaluate an Egison expression. Input is a Haskell string.
runExpr :: Env -> String -> EvalM EgisonValue
runExpr env input =
readExpr input >>= evalExpr env
-- | Evaluate an Egison top expression. Input is a Haskell string.
runTopExpr :: Env -> String -> EvalM (Maybe EgisonValue, Env)
runTopExpr env input =
readTopExpr input >>= evalTopExpr env
-- | Evaluate an Egison top expression. Input is a Haskell string.
runTopExprStr :: Env -> String -> EvalM (Maybe String, Env)
runTopExprStr env input =
readTopExpr input >>= evalTopExprStr env
-- | Evaluate Egison top expressions. Input is a Haskell string.
runTopExprs :: Env -> String -> EvalM Env
runTopExprs env input =
readTopExprs input >>= evalTopExprs env
-- | Load an Egison file.
loadEgisonFile :: Env -> FilePath -> EvalM Env
loadEgisonFile env path = do
(_, env') <- evalTopExpr env (LoadFile path)
return env'
-- | Load an Egison library.
loadEgisonLibrary :: Env -> FilePath -> EvalM Env
loadEgisonLibrary env path = do
(_, env') <- evalTopExpr env (Load path)
return env'
--
-- Helper functions
--
collectDefs :: EgisonOpts -> [ITopExpr] -> EvalM ([(Var, IExpr)], [ITopExpr])
collectDefs opts exprs = collectDefs' opts exprs [] []
where
collectDefs' :: EgisonOpts -> [ITopExpr] -> [(Var, IExpr)] -> [ITopExpr] -> EvalM ([(Var, IExpr)], [ITopExpr])
collectDefs' opts (expr:exprs) bindings rest =
case expr of
IDefine name expr -> collectDefs' opts exprs ((name, expr) : bindings) rest
ITest{} -> collectDefs' opts exprs bindings (expr : rest)
IExecute{} -> collectDefs' opts exprs bindings (expr : rest)
ILoadFile _ | optNoIO opts -> throwError (Default "No IO support")
ILoadFile file -> do
exprs' <- loadFile file >>= desugarTopExprs
collectDefs' opts (exprs' ++ exprs) bindings rest
ILoad _ | optNoIO opts -> throwError (Default "No IO support")
ILoad file -> do
exprs' <- loadLibraryFile file >>= desugarTopExprs
collectDefs' opts (exprs' ++ exprs) bindings rest
collectDefs' _ [] bindings rest = return (bindings, reverse rest)
evalTopExpr' :: Env -> ITopExpr -> EvalM (Maybe EgisonValue, Env)
evalTopExpr' env (IDefine name expr) = do
env' <- recursiveBind env [(name, expr)]
return (Nothing, env')
evalTopExpr' env (ITest expr) = do
pushFuncName (stringToVar "<stdin>")
val <- evalExprDeep env expr
popFuncName
return (Just val, env)
evalTopExpr' env (IExecute expr) = do
pushFuncName (stringToVar "<stdin>")
io <- evalExprShallow env expr
case io of
Value (IOFunc m) -> m >> popFuncName >> return (Nothing, env)
_ -> throwErrorWithTrace (TypeMismatch "io" io)
evalTopExpr' env (ILoad file) = do
opts <- ask
when (optNoIO opts) $ throwError (Default "No IO support")
exprs <- loadLibraryFile file >>= desugarTopExprs
(bindings, _) <- collectDefs opts exprs
env' <- recursiveBind env bindings
return (Nothing, env')
evalTopExpr' env (ILoadFile file) = do
opts <- ask
when (optNoIO opts) $ throwError (Default "No IO support")
exprs <- loadFile file >>= desugarTopExprs
(bindings, _) <- collectDefs opts exprs
env' <- recursiveBind env bindings
return (Nothing, env')