packages feed

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

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

module Descript.BasicInj.Data.Source
  ( Query (..)
  , AModule (..)
  , BModule (..)
  , Program (..)
  , Source (..)
  , Dep
  , DepResult
  , DepResultT
  , DirtyDep
  , DirtyDepT
  , Depd
  , DirtyDepd
  , DepResolver
  , DFile
  , sourceToProgram
  , sourceBModule
  , sourceBModule_
  , sourceAModule
  , sourceAModule_
  , sourceScope
  , moduleScope
  , dsourceAModule
  , dmodule
  , dquery
  ) where

import Descript.BasicInj.Data.Reducer
import qualified Descript.BasicInj.Data.Value.Reg as Reg
import Descript.BasicInj.Data.Type
import Descript.BasicInj.Data.Import
import Descript.Misc
import Data.Semigroup as S
import Data.Monoid as M
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)

type Dep = AModule ()
type DepResult = GenDepResult Dep
type DepResultT u = GenDepResultT u Dep
type DirtyDep an = GenDirtyDep an Dep
type DirtyDepT an u = GenDirtyDepT an u Dep
type Depd a an = GenDepd Dep (a an)
type DirtyDepd a an = GenDepd (DirtyDep an) (a an)
type DepResolver u = GenDepResolver u (AModule ())
type DFile u = GenDFile u (AModule ())

instance (Semigroup an) => Semigroup (AModule an) where
  x <> y
    = AModule
    { amoduleAnn = amoduleAnn x S.<> amoduleAnn y
    , recordCtx = recordCtx x S.<> recordCtx y
    , reduceCtx = reduceCtx x S.<> reduceCtx y
    }

instance (Monoid an) => Monoid (AModule an) where
  mempty
    = AModule
    { amoduleAnn = mempty
    , recordCtx = mempty
    , reduceCtx = mempty
    }

  x `mappend` y
    = AModule
    { amoduleAnn = amoduleAnn x M.<> amoduleAnn y
    , recordCtx = recordCtx x M.<> recordCtx y
    , reduceCtx = reduceCtx x M.<> 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 M.<> "?"

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

-- | 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

-- | The source's bound module without annotations.
sourceBModule_ :: Source an -> BModule ()
sourceBModule_ = remAnns . sourceBModule

-- | Contains the source's anonymous module.
sourceAModule :: Source an -> AModule an
sourceAModule = amodule . sourceBModule

-- | Contains the source's anonymous module, without annotations.
sourceAModule_ :: Source an -> AModule ()
sourceAModule_ = remAnns . sourceAModule

-- | The source's scope - the scope of the source's module, which is
-- also used by the query if the source is a program.
sourceScope :: Source an -> AbsScope
sourceScope = moduleScope . sourceBModule

-- | The scope of the module.
moduleScope :: BModule an -> AbsScope
moduleScope = moduleDeclScope . moduleDecl . importCtx

-- | The full module of a source, including its dependencies.
dsourceAModule :: Depd Source an -> AModule ()
dsourceAModule (Depd extra src) = sourceAModule_ src M.<> extra

-- | The full module of a program, including its dependencies.
dmodule :: Depd Program an -> AModule ()
dmodule (Depd extra prog) = remAnns (amodule $ module' prog) M.<> extra

-- | The query of a program with dependencies.
dquery :: Depd Program an -> Query an
dquery = query . depdVal