-- Copyright 2023 Lennart Augustsson -- See LICENSE file for full license. {-# OPTIONS_GHC -Wno-unused-do-bind #-} module MicroHs.Main(main) where import Prelude import Data.List import Control.DeepSeq import Control.Monad import Data.Maybe import System.Environment import MicroHs.Compile import MicroHs.Exp import MicroHs.ExpPrint import MicroHs.Ident import qualified MicroHs.IdentMap as M import MicroHs.Translate import MicroHs.Interactive import MicroHs.MakeCArray import System.Directory import System.IO import System.Process import Compat import MicroHs.Instances() -- for GHC -- Version number of combinator file. -- Must match version in eval.c. combVersion :: String combVersion = "v6.0\n" mhsVersion :: String mhsVersion = "0.9.1.0" main :: IO () main = do aargs <- getArgs mdir <- lookupEnv "MHSDIR" let dir = fromMaybe "." mdir let args = takeWhile (/= "--") aargs ss = filter ((/= "-") . take 1) args flags = Flags (length (filter (== "-v") args)) (elem "-r" args) ("." : (dir ++ "/lib") : catMaybes (map (stripPrefix "-i") args)) (head $ catMaybes (map (stripPrefix "-o") args) ++ ["out.comb"]) (elem "-l" args) (elem "-C" args && usingMhs) if "--version" `elem` args then putStrLn $ "MicroHs, version " ++ mhsVersion ++ ", combinator file version " ++ combVersion else case ss of [] -> mainInteractive flags [s] -> mainCompile dir flags (mkIdentSLoc (SLoc "command-line" 0 0) s) _ -> error "Usage: mhs [-v] [-l] [-r] [-C] [-iPATH] [-oFILE] [ModuleName]" mainCompile :: FilePath -> Flags -> Ident -> IO () mainCompile mhsdir flags mn = do ds <- if useCache flags then do cash <- getCached flags (ds, cash') <- compileCacheTop flags mn cash when (verbose flags > 0) $ putStrLn $ "Saving cache " ++ show mhsCacheName () <- seq (rnf cash') (return ()) hout <- openFile mhsCacheName WriteMode hSerialize hout cash' hClose hout return ds else fst <$> compileCacheTop flags mn emptyCache t1 <- getTimeMilli let mainName = qualIdent mn (mkIdent "main") cmdl = (mainName, ds) ref i = Var $ mkIdent $ "_" ++ show i defs = M.fromList [ (n, ref i) | ((n, _), i) <- zip ds (enumFrom (0::Int)) ] findIdent n = fromMaybe (error $ "main: findIdent: " ++ showIdent n) $ M.lookup n defs emain = findIdent mainName substv aexp = case aexp of Var n -> findIdent n App f a -> App (substv f) (substv a) e -> e def :: ((Ident, Exp), Int) -> (String -> String) -> (String -> String) def ((_, e), i) r = (("((A :" ++ show i ++ " ") ++) . toStringP (substv e) . (") " ++) . r . (")" ++) res = foldr def (toStringP emain) (zip ds (enumFrom 0)) "" numDefs = M.size defs when (verbose flags > 0) $ putStrLn $ "top level defns: " ++ show numDefs when (verbose flags > 1) $ mapM_ (\ (i, e) -> putStrLn $ showIdent i ++ " = " ++ toStringP e "") ds if runIt flags then do let prg = translateAndRun cmdl -- putStrLn "Run:" -- writeSerialized "ser.comb" prg prg -- putStrLn "done" else do let outData = combVersion ++ show numDefs ++ "\n" ++ res seq (length outData) (return ()) t2 <- getTimeMilli when (verbose flags > 0) $ putStrLn $ "final pass " ++ padLeft 6 (show (t2-t1)) ++ "ms" -- Decode what to do: -- * file ends in .comb: write combinator file -- * file ends in .c: write C version of combinator -- * otherwise, write C file and compile to a binary with cc let outFile = output flags if ".comb" `isSuffixOf` outFile then writeFile outFile outData else if ".c" `isSuffixOf` outFile then writeFile outFile $ makeCArray outData else do (fn, h) <- openTmpFile "mhsc.c" hPutStr h $ makeCArray outData hClose h ct1 <- getTimeMilli mcc <- lookupEnv "MHSCC" compiler <- fromMaybe "cc" <$> lookupEnv "CC" let conf = "unix-" ++ show _wordSize cc = fromMaybe (compiler ++ " -w -Wall -O3 " ++ mhsdir ++ "/src/runtime/eval-" ++ conf ++ ".c " ++ " $IN -lm -o $OUT") mcc cmd = substString "$IN" fn $ substString "$OUT" outFile cc when (verbose flags > 0) $ putStrLn $ "Execute: " ++ show cmd callCommand cmd removeFile fn ct2 <- getTimeMilli when (verbose flags > 0) $ putStrLn $ "C compilation " ++ padLeft 6 (show (ct2-ct1)) ++ "ms"