packages feed

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

-- | Translate the partial AST to our internal AST
module HsBindgen.Frontend.LanguageC.PartialAST.ToBindgen (
    -- * Declarations
    fromDecl
  , fromNamedDecl
  , fromFunDecl
    -- * Types
  , fromPartialType
  , fromUnknownType
  , fromKnownType
  ) where

import HsBindgen.Frontend.LanguageC.Monad
import HsBindgen.Frontend.LanguageC.PartialAST
import HsBindgen.Frontend.Pass.ReparseMacroExpansions.LanC (LanC)
import HsBindgen.Imports
import HsBindgen.IR.C qualified as C
import HsBindgen.IR.Pass (NoAnn (..))
import HsBindgen.Language.C qualified as C

{-------------------------------------------------------------------------------
  Declarations
-------------------------------------------------------------------------------}

fromDecl :: PartialDecl -> FromLanC (Maybe CName, C.Type LanC)
fromDecl partialDecl = do
    typ <- fromKnownType <$> fromPartialType partialDecl.typ
    return (partialDecl.name, typ)

fromNamedDecl :: PartialDecl -> FromLanC (CName, C.Type LanC)
fromNamedDecl partialDecl = do
    name <- partialFromJust partialDecl.name
    typ  <- fromKnownType <$> fromPartialType partialDecl.typ
    return (name, typ)

fromFunDecl ::
     PartialDecl
  -> FromLanC (
         CName
       , ( [(Maybe CName, C.Type LanC)]
         , C.Type LanC
         )
       )
fromFunDecl partialDecl = do
    name          <- partialFromJust partialDecl.name
    (params, res) <- fromTopLevelFun =<< fromPartialType partialDecl.typ
    return (name, (params, res))

{-------------------------------------------------------------------------------
  Types
-------------------------------------------------------------------------------}

fromPartialType :: PartialType -> FromLanC KnownType
fromPartialType = \case
     PartialUnknown typ -> fromUnknownType typ
     PartialKnown typ -> return typ

fromUnknownType :: UnknownType -> FromLanC KnownType
fromUnknownType uty =
      fmap (
          KnownType
        . (if uty.isConst then C.TypeQual C.QualConst else id)
        . (if uty.isComplex then C.TypeComplex else C.TypePrim)
        )
    $ case uty of
        CChar{}  -> pure $ C.PrimChar (C.PrimSignImplicit Nothing)
        CSChar{} -> pure $ C.PrimChar (C.PrimSignExplicit C.Signed)
        CUChar{} -> pure $ C.PrimChar (C.PrimSignExplicit C.Unsigned)
        CShort{} -> pure $ C.PrimIntegral C.PrimShort C.Signed
        CSShort{} -> pure $ C.PrimIntegral C.PrimShort C.Signed
        CUShort{} -> pure $ C.PrimIntegral C.PrimShort C.Unsigned
        CInt{} -> pure $ C.PrimIntegral C.PrimInt C.Signed
        CSInt{} -> pure $ C.PrimIntegral C.PrimInt C.Signed
        CUInt{} -> pure $ C.PrimIntegral C.PrimInt C.Unsigned
        CLong{} -> pure $ C.PrimIntegral C.PrimLong C.Signed
        CSLong{} -> pure $ C.PrimIntegral C.PrimLong C.Signed
        CULong{} -> pure $ C.PrimIntegral C.PrimLong C.Unsigned
        CLLong{} -> pure $ C.PrimIntegral C.PrimLongLong C.Signed
        CSLLong{} -> pure $ C.PrimIntegral C.PrimLongLong C.Signed
        CULLong{} -> pure $ C.PrimIntegral C.PrimLongLong C.Unsigned
        CFloat{} -> pure $ C.PrimFloating C.PrimFloat
        CDouble{} -> pure $ C.PrimFloating C.PrimDouble
        CLDouble{} -> unsupported "long double"
        CTypeUnknown{} -> unexpected $ "incomplete or invalid type: " <> (show uty)

fromKnownType :: KnownType -> C.Type LanC
fromKnownType = \case
    KnownType   typ        -> typ
    TopLevelFun params res -> C.TypeFun (map (mkTypeFunArg . snd) params) res
  where
    mkTypeFunArg typ = C.TypeFunArgF {
          typ = typ
        , ann = NoAnn
        }

fromTopLevelFun ::
     KnownType
  -> FromLanC (
         [(Maybe CName, C.Type LanC)]
       , C.Type LanC
       )
fromTopLevelFun = \case
    TopLevelFun params res -> return (params, res)
    other -> unexpected $ show other

{-------------------------------------------------------------------------------
  Internal auxiliary
-------------------------------------------------------------------------------}

partialFromJust :: HasCallStack => Maybe a -> FromLanC a
partialFromJust Nothing  = unexpected "Nothing"
partialFromJust (Just x) = return x