1
1
mirror of https://github.com/github/semantic.git synced 2024-12-03 00:16:52 +03:00
semantic/test/Rewriting/Python/Spec.hs

36 lines
1.3 KiB
Haskell
Raw Normal View History

2018-12-12 01:21:39 +03:00
{-# LANGUAGE TypeFamilies, TypeOperators #-}
Give Control.Matching API better ergonomics. Given that @tclem and I have found the matcher API frustrating, I've taken a stab at improving its ergonomics, and I've found some success in separating composition of matchers from predicate-based narrowing thereof. The biggest change here is the elimination of the old `match` combinator, which proved to be clumsy in that it complected narrowing and composition. Top-down matching combinators are now written with the `need` combinator and the `>>>` combinator, which is more readable and more versatile. Here's a matcher that accepts functions with Python docstrings: ```haskell docstringMatcher :: ( Decl.Function :< fs , [] :< fs , Lit.TextElement :< fs , term ~ Term (Sum fs) ann ) => Matcher term term docstringMatcher = target <* (need Decl.functionBody >>> narrow @[] >>> mhead >>> narrow @Lit.TextElement >>> ensure Lit.isTripleQuoted)) ``` Pretty readable, right? Each step of the tree regular expression - choosing function bodies, ensuring said bodies are lists, examining the first element, and choosing only TextElements containing triple-quoted strings - is made implicit. The old way would have looked something like this: ```haskell docstringMatcher = target <* match Decl.functionBody $ narrow $ matchM listToMaybe $ target <* ensure Lit.isTripleQuoted ``` which is a good deal more disorganized and less flexible in the quite-common case of applying functions during a matching pass. Separating the act of composition from function application is a big win here. Further comments are inline.
2018-11-03 02:25:29 +03:00
2018-12-12 01:21:39 +03:00
module Rewriting.Python.Spec (spec) where
Give Control.Matching API better ergonomics. Given that @tclem and I have found the matcher API frustrating, I've taken a stab at improving its ergonomics, and I've found some success in separating composition of matchers from predicate-based narrowing thereof. The biggest change here is the elimination of the old `match` combinator, which proved to be clumsy in that it complected narrowing and composition. Top-down matching combinators are now written with the `need` combinator and the `>>>` combinator, which is more readable and more versatile. Here's a matcher that accepts functions with Python docstrings: ```haskell docstringMatcher :: ( Decl.Function :< fs , [] :< fs , Lit.TextElement :< fs , term ~ Term (Sum fs) ann ) => Matcher term term docstringMatcher = target <* (need Decl.functionBody >>> narrow @[] >>> mhead >>> narrow @Lit.TextElement >>> ensure Lit.isTripleQuoted)) ``` Pretty readable, right? Each step of the tree regular expression - choosing function bodies, ensuring said bodies are lists, examining the first element, and choosing only TextElements containing triple-quoted strings - is made implicit. The old way would have looked something like this: ```haskell docstringMatcher = target <* match Decl.functionBody $ narrow $ matchM listToMaybe $ target <* ensure Lit.isTripleQuoted ``` which is a good deal more disorganized and less flexible in the quite-common case of applying functions during a matching pass. Separating the act of composition from function application is a big win here. Further comments are inline.
2018-11-03 02:25:29 +03:00
2018-12-12 01:21:39 +03:00
import Control.Arrow
import Control.Rewriting
Give Control.Matching API better ergonomics. Given that @tclem and I have found the matcher API frustrating, I've taken a stab at improving its ergonomics, and I've found some success in separating composition of matchers from predicate-based narrowing thereof. The biggest change here is the elimination of the old `match` combinator, which proved to be clumsy in that it complected narrowing and composition. Top-down matching combinators are now written with the `need` combinator and the `>>>` combinator, which is more readable and more versatile. Here's a matcher that accepts functions with Python docstrings: ```haskell docstringMatcher :: ( Decl.Function :< fs , [] :< fs , Lit.TextElement :< fs , term ~ Term (Sum fs) ann ) => Matcher term term docstringMatcher = target <* (need Decl.functionBody >>> narrow @[] >>> mhead >>> narrow @Lit.TextElement >>> ensure Lit.isTripleQuoted)) ``` Pretty readable, right? Each step of the tree regular expression - choosing function bodies, ensuring said bodies are lists, examining the first element, and choosing only TextElements containing triple-quoted strings - is made implicit. The old way would have looked something like this: ```haskell docstringMatcher = target <* match Decl.functionBody $ narrow $ matchM listToMaybe $ target <* ensure Lit.isTripleQuoted ``` which is a good deal more disorganized and less flexible in the quite-common case of applying functions during a matching pass. Separating the act of composition from function application is a big win here. Further comments are inline.
2018-11-03 02:25:29 +03:00
import Data.Sum
import qualified Data.Syntax.Declaration as Decl
import qualified Data.Syntax.Literal as Lit
import SpecHelpers
-- This gets the Text contents of all integers
docstringMatcher :: ( Decl.Function :< fs
, [] :< fs
, Lit.TextElement :< fs
, term ~ Term (Sum fs) ann
2018-12-12 01:21:39 +03:00
) => Rewrite term (TermF Decl.Function ann term)
Give Control.Matching API better ergonomics. Given that @tclem and I have found the matcher API frustrating, I've taken a stab at improving its ergonomics, and I've found some success in separating composition of matchers from predicate-based narrowing thereof. The biggest change here is the elimination of the old `match` combinator, which proved to be clumsy in that it complected narrowing and composition. Top-down matching combinators are now written with the `need` combinator and the `>>>` combinator, which is more readable and more versatile. Here's a matcher that accepts functions with Python docstrings: ```haskell docstringMatcher :: ( Decl.Function :< fs , [] :< fs , Lit.TextElement :< fs , term ~ Term (Sum fs) ann ) => Matcher term term docstringMatcher = target <* (need Decl.functionBody >>> narrow @[] >>> mhead >>> narrow @Lit.TextElement >>> ensure Lit.isTripleQuoted)) ``` Pretty readable, right? Each step of the tree regular expression - choosing function bodies, ensuring said bodies are lists, examining the first element, and choosing only TextElements containing triple-quoted strings - is made implicit. The old way would have looked something like this: ```haskell docstringMatcher = target <* match Decl.functionBody $ narrow $ matchM listToMaybe $ target <* ensure Lit.isTripleQuoted ``` which is a good deal more disorganized and less flexible in the quite-common case of applying functions during a matching pass. Separating the act of composition from function application is a big win here. Further comments are inline.
2018-11-03 02:25:29 +03:00
docstringMatcher =
2018-11-06 00:56:49 +03:00
narrowF <* (enter Decl.functionBody
>>> narrow @[]
Give Control.Matching API better ergonomics. Given that @tclem and I have found the matcher API frustrating, I've taken a stab at improving its ergonomics, and I've found some success in separating composition of matchers from predicate-based narrowing thereof. The biggest change here is the elimination of the old `match` combinator, which proved to be clumsy in that it complected narrowing and composition. Top-down matching combinators are now written with the `need` combinator and the `>>>` combinator, which is more readable and more versatile. Here's a matcher that accepts functions with Python docstrings: ```haskell docstringMatcher :: ( Decl.Function :< fs , [] :< fs , Lit.TextElement :< fs , term ~ Term (Sum fs) ann ) => Matcher term term docstringMatcher = target <* (need Decl.functionBody >>> narrow @[] >>> mhead >>> narrow @Lit.TextElement >>> ensure Lit.isTripleQuoted)) ``` Pretty readable, right? Each step of the tree regular expression - choosing function bodies, ensuring said bodies are lists, examining the first element, and choosing only TextElements containing triple-quoted strings - is made implicit. The old way would have looked something like this: ```haskell docstringMatcher = target <* match Decl.functionBody $ narrow $ matchM listToMaybe $ target <* ensure Lit.isTripleQuoted ``` which is a good deal more disorganized and less flexible in the quite-common case of applying functions during a matching pass. Separating the act of composition from function application is a big win here. Further comments are inline.
2018-11-03 02:25:29 +03:00
>>> mhead
>>> narrow @Lit.TextElement
>>> ensure Lit.isTripleQuoted)
spec :: Spec
spec = describe "matching/python" $ do
it "matches top-level docstrings" $ do
parsed <- parseFileQuiet pythonParser "test/fixtures/python/matching/docstrings.py"
let matched = recursively @[] docstringMatcher parsed
Give Control.Matching API better ergonomics. Given that @tclem and I have found the matcher API frustrating, I've taken a stab at improving its ergonomics, and I've found some success in separating composition of matchers from predicate-based narrowing thereof. The biggest change here is the elimination of the old `match` combinator, which proved to be clumsy in that it complected narrowing and composition. Top-down matching combinators are now written with the `need` combinator and the `>>>` combinator, which is more readable and more versatile. Here's a matcher that accepts functions with Python docstrings: ```haskell docstringMatcher :: ( Decl.Function :< fs , [] :< fs , Lit.TextElement :< fs , term ~ Term (Sum fs) ann ) => Matcher term term docstringMatcher = target <* (need Decl.functionBody >>> narrow @[] >>> mhead >>> narrow @Lit.TextElement >>> ensure Lit.isTripleQuoted)) ``` Pretty readable, right? Each step of the tree regular expression - choosing function bodies, ensuring said bodies are lists, examining the first element, and choosing only TextElements containing triple-quoted strings - is made implicit. The old way would have looked something like this: ```haskell docstringMatcher = target <* match Decl.functionBody $ narrow $ matchM listToMaybe $ target <* ensure Lit.isTripleQuoted ``` which is a good deal more disorganized and less flexible in the quite-common case of applying functions during a matching pass. Separating the act of composition from function application is a big win here. Further comments are inline.
2018-11-03 02:25:29 +03:00
length matched `shouldBe` 2
it "matches docstrings recursively" $ do
parsed <- parseFileQuiet pythonParser "test/fixtures/python/matching/docstrings_nested.py"
let matched = recursively @[] docstringMatcher parsed
Give Control.Matching API better ergonomics. Given that @tclem and I have found the matcher API frustrating, I've taken a stab at improving its ergonomics, and I've found some success in separating composition of matchers from predicate-based narrowing thereof. The biggest change here is the elimination of the old `match` combinator, which proved to be clumsy in that it complected narrowing and composition. Top-down matching combinators are now written with the `need` combinator and the `>>>` combinator, which is more readable and more versatile. Here's a matcher that accepts functions with Python docstrings: ```haskell docstringMatcher :: ( Decl.Function :< fs , [] :< fs , Lit.TextElement :< fs , term ~ Term (Sum fs) ann ) => Matcher term term docstringMatcher = target <* (need Decl.functionBody >>> narrow @[] >>> mhead >>> narrow @Lit.TextElement >>> ensure Lit.isTripleQuoted)) ``` Pretty readable, right? Each step of the tree regular expression - choosing function bodies, ensuring said bodies are lists, examining the first element, and choosing only TextElements containing triple-quoted strings - is made implicit. The old way would have looked something like this: ```haskell docstringMatcher = target <* match Decl.functionBody $ narrow $ matchM listToMaybe $ target <* ensure Lit.isTripleQuoted ``` which is a good deal more disorganized and less flexible in the quite-common case of applying functions during a matching pass. Separating the act of composition from function application is a big win here. Further comments are inline.
2018-11-03 02:25:29 +03:00
length matched `shouldBe` 3