module Main where import Control.Monad.Trans.Reader import Control.Monad.Error import Data.List import System.Environment import System.Console.Haskeline import System.Directory import Exp.Lex import Exp.Par import Exp.Print import Exp.Abs import Exp.Layout import Exp.ErrM import MTTtoCTT import Concrete import qualified MTT as A import qualified CTT as C import qualified Eval as E type Interpreter a = InputT IO a defaultPrompt :: String defaultPrompt = "> " lexer :: String -> [Token] lexer = resolveLayout True . myLexer showTree :: (Show a, Print a) => a -> IO () showTree tree = do putStrLn $ "\n[Abstract Syntax]\n\n" ++ show tree putStrLn $ "\n[Linearized tree]\n\n" ++ printTree tree main :: IO () main = getArgs >>= runInputT defaultSettings . runInterpreter -- (not ok,loaded,already loaded defs) -> to load -> (newnotok, newloaded, newdefs) imports :: ([String],[String],[Def]) -> String-> Interpreter ([String],[String],[Def]) imports st@(notok,loaded,defs) f | f `elem` notok = fail ("Looping imports in " ++ f) | f `elem` loaded = return st | otherwise = do s <- lift $ readFile f let ts = lexer s case pModule ts of Bad s -> fail $ "Parse Failed in file " ++ show f ++ "\n" ++ show s Ok mod@(Module _ imps defs') -> do let imps' = [ unIdent s ++ ".cub" | Import s <- imps ] (notok1,loaded1,def1) <- foldM imports (f:notok,loaded,defs) imps' outputStrLn $ "Parsed file " ++ show f ++ " successfully!" return (notok,f:loaded1,def1 ++ defs') runInterpreter :: [FilePath] -> Interpreter () runInterpreter fs = case fs of [f] -> do -- parse and type-check files (_,_,defs) <- imports ([],[],[]) f -- Compute all constructors let cs = concat [ [ unIdent n | Sum n _ <- lbls] | DefData _ _ lbls <- defs ] let res = runResolver (local (insertConstrs cs) (resolveDefs defs)) case res of Left err -> outputStrLn $ "Resolver failed: " ++ err Right adefs -> case A.runDefs A.tEmpty adefs of Left err -> outputStrLn $ "Type checking failed: " ++ err Right tenv -> do outputStrLn "File loaded." loop cs tenv _ -> do outputStrLn $ "Exactly one file expected: " ++ show fs loop [] A.tEmpty where loop :: [String] -> A.TEnv -> Interpreter () loop cs tenv@(A.TEnv _ rho _) = do input <- getInputLine defaultPrompt case input of Nothing -> outputStrLn help >> loop cs tenv Just ":q" -> return () Just ":r" -> runInterpreter fs Just (':':'l':' ':str) -> runInterpreter (words str) Just (':':'c':'d':' ':str) -> lift (setCurrentDirectory str) >> loop cs tenv Just ":h" -> outputStrLn help >> loop cs tenv Just str -> let ts = lexer str in case pExp ts of Bad err -> outputStrLn ("Parse error: " ++ err) >> loop cs tenv Ok exp -> case runResolver (local (const (Env cs)) (resolveExp exp)) of Left err -> outputStrLn ("Resolver failed: " ++ err) >> loop cs tenv Right body -> case A.runInfer tenv body of Left err -> outputStrLn ("Could not type-check: " ++ err) >> loop cs tenv Right _ -> case translate (A.defs rho body) of Left err -> outputStrLn ("Could not translate to internal syntax: " ++ err) >> loop cs tenv Right t -> let value = E.eval C.Empty t in outputStrLn ("EVAL: " ++ show value) >> loop cs tenv help :: String help = "\nAvailable commands:\n" ++ " infer type and evaluate statement\n" ++ " :q quit\n" ++ " :l loads filename (and resets environment before)\n" ++ " :cd change directory to path\n" ++ " :r reload\n" ++ " :h display this message\n"