1
1
mirror of https://github.com/github/semantic.git synced 2024-12-22 06:11:49 +03:00

Merge remote-tracking branch 'origin/master' into try-syntax

This commit is contained in:
joshvera 2016-08-01 13:38:50 -04:00
commit 9bd34fe3ff
9 changed files with 95 additions and 42 deletions

View File

@ -83,6 +83,10 @@ data Category
| Catch | Catch
-- | A finally statement. -- | A finally statement.
| Finally | Finally
-- | A class declaration.
| Class
-- | A class method declaration.
| Method
-- | A non-standard category, which can be used for comparability. -- | A non-standard category, which can be used for comparability.
| Other Text | Other Text
deriving (Eq, Generic, Ord, Show) deriving (Eq, Generic, Ord, Show)

View File

@ -1,6 +1,6 @@
{-# LANGUAGE DataKinds, TypeFamilies, ScopedTypeVariables #-} {-# LANGUAGE DataKinds, TypeFamilies, ScopedTypeVariables #-}
module DiffSummary (DiffSummary(..), diffSummary, DiffInfo(..), annotatedSummaries) where module DiffSummary (DiffSummary(..), diffSummaries, DiffInfo(..), annotatedSummaries) where
import Prologue hiding (snd, intercalate) import Prologue hiding (snd, intercalate)
import Diff import Diff
@ -59,18 +59,23 @@ toTermName source term = case unwrap term of
S.Switch expr _ -> toTermName' expr S.Switch expr _ -> toTermName' expr
S.Ternary expr _ -> toTermName' expr S.Ternary expr _ -> toTermName' expr
S.MathAssignment id _ -> toTermName' id S.MathAssignment id _ -> toTermName' id
S.Operator syntaxes -> mconcat $ toTermName' <$> syntaxes S.Operator _ -> termNameFromSource term
S.Object kvs -> "{" <> intercalate ", " (toTermName' <$> kvs) <> "}" S.Object kvs -> "{" <> intercalate ", " (toTermName' <$> kvs) <> "}"
S.Pair a b -> toTermName' a <> ": " <> toTermName' b S.Pair a b -> toTermName' a <> ": " <> toTermName' b
S.Return expr -> maybe "empty" toTermName' expr S.Return expr -> maybe "empty" toTermName' expr
S.For exprs _ -> toText $ Source.slice (unionRangesFrom forRange forClauseRanges) source S.For exprs _ -> termNameFromChildren term exprs
where forRange = characterRange $ extract term
forClauseRanges = characterRange . extract <$> exprs
S.While expr _ -> toTermName' expr S.While expr _ -> toTermName' expr
S.DoWhile _ expr -> toTermName' expr S.DoWhile _ expr -> toTermName' expr
S.Try expr _ _ -> toText $ Source.slice (characterRange $ extract expr) source S.Try expr _ _ -> toText $ Source.slice (characterRange $ extract expr) source
S.Array _ -> toText $ Source.slice (characterRange $ extract term) source
S.Class identifier _ _ -> toTermName' identifier
S.Method identifier _ _ -> toTermName' identifier
Comment a -> toCategoryName a Comment a -> toCategoryName a
where toTermName' = toTermName source where toTermName' = toTermName source
termNameFromChildren term cs = termNameFromRange (unionRangesFrom (range term) (range <$> cs))
termNameFromSource term = termNameFromRange (range term)
termNameFromRange range = toText $ Source.slice range source
range = characterRange . extract
class HasCategory a where class HasCategory a where
toCategoryName :: a -> Text toCategoryName :: a -> Text
@ -118,6 +123,8 @@ instance HasCategory Category where
C.Catch -> "catch statement" C.Catch -> "catch statement"
C.Try -> "try statement" C.Try -> "try statement"
C.Finally -> "finally statement" C.Finally -> "finally statement"
C.Class -> "class"
C.Method -> "method"
instance (HasCategory leaf, HasField fields Category) => HasCategory (Term leaf (Record fields)) where instance (HasCategory leaf, HasField fields Category) => HasCategory (Term leaf (Record fields)) where
toCategoryName = toCategoryName . category . extract toCategoryName = toCategoryName . category . extract
@ -161,8 +168,8 @@ maybeParentContext annotations = if null annotations
toDoc :: Text -> Doc toDoc :: Text -> Doc
toDoc = string . toS toDoc = string . toS
diffSummary :: (HasCategory leaf, HasField fields Category, HasField fields Range) => Both (Source Char) -> Diff leaf (Record fields) -> [DiffSummary DiffInfo] diffSummaries :: (HasCategory leaf, HasField fields Category, HasField fields Range) => Both (Source Char) -> Diff leaf (Record fields) -> [DiffSummary DiffInfo]
diffSummary sources = cata $ \case diffSummaries sources = cata $ \case
-- Skip comments and leaves since they don't have any changes -- Skip comments and leaves since they don't have any changes
(Free (_ :< Leaf _)) -> [] (Free (_ :< Leaf _)) -> []
Free (_ :< (S.Comment _)) -> [] Free (_ :< (S.Comment _)) -> []
@ -191,6 +198,9 @@ diffSummary sources = cata $ \case
(Free (infos :< S.While expr body)) -> annotateWithCategory infos <$> expr <> body (Free (infos :< S.While expr body)) -> annotateWithCategory infos <$> expr <> body
(Free (infos :< S.DoWhile expr body)) -> annotateWithCategory infos <$> expr <> body (Free (infos :< S.DoWhile expr body)) -> annotateWithCategory infos <$> expr <> body
(Free (infos :< S.Try expr catch finally)) -> annotateWithCategory infos <$> expr <> fromMaybe [] catch <> fromMaybe [] finally (Free (infos :< S.Try expr catch finally)) -> annotateWithCategory infos <$> expr <> fromMaybe [] catch <> fromMaybe [] finally
(Free (infos :< S.Array children)) -> annotateWithCategory infos <$> join children
(Free (infos :< S.Class identifier superclass definitions)) -> annotateWithCategory infos <$> identifier <> fromMaybe [] superclass <> join definitions
(Free (infos :< S.Method identifier params definitions)) -> annotateWithCategory infos <$> identifier <> join params <> join definitions
(Pure (Insert term)) -> [ DiffSummary (Insert $ termToDiffInfo afterSource term) [] ] (Pure (Insert term)) -> [ DiffSummary (Insert $ termToDiffInfo afterSource term) [] ]
(Pure (Delete term)) -> [ DiffSummary (Delete $ termToDiffInfo beforeSource term) [] ] (Pure (Delete term)) -> [ DiffSummary (Delete $ termToDiffInfo beforeSource term) [] ]
(Pure (Replace t1 t2)) -> [ DiffSummary (Replace (termToDiffInfo beforeSource t1) (termToDiffInfo afterSource t2)) [] ] (Pure (Replace t1 t2)) -> [ DiffSummary (Replace (termToDiffInfo beforeSource t1) (termToDiffInfo afterSource t2)) [] ]
@ -212,7 +222,6 @@ termToDiffInfo blob term = case unwrap term of
-- Currently we cannot express the operator for an operator production from TreeSitter. Eventually we should be able to -- Currently we cannot express the operator for an operator production from TreeSitter. Eventually we should be able to
-- use the term name of the operator identifier when we have that production value. Until then, I'm using a placeholder value -- use the term name of the operator identifier when we have that production value. Until then, I'm using a placeholder value
-- to indicate where that value should be when constructing DiffInfos. -- to indicate where that value should be when constructing DiffInfos.
S.Operator _ -> LeafInfo (toCategoryName term) "x"
Commented cs leaf -> BranchInfo (termToDiffInfo' <$> cs <> maybeToList leaf) (toCategoryName term) BCommented Commented cs leaf -> BranchInfo (termToDiffInfo' <$> cs <> maybeToList leaf) (toCategoryName term) BCommented
S.Error sourceSpan _ -> ErrorInfo sourceSpan (toCategoryName term) S.Error sourceSpan _ -> ErrorInfo sourceSpan (toCategoryName term)
_ -> LeafInfo (toCategoryName term) (toTermName' term) _ -> LeafInfo (toCategoryName term) (toTermName' term)

View File

@ -17,13 +17,9 @@ import SourceSpan
-- | and aren't pure. -- | and aren't pure.
type Parser fields = SourceBlob -> IO (Term Text (Record fields)) type Parser fields = SourceBlob -> IO (Term Text (Record fields))
-- | Categories that are treated as fixed nodes. -- | Whether a category is an Operator Category
fixedCategories :: Set.Set Category isOperator :: Category -> Bool
fixedCategories = Set.fromList [ BinaryOperator, Pair ] isOperator = flip Set.member (Set.fromList [ Operator, BinaryOperator ])
-- | Should these categories be treated as fixed nodes?
isFixed :: Category -> Bool
isFixed = flip Set.member fixedCategories
-- | Given a function that maps production names to sets of categories, produce -- | Given a function that maps production names to sets of categories, produce
-- | a Constructor. -- | a Constructor.
@ -49,7 +45,7 @@ termConstructor source sourceSpan info = cofree . construct
construct children | SubscriptAccess == category info = case children of construct children | SubscriptAccess == category info = case children of
(base:element:[]) -> withDefaultInfo $ S.SubscriptAccess base element (base:element:[]) -> withDefaultInfo $ S.SubscriptAccess base element
_ -> withDefaultInfo $ S.Error sourceSpan children _ -> withDefaultInfo $ S.Error sourceSpan children
construct children | Operator == category info = withDefaultInfo $ S.Operator children construct children | isOperator (category info) = withDefaultInfo $ S.Operator children
construct children | Function == category info = case children of construct children | Function == category info = case children of
(body:[]) -> withDefaultInfo $ S.Function Nothing Nothing body (body:[]) -> withDefaultInfo $ S.Function Nothing Nothing body
(params:body:[]) | (info :< _) <- runCofree params, Params == category info -> (params:body:[]) | (info :< _) <- runCofree params, Params == category info ->
@ -92,7 +88,7 @@ termConstructor source sourceSpan info = cofree . construct
toTuple child | S.Leaf c <- unwrap child = [cofree (extract child :< S.Comment c)] toTuple child | S.Leaf c <- unwrap child = [cofree (extract child :< S.Comment c)]
toTuple child = pure child toTuple child = pure child
construct children | isFixed (category info) = withDefaultInfo $ S.Fixed children construct children | Pair == (category info) = withDefaultInfo $ S.Fixed children
construct children | C.Error == category info = construct children | C.Error == category info =
withDefaultInfo $ S.Error sourceSpan children withDefaultInfo $ S.Error sourceSpan children
construct children | For == (category info), Just (exprs, body) <- unsnoc children = construct children | For == (category info), Just (exprs, body) <- unsnoc children =
@ -109,5 +105,36 @@ termConstructor source sourceSpan info = cofree . construct
Finally <- category (extract finally) -> Finally <- category (extract finally) ->
withDefaultInfo $ S.Try body (Just catch) (Just finally) withDefaultInfo $ S.Try body (Just catch) (Just finally)
_ -> withDefaultInfo $ S.Error sourceSpan children _ -> withDefaultInfo $ S.Error sourceSpan children
construct children | ArrayLiteral == category info =
withDefaultInfo $ S.Array children
construct children | Method == category info = case children of
[identifier, params, exprs] |
Params == category (extract params),
S.Indexed params' <- unwrap params,
exprs' <- expressionStatements exprs ->
withDefaultInfo $ S.Method identifier params' exprs'
[identifier, exprs] | exprs' <- expressionStatements exprs ->
withDefaultInfo $ S.Method identifier mempty exprs'
_ ->
withDefaultInfo $ S.Error sourceSpan children
construct children | Class == category info = case children of
[identifier, superclass, definitions] | definitions' <- methodDefinitions definitions ->
withDefaultInfo $ S.Class identifier (Just superclass) definitions'
[identifier, definitions] | definitions' <- methodDefinitions definitions ->
withDefaultInfo $ S.Class identifier Nothing definitions'
_ ->
withDefaultInfo $ S.Error sourceSpan children
construct children = construct children =
withDefaultInfo $ S.Indexed children withDefaultInfo $ S.Indexed children
expressionStatements :: HasField fields Category => Term Text (Record fields) -> [Term Text (Record fields)]
expressionStatements exprs |
Other "statement_block" == category (extract exprs),
S.Indexed exprs' <- unwrap exprs = exprs'
expressionStatements _ = mempty
methodDefinitions :: HasField fields Category => Term Text (Record fields) -> [Term Text (Record fields)]
methodDefinitions definitions |
Other "class_body" == category (extract definitions),
S.Indexed definitions' <- unwrap definitions = definitions'
methodDefinitions _ = mempty

View File

@ -7,7 +7,7 @@ module Renderer.JSON (
import Prologue hiding (toList) import Prologue hiding (toList)
import Alignment import Alignment
import Category import Category
import Data.Aeson hiding (json) import Data.Aeson as A hiding (json)
import Data.Bifunctor.Join import Data.Bifunctor.Join
import Data.ByteString.Builder import Data.ByteString.Builder
import Data.Record import Data.Record
@ -15,7 +15,6 @@ import qualified Data.Text as T
import Data.These import Data.These
import Data.Vector hiding (toList) import Data.Vector hiding (toList)
import Info import Info
import Range
import Renderer import Renderer
import Source hiding (fromList) import Source hiding (fromList)
import SplitDiff import SplitDiff
@ -36,13 +35,13 @@ instance ToJSON Category where
toJSON (Other s) = String s toJSON (Other s) = String s
toJSON s = String . T.pack $ show s toJSON s = String . T.pack $ show s
instance ToJSON Range where instance ToJSON Range where
toJSON (Range start end) = Array . fromList $ toJSON <$> [ start, end ] toJSON (Range start end) = A.Array . fromList $ toJSON <$> [ start, end ]
toEncoding (Range start end) = foldable [ start, end ] toEncoding (Range start end) = foldable [ start, end ]
instance ToJSON a => ToJSON (Join These a) where instance ToJSON a => ToJSON (Join These a) where
toJSON (Join vs) = Array . fromList $ toJSON <$> these pure pure (\ a b -> [ a, b ]) vs toJSON (Join vs) = A.Array . fromList $ toJSON <$> these pure pure (\ a b -> [ a, b ]) vs
toEncoding = foldable toEncoding = foldable
instance ToJSON a => ToJSON (Join (,) a) where instance ToJSON a => ToJSON (Join (,) a) where
toJSON (Join (a, b)) = Array . fromList $ toJSON <$> [ a, b ] toJSON (Join (a, b)) = A.Array . fromList $ toJSON <$> [ a, b ]
toEncoding = foldable toEncoding = foldable
instance (HasField fields Category, HasField fields Range) => ToJSON (SplitDiff leaf (Record fields)) where instance (HasField fields Category, HasField fields Range) => ToJSON (SplitDiff leaf (Record fields)) where
toJSON splitDiff = case runFree splitDiff of toJSON splitDiff = case runFree splitDiff of
@ -91,6 +90,9 @@ termFields info syntax = "range" .= characterRange info : "category" .= category
S.Commented comments child -> childrenFields (comments <> maybeToList child) S.Commented comments child -> childrenFields (comments <> maybeToList child)
S.Error sourceSpan c -> [ "sourceSpan" .= sourceSpan ] <> childrenFields c S.Error sourceSpan c -> [ "sourceSpan" .= sourceSpan ] <> childrenFields c
S.Try body catch finally -> [ "tryBody" .= body ] <> [ "tryCatch" .= catch ] <> [ "tryFinally" .= finally ] S.Try body catch finally -> [ "tryBody" .= body ] <> [ "tryCatch" .= catch ] <> [ "tryFinally" .= finally ]
S.Array c -> childrenFields c
S.Class identifier superclass definitions -> [ "classIdentifier" .= identifier ] <> [ "superclass" .= superclass ] <> [ "definitions" .= definitions ]
S.Method identifier params definitions -> [ "methodIdentifier" .= identifier ] <> [ "params" .= params ] <> [ "definitions" .= definitions ]
where childrenFields c = [ "children" .= c ] where childrenFields c = [ "children" .= c ]
patchFields :: (KeyValue kv, HasField fields Category, HasField fields Range) => SplitPatch (Term leaf (Record fields)) -> [kv] patchFields :: (KeyValue kv, HasField fields Category, HasField fields Range) => SplitPatch (Term leaf (Record fields)) -> [kv]

View File

@ -40,7 +40,6 @@ styleName category = "category-" <> case category of
StringLiteral -> "string" StringLiteral -> "string"
SymbolLiteral -> "symbol" SymbolLiteral -> "symbol"
IntegerLiteral -> "integer" IntegerLiteral -> "integer"
ArrayLiteral -> "array"
C.FunctionCall -> "function_call" C.FunctionCall -> "function_call"
C.Function -> "function" C.Function -> "function"
C.MethodCall -> "method_call" C.MethodCall -> "method_call"
@ -68,6 +67,8 @@ styleName category = "category-" <> case category of
C.Try -> "try_statement" C.Try -> "try_statement"
C.Catch -> "catch_statement" C.Catch -> "catch_statement"
C.Finally -> "finally_statement" C.Finally -> "finally_statement"
ArrayLiteral -> "array"
C.Class -> "class_statement"
Other string -> string Other string -> string
-- | Pick the class name for a split patch. -- | Pick the class name for a split patch.

View File

@ -11,4 +11,4 @@ import Source
summary :: (HasField fields Category, HasField fields Range) => Renderer (Record fields) summary :: (HasField fields Category, HasField fields Range) => Renderer (Record fields)
summary blobs diff = toS . encode $ summaries >>= annotatedSummaries summary blobs diff = toS . encode $ summaries >>= annotatedSummaries
where summaries = diffSummary (source <$> blobs) diff where summaries = diffSummaries (source <$> blobs) diff

View File

@ -61,11 +61,22 @@ data Syntax
| While { whileExpr :: f, whileBody :: f } | While { whileExpr :: f, whileBody :: f }
| Return (Maybe f) | Return (Maybe f)
| Try f (Maybe f) (Maybe f) | Try f (Maybe f) (Maybe f)
-- | An array literal with list of children.
| Array [f]
-- | A class with an identifier, superclass, and a list of definitions.
| Class f (Maybe f) [f]
-- | A method definition with an identifier, params, and a list of expressions.
| Method f [f] [f]
deriving (Eq, Foldable, Functor, Generic, Generic1, Mergeable, Ord, Show, Traversable) deriving (Eq, Foldable, Functor, Generic, Generic1, Mergeable, Ord, Show, Traversable)
-- Instances -- Instances
instance (Arbitrary leaf, Arbitrary f) => Arbitrary (Syntax leaf f) where
arbitrary = sized (syntaxOfSize (`resize` arbitrary) )
shrink = genericShrink
syntaxOfSize :: Arbitrary leaf => (Int -> Gen f) -> Int -> Gen (Syntax leaf f) syntaxOfSize :: Arbitrary leaf => (Int -> Gen f) -> Int -> Gen (Syntax leaf f)
syntaxOfSize recur n | n <= 1 = oneof $ (Leaf <$> arbitrary) : branchGeneratorsOfSize n syntaxOfSize recur n | n <= 1 = oneof $ (Leaf <$> arbitrary) : branchGeneratorsOfSize n
| otherwise = oneof $ branchGeneratorsOfSize n | otherwise = oneof $ branchGeneratorsOfSize n
@ -79,8 +90,3 @@ syntaxOfSize recur n | n <= 1 = oneof $ (Leaf <$> arbitrary) : branchGeneratorsO
first <- recur m first <- recur m
rest <- childrenOfSize (n - m) rest <- childrenOfSize (n - m)
pure $! first : rest pure $! first : rest
instance (Arbitrary leaf, Arbitrary f) => Arbitrary (Syntax leaf f) where
arbitrary = sized (syntaxOfSize (`resize` arbitrary) )
shrink = genericShrink

View File

@ -7,7 +7,6 @@ import Category
import Info import Info
import Language import Language
import Parser import Parser
import Range
import Source import Source
import Foreign import Foreign
import Foreign.C.String import Foreign.C.String
@ -31,19 +30,25 @@ treeSitterParser language grammar blob = do
categoriesForLanguage :: Language -> Text -> Category categoriesForLanguage :: Language -> Text -> Category
categoriesForLanguage language name = case (language, name) of categoriesForLanguage language name = case (language, name) of
(JavaScript, "object") -> Object (JavaScript, "object") -> Object
(JavaScript, "rel_op") -> BinaryOperator -- relational operator, e.g. >, <, <=, >=, ==, !=
(JavaScript, "bool_op") -> BinaryOperator
(JavaScript, "expression_statement") -> ExpressionStatements (JavaScript, "expression_statement") -> ExpressionStatements
(JavaScript, "this_expression") -> Identifier (JavaScript, "this_expression") -> Identifier
(JavaScript, "null") -> Identifier (JavaScript, "null") -> Identifier
(JavaScript, "undefined") -> Identifier (JavaScript, "undefined") -> Identifier
(JavaScript, "arrow_function") -> Function (JavaScript, "arrow_function") -> Function
(JavaScript, "generator_function") -> Function (JavaScript, "generator_function") -> Function
(JavaScript, "delete_op") -> Operator (JavaScript, "math_op") -> BinaryOperator -- bitwise operator, e.g. +, -, *, /.
(JavaScript, "type_op") -> Operator (JavaScript, "bool_op") -> BinaryOperator -- boolean operator, e.g. ||, &&.
(JavaScript, "void_op") -> Operator (JavaScript, "bitwise_op") -> BinaryOperator -- bitwise operator, e.g. ^, &, etc.
(JavaScript, "rel_op") -> BinaryOperator -- relational operator, e.g. >, <, <=, >=, ==, !=.
(JavaScript, "comma_op") -> Operator -- comma operator, e.g. expr1, expr2.
(JavaScript, "delete_op") -> Operator -- delete operator, e.g. delete x[2].
(JavaScript, "type_op") -> Operator -- type operator, e.g. typeof Object.
(JavaScript, "void_op") -> Operator -- void operator, e.g. void 2.
(JavaScript, "for_in_statement") -> For (JavaScript, "for_in_statement") -> For
(JavaScript, "for_of_statement") -> For (JavaScript, "for_of_statement") -> For
(JavaScript, "class") -> Class
(JavaScript, "catch") -> Catch
(JavaScript, "finally") -> Finally
(Ruby, "hash") -> Object (Ruby, "hash") -> Object
_ -> defaultCategoryForNodeName name _ -> defaultCategoryForNodeName name
@ -83,8 +88,7 @@ defaultCategoryForNodeName name = case name of
"do_statement" -> DoWhile "do_statement" -> DoWhile
"return_statement" -> Return "return_statement" -> Return
"try_statement" -> Try "try_statement" -> Try
"catch" -> Catch "method_definition" -> Method
"finally" -> Finally
_ -> Other name _ -> Other name
-- | Return a parser for a tree sitter language & document. -- | Return a parser for a tree sitter language & document.

View File

@ -41,13 +41,13 @@ sources = both (fromText "[]") (fromText "[a]")
spec :: Spec spec :: Spec
spec = parallel $ do spec = parallel $ do
describe "diffSummary" $ do describe "diffSummaries" $ do
it "outputs a diff summary" $ do it "outputs a diff summary" $ do
diffSummary sources testDiff `shouldBe` [ DiffSummary { patch = Insert (LeafInfo "string" "a"), parentAnnotations = [ ArrayLiteral ] } ] diffSummaries sources testDiff `shouldBe` [ DiffSummary { patch = Insert (LeafInfo "string" "a"), parentAnnotations = [ ArrayLiteral ] } ]
prop "equal terms produce identity diffs" $ prop "equal terms produce identity diffs" $
\ a -> let term = toTerm (a :: ArbitraryTerm Text (Record '[Category, Range])) in \ a -> let term = toTerm (a :: ArbitraryTerm Text (Record '[Category, Range])) in
diffSummary sources (diffTerms wrap (==) diffCost term term) `shouldBe` [] diffSummaries sources (diffTerms wrap (==) diffCost term term) `shouldBe` []
describe "annotatedSummaries" $ do describe "annotatedSummaries" $ do
it "should print adds" $ it "should print adds" $
@ -58,7 +58,7 @@ spec = parallel $ do
prop "patches in summaries match the patches in diffs" $ prop "patches in summaries match the patches in diffs" $
\a -> let \a -> let
diff = (toDiff (a :: ArbitraryDiff Text (Record '[Category, Cost, Range]))) diff = (toDiff (a :: ArbitraryDiff Text (Record '[Category, Cost, Range])))
summaries = diffSummary sources diff summaries = diffSummaries sources diff
patches = toList diff patches = toList diff
in in
case (partition isBranchNode (patch <$> summaries), partition isIndexedOrFixed patches) of case (partition isBranchNode (patch <$> summaries), partition isIndexedOrFixed patches) of
@ -67,7 +67,7 @@ spec = parallel $ do
prop "generates one LeafInfo for each child in an arbitrary branch patch" $ prop "generates one LeafInfo for each child in an arbitrary branch patch" $
\a -> let \a -> let
diff = (toDiff (a :: ArbitraryDiff Text (Record '[Category, Range]))) diff = (toDiff (a :: ArbitraryDiff Text (Record '[Category, Range])))
diffInfoPatches = patch <$> diffSummary sources diff diffInfoPatches = patch <$> diffSummaries sources diff
syntaxPatches = toList diff syntaxPatches = toList diff
extractLeaves :: DiffInfo -> [DiffInfo] extractLeaves :: DiffInfo -> [DiffInfo]
extractLeaves (BranchInfo children _ _) = join $ extractLeaves <$> children extractLeaves (BranchInfo children _ _) = join $ extractLeaves <$> children