packages feed

ddc-core-tetra-0.4.3.1: DDC/Core/Tetra/Convert/Boxing.hs

-- | Punned data type and constructor definitions for boxed numeric objects.
--
--   Boxed numeric objects are treated abstractly by the source language, and
--   aren't really algebraic data, but we define them as such so that we can
--   re-use the to-salt conversion code for algebraic data.
--
--   Each primitive numeric type like (Nat#) induces a data type and data
--   constructor of the same name.
--
--   The data constructor has a single unboxed field (U# Nat#) and produces
--   a boxed result type (B# Nat#). Note that the name of the data type (Nat#)
--   is different from the result type (B# Nat#), which is unlike real algebraic
--   data types.
--
module DDC.Core.Tetra.Convert.Boxing
        ( isSomeRepType
        , isBoxedRepType
        , isUnboxedRepType
        , isNumericType
        , isVectorType
        , isTextLitType
        , makeBoxedPrimDataType
        , makeBoxedPrimDataCtor)
where
import DDC.Core.Tetra.Prim
import DDC.Core.Tetra.Compounds
import DDC.Type.DataDef


-- Predicates -----------------------------------------------------------------
-- | Check if this is a representable type.
--   This is the union of `isBoxedRepType` and `isUnboxedRepType`.
isSomeRepType :: Type Name -> Bool
isSomeRepType tt
        = isBoxedRepType tt || isUnboxedRepType tt


-- | Check if some representation type is boxed.
--   The type must have kind Data, otherwise bogus result.
--
--   A "representation type" is the sort of type we get after applying the
--   Boxing transform, which works out how to represent everything.
--
--   The boxed representation types are:
--      1) 'a -> b'     -- the function type
--      1) 'a'          -- polymorphic types.
--      2) 'forall ...' -- abstract types.
--      3) 'Unit'       -- the unit data type.
--      5) User defined data types.
--
isBoxedRepType :: Type Name -> Bool
isBoxedRepType tt
        | Just _        <- takeTFun tt
        = True

        | TVar{}        <- tt   = True
        | TForall{}     <- tt   = True

        -- Unit data type.
        | Just (TyConSpec TcConUnit, _)    <- takeTyConApps tt
        = True

        -- User defined data types.
        | Just (TyConBound (UName _) _, _) <- takeTyConApps tt
        = True

        -- Boxed numeric types
        | isNumericType tt
        = True

        -- The primitive vector type.
        | isVectorType tt
        = True

        | otherwise
        = False


-- | Check if some representation type is unboxed.
--   The type must have kind Data, otherwise bogus result.
--
--   A "representation type" is the sort of type we get after applying the
--   Boxing transform, which works out how to represent everything.
--
--   The unboxed representation are are:
--      1) 'U# T'     -- unboxed numeric types, where T is a boxable type.
--
isUnboxedRepType :: Type Name -> Bool
isUnboxedRepType tt
        | Just ( NameTyConTetra TyConTetraU
               , [ti])                  <- takePrimTyConApps tt
        , isNumericType ti || isTextLitType ti
        = True

        | otherwise
        = False


-- | Check if some type is a numeric or other primtitype.
isNumericType :: Type Name -> Bool
isNumericType tt
        | Just (NamePrimTyCon n, [])   <- takePrimTyConApps tt
        = case n of
                PrimTyConBool           -> True
                PrimTyConNat            -> True
                PrimTyConInt            -> True
                PrimTyConSize           -> True
                PrimTyConWord  _        -> True
                PrimTyConFloat _        -> True
                PrimTyConTextLit        -> True
                _                       -> False

        | otherwise                     = False


-- | Check if some type is the boxed vector type.
isVectorType :: Type Name -> Bool
isVectorType tt
        | Just (NameTyConTetra n, _)   <- takePrimTyConApps tt
        = case n of
                TyConTetraVector        -> True
                _                       -> False

        | otherwise                     = False


-- | Check if this is the string type.
isTextLitType :: Type Name -> Bool
isTextLitType tt
        | Just (NamePrimTyCon n, [])    <- takePrimTyConApps tt
        = case n of
                PrimTyConTextLit        -> True
                _                       -> False

        | otherwise                     = False


-- Punned Defs ----------------------------------------------------------------
-- | Generic data type definition for a primitive numeric type.
makeBoxedPrimDataType :: Type Name -> Maybe (DataType Name)
makeBoxedPrimDataType tt
        | Just (n@NamePrimTyCon{}, []) <- takePrimTyConApps tt
        = Just $ DataType 
        { dataTypeName          = n
        , dataTypeParams        = []
        , dataTypeMode          = DataModeLarge
        , dataTypeIsAlgebraic   = False }

        | otherwise
        = Nothing


-- | Generic data constructor definition for a primtive numeric type.
makeBoxedPrimDataCtor :: Type Name -> Maybe (DataCtor Name)
makeBoxedPrimDataCtor tt
        | Just (n@NamePrimTyCon{}, []) <- takePrimTyConApps tt
        = Just $ DataCtor
        { dataCtorName          = n
        , dataCtorTag           = 0
        , dataCtorFieldTypes    = [tUnboxed tt]
        , dataCtorResultType    = tt
        , dataCtorTypeName      = n
        , dataCtorTypeParams    = [] }

        | otherwise
        = Nothing