{-# LINE 100 "Foo.hs #-} vs. # 100 "Foo.hs"

Marcin 'Qrczak' Kowalczyk qrczak@knm.org.pl
24 Jan 2001 22:36:58 GMT

Mon, 22 Jan 2001 16:42:32 +0000, Keith Wansbrough <Keith.Wansbrough@cl.cam.ac.uk> pisze:

> http://www.cl.cam.ac.uk/~kw217/research/papers.html#Wansbrough99:Macros

hsc2hs, although designed for embedding Haskell constructs depending
on C headers, can be used as a Haskell preprocessor.

It avoids lexing Haskell source using C rules. Among C-specific things
it provides #if/#ifdef/etc., #define/#undef, #include, #error/#warning,
and an ugly way to define macros with optional parameters, token
pasting, stringification and controlled layout.

The implementation delegates all hard work to a C compiler applied to
a C program which outputs the Haskell program. {-# LINE #-} pragmas
are understood and generated. #define and #include are also put into
ghc's .hc files. The only part which differs much from cpp and is
quite ugly is macros to be used in the Haskell program. They can be
defined and used for example thus:

#let assert e = "(if (%s) then id else "                            \
                "const (error \"Assertion failed: %s, %s:%d\")) $", \
                e, e, __FILE__, __LINE__

main =
    #assert "length [1,2,3] == 3"
        putStrLn "Hello world"

and if you don't mind applying C lexical syntax to bits of Haskell code,
you can replace uses of e above by #e and call
    #assert (length [1,2,3] == 3)
where parens are necessary only because the expression contains commas
outside parens.

You can also embed e into the string constant thus:
    "(if (" e ") then id else " ...
instead of using printf format, but this fails if the expression
contains % characters.

Macro expansion is not applied to all occurrences of an identifier
in the source, but just to explicitly used new #-constructs as
#assert above.

A macro definition can be written in an equivalent, more low-level
way thus:

#define hsc_assert(e) printf (                                  \
            "(if (%s) then id else "                            \
            "const (error \"Assertion failed: %s, %s:%d\")) $", \
            e, e, __FILE__, __LINE__);

and can make use of arbitrary C statements which are a part of the
C program created and run during preprocessing.

I once made a file preprocessed twice. The first pass generates
#ifdefs for each identifier passed as a macro argument, the second
pass applies these #ifdefs.

hsc2hs is in the CVS version of ghc and QForeign.

 __("<  Marcin Kowalczyk * qrczak@knm.org.pl http://qrczak.ids.net.pl/
  ^^                      SYGNATURA ZASTĘPCZA