perga/lib/Program.hs

51 lines
1.7 KiB
Haskell

module Program where
import Check
import Control.Monad.Except
import qualified Data.Map.Strict as M
import Elaborator
import Errors
import Eval (Env, checkBeta)
import qualified Eval
import Expr (Expr)
import qualified Expr
import IR
import Parser (parseProgram)
import Preprocessor (runPreprocessor)
insertDef :: Text -> Expr -> Expr -> Env -> Env
insertDef name ty body = M.insert name (Eval.Def ty body)
handleDef :: IRDef -> StateT Env Result ()
handleDef (Axiom name ty) = do
env <- get
whenLeft_ (checkType env $ elaborate ty) throwError
modify $ insertDef name (elaborate ty) (Expr.Axiom name)
handleDef (Def name Nothing irBody) = do
env <- get
let body = elaborate irBody
let ty = checkType env body
either throwError (modify . flip (insertDef name) body) ty
handleDef (Def name (Just irTy) irBody) = do
env <- get
let body = elaborate irBody
let ty = elaborate irTy
let mty' = checkType env body
whenLeft_ mty' throwError
whenRight_ mty' $ \ty' -> do
case checkBeta env ty ty' of
Left err -> throwError err
Right False -> throwError $ NotEquivalent ty ty' body
Right True -> modify $ insertDef name ty' body
evalDef :: Env -> IRDef -> Result Env
evalDef = flip (execStateT . handleDef)
handleProgram :: IRProgram -> Result Env
handleProgram = flip execStateT M.empty . mapM_ handleDef
handleAndParseProgram :: String -> Text -> Either String Env
handleAndParseProgram filename input = (first toString . handleProgram) =<< parseProgram filename input
handleAndParseFile :: String -> ExceptT String IO Env
handleAndParseFile filename = toString `withExceptT` runPreprocessor filename >>= hoistEither . handleAndParseProgram filename