clr-inline-0.2.0.1: src/Clr/Inline/Types/Quote.hs
{-# LANGUAGE PartialTypeSignatures #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeInType #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ViewPatterns #-}
{-# OPTIONS -Wno-partial-type-signatures #-}
module Clr.Inline.Types.Quote
( Quotable
, lookupDelegateMarshalType
, lookupQuotableClrType
, MarshalType
, lookupQuotableMarshalType
, lookupQuotableUnmarshalType
) where
import Clr.Host.BStr
import Clr.Marshal
import Clr.Inline.Types
import Data.Int
import Data.Maybe
import Data.Monoid
import Data.Text (Text)
import Data.Word
import GHC.TypeLits
import Language.Haskell.TH
import Text.Printf
-- | Extensible mapping between quotable CLR types and Haskell types
class Unmarshal marshal unmarshal =>
Quotable (quoted::Symbol) (clr::Symbol) marshal unmarshal
instance Quotable "bool" "System.Boolean" Bool Bool
instance Quotable "double" "System.Double" Double Double
instance Quotable "int" "System.Int32" Int Int
instance Quotable "int16" "System.Int16" Int16 Int16
instance Quotable "int32" "System.Int32" Int32 Int32
instance Quotable "int64" "System.Int64" Int64 Int64
instance Quotable "long" "System.Int64" Int64 Int64
instance Quotable "uint16" "System.UInt16" Word16 Word16
instance Quotable "word16" "System.UInt16" Word16 Word16
instance Quotable "uint32" "System.UInt32" Word32 Word32
instance Quotable "word32" "System.UInt32" Word32 Word32
instance Quotable "uint64" "System.UInt64" Word64 Word64
instance Quotable "word64" "System.UInt64" Word64 Word64
instance Quotable "string" "System.String" BStr String
instance Quotable "text" "System.String" TextBStr Text
instance Quotable "void" "System.Void" () ()
instance Quotable "unit" "Microsoft.FSharp.Core.Unit" () ()
-- | All reference types are handled by this instance.
instance Quotable a a (ClrPtr a) (Clr a)
lookupQuotable :: Show a => ([InstanceDec] -> a) -> String -> Q a
lookupQuotable extract quote = do
let ty = LitT (StrTyLit quote)
a <- newName "clr"
b <- newName "rep"
c <- newName "haskell"
instances <- reifyInstances ''Quotable [ ty, VarT a, VarT b, VarT c ]
return $ extract instances
handleOverlappingInstances :: String -> String -> [Dec] -> a
handleOverlappingInstances msg s instances = error $ printf "Overlapping %s instances for Quotable %s: %s" msg s (show names) -- (show instances)
where
names = [ quote | InstanceD _ _ (_ `AppT` quote `AppT` _ `AppT` _ `AppT` _) _ <- instances ]
extractMostSpecificInstance :: String -> String -> _ -> _ -> [Dec] -> _
extractMostSpecificInstance s msg f1 f2 instances =
fromMaybe (handleOverlappingInstances msg s instances) . getFirst $
foldMap (apply f1) instances <> foldMap (apply f2) instances
where
apply f (InstanceD _ _ (_ `AppT` quote `AppT` clr `AppT` marshal `AppT` unmarshal) _) = First $ f quote clr marshal unmarshal
apply _ _ = error "unreachable"
lookupQuotableClrType :: String -> Q ClrTypeSymbol
lookupQuotableClrType s = lookupQuotable extract s
where
extract = extractMostSpecificInstance s "Clr" specific general
specific _ (LitT (StrTyLit s)) _ _ = Just $ ClrTypeSymbol s
specific _ _ _ _ = Nothing
general quote@VarT{} clr@VarT{} _ _ | quote == clr = Just $ ClrTypeSymbol s
general _ _ _ _ = Nothing
type MarshalType = Type
lookupQuotableMarshalType :: String -> Q MarshalType
lookupQuotableMarshalType s = lookupQuotable extract s
where
extract = extractMostSpecificInstance s "Marshal" specific general
specific LitT{} LitT{} marshalTy _ = Just marshalTy
specific _ _ _ _ = Nothing
general quote@VarT{} clr@VarT{} (con `AppT` v) _ | quote == clr && quote == v= Just $ AppT con (LitT (StrTyLit s))
general _ _ _ _ = Nothing
lookupDelegateMarshalType :: [String] -> TypeQ -> Q MarshalType
lookupDelegateMarshalType args resTy =
foldr (\t u -> arrowT `appT` lookupQuotableMarshalType t `appT` u) [t| IO $(resTy) |] args
lookupQuotableUnmarshalType :: String -> Q Type
lookupQuotableUnmarshalType s = lookupQuotable extract s
where
extract = extractMostSpecificInstance s "Unmarshal" specific general
specific LitT{} LitT{} _ unmarshalTy = Just unmarshalTy
specific _ _ _ _ = Nothing
general quote@VarT{} clr@VarT{} _ (con `AppT` v) | quote == clr && quote == v = Just $ AppT con (LitT (StrTyLit s))
general _ _ _ _ = Nothing