```
-- | Algebraic data type definitions.

-- * Data type definition table
, DataMode   (..)
, DataType   (..)
, DataCtor   (..)

, lookupModeOfDataType)
where
import DDC.Type.Exp
import Data.Map                         (Map)
import qualified Data.Map.Strict        as Map
import Data.Maybe

-- | The definition of a single data type.
{ -- | Name of the data type.

-- | Kinds of type parameters.

-- | Constructors of the data type, or Nothing if there are
--   too many to list (like with `Int`).
, dataDefCtors          :: !(Maybe [(n, [Type n])]) }
deriving Show

-- | A table of data type definitions,
--   unpacked into type and data constructors so we can find them easily.
{ dataDefsTypes :: !(Map n (DataType n))
, dataDefsCtors :: !(Map n (DataCtor n)) }
deriving Show

-- | The mode of a data type records how many data constructors there are.
--   This can be set to 'Large' for large primitive types like Int and Float.
--   In this case we don't ever expect them all to be enumerated
--   as case alternatives.
data DataMode n
= DataModeSmall ![n]
| DataModeLarge
deriving Show

-- | Describes a data type constructor, used in the `DataDefs` table.
data DataType n
= DataType
{ -- | Name of data type constructor.
dataTypeName       :: !n

-- | Kinds of type parameters to constructor.
, dataTypeParamKinds :: ![Kind n]

-- | Names of data constructors of this data type,
--   or `Nothing` if it has infinitely many constructors.
, dataTypeMode       :: !(DataMode n) }
deriving Show

-- | Describes a data constructor, used in the `DataDefs` table.
data DataCtor n
= DataCtor
{ -- | Name of data constructor.
dataCtorName       :: !n

-- | Tag of constructor (order in data type declaration)
, dataCtorTag        :: !Integer

-- | Field types of constructor.
, dataCtorFieldTypes :: ![Type n]

-- | Name of result type of constructor.
, dataCtorTypeName   :: !n }
deriving Show

-- | An empty table of data type definitions.

-- | Insert a data type definition into some DataDefs.
= let  defType = DataType
{ dataTypeName       = nType
, dataTypeParamKinds = ks
, dataTypeMode       = defMode }

defMode = case mCtors of
Nothing    -> DataModeLarge
Just ctors -> DataModeSmall (map fst ctors)

makeDefCtor tag (nCtor, tsFields)
= DataCtor
{ dataCtorName       = nCtor
, dataCtorTag        = tag
, dataCtorFieldTypes = tsFields
, dataCtorTypeName   = nType }

defCtors = case mCtors of
Nothing  -> Nothing
Just cs  -> Just \$ zipWith makeDefCtor [0..] cs

\$ Map.fromList [(n, def)
| def@(DataCtor n _ _ _) <- concat \$ maybeToList defCtors ]}