packages feed

hs-bindgen-1.0.0.0: src-internal/HsBindgen/Frontend/LanguageC/PartialAST.hs

-- | Partial AST
--
-- The translation from the language-c AST to our AST is a bit awkward, because
-- language-c will feed us information in a piecemeal fashion. We therefore
-- introduce this \"partial AST\" as a step in the middle.
--
-- Intended for unqualified import.
module HsBindgen.Frontend.LanguageC.PartialAST (
    PartialDecl(..)
  , PartialType(..)
  , UnknownType(
        ..
      , CChar, CSChar, CUChar
      , CShort, CSShort, CUShort
      , CInt, CSInt, CUInt
      , CLong, CSLong, CULong
      , CLLong, CSLLong, CULLong
      , CFloat, CDouble, CLDouble
      , CTypeUnknown)
  , Base(..)
  , Size(..)
  , KnownType(..)
  , CName
    -- * Starting point: no information known
  , unknownDecl
  ) where

import HsBindgen.Frontend.Pass.ReparseMacroExpansions.LanC (LanC)
import HsBindgen.Imports
import HsBindgen.IR.C qualified as C
import HsBindgen.Language.C qualified as C

{-------------------------------------------------------------------------------
  Definition
-------------------------------------------------------------------------------}

data PartialDecl = PartialDecl{
      name :: Maybe CName
    , typ  :: PartialType
    }
  deriving stock (Show, Generic)

data PartialType =
    PartialUnknown UnknownType
  | PartialKnown KnownType
  deriving stock (Show)

data KnownType =
    KnownType (C.Type LanC)

    -- | Special case for top-level functions, so we can record argument names
    --
    -- It's not necessary to do this recursively: we only want argument names
    -- for top-level function declarations (not for function pointers).
  | TopLevelFun [(Maybe CName, C.Type LanC)] (C.Type LanC)
  deriving stock (Show)

-- | Name
--
-- Since @language-c@ does not really distinguish between a top-level
-- declaration or the \"declaration\" of a function argument, we use 'Text' here
-- rather than 'C.DeclName' or 'C.ScopedName'. Since we do not actually parse
-- top-level struct/enum/union declarations (i.e., deal with \"ordinary\" names
-- only anyway), this causes no trouble.
type CName = Text

{-------------------------------------------------------------------------------
  UnknownType
-------------------------------------------------------------------------------}

-- | The type itself is not yet known, but may have some qualifiers
data UnknownType = UnknownType{
      base      :: [Base]
    , sign      :: [C.PrimSign]
    , size      :: [Size]
    , isConst   :: Bool
    , isComplex :: Bool
    }
  deriving stock (Show, Generic)

data Base = Char | Int | Float | Double
  deriving stock (Show, Eq, Ord, Generic)

data Size = Short | Long
  deriving stock (Show, Eq, Ord, Generic)

{-# COMPLETE
    CChar
  , CSChar
  , CUChar
  , CShort
  , CSShort
  , CUShort
  , CInt
  , CSInt
  , CUInt
  , CLong
  , CSLong
  , CULong
  , CLLong
  , CSLLong
  , CULLong
  , CFloat
  , CDouble
  , CLDouble
  , CTypeUnknown
  #-}

pattern CChar :: UnknownType
pattern CChar <- UnknownType [Char] [] [] _ _

pattern CSChar :: UnknownType
pattern CSChar <- UnknownType [Char] [C.Signed] [] _ _

pattern CUChar :: UnknownType
pattern CUChar <- UnknownType [Char] [C.Unsigned] [] _ _

pattern CShort :: UnknownType
pattern CShort <- UnknownType (optional Int -> True) [] [Short] _ _

pattern CSShort :: UnknownType
pattern CSShort <- UnknownType (optional Int -> True) [C.Signed] [Short] _ _

pattern CUShort :: UnknownType
pattern CUShort <- UnknownType (optional Int -> True) [C.Unsigned] [Short] _ _

pattern CInt :: UnknownType
pattern CInt <- UnknownType [Int] [] [] _ _

pattern CSInt :: UnknownType
pattern CSInt <- UnknownType (optional Int -> True) [C.Signed] [] _ _

pattern CUInt :: UnknownType
pattern CUInt <- UnknownType (optional Int -> True) [C.Unsigned] [] _ _

pattern CLong :: UnknownType
pattern CLong <- UnknownType (optional Int -> True) [] [Long] _ _

pattern CSLong :: UnknownType
pattern CSLong <- UnknownType (optional Int -> True) [C.Signed] [Long] _ _

pattern CULong :: UnknownType
pattern CULong <- UnknownType (optional Int -> True) [C.Unsigned] [Long] _ _

pattern CLLong :: UnknownType
pattern CLLong <- UnknownType (optional Int -> True) [] [Long, Long] _ _

pattern CSLLong :: UnknownType
pattern CSLLong <- UnknownType (optional Int -> True) [C.Signed] [Long, Long] _ _

pattern CULLong :: UnknownType
pattern CULLong <- UnknownType (optional Int -> True) [C.Unsigned] [Long, Long] _ _

pattern CFloat :: UnknownType
pattern CFloat <- UnknownType [Float] [] [] _ _

pattern CDouble :: UnknownType
pattern CDouble <- UnknownType [Double] [] [] _ _

pattern CLDouble :: UnknownType
pattern CLDouble <- UnknownType [Double] [] [Long] _ _

pattern CTypeUnknown :: UnknownType
pattern CTypeUnknown <- UnknownType{}

optional :: Eq a => a -> [a] -> Bool
optional x = \case
    []  -> True
    [y] -> x == y
    _   -> False

{-------------------------------------------------------------------------------
  Starting point: no information known
-------------------------------------------------------------------------------}

unknownDecl :: PartialDecl
unknownDecl = PartialDecl{
      name = Nothing
    , typ  = unknownType
    }

unknownType :: PartialType
unknownType = PartialUnknown UnknownType{
      base      = []
    , sign      = []
    , size      = []
    , isConst   = False
    , isComplex = False
    }