{-# LANGUAGE OverloadedStrings #-}

module CodeGen.Module
  ( Module (Module, code),
    compileToModule,
  )
where

import Control.Monad.Except (Except)
import Control.Monad.Trans.Except (throwE)
import Data.Text (Text)
import qualified Data.Text as Txt
import Parser.Ast (Program)
import Parser.Parser (parseProgram)
import qualified Transformations.Anf.Anf as Anf
import Transformations.Anf.AnfGen (genAnf)
import Transformations.Cc.Cc (ccAst)
import Transformations.Ll.Ll (llAst)
import Transformations.Relabeler.Relabeler (relabelAst)
import Transformations.Simplifier.Simplifier (simplifyAst)
import qualified TypeChecker.PrettyPrinter as TC
import TypeChecker.TypeChecker (checkProgram)

newtype Module = Module {Module -> Program
code :: Anf.Program}
  deriving (Int -> Module -> ShowS
[Module] -> ShowS
Module -> String
(Int -> Module -> ShowS)
-> (Module -> String) -> ([Module] -> ShowS) -> Show Module
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Module -> ShowS
showsPrec :: Int -> Module -> ShowS
$cshow :: Module -> String
show :: Module -> String
$cshowList :: [Module] -> ShowS
showList :: [Module] -> ShowS
Show, Module -> Module -> Bool
(Module -> Module -> Bool)
-> (Module -> Module -> Bool) -> Eq Module
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Module -> Module -> Bool
== :: Module -> Module -> Bool
$c/= :: Module -> Module -> Bool
/= :: Module -> Module -> Bool
Eq)

compileToModule :: Text -> Except Text Module
compileToModule :: Text -> Except Text Module
compileToModule Text
text = do
  Program
program <- Text -> Except Text Program
parseAndVerify Text
text
  let astToAnf :: Program -> Program
astToAnf = Program -> Program
genAnf (Program -> Program) -> (Program -> Program) -> Program -> Program
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Program -> Program
llAst (Program -> Program) -> (Program -> Program) -> Program -> Program
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Program -> Program
ccAst (Program -> Program) -> (Program -> Program) -> Program -> Program
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Program -> Program
relabelAst (Program -> Program) -> (Program -> Program) -> Program -> Program
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Program -> Program
simplifyAst
      anf :: Program
anf = Program -> Program
astToAnf Program
program
      irMod :: Module
irMod = Program -> Module
Module Program
anf
   in Module -> Except Text Module
forall a. a -> ExceptT Text Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return Module
irMod

parseAndVerify :: Text -> Except Text Program
parseAndVerify :: Text -> Except Text Program
parseAndVerify Text
text = case Text -> Maybe Program
parseProgram Text
text of
  Just Program
program -> case Program -> Either TypeError ()
checkProgram Program
program of
    Right () -> Program -> Except Text Program
forall a. a -> ExceptT Text Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return Program
program
    Left TypeError
e -> Text -> Except Text Program
forall (m :: * -> *) e a. Monad m => e -> ExceptT e m a
throwE (Text -> Except Text Program) -> Text -> Except Text Program
forall a b. (a -> b) -> a -> b
$ Text
"Error: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
Txt.pack (TypeError -> String
forall p. Pretty p => p -> String
TC.pretty TypeError
e)
  Maybe Program
Nothing -> Text -> Except Text Program
forall (m :: * -> *) e a. Monad m => e -> ExceptT e m a
throwE Text
"Error: Syntax error"