packages feed

descript-lang-0.2.0.0: src/Descript/Sugar/Data/Value/Out.hs

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

module Descript.Sugar.Data.Value.Out
  ( Property
  , Record
  , InjParam (..)
  , InjApp (..)
  , Part (..)
  , Value
  , immPathVal
  , mapInjAppParams
  , mapInjParamVal
  , traverseInjParamVal
  , idxPropKeys
  ) where

import Descript.Sugar.Data.Value.Gen
import Descript.Sugar.Data.Atom
import Descript.Misc
import Data.Monoid

-- | An output property.
type Property an = GenProperty (GenValue Part) an

-- | An output record.
type Record an = GenRecord (GenValue Part) an

-- | A parameter of an injected function.
data InjParam an
  = InjParam
  { injParamAnn :: an
  , injParamVal :: Value an
  } deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable)

-- | An application of an injected function.
data InjApp an
  = InjApp
  { injAppAnn :: an
  , funcId :: InjSymbol an
  , params :: [InjParam an]
  } deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable)

-- | An output part.
data Part an
  = PartPrim (Prim an)
  | PartRecord (Record an)
  | PartPropPath (PropPath an)
  | PartInjApp (InjApp an)
  deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable)

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

instance GenPart Part where
  type PartPropVal Part = GenValue Part

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

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

  primToPart _ = PartPrim
  recToPart _ = PartRecord

instance Ann Part where
  getAnn (PartPrim x) = getAnn x
  getAnn (PartRecord x) = getAnn x
  getAnn (PartPropPath x) = getAnn x
  getAnn (PartInjApp x) = getAnn x

instance Ann InjApp where
  getAnn = injAppAnn

instance Ann InjParam where
  getAnn (InjParam ann _) = ann

instance Printable Part where
  aprintRec sub (PartPrim prim) = sub prim
  aprintRec sub (PartRecord record) = sub record
  aprintRec sub (PartPropPath path) = sub path
  aprintRec sub (PartInjApp app) = sub app

instance Printable InjApp where
  aprintRec sub app = sub (funcId app) <> paramsPrinted
    where paramsPrinted = "[" <> pintercal ", " paramPrinteds <> "]"
          paramPrinteds = map sub $ params app

instance Printable InjParam where
  aprintRec sub (InjParam _ val) = sub val

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

instance (Show an) => Summary (InjApp an) where
  summaryRec = pprintSummaryRec

instance (Show an) => Summary (InjParam an) where
  summaryRec = pprintSummaryRec

-- | Refers to the immediate property corresponding to the path element.
immPathVal :: PathElem () -> Value ()
immPathVal = singletonValue . PartPropPath . immPath

mapInjAppParams :: (InjParam an -> InjParam an) -> InjApp an -> InjApp an
mapInjAppParams f (InjApp ann funcId' params')
  = InjApp ann funcId' $ map f params'

-- | Transforms the value in the injected parameter.
mapInjParamVal :: (Value an -> Value an) -> InjParam an -> InjParam an
mapInjParamVal f (InjParam ann x) = InjParam ann $ f x

-- | Transforms the value in the injected parameter with side effects.
traverseInjParamVal :: (Functor w)
                    => (Value an -> w (Value an))
                    -> InjParam an
                    -> w (InjParam an)
traverseInjParamVal f (InjParam ann x) = InjParam ann <$> f x

-- | Each of these keys in an injected function application corresponds
-- to a parameter at its position.
idxPropKeys :: [Symbol ()]
idxPropKeys = map (Symbol () . pure) ['a'..'z']