packages feed

Hs2lib-0.5.6: WinDll/CodeGen/Lookup.hs

-----------------------------------------------------------------------------
-- |
-- Module      :  Windll
-- Copyright   :  (c) Tamar Christina 2009 - 2010
-- License     :  BSD3
-- 
-- Maintainer  :  tamar@zhox.com
-- Stability   :  experimental
-- Portability :  portable
--
-- This module contains the lookup functions to convert Haskell to
-- C import types
--
-----------------------------------------------------------------------------

module WinDll.CodeGen.Lookup where

import WinDll.Structs.MShow.MShow
import WinDll.Structs.Structures
import WinDll.Structs.Folds.HaskellSrcExts
import WinDll.Session.Hs2lib
import WinDll.Lib.Native

import Data.List
import Data.Maybe
import Data.Generics (everywhere,mkT)

import qualified Language.Haskell.Exts as Exts

type LookupType = TypeNames -> Type -> Type

-- | Lookup the correct C type of the given value
lookupC :: Defs -> TypeNames -> Type -> Type
lookupC clist vars = lookupType vars (\x->if "CBF" `isPrefixOf` x then "_t" else "_t*") id clist

-- | Lookup the correct C# type of the given value
lookupCs :: (Bool -> Defs) -> Bool -> TypeNames -> Type -> Type
lookupCs cslist struct vars = lookupType vars (\x->if "CBF" `isPrefixOf` x then "" else "*") cbf (cslist struct)
  where cbf x = if "CBF" `isPrefixOf` x then "IntPtr" else x
       
-- | A general lookup function for types
-- .
-- NOTE: This needs to be rewritten to support Applied types in datastructures
-- .
-- e.g.:  data Foo = Foo (Maybe Int)       
lookupType :: TypeNames -> (String -> String) -> (String -> String) -> [(String,String)] -> Type -> Type
lookupType vars prefix test list 
  = let f = \x->fromMaybe (if x `elem` vars
                              then "void*" 
                              else "" ++ x ++ prefix x)  
                          (lookup (test x) list)
    in everywhere (mkT (inner f))
      where
          inner :: (String -> String) -> Exts.Name -> Exts.Name
          inner f (Exts.Ident  s) = Exts.Ident (f s)
          inner f (Exts.Symbol s) = Exts.Symbol (f s)
      
-- | Break up a Haskell type into it's losely coupled components, then convert them to c types.
-- .
-- When type applications are found, they're concatinated to match their specialized variants
-- .  e.g. Maybe Int -> Maybe_int      
genAndLookupC :: Defs -> Type -> TypeNames
genAndLookupC clist t = map lookup' (collectTypes t)
    where lookup' x = case lookup x clist of
                        Nothing -> intercalate "," (words x) ++ (if "CBF" `isPrefixOf` x 
                                                                    then "_t" else "_t*")
                        Just x' -> x'
            
-- | Lookup the C type's size in the lookup table \c_sizes\, this is needed when __stdcall is used.            
lookupSize :: [(String, Int)] -> String -> Int 
lookupSize c_sizes x = maybe defaultPointerSize id (lookup x c_sizes)

-- | Generate the appropriate C types from the given Haskell type
createCType :: Defs -> Type -> TypeNames
createCType clist 
   = foldType( const . const id
             , (++)
             , (\_ b   -> return ("Tuple"++show (length b)++"_t*"))
             , (\a     -> map (\t -> if "CBF" `isPrefixOf` t then t ++ "_t" else t ++ "*") a)
             , (\a b   ->  process a b)
             , (\a     ->maybe [mkRet a] (:[]) (lookup a clist)) . mshow
             , (\a     ->maybe [mkRet a] (:[]) (lookup a clist)) . mshow
             , id -- (\a     -> map (\t -> "(" ++ t ++ ")") a) -- C types can't have braces around them
             , (\_ b _ -> return (mkRet $ mshow b))
             , (\a _   -> a)
             )
        where stripBrace ('(':xs) = init xs
              stripBrace x        = x         

              process a b = if "IO_t*" `elem` a  -- We want to ignore IO, we assume all the functions preserve ref. transparency. in the case of FFI
                               then b'
                               else if "Ptr_t*" `elem` a -- We would want to transform the explicit Ptr type to a C pointer *
                                       then map (++"*") b'
                                       else a
                   where b' = map stripBrace b 
              
              mkRet x = if "CBF" `isPrefixOf` x 
                           then x ++ "_t"
                           else x ++ "_t*"
                                    
-- | Convert C/C++ types to C# types
convertCType :: Defs -> TypeName -> TypeName
convertCType c2cslist n = maybe (strip n) id (lookup n c2cslist)
  where strip n = if "_t" `isSuffixOf` n
                     then take (length n - 2) n
                     else if "_t*" `isSuffixOf` n
                             then take (length n - 3) n
                             else n
                             
-- | Some types when used in lists cannot use their managed counterparts.
--   like [String] needs to become char** in C# and not String*. Since
--   you cannot take the pointer of a managed structure.
swapList :: TypeName -> TypeName
swapList nm = maybe nm id (lookup nm swaplst)
  where swaplst :: [(String     , String    )]
        swaplst =  [("String"   , "char*"   )]

-- | Generate the appropriate C types from the given Haskell type
createCsType :: (Bool -> Defs) -> Type -> TypeNames
createCsType cslist
    = foldType( const . const id
              , (++)
              , (\_ b   -> return ("Tuples.Tuple"++show (length b)++"*"))
              , (\a     -> map ((\t -> if "CBF" `isPrefixOf` t then t ++ "" else t ++ "*") . swapList) a)
              , (\a b   -> process a b) -- We want to ignore IO, we assume all the functions preserve ref. transparency. in the case of FFI
              , (\a     ->maybe [mkRet a] (:[]) (lookup a cslist')) . mshow
              , (\a     ->maybe [mkRet a] (:[]) (lookup a cslist')) . mshow
              , id -- (\a     -> map (\t -> "(" ++ t ++ ")") a) -- The braces are irrelevant
              , (\_ b  _ -> return (mkRet $ mshow b))
              , (\a _   -> a)
              )
         where stripBrace ('(':xs) = init xs
               stripBrace x        = x
               
               cslist' = cslist False
               
               process a b = if "IO*" `elem` a  -- We want to ignore IO, we assume all the functions preserve ref. transparency. in the case of FFI
                                then b'
                                else if "Ptr*" `elem` a -- We would want to transform the explicit Ptr type to a C pointer *
                                        then map (++"*") b'
                                        else a
                    where b' = map stripBrace b 
               
               mkRet x = if "CBF" `isPrefixOf` x 
                            then x ++ ""
                            else x ++ "*"