aihc-cpp-0.1.0.0: Pure Haskell C preprocessor for aihc
LicenseUnlicense
Safe HaskellSafe-Inferred
LanguageHaskell2010

Aihc.Cpp

Description

This module provides a C preprocessor implementation designed for preprocessing Haskell source files that use CPP extensions.

The main entry point is preprocess, which takes a Config and source text, returning a Step that either completes with a Result or requests an include file to be resolved.

Synopsis

Preprocessing

preprocess :: Config -> Text -> Step Source #

Preprocess C preprocessor directives in the input text.

This function handles:

  • Macro definitions (#define) and expansion
  • Conditional compilation (#if, #ifdef, #ifndef, #elif, #else, #endif)
  • File inclusion (#include)
  • Diagnostics (#warning, #error)
  • Line control (#line)
  • Predefined macros (FILE, LINE, DATE, TIME)

Macro expansion

Object-like macros are expanded in the output:

>>> let Done r = preprocess defaultConfig "#define FOO 42\nThe answer is FOO"
>>> T.putStr (resultOutput r)
#line 1 "<input>"

The answer is 42

Function-like macros are also supported:

>>> let Done r = preprocess defaultConfig "#define MAX(a,b) ((a) > (b) ? (a) : (b))\nMAX(3, 5)"
>>> T.putStr (resultOutput r)
#line 1 "<input>"

((3) > (5) ? (3) : (5))

Conditional compilation

Conditional directives control which sections of code are included:

>>> :{
let Done r = preprocess defaultConfig
      "#define DEBUG 1\n#if DEBUG\ndebug mode\n#else\nrelease mode\n#endif"
in T.putStr (resultOutput r)
:}
#line 1 "<input>"


debug mode



Include handling

When an #include directive is encountered, preprocess returns a NeedInclude step. The caller must provide the contents of the included file:

>>> :{
let NeedInclude req k = preprocess defaultConfig "#include \"header.h\"\nmain code"
    Done r = k (Just "-- header content")
in T.putStr (resultOutput r)
:}
#line 1 "<input>"
#line 1 "./header.h"
-- header content
#line 2 "<input>"
main code

If the include file is not found, pass Nothing to emit an error:

>>> :{
let NeedInclude _ k = preprocess defaultConfig "#include \"missing.h\""
    Done r = k Nothing
in do
  T.putStr (resultOutput r)
  mapM_ print (resultDiagnostics r)
:}
#line 1 "<input>"
Diagnostic {diagSeverity = Error, diagMessage = "missing include: missing.h", diagFile = "<input>", diagLine = 1}

Diagnostics

The #warning directive emits a warning:

>>> :{
let Done r = preprocess defaultConfig "#warning This is a warning"
in do
  T.putStr (resultOutput r)
  mapM_ print (resultDiagnostics r)
:}
#line 1 "<input>"

Diagnostic {diagSeverity = Warning, diagMessage = "This is a warning", diagFile = "<input>", diagLine = 1}

The #error directive emits an error and stops preprocessing:

>>> :{
let Done r = preprocess defaultConfig "#error Build failed\nthis line is not processed"
in do
  T.putStr (resultOutput r)
  mapM_ print (resultDiagnostics r)
:}
#line 1 "<input>"

Diagnostic {diagSeverity = Error, diagMessage = "Build failed", diagFile = "<input>", diagLine = 1}

Configuration

data Config Source #

Configuration for the C preprocessor.

Constructors

Config 

Fields

  • configInputFile :: FilePath

    The name of the input file, used in #line directives and FILE expansion.

  • configMacros :: !(Map Text Text)

    User-defined macros. These are expanded as object-like macros. Note that the values should include any necessary quoting. For example, to define a string macro, use ""value"".

defaultConfig :: Config Source #

Default configuration with sensible defaults.

To customize the date and time macros:

>>> import qualified Data.Map.Strict as M
>>> let cfg = defaultConfig { configMacros = M.fromList [("__DATE__", "\"Mar 15 2026\""), ("__TIME__", "\"14:30:00\"")] }
>>> configMacros cfg
fromList [("__DATE__","\"Mar 15 2026\""),("__TIME__","\"14:30:00\"")]

To add additional macros while keeping the defaults:

>>> import qualified Data.Map.Strict as M
>>> let cfg = defaultConfig { configMacros = M.insert "VERSION" "42" (configMacros defaultConfig) }
>>> M.lookup "VERSION" (configMacros cfg)
Just "42"

Results

data Step Source #

A step in the preprocessing process. Either preprocessing is complete (Done) or an #include directive needs to be resolved (NeedInclude).

Constructors

Done !Result

Preprocessing is complete.

NeedInclude !IncludeRequest !(Maybe Text -> Step)

An #include directive was encountered. The caller must provide the contents of the included file (or Nothing if not found), and preprocessing will continue.

data Result Source #

The result of preprocessing.

Constructors

Result 

Fields

Instances

Instances details
NFData Result Source # 
Instance details

Defined in Aihc.Cpp

Methods

rnf :: Result -> () #

Generic Result Source # 
Instance details

Defined in Aihc.Cpp

Associated Types

type Rep Result 
Instance details

Defined in Aihc.Cpp

type Rep Result = D1 ('MetaData "Result" "Aihc.Cpp" "aihc-cpp-0.1.0.0-1NCgSL9pqtVGyxat12Z7AR" 'False) (C1 ('MetaCons "Result" 'PrefixI 'True) (S1 ('MetaSel ('Just "resultOutput") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Text) :*: S1 ('MetaSel ('Just "resultDiagnostics") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 [Diagnostic])))

Methods

from :: Result -> Rep Result x #

to :: Rep Result x -> Result #

Show Result Source # 
Instance details

Defined in Aihc.Cpp

Eq Result Source # 
Instance details

Defined in Aihc.Cpp

Methods

(==) :: Result -> Result -> Bool #

(/=) :: Result -> Result -> Bool #

type Rep Result Source # 
Instance details

Defined in Aihc.Cpp

type Rep Result = D1 ('MetaData "Result" "Aihc.Cpp" "aihc-cpp-0.1.0.0-1NCgSL9pqtVGyxat12Z7AR" 'False) (C1 ('MetaCons "Result" 'PrefixI 'True) (S1 ('MetaSel ('Just "resultOutput") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Text) :*: S1 ('MetaSel ('Just "resultDiagnostics") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 [Diagnostic])))

Include handling

data IncludeRequest Source #

Information about a pending #include that needs to be resolved.

Constructors

IncludeRequest 

Fields

Instances

Instances details
NFData IncludeRequest Source # 
Instance details

Defined in Aihc.Cpp

Methods

rnf :: IncludeRequest -> () #

Generic IncludeRequest Source # 
Instance details

Defined in Aihc.Cpp

Associated Types

type Rep IncludeRequest 
Instance details

Defined in Aihc.Cpp

type Rep IncludeRequest = D1 ('MetaData "IncludeRequest" "Aihc.Cpp" "aihc-cpp-0.1.0.0-1NCgSL9pqtVGyxat12Z7AR" 'False) (C1 ('MetaCons "IncludeRequest" 'PrefixI 'True) ((S1 ('MetaSel ('Just "includePath") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 FilePath) :*: S1 ('MetaSel ('Just "includeKind") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 IncludeKind)) :*: (S1 ('MetaSel ('Just "includeFrom") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 FilePath) :*: S1 ('MetaSel ('Just "includeLine") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Int))))
Show IncludeRequest Source # 
Instance details

Defined in Aihc.Cpp

Eq IncludeRequest Source # 
Instance details

Defined in Aihc.Cpp

type Rep IncludeRequest Source # 
Instance details

Defined in Aihc.Cpp

type Rep IncludeRequest = D1 ('MetaData "IncludeRequest" "Aihc.Cpp" "aihc-cpp-0.1.0.0-1NCgSL9pqtVGyxat12Z7AR" 'False) (C1 ('MetaCons "IncludeRequest" 'PrefixI 'True) ((S1 ('MetaSel ('Just "includePath") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 FilePath) :*: S1 ('MetaSel ('Just "includeKind") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 IncludeKind)) :*: (S1 ('MetaSel ('Just "includeFrom") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 FilePath) :*: S1 ('MetaSel ('Just "includeLine") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Int))))

data IncludeKind Source #

The kind of #include directive.

Instances

Instances details
NFData IncludeKind Source # 
Instance details

Defined in Aihc.Cpp

Methods

rnf :: IncludeKind -> () #

Generic IncludeKind Source # 
Instance details

Defined in Aihc.Cpp

Associated Types

type Rep IncludeKind 
Instance details

Defined in Aihc.Cpp

type Rep IncludeKind = D1 ('MetaData "IncludeKind" "Aihc.Cpp" "aihc-cpp-0.1.0.0-1NCgSL9pqtVGyxat12Z7AR" 'False) (C1 ('MetaCons "IncludeLocal" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "IncludeSystem" 'PrefixI 'False) (U1 :: Type -> Type))
Show IncludeKind Source # 
Instance details

Defined in Aihc.Cpp

Eq IncludeKind Source # 
Instance details

Defined in Aihc.Cpp

type Rep IncludeKind Source # 
Instance details

Defined in Aihc.Cpp

type Rep IncludeKind = D1 ('MetaData "IncludeKind" "Aihc.Cpp" "aihc-cpp-0.1.0.0-1NCgSL9pqtVGyxat12Z7AR" 'False) (C1 ('MetaCons "IncludeLocal" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "IncludeSystem" 'PrefixI 'False) (U1 :: Type -> Type))

Diagnostics

data Diagnostic Source #

A diagnostic message emitted during preprocessing.

Constructors

Diagnostic 

Fields

Instances

Instances details
NFData Diagnostic Source # 
Instance details

Defined in Aihc.Cpp

Methods

rnf :: Diagnostic -> () #

Generic Diagnostic Source # 
Instance details

Defined in Aihc.Cpp

Associated Types

type Rep Diagnostic 
Instance details

Defined in Aihc.Cpp

type Rep Diagnostic = D1 ('MetaData "Diagnostic" "Aihc.Cpp" "aihc-cpp-0.1.0.0-1NCgSL9pqtVGyxat12Z7AR" 'False) (C1 ('MetaCons "Diagnostic" 'PrefixI 'True) ((S1 ('MetaSel ('Just "diagSeverity") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Severity) :*: S1 ('MetaSel ('Just "diagMessage") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Text)) :*: (S1 ('MetaSel ('Just "diagFile") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 FilePath) :*: S1 ('MetaSel ('Just "diagLine") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Int))))
Show Diagnostic Source # 
Instance details

Defined in Aihc.Cpp

Eq Diagnostic Source # 
Instance details

Defined in Aihc.Cpp

type Rep Diagnostic Source # 
Instance details

Defined in Aihc.Cpp

type Rep Diagnostic = D1 ('MetaData "Diagnostic" "Aihc.Cpp" "aihc-cpp-0.1.0.0-1NCgSL9pqtVGyxat12Z7AR" 'False) (C1 ('MetaCons "Diagnostic" 'PrefixI 'True) ((S1 ('MetaSel ('Just "diagSeverity") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Severity) :*: S1 ('MetaSel ('Just "diagMessage") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Text)) :*: (S1 ('MetaSel ('Just "diagFile") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 FilePath) :*: S1 ('MetaSel ('Just "diagLine") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Int))))

data Severity Source #

Severity level for diagnostics.

Constructors

Warning 
Error 

Instances

Instances details
NFData Severity Source # 
Instance details

Defined in Aihc.Cpp

Methods

rnf :: Severity -> () #

Generic Severity Source # 
Instance details

Defined in Aihc.Cpp

Associated Types

type Rep Severity 
Instance details

Defined in Aihc.Cpp

type Rep Severity = D1 ('MetaData "Severity" "Aihc.Cpp" "aihc-cpp-0.1.0.0-1NCgSL9pqtVGyxat12Z7AR" 'False) (C1 ('MetaCons "Warning" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "Error" 'PrefixI 'False) (U1 :: Type -> Type))

Methods

from :: Severity -> Rep Severity x #

to :: Rep Severity x -> Severity #

Show Severity Source # 
Instance details

Defined in Aihc.Cpp

Eq Severity Source # 
Instance details

Defined in Aihc.Cpp

type Rep Severity Source # 
Instance details

Defined in Aihc.Cpp

type Rep Severity = D1 ('MetaData "Severity" "Aihc.Cpp" "aihc-cpp-0.1.0.0-1NCgSL9pqtVGyxat12Z7AR" 'False) (C1 ('MetaCons "Warning" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "Error" 'PrefixI 'False) (U1 :: Type -> Type))