-- | Algebraic data type definitions. module DDC.Core.DataDef ( DataDef (..) -- * Data type definition table , DataDefs (..) , DataMode (..) , DataType (..) , DataCtor (..) , emptyDataDefs , insertDataDef , fromListDataDefs , lookupModeOfDataType) where import DDC.Type.Exp import Data.Map (Map) import qualified Data.Map as Map import Data.Maybe import Control.Monad -- | The definition of a single data type. data DataDef n = DataDef { -- | Name of the data type. dataDefTypeName :: n -- | Kinds of type parameters. , dataDefParamKinds :: [Kind n] -- | Constructors of the data type, or Nothing if there are -- too many to list (like with `Int`). , dataDefCtors :: Maybe [(n, [Type n])] } -- DataDefs ------------------------------------------------------------------- -- | A table of data type definitions, -- unpacked into type and data constructors so we can find them easily. data DataDefs n = DataDefs { dataDefsTypes :: Map n (DataType n) , dataDefsCtors :: Map n (DataCtor n) } -- | 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 -- | 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 } -- | Describes a data constructor, used in the `DataDefs` table. data DataCtor n = DataCtor { -- | Name of data constructor. dataCtorName :: n -- | Field types of constructor. , dataCtorFieldTypes :: [Type n] -- | Name of result type of constructor. , dataCtorTypeName :: n } -- | An empty table of data type definitions. emptyDataDefs :: DataDefs n emptyDataDefs = DataDefs { dataDefsTypes = Map.empty , dataDefsCtors = Map.empty } -- | Insert a data type definition into some DataDefs. insertDataDef :: Ord n => DataDef n -> DataDefs n -> DataDefs n insertDataDef (DataDef nType ks mCtors) dataDefs = let defType = DataType { dataTypeName = nType , dataTypeParamKinds = ks , dataTypeMode = defMode } defMode = case mCtors of Nothing -> DataModeLarge Just ctors -> DataModeSmall (map fst ctors) makeDefCtor (nCtor, tsFields) = DataCtor { dataCtorName = nCtor , dataCtorFieldTypes = tsFields , dataCtorTypeName = nType } defCtors = case mCtors of Nothing -> Nothing Just cs -> Just $ map makeDefCtor cs in dataDefs { dataDefsTypes = Map.insert nType defType (dataDefsTypes dataDefs) , dataDefsCtors = Map.union (dataDefsCtors dataDefs) $ Map.fromList [(n, def) | def@(DataCtor n _ _) <- concat $ maybeToList defCtors] } -- | Build a `DataDefs` table from a list of `DataDef` fromListDataDefs :: Ord n => [DataDef n] -> DataDefs n fromListDataDefs defs = foldr insertDataDef emptyDataDefs defs -- | Yield the list of data constructor names for some data type, -- or `Nothing` for large types with too many constructors to list. lookupModeOfDataType :: Ord n => n -> DataDefs n -> Maybe (DataMode n) lookupModeOfDataType n defs = liftM dataTypeMode $ Map.lookup n (dataDefsTypes defs)