eventuo11y-dsl-0.2.0.0: src/Observe/Event/DSL/Compile.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE TemplateHaskellQuotes #-}
#if ! MIN_VERSION_template_haskell(2,18,0)
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeFamilies #-}
#endif
-- |
-- Description : Compile the "Observe.Event.DSL" with TemplateHaskell
-- Copyright : Copyright 2022 Shea Levy.
-- License : Apache-2.0
-- Maintainer : shea@shealevy.com
module Observe.Event.DSL.Compile (compile) where
import Control.Monad
import Data.Void
import GHC.Exts
import Language.Haskell.TH
import Observe.Event.DSL
#if ! MIN_VERSION_template_haskell(2,18,0)
type Quote m = m ~ Q
#endif
-- | Compile a 'SelectorSpec' into appropriate declarations.
compile :: (Quote m) => SelectorSpec -> m [Dec]
compile (SelectorSpec selectorNameBase selectors) = do
(selectorCtors, defs) <- foldM stepSelectors mempty selectors
let selectorDef =
DataD [] selectorName [(plainTV $ mkName "f")] Nothing selectorCtors []
pure $ selectorDef : defs
where
selectorName = mkName $ upperCamel selectorNameBase <> "Selector"
stepSelectors (selectorCtors, defs) (SelectorConstructorSpec nm NoFields) = pure (ctor : selectorCtors, defs)
where
ctor = GadtC [mkName $ upperCamel nm] [] (AppT (ConT selectorName) (ConT ''Void))
stepSelectors (selectorCtors, defs) (SelectorConstructorSpec nm (Inject t)) = pure (ctor : selectorCtors, defs)
where
varX = mkName "x"
ctor =
GadtC
[mkName $ upperCamel nm]
[(Bang NoSourceUnpackedness SourceStrict, AppT (ConT t) (VarT varX))]
(AppT (ConT selectorName) (VarT varX))
stepSelectors (selectorCtors, defs) (SelectorConstructorSpec nm (SimpleType mt)) = do
t <- toQuote mt
let ctor = GadtC [mkName $ upperCamel nm] [] (AppT (ConT selectorName) t)
pure (ctor : selectorCtors, defs)
stepSelectors (selectorCtors, defs) (SelectorConstructorSpec nm (Specified fieldSpec)) = do
(fieldName, fieldDef) <- compileFieldSpec fieldSpec
let ctor = GadtC [mkName $ upperCamel nm] [] (AppT (ConT selectorName) (ConT fieldName))
pure (ctor : selectorCtors, fieldDef : defs)
compileFieldSpec :: (Quote m) => FieldSpec -> m (Name, Dec)
compileFieldSpec (FieldSpec fieldNameBase fields) = do
ctors <- mapM fieldCtor fields
pure
( fieldName,
DataD [] fieldName [] Nothing ctors []
)
where
makeBangType mt = do
t <- toQuote mt
pure (Bang NoSourceUnpackedness SourceStrict, t)
fieldCtor (FieldConstructorSpec nm ts) = do
let margs = toList <$> mapM makeBangType ts
args <- toQuote margs
pure $ NormalC (mkName $ upperCamel nm) args
fieldName = mkName $ upperCamel fieldNameBase <> "Field"