packages feed

clash-protocols-base-0.1: src/Protocols/Plugin/TaggedBundle/TH.hs

{-# OPTIONS_HADDOCK hide #-}

module Protocols.Plugin.TaggedBundle.TH where

import Data.Tagged
import Language.Haskell.TH

appTs :: Q Type -> [Q Type] -> Q Type
appTs = foldl appT

tupT :: [Q Type] -> Q Type
tupT tyArgs = tupleT (length tyArgs) `appTs` tyArgs

taggedBundleTupleInstances :: Int -> Q [Dec]
taggedBundleTupleInstances n = mapM taggedBundleTupleInstance [3 .. n]

taggedBundleTupleInstance :: Int -> Q Dec
taggedBundleTupleInstance n =
  instanceD
    -- No superclasses
    (pure [])
    -- Head
    ( taggedBundleCon
        `appT` (tupleT n `appTs` tagTyVars)
        `appT` (tupleT n `appTs` tyVars)
    )
    -- Implementation
    [ tySynInstD (tySynEqn Nothing aTypeLhs aTypeRhs)
    , funD taggedBundleFunName [clause [bundlePat] (normalB bundleImpl) []]
    , funD taggedUnbundleFunName [clause [unbundlePat] (normalB unbundleImpl) []]
    ]
 where
  -- associated type
  taggedUnbundledCon = conT (mkName "TaggedUnbundled")
  taggedBundleCon = conT (mkName "TaggedBundle")
  aTypeLhs = taggedUnbundledCon `appT` tupT tagTyVars `appT` tupT tyVars
  aTypeRhs = tupT (zipWith mkTaggedTy tagTyVars tyVars)
  mkTaggedTy ta a = conT ''Tagged `appT` ta `appT` a

  -- bundle
  taggedBundleFunName = mkName "taggedBundle"
  bundlePat = tupP (map (conP 'Tagged . pure . varP) varNames)
  bundleImpl = conE 'Tagged `appE` tupE vars

  -- unbundle
  taggedUnbundleFunName = mkName "taggedUnbundle"
  unbundlePat = conP 'Tagged [tupP (map varP varNames)]
  unbundleImpl = tupE [conE 'Tagged `appE` v | v <- vars]

  -- shared
  tagTyVars = map (varT . mkName . ('t' :) . show) [1 .. n]
  tyVars = map varT varNames
  vars = map varE varNames
  varNames = map (mkName . ('a' :) . show) [1 .. n]