{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RecursiveDo #-}

module Codegen.ExprGen.ControlFlow where

import qualified Ast.Types as AT
import qualified Codegen.Errors as CC
import qualified Codegen.ExprGen.Cast as CC
import {-# SOURCE #-} qualified Codegen.ExprGen.ExprGen as EG
import qualified Codegen.State as CS
import qualified Codegen.Utils as U
import qualified Control.Monad as CM
import qualified Control.Monad.Except as E
import qualified Control.Monad.State as S
import qualified LLVM.AST as AST
import qualified LLVM.AST.Constant as C
import qualified LLVM.AST.IntegerPredicate as IP
import qualified LLVM.AST.Type as T
import qualified LLVM.IRBuilder.Instruction as I
import qualified LLVM.IRBuilder.Monad as IRM
import qualified Shared.Utils as SU

-- | Generate LLVM code for `if` expressions.
generateIf :: (CS.MonadCodegen m, EG.ExprGen AT.Expr) => AT.Expr -> m AST.Operand
generateIf :: forall (m :: * -> *).
(MonadCodegen m, ExprGen Expr) =>
Expr -> m Operand
generateIf (AT.If SrcLoc
_ Expr
cond Expr
thenExpr Maybe Expr
elseExpr) = mdo
  Operand
condVal <- Expr -> m Operand
forall a (m :: * -> *).
(ExprGen a, MonadCodegen m) =>
a -> m Operand
forall (m :: * -> *). MonadCodegen m => Expr -> m Operand
EG.generateExpr Expr
cond
  Operand
condTest <- IntegerPredicate -> Operand -> Operand -> m Operand
forall (m :: * -> *).
MonadIRBuilder m =>
IntegerPredicate -> Operand -> Operand -> m Operand
I.icmp IntegerPredicate
IP.NE Operand
condVal (Constant -> Operand
AST.ConstantOperand (Constant -> Operand) -> Constant -> Operand
forall a b. (a -> b) -> a -> b
$ Word32 -> Integer -> Constant
C.Int Word32
1 Integer
0)
  Operand -> Name -> Name -> m ()
forall (m :: * -> *).
MonadIRBuilder m =>
Operand -> Name -> Name -> m ()
I.condBr Operand
condTest Name
thenBlock Name
elseBlock

  Name
thenBlock <- m Name
forall (m :: * -> *). MonadIRBuilder m => m Name
IRM.block m Name -> ShortByteString -> m Name
forall (m :: * -> *) r.
MonadIRBuilder m =>
m r -> ShortByteString -> m r
`IRM.named` String -> ShortByteString
U.stringToByteString String
"if.then"
  Operand
thenVal <- Expr -> m Operand
forall a (m :: * -> *).
(ExprGen a, MonadCodegen m) =>
a -> m Operand
forall (m :: * -> *). MonadCodegen m => Expr -> m Operand
EG.generateExpr Expr
thenExpr
  Bool
thenTerminated <- m Bool
forall (m :: * -> *). MonadIRBuilder m => m Bool
IRM.hasTerminator
  ()
_ <- Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
S.unless Bool
thenTerminated (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ Name -> m ()
forall (m :: * -> *). MonadIRBuilder m => Name -> m ()
I.br Name
mergeBlock
  Name
thenBlockName <- m Name
forall (m :: * -> *). MonadIRBuilder m => m Name
IRM.currentBlock

  Name
elseBlock <- m Name
forall (m :: * -> *). MonadIRBuilder m => m Name
IRM.block m Name -> ShortByteString -> m Name
forall (m :: * -> *) r.
MonadIRBuilder m =>
m r -> ShortByteString -> m r
`IRM.named` String -> ShortByteString
U.stringToByteString String
"if.else"
  Operand
elseVal <- case Maybe Expr
elseExpr of
    Just Expr
e -> Expr -> m Operand
forall a (m :: * -> *).
(ExprGen a, MonadCodegen m) =>
a -> m Operand
forall (m :: * -> *). MonadCodegen m => Expr -> m Operand
EG.generateExpr Expr
e
    Maybe Expr
Nothing -> Operand -> m Operand
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Constant -> Operand
AST.ConstantOperand (Constant -> Operand) -> Constant -> Operand
forall a b. (a -> b) -> a -> b
$ Type -> Constant
C.Undef Type
T.void)
  Bool
elseTerminated <- m Bool
forall (m :: * -> *). MonadIRBuilder m => m Bool
IRM.hasTerminator
  Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
S.unless Bool
elseTerminated (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ Name -> m ()
forall (m :: * -> *). MonadIRBuilder m => Name -> m ()
I.br Name
mergeBlock
  Name
elseBlockName <- m Name
forall (m :: * -> *). MonadIRBuilder m => m Name
IRM.currentBlock

  Name
mergeBlock <- m Name
forall (m :: * -> *). MonadIRBuilder m => m Name
IRM.block m Name -> ShortByteString -> m Name
forall (m :: * -> *) r.
MonadIRBuilder m =>
m r -> ShortByteString -> m r
`IRM.named` String -> ShortByteString
U.stringToByteString String
"if.merge"
  let validBrs :: [(Operand, Name)]
validBrs =
        [(Operand
thenVal, Name
thenBlockName) | Bool -> Bool
not Bool
thenTerminated]
          [(Operand, Name)] -> [(Operand, Name)] -> [(Operand, Name)]
forall a. [a] -> [a] -> [a]
++ [(Operand
elseVal, Name
elseBlockName) | Bool -> Bool
not Bool
elseTerminated]
  case [(Operand, Name)]
validBrs of
    [] -> Operand -> m Operand
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Operand -> m Operand) -> Operand -> m Operand
forall a b. (a -> b) -> a -> b
$ Constant -> Operand
AST.ConstantOperand (Type -> Constant
C.Undef Type
T.void)
    [(Operand
v, Name
_)] -> Operand -> m Operand
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Operand
v
    [(Operand, Name)]
_ -> [(Operand, Name)] -> m Operand
forall (m :: * -> *).
MonadIRBuilder m =>
[(Operand, Name)] -> m Operand
I.phi [(Operand, Name)]
validBrs
generateIf Expr
expr =
  CodegenError -> m Operand
forall a. CodegenError -> m a
forall e (m :: * -> *) a. MonadError e m => e -> m a
E.throwError (CodegenError -> m Operand) -> CodegenError -> m Operand
forall a b. (a -> b) -> a -> b
$ SrcLoc -> CodegenErrorType -> CodegenError
CC.CodegenError (Expr -> SrcLoc
SU.getLoc Expr
expr) (CodegenErrorType -> CodegenError)
-> CodegenErrorType -> CodegenError
forall a b. (a -> b) -> a -> b
$ Expr -> CodegenErrorType
CC.UnsupportedDefinition Expr
expr

-- | Generate LLVM code for from loops.
generateFromLoop :: (CS.MonadCodegen m, EG.ExprGen AT.Expr) => AT.Expr -> m AST.Operand
generateFromLoop :: forall (m :: * -> *).
(MonadCodegen m, ExprGen Expr) =>
Expr -> m Operand
generateFromLoop (AT.From SrcLoc
loc Expr
_ Expr
endExpr Expr
stepExpr declExpr :: Expr
declExpr@(AT.Declaration SrcLoc
_ String
varName Type
varType Maybe Expr
_) Expr
bodyExpr) = mdo
  Operand
_ <- Expr -> m Operand
forall a (m :: * -> *).
(ExprGen a, MonadCodegen m) =>
a -> m Operand
forall (m :: * -> *). MonadCodegen m => Expr -> m Operand
EG.generateExpr Expr
declExpr
  Name -> m ()
forall (m :: * -> *). MonadIRBuilder m => Name -> m ()
I.br Name
condBlock

  Name
condBlock <- m Name
forall (m :: * -> *). MonadIRBuilder m => m Name
IRM.block m Name -> ShortByteString -> m Name
forall (m :: * -> *) r.
MonadIRBuilder m =>
m r -> ShortByteString -> m r
`IRM.named` String -> ShortByteString
U.stringToByteString String
"for.cond"
  Operand
condVal <- Expr -> m Operand
forall a (m :: * -> *).
(ExprGen a, MonadCodegen m) =>
a -> m Operand
forall (m :: * -> *). MonadCodegen m => Expr -> m Operand
EG.generateExpr (Expr -> m Operand) -> Expr -> m Operand
forall a b. (a -> b) -> a -> b
$ SrcLoc -> Operation -> Expr -> Expr -> Expr
AT.Op SrcLoc
loc Operation
AT.Gt Expr
endExpr Expr
zeroExpr
  Operand
boolCondVal <- SrcLoc -> Operand -> m Operand
forall (m :: * -> *).
MonadCodegen m =>
SrcLoc -> Operand -> m Operand
CC.toBool SrcLoc
loc Operand
condVal
  Operand -> Name -> Name -> m ()
forall (m :: * -> *).
MonadIRBuilder m =>
Operand -> Name -> Name -> m ()
I.condBr Operand
boolCondVal Name
forwardBlock Name
backwardBlock

  Name
forwardBlock <- m Name
forall (m :: * -> *). MonadIRBuilder m => m Name
IRM.block m Name -> ShortByteString -> m Name
forall (m :: * -> *) r.
MonadIRBuilder m =>
m r -> ShortByteString -> m r
`IRM.named` String -> ShortByteString
U.stringToByteString String
"for.cond.forward"
  Operand
forwardVal <- Expr -> m Operand
forall a (m :: * -> *).
(ExprGen a, MonadCodegen m) =>
a -> m Operand
forall (m :: * -> *). MonadCodegen m => Expr -> m Operand
EG.generateExpr (Expr -> m Operand) -> Expr -> m Operand
forall a b. (a -> b) -> a -> b
$ SrcLoc -> Operation -> Expr -> Expr -> Expr
AT.Op SrcLoc
loc Operation
AT.Lt Expr
varExpr Expr
endExpr
  Operand
boolForwardVal <- SrcLoc -> Operand -> m Operand
forall (m :: * -> *).
MonadCodegen m =>
SrcLoc -> Operand -> m Operand
CC.toBool SrcLoc
loc Operand
forwardVal
  Operand -> Name -> Name -> m ()
forall (m :: * -> *).
MonadIRBuilder m =>
Operand -> Name -> Name -> m ()
I.condBr Operand
boolForwardVal Name
bodyBlock Name
exitBlock

  Name
backwardBlock <- m Name
forall (m :: * -> *). MonadIRBuilder m => m Name
IRM.block m Name -> ShortByteString -> m Name
forall (m :: * -> *) r.
MonadIRBuilder m =>
m r -> ShortByteString -> m r
`IRM.named` String -> ShortByteString
U.stringToByteString String
"for.cond.backward"
  Operand
backwardVal <- Expr -> m Operand
forall a (m :: * -> *).
(ExprGen a, MonadCodegen m) =>
a -> m Operand
forall (m :: * -> *). MonadCodegen m => Expr -> m Operand
EG.generateExpr (Expr -> m Operand) -> Expr -> m Operand
forall a b. (a -> b) -> a -> b
$ SrcLoc -> Operation -> Expr -> Expr -> Expr
AT.Op SrcLoc
loc Operation
AT.Gt Expr
varExpr Expr
endExpr
  Operand
boolBackwardVal <- SrcLoc -> Operand -> m Operand
forall (m :: * -> *).
MonadCodegen m =>
SrcLoc -> Operand -> m Operand
CC.toBool SrcLoc
loc Operand
backwardVal
  Operand -> Name -> Name -> m ()
forall (m :: * -> *).
MonadIRBuilder m =>
Operand -> Name -> Name -> m ()
I.condBr Operand
boolBackwardVal Name
bodyBlock Name
exitBlock

  Name
bodyBlock <- m Name
forall (m :: * -> *). MonadIRBuilder m => m Name
IRM.block m Name -> ShortByteString -> m Name
forall (m :: * -> *) r.
MonadIRBuilder m =>
m r -> ShortByteString -> m r
`IRM.named` String -> ShortByteString
U.stringToByteString String
"for.body"
  LoopState
oldLoopState <- (CodegenState -> LoopState) -> m LoopState
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
S.gets CodegenState -> LoopState
CS.loopState
  (CodegenState -> CodegenState) -> m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
S.modify (\CodegenState
s -> CodegenState
s {loopState :: LoopState
CS.loopState = (Name, Name) -> LoopState
forall a. a -> Maybe a
Just (Name
stepBlock, Name
exitBlock)})

  Operand
_ <- Expr -> m Operand
forall a (m :: * -> *).
(ExprGen a, MonadCodegen m) =>
a -> m Operand
forall (m :: * -> *). MonadCodegen m => Expr -> m Operand
EG.generateExpr Expr
bodyExpr

  (CodegenState -> CodegenState) -> m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
S.modify (\CodegenState
s -> CodegenState
s {loopState :: LoopState
CS.loopState = LoopState
oldLoopState})
  Name -> m ()
forall (m :: * -> *). MonadIRBuilder m => Name -> m ()
I.br Name
stepBlock

  Name
stepBlock <- m Name
forall (m :: * -> *). MonadIRBuilder m => m Name
IRM.block m Name -> ShortByteString -> m Name
forall (m :: * -> *) r.
MonadIRBuilder m =>
m r -> ShortByteString -> m r
`IRM.named` String -> ShortByteString
U.stringToByteString String
"for.step"
  Operand
_ <- Expr -> m Operand
forall a (m :: * -> *).
(ExprGen a, MonadCodegen m) =>
a -> m Operand
forall (m :: * -> *). MonadCodegen m => Expr -> m Operand
EG.generateExpr Expr
stepExpr
  Name -> m ()
forall (m :: * -> *). MonadIRBuilder m => Name -> m ()
I.br Name
condBlock

  Name
exitBlock <- m Name
forall (m :: * -> *). MonadIRBuilder m => m Name
IRM.block m Name -> ShortByteString -> m Name
forall (m :: * -> *) r.
MonadIRBuilder m =>
m r -> ShortByteString -> m r
`IRM.named` String -> ShortByteString
U.stringToByteString String
"for.exit"
  Operand -> m Operand
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Operand -> m Operand) -> Operand -> m Operand
forall a b. (a -> b) -> a -> b
$ Constant -> Operand
AST.ConstantOperand (Constant -> Operand) -> Constant -> Operand
forall a b. (a -> b) -> a -> b
$ Type -> Constant
C.Null Type
T.i8
  where
    varExpr :: Expr
varExpr = SrcLoc -> String -> Type -> Expr
AT.Var SrcLoc
loc String
varName Type
varType
    zeroExpr :: Expr
zeroExpr = SrcLoc -> Literal -> Expr
AT.Lit SrcLoc
loc (Integer -> Literal
AT.LInt Integer
0)
generateFromLoop Expr
expr =
  CodegenError -> m Operand
forall a. CodegenError -> m a
forall e (m :: * -> *) a. MonadError e m => e -> m a
E.throwError (CodegenError -> m Operand) -> CodegenError -> m Operand
forall a b. (a -> b) -> a -> b
$ SrcLoc -> CodegenErrorType -> CodegenError
CC.CodegenError (Expr -> SrcLoc
SU.getLoc Expr
expr) (CodegenErrorType -> CodegenError)
-> CodegenErrorType -> CodegenError
forall a b. (a -> b) -> a -> b
$ Expr -> CodegenErrorType
CC.UnsupportedForDefinition Expr
expr

-- | Generate LLVM code for while loops.
generateWhileLoop :: (CS.MonadCodegen m, EG.ExprGen AT.Expr) => AT.Expr -> m AST.Operand
generateWhileLoop :: forall (m :: * -> *).
(MonadCodegen m, ExprGen Expr) =>
Expr -> m Operand
generateWhileLoop (AT.While SrcLoc
loc Expr
condExpr Expr
bodyExpr) = mdo
  Name -> m ()
forall (m :: * -> *). MonadIRBuilder m => Name -> m ()
I.br Name
condBlock

  Name
condBlock <- m Name
forall (m :: * -> *). MonadIRBuilder m => m Name
IRM.block m Name -> ShortByteString -> m Name
forall (m :: * -> *) r.
MonadIRBuilder m =>
m r -> ShortByteString -> m r
`IRM.named` String -> ShortByteString
U.stringToByteString String
"while.cond"
  Operand
condVal <- Expr -> m Operand
forall a (m :: * -> *).
(ExprGen a, MonadCodegen m) =>
a -> m Operand
forall (m :: * -> *). MonadCodegen m => Expr -> m Operand
EG.generateExpr Expr
condExpr
  Operand
boolCondVal <- SrcLoc -> Operand -> m Operand
forall (m :: * -> *).
MonadCodegen m =>
SrcLoc -> Operand -> m Operand
CC.toBool SrcLoc
loc Operand
condVal
  Operand -> Name -> Name -> m ()
forall (m :: * -> *).
MonadIRBuilder m =>
Operand -> Name -> Name -> m ()
I.condBr Operand
boolCondVal Name
bodyBlock Name
exitBlock

  Name
bodyBlock <- m Name
forall (m :: * -> *). MonadIRBuilder m => m Name
IRM.block m Name -> ShortByteString -> m Name
forall (m :: * -> *) r.
MonadIRBuilder m =>
m r -> ShortByteString -> m r
`IRM.named` String -> ShortByteString
U.stringToByteString String
"while.body"
  LoopState
oldLoopState <- (CodegenState -> LoopState) -> m LoopState
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
S.gets CodegenState -> LoopState
CS.loopState
  (CodegenState -> CodegenState) -> m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
S.modify (\CodegenState
s -> CodegenState
s {loopState :: LoopState
CS.loopState = (Name, Name) -> LoopState
forall a. a -> Maybe a
Just (Name
condBlock, Name
exitBlock)})

  Operand
_ <- Expr -> m Operand
forall a (m :: * -> *).
(ExprGen a, MonadCodegen m) =>
a -> m Operand
forall (m :: * -> *). MonadCodegen m => Expr -> m Operand
EG.generateExpr Expr
bodyExpr

  (CodegenState -> CodegenState) -> m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
S.modify (\CodegenState
s -> CodegenState
s {loopState :: LoopState
CS.loopState = LoopState
oldLoopState})
  Bool
bodyTerminated <- m Bool
forall (m :: * -> *). MonadIRBuilder m => m Bool
IRM.hasTerminator
  Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
CM.unless Bool
bodyTerminated (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ Name -> m ()
forall (m :: * -> *). MonadIRBuilder m => Name -> m ()
I.br Name
condBlock

  Name
exitBlock <- m Name
forall (m :: * -> *). MonadIRBuilder m => m Name
IRM.block m Name -> ShortByteString -> m Name
forall (m :: * -> *) r.
MonadIRBuilder m =>
m r -> ShortByteString -> m r
`IRM.named` String -> ShortByteString
U.stringToByteString String
"while.exit"
  Operand -> m Operand
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Operand -> m Operand) -> Operand -> m Operand
forall a b. (a -> b) -> a -> b
$ Constant -> Operand
AST.ConstantOperand (Constant -> Operand) -> Constant -> Operand
forall a b. (a -> b) -> a -> b
$ Type -> Constant
C.Null Type
T.i8
generateWhileLoop Expr
expr =
  CodegenError -> m Operand
forall a. CodegenError -> m a
forall e (m :: * -> *) a. MonadError e m => e -> m a
E.throwError (CodegenError -> m Operand) -> CodegenError -> m Operand
forall a b. (a -> b) -> a -> b
$ SrcLoc -> CodegenErrorType -> CodegenError
CC.CodegenError (Expr -> SrcLoc
SU.getLoc Expr
expr) (CodegenErrorType -> CodegenError)
-> CodegenErrorType -> CodegenError
forall a b. (a -> b) -> a -> b
$ Expr -> CodegenErrorType
CC.UnsupportedWhileDefinition Expr
expr

-- | Generate LLVM code for break statements.
generateBreak :: (CS.MonadCodegen m, EG.ExprGen AT.Expr) => AT.Expr -> m AST.Operand
generateBreak :: forall (m :: * -> *).
(MonadCodegen m, ExprGen Expr) =>
Expr -> m Operand
generateBreak (AT.Break SrcLoc
loc) = do
  CodegenState
state <- m CodegenState
forall s (m :: * -> *). MonadState s m => m s
S.get
  case CodegenState -> LoopState
CS.loopState CodegenState
state of
    Just (Name
_, Name
breakBlock) -> do
      Name -> m ()
forall (m :: * -> *). MonadIRBuilder m => Name -> m ()
I.br Name
breakBlock
      Operand -> m Operand
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Operand -> m Operand) -> Operand -> m Operand
forall a b. (a -> b) -> a -> b
$ Constant -> Operand
AST.ConstantOperand (Constant -> Operand) -> Constant -> Operand
forall a b. (a -> b) -> a -> b
$ Type -> Constant
C.Undef Type
T.void
    LoopState
