%
% (c) The Foo Project, University of Glasgow, 1998
%
% @(#) $Docid: Aug. 21th 2003 08:42 Sigbjorn Finne $
% @(#) $Contactid: sof@galois.com $
%
Misc utilities to help out the desugarer.
\begin{code}
module IDLUtils
( iName
, noAttrs
, removeIdAttrs
, idAttrs
, isUnpointedId
, isConstructedTy
, isCompleteTy
, isReferenceTy
, isMIDLishTy
, isMIDLishId
, isFunTy
, isEmptyStructTy
, isAnonTy
, tyTag
, withTyTag
, getTyQual
, mkReferenceTy
, getTyTag
, isVoidTyDef
, reduceExpr
, isLeafDefn
, tyShort
, tyWord16
, tyInt16
, tyWord32
, tyInt32
, tyGUID
, tyIDispatch
, tyVARIANT
, tySafeArray
, tyCURRENCY
, tyDATE
, tyFILETIME
, tyAddr
, tyVoid
, tyIStream
, tyIStorage
, tyChar
, tyWord64
, tyInt64
, tyByte
, tyVariantBool
, tyIUnknown
, tyHRESULT
, tyBSTR
, tyString
, tyWString
, tyFloat
, tyDouble
, tyInt
, retValAttribute
, defaultAttribute
, lcidAttribute
, optionalAttribute
, controlAttribute
, restrictedAttribute
, hiddenAttribute
, versionAttr
, helpStringAttr
, helpContextAttr
, helpFileAttr
, helpStringDllAttr
, helpStringCtxtAttr
, lcidvalAttribute
, mkFunId
, mkMethodId
, massageId
, sortDefns
, winnowDefns
, exprToName
, exprType
, transferPointedness
, toCConvAttrib
, toPackedAttrib
, mkGNUAttrib
, handlePackPragma
, childAttributes
) where
import IDLSyn
import qualified CoreIDL as Core (Expr(..),Type(..))
import DsMonad
import BasicTypes
import Literal
import Int
import Word ( Word16 )
import Bits
import Utils ( notNull )
import List ( isPrefixOf, find )
import Char ( isDigit, isAlpha, isSpace )
import Opts ( optUnwrapSingletonStructs, optOnlyRemoveDefns )
import Digraph
import Maybe
import Monad
import PpIDLSyn
import Env
\end{code}
\begin{code}
mkFunId :: Id -> [Param] -> Id
mkFunId f ps =
case findCC f of
(mb_cc, i') -> FunId i' mb_cc ps
where
findCC i@Id{} = (Nothing, i)
findCC (AttrId as i) =
case findCC i of
(mb_cc, i') -> (mb_cc, AttrId as i')
findCC i@ArrayId{} = (Nothing, i)
findCC i@FunId{} = (Nothing, i)
findCC (BitFieldId _ i) = findCC i
findCC (Pointed qs i) =
case findCC i of
(mb_cc, i') -> (mb_cc, Pointed qs i')
findCC (CConvId cc i) = (Just cc, i')
where
i' = ripOffCC i
ripOffCC (CConvId _ ci) = ripOffCC ci
ripOffCC i = snd (findCC i)
massageId :: Id -> Id
massageId = mkMethodId
\end{code}
@mkMethodId@ pushes the @FunId@ outwards and @PointedId@s
inwards - need to do this in order to desugar method signatures
correctly.
\begin{code}
mkMethodId :: Id -> Id
mkMethodId m_id = go m_id Nothing []
where
go (Pointed qs i) cacc qacc = go i cacc (qs:qacc)
go (CConvId c i) cacc qacc = go i (cacc `mplus` Just c) qacc
go (AttrId _ i) cacc qacc = go i cacc qacc
go (BitFieldId _ i) cacc qacc = go i cacc qacc
go (FunId i mb_cc ps) cacc qacc =
FunId (foldr Pointed i (reverse qacc))
(cacc `mplus` mb_cc)
ps
go _ _ _ = m_id
\end{code}
When parsing, attributes such as pointer indirection, calling convention etc.
gets associated with the Id of a method/field rather than the (result) type.
@transferPointedness@ shifts it over to the type.
\begin{code}
transferPointedness :: Id -> Type -> Type
transferPointedness pid ty =
case pid of
Pointed _ i -> transferPointedness i (TyPointer ty)
ArrayId i e -> transferPointedness i (TyArray ty e)
FunId i cc ps -> transferPointedness i (TyFun cc ty ps)
AttrId _ i -> transferPointedness i ty
_ -> ty
\end{code}
\begin{code}
iName :: Id -> Name
iName (Id s) = s
iName (ArrayId i _) = iName i
iName (Pointed _ i) = iName i
iName (CConvId _ i) = iName i
iName (AttrId _ i) = iName i
iName (BitFieldId _ i) = iName i
iName (FunId i _ _) = iName i
removeIdAttrs :: Id -> Id
removeIdAttrs (AttrId _ i) = removeIdAttrs i
removeIdAttrs i = i
idAttrs :: Id -> [Attribute]
idAttrs (AttrId as i) = as ++ idAttrs i
idAttrs _ = []
noAttrs :: [Attribute]
noAttrs = []
\end{code}
Various @IDLSyn.Type@ predicates:
\begin{code}
isUnpointedId :: Id -> Bool
isUnpointedId Pointed{} = False
isUnpointedId ArrayId{} = False
isUnpointedId (AttrId _ i) = isUnpointedId i
isUnpointedId _ = True
isConstructedTy :: Type -> Bool
isConstructedTy (TyStruct _ [(_,_,[_])] _) = not optUnwrapSingletonStructs
isConstructedTy TyStruct{} = True
isConstructedTy TyEnum{} = True
isConstructedTy TyUnion{} = True
isConstructedTy TyUnionNon{} = True
isConstructedTy TyCUnion{} = True
isConstructedTy _ = False
isEmptyStructTy :: Type -> Bool
isEmptyStructTy (TyStruct _ [] _) = True
isEmptyStructTy _ = False
isAnonTy :: Type -> Bool
isAnonTy (TyName nm _) = "__IHC_TAG" `isPrefixOf` nm
isAnonTy _ = False
isFunTy :: Type -> Bool
isFunTy TyFun{} = True
isFunTy _ = False
isCompleteTy :: Type -> Bool
isCompleteTy ty =
case ty of
TyStruct _ ls _ -> notNull ls
TyEnum _ ls -> notNull ls
TyUnion _ _ _ _ ls -> notNull ls
TyUnionNon _ ls -> notNull ls
TyCUnion _ ls _ -> notNull ls
_ -> error "isCompleteTy"
isReferenceTy :: Type -> Bool
isReferenceTy = not.isCompleteTy
mkReferenceTy :: Type -> Type
mkReferenceTy ty =
case ty of
TyStruct tg _ _ -> TyStruct tg [] Nothing
TyEnum tg _ -> TyEnum tg []
TyUnion tg t i _ _ -> TyUnion tg t i Nothing []
TyUnionNon tg _ -> TyUnionNon tg []
TyCUnion tg _ _ -> TyCUnion tg [] Nothing
_ -> error "IDLUtils.mkReferenceTy: expected a constructed ty"
getTyTag :: String -> Type -> String
getTyTag def (TyEnum mb_tag _) = fromMaybe def (fmap iName mb_tag)
getTyTag def (TyStruct mb_tag _ _) = fromMaybe def (fmap iName mb_tag)
getTyTag def (TyUnion mb_tag _ _ _ _) = fromMaybe def (fmap iName mb_tag)
getTyTag def (TyUnionNon mb_tag _) = fromMaybe def (fmap iName mb_tag)
getTyTag def (TyCUnion mb_tag _ _) = fromMaybe def (fmap iName mb_tag)
getTyTag _ (TyName n _) = n
getTyTag def (TyPointer t) = getTyTag def t
getTyTag _ t
= error ("IDLUtils.getTyTag: unexpected type: " ++ showIDL (ppType t))
isMIDLishTy :: Type -> Bool
isMIDLishTy ty =
case ty of
TyName nm _ -> isMIDLishNm nm
_ -> False
isMIDLishId :: Id -> Bool
isMIDLishId (Id s) = isMIDLishNm s
isMIDLishId _ = False
isMIDLishNm :: String -> Bool
isMIDLishNm nm = "MIDL___MIDL__" `isPrefixOf` nm'
where
nm' =
case nm of
'_':'_':xs -> xs
_ -> nm
\end{code}
\begin{code}
tyTag :: Type -> String
tyTag (TyStruct (Just i) _ _) = iName i
tyTag (TyEnum (Just i) _) = iName i
tyTag (TyUnion (Just i) _ _ _ _) = iName i
tyTag (TyUnionNon (Just i) _) = iName i
tyTag (TyCUnion (Just i) _ _) = iName i
tyTag (TyName nm _) = nm
tyTag _ = ""
withTyTag :: String -> Type -> Type
withTyTag tg ty =
case ty of
TyStruct Nothing a b -> TyStruct tag a b
TyEnum Nothing a -> TyEnum tag a
TyUnion Nothing a b c d -> TyUnion tag a b c d
TyUnionNon Nothing a -> TyUnionNon tag a
TyCUnion Nothing a b -> TyCUnion tag a b
_ -> ty
where
tag = Just (Id tg)
getTyQual :: Type -> ([Qualifier], Type)
getTyQual (TyApply (TyQualifier q) t) = ([q], t')
where
(_, t') = getTyQual t
getTyQual t = ([],t)
\end{code}
\begin{code}
isVoidTyDef :: Type -> [Id] -> Bool
isVoidTyDef TyVoid [Id _] = True
isVoidTyDef _ _ = False
\end{code}
When filling in values for the enum tags, we have to reduce the expressions
for the tags that do have a value attached to them.
The name to value mapping passed is the mapping for constants.
\begin{code}
reduceExpr :: (Type -> DsM Core.Type) -> Expr -> DsM (Either Int32 Core.Expr)
reduceExpr redType expr =
case expr of
Binary op e1 e2 -> do
i1 <- reduceExpr redType e1
i2 <- reduceExpr redType e2
return (binop_m op i1 i2)
Cond e1 e2 e3 -> do
i1 <- reduceExpr redType e1
i2 <- reduceExpr redType e2
i3 <- reduceExpr redType e3
return (cond_m i1 i2 i3)
Unary op e -> do
i <- reduceExpr redType e
return (unop_m op i)
Var nm -> do
res <- lookupConst nm
case res of
Nothing -> return (Right (Core.Var nm))
Just v -> return v
Lit l -> return (Left (reduceLit l))
Cast t e -> do
res <- reduceExpr redType e
t' <- redType t
case res of
Left i -> return (Left i)
Right e' -> return (Right (Core.Cast t' e'))
Sizeof t -> do
t' <- redType t
return (Right (Core.Sizeof t'))
reduceLit :: Literal -> Int32
reduceLit l =
case l of
IntegerLit (ILit _ i) -> fromInteger i
_ -> error ("reduceLit(" ++ show l ++ "): no can do.")
binop_m :: BinaryOp
-> Either Int32 Core.Expr
-> Either Int32 Core.Expr
-> Either Int32 Core.Expr
binop_m op (Left i1) (Left i2) = Left (binop op i1 i2)
binop_m op e1 e2 = Right (Core.Binary op (toExpr e1) (toExpr e2))
binop :: BinaryOp -> Int32 -> Int32 -> Int32
binop op i1 i2 =
case op of
Add -> i1 + i2
Sub -> i1 i2
Div -> i1 `div` i2
Mod -> i1 `mod` i2
Mul -> i1 * i2
And -> i1 .&. i2
Or -> i1 .|. i2
Xor -> i1 `xor` i2
Shift L -> shiftL i1 (fromIntegral i2)
Shift R -> shiftR i1 (fromIntegral i2)
_ -> error ("binop: unexpected " ++ show op)
cond_m :: Either Int32 Core.Expr -> Either Int32 Core.Expr
-> Either Int32 Core.Expr -> Either Int32 Core.Expr
cond_m (Left i1) (Left i2) (Left i3) = Left (cond i1 i2 i3)
cond_m e1 e2 e3 = Right (Core.Cond (toExpr e1) (toExpr e2) (toExpr e3))
toExpr :: Either Int32 Core.Expr -> Core.Expr
toExpr (Right e) = e
toExpr (Left i) = Core.Lit (IntegerLit (ILit 10 (toInteger i)))
cond :: Int32 -> Int32 -> Int32 -> Int32
cond 0 x _ = x
cond _ _ y = y
unop_m :: UnaryOp -> Either Int32 Core.Expr -> Either Int32 Core.Expr
unop_m op (Left i1) = Left (unop op i1)
unop_m op (Right e1) = Right (Core.Unary op e1)
unop :: UnaryOp -> Int32 -> Int32
unop Minus i = negate i
unop Plus i = i
unop Not i = complement i
unop o _ = error ("unop: unexpected " ++ show o)
\end{code}
\begin{code}
isLeafDefn :: Defn -> Bool
isLeafDefn TypeDecl{} = True
isLeafDefn Typedef{} = True
isLeafDefn Operation{} = True
isLeafDefn Constant{} = True
isLeafDefn _ = False
\end{code}
begin{code}
idlToCoreTy :: Type -> Core.Type
idlToCoreTy ty =
case ty of
TyInteger sz -> Core.Integer sz True
TyFloat sz -> Core.Float sz
TyChar -> Core.Char False
TyWChar -> Core.WChar
TyBool -> Core.Bool
TyOctet -> Core.Octet
TyAny -> Core.Any
TyObject -> Core.Object
TyBString -> bstrTy
TyVoid -> Core.Void
TyName nm Nothing -> Core.Name nm nm Nothing Nothing Nothing Nothing
TyName nm (Just t) -> Core.Name nm nm Nothing Nothing (Just (idlToCoreTy t)) Nothing
TyIface "IUnknown" -> iUnknownTy
TyIface "IDispatch" -> iDispatchTy
TyIface nm -> Core.Iface nm Nothing nm [] False []
TyPointer t -> Core.Pointer Ptr False (idlToCoreTy t)
-- TyFixed mb e i -> Core.Fixed (idlToCoreExpr e) i
TyArray t es -> Core.Array (idlToCoreTy t) (map idlToCoreExpr es)
TyApply (TySigned s) (TyInteger sz) -> Core.Integer sz s
TyApply (TySigned s) TyChar -> Core.Char s
TyApply (TySigned s) _ -> Core.Integer Long s
TySigned s -> Core.Integer Long s
TyApply (TyQualifier _) t -> idlToCoreTy t
TyApply t (TyQualifier _) -> idlToCoreTy t
TyString mb_expr ->
let core_expr = mapFromMb Nothing
(Just . idlToCoreExpr)
mb_expr
in
Core.String (Core.Char False) False core_expr
TyWString mb_expr ->
let
core_expr = mapFromMb Nothing
(Just . idlToCoreExpr)
mb_expr
in
Core.WString False core_expr
TySequence t mb_expr ->
let
core_ty = idlToCoreTy t
core_expr = mapFromMb Nothing
(Just . idlToCoreExpr)
mb_expr
in
Core.Sequence core_ty core_expr Nothing
TyApply (TyQualifier _) t -> idlToCoreTy t
TyEnum (Just (Id nm)) _ -> Core.Enum (mkId nm nm Nothing []) Unclassified []
TyStruct (Just (Id nm)) _ mb_pack -> Core.Struct (mkId nm nm Nothing []) [] mb_pack
TyUnion (Just (Id nm1)) t
(Id nm2) (Just (Id nm3)) _->
Core.Union (mkId nm1 nm1 Nothing []) (idlToCoreTy t)
(mkId nm2 nm2 Nothing []) (mkId nm3 nm3 Nothing []) []
TyUnionNon (Just (Id nm1)) _ ->
Core.UnionNon (mkId nm1 nm1 Nothing []) []
TyCUnion (Just (Id nm)) _ mb_pack ->
Core.CUnion (mkId nm nm Nothing []) [] mb_pack
end{code}
Conversion an IDLSyn expression tree into a CoreIDL one -
a candidate for polytypic treatment.
begin{code}
idlToCoreExpr :: Expr -> Core.Expr
idlToCoreExpr e =
case e of
Binary bop e1 e2 -> Core.Binary bop (idlToCoreExpr e1)
(idlToCoreExpr e2)
Cond e1 e2 e3 -> Core.Cond (idlToCoreExpr e1)
(idlToCoreExpr e2)
(idlToCoreExpr e3)
Unary op e1 -> Core.Unary op (idlToCoreExpr e1)
Var nm -> Core.Var nm
Lit l -> Core.Lit l
Cast t e1 -> Core.Cast (idlToCoreTy t) (idlToCoreExpr e1)
Sizeof t -> Core.Sizeof (idlToCoreTy t)
end{code}
Common attributes:
\begin{code}
simpleAttr :: String -> Attribute
simpleAttr nm = Attrib (Id nm) []
retValAttribute, lcidAttribute, optionalAttribute :: Attribute
retValAttribute = simpleAttr "retval"
lcidAttribute = simpleAttr "lcid"
optionalAttribute = simpleAttr "optional"
controlAttribute, restrictedAttribute, hiddenAttribute :: Attribute
controlAttribute = simpleAttr "control"
restrictedAttribute = simpleAttr "restricted"
hiddenAttribute = simpleAttr "hidden"
defaultAttribute :: Maybe Literal -> Maybe Attribute
defaultAttribute Nothing = Nothing
defaultAttribute (Just x) = Just (Attrib (Id "defaultvalue") [AttrLit x])
versionAttr :: Word16 -> Word16 -> Maybe Attribute
versionAttr maj mino = toMaybe (\ _ -> maj /=0 || mino /=0)
(Attrib (Id "version") [AttrLit (LitLit ((show maj) ++'.':show mino))])
undefined
helpStringAttr :: String -> Maybe Attribute
helpStringAttr s
= toMaybe notNull (Attrib (Id "helpstring") [AttrLit (StringLit s)]) s
helpContextAttr :: Integer -> Maybe Attribute
helpContextAttr c
= toMaybe (/=0) (Attrib (Id "helpcontext") [AttrLit (IntegerLit (ILit 16 c))]) c
helpFileAttr :: String -> Maybe Attribute
helpFileAttr hfile
= toMaybe notNull (Attrib (Id "helpfile") [AttrLit (StringLit hfile)]) hfile
helpStringDllAttr :: String -> Maybe Attribute
helpStringDllAttr dll
= toMaybe notNull (Attrib (Id "helpstringdll")
[AttrLit (StringLit dll)]) dll
helpStringCtxtAttr :: Integer -> Maybe Attribute
helpStringCtxtAttr hc =
toMaybe (/=0) (Attrib (Id "helpstringcontext")
[AttrLit (IntegerLit (ILit 16 hc))]) hc
lcidvalAttribute :: Integer -> Maybe Attribute
lcidvalAttribute lc =
toMaybe (/=0) (Attrib (Id "lcid") [AttrLit (IntegerLit (ILit 10 lc))]) lc
toMaybe :: (a -> Bool) -> b -> a -> Maybe b
toMaybe predic res mb_val
| predic mb_val = Just res
| otherwise = Nothing
\end{code}
The type-library reader needs to map TLB types to IDL types -
here they are:
\begin{code}
tyWord16, tyWord32, tyWord64 :: Type
tyWord16 = TyApply (TySigned False) (TyInteger Short)
tyWord32 = TyApply (TySigned False) (TyInteger Long)
tyWord64 = TyApply (TySigned False) (TyInteger LongLong)
tyInt16, tyInt32, tyInt64, tyShort, tyInt :: Type
tyInt16 = tyShort
tyInt32 = TyApply (TySigned True) (TyInteger Long)
tyInt64 = TyApply (TySigned True) (TyInteger LongLong)
tyShort = TyApply (TySigned True) (TyInteger Short)
tyInt = tyInt32
tyChar, tyByte :: Type
tyChar = TyChar
tyByte = TyOctet
tyAddr, tyVoid :: Type
tyAddr = TyPointer TyVoid
tyVoid = TyVoid
tyGUID :: Type
tyGUID = TyName "GUID" Nothing
tyIUnknown, tyIDispatch :: Type
tyIDispatch = TyIface "IDispatch"
tyIUnknown = TyIface "IUnknown"
tyVARIANT :: Type
tyVARIANT = TyName "VARIANT" Nothing
tySafeArray :: Type -> Type
tySafeArray t = TySafeArray t
tyCURRENCY :: Type
tyCURRENCY = TyName "CURRENCY" Nothing
tyDATE :: Type
tyDATE = TyName "DATE" Nothing
tyFILETIME :: Type
tyFILETIME = TyName "FILETIME" Nothing
tyIStorage, tyIStream :: Type
tyIStream = TyIface "IStream"
tyIStorage = TyIface "IStorage"
tyVariantBool :: Type
tyVariantBool = TyName "VARIANT_BOOL" Nothing
tyHRESULT :: Type
tyHRESULT = TyName "HRESULT" Nothing
tyBSTR, tyString, tyWString :: Type
tyString = TyString Nothing
tyWString = TyWString Nothing
tyBSTR = TyBString
tyFloat, tyDouble :: Type
tyFloat = TyFloat Short
tyDouble = TyFloat Long
\end{code}
Order sorting a sequence of definitions.
\begin{code}
sortDefns :: [Defn] -> [Defn]
sortDefns ds = map sortDefn ds_sorted
where
ds_depped = map mkDefnDep ds
ds_groups = stronglyConnComp ds_depped
ds_i = filter isImport ds
isImport (Import _) = True
isImport (ImportLib _) = True
isImport (CInclude _) = True
isImport _ = False
ds_sorted = ds_i ++ filter (not.isImport) (concatMap expandGroup ds_groups)
sortDefn :: Defn -> Defn
sortDefn (Library i ds) = Library i (sortDefns ds)
sortDefn (Module i ds) = Module i (sortDefns ds)
sortDefn (Attributed x d) = Attributed x (sortDefn d)
sortDefn x = x
mkDefnDep :: Defn -> (Defn, String, [String])
mkDefnDep d = let (def,uses) = getDefUses d in (d,def,uses)
getDefUses :: Defn -> (String,[String])
getDefUses d = (def, uses)
where
uses = getUses d
def = getDef d
getDef :: Defn -> String
getDef d =
case d of
Typedef _ _ (i:_) -> iName i
Attributed _ d1 -> getDef d1
ExternDecl _ [i] -> iName i
Operation i _ _ _ -> iName i
Interface (Id i) _ _ -> i
Module (Id i) _ -> i
DispInterface (Id i) _ _ -> i
CoClass (Id i) _ -> i
Library (Id i) _ -> i
TypeDecl t -> tyTag t
_ -> ""
getUses :: Defn -> [String]
getUses d =
case d of
Typedef ty _ _ -> getTyUses ty
Constant _ _ ty _ -> getTyUses ty
Interface _ is ds -> is ++ concatMap getUses ds
Module _ ds -> concatMap getUses ds
DispInterface _ ps ds -> concatMap (\ (_,t, _) -> getTyUses t) ps ++ concatMap getUses ds
CoClass _ cs -> map (\ (_,Id i,_) -> i) cs
Library _ ds -> concatMap getUses ds
Attributed _ d1 -> getUses d1
TypeDecl t -> getTyUses t
ExternDecl t _ -> getTyUses t
Operation (FunId _ _ ps) r _ _ -> getTyUses r ++ concatMap (\ (Param _ t _) -> getTyUses t) ps
_ -> []
getTyUses :: Type -> [String]
getTyUses ty =
case ty of
TyName n _ -> [n]
TyIface n -> [n]
TySafeArray t -> getTyUses t
TyArray t _ -> getTyUses t
TyPointer t -> getTyUses t
TyCUnion _ fs _ -> concatMap (\ (t,_,_) -> getTyUses t) fs
TyStruct (Just (Id n)) [] _ -> [n]
TyStruct _ fs _ -> concatMap (\ (t,_,_) -> getTyUses t) fs
TyEnum (Just (Id n)) [] -> [n]
TyApply t1 t2 -> getTyUses t1 ++ getTyUses t2
_ -> []
expandGroup :: SCC Defn -> [Defn]
expandGroup (AcyclicSCC d) = [d]
expandGroup (CyclicSCC ds) = ds'
where
ds_uses = map getDef ds
ds' = forwardDecls ds (go [] ds_uses ds)
forwardDecls [] cont = cont
forwardDecls (a:as) cont = mkForwardDecl a (forwardDecls as cont)
mkForwardDecl (Attributed _ d) cont = mkForwardDecl d cont
mkForwardDecl (Interface i _ _) cont = Forward i : cont
mkForwardDecl (DispInterface i _ _) cont = Forward i : cont
mkForwardDecl _ cont = cont
go _ _ [] = []
go _ [] _ = []
go bef (a:aft) (x:xs) = Attributed as x : go (a:bef) aft xs
where
as = map (\ ll -> Attrib (Id "depender") [AttrLit (LitLit ll)]) (bef ++ aft)
\end{code}
Sigh - copy of the routine you'll find in CoreUtils, but this
time over IDLSyn attributes.
\begin{code}
childAttributes :: [Attribute] -> [Attribute]
childAttributes as = filter (not.notAggregatableAttribute) as
notAggregatableAttribute :: Attribute -> Bool
notAggregatableAttribute (Attrib (Id nm) _) = nm `elem` junk_list
where
junk_list =
[ "helpstring"
, "helpcontext"
, "dllname"
, "lcid"
, "odl"
, "restricted"
, "ole"
, "uuid"
, "object"
, "oleautomation"
, "hidden"
, "version"
, "local"
, "custom"
, "public"
, "dual"
, "switch_type"
, "switch_is"
, "depender"
, "ty_params"
, "jni_interface"
, "jni_iface_ty"
, "jni_class"
, "hs_name"
, "hs_import"
, "hs_newtype"
]
notAggregatableAttribute _ = False
\end{code}
The user can off-line specify which of the defns are (or aren't) of interest.
@winnowDefn@ is responsible from picking the chaff from the wheat, as it where.
\begin{code}
winnowDefns :: Env String (Bool,[Attribute])
-> [Defn]
-> [Defn]
winnowDefns wenv ws = reverse $ fst (go wenv "" (reverse ws))
where
go env _ [] = ([], env)
go env prefix (d:ds) =
case getDef d of
"" -> let (ds', e) = go env prefix ds in (d:ds', e)
nm -> let
res = lookupEnv env nm `mplus` lookupEnv env (prefix ++ '.':nm)
uses = getUses d
inh_value = (True, [Mode In])
keep_it = not remove_it && (optOnlyRemoveDefns || isJust res)
remove_it =
case res of
Just (flg,ls) -> not flg && null ls
_ -> False
env'
| isJust res =
if remove_it || optOnlyRemoveDefns then
env
else
addListToEnv env (map (\ x -> (x, inh_value)) uses)
| otherwise = env
newPrefix i
| null prefix = iName i
| otherwise = prefix ++ '.':iName i
in
case d of
Attributed as d1 ->
case go env' prefix [d1] of
([],_) -> go env' prefix ds
((x:_), e) -> let
(ds', e1) = go e prefix ds
in
(Attributed as x : ds', e1)
Interface i inhs ms ->
case go env' (newPrefix i) (reverse ms) of
(ms', e) -> let (ds', e1) = go e prefix ds in
if remove_it || (null ms' && (notNull ms || not keep_it)) then
(ds', e1)
else
(Interface i inhs (reverse ms') : ds', e1)
DispInterface i props ms ->
case go env' (newPrefix i) (reverse ms) of
(ms', e) -> let (ds', e1) = go e prefix ds in
if remove_it || (null ms' && (notNull ms || not keep_it)) then
(ds', e1)
else
(DispInterface i props (reverse ms') : ds', e1)
Library i ls ->
case go env' (newPrefix i) (reverse ls) of
(ls', e) -> let (ds', e1) = go e prefix ds in
if remove_it || (null ls' && (notNull ls || not keep_it)) then
(ds', e1)
else
(Library i (reverse ls') : ds', e1)
Module i ms ->
case go env' (newPrefix i) (reverse ms) of
(ms', e) -> let (ds', e1) = go e prefix ds in
if remove_it || (null ms' && (notNull ms || not keep_it)) then
(ds', e1)
else
(Module i (reverse ms') : ds', e1)
_ -> let (ds', e) = go env' prefix ds in
if keep_it then
(d:ds', e)
else
(ds', e)
\end{code}
\begin{code}
exprToName :: Expr -> String
exprToName e = map (\ x -> if (isAlpha x || isDigit x) then x else '_')
(showIDL (ppExpr e))
\end{code}
Gather the type of an expression - unknown
\begin{code}
exprType :: Type -> Expr -> Type
exprType defTy ex =
case ex of
Lit l -> litType l
Cast t _ -> t
Sizeof{} -> TyInteger Natural
Var{} -> defTy
Cond _ e1 _ -> exprType defTy e1
Binary _ e1 _ -> exprType defTy e1
Unary uop e ->
case uop of
Deref -> TyPointer (exprType defTy e)
_ -> exprType defTy e
litType :: Literal -> Type
litType l =
case l of
IntegerLit{} -> TyInteger Natural
StringLit{} -> TyString Nothing
TypeConst s -> TyName s Nothing
WStringLit{} -> TyWString Nothing
CharLit{} -> TyChar
WCharLit{} -> TyWChar
FixedPtLit{} -> TyFixed Nothing
FloatingLit{} -> TyFloat Long
BooleanLit{} -> TyBool
NullLit{} -> TyPointer TyVoid
GuidLit{} -> TyName "GUID" Nothing
LitLit{} -> error "litType{LitLit}: can't determine type"
\end{code}
\begin{code}
toPackedAttrib :: [GNUAttrib] -> Maybe Int
toPackedAttrib [] = Nothing
toPackedAttrib ls =
case find (==Packed) ls of
Nothing -> Nothing
Just _ -> Just 1
toCConvAttrib :: [GNUAttrib] -> (Id -> Id)
toCConvAttrib [] = id
toCConvAttrib ls =
case find isCConv ls of
Just (CConv cc) -> CConvId cc
_ -> id
where
isCConv CConv{} = True
isCConv _ = False
mkGNUAttrib :: String -> [Expr] -> GNUAttrib
mkGNUAttrib "packed" _ = Packed
mkGNUAttrib x _ = Unsupported x
\end{code}
Hidden here because it is pig ugly.
\begin{code}
handlePackPragma :: String -> DsM ()
handlePackPragma ('p':'a':'c':'k':xs) =
case dropWhile isSpace xs of
')':_ -> pushPack Nothing
'(':'p':'u':'s':'h':')':_ -> pushPack (Just Nothing)
'(':'p':'o':'p':')':_ -> popPack Nothing
'(':'p':'u':'s':'h':',':ys@(y:_) | isAlpha y ->
let
(nm, rs) = break (\x -> x == ',' || x == ')') ys
in
case rs of
')':_ -> pushPack (Just (Just (nm, Nothing)))
',':rs2 ->
let
(val, rs3) = break (== ')') rs2
in
case rs3 of
')':_ ->
case reads val of
((v,_):_) -> pushPack (Just (Just (nm, Just v)))
_ -> return ()
_ -> return ()
_ -> return ()
'(':'p':'u':'s':'h':',':ys@(y:_) | isDigit y ->
let
(val, rs) = break (== ')') ys
in
case rs of
')':_ -> do
case reads val of
((v,_):_) -> pushPack (Just (Just ("", Just v)))
_ -> return ()
_ -> return ()
'(':'p':'o':'p':',':ys@(y:_) | isAlpha y ->
let
(nm, rs) = break (\x -> x == ',' || x == ')') ys
in
case rs of
')':_ -> popPack (Just (nm, Nothing))
',':rs2 ->
let
(val, rs3) = break (== ')') rs2
in
case rs3 of
')':_ ->
case reads val of
((v,_):_) -> popPack (Just (nm, Just v))
_ -> return ()
_ -> return ()
_ -> return ()
'(':'p':'o':'p':',':ys@(y:_) | isDigit y ->
let
(val, rs) = break (== ')') ys
in
case rs of
')':_ -> do
case reads val of
((v,_):_) -> popPack (Just ("", Just v))
_ -> return ()
_ -> return ()
_ -> return ()
handlePackPragma _ = return ()
\end{code}