hydra-0.1.0: src/main/haskell/Hydra/Meta.hs
module Hydra.Meta where
import Hydra.Core
import Hydra.Compute
import Hydra.CoreDecoding
import Hydra.CoreEncoding
import Hydra.Common
import Hydra.Monads
import Hydra.Mantle
import Hydra.Impl.Haskell.Dsl.Terms
import qualified Data.Map as M
import qualified Data.Maybe as Y
aggregateAnnotations :: (a -> Maybe (Annotated a Meta)) -> a -> Meta
aggregateAnnotations getAnn t = Meta $ M.fromList $ addMeta [] t
where
addMeta m t = case getAnn t of
Nothing -> m
Just (Annotated t' (Meta other)) -> addMeta (m ++ M.toList other) t'
getAnnotation :: String -> Meta -> Maybe (Term Meta)
getAnnotation key (Meta m) = M.lookup key m
getDescription :: Meta -> GraphFlow Meta (Y.Maybe String)
getDescription meta = case getAnnotation metaDescription meta of
Nothing -> pure Nothing
Just term -> case term of
TermLiteral (LiteralString s) -> pure $ Just s
_ -> fail $ "unexpected value for " ++ show metaDescription ++ ": " ++ show term
getTermAnnotation :: Context Meta -> String -> Term Meta -> Y.Maybe (Term Meta)
getTermAnnotation cx key = getAnnotation key . termMetaInternal
getTermDescription :: Term Meta -> GraphFlow Meta (Y.Maybe String)
getTermDescription = getDescription . termMetaInternal
getType :: Meta -> GraphFlow Meta (Y.Maybe (Type Meta))
getType meta = case getAnnotation metaType meta of
Nothing -> pure Nothing
Just dat -> Just <$> decodeType dat
getTypeDescription :: Type Meta -> GraphFlow Meta (Y.Maybe String)
getTypeDescription = getDescription . typeMetaInternal
metaAnnotationClass :: AnnotationClass Meta
metaAnnotationClass = AnnotationClass {
annotationClassDefault = Meta M.empty,
annotationClassEqual = (==),
annotationClassCompare = \m1 m2 -> toComparison $ m1 `compare` m2,
annotationClassShow = show,
annotationClassRead = read,
-- TODO: simplify
annotationClassTermMeta = termMetaInternal,
annotationClassTypeMeta = typeMetaInternal,
annotationClassTermDescription = getTermDescription,
annotationClassTypeDescription = getTypeDescription,
annotationClassTermType = getType . termMetaInternal,
annotationClassSetTermDescription = setTermDescription,
annotationClassSetTermType = setTermType,
annotationClassTypeOf = getType,
annotationClassSetTypeOf = setType}
where
toComparison c = case c of
LT -> ComparisonLessThan
EQ -> ComparisonEqualTo
GT -> ComparisonGreaterThan
metaDescription :: String
metaDescription = "description"
metaType :: String
metaType = "type"
setAnnotation :: String -> Y.Maybe (Term Meta) -> Meta -> Meta
setAnnotation key val (Meta m) = Meta $ M.alter (const val) key m
setDescription :: Y.Maybe String -> Meta -> Meta
setDescription d = setAnnotation metaDescription (string <$> d)
setTermAnnotation :: Context Meta -> String -> Y.Maybe (Term Meta) -> Term Meta -> Term Meta
setTermAnnotation cx key val term = if meta == annotationClassDefault (contextAnnotations cx)
then term'
else TermAnnotated $ Annotated term' meta
where
term' = stripTerm term
meta = setAnnotation key val $ termMetaInternal term
setTermDescription :: Context Meta -> Y.Maybe String -> Term Meta -> Term Meta
setTermDescription cx d = setTermAnnotation cx metaDescription (string <$> d)
setTermType :: Context Meta -> Y.Maybe (Type Meta) -> Term Meta -> Term Meta
setTermType cx d = setTermAnnotation cx metaType (encodeType <$> d)
setType :: Y.Maybe (Type Meta) -> Meta -> Meta
setType mt = setAnnotation metaType (encodeType <$> mt)
setTypeAnnotation :: Context Meta -> String -> Y.Maybe (Term Meta) -> Type Meta -> Type Meta
setTypeAnnotation cx key val typ = if meta == annotationClassDefault (contextAnnotations cx)
then typ'
else TypeAnnotated $ Annotated typ' meta
where
typ' = stripType typ
meta = setAnnotation key val $ typeMetaInternal typ
setTypeDescription :: Context Meta -> Y.Maybe String -> Type Meta -> Type Meta
setTypeDescription cx d = setTypeAnnotation cx metaDescription (string <$> d)
termMetaInternal :: Term Meta -> Meta
termMetaInternal = aggregateAnnotations $ \t -> case t of
TermAnnotated a -> Just a
_ -> Nothing
typeMetaInternal :: Type Meta -> Meta
typeMetaInternal = aggregateAnnotations $ \t -> case t of
TypeAnnotated a -> Just a
_ -> Nothing