1
1
mirror of https://github.com/github/semantic.git synced 2024-12-30 10:27:45 +03:00

Merge remote-tracking branch 'origin/master' into fix-ruby-empty-statement

This commit is contained in:
Timothy Clem 2017-07-21 09:28:46 -07:00
commit 1269577a75
13 changed files with 153 additions and 17 deletions

3
.gitmodules vendored
View File

@ -34,3 +34,6 @@
[submodule "languages/python/vendor/tree-sitter-python"] [submodule "languages/python/vendor/tree-sitter-python"]
path = languages/python/vendor/tree-sitter-python path = languages/python/vendor/tree-sitter-python
url = https://github.com/tree-sitter/tree-sitter-python.git url = https://github.com/tree-sitter/tree-sitter-python.git
[submodule "languages/json/vendor/tree-sitter-json"]
path = languages/json/vendor/tree-sitter-json
url = https://github.com/tree-sitter/tree-sitter-json

2
languages/json/Setup.hs Normal file
View File

@ -0,0 +1,2 @@
import Distribution.Simple
main = defaultMain

27
languages/json/json.cabal Normal file
View File

@ -0,0 +1,27 @@
name: json
version: 0.1.0
synopsis: tree-sitter json language bindings
description: Please see README.md
homepage: https://github.com/github/semantic-diff#readme
author: semantic-code
maintainer: vera@github.com
copyright: 2017 GitHub
category: Web
build-type: Simple
-- extra-source-files:
cabal-version: >=1.10
library
hs-source-dirs: src
exposed-modules: Text.Parser.TreeSitter.JSON
build-depends: base >= 4.7 && < 5
, haskell-tree-sitter
default-language: Haskell2010
default-extensions: FlexibleInstances, OverloadedStrings, NoImplicitPrelude, RecordWildCards
c-sources: vendor/tree-sitter-json/src/parser.c
cc-options: -std=c99 -Os
source-repository head
type: git
location: https://github.com/github/semantic-diff

View File

@ -0,0 +1,6 @@
module Text.Parser.TreeSitter.JSON where
import Foreign.Ptr
import Text.Parser.TreeSitter
foreign import ccall unsafe "vendor/tree-sitter-json/src/parser.c tree_sitter_json" tree_sitter_json :: Ptr Language

@ -0,0 +1 @@
Subproject commit 5c21eb6446ca3e0a49fe710fb948d8efb8a5b6da

View File

@ -50,6 +50,8 @@ library
, Language.Markdown.Syntax , Language.Markdown.Syntax
, Language.Go , Language.Go
, Language.Go.Syntax , Language.Go.Syntax
, Language.JSON.Grammar
, Language.JSON.Syntax
, Language.Ruby , Language.Ruby
, Language.Ruby.Grammar , Language.Ruby.Grammar
, Language.Ruby.Syntax , Language.Ruby.Syntax
@ -117,6 +119,7 @@ library
, ruby , ruby
, typescript , typescript
, python , python
, json
default-language: Haskell2010 default-language: Haskell2010
default-extensions: DeriveFunctor, DeriveFoldable, DeriveTraversable, DeriveGeneric, FlexibleContexts, FlexibleInstances, OverloadedStrings, NoImplicitPrelude, RecordWildCards, StrictData default-extensions: DeriveFunctor, DeriveFoldable, DeriveTraversable, DeriveGeneric, FlexibleContexts, FlexibleInstances, OverloadedStrings, NoImplicitPrelude, RecordWildCards, StrictData
ghc-options: -Wall -fno-warn-name-shadowing -O -j ghc-options: -Wall -fno-warn-name-shadowing -O -j

View File

