packages feed

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

-- | @#define@ directive
--
-- 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.HashDefine qualified as C
module HsBindgen.IR.C.HashDefine (
    -- * HashDefine
    HashDefine(..)
  , hashDefineToDirective
  ) where

import HsBindgen.Imports

{-------------------------------------------------------------------------------
  HashDefine
-------------------------------------------------------------------------------}

-- | A @#define@ directive
--
-- This is @#define@ syntax, /not/ C compiler @-D@ syntax; the translation
-- between the two is not the identity:
--
-- * The @=@ of @-DFOO=BAR@ is not @#define@ syntax. @#define FOO=BAR@ is valid
--   C, but defines a macro @FOO@ whose replacement list is @= BAR@. * @-DFOO@
--   is not @#define FOO@. Clang and GCC define a bare @-D@ macro as @1@, so
--   @-DFOO@ and @-DFOO=@ define /different/ macros. Both are @#ifdef@-true, but
--   @#if FOO@ is true for the former and an error for the latter.
--
-- The correspondence is therefore:
--
-- +--------------------+--------------------------------+--------------------+
-- | @-D@ argument      | t'HashDefine'                  | emitted directive  |
-- +====================+================================+====================+
-- | @-D FOO@           | @name = "FOO", value = "1"@    | @#define FOO 1@    |
-- +--------------------+--------------------------------+--------------------+
-- | @-D FOO=BAR@       | @name = "FOO", value = "BAR"@  | @#define FOO BAR@  |
-- +--------------------+--------------------------------+--------------------+
-- | @-D FOO=@          | @name = "FOO", value = ""@     | @#define FOO@      |
-- +--------------------+--------------------------------+--------------------+
-- | @-D \'FOO(x)=x\'@  | @name = "FOO(x)", value = "x"@ | @#define FOO(x) x@ |
-- +--------------------+--------------------------------+--------------------+
--
-- Neither field is parsed or validated: a malformed definition is reported by
-- Clang as a diagnostic in the root header, the same treatment an unresolvable
-- @#include@ gets.
data HashDefine = HashDefine {
      -- | Macro name; may be function-like, e.g. @FOO(x)@
      name :: String

      -- | Replacement list; @""@ for @#define FOO@
    , value :: String
    }
  deriving stock (Show, Eq, Generic)

-- | Render a t'HashDefine' as a @#define@ directive (no trailing newline)
hashDefineToDirective :: HashDefine -> String
hashDefineToDirective hashDefine
  | null hashDefine.value = "#define " ++ hashDefine.name
  | otherwise             = "#define " ++ hashDefine.name ++ " " ++ hashDefine.value