Nothing -> CodegenError -> m Operand
forall a. CodegenError -> m a
forall e (m :: * -> *) a. MonadError e m => e -> m a
E.throwError (CodegenError -> m Operand) -> CodegenError -> m Operand
forall a b. (a -> b) -> a -> b
$ SrcLoc -> CodegenErrorType -> CodegenError
CC.CodegenError SrcLoc
loc CodegenErrorType
CC.BreakOutsideLoop
generateBreak Expr
expr =
  CodegenError -> m Operand
forall a. CodegenError -> m a
forall e (m :: * -> *) a. MonadError e m => e -> m a
E.throwError (CodegenError -> m Operand) -> CodegenError -> m Operand
forall a b. (a -> b) -> a -> b
$ SrcLoc -> CodegenErrorType -> CodegenError
CC.CodegenError (Expr -> SrcLoc
SU.getLoc Expr
expr) (CodegenErrorType -> CodegenError)
-> CodegenErrorType -> CodegenError
forall a b. (a -> b) -> a -> b
$ Expr -> CodegenErrorType
CC.UnsupportedDefinition Expr
expr

-- | Generate LLVM code for continue statements.
generateContinue :: (CS.MonadCodegen m, EG.ExprGen AT.Expr) => AT.Expr -> m AST.Operand
generateContinue :: forall (m :: * -> *).
(MonadCodegen m, ExprGen Expr) =>
Expr -> m Operand
generateContinue (AT.Continue SrcLoc
loc) = do
  CodegenState
