mirror of
https://github.com/github/semantic.git
synced 2024-11-28 18:23:44 +03:00
7ea52dbfe3
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.
81 lines
3.6 KiB
Haskell
81 lines
3.6 KiB
Haskell
module Main where
|
|
|
|
import qualified Analysis.Go.Spec
|
|
import qualified Analysis.PHP.Spec
|
|
import qualified Analysis.Python.Spec
|
|
import qualified Analysis.Ruby.Spec
|
|
import qualified Analysis.TypeScript.Spec
|
|
import qualified Assigning.Assignment.Spec
|
|
import qualified Control.Abstract.Evaluator.Spec
|
|
import qualified Control.Rewriting.Spec
|
|
import qualified Data.Diff.Spec
|
|
import qualified Data.Abstract.Environment.Spec
|
|
import qualified Data.Abstract.Name.Spec
|
|
import qualified Data.Abstract.Path.Spec
|
|
import qualified Data.Functor.Classes.Generic.Spec
|
|
import qualified Data.Graph.Spec
|
|
import qualified Data.Range.Spec
|
|
import qualified Data.Scientific.Spec
|
|
import qualified Data.Semigroup.App.Spec
|
|
import qualified Data.Source.Spec
|
|
import qualified Data.Term.Spec
|
|
import qualified Diffing.Algorithm.RWS.Spec
|
|
import qualified Diffing.Algorithm.SES.Spec
|
|
import qualified Diffing.Interpreter.Spec
|
|
import qualified Graphing.Calls.Spec
|
|
import qualified Integration.Spec
|
|
import qualified Matching.Go.Spec
|
|
import qualified Matching.Python.Spec
|
|
import qualified Numeric.Spec
|
|
import qualified Rendering.TOC.Spec
|
|
import qualified Reprinting.Spec
|
|
import qualified Semantic.Spec
|
|
import qualified Semantic.CLI.Spec
|
|
import qualified Semantic.IO.Spec
|
|
import qualified Semantic.Stat.Spec
|
|
import Semantic.Config (defaultOptions)
|
|
import Semantic.Task (withOptions)
|
|
import Semantic.Util (TaskConfig(..))
|
|
import qualified Proto3.Roundtrip
|
|
import Test.Hspec
|
|
|
|
main :: IO ()
|
|
main = do
|
|
withOptions defaultOptions $ \ config logger statter -> hspec $ do
|
|
let args = TaskConfig config logger statter
|
|
describe "Semantic.Stat" Semantic.Stat.Spec.spec
|
|
parallel $ do
|
|
describe "Analysis.Go" (Analysis.Go.Spec.spec args)
|
|
describe "Analysis.PHP" (Analysis.PHP.Spec.spec args)
|
|
describe "Analysis.Python" (Analysis.Python.Spec.spec args)
|
|
describe "Analysis.Ruby" (Analysis.Ruby.Spec.spec args)
|
|
describe "Analysis.TypeScript" (Analysis.TypeScript.Spec.spec args)
|
|
describe "Assigning.Assignment" Assigning.Assignment.Spec.spec
|
|
describe "Control.Abstract.Evaluator" Control.Abstract.Evaluator.Spec.spec
|
|
describe "Control.Rewriting.Spec" Control.Rewriting.Spec.spec
|
|
describe "Data.Diff" Data.Diff.Spec.spec
|
|
describe "Data.Graph" Data.Graph.Spec.spec
|
|
describe "Data.Abstract.Environment.Spec" Data.Abstract.Environment.Spec.spec
|
|
describe "Data.Abstract.Path" Data.Abstract.Path.Spec.spec
|
|
describe "Data.Abstract.Name" Data.Abstract.Name.Spec.spec
|
|
describe "Data.Functor.Classes.Generic" Data.Functor.Classes.Generic.Spec.spec
|
|
describe "Data.Range" Data.Range.Spec.spec
|
|
describe "Data.Scientific" Data.Scientific.Spec.spec
|
|
describe "Data.Semigroup.App" Data.Semigroup.App.Spec.spec
|
|
describe "Data.Source" Data.Source.Spec.spec
|
|
describe "Data.Term" Data.Term.Spec.spec
|
|
describe "Diffing.Algorithm.RWS" Diffing.Algorithm.RWS.Spec.spec
|
|
describe "Diffing.Algorithm.SES" Diffing.Algorithm.SES.Spec.spec
|
|
describe "Diffing.Interpreter" Diffing.Interpreter.Spec.spec
|
|
describe "Graphing.Calls" Graphing.Calls.Spec.spec
|
|
describe "Matching.Go" Matching.Go.Spec.spec
|
|
describe "Matching.Python" Matching.Python.Spec.spec
|
|
describe "Numeric" Numeric.Spec.spec
|
|
describe "Rendering.TOC" Rendering.TOC.Spec.spec
|
|
describe "Reprinting.Spec" Reprinting.Spec.spec
|
|
describe "Semantic" Semantic.Spec.spec
|
|
describe "Semantic.CLI" Semantic.CLI.Spec.spec
|
|
describe "Semantic.IO" Semantic.IO.Spec.spec
|
|
describe "Integration" (Integration.Spec.spec args)
|
|
describe "Protobuf roundtripping" Proto3.Roundtrip.spec
|