1
1
mirror of https://github.com/github/semantic.git synced 2024-11-24 17:04:47 +03:00

Merge branch 'master' of https://github.com/github/semantic-diff into integrate-abstract-interpretation

This commit is contained in:
Timothy Clem 2017-11-28 15:49:46 -08:00
commit 026cc46dbc
63 changed files with 1539 additions and 2145 deletions

View File

@ -14,7 +14,6 @@ cabal-version: >=1.10
library
hs-source-dirs: src
exposed-modules: Algorithm
, Alignment
, Abstract.Configuration
, Abstract.Environment
, Abstract.Eval
@ -70,7 +69,6 @@ library
, Language.JSON.Assignment
, Language.Ruby.Grammar
, Language.Ruby.Assignment
, Language.TypeScript
, Language.TypeScript.Assignment
, Language.TypeScript.Grammar
, Language.TypeScript.Syntax
@ -82,8 +80,8 @@ library
, Paths_semantic_diff
, Renderer
, Renderer.JSON
, Renderer.Patch
, Renderer.SExpression
, Renderer.Tag
, Renderer.TOC
, RWS
, RWS.FeatureVector
@ -114,6 +112,7 @@ library
, freer-cofreer
, ghc-prim
, gitrev
, Glob
, hashable
, kdt
, mersenne-random-pure64
@ -159,8 +158,7 @@ test-suite test
type: exitcode-stdio-1.0
hs-source-dirs: test
main-is: Spec.hs
other-modules: AlignmentSpec
, CommandSpec
other-modules: CommandSpec
, Data.Functor.Classes.Ord.Generic.Spec
, Data.Functor.Listable
, Data.Mergeable.Spec
@ -171,7 +169,6 @@ test-suite test
, SemanticCmdLineSpec
, Semantic.StatSpec
, InterpreterSpec
, PatchOutputSpec
, SES.Spec
, SourceSpec
, SpecHelpers

View File

