Next Previous Contents

3. Implementation of Haskell Binding Modules

A discussion of binding modules, the principles behind the tool, and a discussion of related work can be found in a research paper located at http://www.cse.unsw.edu.au/~chak/papers/papers.html#c2hs. All features described in the paper, except enum define hooks are implemented in the tool, but since the publication of the paper, the tool has been extended further.

Furthermore, the distribution contains examples that illustrate the use of C->Haskell. In the source distribution, these examples are located below the directories tests and examples. The latter contains a binding for the Gnome HTTP 1.1 library ghttp. The sources of the marshalling library C2HS are in the directory lib and contain a fair amount of comments, which should help getting you started.

Since version 0.8.1 the interface of the marshalling library C2HS changed. The new interface essentially consists of the new Haskell FFI Marshalling Library. More details about this library are provided in the next section. For backward compatibilitym the old interface (i.e., the pre-0.8.1 interface) can still be used by importing C2HSDeprecated instead of C2HS.

The remainder of this section describes the hooks that are available in binding modules.

3.1 Import Hooks

{#import [qualified] modid#}

Is translated into the same syntactic form in Haskell, which implies that it may be followed by an explicit import list. Moreover, it implies that the module modid is also generated by C->Haskell and instructs the tool to read the file modid.chi.

If an explicit output file name is given (--output option), this name determines the basename for the .chi file of the currently translated module.

Currently, only pointer hooks generate information that is stored in a .chi file and needs to be incorporated into any client module that makes use of these pointer types. It is, however, regarded as good style to use import hooks for any module generated by C->Haskell.

3.2 Context Hooks

{#context [header = header] [lib = lib] [prefix = prefix]#}

Context hooks define a set of global configuration options. Currently, there are three parameters all of which are strings:

All three parameters are optional. An example of a context hook is the following:

{#context header = "gtkwidget.h" prefix = "gtk"#}

If a binding module contains a binding hook, it must be the first hook in the module.

3.3 Type Hooks

{#type ident#}

A type hooks maps a C type to a Haskell type. As an example, consider

type GInt = {#type gint#}

The type must be a defined type, primitive types, such as int, are not admissible.

3.4 Sizeof Hooks

{#sizeof ident#}

A sizeof hooks maps a C type to its size in bytes. As an example, consider

gIntSize :: IntgIntSize = {#sizeof gint#}

The type must be a defined type, primitive types, such as int, are not admissible. The size of primitive types can always be obtained using Storable.sizeOf.

3.5 Enumeration Hooks

{#enum cid [as hsid] {alias1 , ... , aliasn} [with prefix = pref] [deriving (clid1 , ... , clidn)]#}

Rewrite the C enumeration called cid into a Haskell data type declaration, which is made an instance of Enum such that the ordinals match those of the enumeration values in C. This takes explicit enumeration values in the C definitions into account. If hsid is given, this is the name of the Haskell data type. The identifiers clid1 to clidn are added to the deriving clause of the Haskell type.

By default, the names of the C enumeration are used for the constructors in Haskell. If alias1 is underscoreToCase, the original C names are capitalised and the use of underscores is rewritten to caps. Moreover, alias1 to aliasn may be aliases of the form cid as hsid, which map individual C names to Haskell names. Instead of the global prefix introduced by a context hook, a local prefix pref can optionally be specified.

As an example, consider

{#enum WindowType {underscoreToCase} deriving (Eq)#}

Note: The enum define hooks described in the C->Haskell are not implemented yet.

3.6 Call Hooks

{#call [fun] [unsafe] cid [as hsid]#}

A call hook rewrites to a call to the C function cid and also ensures that the appropriate foreign import declaration is generated. The tags fun and unsafe specify that the external function is purely functional and cannot re-enter the Haskell runtime, respectively. If hsid is present, it is used as the identifier for the foreign declaration, which otherwise defaults to the cid.

As an example, consider

sin :: Float -> Float
sin  = {#call fun sin as "_sin"#}

3.7 Get Hooks

{#get apath#}

A get hook supports accessing a member value of a C structure. The hook itself yields a function that, when given the address of a structure of the right type, performs the structure access. The member that is to be extracted is specified by the access path apath. Access paths are formed as follows (following a subset of the C expression syntax):

For example, we may have

visualGetType              :: Visual -> IO VisualType
visualGetType (Visual vis)  = liftM cToEnum $ {#get Visual->type#} vis

3.8 Set Hooks

{#get apath#}

Set hooks are formed in the same way as get hooks, but yield a function that assigns a value to a member of a C structure. These functions expect a pointer to the structure as the first and the value to be assigned as the second argument. For example, we may have

{#set sockaddr_in.sin_family#} addr_in (cFromEnum AF_NET)

3.9 Pointer Hooks

{#pointer [*] cid [as hsid] [foreign | stable] [newtype | -> hsid2]#}

A pointer hook facilitates the mapping of C to Haskell pointer types. In particular, it enables the use of ForeignPtr and StablePtr types and defines type name translations for pointers to non-basic types. In general, such a hook establishes an association between the C type cid or *cid and the Haskell type hsid, where the latter defaults to cid if not explicitly given. The identifier cid will usually be a type name, but in the case of *cid may also be a struct, union, or enum tag. If both a type name and a tag of the same name are available, the type name takes precedence. Optionally, the Haskell representation of the pointer can be by a ForeignPtr or StablePtr instead of a plain Ptr. If the newtype tag is given, the Haskell type hsid is defined as a newtype rather than a transparent type synonym. In case of a newtype, the type argument to the Haskell pointer type will be hsid, which gives a cyclic definition, but the type argument is here really only used as a unique type tag. Without newtype, the default type argument is (), but another type can be specified after the symbol ->.

For example, we may have

{#pointer *GtkObject as Object foreign newtype#}

This will generate a new type Object as follows:

newtype Object = Object (ForeignPtr Object)

which allows to export Object as an abstract type and facilitates type checking at call sites of imported functions using the encapsulated foreign pointer. The latter is achieved by C->Haskell as follows. The tool remembers the association of the C type *GtkObject with the Haskell type Object, and so, it generates for the C function

void gtk_unref_object (GtkObject *obj);

the import declaration

foreign import gtk_unref_object :: Object -> IO ()

This function can obviously only be applied to pointers of the right type, and thus, protects against the common mistake of confusing the order of pointer arguments in function calls.

However, as the Haskell FFI does not allow to return ForeignPtrs from function calls, the tool will use the type Ptr HsName in this case, where HsName is the Haskell name of the type. In the above example, that would be Ptr Object.

As an example that does not represent the pointer as an abstract type, consider the C type declaration:

typedef struct {int x, y;} *point;

We can represent it in Haskell as

data Point = Point {x :: Int, y :: Int}
{#pointer point as PointPtr -> Point#}

which will translate to

data Point = Point {x :: Int, y :: Int}
type PointPtr = Ptr Point

and establish a type association between point and PointPtr.

Restriction: The name cid cannot be a basic C type (such as int), it must be a defined name.

3.10 Grammar Rules

The following grammar rules define the syntax of binding hooks:

hook     -> `{#' inner `#}'
inner    -> `import' ['qualified'] ident
          | `context' ctxt
          | `type' ident
          | `sizeof' ident
          | `enum' idalias trans [`with' prefix] [deriving]
          | `call' [`fun'] [`unsafe'] idalias
          | `get' apath
          | `set' apath
          | `pointer' ['*'] idalias ptrkind

ctxt     -> [`header' `=' string] [`lib' `=' string] [prefix]
idalias  -> ident [`as' ident]
prefix   -> `prefix' `=' string
deriving -> `deriving' `(' ident_1 `,' ... `,' ident_n `)'
apath    -> ident
          | `*' apath
          | apath `.' ident
          | apath `->' ident
trans    -> `{' alias_1 `,' ... `,' alias_n `}'
alias    -> `underscoreToCase'
          | ident `as' ident
ptrkind  -> [`foreign' | `stable'] ['newtype' | '->' ident]


Next Previous Contents