state <- m CodegenState
forall s (m :: * -> *). MonadState s m => m s
S.get
  case CodegenState -> LoopState
CS.loopState CodegenState
state of
    Just (Name
continueBlock, Name
_) -> do
      Name -> m ()
forall (m :: * -> *). MonadIRBuilder m => Name -> m ()
I.br Name
continueBlock
      Operand -> m Operand
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Operand -> m Operand) -> Operand -> m Operand
forall a b. (a -> b) -> a -> b
$ Constant -> Operand
AST.ConstantOperand (Constant -> Operand) -> Constant -> Operand
forall a b. (a -> b) -> a -> b
$ Type -> Constant
C.Undef Type
T.void
    LoopState
Nothing -> CodegenError -> m Operand
forall a. CodegenError -> m a
forall e (m :: * -> *) a. MonadError e m => e -> m a
E.throwError (CodegenError -> m Operand) -> CodegenError -> m Operand
forall a b. (a -> b) -> a -> b
$ SrcLoc -> CodegenErrorType -> CodegenError
CC.CodegenError SrcLoc
loc CodegenErrorType
CC.ContinueOutsideLoop
generateContinue Expr
expr =
  CodegenError -> m Operand
forall a. CodegenError -> m a
forall e (m :: * -> *) a. MonadError e m => e -> m a
E.throwError (CodegenError -> m Operand) -> CodegenError -> m Operand
forall a b. (a -> b) -> a -> b
$ SrcLoc -> CodegenErrorType -> CodegenError
CC.CodegenError (Expr -> SrcLoc
SU.getLoc Expr
expr) (CodegenErrorType -> CodegenError)
-> CodegenErrorType -> CodegenError
forall a b. (a -> b) -> a -> b
$ Expr -> CodegenErrorType
CC.UnsupportedDefinition Expr
expr