@ -1,160 +0,0 @@
{-# LANGUAGE RankNTypes, ScopedTypeVariables #-}
module Alignment
( hasChanges
, numberedRows
, alignDiff
, alignBranch
, applyThese
, modifyJoin
) where
import Data.Bifunctor (bimap, first, second)
import Control.Arrow ((***))
import Control.Monad (join)
import Control.Monad.Free (wrap)
import Data.Align
import Data.Bifunctor.Join
import Data.Diff
import Data.Foldable (toList)
import Data.Function (on)
import Data.Functor.Both
import Data.Functor.Foldable (cata)
import Data.Functor.Identity
import Data.List (partition, sortBy)
import Data.Maybe (catMaybes, fromJust, listToMaybe)
import Data.Patch
import Data.Range
import Data.Record
import Data.Semigroup ((<>))
import Data.Source
import Data.SplitDiff
import Data.Term
import Data.These
import Info (byteRange, setByteRange)
import Prelude hiding (fst, snd)
-- | Assign line numbers to the lines on each side of a list of rows.
numberedRows :: [Join These a] -> [Join These (Int, a)]
numberedRows = countUp (both 1 1)
where countUp _ [] = []
countUp from (row : rows) = numberedLine from row : countUp (nextLineNumbers from row) rows
numberedLine from row = fromJust ((,) <$> modifyJoin (uncurry These) from `applyThese` row)
nextLineNumbers from row = modifyJoin (fromThese id id) (succ <$ row) <*> from
-- | Determine whether a line contains any patches.
hasChanges :: (Foldable f, Functor f) => SplitDiff f annotation -> Bool
hasChanges = or . (True <$)
-- | Align a Diff into a list of Join These SplitDiffs representing the (possibly blank) lines on either side.
alignDiff :: (HasField fields Range, Traversable f) => Both Source -> Diff f (Record fields) (Record fields) -> [Join These (SplitDiff [] (Record fields))]
alignDiff sources = cata $ \ diff -> case diff of
Patch patch -> alignPatch sources patch
Merge (In (ann1, ann2) syntax) -> alignSyntax (runBothWith ((Join .) . These)) wrap getRange sources (In (both ann1 ann2) syntax)
-- | Align the contents of a patch into a list of lines on the corresponding side(s) of the diff.
alignPatch :: forall fields f. (Traversable f, HasField fields Range) => Both Source -> Patch (TermF f (Record fields) [Join These (SplitDiff [] (Record fields))]) (TermF f (Record fields) [Join These (SplitDiff [] (Record fields))]) -> [Join These (SplitDiff [] (Record fields))]
alignPatch sources patch = case patch of
Delete term -> fmap (pure . SplitDelete) <$> alignSyntax' this (fst sources) term
Insert term -> fmap (pure . SplitInsert) <$> alignSyntax' that (snd sources) term
Replace term1 term2 -> fmap (pure . SplitReplace) <$> alignWith (fmap (these id id const . runJoin) . Join)
(alignSyntax' this (fst sources) term1)
(alignSyntax' that (snd sources) term2)
where getRange = byteRange . extract
alignSyntax' :: (forall a. Identity a -> Join These a) -> Source -> TermF f (Record fields) [Join These (SplitDiff [] (Record fields))] -> [Join These (Term [] (Record fields))]
alignSyntax' side source = alignSyntax side Term getRange (Identity source) . bimap Identity (fmap (fmap unSplit))
this = Join . This . runIdentity
that = Join . That . runIdentity
-- | The Applicative instance f is either Identity or Both. Identity is for Terms in Patches, Both is for Diffs in unchanged portions of the diff.
alignSyntax :: (Applicative f, HasField fields Range, Foldable g) => (forall a. f a -> Join These a) -> (TermF [] (Record fields) term -> term) -> (term -> Range) -> f Source -> TermF g (f (Record fields)) [Join These term] -> [Join These term]
alignSyntax toJoinThese toNode getRange sources (In infos syntax) =
catMaybes $ wrapInBranch <$> alignBranch getRange (join (toList syntax)) bothRanges
where bothRanges = modifyJoin (fromThese [] []) lineRanges
lineRanges = toJoinThese $ sourceLineRangesWithin . byteRange <$> infos <*> sources
wrapInBranch = applyThese $ toJoinThese (makeNode <$> infos)
makeNode info (range, children) = toNode (In (setByteRange info range) children)
-- | Given a function to get the range, a list of already-aligned children, and the lists of ranges spanned by a branch, return the aligned lines.
alignBranch :: (term -> Range) -> [Join These term] -> Both [Range] -> [Join These (Range, [term])]
-- There are no more ranges, so were done.
alignBranch _ _ (Join ([], [])) = []
-- There are no more children, so we can just zip the remaining ranges together.
alignBranch _ [] ranges = runBothWith (alignWith Join) (fmap (flip (,) []) <$> ranges)
-- There are both children and ranges, so we need to proceed line by line
alignBranch getRange children ranges = case intersectingChildren of
-- No child intersects the current ranges on either side, so advance.
[] -> (flip (,) [] <$> headRanges) : alignBranch getRange children (drop 1 <$> ranges)
-- At least one child intersects on at least one side.
_ -> case intersectionsWithHeadRanges <$> listToMaybe symmetricalChildren of
-- At least one child intersects on both sides, so align symmetrically.
Just (True, True) -> let (line, remaining) = lineAndRemaining intersectingChildren (Just headRanges) in
line $ alignBranch getRange (remaining <> nonIntersectingChildren) (drop 1 <$> ranges)
-- A symmetrical child intersects on the right, so align asymmetrically on the left.
Just (False, True) -> alignAsymmetrically leftRange first
-- A symmetrical child intersects on the left, so align asymmetrically on the right.
Just (True, False) -> alignAsymmetrically rightRange second
-- No symmetrical child intersects, so align asymmetrically, picking the left side first to match the deletion/insertion order convention in diffs.
_ -> if any (isThis . runJoin) asymmetricalChildren
then alignAsymmetrically leftRange first
else alignAsymmetrically rightRange second
where (intersectingChildren, nonIntersectingChildren) = partition (or . intersects getRange headRanges) children
(symmetricalChildren, asymmetricalChildren) = partition (isThese . runJoin) intersectingChildren
intersectionsWithHeadRanges = fromThese True True . runJoin . intersects getRange headRanges
Just headRanges = Join <$> bisequenceL (runJoin (listToMaybe <$> Join (runBothWith These ranges)))
(leftRange, rightRange) = splitThese headRanges
alignAsymmetrically range advanceBy = let (line, remaining) = lineAndRemaining asymmetricalChildren range in
line $ alignBranch getRange (remaining <> symmetricalChildren <> nonIntersectingChildren) (modifyJoin (advanceBy (drop 1)) ranges)
lineAndRemaining _ Nothing = (id, [])
lineAndRemaining children (Just ranges) = let (intersections, remaining) = alignChildren getRange children ranges in
((:) $ (,) <$> ranges `applyToBoth` (sortBy (compare `on` getRange) <$> intersections), remaining)
-- | Given a list of aligned children, produce lists of their intersecting first lines, and a list of the remaining lines/nonintersecting first lines.
alignChildren :: (term -> Range) -> [Join These term] -> Join These Range -> (Both [term], [Join These term])
alignChildren _ [] _ = (both [] [], [])
alignChildren getRange (first:rest) headRanges
| ~(l, r) <- splitThese first
= case intersectionsWithHeadRanges first of
-- It intersects on both sides, so we can just take the first line whole.
(True, True) -> ((<>) <$> toTerms first <*> firstRemaining, restRemaining)
-- It only intersects on the left, so split it up.
(True, False) -> ((<>) <$> toTerms (fromJust l) <*> firstRemaining, maybe id (:) r restRemaining)
-- It only intersects on the right, so split it up.
(False, True) -> ((<>) <$> toTerms (fromJust r) <*> firstRemaining, maybe id (:) l restRemaining)
-- It doesnt intersect at all, so skip it and move along.
(False, False) -> (firstRemaining, first:restRemaining)
| otherwise = alignChildren getRange rest headRanges
where (firstRemaining, restRemaining) = alignChildren getRange rest headRanges
toTerms line = modifyJoin (fromThese [] []) (pure <$> line)
intersectionsWithHeadRanges = fromThese False False . runJoin . intersects getRange headRanges
-- | Test ranges and terms for intersection on either or both sides.
intersects :: (term -> Range) -> Join These Range -> Join These term -> Join These Bool
intersects getRange ranges line = intersectsRange <$> ranges `applyToBoth` modifyJoin (fromThese (Range (-1) (-1)) (Range (-1) (-1))) (getRange <$> line)
-- | Split a These value up into independent These values representing the left and right sides, if any.
splitThese :: Join These a -> (Maybe (Join These a), Maybe (Join These a))
splitThese these = fromThese Nothing Nothing $ bimap (Just . Join . This) (Just . Join . That) (runJoin these)
infixl 4 `applyThese`
-- | Like `<*>`, but it returns its result in `Maybe` since the result is the intersection of the shapes of the inputs.
applyThese :: Join These (a -> b) -> Join These a -> Maybe (Join These b)
applyThese (Join fg) (Join ab) = fmap Join . uncurry maybeThese $ uncurry (***) (bimap (<*>) (<*>) (unpack fg)) (unpack ab)
where unpack = fromThese Nothing Nothing . bimap Just Just
infixl 4 `applyToBoth`
-- | Like `<*>`, but it takes a `Both` on the right to ensure that it can always return a value.
applyToBoth :: Join These (a -> b) -> Both a -> Join These b
applyToBoth (Join fg) (Join (a, b)) = Join $ these (This . ($ a)) (That . ($ b)) (\ f g -> These (f a) (g b)) fg
-- Map over the bifunctor inside a Join, producing another Join.
modifyJoin :: (p a a -> q b b) -> Join p a -> Join q b
modifyJoin f = Join . f . runJoin
-- | Given a pair of Maybes, produce a These containing Just their values, or Nothing if they havent any.
maybeThese :: Maybe a -> Maybe b -> Maybe (These a b)
maybeThese (Just a) (Just b) = Just (These a b)
maybeThese (Just a) _ = Just (This a)
maybeThese _ (Just b) = Just (That b)
maybeThese _ _ = Nothing

View File

@ -5,7 +5,8 @@ import Data.ByteString (ByteString)
import Data.ByteString.Lazy (toStrict)
import Data.Map (Map)
import Data.Semigroup
import Data.Text (Text)
import Data.Text (Text, intercalate)
import Data.Text.Encoding (encodeUtf8)
class Monoid o => Output o where
toOutput :: o -> ByteString
@ -13,6 +14,9 @@ class Monoid o => Output o where
instance Output ByteString where
toOutput s = s
instance Output [Text] where
toOutput = encodeUtf8 . intercalate "\n"
instance Output (Map Text Value) where
toOutput = toStrict . (<> "\n") . encode

View File

@ -4,6 +4,7 @@ module Data.Range
, rangeLength
, offsetRange
, intersectsRange
, subtractRange
) where
import Data.Aeson
@ -27,6 +28,9 @@ offsetRange a b = Range (start a + b) (end a + b)
intersectsRange :: Range -> Range -> Bool
intersectsRange range1 range2 = start range1 < end range2 && start range2 < end range1
subtractRange :: Range -> Range -> Range
subtractRange range1 range2 = Range (start range1) (end range1 - rangeLength (Range (start range2) (max (end range1) (end range2))))
-- Instances

View File

@ -23,6 +23,7 @@ module Data.Source
, spanToRangeInLineRanges
, sourceLineRangesByLineNumber
, rangeToSpan
, newlineIndices
) where
import Control.Arrow ((&&&))
@ -103,7 +104,29 @@ sourceLineRanges source = sourceLineRangesWithin (totalRange source) source
-- | Compute the 'Range's of each line in a 'Range' of a 'Source'.
sourceLineRangesWithin :: Range -> Source -> [Range]
sourceLineRangesWithin range = uncurry (zipWith Range) . ((start range:) &&& (<> [ end range ])) . fmap (+ succ (start range)) . B.elemIndices (toEnum (ord '\n')) . sourceBytes . slice range
sourceLineRangesWithin range = uncurry (zipWith Range)
. ((start range:) &&& (<> [ end range ]))
. fmap (+ succ (start range))
. newlineIndices
. sourceBytes
. slice range
-- | Return all indices of newlines ('\n', '\r', and '\r\n') in the 'ByteString'.
newlineIndices :: B.ByteString -> [Int]
newlineIndices = go 0
where go n bs | B.null bs = []
| otherwise = case (searchCR bs, searchLF bs) of
(Nothing, Nothing) -> []
(Just i, Nothing) -> recur n i bs
(Nothing, Just i) -> recur n i bs
(Just crI, Just lfI)
| succ crI == lfI -> recur n lfI bs
| otherwise -> recur n (min crI lfI) bs
recur n i bs = let j = n + i in j : go (succ j) (B.drop (succ i) bs)
searchLF = B.elemIndex (toEnum (ord '\n'))
searchCR = B.elemIndex (toEnum (ord '\r'))
{-# INLINE newlineIndices #-}
-- Conversion

View File

@ -1,4 +1,4 @@
{-# LANGUAGE DataKinds, GeneralizedNewtypeDeriving, TypeOperators, UndecidableInstances #-}
{-# LANGUAGE DataKinds, GeneralizedNewtypeDeriving, MultiParamTypeClasses, ScopedTypeVariables, TypeFamilies, TypeOperators, UndecidableInstances #-}
module Data.Syntax.Algebra
( FAlgebra
, RAlgebra
@ -108,8 +108,8 @@ constructorNameAndConstantFields :: Show1 f => TermF f a b -> ByteString
constructorNameAndConstantFields (In _ f) = pack (liftShowsPrec (const (const id)) (const id) 0 f "")
-- | Compute a 'ConstructorLabel' label for a 'Union' of syntax 'Term's.
constructorLabel :: Apply ConstructorName fs => TermF (Union fs) a b -> ConstructorLabel
constructorLabel (In _ u) = ConstructorLabel $ pack (apply (Proxy :: Proxy ConstructorName) constructorName u)
constructorLabel :: ConstructorName syntax => TermF syntax a b -> ConstructorLabel
constructorLabel (In _ s) = ConstructorLabel $ pack (constructorName s)
newtype ConstructorLabel = ConstructorLabel ByteString
@ -121,11 +121,40 @@ instance ToJSONFields ConstructorLabel where
toJSONFields (ConstructorLabel s) = [ "category" .= decodeUtf8 s ]
class ConstructorName f where
constructorName :: f a -> String
-- | A typeclass to retrieve the name of the data constructor for a value.
--
-- This typeclass employs the Advanced Overlap techniques designed by Oleg Kiselyov & Simon Peyton Jones: https://wiki.haskell.org/GHC/AdvancedOverlap; see also src/Renderer/TOC.hs for discussion of the details of the mechanism.
class ConstructorName syntax where
constructorName :: syntax a -> String
instance (Generic1 f, GConstructorName (Rep1 f)) => ConstructorName f where
constructorName = gconstructorName . from1
instance (ConstructorNameStrategy syntax ~ strategy, ConstructorNameWithStrategy strategy syntax) => ConstructorName syntax where
constructorName = constructorNameWithStrategy (Proxy :: Proxy strategy)
class CustomConstructorName syntax where
customConstructorName :: syntax a -> String
instance Apply ConstructorName fs => CustomConstructorName (Union fs) where
customConstructorName = apply (Proxy :: Proxy ConstructorName) constructorName
instance CustomConstructorName [] where
customConstructorName [] = "[]"
customConstructorName _ = ""
data Strategy = Default | Custom
type family ConstructorNameStrategy syntax where
ConstructorNameStrategy (Union _) = 'Custom
ConstructorNameStrategy [] = 'Custom
ConstructorNameStrategy syntax = 'Default
class ConstructorNameWithStrategy (strategy :: Strategy) syntax where
constructorNameWithStrategy :: proxy strategy -> syntax a -> String
instance (Generic1 syntax, GConstructorName (Rep1 syntax)) => ConstructorNameWithStrategy 'Default syntax where
constructorNameWithStrategy _ = gconstructorName . from1
instance CustomConstructorName syntax => ConstructorNameWithStrategy 'Custom syntax where
constructorNameWithStrategy _ = customConstructorName
class GConstructorName f where
@ -139,6 +168,4 @@ instance (GConstructorName f, GConstructorName g) => GConstructorName (f :+: g)
gconstructorName (R1 r) = gconstructorName r
instance Constructor c => GConstructorName (M1 C c f) where
gconstructorName x = case conName x of
":" -> ""
n -> n
gconstructorName = conName

View File

@ -87,7 +87,7 @@ instance Ord1 Variable where liftCompare = genericLiftCompare
instance Show1 Variable where liftShowsPrec = genericLiftShowsPrec
data Class a = Class { classContext :: ![a], classIdentifier :: !a, classSuperclasses :: ![a], classBody :: ![a] }
data Class a = Class { classContext :: ![a], classIdentifier :: !a, classSuperclasses :: ![a], classBody :: !a }
deriving (Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
instance Diffable Class where

View File

@ -1,8 +1,11 @@
{-# LANGUAGE OverloadedStrings, TypeSynonymInstances, DeriveAnyClass, DuplicateRecordFields, ScopedTypeVariables #-}
{-# LANGUAGE OverloadedStrings, TypeSynonymInstances, DeriveAnyClass, DuplicateRecordFields, ScopedTypeVariables, TupleSections #-}
module Files
( readFile
, isDirectory
, readBlobPairsFromHandle
, readBlobsFromHandle
, readBlobsFromPaths
, readBlobsFromDir
, languageForFilePath
) where
@ -25,6 +28,8 @@ import Prelude hiding (readFile)
import System.Exit
import System.FilePath
import System.IO (Handle)
import System.FilePath.Glob
import System.Directory (doesDirectoryExist)
import Text.Read
-- | Read a utf8-encoded file to a 'Blob'.
@ -34,6 +39,9 @@ readFile path language = do
raw <- liftIO $ (Just <$> B.readFile path) `catch` (const (pure Nothing) :: IOException -> IO (Maybe B.ByteString))
pure $ fromMaybe (Blob.emptyBlob path) (Blob.sourceBlob path language . fromBytes <$> raw)
isDirectory :: MonadIO m => FilePath -> m Bool
isDirectory path = liftIO (doesDirectoryExist path) >>= pure
-- | Return a language based on a FilePath's extension, or Nothing if extension is not found or not supported.
languageForFilePath :: FilePath -> Maybe Language
languageForFilePath = languageForType . takeExtension
@ -51,6 +59,15 @@ readBlobsFromHandle :: MonadIO m => Handle -> m [Blob.Blob]
readBlobsFromHandle = fmap toBlobs . readFromHandle
where toBlobs BlobParse{..} = fmap toBlob blobs
readBlobsFromPaths :: MonadIO m => [(FilePath, Maybe Language)] -> m [Blob.Blob]
readBlobsFromPaths = traverse (uncurry Files.readFile)
readBlobsFromDir :: MonadIO m => FilePath -> m [Blob.Blob]
readBlobsFromDir path = do
paths <- liftIO (globDir1 (compile "[^vendor]**/*[.rb|.js|.tsx|.go|.py]") path)
let paths' = catMaybes $ fmap (\p -> (p,) . Just <$> languageForFilePath p) paths
traverse (uncurry readFile) paths'
readFromHandle :: (FromJSON a, MonadIO m) => Handle -> m a
readFromHandle h = do
input <- liftIO $ BL.hGetContents h

View File

@ -8,13 +8,13 @@ module Language.Markdown.Assignment
import qualified CMarkGFM
import Data.ByteString (ByteString)
import Data.Function (on)
import Data.Functor (void)
import Data.Record
import Data.Syntax (makeTerm)
import qualified Data.Syntax as Syntax
import Data.Syntax.Assignment hiding (Assignment, Error)
import qualified Data.Syntax.Assignment as Assignment
import Data.Term as Term (Term(..), TermF(..), termIn, unwrap)
import Data.Term as Term (Term(..), TermF(..), termIn)
import qualified Data.Text as Text
import Data.Text.Encoding (encodeUtf8)
import Data.Union
@ -30,7 +30,6 @@ type Syntax =
, Markup.HTMLBlock
, Markup.OrderedList
, Markup.Paragraph
, Markup.Section
, Markup.ThematicBreak
, Markup.UnorderedList
, Markup.Table
@ -61,7 +60,16 @@ assignment = Syntax.handleError $ makeTerm <$> symbol Document <*> children (Mar
-- Block elements
blockElement :: Assignment
blockElement = paragraph <|> list <|> blockQuote <|> codeBlock <|> thematicBreak <|> htmlBlock <|> section <|> table
blockElement = choice
[ paragraph
, list
, blockQuote
, codeBlock
, thematicBreak
, htmlBlock
, heading
, table
]
paragraph :: Assignment
paragraph = makeTerm <$> symbol Paragraph <*> children (Markup.Paragraph <$> many inlineElement)
@ -74,13 +82,8 @@ list = termIn <$> symbol List <*> ((\ (CMarkGFM.LIST CMarkGFM.ListAttributes{..}
item :: Assignment
item = makeTerm <$> symbol Item <*> children (many blockElement)
section :: Assignment
section = makeTerm <$> symbol Heading <*> (heading >>= \ headingTerm -> Markup.Section (level headingTerm) headingTerm <$> while (((<) `on` level) headingTerm) blockElement)
where heading = makeTerm <$> symbol Heading <*> ((\ (CMarkGFM.HEADING level) -> Markup.Heading level) . termAnnotation . termOut <$> currentNode <*> children (many inlineElement))
level term = case term of
_ | Just section <- prj (unwrap term) -> level (Markup.sectionHeading section)
_ | Just heading <- prj (unwrap term) -> Markup.headingLevel heading
_ -> maxBound
heading :: Assignment
heading = makeTerm <$> symbol Heading <*> ((\ (CMarkGFM.HEADING level) -> Markup.Heading level) . termAnnotation . termOut <$> currentNode <*> children (many inlineElement) <*> manyTill blockElement (void (symbol Heading) <|> eof))
blockQuote :: Assignment
blockQuote = makeTerm <$> symbol BlockQuote <*> children (Markup.BlockQuote <$> many blockElement)
@ -106,7 +109,18 @@ tableCell = makeTerm <$> symbol TableCell <*> children (Markup.TableCell <$> man
-- Inline elements
inlineElement :: Assignment
inlineElement = strong <|> emphasis <|> strikethrough <|> text <|> link <|> htmlInline <|> image <|> code <|> lineBreak <|> softBreak
inlineElement = choice
[ strong
, emphasis
, strikethrough
, text
, link
, htmlInline
, image
, code
, lineBreak
, softBreak
]
strong :: Assignment
strong = makeTerm <$> symbol Strong <*> children (Markup.Strong <$> many inlineElement)

View File

@ -28,14 +28,7 @@ instance Eq1 Paragraph where liftEq = genericLiftEq
instance Ord1 Paragraph where liftCompare = genericLiftCompare
instance Show1 Paragraph where liftShowsPrec = genericLiftShowsPrec
data Section a = Section { sectionLevel :: Int, sectionHeading :: a, sectionContent :: [a] }
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
instance Eq1 Section where liftEq = genericLiftEq
instance Ord1 Section where liftCompare = genericLiftCompare
instance Show1 Section where liftShowsPrec = genericLiftShowsPrec
data Heading a = Heading { headingLevel :: Int, headingContent :: [a] }
data Heading a = Heading { headingLevel :: Int, headingContent :: [a], sectionContent :: [a] }
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
instance Eq1 Heading where liftEq = genericLiftEq

View File

@ -255,7 +255,7 @@ async' :: Assignment
async' = makeTerm <$> symbol AnonAsync <*> (Syntax.Identifier <$> source)
classDefinition :: Assignment
classDefinition = makeTerm <$> symbol ClassDefinition <*> children (Declaration.Class <$> pure [] <*> term expression <*> argumentList <*> manyTerm expression)
classDefinition = makeTerm <$> symbol ClassDefinition <*> children (Declaration.Class <$> pure [] <*> term expression <*> argumentList <*> expressions)
where argumentList = symbol ArgumentList *> children (manyTerm expression)
<|> pure []

View File

@ -202,11 +202,11 @@ endBlock :: Assignment
endBlock = makeTerm <$> symbol EndBlock <*> children (Statement.ScopeExit <$> many expression)
class' :: Assignment
class' = makeTerm <$> symbol Class <*> children (Declaration.Class <$> pure [] <*> expression <*> (superclass <|> pure []) <*> many expression)
class' = makeTerm <$> symbol Class <*> children (Declaration.Class <$> pure [] <*> expression <*> (superclass <|> pure []) <*> expressions)
where superclass = pure <$ symbol Superclass <*> children expression
singletonClass :: Assignment
singletonClass = makeTerm <$> symbol SingletonClass <*> children (Declaration.Class <$> pure [] <*> expression <*> pure [] <*> many expression)
singletonClass = makeTerm <$> symbol SingletonClass <*> children (Declaration.Class <$> pure [] <*> expression <*> pure [] <*> expressions)
module' :: Assignment
module' = makeTerm <$> symbol Module <*> children (Declaration.Module <$> expression <*> many expression)

View File

@ -1,183 +0,0 @@
{-# LANGUAGE DataKinds #-}
module Language.TypeScript where
import Control.Comonad (extract)
import Control.Comonad.Cofree (unwrap)
import Data.Foldable (toList)
import Data.Record
import Data.Source
import Data.Term
import Data.Text (Text)
import Info
import Language
import qualified Syntax as S
termAssignment
:: Source -- ^ The source of the term.
-> Category -- ^ The category for the term.
-> [ Term S.Syntax (Record DefaultFields) ] -- ^ The child nodes of the term.
-> Maybe (S.Syntax (Term S.Syntax (Record DefaultFields))) -- ^ The resulting term, in Maybe.
termAssignment _ category children =
case (category, children) of
(Assignment, [ identifier, value ]) -> Just $ S.Assignment identifier value
(MathAssignment, [ identifier, value ]) -> Just $ S.OperatorAssignment identifier value
(MemberAccess, [ base, property ]) -> Just $ S.MemberAccess base property
(SubscriptAccess, [ base, element ]) -> Just $ S.SubscriptAccess base element
(CommaOperator, [ a, b ])
| S.Indexed rest <- unwrap b
-> Just $ S.Indexed $ a : rest
(FunctionCall, id : rest) -> case break ((== Args) . Info.category . extract) rest of
(typeArgs, [ args ]) -> let flatArgs = toList (unwrap args) in
Just $ case unwrap id of
S.MemberAccess target method -> S.MethodCall target method typeArgs flatArgs
_ -> S.FunctionCall id typeArgs flatArgs
_ -> Nothing
(Ternary, condition : cases) -> Just $ S.Ternary condition cases
(Other "variable_declaration", _) -> Just . S.Indexed $ toVarDeclOrAssignment <$> children
(Other "trailing_variable_declaration", _) -> Just . S.Indexed $ toVarDeclOrAssignment <$> children
(Other "lexical_declaration", _) -> Just . S.Indexed $ toVarDeclOrAssignment <$> children
(VarAssignment, [id, assignment]) -> Just $ S.VarAssignment [id] assignment
(FieldDecl, _) -> Just $ S.FieldDecl children
(Object, _) -> Just . S.Object Nothing $ foldMap toTuple children
(DoWhile, [ expr, body ]) -> Just $ S.DoWhile expr body
(Constructor, [ expr ]) -> Just $ S.Constructor expr
(Try, [ body ]) -> Just $ S.Try [body] [] Nothing Nothing
(Try, [ body, catch ])
| Catch <- Info.category (extract catch)
-> Just $ S.Try [body] [catch] Nothing Nothing
(Try, [ body, finally ])
| Finally <- Info.category (extract finally)
-> Just $ S.Try [body] [] Nothing (Just finally)
(Try, [ body, catch, finally ])
| Catch <- Info.category (extract catch)
, Finally <- Info.category (extract finally)
-> Just $ S.Try [body] [catch] Nothing (Just finally)
(ArrayLiteral, _) -> Just $ S.Array Nothing children
(Method, children) -> case break ((== ExpressionStatements) . Info.category . extract) children of
(prev, [body]) -> case break ((== Identifier) . Info.category . extract) prev of
(prev, [id, callSignature]) -> Just $ S.Method prev id Nothing (toList (unwrap callSignature)) (toList (unwrap body))
_ -> Nothing -- No identifier found or callSignature found.
_ -> Nothing -- No body found.``
(Class, identifier : rest) -> case break ((== Other "class_body") . Info.category . extract) rest of
(clauses, [ definitions ]) -> Just $ S.Class identifier clauses (toList (unwrap definitions))
_ -> Nothing
(Module, [ identifier, definitions ]) -> Just $ S.Module identifier (toList (unwrap definitions))
(Namespace, [ identifier, definitions ]) -> Just $ S.Namespace identifier (toList (unwrap definitions))
(Import, [ statements, identifier ] ) -> Just $ S.Import identifier (toList (unwrap statements))
(Import, [ identifier ] ) -> Just $ S.Import identifier []
(Export, [ statements, identifier] ) -> Just $ S.Export (Just identifier) (toList (unwrap statements))
(Export, [ statements ] )
| S.Indexed _ <- unwrap statements
-> Just $ S.Export Nothing (toList (unwrap statements))
| otherwise -> Just $ S.Export (Just statements) []
(For, _:_) -> Just $ S.For (init children >>= flattenExpressionStatements) [last children]
(Function, children) -> case break ((== ExpressionStatements) . Info.category . extract) children of
(inits, [body]) -> case inits of
[id, callSignature] -> Just $ S.Function id (toList (unwrap callSignature)) (toList (unwrap body))
[callSignature] -> Just $ S.AnonymousFunction (toList (unwrap callSignature)) (toList (unwrap body))
_ -> Nothing -- More than 1 identifier found or no call signature found
_ -> Nothing -- No body found.
(Ty, children) -> Just $ S.Ty children
(Interface, children) -> toInterface children
_ -> Nothing
where flattenExpressionStatements term
| Info.category (extract term) `elem` [ExpressionStatements, CommaOperator] = toList (unwrap term) >>= flattenExpressionStatements
| otherwise = [term]
categoryForTypeScriptName :: Text -> Category
categoryForTypeScriptName category = case category of
"object" -> Object
"expression_statement" -> ExpressionStatements
"trailing_expression_statement" -> ExpressionStatements
"this_expression" -> Identifier
"null" -> Identifier
"undefined" -> Identifier
"type_identifier" -> Identifier
"property_identifier" -> Identifier
"shorthand_property_identifier" -> Identifier
"nested_identifier" -> Identifier
"arrow_function" -> Function
"generator_function" -> Function
"math_op" -> MathOperator -- math operator, e.g. +, -, *, /.
"update_expression" -> MathOperator -- math operator, e.g. ++, --
"bool_op" -> BooleanOperator -- boolean operator, e.g. ||, &&.
"comma_op" -> CommaOperator -- comma operator, e.g. expr1, expr2.
"sequence_expression" -> CommaOperator -- comma operator, e.g. expr1, expr2.
"delete_op" -> Operator -- delete operator, e.g. delete x[2].
"type_op" -> Operator -- type operator, e.g. typeof Object.
"void_op" -> Operator -- void operator, e.g. void 2.
"for_statement" -> For
"trailing_for_statement" -> For
"for_in_statement" -> For
"trailing_for_in_statement" -> For
"for_of_statement" -> For
"trailing_for_of_statement" -> For
"new_expression" -> Constructor
"class" -> Class
"catch" -> Catch
"catch_clause" -> Catch
"finally" -> Finally
"finally_clause" -> Finally
"if_statement" -> If
"trailing_if_statement" -> If
"empty_statement" -> Empty
"program" -> Program
"function_call" -> FunctionCall
"call_expression" -> FunctionCall
"pair" -> Pair
"string" -> StringLiteral
"integer" -> IntegerLiteral
"number" -> NumberLiteral
"float" -> FloatLiteral
"symbol" -> SymbolLiteral
"array" -> ArrayLiteral
"function" -> Function
"identifier" -> Identifier
"formal_parameters" -> Params
"arguments" -> Args
"statement_block" -> ExpressionStatements
"assignment" -> Assignment
"assignment_expression" -> Assignment
"member_access" -> MemberAccess
"member_expression" -> MemberAccess
"op" -> Operator
"subscript_access" -> SubscriptAccess
"subscript_expression" -> SubscriptAccess
"regex" -> Regex
"template_string" -> TemplateString
"switch_statement" -> Switch
"math_assignment" -> MathAssignment
"augmented_assignment_expression" -> MathAssignment
"case" -> Case
"switch_case" -> Case
"true" -> Boolean
"false" -> Boolean
"ternary" -> Ternary
"ternary_expression" -> Ternary
"while_statement" -> While
"trailing_while_statement" -> While
"do_statement" -> DoWhile
"trailing_do_statement" -> DoWhile
"return_statement" -> Return
"trailing_return_statement" -> Return
"throw_statement" -> Throw
"trailing_throw_statement" -> Throw
"try_statement" -> Try
"method_definition" -> Method
"comment" -> Comment
"bitwise_op" -> BitwiseOperator
"rel_op" -> RelationalOperator
"import_statement" -> Import
"export_statement" -> Export
"break_statement" -> Break
"continue_statement" -> Continue
"yield_expression" -> Yield
"public_field_definition" -> FieldDecl
"variable_declarator" -> VarAssignment
"type_annotation" -> Ty
"template_chars" -> TemplateString
"module" -> Module
"internal_module" -> Namespace
"interface_declaration" -> Interface
"parenthesized_expression" -> ParenthesizedExpression
name -> Other name

View File

@ -542,9 +542,11 @@ constructorTy = makeTerm <$> symbol ConstructorType <*> children (TypeScript.Syn
statementBlock :: Assignment
statementBlock = makeTerm <$> symbol StatementBlock <*> children (manyTerm statement)
classBodyStatements :: Assignment.Assignment [] Grammar [Term]
classBodyStatements = symbol ClassBody *> children (contextualize' <$> Assignment.manyThrough comment (postContextualize' <$> (concat <$> many ((\as b -> as ++ [b]) <$> manyTerm decorator <*> term (methodDefinition <|> publicFieldDefinition <|> methodSignature <|> indexSignature <|> abstractMethodSignature))) <*> many comment))
classBodyStatements :: Assignment
classBodyStatements = mk <$> symbol ClassBody <*> children (contextualize' <$> Assignment.manyThrough comment (postContextualize' <$> (concat <$> many ((\as b -> as ++ [b]) <$> manyTerm decorator <*> term (methodDefinition <|> publicFieldDefinition <|> methodSignature <|> indexSignature <|> abstractMethodSignature))) <*> many comment))
where
mk _ [a] = a
mk loc children = makeTerm loc children
contextualize' (cs, formalParams) = case nonEmpty cs of
Just cs -> toList cs ++ formalParams
Nothing -> formalParams

View File

@ -419,7 +419,7 @@ instance Eq1 ClassHeritage where liftEq = genericLiftEq
instance Ord1 ClassHeritage where liftCompare = genericLiftCompare
instance Show1 ClassHeritage where liftShowsPrec = genericLiftShowsPrec
data AbstractClass a = AbstractClass { _abstractClassIdentifier :: !a, _abstractClassTypeParameters :: !a, _classHeritage :: ![a], _classBody :: ![a] }
data AbstractClass a = AbstractClass { _abstractClassIdentifier :: !a, _abstractClassTypeParameters :: !a, _classHeritage :: ![a], _classBody :: !a }
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
instance Eq1 AbstractClass where liftEq = genericLiftEq

View File

@ -3,6 +3,7 @@ module Parser
( Parser(..)
, SomeParser(..)
, someParser
, ApplyAll
-- Syntax parsers
, syntaxParserForLanguage
-- À la carte parsers
@ -55,30 +56,30 @@ data Parser term where
MarkdownParser :: Parser (Term (TermF [] CMarkGFM.NodeType) (Node Markdown.Grammar))
-- | 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]) (functors :: [* -> *]) :: Constraint where
ApplyAll (typeclass ': typeclasses) functors = (Apply typeclass functors, ApplyAll typeclasses functors)
ApplyAll '[] functors = ()
type family ApplyAll (typeclasses :: [(* -> *) -> Constraint]) (syntax :: * -> *) :: Constraint where
ApplyAll (typeclass ': typeclasses) syntax = (typeclass syntax, ApplyAll typeclasses syntax)
ApplyAll '[] syntax = ()
-- | A parser for some specific language, producing 'Term's whose syntax satisfies a list of typeclass constraints.
--
-- This enables us to abstract over the details of the specific syntax types in cases where we can describe all the requirements on the syntax with a list of typeclasses.
data SomeParser typeclasses where
SomeParser :: ApplyAll typeclasses fs => { unSomeParser :: Parser (Term (Union fs) (Record Location)) } -> SomeParser typeclasses
data SomeParser typeclasses ann where
SomeParser :: ApplyAll typeclasses syntax => Parser (Term syntax ann) -> SomeParser typeclasses ann
-- | Construct a 'SomeParser' given a proxy for a list of typeclasses and the 'Language' to be parsed, all of which must be satisfied by all of the types in the syntaxes of our supported languages.
--
-- This can be used to perform operations uniformly over terms produced by blobs with different 'Language's, and which therefore have different types in general. For example, given some 'Blob', we can parse and 'show' the parsed & assigned 'Term' like so:
--
-- > case someParser (Proxy :: Proxy '[Show1]) (blobLanguage language) of { Just (SomeParser parser) -> runTask (parse parser blob) >>= putStrLn . show ; _ -> return () }
someParser :: ( ApplyAll typeclasses JSON.Syntax
, ApplyAll typeclasses Markdown.Syntax
, ApplyAll typeclasses Python.Syntax
, ApplyAll typeclasses Ruby.Syntax
, ApplyAll typeclasses TypeScript.Syntax
someParser :: ( ApplyAll typeclasses (Union JSON.Syntax)
, ApplyAll typeclasses (Union Markdown.Syntax)
, ApplyAll typeclasses (Union Python.Syntax)
, ApplyAll typeclasses (Union Ruby.Syntax)
, ApplyAll typeclasses (Union TypeScript.Syntax)
)
=> proxy typeclasses -- ^ A proxy for the list of typeclasses required, e.g. @(Proxy :: Proxy '[Show1])@.
-> Language -- ^ The 'Language' to select.
-> Maybe (SomeParser typeclasses) -- ^ 'Maybe' a 'SomeParser' abstracting the syntax type to be produced.
=> proxy typeclasses -- ^ A proxy for the list of typeclasses required, e.g. @(Proxy :: Proxy '[Show1])@.
-> Language -- ^ The 'Language' to select.
-> Maybe (SomeParser typeclasses (Record Location)) -- ^ 'Maybe' a 'SomeParser' abstracting the syntax type to be produced.
someParser _ Go = Nothing
someParser _ JavaScript = Just (SomeParser typescriptParser)
someParser _ JSON = Just (SomeParser jsonParser)

View File

@ -3,18 +3,17 @@ module Renderer
( DiffRenderer(..)
, TermRenderer(..)
, SomeRenderer(..)
, renderPatch
, renderSExpressionDiff
, renderSExpressionTerm
, renderJSONDiff
, renderJSONTerm
, renderToCDiff
, renderToCTerm
, renderToTags
, HasDeclaration
, declarationAlgebra
, syntaxDeclarationAlgebra
, Summaries(..)
, File(..)
) where
import Data.Aeson (Value)
@ -23,14 +22,12 @@ import qualified Data.Map as Map
import Data.Output
import Data.Text (Text)
import Renderer.JSON as R
import Renderer.Patch as R
import Renderer.SExpression as R
import Renderer.Tag as R
import Renderer.TOC as R
-- | Specification of renderers for diffs, producing output in the parameter type.
data DiffRenderer output where
-- | Render to git-diff-compatible textual output.
PatchDiffRenderer :: DiffRenderer File
-- | Compute a table of contents for the diff & encode it as JSON.
OldToCDiffRenderer :: DiffRenderer Summaries
-- | Compute a table of contents for the diff & encode it as JSON (uses the new Assignment parse tree parser).
@ -51,6 +48,8 @@ data TermRenderer output where
JSONTermRenderer :: TermRenderer [Value]
-- | Render to a 'ByteString' formatted as nested s-expressions.
SExpressionTermRenderer :: TermRenderer ByteString
-- | Render to a list of tags.
TagsTermRenderer :: TermRenderer [Value]
deriving instance Eq (TermRenderer output)
deriving instance Show (TermRenderer output)

View File

@ -1,185 +0,0 @@
{-# LANGUAGE MultiParamTypeClasses #-}
module Renderer.Patch
( renderPatch
, File(..)
, hunks
, Hunk(..)
, truncatePatch
) where
import Alignment
import Data.Bifunctor.Join
import Data.Blob
import Data.ByteString.Char8 (ByteString, pack)
import qualified Data.ByteString.Char8 as ByteString
import Data.Diff
import Data.Functor.Both as Both
import Data.List (span, unzip)
import Data.Maybe (fromMaybe)
import Data.Monoid (Sum(..))
import Data.Output
import Data.Range
import Data.Record
import Data.Semigroup ((<>))
import Data.Source
import Data.SplitDiff
import Data.These
import Prelude hiding (fst, snd)
-- | Render a timed out file as a truncated diff.
truncatePatch :: Both Blob -> ByteString
truncatePatch blobs = header blobs <> "#timed_out\nTruncating diff: timeout reached.\n"
-- | Render a diff in the traditional patch format.
renderPatch :: (HasField fields Range, Traversable f) => Both Blob -> Diff f (Record fields) (Record fields) -> File
renderPatch blobs diff = File $ if not (ByteString.null text) && ByteString.last text /= '\n'
then text <> "\n\\ No newline at end of file\n"
else text
where text = header blobs <> mconcat (showHunk blobs <$> hunks diff blobs)
newtype File = File { unFile :: ByteString }
deriving Show
instance Monoid File where
mempty = File mempty
mappend (File a) (File b) = File (a <> "\n" <> b)
instance Output File where
toOutput = unFile
-- | A hunk in a patch, including the offset, changes, and context.
data Hunk a = Hunk { offset :: Both (Sum Int), changes :: [Change a], trailingContext :: [Join These a] }
deriving (Eq, Show)
-- | A change in a patch hunk, along with its preceding context.
data Change a = Change { context :: [Join These a], contents :: [Join These a] }
deriving (Eq, Show)
-- | The number of lines in the hunk before and after.
hunkLength :: Hunk a -> Both (Sum Int)
hunkLength hunk = mconcat $ (changeLength <$> changes hunk) <> (rowIncrement <$> trailingContext hunk)
-- | The number of lines in change before and after.
changeLength :: Change a -> Both (Sum Int)
changeLength change = mconcat $ (rowIncrement <$> context change) <> (rowIncrement <$> contents change)
-- | The increment the given row implies for line numbering.
rowIncrement :: Join These a -> Both (Sum Int)
rowIncrement = Join . fromThese (Sum 0) (Sum 0) . runJoin . (Sum 1 <$)
-- | Given the before and after sources, render a hunk to a string.
showHunk :: Functor f => HasField fields Range => Both Blob -> Hunk (SplitDiff f (Record fields)) -> ByteString
showHunk blobs hunk = maybeOffsetHeader <>
mconcat (showChange sources <$> changes hunk) <>
showLines (snd sources) ' ' (maybeSnd . runJoin <$> trailingContext hunk)
where sources = blobSource <$> blobs
maybeOffsetHeader = if lengthA > 0 && lengthB > 0
then offsetHeader
else mempty
offsetHeader = "@@ -" <> offsetA <> "," <> pack (show lengthA) <> " +" <> offsetB <> "," <> pack (show lengthB) <> " @@" <> "\n"
(lengthA, lengthB) = runJoin . fmap getSum $ hunkLength hunk
(offsetA, offsetB) = runJoin . fmap (pack . show . getSum) $ offset hunk
-- | Given the before and after sources, render a change to a string.
showChange :: Functor f => HasField fields Range => Both Source -> Change (SplitDiff f (Record fields)) -> ByteString
showChange sources change = showLines (snd sources) ' ' (maybeSnd . runJoin <$> context change) <> deleted <> inserted
where (deleted, inserted) = runJoin $ pure showLines <*> sources <*> both '-' '+' <*> Join (unzip (fromThese Nothing Nothing . runJoin . fmap Just <$> contents change))
-- | Given a source, render a set of lines to a string with a prefix.
showLines :: Functor f => HasField fields Range => Source -> Char -> [Maybe (SplitDiff f (Record fields))] -> ByteString
showLines source prefix lines = fromMaybe "" . mconcat $ fmap prepend . showLine source <$> lines
where prepend "" = ""
prepend source = ByteString.singleton prefix <> source
-- | Given a source, render a line to a string.
showLine :: Functor f => HasField fields Range => Source -> Maybe (SplitDiff f (Record fields)) -> Maybe ByteString
showLine source line | Just line <- line = Just . sourceBytes . (`slice` source) $ getRange line
| otherwise = Nothing
-- | Returns the header given two source blobs and a hunk.
header :: Both Blob -> ByteString
header blobs = ByteString.intercalate "\n" ([filepathHeader, fileModeHeader] <> maybeFilepaths) <> "\n"
where filepathHeader = "diff --git a/" <> pathA <> " b/" <> pathB
fileModeHeader = case (modeA, modeB) of
(Nothing, Just mode) -> ByteString.intercalate "\n" [ "new file mode " <> modeToDigits mode, blobOidHeader ]
(Just mode, Nothing) -> ByteString.intercalate "\n" [ "deleted file mode " <> modeToDigits mode, blobOidHeader ]
(Just mode, Just other) | mode == other -> "index " <> oidA <> ".." <> oidB <> " " <> modeToDigits mode
(Just mode1, Just mode2) -> ByteString.intercalate "\n" [
"old mode " <> modeToDigits mode1,
"new mode " <> modeToDigits mode2,
blobOidHeader
]
(Nothing, Nothing) -> ""
blobOidHeader = "index " <> oidA <> ".." <> oidB
modeHeader :: ByteString -> Maybe BlobKind -> ByteString -> ByteString
modeHeader ty maybeMode path = case maybeMode of
Just _ -> ty <> "/" <> path
Nothing -> "/dev/null"
maybeFilepaths = if (nullOid == oidA && nullSource (snd sources)) || (nullOid == oidB && nullSource (fst sources)) then [] else [ beforeFilepath, afterFilepath ]
beforeFilepath = "--- " <> modeHeader "a" modeA pathA
afterFilepath = "+++ " <> modeHeader "b" modeB pathB
sources = blobSource <$> blobs
(pathA, pathB) = case runJoin $ pack . blobPath <$> blobs of
("", path) -> (path, path)
(path, "") -> (path, path)
paths -> paths
(oidA, oidB) = runJoin $ blobOid <$> blobs
(modeA, modeB) = runJoin $ blobKind <$> blobs
-- | A hunk representing no changes.
emptyHunk :: Hunk (SplitDiff a annotation)
emptyHunk = Hunk { offset = mempty, changes = [], trailingContext = [] }
-- | Render a diff as a series of hunks.
hunks :: (Traversable f, HasField fields Range) => Diff f (Record fields) (Record fields) -> Both Blob -> [Hunk (SplitDiff [] (Record fields))]
hunks _ blobs | sources <- blobSource <$> blobs
, sourcesEqual <- runBothWith (==) sources
, sourcesNull <- runBothWith (&&) (nullSource <$> sources)
, sourcesEqual || sourcesNull
= [emptyHunk]
hunks diff blobs = hunksInRows (pure 1) $ alignDiff (blobSource <$> blobs) diff
-- | Given beginning line numbers, turn rows in a split diff into hunks in a
-- | patch.
hunksInRows :: (Foldable f, Functor f) => Both (Sum Int) -> [Join These (SplitDiff f annotation)] -> [Hunk (SplitDiff f annotation)]
hunksInRows start rows = case nextHunk start rows of
Nothing -> []
Just (hunk, rest) -> hunk : hunksInRows (offset hunk <> hunkLength hunk) rest
-- | Given beginning line numbers, return the next hunk and the remaining rows
-- | of the split diff.
nextHunk :: (Foldable f, Functor f) => Both (Sum Int) -> [Join These (SplitDiff f annotation)] -> Maybe (Hunk (SplitDiff f annotation), [Join These (SplitDiff f annotation)])
nextHunk start rows = case nextChange start rows of
Nothing -> Nothing
Just (offset, change, rest) -> let (changes, rest') = contiguousChanges rest in Just (Hunk offset (change : changes) $ take 3 rest', drop 3 rest')
where contiguousChanges rows = case break rowHasChanges (take 7 rows) of
(_, []) -> ([], rows)
(context, _) -> case changeIncludingContext context (drop (length context) rows) of
Nothing -> ([], rows)
Just (change, rest) -> let (changes, rest') = contiguousChanges rest in (change : changes, rest')
-- | Given beginning line numbers, return the number of lines to the next
-- | the next change, and the remaining rows of the split diff.
nextChange :: (Foldable f, Functor f) => Both (Sum Int) -> [Join These (SplitDiff f annotation)] -> Maybe (Both (Sum Int), Change (SplitDiff f annotation), [Join These (SplitDiff f annotation)])
nextChange start rows = case changeIncludingContext leadingContext afterLeadingContext of
Nothing -> Nothing
Just (change, afterChanges) -> Just (start <> mconcat (rowIncrement <$> skippedContext), change, afterChanges)
where (leadingRows, afterLeadingContext) = break rowHasChanges rows
(skippedContext, leadingContext) = splitAt (max (length leadingRows - 3) 0) leadingRows
-- | Return a Change with the given context and the rows from the begginning of
-- | the given rows that have changes, or Nothing if the first row has no
-- | changes.
changeIncludingContext :: (Foldable f, Functor f) => [Join These (SplitDiff f annotation)] -> [Join These (SplitDiff f annotation)] -> Maybe (Change (SplitDiff f annotation), [Join These (SplitDiff f annotation)])
changeIncludingContext leadingContext rows = case changes of
[] -> Nothing
_ -> Just (Change leadingContext changes, afterChanges)
where (changes, afterChanges) = span rowHasChanges rows
-- | Whether a row has changes on either side.
rowHasChanges :: (Foldable f, Functor f) => Join These (SplitDiff f annotation) -> Bool
rowHasChanges row = or (hasChanges <$> row)
maybeSnd :: These a b -> Maybe b
maybeSnd = these (const Nothing) Just (\ _ a -> Just a)

View File

@ -4,17 +4,20 @@ module Renderer.TOC
, renderToCTerm
, diffTOC
, Summaries(..)
, JSONSummary(..)
, TOCSummary(..)
, isValidSummary
, Declaration(..)
, getDeclaration
, declaration
, HasDeclaration
, declarationAlgebra
, syntaxDeclarationAlgebra
, Entry(..)
, tableOfContentsBy
, termTableOfContentsBy
, dedupe
, entrySummary
, toCategoryName
) where
import Data.Aeson
@ -40,7 +43,7 @@ import Data.Record
import Data.Semigroup ((<>), sconcat)
import Data.Source as Source
import Data.Term
import Data.Text (toLower)
import Data.Text (toLower, stripEnd)
import qualified Data.Text as T
import Data.Union
import GHC.Generics
@ -67,8 +70,9 @@ instance Output Summaries where
instance ToJSON Summaries where
toJSON Summaries{..} = object [ "changes" .= changes, "errors" .= errors ]
data JSONSummary
= JSONSummary
data TOCSummary
= TOCSummary
{ summaryCategoryName :: T.Text
, summaryTermName :: T.Text
, summarySpan :: Span
@ -77,21 +81,21 @@ data JSONSummary
| ErrorSummary { error :: T.Text, errorSpan :: Span, errorLanguage :: Maybe Language }
deriving (Generic, Eq, Show)
instance ToJSON JSONSummary where
toJSON JSONSummary{..} = object [ "changeType" .= summaryChangeType, "category" .= summaryCategoryName, "term" .= summaryTermName, "span" .= summarySpan ]
instance ToJSON TOCSummary where
toJSON TOCSummary{..} = object [ "changeType" .= summaryChangeType, "category" .= summaryCategoryName, "term" .= summaryTermName, "span" .= summarySpan ]
toJSON ErrorSummary{..} = object [ "error" .= error, "span" .= errorSpan, "language" .= errorLanguage ]
isValidSummary :: JSONSummary -> Bool
isValidSummary :: TOCSummary -> Bool
isValidSummary ErrorSummary{} = False
isValidSummary _ = True
-- | A declarations identifier and type.
data Declaration
= MethodDeclaration { declarationIdentifier :: T.Text }
| ClassDeclaration { declarationIdentifier :: T.Text }
| FunctionDeclaration { declarationIdentifier :: T.Text }
| SectionDeclaration { declarationIdentifier :: T.Text, declarationLevel :: Int }
| ErrorDeclaration { declarationIdentifier :: T.Text, declarationLanguage :: Maybe Language }
= MethodDeclaration { declarationIdentifier :: T.Text, declarationText :: T.Text, declarationLanguage :: Maybe Language, declarationReceiver :: Maybe T.Text }
| ClassDeclaration { declarationIdentifier :: T.Text, declarationText :: T.Text, declarationLanguage :: Maybe Language }
| FunctionDeclaration { declarationIdentifier :: T.Text, declarationText :: T.Text, declarationLanguage :: Maybe Language }
| HeadingDeclaration { declarationIdentifier :: T.Text, declarationText :: T.Text, declarationLanguage :: Maybe Language, declarationLevel :: Int }
| ErrorDeclaration { declarationIdentifier :: T.Text, declarationText :: T.Text, declarationLanguage :: Maybe Language }
deriving (Eq, Generic, Show)
@ -131,43 +135,45 @@ class CustomHasDeclaration syntax where
customToDeclaration :: (Foldable whole, HasField fields Range, HasField fields Span) => Blob -> Record fields -> RAlgebra syntax (Term whole (Record fields)) (Maybe Declaration)
-- | Produce a 'SectionDeclaration' from the first line of the heading of a 'Markdown.Section' node.
instance CustomHasDeclaration Markdown.Section where
customToDeclaration Blob{..} _ (Markdown.Section level (Term (In headingAnn headingF), _) _)
= Just $ SectionDeclaration (maybe (getSource (byteRange headingAnn)) (getSource . sconcat) (nonEmpty (byteRange . termAnnotation . unTerm <$> toList headingF))) level
where getSource = firstLine . toText . flip Source.slice blobSource
-- | Produce a 'HeadingDeclaration' from the first line of the heading of a 'Markdown.Heading' node.
instance CustomHasDeclaration Markdown.Heading where
customToDeclaration Blob{..} ann (Markdown.Heading level terms _)
= Just $ HeadingDeclaration (headingText terms) mempty blobLanguage level
where headingText terms = getSource $ maybe (byteRange ann) sconcat (nonEmpty (headingByteRange <$> toList terms))
headingByteRange (Term (In ann _), _) = byteRange ann
getSource = firstLine . toText . flip Source.slice blobSource
firstLine = T.takeWhile (/= '\n')
-- | Produce an 'ErrorDeclaration' for 'Syntax.Error' nodes.
instance CustomHasDeclaration Syntax.Error where
customToDeclaration Blob{..} ann err@Syntax.Error{}
= Just $ ErrorDeclaration (T.pack (formatTOCError (Syntax.unError (sourceSpan ann) err))) blobLanguage
= Just $ ErrorDeclaration (T.pack (formatTOCError (Syntax.unError (sourceSpan ann) err))) mempty blobLanguage
-- | Produce a 'FunctionDeclaration' for 'Declaration.Function' nodes so long as their identifier is non-empty (defined as having a non-empty 'byteRange').
instance CustomHasDeclaration Declaration.Function where
customToDeclaration Blob{..} _ (Declaration.Function _ (Term (In identifierAnn _), _) _ _)
customToDeclaration blob@Blob{..} ann decl@(Declaration.Function _ (Term (In identifierAnn _), _) _ _)
-- Do not summarize anonymous functions
| isEmpty identifierAnn = Nothing
-- Named functions
| otherwise = Just $ FunctionDeclaration (getSource identifierAnn)
| otherwise = Just $ FunctionDeclaration (getSource identifierAnn) (getFunctionSource blob (In ann decl)) blobLanguage
where getSource = toText . flip Source.slice blobSource . byteRange
isEmpty = (== 0) . rangeLength . byteRange
-- | Produce a 'MethodDeclaration' for 'Declaration.Method' nodes. If the methods receiver is non-empty (defined as having a non-empty 'byteRange'), the 'declarationIdentifier' will be formatted as 'receiver.method_name'; otherwise it will be simply 'method_name'.
instance CustomHasDeclaration Declaration.Method where
customToDeclaration Blob{..} _ (Declaration.Method _ (Term (In receiverAnn _), _) (Term (In identifierAnn _), _) _ _)
customToDeclaration blob@Blob{..} ann decl@(Declaration.Method _ (Term (In receiverAnn _), _) (Term (In identifierAnn _), _) _ _)
-- Methods without a receiver
| isEmpty receiverAnn = Just $ MethodDeclaration (getSource identifierAnn)
| isEmpty receiverAnn = Just $ MethodDeclaration (getSource identifierAnn) (getMethodSource blob (In ann decl)) blobLanguage Nothing
-- Methods with a receiver (class methods) are formatted like `receiver.method_name`
| otherwise = Just $ MethodDeclaration (getSource receiverAnn <> "." <> getSource identifierAnn)
| otherwise = Just $ MethodDeclaration (getSource identifierAnn) (getMethodSource blob (In ann decl)) blobLanguage (Just (getSource receiverAnn))
where getSource = toText . flip Source.slice blobSource . byteRange
isEmpty = (== 0) . rangeLength . byteRange
-- | Produce a 'ClassDeclaration' for 'Declaration.Class' nodes.
instance CustomHasDeclaration Declaration.Class where
customToDeclaration Blob{..} _ (Declaration.Class _ (Term (In identifierAnn _), _) _ _)
customToDeclaration blob@Blob{..} ann decl@(Declaration.Class _ (Term (In identifierAnn _), _) _ _)
-- Classes
= Just $ ClassDeclaration (getSource identifierAnn)
= Just $ ClassDeclaration (getSource identifierAnn) (getClassSource blob (In ann decl)) blobLanguage
where getSource = toText . flip Source.slice blobSource . byteRange
-- | Produce a 'Declaration' for 'Union's using the 'HasDeclaration' instance & therefore using a 'CustomHasDeclaration' instance when one exists & the type is listed in 'DeclarationStrategy'.
@ -194,7 +200,7 @@ type family DeclarationStrategy syntax where
DeclarationStrategy Declaration.Class = 'Custom
DeclarationStrategy Declaration.Function = 'Custom
DeclarationStrategy Declaration.Method = 'Custom
DeclarationStrategy Markdown.Section = 'Custom
DeclarationStrategy Markdown.Heading = 'Custom
DeclarationStrategy Syntax.Error = 'Custom
DeclarationStrategy (Union fs) = 'Custom
DeclarationStrategy a = 'Default
@ -219,17 +225,47 @@ declaration (In annotation _) = annotation <$ getDeclaration annotation
-- | Compute 'Declaration's for methods and functions in 'Syntax'.
syntaxDeclarationAlgebra :: HasField fields Range => Blob -> RAlgebra (TermF S.Syntax (Record fields)) (Term S.Syntax (Record fields)) (Maybe Declaration)
syntaxDeclarationAlgebra Blob{..} (In a r) = case r of
S.Function (identifier, _) _ _ -> Just $ FunctionDeclaration (getSource identifier)
S.Method _ (identifier, _) Nothing _ _ -> Just $ MethodDeclaration (getSource identifier)
syntaxDeclarationAlgebra blob@Blob{..} decl@(In a r) = case r of
S.Function (identifier, _) _ _ -> Just $ FunctionDeclaration (getSource identifier) (getSyntaxDeclarationSource blob decl) blobLanguage
S.Method _ (identifier, _) Nothing _ _ -> Just $ MethodDeclaration (getSource identifier) (getSyntaxDeclarationSource blob decl) blobLanguage Nothing
S.Method _ (identifier, _) (Just (receiver, _)) _ _
| S.Indexed [receiverParams] <- unwrap receiver
, S.ParameterDecl (Just ty) _ <- unwrap receiverParams -> Just $ MethodDeclaration ("(" <> getSource ty <> ") " <> getSource identifier)
| otherwise -> Just $ MethodDeclaration (getSource receiver <> "." <> getSource identifier)
S.ParseError{} -> Just $ ErrorDeclaration (toText (Source.slice (byteRange a) blobSource)) blobLanguage
, S.ParameterDecl (Just ty) _ <- unwrap receiverParams -> Just $ MethodDeclaration (getSource identifier) (getSyntaxDeclarationSource blob decl) blobLanguage (Just (getSource ty))
| otherwise -> Just $ MethodDeclaration (getSource identifier) (getSyntaxDeclarationSource blob decl) blobLanguage (Just (getSource receiver))
S.ParseError{} -> Just $ ErrorDeclaration (toText (Source.slice (byteRange a) blobSource)) mempty blobLanguage
_ -> Nothing
where getSource = toText . flip Source.slice blobSource . byteRange . extract
where
getSource = toText . flip Source.slice blobSource . byteRange . extract
getMethodSource :: HasField fields Range => Blob -> TermF Declaration.Method (Record fields) (Term syntax (Record fields), a) -> T.Text
getMethodSource Blob{..} (In a r)
= let declRange = byteRange a
bodyRange = byteRange <$> case r of
Declaration.Method _ _ _ _ (Term (In a' _), _) -> Just a'
in maybe mempty (stripEnd . toText . flip Source.slice blobSource . subtractRange declRange) bodyRange
getFunctionSource :: HasField fields Range => Blob -> TermF Declaration.Function (Record fields) (Term syntax (Record fields), a) -> T.Text
getFunctionSource Blob{..} (In a r)
= let declRange = byteRange a
bodyRange = byteRange <$> case r of
Declaration.Function _ _ _ (Term (In a' _), _) -> Just a'
in maybe mempty (stripEnd . toText . flip Source.slice blobSource . subtractRange declRange) bodyRange
getClassSource :: (HasField fields Range) => Blob -> TermF Declaration.Class (Record fields) (Term syntax (Record fields), a) -> T.Text
getClassSource Blob{..} (In a r)
= let declRange = byteRange a
bodyRange = byteRange <$> case r of
Declaration.Class _ _ _ (Term (In a' _), _) -> Just a'
in maybe mempty (stripEnd . toText . flip Source.slice blobSource . subtractRange declRange) bodyRange
getSyntaxDeclarationSource :: HasField fields Range => Blob -> TermF Syntax (Record fields) (Term syntax (Record fields), a) -> T.Text
getSyntaxDeclarationSource Blob{..} (In a r)
= let declRange = byteRange a
bodyRange = byteRange <$> case r of
S.Function _ _ ((Term (In a' _), _) : _) -> Just a'
S.Method _ _ _ _ ((Term (In a' _), _) : _) -> Just a'
_ -> Nothing
in maybe mempty (stripEnd . toText . flip Source.slice blobSource . subtractRange declRange) bodyRange
formatTOCError :: Error.Error String -> String
formatTOCError e = showExpectation False (errorExpected e) (errorActual e) ""
@ -261,7 +297,7 @@ termTableOfContentsBy :: (Foldable f, Functor f)
-> Term f annotation
-> [a]
termTableOfContentsBy selector = cata termAlgebra
where termAlgebra r | Just a <- selector r = [a]
where termAlgebra r | Just a <- selector r = a : fold r
| otherwise = fold r
@ -292,20 +328,24 @@ dedupe = let tuples = sortOn fst . Map.elems . snd . foldl' go (0, Map.empty) in
dedupeKey entry = DedupeKey ((fmap toCategoryName . getDeclaration . entryPayload) entry, (fmap (toLower . declarationIdentifier) . getDeclaration . entryPayload) entry)
exactMatch = (==) `on` (getDeclaration . entryPayload)
-- | Construct a 'JSONSummary' from an 'Entry'.
entrySummary :: (HasField fields (Maybe Declaration), HasField fields Span) => Entry (Record fields) -> Maybe JSONSummary
-- | Construct a 'TOCSummary' from an 'Entry'.
entrySummary :: (HasField fields (Maybe Declaration), HasField fields Span) => Entry (Record fields) -> Maybe TOCSummary
entrySummary entry = case entry of
Changed a -> recordSummary a "modified"
Deleted a -> recordSummary a "removed"
Inserted a -> recordSummary a "added"
Replaced a -> recordSummary a "modified"
Changed a -> recordSummary "modified" a
Deleted a -> recordSummary "removed" a
Inserted a -> recordSummary "added" a
Replaced a -> recordSummary "modified" a
-- | Construct a 'JSONSummary' from a node annotation and a change type label.
recordSummary :: (HasField fields (Maybe Declaration), HasField fields Span) => Record fields -> T.Text -> Maybe JSONSummary
recordSummary record = case getDeclaration record of
Just (ErrorDeclaration text language) -> Just . const (ErrorSummary text (sourceSpan record) language)
Just declaration -> Just . JSONSummary (toCategoryName declaration) (declarationIdentifier declaration) (sourceSpan record)
Nothing -> const Nothing
-- | Construct a 'TOCSummary' from a node annotation and a change type label.
recordSummary :: (HasField fields (Maybe Declaration), HasField fields Span) => T.Text -> Record fields -> Maybe TOCSummary
recordSummary changeText record = case getDeclaration record of
Just (ErrorDeclaration text _ language) -> Just $ ErrorSummary text (sourceSpan record) language
Just declaration -> Just $ TOCSummary (toCategoryName declaration) (formatIdentifier declaration) (sourceSpan record) changeText
Nothing -> Nothing
where
formatIdentifier (MethodDeclaration identifier _ (Just Language.Go) (Just receiver)) = "(" <> receiver <> ") " <> identifier
formatIdentifier (MethodDeclaration identifier _ _ (Just receiver)) = receiver <> "." <> identifier
formatIdentifier declaration = declarationIdentifier declaration
renderToCDiff :: (HasField fields (Maybe Declaration), HasField fields Span, Foldable f, Functor f) => Both Blob -> Diff f (Record fields) (Record fields) -> Summaries
renderToCDiff blobs = uncurry Summaries . bimap toMap toMap . List.partition isValidSummary . diffTOC
@ -317,22 +357,23 @@ renderToCDiff blobs = uncurry Summaries . bimap toMap toMap . List.partition isV
| before == after -> after
| otherwise -> before <> " -> " <> after
renderToCTerm :: (HasField fields (Maybe Declaration), HasField fields Span, Foldable f, Functor f) => Blob -> Term f (Record fields) -> Summaries
renderToCTerm Blob{..} = uncurry Summaries . bimap toMap toMap . List.partition isValidSummary . termToC
where toMap [] = mempty
toMap as = Map.singleton (T.pack blobPath) (toJSON <$> as)
diffTOC :: (HasField fields (Maybe Declaration), HasField fields Span, Foldable f, Functor f) => Diff f (Record fields) (Record fields) -> [JSONSummary]
diffTOC :: (HasField fields (Maybe Declaration), HasField fields Span, Foldable f, Functor f) => Diff f (Record fields) (Record fields) -> [TOCSummary]
diffTOC = mapMaybe entrySummary . dedupe . tableOfContentsBy declaration
termToC :: (HasField fields (Maybe Declaration), HasField fields Span, Foldable f, Functor f) => Term f (Record fields) -> [JSONSummary]
termToC = mapMaybe (flip recordSummary "unchanged") . termTableOfContentsBy declaration
renderToCTerm :: (HasField fields (Maybe Declaration), HasField fields Span, Foldable f, Functor f) => Blob -> Term f (Record fields) -> Summaries
renderToCTerm Blob{..} = uncurry Summaries . bimap toMap toMap . List.partition isValidSummary . termToC
where
toMap [] = mempty
toMap as = Map.singleton (T.pack blobPath) (toJSON <$> as)
termToC :: (HasField fields (Maybe Declaration), HasField fields Span, Foldable f, Functor f) => Term f (Record fields) -> [TOCSummary]
termToC = mapMaybe (recordSummary "unchanged") . termTableOfContentsBy declaration
-- The user-facing category name
toCategoryName :: Declaration -> T.Text
toCategoryName declaration = case declaration of
FunctionDeclaration _ -> "Function"
ClassDeclaration _ -> "Class"
MethodDeclaration _ -> "Method"
SectionDeclaration _ l -> "Heading " <> T.pack (show l)
ClassDeclaration{} -> "Class"
FunctionDeclaration{} -> "Function"
MethodDeclaration{} -> "Method"
HeadingDeclaration _ _ _ l -> "Heading " <> T.pack (show l)
ErrorDeclaration{} -> "ParseError"

46
src/Renderer/Tag.hs Normal file
View File

@ -0,0 +1,46 @@
{-# LANGUAGE DataKinds, MultiParamTypeClasses, RankNTypes, ScopedTypeVariables, TypeFamilies, TypeOperators, UndecidableInstances #-}
module Renderer.Tag
( renderToTags
) where
import Data.Aeson
import Data.Blob
import Data.Maybe (mapMaybe)
import Data.Record
import Data.Term
import GHC.Generics
import Info
import qualified Data.Text as T
import Renderer.TOC
-- | Render a 'Term' to a ctags like output (See 'Tag').
renderToTags :: (HasField fields (Maybe Declaration), HasField fields Span, Foldable f, Functor f) => Blob -> Term f (Record fields) -> [Value]
renderToTags Blob{..} = fmap toJSON . termToC blobPath
where
termToC :: (HasField fields (Maybe Declaration), HasField fields Span, Foldable f, Functor f) => FilePath -> Term f (Record fields) -> [Tag]
termToC path = mapMaybe (tagSummary path "unchanged") . termTableOfContentsBy declaration
-- | Construct a 'Tag' from a node annotation and a change type label.
tagSummary :: (HasField fields (Maybe Declaration), HasField fields Span) => FilePath -> T.Text -> Record fields -> Maybe Tag
tagSummary path _ record = case getDeclaration record of
Just ErrorDeclaration{} -> Nothing
Just declaration -> Just $ Tag (declarationIdentifier declaration) (T.pack path) (T.pack . show <$> declarationLanguage declaration) (toCategoryName declaration) (declarationText declaration) (sourceSpan record)
_ -> Nothing
data Tag
= Tag { tagSymbol :: T.Text
, tagPath :: T.Text
, tagLanguage :: Maybe T.Text
, tagKind :: T.Text
, tagLine :: T.Text
, tagSpan :: Span
}
deriving (Generic, Eq, Show)
instance ToJSON Tag where
toJSON Tag{..} = object [ "symbol" .= tagSymbol
, "path" .= tagPath
, "language" .= tagLanguage
, "kind" .= tagKind
, "line" .= tagLine
, "span" .= tagSpan ]

View File

@ -9,16 +9,17 @@ module Semantic
import Algorithm (Diffable)
import Control.Exception
import Control.Monad ((<=<))
import Control.Monad ((>=>), guard)
import Control.Monad.Error.Class
import Data.Align.Generic
import Data.Bifoldable
import Data.Blob
import Data.ByteString (ByteString)
import Data.Diff
import Data.Functor.Both as Both
import Data.Functor.Classes
import Data.JSON.Fields
import Data.Output
import Data.Bifoldable
import Data.Record
import Data.Syntax.Algebra
import Data.Term
@ -45,26 +46,22 @@ parseBlobs renderer = fmap toOutput . distributeFoldMap (parseBlob renderer) . f
-- | A task to parse a 'Blob' and render the resulting 'Term'.
parseBlob :: TermRenderer output -> Blob -> Task output
parseBlob renderer blob@Blob{..} = case (renderer, blobLanguage) of
(ToCTermRenderer, lang)
| Just (SomeParser parser) <- lang >>= someParser (Proxy :: Proxy '[HasDeclaration, Foldable, Functor]) ->
parse parser blob >>= decorate (declarationAlgebra blob) >>= render (renderToCTerm blob)
| Just syntaxParser <- lang >>= syntaxParserForLanguage ->
parse syntaxParser blob >>= decorate (syntaxDeclarationAlgebra blob) >>= render (renderToCTerm blob)
parseBlob renderer blob@Blob{..}
| Just (SomeParser parser) <- blobLanguage >>= someParser (Proxy :: Proxy '[ConstructorName, HasDeclaration, Foldable, Functor, ToJSONFields1])
= parse parser blob >>= case renderer of
ToCTermRenderer -> decorate (declarationAlgebra blob) >=> render (renderToCTerm blob)
JSONTermRenderer -> decorate constructorLabel >=> render (renderJSONTerm blob)
SExpressionTermRenderer -> decorate constructorLabel . (Nil <$) >=> render renderSExpressionTerm
TagsTermRenderer -> decorate (declarationAlgebra blob) >=> render (renderToTags blob)
(JSONTermRenderer, lang)
| Just (SomeParser parser) <- lang >>= someParser (Proxy :: Proxy '[ConstructorName, Foldable, Functor]) ->
parse parser blob >>= decorate constructorLabel >>= render (renderJSONTerm blob)
| Just syntaxParser <- lang >>= syntaxParserForLanguage ->
parse syntaxParser blob >>= decorate syntaxIdentifierAlgebra >>= render (renderJSONTerm blob)
| Just parser <- blobLanguage >>= syntaxParserForLanguage
= parse parser blob >>= case renderer of
ToCTermRenderer -> decorate (syntaxDeclarationAlgebra blob) >=> render (renderToCTerm blob)
JSONTermRenderer -> decorate syntaxIdentifierAlgebra >=> render (renderJSONTerm blob)
SExpressionTermRenderer -> render renderSExpressionTerm . fmap keepCategory
TagsTermRenderer -> decorate (syntaxDeclarationAlgebra blob) >=> render (renderToTags blob)
(SExpressionTermRenderer, lang)
| Just (SomeParser parser) <- lang >>= someParser (Proxy :: Proxy '[ConstructorName, Foldable, Functor]) ->
parse parser blob >>= decorate constructorLabel . (Nil <$) >>= render renderSExpressionTerm
| Just syntaxParser <- lang >>= syntaxParserForLanguage ->
parse syntaxParser blob >>= render renderSExpressionTerm . fmap keepCategory
_ -> throwError (SomeException (NoParserForLanguage blobPath blobLanguage))
| otherwise = throwError (SomeException (NoParserForLanguage blobPath blobLanguage))
data NoParserForLanguage = NoParserForLanguage FilePath (Maybe Language.Language)
deriving (Eq, Exception, Ord, Show, Typeable)
@ -75,58 +72,45 @@ diffBlobPairs renderer = fmap toOutput . distributeFoldMap (diffBlobPair rendere
-- | A task to parse a pair of 'Blob's, diff them, and render the 'Diff'.
diffBlobPair :: DiffRenderer output -> Both Blob -> Task output
diffBlobPair renderer blobs = case (renderer, effectiveLanguage) of
(OldToCDiffRenderer, lang)
| elem lang $ fmap Just [
Language.JSX,
Language.JavaScript,
Language.Markdown,
Language.Python,
Language.Ruby,
Language.TypeScript
]
, Just (SomeParser parser) <- lang >>= someParser (Proxy :: Proxy '[Diffable, Eq1, Foldable, Functor, GAlign, HasDeclaration, Show1, Traversable]) ->
run (\ blob -> parse parser blob >>= decorate (declarationAlgebra blob)) diffTerms (renderToCDiff blobs)
| Just syntaxParser <- lang >>= syntaxParserForLanguage ->
run (\ blob -> parse syntaxParser blob >>= decorate (syntaxDeclarationAlgebra blob)) diffSyntaxTerms (renderToCDiff blobs)
diffBlobPair renderer blobs
| Just (SomeParser parser) <- effectiveLanguage >>= qualify >>= someParser (Proxy :: Proxy '[ConstructorName, Diffable, Eq1, GAlign, HasDeclaration, Show1, ToJSONFields1, Traversable])
= case renderer of
OldToCDiffRenderer -> run (\ blob -> parse parser blob >>= decorate (declarationAlgebra blob)) diffTerms renderToCDiff
ToCDiffRenderer -> run (\ blob -> parse parser blob >>= decorate (declarationAlgebra blob)) diffTerms renderToCDiff
JSONDiffRenderer -> run ( parse parser) diffTerms renderJSONDiff
SExpressionDiffRenderer -> run ( parse parser >=> decorate constructorLabel . (Nil <$)) diffTerms (const renderSExpressionDiff)
(ToCDiffRenderer, lang)
| Just (SomeParser parser) <- lang >>= someParser (Proxy :: Proxy '[Diffable, Eq1, Foldable, Functor, GAlign, HasDeclaration, Show1, Traversable]) ->
run (\ blob -> parse parser blob >>= decorate (declarationAlgebra blob)) diffTerms (renderToCDiff blobs)
| Just syntaxParser <- lang >>= syntaxParserForLanguage ->
run (\ blob -> parse syntaxParser blob >>= decorate (syntaxDeclarationAlgebra blob)) diffSyntaxTerms (renderToCDiff blobs)
| Just parser <- effectiveLanguage >>= syntaxParserForLanguage
= case renderer of
OldToCDiffRenderer -> run (\ blob -> parse parser blob >>= decorate (syntaxDeclarationAlgebra blob)) diffSyntaxTerms renderToCDiff
ToCDiffRenderer -> run (\ blob -> parse parser blob >>= decorate (syntaxDeclarationAlgebra blob)) diffSyntaxTerms renderToCDiff
JSONDiffRenderer -> run ( parse parser >=> decorate syntaxIdentifierAlgebra) diffSyntaxTerms renderJSONDiff
SExpressionDiffRenderer -> run ( parse parser >=> pure . fmap keepCategory) diffSyntaxTerms (const renderSExpressionDiff)
(JSONDiffRenderer, lang)
| Just (SomeParser parser) <- lang >>= someParser (Proxy :: Proxy '[Diffable, Eq1, Foldable, Functor, GAlign, Show1, Traversable]) ->
run (parse parser) diffTerms (renderJSONDiff blobs)
| Just syntaxParser <- lang >>= syntaxParserForLanguage ->
run (decorate syntaxIdentifierAlgebra <=< parse syntaxParser) diffSyntaxTerms (renderJSONDiff blobs)
(PatchDiffRenderer, lang)
| Just (SomeParser parser) <- lang >>= someParser (Proxy :: Proxy '[Diffable, Eq1, Foldable, Functor, GAlign, Show1, Traversable]) ->
run (parse parser) diffTerms (renderPatch blobs)
| Just syntaxParser <- lang >>= syntaxParserForLanguage ->
run (parse syntaxParser) diffSyntaxTerms (renderPatch blobs)
(SExpressionDiffRenderer, lang)
| Just (SomeParser parser) <- lang >>= someParser (Proxy :: Proxy '[ConstructorName, Diffable, Eq1, Foldable, Functor, GAlign, Show1, Traversable]) ->
run (decorate constructorLabel . (Nil <$) <=< parse parser) diffTerms renderSExpressionDiff
| Just syntaxParser <- lang >>= syntaxParserForLanguage ->
run (fmap (fmap keepCategory) . parse syntaxParser) diffSyntaxTerms renderSExpressionDiff
_ -> throwError (SomeException (NoParserForLanguage effectivePath effectiveLanguage))
| otherwise = throwError (SomeException (NoParserForLanguage effectivePath effectiveLanguage))
where (effectivePath, effectiveLanguage) = case runJoin blobs of
(Blob { blobLanguage = Just lang, blobPath = path }, _) -> (path, Just lang)
(_, Blob { blobLanguage = Just lang, blobPath = path }) -> (path, Just lang)
(Blob { blobPath = path }, _) -> (path, Nothing)
run :: (Foldable syntax, Functor syntax) => (Blob -> Task (Term syntax ann)) -> (Term syntax ann -> Term syntax ann -> Diff syntax ann ann) -> (Diff syntax ann ann -> output) -> Task output
qualify language | OldToCDiffRenderer <- renderer = guard (language `elem` aLaCarteLanguages) *> Just language
| otherwise = Just language
aLaCarteLanguages
= [ Language.JSX
, Language.JavaScript
, Language.Markdown
, Language.Python
, Language.Ruby
, Language.TypeScript
]
run :: (Foldable syntax, Functor syntax) => (Blob -> Task (Term syntax ann)) -> (Term syntax ann -> Term syntax ann -> Diff syntax ann ann) -> (Both Blob -> Diff syntax ann ann -> output) -> Task output
run parse diff renderer = do
terms <- distributeFor blobs parse
time "diff" languageTag $ do
diff <- runBothWith (diffTermPair blobs diff) terms
writeStat (Stat.count "diff.nodes" (bilength diff) languageTag)
render renderer diff
render (renderer blobs) diff
where
showLanguage = pure . (,) "language" . show
languageTag = let (a, b) = runJoin blobs

View File

@ -32,6 +32,7 @@ import Control.Parallel.Strategies
import qualified Control.Concurrent.Async as Async
import Control.Monad.Free.Freer
import Data.Blob
import Data.Bool
import qualified Data.ByteString as B
import Data.Diff
import qualified Data.Error as Error
@ -175,7 +176,9 @@ runTaskWithOptions options task = do
where
go :: Task a -> IO (Either SomeException a)
go = iterFreerA (\ task yield -> case task of
ReadBlobs source -> (either Files.readBlobsFromHandle (traverse (uncurry Files.readFile)) source >>= yield) `catchError` (pure . Left . toException)
ReadBlobs (Left handle) -> (Files.readBlobsFromHandle handle >>= yield) `catchError` (pure . Left . toException)
ReadBlobs (Right paths@[(path, Nothing)]) -> (Files.isDirectory path >>= bool (Files.readBlobsFromPaths paths) (Files.readBlobsFromDir path) >>= yield) `catchError` (pure . Left . toException)
ReadBlobs (Right paths) -> (Files.readBlobsFromPaths paths >>= yield) `catchError` (pure . Left . toException)
ReadBlobPairs source -> (either Files.readBlobPairsFromHandle (traverse (traverse (uncurry Files.readFile))) source >>= yield) `catchError` (pure . Left . toException)
WriteToOutput destination contents -> either B.hPutStr B.writeFile destination contents >>= yield
WriteLog level message pairs -> queueLogMessage logger level message pairs >>= yield

View File

@ -62,11 +62,10 @@ arguments = info (version <*> helper <*> ((,) <$> optionsParser <*> argumentsPar
diffCommand = command "diff" (info diffArgumentsParser (progDesc "Show changes between commits or paths"))
diffArgumentsParser = runDiff
<$> ( flag (SomeRenderer PatchDiffRenderer) (SomeRenderer PatchDiffRenderer) (long "patch" <> help "Output a patch(1)-compatible diff (default)")
<|> flag' (SomeRenderer JSONDiffRenderer) (long "json" <> help "Output a json diff")
<|> flag' (SomeRenderer SExpressionDiffRenderer) (long "sexpression" <> help "Output an s-expression diff tree")
<|> flag' (SomeRenderer OldToCDiffRenderer) (long "toc" <> help "Output a table of contents for a diff")
<|> flag' (SomeRenderer ToCDiffRenderer) (long "toc-assignment" <> help "Output a table of contents for a diff using the assignment parser") )
<$> ( flag (SomeRenderer SExpressionDiffRenderer) (SomeRenderer SExpressionDiffRenderer) (long "sexpression" <> help "Output s-expression diff tree")
<|> flag' (SomeRenderer JSONDiffRenderer) (long "json" <> help "Output JSON diff trees")
<|> flag' (SomeRenderer OldToCDiffRenderer) (long "toc" <> help "Output JSON table of contents diff summary")
<|> flag' (SomeRenderer ToCDiffRenderer) (long "toc-assignment" <> help "Output JSON table of contents diff summary using the assignment parser") )
<*> ( Right <$> some (both
<$> argument filePathReader (metavar "FILE_A")
<*> argument filePathReader (metavar "FILE_B"))
@ -76,7 +75,8 @@ arguments = info (version <*> helper <*> ((,) <$> optionsParser <*> argumentsPar
parseArgumentsParser = runParse
<$> ( flag (SomeRenderer SExpressionTermRenderer) (SomeRenderer SExpressionTermRenderer) (long "sexpression" <> help "Output s-expression parse trees (default)")
<|> flag' (SomeRenderer JSONTermRenderer) (long "json" <> help "Output JSON parse trees")
<|> flag' (SomeRenderer ToCTermRenderer) (long "toc" <> help "Output a table of contents for a file"))
<|> flag' (SomeRenderer ToCTermRenderer) (long "toc" <> help "Output JSON table of contents summary")
<|> flag' (SomeRenderer TagsTermRenderer) (long "tags" <> help "Output JSON tags/symbols"))
<*> ( Right <$> some (argument filePathReader (metavar "FILES..."))
<|> pure (Left stdin) )

View File

@ -20,7 +20,6 @@ import Data.Term
import Data.Text (Text, pack)
import Language
import qualified Language.Go as Go
import qualified Language.TypeScript as TypeScript
import Foreign
import Foreign.C.String (peekCString)
import Foreign.Marshal.Array (allocaArray)
@ -29,7 +28,6 @@ import qualified TreeSitter.Document as TS
import qualified TreeSitter.Node as TS
import qualified TreeSitter.Language as TS
import qualified TreeSitter.Go as TS
import qualified TreeSitter.TypeScript as TS
import Info
-- | Returns a TreeSitter parser for the given language and TreeSitter grammar.
@ -112,7 +110,6 @@ assignTerm language source annotation children allChildren =
where assignTermByLanguage :: Source -> Category -> [ Term S.Syntax (Record DefaultFields) ] -> Maybe (S.Syntax (Term S.Syntax (Record DefaultFields)))
assignTermByLanguage = case languageForTSLanguage language of
Just Language.Go -> Go.termAssignment
Just TypeScript -> TypeScript.termAssignment
_ -> \ _ _ _ -> Nothing
defaultTermAssignment :: Source -> Record DefaultFields -> [ Term S.Syntax (Record DefaultFields) ] -> IO [ Term S.Syntax (Record DefaultFields) ] -> IO (Term S.Syntax (Record DefaultFields))
@ -190,12 +187,10 @@ categoryForLanguageProductionName = withDefaults . byLanguage
byLanguage language = case languageForTSLanguage language of
Just Language.Go -> Go.categoryForGoName
Just Language.TypeScript -> TypeScript.categoryForTypeScriptName
_ -> Other
languageForTSLanguage :: Ptr TS.Language -> Maybe Language
languageForTSLanguage = flip lookup
[ (TS.tree_sitter_go, Language.Go)
, (TS.tree_sitter_typescript, TypeScript)
]

View File

@ -1,280 +0,0 @@
{-# LANGUAGE DataKinds #-}
module AlignmentSpec where
import Alignment
import Control.Arrow ((&&&))
import Control.Monad.Free (wrap)
import Control.Monad.State
import Data.Align hiding (align)
import Data.Bifunctor
import Data.Bifunctor.Join
import Data.Diff
import Data.Functor.Both as Both hiding (fst, snd)
import Data.Functor.Listable
import Data.List (nub, sort)
import Data.Maybe (catMaybes, fromMaybe)
import Data.Monoid hiding ((<>))
import Data.Range
import Data.Record
import Data.Semigroup ((<>))
import qualified Data.Source as Source
import Data.SplitDiff
import Data.Term
import qualified Data.Text as Text
import Data.These
import Syntax
import Test.Hspec (Spec, describe, it, parallel)
import Test.Hspec.Expectations.Pretty
import Test.Hspec.LeanCheck
import Test.LeanCheck
import GHC.Show (Show(..))
spec :: Spec
spec = parallel $ do
describe "alignBranch" $ do
it "produces symmetrical context" $
alignBranch getRange ([] :: [Join These (SplitDiff Syntax (Record '[Range]))]) (both [Range 0 2, Range 2 4] [Range 0 2, Range 2 4]) `shouldBe`
[ Join (These (Range 0 2, [])
(Range 0 2, []))
, Join (These (Range 2 4, [])
(Range 2 4, []))
]
it "produces asymmetrical context" $
alignBranch getRange ([] :: [Join These (SplitDiff Syntax (Record '[Range]))]) (both [Range 0 2, Range 2 4] [Range 0 1]) `shouldBe`
[ Join (These (Range 0 2, [])
(Range 0 1, []))
, Join (This (Range 2 4, []))
]
prop "covers every input line" $
\ elements -> let (_, children, ranges) = toAlignBranchInputs elements in
join <$> traverse (modifyJoin (fromThese [] []) . fmap (pure . fst)) (alignBranch snd children ranges) `shouldBe` ranges
prop "covers every input child" $
\ elements -> let (_, children, ranges) = toAlignBranchInputs elements in
sort (nub (keysOfAlignedChildren (alignBranch snd children ranges))) `shouldBe` sort (nub (catMaybes (branchElementKey <$> elements)))
prop "covers every line of every input child" $
\ elements -> let (_, children, ranges) = toAlignBranchInputs elements in
sort (keysOfAlignedChildren (alignBranch snd children ranges)) `shouldBe` sort (do
line <- children
these (pure . fst) (pure . fst) (\ (k1, _) (k2, _) -> [ k1, k2 ]) . runJoin $ line)
describe "alignDiff" $ do
it "aligns identical branches on a single line" $
let sources = both (Source.fromText "[ foo ]") (Source.fromText "[ foo ]") in
align sources ((info 0 7, info 0 7) `merge` Indexed [ (info 2 5, info 2 5) `merge` Leaf "foo" ]) `shouldBe` prettyDiff sources
[ Join (These (wrap $ info 0 7 `In` [ wrap $ info 2 5 `In` [] ])
(wrap $ info 0 7 `In` [ wrap $ info 2 5 `In` [] ])) ]
it "aligns identical branches spanning multiple lines" $
let sources = both (Source.fromText "[\nfoo\n]") (Source.fromText "[\nfoo\n]") in
align sources ((info 0 7, info 0 7) `merge` Indexed [ (info 2 5, info 2 5) `merge` Leaf "foo" ]) `shouldBe` prettyDiff sources
[ Join (These (wrap $ info 0 2 `In` [])
(wrap $ info 0 2 `In` []))
, Join (These (wrap $ info 2 6 `In` [ wrap $ info 2 5 `In` [] ])
(wrap $ info 2 6 `In` [ wrap $ info 2 5 `In` [] ]))
, Join (These (wrap $ info 6 7 `In` [])
(wrap $ info 6 7 `In` []))
]
it "aligns reformatted branches" $
let sources = both (Source.fromText "[ foo ]") (Source.fromText "[\nfoo\n]") in
align sources ((info 0 7, info 0 7) `merge` Indexed [ (info 2 5, info 2 5) `merge` Leaf "foo" ]) `shouldBe` prettyDiff sources
[ Join (That (wrap $ info 0 2 `In` []))
, Join (These (wrap $ info 0 7 `In` [ wrap $ info 2 5 `In` [] ])
(wrap $ info 2 6 `In` [ wrap $ info 2 5 `In` [] ]))
, Join (That (wrap $ info 6 7 `In` []))
]
it "aligns nodes following reformatted branches" $
let sources = both (Source.fromText "[ foo ]\nbar\n") (Source.fromText "[\nfoo\n]\nbar\n") in
align sources ((info 0 12, info 0 12) `merge` Indexed [ (info 0 7, info 0 7) `merge` Indexed [ (info 2 5, info 2 5) `merge` Leaf "foo" ], (info 8 11, info 8 11) `merge` Leaf "bar" ]) `shouldBe` prettyDiff sources
[ Join (That (wrap $ info 0 2 `In` [ wrap $ info 0 2 `In` [] ]))
, Join (These (wrap $ info 0 8 `In` [ wrap $ info 0 7 `In` [ wrap $ info 2 5 `In` [] ] ])
(wrap $ info 2 6 `In` [ wrap $ info 2 6 `In` [ wrap $ info 2 5 `In` [] ] ]))
, Join (That (wrap $ info 6 8 `In` [ wrap $ info 6 7 `In` [] ]))
, Join (These (wrap $ info 8 12 `In` [ wrap $ info 8 11 `In` [] ])
(wrap $ info 8 12 `In` [ wrap $ info 8 11 `In` [] ]))
, Join (These (wrap $ info 12 12 `In` [])
(wrap $ info 12 12 `In` []))
]
it "aligns identical branches with multiple children on the same line" $
let sources = pure (Source.fromText "[ foo, bar ]") in
align sources ((info 0 12, info 0 12) `merge` Indexed [ (info 2 5, info 2 5) `merge` Leaf "foo", (info 7 10, info 7 10) `merge` Leaf "bar" ]) `shouldBe` prettyDiff sources
[ Join (runBothWith These (pure (wrap $ info 0 12 `In` [ wrap $ info 2 5 `In` [], wrap $ info 7 10 `In` [] ])) ) ]
it "aligns insertions" $
let sources = both (Source.fromText "a") (Source.fromText "a\nb") in
align sources ((info 0 1, info 0 3) `merge` Indexed [ (info 0 1, info 0 1) `merge` Leaf "a", inserting (Term (info 2 3 `In` Leaf "b")) ]) `shouldBe` prettyDiff sources
[ Join (These (wrap $ info 0 1 `In` [ wrap $ info 0 1 `In` [] ])
(wrap $ info 0 2 `In` [ wrap $ info 0 1 `In` [] ]))
, Join (That (wrap $ info 2 3 `In` [ pure (SplitInsert (Term (info 2 3 `In` []))) ]))
]
it "aligns total insertions" $
let sources = both (Source.fromText "") (Source.fromText "a") in
align sources (inserting (Term (info 0 1 `In` Leaf "a"))) `shouldBe` prettyDiff sources
[ Join (That (pure (SplitInsert (Term (info 0 1 `In` []))))) ]
it "aligns insertions into empty branches" $
let sources = both (Source.fromText "[ ]") (Source.fromText "[a]") in
align sources ((info 0 3, info 0 3) `merge` Indexed [ inserting (Term (info 1 2 `In` Leaf "a")) ]) `shouldBe` prettyDiff sources
[ Join (That (wrap $ info 0 3 `In` [ pure (SplitInsert (Term (info 1 2 `In` []))) ]))
, Join (This (wrap $ info 0 3 `In` []))
]
it "aligns symmetrically following insertions" $
let sources = both (Source.fromText "a\nc") (Source.fromText "a\nb\nc") in
align sources ((info 0 3, info 0 5) `merge` Indexed [ (info 0 1, info 0 1) `merge` Leaf "a", inserting (Term (info 2 3 `In` Leaf "b")), (info 2 3, info 4 5) `merge` Leaf "c" ])
`shouldBe` prettyDiff sources
[ Join (These (wrap $ info 0 2 `In` [ wrap $ info 0 1 `In` [] ])
(wrap $ info 0 2 `In` [ wrap $ info 0 1 `In` [] ]))
, Join (That (wrap $ info 2 4 `In` [ pure (SplitInsert (Term (info 2 3 `In` []))) ]))
, Join (These (wrap $ info 2 3 `In` [ wrap $ info 2 3 `In` [] ])
(wrap $ info 4 5 `In` [ wrap $ info 4 5 `In` [] ]))
]
it "symmetrical nodes force the alignment of asymmetrical nodes on both sides" $
let sources = both (Source.fromText "[ a, b ]") (Source.fromText "[ b, c ]") in
align sources ((info 0 8, info 0 8) `merge` Indexed [ deleting (Term (info 2 3 `In` Leaf "a")), (info 5 6, info 2 3) `merge` Leaf "b", inserting (Term (info 5 6 `In` Leaf "c")) ]) `shouldBe` prettyDiff sources
[ Join (These (wrap $ info 0 8 `In` [ pure (SplitDelete (Term (info 2 3 `In` []))), wrap $ info 5 6 `In` [] ])
(wrap $ info 0 8 `In` [ wrap $ info 2 3 `In` [], pure (SplitInsert (Term (info 5 6 `In` []))) ])) ]
it "when one of two symmetrical nodes must be split, splits the latter" $
let sources = both (Source.fromText "[ a, b ]") (Source.fromText "[ a\n, b\n]") in
align sources ((info 0 8, info 0 9) `merge` Indexed [ (info 2 3, info 2 3) `merge` Leaf "a", (info 5 6, info 6 7) `merge` Leaf "b" ]) `shouldBe` prettyDiff sources
[ Join (These (wrap $ info 0 8 `In` [ wrap $ info 2 3 `In` [], wrap $ info 5 6 `In` [] ])
(wrap $ info 0 4 `In` [ wrap $ info 2 3 `In` [] ]))
, Join (That (wrap $ info 4 8 `In` [ wrap $ info 6 7 `In` [] ]))
, Join (That (wrap $ info 8 9 `In` []))
]
it "aligns deletions before insertions" $
let sources = both (Source.fromText "[ a ]") (Source.fromText "[ b ]") in
align sources ((info 0 5, info 0 5) `merge` Indexed [ deleting (Term (info 2 3 `In` Leaf "a")), inserting (Term (info 2 3 `In` Leaf "b")) ]) `shouldBe` prettyDiff sources
[ Join (This (wrap $ info 0 5 `In` [ pure (SplitDelete (Term (info 2 3 `In` []))) ]))
, Join (That (wrap $ info 0 5 `In` [ pure (SplitInsert (Term (info 2 3 `In` []))) ]))
]
it "aligns context-only lines symmetrically" $
let sources = both (Source.fromText "[\n a\n,\n b\n]") (Source.fromText "[\n a, b\n\n\n]") in
align sources ((info 0 13, info 0 12) `merge` Indexed [ (info 4 5, info 4 5) `merge` Leaf "a", (info 10 11, info 7 8) `merge` Leaf "b" ]) `shouldBe` prettyDiff sources
[ Join (These (wrap $ info 0 2 `In` [])
(wrap $ info 0 2 `In` []))
, Join (These (wrap $ info 2 6 `In` [ wrap $ info 4 5 `In` [] ])
(wrap $ info 2 9 `In` [ wrap $ info 4 5 `In` [], wrap $ info 7 8 `In` [] ]))
, Join (These (wrap $ info 6 8 `In` [])
(wrap $ info 9 10 `In` []))
, Join (This (wrap $ info 8 12 `In` [ wrap $ info 10 11 `In` [] ]))
, Join (These (wrap $ info 12 13 `In` [])
(wrap $ info 10 11 `In` []))
, Join (That (wrap $ info 11 12 `In` []))
]
it "aligns asymmetrical nodes preceding their symmetrical siblings conservatively" $
let sources = both (Source.fromText "[ b, c ]") (Source.fromText "[ a\n, c\n]") in
align sources ((info 0 8, info 0 9) `merge` Indexed [ inserting (Term (info 2 3 `In` Leaf "a")), deleting (Term (info 2 3 `In` Leaf "b")), (info 5 6, info 6 7) `merge` Leaf "c" ]) `shouldBe` prettyDiff sources
[ Join (That (wrap $ info 0 4 `In` [ pure (SplitInsert (Term (info 2 3 `In` []))) ]))
, Join (These (wrap $ info 0 8 `In` [ pure (SplitDelete (Term (info 2 3 `In` []))), wrap $ info 5 6 `In` [] ])
(wrap $ info 4 8 `In` [ wrap $ info 6 7 `In` [] ]))
, Join (That (wrap $ info 8 9 `In` []))
]
it "aligns symmetrical reformatted nodes" $
let sources = both (Source.fromText "a [ b ]\nc") (Source.fromText "a [\nb\n]\nc") in
align sources ((info 0 9, info 0 9) `merge` Indexed [ (info 0 1, info 0 1) `merge` Leaf "a", (info 2 7, info 2 7) `merge` Indexed [ (info 4 5, info 4 5) `merge` Leaf "b" ], (info 8 9, info 8 9) `merge` Leaf "c" ]) `shouldBe` prettyDiff sources
[ Join (These (wrap $ info 0 8 `In` [ wrap $ info 0 1 `In` [], wrap $ info 2 7 `In` [ wrap $ info 4 5 `In` [] ] ])
(wrap $ info 0 4 `In` [ wrap $ info 0 1 `In` [], wrap $ info 2 4 `In` [] ]))
, Join (That (wrap $ info 4 6 `In` [ wrap $ info 4 6 `In` [ wrap $ info 4 5 `In` [] ] ]))
, Join (That (wrap $ info 6 8 `In` [ wrap $ info 6 7 `In` [] ]))
, Join (These (wrap $ info 8 9 `In` [ wrap $ info 8 9 `In` [] ])
(wrap $ info 8 9 `In` [ wrap $ info 8 9 `In` [] ]))
]
describe "numberedRows" $ do
prop "counts only non-empty values" $
\ xs -> counts (numberedRows (unListableF <$> xs :: [Join These Char])) `shouldBe` length . catMaybes <$> Join (unalign (runJoin . unListableF <$> xs))
data BranchElement
= Child Text.Text (Join These Text.Text)
| Margin (Join These Text.Text)
deriving Show
branchElementKey :: BranchElement -> Maybe Text.Text
branchElementKey (Child key _) = Just key
branchElementKey _ = Nothing
toAlignBranchInputs :: [BranchElement] -> (Both Source.Source, [Join These (Text.Text, Range)], Both [Range])
toAlignBranchInputs elements = (sources, join . (`evalState` both 0 0) . traverse go $ elements, ranges)
where go :: BranchElement -> State (Both Int) [Join These (Text.Text, Range)]
go child@(Child key _) = do
lines <- traverse (\ (Child _ contents) -> do
prev <- get
let next = (+) <$> prev <*> modifyJoin (fromThese 0 0) (Text.length <$> contents)
put next
pure $! modifyJoin (runBothWith bimap (const <$> (Range <$> prev <*> next))) contents) (alignBranchElement child)
pure $! fmap ((,) key) <$> lines
go (Margin contents) = do
prev <- get
put $ (+) <$> prev <*> modifyJoin (fromThese 0 0) (Text.length <$> contents)
pure []
alignBranchElement element = case element of
Child key contents -> Child key <$> joinCrosswalk lines contents
Margin contents -> Margin <$> joinCrosswalk lines contents
where lines = fmap Source.toText . Source.sourceLines . Source.fromText
sources = foldMap Source.fromText <$> bothContents elements
ranges = fmap (filter (\ (Range start end) -> start /= end)) $ Source.sourceLineRangesWithin <$> (Source.totalRange <$> sources) <*> sources
bothContents = foldMap (modifyJoin (fromThese [] []) . fmap (:[]) . branchElementContents)
branchElementContents (Child _ contents) = contents
branchElementContents (Margin contents) = contents
keysOfAlignedChildren :: [Join These (Range, [(Text.Text, Range)])] -> [Text.Text]
keysOfAlignedChildren lines = lines >>= these id id (<>) . runJoin . fmap (fmap fst . snd)
joinCrosswalk :: Bicrosswalk p => Align f => (a -> f b) -> Join p a -> f (Join p b)
joinCrosswalk f = fmap Join . bicrosswalk f f . runJoin
instance Listable BranchElement where
tiers = oneof [ (\ key -> Child key `mapT` joinTheseOf (contents key)) `concatMapT` key
, Margin `mapT` joinTheseOf (Text.singleton `mapT` padding '-') ]
where key = Text.singleton `mapT` [['a'..'z'] <> ['A'..'Z'] <> ['0'..'9']]
contents key = (wrap key . Text.singleton) `mapT` padding '*'
wrap key contents = "(" <> key <> contents <> ")" :: Text.Text
padding :: Char -> [Tier Char]
padding char = frequency [ (10, [[char]])
, (1, [['\n']]) ]
joinTheseOf g = oneof [ (Join . This) `mapT` g
, (Join . That) `mapT` g
, productWith ((Join .) . These) g g ]
frequency :: [(Int, [Tier a])] -> [Tier a]
frequency = concatT . foldr ((\/) . pure . uncurry replicate) []
oneof :: [[[a]]] -> [[a]]
oneof = frequency . fmap ((,) 1)
counts :: [Join These (Int, a)] -> Both Int
counts numbered = fromMaybe 0 . getLast . mconcat . fmap Last <$> Join (unalign (runJoin . fmap fst <$> numbered))
align :: Both Source.Source -> Diff Syntax (Record '[Range]) (Record '[Range]) -> PrettyDiff (SplitDiff [] (Record '[Range]))
align sources = PrettyDiff sources . fmap (fmap (getRange &&& id)) . alignDiff sources
info :: Int -> Int -> Record '[Range]
info start end = Range start end :. Nil
prettyDiff :: Both Source.Source -> [Join These (SplitDiff [] (Record '[Range]))] -> PrettyDiff (SplitDiff [] (Record '[Range]))
prettyDiff sources = PrettyDiff sources . fmap (fmap ((getRange &&& id)))
data PrettyDiff a = PrettyDiff { unPrettySources :: Both Source.Source, unPrettyLines :: [Join These (Range, a)] }
deriving Eq
instance Show (PrettyDiff a) where
showsPrec _ (PrettyDiff sources lines) = (prettyPrinted ++) -- . (("\n" ++ show lines) ++)
where prettyPrinted = showLine (maximum (0 : (maximum . fmap length <$> shownLines))) <$> shownLines >>= ('\n':)
shownLines = catMaybes $ toBoth <$> lines
showLine n line = uncurry ((<>) . (++ " | ")) (fromThese (replicate n ' ') (replicate n ' ') (runJoin (pad n <$> line)))
showDiff (range, _) = filter (/= '\n') . Text.unpack . Source.toText . Source.slice range
pad n string = (<>) (take n string) (replicate (max 0 (n - length string)) ' ')
toBoth them = showDiff <$> them `applyThese` modifyJoin (uncurry These) sources

View File

@ -54,6 +54,7 @@ import Renderer.TOC
import RWS
import Syntax as S
import Test.LeanCheck
import qualified Language
type Tier a = [a]
@ -351,10 +352,17 @@ instance Listable Text where
instance Listable Declaration where
tiers
= cons1 (MethodDeclaration)
\/ cons1 (FunctionDeclaration)
\/ cons1 (flip ErrorDeclaration Nothing)
= cons4 MethodDeclaration
\/ cons3 FunctionDeclaration
\/ cons2 (\ a b -> ErrorDeclaration a b Nothing)
instance Listable Language.Language where
tiers
= cons0 Language.Go
\/ cons0 Language.JavaScript
\/ cons0 Language.Python
\/ cons0 Language.Ruby
\/ cons0 Language.TypeScript
instance Listable Range where
tiers = cons2 Range

View File

@ -1,17 +0,0 @@
module PatchOutputSpec where
import Data.Blob
import Data.Diff
import Data.Functor.Both
import Data.Range
import Data.Record
import Renderer.Patch
import Syntax
import Test.Hspec (Spec, describe, it, parallel)
import Test.Hspec.Expectations.Pretty
spec :: Spec
spec = parallel $ do
describe "hunks" $ do
it "empty diffs have empty hunks" $
hunks (merge (Range 0 0 :. Nil, Range 0 0 :. Nil) (Leaf "")) (both (Blob mempty "abcde" "path2.txt" (Just defaultPlainBlob) Nothing) (Blob mempty "xyz" "path2.txt" (Just defaultPlainBlob) Nothing)) `shouldBe` [Hunk {offset = pure 0, changes = [], trailingContext = []}]

View File

@ -53,15 +53,12 @@ parseFixtures =
diffFixtures :: [(SomeRenderer DiffRenderer, Either Handle [Both (FilePath, Maybe Language)], ByteString)]
diffFixtures =
[ (SomeRenderer PatchDiffRenderer, pathMode, patchOutput)
, (SomeRenderer JSONDiffRenderer, pathMode, jsonOutput)
[ (SomeRenderer JSONDiffRenderer, pathMode, jsonOutput)
, (SomeRenderer SExpressionDiffRenderer, pathMode, sExpressionOutput)
, (SomeRenderer OldToCDiffRenderer, pathMode, tocOutput)
]
where pathMode = Right [both ("test/fixtures/ruby/method-declaration.A.rb", Just Ruby) ("test/fixtures/ruby/method-declaration.B.rb", Just Ruby)]
patchOutput = "diff --git a/test/fixtures/ruby/method-declaration.A.rb b/test/fixtures/ruby/method-declaration.B.rb\nindex 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644\n--- a/test/fixtures/ruby/method-declaration.A.rb\n+++ b/test/fixtures/ruby/method-declaration.B.rb\n@@ -1,3 +1,4 @@\n-def foo\n+def bar(a)\n+ baz\n end\n\n"
jsonOutput = "{\"diff\":{\"merge\":{\"after\":{\"sourceRange\":[0,21],\"sourceSpan\":{\"start\":[1,1],\"end\":[4,1]}},\"children\":[{\"merge\":{\"after\":{\"sourceRange\":[0,20],\"sourceSpan\":{\"start\":[1,1],\"end\":[3,4]}},\"children\":[{\"merge\":{\"after\":{\"sourceRange\":[0,0],\"sourceSpan\":{\"start\":[1,1],\"end\":[1,1]}},\"children\":[],\"before\":{\"sourceRange\":[0,0],\"sourceSpan\":{\"start\":[1,1],\"end\":[1,1]}}}},{\"patch\":{\"replace\":[{\"children\":[],\"sourceRange\":[4,7],\"sourceSpan\":{\"start\":[1,5],\"end\":[1,8]}},{\"children\":[],\"sourceRange\":[4,7],\"sourceSpan\":{\"start\":[1,5],\"end\":[1,8]}}]}},{\"patch\":{\"insert\":{\"children\":[],\"sourceRange\":[8,9],\"sourceSpan\":{\"start\":[1,9],\"end\":[1,10]}}}},{\"merge\":{\"after\":{\"sourceRange\":[13,16],\"sourceSpan\":{\"start\":[2,3],\"end\":[2,6]}},\"children\":[{\"patch\":{\"insert\":{\"children\":[],\"sourceRange\":[13,16],\"sourceSpan\":{\"start\":[2,3],\"end\":[2,6]}}}}],\"before\":{\"sourceRange\":[8,11],\"sourceSpan\":{\"start\":[2,1],\"end\":[2,4]}}}}],\"before\":{\"sourceRange\":[0,11],\"sourceSpan\":{\"start\":[1,1],\"end\":[2,4]}}}}],\"before\":{\"sourceRange\":[0,12],\"sourceSpan\":{\"start\":[1,1],\"end\":[3,1]}}}},\"oids\":[\"0000000000000000000000000000000000000000\",\"0000000000000000000000000000000000000000\"],\"paths\":[\"test/fixtures/ruby/method-declaration.A.rb\",\"test/fixtures/ruby/method-declaration.B.rb\"]}\n"
sExpressionOutput = "(Program\n (Method\n (Empty)\n { (Identifier)\n ->(Identifier) }\n {+(Identifier)+}\n (\n {+(Identifier)+})))\n"
tocOutput = "{\"changes\":{\"test/fixtures/ruby/method-declaration.A.rb -> test/fixtures/ruby/method-declaration.B.rb\":[{\"span\":{\"start\":[1,1],\"end\":[3,4]},\"category\":\"Method\",\"term\":\"bar\",\"changeType\":\"modified\"}]},\"errors\":{}}\n"

View File

@ -49,6 +49,20 @@ spec = parallel $ do
prop "covers multiple lines" $
\ n -> totalSpan (fromText (Text.intersperse '\n' (Text.replicate n "*"))) `shouldBe` Span (Pos 1 1) (Pos (max 1 n) (if n > 0 then 2 else 1))
describe "newlineIndices" $ do
it "finds \\n" $
let source = "a\nb" in
newlineIndices source `shouldBe` [1]
it "finds \\r" $
let source = "a\rb" in
newlineIndices source `shouldBe` [1]
it "finds \\r\\n" $
let source = "a\r\nb" in
newlineIndices source `shouldBe` [2]
it "finds intermixed line endings" $
let source = "hi\r}\r}\n xxx \r a" in
newlineIndices source `shouldBe` [2, 4, 6, 12]
prop "preserves characters" . forAll (toTiers (list +| [chr 0xa0..chr 0x24f])) $
\ c -> Text.unpack (toText (fromText (Text.singleton c))) `shouldBe` [c]

View File

@ -1,6 +1,5 @@
module Main where
import qualified AlignmentSpec
import qualified CommandSpec
import qualified Data.Functor.Classes.Ord.Generic.Spec
import qualified Data.Mergeable.Spec
@ -8,7 +7,6 @@ import qualified Data.RandomWalkSimilarity.Spec
import qualified Data.Syntax.Assignment.Spec
import qualified DiffSpec
import qualified InterpreterSpec
import qualified PatchOutputSpec
import qualified SES.Spec
import qualified SourceSpec
import qualified TermSpec
@ -23,7 +21,6 @@ main :: IO ()
main = hspec $ do
describe "Semantic.Stat" Semantic.StatSpec.spec
parallel $ do
describe "Alignment" AlignmentSpec.spec
describe "Command" CommandSpec.spec
describe "Data.Functor.Classes.Ord.Generic" Data.Functor.Classes.Ord.Generic.Spec.spec
describe "Data.Mergeable" Data.Mergeable.Spec.spec
@ -31,7 +28,6 @@ main = hspec $ do
describe "Data.Syntax.Assignment" Data.Syntax.Assignment.Spec.spec
describe "Diff" DiffSpec.spec
describe "Interpreter" InterpreterSpec.spec
describe "PatchOutput" PatchOutputSpec.spec
describe "SES" SES.Spec.spec
describe "Source" SourceSpec.spec
describe "Term" TermSpec.spec

View File

@ -67,50 +67,50 @@ spec = parallel $ do
sourceBlobs <- blobsForPaths (both "ruby/methods.A.rb" "ruby/methods.B.rb")
diff <- runTask $ diffWithParser rubyParser sourceBlobs
diffTOC diff `shouldBe`
[ JSONSummary "Method" "self.foo" (sourceSpanBetween (1, 1) (2, 4)) "added"
, JSONSummary "Method" "bar" (sourceSpanBetween (4, 1) (6, 4)) "modified"
, JSONSummary "Method" "baz" (sourceSpanBetween (4, 1) (5, 4)) "removed"
[ TOCSummary "Method" "self.foo" (sourceSpanBetween (1, 1) (2, 4)) "added"
, TOCSummary "Method" "bar" (sourceSpanBetween (4, 1) (6, 4)) "modified"
, TOCSummary "Method" "baz" (sourceSpanBetween (4, 1) (5, 4)) "removed"
]
it "summarizes changed classes" $ do
sourceBlobs <- blobsForPaths (both "ruby/classes.A.rb" "ruby/classes.B.rb")
diff <- runTask $ diffWithParser rubyParser sourceBlobs
diffTOC diff `shouldBe`
[ JSONSummary "Class" "Baz" (sourceSpanBetween (1, 1) (2, 4)) "removed"
, JSONSummary "Class" "Foo" (sourceSpanBetween (1, 1) (3, 4)) "modified"
, JSONSummary "Class" "Bar" (sourceSpanBetween (5, 1) (6, 4)) "added"
[ TOCSummary "Class" "Baz" (sourceSpanBetween (1, 1) (2, 4)) "removed"
, TOCSummary "Class" "Foo" (sourceSpanBetween (1, 1) (3, 4)) "modified"
, TOCSummary "Class" "Bar" (sourceSpanBetween (5, 1) (6, 4)) "added"
]
it "dedupes changes in same parent method" $ do
sourceBlobs <- blobsForPaths (both "javascript/duplicate-parent.A.js" "javascript/duplicate-parent.B.js")
diff <- runTask $ diffWithParser typescriptParser sourceBlobs
diffTOC diff `shouldBe`
[ JSONSummary "Function" "myFunction" (sourceSpanBetween (1, 1) (6, 2)) "modified" ]
[ TOCSummary "Function" "myFunction" (sourceSpanBetween (1, 1) (6, 2)) "modified" ]
it "dedupes similar methods" $ do
sourceBlobs <- blobsForPaths (both "javascript/erroneous-duplicate-method.A.js" "javascript/erroneous-duplicate-method.B.js")
diff <- runTask $ diffWithParser typescriptParser sourceBlobs
diffTOC diff `shouldBe`
[ JSONSummary "Function" "performHealthCheck" (sourceSpanBetween (8, 1) (29, 2)) "modified" ]
[ TOCSummary "Function" "performHealthCheck" (sourceSpanBetween (8, 1) (29, 2)) "modified" ]
it "summarizes Go methods with receivers with special formatting" $ do
sourceBlobs <- blobsForPaths (both "go/method-with-receiver.A.go" "go/method-with-receiver.B.go")
let Just goParser = syntaxParserForLanguage Go
diff <- runTask $ distributeFor sourceBlobs (\ blob -> parse goParser blob >>= decorate (syntaxDeclarationAlgebra blob)) >>= runBothWith (diffTermPair sourceBlobs diffSyntaxTerms)
diffTOC diff `shouldBe`
[ JSONSummary "Method" "(*apiClient) CheckAuth" (sourceSpanBetween (3,1) (3,101)) "added" ]
[ TOCSummary "Method" "(*apiClient) CheckAuth" (sourceSpanBetween (3,1) (3,101)) "added" ]
it "summarizes Ruby methods that start with two identifiers" $ do
sourceBlobs <- blobsForPaths (both "ruby/method-starts-with-two-identifiers.A.rb" "ruby/method-starts-with-two-identifiers.B.rb")
diff <- runTask $ diffWithParser rubyParser sourceBlobs
diffTOC diff `shouldBe`
[ JSONSummary "Method" "foo" (sourceSpanBetween (1, 1) (4, 4)) "modified" ]
[ TOCSummary "Method" "foo" (sourceSpanBetween (1, 1) (4, 4)) "modified" ]
it "handles unicode characters in file" $ do
sourceBlobs <- blobsForPaths (both "ruby/unicode.A.rb" "ruby/unicode.B.rb")
diff <- runTask $ diffWithParser rubyParser sourceBlobs
diffTOC diff `shouldBe`
[ JSONSummary "Method" "foo" (sourceSpanBetween (6, 1) (7, 4)) "added" ]
[ TOCSummary "Method" "foo" (sourceSpanBetween (6, 1) (7, 4)) "added" ]
it "properly slices source blob that starts with a newline and has multi-byte chars" $ do
sourceBlobs <- blobsForPaths (both "javascript/starts-with-newline.js" "javascript/starts-with-newline.js")
@ -146,13 +146,13 @@ spec = parallel $ do
\a -> let term = defaultFeatureVectorDecorator (Info.category . termAnnotation) (a :: Term') in
diffTOC (diffSyntaxTerms term term) `shouldBe` []
describe "JSONSummary" $ do
describe "TOCSummary" $ do
it "encodes modified summaries to JSON" $ do
let summary = JSONSummary "Method" "foo" (sourceSpanBetween (1, 1) (4, 4)) "modified"
let summary = TOCSummary "Method" "foo" (sourceSpanBetween (1, 1) (4, 4)) "modified"
encode summary `shouldBe` "{\"span\":{\"start\":[1,1],\"end\":[4,4]},\"category\":\"Method\",\"term\":\"foo\",\"changeType\":\"modified\"}"
it "encodes added summaries to JSON" $ do
let summary = JSONSummary "Method" "self.foo" (sourceSpanBetween (1, 1) (2, 4)) "added"
let summary = TOCSummary "Method" "self.foo" (sourceSpanBetween (1, 1) (2, 4)) "added"
encode summary `shouldBe` "{\"span\":{\"start\":[1,1],\"end\":[2,4]},\"category\":\"Method\",\"term\":\"self.foo\",\"changeType\":\"added\"}"
describe "diff with ToCDiffRenderer'" $ do
@ -174,7 +174,7 @@ spec = parallel $ do
it "summarizes Markdown headings" $ do
blobs <- blobsForPaths (both "markdown/headings.A.md" "markdown/headings.B.md")
output <- runTask (diffBlobPair ToCDiffRenderer blobs)
toOutput output `shouldBe` ("{\"changes\":{\"test/fixtures/toc/markdown/headings.A.md -> test/fixtures/toc/markdown/headings.B.md\":[{\"span\":{\"start\":[1,1],\"end\":[7,10]},\"category\":\"Heading 1\",\"term\":\"One\",\"changeType\":\"modified\"},{\"span\":{\"start\":[5,1],\"end\":[7,10]},\"category\":\"Heading 2\",\"term\":\"Two\",\"changeType\":\"added\"},{\"span\":{\"start\":[9,1],\"end\":[10,4]},\"category\":\"Heading 1\",\"term\":\"Final\",\"changeType\":\"added\"}]},\"errors\":{}}\n" :: ByteString)
toOutput output `shouldBe` ("{\"changes\":{\"test/fixtures/toc/markdown/headings.A.md -> test/fixtures/toc/markdown/headings.B.md\":[{\"span\":{\"start\":[1,1],\"end\":[3,16]},\"category\":\"Heading 1\",\"term\":\"Introduction\",\"changeType\":\"removed\"},{\"span\":{\"start\":[5,1],\"end\":[7,4]},\"category\":\"Heading 2\",\"term\":\"Two\",\"changeType\":\"modified\"},{\"span\":{\"start\":[9,1],\"end\":[11,10]},\"category\":\"Heading 3\",\"term\":\"This heading is new\",\"changeType\":\"added\"},{\"span\":{\"start\":[13,1],\"end\":[14,4]},\"category\":\"Heading 1\",\"term\":\"Final\",\"changeType\":\"added\"}]},\"errors\":{}}\n" :: ByteString)
type Diff' = Diff Syntax (Record (Maybe Declaration ': DefaultFields)) (Record (Maybe Declaration ': DefaultFields))
@ -187,14 +187,14 @@ numTocSummaries diff = length $ filter isValidSummary (diffTOC diff)
programWithChange :: Term' -> Diff'
programWithChange body = merge (programInfo, programInfo) (Indexed [ function' ])
where
function' = merge ((Just (FunctionDeclaration "foo") :. functionInfo, Just (FunctionDeclaration "foo") :. functionInfo)) (S.Function name' [] [ inserting body ])
function' = merge ((Just (FunctionDeclaration "foo" mempty Nothing) :. functionInfo, Just (FunctionDeclaration "foo" mempty Nothing) :. functionInfo)) (S.Function name' [] [ inserting body ])
name' = let info = Nothing :. Range 0 0 :. C.Identifier :. sourceSpanBetween (0,0) (0,0) :. Nil in merge (info, info) (Leaf "foo")
-- Return a diff where term is inserted in the program, below a function found on both sides of the diff.
programWithChangeOutsideFunction :: Term' -> Diff'
programWithChangeOutsideFunction term = merge (programInfo, programInfo) (Indexed [ function', term' ])
where
function' = merge (Just (FunctionDeclaration "foo") :. functionInfo, Just (FunctionDeclaration "foo") :. functionInfo) (S.Function name' [] [])
function' = merge (Just (FunctionDeclaration "foo" mempty Nothing) :. functionInfo, Just (FunctionDeclaration "foo" mempty Nothing) :. functionInfo) (S.Function name' [] [])
name' = let info = Nothing :. Range 0 0 :. C.Identifier :. sourceSpanBetween (0,0) (0,0) :. Nil in merge (info, info) (Leaf "foo")
term' = inserting term
@ -211,7 +211,7 @@ programOf :: Diff' -> Diff'
programOf diff = merge (programInfo, programInfo) (Indexed [ diff ])
functionOf :: Text -> Term' -> Term'
functionOf name body = Term $ (Just (FunctionDeclaration name) :. functionInfo) `In` S.Function name' [] [body]
functionOf name body = Term $ (Just (FunctionDeclaration name mempty Nothing) :. functionInfo) `In` S.Function name' [] [body]
where
name' = Term $ (Nothing :. Range 0 0 :. C.Identifier :. sourceSpanBetween (0,0) (0,0) :. Nil) `In` Leaf name

View File

@ -1,111 +1,112 @@
(Program
(Class
(Identifier)
{+(Method
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Identifier)+}
{+(RequiredParameter
(
{+(Method
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Assignment
{+(Identifier)+}
{+(Empty)+})+})+}
{+(
{+(Return
{+(Identifier)+})+})+})+}
{+(Method
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Identifier)+}
{+(RequiredParameter
{+(Empty)+}
{+(Empty)+}
{+(Identifier)+}
{+(RequiredParameter
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Assignment
{+(Identifier)+}
{+(Empty)+})+})+}
{+(
{+(Return
{+(Identifier)+})+})+})+}
{+(Method
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Assignment
{+(Identifier)+}
{+(Empty)+})+})+}
{+(
{+(Return
{+(Identifier)+})+})+})+}
{+(Method
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Identifier)+}
{+(RequiredParameter
{+(Empty)+}
{+(Empty)+}
{+(Identifier)+}
{+(RequiredParameter
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Assignment
{+(Identifier)+}
{+(Empty)+})+})+}
{+(
{+(Return
{+(Identifier)+})+})+})+}
{+(Method
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Assignment
{+(Identifier)+}
{+(Empty)+})+})+}
{+(
{+(Return
{+(Identifier)+})+})+})+}
{-(PublicFieldDefinition
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Identifier)-}
{-(Float)-})-}
{-(Method
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Identifier)-}
{-(RequiredParameter
{+(Empty)+}
{+(Empty)+}
{+(Identifier)+}
{+(RequiredParameter
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Assignment
{+(Identifier)+}
{+(Empty)+})+})+}
{+(
{+(Return
{+(Identifier)+})+})+})+}
{-(PublicFieldDefinition
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Assignment
{-(Identifier)-}
{-(Empty)-})-})-}
{-(
{-(Return
{-(Identifier)-})-})-})-}
{-(Method
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Identifier)-}
{-(RequiredParameter
{-(Identifier)-}
{-(Float)-})-}
{-(Method
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Assignment
{-(Identifier)-}
{-(Empty)-})-})-}
{-(
{-(Return
{-(Identifier)-})-})-})-}
{-(Method
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Identifier)-}
{-(RequiredParameter
{-(Empty)-}
{-(Empty)-}
{-(Identifier)-}
{-(RequiredParameter
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Assignment
{-(Identifier)-}
{-(Empty)-})-})-}
{-(
{-(Return
{-(Identifier)-})-})-})-}
{-(Method
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Assignment
{-(Identifier)-}
{-(Empty)-})-})-}
{-(
{-(Return
{-(Identifier)-})-})-})-}))
{-(Empty)-}
{-(Empty)-}
{-(Identifier)-}
{-(RequiredParameter
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Assignment
{-(Identifier)-}
{-(Empty)-})-})-}
{-(
{-(Return
{-(Identifier)-})-})-})-}
{-(Method
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Identifier)-}
{-(RequiredParameter
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Assignment
{-(Identifier)-}
{-(Empty)-})-})-}
{-(
{-(Return
{-(Identifier)-})-})-})-})))

View File

@ -1,63 +1,64 @@
(Program
(Class
(Identifier)
{+(PublicFieldDefinition
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Identifier)+}
{+(Float)+})+}
(Method
(Empty)
(Empty)
(Empty)
(Empty)
(Empty)
{ (Identifier)
->(Identifier) }
(RequiredParameter
(
{+(PublicFieldDefinition
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Identifier)+}
{+(Float)+})+}
(Method
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))
(Method
(Empty)
(Empty)
(Empty)
(Empty)
(Empty)
{ (Identifier)
->(Identifier) }
(RequiredParameter
(Empty)
(Empty)
{ (Identifier)
->(Identifier) }
(RequiredParameter
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))
(Method
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))
(Method
(Empty)
(Empty)
(Empty)
(Empty)
(Empty)
{ (Identifier)
->(Identifier) }
(RequiredParameter
(Empty)
(Empty)
{ (Identifier)
->(Identifier) }
(RequiredParameter
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))
(Method
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))))
(Empty)
(Empty)
{ (Identifier)
->(Identifier) }
(RequiredParameter
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier)))))))

View File

@ -1,60 +1,61 @@
(Program
(Class
(Identifier)
(PublicFieldDefinition
(Empty)
(Empty)
(Empty)
(Identifier)
(Float))
(Method
(Empty)
(Empty)
(Empty)
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(
(PublicFieldDefinition
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))
(Method
(Empty)
(Empty)
(Empty)
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(Identifier)
(Float))
(Method
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))
(Method
(Empty)
(Empty)
(Empty)
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))
(Method
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))))
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))
(Method
(Empty)
(Empty)
(Empty)
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier)))))))

View File

@ -1,54 +1,55 @@
(Program
(Class
(Identifier)
(Method
(Empty)
(Empty)
(Empty)
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(
(Method
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))
(Method
(Empty)
(Empty)
(Empty)
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))
(Method
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))
(Method
(Empty)
(Empty)
(Empty)
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))
(Method
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))))
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier)))))))

