2017-04-20 02:33:27 +03:00
|
|
|
{-# LANGUAGE GADTs #-}
|
2017-04-21 23:56:19 +03:00
|
|
|
module Semantic
|
|
|
|
( diffBlobs
|
|
|
|
, diffBlobs'
|
|
|
|
, parseBlobs
|
2017-04-22 00:10:50 +03:00
|
|
|
, parseBlob
|
2017-04-21 23:56:19 +03:00
|
|
|
) where
|
2017-04-20 02:33:27 +03:00
|
|
|
|
2017-04-21 01:13:28 +03:00
|
|
|
import Control.Parallel.Strategies
|
2017-04-20 02:33:27 +03:00
|
|
|
import Data.Functor.Both
|
|
|
|
import Data.RandomWalkSimilarity
|
|
|
|
import Data.Record
|
|
|
|
import Diff
|
|
|
|
import Info
|
|
|
|
import Interpreter
|
|
|
|
import Parser.Language
|
|
|
|
import Prologue
|
|
|
|
import Renderer
|
|
|
|
import Source
|
|
|
|
import Syntax
|
2017-04-21 20:25:47 +03:00
|
|
|
import Patch
|
2017-04-20 02:33:27 +03:00
|
|
|
import Term
|
|
|
|
|
|
|
|
|
2017-04-21 23:56:19 +03:00
|
|
|
-- This is the primary interface to the Semantic library which provides two
|
|
|
|
-- major classes of functionality: semantic parsing and diffing of source code
|
|
|
|
-- blobs.
|
|
|
|
--
|
2017-04-20 02:33:27 +03:00
|
|
|
-- Goals:
|
|
|
|
-- - No knowledge of filesystem or Git
|
|
|
|
-- - Built in concurrency where appropriate
|
2017-04-21 23:56:19 +03:00
|
|
|
-- - Easy to consume this interface from other application (e.g a cmdline or web server app).
|
2017-04-20 02:33:27 +03:00
|
|
|
|
2017-04-21 23:56:19 +03:00
|
|
|
-- | Diff a list of SourceBlob pairs and produce a ByteString using the specified renderer.
|
2017-04-20 02:33:27 +03:00
|
|
|
diffBlobs :: (Monoid output, StringConv output ByteString) => DiffRenderer DefaultFields output -> [Both SourceBlob] -> IO ByteString
|
|
|
|
diffBlobs renderer blobs = do
|
|
|
|
diffs <- traverse go blobs
|
2017-04-21 20:25:47 +03:00
|
|
|
let diffs' = diffs >>= \ (blobs, diff) -> (,) blobs <$> toList diff
|
|
|
|
pure . toS $ runDiffRenderer renderer (diffs' `using` parTraversable (parTuple2 r0 rdeepseq))
|
2017-04-20 02:33:27 +03:00
|
|
|
where
|
|
|
|
go blobPair = do
|
|
|
|
diff <- diffBlobs' blobPair
|
|
|
|
pure (blobPair, diff)
|
|
|
|
|
2017-04-21 23:56:19 +03:00
|
|
|
-- | Diff a pair of SourceBlobs.
|
2017-04-21 20:25:47 +03:00
|
|
|
diffBlobs' :: Both SourceBlob -> IO (Maybe (Diff (Syntax Text) (Record DefaultFields)))
|
2017-04-20 02:33:27 +03:00
|
|
|
diffBlobs' blobs = do
|
2017-04-21 23:56:19 +03:00
|
|
|
terms <- traverse parseBlob blobs
|
2017-04-21 20:25:47 +03:00
|
|
|
case (runJoin blobs, runJoin terms) of
|
|
|
|
((left, right), (a, b)) | nonExistentBlob left && nonExistentBlob right -> pure Nothing
|
|
|
|
| nonExistentBlob right -> pure . pure . pure $ Delete a
|
|
|
|
| nonExistentBlob left -> pure . pure . pure $ Insert b
|
|
|
|
| otherwise -> pure . pure $ runDiff terms
|
2017-04-20 02:33:27 +03:00
|
|
|
where
|
2017-04-21 20:25:47 +03:00
|
|
|
runDiff terms = stripDiff (runBothWith diffTerms (fmap decorate (terms `using` parTraversable rdeepseq)))
|
2017-04-20 02:33:27 +03:00
|
|
|
decorate = defaultFeatureVectorDecorator getLabel
|
|
|
|
getLabel :: HasField fields Category => TermF (Syntax Text) (Record fields) a -> (Category, Maybe Text)
|
|
|
|
getLabel (h :< t) = (Info.category h, case t of
|
|
|
|
Leaf s -> Just s
|
|
|
|
_ -> Nothing)
|
|
|
|
|
2017-04-21 23:56:19 +03:00
|
|
|
-- | Parse a list of SourceBlobs and use the specified renderer to produce ByteString output.
|
2017-04-20 04:27:36 +03:00
|
|
|
parseBlobs :: (Monoid output, StringConv output ByteString) => ParseTreeRenderer DefaultFields output -> [SourceBlob] -> IO ByteString
|
|
|
|
parseBlobs renderer blobs = do
|
2017-04-20 21:00:02 +03:00
|
|
|
terms <- traverse go blobs
|
2017-04-21 01:13:28 +03:00
|
|
|
pure . toS $ runParseTreeRenderer renderer (terms `using` parTraversable (parTuple2 r0 rdeepseq))
|
2017-04-20 21:00:02 +03:00
|
|
|
where
|
|
|
|
go blob = do
|
2017-04-21 23:56:19 +03:00
|
|
|
term <- parseBlob blob
|
2017-04-21 01:13:28 +03:00
|
|
|
pure (blob, term)
|
2017-04-20 02:33:27 +03:00
|
|
|
|
|
|
|
-- | Parse a SourceBlob.
|
2017-04-21 23:56:19 +03:00
|
|
|
parseBlob :: SourceBlob -> IO (Term (Syntax Text) (Record DefaultFields))
|
|
|
|
parseBlob blob@SourceBlob{..} = parserForFilePath path blob
|