{-# LANGUAGE LambdaCase, TemplateHaskell #-} module Gen ( Gen , Gen' , Out(..) , outBlocks , outStrings , outFuncs , St(..) , currentBlockLabel , currentBlockInstrs , registerCount , lambdaParentFunc , outerLambdaN , Env(..) , env , dataTypes , lookupDatatype ) where import LLVM.AST import Control.Monad.Writer import Control.Monad.State import Control.Monad.Reader import qualified Data.Map as Map import Data.Map (Map) import Lens.Micro.Platform (makeLenses, view, to) import Misc import MonoAst hiding (Type, Const) data Env = Env -- TODO: Could operands in env be Val instead? I.e., either stack-allocated -- or local? { _env :: Map TypedVar Operand -- ^ Environment of stack allocated variables , _dataTypes :: Map Name Type } makeLenses ''Env data St = St { _currentBlockLabel :: Name , _currentBlockInstrs :: [Named Instruction] , _registerCount :: Word -- | Keep track of the parent function name so that we can name the -- outermost lambdas of a function definition well. , _lambdaParentFunc :: Maybe String , _outerLambdaN :: Word } makeLenses ''St type Gen' = StateT St (Reader Env) -- | The output of generating a function data Out = Out { _outBlocks :: [BasicBlock] , _outStrings :: [(Name, String)] , _outFuncs :: [(Name, [TypedVar], TypedVar, Expr)] } makeLenses ''Out type Gen = WriterT Out Gen' instance Semigroup Out where Out bs1 ss1 fs1 <> Out bs2 ss2 fs2 = Out (bs1 <> bs2) (ss1 <> ss2) (fs1 <> fs2) instance Monoid Out where mempty = Out [] [] [] lookupDatatype :: Name -> Gen' Type lookupDatatype x = view (dataTypes . to (Map.lookup x)) >>= \case Just u -> pure u Nothing -> ice $ "Undefined datatype " ++ show x