%
% @(#) $Docid: Feb. 9th 2003 16:35 Sigbjorn Finne $
% @(#) $Contactid: sof@galois.com $
%
\begin{code}
module BasicTypes
(
Name
, QualName
, qName
, qOrigName
, qModule
, qDefModule
, mkQualName
, toQualName
, prefixQName
, prefixAppQName
, setOrigQName
, ScopedName
, Inherit
, GUID
, Size(..)
, CallConv(..)
, BinaryOp(..)
, UnaryOp(..)
, ShiftDir(..)
, Qualifier(..)
, PointerType(..)
, ParamDir(..)
, isInOut
, ppBinaryOp
, ppUnaryOp
, ppQualifier
, ppSize
, ppCallConv
, ppName
, ppQualName
, ppDirection
, strToCallConv
, EnumKind(..)
, classifyProgression
) where
import PP
import Maybe ( fromMaybe )
import Opts ( optNoQualNames, optIntIsInt )
import Utils ( mapMb )
import Int
\end{code}
\begin{code}
type Name = String
data QualName = QName {
qName :: Name,
qOrigName :: Name,
qModule :: Maybe Name,
qDefModule :: Maybe Name
}
deriving Eq
mkQualName :: Maybe String -> String -> QualName
mkQualName md nm = QName nm nm md Nothing
toQualName :: String -> QualName
toQualName str =
case (break (=='.') (reverse str)) of
(_,[]) -> mkQualName Nothing str
(mn,_:dm) -> mkQualName (Just (reverse dm)) (reverse mn)
setOrigQName :: Name -> QualName -> QualName
setOrigQName nm qn = qn{qOrigName=nm}
prefixQName :: String -> QualName -> QualName
prefixQName v qn = qn{qName=v++qName qn , qDefModule=Nothing}
prefixAppQName :: String -> QualName -> QualName
prefixAppQName v qn = qn{qName=("(" ++v++" "++(qName qn)++")") , qDefModule=Nothing}
type ScopedName = [String]
type Inherit = [Name]
type GUID = [String]
data Size
= Short | Natural | Long | LongLong
deriving (
Show
, Eq
)
data CallConv = Stdcall | Pascal | Cdecl | Fastcall
deriving ( Eq, Show )
strToCallConv :: String -> Maybe CallConv
strToCallConv "stdcall" = Just Stdcall
strToCallConv "cdecl" = Just Cdecl
strToCallConv _ = Nothing
\end{code}
Arithmetic and logical operators allowed in IDL:
\begin{code}
data BinaryOp
= Xor | Or | And | Shift ShiftDir
| Add | Sub | Div | Mod | Mul
| LogAnd | LogOr
| Gt | Ge | Eq | Le | Lt | Ne
deriving ( Eq, Show )
data UnaryOp
= Minus | Plus | Not | Negate | Deref
deriving ( Eq, Show )
data ShiftDir
= L | R
deriving ( Eq, Show )
data Qualifier
= Const | Volatile
deriving (
Show
, Eq
)
data PointerType
= Ptr
| Ref
| Unique
deriving ( Eq, Show )
data ParamDir = In | Out | InOut
deriving (Eq,Show)
isInOut :: ParamDir -> Bool
isInOut InOut = True
isInOut _ = False
\end{code}
\begin{code}
ppBinaryOp :: BinaryOp -> PPDoc a
ppBinaryOp op =
case op of
Xor -> char '^'
Or -> char '|'
And -> char '&'
Shift d -> text (case d of { L -> "<<" ; R -> ">>" })
Add -> char '+'
Sub -> char '-'
Div -> char '/'
Mod -> char '%'
Mul -> char '*'
LogAnd -> text "&&"
LogOr -> text "||"
Gt -> char '>'
Ge -> text ">="
Eq -> text "=="
Le -> text "<="
Lt -> char '<'
Ne -> text "/="
ppUnaryOp :: UnaryOp -> PPDoc a
ppUnaryOp op =
case op of
Minus -> char '-'
Plus -> char '+'
Not -> char '~'
Negate -> char '!'
Deref -> char '*'
ppQualifier :: Qualifier -> PPDoc a
ppQualifier Const = text "const"
ppQualifier Volatile = text "volatile"
\end{code}
\begin{code}
ppSize :: Size -> PPDoc a
ppSize Short = text "short"
ppSize Long = text "long"
ppSize Natural
| optIntIsInt = text "int"
| otherwise = text "long"
ppSize LongLong = text "long long"
ppCallConv :: Bool -> CallConv -> PPDoc a
ppCallConv for_c c =
text $
case c of
Stdcall -> if for_c then "__stdcall" else "stdcall"
Pascal -> if for_c then "__stdcall" else "stdcall"
Cdecl -> if for_c then "" else "ccall"
Fastcall -> "fastcall"
ppName :: Name -> PPDoc a
ppName nm = text nm
ppQualName :: QualName -> PPDoc a
ppQualName (QName nm _ md def_mod)
| optNoQualNames = text nm
| otherwise =
case def_mod of
Nothing -> (fromMaybe empty (mapMb (\ m -> text m <> char '.') md)) <> text nm
Just m -> text m <> char '.' <> text nm
instance Show QualName where
showsPrec _ q = showString (showPPDoc (ppQualName q) ())
\end{code}
\begin{code}
ppDirection :: ParamDir -> PPDoc a
ppDirection d =
text $
case d of
In -> "in"
Out -> "out"
InOut -> "in, out"
\end{code}
A sequence of enumeration tags is classified according to
what common class of progression it represent an instance of.
Knowing this may help us generate less Haskell code in the end.
(by using the "deriving" mechanism or, in the case of ghc, use
its support for going straight between tag values and enum dtors.)
\begin{code}
data EnumKind
= EnumProgression
Int
Int
| EnumFlags
Int
| Unclassified
deriving ( Show
, Eq
)
classifyProgression :: [Int32] -> EnumKind
classifyProgression [] = Unclassified
classifyProgression [x] = EnumProgression (fromIntegral x) 0
classifyProgression ls@(x:y:_)
| x == y = Unclassified
| and (zipWith (==) ls (pow2Series x)) = EnumFlags (fromIntegral x)
| and (zipWith (==) ls [x,(x+(yx))..]) = EnumProgression (fromIntegral x) (fromIntegral (yx))
| otherwise = Unclassified
where
pow2Series n = n : pow2Series (doub n)
doub n | n == 0 = 1
| otherwise = 2*n
\end{code}