module Codegen.Codegen where

import qualified Ast.Types as AT
import qualified Codegen.Errors as CE
import qualified Codegen.ExprGen.ExprGen ()
import qualified Codegen.ExprGen.Global as EG
import qualified Codegen.State as CS
import qualified Codegen.Utils as U
import qualified Control.Monad.Except as E
import qualified Control.Monad.State as S
import qualified LLVM.AST as AST
import qualified LLVM.IRBuilder.Module as M
import qualified LLVM.IRBuilder.Monad as IRM

-- | Generate LLVM code for a program.
codegen :: AT.Program -> Either CE.CodegenError AST.Module
codegen :: Program -> Either CodegenError Module
codegen Program
program =
  Except CodegenError Module -> Either CodegenError Module
forall e a. Except e a -> Either e a
E.runExcept (Except CodegenError Module -> Either CodegenError Module)
-> Except CodegenError Module -> Either CodegenError Module
forall a b. (a -> b) -> a -> b
$
    ShortByteString
-> ModuleBuilderT
     (ExceptT CodegenError Identity) ((), [BasicBlock])
-> Except CodegenError Module
forall (m :: * -> *) a.
Monad m =>
ShortByteString -> ModuleBuilderT m a -> m Module
M.buildModuleT (String -> ShortByteString
U.stringToByteString (String -> ShortByteString) -> String -> ShortByteString
forall a b. (a -> b) -> a -> b
$ Program -> String
AT.sourceFile Program
program) (ModuleBuilderT (ExceptT CodegenError Identity) ((), [BasicBlock])
 -> Except CodegenError Module)
-> ModuleBuilderT
     (ExceptT CodegenError Identity) ((), [BasicBlock])
-> Except CodegenError Module
forall a b. (a -> b) -> a -> b
$
      IRBuilderState
-> IRBuilderT (ModuleBuilderT (ExceptT CodegenError Identity)) ()
-> ModuleBuilderT
     (ExceptT CodegenError Identity) ((), [BasicBlock])
forall (m :: * -> *) a.
Monad m =>
IRBuilderState -> IRBuilderT m a -> m (a, [BasicBlock])
IRM.runIRBuilderT IRBuilderState
IRM.emptyIRBuilder (IRBuilderT (ModuleBuilderT (ExceptT CodegenError Identity)) ()
 -> ModuleBuilderT
      (ExceptT CodegenError Identity) ((), [BasicBlock]))
-> IRBuilderT (ModuleBuilderT (ExceptT CodegenError Identity)) ()
-> ModuleBuilderT
     (ExceptT CodegenError Identity) ((), [BasicBlock])
forall a b. (a -> b) -> a -> b
$
        StateT
  CodegenState
  (IRBuilderT (ModuleBuilderT (ExceptT CodegenError Identity)))
  ()
-> CodegenState
-> IRBuilderT (ModuleBuilderT (ExceptT CodegenError Identity)) ()
forall (m :: * -> *) s a. Monad m => StateT s m a -> s -> m a
S.evalStateT
          (((String, Expr)
 -> StateT
      CodegenState
      (IRBuilderT (ModuleBuilderT (ExceptT CodegenError Identity)))
      ())
-> [(String, Expr)]
-> StateT
     CodegenState
     (IRBuilderT (ModuleBuilderT (ExceptT CodegenError Identity)))
     ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (Expr
-> StateT
     CodegenState
     (IRBuilderT (ModuleBuilderT (ExceptT CodegenError Identity)))
     ()
forall (m :: * -> *).
(MonadCodegen m, ExprGen Expr) =>
Expr -> m ()
EG.generateGlobal (Expr
 -> StateT
      CodegenState
      (IRBuilderT (ModuleBuilderT (ExceptT CodegenError Identity)))
      ())
-> ((String, Expr) -> Expr)
-> (String, Expr)
-> StateT
     CodegenState
     (IRBuilderT (ModuleBuilderT (ExceptT CodegenError Identity)))
     ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String, Expr) -> Expr
forall a b. (a, b) -> b
snd) (Program -> [(String, Expr)]
AT.globals Program
program))
          (LocalState
-> LocalState
-> LoopState
-> LocalState
-> UniqueNameState
-> CodegenState
CS.CodegenState [] [] LoopState
forall a. Maybe a
Nothing [] UniqueNameState
0)