module Helium.Main.Compile where
import Helium.Main.PhaseLexer
import Helium.Main.PhaseParser
import Helium.Main.PhaseImport
import Helium.Main.PhaseResolveOperators
import Helium.Main.PhaseStaticChecks
import Helium.Main.PhaseKindInferencer
import Helium.Main.PhaseTypingStrategies
import Helium.Main.PhaseTypeInferencer
import Helium.Main.PhaseDesugarer
import Helium.Main.PhaseCodeGenerator
import Helium.Main.CompileUtils
import Helium.Utils.Utils
import qualified Control.Exception as CE (catch, IOException)
import Data.IORef
import Helium.StaticAnalysis.Messages.StaticErrors(errorsLogCode)
compile :: String -> String -> [Option] -> [String] -> [String] -> IO ()
compile basedir fullName options lvmPath doneModules =
do
let compileOptions = (options, fullName, doneModules)
putStrLn ("Compiling " ++ fullName)
writeIORef refToCurrentFileName fullName
writeIORef refToCurrentImported doneModules
contents <- safeReadFile fullName
(lexerWarnings, tokens) <-
doPhaseWithExit 20 (const "L") compileOptions $
phaseLexer fullName contents options
unless (NoWarnings `elem` options) $
showMessages lexerWarnings
parsedModule <-
doPhaseWithExit 20 (const "P") compileOptions $
phaseParser fullName tokens options
(indirectionDecls, importEnvs) <-
phaseImport fullName parsedModule lvmPath options
resolvedModule <-
doPhaseWithExit 20 (const "R") compileOptions $
phaseResolveOperators parsedModule importEnvs options
stopCompilingIf (StopAfterParser `elem` options)
(localEnv, typeSignatures, staticWarnings) <-
doPhaseWithExit 20 (("S"++) . errorsLogCode) compileOptions $
phaseStaticChecks fullName resolvedModule importEnvs options
unless (NoWarnings `elem` options) $
showMessages staticWarnings
stopCompilingIf (StopAfterStaticAnalysis `elem` options)
let combinedEnv = foldr combineImportEnvironments localEnv importEnvs
when (KindInferencing `elem` options) $
doPhaseWithExit maximumNumberOfKindErrors (const "K") compileOptions $
phaseKindInferencer combinedEnv resolvedModule options
(beforeTypeInferEnv, typingStrategiesDecls) <-
phaseTypingStrategies fullName combinedEnv typeSignatures options
(dictionaryEnv, afterTypeInferEnv, toplevelTypes, typeWarnings) <-
doPhaseWithExit maximumNumberOfTypeErrors (const "T") compileOptions $
phaseTypeInferencer basedir fullName resolvedModule localEnv beforeTypeInferEnv options
unless (NoWarnings `elem` options) $
showMessages typeWarnings
stopCompilingIf (StopAfterTypeInferencing `elem` options)
coreModule <-
phaseDesugarer dictionaryEnv
fullName resolvedModule
(typingStrategiesDecls ++ indirectionDecls)
afterTypeInferEnv
toplevelTypes
options
stopCompilingIf (StopAfterDesugar `elem` options)
phaseCodeGenerator fullName coreModule options
sendLog "C" fullName doneModules options
let number = length staticWarnings + length typeWarnings + length lexerWarnings
putStrLn $ "Compilation successful" ++
if number == 0 || (NoWarnings `elem` options)
then ""
else " with " ++ show number ++ " warning" ++ if number == 1 then "" else "s"
safeReadFile :: String -> IO String
safeReadFile fullName =
CE.catch
(readFile fullName)
(\ioErr ->
let message = "Unable to read file " ++ show fullName
++ " (" ++ show (ioErr :: CE.IOException) ++ ")"
in throw message)
stopCompilingIf :: Bool -> IO ()
stopCompilingIf bool = when bool (exitWith (ExitFailure 1))
maximumNumberOfTypeErrors :: Int
maximumNumberOfTypeErrors = 3
maximumNumberOfKindErrors :: Int
maximumNumberOfKindErrors = 1