1
1
mirror of https://github.com/github/semantic.git synced 2024-12-01 09:15:01 +03:00

Merge branch 'fix-permutation-diffs' into faster-feature-vector-computation

This commit is contained in:
Rob Rix 2017-10-26 13:54:33 -04:00
commit b8234804af
42 changed files with 485 additions and 644 deletions

View File

@ -1,15 +1,31 @@
{-# LANGUAGE DataKinds, RankNTypes, TypeFamilies, TypeOperators #-}
module Data.Diff where
module Data.Diff
( Diff(..)
, DiffF(..)
, replacing
, inserting
, insertF
, deleting
, deleteF
, merge
, mergeF
, merging
, diffPatches
, beforeTerm
, afterTerm
, stripDiff
) where
import Control.Applicative ((<|>))
import Data.Aeson
import Data.Bifoldable
import Data.Bifunctor
import Data.Bitraversable
import Data.Foldable (toList)
import Data.Foldable (asum, toList)
import Data.Functor.Classes
import Data.Functor.Foldable hiding (fold)
import Data.JSON.Fields
import Data.Mergeable
import Data.Mergeable (Mergeable(sequenceAlt))
import Data.Patch
import Data.Record
import Data.Term
@ -61,16 +77,6 @@ merging :: Functor syntax => Term syntax ann -> Diff syntax ann ann
merging = cata (\ (In ann syntax) -> mergeF (In (ann, ann) syntax))
diffSum :: (Foldable syntax, Functor syntax) => (forall a b. Patch a b -> Int) -> Diff syntax ann1 ann2 -> Int
diffSum patchCost = cata $ \ diff -> case diff of
Patch patch -> patchCost patch + sum (sum <$> patch)
Merge merge -> sum merge
-- | The sum of the node count of the diffs patches.
diffCost :: (Foldable syntax, Functor syntax) => Diff syntax ann1 ann2 -> Int
diffCost = diffSum (const 1)
diffPatch :: Diff syntax ann1 ann2 -> Maybe (Patch (TermF syntax ann1 (Diff syntax ann1 ann2)) (TermF syntax ann2 (Diff syntax ann1 ann2)))
diffPatch diff = case unDiff diff of
Patch patch -> Just patch
@ -82,21 +88,17 @@ diffPatches = para $ \ diff -> case diff of
Merge merge -> foldMap (toList . diffPatch . fst) merge
-- | Merge a diff using a function to provide the Term (in Maybe, to simplify recovery of the before/after state) for every Patch.
mergeMaybe :: (Mergeable syntax, Traversable syntax) => (DiffF syntax ann1 ann2 (Maybe (Term syntax combined)) -> Maybe (Term syntax combined)) -> Diff syntax ann1 ann2 -> Maybe (Term syntax combined)
mergeMaybe = cata
-- | Recover the before state of a diff.
beforeTerm :: (Mergeable syntax, Traversable syntax) => Diff syntax ann1 ann2 -> Maybe (Term syntax ann1)
beforeTerm = mergeMaybe $ \ diff -> case diff of
Patch patch -> before patch >>= \ (In a l) -> termIn a <$> sequenceAlt l
Merge (In (a, _) l) -> termIn a <$> sequenceAlt l
beforeTerm = cata $ \ diff -> case diff of
Patch patch -> (before patch >>= \ (In a l) -> termIn a <$> sequenceAlt l) <|> (after patch >>= asum)
Merge (In (a, _) l) -> termIn a <$> sequenceAlt l
-- | Recover the after state of a diff.
afterTerm :: (Mergeable syntax, Traversable syntax) => Diff syntax ann1 ann2 -> Maybe (Term syntax ann2)
afterTerm = mergeMaybe $ \ diff -> case diff of
Patch patch -> after patch >>= \ (In b r) -> termIn b <$> sequenceAlt r
Merge (In (_, b) r) -> termIn b <$> sequenceAlt r
afterTerm = cata $ \ diff -> case diff of
Patch patch -> (after patch >>= \ (In b r) -> termIn b <$> sequenceAlt r) <|> (before patch >>= asum)
Merge (In (_, b) r) -> termIn b <$> sequenceAlt r
-- | Strips the head annotation off a diff annotated with non-empty records.

View File

@ -37,7 +37,8 @@ instance Mergeable [] where
merge _ [] = pure []
instance Mergeable NonEmpty where
merge f (x:|xs) = (:|) <$> f x <*> merge f xs
merge f (x:|[]) = (:|) <$> f x <*> pure []
merge f (x1:|x2:xs) = (:|) <$> f x1 <*> merge f (x2 : xs) <|> merge f (x2:|xs)
instance Mergeable Maybe where
merge f (Just a) = Just <$> f a

View File

@ -50,10 +50,10 @@ instance {-# OVERLAPPABLE #-} HasField (field ': fields) field where
instance (Show h, Show (Record t)) => Show (Record (h ': t)) where
showsPrec n (h :. t) = showParen (n > 0) $ showsPrec 1 h . (" :. " <>) . shows t
showsPrec n (h :. t) = showParen (n > 0) $ showsPrec 1 h . showString " :. " . showsPrec 0 t
instance Show (Record '[]) where
showsPrec n Nil = showParen (n > 0) ("Nil" <>)
showsPrec _ Nil = showString "Nil"
instance (Eq h, Eq (Record t)) => Eq (Record (h ': t)) where
(h1 :. t1) == (h2 :. t2) = h1 == h2 && t1 == t2

View File

@ -1,6 +1,8 @@
{-# LANGUAGE GADTs, DataKinds, RankNTypes, TypeOperators #-}
module RWS
( rws
, Options(..)
, defaultOptions
, ComparabilityRelation
, FeatureVector(..)
, defaultFeatureVectorDecorator
@ -14,7 +16,8 @@ module RWS
import Control.Applicative (empty)
import Control.Arrow ((&&&))
import Control.Monad.Random
import Control.Monad (replicateM)
import Control.Monad.Random.Strict
import Control.Monad.State.Strict
import Data.Align.Generic
import Data.Array.Unboxed
@ -24,8 +27,7 @@ import Data.Function ((&))
import Data.Functor.Classes
import Data.Functor.Foldable
import Data.Hashable
import qualified Data.IntMap as IntMap
import Data.KdMap.Static hiding (elems, empty)
import qualified Data.KdMap.Static as KdMap
import Data.List (sortOn)
import Data.Maybe
import Data.Record
@ -46,219 +48,76 @@ type ComparabilityRelation syntax ann1 ann2 = forall a b. TermF syntax ann1 a ->
newtype FeatureVector = FV { unFV :: UArray Int Double }
deriving (Eq, Ord, Show)
-- | A term which has not yet been mapped by `rws`, along with its feature vector summary & index.
data UnmappedTerm syntax ann = UnmappedTerm
{ termIndex :: {-# UNPACK #-} !Int -- ^ The index of the term within its root term.
, feature :: {-# UNPACK #-} !FeatureVector -- ^ Feature vector
, term :: Term syntax ann -- ^ The unmapped term
}
-- | Either a `term`, an index of a matched term, or nil.
data TermOrIndexOrNone term = Term term | Index {-# UNPACK #-} !Int | None
rws :: (Foldable syntax, Functor syntax, GAlign syntax)
=> ComparabilityRelation syntax (Record (FeatureVector ': fields1)) (Record (FeatureVector ': fields2))
-> (Term syntax (Record (FeatureVector ': fields1)) -> Term syntax (Record (FeatureVector ': fields2)) -> Bool)
-> [Term syntax (Record (FeatureVector ': fields1))]
-> [Term syntax (Record (FeatureVector ': fields2))]
-> RWSEditScript syntax (Record (FeatureVector ': fields1)) (Record (FeatureVector ': fields2))
-> EditScript (Term syntax (Record (FeatureVector ': fields1))) (Term syntax (Record (FeatureVector ': fields2)))
rws _ _ as [] = This <$> as
rws _ _ [] bs = That <$> bs
rws canCompare _ [a] [b] = if canCompareTerms canCompare a b then [These a b] else [That b, This a]
rws canCompare equivalent as bs =
let sesDiffs = ses equivalent as bs
(featureAs, featureBs, mappedDiffs, allDiffs) = genFeaturizedTermsAndDiffs sesDiffs
(diffs, remaining) = findNearestNeighboursToDiff canCompare allDiffs featureAs featureBs
diffs' = deleteRemaining diffs remaining
rwsDiffs = insertMapped mappedDiffs diffs'
in fmap snd rwsDiffs
rws canCompare equivalent as bs
= ses equivalent as bs
& mapContiguous [] []
where Options{..} = defaultOptions
-- | An IntMap of unmapped terms keyed by their position in a list of terms.
type UnmappedTerms syntax ann = IntMap.IntMap (UnmappedTerm syntax ann)
-- Map contiguous sequences of unmapped terms separated by SES-mapped equivalencies.
mapContiguous as bs [] = mapSimilar (reverse as) (reverse bs)
mapContiguous as bs (first : rest) = case first of
This a -> mapContiguous (a : as) bs rest
That b -> mapContiguous as (b : bs) rest
These _ _ -> mapSimilar (reverse as) (reverse bs) <> (first : mapContiguous [] [] rest)
type Edit syntax ann1 ann2 = These (Term syntax ann1) (Term syntax ann2)
-- Map comparable, mutually similar terms, inserting & deleting surrounding terms.
mapSimilar as' bs' = go as bs
where go as [] = This . snd <$> as
go [] bs = That . snd <$> bs
go [a] [b] | canCompareTerms canCompare (snd a) (snd b) = [These (snd a) (snd b)]
| otherwise = [That (snd b), This (snd a)]
go as@((i, _) : _) ((j, b) : restB) =
fromMaybe (That b : go as restB) $ do
-- Look up the most similar term to b near i.
(i', a) <- mostSimilarMatching (\ i' a -> inRange (i, i + optionsLookaheadPlaces) i' && canCompareTerms canCompare a b) kdMapA b
-- Look up the most similar term to a near j.
(j', _) <- mostSimilarMatching (\ j' b -> inRange (j, j + optionsLookaheadPlaces) j' && canCompareTerms canCompare a b) kdMapB a
-- Fail out if theres a better match for a nearby.
guard (j == j')
-- Delete any elements of as before the selected element.
let (deleted, _ : restA) = span ((< i') . fst) as
pure $! (This . snd <$> deleted) <> (These a b : go restA restB)
(as, bs) = (zip [0..] as', zip [0..] bs')
(kdMapA, kdMapB) = (toKdMap as, toKdMap bs)
-- A Diff paired with both its indices
type MappedDiff syntax ann1 ann2 = (These Int Int, Edit syntax ann1 ann2)
-- Find the most similar term matching a predicate, if any.
--
-- RWS can produce false positives in the case of e.g. hash collisions. Therefore, we find the _l_ nearest candidates, filter out any which dont match the predicate, and select the minimum of the remaining by (a constant-time approximation of) edit distance.
--
-- cf §4.2 of RWS-Diff
mostSimilarMatching isEligible tree term = listToMaybe (sortOn (editDistanceUpTo optionsNodeComparisons term . snd) candidates)
where candidates = filter (uncurry isEligible) (snd <$> KdMap.kNearest tree optionsMaxSimilarTerms (rhead (extract term)))
type RWSEditScript syntax ann1 ann2 = [Edit syntax ann1 ann2]
data Options = Options
{ optionsLookaheadPlaces :: {-# UNPACK #-} !Int -- ^ How many places ahead should we look for similar terms?
, optionsMaxSimilarTerms :: {-# UNPACK #-} !Int -- ^ The maximum number of similar terms to consider.
, optionsNodeComparisons :: {-# UNPACK #-} !Int -- ^ The number of nodes to compare when selecting the most similar term.
}
insertMapped :: Foldable t
=> t (MappedDiff syntax ann1 ann2)
-> [MappedDiff syntax ann1 ann2]
-> [MappedDiff syntax ann1 ann2]
insertMapped diffs into = foldl' (flip insertDiff) into diffs
defaultOptions :: Options
defaultOptions = Options
{ optionsLookaheadPlaces = 0
, optionsMaxSimilarTerms = 2
, optionsNodeComparisons = 10
}
deleteRemaining :: Traversable t
=> [MappedDiff syntax ann1 ann2]
-> t (UnmappedTerm syntax ann1)
-> [MappedDiff syntax ann1 ann2]
deleteRemaining diffs unmappedAs =
foldl' (flip insertDiff) diffs ((This . termIndex &&& This . term) <$> unmappedAs)
-- | Inserts an index and diff pair into a list of indices and diffs.
insertDiff :: MappedDiff syntax ann1 ann2
-> [MappedDiff syntax ann1 ann2]
-> [MappedDiff syntax ann1 ann2]
insertDiff inserted [] = [ inserted ]
insertDiff a@(ij1, _) (b@(ij2, _):rest) = case (ij1, ij2) of
(These i1 i2, These j1 j2) -> if i1 <= j1 && i2 <= j2 then a : b : rest else b : insertDiff a rest
(This i, This j) -> if i <= j then a : b : rest else b : insertDiff a rest
(That i, That j) -> if i <= j then a : b : rest else b : insertDiff a rest
(This i, These j _) -> if i <= j then a : b : rest else b : insertDiff a rest
(That i, These _ j) -> if i <= j then a : b : rest else b : insertDiff a rest
(This _, That _) -> b : insertDiff a rest
(That _, This _) -> b : insertDiff a rest
(These i1 i2, _) -> case break (isThese . fst) rest of
(rest, tail) -> let (before, after) = foldr' (combine i1 i2) ([], []) (b : rest) in
case after of
[] -> before <> insertDiff a tail
_ -> before <> (a : after) <> tail
where
combine i1 i2 each (before, after) = case fst each of
This j1 -> if i1 <= j1 then (before, each : after) else (each : before, after)
That j2 -> if i2 <= j2 then (before, each : after) else (each : before, after)
These _ _ -> (before, after)
findNearestNeighboursToDiff :: (Foldable syntax, Functor syntax, GAlign syntax)
=> ComparabilityRelation syntax ann1 ann2 -- ^ A relation determining whether two terms can be compared.
-> [TermOrIndexOrNone (UnmappedTerm syntax ann2)]
-> [UnmappedTerm syntax ann1]
-> [UnmappedTerm syntax ann2]
-> ([MappedDiff syntax ann1 ann2], UnmappedTerms syntax ann1)
findNearestNeighboursToDiff canCompare allDiffs featureAs featureBs = (diffs, remaining)
where
(diffs, (_, remaining, _)) =
traverse (findNearestNeighbourToDiff' canCompare (toKdMap featureAs) (toKdMap featureBs)) allDiffs &
fmap catMaybes &
(`runState` (minimumTermIndex featureAs, toMap featureAs, toMap featureBs))
findNearestNeighbourToDiff' :: (Foldable syntax, Functor syntax, GAlign syntax)
=> ComparabilityRelation syntax ann1 ann2 -- ^ A relation determining whether two terms can be compared.
-> KdMap Double FeatureVector (UnmappedTerm syntax ann1)
-> KdMap Double FeatureVector (UnmappedTerm syntax ann2)
-> TermOrIndexOrNone (UnmappedTerm syntax ann2)
-> State (Int, UnmappedTerms syntax ann1, UnmappedTerms syntax ann2)
(Maybe (MappedDiff syntax ann1 ann2))
findNearestNeighbourToDiff' canCompare kdTreeA kdTreeB termThing = case termThing of
None -> pure Nothing
RWS.Term term -> Just <$> findNearestNeighbourTo canCompare kdTreeA kdTreeB term
Index i -> modify' (\ (_, unA, unB) -> (i, unA, unB)) >> pure Nothing
-- | Construct a diff for a term in B by matching it against the most similar eligible term in A (if any), marking both as ineligible for future matches.
findNearestNeighbourTo :: (Foldable syntax, Functor syntax, GAlign syntax)
=> ComparabilityRelation syntax ann1 ann2 -- ^ A relation determining whether two terms can be compared.
-> KdMap Double FeatureVector (UnmappedTerm syntax ann1)
-> KdMap Double FeatureVector (UnmappedTerm syntax ann2)
-> UnmappedTerm syntax ann2
-> State (Int, UnmappedTerms syntax ann1, UnmappedTerms syntax ann2)
(MappedDiff syntax ann1 ann2)
findNearestNeighbourTo canCompare kdTreeA kdTreeB term@(UnmappedTerm j _ b) = do
(previous, unmappedA, unmappedB) <- get
fromMaybe (insertion previous unmappedA unmappedB term) $ do
-- Look up the nearest unmapped term in `unmappedA`.
foundA@(UnmappedTerm i _ a) <- nearestUnmapped canCompare (termsWithinMoveBoundsFrom previous unmappedA) kdTreeA term
-- Look up the nearest `foundA` in `unmappedB`
UnmappedTerm j' _ _ <- nearestUnmapped (flip canCompare) (termsWithinMoveBoundsFrom (pred j) unmappedB) kdTreeB foundA
-- Return Nothing if their indices don't match
guard (j == j')
guard (canCompareTerms canCompare a b)
pure $! do
put (i, IntMap.delete i unmappedA, IntMap.delete j unmappedB)
pure (These i j, These a b)
where termsWithinMoveBoundsFrom bound = IntMap.filterWithKey (\ k _ -> isInMoveBounds bound k)
isInMoveBounds :: Int -> Int -> Bool
isInMoveBounds previous i = previous < i && i < previous + defaultMoveBound
-- | Finds the most-similar unmapped term to the passed-in term, if any.
--
-- RWS can produce false positives in the case of e.g. hash collisions. Therefore, we find the _l_ nearest candidates, filter out any which have already been mapped, and select the minimum of the remaining by (a constant-time approximation of) edit distance.
--
-- cf §4.2 of RWS-Diff
nearestUnmapped :: (Foldable syntax, Functor syntax, GAlign syntax)
=> ComparabilityRelation syntax ann1 ann2 -- ^ A relation determining whether two terms can be compared.
-> UnmappedTerms syntax ann1 -- ^ A set of terms eligible for matching against.
-> KdMap Double FeatureVector (UnmappedTerm syntax ann1) -- ^ The k-d tree to look up nearest neighbours within.
-> UnmappedTerm syntax ann2 -- ^ The term to find the nearest neighbour to.
-> Maybe (UnmappedTerm syntax ann1) -- ^ The most similar unmapped term, if any.
nearestUnmapped canCompare unmapped tree key = listToMaybe (sortOn approximateEditDistance candidates)
where candidates = toList (IntMap.intersection unmapped (toMap (fmap snd (kNearest tree defaultL (feature key)))))
approximateEditDistance = editDistanceIfComparable (flip canCompare) (term key) . term
editDistanceIfComparable :: (Foldable syntax, Functor syntax, GAlign syntax)
=> ComparabilityRelation syntax ann1 ann2
-> Term syntax ann1
-> Term syntax ann2
-> Int
editDistanceIfComparable canCompare a b = if canCompareTerms canCompare a b
then editDistanceUpTo defaultM (These a b)
else maxBound
defaultD, defaultL, defaultP, defaultQ, defaultMoveBound :: Int
defaultD, defaultP, defaultQ :: Int
defaultD = 15
defaultL = 2
defaultP = 2
defaultQ = 3
defaultMoveBound = 2
-- Returns a state (insertion index, old unmapped terms, new unmapped terms), and value of (index, inserted diff),
-- given a previous index, two sets of umapped terms, and an unmapped term to insert.
insertion :: Int
-> UnmappedTerms syntax ann1
-> UnmappedTerms syntax ann2
-> UnmappedTerm syntax ann2
-> State (Int, UnmappedTerms syntax ann1, UnmappedTerms syntax ann2)
(MappedDiff syntax ann1 ann2)
insertion previous unmappedA unmappedB (UnmappedTerm j _ b) = do
put (previous, unmappedA, IntMap.delete j unmappedB)
pure (That j, That b)
genFeaturizedTermsAndDiffs :: Functor syntax
=> RWSEditScript syntax (Record (FeatureVector ': fields1)) (Record (FeatureVector ': fields2))
-> ( [UnmappedTerm syntax (Record (FeatureVector ': fields1))]
, [UnmappedTerm syntax (Record (FeatureVector ': fields2))]
, [MappedDiff syntax (Record (FeatureVector ': fields1)) (Record (FeatureVector ': fields2))]
, [TermOrIndexOrNone (UnmappedTerm syntax (Record (FeatureVector ': fields2)))]
)
genFeaturizedTermsAndDiffs sesDiffs = let Mapping _ _ a b c d = foldl' combine (Mapping 0 0 [] [] [] []) sesDiffs in (reverse a, reverse b, reverse c, reverse d)
where combine (Mapping counterA counterB as bs mappedDiffs allDiffs) diff = case diff of
This term -> Mapping (succ counterA) counterB (featurize counterA term : as) bs mappedDiffs (None : allDiffs)
That term -> Mapping counterA (succ counterB) as (featurize counterB term : bs) mappedDiffs (RWS.Term (featurize counterB term) : allDiffs)
These a b -> Mapping (succ counterA) (succ counterB) as bs ((These counterA counterB, These a b) : mappedDiffs) (Index counterA : allDiffs)
data Mapping syntax ann1 ann2
= Mapping
{-# UNPACK #-} !Int
{-# UNPACK #-} !Int
![UnmappedTerm syntax ann1]
![UnmappedTerm syntax ann2]
![MappedDiff syntax ann1 ann2]
![TermOrIndexOrNone (UnmappedTerm syntax ann2)]
featurize :: Functor syntax => Int -> Term syntax (Record (FeatureVector ': fields)) -> UnmappedTerm syntax (Record (FeatureVector ': fields))
featurize index term = UnmappedTerm index (getField (extract term)) (eraseFeatureVector term)
eraseFeatureVector :: Functor syntax => Term syntax (Record (FeatureVector ': fields)) -> Term syntax (Record (FeatureVector ': fields))
eraseFeatureVector (Term.Term (In record functor)) = termIn (setFeatureVector record nullFeatureVector) functor
nullFeatureVector :: FeatureVector
nullFeatureVector = FV $ listArray (0, 0) [0]
setFeatureVector :: Record (FeatureVector ': fields) -> FeatureVector -> Record (FeatureVector ': fields)
setFeatureVector = setField
minimumTermIndex :: [UnmappedTerm syntax ann] -> Int
minimumTermIndex = pred . maybe 0 getMin . getOption . foldMap (Option . Just . Min . termIndex)
toMap :: [UnmappedTerm syntax ann] -> IntMap.IntMap (UnmappedTerm syntax ann)
toMap = IntMap.fromList . fmap (termIndex &&& id)
toKdMap :: [UnmappedTerm syntax ann] -> KdMap Double FeatureVector (UnmappedTerm syntax ann)
toKdMap = build (elems . unFV) . fmap (feature &&& id)
toKdMap :: Functor syntax => [(Int, Term syntax (Record (FeatureVector ': fields)))] -> KdMap.KdMap Double FeatureVector (Int, Term syntax (Record (FeatureVector ': fields)))
toKdMap = KdMap.build (elems . unFV) . fmap (rhead . extract . snd &&& id)
-- | A `Gram` is a fixed-size view of some portion of a tree, consisting of a `stem` of _p_ labels for parent nodes, and a `base` of _q_ labels of sibling nodes. Collectively, the bag of `Gram`s for each node of a tree (e.g. as computed by `pqGrams`) form a summary of the tree.
data Gram label = Gram { stem :: [Maybe label], base :: [Maybe label] }
@ -316,7 +175,7 @@ unitVector :: Int -> Int -> FeatureVector
unitVector d hash = FV $ listArray (0, d - 1) ((* invMagnitude) <$> components)
where
invMagnitude = 1 / sqrt (sum (fmap (** 2) components))
components = evalRand (sequenceA (replicate d (liftRand randomDouble))) (pureMT (fromIntegral hash))
components = evalRand (replicateM d (liftRand randomDouble)) (pureMT (fromIntegral hash))
-- | Test the comparability of two root 'Term's in O(1).
canCompareTerms :: ComparabilityRelation syntax ann1 ann2 -> Term syntax ann1 -> Term syntax ann2 -> Bool
@ -328,14 +187,11 @@ equalTerms canCompare = go
where go a b = canCompareTerms canCompare a b && liftEq go (termOut (unTerm a)) (termOut (unTerm b))
-- | How many nodes to consider for our constant-time approximation to tree edit distance.
defaultM :: Integer
defaultM = 10
-- | Return an edit distance as the sum of it's term sizes, given an cutoff and a syntax of terms 'f a'.
-- | Computes a constant-time approximation to the edit distance of a diff. This is done by comparing at most _m_ nodes, & assuming the rest are zero-cost.
editDistanceUpTo :: (GAlign syntax, Foldable syntax, Functor syntax) => Integer -> Edit syntax ann1 ann2 -> Int
editDistanceUpTo m = these termSize termSize (\ a b -> diffCost m (approximateDiff a b))
-- | Return an edit distance between two terms, up to a certain depth.
--
-- Computes a constant-time approximation to the edit distance of a diff. This is done by comparing at most _m_ nodes, & assuming the rest are zero-cost.
editDistanceUpTo :: (GAlign syntax, Foldable syntax, Functor syntax) => Int -> Term syntax ann1 -> Term syntax ann2 -> Int
editDistanceUpTo m a b = diffCost m (approximateDiff a b)
where diffCost = flip . cata $ \ diff m -> case diff of
_ | m <= 0 -> 0
Merge body -> sum (fmap ($ pred m) body)

View File

@ -299,6 +299,9 @@ instance (Listable1 f, Listable1 (Union (g ': fs))) => Listable1 (Union (f ': g
instance Listable1 f => Listable1 (Union '[f]) where
liftTiers tiers = inj `mapT` ((liftTiers :: [Tier a] -> [Tier (f a)]) tiers)
instance (Listable1 (Union fs), Listable a) => Listable (Union fs a) where
tiers = tiers1
instance Listable1 Comment.Comment where
liftTiers _ = cons1 Comment.Comment

View File

@ -6,6 +6,7 @@ import Data.Functor.Identity
import Data.Functor.Listable
import Data.Maybe (catMaybes)
import Data.Mergeable
import Data.Syntax
import Syntax
import Test.Hspec
import Test.Hspec.LeanCheck
@ -22,6 +23,9 @@ spec = parallel $ do
describe "Identity" $ do
withAlternativeInstances sequenceAltLaws (Identity `mapT` tiers :: [Tier (Identity Char)])
withAlternativeInstances mergeLaws (Identity `mapT` tiers :: [Tier (Identity Char)])
describe "Union" $ do
withAlternativeInstances sequenceAltLaws (tiers :: [Tier (ListableSyntax Char)])
withAlternativeInstances mergeLaws (tiers :: [Tier (ListableSyntax Char)])
describe "Syntax" $ do
withAlternativeInstances sequenceAltLaws (tiers :: [Tier (Syntax Char)])
withAlternativeInstances mergeLaws (tiers :: [Tier (Syntax Char)])

View File

@ -2,14 +2,8 @@
module DiffSpec where
import Data.Diff
import Data.Functor.Both
import Data.Functor.Foldable (cata)
import Data.Functor.Listable (ListableSyntax)
import Data.Record
import Data.Term
import Data.Union
import Interpreter
import RWS
import Test.Hspec
import Test.Hspec.LeanCheck
@ -17,28 +11,3 @@ spec :: Spec
spec = parallel $ do
prop "equality is reflexive" $
\ diff -> diff `shouldBe` (diff :: Diff ListableSyntax (Record '[]) (Record '[]))
prop "equal terms produce identity diffs" $
\ term -> diffCost (diffTerms term (term :: Term ListableSyntax (Record '[]))) `shouldBe` 0
describe "beforeTerm" $ do
prop "recovers the before term" $
\ a b -> let diff = diffTerms a b :: Diff ListableSyntax (Record '[]) (Record '[]) in
beforeTerm diff `shouldBe` Just a
describe "afterTerm" $ do
prop "recovers the after term" $
\ a b -> let diff = diffTerms a b :: Diff ListableSyntax (Record '[]) (Record '[]) in
afterTerm diff `shouldBe` Just b
prop "forward permutations are changes" $ pendingWith "https://github.com/github/semantic-diff/issues/1359"
-- \ a -> let wrap = termIn Nil . inj
-- b = wrap [a]
-- c = wrap [a, b] in
-- diffTerms (wrap [a, b, c]) (wrap [c, a, b :: Term ListableSyntax (Record '[])]) `shouldBe` merge (Nil, Nil) (inj [ inserting c, merging a, merging b, deleting c ])
prop "backward permutations are changes" $
\ a -> let wrap = termIn Nil . inj
b = wrap [a]
c = wrap [a, b] in
diffTerms (wrap [a, b, c]) (wrap [b, c, a :: Term ListableSyntax (Record '[])]) `shouldBe` merge (Nil, Nil) (inj [ deleting a, merging b, merging c, inserting a ])

View File

@ -26,7 +26,7 @@ spec = parallel $ do
describe "go" $ runTestsIn "test/fixtures/go/" []
describe "javascript" $ runTestsIn "test/fixtures/javascript/" []
describe "python" $ runTestsIn "test/fixtures/python/" [ ("test/fixtures/python/while-statement.diffB-A.txt", "https://github.com/github/semantic-diff/issues/1359") ]
describe "python" $ runTestsIn "test/fixtures/python/" []
describe "ruby" $ runTestsIn "test/fixtures/ruby/" []
describe "typescript" $ runTestsIn "test/fixtures/typescript/" []

View File

@ -16,7 +16,7 @@ import Test.Hspec.LeanCheck
spec :: Spec
spec = parallel $ do
describe "interpret" $ do
describe "diffTerms" $ do
it "returns a replacement when comparing two unicode equivalent terms" $
let termA = termIn Nil (inj (Syntax.Identifier "t\776"))
termB = termIn Nil (inj (Syntax.Identifier "\7831")) in
@ -26,9 +26,9 @@ spec = parallel $ do
\ a b -> let diff = diffTerms a b :: Diff ListableSyntax (Record '[]) (Record '[]) in
(beforeTerm diff, afterTerm diff) `shouldBe` (Just a, Just b)
prop "constructs zero-cost diffs of equal terms" $
prop "produces identity diffs for equal terms " $
\ a -> let diff = diffTerms a a :: Diff ListableSyntax (Record '[]) (Record '[]) in
diffCost diff `shouldBe` 0
length (diffPatches diff) `shouldBe` 0
it "produces unbiased insertions within branches" $
let term s = termIn Nil (inj [ termIn Nil (inj (Syntax.Identifier s)) ]) :: Term ListableSyntax (Record '[])
@ -37,3 +37,15 @@ spec = parallel $ do
prop "compares nodes against context" $
\ a b -> diffTerms a (termIn Nil (inj (Syntax.Context (pure b) a))) `shouldBe` insertF (In Nil (inj (Syntax.Context (pure (inserting b)) (merging (a :: Term ListableSyntax (Record '[]))))))
prop "diffs forward permutations as changes" $
\ a -> let wrap = termIn Nil . inj
b = wrap [a]
c = wrap [a, b] in
diffTerms (wrap [a, b, c]) (wrap [c, a, b :: Term ListableSyntax (Record '[])]) `shouldBe` merge (Nil, Nil) (inj [ inserting c, merging a, merging b, deleting c ])
prop "diffs backward permutations as changes" $
\ a -> let wrap = termIn Nil . inj
b = wrap [a]
c = wrap [a, b] in
diffTerms (wrap [a, b, c]) (wrap [b, c, a :: Term ListableSyntax (Record '[])]) `shouldBe` merge (Nil, Nil) (inj [ deleting a, merging b, merging c, inserting a ])

View File

@ -66,8 +66,10 @@ 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)) "modified"
, JSONSummary "Method" "bar" (sourceSpanBetween (4, 1) (6, 4)) "modified" ]
[ 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"
]
it "dedupes changes in same parent method" $ do
sourceBlobs <- blobsForPaths (both "javascript/duplicate-parent.A.js" "javascript/duplicate-parent.B.js")
@ -147,7 +149,7 @@ spec = parallel $ do
it "produces JSON output" $ do
blobs <- blobsForPaths (both "ruby/methods.A.rb" "ruby/methods.B.rb")
output <- runTask (diffBlobPair ToCDiffRenderer blobs)
toOutput output `shouldBe` ("{\"changes\":{\"test/fixtures/toc/ruby/methods.A.rb -> test/fixtures/toc/ruby/methods.B.rb\":[{\"span\":{\"start\":[1,1],\"end\":[2,4]},\"category\":\"Method\",\"term\":\"self.foo\",\"changeType\":\"modified\"},{\"span\":{\"start\":[4,1],\"end\":[6,4]},\"category\":\"Method\",\"term\":\"bar\",\"changeType\":\"modified\"}]},\"errors\":{}}\n" :: ByteString)
toOutput output `shouldBe` ("{\"changes\":{\"test/fixtures/toc/ruby/methods.A.rb -> test/fixtures/toc/ruby/methods.B.rb\":[{\"span\":{\"start\":[1,1],\"end\":[2,4]},\"category\":\"Method\",\"term\":\"self.foo\",\"changeType\":\"added\"},{\"span\":{\"start\":[4,1],\"end\":[6,4]},\"category\":\"Method\",\"term\":\"bar\",\"changeType\":\"modified\"},{\"span\":{\"start\":[4,1],\"end\":[5,4]},\"category\":\"Method\",\"term\":\"baz\",\"changeType\":\"removed\"}]},\"errors\":{}}\n" :: ByteString)
it "produces JSON output if there are parse errors" $ do
blobs <- blobsForPaths (both "ruby/methods.A.rb" "ruby/methods.X.rb")

View File

@ -15,5 +15,5 @@
->(NumberLiteral) }
{ (NumberLiteral)
->(NumberLiteral) }
{+(NumberLiteral)+}
{-(NumberLiteral)-}))))))
{ (NumberLiteral)
->(NumberLiteral) }))))))

View File

@ -15,5 +15,5 @@
->(NumberLiteral) }
{ (NumberLiteral)
->(NumberLiteral) }
{+(NumberLiteral)+}
{-(NumberLiteral)-}))))))
{ (NumberLiteral)
->(NumberLiteral) }))))))

View File

@ -11,8 +11,7 @@
->(Identifier) }
{ (Identifier)
->(Identifier) }
{+(Other "expression_list"
{+(NumberLiteral)+}
{+(NumberLiteral)+})+}
{-(Other "expression_list"
{-(NumberLiteral)-})-}))))
(Other "expression_list"
{ (NumberLiteral)
->(NumberLiteral) }
{+(NumberLiteral)+})))))

View File

@ -3,14 +3,13 @@
(Empty)
(Empty)
(Empty)
(RequiredParameter
(Empty)
(Empty)
(Empty)
(Assignment
{ (Identifier)
->(Identifier) }
(Empty)))
{+(RequiredParameter
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Assignment
{+(Identifier)+}
{+(Empty)+})+})+}
(RequiredParameter
(Empty)
(Empty)
@ -18,6 +17,13 @@
(Assignment
(Identifier)
(Empty)))
{-(RequiredParameter
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Assignment
{-(Identifier)-}
{-(Empty)-})-})-}
(
(Return
{ (Times

View File

@ -107,37 +107,36 @@
{-(Empty)-}
{-(Identifier)-}
{-([])-})-})
{+(Export
{+(TextElement)+})+}
{+(Export
{+(ExportClause
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Empty)+})+}
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Empty)+})+}
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Empty)+})+})+}
{+(TextElement)+})+}
{+(Export
{+(ExportClause
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Identifier)+})+}
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Identifier)+})+}
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Empty)+})+})+}
{+(TextElement)+})+}
{-(Export
(Export
{+(TextElement)+}
{-(ExportClause
{-(ImportExportSpecifier
{-(Identifier)-}
{-(Identifier)-})-})-})-}
{-(Identifier)-})-})-})
{+(Export
{+(ExportClause
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Empty)+})+}
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Empty)+})+}
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Empty)+})+})+}
{+(TextElement)+})+}
{+(Export
{+(ExportClause
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Identifier)+})+}
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Identifier)+})+}
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Empty)+})+})+}
{+(TextElement)+})+}
{-(Export
{-(TextElement)-})-}
{-(Export

View File

@ -25,17 +25,17 @@
{-(Empty)-})-}))
(Export
(ExportClause
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Identifier)+})+}
(ImportExportSpecifier
(Identifier)
(Identifier))
(ImportExportSpecifier
{ (Identifier)
->(Identifier) }
{ (Identifier)
->(Identifier) })
(ImportExportSpecifier
(Identifier)
(Identifier))
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Empty)+})+}
->(Empty) })
{-(ImportExportSpecifier
{-(Identifier)-}
{-(Empty)-})-}))
@ -105,14 +105,14 @@
{-(ImportExportSpecifier
{-(Identifier)-}
{-(Identifier)-})-})-})
{+(Export
(Export
{+(ExportClause
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Identifier)+})+})+})+}
(Export
{ (TextElement)
->(TextElement) })
{+(Identifier)+})+})+}
{-(TextElement)-})
{+(Export
{+(TextElement)+})+}
(Export
(ExportClause
(ImportExportSpecifier
@ -133,27 +133,21 @@
{-(Empty)-})-})
{ (TextElement)
->(TextElement) })
{+(Export
{+(ExportClause
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Identifier)+})+}
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Identifier)+})+}
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Empty)+})+})+}
{+(TextElement)+})+}
{-(Export
{-(ExportClause
{-(ImportExportSpecifier
{-(Identifier)-}
{-(Identifier)-})-}
{-(ImportExportSpecifier
{-(Identifier)-}
{-(Identifier)-})-}
{-(ImportExportSpecifier
{-(Identifier)-}
{-(Empty)-})-})-}
{-(TextElement)-})-})
(Export
(ExportClause
(ImportExportSpecifier
{ (Identifier)
->(Identifier) }
{ (Identifier)
->(Identifier) })
(ImportExportSpecifier
{ (Identifier)
->(Identifier) }
{ (Identifier)
->(Identifier) })
(ImportExportSpecifier
{ (Identifier)
->(Identifier) }
(Empty)))
{ (TextElement)
->(TextElement) }))