-- | Generate LLVM code for return statements.
generateReturn :: (CS.MonadCodegen m, EG.ExprGen AT.Expr) => AT.Expr -> m AST.Operand
generateReturn :: forall (m :: * -> *).
(MonadCodegen m, ExprGen Expr) =>
Expr -> m Operand
generateReturn (AT.Return SrcLoc
_ Maybe Expr
mExpr) = do
  case Maybe Expr
mExpr of
    Just Expr
expr -> do
      Operand
result <- Expr -> m Operand
forall a (m :: * -> *).
(ExprGen a, MonadCodegen m) =>
a -> m Operand
forall (m :: * -> *). MonadCodegen m => Expr -> m Operand
EG.generateExpr Expr
expr
      Operand -> m ()
forall (m :: * -> *). MonadIRBuilder m => Operand -> m ()
I.ret Operand
result
      Operand -> m Operand
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Operand
result
    Maybe Expr
Nothing -> do
      m ()
forall (m :: * -> *). MonadIRBuilder m => m ()
I.retVoid
      Operand -> m Operand
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Operand -> m Operand) -> Operand -> m Operand
forall a b. (a -> b) -> a -> b
$ Constant -> Operand
AST.ConstantOperand (Constant -> Operand) -> Constant -> Operand
forall a b. (a -> b) -> a -> b
$ Type -> Constant
C.Undef Type
T.void
generateReturn Expr
expr =
  CodegenError -> m Operand
