packages feed

cryptol-3.6.0: src/Cryptol/IR/TraverseExprs.hs

{-# Language ScopedTypeVariables #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RecordWildCards #-}

module Cryptol.IR.TraverseExprs 
  ( TraverseExprs(..)
  , traverseSubExprs
  , traverseImmSubExprs
  , mapSubExprs
  , mapExprs
  , foldMapSubExprs
  , foldMapExprs
  ) where

import Control.Monad.Writer

import Data.Functor.Identity
import Data.Set(Set)
import qualified Data.Set as Set

import Cryptol.TypeCheck.AST
import Cryptol.Parser.Position(Located(..))

class TraverseExprs t where
  -- | Traverse over constituent expressions, without recursing into sub-expressions.
  traverseExprs :: Applicative f => (Expr -> f Expr) -> t -> f t

-- | Traverse over constituent expressions, first recursing into sub-expressions.
traverseSubExprs ::
  forall t m. (TraverseExprs t, Monad m) => (Expr -> m Expr) -> (t -> m t)
traverseSubExprs f = traverseExprs go
  where
    go :: Expr -> m Expr
    go e = traverseImmSubExprs go e >>= f

mapSubExprs :: TraverseExprs t => (Expr -> Expr) -> t -> t
mapSubExprs f x = runIdentity (traverseSubExprs (Identity . f) x)

mapExprs :: TraverseExprs t => (Expr -> Expr) -> t -> t
mapExprs f x = runIdentity (traverseExprs (Identity . f) x)

foldMapSubExprs :: (TraverseExprs t, Monoid m) => (Expr -> m) -> t -> m
foldMapSubExprs f t = execWriter $ traverseSubExprs (\e -> tell (f e) >> return e) t

foldMapExprs :: (TraverseExprs t, Monoid m) => (Expr -> m) -> t -> m
foldMapExprs f t = execWriter $ traverseExprs (\e -> tell (f e) >> return e) t

-- | Traverse over immediate sub-expressions.
traverseImmSubExprs :: forall f. Applicative f => (Expr -> f Expr) -> Expr -> f Expr
traverseImmSubExprs f se = case se of
  EList es t -> EList <$> go es <*> pure t
  ETuple es -> ETuple <$> go es
  ERec mp -> ERec <$> traverse go mp
  ESel e sel -> ESel <$> go e <*> pure sel
  ESet t e1 sel e2 -> ESet <$> pure t <*> go e1 <*> pure sel <*> go e2
  EIf eP eT eF -> EIf <$> go eP <*> go eT <*> go eF
  ECase e alts malt -> ECase
    <$> go e <*> traverse go alts <*> go malt
  EComp t1 t2 e matches -> EComp
    <$> pure t1 <*> pure t2 <*> go e <*> go matches
  EVar n -> EVar <$> pure n
  ETAbs tps e -> ETAbs <$> pure tps <*> go e
  ETApp e t -> ETApp <$> go e <*> pure t
  EApp e1 e2 -> EApp <$> go e1 <*> go e2
  EAbs n t e -> EAbs <$> pure n <*> pure t <*> go e
  ELocated r e -> ELocated <$> pure r <*> go e
  EProofAbs p e -> EProofAbs <$> pure p <*> go e
  EProofApp e -> EProofApp <$> go e
  EWhere e decls -> EWhere <$> go e <*> traverse go decls
  EPropGuards gs t  -> EPropGuards <$> traverse doG gs <*> pure t
    where doG (xs, e) = (,) <$> pure xs <*> go e
  where
    go :: forall t. TraverseExprs t => t -> f t
    go = traverseExprs f

instance TraverseExprs a => TraverseExprs [a] where
  traverseExprs f = traverse (traverseExprs f)

instance TraverseExprs a => TraverseExprs (Maybe a) where
  traverseExprs f = traverse (traverseExprs f)

instance (Ord a, TraverseExprs a) => TraverseExprs (Set a) where
  traverseExprs f = fmap Set.fromList . traverseExprs f . Set.toList

instance TraverseExprs a => TraverseExprs (Located a) where
  traverseExprs f (Located r a) = Located r <$> traverseExprs f a

instance TraverseExprs Expr where
  traverseExprs f = f

instance TraverseExprs CaseAlt where
  traverseExprs f (CaseAlt xs e) =
    CaseAlt <$> pure xs <*> traverseExprs f e

instance TraverseExprs Match where
  traverseExprs f = \case
    From x t1 t2 e -> From <$> pure x <*> pure t1 <*> pure t2 <*> traverseExprs f e
    Let d -> Let <$> traverseExprs f d

instance TraverseExprs DeclDef where
  traverseExprs f = \case
    DPrim -> pure DPrim
    DForeign ffi me -> DForeign <$> pure ffi <*> traverseExprs f me
    DExpr e -> DExpr <$> traverseExprs f e

instance TraverseExprs DeclGroup where
  traverseExprs f = \case
    Recursive ds -> Recursive <$> traverseExprs f ds
    NonRecursive d -> NonRecursive <$> traverseExprs f d

instance TraverseExprs Decl where
  traverseExprs f Decl{..} = Decl
    <$> pure dName <*> pure dSignature <*> traverseExprs f dDefinition <*> pure dPragmas 
    <*> pure dInfix <*> pure dFixity <*> pure dDoc