{- | Module : Language.Egison.Parser Licence : MIT This module provides the parser interface. -} module Language.Egison.Parser ( -- * Parse and desugar readTopExprs , readTopExpr , readExprs , readExpr -- * Parse and desugar a file , loadLibraryFile , loadFile -- * Parser utils (for translator) , removeShebang , readUTF8File ) where import Control.Monad.Except (liftIO, throwError) import Control.Monad.State (unless) import System.Directory (doesFileExist, getHomeDirectory) import System.IO import Language.Egison.AST import Language.Egison.Desugar import Language.Egison.Data import qualified Language.Egison.Parser.SExpr as SExpr import qualified Language.Egison.Parser.NonS as NonS import Paths_egison (getDataFileName) readTopExprs :: Bool -> String -> EvalM [EgisonTopExpr] readTopExprs useSExpr = either throwError (mapM desugarTopExpr) . parseTopExprs where parseTopExprs | useSExpr = SExpr.parseTopExprs | otherwise = NonS.parseTopExprs -- TODO(momohatt): Parse from the last state readTopExpr :: Bool -> String -> EvalM EgisonTopExpr readTopExpr useSExpr = either throwError desugarTopExpr . parseTopExpr where parseTopExpr | useSExpr = SExpr.parseTopExpr | otherwise = NonS.parseTopExpr readExprs :: Bool -> String -> EvalM [EgisonExpr] readExprs useSExpr = either throwError (mapM desugarExpr) . parseExprs where parseExprs | useSExpr = SExpr.parseExprs | otherwise = NonS.parseExprs readExpr :: Bool -> String -> EvalM EgisonExpr readExpr useSExpr = either throwError desugarExpr . parseExpr where parseExpr | useSExpr = SExpr.parseExpr | otherwise = NonS.parseExpr -- |Load a libary file loadLibraryFile :: FilePath -> EvalM [EgisonTopExpr] loadLibraryFile file = do homeDir <- liftIO getHomeDirectory doesExist <- liftIO $ doesFileExist $ homeDir ++ "/.egison/" ++ file if doesExist then loadFile $ homeDir ++ "/.egison/" ++ file else liftIO (getDataFileName file) >>= loadFile -- |Load a file loadFile :: FilePath -> EvalM [EgisonTopExpr] loadFile file = do doesExist <- liftIO $ doesFileExist file unless doesExist $ throwError $ Default ("file does not exist: " ++ file) input <- liftIO $ readUTF8File file useSExpr <- checkIfUseSExpr file exprs <- readTopExprs useSExpr $ removeShebang useSExpr input concat <$> mapM recursiveLoad exprs where recursiveLoad (Load file) = loadLibraryFile file recursiveLoad (LoadFile file) = loadFile file recursiveLoad expr = return [expr] removeShebang :: Bool -> String -> String removeShebang useSExpr cs@('#':'!':_) = if useSExpr then ';' : cs else "--" ++ cs removeShebang _ cs = cs readUTF8File :: FilePath -> IO String readUTF8File name = do h <- openFile name ReadMode hSetEncoding h utf8 hGetContents h hasDotEgiExtension :: String -> Bool hasDotEgiExtension file = drop (length file - 4) file == ".egi" hasDotSEgiExtension :: String -> Bool hasDotSEgiExtension file = drop (length file - 5) file == ".segi" checkIfUseSExpr :: String -> EvalM Bool checkIfUseSExpr file | hasDotEgiExtension file = return False | hasDotSEgiExtension file = return True | otherwise = throwError (UnknownFileExtension file)