View File

@ -3,30 +3,33 @@
{ (Identifier)
->(Identifier) }
{+(Identifier)+}
(Annotation
(Function
{ (Identifier)
->(Identifier) }
(Identifier)
(
(Return
{ (Identifier)
->(Empty) })))
(Empty)))
(
(Annotation
(Function
{ (Identifier)
->(Identifier) }
(Identifier)
(
(Return
{ (Identifier)
->(Empty) })))
(Empty))))
{-(Class
{-(Identifier)-}
{-(NoOp
{-(Empty)-})-})-}
{-(
{-(NoOp
{-(Empty)-})-})-})-}
(Class
(Identifier)
{-(Identifier)-}
(Annotation
(Function
{ (Identifier)
->(Identifier) }
(Identifier)
(
(Return
{ (Empty)
->(Identifier) })))
(Empty))))
(
(Annotation
(Function
{ (Identifier)
->(Identifier) }
(Identifier)
(
(Return
{ (Empty)
->(Identifier) })))
(Empty)))))

View File

@ -3,30 +3,33 @@
{ (Identifier)
->(Identifier) }
{-(Identifier)-}
(Annotation
(Function
{ (Identifier)
->(Identifier) }
(Identifier)
(
(Return
{ (Empty)
->(Identifier) })))
(Empty)))
(
(Annotation
(Function
{ (Identifier)
->(Identifier) }
(Identifier)
(
(Return
{ (Empty)
->(Identifier) })))
(Empty))))
{+(Class
{+(Identifier)+}
{+(NoOp
{+(Empty)+})+})+}
{+(
{+(NoOp
{+(Empty)+})+})+})+}
(Class
(Identifier)
{+(Identifier)+}
(Annotation
(Function
{ (Identifier)
->(Identifier) }
(Identifier)
(
(Return
{ (Identifier)
->(Empty) })))
(Empty))))
(
(Annotation
(Function
{ (Identifier)
->(Identifier) }
(Identifier)
(
(Return
{ (Identifier)
->(Empty) })))
(Empty)))))

