This is a rough description of some of the coding practices and style that we use for Haskell code inside ghc/compiler.
The general rule is to stick to the same coding style as is already used in the file you're editing. If you must make stylistic changes, commit them separately from functional changes, so that someone looking back through the change logs can easily distinguish them.
In GHC we use a mixture of literate (.lhs) and non-literate (.hs) source. I (Simon M.) prefer to use non-literate style, because I think the \begin{code}..\end{code} clutter up the source too much, and I like to use Haddock-style comments (we haven't tried processing the whole of GHC with Haddock yet, though).
We pass all the compiler sources through CPP. The -cpp flag is always added by the build system.
The following CPP symbols are used throughout the compiler:
All debugging output should be placed inside #ifdef DEBUG; we generally use this to provide warnings about strange cases and things that might warrant investigation. When DEBUG is off, the compiler should normally be silent unless something goes wrong (exception when the verbosity level is greater than zero).
A good rule of thumb is that DEBUG shouldn't add more than about 10-20% to the compilation time. This is the case at the moment. If it gets too expensive, we won't use it. For more expensive runtime checks, consider adding a flag - see for example -dcore-lint.
There are three platforms of interest to GHC:
At the moment, there is very limited support for having different values for buil, host, and target. In particular:
In the compiler's source code, you may make use of the following CPP symbols:
where xxx is the appropriate value: eg. i386_TARGET_ARCH.
GHC must be compilable by every major version of GHC from 5.02 onwards, and itself. It isn't necessary for it to be compilable by every intermediate development version (that includes last week's CVS sources).
To maintain compatibility, use HsVersions.h (see below) where possible, and try to avoid using #ifdef in the source itself.
We now describe a typical source file, annotating stylistic choices as we go.
{-# OPTIONS ... #-}
An OPTIONS pragma is optional, but if present it should go right at the top of the file. Things you might want to put in OPTIONS include:
Don't bother putting -cpp or -fglasgow-exts in the OPTIONS pragma; these are already added to the command line by the build system.
module Foo ( T(..), foo, -- :: T -> T ) where
We usually (99% of the time) include an export list. The only exceptions are perhaps where the export list would list absolutely everything in the module, and even then sometimes we do it anyway.
It's helpful to give type signatures inside comments in the export list, but hard to keep them consistent, so we don't always do that.
#include "HsVersions.h"
HsVersions.h is a CPP header file containing a number of macros that help smooth out the differences between compiler versions. It defines, for example, macros for library module names which have moved between versions. Take a look.
-- friends import SimplMonad -- GHC import CoreSyn import Id ( idName, idType ) import BasicTypes -- libraries import DATA_IOREF ( newIORef, readIORef ) -- std import List ( partition ) import Maybe ( fromJust )
List imports in the following order:
Import library modules from the base and haskell98 packages only. Use #defines in HsVersions.h when the modules names differ between versions of GHC (eg. DATA_IOREF in the example above). For code inside #ifdef GHCI, don't need to worry about GHC versioning (because we are bootstrapped).
We usually use import specs to give an explicit list of the entities imported from a module. The main reason for doing this is so that you can search the file for an entity and find which module it comes from. However, huge import lists can be a pain to maintain, so we often omit the import specs when they start to get long (actually I start omitting them when they don't fit on one line --Simon M.). Tip: use GHC's -fwarn-unused-imports flag so that you get notified when an import isn't being used any more.
If the module can be compiled multiple ways (eg. GHCI vs. non-GHCI), make sure the imports are properly #ifdefed too, so as to avoid spurious unused import warnings.
ToDo: finish this