{-# LANGUAGE QuasiQuotes #-} -- | Interface for evaluation and compilation of pure expressions module Language.Embedded.Expression ( VarId , VarPred , EvalExp(..) , CompExp(..) , freshVar , freshVar_ ) where import Data.Proxy import Data.Constraint import Language.C.Monad import Language.C.Quote.C import Language.C.Syntax (Exp,Type) import qualified Language.C.Syntax as C -- | Constraint on the types of variables in a given expression language type family VarPred (exp :: * -> *) :: * -> Constraint -- | General interface for evaluating expressions class EvalExp exp where -- | Literal expressions litExp :: VarPred exp a => a -> exp a -- | Evaluation of (closed) expressions evalExp :: exp a -> a -- | General interface for compiling expressions class CompExp exp where -- | Variable expressions varExp :: VarPred exp a => VarId -> exp a -- | Compilation of expressions -- -- /NOTE: It is assumed that free variables in the expression are rendered as @vIII@, where/ -- / @III@ is the variable identifier./ compExp :: (MonadC m) => exp a -> m Exp -- | Extract expression type compType :: forall m a . (MonadC m, VarPred exp a) => exp a -> m Type compType _ = compTypeP (Proxy :: Proxy (exp a)) {-# INLINE compType #-} -- | Extract expression type compTypeP :: forall proxy m a . (MonadC m, VarPred exp a) => proxy (exp a) -> m Type compTypeP _ = compTypePP (Proxy :: Proxy exp) (Proxy :: Proxy a) {-# INLINE compTypeP #-} -- | Extract expression type compTypePP :: forall proxy1 proxy2 m a . (MonadC m, VarPred exp a) => proxy1 exp -> proxy2 a -> m Type compTypePP _ _ = compTypePP2 (Proxy :: Proxy exp) (Proxy :: Proxy (Proxy a)) {-# INLINE compTypePP #-} -- | Extract expression type compTypePP2 :: forall proxy proxy1 proxy2 m a . (MonadC m, VarPred exp a) => proxy exp -> proxy1 (proxy2 a) -> m Type compTypePP2 _ _ = compType (undefined :: exp a) {-# INLINE compTypePP2 #-} {-# MINIMAL varExp , compExp , (compType | compTypeP | compTypePP | compTypePP2 ) #-} -- | Variable identifier type VarId = Integer -- | Create and declare a fresh variable and return its name freshVar :: forall exp m a. (CompExp exp, VarPred exp a, MonadC m) => m (exp a, C.Id) freshVar = do v <- fmap varExp freshId t <- compTypeP (Proxy :: Proxy (exp a)) C.Var n _ <- compExp v touchVar n case t of C.Type _ C.Ptr{} _ -> addLocal [cdecl| $ty:t $id:n = NULL; |] _ -> addLocal [cdecl| $ty:t $id:n; |] return (v,n) -- | Create and declare a fresh variable freshVar_ :: forall exp m a. (CompExp exp, VarPred exp a, MonadC m) => m (exp a) freshVar_ = fst `fmap` freshVar