summaryrefslogtreecommitdiff
path: root/src/Main.hs
blob: 9e70cd68f602c6ad912e4ee3fbc13ff457c3af0d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
{- This Source Code Form is subject to the terms of the Mozilla Public License,
   v. 2.0. If a copy of the MPL was not distributed with this file, You can
   obtain one at https://mozilla.org/MPL/2.0/. -}

module Main
    ( main
    ) where

import Language.Elna.Driver
    ( Driver(..)
    , IntermediateStage(..)
    , drive
    )
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 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.
-- 6 - Register allocation error.

main :: IO ()
main = drive >>= withCommandLine
  where
    withCommandLine driver@Driver{ input }
        = catch (Text.readFile input) (printAndExit 2 :: IOException -> IO a)
        >>= withParsedInput driver
        . runParser programP input
    withParsedInput driver@Driver{ intermediateStage } (Right program)
        | Just ParseStage <- intermediateStage = pure ()
        | otherwise
            = either (printAndExit 4) (withSymbolTable driver program)
            $ nameAnalysis program 
    withParsedInput _ (Left errorBundle)
        = putStrLn (errorBundlePretty errorBundle)
        >> exitWith (ExitFailure 3)
    withSymbolTable driver@Driver{ intermediateStage } program symbolTable
        | Just typeError <- typeAnalysis symbolTable program =
            printAndExit 5 typeError
        | Just ValidateStage <- intermediateStage = pure ()
        | otherwise = either (printAndExit 6) (withTac driver)
            $ allocate riscVConfiguration symbolTable
            $ glue symbolTable program
    withTac Driver{ intermediateStage, output } tac
        | Just CodeGenStage <- intermediateStage = pure ()
        | otherwise = elfObject output $ riscv32Elf $ generateRiscV tac
    printAndExit :: Show b => forall a. Int -> b -> IO a
    printAndExit failureCode e = print e >> exitWith (ExitFailure failureCode)