View File

@ -1,26 +1,29 @@
(Program
(Class
(Identifier)
(Annotation
(Function
(Identifier)
(Identifier)
(
(Return
(Identifier))))
(Empty)))
(
(Annotation
(Function
(Identifier)
(Identifier)
(
(Return
(Identifier))))
(Empty))))
(Class
(Identifier)
(NoOp
(Empty)))
(
(NoOp
(Empty))))
(Class
(Identifier)
(Identifier)
(Annotation
(Function
(Identifier)
(Identifier)
(
(Return
(Empty))))
(Empty))))
(
(Annotation
(Function
(Identifier)
(Identifier)
(
(Return
(Empty))))
(Empty)))))

View File

@ -2,21 +2,23 @@
(Class
(Identifier)
(Identifier)
(Annotation
(Function
(Identifier)
(Identifier)
(
(Return
(Empty))))
(Empty)))
(
(Annotation
(Function
(Identifier)
(Identifier)
(
(Return
(Empty))))
(Empty))))
(Class
(Identifier)
(Annotation
(Function
(Identifier)
(Identifier)
(
(Return
(Identifier))))
(Empty))))
(
(Annotation
(Function
(Identifier)
(Identifier)
(
(Return
(Identifier))))
(Empty)))))

View File

@ -6,42 +6,38 @@
(Class
{ (Identifier)
->(Identifier) }
(Decorator
(ScopeResolution
(Identifier))
([])
(
(Decorator
(ScopeResolution
{ (Identifier)
->(Identifier) })
(
{+(Identifier)+}
{-(Integer)-})
(Identifier))
([])
(Decorator
(ScopeResolution
{ (Identifier)
->(Identifier) })
(
{+(Identifier)+}
{-(Integer)-}
{-(Integer)-})
(Decorator
(ScopeResolution
(Identifier))
{ (Identifier)
->(Identifier) })
(
{+(Integer)+}
(Assignment
{ (Identifier)
->(Identifier) }
(Boolean))
{+(Identifier)+}
{+(Identifier)+})
{ (Decorator
{-(ScopeResolution
{-(Identifier)-})-}
{-(
{-(Identifier)-})-}
{-(Decorator
{-(Integer)-}
{-(Integer)-})
(Decorator
(ScopeResolution
(Identifier))
(
{+(Integer)+}
(Assignment
{ (Identifier)
->(Identifier) }
(Boolean))
{+(Identifier)+}
{+(Identifier)+})
{ (Decorator
{-(ScopeResolution
{-(Identifier)-})-}
{-(
@ -50,21 +46,26 @@
{-(ScopeResolution
{-(Identifier)-})-}
{-(
{-(Integer)-}
{-(Assignment
{-(Identifier)-}
{-(Boolean)-})-}
{-(Identifier)-}
{-(Identifier)-})-}
{-(Annotation
{-(Function
{-(Decorator
{-(ScopeResolution
{-(Identifier)-})-}
{-(
{-(Integer)-}
{-(Assignment
{-(Identifier)-}
{-(Boolean)-})-}
{-(Identifier)-}
{-(
{-(Identifier)-})-})-}
{-(Empty)-})-})-})-})
->(Annotation
{+(Function
{+(Identifier)+}
{+(
{+(Identifier)+})+})+}
{+(Empty)+}) })))))))
{-(Identifier)-})-}
{-(Annotation
{-(Function
{-(Identifier)-}
{-(
{-(Identifier)-})-})-}
{-(Empty)-})-})-})-})
->(Annotation
{+(Function
{+(Identifier)+}
{+(
{+(Identifier)+})+})+}
{+(Empty)+}) }))))))))

