packages feed

hs-bindgen-1.0.0.0: src-internal/HsBindgen/IR/C/RootDirective.hs

-- | Root header directives
--
-- This module should only be used within the @HsBindgen.IR@ hierarchy.  From
-- outside the @HsBindgen.IR@ hierarchy, "HsBindgen.IR.C" should be used.
--
-- Within @HsBindgen.IR@, all modules aside from "HsBindgen.IR.C" should import
-- this module qualified for consistency.
--
-- > import HsBindgen.IR.C.RootDirective qualified as C
module HsBindgen.IR.C.RootDirective (
    -- * RootDirective
    RootDirective(..)
  , UncheckedRootDirective
  , hashIncludeArgsOf
    -- * Rendering
  , renderRootDirectives
  ) where

import HsBindgen.Imports
import HsBindgen.IR.C.HashDefine (HashDefine, hashDefineToDirective)
import HsBindgen.IR.C.HashIncludeArg (HashIncludeArg (..),
                                      UncheckedHashIncludeArg)

{-------------------------------------------------------------------------------
  RootDirective
-------------------------------------------------------------------------------}

-- | A directive of the root header
--
-- The user states @#include@s and @#define@s as a single ordered list, because
-- the order matters: a @#define@ only affects the headers included after it.
--
-- The parameter is the @#include@ argument, which has an unchecked (as given by
-- the user) and a checked form; @#define@s need no checking.
data RootDirective arg =
    DirectiveHashInclude arg
  | DirectiveHashDefine  HashDefine
  deriving stock (Show, Eq, Generic, Functor, Foldable, Traversable)

-- | Root directive with an unchecked @#include@ argument
type UncheckedRootDirective = RootDirective UncheckedHashIncludeArg

-- | The @#include@ arguments, in order, discarding the @#define@s
--
-- For consumers that genuinely only care about the headers.
hashIncludeArgsOf :: [RootDirective arg] -> [arg]
hashIncludeArgsOf = concatMap toList

{-------------------------------------------------------------------------------
  Rendering
-------------------------------------------------------------------------------}

-- | Render root directives, one per line, in order
--
-- This is the single source of truth for the C source seen by /all/ C stages:
-- the root header parsed by @libclang@, the generated CAPI wrapper source
-- compiled by GHC, and the generated C test source.
renderRootDirectives :: [RootDirective HashIncludeArg] -> String
renderRootDirectives = unlines . map render
  where
    render :: RootDirective HashIncludeArg -> String
    render = \case
      DirectiveHashInclude arg -> "#include <" ++ arg.path ++ ">"
      DirectiveHashDefine  d   -> hashDefineToDirective d