descript-lang-0.2.0.0: src/Descript/Sugar/Data/Source.hs
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE OverloadedStrings #-}
module Descript.Sugar.Data.Source
( Query (..)
, AModule (..)
, BModule (..)
, Program (..)
, Source (..)
, mkSource
, sourceToProgram
, sourceBModule
, sourceImportCtx
) where
import Descript.Sugar.Data.Reducer
import qualified Descript.Sugar.Data.Value.Reg as Reg
import Descript.Sugar.Data.Type
import Descript.Sugar.Data.Import
import Descript.Misc
import Data.Monoid
import Data.List
import Prelude hiding (mod)
-- | The "main" value in a program. A program is interpreted by reducing
-- its query - this reduced is the output of a program.
data Query an
= Query
{ queryAnn :: an
, queryVal :: Reg.Value an
} deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable)
-- | Anonymous module - no scope. Defines how a program is interpreted.
-- When a module imports another, the other's 'AModule' is appended.
data AModule an
= AModule
{ amoduleAnn :: an
, recordCtx :: RecordCtx an
, reduceCtx :: ReduceCtx an
} deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable)
-- | A module with a scope and imports, which allows it to import other
-- modules.
data BModule an
= BModule
{ bmoduleAnn :: an
, importCtx :: ImportCtx an
, amodule :: AModule an
} deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable)
-- | Parsed from a source file and interpreted. To interpret, the query
-- is reduced using the module.
data Program an
= Program
{ programAnn :: an
, module' :: BModule an
, query :: Query an
} deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable)
-- | Every source file gets parsed into one of these.
data Source an
= SourceModule (BModule an)
| SourceProgram (Program an)
deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable)
instance (Monoid an) => Monoid (AModule an) where
mempty
= AModule
{ amoduleAnn = mempty
, recordCtx = mempty
, reduceCtx = mempty
}
x `mappend` y
= AModule
{ amoduleAnn = amoduleAnn x <> amoduleAnn y
, recordCtx = recordCtx x <> recordCtx y
, reduceCtx = reduceCtx x <> reduceCtx y
}
instance Ann Source where
getAnn (SourceModule mod) = getAnn mod
getAnn (SourceProgram prog) = getAnn prog
instance Ann Program where
getAnn = programAnn
instance Ann BModule where
getAnn = bmoduleAnn
instance Ann AModule where
getAnn = amoduleAnn
instance Ann Query where
getAnn = queryAnn
instance Printable Source where
aprintRec sub (SourceModule mod) = sub mod
aprintRec sub (SourceProgram prog) = sub prog
instance Printable Program where
aprintRec sub prog = pintercal "\n\n" $ filter (/= mempty)
[ sub $ module' prog
, sub $ query prog
]
instance Printable BModule where
aprintRec sub mod = pintercal "\n\n" $ filter (/= mempty)
[ sub $ importCtx mod
, sub $ amodule mod
]
instance Printable AModule where
aprintRec sub mod = pintercal "\n\n" $ filter (/= mempty)
[ sub $ recordCtx mod
, sub $ reduceCtx mod
]
instance Printable Query where
aprintRec sub (Query _ val) = sub val <> "?"
instance (Show an) => Summary (Source an) where
summaryRec = pprintSummaryRec
instance (Show an) => Summary (Program an) where
summaryRec = pprintSummaryRec
instance (Show an) => Summary (BModule an) where
summaryRec = pprintSummaryRec
instance (Show an) => Summary (AModule an) where
summaryRec = pprintSummaryRec
instance (Show an) => Summary (Query an) where
summaryRec = pprintSummaryRec
-- | Creates a source program if the query exists, or a source module if it doesn't.
mkSource :: an -> BModule an -> Maybe (Query an) -> Source an
mkSource _ mod Nothing = SourceModule mod
mkSource ann mod (Just qry) = SourceProgram $ Program ann mod qry
-- | If the source is a program, returns it.
-- If it's a module, returns 'Nothing'.
sourceToProgram :: Source an -> Maybe (Program an)
sourceToProgram (SourceModule _) = Nothing
sourceToProgram (SourceProgram prog) = Just prog
-- | The source's bound module.
sourceBModule :: Source an -> BModule an
sourceBModule (SourceModule mod) = mod
sourceBModule (SourceProgram prog) = module' prog
-- | Contains the source's module declaration and imports.
sourceImportCtx :: Source an -> ImportCtx an
sourceImportCtx = importCtx . sourceBModule