View File

@ -6,50 +6,46 @@
(Class
{ (Identifier)
->(Identifier) }
(Decorator
(ScopeResolution
(Identifier))
([])
(
(Decorator
(ScopeResolution
{ (Identifier)
->(Identifier) })
(
{+(Integer)+}
{-(Identifier)-})
(Identifier))
([])
(Decorator
(ScopeResolution
{ (Identifier)
->(Identifier) })
(
{+(Integer)+}
{+(Integer)+}
{-(Identifier)-})
(Decorator
(ScopeResolution
(Identifier))
{ (Identifier)
->(Identifier) })
(
{+(Assignment
{+(Identifier)+}
{+(Boolean)+})+}
{-(Integer)-}
{-(Assignment
{-(Identifier)-}
{-(Boolean)-})-}
{-(Identifier)-}
{+(Integer)+}
{+(Integer)+}
{-(Identifier)-})
{ (Annotation
{-(Function
(Decorator
(ScopeResolution
(Identifier))
(
{+(Assignment
{+(Identifier)+}
{+(Boolean)+})+}
{-(Integer)-}
{-(Assignment
{-(Identifier)-}
{-(Boolean)-})-}
{-(Identifier)-}
{-(
{-(Identifier)-})-})-}
{-(Empty)-})
->(Decorator
{+(ScopeResolution
{+(Identifier)+})+}
{+(
{+(Identifier)+})+}
{+(Decorator
{-(Identifier)-})
{ (Annotation
{-(Function
{-(Identifier)-}
{-(
{-(Identifier)-})-})-}
{-(Empty)-})
->(Decorator
{+(ScopeResolution
{+(Identifier)+})+}
{+(
@ -58,15 +54,20 @@
{+(ScopeResolution
{+(Identifier)+})+}
{+(
{+(Integer)+}
{+(Assignment
{+(Identifier)+}
{+(Boolean)+})+}
{+(Identifier)+}
{+(Identifier)+})+}
{+(Annotation
{+(Function
{+(Decorator
{+(ScopeResolution
{+(Identifier)+})+}
{+(
{+(Integer)+}
{+(Assignment
{+(Identifier)+}
{+(Boolean)+})+}
{+(Identifier)+}
{+(
{+(Identifier)+})+})+}
{+(Empty)+})+})+})+}) })))))))
{+(Identifier)+})+}
{+(Annotation
{+(Function
{+(Identifier)+}
{+(
{+(Identifier)+})+})+}
{+(Empty)+})+})+})+}) }))))))))

