module Darcs.Patch.Unwind
( Unwind(..)
, Unwound(..)
, mkUnwound
, squashUnwound
) where
import Darcs.Prelude
import Darcs.Patch.Commute
( Commute, commute, selfCommuter
)
import Darcs.Patch.CommuteFn
( commuterIdFL, commuterFLId
)
import Darcs.Patch.Format ( PatchListFormat )
import Darcs.Patch.FromPrim ( PrimOf )
import Darcs.Patch.Invert
( Invert(..), invertFL, invertRL
)
import Darcs.Patch.Show ( ShowPatchBasic(..) )
import Darcs.Patch.Viewing ()
import Darcs.Patch.Witnesses.Eq ( EqCheck(..), Eq2(..) )
import Darcs.Patch.Witnesses.Maybe ( Maybe2(..) )
import Darcs.Patch.Witnesses.Ordered
( FL(..), (:>)(..), (+>+), reverseFL
, RL(..), (+<+), reverseRL
)
import Darcs.Patch.Witnesses.Show ( Show1, Show2, show2 )
import Darcs.Util.Printer ( blueText, vcat )
data Unwound prim wX wY where
Unwound
:: FL prim wA wB
-> FL prim wB wC
-> RL prim wC wD
-> Unwound prim wA wD
deriving instance Show2 prim => Show (Unwound prim wX wY)
instance Show2 prim => Show1 (Unwound prim wX)
instance Show2 prim => Show2 (Unwound prim)
instance (PatchListFormat prim, ShowPatchBasic prim)
=> ShowPatchBasic (Unwound prim) where
showPatch f (Unwound before prims after) =
vcat [
blueText "before:",
showPatch f before,
blueText "prims:",
showPatch f prims,
blueText "after:",
showPatch f after
]
instance Invert prim => Invert (Unwound prim) where
invert (Unwound before prim after)
= Unwound (invertRL after) (invert prim) (invertFL before)
class Unwind p where
fullUnwind :: p wX wY -> Unwound (PrimOf p) wX wY
mkUnwound
:: (Commute prim, Invert prim, Eq2 prim)
=> FL prim wA wB
-> FL prim wB wC
-> FL prim wC wD
-> Unwound prim wA wD
mkUnwound before ps after =
consBefores before .
flip consAfters after $
Unwound NilFL ps NilRL
consBefores
:: (Commute prim, Invert prim, Eq2 prim)
=> FL prim wA wB
-> Unwound prim wB wC
-> Unwound prim wA wC
consBefores NilFL u = u
consBefores (b :>: bs) u = consBefore b (consBefores bs u)
consAfters
:: (Commute prim, Invert prim, Eq2 prim)
=> Unwound prim wA wB
-> FL prim wB wC
-> Unwound prim wA wC
consAfters u NilFL = u
consAfters u (a :>: as) = consAfters (consAfter u a) as
consBefore
:: (Commute prim, Invert prim, Eq2 prim)
=> prim wA wB
-> Unwound prim wB wC
-> Unwound prim wA wC
consBefore b (Unwound NilFL ps after) =
case commuterIdFL selfCommuter (b :> ps) of
Nothing -> Unwound (b :>: NilFL) ps after
Just (ps' :> b') -> Unwound NilFL ps' (propagateAfter (NilRL :> b' :> reverseRL after))
consBefore b1 (Unwound (b2 :>: bs) ps after)
| IsEq <- invert b1 =\/= b2 = Unwound bs ps after
| Just (b2' :> b1') <- commute (b1 :> b2)
= case consBefore b1' (Unwound bs ps after) of
Unwound bs' ps' after' -> Unwound (b2' :>: bs') ps' after'
consBefore b (Unwound bs ps after) = Unwound (b :>: bs) ps after
consAfter
:: (Commute prim, Invert prim, Eq2 prim)
=> Unwound prim wA wB
-> prim wB wC
-> Unwound prim wA wC
consAfter (Unwound before ps NilRL) a =
case commuterFLId selfCommuter (ps :> a) of
Nothing -> Unwound before ps (NilRL :<: a)
Just (a' :> ps') -> Unwound (propagateBefore (reverseFL before :> a' :> NilFL)) ps' NilRL
consAfter (Unwound before ps (as :<: a1)) a2
| IsEq <- invert a1 =\/= a2 = Unwound before ps as
| Just (a2' :> a1') <- commute (a1 :> a2)
= case consAfter (Unwound before ps as) a2' of
Unwound before' ps' as' -> Unwound before' ps' (as' :<: a1')
consAfter (Unwound before ps as) a = Unwound before ps (as :<: a)
propagateBefore
:: (Commute prim, Invert prim, Eq2 prim)
=> (RL prim :> prim :> FL prim) wA wB
-> FL prim wA wB
propagateBefore (NilRL :> p :> acc) = p :>: acc
propagateBefore (qs :<: q :> p :> acc)
| IsEq <- invert q =\/= p = reverseRL qs +>+ acc
| Just (p' :> q') <- commute (q :> p)
= propagateBefore (qs :> p' :> q' :>: acc)
| otherwise = reverseRL qs +>+ q :>: p :>: acc
propagateAfter
:: (Commute prim, Invert prim, Eq2 prim)
=> (RL prim :> prim :> FL prim) wA wB
-> RL prim wA wB
propagateAfter (acc :> p :> NilFL) = acc :<: p
propagateAfter (acc :> p :> q :>: qs)
| IsEq <- invert p =\/= q = acc +<+ reverseFL qs
| Just (q' :> p') <- commute (p :> q)
= propagateAfter (acc :<: q' :> p' :> qs)
| otherwise = acc :<: p :<: q +<+ reverseFL qs
squashUnwound
:: (Show2 prim, Commute prim, Eq2 prim, Invert prim)
=> FL (Unwound prim) wX wY
-> Unwound prim wX wY
squashUnwound NilFL = Unwound NilFL NilFL NilRL
squashUnwound (u :>: us) =
squashPair (moveCommutingToBefore u :> moveCommutingToAfter (squashUnwound us))
moveCommutingToBefore
:: (Commute prim, Invert prim, Eq2 prim)
=> Unwound prim wA wB
-> Unwound prim wA wB
moveCommutingToBefore (Unwound before ps after) =
flip consAfters (reverseRL after) $
Unwound before ps NilRL
moveCommutingToAfter
:: (Commute prim, Invert prim, Eq2 prim)
=> Unwound prim wA wB
-> Unwound prim wA wB
moveCommutingToAfter (Unwound before ps after) =
consBefores before $
Unwound NilFL ps after
squashPair
:: (Show2 prim, Commute prim, Eq2 prim, Invert prim)
=> (Unwound prim :> Unwound prim) wX wY
-> Unwound prim wX wY
squashPair (Unwound before ps1 NilRL :> Unwound NilFL ps2 after) =
Unwound before (ps1 +>+ ps2) after
squashPair (Unwound before1 ps1 (after1 :<: a) :> Unwound before2 ps2 after2) =
case pushPastForward (a :> before2) of
before2' :> Nothing2 ->
squashPair (Unwound before1 ps1 after1 :> Unwound before2' ps2 after2)
before2' :> Just2 a' ->
case commuterIdFL selfCommuter (a' :> ps2) of
Nothing -> error $ "stuck patch: squashPair 1:\n" ++ show2 a' ++ "\n" ++ show2 ps2
Just (ps2' :> a'') ->
squashPair (Unwound before1 ps1 after1 :> Unwound before2' ps2' (NilRL :<: a'' +<+ after2))
squashPair (Unwound before1 ps1 NilRL :> Unwound (b :>: before2) ps2 after2) =
case commuterFLId selfCommuter (ps1 :> b) of
Nothing -> error "stuck patch: squashPair 2"
Just (b' :> ps1') -> squashPair (Unwound (before1 +>+ b' :>: NilFL) ps1' NilRL :> Unwound before2 ps2 after2)
pushPastForward
:: (Show2 prim, Commute prim, Eq2 prim, Invert prim)
=> (prim :> FL prim) wX wY
-> (FL prim :> Maybe2 prim) wX wY
pushPastForward (p :> NilFL) = NilFL :> Just2 p
pushPastForward (p :> (q :>: qs))
| IsEq <- invert p =\/= q = qs :> Nothing2
| Just (q' :> p') <- commute (p :> q)
= case pushPastForward (p' :> qs) of
qs' :> p'' -> (q' :>: qs') :> p''
| otherwise = error $ "stuck patch: pushPastForward:\n" ++ show2 p ++ "\n" ++ show2 q