View File

@ -8,14 +8,13 @@
(Empty)
(Empty)
(Empty)
(RequiredParameter
(Empty)
(Empty)
(Empty)
(Assignment
{ (Identifier)
->(Identifier) }
(Empty)))
{+(RequiredParameter
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Assignment
{+(Identifier)+}
{+(Empty)+})+})+}
(RequiredParameter
(Empty)
(Empty)
@ -23,6 +22,13 @@
(Assignment
(Identifier)
(Empty)))
{-(RequiredParameter
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Assignment
{-(Identifier)-}
{-(Empty)-})-})-}
(
(Call
(MemberAccess

View File

@ -1,35 +1,36 @@
(Program
(Annotation
(Annotation
(Function
{ (Identifier)
->(Identifier) }
{-(Identifier)-}
(Identifier)
{+(Identifier)+}
(
{ (Identifier)
->(Identifier) }))
(Empty))
(Identifier))
(Annotation
(Annotation
(Function
(Identifier)
(
{ (Identifier)
->(Identifier) }))
(Empty))
(Identifier))
{+(Annotation
{+(Annotation
{+(Function
{+(Identifier)+}
{+(Identifier)+}
{+(Identifier)+}
{+(
{+(Identifier)+})+})+}
{+(Empty)+})+}
{+(Identifier)+})+}
(Annotation
(Annotation
(Function
(Identifier)
(
{ (Identifier)
->(Identifier) }))
(Empty))
(Identifier))
(Annotation
(Annotation
(Function
{ (Identifier)
->(Identifier) }
{ (Identifier)
->(Identifier) }
{-(Identifier)-}
(
{ (Identifier)
->(Identifier) }))
(Empty))
(Identifier))
{-(Annotation
{-(Annotation
{-(Function

View File

@ -1,10 +1,8 @@
(Program
(Hash
(KeyValue
{ (Identifier)
->(Identifier) }
{ (Integer)
->(Integer) }))
{+(Hash
{+(KeyValue
{+(Identifier)+}
{+(Integer)+})+})+}
(Hash)
{+(Assignment
{+(Identifier)+}
@ -17,6 +15,10 @@
{+(KeyValue
{+(Identifier)+}
{+(Identifier)+})+})+})+}
{-(Hash
{-(KeyValue
{-(Identifier)-}
{-(Integer)-})-})-}
{-(Hash
{-(KeyValue
{-(Identifier)-}

View File

@ -12,13 +12,10 @@
{+(Identifier)+}
{-(Null)-}
(Empty))
{+(Call
{+(Identifier)+}
{+(TextElement)+}
{+(Empty)+})+}
{-(Call
{-(Identifier)-}
{-(TextElement)-}
(Call
(Identifier)
{ (TextElement)
->(TextElement) }
{-(Identifier)-}
{-(Identifier)-}
{-(Empty)-})-})
(Empty)))

View File

@ -12,13 +12,10 @@
{-(Identifier)-}
{-(Identifier)-}
(Empty))
{+(Call
{+(Identifier)+}
{+(TextElement)+}
(Call
(Identifier)
{ (TextElement)
->(TextElement) }
{+(Identifier)+}
{+(Identifier)+}
{+(Empty)+})+}
{-(Call
{-(Identifier)-}
{-(TextElement)-}
{-(Empty)-})-})
(Empty)))

View File

@ -9,9 +9,10 @@
(Integer))
{+(Identifier)+}
(
{+(Integer)+}
(Integer)
(Integer)
(Integer))
{-(Integer)-})
{+(Plus
{+(Identifier)+}
{+(Identifier)+})+})

View File

@ -1,6 +1,5 @@
(Program
{ (Identifier)
->(Identifier) }
{+(Identifier)+}
{+(Plus
{+(Identifier)+}
{+(Identifier)+})+}
@ -12,6 +11,7 @@
{+(Integer)+}
{+(Integer)+}
{+(Integer)+})+}
{-(Identifier)-}
{-(
{-(Integer)-}
{-(Integer)-}

View File

@ -23,28 +23,24 @@
{ (Identifier)
->(Identifier) }))
(Empty))
{+(Annotation
{+(Function
{+(Identifier)+}
{+(
{+(Identifier)+})+})+}
{+(Empty)+})+}
{+(Annotation
{+(Function
{+(Identifier)+}
{+(Identifier)+}
{+(
{+(Identifier)+})+})+}
{+(Empty)+})+}
{-(Annotation
{-(Function
{-(Identifier)-}
(Annotation
(Function
{ (Identifier)
->(Identifier) }
{-(Assignment
{-(Identifier)-}
{-(Identifier)-})-}
{-(
{-(Identifier)-})-})-}
{-(Empty)-})-}
(
{ (Identifier)
->(Identifier) }))
(Empty))
{+(Annotation
{+(Function
{+(Identifier)+}
{+(Identifier)+}
{+(
{+(Identifier)+})+})+}
{+(Empty)+})+}
(Annotation
(Function
(Identifier)

View File

@ -1,18 +1,14 @@
(Program
{+(Annotation
{+(Function
{+(Identifier)+}
{+(
{+(Identifier)+})+})+}
{+(Empty)+})+}
{-(Annotation
{-(Function
(Annotation
(Function
{ (Identifier)
->(Identifier) }
{-(Identifier)-}
{-(Identifier)-}
{-(Identifier)-}
{-(
{-(Identifier)-})-})-}
{-(Empty)-})-}
(
{ (Identifier)
->(Identifier) }))
(Empty))
(Annotation
(Function
(Identifier)

View File

@ -3,9 +3,9 @@
{ (Identifier)
->(Identifier) }
(
{ (Identifier)
->(Identifier) }
(Identifier))
{+(Identifier)+}
(Identifier)
{-(Identifier)-})
{ (If
{-(Identifier)-}
{-(

View File

@ -7,12 +7,14 @@
{+(ScopeResolution
{+(Identifier)+})+})
(Import
{+(ScopeResolution
{+(Identifier)+})+}
(ScopeResolution
(Identifier))
(ScopeResolution
(Identifier))
(ScopeResolution
(Identifier)))
{-(ScopeResolution
{-(Identifier)-})-})
(Import
(ScopeResolution
{ (Identifier)

View File

@ -1,9 +1,9 @@
(Program
(Call
(Identifier)
{ (Identifier)
->(Identifier) }
{+(Identifier)+}
(Identifier)
{-(Identifier)-}
(Empty))
(Call
(Identifier)

View File

@ -1,19 +1,29 @@
(Program
{+(Throw
{+(
{+(Call
{+(Identifier)+}
{+(TextElement)+}
{+(Empty)+})+})+})+}
{+(Throw
{+(
{+(Call
{+(Identifier)+}
{+(TextElement)+}
{+(Empty)+})+}
{+(Identifier)+})+})+}
(Throw
(
(Call
(Identifier)
{ (TextElement)
->(TextElement) }
(Empty))))
(Throw
(
(Call
(Identifier)
{ (TextElement)
->(TextElement) }
(Empty))
{ (Identifier)
->(Identifier) }))
(Throw
([])))
([]))
{-(Throw
{-(
{-(Call
{-(Identifier)-}
{-(TextElement)-}
{-(Empty)-})-})-})-}
{-(Throw
{-(
{-(Call
{-(Identifier)-}
{-(TextElement)-}
{-(Empty)-})-}
{-(Identifier)-})-})-})

View File

@ -1,18 +1,20 @@
(Program
(Return
(
(Plus
{ (Identifier)
->(Identifier) }
{ (Identifier)
->(Identifier) })
{ (Identifier)
->(Identifier) }))
{+(Return
{+(
{+(Plus
{+(Identifier)+}
{+(Identifier)+})+}
{+(Identifier)+})+})+}
(Return
(Empty))
{+(Return
{+(Not
{+(Identifier)+})+})+}
(Return
{ (
{-(Plus
{-(Identifier)-}
{-(Identifier)-})-}
{-(Identifier)-})
->(Not
{+(Identifier)+}) })
{-(Return
{-(Not
{-(Identifier)-})-})-})

View File

@ -1,10 +1,10 @@
(Program
{ (TextElement)
->(TextElement) }
{+(TextElement)+}
(TextElement)
{+(TextElement)+}
{+(TextElement)+}
{+(TextElement)+}
{ (TextElement)
->(TextElement) }
{+(TextElement)+}
{+(TextElement)+}
{-(TextElement)-}

View File

@ -6,9 +6,9 @@
->(TextElement) }
{+(TextElement)+}
{+(TextElement)+}
{+(TextElement)+}
{ (TextElement)
->(TextElement) }
{+(TextElement)+}
{-(TextElement)-}
{-(TextElement)-}
{-(TextElement)-}

View File

@ -3,9 +3,10 @@
{+(Identifier)+}
{+(Identifier)+})+}
(Tuple
{+(Identifier)+}
(Identifier)
(Identifier)
(Identifier))
{-(Identifier)-})
{-(Tuple
{-(Identifier)-}
{-(Identifier)-})-}

View File

@ -3,15 +3,11 @@
{ (Identifier)
->(Identifier) }
(
{ (Break
{-(Empty)-})
->(NoOp
{+(Empty)+}) }
{ (Continue
{-(Empty)-})
->(Break
{+(Empty)+}) }
{ (NoOp
{-(Empty)-})
->(Continue
{+(Empty)+}) })))
{+(NoOp
{+(Empty)+})+}
(Break
(Empty))
(Continue
(Empty))
{-(NoOp
{-(Empty)-})-})))

View File

@ -1,10 +1,4 @@
(Program
{+(AmbientDeclaration
{+(InternalModule
{+(Identifier)+})+})+}
{+(AmbientDeclaration
{+(Class
{+(Identifier)+})+})+}
(AmbientDeclaration
{ (Class
{-(Identifier)-}
@ -15,18 +9,23 @@
{-(TypeIdentifier)-})-}
{-(Identifier)-}
{-(Empty)-})-})
->(InterfaceDeclaration
{+(Empty)+}
{+(Empty)+}
{+(Identifier)+}
{+(ObjectType)+}) })
{-(AmbientDeclaration
{-(VariableDeclaration
->(InternalModule
{+(Identifier)+}) })
(AmbientDeclaration
{ (VariableDeclaration
{-(Assignment
{-(Annotation
{-(PredefinedType)-})-}
{-(Identifier)-}
{-(Empty)-})-})-})-}
{-(Empty)-})-})
->(Class
{+(Identifier)+}) })
{+(AmbientDeclaration
{+(InterfaceDeclaration
{+(Empty)+}
{+(Empty)+}
{+(Identifier)+}
{+(ObjectType)+})+})+}
{-(AmbientDeclaration
{-(AmbientFunction
{-(Empty)-}

View File

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

View File

@ -3,14 +3,13 @@
(Empty)
(Empty)
(Empty)
(RequiredParameter
(Empty)
(Empty)
(Empty)
(Assignment
{ (Identifier)
->(Identifier) }
(Empty)))
{+(RequiredParameter
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Assignment
{+(Identifier)+}
{+(Empty)+})+})+}
(RequiredParameter
(Empty)
(Empty)
@ -18,6 +17,13 @@
(Assignment
(Identifier)
(Empty)))
{-(RequiredParameter
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Assignment
{-(Identifier)-}
{-(Empty)-})-})-}
(
(Return
{ (Times

View File

@ -107,37 +107,36 @@
{-(Empty)-}
{-(Identifier)-}
{-([])-})-})
{+(Export
{+(TextElement)+})+}
{+(Export
{+(ExportClause
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Empty)+})+}
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Empty)+})+}
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Empty)+})+})+}
{+(TextElement)+})+}
{+(Export
{+(ExportClause
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Identifier)+})+}
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Identifier)+})+}
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Empty)+})+})+}
{+(TextElement)+})+}
{-(Export
(Export
{+(TextElement)+}
{-(ExportClause
{-(ImportExportSpecifier
{-(Identifier)-}
{-(Identifier)-})-})-})-}
{-(Identifier)-})-})-})
{+(Export
{+(ExportClause
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Empty)+})+}
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Empty)+})+}
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Empty)+})+})+}
{+(TextElement)+})+}
{+(Export
{+(ExportClause
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Identifier)+})+}
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Identifier)+})+}
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Empty)+})+})+}
{+(TextElement)+})+}
{-(Export
{-(TextElement)-})-}
{-(Export

View File

@ -25,17 +25,17 @@
{-(Empty)-})-}))
(Export
(ExportClause
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Identifier)+})+}
(ImportExportSpecifier
(Identifier)
(Identifier))
(ImportExportSpecifier
{ (Identifier)
->(Identifier) }
{ (Identifier)
->(Identifier) })
(ImportExportSpecifier
(Identifier)
(Identifier))
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Empty)+})+}
->(Empty) })
{-(ImportExportSpecifier
{-(Identifier)-}
{-(Empty)-})-}))
@ -105,14 +105,14 @@
{-(ImportExportSpecifier
{-(Identifier)-}
{-(Identifier)-})-})-})
{+(Export
(Export
{+(ExportClause
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Identifier)+})+})+})+}
(Export
{ (TextElement)
->(TextElement) })
{+(Identifier)+})+})+}
{-(TextElement)-})
{+(Export
{+(TextElement)+})+}
(Export
(ExportClause
(ImportExportSpecifier
@ -133,27 +133,21 @@
{-(Empty)-})-})
{ (TextElement)
->(TextElement) })
{+(Export
{+(ExportClause
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Identifier)+})+}
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Identifier)+})+}
{+(ImportExportSpecifier
{+(Identifier)+}
{+(Empty)+})+})+}
{+(TextElement)+})+}
{-(Export
{-(ExportClause
{-(ImportExportSpecifier
{-(Identifier)-}
{-(Identifier)-})-}
{-(ImportExportSpecifier
{-(Identifier)-}
{-(Identifier)-})-}
{-(ImportExportSpecifier
{-(Identifier)-}
{-(Empty)-})-})-}
{-(TextElement)-})-})
(Export
(ExportClause
(ImportExportSpecifier
{ (Identifier)
->(Identifier) }
{ (Identifier)
->(Identifier) })
(ImportExportSpecifier
{ (Identifier)
->(Identifier) }
{ (Identifier)
->(Identifier) })
(ImportExportSpecifier
{ (Identifier)
->(Identifier) }
(Empty)))
{ (TextElement)
->(TextElement) }))

