packages feed

g2-0.2.0.0: src/G2/QuasiQuotes/Support.hs

{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}

-- Converts types with Name's to types with QQNames, since uniques in the
-- QuasiQuoter will most likely not match up with uniques from the original
-- code

module G2.QuasiQuotes.Support ( QQName (..)
                              , QQMap
                              , qqMap
                              , nameToQQName
                              , thNameToQQName
                              , qqNameToName0

                              , qqAlgDataTyLookup
                              , qqDataConLookup

                              , toTHType ) where

import G2.Language as G2

import Language.Haskell.TH as TH

import GHC.Generics (Generic)
import Data.Data
import Data.Foldable
import Data.Hashable
import qualified Data.HashMap.Lazy as HM
import qualified Data.Text as T

data QQName = QQName T.Text (Maybe T.Text)
            deriving (Eq, Show, Read, Generic, Typeable, Data)

instance Hashable QQName

type QQMap = HM.HashMap QQName G2.Name

qqMap :: Named n => CleanedNames -> n -> QQMap
qqMap cn n =
    let
        ns = toList $ names n
    in
    HM.fromList $ zip (map (nameToQQName . renames cn) ns) ns

nameToQQName :: G2.Name -> QQName
nameToQQName (Name n m _ _) = QQName n m

thNameToQQName :: TH.Name -> QQName
thNameToQQName n =
    QQName (T.pack $ TH.nameBase n) (fmap T.pack $ TH.nameModule n)

-- | Maps a `QQName` to a `Name` with unique 0
qqNameToName0 :: QQName -> G2.Name
qqNameToName0 (QQName n m) = Name n m 0 Nothing

qqAlgDataTyLookup :: QQName -> QQMap -> TypeEnv -> Maybe AlgDataTy
qqAlgDataTyLookup qqn qqm tenv = flip HM.lookup tenv =<< HM.lookup qqn qqm

qqDataConLookup :: QQName -> QQName -> QQMap -> QQMap -> TypeEnv -> Maybe DataCon
qqDataConLookup qqtn qqdcn type_nm_qqm dc_nm_qqm tenv
    | Just adt <- qqAlgDataTyLookup qqtn type_nm_qqm tenv
    , Just dcn <- HM.lookup qqdcn dc_nm_qqm = dataConWithName adt dcn
    | otherwise = Nothing

toTHType :: CleanedNames -> G2.Type -> Q TH.Type
toTHType cleaned (TyFun t1 t2) = appT (appT arrowT $ toTHType cleaned t1) (toTHType cleaned t2)
toTHType cleaned (TyApp t1 t2) = appT (toTHType cleaned t1) (toTHType cleaned t2)
toTHType cleaned t@(TyCon n _)
    | nameOcc (renames cleaned n) == "List" = listT -- GHC 9.6 on
    | nameOcc (renames cleaned n) == "[]" = listT -- pre GHC 9.6
    | Just i <- tupleNum . nameOcc $ renames cleaned n = tupleT i
    | otherwise = do
        tn <- lookupTypeName . T.unpack . nameOcc $ renames cleaned n
        case tn of
            Just tn' -> conT tn'
            Nothing -> error $ "toTHType: Unhandled case\n" ++ show (renames cleaned t)
toTHType _ t = error $ "toTHType: Unhandled case\n" ++ show t

tupleNum :: T.Text -> Maybe Int
tupleNum = tupleNum' 0 . T.unpack

tupleNum' :: Int -> String -> Maybe Int
tupleNum' 0 ("()") = Just 0
tupleNum' 0 ('(':xs) = tupleNum' 1 xs
tupleNum' !n (',':xs) = tupleNum' (1 + n) xs
tupleNum' !n ")" = Just n
tupleNum' _ _ = Nothing