From 9557070bfb777bac79ed4a1def5c5c10e4fb5519 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 17 Oct 2019 22:15:58 -0400 Subject: [PATCH 001/118] Rename Replace to Compare. --- src/Data/Diff.hs | 4 ++-- src/Data/Patch.hs | 18 +++++++++--------- src/Rendering/Graph.hs | 2 +- src/Rendering/JSON.hs | 4 ++-- src/Serializing/SExpression.hs | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Data/Diff.hs b/src/Data/Diff.hs index 94c0d3999..31db4bf41 100644 --- a/src/Data/Diff.hs +++ b/src/Data/Diff.hs @@ -30,7 +30,7 @@ newtype Diff syntax ann1 ann2 = Diff { unDiff :: DiffF syntax ann1 ann2 (Diff sy -- | A single entry within a recursive 'Diff'. data DiffF syntax ann1 ann2 recur - -- | A changed node, represented as 'Insert'ed, 'Delete'd, or 'Replace'd 'TermF's, consisting of syntax labelled with an annotation. + -- | A changed node, represented as 'Insert'ed, 'Delete'd, or 'Compare'd 'TermF's, consisting of syntax labelled with an annotation. = Patch (Patch (TermF syntax ann1 recur) (TermF syntax ann2 recur)) -- | An unchanged node, consisting of syntax labelled with both the original annotations. @@ -42,7 +42,7 @@ replacing (Term (In a1 r1)) (Term (In a2 r2)) = replaceF (In a1 (deleting <$> r1 -- | Constructs a 'Diff' replacing one 'TermF' populated by further 'Diff's with another. replaceF :: TermF syntax ann1 (Diff syntax ann1 ann2) -> TermF syntax ann2 (Diff syntax ann1 ann2) -> Diff syntax ann1 ann2 -replaceF t1 t2 = Diff (Patch (Replace t1 t2)) +replaceF t1 t2 = Diff (Patch (Compare t1 t2)) -- | Constructs a 'Diff' inserting a 'Term' recursively. inserting :: Functor syntax => Term syntax ann2 -> Diff syntax ann1 ann2 diff --git a/src/Data/Patch.hs b/src/Data/Patch.hs index 952de6abf..eca782d78 100644 --- a/src/Data/Patch.hs +++ b/src/Data/Patch.hs @@ -15,7 +15,7 @@ import Data.JSON.Fields data Patch a b = Delete a | Insert b - | Replace a b + | Compare a b deriving (Eq, Foldable, Functor, Generic, Generic1, Ord, Show, Traversable) @@ -31,7 +31,7 @@ before = patch Just (const Nothing) (\ a _ -> Just a) patch :: (before -> result) -> (after -> result) -> (before -> after -> result) -> Patch before after -> result patch ifDelete _ _ (Delete a) = ifDelete a patch _ ifInsert _ (Insert b) = ifInsert b -patch _ _ ifReplace (Replace a b) = ifReplace a b +patch _ _ ifReplace (Compare a b) = ifReplace a b -- Instances @@ -39,38 +39,38 @@ patch _ _ ifReplace (Replace a b) = ifReplace a b instance Bifunctor Patch where bimap f _ (Delete a) = Delete (f a) bimap _ g (Insert b) = Insert (g b) - bimap f g (Replace a b) = Replace (f a) (g b) + bimap f g (Compare a b) = Compare (f a) (g b) instance Bifoldable Patch where bifoldMap f _ (Delete a) = f a bifoldMap _ g (Insert b) = g b - bifoldMap f g (Replace a b) = f a `mappend` g b + bifoldMap f g (Compare a b) = f a `mappend` g b instance Bitraversable Patch where bitraverse f _ (Delete a) = Delete <$> f a bitraverse _ g (Insert b) = Insert <$> g b - bitraverse f g (Replace a b) = Replace <$> f a <*> g b + bitraverse f g (Compare a b) = Compare <$> f a <*> g b instance Bicrosswalk Patch where bicrosswalk f _ (Delete a) = Delete <$> f a bicrosswalk _ g (Insert b) = Insert <$> g b - bicrosswalk f g (Replace a b) = alignWith (these Delete Insert Replace) (f a) (g b) + bicrosswalk f g (Compare a b) = alignWith (these Delete Insert Compare) (f a) (g b) instance Eq2 Patch where liftEq2 eqBefore eqAfter p1 p2 = case (p1, p2) of (Delete a1, Delete a2) -> eqBefore a1 a2 (Insert b1, Insert b2) -> eqAfter b1 b2 - (Replace a1 b1, Replace a2 b2) -> eqBefore a1 a2 && eqAfter b1 b2 + (Compare a1 b1, Compare a2 b2) -> eqBefore a1 a2 && eqAfter b1 b2 _ -> False instance Show2 Patch where liftShowsPrec2 spBefore _ spAfter _ d p = case p of Delete a -> showsUnaryWith spBefore "Delete" d a Insert b -> showsUnaryWith spAfter "Insert" d b - Replace a b -> showsBinaryWith spBefore spAfter "Replace" d a b + Compare a b -> showsBinaryWith spBefore spAfter "Compare" d a b instance (ToJSONFields a, ToJSONFields b) => ToJSONFields (Patch a b) where toJSONFields (Insert a) = [ "insert" .= object (toJSONFields a) ] toJSONFields (Delete a) = [ "delete" .= object (toJSONFields a) ] - toJSONFields (Replace a b) = [ "replace" .= [object (toJSONFields a), object (toJSONFields b)] ] + toJSONFields (Compare a b) = [ "replace" .= [object (toJSONFields a), object (toJSONFields b)] ] diff --git a/src/Rendering/Graph.hs b/src/Rendering/Graph.hs index 4c9215318..fece93f88 100644 --- a/src/Rendering/Graph.hs +++ b/src/Rendering/Graph.hs @@ -99,7 +99,7 @@ instance (ConstructorName syntax, Foldable syntax) => Patch (Insert t2@(In a2 syntax)) -> diffAlgebra t2 . DiffTreeVertex'Inserted $ defMessage & P.term .~ T.pack (constructorName syntax) & P.maybe'span .~ ann a2 - Patch (Replace t1@(In a1 syntax1) t2@(In a2 syntax2)) -> do + Patch (Compare t1@(In a1 syntax1) t2@(In a2 syntax2)) -> do i <- fresh parent <- ask let (beforeName, beforeSpan) = (T.pack (constructorName syntax1), ann a1) diff --git a/src/Rendering/JSON.hs b/src/Rendering/JSON.hs index 39dd4f0e7..119e73ec3 100644 --- a/src/Rendering/JSON.hs +++ b/src/Rendering/JSON.hs @@ -56,8 +56,8 @@ newtype JSONStat = JSONStat { jsonStatBlobs :: BlobPair } deriving (Eq, Show) instance ToJSON JSONStat where - toJSON JSONStat{..} = object ("path" .= pathKeyForBlobPair jsonStatBlobs : toJSONFields (these Delete Insert Replace (getBlobPair jsonStatBlobs))) - toEncoding JSONStat{..} = pairs (fold ("path" .= pathKeyForBlobPair jsonStatBlobs : toJSONFields (these Delete Insert Replace (getBlobPair jsonStatBlobs)))) + toJSON JSONStat{..} = object ("path" .= pathKeyForBlobPair jsonStatBlobs : toJSONFields (these Delete Insert Compare (getBlobPair jsonStatBlobs))) + toEncoding JSONStat{..} = pairs (fold ("path" .= pathKeyForBlobPair jsonStatBlobs : toJSONFields (these Delete Insert Compare (getBlobPair jsonStatBlobs)))) -- | Render a term to a value representing its JSON. renderJSONTerm :: ToJSON a => Blob -> a -> JSON "trees" SomeJSON diff --git a/src/Serializing/SExpression.hs b/src/Serializing/SExpression.hs index 96d94f0b1..c994a944f 100644 --- a/src/Serializing/SExpression.hs +++ b/src/Serializing/SExpression.hs @@ -43,6 +43,6 @@ instance (ConstructorName syntax, Foldable syntax, Show ann1, Show ann2) => ToSE toSExpression options diff n = case diff of Patch (Delete term) -> nl n <> pad (n - 1) <> "{-" <> namedBranch options term n <> "-}" Patch (Insert term) -> nl n <> pad (n - 1) <> "{+" <> namedBranch options term n <> "+}" - Patch (Replace term1 term2) -> nl n <> pad (n - 1) <> "{ " <> namedBranch options term1 n + Patch (Compare term1 term2) -> nl n <> pad (n - 1) <> "{ " <> namedBranch options term1 n <> nl (n + 1) <> pad (n - 1) <> "->" <> namedBranch options term2 n <> " }" Merge term -> nl n <> pad n <> namedBranch options term n From dd7f65828a77802c4edc6d7cab717404bc13eea5 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 17 Oct 2019 22:17:01 -0400 Subject: [PATCH 002/118] Rename replaceF to compareF. --- src/Data/Diff.hs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Data/Diff.hs b/src/Data/Diff.hs index 31db4bf41..5b20486f3 100644 --- a/src/Data/Diff.hs +++ b/src/Data/Diff.hs @@ -3,7 +3,7 @@ module Data.Diff ( Diff(..) , DiffF(..) , replacing -, replaceF +, compareF , inserting , insertF , deleting @@ -38,11 +38,11 @@ data DiffF syntax ann1 ann2 recur -- | Constructs a 'Diff' replacing one 'Term' with another recursively. replacing :: Functor syntax => Term syntax ann1 -> Term syntax ann2 -> Diff syntax ann1 ann2 -replacing (Term (In a1 r1)) (Term (In a2 r2)) = replaceF (In a1 (deleting <$> r1)) (In a2 (inserting <$> r2)) +replacing (Term (In a1 r1)) (Term (In a2 r2)) = compareF (In a1 (deleting <$> r1)) (In a2 (inserting <$> r2)) -- | Constructs a 'Diff' replacing one 'TermF' populated by further 'Diff's with another. -replaceF :: TermF syntax ann1 (Diff syntax ann1 ann2) -> TermF syntax ann2 (Diff syntax ann1 ann2) -> Diff syntax ann1 ann2 -replaceF t1 t2 = Diff (Patch (Compare t1 t2)) +compareF :: TermF syntax ann1 (Diff syntax ann1 ann2) -> TermF syntax ann2 (Diff syntax ann1 ann2) -> Diff syntax ann1 ann2 +compareF t1 t2 = Diff (Patch (Compare t1 t2)) -- | Constructs a 'Diff' inserting a 'Term' recursively. inserting :: Functor syntax => Term syntax ann2 -> Diff syntax ann1 ann2 From 64c4fed882ad7d2492b14e34cf04d9f6d78717c1 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 17 Oct 2019 22:18:48 -0400 Subject: [PATCH 003/118] Rename replacing to comparing. --- src/Data/Diff.hs | 10 +++++----- src/Diffing/Algorithm/RWS.hs | 4 ++-- src/Diffing/Interpreter.hs | 6 +++--- test/Diffing/Algorithm/RWS/Spec.hs | 2 +- test/Diffing/Interpreter/Spec.hs | 2 +- test/Rendering/TOC/Spec.hs | 4 ++-- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Data/Diff.hs b/src/Data/Diff.hs index 5b20486f3..39b778c8b 100644 --- a/src/Data/Diff.hs +++ b/src/Data/Diff.hs @@ -2,7 +2,7 @@ module Data.Diff ( Diff(..) , DiffF(..) -, replacing +, comparing , compareF , inserting , insertF @@ -36,11 +36,11 @@ data DiffF syntax ann1 ann2 recur -- | An unchanged node, consisting of syntax labelled with both the original annotations. | Merge (TermF syntax (ann1, ann2) recur) --- | Constructs a 'Diff' replacing one 'Term' with another recursively. -replacing :: Functor syntax => Term syntax ann1 -> Term syntax ann2 -> Diff syntax ann1 ann2 -replacing (Term (In a1 r1)) (Term (In a2 r2)) = compareF (In a1 (deleting <$> r1)) (In a2 (inserting <$> r2)) +-- | Constructs a 'Diff' comparing one 'Term' with another recursively. +comparing :: Functor syntax => Term syntax ann1 -> Term syntax ann2 -> Diff syntax ann1 ann2 +comparing (Term (In a1 r1)) (Term (In a2 r2)) = compareF (In a1 (deleting <$> r1)) (In a2 (inserting <$> r2)) --- | Constructs a 'Diff' replacing one 'TermF' populated by further 'Diff's with another. +-- | Constructs a 'Diff' comparing one 'TermF' populated by further 'Diff's with another. compareF :: TermF syntax ann1 (Diff syntax ann1 ann2) -> TermF syntax ann2 (Diff syntax ann1 ann2) -> Diff syntax ann1 ann2 compareF t1 t2 = Diff (Patch (Compare t1 t2)) diff --git a/src/Diffing/Algorithm/RWS.hs b/src/Diffing/Algorithm/RWS.hs index 65dda81a9..74941bce6 100644 --- a/src/Diffing/Algorithm/RWS.hs +++ b/src/Diffing/Algorithm/RWS.hs @@ -15,7 +15,7 @@ module Diffing.Algorithm.RWS ) where import Control.Monad.State.Strict -import Data.Diff (DiffF(..), deleting, inserting, merge, replacing) +import Data.Diff (DiffF(..), comparing, deleting, inserting, merge) import qualified Data.KdMap.Static as KdMap import Data.List (sortOn) import Data.Term as Term @@ -158,7 +158,7 @@ editDistanceUpTo m a b = diffCost m (approximateDiff a b) _ | m <= 0 -> 0 Merge body -> sum (fmap ($ pred m) body) body -> succ (sum (fmap ($ pred m) body)) - approximateDiff a b = maybe (replacing a b) (merge (termAnnotation a, termAnnotation b)) (tryAlignWith (Just . these deleting inserting approximateDiff) (termOut a) (termOut b)) + approximateDiff a b = maybe (comparing a b) (merge (termAnnotation a, termAnnotation b)) (tryAlignWith (Just . these deleting inserting approximateDiff) (termOut a) (termOut b)) data Label syntax where diff --git a/src/Diffing/Interpreter.hs b/src/Diffing/Interpreter.hs index e4d3a01d1..73d874fdb 100644 --- a/src/Diffing/Interpreter.hs +++ b/src/Diffing/Interpreter.hs @@ -20,7 +20,7 @@ diffTerms :: (Diffable syntax, Eq1 syntax, Hashable1 syntax, Traversable syntax) => Term syntax ann1 -> Term syntax ann2 -> Diff.Diff syntax ann1 ann2 -diffTerms t1 t2 = stripDiff (fromMaybe (Diff.replacing t1' t2') (run (runNonDetOnce (runDiff (algorithmForTerms t1' t2'))))) +diffTerms t1 t2 = stripDiff (fromMaybe (Diff.comparing t1' t2') (run (runNonDetOnce (runDiff (algorithmForTerms t1' t2'))))) where (t1', t2') = ( defaultFeatureVectorDecorator t1 , defaultFeatureVectorDecorator t2) @@ -71,10 +71,10 @@ instance ( Alternative m (Diff (Term syntax (FeatureVector, ann1)) (Term syntax (FeatureVector, ann2)) (Diff.Diff syntax (FeatureVector, ann1) (FeatureVector, ann2)) :+: sig) (DiffC (Term syntax (FeatureVector, ann1)) (Term syntax (FeatureVector, ann2)) (Diff.Diff syntax (FeatureVector, ann1) (FeatureVector, ann2)) m) where eff (L op) = case op of - Diff t1 t2 k -> runDiff (algorithmForTerms t1 t2) <|> pure (Diff.replacing t1 t2) >>= k + Diff t1 t2 k -> runDiff (algorithmForTerms t1 t2) <|> pure (Diff.comparing t1 t2) >>= k Linear (Term (In ann1 f1)) (Term (In ann2 f2)) k -> Diff.merge (ann1, ann2) <$> tryAlignWith (runDiff . diffThese) f1 f2 >>= k RWS as bs k -> traverse (runDiff . diffThese . toThese) (rws comparableTerms equivalentTerms as bs) >>= k Delete a k -> k (Diff.deleting a) Insert b k -> k (Diff.inserting b) - Replace a b k -> k (Diff.replacing a b) + Replace a b k -> k (Diff.comparing a b) eff (R other) = DiffC . eff . handleCoercible $ other diff --git a/test/Diffing/Algorithm/RWS/Spec.hs b/test/Diffing/Algorithm/RWS/Spec.hs index 0e88dada1..b32623cc5 100644 --- a/test/Diffing/Algorithm/RWS/Spec.hs +++ b/test/Diffing/Algorithm/RWS/Spec.hs @@ -40,7 +40,7 @@ spec = do where decorate = defaultFeatureVectorDecorator - diffThese = these deleting inserting replacing + diffThese = these deleting inserting comparing stripTerm :: Functor f => Term f (FeatureVector, ()) -> Term f () stripTerm = fmap snd diff --git a/test/Diffing/Interpreter/Spec.hs b/test/Diffing/Interpreter/Spec.hs index a040fd002..d8a67d18c 100644 --- a/test/Diffing/Interpreter/Spec.hs +++ b/test/Diffing/Interpreter/Spec.hs @@ -26,7 +26,7 @@ spec = do it "returns a replacement when comparing two unicode equivalent terms" $ let termA = termIn emptyAnnotation (inject (Syntax.Identifier "t\776")) termB = termIn emptyAnnotation (inject (Syntax.Identifier "\7831")) in - diffTerms termA termB `shouldBe` replacing termA (termB :: Term ListableSyntax ()) + diffTerms termA termB `shouldBe` comparing termA (termB :: Term ListableSyntax ()) prop "produces correct diffs" $ \ a b -> let diff = diffTerms a b :: Diff ListableSyntax () () in diff --git a/test/Rendering/TOC/Spec.hs b/test/Rendering/TOC/Spec.hs index 10de55ffd..bfcd90a2b 100644 --- a/test/Rendering/TOC/Spec.hs +++ b/test/Rendering/TOC/Spec.hs @@ -37,7 +37,7 @@ spec = do \ term -> tableOfContentsBy (Just . termFAnnotation) (diffTerms term (term :: Term ListableSyntax ())) `shouldBe` [] prop "produces inserted/deleted/replaced entries for relevant nodes within patches" $ - \ p -> tableOfContentsBy (Just . termFAnnotation) (patch deleting inserting replacing p) + \ p -> tableOfContentsBy (Just . termFAnnotation) (patch deleting inserting comparing p) `shouldBe` patch (fmap (Deleted,)) (fmap (Inserted,)) (\ as bs -> (Replaced, head bs) : fmap (Deleted,) (tail as) <> fmap (Inserted,) (tail bs)) (bimap (foldMap pure) (foldMap pure) (p :: Patch (Term ListableSyntax Int) (Term ListableSyntax Int))) @@ -183,7 +183,7 @@ programWithDelete :: Text -> Term' -> Diff' programWithDelete name body = programOf $ deleting (functionOf name body) programWithReplace :: Text -> Term' -> Diff' -programWithReplace name body = programOf $ replacing (functionOf name body) (functionOf (name <> "2") body) +programWithReplace name body = programOf $ comparing (functionOf name body) (functionOf (name <> "2") body) programOf :: Diff' -> Diff' programOf diff = merge (Nothing, Nothing) (inject [ diff ]) From fb72904e1b7b64fdc548684b51d4dc56eec3d410 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 17 Oct 2019 22:19:48 -0400 Subject: [PATCH 004/118] Correct a doc comment. --- src/Data/Patch.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Data/Patch.hs b/src/Data/Patch.hs index eca782d78..95fb43b69 100644 --- a/src/Data/Patch.hs +++ b/src/Data/Patch.hs @@ -11,7 +11,7 @@ import Data.Aeson import Data.Align import Data.JSON.Fields --- | An operation to replace, insert, or delete an item. +-- | An operation to compare, insert, or delete an item. data Patch a b = Delete a | Insert b From aeff33b31a98fd12dc8563a02eec672c197f9555 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 17 Oct 2019 22:20:41 -0400 Subject: [PATCH 005/118] :fire: a redundant OPTIONS_GHC pragma. --- src/Data/Patch.hs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Data/Patch.hs b/src/Data/Patch.hs index 95fb43b69..6899aad84 100644 --- a/src/Data/Patch.hs +++ b/src/Data/Patch.hs @@ -1,4 +1,3 @@ -{-# OPTIONS_GHC -funbox-strict-fields #-} module Data.Patch ( Patch(..) , after From 20c92cb22a83cb620a59643433ab7ef9c88ebfc7 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 17 Oct 2019 22:21:26 -0400 Subject: [PATCH 006/118] :fire: --- src/Data/Patch.hs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Data/Patch.hs b/src/Data/Patch.hs index 6899aad84..b0db7f9b8 100644 --- a/src/Data/Patch.hs +++ b/src/Data/Patch.hs @@ -33,8 +33,6 @@ patch _ ifInsert _ (Insert b) = ifInsert b patch _ _ ifReplace (Compare a b) = ifReplace a b --- Instances - instance Bifunctor Patch where bimap f _ (Delete a) = Delete (f a) bimap _ g (Insert b) = Insert (g b) From 3cf78abe5fd52d3f3ff4dcaa56a3338776b984b9 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 17 Oct 2019 22:24:46 -0400 Subject: [PATCH 007/118] LambdaCase. --- src/Data/Patch.hs | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/Data/Patch.hs b/src/Data/Patch.hs index b0db7f9b8..2096ce2fb 100644 --- a/src/Data/Patch.hs +++ b/src/Data/Patch.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE LambdaCase #-} module Data.Patch ( Patch(..) , after @@ -34,24 +35,28 @@ patch _ _ ifReplace (Compare a b) = ifReplace a b instance Bifunctor Patch where - bimap f _ (Delete a) = Delete (f a) - bimap _ g (Insert b) = Insert (g b) - bimap f g (Compare a b) = Compare (f a) (g b) + bimap f g = \case + Delete a -> Delete (f a) + Insert b -> Insert (g b) + Compare a b -> Compare (f a) (g b) instance Bifoldable Patch where - bifoldMap f _ (Delete a) = f a - bifoldMap _ g (Insert b) = g b - bifoldMap f g (Compare a b) = f a `mappend` g b + bifoldMap f g = \case + Delete a -> f a + Insert b -> g b + Compare a b -> f a <> g b instance Bitraversable Patch where - bitraverse f _ (Delete a) = Delete <$> f a - bitraverse _ g (Insert b) = Insert <$> g b - bitraverse f g (Compare a b) = Compare <$> f a <*> g b + bitraverse f g = \case + Delete a -> Delete <$> f a + Insert b -> Insert <$> g b + Compare a b -> Compare <$> f a <*> g b instance Bicrosswalk Patch where - bicrosswalk f _ (Delete a) = Delete <$> f a - bicrosswalk _ g (Insert b) = Insert <$> g b - bicrosswalk f g (Compare a b) = alignWith (these Delete Insert Compare) (f a) (g b) + bicrosswalk f g = \case + Delete a -> Delete <$> f a + Insert b -> Insert <$> g b + Compare a b -> alignWith (these Delete Insert Compare) (f a) (g b) instance Eq2 Patch where liftEq2 eqBefore eqAfter p1 p2 = case (p1, p2) of @@ -61,7 +66,7 @@ instance Eq2 Patch where _ -> False instance Show2 Patch where - liftShowsPrec2 spBefore _ spAfter _ d p = case p of + liftShowsPrec2 spBefore _ spAfter _ d = \case Delete a -> showsUnaryWith spBefore "Delete" d a Insert b -> showsUnaryWith spAfter "Insert" d b Compare a b -> showsBinaryWith spBefore spAfter "Compare" d a b From 8f91dd09bbae48003629f0a555b5d2ffc7a106e4 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 17 Oct 2019 22:25:15 -0400 Subject: [PATCH 008/118] Use defaults in terms of bitraverse. --- src/Data/Patch.hs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/Data/Patch.hs b/src/Data/Patch.hs index 2096ce2fb..b2df724e0 100644 --- a/src/Data/Patch.hs +++ b/src/Data/Patch.hs @@ -35,16 +35,10 @@ patch _ _ ifReplace (Compare a b) = ifReplace a b instance Bifunctor Patch where - bimap f g = \case - Delete a -> Delete (f a) - Insert b -> Insert (g b) - Compare a b -> Compare (f a) (g b) + bimap = bimapDefault instance Bifoldable Patch where - bifoldMap f g = \case - Delete a -> f a - Insert b -> g b - Compare a b -> f a <> g b + bifoldMap = bifoldMapDefault instance Bitraversable Patch where bitraverse f g = \case From c4523858697f891d58558e19eb828b50812204a0 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 17 Oct 2019 22:26:17 -0400 Subject: [PATCH 009/118] Use LambdaCase to define patch. --- src/Data/Patch.hs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Data/Patch.hs b/src/Data/Patch.hs index b2df724e0..0863cd282 100644 --- a/src/Data/Patch.hs +++ b/src/Data/Patch.hs @@ -29,9 +29,10 @@ before = patch Just (const Nothing) (\ a _ -> Just a) -- | Return both sides of a patch. patch :: (before -> result) -> (after -> result) -> (before -> after -> result) -> Patch before after -> result -patch ifDelete _ _ (Delete a) = ifDelete a -patch _ ifInsert _ (Insert b) = ifInsert b -patch _ _ ifReplace (Compare a b) = ifReplace a b +patch delete insert compare = \case + Delete a -> delete a + Insert b -> insert b + Compare a b -> compare a b instance Bifunctor Patch where From c59e205447e961fc996e9bca45ddf0853f573634 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 17 Oct 2019 22:28:15 -0400 Subject: [PATCH 010/118] Rename some type parameters. --- src/Data/Patch.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Data/Patch.hs b/src/Data/Patch.hs index 0863cd282..68fb48f91 100644 --- a/src/Data/Patch.hs +++ b/src/Data/Patch.hs @@ -20,15 +20,15 @@ data Patch a b -- | Return the item from the after side of the patch. -after :: Patch before after -> Maybe after +after :: Patch l r -> Maybe r after = patch (const Nothing) Just (\ _ b -> Just b) -- | Return the item from the before side of the patch. -before :: Patch before after -> Maybe before +before :: Patch l r -> Maybe l before = patch Just (const Nothing) (\ a _ -> Just a) -- | Return both sides of a patch. -patch :: (before -> result) -> (after -> result) -> (before -> after -> result) -> Patch before after -> result +patch :: (l -> a) -> (r -> a) -> (l -> r -> a) -> Patch l r -> a patch delete insert compare = \case Delete a -> delete a Insert b -> insert b From fc394d69e7ac174f32e1a4819ff72e857f072ec7 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 17 Oct 2019 22:28:35 -0400 Subject: [PATCH 011/118] Rename some variables. --- src/Data/Patch.hs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Data/Patch.hs b/src/Data/Patch.hs index 68fb48f91..721bde412 100644 --- a/src/Data/Patch.hs +++ b/src/Data/Patch.hs @@ -61,10 +61,10 @@ instance Eq2 Patch where _ -> False instance Show2 Patch where - liftShowsPrec2 spBefore _ spAfter _ d = \case - Delete a -> showsUnaryWith spBefore "Delete" d a - Insert b -> showsUnaryWith spAfter "Insert" d b - Compare a b -> showsBinaryWith spBefore spAfter "Compare" d a b + liftShowsPrec2 spl _ spr _ d = \case + Delete a -> showsUnaryWith spl "Delete" d a + Insert b -> showsUnaryWith spr "Insert" d b + Compare a b -> showsBinaryWith spl spr "Compare" d a b instance (ToJSONFields a, ToJSONFields b) => ToJSONFields (Patch a b) where From eb549cff266007a9996a58bab074797ae214e86f Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 17 Oct 2019 22:31:16 -0400 Subject: [PATCH 012/118] Align. --- src/Data/Patch.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Data/Patch.hs b/src/Data/Patch.hs index 721bde412..e99f06b2b 100644 --- a/src/Data/Patch.hs +++ b/src/Data/Patch.hs @@ -43,8 +43,8 @@ instance Bifoldable Patch where instance Bitraversable Patch where bitraverse f g = \case - Delete a -> Delete <$> f a - Insert b -> Insert <$> g b + Delete a -> Delete <$> f a + Insert b -> Insert <$> g b Compare a b -> Compare <$> f a <*> g b instance Bicrosswalk Patch where From 76d35900df6485224bea71cae1c28f18ba158e8a Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 17 Oct 2019 22:34:19 -0400 Subject: [PATCH 013/118] Rename patch to edit. --- src/Data/Patch.hs | 10 +++++----- src/Rendering/TOC.hs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Data/Patch.hs b/src/Data/Patch.hs index e99f06b2b..273c2287a 100644 --- a/src/Data/Patch.hs +++ b/src/Data/Patch.hs @@ -3,7 +3,7 @@ module Data.Patch ( Patch(..) , after , before -, patch +, edit ) where import Prologue @@ -21,15 +21,15 @@ data Patch a b -- | Return the item from the after side of the patch. after :: Patch l r -> Maybe r -after = patch (const Nothing) Just (\ _ b -> Just b) +after = edit (const Nothing) Just (\ _ b -> Just b) -- | Return the item from the before side of the patch. before :: Patch l r -> Maybe l -before = patch Just (const Nothing) (\ a _ -> Just a) +before = edit Just (const Nothing) (\ a _ -> Just a) -- | Return both sides of a patch. -patch :: (l -> a) -> (r -> a) -> (l -> r -> a) -> Patch l r -> a -patch delete insert compare = \case +edit :: (l -> a) -> (r -> a) -> (l -> r -> a) -> Patch l r -> a +edit delete insert compare = \case Delete a -> delete a Insert b -> insert b Compare a b -> compare a b diff --git a/src/Rendering/TOC.hs b/src/Rendering/TOC.hs index d6b03188c..26337d9cd 100644 --- a/src/Rendering/TOC.hs +++ b/src/Rendering/TOC.hs @@ -82,7 +82,7 @@ tableOfContentsBy selector = fromMaybe [] . cata (\ r -> case r of Merge (In (_, ann2) r) -> case (selector (In ann2 r), fold r) of (Just a, Just entries) -> Just ((Changed, a) : entries) (_ , entries) -> entries) - where patchEntry = patch (Deleted,) (Inserted,) (const (Replaced,)) + where patchEntry = edit (Deleted,) (Inserted,) (const (Replaced,)) data DedupeKey = DedupeKey !Kind {-# UNPACK #-} !T.Text From e6ffee08294ca6d1919c7dde0e5357b455204981 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 17 Oct 2019 22:35:43 -0400 Subject: [PATCH 014/118] Import everything explicitly. --- src/Data/Patch.hs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Data/Patch.hs b/src/Data/Patch.hs index 273c2287a..14574eabb 100644 --- a/src/Data/Patch.hs +++ b/src/Data/Patch.hs @@ -6,10 +6,15 @@ module Data.Patch , edit ) where -import Prologue import Data.Aeson import Data.Align +import Data.Bifoldable +import Data.Bifunctor +import Data.Bitraversable +import Data.Functor.Classes import Data.JSON.Fields +import Data.These +import GHC.Generics (Generic, Generic1) -- | An operation to compare, insert, or delete an item. data Patch a b From b6caf8d98f29dc078aa1b0b0a46829002a652e3e Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 17 Oct 2019 22:36:50 -0400 Subject: [PATCH 015/118] Move the ToJSONFields instance for Patch into Data.JSON.Fields. --- src/Data/JSON/Fields.hs | 6 ++++++ src/Data/Patch.hs | 8 -------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/Data/JSON/Fields.hs b/src/Data/JSON/Fields.hs index c199425c7..d81ab83e6 100644 --- a/src/Data/JSON/Fields.hs +++ b/src/Data/JSON/Fields.hs @@ -10,6 +10,7 @@ module Data.JSON.Fields import Data.Aeson import qualified Data.Map as Map +import Data.Patch import Data.Sum (Apply (..), Sum) import qualified Data.Text as Text import GHC.Generics @@ -57,6 +58,11 @@ instance ToJSONFields Span where instance ToJSONFields Loc where toJSONFields Loc{..} = toJSONFields byteRange <> toJSONFields span +instance (ToJSONFields a, ToJSONFields b) => ToJSONFields (Patch a b) where + toJSONFields (Insert a) = [ "insert" .= object (toJSONFields a) ] + toJSONFields (Delete a) = [ "delete" .= object (toJSONFields a) ] + toJSONFields (Compare a b) = [ "replace" .= [object (toJSONFields a), object (toJSONFields b)] ] + newtype JSONFields a = JSONFields { unJSONFields :: a } diff --git a/src/Data/Patch.hs b/src/Data/Patch.hs index 14574eabb..951e666b6 100644 --- a/src/Data/Patch.hs +++ b/src/Data/Patch.hs @@ -6,13 +6,11 @@ module Data.Patch , edit ) where -import Data.Aeson import Data.Align import Data.Bifoldable import Data.Bifunctor import Data.Bitraversable import Data.Functor.Classes -import Data.JSON.Fields import Data.These import GHC.Generics (Generic, Generic1) @@ -70,9 +68,3 @@ instance Show2 Patch where Delete a -> showsUnaryWith spl "Delete" d a Insert b -> showsUnaryWith spr "Insert" d b Compare a b -> showsBinaryWith spl spr "Compare" d a b - - -instance (ToJSONFields a, ToJSONFields b) => ToJSONFields (Patch a b) where - toJSONFields (Insert a) = [ "insert" .= object (toJSONFields a) ] - toJSONFields (Delete a) = [ "delete" .= object (toJSONFields a) ] - toJSONFields (Compare a b) = [ "replace" .= [object (toJSONFields a), object (toJSONFields b)] ] From 6b7ef7c725992a13de3509584acf079f40c152f5 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 17 Oct 2019 22:39:34 -0400 Subject: [PATCH 016/118] :fire: before/after. --- src/Data/Patch.hs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/Data/Patch.hs b/src/Data/Patch.hs index 951e666b6..242b98ea6 100644 --- a/src/Data/Patch.hs +++ b/src/Data/Patch.hs @@ -1,8 +1,6 @@ {-# LANGUAGE LambdaCase #-} module Data.Patch ( Patch(..) -, after -, before , edit ) where @@ -22,14 +20,6 @@ data Patch a b deriving (Eq, Foldable, Functor, Generic, Generic1, Ord, Show, Traversable) --- | Return the item from the after side of the patch. -after :: Patch l r -> Maybe r -after = edit (const Nothing) Just (\ _ b -> Just b) - --- | Return the item from the before side of the patch. -before :: Patch l r -> Maybe l -before = edit Just (const Nothing) (\ a _ -> Just a) - -- | Return both sides of a patch. edit :: (l -> a) -> (r -> a) -> (l -> r -> a) -> Patch l r -> a edit delete insert compare = \case From 7b37f3789f3acd63abf25fee328be0ed6b242edd Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 17 Oct 2019 22:43:03 -0400 Subject: [PATCH 017/118] Rename Data.Patch to Data.Edit. --- semantic.cabal | 2 +- src/Data/Diff.hs | 2 +- src/Data/{Patch.hs => Edit.hs} | 2 +- src/Data/JSON/Fields.hs | 2 +- src/Rendering/Graph.hs | 2 +- src/Rendering/JSON.hs | 4 ++-- src/Rendering/TOC.hs | 2 +- src/Serializing/SExpression.hs | 2 +- test/Data/Functor/Listable.hs | 2 +- test/Diffing/Interpreter/Spec.hs | 10 +++++++++- test/Rendering/TOC/Spec.hs | 2 +- 11 files changed, 20 insertions(+), 12 deletions(-) rename src/Data/{Patch.hs => Edit.hs} (98%) diff --git a/semantic.cabal b/semantic.cabal index dc5874931..ee1eb1796 100644 --- a/semantic.cabal +++ b/semantic.cabal @@ -148,6 +148,7 @@ library , Data.Blob.IO , Data.Diff , Data.Duration + , Data.Edit , Data.Error , Data.Flag , Data.Functor.Both @@ -160,7 +161,6 @@ library , Data.JSON.Fields , Data.Language , Data.Map.Monoidal - , Data.Patch , Data.Project , Data.Quieterm , Data.Semigroup.App diff --git a/src/Data/Diff.hs b/src/Data/Diff.hs index 39b778c8b..61eca38f7 100644 --- a/src/Data/Diff.hs +++ b/src/Data/Diff.hs @@ -18,10 +18,10 @@ import Data.Aeson import Data.Bifoldable import Data.Bifunctor import Data.Bitraversable +import Data.Edit import Data.Functor.Classes import Data.Functor.Foldable import Data.JSON.Fields -import Data.Patch import Data.Term import Text.Show diff --git a/src/Data/Patch.hs b/src/Data/Edit.hs similarity index 98% rename from src/Data/Patch.hs rename to src/Data/Edit.hs index 242b98ea6..5500f2afa 100644 --- a/src/Data/Patch.hs +++ b/src/Data/Edit.hs @@ -1,5 +1,5 @@ {-# LANGUAGE LambdaCase #-} -module Data.Patch +module Data.Edit ( Patch(..) , edit ) where diff --git a/src/Data/JSON/Fields.hs b/src/Data/JSON/Fields.hs index d81ab83e6..e0c938eee 100644 --- a/src/Data/JSON/Fields.hs +++ b/src/Data/JSON/Fields.hs @@ -9,8 +9,8 @@ module Data.JSON.Fields ) where import Data.Aeson +import Data.Edit import qualified Data.Map as Map -import Data.Patch import Data.Sum (Apply (..), Sum) import qualified Data.Text as Text import GHC.Generics diff --git a/src/Rendering/Graph.hs b/src/Rendering/Graph.hs index fece93f88..5994c724f 100644 --- a/src/Rendering/Graph.hs +++ b/src/Rendering/Graph.hs @@ -14,8 +14,8 @@ import Control.Effect.Reader import Control.Effect.State import Control.Lens import Data.Diff +import Data.Edit import Data.Graph -import Data.Patch import Data.ProtoLens (defMessage) import Data.String (IsString (..)) import Data.Term diff --git a/src/Rendering/JSON.hs b/src/Rendering/JSON.hs index 119e73ec3..10f522635 100644 --- a/src/Rendering/JSON.hs +++ b/src/Rendering/JSON.hs @@ -15,9 +15,9 @@ module Rendering.JSON import Data.Aeson (ToJSON, toJSON, object, (.=)) import Data.Aeson as A -import Data.JSON.Fields import Data.Blob -import Data.Patch +import Data.Edit +import Data.JSON.Fields import Data.Text (pack) import GHC.TypeLits import Prologue diff --git a/src/Rendering/TOC.hs b/src/Rendering/TOC.hs index 26337d9cd..1d27ee3f6 100644 --- a/src/Rendering/TOC.hs +++ b/src/Rendering/TOC.hs @@ -15,10 +15,10 @@ import Analysis.TOCSummary import Data.Align (bicrosswalk) import Data.Aeson (ToJSON(..), Value, (.=), object) import Data.Diff +import Data.Edit import Data.Language as Language import Data.List (sortOn) import qualified Data.Map.Monoidal as Map -import Data.Patch import Data.Term import qualified Data.Text as T import Source.Loc diff --git a/src/Serializing/SExpression.hs b/src/Serializing/SExpression.hs index c994a944f..7681fabe5 100644 --- a/src/Serializing/SExpression.hs +++ b/src/Serializing/SExpression.hs @@ -8,7 +8,7 @@ module Serializing.SExpression import Analysis.ConstructorName import Data.ByteString.Builder import Data.Diff -import Data.Patch +import Data.Edit import Data.Term import Prelude import Prologue diff --git a/test/Data/Functor/Listable.hs b/test/Data/Functor/Listable.hs index d42f76fdc..992407efd 100644 --- a/test/Data/Functor/Listable.hs +++ b/test/Data/Functor/Listable.hs @@ -20,10 +20,10 @@ import qualified Analysis.TOCSummary as ToC import Data.Abstract.ScopeGraph (AccessControl(..)) import Data.Bifunctor.Join import Data.Diff +import Data.Edit import Data.Functor.Both import qualified Data.Language as Language import Data.List.NonEmpty -import Data.Patch import qualified Data.Syntax as Syntax import qualified Data.Syntax.Comment as Comment import qualified Data.Syntax.Declaration as Declaration diff --git a/test/Diffing/Interpreter/Spec.hs b/test/Diffing/Interpreter/Spec.hs index d8a67d18c..1e42b1632 100644 --- a/test/Diffing/Interpreter/Spec.hs +++ b/test/Diffing/Interpreter/Spec.hs @@ -3,12 +3,12 @@ module Diffing.Interpreter.Spec (spec, afterTerm, beforeTerm) where import Control.Applicative ((<|>)) import Data.Diff +import Data.Edit (edit) import Data.Foldable (asum) import Data.Functor.Foldable (cata) import Data.Functor.Listable import Data.Maybe import Data.Mergeable -import Data.Patch (after, before) import Data.Sum import Data.Term import Data.These @@ -81,5 +81,13 @@ afterTerm = cata $ \ diff -> case diff of Patch patch -> (after patch >>= \ (In b r) -> termIn b <$> sequenceAlt r) <|> (before patch >>= asum) Merge (In (_, b) r) -> termIn b <$> sequenceAlt r +-- | Return the item from the after side of the patch. +after :: Patch l r -> Maybe r +after = edit (const Nothing) Just (\ _ b -> Just b) + +-- | Return the item from the before side of the patch. +before :: Patch l r -> Maybe l +before = edit Just (const Nothing) (\ a _ -> Just a) + emptyAnnotation :: () emptyAnnotation = () diff --git a/test/Rendering/TOC/Spec.hs b/test/Rendering/TOC/Spec.hs index bfcd90a2b..5d6a669cb 100644 --- a/test/Rendering/TOC/Spec.hs +++ b/test/Rendering/TOC/Spec.hs @@ -7,8 +7,8 @@ import Control.Effect.Reader import Data.Aeson hiding (defaultOptions) import Data.Bifunctor import Data.Diff +import Data.Edit import Data.Either (isRight) -import Data.Patch import Data.Sum import Data.Term import Data.Text (Text) From e4af857c5be187ddbab917728eb4d18c62440ec4 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 17 Oct 2019 22:44:57 -0400 Subject: [PATCH 018/118] Rename Copy to Compare. --- src/Diffing/Algorithm/RWS.hs | 12 ++++++------ src/Diffing/Algorithm/SES.hs | 8 ++++---- src/Semantic/Api/TOCSummaries.hs | 2 +- test/Diffing/Algorithm/RWS/Spec.hs | 2 +- test/Diffing/Algorithm/SES/Spec.hs | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Diffing/Algorithm/RWS.hs b/src/Diffing/Algorithm/RWS.hs index 74941bce6..1e63e0d18 100644 --- a/src/Diffing/Algorithm/RWS.hs +++ b/src/Diffing/Algorithm/RWS.hs @@ -37,7 +37,7 @@ rws :: (Foldable syntax, Functor syntax, Diffable syntax) -> [Edit (Term syntax (FeatureVector, ann1)) (Term syntax (FeatureVector, ann2))] rws _ _ as [] = Delete <$> as rws _ _ [] bs = Insert <$> bs -rws canCompare _ [a] [b] = if canCompareTerms canCompare a b then [Copy a b] else [Insert b, Delete a] +rws canCompare _ [a] [b] = if canCompareTerms canCompare a b then [Compare a b] else [Insert b, Delete a] rws canCompare equivalent as bs = ses equivalent as bs & mapContiguous [] [] @@ -46,15 +46,15 @@ rws canCompare equivalent as bs -- Map contiguous sequences of unmapped terms separated by SES-mapped equivalencies. mapContiguous as bs [] = mapSimilar (reverse as) (reverse bs) mapContiguous as bs (first : rest) = case first of - Delete a -> mapContiguous (a : as) bs rest - Insert b -> mapContiguous as (b : bs) rest - Copy _ _ -> mapSimilar (reverse as) (reverse bs) <> (first : mapContiguous [] [] rest) + Delete a -> mapContiguous (a : as) bs rest + Insert b -> mapContiguous as (b : bs) rest + Compare _ _ -> mapSimilar (reverse as) (reverse bs) <> (first : mapContiguous [] [] rest) -- Map comparable, mutually similar terms, inserting & deleting surrounding terms. mapSimilar as' bs' = go as bs where go as [] = Delete . snd <$> as go [] bs = Insert . snd <$> bs - go [a] [b] | canCompareTerms canCompare (snd a) (snd b) = [Copy (snd a) (snd b)] + go [a] [b] | canCompareTerms canCompare (snd a) (snd b) = [Compare (snd a) (snd b)] | otherwise = [Insert (snd b), Delete (snd a)] go as@((i, _) : _) ((j, b) : restB) = fromMaybe (Insert b : go as restB) $ do @@ -66,7 +66,7 @@ rws canCompare equivalent as bs guard (j == j') -- Delete any elements of as before the selected element. let (deleted, _ : restA) = span ((< i') . fst) as - pure $! (Delete . snd <$> deleted) <> (Copy a b : go restA restB) + pure $! (Delete . snd <$> deleted) <> (Compare a b : go restA restB) (as, bs) = (zip [0..] as', zip [0..] bs') (kdMapA, kdMapB) = (toKdMap as, toKdMap bs) diff --git a/src/Diffing/Algorithm/SES.hs b/src/Diffing/Algorithm/SES.hs index 581256066..117a01cfa 100644 --- a/src/Diffing/Algorithm/SES.hs +++ b/src/Diffing/Algorithm/SES.hs @@ -16,20 +16,20 @@ import Data.These data Edit a b = Delete a | Insert b - | Copy a b + | Compare a b deriving (Eq, Functor, Ord, Show) instance Bifunctor Edit where bimap f g = \case Delete a -> Delete (f a) Insert b -> Insert (g b) - Copy a b -> Copy (f a) (g b) + Compare a b -> Compare (f a) (g b) toThese :: Edit a b -> These a b toThese = \case Delete a -> This a Insert b -> That b - Copy a b -> These a b + Compare a b -> These a b data Endpoint a b = Endpoint { x :: {-# UNPACK #-} !Int, _y :: {-# UNPACK #-} !Int, _script :: [Edit a b] } deriving (Eq, Show) @@ -78,7 +78,7 @@ ses eq as' bs' slideFrom (Endpoint x y script) | Just a <- as !? x , Just b <- bs !? y - , a `eq` b = slideFrom (Endpoint (succ x) (succ y) (Copy a b : script)) + , a `eq` b = slideFrom (Endpoint (succ x) (succ y) (Compare a b : script)) | otherwise = Endpoint x y script diff --git a/src/Semantic/Api/TOCSummaries.hs b/src/Semantic/Api/TOCSummaries.hs index 2d51aef97..9f05cc42b 100644 --- a/src/Semantic/Api/TOCSummaries.hs +++ b/src/Semantic/Api/TOCSummaries.hs @@ -132,7 +132,7 @@ instance Tagging.ToTags t => SummarizeDiff (ViaTags t) where toChange = \case SES.Delete tag -> (Deleted,) <$> toDecl tag SES.Insert tag -> (Inserted,) <$> toDecl tag - SES.Copy t1 t2 + SES.Compare t1 t2 | Source.slice s1 (byteRange (Tag.loc t1)) /= Source.slice s2 (byteRange (Tag.loc t2)) -> (Changed,) <$> toDecl t2 | otherwise -> Nothing diff --git a/test/Diffing/Algorithm/RWS/Spec.hs b/test/Diffing/Algorithm/RWS/Spec.hs index b32623cc5..76bcaa970 100644 --- a/test/Diffing/Algorithm/RWS/Spec.hs +++ b/test/Diffing/Algorithm/RWS/Spec.hs @@ -36,7 +36,7 @@ spec = do it "produces unbiased insertions within branches" $ let (a, b) = (decorate (termIn emptyAnnotation (inject [ termIn emptyAnnotation (inject (Syntax.Identifier "a")) ])), decorate (termIn emptyAnnotation (inject [ termIn emptyAnnotation (inject (Syntax.Identifier "b")) ]))) in - fmap (bimap stripTerm stripTerm) (rws comparableTerms (equalTerms comparableTerms) [ b ] [ a, b ]) `shouldBe` fmap (bimap stripTerm stripTerm) [ Insert a, Copy b b ] + fmap (bimap stripTerm stripTerm) (rws comparableTerms (equalTerms comparableTerms) [ b ] [ a, b ]) `shouldBe` fmap (bimap stripTerm stripTerm) [ Insert a, Compare b b ] where decorate = defaultFeatureVectorDecorator diff --git a/test/Diffing/Algorithm/SES/Spec.hs b/test/Diffing/Algorithm/SES/Spec.hs index 79b48aad0..1e573fcc4 100644 --- a/test/Diffing/Algorithm/SES/Spec.hs +++ b/test/Diffing/Algorithm/SES/Spec.hs @@ -9,7 +9,7 @@ spec :: Spec spec = do describe "ses" $ do prop "returns equal lists in These" $ - \ as -> (ses (==) as as :: [Edit Char Char]) `shouldBe` zipWith Copy as as + \ as -> (ses (==) as as :: [Edit Char Char]) `shouldBe` zipWith Compare as as prop "returns deletions in This" $ \ as -> (ses (==) as [] :: [Edit Char Char]) `shouldBe` fmap Delete as From 209f8871a5a9c86cea1059ebe50870b14c9c442d Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 17 Oct 2019 22:48:19 -0400 Subject: [PATCH 019/118] Rename Patch to Edit. --- src/Data/Diff.hs | 8 ++++---- src/Data/Edit.hs | 18 +++++++++--------- src/Data/JSON/Fields.hs | 2 +- test/Data/Functor/Listable.hs | 4 ++-- test/Diffing/Interpreter/Spec.hs | 4 ++-- test/Rendering/TOC/Spec.hs | 2 +- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/Data/Diff.hs b/src/Data/Diff.hs index 61eca38f7..a1bb48be6 100644 --- a/src/Data/Diff.hs +++ b/src/Data/Diff.hs @@ -31,10 +31,10 @@ newtype Diff syntax ann1 ann2 = Diff { unDiff :: DiffF syntax ann1 ann2 (Diff sy -- | A single entry within a recursive 'Diff'. data DiffF syntax ann1 ann2 recur -- | A changed node, represented as 'Insert'ed, 'Delete'd, or 'Compare'd 'TermF's, consisting of syntax labelled with an annotation. - = Patch (Patch (TermF syntax ann1 recur) - (TermF syntax ann2 recur)) + = Patch (Edit (TermF syntax ann1 recur) + (TermF syntax ann2 recur)) -- | An unchanged node, consisting of syntax labelled with both the original annotations. - | Merge (TermF syntax (ann1, ann2) recur) + | Merge (TermF syntax (ann1, ann2) recur) -- | Constructs a 'Diff' comparing one 'Term' with another recursively. comparing :: Functor syntax => Term syntax ann1 -> Term syntax ann2 -> Diff syntax ann1 ann2 @@ -75,7 +75,7 @@ merging :: Functor syntax => Term syntax ann -> Diff syntax ann ann merging = cata (\ (In ann syntax) -> mergeF (In (ann, ann) syntax)) -diffPatches :: (Foldable syntax, Functor syntax) => Diff syntax ann1 ann2 -> [Patch (TermF syntax ann1 (Diff syntax ann1 ann2)) (TermF syntax ann2 (Diff syntax ann1 ann2))] +diffPatches :: (Foldable syntax, Functor syntax) => Diff syntax ann1 ann2 -> [Edit (TermF syntax ann1 (Diff syntax ann1 ann2)) (TermF syntax ann2 (Diff syntax ann1 ann2))] diffPatches = para $ \ diff -> case diff of Patch patch -> bimap (fmap fst) (fmap fst) patch : bifoldMap (foldMap snd) (foldMap snd) patch Merge merge -> foldMap snd merge diff --git a/src/Data/Edit.hs b/src/Data/Edit.hs index 5500f2afa..053ef796d 100644 --- a/src/Data/Edit.hs +++ b/src/Data/Edit.hs @@ -1,6 +1,6 @@ {-# LANGUAGE LambdaCase #-} module Data.Edit -( Patch(..) +( Edit(..) , edit ) where @@ -13,7 +13,7 @@ import Data.These import GHC.Generics (Generic, Generic1) -- | An operation to compare, insert, or delete an item. -data Patch a b +data Edit a b = Delete a | Insert b | Compare a b @@ -21,39 +21,39 @@ data Patch a b -- | Return both sides of a patch. -edit :: (l -> a) -> (r -> a) -> (l -> r -> a) -> Patch l r -> a +edit :: (l -> a) -> (r -> a) -> (l -> r -> a) -> Edit l r -> a edit delete insert compare = \case Delete a -> delete a Insert b -> insert b Compare a b -> compare a b -instance Bifunctor Patch where +instance Bifunctor Edit where bimap = bimapDefault -instance Bifoldable Patch where +instance Bifoldable Edit where bifoldMap = bifoldMapDefault -instance Bitraversable Patch where +instance Bitraversable Edit where bitraverse f g = \case Delete a -> Delete <$> f a Insert b -> Insert <$> g b Compare a b -> Compare <$> f a <*> g b -instance Bicrosswalk Patch where +instance Bicrosswalk Edit where bicrosswalk f g = \case Delete a -> Delete <$> f a Insert b -> Insert <$> g b Compare a b -> alignWith (these Delete Insert Compare) (f a) (g b) -instance Eq2 Patch where +instance Eq2 Edit where liftEq2 eqBefore eqAfter p1 p2 = case (p1, p2) of (Delete a1, Delete a2) -> eqBefore a1 a2 (Insert b1, Insert b2) -> eqAfter b1 b2 (Compare a1 b1, Compare a2 b2) -> eqBefore a1 a2 && eqAfter b1 b2 _ -> False -instance Show2 Patch where +instance Show2 Edit where liftShowsPrec2 spl _ spr _ d = \case Delete a -> showsUnaryWith spl "Delete" d a Insert b -> showsUnaryWith spr "Insert" d b diff --git a/src/Data/JSON/Fields.hs b/src/Data/JSON/Fields.hs index e0c938eee..2556f62e7 100644 --- a/src/Data/JSON/Fields.hs +++ b/src/Data/JSON/Fields.hs @@ -58,7 +58,7 @@ instance ToJSONFields Span where instance ToJSONFields Loc where toJSONFields Loc{..} = toJSONFields byteRange <> toJSONFields span -instance (ToJSONFields a, ToJSONFields b) => ToJSONFields (Patch a b) where +instance (ToJSONFields a, ToJSONFields b) => ToJSONFields (Edit a b) where toJSONFields (Insert a) = [ "insert" .= object (toJSONFields a) ] toJSONFields (Delete a) = [ "delete" .= object (toJSONFields a) ] toJSONFields (Compare a b) = [ "replace" .= [object (toJSONFields a), object (toJSONFields b)] ] diff --git a/test/Data/Functor/Listable.hs b/test/Data/Functor/Listable.hs index 992407efd..ab28bf3b8 100644 --- a/test/Data/Functor/Listable.hs +++ b/test/Data/Functor/Listable.hs @@ -160,10 +160,10 @@ instance (Listable1 syntax, Listable ann1, Listable ann2) => Listable (Diff synt tiers = tiers2 -instance Listable2 Patch where +instance Listable2 Edit where liftTiers2 t1 t2 = liftCons1 t2 Insert \/ liftCons1 t1 Delete \/ liftCons2 t1 t2 Replace -instance (Listable a, Listable b) => Listable (Patch a b) where +instance (Listable a, Listable b) => Listable (Edit a b) where tiers = tiers2 diff --git a/test/Diffing/Interpreter/Spec.hs b/test/Diffing/Interpreter/Spec.hs index 1e42b1632..017251470 100644 --- a/test/Diffing/Interpreter/Spec.hs +++ b/test/Diffing/Interpreter/Spec.hs @@ -82,11 +82,11 @@ afterTerm = cata $ \ diff -> case diff of Merge (In (_, b) r) -> termIn b <$> sequenceAlt r -- | Return the item from the after side of the patch. -after :: Patch l r -> Maybe r +after :: Edit l r -> Maybe r after = edit (const Nothing) Just (\ _ b -> Just b) -- | Return the item from the before side of the patch. -before :: Patch l r -> Maybe l +before :: Edit l r -> Maybe l before = edit Just (const Nothing) (\ a _ -> Just a) emptyAnnotation :: () diff --git a/test/Rendering/TOC/Spec.hs b/test/Rendering/TOC/Spec.hs index 5d6a669cb..089de427c 100644 --- a/test/Rendering/TOC/Spec.hs +++ b/test/Rendering/TOC/Spec.hs @@ -39,7 +39,7 @@ spec = do prop "produces inserted/deleted/replaced entries for relevant nodes within patches" $ \ p -> tableOfContentsBy (Just . termFAnnotation) (patch deleting inserting comparing p) `shouldBe` - patch (fmap (Deleted,)) (fmap (Inserted,)) (\ as bs -> (Replaced, head bs) : fmap (Deleted,) (tail as) <> fmap (Inserted,) (tail bs)) (bimap (foldMap pure) (foldMap pure) (p :: Patch (Term ListableSyntax Int) (Term ListableSyntax Int))) + patch (fmap (Deleted,)) (fmap (Inserted,)) (\ as bs -> (Replaced, head bs) : fmap (Deleted,) (tail as) <> fmap (Inserted,) (tail bs)) (bimap (foldMap pure) (foldMap pure) (p :: Edit (Term ListableSyntax Int) (Term ListableSyntax Int))) prop "produces changed entries for relevant nodes containing irrelevant patches" $ \ diff -> do From b26c941b9c2f66ec271d37fa6a63442c7bd8c70f Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 17 Oct 2019 22:50:14 -0400 Subject: [PATCH 020/118] :fire: SES.Edit. --- src/Diffing/Algorithm/RWS.hs | 1 + src/Diffing/Algorithm/SES.hs | 18 ++---------------- src/Semantic/Api/TOCSummaries.hs | 7 ++++--- 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/src/Diffing/Algorithm/RWS.hs b/src/Diffing/Algorithm/RWS.hs index 1e63e0d18..9207fe822 100644 --- a/src/Diffing/Algorithm/RWS.hs +++ b/src/Diffing/Algorithm/RWS.hs @@ -16,6 +16,7 @@ module Diffing.Algorithm.RWS import Control.Monad.State.Strict import Data.Diff (DiffF(..), comparing, deleting, inserting, merge) +import Data.Edit import qualified Data.KdMap.Static as KdMap import Data.List (sortOn) import Data.Term as Term diff --git a/src/Diffing/Algorithm/SES.hs b/src/Diffing/Algorithm/SES.hs index 117a01cfa..4aeb1e090 100644 --- a/src/Diffing/Algorithm/SES.hs +++ b/src/Diffing/Algorithm/SES.hs @@ -1,30 +1,16 @@ {-# LANGUAGE BangPatterns, GADTs, LambdaCase, MultiParamTypeClasses, ScopedTypeVariables #-} module Diffing.Algorithm.SES -( Edit(..) -, toThese +( toThese , ses ) where import Data.Array ((!)) import qualified Data.Array as Array -import Data.Bifunctor +import Data.Edit import Data.Foldable (find, toList) import Data.Ix import Data.These --- | An edit script, i.e. a sequence of changes/copies of elements. -data Edit a b - = Delete a - | Insert b - | Compare a b - deriving (Eq, Functor, Ord, Show) - -instance Bifunctor Edit where - bimap f g = \case - Delete a -> Delete (f a) - Insert b -> Insert (g b) - Compare a b -> Compare (f a) (g b) - toThese :: Edit a b -> These a b toThese = \case Delete a -> This a diff --git a/src/Semantic/Api/TOCSummaries.hs b/src/Semantic/Api/TOCSummaries.hs index 9f05cc42b..d9eee1488 100644 --- a/src/Semantic/Api/TOCSummaries.hs +++ b/src/Semantic/Api/TOCSummaries.hs @@ -18,6 +18,7 @@ import Control.Monad.IO.Class import Data.Aeson import Data.Blob import Data.ByteString.Builder +import Data.Edit as Edit import Data.Either (partitionEithers) import Data.Function (on) import Data.Functor.Classes @@ -130,9 +131,9 @@ instance Tagging.ToTags t => SummarizeDiff (ViaTags t) where compare = liftA2 (&&) <$> ((==) `on` Tag.kind) <*> ((==) `on` Tag.name) toChange = \case - SES.Delete tag -> (Deleted,) <$> toDecl tag - SES.Insert tag -> (Inserted,) <$> toDecl tag - SES.Compare t1 t2 + Edit.Delete tag -> (Deleted,) <$> toDecl tag + Edit.Insert tag -> (Inserted,) <$> toDecl tag + Edit.Compare t1 t2 | Source.slice s1 (byteRange (Tag.loc t1)) /= Source.slice s2 (byteRange (Tag.loc t2)) -> (Changed,) <$> toDecl t2 | otherwise -> Nothing From 55ee8b4f7a3109c728168f290cfdd5975d9900ff Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 17 Oct 2019 22:53:21 -0400 Subject: [PATCH 021/118] Define a helper to diff an Edit of terms. --- src/Diffing/Algorithm.hs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Diffing/Algorithm.hs b/src/Diffing/Algorithm.hs index ea23cb983..480045e7d 100644 --- a/src/Diffing/Algorithm.hs +++ b/src/Diffing/Algorithm.hs @@ -6,6 +6,7 @@ module Diffing.Algorithm , Equivalence (..) , diff , diffThese + , diffEdit , diffMaybe , linearly , byReplacing @@ -17,6 +18,7 @@ module Diffing.Algorithm import Control.Effect.Carrier hiding ((:+:)) import Control.Effect.NonDet import qualified Data.Diff as Diff +import qualified Data.Edit as Edit import Data.Sum import Data.Term import GHC.Generics @@ -57,6 +59,10 @@ diff a1 a2 = send (Diff a1 a2 pure) diffThese :: (Carrier sig m, Member (Diff term1 term2 diff) sig) => These term1 term2 -> Algorithm term1 term2 diff m diff diffThese = these byDeleting byInserting diff +-- | Diff an 'Edit' of terms without specifying the algorithm to be used. +diffEdit :: (Carrier sig m, Member (Diff term1 term2 diff) sig) => Edit.Edit term1 term2 -> Algorithm term1 term2 diff m diff +diffEdit = Edit.edit byDeleting byInserting diff + -- | Diff a pair of optional terms without specifying the algorithm to be used. diffMaybe :: (Carrier sig m, Member (Diff term1 term2 diff) sig) => Maybe term1 -> Maybe term2 -> Algorithm term1 term2 diff m (Maybe diff) diffMaybe (Just a1) (Just a2) = Just <$> diff a1 a2 From 15fdc198bb99550704e8500c95a70c15629bb3c9 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 17 Oct 2019 22:53:35 -0400 Subject: [PATCH 022/118] =?UTF-8?q?Don=E2=80=99t=20convert=20to=20These.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/Diffing/Algorithm/SES/Spec.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Diffing/Algorithm/SES/Spec.hs b/test/Diffing/Algorithm/SES/Spec.hs index 1e573fcc4..aadc139f3 100644 --- a/test/Diffing/Algorithm/SES/Spec.hs +++ b/test/Diffing/Algorithm/SES/Spec.hs @@ -1,6 +1,6 @@ module Diffing.Algorithm.SES.Spec (spec) where -import Data.These +import Data.Edit import Diffing.Algorithm.SES import Test.Hspec import Test.Hspec.LeanCheck @@ -21,4 +21,4 @@ spec = do \ as bs -> length (ses (==) ((,) 0 <$> as :: [(Int, Char)]) ((,) 1 <$> bs :: [(Int, Char)])) `shouldBe` length as + length bs prop "is lossless w.r.t. both input elements & ordering" $ - \ as bs -> foldr (\ each (as, bs) -> these (flip (,) bs. (:as)) ((,) as . (:bs)) (\ a b -> (a:as, b:bs)) (toThese each)) ([], []) (ses (==) as bs :: [Edit Char Char]) `shouldBe` (as, bs) + \ as bs -> foldr (\ each (as, bs) -> edit (flip (,) bs. (:as)) ((,) as . (:bs)) (\ a b -> (a:as, b:bs)) each) ([], []) (ses (==) as bs :: [Edit Char Char]) `shouldBe` (as, bs) From 6f0c2a645001d9821cd914be08847b3db791c934 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 17 Oct 2019 22:53:45 -0400 Subject: [PATCH 023/118] Diff directly in Edit. --- src/Diffing/Interpreter.hs | 3 +-- test/Diffing/Algorithm/RWS/Spec.hs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Diffing/Interpreter.hs b/src/Diffing/Interpreter.hs index 73d874fdb..b2f85fe43 100644 --- a/src/Diffing/Interpreter.hs +++ b/src/Diffing/Interpreter.hs @@ -12,7 +12,6 @@ import qualified Data.Diff as Diff import Data.Term import Diffing.Algorithm import Diffing.Algorithm.RWS -import Diffing.Algorithm.SES (toThese) import Prologue -- | Diff two à la carte terms recursively. @@ -73,7 +72,7 @@ instance ( Alternative m eff (L op) = case op of Diff t1 t2 k -> runDiff (algorithmForTerms t1 t2) <|> pure (Diff.comparing t1 t2) >>= k Linear (Term (In ann1 f1)) (Term (In ann2 f2)) k -> Diff.merge (ann1, ann2) <$> tryAlignWith (runDiff . diffThese) f1 f2 >>= k - RWS as bs k -> traverse (runDiff . diffThese . toThese) (rws comparableTerms equivalentTerms as bs) >>= k + RWS as bs k -> traverse (runDiff . diffEdit) (rws comparableTerms equivalentTerms as bs) >>= k Delete a k -> k (Diff.deleting a) Insert b k -> k (Diff.inserting b) Replace a b k -> k (Diff.comparing a b) diff --git a/test/Diffing/Algorithm/RWS/Spec.hs b/test/Diffing/Algorithm/RWS/Spec.hs index 76bcaa970..b0166b1bc 100644 --- a/test/Diffing/Algorithm/RWS/Spec.hs +++ b/test/Diffing/Algorithm/RWS/Spec.hs @@ -31,7 +31,7 @@ spec = do \ (as, bs) -> let tas = decorate <$> (as :: [Term ListableSyntax ()]) tbs = decorate <$> (bs :: [Term ListableSyntax ()]) wrap = termIn emptyAnnotation . inject - diff = merge (emptyAnnotation, emptyAnnotation) (inject (stripDiff . diffThese . toThese <$> rws comparableTerms (equalTerms comparableTerms) tas tbs)) in + diff = merge (emptyAnnotation, emptyAnnotation) (inject (stripDiff . diffEdit <$> rws comparableTerms (equalTerms comparableTerms) tas tbs)) in (beforeTerm diff, afterTerm diff) `shouldBe` (Just (wrap (stripTerm <$> tas)), Just (wrap (stripTerm <$> tbs))) it "produces unbiased insertions within branches" $ From 88c12a963ba698ce6c34cb58773c6609731a4ed1 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 17 Oct 2019 22:54:16 -0400 Subject: [PATCH 024/118] :fire: toThese. --- src/Diffing/Algorithm/SES.hs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/Diffing/Algorithm/SES.hs b/src/Diffing/Algorithm/SES.hs index 4aeb1e090..0748c3a7c 100644 --- a/src/Diffing/Algorithm/SES.hs +++ b/src/Diffing/Algorithm/SES.hs @@ -1,7 +1,6 @@ {-# LANGUAGE BangPatterns, GADTs, LambdaCase, MultiParamTypeClasses, ScopedTypeVariables #-} module Diffing.Algorithm.SES -( toThese -, ses +( ses ) where import Data.Array ((!)) @@ -9,13 +8,6 @@ import qualified Data.Array as Array import Data.Edit import Data.Foldable (find, toList) import Data.Ix -import Data.These - -toThese :: Edit a b -> These a b -toThese = \case - Delete a -> This a - Insert b -> That b - Compare a b -> These a b data Endpoint a b = Endpoint { x :: {-# UNPACK #-} !Int, _y :: {-# UNPACK #-} !Int, _script :: [Edit a b] } deriving (Eq, Show) From 29ceb4c8d640a6921960e14ebb12a723c1baeb3a Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 10:26:20 -0400 Subject: [PATCH 025/118] =?UTF-8?q?Don=E2=80=99t=20export=20Both=20in=20th?= =?UTF-8?q?e=20Prologue.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Prologue.hs | 1 - src/Semantic/CLI.hs | 1 + src/Semantic/Task/Files.hs | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Prologue.hs b/src/Prologue.hs index 8e18e082e..d1d429e6d 100644 --- a/src/Prologue.hs +++ b/src/Prologue.hs @@ -16,7 +16,6 @@ import Data.Bits as X import Data.ByteString as X (ByteString) import Data.Coerce as X import Data.Int as X (Int8, Int16, Int32, Int64) -import Data.Functor.Both as X (Both (Both), runBothWith) import Data.Either as X (fromLeft, fromRight) import Data.IntMap as X (IntMap) import Data.IntSet as X (IntSet) diff --git a/src/Semantic/CLI.hs b/src/Semantic/CLI.hs index 57e5687ee..254ef3c71 100644 --- a/src/Semantic/CLI.hs +++ b/src/Semantic/CLI.hs @@ -7,6 +7,7 @@ import Control.Exception as Exc (displayException) import Data.Blob import Data.Blob.IO import qualified Data.ByteString.Char8 as B +import Data.Functor.Both import Data.Handle import qualified Data.Language as Language import Data.List (intercalate) diff --git a/src/Semantic/Task/Files.hs b/src/Semantic/Task/Files.hs index 222e45479..7b7ee4e83 100644 --- a/src/Semantic/Task/Files.hs +++ b/src/Semantic/Task/Files.hs @@ -23,6 +23,7 @@ import Control.Effect.Error import Data.Blob import Data.Blob.IO import qualified Data.ByteString.Builder as B +import Data.Functor.Both import Data.Handle import Data.Language import Data.Project From b8b9105a0a3f32a0e739bb4100215120844c12bb Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 10:27:42 -0400 Subject: [PATCH 026/118] Define readFilePathPair as a composition. --- test/SpecHelpers.hs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/SpecHelpers.hs b/test/SpecHelpers.hs index 4e965f23e..ebceb714b 100644 --- a/test/SpecHelpers.hs +++ b/test/SpecHelpers.hs @@ -105,8 +105,7 @@ runParseWithConfig task = asks configTreeSitterParseTimeout >>= \ timeout -> run -- | Read two files to a BlobPair. readFilePathPair :: Both Path.RelFile -> IO BlobPair -readFilePathPair paths = let paths' = fmap fileForTypedPath paths in - runBothWith readFilePair paths' +readFilePathPair = runBothWith readFilePair . fmap fileForTypedPath parseTestFile :: Parser term -> Path.RelFile -> IO (Blob, term) parseTestFile parser path = runTaskOrDie $ do From 9ef511b6f11b59b113e176d1fbf0bdac976fce66 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 10:29:43 -0400 Subject: [PATCH 027/118] Write diffFilePaths using do notation. --- test/SpecHelpers.hs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/SpecHelpers.hs b/test/SpecHelpers.hs index ebceb714b..cef81e296 100644 --- a/test/SpecHelpers.hs +++ b/test/SpecHelpers.hs @@ -88,10 +88,10 @@ instance IsString Name where -- | Returns an s-expression formatted diff for the specified FilePath pair. diffFilePaths :: TaskSession -> Both Path.RelFile -> IO ByteString -diffFilePaths session paths - = readFilePathPair paths - >>= runTask session . runParse (configTreeSitterParseTimeout (config session)) . parseDiffBuilder @[] DiffSExpression . pure - >>= either (die . displayException) (pure . runBuilder) +diffFilePaths session paths = do + blobs <- readFilePathPair paths + builder <- runTask session (runParse (configTreeSitterParseTimeout (config session)) (parseDiffBuilder DiffSExpression [ blobs ])) + either (die . displayException) (pure . runBuilder) builder -- | Returns an s-expression parse tree for the specified path. parseFilePath :: TaskSession -> Path.RelFile -> IO (Either SomeException ByteString) From 86389e8e873703b5250b6f81ca49609ad2bd7546 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 10:33:47 -0400 Subject: [PATCH 028/118] Re-export Edit. --- test/Diffing/Interpreter/Spec.hs | 3 +-- test/Rendering/TOC/Spec.hs | 1 - test/SpecHelpers.hs | 1 + 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/test/Diffing/Interpreter/Spec.hs b/test/Diffing/Interpreter/Spec.hs index 017251470..01f85eb90 100644 --- a/test/Diffing/Interpreter/Spec.hs +++ b/test/Diffing/Interpreter/Spec.hs @@ -3,7 +3,6 @@ module Diffing.Interpreter.Spec (spec, afterTerm, beforeTerm) where import Control.Applicative ((<|>)) import Data.Diff -import Data.Edit (edit) import Data.Foldable (asum) import Data.Functor.Foldable (cata) import Data.Functor.Listable @@ -18,7 +17,7 @@ import Test.Hspec (Spec, describe, it) import Test.Hspec.Expectations import Test.Hspec.LeanCheck import Test.LeanCheck.Core -import SpecHelpers () +import SpecHelpers (edit) spec :: Spec spec = do diff --git a/test/Rendering/TOC/Spec.hs b/test/Rendering/TOC/Spec.hs index 089de427c..bf5c4a01a 100644 --- a/test/Rendering/TOC/Spec.hs +++ b/test/Rendering/TOC/Spec.hs @@ -7,7 +7,6 @@ import Control.Effect.Reader import Data.Aeson hiding (defaultOptions) import Data.Bifunctor import Data.Diff -import Data.Edit import Data.Either (isRight) import Data.Sum import Data.Term diff --git a/test/SpecHelpers.hs b/test/SpecHelpers.hs index cef81e296..b75e267ca 100644 --- a/test/SpecHelpers.hs +++ b/test/SpecHelpers.hs @@ -61,6 +61,7 @@ import Debug.Trace as X (traceShowM, traceM) import Data.ByteString as X (ByteString) import Data.Functor.Both as X (Both (Both), runBothWith) +import Data.Edit as X import Data.Maybe as X import Data.Monoid as X (Monoid(..), First(..), Last(..)) import Data.Semigroup as X (Semigroup(..)) From e2cc2790cc928e28fbf544e22df2ab9dbd95a452 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 10:36:47 -0400 Subject: [PATCH 029/118] Fix some doc comments. --- test/Rendering/TOC/Spec.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Rendering/TOC/Spec.hs b/test/Rendering/TOC/Spec.hs index bf5c4a01a..003e7fbf1 100644 --- a/test/Rendering/TOC/Spec.hs +++ b/test/Rendering/TOC/Spec.hs @@ -160,14 +160,14 @@ type Term' = Term ListableSyntax (Maybe Declaration) numTocSummaries :: Diff' -> Int numTocSummaries diff = length $ filter isRight (diffTOC diff) --- Return a diff where body is inserted in the expressions of a function. The function is present in Both sides of the diff. +-- Return a diff where body is inserted in the expressions of a function. The function is present in both sides of the diff. programWithChange :: Term' -> Diff' programWithChange body = merge (Nothing, Nothing) (inject [ function' ]) where function' = merge (Just (Declaration Function "foo" lowerBound Ruby), Just (Declaration Function "foo" lowerBound Ruby)) (inject (Declaration.Function [] name' [] (merge (Nothing, Nothing) (inject [ inserting body ])))) name' = merge (Nothing, Nothing) (inject (Syntax.Identifier (name "foo"))) --- Return a diff where term is inserted in the program, below a function found on Both sides of the diff. +-- Return a diff where term is inserted in the program, below a function found on both sides of the diff. programWithChangeOutsideFunction :: Term' -> Diff' programWithChangeOutsideFunction term = merge (Nothing, Nothing) (inject [ function', term' ]) where From 6606d528419bd06d41d6b5f1b2ea6934402615f9 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 10:45:59 -0400 Subject: [PATCH 030/118] Eliminate uses of Both. --- src/Semantic/CLI.hs | 3 +-- src/Semantic/Task/Files.hs | 9 ++++----- test/Integration/Spec.hs | 2 +- test/Rendering/TOC/Spec.hs | 27 ++++++++++++++------------- test/Semantic/CLI/Spec.hs | 6 +++--- test/SpecHelpers.hs | 11 +++++------ 6 files changed, 28 insertions(+), 30 deletions(-) diff --git a/src/Semantic/CLI.hs b/src/Semantic/CLI.hs index 254ef3c71..8960baa86 100644 --- a/src/Semantic/CLI.hs +++ b/src/Semantic/CLI.hs @@ -7,7 +7,6 @@ import Control.Exception as Exc (displayException) import Data.Blob import Data.Blob.IO import qualified Data.ByteString.Char8 as B -import Data.Functor.Both import Data.Handle import qualified Data.Language as Language import Data.List (intercalate) @@ -100,7 +99,7 @@ diffCommand = command "diff" (info diffArgumentsParser (progDesc "Compute change <|> flag' (diffSummaryBuilder JSON) (long "toc" <> help "Output JSON table of contents diff summary") <|> flag' (parseDiffBuilder DiffDotGraph) (long "dot" <> help "Output the diff as a DOT graph") <|> flag' (parseDiffBuilder DiffShow) (long "show" <> help "Output using the Show instance (debug only, format subject to change without notice)") - filesOrStdin <- Right <$> some (Both <$> argument filePathReader (metavar "FILE_A") <*> argument filePathReader (metavar "FILE_B")) <|> pure (Left stdin) + filesOrStdin <- Right <$> some ((,) <$> argument filePathReader (metavar "FILE_A") <*> argument filePathReader (metavar "FILE_B")) <|> pure (Left stdin) pure $ Task.readBlobPairs filesOrStdin >>= runReader languageModes . renderer parseCommand :: Mod CommandFields (Parse.ParseC Task.TaskC Builder) diff --git a/src/Semantic/Task/Files.hs b/src/Semantic/Task/Files.hs index 7b7ee4e83..5a1564437 100644 --- a/src/Semantic/Task/Files.hs +++ b/src/Semantic/Task/Files.hs @@ -23,7 +23,6 @@ import Control.Effect.Error import Data.Blob import Data.Blob.IO import qualified Data.ByteString.Builder as B -import Data.Functor.Both import Data.Handle import Data.Language import Data.Project @@ -40,7 +39,7 @@ data Source blob where FromHandle :: Handle 'IO.ReadMode -> Source [Blob] FromDir :: Path.AbsRelDir -> Source [Blob] FromGitRepo :: FilePath -> Git.OID -> PathFilter -> Source [Blob] - FromPathPair :: Both File -> Source BlobPair + FromPathPair :: File -> File -> Source BlobPair FromPairHandle :: Handle 'IO.ReadMode -> Source [BlobPair] data Destination = ToPath Path.AbsRelFile | ToHandle (Handle 'IO.WriteMode) @@ -89,7 +88,7 @@ instance (Member (Error SomeException) sig, Member Catch sig, MonadIO m, Carrier Read (FromGitRepo path sha (ExcludeFromHandle handle)) k -> rethrowing (readPathsFromHandle handle >>= (\x -> readBlobsFromGitRepo path sha x mempty)) >>= k Read (FromGitRepo path sha (IncludePaths includePaths)) k -> rethrowing (readBlobsFromGitRepo path sha mempty includePaths) >>= k Read (FromGitRepo path sha (IncludePathsFromHandle h)) k -> rethrowing (readPathsFromHandle h >>= readBlobsFromGitRepo path sha mempty) >>= k - Read (FromPathPair paths) k -> rethrowing (runBothWith readFilePair paths) >>= k + Read (FromPathPair p1 p2) k -> rethrowing (readFilePair p1 p2) >>= k Read (FromPairHandle handle) k -> rethrowing (readBlobPairsFromHandle handle) >>= k ReadProject rootDir dir language excludeDirs k -> rethrowing (readProjectFromPaths rootDir dir language excludeDirs) >>= k FindFiles dir exts excludeDirs k -> rethrowing (findFilesInDir dir exts excludeDirs) >>= k @@ -117,9 +116,9 @@ readBlobs (FilesFromPaths paths) = traverse (send . flip Read pure . FromPath) p readBlobs (FilesFromGitRepo path sha filter) = send (Read (FromGitRepo path sha filter) pure) -- | A task which reads a list of pairs of 'Blob's from a 'Handle' or a list of pairs of 'FilePath's optionally paired with 'Language's. -readBlobPairs :: (Member Files sig, Carrier sig m) => Either (Handle 'IO.ReadMode) [Both File] -> m [BlobPair] +readBlobPairs :: (Member Files sig, Carrier sig m) => Either (Handle 'IO.ReadMode) [(File, File)] -> m [BlobPair] readBlobPairs (Left handle) = send (Read (FromPairHandle handle) pure) -readBlobPairs (Right paths) = traverse (send . flip Read pure . FromPathPair) paths +readBlobPairs (Right paths) = traverse (send . flip Read pure . uncurry FromPathPair) paths readProject :: (Member Files sig, Carrier sig m) => Maybe FilePath -> FilePath -> Language -> [FilePath] -> m Project readProject rootDir dir lang excludeDirs = send (ReadProject rootDir dir lang excludeDirs pure) diff --git a/test/Integration/Spec.hs b/test/Integration/Spec.hs index 5eb79e8bb..29c317ef1 100644 --- a/test/Integration/Spec.hs +++ b/test/Integration/Spec.hs @@ -39,7 +39,7 @@ testForExample = \case ("diffs " <> Path.toString diffOutput) (\ref new -> ["git", "diff", ref, new]) (Path.toString diffOutput) - (BL.fromStrict <$> diffFilePaths ?session (Both fileA fileB)) + (BL.fromStrict <$> diffFilePaths ?session fileA fileB) ParseExample{file, parseOutput} -> goldenVsStringDiff ("parses " <> Path.toString parseOutput) diff --git a/test/Rendering/TOC/Spec.hs b/test/Rendering/TOC/Spec.hs index 003e7fbf1..dc65a1ec7 100644 --- a/test/Rendering/TOC/Spec.hs +++ b/test/Rendering/TOC/Spec.hs @@ -52,7 +52,7 @@ spec = do diffTOC blankDiff `shouldBe` [ ] it "summarizes changed methods" $ do - sourceBlobs <- blobsForPaths (Both (Path.relFile "ruby/toc/methods.A.rb") (Path.relFile "ruby/toc/methods.B.rb")) + sourceBlobs <- blobsForPaths (Path.relFile "ruby/toc/methods.A.rb") (Path.relFile "ruby/toc/methods.B.rb") diff <- runTaskOrDie $ summarize sourceBlobs diff `shouldBe` [ Right $ TOCSummary (Method (Just "self")) "self.foo" (Span (Pos 1 1) (Pos 2 4)) Inserted @@ -61,37 +61,37 @@ spec = do ] it "dedupes changes in same parent method" $ do - sourceBlobs <- blobsForPaths (Both (Path.relFile "javascript/toc/duplicate-parent.A.js") (Path.relFile "javascript/toc/duplicate-parent.B.js")) + sourceBlobs <- blobsForPaths (Path.relFile "javascript/toc/duplicate-parent.A.js") (Path.relFile "javascript/toc/duplicate-parent.B.js") diff <- runTaskOrDie $ summarize sourceBlobs diff `shouldBe` [ Right $ TOCSummary Function "myFunction" (Span (Pos 1 1) (Pos 6 2)) Changed ] it "dedupes similar methods" $ do - sourceBlobs <- blobsForPaths (Both (Path.relFile "javascript/toc/erroneous-duplicate-method.A.js") (Path.relFile "javascript/toc/erroneous-duplicate-method.B.js")) + sourceBlobs <- blobsForPaths (Path.relFile "javascript/toc/erroneous-duplicate-method.A.js") (Path.relFile "javascript/toc/erroneous-duplicate-method.B.js") diff <- runTaskOrDie $ summarize sourceBlobs diff `shouldBe` [ Right $ TOCSummary Function "performHealthCheck" (Span (Pos 8 1) (Pos 29 2)) Replaced ] it "summarizes Go methods with receivers with special formatting" $ do - sourceBlobs <- blobsForPaths (Both (Path.relFile "go/toc/method-with-receiver.A.go") (Path.relFile "go/toc/method-with-receiver.B.go")) + sourceBlobs <- blobsForPaths (Path.relFile "go/toc/method-with-receiver.A.go") (Path.relFile "go/toc/method-with-receiver.B.go") diff <- runTaskOrDie $ summarize sourceBlobs diff `shouldBe` [ Right $ TOCSummary (Method (Just "*apiClient")) "(*apiClient) CheckAuth" (Span (Pos 3 1) (Pos 3 101)) Inserted ] it "summarizes Ruby methods that start with two identifiers" $ do - sourceBlobs <- blobsForPaths (Both (Path.relFile "ruby/toc/method-starts-with-two-identifiers.A.rb") (Path.relFile "ruby/toc/method-starts-with-two-identifiers.B.rb")) + sourceBlobs <- blobsForPaths (Path.relFile "ruby/toc/method-starts-with-two-identifiers.A.rb") (Path.relFile "ruby/toc/method-starts-with-two-identifiers.B.rb") diff <- runTaskOrDie $ summarize sourceBlobs diff `shouldBe` [ Right $ TOCSummary (Method Nothing) "foo" (Span (Pos 1 1) (Pos 4 4)) Changed ] it "handles unicode characters in file" $ do - sourceBlobs <- blobsForPaths (Both (Path.relFile "ruby/toc/unicode.A.rb") (Path.relFile "ruby/toc/unicode.B.rb")) + sourceBlobs <- blobsForPaths (Path.relFile "ruby/toc/unicode.A.rb") (Path.relFile "ruby/toc/unicode.B.rb") diff <- runTaskOrDie $ summarize sourceBlobs diff `shouldBe` [ Right $ TOCSummary (Method Nothing) "foo" (Span (Pos 6 1) (Pos 7 4)) Inserted ] it "properly slices source blob that starts with a newline and has multi-byte chars" $ do - sourceBlobs <- blobsForPaths (Both (Path.relFile "javascript/toc/starts-with-newline.js") (Path.relFile "javascript/toc/starts-with-newline.js")) + sourceBlobs <- blobsForPaths (Path.relFile "javascript/toc/starts-with-newline.js") (Path.relFile "javascript/toc/starts-with-newline.js") diff <- runTaskOrDie $ summarize sourceBlobs diff `shouldBe` [] @@ -134,22 +134,22 @@ spec = do describe "diff with ToCDiffRenderer'" $ do it "produces JSON output" $ do - blobs <- blobsForPaths (Both (Path.relFile "ruby/toc/methods.A.rb") (Path.relFile "ruby/toc/methods.B.rb")) + blobs <- blobsForPaths (Path.relFile "ruby/toc/methods.A.rb") (Path.relFile "ruby/toc/methods.B.rb") output <- runTaskOrDie (runReader defaultLanguageModes (diffSummaryBuilder Format.JSON [blobs])) runBuilder output `shouldBe` ("{\"files\":[{\"path\":\"test/fixtures/ruby/toc/methods.A.rb -> test/fixtures/ruby/toc/methods.B.rb\",\"language\":\"Ruby\",\"changes\":[{\"category\":\"Method\",\"term\":\"self.foo\",\"span\":{\"start\":{\"line\":1,\"column\":1},\"end\":{\"line\":2,\"column\":4}},\"changeType\":\"ADDED\"},{\"category\":\"Method\",\"term\":\"bar\",\"span\":{\"start\":{\"line\":4,\"column\":1},\"end\":{\"line\":6,\"column\":4}},\"changeType\":\"MODIFIED\"},{\"category\":\"Method\",\"term\":\"baz\",\"span\":{\"start\":{\"line\":4,\"column\":1},\"end\":{\"line\":5,\"column\":4}},\"changeType\":\"REMOVED\"}]}]}\n" :: ByteString) it "produces JSON output if there are parse errors" $ do - blobs <- blobsForPaths (Both (Path.relFile "ruby/toc/methods.A.rb") (Path.relFile "ruby/toc/methods.X.rb")) + blobs <- blobsForPaths (Path.relFile "ruby/toc/methods.A.rb") (Path.relFile "ruby/toc/methods.X.rb") output <- runTaskOrDie (runReader defaultLanguageModes (diffSummaryBuilder Format.JSON [blobs])) runBuilder output `shouldBe` ("{\"files\":[{\"path\":\"test/fixtures/ruby/toc/methods.A.rb -> test/fixtures/ruby/toc/methods.X.rb\",\"language\":\"Ruby\",\"changes\":[{\"category\":\"Method\",\"term\":\"bar\",\"span\":{\"start\":{\"line\":1,\"column\":1},\"end\":{\"line\":2,\"column\":4}},\"changeType\":\"REMOVED\"},{\"category\":\"Method\",\"term\":\"baz\",\"span\":{\"start\":{\"line\":4,\"column\":1},\"end\":{\"line\":5,\"column\":4}},\"changeType\":\"REMOVED\"}],\"errors\":[{\"error\":\"expected end of input nodes, but got ParseError\",\"span\":{\"start\":{\"line\":1,\"column\":1},\"end\":{\"line\":2,\"column\":3}}}]}]}\n" :: ByteString) it "ignores anonymous functions" $ do - blobs <- blobsForPaths (Both (Path.relFile "ruby/toc/lambda.A.rb") (Path.relFile "ruby/toc/lambda.B.rb")) + blobs <- blobsForPaths (Path.relFile "ruby/toc/lambda.A.rb") (Path.relFile "ruby/toc/lambda.B.rb") output <- runTaskOrDie (runReader defaultLanguageModes (diffSummaryBuilder Format.JSON [blobs])) runBuilder output `shouldBe` ("{\"files\":[{\"path\":\"test/fixtures/ruby/toc/lambda.A.rb -> test/fixtures/ruby/toc/lambda.B.rb\",\"language\":\"Ruby\"}]}\n" :: ByteString) it "summarizes Markdown headings" $ do - blobs <- blobsForPaths (Both (Path.relFile "markdown/toc/headings.A.md") (Path.relFile "markdown/toc/headings.B.md")) + blobs <- blobsForPaths (Path.relFile "markdown/toc/headings.A.md") (Path.relFile "markdown/toc/headings.B.md") output <- runTaskOrDie (runReader defaultLanguageModes (diffSummaryBuilder Format.JSON [blobs])) runBuilder output `shouldBe` ("{\"files\":[{\"path\":\"test/fixtures/markdown/toc/headings.A.md -> test/fixtures/markdown/toc/headings.B.md\",\"language\":\"Markdown\",\"changes\":[{\"category\":\"Heading 1\",\"term\":\"Introduction\",\"span\":{\"start\":{\"line\":1,\"column\":1},\"end\":{\"line\":3,\"column\":16}},\"changeType\":\"REMOVED\"},{\"category\":\"Heading 2\",\"term\":\"Two\",\"span\":{\"start\":{\"line\":5,\"column\":1},\"end\":{\"line\":7,\"column\":4}},\"changeType\":\"MODIFIED\"},{\"category\":\"Heading 3\",\"term\":\"This heading is new\",\"span\":{\"start\":{\"line\":9,\"column\":1},\"end\":{\"line\":11,\"column\":10}},\"changeType\":\"ADDED\"},{\"category\":\"Heading 1\",\"term\":\"Final\",\"span\":{\"start\":{\"line\":13,\"column\":1},\"end\":{\"line\":14,\"column\":4}},\"changeType\":\"ADDED\"}]}]}\n" :: ByteString) @@ -207,8 +207,9 @@ isMethodOrFunction a | any isJust (foldMap (:[]) a) = True | otherwise = False -blobsForPaths :: Both Path.RelFile -> IO BlobPair -blobsForPaths = readFilePathPair . fmap (Path.relDir "test/fixtures" ) +blobsForPaths :: Path.RelFile -> Path.RelFile -> IO BlobPair +blobsForPaths p1 p2 = readFilePathPair (prefix p1) (prefix p2) where + prefix = (Path.relDir "test/fixtures" ) blankDiff :: Diff' blankDiff = merge (Nothing, Nothing) (inject [ inserting (termIn Nothing (inject (Syntax.Identifier (name "\"a\"")))) ]) diff --git a/test/Semantic/CLI/Spec.hs b/test/Semantic/CLI/Spec.hs index 7d5c7d800..c95b6c1e7 100644 --- a/test/Semantic/CLI/Spec.hs +++ b/test/Semantic/CLI/Spec.hs @@ -34,7 +34,7 @@ renderDiff ref new = unsafePerformIO $ do else ["git", "diff", ref, new] {-# NOINLINE renderDiff #-} -testForDiffFixture :: (String, [BlobPair] -> ParseC TaskC Builder, [Both File], Path.RelFile) -> TestTree +testForDiffFixture :: (String, [BlobPair] -> ParseC TaskC Builder, [(File, File)], Path.RelFile) -> TestTree testForDiffFixture (diffRenderer, runDiff, files, expected) = goldenVsStringDiff ("diff fixture renders to " <> diffRenderer <> " " <> show files) @@ -65,12 +65,12 @@ parseFixtures = prefix = Path.relDir "test/fixtures/cli" run = runReader (PerLanguageModes ALaCarte) -diffFixtures :: [(String, [BlobPair] -> ParseC TaskC Builder, [Both File], Path.RelFile)] +diffFixtures :: [(String, [BlobPair] -> ParseC TaskC Builder, [(File, File)], Path.RelFile)] diffFixtures = [ ("json diff", parseDiffBuilder DiffJSONTree, pathMode, prefix Path.file "diff-tree.json") , ("s-expression diff", parseDiffBuilder DiffSExpression, pathMode, Path.relFile "test/fixtures/ruby/corpus/method-declaration.diffA-B.txt") , ("toc summaries diff", runReader defaultLanguageModes . diffSummaryBuilder Serializing.Format.JSON, pathMode, prefix Path.file "diff-tree.toc.json") , ("protobuf diff", runReader defaultLanguageModes . diffSummaryBuilder Serializing.Format.Proto, pathMode, prefix Path.file "diff-tree.toc.protobuf.bin") ] - where pathMode = [Both (File "test/fixtures/ruby/corpus/method-declaration.A.rb" Ruby) (File "test/fixtures/ruby/corpus/method-declaration.B.rb" Ruby)] + where pathMode = [(File "test/fixtures/ruby/corpus/method-declaration.A.rb" Ruby, File "test/fixtures/ruby/corpus/method-declaration.B.rb" Ruby)] prefix = Path.relDir "test/fixtures/cli" diff --git a/test/SpecHelpers.hs b/test/SpecHelpers.hs index b75e267ca..1a9f5873e 100644 --- a/test/SpecHelpers.hs +++ b/test/SpecHelpers.hs @@ -60,7 +60,6 @@ import Source.Span as X hiding (HasSpan(..), start, end, point) import Debug.Trace as X (traceShowM, traceM) import Data.ByteString as X (ByteString) -import Data.Functor.Both as X (Both (Both), runBothWith) import Data.Edit as X import Data.Maybe as X import Data.Monoid as X (Monoid(..), First(..), Last(..)) @@ -88,9 +87,9 @@ instance IsString Name where fromString = X.name . fromString -- | Returns an s-expression formatted diff for the specified FilePath pair. -diffFilePaths :: TaskSession -> Both Path.RelFile -> IO ByteString -diffFilePaths session paths = do - blobs <- readFilePathPair paths +diffFilePaths :: TaskSession -> Path.RelFile -> Path.RelFile -> IO ByteString +diffFilePaths session p1 p2 = do + blobs <- readFilePathPair p1 p2 builder <- runTask session (runParse (configTreeSitterParseTimeout (config session)) (parseDiffBuilder DiffSExpression [ blobs ])) either (die . displayException) (pure . runBuilder) builder @@ -105,8 +104,8 @@ runParseWithConfig :: (Carrier sig m, Member (Reader Config) sig) => ParseC m a runParseWithConfig task = asks configTreeSitterParseTimeout >>= \ timeout -> runParse timeout task -- | Read two files to a BlobPair. -readFilePathPair :: Both Path.RelFile -> IO BlobPair -readFilePathPair = runBothWith readFilePair . fmap fileForTypedPath +readFilePathPair :: Path.RelFile -> Path.RelFile -> IO BlobPair +readFilePathPair p1 p2 = readFilePair (fileForTypedPath p1) (fileForTypedPath p2) parseTestFile :: Parser term -> Path.RelFile -> IO (Blob, term) parseTestFile parser path = runTaskOrDie $ do From 50c53c242fd4a1ccae475390ab805084bbd74375 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 10:46:41 -0400 Subject: [PATCH 031/118] :fire: the Listable1 instance for Both. --- test/Data/Functor/Listable.hs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/Data/Functor/Listable.hs b/test/Data/Functor/Listable.hs index ab28bf3b8..16dabf916 100644 --- a/test/Data/Functor/Listable.hs +++ b/test/Data/Functor/Listable.hs @@ -21,7 +21,6 @@ import Data.Abstract.ScopeGraph (AccessControl(..)) import Data.Bifunctor.Join import Data.Diff import Data.Edit -import Data.Functor.Both import qualified Data.Language as Language import Data.List.NonEmpty import qualified Data.Syntax as Syntax @@ -122,9 +121,6 @@ instance Listable1 NonEmpty where instance Listable2 p => Listable1 (Join p) where liftTiers tiers = liftCons1 (liftTiers2 tiers tiers) Join -instance Listable1 Both where - liftTiers tiers = liftCons2 tiers tiers Both - instance Listable1 f => Listable2 (TermF f) where liftTiers2 annotationTiers recurTiers = liftCons2 annotationTiers (liftTiers recurTiers) In From 9cce18a9217ab3edce78e848cebbd077f1606d93 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 10:46:45 -0400 Subject: [PATCH 032/118] :fire: Both. --- semantic.cabal | 1 - src/Data/Functor/Both.hs | 23 ----------------------- 2 files changed, 24 deletions(-) delete mode 100644 src/Data/Functor/Both.hs diff --git a/semantic.cabal b/semantic.cabal index ee1eb1796..199995996 100644 --- a/semantic.cabal +++ b/semantic.cabal @@ -151,7 +151,6 @@ library , Data.Edit , Data.Error , Data.Flag - , Data.Functor.Both , Data.Functor.Classes.Generic , Data.Graph , Data.Graph.ControlFlowVertex diff --git a/src/Data/Functor/Both.hs b/src/Data/Functor/Both.hs deleted file mode 100644 index 09658aea3..000000000 --- a/src/Data/Functor/Both.hs +++ /dev/null @@ -1,23 +0,0 @@ -{-# LANGUAGE DerivingVia #-} - -module Data.Functor.Both -( Both (..) -, runBothWith -) where - -import Data.Functor.Classes -import Data.Functor.Classes.Generic -import Data.Monoid.Generic -import GHC.Generics - --- | A computation over both sides of a pair. -data Both a = Both a a - deriving (Eq, Show, Ord, Functor, Foldable, Traversable, Generic1, Generic) - deriving Semigroup via GenericSemigroup (Both a) - deriving Monoid via GenericMonoid (Both a) - deriving (Eq1, Show1, Ord1) via Generically Both - --- | Apply a function to `Both` sides of a computation. --- The eliminator/catamorphism over 'Both'. -runBothWith :: (a -> a -> b) -> Both a -> b -runBothWith f (Both a b) = f a b From 759ca6d3cc5f3926f547a6afc7cec92c81f73774 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 10:58:36 -0400 Subject: [PATCH 033/118] Define BlobPair using Edit. --- src/Control/Effect/Parse.hs | 3 ++- src/Data/Blob.hs | 17 +++++++++-------- src/Rendering/JSON.hs | 5 ++--- src/Semantic/Api/Diffs.hs | 3 ++- src/Semantic/Api/TOCSummaries.hs | 4 ++-- 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/Control/Effect/Parse.hs b/src/Control/Effect/Parse.hs index 747151e12..2e4a67484 100644 --- a/src/Control/Effect/Parse.hs +++ b/src/Control/Effect/Parse.hs @@ -12,6 +12,7 @@ import Control.Effect.Error import Control.Exception (SomeException) import Data.Bitraversable import Data.Blob +import Data.Edit import Data.Language import qualified Data.Map as Map import Data.These @@ -56,6 +57,6 @@ parsePairWith -> BlobPair -- ^ The blob pair to parse. -> m a parsePairWith parsers with blobPair = case Map.lookup (languageForBlobPair blobPair) parsers of - Just (SomeParser parser) -> bitraverse (p parser) (p parser) (getBlobPair blobPair) >>= with + Just (SomeParser parser) -> bitraverse (p parser) (p parser) (getBlobPair blobPair) >>= with . edit This That These _ -> noLanguageForBlob (pathForBlobPair blobPair) where p parser blob = (,) blob <$> parse parser blob diff --git a/src/Data/Blob.hs b/src/Data/Blob.hs index d63caf0a6..03e784c8c 100644 --- a/src/Data/Blob.hs +++ b/src/Data/Blob.hs @@ -30,6 +30,7 @@ import Prologue import Control.Effect.Error import Data.Aeson import qualified Data.ByteString.Lazy as BL +import Data.Edit import Data.JSON.Fields import Data.Language import Source.Source (Source) @@ -101,7 +102,7 @@ noLanguageForBlob blobPath = throwError (SomeException (NoLanguageForBlob blobPa -- | Represents a blobs suitable for diffing which can be either a blob to -- delete, a blob to insert, or a pair of blobs to diff. -newtype BlobPair = BlobPair { getBlobPair :: These Blob Blob } +newtype BlobPair = BlobPair { getBlobPair :: Edit Blob Blob } deriving (Eq, Show) instance FromJSON BlobPair where @@ -115,13 +116,13 @@ instance FromJSON BlobPair where _ -> Prelude.fail "Expected object with 'before' and/or 'after' keys only" pattern Diffing :: Blob -> Blob -> BlobPair -pattern Diffing a b = BlobPair (These a b) +pattern Diffing a b = BlobPair (Compare a b) pattern Inserting :: Blob -> BlobPair -pattern Inserting a = BlobPair (That a) +pattern Inserting a = BlobPair (Insert a) pattern Deleting :: Blob -> BlobPair -pattern Deleting b = BlobPair (This b) +pattern Deleting b = BlobPair (Delete b) {-# COMPLETE Diffing, Inserting, Deleting #-} @@ -153,10 +154,10 @@ languageTagForBlobPair pair = showLanguage (languageForBlobPair pair) pathKeyForBlobPair :: BlobPair -> FilePath pathKeyForBlobPair blobs = case bimap blobPath blobPath (getBlobPair blobs) of - This before -> before - That after -> after - These before after | before == after -> after - | otherwise -> before <> " -> " <> after + Delete before -> before + Insert after -> after + Compare before after | before == after -> after + | otherwise -> before <> " -> " <> after instance ToJSONFields Blob where toJSONFields p = [ "path" .= blobPath p, "language" .= blobLanguage p] diff --git a/src/Rendering/JSON.hs b/src/Rendering/JSON.hs index 10f522635..f5bb43031 100644 --- a/src/Rendering/JSON.hs +++ b/src/Rendering/JSON.hs @@ -16,7 +16,6 @@ module Rendering.JSON import Data.Aeson (ToJSON, toJSON, object, (.=)) import Data.Aeson as A import Data.Blob -import Data.Edit import Data.JSON.Fields import Data.Text (pack) import GHC.TypeLits @@ -56,8 +55,8 @@ newtype JSONStat = JSONStat { jsonStatBlobs :: BlobPair } deriving (Eq, Show) instance ToJSON JSONStat where - toJSON JSONStat{..} = object ("path" .= pathKeyForBlobPair jsonStatBlobs : toJSONFields (these Delete Insert Compare (getBlobPair jsonStatBlobs))) - toEncoding JSONStat{..} = pairs (fold ("path" .= pathKeyForBlobPair jsonStatBlobs : toJSONFields (these Delete Insert Compare (getBlobPair jsonStatBlobs)))) + toJSON JSONStat{..} = object ("path" .= pathKeyForBlobPair jsonStatBlobs : toJSONFields (getBlobPair jsonStatBlobs)) + toEncoding JSONStat{..} = pairs (fold ("path" .= pathKeyForBlobPair jsonStatBlobs : toJSONFields (getBlobPair jsonStatBlobs))) -- | Render a term to a value representing its JSON. renderJSONTerm :: ToJSON a => Blob -> a -> JSON "trees" SomeJSON diff --git a/src/Semantic/Api/Diffs.hs b/src/Semantic/Api/Diffs.hs index bfbf0b0d2..fd08227e6 100644 --- a/src/Semantic/Api/Diffs.hs +++ b/src/Semantic/Api/Diffs.hs @@ -18,6 +18,7 @@ import Control.Lens import Control.Monad.IO.Class import Data.Blob import Data.ByteString.Builder +import Data.Edit import Data.Graph import Data.JSON.Fields import Data.Language @@ -161,4 +162,4 @@ diffTerms terms = time "diff" languageTag $ do let diff = diffTermPair (bimap snd snd terms) diff <$ writeStat (Stat.count "diff.nodes" (bilength diff) languageTag) where languageTag = languageTagForBlobPair blobs - blobs = BlobPair (bimap fst fst terms) + blobs = BlobPair (these Delete Insert Compare (bimap fst fst terms)) diff --git a/src/Semantic/Api/TOCSummaries.hs b/src/Semantic/Api/TOCSummaries.hs index d9eee1488..482281704 100644 --- a/src/Semantic/Api/TOCSummaries.hs +++ b/src/Semantic/Api/TOCSummaries.hs @@ -31,7 +31,7 @@ import Data.ProtoLens (defMessage) import Data.Semilattice.Lower import Data.Term (Term) import qualified Data.Text as T -import Data.These (These, fromThese) +import Data.These (These, fromThese, these) import Diffing.Algorithm (Diffable) import qualified Diffing.Algorithm.SES as SES import qualified Language.Java as Java @@ -126,7 +126,7 @@ newtype ViaTags t a = ViaTags (t a) instance Tagging.ToTags t => SummarizeDiff (ViaTags t) where summarizeTerms terms = pure . map (uncurry summarizeChange) . dedupe . mapMaybe toChange . uncurry (SES.ses compare) . fromThese [] [] . bimap (uncurry go) (uncurry go) $ terms where go blob (ViaTags t) = Tagging.tags (blobSource blob) t - lang = languageForBlobPair (BlobPair (bimap fst fst terms)) + lang = languageForBlobPair (BlobPair (these Delete Insert Compare (bimap fst fst terms))) (s1, s2) = fromThese mempty mempty (bimap (blobSource . fst) (blobSource . fst) terms) compare = liftA2 (&&) <$> ((==) `on` Tag.kind) <*> ((==) `on` Tag.name) From 5c6371b6db90f86ba0b42c086cd267f9794f8236 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 10:59:00 -0400 Subject: [PATCH 034/118] =?UTF-8?q?Don=E2=80=99t=20qualify=20the=20names?= =?UTF-8?q?=20of=20the=20Edit=20constructors.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Semantic/Api/TOCSummaries.hs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Semantic/Api/TOCSummaries.hs b/src/Semantic/Api/TOCSummaries.hs index 482281704..d3d82884e 100644 --- a/src/Semantic/Api/TOCSummaries.hs +++ b/src/Semantic/Api/TOCSummaries.hs @@ -18,7 +18,7 @@ import Control.Monad.IO.Class import Data.Aeson import Data.Blob import Data.ByteString.Builder -import Data.Edit as Edit +import Data.Edit import Data.Either (partitionEithers) import Data.Function (on) import Data.Functor.Classes @@ -131,9 +131,9 @@ instance Tagging.ToTags t => SummarizeDiff (ViaTags t) where compare = liftA2 (&&) <$> ((==) `on` Tag.kind) <*> ((==) `on` Tag.name) toChange = \case - Edit.Delete tag -> (Deleted,) <$> toDecl tag - Edit.Insert tag -> (Inserted,) <$> toDecl tag - Edit.Compare t1 t2 + Delete tag -> (Deleted,) <$> toDecl tag + Insert tag -> (Inserted,) <$> toDecl tag + Compare t1 t2 | Source.slice s1 (byteRange (Tag.loc t1)) /= Source.slice s2 (byteRange (Tag.loc t2)) -> (Changed,) <$> toDecl t2 | otherwise -> Nothing From bf9a4e1260e4bbd2eadae6679ab26a3048178018 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 11:09:06 -0400 Subject: [PATCH 035/118] Parsing produces an Edit of terms. --- src/Control/Effect/Parse.hs | 9 ++++----- src/Diffing/Interpreter.hs | 7 ++++--- src/Semantic/Api/Diffs.hs | 4 ++-- src/Semantic/Api/TOCSummaries.hs | 9 ++++----- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/Control/Effect/Parse.hs b/src/Control/Effect/Parse.hs index 2e4a67484..6e330ef61 100644 --- a/src/Control/Effect/Parse.hs +++ b/src/Control/Effect/Parse.hs @@ -15,7 +15,6 @@ import Data.Blob import Data.Edit import Data.Language import qualified Data.Map as Map -import Data.These import Parsing.Parser data Parse m k @@ -52,11 +51,11 @@ parseWith parsers with blob = case Map.lookup (blobLanguage blob) parsers of -- | Parse a 'BlobPair' with one of the provided parsers, and run an action on the abstracted term pair. parsePairWith :: (Carrier sig m, Member (Error SomeException) sig, Member Parse sig) - => Map.Map Language (SomeParser c ann) -- ^ The set of parsers to select from. - -> (forall term . c term => These (Blob, term ann) (Blob, term ann) -> m a) -- ^ A function to run on the parsed terms. Note that the terms are abstract, but constrained by @c@, allowing you to do anything @c@ allows, and requiring that all the input parsers produce terms supporting @c@. - -> BlobPair -- ^ The blob pair to parse. + => Map.Map Language (SomeParser c ann) -- ^ The set of parsers to select from. + -> (forall term . c term => Edit (Blob, term ann) (Blob, term ann) -> m a) -- ^ A function to run on the parsed terms. Note that the terms are abstract, but constrained by @c@, allowing you to do anything @c@ allows, and requiring that all the input parsers produce terms supporting @c@. + -> BlobPair -- ^ The blob pair to parse. -> m a parsePairWith parsers with blobPair = case Map.lookup (languageForBlobPair blobPair) parsers of - Just (SomeParser parser) -> bitraverse (p parser) (p parser) (getBlobPair blobPair) >>= with . edit This That These + Just (SomeParser parser) -> bitraverse (p parser) (p parser) (getBlobPair blobPair) >>= with _ -> noLanguageForBlob (pathForBlobPair blobPair) where p parser blob = (,) blob <$> parse parser blob diff --git a/src/Diffing/Interpreter.hs b/src/Diffing/Interpreter.hs index b2f85fe43..d2d5ba54e 100644 --- a/src/Diffing/Interpreter.hs +++ b/src/Diffing/Interpreter.hs @@ -9,6 +9,7 @@ import Control.Effect.Carrier import Control.Effect.Cull import Control.Effect.NonDet import qualified Data.Diff as Diff +import Data.Edit (Edit, edit) import Data.Term import Diffing.Algorithm import Diffing.Algorithm.RWS @@ -36,12 +37,12 @@ class Bifoldable (DiffFor term) => DiffTerms term where -- Note that the dependency means that the diff type is in 1:1 correspondence with the term type. This allows subclasses of 'DiffTerms' to receive e.g. @'DiffFor' term a b@ without incurring ambiguity, since every diff type is unique to its term type. type DiffFor term = (diff :: * -> * -> *) | diff -> term - -- | Diff a 'These' of terms. - diffTermPair :: These (term ann1) (term ann2) -> DiffFor term ann1 ann2 + -- | Diff an 'Edit' of terms. + diffTermPair :: Edit (term ann1) (term ann2) -> DiffFor term ann1 ann2 instance (Diffable syntax, Eq1 syntax, Hashable1 syntax, Traversable syntax) => DiffTerms (Term syntax) where type DiffFor (Term syntax) = Diff.Diff syntax - diffTermPair = these Diff.deleting Diff.inserting diffTerms + diffTermPair = edit Diff.deleting Diff.inserting diffTerms -- | Run an 'Algorithm' to completion in an 'Alternative' context using the supplied comparability & equivalence relations. diff --git a/src/Semantic/Api/Diffs.hs b/src/Semantic/Api/Diffs.hs index fd08227e6..dc0e13d23 100644 --- a/src/Semantic/Api/Diffs.hs +++ b/src/Semantic/Api/Diffs.hs @@ -157,9 +157,9 @@ diffWith diffWith parsers render = parsePairWith parsers (render <=< diffTerms) diffTerms :: (DiffTerms term, Member Telemetry sig, Carrier sig m, MonadIO m) - => These (Blob, term ann) (Blob, term ann) -> m (DiffFor term ann ann) + => Edit (Blob, term ann) (Blob, term ann) -> m (DiffFor term ann ann) diffTerms terms = time "diff" languageTag $ do let diff = diffTermPair (bimap snd snd terms) diff <$ writeStat (Stat.count "diff.nodes" (bilength diff) languageTag) where languageTag = languageTagForBlobPair blobs - blobs = BlobPair (these Delete Insert Compare (bimap fst fst terms)) + blobs = BlobPair (bimap fst fst terms) diff --git a/src/Semantic/Api/TOCSummaries.hs b/src/Semantic/Api/TOCSummaries.hs index d3d82884e..f40d89fe1 100644 --- a/src/Semantic/Api/TOCSummaries.hs +++ b/src/Semantic/Api/TOCSummaries.hs @@ -31,7 +31,6 @@ import Data.ProtoLens (defMessage) import Data.Semilattice.Lower import Data.Term (Term) import qualified Data.Text as T -import Data.These (These, fromThese, these) import Diffing.Algorithm (Diffable) import qualified Diffing.Algorithm.SES as SES import qualified Language.Java as Java @@ -108,7 +107,7 @@ summarizeDiffParsers :: PerLanguageModes -> Map Language (SomeParser SummarizeDi summarizeDiffParsers = allParsers class SummarizeDiff term where - summarizeTerms :: (Member Telemetry sig, Carrier sig m, MonadIO m) => These (Blob, term Loc) (Blob, term Loc) -> m [Either ErrorSummary TOCSummary] + summarizeTerms :: (Member Telemetry sig, Carrier sig m, MonadIO m) => Edit (Blob, term Loc) (Blob, term Loc) -> m [Either ErrorSummary TOCSummary] instance (Diffable syntax, Eq1 syntax, HasDeclaration syntax, Hashable1 syntax, Traversable syntax) => SummarizeDiff (Term syntax) where summarizeTerms = fmap diffTOC . diffTerms . bimap decorateTerm decorateTerm where @@ -124,10 +123,10 @@ deriving via (ViaTags Python.Term) instance SummarizeDiff Python.Term newtype ViaTags t a = ViaTags (t a) instance Tagging.ToTags t => SummarizeDiff (ViaTags t) where - summarizeTerms terms = pure . map (uncurry summarizeChange) . dedupe . mapMaybe toChange . uncurry (SES.ses compare) . fromThese [] [] . bimap (uncurry go) (uncurry go) $ terms where + summarizeTerms terms = pure . map (uncurry summarizeChange) . dedupe . mapMaybe toChange . edit (map Delete) (map Insert) (SES.ses compare) . bimap (uncurry go) (uncurry go) $ terms where go blob (ViaTags t) = Tagging.tags (blobSource blob) t - lang = languageForBlobPair (BlobPair (these Delete Insert Compare (bimap fst fst terms))) - (s1, s2) = fromThese mempty mempty (bimap (blobSource . fst) (blobSource . fst) terms) + lang = languageForBlobPair (BlobPair (bimap fst fst terms)) + (s1, s2) = edit (,mempty) (mempty,) (,) (bimap (blobSource . fst) (blobSource . fst) terms) compare = liftA2 (&&) <$> ((==) `on` Tag.kind) <*> ((==) `on` Tag.name) toChange = \case From c80219296e56ab30c0a5d95f2ce5142e2f53f595 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 11:12:54 -0400 Subject: [PATCH 036/118] Redefine BlobPair as a type synonym. --- src/Control/Effect/Parse.hs | 2 +- src/Data/Blob.hs | 13 ++++++------- src/Rendering/JSON.hs | 4 ++-- src/Semantic/Api/Diffs.hs | 2 +- src/Semantic/Api/TOCSummaries.hs | 2 +- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/Control/Effect/Parse.hs b/src/Control/Effect/Parse.hs index 6e330ef61..c391143ec 100644 --- a/src/Control/Effect/Parse.hs +++ b/src/Control/Effect/Parse.hs @@ -56,6 +56,6 @@ parsePairWith -> BlobPair -- ^ The blob pair to parse. -> m a parsePairWith parsers with blobPair = case Map.lookup (languageForBlobPair blobPair) parsers of - Just (SomeParser parser) -> bitraverse (p parser) (p parser) (getBlobPair blobPair) >>= with + Just (SomeParser parser) -> bitraverse (p parser) (p parser) blobPair >>= with _ -> noLanguageForBlob (pathForBlobPair blobPair) where p parser blob = (,) blob <$> parse parser blob diff --git a/src/Data/Blob.hs b/src/Data/Blob.hs index 03e784c8c..cf1b90e05 100644 --- a/src/Data/Blob.hs +++ b/src/Data/Blob.hs @@ -13,7 +13,7 @@ module Data.Blob , nullBlob , sourceBlob , noLanguageForBlob -, BlobPair(..) +, BlobPair , pattern Diffing , pattern Inserting , pattern Deleting @@ -102,8 +102,7 @@ noLanguageForBlob blobPath = throwError (SomeException (NoLanguageForBlob blobPa -- | Represents a blobs suitable for diffing which can be either a blob to -- delete, a blob to insert, or a pair of blobs to diff. -newtype BlobPair = BlobPair { getBlobPair :: Edit Blob Blob } - deriving (Eq, Show) +type BlobPair = Edit Blob Blob instance FromJSON BlobPair where parseJSON = withObject "BlobPair" $ \o -> do @@ -116,13 +115,13 @@ instance FromJSON BlobPair where _ -> Prelude.fail "Expected object with 'before' and/or 'after' keys only" pattern Diffing :: Blob -> Blob -> BlobPair -pattern Diffing a b = BlobPair (Compare a b) +pattern Diffing a b = Compare a b pattern Inserting :: Blob -> BlobPair -pattern Inserting a = BlobPair (Insert a) +pattern Inserting a = Insert a pattern Deleting :: Blob -> BlobPair -pattern Deleting b = BlobPair (Delete b) +pattern Deleting b = Delete b {-# COMPLETE Diffing, Inserting, Deleting #-} @@ -153,7 +152,7 @@ languageTagForBlobPair pair = showLanguage (languageForBlobPair pair) where showLanguage = pure . (,) "language" . show pathKeyForBlobPair :: BlobPair -> FilePath -pathKeyForBlobPair blobs = case bimap blobPath blobPath (getBlobPair blobs) of +pathKeyForBlobPair blobs = case bimap blobPath blobPath blobs of Delete before -> before Insert after -> after Compare before after | before == after -> after diff --git a/src/Rendering/JSON.hs b/src/Rendering/JSON.hs index f5bb43031..e2486c880 100644 --- a/src/Rendering/JSON.hs +++ b/src/Rendering/JSON.hs @@ -55,8 +55,8 @@ newtype JSONStat = JSONStat { jsonStatBlobs :: BlobPair } deriving (Eq, Show) instance ToJSON JSONStat where - toJSON JSONStat{..} = object ("path" .= pathKeyForBlobPair jsonStatBlobs : toJSONFields (getBlobPair jsonStatBlobs)) - toEncoding JSONStat{..} = pairs (fold ("path" .= pathKeyForBlobPair jsonStatBlobs : toJSONFields (getBlobPair jsonStatBlobs))) + toJSON JSONStat{..} = object ("path" .= pathKeyForBlobPair jsonStatBlobs : toJSONFields jsonStatBlobs) + toEncoding JSONStat{..} = pairs (fold ("path" .= pathKeyForBlobPair jsonStatBlobs : toJSONFields jsonStatBlobs)) -- | Render a term to a value representing its JSON. renderJSONTerm :: ToJSON a => Blob -> a -> JSON "trees" SomeJSON diff --git a/src/Semantic/Api/Diffs.hs b/src/Semantic/Api/Diffs.hs index dc0e13d23..582cd11c4 100644 --- a/src/Semantic/Api/Diffs.hs +++ b/src/Semantic/Api/Diffs.hs @@ -162,4 +162,4 @@ diffTerms terms = time "diff" languageTag $ do let diff = diffTermPair (bimap snd snd terms) diff <$ writeStat (Stat.count "diff.nodes" (bilength diff) languageTag) where languageTag = languageTagForBlobPair blobs - blobs = BlobPair (bimap fst fst terms) + blobs = bimap fst fst terms diff --git a/src/Semantic/Api/TOCSummaries.hs b/src/Semantic/Api/TOCSummaries.hs index f40d89fe1..484045c38 100644 --- a/src/Semantic/Api/TOCSummaries.hs +++ b/src/Semantic/Api/TOCSummaries.hs @@ -125,7 +125,7 @@ newtype ViaTags t a = ViaTags (t a) instance Tagging.ToTags t => SummarizeDiff (ViaTags t) where summarizeTerms terms = pure . map (uncurry summarizeChange) . dedupe . mapMaybe toChange . edit (map Delete) (map Insert) (SES.ses compare) . bimap (uncurry go) (uncurry go) $ terms where go blob (ViaTags t) = Tagging.tags (blobSource blob) t - lang = languageForBlobPair (BlobPair (bimap fst fst terms)) + lang = languageForBlobPair (bimap fst fst terms) (s1, s2) = edit (,mempty) (mempty,) (,) (bimap (blobSource . fst) (blobSource . fst) terms) compare = liftA2 (&&) <$> ((==) `on` Tag.kind) <*> ((==) `on` Tag.name) From e8dacbe18697442ae666e085fdee50e02222c349 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 11:17:24 -0400 Subject: [PATCH 037/118] :fire: a redundant binding. --- test/Diffing/Algorithm/RWS/Spec.hs | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/Diffing/Algorithm/RWS/Spec.hs b/test/Diffing/Algorithm/RWS/Spec.hs index b0166b1bc..94039c603 100644 --- a/test/Diffing/Algorithm/RWS/Spec.hs +++ b/test/Diffing/Algorithm/RWS/Spec.hs @@ -40,8 +40,6 @@ spec = do where decorate = defaultFeatureVectorDecorator - diffThese = these deleting inserting comparing - stripTerm :: Functor f => Term f (FeatureVector, ()) -> Term f () stripTerm = fmap snd From a7dc70f47409cc5bb16c60a6cd17d05ee1328272 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 11:20:35 -0400 Subject: [PATCH 038/118] :fire: diffThese. --- src/Diffing/Algorithm.hs | 5 ----- src/Diffing/Interpreter.hs | 10 +++++----- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/Diffing/Algorithm.hs b/src/Diffing/Algorithm.hs index 480045e7d..91da524f6 100644 --- a/src/Diffing/Algorithm.hs +++ b/src/Diffing/Algorithm.hs @@ -5,7 +5,6 @@ module Diffing.Algorithm , Diffable (..) , Equivalence (..) , diff - , diffThese , diffEdit , diffMaybe , linearly @@ -55,10 +54,6 @@ instance Carrier sig m => Carrier sig (Algorithm term1 term2 diff m) where diff :: (Carrier sig m, Member (Diff term1 term2 diff) sig) => term1 -> term2 -> m diff diff a1 a2 = send (Diff a1 a2 pure) --- | Diff a These of terms without specifying the algorithm to be used. -diffThese :: (Carrier sig m, Member (Diff term1 term2 diff) sig) => These term1 term2 -> Algorithm term1 term2 diff m diff -diffThese = these byDeleting byInserting diff - -- | Diff an 'Edit' of terms without specifying the algorithm to be used. diffEdit :: (Carrier sig m, Member (Diff term1 term2 diff) sig) => Edit.Edit term1 term2 -> Algorithm term1 term2 diff m diff diffEdit = Edit.edit byDeleting byInserting diff diff --git a/src/Diffing/Interpreter.hs b/src/Diffing/Interpreter.hs index d2d5ba54e..2ab99e165 100644 --- a/src/Diffing/Interpreter.hs +++ b/src/Diffing/Interpreter.hs @@ -9,7 +9,7 @@ import Control.Effect.Carrier import Control.Effect.Cull import Control.Effect.NonDet import qualified Data.Diff as Diff -import Data.Edit (Edit, edit) +import qualified Data.Edit as Edit import Data.Term import Diffing.Algorithm import Diffing.Algorithm.RWS @@ -37,12 +37,12 @@ class Bifoldable (DiffFor term) => DiffTerms term where -- Note that the dependency means that the diff type is in 1:1 correspondence with the term type. This allows subclasses of 'DiffTerms' to receive e.g. @'DiffFor' term a b@ without incurring ambiguity, since every diff type is unique to its term type. type DiffFor term = (diff :: * -> * -> *) | diff -> term - -- | Diff an 'Edit' of terms. - diffTermPair :: Edit (term ann1) (term ann2) -> DiffFor term ann1 ann2 + -- | Diff an 'Edit.Edit' of terms. + diffTermPair :: Edit.Edit (term ann1) (term ann2) -> DiffFor term ann1 ann2 instance (Diffable syntax, Eq1 syntax, Hashable1 syntax, Traversable syntax) => DiffTerms (Term syntax) where type DiffFor (Term syntax) = Diff.Diff syntax - diffTermPair = edit Diff.deleting Diff.inserting diffTerms + diffTermPair = Edit.edit Diff.deleting Diff.inserting diffTerms -- | Run an 'Algorithm' to completion in an 'Alternative' context using the supplied comparability & equivalence relations. @@ -72,7 +72,7 @@ instance ( Alternative m (DiffC (Term syntax (FeatureVector, ann1)) (Term syntax (FeatureVector, ann2)) (Diff.Diff syntax (FeatureVector, ann1) (FeatureVector, ann2)) m) where eff (L op) = case op of Diff t1 t2 k -> runDiff (algorithmForTerms t1 t2) <|> pure (Diff.comparing t1 t2) >>= k - Linear (Term (In ann1 f1)) (Term (In ann2 f2)) k -> Diff.merge (ann1, ann2) <$> tryAlignWith (runDiff . diffThese) f1 f2 >>= k + Linear (Term (In ann1 f1)) (Term (In ann2 f2)) k -> Diff.merge (ann1, ann2) <$> tryAlignWith (runDiff . diffEdit . these Edit.Delete Edit.Insert Edit.Compare) f1 f2 >>= k RWS as bs k -> traverse (runDiff . diffEdit) (rws comparableTerms equivalentTerms as bs) >>= k Delete a k -> k (Diff.deleting a) Insert b k -> k (Diff.inserting b) From 939041c43a15c8d5bcb7aaf2183b06a5116f15eb Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 11:25:02 -0400 Subject: [PATCH 039/118] tryAlignWith uses Edit. --- src/Diffing/Algorithm.hs | 24 ++++++++++++------------ src/Diffing/Algorithm/RWS.hs | 2 +- src/Diffing/Interpreter.hs | 10 +++++----- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Diffing/Algorithm.hs b/src/Diffing/Algorithm.hs index 91da524f6..391daade9 100644 --- a/src/Diffing/Algorithm.hs +++ b/src/Diffing/Algorithm.hs @@ -54,7 +54,7 @@ instance Carrier sig m => Carrier sig (Algorithm term1 term2 diff m) where diff :: (Carrier sig m, Member (Diff term1 term2 diff) sig) => term1 -> term2 -> m diff diff a1 a2 = send (Diff a1 a2 pure) --- | Diff an 'Edit' of terms without specifying the algorithm to be used. +-- | Diff an 'Edit.Edit' of terms without specifying the algorithm to be used. diffEdit :: (Carrier sig m, Member (Diff term1 term2 diff) sig) => Edit.Edit term1 term2 -> Algorithm term1 term2 diff m diff diffEdit = Edit.edit byDeleting byInserting diff @@ -144,8 +144,8 @@ class Diffable f where -> Algorithm term1 term2 diff m (f diff) algorithmFor = genericAlgorithmFor - tryAlignWith :: Alternative g => (These a1 a2 -> g b) -> f a1 -> f a2 -> g (f b) - default tryAlignWith :: (Alternative g, Generic1 f, GDiffable (Rep1 f)) => (These a1 a2 -> g b) -> f a1 -> f a2 -> g (f b) + tryAlignWith :: Alternative g => (Edit.Edit a1 a2 -> g b) -> f a1 -> f a2 -> g (f b) + default tryAlignWith :: (Alternative g, Generic1 f, GDiffable (Rep1 f)) => (Edit.Edit a1 a2 -> g b) -> f a1 -> f a2 -> g (f b) tryAlignWith f a b = to1 <$> gtryAlignWith f (from1 a) (from1 b) -- | Construct an algorithm to diff against positions inside an @f@. @@ -208,30 +208,30 @@ instance Apply Diffable fs => Diffable (Sum fs) where instance Diffable Maybe where algorithmFor = diffMaybe - tryAlignWith f (Just a1) (Just a2) = Just <$> f (These a1 a2) - tryAlignWith f (Just a1) Nothing = Just <$> f (This a1) - tryAlignWith f Nothing (Just a2) = Just <$> f (That a2) + tryAlignWith f (Just a1) (Just a2) = Just <$> f (Edit.Compare a1 a2) + tryAlignWith f (Just a1) Nothing = Just <$> f (Edit.Delete a1) + tryAlignWith f Nothing (Just a2) = Just <$> f (Edit.Insert a2) tryAlignWith _ Nothing Nothing = pure Nothing -- | Diff two lists using RWS. instance Diffable [] where algorithmFor = byRWS - tryAlignWith f (a1:as1) (a2:as2) = (:) <$> f (These a1 a2) <*> tryAlignWith f as1 as2 - tryAlignWith f [] as2 = traverse (f . That) as2 - tryAlignWith f as1 [] = traverse (f . This) as1 + tryAlignWith f (a1:as1) (a2:as2) = (:) <$> f (Edit.Compare a1 a2) <*> tryAlignWith f as1 as2 + tryAlignWith f [] as2 = traverse (f . Edit.Insert) as2 + tryAlignWith f as1 [] = traverse (f . Edit.Delete) as1 -- | Diff two non-empty lists using RWS. instance Diffable NonEmpty where algorithmFor (a1:|as1) (a2:|as2) = nonEmpty <$> byRWS (a1:as1) (a2:as2) >>= maybeM empty - tryAlignWith f (a1:|as1) (a2:|as2) = (:|) <$> f (These a1 a2) <*> tryAlignWith f as1 as2 + tryAlignWith f (a1:|as1) (a2:|as2) = (:|) <$> f (Edit.Compare a1 a2) <*> tryAlignWith f as1 as2 -- | A generic type class for diffing two terms defined by the Generic1 interface. class GDiffable f where galgorithmFor :: (Alternative m, Carrier sig m, Member (Diff term1 term2 diff) sig, Member NonDet sig) => f term1 -> f term2 -> Algorithm term1 term2 diff m (f diff) - gtryAlignWith :: Alternative g => (These a1 a2 -> g b) -> f a1 -> f a2 -> g (f b) + gtryAlignWith :: Alternative g => (Edit.Edit a1 a2 -> g b) -> f a1 -> f a2 -> g (f b) gcomparableTo :: f term1 -> f term2 -> Bool gcomparableTo _ _ = True @@ -272,7 +272,7 @@ instance (GDiffable f, GDiffable g) => GDiffable (f :+: g) where instance GDiffable Par1 where galgorithmFor (Par1 a1) (Par1 a2) = Par1 <$> diff a1 a2 - gtryAlignWith f (Par1 a) (Par1 b) = Par1 <$> f (These a b) + gtryAlignWith f (Par1 a) (Par1 b) = Par1 <$> f (Edit.Compare a b) -- | Diff two constant parameters (K1 is the Generic1 newtype representing type parameter constants). -- i.e. data Foo = Foo Int (the 'Int' is a constant parameter). diff --git a/src/Diffing/Algorithm/RWS.hs b/src/Diffing/Algorithm/RWS.hs index 9207fe822..c705353b5 100644 --- a/src/Diffing/Algorithm/RWS.hs +++ b/src/Diffing/Algorithm/RWS.hs @@ -159,7 +159,7 @@ editDistanceUpTo m a b = diffCost m (approximateDiff a b) _ | m <= 0 -> 0 Merge body -> sum (fmap ($ pred m) body) body -> succ (sum (fmap ($ pred m) body)) - approximateDiff a b = maybe (comparing a b) (merge (termAnnotation a, termAnnotation b)) (tryAlignWith (Just . these deleting inserting approximateDiff) (termOut a) (termOut b)) + approximateDiff a b = maybe (comparing a b) (merge (termAnnotation a, termAnnotation b)) (tryAlignWith (Just . edit deleting inserting approximateDiff) (termOut a) (termOut b)) data Label syntax where diff --git a/src/Diffing/Interpreter.hs b/src/Diffing/Interpreter.hs index 2ab99e165..8857eff15 100644 --- a/src/Diffing/Interpreter.hs +++ b/src/Diffing/Interpreter.hs @@ -9,7 +9,7 @@ import Control.Effect.Carrier import Control.Effect.Cull import Control.Effect.NonDet import qualified Data.Diff as Diff -import qualified Data.Edit as Edit +import Data.Edit (Edit, edit) import Data.Term import Diffing.Algorithm import Diffing.Algorithm.RWS @@ -37,12 +37,12 @@ class Bifoldable (DiffFor term) => DiffTerms term where -- Note that the dependency means that the diff type is in 1:1 correspondence with the term type. This allows subclasses of 'DiffTerms' to receive e.g. @'DiffFor' term a b@ without incurring ambiguity, since every diff type is unique to its term type. type DiffFor term = (diff :: * -> * -> *) | diff -> term - -- | Diff an 'Edit.Edit' of terms. - diffTermPair :: Edit.Edit (term ann1) (term ann2) -> DiffFor term ann1 ann2 + -- | Diff an 'Edit' of terms. + diffTermPair :: Edit (term ann1) (term ann2) -> DiffFor term ann1 ann2 instance (Diffable syntax, Eq1 syntax, Hashable1 syntax, Traversable syntax) => DiffTerms (Term syntax) where type DiffFor (Term syntax) = Diff.Diff syntax - diffTermPair = Edit.edit Diff.deleting Diff.inserting diffTerms + diffTermPair = edit Diff.deleting Diff.inserting diffTerms -- | Run an 'Algorithm' to completion in an 'Alternative' context using the supplied comparability & equivalence relations. @@ -72,7 +72,7 @@ instance ( Alternative m (DiffC (Term syntax (FeatureVector, ann1)) (Term syntax (FeatureVector, ann2)) (Diff.Diff syntax (FeatureVector, ann1) (FeatureVector, ann2)) m) where eff (L op) = case op of Diff t1 t2 k -> runDiff (algorithmForTerms t1 t2) <|> pure (Diff.comparing t1 t2) >>= k - Linear (Term (In ann1 f1)) (Term (In ann2 f2)) k -> Diff.merge (ann1, ann2) <$> tryAlignWith (runDiff . diffEdit . these Edit.Delete Edit.Insert Edit.Compare) f1 f2 >>= k + Linear (Term (In ann1 f1)) (Term (In ann2 f2)) k -> Diff.merge (ann1, ann2) <$> tryAlignWith (runDiff . diffEdit) f1 f2 >>= k RWS as bs k -> traverse (runDiff . diffEdit) (rws comparableTerms equivalentTerms as bs) >>= k Delete a k -> k (Diff.deleting a) Insert b k -> k (Diff.inserting b) From 9c67f48905ba86353c569107815ab2d5e42496ad Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 11:26:50 -0400 Subject: [PATCH 040/118] Fix some property names. --- test/Diffing/Algorithm/SES/Spec.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/Diffing/Algorithm/SES/Spec.hs b/test/Diffing/Algorithm/SES/Spec.hs index aadc139f3..53e136475 100644 --- a/test/Diffing/Algorithm/SES/Spec.hs +++ b/test/Diffing/Algorithm/SES/Spec.hs @@ -8,13 +8,13 @@ import Test.Hspec.LeanCheck spec :: Spec spec = do describe "ses" $ do - prop "returns equal lists in These" $ + prop "returns equal lists in Compare" $ \ as -> (ses (==) as as :: [Edit Char Char]) `shouldBe` zipWith Compare as as - prop "returns deletions in This" $ + prop "returns deletions in Delete" $ \ as -> (ses (==) as [] :: [Edit Char Char]) `shouldBe` fmap Delete as - prop "returns insertions in That" $ + prop "returns insertions in Insert" $ \ bs -> (ses (==) [] bs :: [Edit Char Char]) `shouldBe` fmap Insert bs prop "returns all elements individually for disjoint inputs" $ From 2a788703ba68b457bb205b61059f346a103958eb Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 11:28:03 -0400 Subject: [PATCH 041/118] Fix up some tests. --- test/Diffing/Interpreter/Spec.hs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/Diffing/Interpreter/Spec.hs b/test/Diffing/Interpreter/Spec.hs index 01f85eb90..56d59145e 100644 --- a/test/Diffing/Interpreter/Spec.hs +++ b/test/Diffing/Interpreter/Spec.hs @@ -10,14 +10,13 @@ import Data.Maybe import Data.Mergeable import Data.Sum import Data.Term -import Data.These import Diffing.Interpreter import qualified Data.Syntax as Syntax import Test.Hspec (Spec, describe, it) import Test.Hspec.Expectations import Test.Hspec.LeanCheck import Test.LeanCheck.Core -import SpecHelpers (edit) +import SpecHelpers (Edit(..), edit) spec :: Spec spec = do @@ -60,11 +59,11 @@ spec = do describe "diffTermPair" $ do prop "produces an Insert when the first term is missing" $ do - \ after -> let diff = diffTermPair (That after) :: Diff ListableSyntax () () in + \ after -> let diff = diffTermPair (Insert after) :: Diff ListableSyntax () () in diff `shouldBe` inserting after prop "produces a Delete when the second term is missing" $ do - \ before -> let diff = diffTermPair (This before) :: Diff ListableSyntax () () in + \ before -> let diff = diffTermPair (Delete before) :: Diff ListableSyntax () () in diff `shouldBe` deleting before From d1ab2e11c64daed6c8260b7ba5404f0b436d29b3 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 11:28:09 -0400 Subject: [PATCH 042/118] :fire: a redundant import. --- test/Diffing/Algorithm/RWS/Spec.hs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/Diffing/Algorithm/RWS/Spec.hs b/test/Diffing/Algorithm/RWS/Spec.hs index 94039c603..4e7b74c04 100644 --- a/test/Diffing/Algorithm/RWS/Spec.hs +++ b/test/Diffing/Algorithm/RWS/Spec.hs @@ -7,7 +7,6 @@ import Data.Functor.Listable (ListableSyntax) import Data.Sum import qualified Data.Syntax as Syntax import Data.Term -import Data.These import Diffing.Algorithm (comparableTerms) import Diffing.Interpreter (stripDiff) import Diffing.Algorithm.RWS From 9813bdd5f05345ae9b48b5adc7226f6f06d6e3dc Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 11:29:03 -0400 Subject: [PATCH 043/118] :fire: the re-export of Data.These from Prologue. --- src/Data/Syntax/Expression.hs | 2 +- src/Prologue.hs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Data/Syntax/Expression.hs b/src/Data/Syntax/Expression.hs index 3f8e9c1d0..eeb5d942d 100644 --- a/src/Data/Syntax/Expression.hs +++ b/src/Data/Syntax/Expression.hs @@ -3,7 +3,7 @@ module Data.Syntax.Expression where import Prelude hiding (null) -import Prologue hiding (This, index, null) +import Prologue hiding (index, null) import Control.Abstract hiding (Bitwise (..), Call, Member) import Data.Abstract.Evaluatable as Abstract hiding (Member) diff --git a/src/Prologue.hs b/src/Prologue.hs index d1d429e6d..c0590ee6c 100644 --- a/src/Prologue.hs +++ b/src/Prologue.hs @@ -29,7 +29,6 @@ import Data.Semilattice.Lower as X (Lower(..)) import Data.Set as X (Set) import Data.Sum as X (Sum, Element, Elements, (:<), (:<:), Apply (..), inject) import Data.Text as X (Text) -import Data.These as X import Data.Word as X (Word8, Word16, Word32, Word64) import Control.Exception as X hiding (Handler (..), assert, evaluate, throw, throwIO, throwTo) From 9170893153ad2860661918ffa2a3467470f95c2e Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 11:48:43 -0400 Subject: [PATCH 044/118] Inline the definition of bicrosswalk & alignWith. --- src/Rendering/TOC.hs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Rendering/TOC.hs b/src/Rendering/TOC.hs index 1d27ee3f6..a472c8f9f 100644 --- a/src/Rendering/TOC.hs +++ b/src/Rendering/TOC.hs @@ -12,7 +12,6 @@ module Rendering.TOC import Prologue hiding (index) import Analysis.TOCSummary -import Data.Align (bicrosswalk) import Data.Aeson (ToJSON(..), Value, (.=), object) import Data.Diff import Data.Edit @@ -78,12 +77,17 @@ tableOfContentsBy :: (Foldable f, Functor f) -> Diff f ann ann -- ^ The diff to compute the table of contents for. -> [(Change, a)] -- ^ A list of entries for relevant changed nodes in the diff. tableOfContentsBy selector = fromMaybe [] . cata (\ r -> case r of - Patch patch -> (pure . patchEntry <$> bicrosswalk selector selector patch) <> bifoldMap fold fold patch <> Just [] + Patch patch -> (pure . patchEntry <$> select (bimap selector selector patch)) <> bifoldMap fold fold patch <> Just [] Merge (In (_, ann2) r) -> case (selector (In ann2 r), fold r) of (Just a, Just entries) -> Just ((Changed, a) : entries) (_ , entries) -> entries) where patchEntry = edit (Deleted,) (Inserted,) (const (Replaced,)) + select = \case + Delete a -> Delete <$> a + Insert b -> Insert <$> b + Compare a b -> liftA2 Compare a b <|> Delete <$> a <|> Insert <$> b + data DedupeKey = DedupeKey !Kind {-# UNPACK #-} !T.Text deriving (Eq, Ord) From 7a3c4ac5fcfb702248491004075e7369433b61e5 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 11:50:16 -0400 Subject: [PATCH 045/118] :fire: the Bicrosswalk instance for Edit. --- src/Data/Edit.hs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/Data/Edit.hs b/src/Data/Edit.hs index 053ef796d..cf43d8f70 100644 --- a/src/Data/Edit.hs +++ b/src/Data/Edit.hs @@ -4,12 +4,10 @@ module Data.Edit , edit ) where -import Data.Align import Data.Bifoldable import Data.Bifunctor import Data.Bitraversable import Data.Functor.Classes -import Data.These import GHC.Generics (Generic, Generic1) -- | An operation to compare, insert, or delete an item. @@ -40,12 +38,6 @@ instance Bitraversable Edit where Insert b -> Insert <$> g b Compare a b -> Compare <$> f a <*> g b -instance Bicrosswalk Edit where - bicrosswalk f g = \case - Delete a -> Delete <$> f a - Insert b -> Insert <$> g b - Compare a b -> alignWith (these Delete Insert Compare) (f a) (g b) - instance Eq2 Edit where liftEq2 eqBefore eqAfter p1 p2 = case (p1, p2) of (Delete a1, Delete a2) -> eqBefore a1 a2 From f36df7f972d82fae0e4a8264f4feadb3563aed70 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 11:50:49 -0400 Subject: [PATCH 046/118] :fire: the dependency on these. --- semantic.cabal | 1 - 1 file changed, 1 deletion(-) diff --git a/semantic.cabal b/semantic.cabal index 199995996..7ba1a66cf 100644 --- a/semantic.cabal +++ b/semantic.cabal @@ -69,7 +69,6 @@ common dependencies , streaming ^>= 0.2.2.0 , streaming-bytestring ^>= 0.1.6 , text ^>= 1.2.3.1 - , these >= 0.7 && <1 , unix ^>= 2.7.2.2 , lingo ^>= 0.2 From 571cb74d435aea97ecf3d8315652f63b9c83ad5e Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 11:52:38 -0400 Subject: [PATCH 047/118] Style. --- src/Diffing/Algorithm/SES.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Diffing/Algorithm/SES.hs b/src/Diffing/Algorithm/SES.hs index 0748c3a7c..caaf4fd66 100644 --- a/src/Diffing/Algorithm/SES.hs +++ b/src/Diffing/Algorithm/SES.hs @@ -61,6 +61,6 @@ ses eq as' bs' (!?) :: Ix i => Array.Array i a -> i -> Maybe a -(!?) v i | inRange (Array.bounds v) i, !a <- v ! i = Just a - | otherwise = Nothing +v !? i | inRange (Array.bounds v) i, !a <- v ! i = Just a + | otherwise = Nothing {-# INLINE (!?) #-} From 36ee5fcfce31edb56f8f1bd0bad410452cee12ac Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 11:52:50 -0400 Subject: [PATCH 048/118] Alignment. --- src/Diffing/Algorithm/SES.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Diffing/Algorithm/SES.hs b/src/Diffing/Algorithm/SES.hs index caaf4fd66..ae83362d6 100644 --- a/src/Diffing/Algorithm/SES.hs +++ b/src/Diffing/Algorithm/SES.hs @@ -62,5 +62,5 @@ ses eq as' bs' (!?) :: Ix i => Array.Array i a -> i -> Maybe a v !? i | inRange (Array.bounds v) i, !a <- v ! i = Just a - | otherwise = Nothing + | otherwise = Nothing {-# INLINE (!?) #-} From b00715e247de91221e00f0e672dbcd4255c050ee Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 11:57:26 -0400 Subject: [PATCH 049/118] :fire: the pattern synonyms. --- src/Data/Blob.hs | 38 ++++++++++++-------------------------- src/Semantic/Api/Bridge.hs | 13 +++++++------ test/Semantic/IO/Spec.hs | 14 +++++++------- 3 files changed, 26 insertions(+), 39 deletions(-) diff --git a/src/Data/Blob.hs b/src/Data/Blob.hs index cf1b90e05..d16806f7b 100644 --- a/src/Data/Blob.hs +++ b/src/Data/Blob.hs @@ -14,9 +14,6 @@ module Data.Blob , sourceBlob , noLanguageForBlob , BlobPair -, pattern Diffing -, pattern Inserting -, pattern Deleting , maybeBlobPair , decodeBlobPairs , languageForBlobPair @@ -109,33 +106,22 @@ instance FromJSON BlobPair where before <- o .:? "before" after <- o .:? "after" case (before, after) of - (Just b, Just a) -> pure $ Diffing b a - (Just b, Nothing) -> pure $ Deleting b - (Nothing, Just a) -> pure $ Inserting a + (Just b, Just a) -> pure $ Compare b a + (Just b, Nothing) -> pure $ Delete b + (Nothing, Just a) -> pure $ Insert a _ -> Prelude.fail "Expected object with 'before' and/or 'after' keys only" -pattern Diffing :: Blob -> Blob -> BlobPair -pattern Diffing a b = Compare a b - -pattern Inserting :: Blob -> BlobPair -pattern Inserting a = Insert a - -pattern Deleting :: Blob -> BlobPair -pattern Deleting b = Delete b - -{-# COMPLETE Diffing, Inserting, Deleting #-} - maybeBlobPair :: MonadFail m => Maybe Blob -> Maybe Blob -> m BlobPair maybeBlobPair a b = case (a, b) of - (Just a, Nothing) -> pure (Deleting a) - (Nothing, Just b) -> pure (Inserting b) - (Just a, Just b) -> pure (Diffing a b) + (Just a, Nothing) -> pure (Delete a) + (Nothing, Just b) -> pure (Insert b) + (Just a, Just b) -> pure (Compare a b) _ -> Prologue.fail "expected file pair with content on at least one side" languageForBlobPair :: BlobPair -> Language -languageForBlobPair (Deleting b) = blobLanguage b -languageForBlobPair (Inserting b) = blobLanguage b -languageForBlobPair (Diffing a b) +languageForBlobPair (Delete b) = blobLanguage b +languageForBlobPair (Insert b) = blobLanguage b +languageForBlobPair (Compare a b) | blobLanguage a == Unknown || blobLanguage b == Unknown = Unknown | otherwise @@ -143,9 +129,9 @@ languageForBlobPair (Diffing a b) pathForBlobPair :: BlobPair -> FilePath pathForBlobPair x = blobPath $ case x of - (Inserting b) -> b - (Deleting b) -> b - (Diffing _ b) -> b + (Insert b) -> b + (Delete b) -> b + (Compare _ b) -> b languageTagForBlobPair :: BlobPair -> [(String, String)] languageTagForBlobPair pair = showLanguage (languageForBlobPair pair) diff --git a/src/Semantic/Api/Bridge.hs b/src/Semantic/Api/Bridge.hs index dee30b8ea..43fdd153d 100644 --- a/src/Semantic/Api/Bridge.hs +++ b/src/Semantic/Api/Bridge.hs @@ -7,6 +7,7 @@ module Semantic.Api.Bridge import Control.Lens import qualified Data.Blob as Data +import qualified Data.Edit as Data import qualified Data.Language as Data import Data.ProtoLens (defMessage) import qualified Data.Text as T @@ -78,11 +79,11 @@ instance APIConvert API.BlobPair Data.BlobPair where converting = prism' blobPairToApiBlobPair apiBlobPairToBlobPair where apiBlobPairToBlobPair blobPair = case (blobPair^.maybe'before, blobPair^.maybe'after) of - (Just before, Just after) -> Just $ Data.Diffing (before^.bridging) (after^.bridging) - (Just before, Nothing) -> Just $ Data.Deleting (before^.bridging) - (Nothing, Just after) -> Just $ Data.Inserting (after^.bridging) + (Just before, Just after) -> Just $ Data.Compare (before^.bridging) (after^.bridging) + (Just before, Nothing) -> Just $ Data.Delete (before^.bridging) + (Nothing, Just after) -> Just $ Data.Insert (after^.bridging) _ -> Nothing - blobPairToApiBlobPair (Data.Diffing before after) = defMessage & P.maybe'before .~ (bridging #? before) & P.maybe'after .~ (bridging #? after) - blobPairToApiBlobPair (Data.Inserting after) = defMessage & P.maybe'before .~ Nothing & P.maybe'after .~ (bridging #? after) - blobPairToApiBlobPair (Data.Deleting before) = defMessage & P.maybe'before .~ (bridging #? before) & P.maybe'after .~ Nothing + blobPairToApiBlobPair (Data.Compare before after) = defMessage & P.maybe'before .~ (bridging #? before) & P.maybe'after .~ (bridging #? after) + blobPairToApiBlobPair (Data.Insert after) = defMessage & P.maybe'before .~ Nothing & P.maybe'after .~ (bridging #? after) + blobPairToApiBlobPair (Data.Delete before) = defMessage & P.maybe'before .~ (bridging #? before) & P.maybe'after .~ Nothing diff --git a/test/Semantic/IO/Spec.hs b/test/Semantic/IO/Spec.hs index eb10de200..871509c82 100644 --- a/test/Semantic/IO/Spec.hs +++ b/test/Semantic/IO/Spec.hs @@ -97,34 +97,34 @@ spec = do let b = sourceBlob "method.rb" Ruby "def bar(x); end" it "returns blobs for valid JSON encoded diff input" $ do blobs <- blobsFromFilePath "test/fixtures/cli/diff.json" - blobs `shouldBe` [Diffing a b] + blobs `shouldBe` [Compare a b] it "returns blobs when there's no before" $ do blobs <- blobsFromFilePath "test/fixtures/cli/diff-no-before.json" - blobs `shouldBe` [Inserting b] + blobs `shouldBe` [Insert b] it "returns blobs when there's null before" $ do blobs <- blobsFromFilePath "test/fixtures/cli/diff-null-before.json" - blobs `shouldBe` [Inserting b] + blobs `shouldBe` [Insert b] it "returns blobs when there's no after" $ do blobs <- blobsFromFilePath "test/fixtures/cli/diff-no-after.json" - blobs `shouldBe` [Deleting a] + blobs `shouldBe` [Delete a] it "returns blobs when there's null after" $ do blobs <- blobsFromFilePath "test/fixtures/cli/diff-null-after.json" - blobs `shouldBe` [Deleting a] + blobs `shouldBe` [Delete a] it "returns blobs for unsupported language" $ do h <- openFileForReading "test/fixtures/cli/diff-unsupported-language.json" blobs <- readBlobPairsFromHandle h let b' = sourceBlob "test.kt" Unknown "fun main(args: Array) {\nprintln(\"hi\")\n}\n" - blobs `shouldBe` [Inserting b'] + blobs `shouldBe` [Insert b'] it "detects language based on filepath for empty language" $ do blobs <- blobsFromFilePath "test/fixtures/cli/diff-empty-language.json" - blobs `shouldBe` [Diffing a b] + blobs `shouldBe` [Compare a b] it "throws on blank input" $ do h <- openFileForReading "test/fixtures/cli/blank.json" From 23d34a7c6e2cbebabb1587d0fca979c826519483 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 11:59:27 -0400 Subject: [PATCH 050/118] :fire: redundant parens. --- src/Data/Blob.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Data/Blob.hs b/src/Data/Blob.hs index d16806f7b..a2cbbfd0a 100644 --- a/src/Data/Blob.hs +++ b/src/Data/Blob.hs @@ -129,9 +129,9 @@ languageForBlobPair (Compare a b) pathForBlobPair :: BlobPair -> FilePath pathForBlobPair x = blobPath $ case x of - (Insert b) -> b - (Delete b) -> b - (Compare _ b) -> b + Insert b -> b + Delete b -> b + Compare _ b -> b languageTagForBlobPair :: BlobPair -> [(String, String)] languageTagForBlobPair pair = showLanguage (languageForBlobPair pair) From 43eeca7d109fd3b2f220f6ad0ce052426a9156d5 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 12:02:38 -0400 Subject: [PATCH 051/118] Define a helper to merge edits. --- src/Data/Edit.hs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Data/Edit.hs b/src/Data/Edit.hs index cf43d8f70..a277502a8 100644 --- a/src/Data/Edit.hs +++ b/src/Data/Edit.hs @@ -2,6 +2,7 @@ module Data.Edit ( Edit(..) , edit +, mergeEdit ) where import Data.Bifoldable @@ -25,6 +26,9 @@ edit delete insert compare = \case Insert b -> insert b Compare a b -> compare a b +mergeEdit :: (a -> a -> a) -> Edit a a -> a +mergeEdit = edit id id + instance Bifunctor Edit where bimap = bimapDefault From 0b6b79b42bde3fe91bf35ae06e07b849e5ceb177 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 12:02:47 -0400 Subject: [PATCH 052/118] Use mergeEdit to define pathForBlobPair. --- src/Data/Blob.hs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Data/Blob.hs b/src/Data/Blob.hs index a2cbbfd0a..2874bf9ae 100644 --- a/src/Data/Blob.hs +++ b/src/Data/Blob.hs @@ -128,10 +128,7 @@ languageForBlobPair (Compare a b) = blobLanguage b pathForBlobPair :: BlobPair -> FilePath -pathForBlobPair x = blobPath $ case x of - Insert b -> b - Delete b -> b - Compare _ b -> b +pathForBlobPair = blobPath . mergeEdit (const id) languageTagForBlobPair :: BlobPair -> [(String, String)] languageTagForBlobPair pair = showLanguage (languageForBlobPair pair) From 0dd2021a44aa7139f24369fc6e8362317ad1b1b6 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 12:04:16 -0400 Subject: [PATCH 053/118] Define a generalization of mergeEdit. --- src/Data/Edit.hs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Data/Edit.hs b/src/Data/Edit.hs index a277502a8..729c0111f 100644 --- a/src/Data/Edit.hs +++ b/src/Data/Edit.hs @@ -3,6 +3,7 @@ module Data.Edit ( Edit(..) , edit , mergeEdit +, mergeEditWith ) where import Data.Bifoldable @@ -29,6 +30,9 @@ edit delete insert compare = \case mergeEdit :: (a -> a -> a) -> Edit a a -> a mergeEdit = edit id id +mergeEditWith :: (l -> a) -> (r -> a) -> (a -> a -> a) -> Edit l r -> a +mergeEditWith f g h = mergeEdit h . bimap f g + instance Bifunctor Edit where bimap = bimapDefault From 14182b3d215491970a6434b5fd7b0bffee154fe9 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 12:05:13 -0400 Subject: [PATCH 054/118] Use mergeEditWith to compute path keys. --- src/Data/Blob.hs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Data/Blob.hs b/src/Data/Blob.hs index 2874bf9ae..346962c8b 100644 --- a/src/Data/Blob.hs +++ b/src/Data/Blob.hs @@ -135,11 +135,9 @@ languageTagForBlobPair pair = showLanguage (languageForBlobPair pair) where showLanguage = pure . (,) "language" . show pathKeyForBlobPair :: BlobPair -> FilePath -pathKeyForBlobPair blobs = case bimap blobPath blobPath blobs of - Delete before -> before - Insert after -> after - Compare before after | before == after -> after - | otherwise -> before <> " -> " <> after +pathKeyForBlobPair = mergeEditWith blobPath blobPath combine where + combine before after | before == after = after + | otherwise = before <> " -> " <> after instance ToJSONFields Blob where toJSONFields p = [ "path" .= blobPath p, "language" .= blobLanguage p] From 1e30f499845cc9a5b1084c70cf0cb68b0cea607b Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 12:06:53 -0400 Subject: [PATCH 055/118] Use mergeEditWith to compute languageForBlobPair. --- src/Data/Blob.hs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/Data/Blob.hs b/src/Data/Blob.hs index 346962c8b..2b20f87a2 100644 --- a/src/Data/Blob.hs +++ b/src/Data/Blob.hs @@ -119,13 +119,10 @@ maybeBlobPair a b = case (a, b) of _ -> Prologue.fail "expected file pair with content on at least one side" languageForBlobPair :: BlobPair -> Language -languageForBlobPair (Delete b) = blobLanguage b -languageForBlobPair (Insert b) = blobLanguage b -languageForBlobPair (Compare a b) - | blobLanguage a == Unknown || blobLanguage b == Unknown - = Unknown - | otherwise - = blobLanguage b +languageForBlobPair = mergeEditWith blobLanguage blobLanguage combine where + combine a b + | a == Unknown || b == Unknown = Unknown + | otherwise = b pathForBlobPair :: BlobPair -> FilePath pathForBlobPair = blobPath . mergeEdit (const id) From 7e5f28dba54667a93a4324b5988b783cb2460715 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 12:10:50 -0400 Subject: [PATCH 056/118] Define an Ord2 instance for Edit. --- src/Data/Edit.hs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Data/Edit.hs b/src/Data/Edit.hs index 729c0111f..399b2fd5d 100644 --- a/src/Data/Edit.hs +++ b/src/Data/Edit.hs @@ -53,6 +53,15 @@ instance Eq2 Edit where (Compare a1 b1, Compare a2 b2) -> eqBefore a1 a2 && eqAfter b1 b2 _ -> False +instance Ord2 Edit where + liftCompare2 cmpl cmpr p1 p2 = case (p1, p2) of + (Delete a1 , Delete a2 ) -> cmpl a1 a2 + (Delete _ , _ ) -> LT + (Insert b1, Insert b2) -> cmpr b1 b2 + (Insert _ , _ ) -> LT + (Compare a1 b1, Compare a2 b2) -> cmpl a1 a2 <> cmpr b1 b2 + _ -> GT + instance Show2 Edit where liftShowsPrec2 spl _ spr _ d = \case Delete a -> showsUnaryWith spl "Delete" d a From 38cff494e768cc25abd3559a32ad7687ef6cb6ca Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 12:11:06 -0400 Subject: [PATCH 057/118] LambdaCase. --- src/Data/Edit.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Data/Edit.hs b/src/Data/Edit.hs index 399b2fd5d..d3d40078f 100644 --- a/src/Data/Edit.hs +++ b/src/Data/Edit.hs @@ -54,7 +54,7 @@ instance Eq2 Edit where _ -> False instance Ord2 Edit where - liftCompare2 cmpl cmpr p1 p2 = case (p1, p2) of + liftCompare2 cmpl cmpr = curry $ \case (Delete a1 , Delete a2 ) -> cmpl a1 a2 (Delete _ , _ ) -> LT (Insert b1, Insert b2) -> cmpr b1 b2 From 0764de8320dac9fdb994771f912b0058d626fa67 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 12:11:19 -0400 Subject: [PATCH 058/118] LambdaCase. --- src/Data/Edit.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Data/Edit.hs b/src/Data/Edit.hs index d3d40078f..22ae1784c 100644 --- a/src/Data/Edit.hs +++ b/src/Data/Edit.hs @@ -47,7 +47,7 @@ instance Bitraversable Edit where Compare a b -> Compare <$> f a <*> g b instance Eq2 Edit where - liftEq2 eqBefore eqAfter p1 p2 = case (p1, p2) of + liftEq2 eqBefore eqAfter = curry $ \case (Delete a1, Delete a2) -> eqBefore a1 a2 (Insert b1, Insert b2) -> eqAfter b1 b2 (Compare a1 b1, Compare a2 b2) -> eqBefore a1 a2 && eqAfter b1 b2 From 8a7d72edbf41415fe60f3b3a46f3103deddca658 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 12:11:33 -0400 Subject: [PATCH 059/118] Rename the eq parameters. --- src/Data/Edit.hs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Data/Edit.hs b/src/Data/Edit.hs index 22ae1784c..1c3a1cf9a 100644 --- a/src/Data/Edit.hs +++ b/src/Data/Edit.hs @@ -47,10 +47,10 @@ instance Bitraversable Edit where Compare a b -> Compare <$> f a <*> g b instance Eq2 Edit where - liftEq2 eqBefore eqAfter = curry $ \case - (Delete a1, Delete a2) -> eqBefore a1 a2 - (Insert b1, Insert b2) -> eqAfter b1 b2 - (Compare a1 b1, Compare a2 b2) -> eqBefore a1 a2 && eqAfter b1 b2 + liftEq2 eql eqr = curry $ \case + (Delete a1, Delete a2) -> eql a1 a2 + (Insert b1, Insert b2) -> eqr b1 b2 + (Compare a1 b1, Compare a2 b2) -> eql a1 a2 && eqr b1 b2 _ -> False instance Ord2 Edit where From f870e977ffcf5c66447273e54ba38da1c35abf89 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 12:12:02 -0400 Subject: [PATCH 060/118] Align. --- src/Data/Edit.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Data/Edit.hs b/src/Data/Edit.hs index 1c3a1cf9a..211ffb50f 100644 --- a/src/Data/Edit.hs +++ b/src/Data/Edit.hs @@ -48,10 +48,10 @@ instance Bitraversable Edit where instance Eq2 Edit where liftEq2 eql eqr = curry $ \case - (Delete a1, Delete a2) -> eql a1 a2 - (Insert b1, Insert b2) -> eqr b1 b2 + (Delete a1 , Delete a2 ) -> eql a1 a2 + (Insert b1, Insert b2) -> eqr b1 b2 (Compare a1 b1, Compare a2 b2) -> eql a1 a2 && eqr b1 b2 - _ -> False + _ -> False instance Ord2 Edit where liftCompare2 cmpl cmpr = curry $ \case From b3e6f527a309457ee2640bb083715c3a5a477d4a Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 12:12:29 -0400 Subject: [PATCH 061/118] More alignment. --- src/Data/Edit.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Data/Edit.hs b/src/Data/Edit.hs index 211ffb50f..a67f0d484 100644 --- a/src/Data/Edit.hs +++ b/src/Data/Edit.hs @@ -49,7 +49,7 @@ instance Bitraversable Edit where instance Eq2 Edit where liftEq2 eql eqr = curry $ \case (Delete a1 , Delete a2 ) -> eql a1 a2 - (Insert b1, Insert b2) -> eqr b1 b2 + (Insert b1, Insert b2) -> eqr b1 b2 (Compare a1 b1, Compare a2 b2) -> eql a1 a2 && eqr b1 b2 _ -> False @@ -57,7 +57,7 @@ instance Ord2 Edit where liftCompare2 cmpl cmpr = curry $ \case (Delete a1 , Delete a2 ) -> cmpl a1 a2 (Delete _ , _ ) -> LT - (Insert b1, Insert b2) -> cmpr b1 b2 + (Insert b1, Insert b2) -> cmpr b1 b2 (Insert _ , _ ) -> LT (Compare a1 b1, Compare a2 b2) -> cmpl a1 a2 <> cmpr b1 b2 _ -> GT From a2812137c252777b8be6f1751f9635f7a804593d Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 12:12:55 -0400 Subject: [PATCH 062/118] Alignment. --- src/Data/Edit.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Data/Edit.hs b/src/Data/Edit.hs index a67f0d484..1dddc879b 100644 --- a/src/Data/Edit.hs +++ b/src/Data/Edit.hs @@ -64,6 +64,6 @@ instance Ord2 Edit where instance Show2 Edit where liftShowsPrec2 spl _ spr _ d = \case - Delete a -> showsUnaryWith spl "Delete" d a - Insert b -> showsUnaryWith spr "Insert" d b + Delete a -> showsUnaryWith spl "Delete" d a + Insert b -> showsUnaryWith spr "Insert" d b Compare a b -> showsBinaryWith spl spr "Compare" d a b From 84a448ad4fe7b26588f53a925f8ac76913c248a8 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 12:14:47 -0400 Subject: [PATCH 063/118] Simplify the Bitraversable instance. --- src/Data/Edit.hs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Data/Edit.hs b/src/Data/Edit.hs index 1dddc879b..2fb9ca3a2 100644 --- a/src/Data/Edit.hs +++ b/src/Data/Edit.hs @@ -6,6 +6,7 @@ module Data.Edit , mergeEditWith ) where +import Control.Applicative (liftA2) import Data.Bifoldable import Data.Bifunctor import Data.Bitraversable @@ -41,10 +42,7 @@ instance Bifoldable Edit where bifoldMap = bifoldMapDefault instance Bitraversable Edit where - bitraverse f g = \case - Delete a -> Delete <$> f a - Insert b -> Insert <$> g b - Compare a b -> Compare <$> f a <*> g b + bitraverse f g = edit (fmap Delete) (fmap Insert) (liftA2 Compare) . bimap f g instance Eq2 Edit where liftEq2 eql eqr = curry $ \case From 6722f2f9dae299258aafa9945b280ae78ed85aa8 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 12:15:20 -0400 Subject: [PATCH 064/118] Fix docs. --- src/Data/Edit.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Data/Edit.hs b/src/Data/Edit.hs index 2fb9ca3a2..ac62d57f8 100644 --- a/src/Data/Edit.hs +++ b/src/Data/Edit.hs @@ -13,7 +13,7 @@ import Data.Bitraversable import Data.Functor.Classes import GHC.Generics (Generic, Generic1) --- | An operation to compare, insert, or delete an item. +-- | The deletion, insertion, or comparison of values. data Edit a b = Delete a | Insert b @@ -21,7 +21,7 @@ data Edit a b deriving (Eq, Foldable, Functor, Generic, Generic1, Ord, Show, Traversable) --- | Return both sides of a patch. +-- | Return both sides of an edit. edit :: (l -> a) -> (r -> a) -> (l -> r -> a) -> Edit l r -> a edit delete insert compare = \case Delete a -> delete a From f140d97d23aa11ef264c924066609e768e88863f Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 12:16:26 -0400 Subject: [PATCH 065/118] Fix the docs for edit. --- src/Data/Edit.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Data/Edit.hs b/src/Data/Edit.hs index ac62d57f8..32513f6b7 100644 --- a/src/Data/Edit.hs +++ b/src/Data/Edit.hs @@ -21,7 +21,7 @@ data Edit a b deriving (Eq, Foldable, Functor, Generic, Generic1, Ord, Show, Traversable) --- | Return both sides of an edit. +-- | Eliminate an 'Edit' by case analysis. edit :: (l -> a) -> (r -> a) -> (l -> r -> a) -> Edit l r -> a edit delete insert compare = \case Delete a -> delete a From 1d72bfe0ef98ed8a580941a8a4bae968d8d3e6ba Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 12:17:34 -0400 Subject: [PATCH 066/118] :memo: mergeEdit. --- src/Data/Edit.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Data/Edit.hs b/src/Data/Edit.hs index 32513f6b7..eb277a0da 100644 --- a/src/Data/Edit.hs +++ b/src/Data/Edit.hs @@ -28,6 +28,7 @@ edit delete insert compare = \case Insert b -> insert b Compare a b -> compare a b +-- | Extract the values from an 'Edit', combining 'Compare's with the passed function. mergeEdit :: (a -> a -> a) -> Edit a a -> a mergeEdit = edit id id From c80af0fc2188de907a98ea7ccbc798c8e8f1452e Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 12:18:47 -0400 Subject: [PATCH 067/118] :fire: mergeEditWith. --- src/Data/Blob.hs | 4 ++-- src/Data/Edit.hs | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Data/Blob.hs b/src/Data/Blob.hs index 2b20f87a2..cebef5dd5 100644 --- a/src/Data/Blob.hs +++ b/src/Data/Blob.hs @@ -119,7 +119,7 @@ maybeBlobPair a b = case (a, b) of _ -> Prologue.fail "expected file pair with content on at least one side" languageForBlobPair :: BlobPair -> Language -languageForBlobPair = mergeEditWith blobLanguage blobLanguage combine where +languageForBlobPair = mergeEdit combine . bimap blobLanguage blobLanguage where combine a b | a == Unknown || b == Unknown = Unknown | otherwise = b @@ -132,7 +132,7 @@ languageTagForBlobPair pair = showLanguage (languageForBlobPair pair) where showLanguage = pure . (,) "language" . show pathKeyForBlobPair :: BlobPair -> FilePath -pathKeyForBlobPair = mergeEditWith blobPath blobPath combine where +pathKeyForBlobPair = mergeEdit combine . bimap blobPath blobPath where combine before after | before == after = after | otherwise = before <> " -> " <> after diff --git a/src/Data/Edit.hs b/src/Data/Edit.hs index eb277a0da..084a06538 100644 --- a/src/Data/Edit.hs +++ b/src/Data/Edit.hs @@ -3,7 +3,6 @@ module Data.Edit ( Edit(..) , edit , mergeEdit -, mergeEditWith ) where import Control.Applicative (liftA2) @@ -32,9 +31,6 @@ edit delete insert compare = \case mergeEdit :: (a -> a -> a) -> Edit a a -> a mergeEdit = edit id id -mergeEditWith :: (l -> a) -> (r -> a) -> (a -> a -> a) -> Edit l r -> a -mergeEditWith f g h = mergeEdit h . bimap f g - instance Bifunctor Edit where bimap = bimapDefault From 1bdf9ff63a0e50fa3725b4bd5264e5bc6a851d8a Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 12:19:02 -0400 Subject: [PATCH 068/118] Alignment. --- src/Data/Edit.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Data/Edit.hs b/src/Data/Edit.hs index 084a06538..d9ac0437f 100644 --- a/src/Data/Edit.hs +++ b/src/Data/Edit.hs @@ -14,8 +14,8 @@ import GHC.Generics (Generic, Generic1) -- | The deletion, insertion, or comparison of values. data Edit a b - = Delete a - | Insert b + = Delete a + | Insert b | Compare a b deriving (Eq, Foldable, Functor, Generic, Generic1, Ord, Show, Traversable) From cb3fa623b1cbe64289fd081dfad988a79758d042 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 12:20:32 -0400 Subject: [PATCH 069/118] Alignment. --- src/Data/Blob.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Data/Blob.hs b/src/Data/Blob.hs index cebef5dd5..59e385f43 100644 --- a/src/Data/Blob.hs +++ b/src/Data/Blob.hs @@ -104,7 +104,7 @@ type BlobPair = Edit Blob Blob instance FromJSON BlobPair where parseJSON = withObject "BlobPair" $ \o -> do before <- o .:? "before" - after <- o .:? "after" + after <- o .:? "after" case (before, after) of (Just b, Just a) -> pure $ Compare b a (Just b, Nothing) -> pure $ Delete b From fc93bb4b4d0c311671f76f6d4ee836d4f2b87954 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 12:24:44 -0400 Subject: [PATCH 070/118] Define a helper to construct an Edit from a pair of Maybes. --- src/Data/Edit.hs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Data/Edit.hs b/src/Data/Edit.hs index d9ac0437f..50735be37 100644 --- a/src/Data/Edit.hs +++ b/src/Data/Edit.hs @@ -3,9 +3,10 @@ module Data.Edit ( Edit(..) , edit , mergeEdit +, fromMaybes ) where -import Control.Applicative (liftA2) +import Control.Applicative ((<|>), liftA2) import Data.Bifoldable import Data.Bifunctor import Data.Bitraversable @@ -31,6 +32,9 @@ edit delete insert compare = \case mergeEdit :: (a -> a -> a) -> Edit a a -> a mergeEdit = edit id id +fromMaybes :: Maybe a -> Maybe b -> Maybe (Edit a b) +fromMaybes a b = liftA2 Compare a b <|> Delete <$> a <|> Insert <$> b + instance Bifunctor Edit where bimap = bimapDefault From fecb0d8f1f0ad9ab2c5c3310c77c66aa8c892680 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 12:25:09 -0400 Subject: [PATCH 071/118] Use fromMaybes to clean up the FromJSON instance for BlobPair. --- src/Data/Blob.hs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Data/Blob.hs b/src/Data/Blob.hs index 59e385f43..3a78a1c42 100644 --- a/src/Data/Blob.hs +++ b/src/Data/Blob.hs @@ -105,11 +105,7 @@ instance FromJSON BlobPair where parseJSON = withObject "BlobPair" $ \o -> do before <- o .:? "before" after <- o .:? "after" - case (before, after) of - (Just b, Just a) -> pure $ Compare b a - (Just b, Nothing) -> pure $ Delete b - (Nothing, Just a) -> pure $ Insert a - _ -> Prelude.fail "Expected object with 'before' and/or 'after' keys only" + maybeM (Prelude.fail "Expected object with 'before' and/or 'after' keys only") (fromMaybes before after) maybeBlobPair :: MonadFail m => Maybe Blob -> Maybe Blob -> m BlobPair maybeBlobPair a b = case (a, b) of From 41f38b1c59ad4dbbaad7a5e35d246361277be6f2 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 12:25:40 -0400 Subject: [PATCH 072/118] Use Applicative to tidy up further. --- src/Data/Blob.hs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Data/Blob.hs b/src/Data/Blob.hs index 3a78a1c42..09020e262 100644 --- a/src/Data/Blob.hs +++ b/src/Data/Blob.hs @@ -102,10 +102,9 @@ noLanguageForBlob blobPath = throwError (SomeException (NoLanguageForBlob blobPa type BlobPair = Edit Blob Blob instance FromJSON BlobPair where - parseJSON = withObject "BlobPair" $ \o -> do - before <- o .:? "before" - after <- o .:? "after" - maybeM (Prelude.fail "Expected object with 'before' and/or 'after' keys only") (fromMaybes before after) + parseJSON = withObject "BlobPair" $ \o -> + fromMaybes <$> (o .:? "before") <*> (o .:? "after") + >>= maybeM (Prelude.fail "Expected object with 'before' and/or 'after' keys only") maybeBlobPair :: MonadFail m => Maybe Blob -> Maybe Blob -> m BlobPair maybeBlobPair a b = case (a, b) of From b6f9fea37d1f8a1bc9a801fb879ef884d8a8076f Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 12:26:50 -0400 Subject: [PATCH 073/118] Use fromMaybes to define maybeBlobPair. --- src/Data/Blob.hs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Data/Blob.hs b/src/Data/Blob.hs index 09020e262..80ae3c825 100644 --- a/src/Data/Blob.hs +++ b/src/Data/Blob.hs @@ -107,11 +107,7 @@ instance FromJSON BlobPair where >>= maybeM (Prelude.fail "Expected object with 'before' and/or 'after' keys only") maybeBlobPair :: MonadFail m => Maybe Blob -> Maybe Blob -> m BlobPair -maybeBlobPair a b = case (a, b) of - (Just a, Nothing) -> pure (Delete a) - (Nothing, Just b) -> pure (Insert b) - (Just a, Just b) -> pure (Compare a b) - _ -> Prologue.fail "expected file pair with content on at least one side" +maybeBlobPair a b = maybeM (Prologue.fail "expected file pair with content on at least one side") (fromMaybes a b) languageForBlobPair :: BlobPair -> Language languageForBlobPair = mergeEdit combine . bimap blobLanguage blobLanguage where From f119b444ff40e8c5a5468fa5a56b2097f09461c7 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 12:28:13 -0400 Subject: [PATCH 074/118] Rename a parameter. --- src/Rendering/TOC.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Rendering/TOC.hs b/src/Rendering/TOC.hs index a472c8f9f..169d7a63e 100644 --- a/src/Rendering/TOC.hs +++ b/src/Rendering/TOC.hs @@ -77,7 +77,7 @@ tableOfContentsBy :: (Foldable f, Functor f) -> Diff f ann ann -- ^ The diff to compute the table of contents for. -> [(Change, a)] -- ^ A list of entries for relevant changed nodes in the diff. tableOfContentsBy selector = fromMaybe [] . cata (\ r -> case r of - Patch patch -> (pure . patchEntry <$> select (bimap selector selector patch)) <> bifoldMap fold fold patch <> Just [] + Patch edit -> (pure . patchEntry <$> select (bimap selector selector edit)) <> bifoldMap fold fold edit <> Just [] Merge (In (_, ann2) r) -> case (selector (In ann2 r), fold r) of (Just a, Just entries) -> Just ((Changed, a) : entries) (_ , entries) -> entries) From e31f59ccdaefcf12606bd68a134b5b2811c13046 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 12:40:18 -0400 Subject: [PATCH 075/118] Alignment. --- src/Semantic/Api/Bridge.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Semantic/Api/Bridge.hs b/src/Semantic/Api/Bridge.hs index 43fdd153d..3047e2556 100644 --- a/src/Semantic/Api/Bridge.hs +++ b/src/Semantic/Api/Bridge.hs @@ -85,5 +85,5 @@ instance APIConvert API.BlobPair Data.BlobPair where _ -> Nothing blobPairToApiBlobPair (Data.Compare before after) = defMessage & P.maybe'before .~ (bridging #? before) & P.maybe'after .~ (bridging #? after) - blobPairToApiBlobPair (Data.Insert after) = defMessage & P.maybe'before .~ Nothing & P.maybe'after .~ (bridging #? after) - blobPairToApiBlobPair (Data.Delete before) = defMessage & P.maybe'before .~ (bridging #? before) & P.maybe'after .~ Nothing + blobPairToApiBlobPair (Data.Insert after) = defMessage & P.maybe'before .~ Nothing & P.maybe'after .~ (bridging #? after) + blobPairToApiBlobPair (Data.Delete before) = defMessage & P.maybe'before .~ (bridging #? before) & P.maybe'after .~ Nothing From 11d052f594fa4b7b5ddefb29e04b2aa326a108c9 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 18 Oct 2019 12:45:17 -0400 Subject: [PATCH 076/118] Fix an elided reference. --- test/Diffing/Algorithm/RWS/Spec.hs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/Diffing/Algorithm/RWS/Spec.hs b/test/Diffing/Algorithm/RWS/Spec.hs index 4e7b74c04..9bc874f20 100644 --- a/test/Diffing/Algorithm/RWS/Spec.hs +++ b/test/Diffing/Algorithm/RWS/Spec.hs @@ -39,6 +39,8 @@ spec = do where decorate = defaultFeatureVectorDecorator + diffEdit = edit deleting inserting comparing + stripTerm :: Functor f => Term f (FeatureVector, ()) -> Term f () stripTerm = fmap snd From 559e2e0c59e1b53d9ffd34897b00d89f4f417b5a Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 21 Oct 2019 11:42:55 -0400 Subject: [PATCH 077/118] Fix a missed rename. --- test/Data/Functor/Listable.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Data/Functor/Listable.hs b/test/Data/Functor/Listable.hs index 16dabf916..ebc943c26 100644 --- a/test/Data/Functor/Listable.hs +++ b/test/Data/Functor/Listable.hs @@ -157,7 +157,7 @@ instance (Listable1 syntax, Listable ann1, Listable ann2) => Listable (Diff synt instance Listable2 Edit where - liftTiers2 t1 t2 = liftCons1 t2 Insert \/ liftCons1 t1 Delete \/ liftCons2 t1 t2 Replace + liftTiers2 t1 t2 = liftCons1 t2 Insert \/ liftCons1 t1 Delete \/ liftCons2 t1 t2 Compare instance (Listable a, Listable b) => Listable (Edit a b) where tiers = tiers2 From 5da3a1183b8c014186b73f769ee644b2ecfc2475 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 21 Oct 2019 12:03:07 -0400 Subject: [PATCH 078/118] Correct stale references to patch. --- test/Rendering/TOC/Spec.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Rendering/TOC/Spec.hs b/test/Rendering/TOC/Spec.hs index dc65a1ec7..7e091df89 100644 --- a/test/Rendering/TOC/Spec.hs +++ b/test/Rendering/TOC/Spec.hs @@ -36,9 +36,9 @@ spec = do \ term -> tableOfContentsBy (Just . termFAnnotation) (diffTerms term (term :: Term ListableSyntax ())) `shouldBe` [] prop "produces inserted/deleted/replaced entries for relevant nodes within patches" $ - \ p -> tableOfContentsBy (Just . termFAnnotation) (patch deleting inserting comparing p) + \ p -> tableOfContentsBy (Just . termFAnnotation) (edit deleting inserting comparing p) `shouldBe` - patch (fmap (Deleted,)) (fmap (Inserted,)) (\ as bs -> (Replaced, head bs) : fmap (Deleted,) (tail as) <> fmap (Inserted,) (tail bs)) (bimap (foldMap pure) (foldMap pure) (p :: Edit (Term ListableSyntax Int) (Term ListableSyntax Int))) + edit (fmap (Deleted,)) (fmap (Inserted,)) (\ as bs -> (Replaced, head bs) : fmap (Deleted,) (tail as) <> fmap (Inserted,) (tail bs)) (bimap (foldMap pure) (foldMap pure) (p :: Edit (Term ListableSyntax Int) (Term ListableSyntax Int))) prop "produces changed entries for relevant nodes containing irrelevant patches" $ \ diff -> do From 7ae14819c9b38d8832c632feb39092edfb99c1ff Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 21 Oct 2019 13:19:27 -0400 Subject: [PATCH 079/118] :fire: a redundant import. --- test/Diffing/Algorithm/RWS/Spec.hs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/Diffing/Algorithm/RWS/Spec.hs b/test/Diffing/Algorithm/RWS/Spec.hs index 9bc874f20..0569b2998 100644 --- a/test/Diffing/Algorithm/RWS/Spec.hs +++ b/test/Diffing/Algorithm/RWS/Spec.hs @@ -10,7 +10,6 @@ import Data.Term import Diffing.Algorithm (comparableTerms) import Diffing.Interpreter (stripDiff) import Diffing.Algorithm.RWS -import Diffing.Algorithm.SES import Diffing.Interpreter.Spec (afterTerm, beforeTerm) import Test.Hspec.LeanCheck import SpecHelpers From f822bb15c6410a7be2a8b2673465cec659276401 Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Mon, 21 Oct 2019 14:05:21 -0400 Subject: [PATCH 080/118] Adjust hlint settings for a new (GHC 8.6+) universe. --- .hlint.yaml | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/.hlint.yaml b/.hlint.yaml index e8e2be0e8..4111be9a7 100644 --- a/.hlint.yaml +++ b/.hlint.yaml @@ -34,6 +34,10 @@ # Change the severity of hints we don’t want to fail CI for - suggest: {name: Eta reduce} +# While I think DerivingStrategies is good, it's too noisy to suggest by default +- ignore: + name: Use DerivingStrategies + # Ignore eta reduce in the assignment modules - ignore: name: Eta reduce @@ -45,8 +49,29 @@ - ignore: {name: Use ., within: [Analysis.Abstract.Graph.graphingModules, Semantic.Distribute]} -- ignore: {name: Reduce duplication, within: [Semantic.Util, Semantic.UtilDisabled]} -- ignore: {name: Use newtype instead of data, within: [Semantic.Api.V1.CodeAnalysisPB]} +- ignore: + within: + - Proto.Semantic + - Proto.Semantic_Fields + - Proto.Semantic_JSON + +- ignore: + name: Reduce duplication + within: + - Semantic.Util + +# hlint has issues with QuantifiedConstraints (see https://github.com/ndmitchell/hlint/issues/759) +# Once the above is fixed, we can drop this error. + +- ignore: { name: Parse error } + +# hlint is too paranoid about NonEmpty functions (https://github.com/ndmitchell/hlint/issues/787) + +- ignore: + name: Avoid restricted function + within: + - Language.Python.Syntax + - Data.Syntax.Expression # Our customized warnings From fd06ccf462445ed63727f8534afbd5882344e61a Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Mon, 21 Oct 2019 14:05:44 -0400 Subject: [PATCH 081/118] Address hlint suggestions in semantic. --- src/Control/Abstract/Value.hs | 20 ++++---------------- src/Control/Carrier/Parse/Simple.hs | 2 +- src/Data/Diff.hs | 4 ++-- src/Data/ImportPath.hs | 2 +- src/Data/Syntax/Declaration.hs | 4 +--- src/Rendering/TOC.hs | 2 +- src/Semantic/Analysis.hs | 4 ++-- src/Semantic/Api/Bridge.hs | 2 +- src/Semantic/Task.hs | 2 +- src/Serializing/SExpression/Precise.hs | 2 +- src/Tags/Taggable.hs | 2 +- src/Tags/Tagging.hs | 11 +++++------ 12 files changed, 21 insertions(+), 36 deletions(-) diff --git a/src/Control/Abstract/Value.hs b/src/Control/Abstract/Value.hs index a5bc48e1f..ca7165132 100644 --- a/src/Control/Abstract/Value.hs +++ b/src/Control/Abstract/Value.hs @@ -292,15 +292,9 @@ liftNumeric2 :: (Member (Numeric value) sig, Carrier sig m) -> m value liftNumeric2 t v1 v2 = send (LiftNumeric2 (Numeric2Function t) v1 v2 pure) -data NumericFunction = NumericFunction (forall a . Num a => a -> a) +newtype NumericFunction = NumericFunction { runNumericFunction :: forall a . Num a => a -> a } -runNumericFunction :: Num a => NumericFunction -> a -> a -runNumericFunction (NumericFunction f) a = f a - -data Numeric2Function = Numeric2Function (forall a b. Number a -> Number b -> SomeNumber) - -runNumeric2Function :: Numeric2Function -> Number a -> Number b -> SomeNumber -runNumeric2Function (Numeric2Function f) a b = f a b +newtype Numeric2Function = Numeric2Function { runNumeric2Function :: forall a b. Number a -> Number b -> SomeNumber } data Numeric value (m :: * -> *) k = Integer Integer (value -> m k) @@ -347,15 +341,9 @@ unsignedRShift :: (Member (Bitwise value) sig, Carrier sig m) -> m value unsignedRShift v1 v2 = send (UnsignedRShift v1 v2 pure) -data BitwiseFunction = BitwiseFunction (forall a . Bits a => a -> a) +newtype BitwiseFunction = BitwiseFunction { runBitwiseFunction :: forall a . Bits a => a -> a } -runBitwiseFunction :: Bits a => BitwiseFunction -> a -> a -runBitwiseFunction (BitwiseFunction f) a = f a - -data Bitwise2Function = Bitwise2Function (forall a . (Integral a, Bits a) => a -> a -> a) - -runBitwise2Function :: (Integral a, Bits a) => Bitwise2Function -> a -> a -> a -runBitwise2Function (Bitwise2Function f) a b = f a b +newtype Bitwise2Function = Bitwise2Function { runBitwise2Function :: forall a . (Integral a, Bits a) => a -> a -> a } data Bitwise value (m :: * -> *) k = CastToInteger value (value -> m k) diff --git a/src/Control/Carrier/Parse/Simple.hs b/src/Control/Carrier/Parse/Simple.hs index 4dc1d6243..12dc5dcbe 100644 --- a/src/Control/Carrier/Parse/Simple.hs +++ b/src/Control/Carrier/Parse/Simple.hs @@ -63,7 +63,7 @@ runParser timeout blob@Blob{..} parser = case parser of let term = cmarkParser blobSource in length term `seq` pure term -data ParseFailure = ParseFailure String +newtype ParseFailure = ParseFailure String deriving (Show, Typeable) instance Exception ParseFailure diff --git a/src/Data/Diff.hs b/src/Data/Diff.hs index 94c0d3999..80b09616d 100644 --- a/src/Data/Diff.hs +++ b/src/Data/Diff.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE DataKinds, RankNTypes, TypeFamilies, TypeOperators, ScopedTypeVariables, UndecidableInstances #-} +{-# LANGUAGE DataKinds, LambdaCase, RankNTypes, TypeFamilies, TypeOperators, ScopedTypeVariables, UndecidableInstances #-} module Data.Diff ( Diff(..) , DiffF(..) @@ -76,7 +76,7 @@ merging = cata (\ (In ann syntax) -> mergeF (In (ann, ann) syntax)) diffPatches :: (Foldable syntax, Functor syntax) => Diff syntax ann1 ann2 -> [Patch (TermF syntax ann1 (Diff syntax ann1 ann2)) (TermF syntax ann2 (Diff syntax ann1 ann2))] -diffPatches = para $ \ diff -> case diff of +diffPatches = para $ \case Patch patch -> bimap (fmap fst) (fmap fst) patch : bifoldMap (foldMap snd) (foldMap snd) patch Merge merge -> foldMap snd merge diff --git a/src/Data/ImportPath.hs b/src/Data/ImportPath.hs index 22f9201a2..2cbe895bc 100644 --- a/src/Data/ImportPath.hs +++ b/src/Data/ImportPath.hs @@ -19,7 +19,7 @@ data ImportPath = ImportPath { unPath :: FilePath, pathIsRelative :: IsRelative importPath :: Text -> ImportPath importPath str = let path = stripQuotes str in ImportPath (T.unpack path) (pathType path) where - pathType xs | not (T.null xs), T.head xs == '.' = Relative -- head call here is safe + pathType xs | not (T.null xs), fmap fst (T.uncons xs) == Just '.' = Relative -- head call here is safe | otherwise = NonRelative defaultAlias :: ImportPath -> Name diff --git a/src/Data/Syntax/Declaration.hs b/src/Data/Syntax/Declaration.hs index 0c166d8f9..6eff484f5 100644 --- a/src/Data/Syntax/Declaration.hs +++ b/src/Data/Syntax/Declaration.hs @@ -216,9 +216,7 @@ instance Evaluatable Class where currentScope' <- currentScope superScopes <- for classSuperclasses $ \superclass -> do - name <- case declaredName superclass of - Just name -> pure name - Nothing -> gensym + name <- maybeM gensym (declaredName superclass) scope <- associatedScope (Declaration name) slot <- lookupSlot (Declaration name) superclassFrame <- scopedEnvironment =<< deref slot diff --git a/src/Rendering/TOC.hs b/src/Rendering/TOC.hs index d6b03188c..81c318c87 100644 --- a/src/Rendering/TOC.hs +++ b/src/Rendering/TOC.hs @@ -77,7 +77,7 @@ tableOfContentsBy :: (Foldable f, Functor f) => (forall b. TermF f ann b -> Maybe a) -- ^ A function mapping relevant nodes onto values in Maybe. -> Diff f ann ann -- ^ The diff to compute the table of contents for. -> [(Change, a)] -- ^ A list of entries for relevant changed nodes in the diff. -tableOfContentsBy selector = fromMaybe [] . cata (\ r -> case r of +tableOfContentsBy selector = fromMaybe [] . cata (\case Patch patch -> (pure . patchEntry <$> bicrosswalk selector selector patch) <> bifoldMap fold fold patch <> Just [] Merge (In (_, ann2) r) -> case (selector (In ann2 r), fold r) of (Just a, Just entries) -> Just ((Changed, a) : entries) diff --git a/src/Semantic/Analysis.hs b/src/Semantic/Analysis.hs index 3b7d702b3..e66361d6d 100644 --- a/src/Semantic/Analysis.hs +++ b/src/Semantic/Analysis.hs @@ -46,10 +46,10 @@ type DomainC term address value m -- | Evaluate a list of modules with the prelude for the passed language available, and applying the passed function to every module. evaluate :: ( Carrier outerSig outer , derefSig ~ (Deref value :+: allocatorSig) - , derefC ~ (DerefC address value allocatorC) + , derefC ~ DerefC address value allocatorC , Carrier derefSig derefC , allocatorSig ~ (Allocator address :+: Reader ModuleInfo :+: outerSig) - , allocatorC ~ (AllocatorC address (ReaderC ModuleInfo outer)) + , allocatorC ~ AllocatorC address (ReaderC ModuleInfo outer) , Carrier allocatorSig allocatorC , Effect outerSig , Member Fresh outerSig diff --git a/src/Semantic/Api/Bridge.hs b/src/Semantic/Api/Bridge.hs index dee30b8ea..0292605cf 100644 --- a/src/Semantic/Api/Bridge.hs +++ b/src/Semantic/Api/Bridge.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE FunctionalDependencies, LambdaCase #-} +{-# LANGUAGE FunctionalDependencies #-} module Semantic.Api.Bridge ( APIBridge (..) , APIConvert (..) diff --git a/src/Semantic/Task.hs b/src/Semantic/Task.hs index 351296fbc..5ee650b0a 100644 --- a/src/Semantic/Task.hs +++ b/src/Semantic/Task.hs @@ -1,5 +1,5 @@ {-# LANGUAGE ConstraintKinds, ExistentialQuantification, GADTs, GeneralizedNewtypeDeriving, KindSignatures, - ScopedTypeVariables, StandaloneDeriving, TypeOperators, UndecidableInstances #-} + ScopedTypeVariables, TypeOperators, UndecidableInstances #-} module Semantic.Task ( TaskC , Level(..) diff --git a/src/Serializing/SExpression/Precise.hs b/src/Serializing/SExpression/Precise.hs index ae2cf6b21..70238e405 100644 --- a/src/Serializing/SExpression/Precise.hs +++ b/src/Serializing/SExpression/Precise.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE AllowAmbiguousTypes, DataKinds, FlexibleContexts, FlexibleInstances, KindSignatures, MultiParamTypeClasses, OverloadedStrings, ScopedTypeVariables, TypeApplications, TypeFamilies, TypeOperators, UndecidableInstances #-} +{-# LANGUAGE AllowAmbiguousTypes, DataKinds, FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, OverloadedStrings, ScopedTypeVariables, TypeApplications, TypeFamilies, TypeOperators, UndecidableInstances #-} module Serializing.SExpression.Precise ( serializeSExpression , ToSExpression(..) diff --git a/src/Tags/Taggable.hs b/src/Tags/Taggable.hs index c5d8eb516..b90174df2 100644 --- a/src/Tags/Taggable.hs +++ b/src/Tags/Taggable.hs @@ -12,7 +12,7 @@ identify a new syntax as Taggable, you need to: constructor name of this syntax. -} -{-# LANGUAGE AllowAmbiguousTypes, ConstraintKinds, KindSignatures, ScopedTypeVariables, TypeFamilies, UndecidableInstances #-} +{-# LANGUAGE AllowAmbiguousTypes, ConstraintKinds, ScopedTypeVariables, TypeFamilies, UndecidableInstances #-} module Tags.Taggable ( Tagger , Token(..) diff --git a/src/Tags/Tagging.hs b/src/Tags/Tagging.hs index ae2d22e2c..4b06f0855 100644 --- a/src/Tags/Tagging.hs +++ b/src/Tags/Tagging.hs @@ -57,12 +57,11 @@ contextualizing :: ( Member (State [ContextToken]) sig contextualizing source toKind = Streaming.mapMaybeM $ \case Enter x r -> Nothing <$ enterScope (x, r) Exit x r -> Nothing <$ exitScope (x, r) - Iden iden loc docsLiteralRange -> get @[ContextToken] >>= pure . \case - ((x, r):("Context", cr):_) | Just kind <- toKind x - -> Just $ Tag iden kind loc (firstLine (slice r)) (Just (slice cr)) - ((x, r):_) | Just kind <- toKind x - -> Just $ Tag iden kind loc (firstLine (slice r)) (slice <$> docsLiteralRange) - _ -> Nothing + Iden iden loc docsLiteralRange -> fmap go (get @[ContextToken]) where + go = \case + ((x, r):("Context", cr):_) | Just kind <- toKind x -> Just $ Tag iden kind loc (firstLine (slice r)) (Just (slice cr)) + ((x, r):_) | Just kind <- toKind x -> Just $ Tag iden kind loc (firstLine (slice r)) (slice <$> docsLiteralRange) + _ -> Nothing where slice = stripEnd . Source.toText . Source.slice source firstLine = T.take 180 . fst . breakOn "\n" From 2d4f4cb64aae234510edf8098e9162c4422429dc Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Mon, 21 Oct 2019 14:09:02 -0400 Subject: [PATCH 082/118] Run hlint in Travis. --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 5bdd102fe..63dd54678 100644 --- a/.travis.yml +++ b/.travis.yml @@ -42,6 +42,8 @@ script: - cabal new-run semantic-source:doctest # parse-examples is disabled because it slaughters our CI # - cabal new-run semantic:parse-examples +# Downloads an hlint binary rather than going through cabal-install +- curl -sSL https://raw.github.com/ndmitchell/hlint/master/misc/run.sh | sh -s src # Any branch linked with a pull request will be built, as well as the non-PR # branches listed below: From 386e8317dc2c91792417cceb301e67957b34b0cc Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Mon, 21 Oct 2019 14:09:20 -0400 Subject: [PATCH 083/118] lint semantic-python --- .travis.yml | 2 +- semantic-python/test/Directive.hs | 4 ++-- semantic-python/test/Instances.hs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 63dd54678..0990cfac6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -43,7 +43,7 @@ script: # parse-examples is disabled because it slaughters our CI # - cabal new-run semantic:parse-examples # Downloads an hlint binary rather than going through cabal-install -- curl -sSL https://raw.github.com/ndmitchell/hlint/master/misc/run.sh | sh -s src +- curl -sSL https://raw.github.com/ndmitchell/hlint/master/misc/run.sh | sh -s src semantic-python # Any branch linked with a pull request will be built, as well as the non-PR # branches listed below: diff --git a/semantic-python/test/Directive.hs b/semantic-python/test/Directive.hs index db95ff4dc..cd81413e4 100644 --- a/semantic-python/test/Directive.hs +++ b/semantic-python/test/Directive.hs @@ -7,8 +7,8 @@ module Directive ( Directive (..) import Control.Applicative import Control.Monad import Core.Core (Core) -import qualified Core.Parser as Core.Parser -import qualified Core.Pretty as Core.Pretty +import qualified Core.Parser +import qualified Core.Pretty import Core.Name (Name) import Data.ByteString.Char8 (ByteString) import qualified Data.ByteString.Char8 as ByteString diff --git a/semantic-python/test/Instances.hs b/semantic-python/test/Instances.hs index 8e038b6e2..b7dd82858 100644 --- a/semantic-python/test/Instances.hs +++ b/semantic-python/test/Instances.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE DeriveAnyClass, DerivingStrategies, GeneralizedNewtypeDeriving, LambdaCase, StandaloneDeriving, FlexibleInstances, NamedFieldPuns, OverloadedStrings, QuantifiedConstraints, TypeOperators, UndecidableInstances, TypeApplications #-} +{-# LANGUAGE DerivingStrategies, GeneralizedNewtypeDeriving, LambdaCase, StandaloneDeriving, FlexibleInstances, NamedFieldPuns, OverloadedStrings, QuantifiedConstraints, TypeOperators, UndecidableInstances, TypeApplications #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Instances () where From c1d90f73e7e904fc5fa83a95ac83118715cd1234 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 21 Oct 2019 14:14:46 -0400 Subject: [PATCH 084/118] Revert "Simplify the Bitraversable instance." This reverts commit 84a448ad4fe7b26588f53a925f8ac76913c248a8. --- src/Data/Edit.hs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Data/Edit.hs b/src/Data/Edit.hs index 50735be37..a98fde90b 100644 --- a/src/Data/Edit.hs +++ b/src/Data/Edit.hs @@ -43,7 +43,10 @@ instance Bifoldable Edit where bifoldMap = bifoldMapDefault instance Bitraversable Edit where - bitraverse f g = edit (fmap Delete) (fmap Insert) (liftA2 Compare) . bimap f g + bitraverse f g = \case + Delete a -> Delete <$> f a + Insert b -> Insert <$> g b + Compare a b -> Compare <$> f a <*> g b instance Eq2 Edit where liftEq2 eql eqr = curry $ \case From b06b3338f82fe5239fe6fd478f636365feaa1c73 Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Mon, 21 Oct 2019 14:59:42 -0400 Subject: [PATCH 085/118] Unused pragmas. --- semantic-python/test/Instances.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/semantic-python/test/Instances.hs b/semantic-python/test/Instances.hs index b7dd82858..857f0f7b8 100644 --- a/semantic-python/test/Instances.hs +++ b/semantic-python/test/Instances.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE DerivingStrategies, GeneralizedNewtypeDeriving, LambdaCase, StandaloneDeriving, FlexibleInstances, NamedFieldPuns, OverloadedStrings, QuantifiedConstraints, TypeOperators, UndecidableInstances, TypeApplications #-} +{-# LANGUAGE DerivingStrategies, GeneralizedNewtypeDeriving, StandaloneDeriving, FlexibleInstances, NamedFieldPuns, OverloadedStrings, QuantifiedConstraints, TypeOperators, UndecidableInstances #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Instances () where From 025ccc713b2b3910f793d7ec0de7c5a4a6f9ff11 Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Mon, 21 Oct 2019 15:04:51 -0400 Subject: [PATCH 086/118] Remove otiose boolean check. --- src/Data/ImportPath.hs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Data/ImportPath.hs b/src/Data/ImportPath.hs index 2cbe895bc..a85cd16ba 100644 --- a/src/Data/ImportPath.hs +++ b/src/Data/ImportPath.hs @@ -19,8 +19,9 @@ data ImportPath = ImportPath { unPath :: FilePath, pathIsRelative :: IsRelative importPath :: Text -> ImportPath importPath str = let path = stripQuotes str in ImportPath (T.unpack path) (pathType path) where - pathType xs | not (T.null xs), fmap fst (T.uncons xs) == Just '.' = Relative -- head call here is safe - | otherwise = NonRelative + pathType xs | startsWithDot xs = Relative -- head call here is safe + | otherwise = NonRelative + startsWithDot t = fmap fst (T.uncons t) == Just '.' defaultAlias :: ImportPath -> Name defaultAlias = name . T.pack . takeFileName . unPath From 54b59e6942c302d74bb67a8dc7f7130ea4246aaa Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Mon, 21 Oct 2019 15:11:36 -0400 Subject: [PATCH 087/118] Download hlint in the pre-install phase. --- .travis.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index b75ab800b..847fda22a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,13 +21,17 @@ before_cache: - rm -rfv $HOME/.cabal/store/{!(ghc-8.6.5)} - rm -rfv $TRAVIS_BUILD_DIR/dist-newstyle/build/*/{!(ghc-8.6.5)} + # download and install hlint + - mkdir -p $HOME/.local/bin + - curl "https://github.com/ndmitchell/hlint/releases/download/v2.2.3/hlint-2.2.3-x86_64-linux.tar.gz" + - tar -xf hlint-2.2.3-x86_64-linux.tar.gz -C $HOME/.local/bin + matrix: include: - compiler: "ghc-8.6.5" addons: {apt: {packages: [cabal-install-2.4,ghc-8.6.5], sources: [hvr-ghc]}} before_install: -- mkdir -p $HOME/.local/bin - "PATH=/opt/ghc/bin:$HOME/local/bin:$PATH" - ghc --version - cabal --version @@ -46,8 +50,7 @@ script: - cabal v2-run semantic-source:doctest # parse-examples is disabled because it slaughters our CI # - cabal v2-run semantic:parse-examples -# Downloads an hlint binary rather than going through cabal-install -- curl -sSL https://raw.github.com/ndmitchell/hlint/master/misc/run.sh | sh -s src semantic-python +- hlint src semantic-python # Any branch linked with a pull request will be built, as well as the non-PR # branches listed below: From a1b422a69c75287b2c45a50e9be32de2b7873555 Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Mon, 21 Oct 2019 16:28:20 -0400 Subject: [PATCH 088/118] Install hlint in the right location and run it first. --- .travis.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 85a7a7d66..8dd5ecd9d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,20 +17,19 @@ before_cache: - rm -rfv $HOME/.cabal/packages/head.hackage - # download and install hlint - - mkdir -p $HOME/.local/bin - - curl "https://github.com/ndmitchell/hlint/releases/download/v2.2.3/hlint-2.2.3-x86_64-linux.tar.gz" - - tar -xf hlint-2.2.3-x86_64-linux.tar.gz -C $HOME/.local/bin - matrix: include: - compiler: "ghc-8.6.5" addons: {apt: {packages: [cabal-install-2.4,ghc-8.6.5], sources: [hvr-ghc]}} before_install: +- mkdir -p $HOME/.local/bin +- curl "https://github.com/ndmitchell/hlint/releases/download/v2.2.3/hlint-2.2.3-x86_64-linux.tar.gz" +- tar -xf hlint-2.2.3-x86_64-linux.tar.gz -C $HOME/.local/bin - "PATH=/opt/ghc/bin:$HOME/local/bin:$PATH" - ghc --version - cabal --version +- hlint --version install: - cabal v2-update -v @@ -38,6 +37,7 @@ install: - cabal v2-build --only-dependencies script: +- hlint src semantic-python - cabal v2-build - cabal v2-run semantic:test - cabal v2-run semantic-core:test @@ -46,7 +46,6 @@ script: - cabal v2-run semantic-source:doctest # parse-examples is disabled because it slaughters our CI # - cabal v2-run semantic:parse-examples -- hlint src semantic-python # Any branch linked with a pull request will be built, as well as the non-PR # branches listed below: From 9acb44abe46ab54e5c629a75774f3802adb576a9 Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Mon, 21 Oct 2019 16:36:42 -0400 Subject: [PATCH 089/118] Remove CLI parser for git repo stuff. --- src/Semantic/CLI.hs | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/Semantic/CLI.hs b/src/Semantic/CLI.hs index 8960baa86..c6394e241 100644 --- a/src/Semantic/CLI.hs +++ b/src/Semantic/CLI.hs @@ -6,7 +6,6 @@ import Control.Effect.Reader import Control.Exception as Exc (displayException) import Data.Blob import Data.Blob.IO -import qualified Data.ByteString.Char8 as B import Data.Handle import qualified Data.Language as Language import Data.List (intercalate) @@ -18,7 +17,6 @@ import Semantic.Api hiding (File) import Semantic.Config import qualified Semantic.Graph as Graph import qualified Semantic.Task as Task -import qualified Semantic.Git as Git import Semantic.Task.Files import Semantic.Telemetry import qualified Semantic.Telemetry.Log as Log @@ -134,14 +132,7 @@ parseCommand = command "parse" (info parseArgumentsParser (progDesc "Generate pa <|> flag' (parseTermBuilder TermQuiet) ( long "quiet" <> help "Don't produce output, but show timing stats") - filesOrStdin <- FilesFromGitRepo - <$> option str (long "gitDir" <> help "A .git directory to read from") - <*> option shaReader (long "sha" <> help "The commit SHA1 to read from") - <*> ( ExcludePaths <$> many (option str (long "exclude" <> short 'x' <> help "Paths to exclude")) - <|> ExcludeFromHandle <$> flag' stdin (long "exclude-stdin" <> help "Exclude paths given to stdin") - <|> IncludePaths <$> many (option str (long "only" <> help "Only include the specified paths")) - <|> IncludePathsFromHandle <$> flag' stdin (long "only-stdin" <> help "Include only the paths given to stdin")) - <|> FilesFromPaths <$> some (argument filePathReader (metavar "FILES...")) + filesOrStdin <- FilesFromPaths <$> some (argument filePathReader (metavar "FILES...")) <|> pure (FilesFromHandle stdin) pure $ Task.readBlobs filesOrStdin >>= runReader languageModes . renderer @@ -183,12 +174,6 @@ languageModes = Language.PerLanguageModes <> value Language.ALaCarte <> showDefault) -shaReader :: ReadM Git.OID -shaReader = eitherReader parseSha - where parseSha arg = if length arg == 40 || arg == "HEAD" - then Right (Git.OID (B.pack arg)) - else Left (arg <> " is not a valid sha1") - filePathReader :: ReadM File filePathReader = fileForPath <$> str From 927af0deb26aa1bd32a8ce0643041f233388ffff Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Mon, 21 Oct 2019 16:37:00 -0400 Subject: [PATCH 090/118] Remove Blob.IO.readBlobsFromGitRepo. --- src/Data/Blob/IO.hs | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/src/Data/Blob/IO.hs b/src/Data/Blob/IO.hs index 9ab95ac64..fb4c3bb08 100644 --- a/src/Data/Blob/IO.hs +++ b/src/Data/Blob/IO.hs @@ -6,8 +6,6 @@ module Data.Blob.IO ( readBlobFromFile , readBlobFromFile' , readBlobsFromDir - , readBlobsFromGitRepo - , readBlobsFromGitRepoPath , readFilePair ) where @@ -42,28 +40,6 @@ readBlobsFromDir :: MonadIO m => Path.AbsRelDir -> m [Blob] readBlobsFromDir path = liftIO . fmap catMaybes $ findFilesInDir path supportedExts mempty >>= Async.mapConcurrently (readBlobFromFile . fileForTypedPath) -readBlobsFromGitRepoPath :: (Part.AbsRel ar, MonadIO m) => Path.Dir ar -> Git.OID -> [Path.RelFile] -> [Path.RelFile] -> m [Blob] -readBlobsFromGitRepoPath path oid excludePaths includePaths - = readBlobsFromGitRepo (Path.toString path) oid (fmap Path.toString excludePaths) (fmap Path.toString includePaths) - --- | Read all blobs from a git repo. Prefer readBlobsFromGitRepoPath, which is typed. -readBlobsFromGitRepo :: MonadIO m => FilePath -> Git.OID -> [FilePath] -> [FilePath] -> m [Blob] -readBlobsFromGitRepo path oid excludePaths includePaths = liftIO . fmap catMaybes $ - Git.lsTree path oid >>= Async.mapConcurrently (blobFromTreeEntry path) - where - -- Only read tree entries that are normal mode, non-minified blobs in a language we can parse. - blobFromTreeEntry :: FilePath -> Git.TreeEntry -> IO (Maybe Blob) - blobFromTreeEntry gitDir (Git.TreeEntry Git.NormalMode Git.BlobObject oid path) - | lang <- languageForFilePath path - , lang `elem` codeNavLanguages - , not (pathIsMinified path) - , path `notElem` excludePaths - , null includePaths || path `elem` includePaths - = Just . sourceBlob' path lang oid <$> Git.catFile gitDir oid - blobFromTreeEntry _ _ = pure Nothing - - sourceBlob' filepath language (Git.OID oid) source = makeBlob source filepath language (decodeUtf8 oid) - readFilePair :: MonadIO m => File -> File -> m BlobPair readFilePair a b = do before <- readBlobFromFile a From c5802304c2e2f16a2fa777a8adca301ce80ae53d Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Mon, 21 Oct 2019 16:37:15 -0400 Subject: [PATCH 091/118] Remove FromGitRepo and FilesFromGitRepo from Files DSL. --- src/Semantic/Task/Files.hs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/Semantic/Task/Files.hs b/src/Semantic/Task/Files.hs index 5a1564437..c422f39b1 100644 --- a/src/Semantic/Task/Files.hs +++ b/src/Semantic/Task/Files.hs @@ -28,7 +28,6 @@ import Data.Language import Data.Project import Prelude hiding (readFile) import Prologue hiding (catch) -import qualified Semantic.Git as Git import Semantic.IO import qualified System.IO as IO hiding (withBinaryFile) import qualified System.Path.IO as IO (withBinaryFile) @@ -38,7 +37,6 @@ data Source blob where FromPath :: File -> Source Blob FromHandle :: Handle 'IO.ReadMode -> Source [Blob] FromDir :: Path.AbsRelDir -> Source [Blob] - FromGitRepo :: FilePath -> Git.OID -> PathFilter -> Source [Blob] FromPathPair :: File -> File -> Source BlobPair FromPairHandle :: Handle 'IO.ReadMode -> Source [BlobPair] @@ -84,10 +82,6 @@ instance (Member (Error SomeException) sig, Member Catch sig, MonadIO m, Carrier Read (FromPath path) k -> rethrowing (readBlobFromFile' path) >>= k Read (FromHandle handle) k -> rethrowing (readBlobsFromHandle handle) >>= k Read (FromDir dir) k -> rethrowing (readBlobsFromDir dir) >>= k - Read (FromGitRepo path sha (ExcludePaths excludePaths)) k -> rethrowing (readBlobsFromGitRepo path sha excludePaths mempty) >>= k - Read (FromGitRepo path sha (ExcludeFromHandle handle)) k -> rethrowing (readPathsFromHandle handle >>= (\x -> readBlobsFromGitRepo path sha x mempty)) >>= k - Read (FromGitRepo path sha (IncludePaths includePaths)) k -> rethrowing (readBlobsFromGitRepo path sha mempty includePaths) >>= k - Read (FromGitRepo path sha (IncludePathsFromHandle h)) k -> rethrowing (readPathsFromHandle h >>= readBlobsFromGitRepo path sha mempty) >>= k Read (FromPathPair p1 p2) k -> rethrowing (readFilePair p1 p2) >>= k Read (FromPairHandle handle) k -> rethrowing (readBlobPairsFromHandle handle) >>= k ReadProject rootDir dir language excludeDirs k -> rethrowing (readProjectFromPaths rootDir dir language excludeDirs) >>= k @@ -102,7 +96,6 @@ readBlob file = send (Read (FromPath file) pure) data FilesArg = FilesFromHandle (Handle 'IO.ReadMode) | FilesFromPaths [File] - | FilesFromGitRepo FilePath Git.OID PathFilter -- | A task which reads a list of 'Blob's from a 'Handle' or a list of 'FilePath's optionally paired with 'Language's. readBlobs :: (Member Files sig, Carrier sig m, MonadIO m) => FilesArg -> m [Blob] @@ -113,7 +106,6 @@ readBlobs (FilesFromPaths [path]) = do then send (Read (FromDir (Path.path (filePath path))) pure) else pure <$> send (Read (FromPath path) pure) readBlobs (FilesFromPaths paths) = traverse (send . flip Read pure . FromPath) paths -readBlobs (FilesFromGitRepo path sha filter) = send (Read (FromGitRepo path sha filter) pure) -- | A task which reads a list of pairs of 'Blob's from a 'Handle' or a list of pairs of 'FilePath's optionally paired with 'Language's. readBlobPairs :: (Member Files sig, Carrier sig m) => Either (Handle 'IO.ReadMode) [(File, File)] -> m [BlobPair] From 46717327125e7fb2bd52626d1853f3beccbcaaff Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Mon, 21 Oct 2019 16:39:24 -0400 Subject: [PATCH 092/118] Unused imports. --- src/Data/Blob/IO.hs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Data/Blob/IO.hs b/src/Data/Blob/IO.hs index fb4c3bb08..ae19501ff 100644 --- a/src/Data/Blob/IO.hs +++ b/src/Data/Blob/IO.hs @@ -15,12 +15,9 @@ import qualified Control.Concurrent.Async as Async import Data.Blob import qualified Data.ByteString as B import Data.Language -import Data.Text.Encoding (decodeUtf8) -import qualified Semantic.Git as Git import Semantic.IO import qualified Source.Source as Source import qualified System.Path as Path -import qualified System.Path.PartClass as Part -- | Read a utf8-encoded file to a 'Blob'. readBlobFromFile :: forall m. MonadIO m => File -> m (Maybe Blob) From b6079e0db98d989f39b04b08581b3ff60563e732 Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Mon, 21 Oct 2019 16:46:02 -0400 Subject: [PATCH 093/118] Remove irrelevant specs. --- test/Semantic/IO/Spec.hs | 74 ---------------------------------------- test/Semantic/Spec.hs | 27 ++------------- 2 files changed, 2 insertions(+), 99 deletions(-) diff --git a/test/Semantic/IO/Spec.hs b/test/Semantic/IO/Spec.hs index 871509c82..c3e76c624 100644 --- a/test/Semantic/IO/Spec.hs +++ b/test/Semantic/IO/Spec.hs @@ -4,86 +4,12 @@ module Semantic.IO.Spec (spec) where import Prelude hiding (readFile) -import Control.Monad.IO.Class -import Data.List -import Data.String -import qualified Data.Text as Text -import System.Directory -import System.IO.Temp - import Data.Blob import Data.Handle -import qualified Semantic.Git as Git -import Shelly (cd, run_, shelly, silently, touchfile, writefile) -import qualified Source.Source as Source import SpecHelpers -import System.Path (()) -import qualified System.Path as Path - - -makeGitRepo :: FilePath -> IO () -makeGitRepo dir = shelly . silently $ do - cd (fromString dir) - let git = run_ "git" - git ["init"] - touchfile "bar.py" - writefile "日本語.rb" "# coding: utf-8\n日本語 = 'hello'" - git ["add", "日本語.rb", "bar.py"] - git ["config", "user.name", "'Test'"] - git ["config", "user.email", "'test@test.test'"] - git ["commit", "-am", "'test commit'"] spec :: Spec spec = do - describe "catFile" $ do - hasGit <- runIO $ isJust <$> findExecutable "git" - when hasGit . it "should not corrupt the output of files with UTF-8 identifiers" $ do - result <- liftIO . withSystemTempDirectory "semantic-temp-git-repo" $ \dir -> do - makeGitRepo dir - trees <- Git.lsTree (dir <> "/.git") (Git.OID "HEAD") - Just it <- pure $ find (\p -> "日本語" `isInfixOf` Git.treeEntryPath p) trees - Git.catFile (dir <> "/.git") (Git.treeEntryOid it) - Source.toText result `shouldSatisfy` ("日本語" `Text.isInfixOf`) - - describe "lsTree" $ do - hasGit <- runIO $ isJust <$> findExecutable "git" - when hasGit . it "should read all tree entries from a repo" $ do - items <- liftIO . withSystemTempDirectory "semantic-temp-git-repo" $ \dir -> do - makeGitRepo dir - Git.lsTree dir (Git.OID "HEAD") - - length items `shouldBe` 2 - - describe "readBlobsFromGitRepo" $ do - hasGit <- runIO $ isJust <$> findExecutable "git" - when hasGit . it "should read from a git directory" $ do - -- This temporary directory will be cleaned after use. - blobs <- liftIO . withSystemTempDirectory "semantic-temp-git-repo" $ \dir -> do - makeGitRepo dir - readBlobsFromGitRepoPath (Path.absDir dir Path.relDir ".git") (Git.OID "HEAD") [] [] - let files = sortOn fileLanguage (blobFile <$> blobs) - files `shouldBe` [ File "bar.py" Python - , File "日本語.rb" Ruby - ] - - when hasGit . it "should read from a git directory with --only" $ do - -- This temporary directory will be cleaned after use. - blobs <- liftIO . withSystemTempDirectory "semantic-temp-git-repo" $ \dir -> do - let pdir = Path.absDir dir - makeGitRepo dir - readBlobsFromGitRepoPath (pdir Path.relDir ".git") (Git.OID "HEAD") [] [Path.relFile "日本語.rb"] - let files = sortOn fileLanguage (blobFile <$> blobs) - files `shouldBe` [ File "日本語.rb" Ruby ] - - when hasGit . it "should read from a git directory with --exclude" $ do - -- This temporary directory will be cleaned after use. - blobs <- liftIO . withSystemTempDirectory "semantic-temp-git-repo" $ \dir -> do - makeGitRepo dir - - readBlobsFromGitRepoPath (Path.absDir dir Path.relDir ".git") (Git.OID "HEAD") [Path.relFile "日本語.rb"] [] - let files = sortOn fileLanguage (blobFile <$> blobs) - files `shouldBe` [ File "bar.py" Python ] - describe "readFile" $ do it "returns a blob for extant files" $ do Just blob <- readBlobFromFile (File "semantic.cabal" Unknown) diff --git a/test/Semantic/Spec.hs b/test/Semantic/Spec.hs index 90728fd9d..c5b42d89f 100644 --- a/test/Semantic/Spec.hs +++ b/test/Semantic/Spec.hs @@ -6,7 +6,6 @@ import SpecHelpers import Data.Blob (NoLanguageForBlob (..)) import Semantic.Api hiding (Blob) -import Semantic.Git -- we need some lenses here, oof setBlobLanguage :: Language -> Blob -> Blob @@ -15,6 +14,8 @@ setBlobLanguage lang b = b { blobFile = (blobFile b) { fileLanguage = lang }} spec :: Spec spec = do describe "parseBlob" $ do + let methodsBlob = makeBlob "def foo\nend\n" "methods.rb" Ruby mempty + it "returns error if given an unknown language (json)" $ do output <- fmap runBuilder . runTaskOrDie . runReader (PerLanguageModes ALaCarte) $ parseTermBuilder TermJSONTree [ setBlobLanguage Unknown methodsBlob ] output `shouldBe` "{\"trees\":[{\"path\":\"methods.rb\",\"error\":\"NoLanguageForBlob \\\"methods.rb\\\"\",\"language\":\"Unknown\"}]}\n" @@ -28,27 +29,3 @@ spec = do it "renders with the specified renderer" $ do output <- fmap runBuilder . runTaskOrDie . runReader (PerLanguageModes ALaCarte) $ parseTermBuilder TermSExpression [methodsBlob] output `shouldBe` "(Statements\n (Method\n (Empty)\n (Identifier)\n (Statements)))\n" - - describe "git ls-tree parsing" $ do - it "parses a git output string" $ do - let input = "100644 tree abcdef\t/this/is/the/path" - let expected = Right $ TreeEntry NormalMode TreeObject (OID "abcdef") "/this/is/the/path" - parseEntry input `shouldBe` expected - - it "allows whitespace in the path" $ do - let input = "100644 tree 12345\t/this\n/is\t/the /path\r" - let expected = Right $ TreeEntry NormalMode TreeObject (OID "12345") "/this\n/is\t/the /path\r" - parseEntry input `shouldBe` expected - - it "parses many outputs separated by \\NUL" $ do - let input = "100644 tree abcdef\t/this/is/the/path\NUL120000 blob 17776\t/dev/urandom\NUL\n" - let expected = [ TreeEntry NormalMode TreeObject (OID "abcdef") "/this/is/the/path", TreeEntry SymlinkMode BlobObject (OID "17776") "/dev/urandom"] - parseEntries input `shouldBe` expected - - it "parses submodules and other types" $ do - let input = "160000 commit 50865e8895c54037bf06c4c1691aa925d030a59d\tgemoji" - let expected = Right $ TreeEntry OtherMode OtherObjectType (OID "50865e8895c54037bf06c4c1691aa925d030a59d") "gemoji" - parseEntry input `shouldBe` expected - - where - methodsBlob = makeBlob "def foo\nend\n" "methods.rb" Ruby mempty From 5cfde65db00efeae39770e485c0f88f2ae187023 Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Mon, 21 Oct 2019 16:48:37 -0400 Subject: [PATCH 094/118] Remove Semantic.Git. --- src/Semantic/Git.hs | 109 -------------------------------------------- 1 file changed, 109 deletions(-) delete mode 100644 src/Semantic/Git.hs diff --git a/src/Semantic/Git.hs b/src/Semantic/Git.hs deleted file mode 100644 index bae25e994..000000000 --- a/src/Semantic/Git.hs +++ /dev/null @@ -1,109 +0,0 @@ -module Semantic.Git - ( -- Primary (partial) API for cmd line git - clone - , lsTree - , catFile - - -- Intermediate datatypes - , TreeEntry(..) - , ObjectType(..) - , ObjectMode(..) - , OID(..) - - -- Testing Purposes - , parseEntries - , parseEntry - ) where - -import Prologue - -import Data.Attoparsec.ByteString (Parser) -import Data.Attoparsec.ByteString as AP -import Data.ByteString (ByteString) -import Data.ByteString.Internal (w2c) -import qualified Data.ByteString.UTF8 as UTF8 -import qualified Data.ByteString.Streaming as ByteStream -import qualified Data.Attoparsec.ByteString.Streaming as AP.Streaming -import Data.Char -import Data.Either (fromRight) -import Data.Text as Text -import Text.Parser.Combinators (sepEndBy) -import qualified Streaming.Process -import qualified System.Process as Process -import qualified Source.Source as Source - --- | git clone --bare -clone :: Text -> FilePath -> IO () -clone url path = Process.callProcess "git" - ["clone", "--bare", Text.unpack url, path] - --- | Runs @git cat-file -p@. Throws 'ProcessExitedUnsuccessfully' if the --- underlying git command returns a nonzero exit code. Loads the contents --- of the file into memory all at once and strictly. -catFile :: FilePath -> OID -> IO Source.Source -catFile gitDir (OID oid) = - let process = Process.proc "git" ["-C", gitDir, "cat-file", "-p", UTF8.toString oid] - consumeStdout stream = Streaming.Process.withProcessOutput stream ByteStream.toStrict_ - in Source.fromUTF8 <$> Streaming.Process.withStreamProcess process consumeStdout - --- | git ls-tree -rz -lsTree :: FilePath -> OID -> IO [TreeEntry] -lsTree gitDir (OID sha) = - let process = Process.proc "git" ["-C", gitDir, "ls-tree", "-rz", UTF8.toString sha] - allEntries = (entryParser `sepEndBy` AP.word8 0) <* AP.endOfInput - ignoreFailures = fmap (fromRight [] . fst) - in Streaming.Process.withStreamProcess process $ - \stream -> Streaming.Process.withProcessOutput stream (ignoreFailures . AP.Streaming.parse allEntries) - - --- | Parses an list of entries separated by \NUL, and on failure return [] -parseEntries :: ByteString -> [TreeEntry] -parseEntries = fromRight [] . AP.parseOnly everything - where - everything = AP.sepBy entryParser (AP.word8 0) - --- | Parse the entire input with entryParser, and on failure return a default --- For testing purposes only -parseEntry :: ByteString -> Either String TreeEntry -parseEntry = AP.parseOnly (entryParser <* AP.endOfInput) - --- | Parses a TreeEntry -entryParser :: Parser TreeEntry -entryParser = TreeEntry - <$> modeParser <* AP.word8 space - <*> typeParser <* AP.word8 space - <*> oidParser <* AP.word8 tab - <*> (UTF8.toString <$> AP.takeWhile (/= nul)) - where - char = fromIntegral @Int @Word8 . ord - space = char ' ' - tab = char '\t' - nul = char '\NUL' - typeParser = AP.choice [BlobObject <$ "blob", TreeObject <$ "tree", OtherObjectType <$ AP.takeWhile (isAlphaNum . w2c)] - modeParser = AP.choice [NormalMode <$ "100644", ExecutableMode <$ "100755", SymlinkMode <$ "120000", TreeMode <$ "040000", OtherMode <$ AP.takeWhile (isAlphaNum . w2c)] - oidParser = OID <$> AP.takeWhile (isHexDigit . w2c) - -newtype OID = OID ByteString - deriving (Eq, Show, Ord) - -data ObjectMode - = NormalMode - | ExecutableMode - | SymlinkMode - | TreeMode - | OtherMode - deriving (Eq, Show) - -data ObjectType - = BlobObject - | TreeObject - | OtherObjectType - deriving (Eq, Show) - -data TreeEntry - = TreeEntry - { treeEntryMode :: ObjectMode - , treeEntryType :: ObjectType - , treeEntryOid :: OID - , treeEntryPath :: FilePath - } deriving (Eq, Show) From 534c837c1f2e23ec4b3c44eb56a984e7b8ea3e8e Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Mon, 21 Oct 2019 16:48:43 -0400 Subject: [PATCH 095/118] Remove otiose dependencies. --- semantic.cabal | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/semantic.cabal b/semantic.cabal index aeb4f5c12..4f1687892 100644 --- a/semantic.cabal +++ b/semantic.cabal @@ -67,7 +67,6 @@ common dependencies , semantic-source ^>= 0.0 , semilattices ^>= 0.0.0.3 , streaming ^>= 0.2.2.0 - , streaming-bytestring ^>= 0.1.6 , text ^>= 1.2.3.1 , unix ^>= 2.7.2.2 , lingo ^>= 0.3.0.0 @@ -227,7 +226,6 @@ library , Semantic.Config , Semantic.Distribute , Semantic.Env - , Semantic.Git , Semantic.Graph , Semantic.IO , Semantic.Resolution @@ -286,8 +284,6 @@ library , semantic-tags ^>= 0 , semigroupoids ^>= 5.3.2 , split ^>= 0.2.3.3 - , streaming-attoparsec ^>= 1.0.0.1 - , streaming-process ^>= 0.1 , stm-chans ^>= 3.0.0.4 , template-haskell ^>= 2.14 , time ^>= 1.8.0.2 @@ -360,7 +356,6 @@ test-suite test , hspec >= 2.6 && <3 , hspec-core >= 2.6 && <3 , hspec-expectations ^>= 0.8.2 - , shelly >= 1.5 && <2 , tasty ^>= 1.2.3 , tasty-golden ^>= 2.3.2 , tasty-hedgehog ^>= 1.0.0.1 @@ -382,7 +377,7 @@ test-suite parse-examples , foldl ^>= 1.4.5 , resourcet ^>= 1.2 , streaming - , streaming-bytestring + , streaming-bytestring ^>= 0.1.6 , tasty , tasty-hunit From 7089a4bb51912c0a39fb771011ad2dfa5933e35c Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Mon, 21 Oct 2019 16:51:56 -0400 Subject: [PATCH 096/118] Correct curl incantation. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8dd5ecd9d..f78448391 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,8 +24,8 @@ matrix: before_install: - mkdir -p $HOME/.local/bin -- curl "https://github.com/ndmitchell/hlint/releases/download/v2.2.3/hlint-2.2.3-x86_64-linux.tar.gz" -- tar -xf hlint-2.2.3-x86_64-linux.tar.gz -C $HOME/.local/bin +- curl -L -o /tmp/hlint.tar.gz "https://github.com/ndmitchell/hlint/releases/download/v2.2.3/hlint-2.2.3-x86_64-linux.tar.gz" +- tar -xf /tmp/hlint.tar.gz -C $HOME/.local/bin - "PATH=/opt/ghc/bin:$HOME/local/bin:$PATH" - ghc --version - cabal --version From 6c137e5addeccb8fccc64e54a358de6ec07504e3 Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Mon, 21 Oct 2019 17:01:08 -0400 Subject: [PATCH 097/118] Start rubbing some typed paths on readProjectFromPaths. --- src/Data/Project.hs | 15 ++++++++++----- src/Semantic/CLI.hs | 4 ++-- src/Semantic/Task/Files.hs | 4 ++-- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/Data/Project.hs b/src/Data/Project.hs index 97c1fc30c..459e14d6d 100644 --- a/src/Data/Project.hs +++ b/src/Data/Project.hs @@ -35,16 +35,21 @@ projectExtensions = extensionsForLanguage . projectLanguage projectFiles :: Project -> [File] projectFiles = fmap blobFile . projectBlobs -readProjectFromPaths :: MonadIO m => Maybe FilePath -> FilePath -> Language -> [FilePath] -> m Project +readProjectFromPaths :: MonadIO m + => Maybe Path.AbsRelDir + -> FilePath + -> Language + -> [Path.AbsRelDir] + -> m Project readProjectFromPaths maybeRoot path lang excludeDirs = do isDir <- isDirectory path let rootDir = if isDir - then fromMaybe path maybeRoot - else fromMaybe (takeDirectory path) maybeRoot + then fromMaybe path (fmap Path.toString maybeRoot) + else fromMaybe (takeDirectory path) (fmap Path.toString maybeRoot) - paths <- liftIO $ findFilesInDir (Path.absRel rootDir) exts (fmap Path.absRel excludeDirs) + paths <- liftIO $ findFilesInDir (Path.absRel rootDir) exts excludeDirs blobs <- liftIO $ traverse (readBlobFromFile' . toFile) paths - pure $ Project rootDir blobs lang excludeDirs + pure $ Project rootDir blobs lang (fmap Path.toString excludeDirs) where toFile path = File (Path.toString path) lang exts = extensionsForLanguage lang diff --git a/src/Semantic/CLI.hs b/src/Semantic/CLI.hs index c6394e241..9aaa26c5a 100644 --- a/src/Semantic/CLI.hs +++ b/src/Semantic/CLI.hs @@ -160,8 +160,8 @@ graphCommand = command "graph" (info graphArgumentsParser (progDesc "Compute a g _ -> pure $! Project "/" mempty Language.Unknown mempty readProjectRecursively = makeReadProjectRecursivelyTask <$> option auto (long "language" <> help "The language for the analysis.") - <*> optional (strOption (long "root" <> help "Root directory of project. Optional, defaults to entry file/directory." <> metavar "DIR")) - <*> many (strOption (long "exclude-dir" <> help "Exclude a directory (e.g. vendor)" <> metavar "DIR")) + <*> optional (pathOption (long "root" <> help "Root directory of project. Optional, defaults to entry file/directory." <> metavar "DIR")) + <*> many (pathOption (long "exclude-dir" <> help "Exclude a directory (e.g. vendor)" <> metavar "DIR")) <*> argument str (metavar "DIR") makeReadProjectRecursivelyTask language rootDir excludeDirs dir = Task.readProject rootDir dir language excludeDirs makeGraphTask graphType includePackages serializer projectTask = projectTask >>= Graph.runGraph graphType includePackages >>= serializer diff --git a/src/Semantic/Task/Files.hs b/src/Semantic/Task/Files.hs index c422f39b1..f62d62717 100644 --- a/src/Semantic/Task/Files.hs +++ b/src/Semantic/Task/Files.hs @@ -51,7 +51,7 @@ data PathFilter -- | An effect to read/write 'Blob's from 'Handle's or 'FilePath's. data Files (m :: * -> *) k = forall a . Read (Source a) (a -> m k) - | ReadProject (Maybe FilePath) FilePath Language [FilePath] (Project -> m k) + | ReadProject (Maybe Path.AbsRelDir) FilePath Language [Path.AbsRelDir] (Project -> m k) | FindFiles Path.AbsRelDir [String] [Path.AbsRelDir] ([Path.AbsRelFile] -> m k) | Write Destination B.Builder (m k) @@ -112,7 +112,7 @@ readBlobPairs :: (Member Files sig, Carrier sig m) => Either (Handle 'IO.ReadMod readBlobPairs (Left handle) = send (Read (FromPairHandle handle) pure) readBlobPairs (Right paths) = traverse (send . flip Read pure . uncurry FromPathPair) paths -readProject :: (Member Files sig, Carrier sig m) => Maybe FilePath -> FilePath -> Language -> [FilePath] -> m Project +readProject :: (Member Files sig, Carrier sig m) => Maybe Path.AbsRelDir -> FilePath -> Language -> [Path.AbsRelDir] -> m Project readProject rootDir dir lang excludeDirs = send (ReadProject rootDir dir lang excludeDirs pure) findFiles :: (Member Files sig, Carrier sig m) => Path.AbsRelDir -> [String] -> [Path.AbsRelDir] -> m [Path.AbsRelFile] From 278f27af5df06e5cfcd8a8ec12d4b16ae66dcade Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Mon, 21 Oct 2019 17:03:58 -0400 Subject: [PATCH 098/118] output wasn't shaped right --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f78448391..4f137227d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,8 @@ matrix: before_install: - mkdir -p $HOME/.local/bin - curl -L -o /tmp/hlint.tar.gz "https://github.com/ndmitchell/hlint/releases/download/v2.2.3/hlint-2.2.3-x86_64-linux.tar.gz" -- tar -xf /tmp/hlint.tar.gz -C $HOME/.local/bin +- tar -xf /tmp/hlint.tar.gz -C /tmp +- cp /tmp/hlint-2.2.3/hlint $HOME/local/bin - "PATH=/opt/ghc/bin:$HOME/local/bin:$PATH" - ghc --version - cabal --version From be61c98e663d33052ef16e261ec7f21c5fa0ecda Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Mon, 21 Oct 2019 17:33:36 -0400 Subject: [PATCH 099/118] First, tentative port of readProjectFromPaths. --- src/Data/Project.hs | 18 ++++++++++-------- src/Semantic/CLI.hs | 2 +- src/Semantic/Task/Files.hs | 4 ++-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/Data/Project.hs b/src/Data/Project.hs index 459e14d6d..02907e6d7 100644 --- a/src/Data/Project.hs +++ b/src/Data/Project.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE ScopedTypeVariables #-} module Data.Project ( Project (..) , projectExtensions @@ -36,20 +37,21 @@ projectFiles :: Project -> [File] projectFiles = fmap blobFile . projectBlobs readProjectFromPaths :: MonadIO m - => Maybe Path.AbsRelDir - -> FilePath + => Maybe Path.AbsRelDir -- ^ An optional root directory for the project + -> Path.AbsRelFileDir -- ^ A file or directory to parse. Passing a directory will load -> Language -> [Path.AbsRelDir] -> m Project readProjectFromPaths maybeRoot path lang excludeDirs = do - isDir <- isDirectory path - let rootDir = if isDir - then fromMaybe path (fmap Path.toString maybeRoot) - else fromMaybe (takeDirectory path) (fmap Path.toString maybeRoot) + let (rootDir :: Path.AbsRelDir) = case maybeRoot of + Just root -> fromMaybe (Path.dirFromFileDir path) (Path.fromAbsRel root) + Nothing -> case Path.fileFromFileDir path of + Just fp -> Path.takeDirectory fp + Nothing -> Path.dirFromFileDir path - paths <- liftIO $ findFilesInDir (Path.absRel rootDir) exts excludeDirs + paths <- liftIO $ findFilesInDir rootDir exts excludeDirs blobs <- liftIO $ traverse (readBlobFromFile' . toFile) paths - pure $ Project rootDir blobs lang (fmap Path.toString excludeDirs) + pure $ Project (Path.toString rootDir) blobs lang (fmap Path.toString excludeDirs) where toFile path = File (Path.toString path) lang exts = extensionsForLanguage lang diff --git a/src/Semantic/CLI.hs b/src/Semantic/CLI.hs index 9aaa26c5a..ba2bab166 100644 --- a/src/Semantic/CLI.hs +++ b/src/Semantic/CLI.hs @@ -162,7 +162,7 @@ graphCommand = command "graph" (info graphArgumentsParser (progDesc "Compute a g <$> option auto (long "language" <> help "The language for the analysis.") <*> optional (pathOption (long "root" <> help "Root directory of project. Optional, defaults to entry file/directory." <> metavar "DIR")) <*> many (pathOption (long "exclude-dir" <> help "Exclude a directory (e.g. vendor)" <> metavar "DIR")) - <*> argument str (metavar "DIR") + <*> argument path (metavar "PATH") makeReadProjectRecursivelyTask language rootDir excludeDirs dir = Task.readProject rootDir dir language excludeDirs makeGraphTask graphType includePackages serializer projectTask = projectTask >>= Graph.runGraph graphType includePackages >>= serializer diff --git a/src/Semantic/Task/Files.hs b/src/Semantic/Task/Files.hs index f62d62717..c3f2e0cb7 100644 --- a/src/Semantic/Task/Files.hs +++ b/src/Semantic/Task/Files.hs @@ -51,7 +51,7 @@ data PathFilter -- | An effect to read/write 'Blob's from 'Handle's or 'FilePath's. data Files (m :: * -> *) k = forall a . Read (Source a) (a -> m k) - | ReadProject (Maybe Path.AbsRelDir) FilePath Language [Path.AbsRelDir] (Project -> m k) + | ReadProject (Maybe Path.AbsRelDir) Path.AbsRelFileDir Language [Path.AbsRelDir] (Project -> m k) | FindFiles Path.AbsRelDir [String] [Path.AbsRelDir] ([Path.AbsRelFile] -> m k) | Write Destination B.Builder (m k) @@ -112,7 +112,7 @@ readBlobPairs :: (Member Files sig, Carrier sig m) => Either (Handle 'IO.ReadMod readBlobPairs (Left handle) = send (Read (FromPairHandle handle) pure) readBlobPairs (Right paths) = traverse (send . flip Read pure . uncurry FromPathPair) paths -readProject :: (Member Files sig, Carrier sig m) => Maybe Path.AbsRelDir -> FilePath -> Language -> [Path.AbsRelDir] -> m Project +readProject :: (Member Files sig, Carrier sig m) => Maybe Path.AbsRelDir -> Path.AbsRelFileDir -> Language -> [Path.AbsRelDir] -> m Project readProject rootDir dir lang excludeDirs = send (ReadProject rootDir dir lang excludeDirs pure) findFiles :: (Member Files sig, Carrier sig m) => Path.AbsRelDir -> [String] -> [Path.AbsRelDir] -> m [Path.AbsRelFile] From 407d7a21207a12e30929a9d613cebaa208470d15 Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Mon, 21 Oct 2019 17:40:34 -0400 Subject: [PATCH 100/118] forgot a dot. fordot. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4f137227d..a6e72d7e5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,7 @@ before_install: - mkdir -p $HOME/.local/bin - curl -L -o /tmp/hlint.tar.gz "https://github.com/ndmitchell/hlint/releases/download/v2.2.3/hlint-2.2.3-x86_64-linux.tar.gz" - tar -xf /tmp/hlint.tar.gz -C /tmp -- cp /tmp/hlint-2.2.3/hlint $HOME/local/bin +- cp /tmp/hlint-2.2.3/hlint $HOME/.local/bin - "PATH=/opt/ghc/bin:$HOME/local/bin:$PATH" - ghc --version - cabal --version From 2d5a7e7fbbf320e3610a04fff19b5c46fb5a817a Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Mon, 21 Oct 2019 17:48:27 -0400 Subject: [PATCH 101/118] Comment and clarify. --- src/Data/Project.hs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Data/Project.hs b/src/Data/Project.hs index 02907e6d7..743447164 100644 --- a/src/Data/Project.hs +++ b/src/Data/Project.hs @@ -38,15 +38,18 @@ projectFiles = fmap blobFile . projectBlobs readProjectFromPaths :: MonadIO m => Maybe Path.AbsRelDir -- ^ An optional root directory for the project - -> Path.AbsRelFileDir -- ^ A file or directory to parse. Passing a directory will load + -> Path.AbsRelFileDir -- ^ A file or directory to parse. Passing a file path loads all files in that file's parent directory. -> Language - -> [Path.AbsRelDir] + -> [Path.AbsRelDir] -- ^ Directories to exclude. -> m Project readProjectFromPaths maybeRoot path lang excludeDirs = do - let (rootDir :: Path.AbsRelDir) = case maybeRoot of - Just root -> fromMaybe (Path.dirFromFileDir path) (Path.fromAbsRel root) + let (rootDir :: Path.AbsRelDir) = case maybeRoot >>= Path.fromAbsRel of + -- If we were provided a root directory, use that. + Just root -> root Nothing -> case Path.fileFromFileDir path of + -- If we weren't and the path is a file, drop its file name. Just fp -> Path.takeDirectory fp + -- Otherwise, load from the path. Nothing -> Path.dirFromFileDir path paths <- liftIO $ findFilesInDir rootDir exts excludeDirs From 43c783f93ed7d4e88db058de7af8c338354da371 Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Mon, 21 Oct 2019 17:49:33 -0400 Subject: [PATCH 102/118] No scoped type variables necessary. --- src/Data/Project.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Data/Project.hs b/src/Data/Project.hs index 743447164..994049521 100644 --- a/src/Data/Project.hs +++ b/src/Data/Project.hs @@ -1,4 +1,3 @@ -{-# LANGUAGE ScopedTypeVariables #-} module Data.Project ( Project (..) , projectExtensions @@ -43,7 +42,8 @@ readProjectFromPaths :: MonadIO m -> [Path.AbsRelDir] -- ^ Directories to exclude. -> m Project readProjectFromPaths maybeRoot path lang excludeDirs = do - let (rootDir :: Path.AbsRelDir) = case maybeRoot >>= Path.fromAbsRel of + let rootDir :: Path.AbsRelDir + rootDir = case maybeRoot >>= Path.fromAbsRel of -- If we were provided a root directory, use that. Just root -> root Nothing -> case Path.fileFromFileDir path of From da2d9eeee1d08a175e361924313d001934877d26 Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Mon, 21 Oct 2019 17:56:26 -0400 Subject: [PATCH 103/118] copy the data files --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index a6e72d7e5..91d1c94ac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,6 +27,7 @@ before_install: - curl -L -o /tmp/hlint.tar.gz "https://github.com/ndmitchell/hlint/releases/download/v2.2.3/hlint-2.2.3-x86_64-linux.tar.gz" - tar -xf /tmp/hlint.tar.gz -C /tmp - cp /tmp/hlint-2.2.3/hlint $HOME/.local/bin +- cp -r /tmp/hlint-2.2.3/hlint/data $HOME/.local/bin - "PATH=/opt/ghc/bin:$HOME/local/bin:$PATH" - ghc --version - cabal --version From 5585f8caebe51719ac2048fc6d28dc99836654bd Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Mon, 21 Oct 2019 18:06:40 -0400 Subject: [PATCH 104/118] Convert projectExcludeDirs to use AbsRelDir. --- src/Data/Project.hs | 4 ++-- src/Semantic/Resolution.hs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Data/Project.hs b/src/Data/Project.hs index 994049521..ddae8d527 100644 --- a/src/Data/Project.hs +++ b/src/Data/Project.hs @@ -23,7 +23,7 @@ data Project = Project { projectRootDir :: FilePath , projectBlobs :: [Blob] , projectLanguage :: Language - , projectExcludeDirs :: [FilePath] + , projectExcludeDirs :: [Path.AbsRelDir] } deriving (Eq, Show, Generic) projectName :: Project -> Text @@ -54,7 +54,7 @@ readProjectFromPaths maybeRoot path lang excludeDirs = do paths <- liftIO $ findFilesInDir rootDir exts excludeDirs blobs <- liftIO $ traverse (readBlobFromFile' . toFile) paths - pure $ Project (Path.toString rootDir) blobs lang (fmap Path.toString excludeDirs) + pure $ Project (Path.toString rootDir) blobs lang excludeDirs where toFile path = File (Path.toString path) lang exts = extensionsForLanguage lang diff --git a/src/Semantic/Resolution.hs b/src/Semantic/Resolution.hs index 4b71aff3c..17ac0b867 100644 --- a/src/Semantic/Resolution.hs +++ b/src/Semantic/Resolution.hs @@ -23,9 +23,9 @@ import System.FilePath.Posix import qualified System.Path as Path -nodeJSResolutionMap :: (Member Files sig, Carrier sig m, MonadIO m) => FilePath -> Text -> [FilePath] -> m (Map FilePath FilePath) +nodeJSResolutionMap :: (Member Files sig, Carrier sig m, MonadIO m) => FilePath -> Text -> [Path.AbsRelDir] -> m (Map FilePath FilePath) nodeJSResolutionMap rootDir prop excludeDirs = do - files <- findFiles (Path.absRel rootDir) [".json"] (fmap Path.absRel excludeDirs) + files <- findFiles (Path.absRel rootDir) [".json"] excludeDirs let packageFiles = fileForTypedPath <$> filter ((==) (Path.relFile "package.json") . Path.takeFileName) files blobs <- readBlobs (FilesFromPaths packageFiles) pure $ fold (mapMaybe (lookup prop) blobs) @@ -45,8 +45,8 @@ resolutionMap Project{..} = case projectLanguage of _ -> send (NoResolution pure) data Resolution (m :: * -> *) k - = NodeJSResolution FilePath Text [FilePath] (Map FilePath FilePath -> m k) - | NoResolution (Map FilePath FilePath -> m k) + = NodeJSResolution FilePath Text [Path.AbsRelDir] (Map FilePath FilePath -> m k) + | NoResolution (Map FilePath FilePath -> m k) deriving stock (Functor, Generic1) deriving anyclass (HFunctor, Effect) From 3e55cace903d4fd742d95b649d145969404dfb85 Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Mon, 21 Oct 2019 18:24:35 -0400 Subject: [PATCH 105/118] Wrong path. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 91d1c94ac..12ea1e630 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,7 @@ before_install: - curl -L -o /tmp/hlint.tar.gz "https://github.com/ndmitchell/hlint/releases/download/v2.2.3/hlint-2.2.3-x86_64-linux.tar.gz" - tar -xf /tmp/hlint.tar.gz -C /tmp - cp /tmp/hlint-2.2.3/hlint $HOME/.local/bin -- cp -r /tmp/hlint-2.2.3/hlint/data $HOME/.local/bin +- cp -r /tmp/hlint-2.2.3/data $HOME/.local/bin - "PATH=/opt/ghc/bin:$HOME/local/bin:$PATH" - ghc --version - cabal --version From 17e2c5a28db7d6e33279d7e3e8a28372b60d0db0 Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Mon, 21 Oct 2019 19:52:34 -0400 Subject: [PATCH 106/118] Fix last few warnings. --- src/Diffing/Algorithm/SES.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Diffing/Algorithm/SES.hs b/src/Diffing/Algorithm/SES.hs index ae83362d6..067120436 100644 --- a/src/Diffing/Algorithm/SES.hs +++ b/src/Diffing/Algorithm/SES.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE BangPatterns, GADTs, LambdaCase, MultiParamTypeClasses, ScopedTypeVariables #-} +{-# LANGUAGE BangPatterns, GADTs, MultiParamTypeClasses, ScopedTypeVariables #-} module Diffing.Algorithm.SES ( ses ) where From 4e42379a2c7384da0465997e0973108a279e1abb Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Mon, 21 Oct 2019 19:55:38 -0400 Subject: [PATCH 107/118] This auxiliary data type can die. --- src/Semantic/Task/Files.hs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/Semantic/Task/Files.hs b/src/Semantic/Task/Files.hs index c422f39b1..2ced4d0c9 100644 --- a/src/Semantic/Task/Files.hs +++ b/src/Semantic/Task/Files.hs @@ -14,7 +14,6 @@ module Semantic.Task.Files , Handle (..) , FilesC(..) , FilesArg(..) - , PathFilter(..) ) where import Control.Effect.Carrier @@ -42,12 +41,6 @@ data Source blob where data Destination = ToPath Path.AbsRelFile | ToHandle (Handle 'IO.WriteMode) -data PathFilter - = ExcludePaths [FilePath] - | ExcludeFromHandle (Handle 'IO.ReadMode) - | IncludePaths [FilePath] - | IncludePathsFromHandle (Handle 'IO.ReadMode) - -- | An effect to read/write 'Blob's from 'Handle's or 'FilePath's. data Files (m :: * -> *) k = forall a . Read (Source a) (a -> m k) From d6f43ccf739358fffdc6c5c24365453bfa634111 Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Tue, 22 Oct 2019 01:16:03 -0400 Subject: [PATCH 108/118] Revert "Convert projectExcludeDirs to use AbsRelDir." This reverts commit 5585f8caebe51719ac2048fc6d28dc99836654bd. --- src/Data/Project.hs | 4 ++-- src/Semantic/Resolution.hs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Data/Project.hs b/src/Data/Project.hs index ddae8d527..994049521 100644 --- a/src/Data/Project.hs +++ b/src/Data/Project.hs @@ -23,7 +23,7 @@ data Project = Project { projectRootDir :: FilePath , projectBlobs :: [Blob] , projectLanguage :: Language - , projectExcludeDirs :: [Path.AbsRelDir] + , projectExcludeDirs :: [FilePath] } deriving (Eq, Show, Generic) projectName :: Project -> Text @@ -54,7 +54,7 @@ readProjectFromPaths maybeRoot path lang excludeDirs = do paths <- liftIO $ findFilesInDir rootDir exts excludeDirs blobs <- liftIO $ traverse (readBlobFromFile' . toFile) paths - pure $ Project (Path.toString rootDir) blobs lang excludeDirs + pure $ Project (Path.toString rootDir) blobs lang (fmap Path.toString excludeDirs) where toFile path = File (Path.toString path) lang exts = extensionsForLanguage lang diff --git a/src/Semantic/Resolution.hs b/src/Semantic/Resolution.hs index 17ac0b867..4b71aff3c 100644 --- a/src/Semantic/Resolution.hs +++ b/src/Semantic/Resolution.hs @@ -23,9 +23,9 @@ import System.FilePath.Posix import qualified System.Path as Path -nodeJSResolutionMap :: (Member Files sig, Carrier sig m, MonadIO m) => FilePath -> Text -> [Path.AbsRelDir] -> m (Map FilePath FilePath) +nodeJSResolutionMap :: (Member Files sig, Carrier sig m, MonadIO m) => FilePath -> Text -> [FilePath] -> m (Map FilePath FilePath) nodeJSResolutionMap rootDir prop excludeDirs = do - files <- findFiles (Path.absRel rootDir) [".json"] excludeDirs + files <- findFiles (Path.absRel rootDir) [".json"] (fmap Path.absRel excludeDirs) let packageFiles = fileForTypedPath <$> filter ((==) (Path.relFile "package.json") . Path.takeFileName) files blobs <- readBlobs (FilesFromPaths packageFiles) pure $ fold (mapMaybe (lookup prop) blobs) @@ -45,8 +45,8 @@ resolutionMap Project{..} = case projectLanguage of _ -> send (NoResolution pure) data Resolution (m :: * -> *) k - = NodeJSResolution FilePath Text [Path.AbsRelDir] (Map FilePath FilePath -> m k) - | NoResolution (Map FilePath FilePath -> m k) + = NodeJSResolution FilePath Text [FilePath] (Map FilePath FilePath -> m k) + | NoResolution (Map FilePath FilePath -> m k) deriving stock (Functor, Generic1) deriving anyclass (HFunctor, Effect) From 559958d9cf1ad077b7b4d0ad84a896c47a388492 Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Tue, 22 Oct 2019 17:27:44 -0400 Subject: [PATCH 109/118] Define new :? type for checked lookups and try implementing it. --- semantic-core/src/Core/Core.hs | 9 +++++++++ semantic-core/src/Core/Eval.hs | 19 +++++++++++++++++++ semantic-python/src/Language/Python/Core.hs | 4 +++- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/semantic-core/src/Core/Core.hs b/semantic-core/src/Core/Core.hs index 481a11b7b..ac44921b5 100644 --- a/semantic-core/src/Core/Core.hs +++ b/semantic-core/src/Core/Core.hs @@ -26,6 +26,7 @@ module Core.Core , load , record , (...) +, (.?) , (.=) , Ann(..) , ann @@ -75,6 +76,8 @@ data Core f a | Record [(Name, f a)] -- | Projection from a record. | f a :. Name + -- | Projection of a record, with failure. + | f a :? Name -- | Assignment of a value to the reference returned by the lhs. | f a := f a deriving (Foldable, Functor, Generic1, Traversable) @@ -105,6 +108,7 @@ instance RightModule Core where Load b >>=* f = Load (b >>= f) Record fs >>=* f = Record (map (fmap (>>= f)) fs) (a :. b) >>=* f = (a >>= f) :. b + (a :? b) >>=* f = (a >>= f) : b (a := b) >>=* f = (a >>= f) := (b >>= f) @@ -209,6 +213,11 @@ a ... b = send (a :. b) infixl 9 ... +(.?) :: (Carrier sig m, Member Core sig) => m a -> Name -> m a +a .? b = send (a :? b) + +infixl 9 .? + (.=) :: (Carrier sig m, Member Core sig) => m a -> m a -> m a a .= b = send (a := b) diff --git a/semantic-core/src/Core/Eval.hs b/semantic-core/src/Core/Eval.hs index 01ac38d0f..5cbe7782a 100644 --- a/semantic-core/src/Core/Eval.hs +++ b/semantic-core/src/Core/Eval.hs @@ -15,12 +15,15 @@ import Analysis.File import Control.Applicative (Alternative (..)) import Control.Effect.Carrier import Control.Effect.Fail +import Control.Effect.Fresh import Control.Effect.Reader import Control.Monad ((>=>)) import Core.Core as Core import Core.Name import Data.Functor import Data.Maybe (fromMaybe) +import Data.Text (Text) +import qualified Data.Text as Text import GHC.Stack import Prelude hiding (fail) import Source.Span @@ -28,8 +31,11 @@ import Syntax.Scope import Syntax.Term import qualified System.Path as Path +type Gensym = Fresh + eval :: ( Carrier sig m , Member (Reader Span) sig + , Member Fresh sig , MonadFail m , Semigroup value ) @@ -68,6 +74,19 @@ eval Analysis{..} eval = \case a :. b -> do a' <- ref a a' ... b >>= maybe (freeVariable (show b)) (deref' b) + a :? b -> do + a' <- ref a + mFound <- a' ... b + case mFound of + Nothing -> + eval . Core.lam (named' "nothing") + . Core.lam (named' "just") + $ pure "nothing" + Just item -> do + value <- deref' b item + abstract eval "nothing" (instantiate1 (pure "nothing") (Syntax.Scope.abstract _ _)) + + a := b -> do b' <- eval b addr <- ref a diff --git a/semantic-python/src/Language/Python/Core.hs b/semantic-python/src/Language/Python/Core.hs index 7511abdbb..62e40565b 100644 --- a/semantic-python/src/Language/Python/Core.hs +++ b/semantic-python/src/Language/Python/Core.hs @@ -100,7 +100,9 @@ instance (Compile l, Compile r) => Compile (l :+: r) where compile (R1 r) cc = compile r cc instance Compile Py.AssertStatement -instance Compile Py.Attribute + +instance Compile Py.Attribute where + compile it@Py.Attribute { extraChildren = [L1 lhs, R1 rhs]} = _ -- Assignment compilation. Assignments are an uneasy hybrid of expressions -- (since they appear to have values, i.e. `a = b = c`) and statements (because From 5d5113ff699bc62c975cd376b2276736bbc146cc Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Wed, 23 Oct 2019 10:31:55 -0400 Subject: [PATCH 110/118] fix brokenness that crept in overnight (?) --- semantic-core/src/Core/Core.hs | 2 +- semantic-core/src/Core/Eval.hs | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/semantic-core/src/Core/Core.hs b/semantic-core/src/Core/Core.hs index ac44921b5..84b475da3 100644 --- a/semantic-core/src/Core/Core.hs +++ b/semantic-core/src/Core/Core.hs @@ -108,7 +108,7 @@ instance RightModule Core where Load b >>=* f = Load (b >>= f) Record fs >>=* f = Record (map (fmap (>>= f)) fs) (a :. b) >>=* f = (a >>= f) :. b - (a :? b) >>=* f = (a >>= f) : b + (a :? b) >>=* f = (a >>= f) :. b (a := b) >>=* f = (a >>= f) := (b >>= f) diff --git a/semantic-core/src/Core/Eval.hs b/semantic-core/src/Core/Eval.hs index 5cbe7782a..1794e2375 100644 --- a/semantic-core/src/Core/Eval.hs +++ b/semantic-core/src/Core/Eval.hs @@ -15,7 +15,6 @@ import Analysis.File import Control.Applicative (Alternative (..)) import Control.Effect.Carrier import Control.Effect.Fail -import Control.Effect.Fresh import Control.Effect.Reader import Control.Monad ((>=>)) import Core.Core as Core @@ -31,11 +30,8 @@ import Syntax.Scope import Syntax.Term import qualified System.Path as Path -type Gensym = Fresh - eval :: ( Carrier sig m , Member (Reader Span) sig - , Member Fresh sig , MonadFail m , Semigroup value ) @@ -82,9 +78,7 @@ eval Analysis{..} eval = \case eval . Core.lam (named' "nothing") . Core.lam (named' "just") $ pure "nothing" - Just item -> do - value <- deref' b item - abstract eval "nothing" (instantiate1 (pure "nothing") (Syntax.Scope.abstract _ _)) + Just item -> undefined a := b -> do From cb783e6646ebc0847dbc4b591bcb13d8feda6328 Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Wed, 23 Oct 2019 11:59:23 -0400 Subject: [PATCH 111/118] Make this a boolean operator pending resolution of #358. --- semantic-core/src/Core/Eval.hs | 10 ++-------- semantic-python/src/Prelude.score | 3 +++ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/semantic-core/src/Core/Eval.hs b/semantic-core/src/Core/Eval.hs index 1794e2375..4f44aa0df 100644 --- a/semantic-core/src/Core/Eval.hs +++ b/semantic-core/src/Core/Eval.hs @@ -20,7 +20,7 @@ import Control.Monad ((>=>)) import Core.Core as Core import Core.Name import Data.Functor -import Data.Maybe (fromMaybe) +import Data.Maybe (fromMaybe, isJust) import Data.Text (Text) import qualified Data.Text as Text import GHC.Stack @@ -73,13 +73,7 @@ eval Analysis{..} eval = \case a :? b -> do a' <- ref a mFound <- a' ... b - case mFound of - Nothing -> - eval . Core.lam (named' "nothing") - . Core.lam (named' "just") - $ pure "nothing" - Just item -> undefined - + bool (isJust mFound) a := b -> do b' <- eval b diff --git a/semantic-python/src/Prelude.score b/semantic-python/src/Prelude.score index d8b4b94f8..2b60b8f23 100644 --- a/semantic-python/src/Prelude.score +++ b/semantic-python/src/Prelude.score @@ -5,4 +5,7 @@ object <- type "object" #unit #record{}; #record { type: type, object: object } + + + lookup <- \item -> \name -> if item.?name then item.name else item.class.name } From b58132ba0e972975fcff81ef95f4ebb258eb210d Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Wed, 23 Oct 2019 12:05:28 -0400 Subject: [PATCH 112/118] Unused imports. --- semantic-core/src/Core/Eval.hs | 2 -- 1 file changed, 2 deletions(-) diff --git a/semantic-core/src/Core/Eval.hs b/semantic-core/src/Core/Eval.hs index 4f44aa0df..f7c23b5d7 100644 --- a/semantic-core/src/Core/Eval.hs +++ b/semantic-core/src/Core/Eval.hs @@ -21,8 +21,6 @@ import Core.Core as Core import Core.Name import Data.Functor import Data.Maybe (fromMaybe, isJust) -import Data.Text (Text) -import qualified Data.Text as Text import GHC.Stack import Prelude hiding (fail) import Source.Span From 9b56f60132991c22955604cfa013267f29ca1e17 Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Wed, 23 Oct 2019 12:05:35 -0400 Subject: [PATCH 113/118] Add parsing support. --- semantic-core/src/Core/Parser.hs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/semantic-core/src/Core/Parser.hs b/semantic-core/src/Core/Parser.hs index 34e417364..e9d11d9e8 100644 --- a/semantic-core/src/Core/Parser.hs +++ b/semantic-core/src/Core/Parser.hs @@ -93,9 +93,13 @@ rec = Core.rec <$ reserved "rec" <*> name <* symbolic '=' <*> expr "recursiv load :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t Name) load = Core.load <$ reserved "load" <*> expr +query :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t Name) +query = (Core..?) <$> atom <*> (namedValue <$ symbol ".?" <*> name) + lvalue :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t Name) lvalue = choice - [ projection + [ query + , projection , ident , parens expr ] From 8f0790ced23b46b4e6659e0a19599ccd545ea35d Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Wed, 23 Oct 2019 12:05:40 -0400 Subject: [PATCH 114/118] Add pretty-printing support. --- semantic-core/src/Core/Pretty.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/semantic-core/src/Core/Pretty.hs b/semantic-core/src/Core/Pretty.hs index 808f02f69..5babed821 100644 --- a/semantic-core/src/Core/Pretty.hs +++ b/semantic-core/src/Core/Pretty.hs @@ -74,6 +74,7 @@ prettyCore style = unPrec . go . fmap name Load p -> prec 3 (keyword "load" <+> withPrec 9 (go p)) item :. body -> prec 9 (withPrec 9 (go item) <> symbol "." <> name body) + item :? body -> prec 9 (withPrec 9 (go item) <> symbol ".?" <> name body) lhs := rhs -> prec 3 . group . nest 2 $ vsep [ withPrec 4 (go lhs) From 91558a7d65db9e3ffbf619fa11cd94722de04554 Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Wed, 23 Oct 2019 12:24:26 -0400 Subject: [PATCH 115/118] Add generator for .? (this kills the crab^Wtests). --- semantic-core/test/Generators.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/semantic-core/test/Generators.hs b/semantic-core/test/Generators.hs index 01cfd6feb..d96a82cdf 100644 --- a/semantic-core/test/Generators.hs +++ b/semantic-core/test/Generators.hs @@ -70,5 +70,6 @@ expr = Gen.recursive Gen.choice atoms , Gen.subterm expr Core.load , record expr , Gen.subtermM expr (\ x -> (x Core....) . namedValue <$> name) + , Gen.subtermM expr (\ x -> (x Core..?) . namedValue <$> name) , Gen.subterm2 expr expr (Core..=) ] From 14c3faf750d56ece62be5e84a53bc2d845bd553a Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Wed, 23 Oct 2019 13:09:26 -0400 Subject: [PATCH 116/118] the tests pass now --- semantic-core/src/Core/Parser.hs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/semantic-core/src/Core/Parser.hs b/semantic-core/src/Core/Parser.hs index e9d11d9e8..1743bae0d 100644 --- a/semantic-core/src/Core/Parser.hs +++ b/semantic-core/src/Core/Parser.hs @@ -11,12 +11,12 @@ module Core.Parser -- Consult @doc/grammar.md@ for an EBNF grammar. import Control.Applicative +import Control.Category ((>>>)) import Control.Effect.Carrier import Core.Core ((:<-) (..), Core) import qualified Core.Core as Core import Core.Name import qualified Data.Char as Char -import Data.Foldable (foldl') import Data.String import qualified Text.Parser.Token as Token import qualified Text.Parser.Token.Highlight as Highlight @@ -61,7 +61,12 @@ application :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t application = projection `chainl1` (pure (Core.$$)) projection :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t Name) -projection = foldl' (Core....) <$> atom <*> many (namedValue <$ dot <*> name) +projection = let a <$$> b = flip a <$> b in do + head <- atom + res <- many (choice [ (Core..?) <$$> (symbol ".?" *> identifier) + , (Core....) <$$> (dot *> identifier) + ]) + pure (foldr (>>>) id res head) atom :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t Name) atom = choice @@ -93,13 +98,9 @@ rec = Core.rec <$ reserved "rec" <*> name <* symbolic '=' <*> expr "recursiv load :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t Name) load = Core.load <$ reserved "load" <*> expr -query :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t Name) -query = (Core..?) <$> atom <*> (namedValue <$ symbol ".?" <*> name) - lvalue :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t Name) lvalue = choice - [ query - , projection + [ projection , ident , parens expr ] From 9b46692cbd5bf5b0e9e38366a26f4ae421591d44 Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Wed, 23 Oct 2019 13:15:42 -0400 Subject: [PATCH 117/118] Don't try to implement this yet. --- semantic-python/src/Language/Python/Core.hs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/semantic-python/src/Language/Python/Core.hs b/semantic-python/src/Language/Python/Core.hs index 62e40565b..7511abdbb 100644 --- a/semantic-python/src/Language/Python/Core.hs +++ b/semantic-python/src/Language/Python/Core.hs @@ -100,9 +100,7 @@ instance (Compile l, Compile r) => Compile (l :+: r) where compile (R1 r) cc = compile r cc instance Compile Py.AssertStatement - -instance Compile Py.Attribute where - compile it@Py.Attribute { extraChildren = [L1 lhs, R1 rhs]} = _ +instance Compile Py.Attribute -- Assignment compilation. Assignments are an uneasy hybrid of expressions -- (since they appear to have values, i.e. `a = b = c`) and statements (because From 21dd102e616a4f8ea22cad30abbbab8defac959c Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Wed, 23 Oct 2019 14:30:45 -0400 Subject: [PATCH 118/118] Implement member lookup in a way that doesn't crash the scope graph --- semantic-python/src/Prelude.score | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/semantic-python/src/Prelude.score b/semantic-python/src/Prelude.score index 2b60b8f23..8a158a7b0 100644 --- a/semantic-python/src/Prelude.score +++ b/semantic-python/src/Prelude.score @@ -1,11 +1,12 @@ { - type <- \name -> \bases -> \dict -> - #record { __name: name, __bases: bases, __dict: dict }; + type <- \name -> \super -> \slots -> + #record { __name: name, __super: super, __slots: slots }; object <- type "object" #unit #record{}; - #record { type: type, object: object } + getitem <- rec getitem = \item -> \attr -> + if item.slots.?attr then item.slots.attr else #unit; + #record { type: type, object: object, getitem: getitem } - lookup <- \item -> \name -> if item.?name then item.name else item.class.name }