1
1
mirror of https://github.com/github/semantic.git synced 2024-12-18 04:11:48 +03:00

Merge branch 'master' into json-and-core-are-breaking-up

This commit is contained in:
Patrick Thomson 2019-10-02 13:50:12 -04:00 committed by GitHub
commit 90f5c78b0d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 303 additions and 244 deletions

View File

@ -21,10 +21,6 @@ import Data.Scope (Scope, Incr)
import qualified Data.Scope as Scope import qualified Data.Scope as Scope
import Data.Name import Data.Name
-- We default to deriving the default toEncoding definition (that piggybacks
-- off of toJSON) so that we never hit the problematic code paths associated
-- with toEncoding above.
instance ToJSON a => ToJSON (File a) where instance ToJSON a => ToJSON (File a) where
toJSON File{fileLoc, fileBody} = object toJSON File{fileLoc, fileBody} = object
[ "location" .= fileLoc [ "location" .= fileLoc

View File

@ -75,7 +75,6 @@ runParser blob@Blob{..} parser = case parser of
time "parse.cmark_parse" languageTag $ time "parse.cmark_parse" languageTag $
let term = cmarkParser blobSource let term = cmarkParser blobSource
in length term `seq` pure term in length term `seq` pure term
SomeParser parser -> SomeTerm <$> runParser blob parser
where languageTag = [("language" :: String, show (blobLanguage blob))] where languageTag = [("language" :: String, show (blobLanguage blob))]
data ParserCancelled = ParserTimedOut | AssignmentTimedOut data ParserCancelled = ParserTimedOut | AssignmentTimedOut

View File

@ -65,7 +65,6 @@ runParser timeout blob@Blob{..} parser = case parser of
MarkdownParser -> MarkdownParser ->
let term = cmarkParser blobSource let term = cmarkParser blobSource
in length term `seq` pure term in length term `seq` pure term
SomeParser parser -> SomeTerm <$> runParser timeout blob parser
data ParseFailure = ParseFailure String data ParseFailure = ParseFailure String
deriving (Show, Typeable) deriving (Show, Typeable)

View File

@ -30,11 +30,11 @@ import Prologue
type ComparabilityRelation syntax ann1 ann2 = forall a b. TermF syntax ann1 a -> TermF syntax ann2 b -> Bool type ComparabilityRelation syntax ann1 ann2 = forall a b. TermF syntax ann1 a -> TermF syntax ann2 b -> Bool
rws :: (Foldable syntax, Functor syntax, Diffable syntax) rws :: (Foldable syntax, Functor syntax, Diffable syntax)
=> ComparabilityRelation syntax (FeatureVector, ann) (FeatureVector, ann) => ComparabilityRelation syntax (FeatureVector, ann1) (FeatureVector, ann2)
-> (Term syntax (FeatureVector, ann) -> Term syntax (FeatureVector, ann) -> Bool) -> (Term syntax (FeatureVector, ann1) -> Term syntax (FeatureVector, ann2) -> Bool)
-> [Term syntax (FeatureVector, ann)] -> [Term syntax (FeatureVector, ann1)]
-> [Term syntax (FeatureVector, ann)] -> [Term syntax (FeatureVector, ann2)]
-> EditScript (Term syntax (FeatureVector, ann)) (Term syntax (FeatureVector, ann)) -> EditScript (Term syntax (FeatureVector, ann1)) (Term syntax (FeatureVector, ann2))
rws _ _ as [] = This <$> as rws _ _ as [] = This <$> as
rws _ _ [] bs = That <$> bs rws _ _ [] bs = That <$> bs
rws canCompare _ [a] [b] = if canCompareTerms canCompare a b then [These a b] else [That b, This a] rws canCompare _ [a] [b] = if canCompareTerms canCompare a b then [These a b] else [That b, This a]

View File

@ -1,7 +1,7 @@
{-# LANGUAGE GeneralizedNewtypeDeriving, TypeOperators, UndecidableInstances #-} {-# LANGUAGE FunctionalDependencies, GeneralizedNewtypeDeriving, TypeOperators, UndecidableInstances #-}
module Diffing.Interpreter module Diffing.Interpreter
( diffTerms ( diffTerms
, diffTermPair , DiffTerms(..)
, stripDiff , stripDiff
) where ) where
@ -16,30 +16,33 @@ import Prologue
-- | Diff two à la carte terms recursively. -- | Diff two à la carte terms recursively.
diffTerms :: (Diffable syntax, Eq1 syntax, Hashable1 syntax, Traversable syntax) diffTerms :: (Diffable syntax, Eq1 syntax, Hashable1 syntax, Traversable syntax)
=> Term syntax ann => Term syntax ann1
-> Term syntax ann -> Term syntax ann2
-> Diff.Diff syntax ann ann -> Diff.Diff syntax ann1 ann2
diffTerms t1 t2 = stripDiff (fromMaybe (Diff.replacing t1' t2') (run (runNonDetOnce (runDiff (algorithmForTerms t1' t2'))))) diffTerms t1 t2 = stripDiff (fromMaybe (Diff.replacing t1' t2') (run (runNonDetOnce (runDiff (algorithmForTerms t1' t2')))))
where (t1', t2') = ( defaultFeatureVectorDecorator t1 where (t1', t2') = ( defaultFeatureVectorDecorator t1
, defaultFeatureVectorDecorator t2) , defaultFeatureVectorDecorator t2)
-- | Strips the head annotation off a diff annotated with non-empty records. -- | Strips the head annotation off a diff annotated with non-empty records.
stripDiff :: Functor syntax stripDiff :: Functor syntax
=> Diff.Diff syntax (FeatureVector, ann) (FeatureVector, ann) => Diff.Diff syntax (FeatureVector, ann1) (FeatureVector, ann2)
-> Diff.Diff syntax ann ann -> Diff.Diff syntax ann1 ann2
stripDiff = bimap snd snd stripDiff = bimap snd snd
-- | Diff a 'These' of terms. class DiffTerms term diff | diff -> term, term -> diff where
diffTermPair :: (Diffable syntax, Eq1 syntax, Hashable1 syntax, Traversable syntax) => These (Term syntax ann) (Term syntax ann) -> Diff.Diff syntax ann ann -- | Diff a 'These' of terms.
diffTermPair = these Diff.deleting Diff.inserting diffTerms diffTermPair :: These (term ann1) (term ann2) -> diff ann1 ann2
instance (Diffable syntax, Eq1 syntax, Hashable1 syntax, Traversable syntax) => DiffTerms (Term syntax) (Diff.Diff syntax) where
diffTermPair = these Diff.deleting Diff.inserting diffTerms
-- | Run an 'Algorithm' to completion in an 'Alternative' context using the supplied comparability & equivalence relations. -- | Run an 'Algorithm' to completion in an 'Alternative' context using the supplied comparability & equivalence relations.
runDiff :: Algorithm runDiff :: Algorithm
(Term syntax (FeatureVector, ann)) (Term syntax (FeatureVector, ann1))
(Term syntax (FeatureVector, ann)) (Term syntax (FeatureVector, ann2))
(Diff.Diff syntax (FeatureVector, ann) (FeatureVector, ann)) (Diff.Diff syntax (FeatureVector, ann1) (FeatureVector, ann2))
(DiffC (Term syntax (FeatureVector, ann)) (Term syntax (FeatureVector, ann)) (Diff.Diff syntax (FeatureVector, ann) (FeatureVector, ann)) m) (DiffC (Term syntax (FeatureVector, ann1)) (Term syntax (FeatureVector, ann2)) (Diff.Diff syntax (FeatureVector, ann1) (FeatureVector, ann2)) m)
result result
-> m result -> m result
runDiff = runDiffC . runAlgorithm runDiff = runDiffC . runAlgorithm
@ -57,8 +60,8 @@ instance ( Alternative m
, Traversable syntax , Traversable syntax
) )
=> Carrier => Carrier
(Diff (Term syntax (FeatureVector, ann)) (Term syntax (FeatureVector, ann)) (Diff.Diff syntax (FeatureVector, ann) (FeatureVector, ann)) :+: sig) (Diff (Term syntax (FeatureVector, ann1)) (Term syntax (FeatureVector, ann2)) (Diff.Diff syntax (FeatureVector, ann1) (FeatureVector, ann2)) :+: sig)
(DiffC (Term syntax (FeatureVector, ann)) (Term syntax (FeatureVector, ann)) (Diff.Diff syntax (FeatureVector, ann) (FeatureVector, ann)) m) where (DiffC (Term syntax (FeatureVector, ann1)) (Term syntax (FeatureVector, ann2)) (Diff.Diff syntax (FeatureVector, ann1) (FeatureVector, ann2)) m) where
eff (L op) = case op of eff (L op) = case op of
Diff t1 t2 k -> runDiff (algorithmForTerms t1 t2) <|> pure (Diff.replacing t1 t2) >>= k Diff t1 t2 k -> runDiff (algorithmForTerms t1 t2) <|> pure (Diff.replacing t1 t2) >>= k
Linear (Term (In ann1 f1)) (Term (In ann2 f2)) k -> Diff.merge (ann1, ann2) <$> tryAlignWith (runDiff . diffThese) f1 f2 >>= k Linear (Term (In ann1 f1)) (Term (In ann2 f2)) k -> Diff.merge (ann1, ann2) <$> tryAlignWith (runDiff . diffThese) f1 f2 >>= k

View File

@ -1,8 +1,6 @@
{-# LANGUAGE AllowAmbiguousTypes, ConstraintKinds, GADTs, RankNTypes, ScopedTypeVariables, TypeFamilies, TypeOperators #-} {-# LANGUAGE AllowAmbiguousTypes, ConstraintKinds, GADTs, RankNTypes, ScopedTypeVariables, TypeFamilies, TypeOperators #-}
module Parsing.Parser module Parsing.Parser
( Parser(..) ( Parser(..)
, SomeTerm(..)
, withSomeTerm
, SomeAnalysisParser(..) , SomeAnalysisParser(..)
, SomeASTParser(..) , SomeASTParser(..)
, someASTParser , someASTParser
@ -112,8 +110,7 @@ data Parser term where
-> Parser (Term (Sum syntaxes) Loc) -> Parser (Term (Sum syntaxes) Loc)
-- | A parser for 'Markdown' using cmark. -- | A parser for 'Markdown' using cmark.
MarkdownParser :: Parser (Term (TermF [] CMarkGFM.NodeType) (Node Markdown.Grammar)) MarkdownParser :: Parser (Term (TermF [] CMarkGFM.NodeType) (Node Markdown.Grammar))
-- | An abstraction over parsers when we dont know the details of the term type.
SomeParser :: ApplyAll typeclasses syntax => Parser (Term syntax ann) -> Parser (SomeTerm typeclasses ann)
-- | Apply all of a list of typeclasses to all of a list of functors using 'Apply'. Used by 'someParser' to constrain all of the language-specific syntax types to the typeclasses in question. -- | Apply all of a list of typeclasses to all of a list of functors using 'Apply'. Used by 'someParser' to constrain all of the language-specific syntax types to the typeclasses in question.
type family ApplyAll (typeclasses :: [(* -> *) -> Constraint]) (syntax :: * -> *) :: Constraint where type family ApplyAll (typeclasses :: [(* -> *) -> Constraint]) (syntax :: * -> *) :: Constraint where
@ -168,12 +165,6 @@ precisePythonParser :: Parser (Py.Term Loc)
precisePythonParser = UnmarshalParser tree_sitter_python precisePythonParser = UnmarshalParser tree_sitter_python
data SomeTerm typeclasses ann where
SomeTerm :: ApplyAll typeclasses syntax => Term syntax ann -> SomeTerm typeclasses ann
withSomeTerm :: (forall syntax . ApplyAll typeclasses syntax => Term syntax ann -> a) -> SomeTerm typeclasses ann -> a
withSomeTerm with (SomeTerm term) = with term
-- | A parser for producing specialized (tree-sitter) ASTs. -- | A parser for producing specialized (tree-sitter) ASTs.
data SomeASTParser where data SomeASTParser where
SomeASTParser :: (Bounded grammar, Enum grammar, Show grammar) SomeASTParser :: (Bounded grammar, Enum grammar, Show grammar)

View File

@ -1,7 +1,6 @@
{-# LANGUAGE DerivingVia, RankNTypes, ScopedTypeVariables #-} {-# LANGUAGE DerivingVia, RankNTypes, ScopedTypeVariables #-}
module Rendering.TOC module Rendering.TOC
( renderToCDiff ( renderToCDiff
, renderToCTerm
, diffTOC , diffTOC
, Summaries(..) , Summaries(..)
, TOCSummary(..) , TOCSummary(..)
@ -143,15 +142,6 @@ renderToCDiff blobs = uncurry Summaries . bimap toMap toMap . List.partition isV
diffTOC :: (Foldable f, Functor f) => Diff f (Maybe Declaration) (Maybe Declaration) -> [TOCSummary] diffTOC :: (Foldable f, Functor f) => Diff f (Maybe Declaration) (Maybe Declaration) -> [TOCSummary]
diffTOC = fmap entrySummary . dedupe . tableOfContentsBy declaration diffTOC = fmap entrySummary . dedupe . tableOfContentsBy declaration
renderToCTerm :: (Foldable f, Functor f) => Blob -> Term f (Maybe Declaration) -> Summaries
renderToCTerm b@Blob{..} = uncurry Summaries . bimap toMap toMap . List.partition isValidSummary . termToC
where
toMap [] = mempty
toMap as = Map.singleton (T.pack (blobPath b)) (toJSON <$> as)
termToC :: (Foldable f, Functor f) => Term f (Maybe Declaration) -> [TOCSummary]
termToC = fmap (recordSummary "unchanged") . termTableOfContentsBy declaration
-- The user-facing category name -- The user-facing category name
toCategoryName :: Declaration -> T.Text toCategoryName :: Declaration -> T.Text
toCategoryName declaration = case declaration of toCategoryName declaration = case declaration of

View File

@ -1,4 +1,4 @@
{-# LANGUAGE GADTs, ConstraintKinds, TypeOperators, RankNTypes #-} {-# LANGUAGE GADTs, ConstraintKinds, FunctionalDependencies, LambdaCase, RankNTypes #-}
module Semantic.Api.Diffs module Semantic.Api.Diffs
( parseDiffBuilder ( parseDiffBuilder
, DiffOutputFormat(..) , DiffOutputFormat(..)
@ -8,11 +8,14 @@ module Semantic.Api.Diffs
, DiffEffects , DiffEffects
, SomeTermPair(..) , SomeTermPair(..)
, withSomeTermPair
, LegacySummarizeDiff(..)
, SummarizeDiff(..)
) where ) where
import Analysis.ConstructorName (ConstructorName) import Analysis.ConstructorName (ConstructorName)
import Analysis.TOCSummary (HasDeclaration) import Analysis.Decorator (decoratorWithAlgebra)
import Analysis.TOCSummary (Declaration, HasDeclaration, declarationAlgebra)
import Control.Effect.Error import Control.Effect.Error
import Control.Effect.Parse import Control.Effect.Parse
import Control.Effect.Reader import Control.Effect.Reader
@ -28,13 +31,13 @@ import Data.Language
import Data.Term import Data.Term
import qualified Data.Text as T import qualified Data.Text as T
import qualified Data.Vector as V import qualified Data.Vector as V
import Diffing.Algorithm (Diffable) import Diffing.Interpreter (DiffTerms(..))
import Diffing.Interpreter (diffTermPair)
import Parsing.Parser import Parsing.Parser
import Prologue import Prologue
import Rendering.Graph import Rendering.Graph
import Rendering.JSON hiding (JSON) import Rendering.JSON hiding (JSON)
import qualified Rendering.JSON import qualified Rendering.JSON
import Rendering.TOC
import Semantic.Api.Bridge import Semantic.Api.Bridge
import Semantic.Config import Semantic.Config
import Semantic.Proto.SemanticPB hiding (Blob, BlobPair) import Semantic.Proto.SemanticPB hiding (Blob, BlobPair)
@ -53,83 +56,139 @@ data DiffOutputFormat
deriving (Eq, Show) deriving (Eq, Show)
parseDiffBuilder :: (Traversable t, DiffEffects sig m) => DiffOutputFormat -> t BlobPair -> m Builder parseDiffBuilder :: (Traversable t, DiffEffects sig m) => DiffOutputFormat -> t BlobPair -> m Builder
parseDiffBuilder DiffJSONTree = distributeFoldMap (jsonDiff renderJSONTree) >=> serialize Format.JSON -- NB: Serialize happens at the top level for these two JSON formats to collect results of multiple blob pairs. parseDiffBuilder DiffJSONTree = distributeFoldMap jsonDiff >=> serialize Format.JSON -- NB: Serialize happens at the top level for these two JSON formats to collect results of multiple blob pairs.
parseDiffBuilder DiffJSONGraph = diffGraph >=> serialize Format.JSON parseDiffBuilder DiffJSONGraph = diffGraph >=> serialize Format.JSON
parseDiffBuilder DiffSExpression = distributeFoldMap sexpDiff parseDiffBuilder DiffSExpression = distributeFoldMap (doDiff (const id) sexprDiff)
parseDiffBuilder DiffShow = distributeFoldMap showDiff parseDiffBuilder DiffShow = distributeFoldMap (doDiff (const id) showDiff)
parseDiffBuilder DiffDotGraph = distributeFoldMap dotGraphDiff parseDiffBuilder DiffDotGraph = distributeFoldMap (doDiff (const id) dotGraphDiff)
type RenderJSON m syntax = forall syntax . CanDiff syntax => BlobPair -> Diff syntax Loc Loc -> m (Rendering.JSON.JSON "diffs" SomeJSON) jsonDiff :: DiffEffects sig m => BlobPair -> m (Rendering.JSON.JSON "diffs" SomeJSON)
jsonDiff blobPair = doDiff (const id) (pure . jsonTreeDiff blobPair) blobPair `catchError` jsonError blobPair
jsonDiff :: (DiffEffects sig m) => RenderJSON m syntax -> BlobPair -> m (Rendering.JSON.JSON "diffs" SomeJSON)
jsonDiff f blobPair = doDiff blobPair (const id) f `catchError` jsonError blobPair
jsonError :: Applicative m => BlobPair -> SomeException -> m (Rendering.JSON.JSON "diffs" SomeJSON) jsonError :: Applicative m => BlobPair -> SomeException -> m (Rendering.JSON.JSON "diffs" SomeJSON)
jsonError blobPair (SomeException e) = pure $ renderJSONDiffError blobPair (show e) jsonError blobPair (SomeException e) = pure $ renderJSONDiffError blobPair (show e)
renderJSONTree :: (Applicative m, ToJSONFields1 syntax) => BlobPair -> Diff syntax Loc Loc -> m (Rendering.JSON.JSON "diffs" SomeJSON)
renderJSONTree blobPair = pure . renderJSONDiff blobPair
diffGraph :: (Traversable t, DiffEffects sig m) => t BlobPair -> m DiffTreeGraphResponse diffGraph :: (Traversable t, DiffEffects sig m) => t BlobPair -> m DiffTreeGraphResponse
diffGraph blobs = DiffTreeGraphResponse . V.fromList . toList <$> distributeFor blobs go diffGraph blobs = DiffTreeGraphResponse . V.fromList . toList <$> distributeFor blobs go
where where
go :: (DiffEffects sig m) => BlobPair -> m DiffTreeFileGraph go :: DiffEffects sig m => BlobPair -> m DiffTreeFileGraph
go blobPair = doDiff blobPair (const id) render go blobPair = doDiff (const id) (pure . jsonGraphDiff blobPair) blobPair
`catchError` \(SomeException e) -> `catchError` \(SomeException e) ->
pure (DiffTreeFileGraph path lang mempty mempty (V.fromList [ParseError (T.pack (show e))])) pure (DiffTreeFileGraph path lang mempty mempty (V.fromList [ParseError (T.pack (show e))]))
where where
path = T.pack $ pathForBlobPair blobPair path = T.pack $ pathForBlobPair blobPair
lang = bridging # languageForBlobPair blobPair lang = bridging # languageForBlobPair blobPair
render :: (Foldable syntax, Functor syntax, ConstructorName syntax, Applicative m) => BlobPair -> Diff syntax Loc Loc -> m DiffTreeFileGraph
render _ diff =
let graph = renderTreeGraph diff
toEdge (Edge (a, b)) = DiffTreeEdge (diffVertexId a) (diffVertexId b)
in pure $ DiffTreeFileGraph path lang (V.fromList (vertexList graph)) (V.fromList (fmap toEdge (edgeList graph))) mempty
sexpDiff :: (DiffEffects sig m) => BlobPair -> m Builder
sexpDiff blobPair = doDiff blobPair (const id) (const (serialize (SExpression ByConstructorName)))
showDiff :: (DiffEffects sig m) => BlobPair -> m Builder
showDiff blobPair = doDiff blobPair (const id) (const (serialize Show))
dotGraphDiff :: (DiffEffects sig m) => BlobPair -> m Builder
dotGraphDiff blobPair = doDiff blobPair (const id) render
where render _ = serialize (DOT (diffStyle "diffs")) . renderTreeGraph
type DiffEffects sig m = (Member (Error SomeException) sig, Member (Reader Config) sig, Member Telemetry sig, Member Distribute sig, Member Parse sig, Carrier sig m, MonadIO m) type DiffEffects sig m = (Member (Error SomeException) sig, Member (Reader Config) sig, Member Telemetry sig, Member Distribute sig, Member Parse sig, Carrier sig m, MonadIO m)
type CanDiff syntax = (ConstructorName syntax, Diffable syntax, Eq1 syntax, HasDeclaration syntax, Hashable1 syntax, Show1 syntax, ToJSONFields1 syntax, Traversable syntax) type Decorate a b = forall term diff . DiffActions term diff => Blob -> term a -> term b
type Decorate a b = forall syntax . CanDiff syntax => Blob -> Term syntax a -> Term syntax b
type TermPairConstraints =
'[ ConstructorName
, Diffable
, Eq1
, HasDeclaration
, Hashable1
, Show1
, Traversable
, ToJSONFields1
]
doDiff :: (DiffEffects sig m) class DOTGraphDiff diff where
=> BlobPair -> Decorate Loc ann -> (forall syntax . CanDiff syntax => BlobPair -> Diff syntax ann ann -> m output) -> m output dotGraphDiff :: (Carrier sig m, Member (Reader Config) sig) => diff Loc Loc -> m Builder
doDiff blobPair decorate render = do
instance (ConstructorName syntax, Foldable syntax, Functor syntax) => DOTGraphDiff (Diff syntax) where
dotGraphDiff = serialize (DOT (diffStyle "diffs")) . renderTreeGraph
class JSONGraphDiff diff where
jsonGraphDiff :: BlobPair -> diff Loc Loc -> DiffTreeFileGraph
instance (Foldable syntax, Functor syntax, ConstructorName syntax) => JSONGraphDiff (Diff syntax) where
jsonGraphDiff blobPair diff
= let graph = renderTreeGraph diff
toEdge (Edge (a, b)) = DiffTreeEdge (diffVertexId a) (diffVertexId b)
in DiffTreeFileGraph path lang (V.fromList (vertexList graph)) (V.fromList (fmap toEdge (edgeList graph))) mempty where
path = T.pack $ pathForBlobPair blobPair
lang = bridging # languageForBlobPair blobPair
class JSONTreeDiff diff where
jsonTreeDiff :: BlobPair -> diff Loc Loc -> Rendering.JSON.JSON "diffs" SomeJSON
instance ToJSONFields1 syntax => JSONTreeDiff (Diff syntax) where
jsonTreeDiff = renderJSONDiff
class SExprDiff diff where
sexprDiff :: (Carrier sig m, Member (Reader Config) sig) => diff Loc Loc -> m Builder
instance (ConstructorName syntax, Foldable syntax, Functor syntax) => SExprDiff (Diff syntax) where
sexprDiff = serialize (SExpression ByConstructorName)
class ShowDiff diff where
showDiff :: (Carrier sig m, Member (Reader Config) sig) => diff Loc Loc -> m Builder
instance Show1 syntax => ShowDiff (Diff syntax) where
showDiff = serialize Show
class LegacySummarizeDiff term diff | diff -> term, term -> diff where
legacyDecorateTerm :: Blob -> term Loc -> term (Maybe Declaration)
legacySummarizeDiff :: BlobPair -> diff (Maybe Declaration) (Maybe Declaration) -> Summaries
instance (Foldable syntax, Functor syntax, HasDeclaration syntax) => LegacySummarizeDiff (Term syntax) (Diff syntax) where
legacyDecorateTerm = decoratorWithAlgebra . declarationAlgebra
legacySummarizeDiff = renderToCDiff
class SummarizeDiff term diff | diff -> term, term -> diff where
decorateTerm :: Blob -> term Loc -> term (Maybe Declaration)
summarizeDiff :: BlobPair -> diff (Maybe Declaration) (Maybe Declaration) -> TOCSummaryFile
instance (Foldable syntax, Functor syntax, HasDeclaration syntax) => SummarizeDiff (Term syntax) (Diff syntax) where
decorateTerm = decoratorWithAlgebra . declarationAlgebra
summarizeDiff blobPair diff = foldr go (TOCSummaryFile path lang mempty mempty) (diffTOC diff)
where
path = T.pack $ pathKeyForBlobPair blobPair
lang = bridging # languageForBlobPair blobPair
toChangeType = \case
"added" -> Added
"modified" -> Modified
"removed" -> Removed
_ -> None
go :: TOCSummary -> TOCSummaryFile -> TOCSummaryFile
go TOCSummary{..} TOCSummaryFile{..}
= TOCSummaryFile path language (V.cons (TOCSummaryChange summaryCategoryName summaryTermName (converting #? summarySpan) (toChangeType summaryChangeType)) changes) errors
go ErrorSummary{..} TOCSummaryFile{..}
= TOCSummaryFile path language changes (V.cons (TOCSummaryError errorText (converting #? errorSpan)) errors)
type DiffActions term diff =
( Bifoldable diff
, DiffTerms term diff
, DOTGraphDiff diff
, JSONGraphDiff diff
, JSONTreeDiff diff
, SExprDiff diff
, ShowDiff diff
, LegacySummarizeDiff term diff
, SummarizeDiff term diff
)
doDiff
:: DiffEffects sig m
=> Decorate Loc ann
-> (forall term diff . DiffActions term diff => diff ann ann -> m output)
-> BlobPair
-> m output
doDiff decorate render blobPair = do
SomeTermPair terms <- doParse blobPair decorate SomeTermPair terms <- doParse blobPair decorate
diff <- diffTerms blobPair terms diff <- diffTerms blobPair terms
render blobPair diff render diff
diffTerms :: (CanDiff syntax, Member Telemetry sig, Carrier sig m, MonadIO m) diffTerms :: (DiffActions term diff, Member Telemetry sig, Carrier sig m, MonadIO m)
=> BlobPair -> Join These (Term syntax ann) -> m (Diff syntax ann ann) => BlobPair -> Join These (term ann) -> m (diff ann ann)
diffTerms blobs terms = time "diff" languageTag $ do diffTerms blobs terms = time "diff" languageTag $ do
let diff = diffTermPair (runJoin terms) let diff = diffTermPair (runJoin terms)
diff <$ writeStat (Stat.count "diff.nodes" (bilength diff) languageTag) diff <$ writeStat (Stat.count "diff.nodes" (bilength diff) languageTag)
where languageTag = languageTagForBlobPair blobs where languageTag = languageTagForBlobPair blobs
doParse :: (Member (Error SomeException) sig, Member Distribute sig, Member Parse sig, Carrier sig m) doParse :: (Member (Error SomeException) sig, Member Distribute sig, Member Parse sig, Carrier sig m)
=> BlobPair -> Decorate Loc ann -> m (SomeTermPair TermPairConstraints ann) => BlobPair -> Decorate Loc ann -> m (SomeTermPair ann)
doParse blobPair decorate = case languageForBlobPair blobPair of doParse blobPair decorate = case languageForBlobPair blobPair of
Go -> SomeTermPair <$> distributeFor blobPair (\ blob -> decorate blob <$> parse goParser blob) Go -> SomeTermPair <$> distributeFor blobPair (\ blob -> decorate blob <$> parse goParser blob)
Haskell -> SomeTermPair <$> distributeFor blobPair (\ blob -> decorate blob <$> parse haskellParser blob) Haskell -> SomeTermPair <$> distributeFor blobPair (\ blob -> decorate blob <$> parse haskellParser blob)
@ -144,8 +203,5 @@ doParse blobPair decorate = case languageForBlobPair blobPair of
PHP -> SomeTermPair <$> distributeFor blobPair (\ blob -> decorate blob <$> parse phpParser blob) PHP -> SomeTermPair <$> distributeFor blobPair (\ blob -> decorate blob <$> parse phpParser blob)
_ -> noLanguageForBlob (pathForBlobPair blobPair) _ -> noLanguageForBlob (pathForBlobPair blobPair)
data SomeTermPair typeclasses ann where data SomeTermPair ann where
SomeTermPair :: ApplyAll typeclasses syntax => Join These (Term syntax ann) -> SomeTermPair typeclasses ann SomeTermPair :: DiffActions term diff => Join These (term ann) -> SomeTermPair ann
withSomeTermPair :: (forall syntax . ApplyAll typeclasses syntax => Join These (Term syntax ann) -> a) -> SomeTermPair typeclasses ann -> a
withSomeTermPair with (SomeTermPair terms) = with terms

View File

@ -1,4 +1,4 @@
{-# LANGUAGE GADTs, TypeOperators, DerivingStrategies #-} {-# LANGUAGE MonoLocalBinds, RankNTypes #-}
module Semantic.Api.Symbols module Semantic.Api.Symbols
( legacyParseSymbols ( legacyParseSymbols
, parseSymbols , parseSymbols
@ -17,25 +17,24 @@ import Data.Term
import qualified Data.Text as T import qualified Data.Text as T
import qualified Data.Vector as V import qualified Data.Vector as V
import Data.Text (pack) import Data.Text (pack)
import qualified Language.Python as Py import qualified Parsing.Parser as Parser
import Parsing.Parser
import Prologue import Prologue
import Semantic.Api.Bridge import Semantic.Api.Bridge
import qualified Semantic.Api.LegacyTypes as Legacy import qualified Semantic.Api.LegacyTypes as Legacy
import Semantic.Api.Terms (ParseEffects, doParse)
import Semantic.Proto.SemanticPB hiding (Blob) import Semantic.Proto.SemanticPB hiding (Blob)
import Semantic.Config
import Semantic.Task import Semantic.Task
import Serializing.Format import Serializing.Format (Format)
import Source.Loc import Source.Loc
import Tags.Taggable import Tags.Taggable
import Tags.Tagging import Tags.Tagging
import qualified Tags.Tagging.Precise as Precise import qualified Tags.Tagging.Precise as Precise
legacyParseSymbols :: (Member Distribute sig, ParseEffects sig m, Traversable t) => t Blob -> m Legacy.ParseTreeSymbolResponse legacyParseSymbols :: (Member Distribute sig, Member (Error SomeException) sig, Member (Reader PerLanguageModes) sig, Member Parse sig, Carrier sig m, Traversable t) => t Blob -> m Legacy.ParseTreeSymbolResponse
legacyParseSymbols blobs = Legacy.ParseTreeSymbolResponse <$> distributeFoldMap go blobs legacyParseSymbols blobs = Legacy.ParseTreeSymbolResponse <$> distributeFoldMap go blobs
where where
go :: ParseEffects sig m => Blob -> m [Legacy.File] go :: (Member (Error SomeException) sig, Member (Reader PerLanguageModes) sig, Member Parse sig, Carrier sig m) => Blob -> m [Legacy.File]
go blob@Blob{..} = (doParse blob >>= withSomeTerm renderToSymbols) `catchError` (\(SomeException _) -> pure (pure emptyFile)) go blob@Blob{..} = doParse (pure . renderToSymbols) symbolsToSummarize blob `catchError` (\(SomeException _) -> pure (pure emptyFile))
where where
emptyFile = tagsToFile [] emptyFile = tagsToFile []
@ -43,8 +42,8 @@ legacyParseSymbols blobs = Legacy.ParseTreeSymbolResponse <$> distributeFoldMap
symbolsToSummarize :: [Text] symbolsToSummarize :: [Text]
symbolsToSummarize = ["Function", "Method", "Class", "Module"] symbolsToSummarize = ["Function", "Method", "Class", "Module"]
renderToSymbols :: (IsTaggable f, Applicative m) => Term f Loc -> m [Legacy.File] renderToSymbols :: Precise.ToTags t => t Loc -> [Legacy.File]
renderToSymbols = pure . pure . tagsToFile . runTagging blob symbolsToSummarize renderToSymbols = pure . tagsToFile . Precise.tags blobSource
tagsToFile :: [Tag] -> Legacy.File tagsToFile :: [Tag] -> Legacy.File
tagsToFile tags = Legacy.File (pack (blobPath blob)) (pack (show (blobLanguage blob))) (fmap tagToSymbol tags) tagsToFile tags = Legacy.File (pack (blobPath blob)) (pack (show (blobLanguage blob))) (fmap tagToSymbol tags)
@ -58,31 +57,22 @@ legacyParseSymbols blobs = Legacy.ParseTreeSymbolResponse <$> distributeFoldMap
, symbolSpan = converting #? span , symbolSpan = converting #? span
} }
parseSymbolsBuilder :: (Member Distribute sig, ParseEffects sig m, Traversable t) => Format ParseTreeSymbolResponse -> t Blob -> m Builder parseSymbolsBuilder :: (Member Distribute sig, Member (Error SomeException) sig, Member Parse sig, Member (Reader Config) sig, Member (Reader PerLanguageModes) sig, Carrier sig m, Traversable t) => Format ParseTreeSymbolResponse -> t Blob -> m Builder
parseSymbolsBuilder format blobs = parseSymbols blobs >>= serialize format parseSymbolsBuilder format blobs = parseSymbols blobs >>= serialize format
parseSymbols :: (Member Distribute sig, ParseEffects sig m, Traversable t) => t Blob -> m ParseTreeSymbolResponse parseSymbols :: (Member Distribute sig, Member (Error SomeException) sig, Member (Reader PerLanguageModes) sig, Member Parse sig, Carrier sig m, Traversable t) => t Blob -> m ParseTreeSymbolResponse
parseSymbols blobs = do parseSymbols blobs = ParseTreeSymbolResponse . V.fromList . toList <$> distributeFor blobs go
modes <- ask
ParseTreeSymbolResponse . V.fromList . toList <$> distributeFor blobs (go modes)
where where
go :: ParseEffects sig m => PerLanguageModes -> Blob -> m File go :: (Member (Error SomeException) sig, Member (Reader PerLanguageModes) sig, Member Parse sig, Carrier sig m) => Blob -> m File
go modes blob@Blob{..} go blob@Blob{..} = catching $ doParse (pure . renderToSymbols) symbolsToSummarize blob
| Precise <- pythonMode modes
, Python <- blobLanguage'
= catching $ renderPreciseToSymbols <$> parse precisePythonParser blob
| otherwise = catching $ withSomeTerm renderToSymbols <$> doParse blob
where where
catching m = m `catchError` (\(SomeException e) -> pure $ errorFile (show e)) catching m = m `catchError` (\(SomeException e) -> pure $ errorFile (show e))
blobLanguage' = blobLanguage blob blobLanguage' = blobLanguage blob
blobPath' = pack $ blobPath blob blobPath' = pack $ blobPath blob
errorFile e = File blobPath' (bridging # blobLanguage') mempty (V.fromList [ParseError (T.pack e)]) blobOid errorFile e = File blobPath' (bridging # blobLanguage') mempty (V.fromList [ParseError (T.pack e)]) blobOid
renderToSymbols :: IsTaggable f => Term f Loc -> File renderToSymbols :: Precise.ToTags t => t Loc -> File
renderToSymbols term = tagsToFile (runTagging blob symbolsToSummarize term) renderToSymbols term = tagsToFile (Precise.tags blobSource term)
renderPreciseToSymbols :: Py.Term Loc -> File
renderPreciseToSymbols term = tagsToFile (Precise.tags blobSource term)
tagsToFile :: [Tag] -> File tagsToFile :: [Tag] -> File
tagsToFile tags = File blobPath' (bridging # blobLanguage') (V.fromList (fmap tagToSymbol tags)) mempty blobOid tagsToFile tags = File blobPath' (bridging # blobLanguage') (V.fromList (fmap tagToSymbol tags)) mempty blobOid
@ -98,3 +88,40 @@ tagToSymbol Tag{..} = Symbol
, span = converting #? span , span = converting #? span
, docs = fmap Docstring docs , docs = fmap Docstring docs
} }
data ALaCarteTerm syntax ann = ALaCarteTerm Language [Text] (Term syntax ann)
instance IsTaggable syntax => Precise.ToTags (ALaCarteTerm syntax) where
tags source (ALaCarteTerm lang symbolsToSummarize term) = runTagging lang source symbolsToSummarize term
doParse
:: ( Carrier sig m
, Member (Error SomeException) sig
, Member Parse sig
, Member (Reader PerLanguageModes) sig
)
=> (forall t . Precise.ToTags t => t Loc -> m a)
-> [Text]
-> Blob
-> m a
doParse with symbolsToSummarize blob = do
modes <- ask @PerLanguageModes
case blobLanguage blob of
Go -> parse Parser.goParser blob >>= with . mkTerm
Haskell -> parse Parser.haskellParser blob >>= with . mkTerm
JavaScript -> parse Parser.tsxParser blob >>= with . mkTerm
JSON -> parse Parser.jsonParser blob >>= with . mkTerm
JSX -> parse Parser.tsxParser blob >>= with . mkTerm
Markdown -> parse Parser.markdownParser blob >>= with . mkTerm
Python
| Precise <- pythonMode modes -> parse Parser.precisePythonParser blob >>= with
| otherwise -> parse Parser.pythonParser blob >>= with . mkTerm
Ruby -> parse Parser.rubyParser blob >>= with . mkTerm
TypeScript -> parse Parser.typescriptParser blob >>= with . mkTerm
TSX -> parse Parser.tsxParser blob >>= with . mkTerm
PHP -> parse Parser.phpParser blob >>= with . mkTerm
_ -> noLanguageForBlob (blobPath blob)
where mkTerm :: Term syntax Loc -> ALaCarteTerm syntax Loc
mkTerm = ALaCarteTerm (blobLanguage blob) symbolsToSummarize

View File

@ -1,14 +1,10 @@
{-# LANGUAGE GADTs, TypeOperators, DerivingStrategies, LambdaCase #-}
module Semantic.Api.TOCSummaries (diffSummary, legacyDiffSummary, diffSummaryBuilder) where module Semantic.Api.TOCSummaries (diffSummary, legacyDiffSummary, diffSummaryBuilder) where
import Analysis.Decorator (decoratorWithAlgebra)
import Analysis.TOCSummary (Declaration, declarationAlgebra)
import Control.Effect.Error import Control.Effect.Error
import Control.Lens import Control.Lens
import Data.Aeson import Data.Aeson
import Data.Blob import Data.Blob
import Data.ByteString.Builder import Data.ByteString.Builder
import Data.Diff
import qualified Data.Map.Monoidal as Map import qualified Data.Map.Monoidal as Map
import qualified Data.Text as T import qualified Data.Text as T
import qualified Data.Vector as V import qualified Data.Vector as V
@ -20,46 +16,26 @@ import Semantic.Proto.SemanticPB hiding (Blob, BlobPair)
import Semantic.Task as Task import Semantic.Task as Task
import Serializing.Format import Serializing.Format
diffSummaryBuilder :: (DiffEffects sig m) => Format DiffTreeTOCResponse -> [BlobPair] -> m Builder diffSummaryBuilder :: DiffEffects sig m => Format DiffTreeTOCResponse -> [BlobPair] -> m Builder
diffSummaryBuilder format blobs = diffSummary blobs >>= serialize format diffSummaryBuilder format blobs = diffSummary blobs >>= serialize format
legacyDiffSummary :: (DiffEffects sig m) => [BlobPair] -> m Summaries legacyDiffSummary :: DiffEffects sig m => [BlobPair] -> m Summaries
legacyDiffSummary = distributeFoldMap go legacyDiffSummary = distributeFoldMap go
where where
go :: (DiffEffects sig m) => BlobPair -> m Summaries go :: DiffEffects sig m => BlobPair -> m Summaries
go blobPair = doDiff blobPair (\ blob -> decoratorWithAlgebra (declarationAlgebra blob)) render go blobPair = doDiff legacyDecorateTerm (pure . legacySummarizeDiff blobPair) blobPair
`catchError` \(SomeException e) -> `catchError` \(SomeException e) ->
pure $ Summaries mempty (Map.singleton path [toJSON (ErrorSummary (T.pack (show e)) lowerBound lang)]) pure $ Summaries mempty (Map.singleton path [toJSON (ErrorSummary (T.pack (show e)) lowerBound lang)])
where path = T.pack $ pathKeyForBlobPair blobPair where path = T.pack $ pathKeyForBlobPair blobPair
lang = languageForBlobPair blobPair lang = languageForBlobPair blobPair
render :: (Foldable syntax, Functor syntax, Applicative m) => BlobPair -> Diff syntax (Maybe Declaration) (Maybe Declaration) -> m Summaries
render blobPair = pure . renderToCDiff blobPair
diffSummary :: (DiffEffects sig m) => [BlobPair] -> m DiffTreeTOCResponse diffSummary :: DiffEffects sig m => [BlobPair] -> m DiffTreeTOCResponse
diffSummary blobs = DiffTreeTOCResponse . V.fromList <$> distributeFor blobs go diffSummary blobs = DiffTreeTOCResponse . V.fromList <$> distributeFor blobs go
where where
go :: (DiffEffects sig m) => BlobPair -> m TOCSummaryFile go :: DiffEffects sig m => BlobPair -> m TOCSummaryFile
go blobPair = doDiff blobPair (\ blob -> decoratorWithAlgebra (declarationAlgebra blob)) render go blobPair = doDiff decorateTerm (pure . summarizeDiff blobPair) blobPair
`catchError` \(SomeException e) -> `catchError` \(SomeException e) ->
pure $ TOCSummaryFile path lang mempty (V.fromList [TOCSummaryError (T.pack (show e)) Nothing]) pure $ TOCSummaryFile path lang mempty (V.fromList [TOCSummaryError (T.pack (show e)) Nothing])
where path = T.pack $ pathKeyForBlobPair blobPair where path = T.pack $ pathKeyForBlobPair blobPair
lang = bridging # languageForBlobPair blobPair lang = bridging # languageForBlobPair blobPair
render :: (Foldable syntax, Functor syntax, Applicative m) => BlobPair -> Diff syntax (Maybe Declaration) (Maybe Declaration) -> m TOCSummaryFile
render blobPair diff = pure $ foldr go (TOCSummaryFile path lang mempty mempty) (diffTOC diff)
where
path = T.pack $ pathKeyForBlobPair blobPair
lang = bridging # languageForBlobPair blobPair
toChangeType = \case
"added" -> Added
"modified" -> Modified
"removed" -> Removed
_ -> None
go :: TOCSummary -> TOCSummaryFile -> TOCSummaryFile
go TOCSummary{..} TOCSummaryFile{..}
= TOCSummaryFile path language (V.cons (TOCSummaryChange summaryCategoryName summaryTermName (converting #? summarySpan) (toChangeType summaryChangeType)) changes) errors
go ErrorSummary{..} TOCSummaryFile{..}
= TOCSummaryFile path language changes (V.cons (TOCSummaryError errorText (converting #? errorSpan)) errors)

View File

@ -1,19 +1,10 @@
{-# LANGUAGE ConstraintKinds, GADTs, TypeOperators, DerivingStrategies #-} {-# LANGUAGE ConstraintKinds, MonoLocalBinds, RankNTypes #-}
module Semantic.Api.Terms module Semantic.Api.Terms
( ( termGraph
termGraph
, parseTermBuilder , parseTermBuilder
, TermOutputFormat(..) , TermOutputFormat(..)
, doParse
, ParseEffects
, TermConstraints
, SomeTerm(..)
, withSomeTerm
) where ) where
import Analysis.ConstructorName (ConstructorName) import Analysis.ConstructorName (ConstructorName)
import Control.Effect.Error import Control.Effect.Error
import Control.Effect.Parse import Control.Effect.Parse
@ -21,7 +12,6 @@ import Control.Effect.Reader
import Control.Lens import Control.Lens
import Control.Monad import Control.Monad
import Control.Monad.IO.Class import Control.Monad.IO.Class
import Data.Abstract.Declarations
import Data.Blob import Data.Blob
import Data.ByteString.Builder import Data.ByteString.Builder
import Data.Either import Data.Either
@ -44,23 +34,20 @@ import Semantic.Task
import Serializing.Format hiding (JSON) import Serializing.Format hiding (JSON)
import qualified Serializing.Format as Format import qualified Serializing.Format as Format
import Source.Loc import Source.Loc
import Tags.Taggable
import qualified Language.Python as Py
termGraph :: (Traversable t, Member Distribute sig, ParseEffects sig m) => t Blob -> m ParseTreeGraphResponse termGraph :: (Traversable t, Member Distribute sig, ParseEffects sig m) => t Blob -> m ParseTreeGraphResponse
termGraph blobs = ParseTreeGraphResponse . V.fromList . toList <$> distributeFor blobs go termGraph blobs = ParseTreeGraphResponse . V.fromList . toList <$> distributeFor blobs go
where where
go :: ParseEffects sig m => Blob -> m ParseTreeFileGraph go :: ParseEffects sig m => Blob -> m ParseTreeFileGraph
go blob = (doParse blob >>= withSomeTerm (pure . render)) go blob = doParse (pure . jsonGraphTerm blob) blob
`catchError` \(SomeException e) -> `catchError` \(SomeException e) ->
pure (ParseTreeFileGraph path lang mempty mempty (V.fromList [ParseError (T.pack (show e))])) pure (ParseTreeFileGraph path lang mempty mempty (V.fromList [ParseError (T.pack (show e))]))
where where
path = T.pack $ blobPath blob path = T.pack $ blobPath blob
lang = bridging # blobLanguage blob lang = bridging # blobLanguage blob
render :: (Foldable syntax, Functor syntax, ConstructorName syntax) => Term syntax Loc -> ParseTreeFileGraph
render t = let graph = renderTreeGraph t
toEdge (Edge (a, b)) = TermEdge (vertexId a) (vertexId b)
in ParseTreeFileGraph path lang (V.fromList (vertexList graph)) (V.fromList (fmap toEdge (edgeList graph))) mempty
data TermOutputFormat data TermOutputFormat
= TermJSONTree = TermJSONTree
@ -75,28 +62,19 @@ parseTermBuilder :: (Traversable t, Member Distribute sig, ParseEffects sig m, M
=> TermOutputFormat -> t Blob -> m Builder => TermOutputFormat -> t Blob -> m Builder
parseTermBuilder TermJSONTree = distributeFoldMap jsonTerm >=> serialize Format.JSON -- NB: Serialize happens at the top level for these two JSON formats to collect results of multiple blobs. parseTermBuilder TermJSONTree = distributeFoldMap jsonTerm >=> serialize Format.JSON -- NB: Serialize happens at the top level for these two JSON formats to collect results of multiple blobs.
parseTermBuilder TermJSONGraph = termGraph >=> serialize Format.JSON parseTermBuilder TermJSONGraph = termGraph >=> serialize Format.JSON
parseTermBuilder TermSExpression = distributeFoldMap sexpTerm parseTermBuilder TermSExpression = distributeFoldMap (doParse sexprTerm)
parseTermBuilder TermDotGraph = distributeFoldMap dotGraphTerm parseTermBuilder TermDotGraph = distributeFoldMap (doParse dotGraphTerm)
parseTermBuilder TermShow = distributeFoldMap showTerm parseTermBuilder TermShow = distributeFoldMap (doParse showTerm)
parseTermBuilder TermQuiet = distributeFoldMap quietTerm parseTermBuilder TermQuiet = distributeFoldMap quietTerm
jsonTerm :: (ParseEffects sig m) => Blob -> m (Rendering.JSON.JSON "trees" SomeJSON) jsonTerm :: ParseEffects sig m => Blob -> m (Rendering.JSON.JSON "trees" SomeJSON)
jsonTerm blob = (doParse blob >>= withSomeTerm (pure . renderJSONTerm blob)) `catchError` jsonError blob jsonTerm blob = doParse (pure . jsonTreeTerm blob) blob `catchError` jsonError blob
jsonError :: Applicative m => Blob -> SomeException -> m (Rendering.JSON.JSON "trees" SomeJSON) jsonError :: Applicative m => Blob -> SomeException -> m (Rendering.JSON.JSON "trees" SomeJSON)
jsonError blob (SomeException e) = pure $ renderJSONError blob (show e) jsonError blob (SomeException e) = pure $ renderJSONError blob (show e)
sexpTerm :: (ParseEffects sig m) => Blob -> m Builder
sexpTerm = doParse >=> withSomeTerm (serialize (SExpression ByConstructorName))
dotGraphTerm :: (ParseEffects sig m) => Blob -> m Builder
dotGraphTerm = doParse >=> withSomeTerm (serialize (DOT (termStyle "terms")) . renderTreeGraph)
showTerm :: (ParseEffects sig m) => Blob -> m Builder
showTerm = doParse >=> withSomeTerm (serialize Show . quieterm)
quietTerm :: (ParseEffects sig m, MonadIO m) => Blob -> m Builder quietTerm :: (ParseEffects sig m, MonadIO m) => Blob -> m Builder
quietTerm blob = showTiming blob <$> time' ( (doParse blob >>= withSomeTerm (fmap (const (Right ())) . serialize Show . quieterm)) `catchError` timingError ) quietTerm blob = showTiming blob <$> time' ( doParse (fmap (const (Right ())) . showTerm) blob `catchError` timingError )
where where
timingError (SomeException e) = pure (Left (show e)) timingError (SomeException e) = pure (Left (show e))
showTiming Blob{..} (res, duration) = showTiming Blob{..} (res, duration) =
@ -106,27 +84,70 @@ quietTerm blob = showTiming blob <$> time' ( (doParse blob >>= withSomeTerm (fma
type ParseEffects sig m = (Member (Error SomeException) sig, Member (Reader PerLanguageModes) sig, Member Parse sig, Member (Reader Config) sig, Carrier sig m) type ParseEffects sig m = (Member (Error SomeException) sig, Member (Reader PerLanguageModes) sig, Member Parse sig, Member (Reader Config) sig, Carrier sig m)
type TermConstraints =
'[ Taggable
, Declarations1
, ConstructorName
, HasTextElement
, Show1
, ToJSONFields1
, Traversable
]
doParse :: (ParseEffects sig m) => Blob -> m (SomeTerm TermConstraints Loc) class ShowTerm term where
doParse blob = case blobLanguage blob of showTerm :: (Carrier sig m, Member (Reader Config) sig) => term Loc -> m Builder
Go -> SomeTerm <$> parse goParser blob
Haskell -> SomeTerm <$> parse haskellParser blob instance (Functor syntax, Show1 syntax) => ShowTerm (Term syntax) where
JavaScript -> SomeTerm <$> parse tsxParser blob showTerm = serialize Show . quieterm
JSON -> SomeTerm <$> parse jsonParser blob
JSX -> SomeTerm <$> parse tsxParser blob instance ShowTerm Py.Term where
Markdown -> SomeTerm <$> parse markdownParser blob showTerm = serialize Show . Py.getTerm
Python -> SomeTerm <$> parse pythonParser blob
Ruby -> SomeTerm <$> parse rubyParser blob
TypeScript -> SomeTerm <$> parse typescriptParser blob class SExprTerm term where
TSX -> SomeTerm <$> parse tsxParser blob sexprTerm :: (Carrier sig m, Member (Reader Config) sig) => term Loc -> m Builder
PHP -> SomeTerm <$> parse phpParser blob
instance (ConstructorName syntax, Foldable syntax, Functor syntax) => SExprTerm (Term syntax) where
sexprTerm = serialize (SExpression ByConstructorName)
class DOTGraphTerm term where
dotGraphTerm :: (Carrier sig m, Member (Reader Config) sig) => term Loc -> m Builder
instance (ConstructorName syntax, Foldable syntax, Functor syntax) => DOTGraphTerm (Term syntax) where
dotGraphTerm = serialize (DOT (termStyle "terms")) . renderTreeGraph
class JSONTreeTerm term where
jsonTreeTerm :: Blob -> term Loc -> Rendering.JSON.JSON "trees" SomeJSON
instance ToJSONFields1 syntax => JSONTreeTerm (Term syntax) where
jsonTreeTerm = renderJSONTerm
class JSONGraphTerm term where
jsonGraphTerm :: Blob -> term Loc -> ParseTreeFileGraph
instance (Foldable syntax, Functor syntax, ConstructorName syntax) => JSONGraphTerm (Term syntax) where
jsonGraphTerm blob t
= let graph = renderTreeGraph t
toEdge (Edge (a, b)) = TermEdge (vertexId a) (vertexId b)
in ParseTreeFileGraph path lang (V.fromList (vertexList graph)) (V.fromList (fmap toEdge (edgeList graph))) mempty where
path = T.pack $ blobPath blob
lang = bridging # blobLanguage blob
type TermActions t = (DOTGraphTerm t, JSONGraphTerm t, JSONTreeTerm t, SExprTerm t, ShowTerm t)
doParse
:: ( Carrier sig m
, Member (Error SomeException) sig
, Member Parse sig
)
=> (forall term . TermActions term => term Loc -> m a)
-> Blob
-> m a
doParse with blob = case blobLanguage blob of
Go -> parse goParser blob >>= with
Haskell -> parse haskellParser blob >>= with
JavaScript -> parse tsxParser blob >>= with
JSON -> parse jsonParser blob >>= with
JSX -> parse tsxParser blob >>= with
Markdown -> parse markdownParser blob >>= with
Python -> parse pythonParser blob >>= with
Ruby -> parse rubyParser blob >>= with
TypeScript -> parse typescriptParser blob >>= with
TSX -> parse tsxParser blob >>= with
PHP -> parse phpParser blob >>= with
_ -> noLanguageForBlob (blobPath blob) _ -> noLanguageForBlob (blobPath blob)

View File

@ -1,6 +1,7 @@
{-# LANGUAGE DataKinds, FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, OverloadedStrings, ScopedTypeVariables, TypeApplications, TypeFamilies, TypeOperators, UndecidableInstances #-} {-# LANGUAGE DataKinds, FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, OverloadedStrings, ScopedTypeVariables, TypeApplications, TypeFamilies, TypeOperators, UndecidableInstances #-}
module Serializing.SExpression.Precise module Serializing.SExpression.Precise
( serializeSExpression ( serializeSExpression
, ToSExpression(..)
) where ) where
import Data.ByteString.Builder import Data.ByteString.Builder

View File

@ -29,7 +29,6 @@ import Analysis.ConstructorName
import Analysis.HasTextElement import Analysis.HasTextElement
import Data.Abstract.Declarations import Data.Abstract.Declarations
import Data.Abstract.Name import Data.Abstract.Name
import Data.Blob
import Data.Language import Data.Language
import Data.Term import Data.Term
import Data.Text hiding (empty) import Data.Text hiding (empty)
@ -99,10 +98,10 @@ type IsTaggable syntax =
) )
tagging :: (Monad m, IsTaggable syntax) tagging :: (Monad m, IsTaggable syntax)
=> Blob => Language
-> Term syntax Loc -> Term syntax Loc
-> Stream (Of Token) m () -> Stream (Of Token) m ()
tagging b = foldSubterms (descend (blobLanguage b)) tagging = foldSubterms . descend
descend :: descend ::
( ConstructorName (TermF syntax Loc) ( ConstructorName (TermF syntax Loc)

View File

@ -14,7 +14,7 @@ import Data.Text as T hiding (empty)
import Streaming import Streaming
import qualified Streaming.Prelude as Streaming import qualified Streaming.Prelude as Streaming
import Data.Blob import Data.Language
import Data.Term import Data.Term
import Source.Loc import Source.Loc
import qualified Source.Source as Source import qualified Source.Source as Source
@ -22,16 +22,17 @@ import Tags.Tag
import Tags.Taggable import Tags.Taggable
runTagging :: (IsTaggable syntax) runTagging :: (IsTaggable syntax)
=> Blob => Language
-> Source.Source
-> [Text] -> [Text]
-> Term syntax Loc -> Term syntax Loc
-> [Tag] -> [Tag]
runTagging blob symbolsToSummarize runTagging lang source symbolsToSummarize
= Eff.run = Eff.run
. evalState @[ContextToken] [] . evalState @[ContextToken] []
. Streaming.toList_ . Streaming.toList_
. contextualizing blob toKind . contextualizing source toKind
. tagging blob . tagging lang
where where
toKind x = do toKind x = do
guard (x `elem` symbolsToSummarize) guard (x `elem` symbolsToSummarize)
@ -49,11 +50,11 @@ type ContextToken = (Text, Range)
contextualizing :: ( Member (State [ContextToken]) sig contextualizing :: ( Member (State [ContextToken]) sig
, Carrier sig m , Carrier sig m
) )
=> Blob => Source.Source
-> (Text -> Maybe Kind) -> (Text -> Maybe Kind)
-> Stream (Of Token) m a -> Stream (Of Token) m a
-> Stream (Of Tag) m a -> Stream (Of Tag) m a
contextualizing Blob{..} toKind = Streaming.mapMaybeM $ \case contextualizing source toKind = Streaming.mapMaybeM $ \case
Enter x r -> Nothing <$ enterScope (x, r) Enter x r -> Nothing <$ enterScope (x, r)
Exit x r -> Nothing <$ exitScope (x, r) Exit x r -> Nothing <$ exitScope (x, r)
Iden iden span docsLiteralRange -> get @[ContextToken] >>= pure . \case Iden iden span docsLiteralRange -> get @[ContextToken] >>= pure . \case
@ -63,7 +64,7 @@ contextualizing Blob{..} toKind = Streaming.mapMaybeM $ \case
-> Just $ Tag iden kind span (firstLine (slice r)) (slice <$> docsLiteralRange) -> Just $ Tag iden kind span (firstLine (slice r)) (slice <$> docsLiteralRange)
_ -> Nothing _ -> Nothing
where where
slice = stripEnd . Source.toText . Source.slice blobSource slice = stripEnd . Source.toText . Source.slice source
firstLine = T.take 180 . fst . breakOn "\n" firstLine = T.take 180 . fst . breakOn "\n"
enterScope, exitScope :: ( Member (State [ContextToken]) sig enterScope, exitScope :: ( Member (State [ContextToken]) sig

View File

@ -10,40 +10,40 @@ spec = do
describe "go" $ do describe "go" $ do
it "produces tags for functions with docs" $ do it "produces tags for functions with docs" $ do
(blob, tree) <- parseTestFile goParser (Path.relFile "test/fixtures/go/tags/simple_functions.go") (blob, tree) <- parseTestFile goParser (Path.relFile "test/fixtures/go/tags/simple_functions.go")
runTagging blob symbolsToSummarize tree `shouldBe` runTagging (blobLanguage blob) (blobSource blob) symbolsToSummarize tree `shouldBe`
[ Tag "TestFromBits" Function (Span (Pos 6 1) (Pos 8 2)) "func TestFromBits(t *testing.T) {" (Just "// TestFromBits ...") [ Tag "TestFromBits" Function (Span (Pos 6 1) (Pos 8 2)) "func TestFromBits(t *testing.T) {" (Just "// TestFromBits ...")
, Tag "Hi" Function (Span (Pos 10 1) (Pos 11 2)) "func Hi()" Nothing ] , Tag "Hi" Function (Span (Pos 10 1) (Pos 11 2)) "func Hi()" Nothing ]
it "produces tags for methods" $ do it "produces tags for methods" $ do
(blob, tree) <- parseTestFile goParser (Path.relFile "test/fixtures/go/tags/method.go") (blob, tree) <- parseTestFile goParser (Path.relFile "test/fixtures/go/tags/method.go")
runTagging blob symbolsToSummarize tree `shouldBe` runTagging (blobLanguage blob) (blobSource blob) symbolsToSummarize tree `shouldBe`
[ Tag "CheckAuth" Method (Span (Pos 3 1) (Pos 3 100)) "func (c *apiClient) CheckAuth(req *http.Request, user, repo string) (*authenticatedActor, error)" Nothing] [ Tag "CheckAuth" Method (Span (Pos 3 1) (Pos 3 100)) "func (c *apiClient) CheckAuth(req *http.Request, user, repo string) (*authenticatedActor, error)" Nothing]
it "produces tags for calls" $ do it "produces tags for calls" $ do
(blob, tree) <- parseTestFile goParser (Path.relFile "test/fixtures/go/tags/simple_functions.go") (blob, tree) <- parseTestFile goParser (Path.relFile "test/fixtures/go/tags/simple_functions.go")
runTagging blob ["Call"] tree `shouldBe` runTagging (blobLanguage blob) (blobSource blob) ["Call"] tree `shouldBe`
[ Tag "Hi" Call (Span (Pos 7 2) (Pos 7 6)) "Hi()" Nothing] [ Tag "Hi" Call (Span (Pos 7 2) (Pos 7 6)) "Hi()" Nothing]
describe "javascript and typescript" $ do describe "javascript and typescript" $ do
it "produces tags for functions with docs" $ do it "produces tags for functions with docs" $ do
(blob, tree) <- parseTestFile typescriptParser (Path.relFile "test/fixtures/javascript/tags/simple_function_with_docs.js") (blob, tree) <- parseTestFile typescriptParser (Path.relFile "test/fixtures/javascript/tags/simple_function_with_docs.js")
runTagging blob symbolsToSummarize tree `shouldBe` runTagging (blobLanguage blob) (blobSource blob) symbolsToSummarize tree `shouldBe`
[ Tag "myFunction" Function (Span (Pos 2 1) (Pos 4 2)) "function myFunction()" (Just "// This is myFunction") ] [ Tag "myFunction" Function (Span (Pos 2 1) (Pos 4 2)) "function myFunction()" (Just "// This is myFunction") ]
it "produces tags for classes" $ do it "produces tags for classes" $ do
(blob, tree) <- parseTestFile typescriptParser (Path.relFile "test/fixtures/typescript/tags/class.ts") (blob, tree) <- parseTestFile typescriptParser (Path.relFile "test/fixtures/typescript/tags/class.ts")
runTagging blob symbolsToSummarize tree `shouldBe` runTagging (blobLanguage blob) (blobSource blob) symbolsToSummarize tree `shouldBe`
[ Tag "FooBar" Class (Span (Pos 1 1) (Pos 1 16)) "class FooBar" Nothing ] [ Tag "FooBar" Class (Span (Pos 1 1) (Pos 1 16)) "class FooBar" Nothing ]
it "produces tags for modules" $ do it "produces tags for modules" $ do
(blob, tree) <- parseTestFile typescriptParser (Path.relFile "test/fixtures/typescript/tags/module.ts") (blob, tree) <- parseTestFile typescriptParser (Path.relFile "test/fixtures/typescript/tags/module.ts")
runTagging blob symbolsToSummarize tree `shouldBe` runTagging (blobLanguage blob) (blobSource blob) symbolsToSummarize tree `shouldBe`
[ Tag "APromise" Tags.Module (Span (Pos 1 1) (Pos 1 20)) "module APromise { }" Nothing ] [ Tag "APromise" Tags.Module (Span (Pos 1 1) (Pos 1 20)) "module APromise { }" Nothing ]
describe "python" $ do describe "python" $ do
it "produces tags for functions" $ do it "produces tags for functions" $ do
(blob, tree) <- parseTestFile pythonParser (Path.relFile "test/fixtures/python/tags/simple_functions.py") (blob, tree) <- parseTestFile pythonParser (Path.relFile "test/fixtures/python/tags/simple_functions.py")
runTagging blob symbolsToSummarize tree `shouldBe` runTagging (blobLanguage blob) (blobSource blob) symbolsToSummarize tree `shouldBe`
[ Tag "Foo" Function (Span (Pos 1 1) (Pos 5 17)) "def Foo(x):" Nothing [ Tag "Foo" Function (Span (Pos 1 1) (Pos 5 17)) "def Foo(x):" Nothing
, Tag "Bar" Function (Span (Pos 7 1) (Pos 11 13)) "def Bar():" Nothing , Tag "Bar" Function (Span (Pos 7 1) (Pos 11 13)) "def Bar():" Nothing
, Tag "local" Function (Span (Pos 8 5) (Pos 9 17)) "def local():" Nothing , Tag "local" Function (Span (Pos 8 5) (Pos 9 17)) "def local():" Nothing
@ -51,30 +51,30 @@ spec = do
it "produces tags for functions with docs" $ do it "produces tags for functions with docs" $ do
(blob, tree) <- parseTestFile pythonParser (Path.relFile "test/fixtures/python/tags/simple_function_with_docs.py") (blob, tree) <- parseTestFile pythonParser (Path.relFile "test/fixtures/python/tags/simple_function_with_docs.py")
runTagging blob symbolsToSummarize tree `shouldBe` runTagging (blobLanguage blob) (blobSource blob) symbolsToSummarize tree `shouldBe`
[ Tag "Foo" Function (Span (Pos 1 1) (Pos 3 13)) "def Foo(x):" (Just "\"\"\"This is the foo function\"\"\"") ] [ Tag "Foo" Function (Span (Pos 1 1) (Pos 3 13)) "def Foo(x):" (Just "\"\"\"This is the foo function\"\"\"") ]
it "produces tags for classes" $ do it "produces tags for classes" $ do
(blob, tree) <- parseTestFile pythonParser (Path.relFile "test/fixtures/python/tags/class.py") (blob, tree) <- parseTestFile pythonParser (Path.relFile "test/fixtures/python/tags/class.py")
runTagging blob symbolsToSummarize tree `shouldBe` runTagging (blobLanguage blob) (blobSource blob) symbolsToSummarize tree `shouldBe`
[ Tag "Foo" Class (Span (Pos 1 1) (Pos 5 17)) "class Foo:" (Just "\"\"\"The Foo class\"\"\"") [ Tag "Foo" Class (Span (Pos 1 1) (Pos 5 17)) "class Foo:" (Just "\"\"\"The Foo class\"\"\"")
, Tag "f" Function (Span (Pos 3 5) (Pos 5 17)) "def f(self):" (Just "\"\"\"The f method\"\"\"") , Tag "f" Function (Span (Pos 3 5) (Pos 5 17)) "def f(self):" (Just "\"\"\"The f method\"\"\"")
] ]
it "produces tags for multi-line functions" $ do it "produces tags for multi-line functions" $ do
(blob, tree) <- parseTestFile pythonParser (Path.relFile "test/fixtures/python/tags/multiline.py") (blob, tree) <- parseTestFile pythonParser (Path.relFile "test/fixtures/python/tags/multiline.py")
runTagging blob symbolsToSummarize tree `shouldBe` runTagging (blobLanguage blob) (blobSource blob) symbolsToSummarize tree `shouldBe`
[ Tag "Foo" Function (Span (Pos 1 1) (Pos 3 13)) "def Foo(x," Nothing ] [ Tag "Foo" Function (Span (Pos 1 1) (Pos 3 13)) "def Foo(x," Nothing ]
describe "ruby" $ do describe "ruby" $ do
it "produces tags for methods" $ do it "produces tags for methods" $ do
(blob, tree) <- parseTestFile rubyParser (Path.relFile "test/fixtures/ruby/tags/simple_method.rb") (blob, tree) <- parseTestFile rubyParser (Path.relFile "test/fixtures/ruby/tags/simple_method.rb")
runTagging blob symbolsToSummarize tree `shouldBe` runTagging (blobLanguage blob) (blobSource blob) symbolsToSummarize tree `shouldBe`
[ Tag "foo" Method (Span (Pos 1 1) (Pos 4 4)) "def foo" Nothing ] [ Tag "foo" Method (Span (Pos 1 1) (Pos 4 4)) "def foo" Nothing ]
it "produces tags for sends" $ do it "produces tags for sends" $ do
(blob, tree) <- parseTestFile rubyParser (Path.relFile "test/fixtures/ruby/tags/simple_method.rb") (blob, tree) <- parseTestFile rubyParser (Path.relFile "test/fixtures/ruby/tags/simple_method.rb")
runTagging blob ["Send"] tree `shouldBe` runTagging (blobLanguage blob) (blobSource blob) ["Send"] tree `shouldBe`
[ Tag "puts" Call (Span (Pos 2 3) (Pos 2 12)) "puts \"hi\"" Nothing [ Tag "puts" Call (Span (Pos 2 3) (Pos 2 12)) "puts \"hi\"" Nothing
, Tag "bar" Call (Span (Pos 3 3) (Pos 3 8)) "a.bar" Nothing , Tag "bar" Call (Span (Pos 3 3) (Pos 3 8)) "a.bar" Nothing
, Tag "a" Call (Span (Pos 3 3) (Pos 3 4)) "a" Nothing , Tag "a" Call (Span (Pos 3 3) (Pos 3 4)) "a" Nothing
@ -82,17 +82,17 @@ spec = do
it "produces tags for methods with docs" $ do it "produces tags for methods with docs" $ do
(blob, tree) <- parseTestFile rubyParser (Path.relFile "test/fixtures/ruby/tags/simple_method_with_docs.rb") (blob, tree) <- parseTestFile rubyParser (Path.relFile "test/fixtures/ruby/tags/simple_method_with_docs.rb")
runTagging blob symbolsToSummarize tree `shouldBe` runTagging (blobLanguage blob) (blobSource blob) symbolsToSummarize tree `shouldBe`
[ Tag "foo" Method (Span (Pos 2 1) (Pos 3 4)) "def foo" (Just "# Public: foo") ] [ Tag "foo" Method (Span (Pos 2 1) (Pos 3 4)) "def foo" (Just "# Public: foo") ]
it "correctly tags files containing multibyte UTF-8 characters" $ do it "correctly tags files containing multibyte UTF-8 characters" $ do
(blob, tree) <- parseTestFile rubyParser (Path.relFile "test/fixtures/ruby/tags/unicode_identifiers.rb") (blob, tree) <- parseTestFile rubyParser (Path.relFile "test/fixtures/ruby/tags/unicode_identifiers.rb")
runTagging blob symbolsToSummarize tree `shouldBe` runTagging (blobLanguage blob) (blobSource blob) symbolsToSummarize tree `shouldBe`
[ Tag "日本語" Method (Span (Pos 2 1) (Pos 4 4)) "def 日本語" (Just "# coding: utf-8")] [ Tag "日本語" Method (Span (Pos 2 1) (Pos 4 4)) "def 日本語" (Just "# coding: utf-8")]
it "produces tags for methods and classes with docs" $ do it "produces tags for methods and classes with docs" $ do
(blob, tree) <- parseTestFile rubyParser (Path.relFile "test/fixtures/ruby/tags/class_module.rb") (blob, tree) <- parseTestFile rubyParser (Path.relFile "test/fixtures/ruby/tags/class_module.rb")
runTagging blob symbolsToSummarize tree `shouldBe` runTagging (blobLanguage blob) (blobSource blob) symbolsToSummarize tree `shouldBe`
[ Tag "Foo" Tags.Module (Span (Pos 2 1 ) (Pos 12 4)) "module Foo" (Just "# Public: Foo") [ Tag "Foo" Tags.Module (Span (Pos 2 1 ) (Pos 12 4)) "module Foo" (Just "# Public: Foo")
, Tag "Bar" Class (Span (Pos 5 3 ) (Pos 11 6)) "class Bar" (Just "# Public: Bar") , Tag "Bar" Class (Span (Pos 5 3 ) (Pos 11 6)) "class Bar" (Just "# Public: Bar")
, Tag "baz" Method (Span (Pos 8 5 ) (Pos 10 8)) "def baz(a)" (Just "# Public: baz") , Tag "baz" Method (Span (Pos 8 5 ) (Pos 10 8)) "def baz(a)" (Just "# Public: baz")