1
1
mirror of https://github.com/github/semantic.git synced 2024-12-26 16:33:03 +03:00
semantic/src/Renderer/TOC.hs

172 lines
8.1 KiB
Haskell
Raw Normal View History

2017-01-23 20:16:59 +03:00
{-# LANGUAGE ScopedTypeVariables #-}
2017-01-26 20:45:36 +03:00
module Renderer.TOC (toc) where
2017-01-23 19:22:51 +03:00
2017-01-23 22:12:05 +03:00
import Category as C
import Data.Aeson
import Data.Functor.Both hiding (fst, snd)
2017-01-24 00:59:47 +03:00
import qualified Data.Functor.Both as Both
2017-01-23 19:22:51 +03:00
import Data.Record
2017-01-23 22:12:05 +03:00
import Diff
2017-01-23 19:22:51 +03:00
import Info
2017-01-23 22:12:05 +03:00
import Prologue
import Range
2017-01-23 22:12:05 +03:00
import qualified Data.List as List
import qualified Data.Map as Map hiding (null)
import Renderer
import Source hiding (null)
2017-01-23 22:12:05 +03:00
import Syntax as S
import Term
import Patch
2017-01-24 20:13:59 +03:00
import Unsafe (unsafeHead)
2017-01-23 20:16:59 +03:00
data JSONSummary = JSONSummary { info :: Summarizable }
| ErrorSummary { error :: Text, errorSpan :: SourceSpan }
2017-01-23 22:12:05 +03:00
deriving (Generic, Eq, Show)
instance ToJSON JSONSummary where
toJSON JSONSummary{..} = object $ case info of
2017-01-25 01:20:22 +03:00
InSummarizable{..} -> [ "changeType" .= ("modified" :: Text), "category" .= (show parentCategory :: Text), "term" .= parentTermName, "span" .= parentSourceSpan ]
Summarizable{..} -> [ "changeType" .= summarizableChangeType, "category" .= (show summarizableCategory :: Text), "term" .= summarizableTermName, "span" .= summarizableSourceSpan ]
NotSummarizable -> panic "NotSummarizable should have been pruned"
toJSON ErrorSummary{..} = object [ "error" .= error, "span" .= errorSpan ]
2017-01-23 22:12:05 +03:00
isErrorSummary :: JSONSummary -> Bool
2017-01-23 22:12:05 +03:00
isErrorSummary ErrorSummary{} = True
isErrorSummary _ = False
2017-01-23 20:16:59 +03:00
data DiffInfo = LeafInfo { leafCategory :: Category, termName :: Text, leafSourceSpan :: SourceSpan }
2017-01-23 20:16:59 +03:00
| BranchInfo { branches :: [ DiffInfo ], branchCategory :: Category }
| ErrorInfo { infoSpan :: SourceSpan, termName :: Text }
2017-01-23 20:16:59 +03:00
deriving (Eq, Show)
data TOCSummary a = TOCSummary {
2017-01-25 21:45:56 +03:00
summaryPatch :: Patch a,
parentInfo :: Summarizable
} deriving (Eq, Functor, Show, Generic)
2017-01-23 20:16:59 +03:00
data Summarizable = Summarizable { summarizableCategory :: Category, summarizableTermName :: Text, summarizableSourceSpan :: SourceSpan, summarizableChangeType :: Text }
| InSummarizable { parentCategory :: Category, parentTermName :: Text, parentSourceSpan :: SourceSpan }
| NotSummarizable
deriving (Eq, Show)
data SummarizableTerm a = SummarizableTerm a | NotSummarizableTerm a
2017-01-23 22:12:05 +03:00
toc :: (DefaultFields fields) => Renderer (Record fields)
toc blobs diff = TOCOutput $ Map.fromList [
("changes", changes),
("errors", errors)
]
where
changes = if null changes' then mempty else Map.singleton summaryKey (toJSON <$> changes')
errors = if null errors' then mempty else Map.singleton summaryKey (toJSON <$> errors')
(errors', changes') = List.partition isErrorSummary summaries
summaryKey = toSummaryKey (path <$> blobs)
summaries = diffTOC blobs diff
2017-01-23 20:16:59 +03:00
diffTOC :: (StringConv leaf Text, DefaultFields fields) => Both SourceBlob -> SyntaxDiff leaf fields -> [JSONSummary]
2017-01-26 23:07:18 +03:00
diffTOC blobs diff = do
noDupes <- removeDupes (diffToTOCSummaries (source <$> blobs) diff)
toJSONSummaries noDupes
2017-01-23 22:12:05 +03:00
where
2017-01-24 20:13:59 +03:00
removeDupes :: [TOCSummary DiffInfo] -> [TOCSummary DiffInfo]
removeDupes [] = []
2017-01-24 20:13:59 +03:00
removeDupes xs = (fmap unsafeHead . List.groupBy (\a b -> parentInfo a == parentInfo b)) xs
diffToTOCSummaries :: (StringConv leaf Text, DefaultFields fields) => Both Source -> SyntaxDiff leaf fields -> [TOCSummary DiffInfo]
2017-01-23 22:12:05 +03:00
diffToTOCSummaries sources = para $ \diff ->
let
2017-01-24 00:59:47 +03:00
diff' = free (Prologue.fst <$> diff)
patch' = mapPatch (termToDiffInfo beforeSource) (termToDiffInfo afterSource)
2017-01-23 22:12:05 +03:00
(beforeSource, afterSource) = runJoin sources
in case diff of
(Free (_ :< syntax)) -> mapToInSummarizable sources diff' (toList syntax >>= snd)
(Pure patch) -> toTOCSummaries (patch' patch)
-- Mark which leaves are summarizable.
toTOCSummaries :: Patch DiffInfo -> [TOCSummary DiffInfo]
2017-01-24 23:58:17 +03:00
toTOCSummaries patch = case afterOrBefore patch of
2017-01-26 23:07:18 +03:00
Just diffInfo -> toTOCSummaries' patch diffInfo
2017-01-24 23:58:17 +03:00
Nothing -> panic "No diff"
where
2017-01-26 23:07:18 +03:00
toTOCSummaries' patch' diffInfo = case diffInfo of
ErrorInfo{..} -> pure $ TOCSummary patch' NotSummarizable
BranchInfo{..} -> join $ zipWith toTOCSummaries' (flattenPatch patch') branches
LeafInfo{..} -> pure . TOCSummary patch' $ case leafCategory of
C.Function -> Summarizable leafCategory termName leafSourceSpan (patchType patch')
C.Method -> Summarizable leafCategory termName leafSourceSpan (patchType patch')
_ -> NotSummarizable
2017-01-26 23:07:18 +03:00
flattenPatch :: Patch DiffInfo -> [Patch DiffInfo]
flattenPatch = \case
Replace i1 i2 -> zipWith Replace (toLeafInfos' i1) (toLeafInfos' i2)
Insert info -> Insert <$> toLeafInfos' info
Delete info -> Delete <$> toLeafInfos' info
toLeafInfos' :: DiffInfo -> [DiffInfo]
toLeafInfos' BranchInfo{..} = branches >>= toLeafInfos'
toLeafInfos' leaf = [leaf]
mapToInSummarizable :: forall leaf fields. DefaultFields fields => Both Source -> SyntaxDiff leaf fields -> [TOCSummary DiffInfo] -> [TOCSummary DiffInfo]
mapToInSummarizable sources diff children = case (beforeTerm diff, afterTerm diff) of
(_, Just diff') -> mapToInSummarizable' (Both.snd sources) diff' <$> children
(Just diff', _) -> mapToInSummarizable' (Both.fst sources) diff' <$> children
(Nothing, Nothing) -> []
where
mapToInSummarizable' :: Source -> SyntaxTerm leaf fields -> TOCSummary DiffInfo -> TOCSummary DiffInfo
mapToInSummarizable' source term summary =
case (parentInfo summary, summarizable term) of
(NotSummarizable, SummarizableTerm _) ->
2017-02-10 00:33:33 +03:00
summary { parentInfo = InSummarizable (category (extract term)) (toTermName' term) (Info.sourceSpan (extract term)) }
(_, _) -> summary
2017-02-10 00:33:33 +03:00
where
toTermName' :: SyntaxTerm leaf fields -> Text
toTermName' subterm = toTermName (Source.slice (range subterm) source) subterm
range = characterRange . extract
summarizable :: ComonadCofree (Syntax t) w => w a -> SummarizableTerm (w a)
summarizable term = go (unwrap term) term
where go = \case
S.Method{} -> SummarizableTerm
S.Function{} -> SummarizableTerm
_ -> NotSummarizableTerm
toJSONSummaries :: TOCSummary DiffInfo -> [JSONSummary]
2017-01-25 21:45:56 +03:00
toJSONSummaries TOCSummary{..} = case afterOrBefore summaryPatch of
2017-01-24 23:58:17 +03:00
Just diffInfo -> toJSONSummaries' diffInfo
Nothing -> panic "No diff"
where
toJSONSummaries' = \case
ErrorInfo{..} -> pure $ ErrorSummary termName infoSpan
BranchInfo{..} -> branches >>= toJSONSummaries'
LeafInfo{..} -> case parentInfo of
NotSummarizable -> []
_ -> pure $ JSONSummary parentInfo
2017-01-23 22:12:05 +03:00
termToDiffInfo :: forall leaf fields. (StringConv leaf Text, DefaultFields fields) => Source -> SyntaxTerm leaf fields -> DiffInfo
2017-02-10 22:18:55 +03:00
termToDiffInfo source term = case unwrap term of
2017-01-23 22:12:05 +03:00
S.Indexed children -> BranchInfo (termToDiffInfo' <$> children) (category $ extract term)
S.Fixed children -> BranchInfo (termToDiffInfo' <$> children) (category $ extract term)
S.AnonymousFunction _ _ -> LeafInfo C.AnonymousFunction (toTermName' term) (getField $ extract term)
S.Commented cs leaf -> BranchInfo (termToDiffInfo' <$> cs <> maybeToList leaf) (category $ extract term)
2017-01-26 20:48:03 +03:00
S.ParseError _ -> ErrorInfo (getField $ extract term) (toTermName' term)
2017-01-23 22:12:05 +03:00
_ -> toLeafInfo term
2017-02-10 00:33:33 +03:00
where
toTermName' :: SyntaxTerm leaf fields -> Text
toTermName' subterm = toTermName (Source.slice (subtermRange subterm) source) subterm
2017-02-10 00:33:33 +03:00
range = characterRange . extract
subtermRange subterm = offsetRange (range subterm) (negate (start (range term)))
termToDiffInfo' subterm = termToDiffInfo (Source.slice (subtermRange subterm) source) subterm
2017-02-10 00:33:33 +03:00
toLeafInfo term = LeafInfo (category $ extract term) (toTermName' term) (getField $ extract term)
2017-01-23 19:22:51 +03:00
toTermName :: forall leaf fields. DefaultFields fields => Source -> SyntaxTerm leaf fields -> Text
toTermName source term = case unwrap term of
2017-01-26 02:26:03 +03:00
S.Function identifier _ _ _ -> toTermName' identifier
2017-02-08 01:53:15 +03:00
S.Method identifier Nothing _ _ _ -> toTermName' identifier
S.Method identifier (Just receiver) _ _ _ -> toTermName' receiver <> "." <> toTermName' identifier
2017-02-10 00:33:33 +03:00
_ -> toText source
2017-01-23 22:12:05 +03:00
where
2017-02-10 00:33:33 +03:00
toTermName' :: SyntaxTerm leaf fields -> Text
toTermName' subterm = toTermName (Source.slice (range' subterm) source) subterm
range' subterm = offsetRange (range subterm) (negate (start (range term)))
2017-01-23 22:12:05 +03:00
range = characterRange . extract