View File

@ -5,33 +5,29 @@
(Identifier))
(Class
(Identifier)
(Decorator
(ScopeResolution
(Identifier))
([])
(
(Decorator
(ScopeResolution
(Identifier))
(
(Integer))
([])
(Decorator
(ScopeResolution
(Identifier))
(
(Integer)
(Integer))
(Decorator
(ScopeResolution
(Identifier))
(
(Assignment
(Identifier)
(Boolean)))
(Integer)
(Integer))
(Decorator
(ScopeResolution
(Identifier))
(
(Identifier))
(Assignment
(Identifier)
(Boolean)))
(Decorator
(ScopeResolution
(Identifier))
@ -41,15 +37,20 @@
(ScopeResolution
(Identifier))
(
(Integer)
(Assignment
(Identifier)
(Boolean))
(Identifier)
(Identifier))
(Annotation
(Function
(Decorator
(ScopeResolution
(Identifier))
(
(Integer)
(Assignment
(Identifier)
(Boolean))
(Identifier)
(
(Identifier)))
(Empty))))))))))))
(Identifier))
(Annotation
(Function
(Identifier)
(
(Identifier)))
(Empty)))))))))))))

View File

@ -5,15 +5,11 @@
(Identifier))
(Class
(Identifier)
(Decorator
(ScopeResolution
(Identifier))
([])
(
(Decorator
(ScopeResolution
(Identifier))
(
(Identifier))
([])
(Decorator
(ScopeResolution
(Identifier))
@ -23,15 +19,20 @@
(ScopeResolution
(Identifier))
(
(Integer)
(Assignment
(Identifier)
(Boolean))
(Identifier)
(Identifier))
(Annotation
(Function
(Decorator
(ScopeResolution
(Identifier))
(
(Integer)
(Assignment
(Identifier)
(Boolean))
(Identifier)
(
(Identifier)))
(Empty)))))))))
(Identifier))
(Annotation
(Function
(Identifier)
(
(Identifier)))
(Empty))))))))))

