| License | Unlicense |
|---|---|
| Safe Haskell | Safe-Inferred |
| Language | Haskell2010 |
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
- preprocess :: Config -> Text -> Step
- data Config = Config {
- configInputFile :: FilePath
- configMacros :: !(Map Text Text)
- defaultConfig :: Config
- data Step
- = Done !Result
- | NeedInclude !IncludeRequest !(Maybe Text -> Step)
- data Result = Result {
- resultOutput :: !Text
- resultDiagnostics :: ![Diagnostic]
- data IncludeRequest = IncludeRequest {
- includePath :: !FilePath
- includeKind :: !IncludeKind
- includeFrom :: !FilePath
- includeLine :: !Int
- data IncludeKind
- data Diagnostic = Diagnostic {
- diagSeverity :: !Severity
- diagMessage :: !Text
- diagFile :: !FilePath
- diagLine :: !Int
- data Severity
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
Configuration for the C preprocessor.
Constructors
| Config | |
Fields
| |
defaultConfig :: Config Source #
Default configuration with sensible defaults.
configInputFileis set to"<input>"configMacrosincludesDATEandTIMEset to the Unix epoch
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 cfgfromList [("__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
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 |
The result of preprocessing.
Constructors
| Result | |
Fields
| |
Instances
| NFData Result Source # | |||||
| Generic Result Source # | |||||
Defined in Aihc.Cpp Associated Types
| |||||
| Show Result Source # | |||||
| Eq Result Source # | |||||
| type Rep Result Source # | |||||
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
data IncludeKind Source #
The kind of #include directive.
Constructors
| IncludeLocal | |
| IncludeSystem |
Instances
| NFData IncludeKind Source # | |||||
Defined in Aihc.Cpp Methods rnf :: IncludeKind -> () # | |||||
| Generic IncludeKind Source # | |||||
Defined in Aihc.Cpp Associated Types
| |||||
| Show IncludeKind Source # | |||||
Defined in Aihc.Cpp Methods showsPrec :: Int -> IncludeKind -> ShowS # show :: IncludeKind -> String # showList :: [IncludeKind] -> ShowS # | |||||
| Eq IncludeKind Source # | |||||
Defined in Aihc.Cpp | |||||
| type Rep IncludeKind Source # | |||||
Diagnostics
data Diagnostic Source #
A diagnostic message emitted during preprocessing.
Constructors
| Diagnostic | |
Fields
| |
Instances
| NFData Diagnostic Source # | |||||
Defined in Aihc.Cpp Methods rnf :: Diagnostic -> () # | |||||
| Generic Diagnostic Source # | |||||
Defined in Aihc.Cpp Associated Types
| |||||
| Show Diagnostic Source # | |||||
Defined in Aihc.Cpp Methods showsPrec :: Int -> Diagnostic -> ShowS # show :: Diagnostic -> String # showList :: [Diagnostic] -> ShowS # | |||||
| Eq Diagnostic Source # | |||||
Defined in Aihc.Cpp | |||||
| type Rep Diagnostic Source # | |||||
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)))) | |||||