packages feed

descript-lang-0.2.0.0: src/Descript/BasicInj/Data/Value/In.hs

{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE OverloadedStrings #-}

module Descript.BasicInj.Data.Value.In
  ( Property
  , Record
  , Part (..)
  , Value
  , OptValue (..)
  , optValToMaybeVal
  , maybeValToOptVal
  , mapOptVal
  , traverseOptVal
  , fullConsumeProp
  ) where

import Descript.BasicInj.Data.Value.Gen
import Descript.BasicInj.Data.Atom
import Descript.Misc
import Data.Semigroup as S
import Data.Monoid as M
import Core.Data.Monoid
import Core.Data.Semigroup

-- | An input property.
type Property an = GenProperty OptValue an

-- | An input record.
type Record an = GenRecord OptValue an

-- | An input part.
data Part an
  = PartPrim (Prim an)
  | PartPrimType (PrimType an)
  | PartRecord (Record an)
  deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable)

-- | An input value.
type Value an = GenValue Part an

-- | Either nothing or a value. Composition of 'Maybe' and 'Value'.
data OptValue an
  = NothingValue
  | JustValue (Value an)
  deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable)

instance (Semigroup an, Monoid an) => Monoid (OptValue an) where
  mempty = JustValue mempty
  NothingValue `mappend` _ = NothingValue
  JustValue _ `mappend` NothingValue = NothingValue
  JustValue x `mappend` JustValue y = JustValue $ x M.<> y

instance (Semigroup an) => Semigroup (OptValue an) where
  NothingValue <> _ = NothingValue
  JustValue _ <> NothingValue = NothingValue
  JustValue x <> JustValue y = JustValue $ x S.<> y

instance GenPropVal OptValue where
  doesPrint NothingValue = False
  doesPrint (JustValue _) = True

instance Monoid1 OptValue

instance Semigroup1 OptValue

instance GenPart Part where
  type PartPropVal Part = OptValue

  partToPrim (PartPrim prim) = Just prim
  partToPrim _ = Nothing

  partToRec (PartRecord record) = Just record
  partToRec _ = Nothing

  primToPart _ = PartPrim
  recToPart _ = PartRecord

  mergeAddPart (PartPrim prim) parts = PartPrim prim : parts
  mergeAddPart (PartPrimType typ) parts = PartPrimType typ : parts
  mergeAddPart (PartRecord record) parts = mergeAddRecord record parts

instance Ann Part where
  getAnn (PartPrim x) = getAnn x
  getAnn (PartPrimType x) = getAnn x
  getAnn (PartRecord x) = getAnn x

instance FwdPrintable OptValue where
  afprintRec _ NothingValue = mempty
  afprintRec sub (JustValue x) = sub x

instance Printable Part where
  aprintRec sub (PartPrim prim) = sub prim
  aprintRec sub (PartPrimType primType) = sub primType
  aprintRec sub (PartRecord record) = aprintRec sub record

instance (Show an) => Summary (OptValue an) where
  summaryRec sub = pprintSummaryRecF sub

instance (Show an) => Summary (Part an) where
  summaryRec sub = pprintSummaryRec sub

-- | Converts the 'OptValue' to an equivalent maybe value.
optValToMaybeVal :: OptValue an -> Maybe (Value an)
optValToMaybeVal NothingValue = Nothing
optValToMaybeVal (JustValue val) = Just val

-- | Converts the maybe value to an equivalent 'OptValue'.
maybeValToOptVal :: Maybe (Value an) -> OptValue an
maybeValToOptVal Nothing = NothingValue
maybeValToOptVal (Just val) = JustValue val

-- | Transform the value.
mapOptVal :: (Value an1 -> Value an2) -> OptValue an1 -> OptValue an2
mapOptVal _ NothingValue = NothingValue
mapOptVal f (JustValue x) = JustValue $ f x

-- | Transform the value with side effects if it exists.
traverseOptVal :: (Applicative w)
               => (Value an1 -> w (Value an2))
               -> OptValue an1
               -> w (OptValue an2)
traverseOptVal _ NothingValue = pure NothingValue
traverseOptVal f (JustValue x) = JustValue <$> f x

-- | A property with the given key and 'NothingValue' (consumes all
-- input) as its value.
fullConsumeProp :: Symbol an -> Property an
fullConsumeProp key = Property ann key NothingValue
  where ann = getAnn key