rest-rewrite-0.4.1: src/Language/REST/RuntimeTerm.hs
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
module Language.REST.RuntimeTerm
( RuntimeTerm(..)
, ToRuntimeTerm(..)
, subTerms
, contains
)
where
import Data.Hashable
import GHC.Generics (Generic)
import Text.Printf
import qualified Data.List as L
import Language.REST.Op
-- | Ground terms
data RuntimeTerm = App Op [RuntimeTerm] deriving (Eq, Ord, Generic, Hashable)
instance Show RuntimeTerm where
show (App op []) = show op
show (App op ts) = printf "%s(%s)" (show op) $ L.intercalate ", " (map show ts)
-- | Transformable to a ground term
class ToRuntimeTerm a where
toRuntimeTerm :: a -> RuntimeTerm
instance ToRuntimeTerm Op where
toRuntimeTerm op = App op []
instance ToRuntimeTerm RuntimeTerm where
toRuntimeTerm = id
-- | @subTerms t@ returns a list of pairs @(s, f)@, where @s@ is a subterm of @t@,
-- and @f@ is a function that takes a replacement @s'@ for @s@, and generates a new
-- term where @s@ is replaced with @s'@ in @t@. Also includes the pair (t, id),
-- representing the term itself.
-- TODO: Consider more efficient implementations
subTerms :: RuntimeTerm -> [(RuntimeTerm, RuntimeTerm -> RuntimeTerm)]
subTerms t@(App f ts) = (t, id) : concatMap st [0..length ts - 1]
where
st :: Int -> [(RuntimeTerm, RuntimeTerm -> RuntimeTerm)]
st i =
let
ti = ts !! i
go t' =
App f $ take i ts ++ [t'] ++ drop (i + 1) ts
go2 (srt, toFull) = (srt, go . toFull)
in
map go2 (subTerms ti)
-- | @t `contains` u@ iff @t == u@ or @u@ is a subterm of @t@
contains :: RuntimeTerm -> RuntimeTerm -> Bool
contains t1 t2 | t1 == t2 = True
contains (App _ ts) t = any (contains t) ts