{-# LANGUAGE TemplateHaskell, FlexibleContexts, UndecidableInstances #-}
module AST.Diff
( diff
, Diff(..), _CommonBody, _CommonSubTree, _Different
, CommonBody(..), anns, val
, foldDiffs
, diffP
, DiffP(..), _CommonBodyP, _CommonSubTreeP, _DifferentP
, foldDiffsP
) where
import AST
import AST.Class.ZipMatch (ZipMatch(..))
import AST.Recurse
import AST.TH.Internal.Instances (makeCommonInstances)
import Control.Lens (makeLenses, makePrisms)
import Control.Lens.Operators
import Data.Constraint (withDict)
import Data.Proxy (Proxy(..))
import GHC.Generics (Generic)
import Prelude.Compat
data Diff a b e
= CommonSubTree (Ann (a, b) e)
| CommonBody (CommonBody a b e)
| Different (Product (Ann a) (Ann b) e)
deriving Generic
data CommonBody a b e = MkCommonBody
{ _anns :: (a, b)
, _val :: e # Diff a b
} deriving Generic
makePrisms ''Diff
makeLenses ''CommonBody
diff ::
forall t a b.
(Recursively ZipMatch t, RTraversable t) =>
Tree (Ann a) t -> Tree (Ann b) t -> Tree (Diff a b) t
diff x@(Ann xA xB) y@(Ann yA yB) =
withDict (recursively (Proxy @(ZipMatch t))) $
withDict (recurse (Proxy @(RTraversable t))) $
case zipMatch xB yB of
Nothing -> Different (Pair x y)
Just match ->
case traverseK (const (^? _CommonSubTree)) sub of
Nothing -> MkCommonBody (xA, yA) sub & CommonBody
Just r -> Ann (xA, yA) r & CommonSubTree
where
sub =
mapK
( Proxy @(Recursively ZipMatch) #*# Proxy @RTraversable #>
\(Pair xC yC) -> diff xC yC
) match
foldDiffs ::
forall r k a b.
(Monoid r, Recursively KFoldable k) =>
(forall n. KRecWitness k n -> Tree (Ann a) n -> Tree (Ann b) n -> r) ->
Tree (Diff a b) k ->
r
foldDiffs _ CommonSubTree{} = mempty
foldDiffs f (Different (Pair x y)) = f KRecSelf x y
foldDiffs f (CommonBody (MkCommonBody _ x)) =
withDict (recursively (Proxy @(KFoldable k))) $
foldMapK
( Proxy @(Recursively KFoldable) #*#
\w -> foldDiffs (f . KRecSub w)
) x
data DiffP k
= CommonSubTreeP (KPlain (GetKnot k))
| CommonBodyP (k # DiffP)
| DifferentP (KPlain (GetKnot k)) (KPlain (GetKnot k))
deriving Generic
makePrisms ''DiffP
diffP ::
forall k.
(Recursively ZipMatch k, Recursively KHasPlain k, RTraversable k) =>
KPlain k -> KPlain k -> Tree DiffP k
diffP x y =
withDict (recursively (Proxy @(KHasPlain k))) $
diffPH (x ^. kPlain) (y ^. kPlain)
diffPH ::
forall k.
(Recursively ZipMatch k, Recursively KHasPlain k, RTraversable k) =>
Tree Pure k -> Tree Pure k -> Tree DiffP k
diffPH x y =
withDict (recursively (Proxy @(ZipMatch k))) $
withDict (recursively (Proxy @(KHasPlain k))) $
withDict (recurse (Proxy @(RTraversable k))) $
case zipMatch (x ^. _Pure) (y ^. _Pure) of
Nothing -> DifferentP (kPlain # x) (kPlain # y)
Just match ->
case traverseK_ (const ((() <$) . (^? _CommonSubTreeP))) sub of
Nothing -> CommonBodyP sub
Just () -> _CommonSubTreeP . kPlain # x
where
sub =
mapK
( Proxy @(Recursively ZipMatch) #*#
Proxy @(Recursively KHasPlain) #*#
Proxy @RTraversable #>
\(Pair xC yC) -> diffPH xC yC
) match
makeCommonInstances [''Diff, ''CommonBody, ''DiffP]
foldDiffsP ::
forall r k.
(Monoid r, Recursively KFoldable k, Recursively KHasPlain k) =>
(forall n. KHasPlain n => KRecWitness k n -> KPlain n -> KPlain n -> r) ->
Tree DiffP k ->
r
foldDiffsP f =
withDict (recursively (Proxy @(KHasPlain k))) $
\case
CommonSubTreeP{} -> mempty
DifferentP x y -> f KRecSelf x y
CommonBodyP x ->
withDict (recursively (Proxy @(KFoldable k))) $
foldMapK
( Proxy @(Recursively KFoldable) #*# Proxy @(Recursively KHasPlain) #*#
\w -> foldDiffsP (f . KRecSub w)
) x