View File

@ -9,4 +9,5 @@
{-(Class
{-(ScopeResolution
{-(Identifier)-}
{-(Identifier)-})-})-})
{-(Identifier)-})-}
{-([])-})-})

View File

@ -9,4 +9,5 @@
{+(Class
{+(ScopeResolution
{+(Identifier)+}
{+(Identifier)+})+})+})
{+(Identifier)+})+}
{+([])+})+})

View File

@ -9,4 +9,5 @@
(Class
(ScopeResolution
(Identifier)
(Identifier))))
(Identifier))
([])))

View File

@ -1,3 +1,11 @@
# Introduction
one, two, three
# One
Just some text
## Two
abc

View File

@ -4,6 +4,10 @@ Just some text
## Two
xyz
### This heading is new
more text
Final

View File

@ -1,16 +1,19 @@
(Program
{+(AmbientDeclaration
{+(InternalModule
{+(Identifier)+})+})+}
(AmbientDeclaration
{ (Class
{-(Identifier)-}
{-(PublicFieldDefinition
(Class
{ (Identifier)
->(Identifier) }
{ (PublicFieldDefinition
{-(Empty)-}
{-(Empty)-}
{-(Annotation
{-(TypeIdentifier)-})-}
{-(Identifier)-}
{-(Empty)-})-})
->(InternalModule
{+(Identifier)+}) })
{-(Empty)-})
->([]) }))
(AmbientDeclaration
{ (VariableDeclaration
{-(Assignment
@ -18,14 +21,11 @@
{-(PredefinedType)-})-}
{-(Identifier)-}
{-(Empty)-})-})
->(Class
{+(Identifier)+}) })
{+(AmbientDeclaration
{+(InterfaceDeclaration
->(InterfaceDeclaration
{+(Empty)+}
{+(Empty)+}
{+(Identifier)+}
{+(ObjectType)+})+})+}
{+(ObjectType)+}) })
{-(AmbientDeclaration
{-(AmbientFunction
{-(Empty)-}
@ -99,34 +99,35 @@
(AmbientDeclaration
(Class
(Identifier)
(MethodSignature
(Empty)
(Empty)
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(
(MethodSignature
(Empty)
(Empty)
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(Empty)
(Empty)
(Annotation
(PredefinedType))
(Assignment
(Identifier)
(Empty))))
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(PredefinedType))
(Assignment
(Identifier)
(Empty))))
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(PredefinedType))
(Identifier)
(Empty))
(MethodSignature
(Empty)
(Empty)
(Empty)
(Annotation
(PredefinedType))
(Identifier))))
(Identifier)
(Empty))
(MethodSignature
(Empty)
(Empty)
(Empty)
(Annotation
(PredefinedType))
(Identifier)))))
{+(AmbientDeclaration
{+(AmbientFunction
{+(Empty)+}

View File

@ -1,8 +1,6 @@
(Program
(AmbientDeclaration
{ (InternalModule
{-(Identifier)-})
->(Class
{+(AmbientDeclaration
{+(Class
{+(Identifier)+}
{+(PublicFieldDefinition
{+(Empty)+}
@ -10,16 +8,14 @@
{+(Annotation
{+(TypeIdentifier)+})+}
{+(Identifier)+}
{+(Empty)+})+}) })
(AmbientDeclaration
{ (Class
{-(Identifier)-})
->(VariableDeclaration
{+(Empty)+})+})+})+}
{+(AmbientDeclaration
{+(VariableDeclaration
{+(Assignment
{+(Annotation
{+(PredefinedType)+})+}
{+(Identifier)+}
{+(Empty)+})+}) })
{+(Empty)+})+})+})+}
{+(AmbientDeclaration
{+(AmbientFunction
{+(Empty)+}
@ -34,13 +30,8 @@
{+(Assignment
{+(Identifier)+}
{+(Empty)+})+})+})+})+}
(AmbientDeclaration
{ (InterfaceDeclaration
{-(Empty)-}
{-(Empty)-}
{-(Identifier)-}
{-(ObjectType)-})
->(InternalModule
{+(AmbientDeclaration
{+(InternalModule
{+(Identifier)+}
{+(AmbientFunction
{+(Empty)+}
@ -94,38 +85,52 @@
{+(Empty)+}
{+(Annotation
{+(PredefinedType)+})+}
{+(Identifier)+})+})+})+}) })
{+(Identifier)+})+})+})+})+})+}
{-(AmbientDeclaration
{-(InternalModule
{-(Identifier)-})-})-}
{-(AmbientDeclaration
{-(Class
{-(Identifier)-}
{-([])-})-})-}
{-(AmbientDeclaration
{-(InterfaceDeclaration
{-(Empty)-}
{-(Empty)-}
{-(Identifier)-}
{-(ObjectType)-})-})-}
(AmbientDeclaration
(Class
(Identifier)
(MethodSignature
(Empty)
(Empty)
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(
(MethodSignature
(Empty)
(Empty)
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(Empty)
(Empty)
(Annotation
(PredefinedType))
(Assignment
(Identifier)
(Empty))))
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(PredefinedType))
(Assignment
(Identifier)
(Empty))))
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(PredefinedType))
(Identifier)
(Empty))
(MethodSignature
(Empty)
(Empty)
(Empty)
(Annotation
(PredefinedType))
(Identifier))))
(Identifier)
(Empty))
(MethodSignature
(Empty)
(Empty)
(Empty)
(Annotation
(PredefinedType))
(Identifier)))))
{-(AmbientDeclaration
{-(AmbientFunction
{-(Empty)-}

View File

@ -89,31 +89,32 @@
(AmbientDeclaration
(Class
(Identifier)
(MethodSignature
(Empty)
(Empty)
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(
(MethodSignature
(Empty)
(Empty)
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(Empty)
(Empty)
(Annotation
(PredefinedType))
(Assignment
(Identifier)
(Empty))))
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(PredefinedType))
(Assignment
(Identifier)
(Empty))))
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(PredefinedType))
(Identifier)
(Empty))
(MethodSignature
(Empty)
(Empty)
(Empty)
(Annotation
(PredefinedType))
(Identifier)))))
(Identifier)
(Empty))
(MethodSignature
(Empty)
(Empty)
(Empty)
(Annotation
(PredefinedType))
(Identifier))))))

