packages feed

descript-lang-0.2.0.0: src/Descript/Free/Data.hs

{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE OverloadedStrings #-}

-- | Defines "free" versions of datatypes, which are very general, and
-- can be refined to more constrained, specific datatypes.
module Descript.Free.Data
  ( module Descript.Free.Data.Import
  , module Descript.Free.Data.Atom
  , Property (..)
  , Record (..)
  , Part (..)
  , Value (..)
  , ValueRefinement (..)
  , RecordDecl (..)
  , Reducer (..)
  , Query (..)
  , TopLevel (..)
  , mkTopLevel
  , topLevelToModuleDecl
  , topLevelToImportDecl
  , topLevelToRecordDecl
  , topLevelToReducer
  , topLevelIsPhaseSep
  , topLevelToQuery
  , valueToPropKey
  ) where

import Prelude hiding (head)
import Descript.Free.Data.Import
import Descript.Free.Data.Atom
import Descript.Misc
import Data.Monoid
import Data.List.NonEmpty (NonEmpty (..))

-- | A free property. Can be refined into a property declaration for a
-- record type (as just a key), or an actual property (as a define).
data Property an
  = PropertySingle (Value an)
  | PropertyDef an (Symbol an) (Value an)
  deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable)

-- | A free record. Can be refined into a regular record, or a record type.
data Record an
  = Record
  { recordAnn :: an
  , head :: Symbol an
  , properties :: [Property an]
  } deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable)

-- | A free part. Can be refined into a regular part, input part, or
-- output part.
data Part an
  = PartPrim (Prim an)
  | PartRecord (Record an)
  | PartPropPath (PropPath an)
  deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable)

-- | A free value. Can be refined into a regular value, input value, or
-- output value.
data Value an
  = Value an [Part an]
  deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable)

-- | Converts a value into a top-level declaration.
-- Useful for parsing - parse a value, then a refinement.
data ValueRefinement an
  = ToRecordDecl -- ^ Refine into a record type declaration.
  -- | Refine into a reducer with the given output,
  -- where the value being converted is the input.
  | ToReducer (Value an)
  | ToQuery -- ^ Refine into a query.
  deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable)

-- | Declares a record type to be used in values.
data RecordDecl an
  = RecordDecl an (Value an)
  deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable)

-- | A reducer. It takes a value and converts it into a new value.
-- Programs are interpreted/compiled by taking values and reducing them -
-- the program starts with a value representing a question or source
-- code, and reducers convert this value into the answer or compiled code.
-- This is like a function, or even better, an implicit conversion.
data Reducer an
  = Reducer
  { reducerAnn :: an
  , input :: Value an
  , output :: Value an
  } deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable)

-- | Declares a program's query.
data Query an
  = Query an (Value an)
  deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable)

-- | A top-level declaration in source.
data TopLevel an
  = TopLevelModuleDecl (ModuleDecl an)
  | TopLevelImportDecl (ImportDecl an)
  | TopLevelRecordDecl (RecordDecl an)
  | TopLevelReducer (Reducer an)
  | TopLevelPhaseSep an
  | TopLevelQuery (Query an)
  deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable)

instance Ann TopLevel where
  getAnn (TopLevelModuleDecl x) = getAnn x
  getAnn (TopLevelImportDecl x) = getAnn x
  getAnn (TopLevelRecordDecl x) = getAnn x
  getAnn (TopLevelReducer x) = getAnn x
  getAnn (TopLevelPhaseSep ann) = ann
  getAnn (TopLevelQuery x) = getAnn x

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

instance Ann Reducer where
  getAnn = reducerAnn

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

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

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

instance Ann Record where
  getAnn = recordAnn

instance Ann Property where
  getAnn (PropertySingle x) = getAnn x
  getAnn (PropertyDef ann _ _) = ann

instance Printable TopLevel where
  aprintRec sub (TopLevelModuleDecl decl) = sub decl
  aprintRec sub (TopLevelImportDecl decl) = sub decl
  aprintRec sub (TopLevelRecordDecl decl) = sub decl
  aprintRec sub (TopLevelReducer reducer) = sub reducer
  aprintRec _ (TopLevelPhaseSep _) = "---"
  aprintRec sub (TopLevelQuery query) = sub query

instance Printable RecordDecl where
  aprintRec sub (RecordDecl _ recordType) = sub recordType <> "."

instance Printable Reducer where
  aprintRec sub reducer = sub (input reducer) <> ": " <> sub (output reducer)

instance Printable Query where
  aprintRec sub (Query _ value) = sub value <> "?"

instance Printable Value where
  aprintRec sub (Value _ parts) = pintercal " | " $ map sub parts

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

instance Printable Record where
  aprintRec sub record = sub (head record) <> propsPrinted
    where propsPrinted = "[" <> pintercal ", " propPrinteds <> "]"
          propPrinteds = map sub $ properties record

instance Printable Property where
  aprintRec sub (PropertySingle x) = sub x
  aprintRec sub (PropertyDef _ key val) = sub key <> ": " <> sub val

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

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

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

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

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

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

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

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

-- | Creates a top-level declaration, which starts with the given value
-- and then has the given refinement.
mkTopLevel :: an -> Value an -> ValueRefinement an -> TopLevel an
mkTopLevel ann val ToRecordDecl = TopLevelRecordDecl $ RecordDecl ann val
mkTopLevel ann val (ToReducer out) = TopLevelReducer $ Reducer ann val out
mkTopLevel ann val ToQuery = TopLevelQuery $ Query ann val

topLevelToModuleDecl :: TopLevel an -> Maybe (ModuleDecl an)
topLevelToModuleDecl (TopLevelModuleDecl decl) = Just decl
topLevelToModuleDecl _ = Nothing

topLevelToImportDecl :: TopLevel an -> Maybe (ImportDecl an)
topLevelToImportDecl (TopLevelImportDecl decl) = Just decl
topLevelToImportDecl _ = Nothing

topLevelToRecordDecl :: TopLevel an -> Maybe (RecordDecl an)
topLevelToRecordDecl (TopLevelRecordDecl decl) = Just decl
topLevelToRecordDecl _ = Nothing

topLevelToReducer :: TopLevel an -> Maybe (Reducer an)
topLevelToReducer (TopLevelReducer reducer) = Just reducer
topLevelToReducer _ = Nothing

topLevelIsPhaseSep :: TopLevel an -> Bool
topLevelIsPhaseSep (TopLevelPhaseSep _) = True
topLevelIsPhaseSep _ = False

topLevelToQuery :: TopLevel an -> Maybe (Query an)
topLevelToQuery (TopLevelQuery query') = Just query'
topLevelToQuery _ = Nothing

valueToPropKey :: Value an -> Maybe (Symbol an)
valueToPropKey (Value _ [PartPropPath (PropPath _ (PathElemImp sym :| []))])
  = Just sym
valueToPropKey _ = Nothing