packages feed

descript-lang-0.2.0.0: src/Descript/BasicInj/Traverse.hs

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}

-- | Abstracts traversals over source ASTs.
module Descript.BasicInj.Traverse
  ( module Descript.BasicInj.Traverse.Termed
  , TTerm
  , Traversal (..)
  , Fold (..)
  , Mapping (..)
  , travTerm
  , foldTerm
  , mapTerm
  ) where

import Descript.BasicInj.Traverse.Termed
import Descript.BasicInj.Traverse.Term (TTerm)
import qualified Descript.BasicInj.Traverse.Term as T
import qualified Descript.BasicInj.Data.Value.Reg as Reg
import qualified Descript.BasicInj.Data.Value.In as In
import qualified Descript.BasicInj.Data.Value.Out as Out
import Descript.BasicInj.Data
import Data.Functor.Identity
import Control.Monad ((<=<))
import Control.Monad.Trans.Writer.Strict
import Prelude hiding (mod)

newtype FoldTrav a = FoldTrav a
newtype MappingTrav a = MappingTrav a

class (Monad (Eff f)) => Traversal f where
  type Eff f :: * -> *
  type TAnn f :: *

  tonTerm :: TTerm t -> f -> t (TAnn f) -> Eff f (t (TAnn f))
  tonTerm _ _ = pure

class (Monoid (Res f)) => Fold f where
  type Res f :: *
  type FAnn f :: *

  fonTerm :: TTerm t -> f -> t (FAnn f) -> Res f
  fonTerm _ _ = mempty

class Mapping f where
  type MAnn f :: *

  monTerm :: TTerm t -> f -> t (MAnn f) -> t (MAnn f)
  monTerm _ _ = id

instance (Fold f) => Traversal (FoldTrav f) where
  type Eff (FoldTrav f) = Writer (Res f)
  type TAnn (FoldTrav f) = FAnn f

  tonTerm term (FoldTrav t) x = x <$ tell (fonTerm term t x)

instance (Mapping f) => Traversal (MappingTrav f) where
  type Eff (MappingTrav f) = Identity
  type TAnn (MappingTrav f) = MAnn f

  tonTerm term (MappingTrav t) = Identity . monTerm term t

travTerm :: (Traversal f) => TTerm t -> f -> t (TAnn f) -> Eff f (t (TAnn f))
travTerm term t = travSubTerm term t <=< tonTerm term t

foldTerm :: (Fold f) => TTerm t -> f -> t (FAnn f) -> Res f
foldTerm term t = execWriter . travTerm term (FoldTrav t)

mapTerm :: (Mapping f) => TTerm t -> f -> t (MAnn f) -> t (MAnn f)
mapTerm term t = runIdentity . travTerm term (MappingTrav t)

travSubTerm :: (Traversal f) => TTerm t -> f -> t (TAnn f) -> Eff f (t (TAnn f))
travSubTerm T.Source t (SourceModule mod)
  = SourceModule <$> travTerm T.BModule t mod
travSubTerm T.Source t (SourceProgram prog)
  = SourceProgram <$> travTerm T.Program t prog
