module Main ( main ) where import Language.Elna.CommandLine (CommandLine(..), commandLine, execParser) import Language.Elna.Object.ElfCoder (elfObject) import Language.Elna.Backend.Allocator (allocate) import Language.Elna.Glue (glue) import Language.Elna.Frontend.NameAnalysis (nameAnalysis) import Language.Elna.Frontend.Parser (programP) import Language.Elna.Frontend.TypeAnalysis (typeAnalysis) import Language.Elna.RiscV.CodeGenerator (generateRiscV, riscVConfiguration) import Language.Elna.RiscV.ElfWriter (riscv32Elf) import Data.Maybe (fromMaybe) import System.FilePath (replaceExtension, takeFileName) import Text.Megaparsec (runParser, errorBundlePretty) import qualified Data.Text.IO as Text import System.Exit (ExitCode(..), exitWith) import Control.Exception (IOException, catch) -- * Error codes -- -- 1 - Command line parsing failed and other errors. -- 2 - The input could not be read. -- 3 - Parse error. -- 4 - Name analysis error. -- 5 - Type error. main :: IO () main = execParser commandLine >>= withCommandLine where withCommandLine CommandLine{..} = let defaultOutputName = replaceExtension (takeFileName input) "o" outputName = fromMaybe defaultOutputName output in catch (Text.readFile input) (printAndExit 2 :: IOException -> IO a) >>= withParsedInput outputName . runParser programP input withParsedInput output (Right program) = either (printAndExit 4) (withSymbolTable output program) $ nameAnalysis program withParsedInput _ (Left errorBundle) = putStrLn (errorBundlePretty errorBundle) >> exitWith (ExitFailure 3) withSymbolTable output program symbolTable | Just typeError <- typeAnalysis symbolTable program = printAndExit 5 typeError | otherwise = let instructions = generateRiscV $ allocate riscVConfiguration $ glue symbolTable program in elfObject output $ riscv32Elf instructions printAndExit :: Show b => forall a. Int -> b -> IO a printAndExit failureCode e = print e >> exitWith (ExitFailure failureCode)