packages feed

grisette-0.12.0.0: src/Grisette/Internal/TH/Derivation/ShowPPrintCommon.hs

{-# LANGUAGE TemplateHaskell #-}

-- |
-- Module      :   Grisette.Internal.TH.Derivation.ShowPPrintCommon
-- Copyright   :   (c) Sirui Lu 2024
-- License     :   BSD-3-Clause (see the LICENSE file)
--
-- Maintainer  :   siruilu@cs.washington.edu
-- Stability   :   Experimental
-- Portability :   GHC only
module Grisette.Internal.TH.Derivation.ShowPPrintCommon (showPrintFieldFunExp) where

import qualified Data.Map as M
import qualified Data.Set as S
import Grisette.Internal.TH.Derivation.UnaryOpCommon (FieldFunExp)
import Language.Haskell.TH (Name, Type (AppT, VarT), varE)
import Language.Haskell.TH.Datatype (TypeSubstitution (freeVariables))

-- | Common 'FieldFunExp' for 'Show' and 'Grisette.Core.PPrint' on a GADT.
showPrintFieldFunExp :: [Name] -> [Name] -> FieldFunExp
showPrintFieldFunExp precNames listNames argToFunPat liftedExps = go
  where
    allArgNames = M.keysSet argToFunPat
    typeHasNoArg ty =
      S.fromList (freeVariables [ty])
        `S.intersection` allArgNames
        == S.empty
    goLst ty = do
      let fun0 = varE (head listNames)
          fun1 b = [|$(varE $ listNames !! 1) $(go b) $(goLst b)|]
          fun2 b c =
            [|$(varE $ listNames !! 2) $(go b) $(goLst b) $(go c) $(goLst c)|]
      case ty of
        AppT (AppT (VarT _) b) c -> fun2 b c
        AppT (VarT _) b -> fun1 b
        _ | typeHasNoArg ty -> fun0
        AppT a b | typeHasNoArg a -> fun1 b
        AppT (AppT a b) c | typeHasNoArg a -> fun2 b c
        VarT nm -> case M.lookup nm liftedExps of
          Just [p] -> varE p
          _ -> fail $ "defaultFieldFunExp: unsupported type: " <> show ty
        _ -> fail $ "defaultFieldFunExp: unsupported type: " <> show ty
    go ty = do
      let fun0 = varE (head precNames)
          fun1 b = [|$(varE $ precNames !! 1) $(go b) $(goLst b)|]
          fun2 b c =
            [|$(varE $ precNames !! 2) $(go b) $(goLst b) $(go c) $(goLst c)|]
      case ty of
        AppT (AppT (VarT _) b) c -> fun2 b c
        AppT (VarT _) b -> fun1 b
        _ | typeHasNoArg ty -> fun0
        AppT a b | typeHasNoArg a -> fun1 b
        AppT (AppT a b) c | typeHasNoArg a -> fun2 b c
        VarT nm -> case M.lookup nm argToFunPat of
          Just pname -> varE pname
          _ -> fail $ "defaultFieldFunExp: unsupported type: " <> show ty
        _ -> fail $ "defaultFieldFunExp: unsupported type: " <> show ty