travSubTerm T.Program t (Program ann mod query')
  = Program ann <$> travTerm T.BModule t mod <*> travTerm T.Query t query'
travSubTerm T.BModule t (BModule ann ictx amod)
  = BModule ann <$> travTerm T.ImportCtx t ictx <*> travTerm T.AModule t amod
travSubTerm T.AModule t (AModule ann recordCtx' reduceCtx')
    = AModule ann
  <$> travTerm T.RecordCtx t recordCtx'
  <*> travTerm T.ReduceCtx t reduceCtx'
travSubTerm T.ImportCtx t (ImportCtx ann mdecl idecls)
    = ImportCtx ann
  <$> travTerm T.ModuleDecl t mdecl
  <*> traverse (travTerm T.ImportDecl t) idecls
travSubTerm T.RecordCtx t (RecordCtx ann records)
  = RecordCtx ann <$> traverse (travTerm T.RecordDecl t) records
travSubTerm T.ReduceCtx t (ReduceCtx ann topCtx lowCtxs)
    = ReduceCtx ann
  <$> travTerm T.PhaseCtx t topCtx
  <*> traverse (travTerm T.PhaseCtx t) lowCtxs
travSubTerm T.PhaseCtx t (PhaseCtx ann reducers)
  = PhaseCtx ann <$> traverse (travTerm T.Reducer t) reducers
travSubTerm T.Query t (Query ann val) = Query ann <$> travTerm T.RegValue t val
travSubTerm T.ModuleDecl t (ModuleDecl ann path)
  = ModuleDecl ann <$> travTerm T.ModulePath t path
travSubTerm T.ImportDecl t (ImportDecl ann path isrcs idsts)
    = ImportDecl ann
  <$> travTerm T.ModulePath t path
  <*> traverse (travTerm T.ImportRecord t) isrcs
  <*> traverse (travTerm T.ImportRecord t) idsts
travSubTerm T.RecordDecl t (RecordDecl ann recordType)
  = RecordDecl ann <$> travTerm T.RecordType t recordType
travSubTerm T.Reducer t (Reducer ann input' output')
  = Reducer ann <$> travTerm T.Input t input' <*> travTerm T.Output t output'
travSubTerm T.ModulePath t (ModulePath ann xs)
  = ModulePath ann <$> traverse (travTerm T.ModulePathElem t) xs
travSubTerm T.ImportRecord t (ImportRecord ann from to)
    = ImportRecord ann
  <$> travTerm T.RecordHead t from
  <*> travTerm T.RecordHead t to
travSubTerm T.RecordType t (RecordType ann head' properties')
    = RecordType ann
  <$> travTerm T.RecordHead t head'
  <*> traverse (travTerm T.PropertyKey t) properties'
travSubTerm T.RegValue t (Value ann parts)
    = travTerm T.GenValue t
  =<< Value ann <$> traverse (travTerm T.RegPart t) parts
travSubTerm T.Input t (Value ann parts)
    = travTerm T.GenValue t
  =<< Value ann <$> traverse (travTerm T.InPart t) parts
travSubTerm T.Output t (Value ann parts)
    = travTerm T.GenValue t
  =<< Value ann <$> traverse (travTerm T.OutPart t) parts
travSubTerm T.GenValue _ x = pure x
travSubTerm T.RegPart t (Reg.PartPrim prim)
  = Reg.PartPrim <$> travTerm T.Prim t prim
travSubTerm T.RegPart t (Reg.PartRecord record)
  = Reg.PartRecord <$> travTerm T.RegRecord t record
travSubTerm T.InPart t (In.PartPrim prim)
  = In.PartPrim <$> travTerm T.Prim t prim
travSubTerm T.InPart t (In.PartPrimType primType)
  = In.PartPrimType <$> travTerm T.PrimType t primType
travSubTerm T.InPart t (In.PartRecord record)
  = In.PartRecord <$> travTerm T.InRecord t record
travSubTerm T.OutPart t (Out.PartPrim prim)
  = Out.PartPrim <$> travTerm T.Prim t prim
travSubTerm T.OutPart t (Out.PartRecord record)
  = Out.PartRecord <$> travTerm T.OutRecord t record
travSubTerm T.OutPart t (Out.PartPropPath path)
  = Out.PartPropPath <$> travTerm T.PropPath t path
travSubTerm T.OutPart t (Out.PartInjApp app)
  = Out.PartInjApp <$> travTerm T.InjApp t app
travSubTerm T.Prim _ x = pure x
travSubTerm T.PrimType _ x = pure x
travSubTerm T.RegRecord t (Record ann head' properties')
    = travTerm T.GenRecord t
  =<< Record ann head' <$> traverse (travTerm T.RegProperty t) properties'
travSubTerm T.InRecord t (Record ann head' properties')
    = travTerm T.GenRecord t
  =<< Record ann head' <$> traverse (travTerm T.InProperty t) properties'
travSubTerm T.OutRecord t (Record ann head' properties')
    = travTerm T.GenRecord t
  =<< Record ann head' <$> traverse (travTerm T.OutProperty t) properties'
travSubTerm T.GenRecord t (Record ann head' properties')
  = Record ann <$> travTerm T.RecordHead t head' <*> pure properties'
travSubTerm T.RegProperty t (Property ann key val)
    = Property ann
  <$> travTerm T.PropertyKey t key
  <*> travTerm T.RegValue t val
travSubTerm T.InProperty t (Property ann key val)
    = Property ann
  <$> travTerm T.PropertyKey t key
  <*> In.traverseOptVal (travTerm T.Input t) val
travSubTerm T.OutProperty t (Property ann key val)
    = Property ann
  <$> travTerm T.PropertyKey t key
  <*> travTerm T.Output t val
travSubTerm T.GenProperty _ x = pure x
travSubTerm T.PropPath t (PropPath ann elems)
  = PropPath ann <$> traverse (travTerm T.PathElem t) elems
travSubTerm T.PathElem t (PathElem ann propKey' headKey')
    = PathElem ann
  <$> travTerm T.PropertyKey t propKey'
  <*> travTerm T.RecordHead t headKey'
travSubTerm T.InjApp t (Out.InjApp ann funcId' params')
    = Out.InjApp ann funcId'
  <$> traverse (Out.traverseInjParamVal $ travTerm T.Output t) params'
travSubTerm T.ModulePathElem _ x = pure x
travSubTerm T.RecordHead _ x = pure x
travSubTerm T.PropertyKey _ x = pure x