@ -295,9 +295,10 @@ runAssignment source toNode = iterFreer run . fmap ((pure .) . (,))
runMany :: Assignment ast grammar v -> AssignmentState ast grammar -> ([v], AssignmentState ast grammar) runMany :: Assignment ast grammar v -> AssignmentState ast grammar -> ([v], AssignmentState ast grammar)
runMany rule state = case runAssignment source toNode rule state of runMany rule state = case runAssignment source toNode rule state of
Left err -> ([], state { stateError = Just err }) Left err -> ([], state { stateError = Just err })
Right (a, state') -> if ((/=) `on` stateCounter) state state' Right (a, state') | ((/=) `on` stateCounter) state state' ->
then let (as, state'') = runMany rule state' in as `seq` (a : as, state'') let (as, state'') = runMany rule state'
else ([a], state') in as `seq` (a : as, state'')
| otherwise -> ([a], state')
{-# INLINE run #-} {-# INLINE run #-}
dropAnonymous :: (Symbol grammar, Recursive ast) => (forall x. Base ast x -> Node grammar) -> AssignmentState ast grammar -> AssignmentState ast grammar dropAnonymous :: (Symbol grammar, Recursive ast) => (forall x. Base ast x -> Node grammar) -> AssignmentState ast grammar -> AssignmentState ast grammar

View File

@ -14,6 +14,7 @@ data Language =
C C
| Go | Go
| JavaScript | JavaScript
| JSON
| Markdown | Markdown
| Python | Python
| Ruby | Ruby
@ -25,6 +26,7 @@ languageForType :: String -> Maybe Language
languageForType mediaType = case mediaType of languageForType mediaType = case mediaType of
".h" -> Just C ".h" -> Just C
".c" -> Just C ".c" -> Just C
".json" -> Just JSON
".md" -> Just Markdown ".md" -> Just Markdown
".rb" -> Just Ruby ".rb" -> Just Ruby
".go" -> Just Language.Go ".go" -> Just Language.Go

View File

@ -0,0 +1,10 @@
{-# LANGUAGE TemplateHaskell #-}
module Language.JSON.Grammar where
import Language.Haskell.TH
import Text.Parser.TreeSitter.Language
import Text.Parser.TreeSitter.JSON
-- | Statically-known rules corresponding to symbols in the grammar.
-- v1 - bump this to regenerate
mkSymbolDatatype (mkName "Grammar") tree_sitter_json

View File

@ -0,0 +1,68 @@
{-# LANGUAGE DataKinds, GADTs, RankNTypes, TypeOperators #-}
module Language.JSON.Syntax
( assignment
, Syntax
, Grammar
, Term)
where
import qualified Data.Syntax as Syntax
import qualified Data.Syntax.Literal as Literal
import Data.Syntax.Assignment hiding (Assignment, Error)
import qualified Data.Syntax.Assignment as Assignment
import Language.JSON.Grammar as Grammar
import qualified Term
import Data.Record
import Data.Union
import GHC.Stack
import Prologue hiding (Location)
type Syntax =
[ Literal.Array
, Literal.Boolean
, Literal.Hash
, Literal.Float
, Literal.KeyValue
, Literal.Null
, Literal.String
, Literal.TextElement
, Syntax.Error
, []
]
type Term = Term.Term (Union Syntax) (Record Location)
type Assignment = HasCallStack => Assignment.Assignment (AST Grammar) Grammar Term
makeTerm :: (HasCallStack, f :< fs) => a -> f (Term.Term (Union fs) a) -> Term.Term (Union fs) a
makeTerm a f = cofree (a :< inj f)
parseError :: Assignment
parseError = makeTerm <$> symbol ParseError <*> (Syntax.Error [] <$ source)
assignment :: Assignment
assignment = object <|> array <|> parseError
value :: Assignment
value = object <|> array <|> number <|> string <|> boolean <|> none <|> parseError
object :: Assignment
object = makeTerm <$> symbol Object <*> children (Literal.Hash <$> many pairs)
where pairs = makeTerm <$> symbol Pair <*> children (Literal.KeyValue <$> (number <|> string) <*> value)
array :: Assignment
array = makeTerm <$> symbol Array <*> children (Literal.Array <$> many value)
number :: Assignment
number = makeTerm <$> symbol Number <*> (Literal.Float <$> source)
string :: Assignment
string = makeTerm <$> symbol String <*> (Literal.TextElement <$> source)
boolean :: Assignment
boolean = makeTerm <$> symbol Grammar.True <*> (Literal.true <$ source)
<|> makeTerm <$> symbol Grammar.False <*> (Literal.false <$ source)
none :: Assignment
none = makeTerm <$> symbol Null <*> (Literal.Null <$ source)

View File

@ -5,6 +5,7 @@ module Parser
-- Syntax parsers -- Syntax parsers
, parserForLanguage , parserForLanguage
-- À la carte parsers -- À la carte parsers
, jsonParser
, markdownParser , markdownParser
, pythonParser , pythonParser
, rubyParser , rubyParser
@ -21,6 +22,7 @@ import Data.Union
import Info hiding (Empty, Go) import Info hiding (Empty, Go)
import Language import Language
import Language.Markdown import Language.Markdown
import qualified Language.JSON.Syntax as JSON
import qualified Language.Markdown.Syntax as Markdown import qualified Language.Markdown.Syntax as Markdown
import qualified Language.Python.Syntax as Python import qualified Language.Python.Syntax as Python
import qualified Language.Ruby.Syntax as Ruby import qualified Language.Ruby.Syntax as Ruby
@ -34,6 +36,7 @@ import Text.Parser.TreeSitter.Go
import Text.Parser.TreeSitter.Python import Text.Parser.TreeSitter.Python
import Text.Parser.TreeSitter.Ruby import Text.Parser.TreeSitter.Ruby
import Text.Parser.TreeSitter.TypeScript import Text.Parser.TreeSitter.TypeScript
import Text.Parser.TreeSitter.JSON
import TreeSitter import TreeSitter
-- | A parser from 'Source' onto some term type. -- | A parser from 'Source' onto some term type.
@ -59,6 +62,7 @@ parserForLanguage Nothing = LineByLineParser
parserForLanguage (Just language) = case language of parserForLanguage (Just language) = case language of
C -> TreeSitterParser C tree_sitter_c C -> TreeSitterParser C tree_sitter_c
Go -> TreeSitterParser Go tree_sitter_go Go -> TreeSitterParser Go tree_sitter_go
JSON -> TreeSitterParser JSON tree_sitter_json
JavaScript -> TreeSitterParser TypeScript tree_sitter_typescript JavaScript -> TreeSitterParser TypeScript tree_sitter_typescript
Ruby -> TreeSitterParser Ruby tree_sitter_ruby Ruby -> TreeSitterParser Ruby tree_sitter_ruby
TypeScript -> TreeSitterParser TypeScript tree_sitter_typescript TypeScript -> TreeSitterParser TypeScript tree_sitter_typescript
@ -70,6 +74,9 @@ rubyParser = AssignmentParser (ASTParser tree_sitter_ruby) headF Ruby.assignment
pythonParser :: Parser Python.Term pythonParser :: Parser Python.Term
pythonParser = AssignmentParser (ASTParser tree_sitter_python) headF Python.assignment pythonParser = AssignmentParser (ASTParser tree_sitter_python) headF Python.assignment
jsonParser :: Parser JSON.Term
jsonParser = AssignmentParser (ASTParser tree_sitter_json) headF JSON.assignment
markdownParser :: Parser Markdown.Term markdownParser :: Parser Markdown.Term
markdownParser = AssignmentParser MarkdownParser (\ (node@Node{..} :< _) -> node { nodeSymbol = toGrammar nodeSymbol }) Markdown.assignment markdownParser = AssignmentParser MarkdownParser (\ (node@Node{..} :< _) -> node { nodeSymbol = toGrammar nodeSymbol }) Markdown.assignment

View File

@ -47,12 +47,15 @@ parseBlob renderer blob@Blob{..} = case (renderer, blobLanguage) of
(ToCTermRenderer, _) -> parse syntaxParser blob >>= decorate (syntaxDeclarationAlgebra blob) >>= render (renderToCTerm blob) (ToCTermRenderer, _) -> parse syntaxParser blob >>= decorate (syntaxDeclarationAlgebra blob) >>= render (renderToCTerm blob)
(JSONTermRenderer, Just Language.Markdown) -> parse markdownParser blob >>= decorate constructorLabel >>= render (renderJSONTerm blob) (JSONTermRenderer, Just Language.Markdown) -> parse markdownParser blob >>= decorate constructorLabel >>= render (renderJSONTerm blob)
(JSONTermRenderer, Just Language.Python) -> parse pythonParser blob >>= decorate constructorLabel >>= render (renderJSONTerm blob) (JSONTermRenderer, Just Language.Python) -> parse pythonParser blob >>= decorate constructorLabel >>= render (renderJSONTerm blob)
(JSONTermRenderer, Just Language.JSON) -> parse jsonParser blob >>= decorate constructorLabel >>= render (renderJSONTerm blob)
(JSONTermRenderer, _) -> parse syntaxParser blob >>= decorate identifierAlgebra >>= render (renderJSONTerm blob) (JSONTermRenderer, _) -> parse syntaxParser blob >>= decorate identifierAlgebra >>= render (renderJSONTerm blob)
(SExpressionTermRenderer, Just Language.Markdown) -> parse markdownParser blob >>= decorate constructorLabel >>= render renderSExpressionTerm . fmap keepConstructorLabel (SExpressionTermRenderer, Just Language.Markdown) -> parse markdownParser blob >>= decorate constructorLabel >>= render renderSExpressionTerm . fmap keepConstructorLabel
(SExpressionTermRenderer, Just Language.Python) -> parse pythonParser blob >>= decorate constructorLabel >>= render renderSExpressionTerm . fmap keepConstructorLabel (SExpressionTermRenderer, Just Language.Python) -> parse pythonParser blob >>= decorate constructorLabel >>= render renderSExpressionTerm . fmap keepConstructorLabel
(SExpressionTermRenderer, Just Language.JSON) -> parse jsonParser blob >>= decorate constructorLabel >>= render renderSExpressionTerm . fmap keepConstructorLabel
(SExpressionTermRenderer, _) -> parse syntaxParser blob >>= render renderSExpressionTerm . fmap keepCategory (SExpressionTermRenderer, _) -> parse syntaxParser blob >>= render renderSExpressionTerm . fmap keepCategory
(IdentityTermRenderer, Just Language.Markdown) -> pure Nothing (IdentityTermRenderer, Just Language.Markdown) -> pure Nothing
(IdentityTermRenderer, Just Language.Python) -> pure Nothing (IdentityTermRenderer, Just Language.Python) -> pure Nothing
(IdentityTermRenderer, Just Language.JSON) -> pure Nothing
(IdentityTermRenderer, _) -> Just <$> parse syntaxParser blob (IdentityTermRenderer, _) -> Just <$> parse syntaxParser blob
where syntaxParser = parserForLanguage blobLanguage where syntaxParser = parserForLanguage blobLanguage
@ -69,12 +72,15 @@ diffBlobPair renderer blobs = case (renderer, effectiveLanguage) of
(ToCDiffRenderer, _) -> run (\ blob -> parse syntaxParser blob >>= decorate (syntaxDeclarationAlgebra blob)) diffTerms (renderToCDiff blobs) (ToCDiffRenderer, _) -> run (\ blob -> parse syntaxParser blob >>= decorate (syntaxDeclarationAlgebra blob)) diffTerms (renderToCDiff blobs)
(JSONDiffRenderer, Just Language.Markdown) -> run (parse markdownParser) diffLinearly (renderJSONDiff blobs) (JSONDiffRenderer, Just Language.Markdown) -> run (parse markdownParser) diffLinearly (renderJSONDiff blobs)
(JSONDiffRenderer, Just Language.Python) -> run (parse pythonParser) diffLinearly (renderJSONDiff blobs) (JSONDiffRenderer, Just Language.Python) -> run (parse pythonParser) diffLinearly (renderJSONDiff blobs)
(JSONDiffRenderer, Just Language.JSON) -> run (parse jsonParser) diffLinearly (renderJSONDiff blobs)
(JSONDiffRenderer, _) -> run (decorate identifierAlgebra <=< parse syntaxParser) diffTerms (renderJSONDiff blobs) (JSONDiffRenderer, _) -> run (decorate identifierAlgebra <=< parse syntaxParser) diffTerms (renderJSONDiff blobs)
(PatchDiffRenderer, Just Language.Markdown) -> run (parse markdownParser) diffLinearly (renderPatch blobs) (PatchDiffRenderer, Just Language.Markdown) -> run (parse markdownParser) diffLinearly (renderPatch blobs)
(PatchDiffRenderer, Just Language.Python) -> run (parse pythonParser) diffLinearly (renderPatch blobs) (PatchDiffRenderer, Just Language.Python) -> run (parse pythonParser) diffLinearly (renderPatch blobs)
(PatchDiffRenderer, Just Language.JSON) -> run (parse jsonParser) diffLinearly (renderPatch blobs)
(PatchDiffRenderer, _) -> run (parse syntaxParser) diffTerms (renderPatch blobs) (PatchDiffRenderer, _) -> run (parse syntaxParser) diffTerms (renderPatch blobs)
(SExpressionDiffRenderer, Just Language.Markdown) -> run (decorate constructorLabel <=< parse markdownParser) diffLinearly (renderSExpressionDiff . mapAnnotations keepConstructorLabel) (SExpressionDiffRenderer, Just Language.Markdown) -> run (decorate constructorLabel <=< parse markdownParser) diffLinearly (renderSExpressionDiff . mapAnnotations keepConstructorLabel)
(SExpressionDiffRenderer, Just Language.Python) -> run (decorate constructorLabel <=< parse pythonParser) diffLinearly (renderSExpressionDiff . mapAnnotations keepConstructorLabel) (SExpressionDiffRenderer, Just Language.Python) -> run (decorate constructorLabel <=< parse pythonParser) diffLinearly (renderSExpressionDiff . mapAnnotations keepConstructorLabel)
(SExpressionDiffRenderer, Just Language.JSON) -> run (decorate constructorLabel <=< parse jsonParser) diffLinearly (renderSExpressionDiff . mapAnnotations keepConstructorLabel)
(SExpressionDiffRenderer, _) -> run (parse syntaxParser) diffTerms (renderSExpressionDiff . mapAnnotations keepCategory) (SExpressionDiffRenderer, _) -> run (parse syntaxParser) diffTerms (renderSExpressionDiff . mapAnnotations keepCategory)
(IdentityDiffRenderer, _) -> run (\ blob -> parse syntaxParser blob >>= decorate (syntaxDeclarationAlgebra blob)) diffTerms Just (IdentityDiffRenderer, _) -> run (\ blob -> parse syntaxParser blob >>= decorate (syntaxDeclarationAlgebra blob)) diffTerms Just
where effectiveLanguage = runBothWith (<|>) (blobLanguage <$> blobs) where effectiveLanguage = runBothWith (<|>) (blobLanguage <$> blobs)

View File

@ -84,50 +84,50 @@ spec = do
describe "in many" $ do describe "in many" $ do
it "handler that always matches" $ it "handler that always matches" $
fst <$> runAssignment "PG" headF fst <$> runAssignment "PG" headF
(symbol Palatte *> children ( (symbol Palette *> children (
many (red `catchError` (\ _ -> OutError <$ location <*> source)) many (red `catchError` (\ _ -> OutError <$ location <*> source))
)) ))
(makeState [node Palatte 0 1 [node Green 1 2 []]]) (makeState [node Palette 0 1 [node Green 1 2 []]])
`shouldBe` `shouldBe`
Right [OutError "G"] Right [OutError "G"]
it "handler that matches" $ it "handler that matches" $
fst <$> runAssignment "PG" headF fst <$> runAssignment "PG" headF
(symbol Palatte *> children ( many (red `catchError` const green) )) (symbol Palette *> children ( many (red `catchError` const green) ))
(makeState [node Palatte 0 1 [node Green 1 2 []]]) (makeState [node Palette 0 1 [node Green 1 2 []]])
`shouldBe` `shouldBe`
Right [Out "G"] Right [Out "G"]
it "handler that doesn't match produces error" $ it "handler that doesn't match produces error" $
runAssignment "PG" headF runAssignment "PG" headF
(symbol Palatte *> children ( many (red `catchError` const blue) )) (symbol Palette *> children ( many (red `catchError` const blue) ))
(makeState [node Palatte 0 1 [node Green 1 2 []]]) (makeState [node Palette 0 1 [node Green 1 2 []]])
`shouldBe` `shouldBe`
Left (Error (Info.Pos 1 2) (UnexpectedSymbol [Blue] Green)) Left (Error (Info.Pos 1 2) (UnexpectedSymbol [Blue] Green))
it "handler that always matches with apply consumes and then errors" $ it "handler that always matches with apply consumes and then errors" $
runAssignment "PG" headF runAssignment "PG" headF
(symbol Palatte *> children ( (symbol Palette *> children (
(,) <$> many (red `catchError` (\ _ -> OutError <$ location <*> source)) <*> green (,) <$> many (red `catchError` (\ _ -> OutError <$ location <*> source)) <*> green
)) ))
(makeState [node Palatte 0 1 [node Green 1 2 []]]) (makeState [node Palette 0 1 [node Green 1 2 []]])
`shouldBe` `shouldBe`
Left (Error (Info.Pos 1 3) (UnexpectedEndOfInput [Green])) Left (Error (Info.Pos 1 3) (UnexpectedEndOfInput [Green]))
it "handler that doesn't match with apply" $ it "handler that doesn't match with apply" $
fst <$> runAssignment "PG" headF fst <$> runAssignment "PG" headF
(symbol Palatte *> children ( (symbol Palette *> children (
(,) <$> many (red `catchError` const blue) <*> green (,) <$> many (red `catchError` const blue) <*> green
)) ))
(makeState [node Palatte 0 1 [node Green 1 2 []]]) (makeState [node Palette 0 1 [node Green 1 2 []]])
`shouldBe` `shouldBe`
Right ([], Out "G") Right ([], Out "G")
describe "many" $ do describe "many" $ do
it "takes ones and only one zero width repetition" $ it "takes ones and only one zero width repetition" $
fst <$> runAssignment "PGG" headF fst <$> runAssignment "PGG" headF
(symbol Palatte *> children ( many (green <|> pure (Out "always")) )) (symbol Palette *> children ( many (green <|> pure (Out "always")) ))
(makeState [node Palatte 0 1 [node Green 1 2 [], node Green 2 3 []]]) (makeState [node Palette 0 1 [node Green 1 2 [], node Green 2 3 []]])
`shouldBe` `shouldBe`
Right [Out "G", Out "G", Out "always"] Right [Out "G", Out "G", Out "always"]
@ -176,7 +176,7 @@ spec = do
fst <$> runAssignment "12" headF fst <$> runAssignment "12" headF
(symbol Red *> children (many (symbol Green *> children (symbol Blue *> source)))) (symbol Red *> children (many (symbol Green *> children (symbol Blue *> source))))
(makeState [ node Red 0 2 [ node Green 0 1 [ node Blue 0 1 [] ] (makeState [ node Red 0 2 [ node Green 0 1 [ node Blue 0 1 [] ]
, node Green 1 2 [ node Blue 1 2 [] ] ] ]) , node Green 1 2 [ node Blue 1 2 [] ] ] ])
`shouldBe` `shouldBe`
Right ["1", "2"] Right ["1", "2"]
@ -199,7 +199,7 @@ spec = do
node :: symbol -> Int -> Int -> [AST symbol] -> AST symbol node :: symbol -> Int -> Int -> [AST symbol] -> AST symbol
node symbol start end children = cofree $ Node symbol (Range start end) (Info.Span (Info.Pos 1 (succ start)) (Info.Pos 1 (succ end))) :< children node symbol start end children = cofree $ Node symbol (Range start end) (Info.Span (Info.Pos 1 (succ start)) (Info.Pos 1 (succ end))) :< children
data Grammar = Palatte | Red | Green | Blue | Magenta data Grammar = Palette | Red | Green | Blue | Magenta
deriving (Enum, Eq, Show) deriving (Enum, Eq, Show)
instance Symbol Grammar where instance Symbol Grammar where