View File

@ -8,14 +8,13 @@
(Empty)
(Empty)
(Empty)
(RequiredParameter
(Empty)
(Empty)
(Empty)
(Assignment
{ (Identifier)
->(Identifier) }
(Empty)))
{+(RequiredParameter
{+(Empty)+}
{+(Empty)+}
{+(Empty)+}
{+(Assignment
{+(Identifier)+}
{+(Empty)+})+})+}
(RequiredParameter
(Empty)
(Empty)
@ -23,6 +22,13 @@
(Assignment
(Identifier)
(Empty)))
{-(RequiredParameter
{-(Empty)-}
{-(Empty)-}
{-(Empty)-}
{-(Assignment
{-(Identifier)-}
{-(Empty)-})-})-}
(
(Call
(MemberAccess

View File

@ -19,33 +19,23 @@
(Empty)
(Identifier)
(Empty))
{+(PublicFieldDefinition
{+(Identifier)+}
{+(Readonly)+}
(PublicFieldDefinition
(Identifier)
(Readonly)
{+(Annotation
{+(TypeIdentifier)+})+}
{+(Identifier)+}
{+(Float)+})+}
{+(PublicFieldDefinition
{+(Identifier)+}
{+(Empty)+}
{+(Annotation
{+(TypeIdentifier)+})+}
{+(Identifier)+}
{+(Float)+})+}
{-(PublicFieldDefinition
{-(Identifier)-}
{-(Readonly)-}
{-(Empty)-}
{-(Identifier)-}
{-(Float)-})-}
{-(PublicFieldDefinition
{-(Identifier)-}
(Identifier)
(Float))
(PublicFieldDefinition
{ (Identifier)
->(Identifier) }
{+(Empty)+}
{-(Readonly)-}
{-(Annotation
{-(TypeIdentifier)-})-}
{-(Identifier)-}
{-(Float)-})-}
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Empty)
(Empty)

View File

@ -19,27 +19,23 @@
(Empty)
(Identifier)
(Empty))
{+(PublicFieldDefinition
{+(Identifier)+}
{+(Readonly)+}
{+(Empty)+}
{+(Identifier)+}
{+(Float)+})+}
(PublicFieldDefinition
(Identifier)
(Readonly)
(Annotation
(TypeIdentifier))
{ (Identifier)
->(Identifier) }
(Float))
{-(PublicFieldDefinition
{-(Identifier)-}
{-(Empty)-}
{+(Empty)+}
{-(Annotation
{-(TypeIdentifier)-})-}
{-(Identifier)-}
{-(Float)-})-}
(Identifier)
(Float))
(PublicFieldDefinition
{ (Identifier)
->(Identifier) }
{+(Readonly)+}
{-(Empty)-}
(Annotation
(TypeIdentifier))
(Identifier)
(Float))
(PublicFieldDefinition
(Empty)
(Empty)