1
1
mirror of https://github.com/github/semantic.git synced 2024-12-22 22:31:36 +03:00
semantic/test/Matching/Go/Spec.hs
Patrick Thomson 034bb562d4 Introduce tree-automata DSL for filtering and matching ASTs.
This patch adds the `Matcher` monad, which is capable of filtering any
recursive data structure, bottom-up, yielding a list of (or an
optional) result. These functions are probably going to be used over
`Term` values, so API is provided to wrap common projection functions.

The API was more or less copied directly from that of Clang's AST
matching facilities.

There are a lot of things we can do in the future:
* Binding results yielded in matchers to associated names, for future
  transformation stages to look up and modify.
* Actual transformation stages.
* Optimizations. This is not very fast.

A million thanks to @robrix, whose sage advice managed to turn my
kooky idea for an API into something really special and exciting.
2018-03-27 16:14:30 -04:00

41 lines
1.4 KiB
Haskell

{-# LANGUAGE TypeOperators #-}
module Matching.Go.Spec (spec) where
import Control.Abstract.Matching
import Data.Abstract.Module
import Data.List
import qualified Data.Syntax.Declaration as Decl
import qualified Data.Syntax.Literal as Lit
import qualified Data.Syntax.Statement as Stmt
import Data.Union
import SpecHelpers
-- This gets the ByteString contents of all integers
integerMatcher :: (Lit.Integer :< fs) => Matcher (Term (Union fs) ann) ByteString
integerMatcher = match Lit.integerContent target
-- This matches all for-loops with its index variable new variable bound to 0,
-- e.g. `for i := 0; i < 10; i++`
loopMatcher :: ( Stmt.For :< fs
, Stmt.Assignment :< fs
, Lit.Integer :< fs)
=> TermMatcher fs ann
loopMatcher = target <* go where
go = match Stmt.forBefore $
match Stmt.assignmentValue $
match Lit.integerContent $
ensure (== "0")
spec :: Spec
spec = describe "matching/go" $ do
it "extracts integers" $ do
parsed <- moduleBody <$> parseFile goParser Nothing "test/fixtures/go/matching/integers.go"
let matched = runMatcher integerMatcher parsed
sort matched `shouldBe` ["1", "2", "3"]
it "counts for loops" $ do
parsed <- moduleBody <$> parseFile goParser Nothing "test/fixtures/go/matching/for.go"
let matched = runMatcher @[] loopMatcher parsed
length matched `shouldBe` 2