{-# LANGUAGE TupleSections #-} module Main where import Control.Monad.Except ( MonadError(..) ) -- import Control.Bifunctor import qualified Data.List as List import Lexer (alexScanTokens) import qualified Parser as HappyParser import qualified Concrete as C import qualified Abstract as A -- import qualified Stream -- NOT USED import TheMonad import qualified Scoping import qualified ScopeMonad as Scoping -- import ErrorExpected -- Engines import qualified OrderedCom2 as Ordered import qualified Closures import qualified Monolith import qualified HerBruijn import qualified NamedExplSubst import qualified TGChecker import System.Exit import System.Environment (getArgs) import System.IO (stdout, hSetBuffering, BufferMode(..)) import System.Console.GetOpt ( getOpt, usageInfo, ArgOrder(Permute,ReturnInOrder) , OptDescr(..), ArgDescr(..) ) data Engine = Closures | Ordered | HerBruijn | Monolith | TGChecker deriving (Eq,Show,Enum,Bounded,Read) engines :: [Engine] engines = [minBound..maxBound] defaultEngine = Closures {- data Options = Options { optEngine :: Engine -- , optInputFile :: Maybe FilePath } defaultOptions :: Options defaultOptions = Options { optEngine = defaultEngine -- , optInputFile = Nothing } {- | @f :: Flag opts@ is an action on the option record that results from parsing an option. @f opts@ produces either an error message or an updated options record -} type Flag opts = opts -> opts -- Either String opts -} {- inputFlag :: FilePath -> Flag Options inputFlag f o = case optInputFile o of Nothing -> return $ o { optInputFile = Just f } Just _ -> throwError "only one input file allowed" -} data Flag = Engine Engine deriving Show engineFlag :: String -> Flag engineFlag arg = let engine :: Engine engine = read arg in Engine engine options :: [OptDescr Flag] options = [ Option ['e'] ["engine"] (ReqArg engineFlag "ENGINE") ("set lambda engine (default = " ++ show defaultEngine ++ "), possible values: " ++ show engines) ] {- engineFlag :: String -> Flag Options engineFlag arg o = let engine :: Engine engine = read arg in o { optEngine = engine } options :: [OptDescr (Flag Options)] options = [ Option ['e'] ["engine"] (ReqArg engineFlag "ENGINE") ("set lambda engine (default = " ++ show defaultEngine ++ "), possible values: " ++ show engines) ] -- | Don't export parseOptions' :: [String] -> [OptDescr (Flag opts)] -> (String -> Flag opts) -> Flag opts parseOptions' argv opts = \defaults -> case getOpt (Permute) opts argv of (o,_,[]) -> foldl (>>=) (return defaults) o (_,_,errs) -> throwError $ concat errs -- | Parse the standard options. parseOptions :: [String] -> Either String Options parseOptions argv = -- checkOpts =<< parseOptions' argv options inputFlag defaultOptions -} main :: IO () main = do hSetBuffering stdout NoBuffering putStrLn $ "HELF - Haskell implementation of the Edinburgh Logical Framework" putStrLn $ "(C) Andreas Abel and Nicolai Kraus" args <- getArgs (o,files) <- case getOpt Permute options args of (o,files,[]) -> return (o,files) (_,_,errs) -> do putStrLn ("error during parsing commandline:" ++ show errs) exitFailure let isEngine Engine{} = True -- isEngine _ = False -- currently every flag is Engine let engine = case List.find isEngine o of Nothing -> defaultEngine Just (Engine e) -> e mapM_ (mainFile engine) files mainFile :: Engine -> String -> IO () mainFile engine fileName = do putStrLn $ "%%% opening " ++ show fileName ++ " %%%" file <- readFile fileName -- putStrLn "%%% lexing %%%" let t = alexScanTokens file -- putStrLn (show t) putStrLn $ "%%% parsing %%%" let cdecls = HappyParser.parse t {- putStrLn (show cdecls) -} putStrLn $ "%%% scope checking %%%" (adecls, st) <- doScopeCheck cdecls {- -- cdecls <- doUnparse adecls st cdecls <- return $ runSRM (Scoping.unparse adecls) st putStrLn . show $ cdecls -} putStrLn $ "%%% type checking with engine " ++ show engine ++ " %%%" doTypeCheck engine st adecls putStrLn $ "%%% closing " ++ show fileName ++ " %%%" runCheckDecls Closures = Closures.runCheckDecls runCheckDecls Ordered = Ordered.runCheckDecls runCheckDecls HerBruijn = HerBruijn.runCheckDecls runCheckDecls Monolith = Monolith.runCheckDecls runCheckDecls TGChecker = TGChecker.runCheckDecls doTypeCheck :: Engine -> Scoping.ScopeState -> A.Declarations -> IO () doTypeCheck engine st decls = do res <- runCheckDecls engine decls case res of Left err -> do putStrLn $ "error during typechecking:\n" ++ err exitFailure Right () -> return () {- Right (edecls, st) -> return (edecls, signature st) -} doScopeCheck :: C.Declarations -> IO (A.Declarations, TheState) doScopeCheck cdecls = case runTCM (Scoping.parse cdecls) initState of Left err -> do putStrLn $ "scope check error: " ++ show err exitFailure Right (adecls, st) -> return (adecls, st) {- an unfinished attempt to use streams data StList s e a = Fail e | Done s | Cons a (StList s e a) build :: (s -> Either e (Either s' (a, s))) -> s -> StList s' e a build f s = loop (f s) where loop result = case result of Left err -> Fail err Right (Left s') -> Done s' Right (Right (a, s)) -> Cons a (loop (f s)) scopeCheck :: C.Declarations -> StList TheState Scoping.ParseError [A.Declaration] scopeCheck (C.Declarations cdecls) = build step (cdecls, initState) where step :: ([C.Declaration], TheState) -> Either Scoping.ParseError (Either TheState ([A.Declaration], ([C.Declaration], TheState))) step ([] , st) = Right $ Left st step (d:ds, st) = bimap id (Right . bimap id (ds,)) $ runTCM (Scoping.parse d) st -} {- scopeCheckStream :: scopeCheckStream cdecls = foldr (\ cdecl (adecls, st) -> let (ds, st') = runTCM (Scoping.parse cdecl) st in (ds -} {- scopeCheckStream :: C.Declarations -> Stream TCM A.Declaration scopeCheckStream (C.Declarations cdecls) = loop cdecls initState where loop [] st = Stream.empty loop (cdec:cdecls) = -} {- doUnparse :: A.Declarations -> TheState -> IO C.Declarations doUnparse adecls st = case runTCM (Scoping.unparse adecls) st of Left err -> do putStrLn $ "error during unparsing: " ++ show err exitFailure Right (cdecls, _) -> return cdecls -}