View File

@ -4,7 +4,8 @@
(Identifier)))
(AmbientDeclaration
(Class
(Identifier)))
(Identifier)
([])))
(AmbientDeclaration
(InterfaceDeclaration
(Empty)
@ -14,34 +15,35 @@
(AmbientDeclaration
(Class
(Identifier)
(MethodSignature
(Empty)
(Empty)
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(
(MethodSignature
(Empty)
(Empty)
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(Empty)
(Empty)
(Annotation
(PredefinedType))
(Assignment
(Identifier)
(Empty))))
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(PredefinedType))
(Assignment
(Identifier)
(Empty))))
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(PredefinedType))
(Identifier)
(Empty))
(MethodSignature
(Empty)
(Empty)
(Empty)
(Annotation
(PredefinedType))
(Identifier))))
(Identifier)
(Empty))
(MethodSignature
(Empty)
(Empty)
(Empty)
(Annotation
(PredefinedType))
(Identifier)))))
(AmbientDeclaration
(AmbientFunction
(Empty)

View File

@ -26,4 +26,5 @@
{+(ShorthandPropertyIdentifier)+}
{+(ShorthandPropertyIdentifier)+})+})+})+})+}
{-(Class
{-(Identifier)-})-}))
{-(Identifier)-}
{-([])-})-}))

View File

@ -1,7 +1,8 @@
(Program
(Export
{+(Class
{+(Identifier)+})+}
{+(Identifier)+}
{+([])+})+}
{-(Function
{-(Empty)-}
{-(Empty)-}

View File

@ -1,4 +1,5 @@
(Program
(Export
(Class
(Identifier))))
(Identifier)
([]))))

View File

@ -10,111 +10,112 @@
(ExtendsClause
{ (TypeIdentifier)
->(TypeIdentifier) })
{+(Method
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Identifier)+}
{+(RequiredParameter
(
{+(Method
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Assignment
{+(Identifier)+}
{+(Empty)+})+})+}
{+(
{+(Return
{+(Identifier)+})+})+})+}
{+(Method
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Identifier)+}
{+(RequiredParameter
{+(Empty)+}
{+(Empty)+}
{+(Identifier)+}
{+(RequiredParameter
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Assignment
{+(Identifier)+}
{+(Empty)+})+})+}
{+(
{+(Return
{+(Identifier)+})+})+})+}
{+(Method
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Assignment
{+(Identifier)+}
{+(Empty)+})+})+}
{+(
{+(Return
{+(Identifier)+})+})+})+}
{+(Method
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Identifier)+}
{+(RequiredParameter
{+(Empty)+}
{+(Empty)+}
{+(Identifier)+}
{+(RequiredParameter
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Assignment
{+(Identifier)+}
{+(Empty)+})+})+}
{+(
{+(Return
{+(Identifier)+})+})+})+}
{+(Method
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Assignment
{+(Identifier)+}
{+(Empty)+})+})+}
{+(
{+(Return
{+(Identifier)+})+})+})+}
{-(PublicFieldDefinition
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Identifier)-}
{-(Float)-})-}
{-(Method
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Identifier)-}
{-(RequiredParameter
{+(Empty)+}
{+(Empty)+}
{+(Identifier)+}
{+(RequiredParameter
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Assignment
{+(Identifier)+}
{+(Empty)+})+})+}
{+(
{+(Return
{+(Identifier)+})+})+})+}
{-(PublicFieldDefinition
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Assignment
{-(Identifier)-}
{-(Empty)-})-})-}
{-(
{-(Return
{-(Identifier)-})-})-})-}
{-(Method
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Identifier)-}
{-(RequiredParameter
{-(Identifier)-}
{-(Float)-})-}
{-(Method
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Assignment
{-(Identifier)-}
{-(Empty)-})-})-}
{-(
{-(Return
{-(Identifier)-})-})-})-}
{-(Method
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Identifier)-}
{-(RequiredParameter
{-(Empty)-}
{-(Empty)-}
{-(Identifier)-}
{-(RequiredParameter
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Assignment
{-(Identifier)-}
{-(Empty)-})-})-}
{-(
{-(Return
{-(Identifier)-})-})-})-}
{-(Method
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Assignment
{-(Identifier)-}
{-(Empty)-})-})-}
{-(
{-(Return
{-(Identifier)-})-})-})-}))
{-(Empty)-}
{-(Empty)-}
{-(Identifier)-}
{-(RequiredParameter
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Assignment
{-(Identifier)-}
{-(Empty)-})-})-}
{-(
{-(Return
{-(Identifier)-})-})-})-}
{-(Method
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Identifier)-}
{-(RequiredParameter
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Assignment
{-(Identifier)-}
{-(Empty)-})-})-}
{-(
{-(Return
{-(Identifier)-})-})-})-})))

View File

@ -10,63 +10,64 @@
(ExtendsClause
{ (TypeIdentifier)
->(TypeIdentifier) })
{+(PublicFieldDefinition
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Identifier)+}
{+(Float)+})+}
(Method
(Empty)
(Empty)
(Empty)
(Empty)
(Empty)
{ (Identifier)
->(Identifier) }
(RequiredParameter
(
{+(PublicFieldDefinition
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Identifier)+}
{+(Float)+})+}
(Method
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))
(Method
(Empty)
(Empty)
(Empty)
(Empty)
(Empty)
{ (Identifier)
->(Identifier) }
(RequiredParameter
(Empty)
(Empty)
{ (Identifier)
->(Identifier) }
(RequiredParameter
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))
(Method
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))
(Method
(Empty)
(Empty)
(Empty)
(Empty)
(Empty)
{ (Identifier)
->(Identifier) }
(RequiredParameter
(Empty)
(Empty)
{ (Identifier)
->(Identifier) }
(RequiredParameter
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))
(Method
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))))
(Empty)
(Empty)
{ (Identifier)
->(Identifier) }
(RequiredParameter
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier)))))))

View File

@ -7,60 +7,61 @@
(Identifier)
(ExtendsClause
(TypeIdentifier))
(PublicFieldDefinition
(Empty)
(Empty)
(Empty)
(Identifier)
(Float))
(Method
(Empty)
(Empty)
(Empty)
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(
(PublicFieldDefinition
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))
(Method
(Empty)
(Empty)
(Empty)
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(Identifier)
(Float))
(Method
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))
(Method
(Empty)
(Empty)
(Empty)
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))
(Method
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))))
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))
(Method
(Empty)
(Empty)
(Empty)
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier)))))))

View File

@ -7,54 +7,55 @@
(Identifier)
(ExtendsClause
(TypeIdentifier))
(Method
(Empty)
(Empty)
(Empty)
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(
(Method
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))
(Method
(Empty)
(Empty)
(Empty)
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))
(Method
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))
(Method
(Empty)
(Empty)
(Empty)
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))
(Method
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier))))))
(Empty)
(Empty)
(Identifier)
(RequiredParameter
(Empty)
(Empty)
(Empty)
(Assignment
(Identifier)
(Empty)))
(
(Return
(Identifier)))))))

View File

@ -1,85 +1,86 @@
(Program
(Class
(Identifier)
(PublicFieldDefinition
(Empty)
(Readonly)
(Empty)
(Identifier)
(Empty))
(PublicFieldDefinition
(Empty)
(Readonly)
(Empty)
(Identifier)
(Empty))
(PublicFieldDefinition
(Identifier)
(Readonly)
(Empty)
(Identifier)
(Empty))
(PublicFieldDefinition
(Identifier)
(Readonly)
{+(Annotation
{+(TypeIdentifier)+})+}
{-(Empty)-}
(Identifier)
(Float))
(PublicFieldDefinition
{ (Identifier)
->(Identifier) }
{+(Empty)+}
{-(Readonly)-}
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
{+(Identifier)+}
(Empty)
{-(Readonly)-}
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
{+(Identifier)+}
{-(Empty)-}
(Readonly)
(Annotation
{ (TypeIdentifier)
->(TypeIdentifier) })
(Identifier)
{ (Float)
->(TextElement) })
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(TypeIdentifier))
{ (Identifier)
->(Identifier) }
(Float))
(PublicFieldDefinition
(Empty)
(Empty)
(Empty)
(Identifier)
{ (Float)
->(Float) })))
(
(PublicFieldDefinition
(Empty)
(Readonly)
(Empty)
(Identifier)
(Empty))
(PublicFieldDefinition
(Empty)
(Readonly)
(Empty)
(Identifier)
(Empty))
(PublicFieldDefinition
(Identifier)
(Readonly)
(Empty)
(Identifier)
(Empty))
(PublicFieldDefinition
(Identifier)
(Readonly)
{+(Annotation
{+(TypeIdentifier)+})+}
{-(Empty)-}
(Identifier)
(Float))
(PublicFieldDefinition
{ (Identifier)
->(Identifier) }
{+(Empty)+}
{-(Readonly)-}
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
{+(Identifier)+}
(Empty)
{-(Readonly)-}
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
{+(Identifier)+}
{-(Empty)-}
(Readonly)
(Annotation
{ (TypeIdentifier)
->(TypeIdentifier) })
(Identifier)
{ (Float)
->(TextElement) })
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(TypeIdentifier))
{ (Identifier)
->(Identifier) }
(Float))
(PublicFieldDefinition
(Empty)
(Empty)
(Empty)
(Identifier)
{ (Float)
->(Float) }))))

View File

@ -1,85 +1,86 @@
(Program
(Class
(Identifier)
(PublicFieldDefinition
(Empty)
(Readonly)
(Empty)
(Identifier)
(Empty))
(PublicFieldDefinition
(Empty)
(Readonly)
(Empty)
(Identifier)
(Empty))
(PublicFieldDefinition
(Identifier)
(Readonly)
(Empty)
(Identifier)
(Empty))
(PublicFieldDefinition
(Identifier)
(Readonly)
{+(Empty)+}
{-(Annotation
{-(TypeIdentifier)-})-}
(Identifier)
(Float))
(PublicFieldDefinition
{ (Identifier)
->(Identifier) }
{+(Readonly)+}
{-(Empty)-}
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
{-(Identifier)-}
(Empty)
{+(Readonly)+}
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
{+(Empty)+}
{-(Identifier)-}
(Readonly)
(Annotation
{ (TypeIdentifier)
->(TypeIdentifier) })
(Identifier)
{ (TextElement)
->(Float) })
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(TypeIdentifier))
{ (Identifier)
->(Identifier) }
(Float))
(PublicFieldDefinition
(Empty)
(Empty)
(Empty)
(Identifier)
{ (Float)
->(Float) })))
(
(PublicFieldDefinition
(Empty)
(Readonly)
(Empty)
(Identifier)
(Empty))
(PublicFieldDefinition
(Empty)
(Readonly)
(Empty)
(Identifier)
(Empty))
(PublicFieldDefinition
(Identifier)
(Readonly)
(Empty)
(Identifier)
(Empty))
(PublicFieldDefinition
(Identifier)
(Readonly)
{+(Empty)+}
{-(Annotation
{-(TypeIdentifier)-})-}
(Identifier)
(Float))
(PublicFieldDefinition
{ (Identifier)
->(Identifier) }
{+(Readonly)+}
{-(Empty)-}
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
{-(Identifier)-}
(Empty)
{+(Readonly)+}
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
{+(Empty)+}
{-(Identifier)-}
(Readonly)
(Annotation
{ (TypeIdentifier)
->(TypeIdentifier) })
(Identifier)
{ (TextElement)
->(Float) })
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(TypeIdentifier))
{ (Identifier)
->(Identifier) }
(Float))
(PublicFieldDefinition
(Empty)
(Empty)
(Empty)
(Identifier)
{ (Float)
->(Float) }))))

View File

@ -1,75 +1,76 @@
(Program
(Class
(Identifier)
(PublicFieldDefinition
(Empty)
(Readonly)
(Empty)
(Identifier)
(Empty))
(PublicFieldDefinition
(Empty)
(Readonly)
(Empty)
(Identifier)
(Empty))
(PublicFieldDefinition
(Identifier)
(Readonly)
(Empty)
(Identifier)
(Empty))
(PublicFieldDefinition
(Identifier)
(Readonly)
(Empty)
(Identifier)
(Float))
(PublicFieldDefinition
(Identifier)
(Readonly)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Empty)
(Readonly)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Empty)
(Readonly)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Empty)
(Empty)
(Empty)
(Identifier)
(Float))))
(
(PublicFieldDefinition
(Empty)
(Readonly)
(Empty)
(Identifier)
(Empty))
(PublicFieldDefinition
(Empty)
(Readonly)
(Empty)
(Identifier)
(Empty))
(PublicFieldDefinition
(Identifier)
(Readonly)
(Empty)
(Identifier)
(Empty))
(PublicFieldDefinition
(Identifier)
(Readonly)
(Empty)
(Identifier)
(Float))
(PublicFieldDefinition
(Identifier)
(Readonly)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Empty)
(Readonly)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Empty)
(Readonly)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Empty)
(Empty)
(Empty)
(Identifier)
(Float)))))

View File

@ -1,76 +1,77 @@
(Program
(Class
(Identifier)
(PublicFieldDefinition
(Empty)
(Readonly)
(Empty)
(Identifier)
(Empty))
(PublicFieldDefinition
(Empty)
(Readonly)
(Empty)
(Identifier)
(Empty))
(PublicFieldDefinition
(Identifier)
(Readonly)
(Empty)
(Identifier)
(Empty))
(PublicFieldDefinition
(Identifier)
(Readonly)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Identifier)
(Empty)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Identifier)
(Empty)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Identifier)
(Readonly)
(Annotation
(TypeIdentifier))
(Identifier)
(TextElement))
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Empty)
(Empty)
(Empty)
(Identifier)
(Float))))
(
(PublicFieldDefinition
(Empty)
(Readonly)
(Empty)
(Identifier)
(Empty))
(PublicFieldDefinition
(Empty)
(Readonly)
(Empty)
(Identifier)
(Empty))
(PublicFieldDefinition
(Identifier)
(Readonly)
(Empty)
(Identifier)
(Empty))
(PublicFieldDefinition
(Identifier)
(Readonly)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Identifier)
(Empty)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Identifier)
(Empty)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Identifier)
(Readonly)
(Annotation
(TypeIdentifier))
(Identifier)
(TextElement))
(PublicFieldDefinition
(Empty)
(Empty)
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Empty)
(Empty)
(Empty)
(Identifier)
(Float)))))