clua-0.2: BStruct.hs
module BStruct (BSigned(..), BType(..), BStruct(..), bStructs, BEnum(..), bEnums) where
import CAnalyze
import qualified Data.ByteString.Char8 -- input for Language.C parser
import qualified Text.Show.Pretty -- cabal install pretty-show
import Language.C -- cabal install language-c
import Language.C.Pretty -- pretty-show
import Language.C.Data.Ident
import Language.C.Analysis.AstAnalysis
import Language.C.Analysis.TravMonad
import Language.C.Analysis.SemRep
-- import Language.C.Syntax.AST
-- import Language.C.Data.Position
import Data.Map -- Language.C.Analysis output
import Data.List
import Control.Monad
import System
-- Simple enum dictionary type to complement BStruct.
data BEnum = BEnum [(String, Integer)] deriving (Show, Eq)
bEnums top = bes where
syms = enums $ globalDecls top
bes = liftM (BEnum . sort) $ sequence $ Prelude.map be $ assocs syms
be (Ident id _ _, e) =
case evalC syms e of
Right val -> Right (id, val)
Left err -> Left err
-- Binary representable types. No pointers!
data BSigned = S | U deriving (Show, Eq)
data BType = BInt BSigned Integer
| BFloat Integer
| BArr Integer BType
| BComp SUERef -- open recursion
deriving (Show, Eq)
data BStruct = BStruct String [(BType, String)]
deriving (Show, Eq)
-- Base type representation. Note that the point of parsing these
-- structs is to parse binary blobs, which do not contain pointer or
-- function pointers.
-- http://hackage.haskell.org/packages/archive/language-c/0.4.2/doc/html/Language-C-Analysis-SemRep.html#t:Type
flatType syms = typ where
oops msg x = error $ "\n" ++ msg ++ "\n" ++ (show x)
typ (DirectType name quals attrs) = nam name
typ (TypeDefType ref quals attrs) = tdnam ref
typ (ArrayType t s quals attrs) = do
s' <- as s
t' <- typ t
return $ BArr s' t'
-- PtrType Type TypeQuals Attributes
-- FunctionType FunType Attributes
typ _ = Left $ "PtrTpe or FunctionType are not flat types"
as (ArraySize _ e) = evalC syms e
-- tdnam (TypeDefRef (Ident id _ _) Nothing _) = id
tdnam (TypeDefRef _ (Just t) _) = typ t -- recurse down typedefs
tdnam _ = Left $ "TypeDefRef: no type"
nam (TyIntegral t) = Right $ int t
nam (TyFloating t) = Right $ float t
nam (TyComp (CompTypeRef sueref kind _)) = Right $ BComp sueref
-- FIXME: support when needed
nam TyVoid = Left $ "TyVoid not supported"
nam (TyComplex _) = Left $ "TyComplex not supported"
nam (TyEnum _) = Left $ "TyEnum not supported"
nam (TyBuiltin _) = Left $ "TyBuiltin not supported"
-- IntType
int TyBool = BInt U 1
int TyUChar = BInt U 8
int TyUShort = BInt U 16
int TyUInt = BInt U 32
int TyULong = BInt U 32
int TyULLong = BInt U 64
int TyChar = BInt S 8
int TySChar = BInt S 8
int TyShort = BInt S 16
int TyInt = BInt S 32
int TyLong = BInt S 32
int TyLLong = BInt S 64
-- FloatType
float TyFloat = BFloat 32
float TyDouble = BFloat 64
flat syms = sequence . Data.Map.elems . (Data.Map.map f) where
f (CompDef (CompType r StructTag ms _ _)) = rv where
rv = case members (flatType syms) ms of
Right m -> Right $ BStruct (ref r) m
Left err -> Left err
ref (NamedRef (Ident id _ _)) = id
-- Distill binary packed structs.
bStructs toplevel = flt where
gs = globalDecls toplevel
es = enums gs
ss = packedStructs gs
flt = flat es ss
-- bEnums toplevel
-- TEST
-- x f = report f "/tmp/test.c"
-- x (aKeys packedStructs)