descript-lang-0.2.0.0: src/Descript/BasicInj/Data/Type.hs
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE OverloadedStrings #-}
module Descript.BasicInj.Data.Type
( Symbol (..)
, RecordType (..)
, RecordDecl (..)
, RecordCtx (..)
, recordCtxTypes
, lookupRecordType
, recTypeHasHead
) where
import Descript.BasicInj.Data.Atom
import Descript.Misc
import Data.Semigroup as S
import Data.Monoid as M
import Data.List hiding (head)
import Prelude hiding (head)
-- | A record type.
data RecordType an
= RecordType
{ recordTypeAnn :: an
, head :: FSymbol an -- ^ Identifies and distinguishes the type.
, properties :: [Symbol an] -- ^ All instances should have properties with these keys.
} deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable)
-- | A record declaration.
data RecordDecl an
= RecordDecl
{ recordDeclAnn :: an
, recordDeclType :: RecordType an
} deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable)
-- | Contains a source file's data definitions.
-- These record types encode the types of records which can be used
-- throughout the rest of the source.
-- Each of them should have a different head.
data RecordCtx an
= RecordCtx
{ recordCtxAnn :: an
, recordCtxDecls :: [RecordDecl an]
} deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable)
instance (Semigroup an) => Semigroup (RecordCtx an) where
RecordCtx xAnn xds <> RecordCtx yAnn yds
= RecordCtx (xAnn S.<> yAnn) (xds ++ yds)
instance (Monoid an) => Monoid (RecordCtx an) where
mempty = RecordCtx mempty []
RecordCtx xAnn xds `mappend` RecordCtx yAnn yds
= RecordCtx (xAnn M.<> yAnn) (xds ++ yds)
instance Ann RecordCtx where
getAnn = recordCtxAnn
instance Ann RecordDecl where
getAnn = recordDeclAnn
instance Ann RecordType where
getAnn = recordTypeAnn
instance Printable RecordCtx where
aprintRec sub (RecordCtx _ recordDecls) = pintercal "\n" $ map sub recordDecls
instance Printable RecordDecl where
aprintRec sub (RecordDecl _ recordType) = sub recordType M.<> "."
instance Printable RecordType where
aprintRec sub recordType = sub (head recordType) M.<> propsPrinted
where propsPrinted = "[" M.<> pintercal ", " propPrinteds M.<> "]"
propPrinteds = map sub $ properties recordType
instance (Show an) => Summary (RecordCtx an) where
summaryRec = pprintSummaryRec
instance (Show an) => Summary (RecordDecl an) where
summaryRec = pprintSummaryRec
instance (Show an) => Summary (RecordType an) where
summaryRec = pprintSummaryRec
-- | The record types declared in the context.
recordCtxTypes :: RecordCtx an -> [RecordType an]
recordCtxTypes = map recordDeclType . recordCtxDecls
-- | Finds the record type with the given head in the context.
lookupRecordType :: FSymbol an -> RecordCtx an -> Maybe (RecordType an)
lookupRecordType head' = find (recTypeHasHead head') . recordCtxTypes
-- | Does the record type have the given head?
recTypeHasHead :: FSymbol an1 -> RecordType an2 -> Bool
recTypeHasHead head' record = head' =@= head record