forall a. CodegenError -> m a
forall e (m :: * -> *) a. MonadError e m => e -> m a
E.throwError (CodegenError -> m Operand) -> CodegenError -> m Operand
forall a b. (a -> b) -> a -> b
$ SrcLoc -> CodegenErrorType -> CodegenError
CC.CodegenError (Expr -> SrcLoc
SU.getLoc Expr
expr) (CodegenErrorType -> CodegenError)
-> CodegenErrorType -> CodegenError
forall a b. (a -> b) -> a -> b
$ Expr -> CodegenErrorType
CC.UnsupportedDefinition Expr
expr

-- | Generate LLVM code for blocks.
generateBlock :: (CS.MonadCodegen m, EG.ExprGen AT.Expr) => AT.Expr -> m AST.Operand
generateBlock :: forall (m :: * -> *).
(MonadCodegen m, ExprGen Expr) =>
Expr -> m Operand
generateBlock (AT.Block []) = Operand -> m Operand
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Operand -> m Operand) -> Operand -> m Operand
forall a b. (a -> b) -> a -> b
$ Constant -> Operand
AST.ConstantOperand (Constant -> Operand) -> Constant -> Operand
forall a b. (a -> b) -> a -> b
$ Type -> Constant
C.Undef Type
T.void
generateBlock (AT.Block [Expr]
exprs) = do
  [Operand] -> Operand
forall a. HasCallStack => [a] -> a
last ([Operand] -> Operand) -> m [Operand] -> m Operand
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Expr -> m Operand) -> [Expr] -> m [Operand]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> [a] -> f [b]
traverse Expr -> m Operand
forall a (m :: * -> *).
(ExprGen a, MonadCodegen m) =>
a -> m Operand
forall (m :: * -> *). MonadCodegen m => Expr -> m Operand
EG.generateExpr [Expr]
exprs
generateBlock Expr
expr =
  CodegenError -> m Operand
forall a. CodegenError -> m a
forall e (m :: * -> *) a. MonadError e m => e -> m a
E.throwError (CodegenError -> m Operand) -> CodegenError -> m Operand
forall a b. (a -> b) -> a -> b
$ SrcLoc -> CodegenErrorType -> CodegenError
CC.CodegenError (Expr -> SrcLoc
SU.getLoc Expr
expr) (CodegenErrorType -> CodegenError)
-> CodegenErrorType -> CodegenError
forall a b. (a -> b) -> a -> b
$ Expr -> CodegenErrorType
CC.UnsupportedDefinition Expr
expr