% % (c) The Foo Project, Universities of Glasgow & Utrecht, 1997-8 % % @(#) $Docid: Nov. 16th 2001 17:13 Sigbjorn Finne $ % @(#) $Contactid: sof@galconn.com $ % The CoreIDL interface defines the intermediate representation used for IDL specifications. \begin{code}
module CoreIDL where

import Literal
import BasicTypes
import Int ( Int32 )
import TypeInfo
\end{code} \begin{code}
data Decl
  = Typedef       { declId :: Id, declType :: Type, declOrigType :: Type }
  | Constant      { declId       :: Id
  		  , declType     :: Type
		  , declOrigType :: Type
		  , declExpr     :: Expr
		  }
  | Interface     { declId :: Id
		  , isReference :: Bool -- => True, not a defining occurrence, but a use.
					-- need to make the distinction when dealing with
					--
					--    library {  interface IA; ... } 
					-- 
					-- and 
					-- 
					--    dispinterface { interface IA; }
					--
		  , declInherit :: InterfaceInherit
		  , declDecls :: [InterfaceDecl]
		  }
  | Module        { declId :: Id, declDecls :: [ModuleDecl]  }
  | DispInterface { declId :: Id
		  , dispExpandedFrom :: Maybe Decl 
		          -- Just IA => expanded from "dispinterface DA { interface IA; };"
                  , declProps :: [DispInterfaceDecl]
		  , declDecls :: [DispInterfaceDecl]
		  }
  | CoClass       { declId :: Id, declCoDecls :: [CoClassDecl] }
  | Library       { declId :: Id, declDecls :: [LibraryDecl] }
  | Method        { declId :: Id
		  , methCallConv :: CallConv
		  , methResult   :: Result
		  , methParams   :: [Param]
		  , methOffset   :: Maybe Int   -- used by type libraries only.
		  }
  | Property      { declId     :: Id
  		  , declType   :: Type
		  , propOffset :: Maybe Int
		  , declSetId  :: Id
		  , declGetId  :: Id
		  }
  | HsLiteral	  String -- literal Haskell code.
  | CInclude	  String
  | CLiteral	  String -- literal C code (used when generating header files from IDL spec.)

type InterfaceDecl     = Decl
  -- Typedef, Constant, Method

type ModuleDecl        = Decl
  -- Constant, Method

type DispInterfaceDecl = Decl
  -- Method, Property

data CoClassDecl 
 = CoClassInterface     { coClassId :: Id, coClassDecl :: Maybe Decl }
 | CoClassDispInterface { coClassId :: Id, coClassDecl :: Maybe Decl }

type LibraryDecl       = Decl
  -- any (apart from Library)

type InterfaceInherit = 
   [( QualName
    , Int	    -- Just x => interface contains m methods.
    )]

\end{code} \begin{code}
data Expr
 = Binary BinaryOp Expr Expr
 | Cond   Expr Expr Expr
 | Unary  UnaryOp Expr
 | Var    Name
 | Lit    Literal
 | Cast   Type Expr
 | Sizeof Type
   deriving ( Eq
{-
-- trick to get conditional code blocks work
-- for Haskell systems that do/do not offer CPP preprocessing.
-- (for systems that don't (i.e. Hugs), the code block will be
-- used.
#ifdef DEBUG
-}
	    , Show
{-
#endif
-}
	    )
\end{code} The type language for Core IDL: \begin{code}
data Type
 = Integer Size Signed
 | StablePtr
 | FunTy   CallConv Result [Param]
 | Float   Size
 | Char    Signed
 | WChar
 | Bool   | Octet | Any  | Object
 | String Type Bool (Maybe Expr) | WString Bool (Maybe Expr)
 | Sequence Type (Maybe Expr) (Maybe Expr)
 | Fixed Expr IntegerLit
 | Name     Name
 	    Name		-- original name
 	    (Maybe Name)	-- where it is defined.
	    (Maybe [Attribute]) -- the attributes at its definition site.
	    (Maybe Type)	-- the type it expands to.
	    (Maybe TypeInfo)    -- custom/off-line type info.

 | Struct   Id 
            [Field]
	    (Maybe Int)		-- packed (in bytes.)

 | Enum     Id EnumKind [EnumValue]
 | Union    Id Type Id Id [Switch]
 | UnionNon Id [Switch]    -- non-encapsulated union.
 | CUnion   Id [Field]     -- C-style union
	       (Maybe Int) -- packed (in bytes.)

 | Pointer  PointerType
 	    Bool           -- True  => pointer type was explicitly given
	                   -- False => not explicit, default type.
 	    Type
 | Array    Type [Expr]
 | Void
 | Iface    Name              -- an interface/abstract type
	    (Maybe Name)      -- the module it was imported from.
 	    Name	      -- it's original name
	    [Attribute]       -- attributes used at definition site.
	    Bool	      -- True => derives from IDispatch.
	    InterfaceInherit  -- what it extends (in *reverse* order, i.e., base iface comes first, since
			      -- we're mostly interested in the iface/object's base when marshalling.)

     -- the following are only produced in MS IDL mode:
 | SafeArray Type
   deriving ( Eq
{-
#ifdef DEBUG
-}
	    , Show
{-
#endif
-}
	    )

type Signed = Bool

\end{code} In Core, we pin attributes on Ids: \begin{code}
data Id 
 = Id {
      idName       :: Name,	    -- a unique, Haskellised name
      idOrigName   :: Name,	    -- source name
      idModule     :: Maybe Name,   -- where it is defined, Nothing => local.
      idAttributes :: [Attribute]
   }
   deriving ( Eq
{-
#ifdef DEBUG
-}
	    , Show
{-
#endif
-}
	    )

\end{code} \begin{code}
data Attribute 
 = AttrMode ParamDir
 | AttrDependent {
      atReason    :: DepReason,
      atParams    :: [AttributeParam]
   }
 | Attribute {
      atName      :: Name,
      atParams    :: [AttributeParam]
   } 
   deriving ( Eq
{-
#ifdef DEBUG
-}
	    , Show
{-
#endif
-}
	    )

data AttributeParam
 = ParamLit    Literal
 | ParamType   Type
 | ParamExpr   Expr
 | ParamVar    Name
 | ParamVoid
 | ParamPtr AttributeParam
    deriving ( Eq
{-
#ifdef DEBUG
-}
	     , Show
{-
#endif
-}
	     )

data DepReason
 = SizeIs  | LengthIs
 | LastIs  | FirstIs
 | MaxIs   | MinIs
 | SwitchIs
   deriving ( Eq, Show )
\end{code} \begin{code}
data Result =
   Result { 
     resultType     :: Type,  -- used 
     resultOrigType :: Type
   }  
     deriving ( Eq
{-
#ifdef DEBUG
-}
	      , Show
{-
#endif
-}
	      )

data Param
 = Param {
     paramId        :: Id,
     paramMode      :: ParamDir,
     paramType      :: Type,  -- used for marshalling purposes
     paramOrigType  :: Type,  -- un-reduced version.
     paramDependent :: Bool
   }
     deriving ( Eq
{-
#ifdef DEBUG
-}
	      , Show
{-
#endif
-}
	      )

data Switch    
 = Switch {
     switchId	    :: Id,
     switchLabels   :: [CaseLabel],
     switchType     :: Type,
     switchOrigType :: Type
   } 
 | SwitchEmpty  (Maybe [(CaseLabel,String)]) 
                            -- Nothing      => default switch.
			    -- Just [(x,y)] => y is the tag name.
   deriving ( Eq
{-
#ifdef DEBUG
-}
	    , Show
{-
#endif
-}
	    )

data CaseLabel 
 = Case Expr | Default
   deriving ( Eq
{-
#ifdef DEBUG
-}
	    , Show
{-
#endif
-}
	    )

-- for struct & C union fields
data Field 
 = Field {
     fieldId       :: Id,
     fieldType     :: Type,
     fieldOrigType :: Type,
     fieldSize     :: Maybe Int,
     fieldOffset   :: Maybe Int
   } deriving ( Eq
{-
#ifdef DEBUG
-}
	      , Show
{-
#endif
-}
	      )

data EnumValue 
 = EnumValue {
     enumName  :: Id,
     enumValue :: (Either Int32 Expr)
   } deriving ( Eq
{-
#ifdef DEBUG
-}
	      , Show
{-
#endif
-}
	      )

\end{code}