Hs2lib-0.4.8: WinDll/Shared/Remapper.hs
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE IncoherentInstances #-}
-----------------------------------------------------------------------------
-- |
-- Module : Windll
-- Copyright : (c) Tamar Christina 2009 - 2010
-- License : BSD3
--
-- Maintainer : tamar@zhox.com
-- Stability : experimental
-- Portability : portable
--
-- A module to convert one datatype to another isomorphic datatype.
--
-----------------------------------------------------------------------------
module WinDll.Shared.Remapper where
import Data.Data hiding (DataType)
import Data.Typeable
import Data.Generics hiding (DataType)
import Foreign
import WinDll.Lib.NativeMapping
import WinDll.Structs.Structures
-- | Get the number of fields of a constructor
nrArgs :: Data a => a -> Int
nrArgs = gmapQr (+) 0 (const 1)
-- | Convert at runtime back and forth between *simple* data structures. (Enums only). For more complex types the compiler generates the structures. This is usefull for when the preprocessor does not have the source readily available
isoConvert :: (Data a, Data b) => a -> b
isoConvert a = let conDest i = indexConstr (dataTypeOf result) i
constIndex = constrRep $ toConstr a
result = case constIndex of
(AlgConstr i) -> fromConstr (conDest i)
rest -> fromConstr (repConstr (dataTypeOf result) rest)
in result
-- | Class to manage the convertions that the parser generates
class FFIType a b => IsoConvert a b where
convertTo :: a -> b
convertFrom :: b -> a
-- | Same types are always convertable to eachother, because they implement FFITypes
instance Num a => IsoConvert a a where
convertTo = id
convertFrom = id
-- | Boolean types can also be converted, yay
instance IsoConvert Bool Bool where
convertTo = id
convertFrom = id
-- | Creating of pointer type should also always be possible (this instance is redundant, FFITypes also provides this conversion, however, since we'll use IsoConvert for all type conversions, this instances simplifies things)
instance Storable a => IsoConvert a (Ptr a) where
convertTo = toFFI
convertFrom = fromFFI
-- data DataType = DataType Name [Type] [DataType]
-- | NewType Name [Type] DataType
-- | Constr Name [Type]
-- | generate the isomorphic convertion from and between the two type given and the associated FFI type
createDataTypeIsoMorphism :: DataType -> String
createDataTypeIsoMorphism d@(DataType name types consts tag) = unlines $ (genInstance d) : (createFromDataIsoConvert name types consts) : []
createDataTypeIsoMorphism d@(NewType name types cons tag ) = unlines $ (genInstance d) : (createFromDataIsoConvert name types [cons]) : []
createDataTypeIsoMorphism (Constr name typevars ) = []
-- | Create the from Convertion function
createFromDataIsoConvert :: Name -> Types -> DataTypes -> String
createFromDataIsoConvert name types datatypes = []
-- | Generate the instance declaration
genInstance :: DataType -> String
genInstance (DataType name types _ _) = internalGenInstance name types
genInstance (NewType name types _ _ ) = internalGenInstance name types
genInstance (Constr _ _ ) = error "Called GenInstance on a constructor"
internalGenInstance :: Name -> [Type] -> String
internalGenInstance name types =
unlines $
(case null types of
True -> "instance IsoConvert " ++ name ++ " T" ++ name ++ " where"
False -> "instance FFYType " ++ listTypesUsing " " types ++ " => IsoConvert (" ++ name ++ " " ++ listTypesUsing " " types ++ ") (T" ++ name ++ " " ++ listTypesUsing " " types ++ ") where")
: [" convertTo = toT" ++ name," convertFrom = fromT" ++ name]
-- | Converts a list of Types to a string to be printed to file.
listTypesUsing :: String -> [Type] -> String
listTypesUsing _ [] = []
listTypesUsing f types = foldl1 (\a b->a++f++b) types