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

Major updates to identifiers: free variables can be qualified names

(break all the tests too 😁)
This commit is contained in:
Timothy Clem 2018-03-07 17:01:47 -08:00
parent a71729d76d
commit 835e8f5980
16 changed files with 131 additions and 120 deletions

View File

@ -12,7 +12,6 @@ import Data.Abstract.ModuleTable
import Data.Abstract.Store
import Data.Abstract.Value
import Data.Blob
import Data.List (intercalate)
import Data.List.Split (splitWhen)
import Prologue
import qualified Data.ByteString.Char8 as BC
@ -65,8 +64,8 @@ withModules Blob{..} pairs = localModuleTable (const moduleTable)
where
moduleTable = ModuleTable (Map.fromList (map (first moduleName) pairs))
rootDir = dropFileName blobPath
replacePathSeps str = intercalate "." (splitWhen (== pathSeparator) str)
moduleName Blob{..} = BC.pack $ replacePathSeps (dropExtensions (makeRelative rootDir blobPath))
moduleName Blob{..} = toName (dropExtensions (makeRelative rootDir blobPath))
toName str = qualifiedName (fmap BC.pack (splitWhen (== pathSeparator) str))
-- | An analysis performing concrete evaluation of @term@s to @value@s.
newtype Evaluation term value a = Evaluation { runEvaluation :: Evaluator (EvaluationEffects term value) term value a }

View File

@ -14,6 +14,7 @@ import Data.Record
import Data.Source as Source
import Data.Span
import Data.Term
import Data.Abstract.FreeVariables
import qualified Data.Syntax as Syntax
import qualified Data.Syntax.Declaration as Declaration
import qualified Data.Syntax.Expression as Expression
@ -131,7 +132,7 @@ instance CustomHasDeclaration (Union fs) Declaration.QualifiedImport where
| otherwise = alias
basename = last . T.splitOn "/"
getSource = T.dropAround (`elem` ['"', '\'']) . toText . flip Source.slice blobSource . getField
getSymbol (a, b) = (T.decodeUtf8 a, T.decodeUtf8 b)
getSymbol = let f = (T.decodeUtf8 . friendlyName) in bimap f f
instance (Expression.MemberAccess :< fs) => CustomHasDeclaration (Union fs) Expression.Call where
customToDeclaration Blob{..} _ (Expression.Call _ (Term (In fromAnn fromF), _) _ _)

View File

@ -5,11 +5,12 @@ module Analysis.IdentifierName
, identifierLabel
) where
import Prologue
import Data.Abstract.FreeVariables
import Data.Aeson
import Data.JSON.Fields
import Data.Term
import Data.Text.Encoding (decodeUtf8)
import Prologue
import qualified Data.Syntax
-- | Compute a 'IdentifierLabel' label for a 'Term'.
@ -39,7 +40,7 @@ instance Apply IdentifierName fs => CustomIdentifierName (Union fs) where
customIdentifierName = apply (Proxy :: Proxy IdentifierName) identifierName
instance CustomIdentifierName Data.Syntax.Identifier where
customIdentifierName (Data.Syntax.Identifier name) = Just name
customIdentifierName (Data.Syntax.Identifier name) = Just (friendlyName name)
data Strategy = Default | Custom

View File

@ -3,10 +3,26 @@ module Data.Abstract.FreeVariables where
import Prologue
import Data.Term
import Data.ByteString as B
-- | The type of variable names.
type Name = ByteString
data Name = Name ByteString | Qualified ByteString Name
deriving (Eq, Ord, Show)
name :: ByteString -> Name
name = Name
qualifiedName :: [ByteString] -> Name
qualifiedName [] = Name "THIS IS BROKEN"
qualifiedName [x] = Name x
qualifiedName (x:xs) = Qualified x (qualifiedName xs)
friendlyName :: Name -> ByteString
friendlyName (Name a) = a
friendlyName (Qualified a b) = a <> "." <> friendlyName b
instance Semigroup Name where
(<>) (Name a) n = Qualified a n
(<>) (Qualified a rest) n = Qualified a (rest <> n)
-- | Types which can contain unbound variables.
@ -33,8 +49,8 @@ freeVariable term = let [n] = toList (freeVariables term) in n
-- TODO: Need a dedicated concept of qualified names outside of freevariables (a
-- Set) b/c you can have something like `a.a.b.a`
qualifiedName :: FreeVariables term => term -> Name
qualifiedName term = let names = toList (freeVariables term) in B.intercalate "." names
-- qualifiedName :: FreeVariables term => term -> Name
-- qualifiedName term = let names = toList (freeVariables term) in B.intercalate "." names
instance (FreeVariables1 syntax, Functor syntax) => FreeVariables (Term syntax ann) where
freeVariables = cata (liftFreeVariables id)

View File

@ -6,14 +6,13 @@ module Data.Abstract.ModuleTable
, moduleTableInsert
) where
import Data.ByteString
import Data.Abstract.FreeVariables
import Data.Semigroup
import GHC.Generics
import qualified Data.Map as Map
type ModuleName = ByteString
type ModuleName = Name
newtype ModuleTable a = ModuleTable { unModuleTable :: Map.Map ModuleName a }
deriving (Eq, Foldable, Functor, Generic1, Monoid, Ord, Semigroup, Show, Traversable)

View File

@ -5,7 +5,6 @@ import Control.Monad.Fail
import Data.Abstract.Environment
import Data.Abstract.Evaluatable
import Data.AST
import Data.ByteString.Char8 (unpack)
import Data.Range
import Data.Record
import Data.Span
@ -100,7 +99,7 @@ infixContext context left right operators = uncurry (&) <$> postContextualizeThr
-- Common
-- | An identifier of some other construct, whether a containing declaration (e.g. a class name) or a reference (e.g. a variable).
newtype Identifier a = Identifier ByteString
newtype Identifier a = Identifier Name
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
instance Eq1 Identifier where liftEq = genericLiftEq
@ -110,24 +109,11 @@ instance Show1 Identifier where liftShowsPrec = genericLiftShowsPrec
instance Evaluatable Identifier where
eval (Identifier name) = do
env <- askLocalEnv
maybe (fail ("free variable: " <> unpack name)) deref (envLookup name env)
maybe (fail ("free variable: " <> show name)) deref (envLookup name env)
instance FreeVariables1 Identifier where
liftFreeVariables _ (Identifier x) = point x
newtype QualifiedIdentifier a = QualifiedIdentifier a
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable, FreeVariables1)
instance Eq1 QualifiedIdentifier where liftEq = genericLiftEq
instance Ord1 QualifiedIdentifier where liftCompare = genericLiftCompare
instance Show1 QualifiedIdentifier where liftShowsPrec = genericLiftShowsPrec
instance Evaluatable QualifiedIdentifier where
eval (QualifiedIdentifier xs) = do
env <- askLocalEnv
let name = qualifiedName (subterm xs)
maybe (fail ("free variable: " <> unpack name)) deref (envLookup name env)
newtype Program a = Program [a]
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable, FreeVariables1)

View File

@ -221,12 +221,12 @@ instance Evaluatable QualifiedImport where
eval (QualifiedImport from alias xs) = do
env <- getGlobalEnv
putGlobalEnv mempty
importedEnv <- require (qualifiedName (subterm from))
importedEnv <- require (freeVariable (subterm from))
env' <- Map.foldrWithKey copy (pure env) (unEnvironment importedEnv)
modifyGlobalEnv (const env')
unit
where
prefix = qualifiedName (subterm alias) <> "."
prefix = freeVariable (subterm alias)
symbols = Map.fromList xs
copy = if Map.null symbols then qualifyInsert else directInsert
qualifyInsert k v rest = envInsert (prefix <> k) v <$> rest
@ -247,7 +247,7 @@ instance Evaluatable Import where
eval (Import from xs) = do
env <- getGlobalEnv
putGlobalEnv mempty
importedEnv <- require (qualifiedName (subterm from))
importedEnv <- require (freeVariable (subterm from))
env' <- Map.foldrWithKey directInsert (pure env) (unEnvironment importedEnv)
modifyGlobalEnv (const env')
unit
@ -267,7 +267,7 @@ instance Ord1 WildcardImport where liftCompare = genericLiftCompare
instance Show1 WildcardImport where liftShowsPrec = genericLiftShowsPrec
instance Evaluatable WildcardImport where
eval (WildcardImport from _) = putGlobalEnv mempty *> require (qualifiedName (subterm from)) *> unit
eval (WildcardImport from _) = putGlobalEnv mempty *> require (freeVariable (subterm from)) *> unit
-- | A declared type (e.g. `a []int` in Go).
data Type a = Type { typeName :: !a, typeKind :: !a }

View File

@ -6,12 +6,16 @@ module Language.Go.Assignment
, Term
) where
import Prologue
import Assigning.Assignment hiding (Assignment, Error)
import qualified Assigning.Assignment as Assignment
import Data.Record
import Data.Abstract.FreeVariables
import Data.ByteString as B
import Data.Record
import Data.Syntax (contextualize, emptyTerm, parseError, handleError, infixContext, makeTerm, makeTerm', makeTerm'', makeTerm1)
import Language.Go.Grammar as Grammar
import Language.Go.Syntax as Go.Syntax
import Language.Go.Type as Go.Type
import Prologue
import qualified Assigning.Assignment as Assignment
import qualified Data.Syntax as Syntax
import qualified Data.Syntax.Comment as Comment
import qualified Data.Syntax.Declaration as Declaration
@ -20,9 +24,6 @@ import qualified Data.Syntax.Literal as Literal
import qualified Data.Syntax.Statement as Statement
import qualified Data.Syntax.Type as Type
import qualified Data.Term as Term
import Language.Go.Grammar as Grammar
import Language.Go.Syntax as Go.Syntax
import Language.Go.Type as Go.Type
type Syntax =
'[ Comment.Comment
@ -224,13 +225,13 @@ element :: Assignment
element = symbol Element *> children expression
fieldIdentifier :: Assignment
fieldIdentifier = makeTerm <$> symbol FieldIdentifier <*> (Syntax.Identifier <$> source)
fieldIdentifier = makeTerm <$> symbol FieldIdentifier <*> (Syntax.Identifier <$> (name <$> source))
floatLiteral :: Assignment
floatLiteral = makeTerm <$> symbol FloatLiteral <*> (Literal.Float <$> source)
identifier :: Assignment
identifier = makeTerm <$> (symbol Identifier <|> symbol Identifier') <*> (Syntax.Identifier <$> source)
identifier = makeTerm <$> (symbol Identifier <|> symbol Identifier') <*> (Syntax.Identifier <$> (name <$> source))
imaginaryLiteral :: Assignment
imaginaryLiteral = makeTerm <$> symbol ImaginaryLiteral <*> (Literal.Complex <$> source)
@ -245,7 +246,7 @@ literalValue :: Assignment
literalValue = makeTerm <$> symbol LiteralValue <*> children (manyTerm expression)
packageIdentifier :: Assignment
packageIdentifier = makeTerm <$> symbol PackageIdentifier <*> (Syntax.Identifier <$> source)
packageIdentifier = makeTerm <$> symbol PackageIdentifier <*> (Syntax.Identifier <$> (name <$> source))
parenthesizedType :: Assignment
parenthesizedType = makeTerm <$> symbol Grammar.ParenthesizedType <*> children (Type.Parenthesized <$> expression)
@ -257,7 +258,7 @@ runeLiteral :: Assignment
runeLiteral = makeTerm <$> symbol Grammar.RuneLiteral <*> (Go.Syntax.Rune <$> source)
typeIdentifier :: Assignment
typeIdentifier = makeTerm <$> symbol TypeIdentifier <*> (Syntax.Identifier <$> source)
typeIdentifier = makeTerm <$> symbol TypeIdentifier <*> (Syntax.Identifier <$> (name <$> source))
-- Primitive Types
@ -372,7 +373,7 @@ expressionSwitchStatement :: Assignment
expressionSwitchStatement = makeTerm <$> symbol ExpressionSwitchStatement <*> children (Statement.Match <$> (makeTerm <$> location <*> manyTermsTill expression (void (symbol ExpressionCaseClause)) <|> emptyTerm) <*> expressions)
fallThroughStatement :: Assignment
fallThroughStatement = makeTerm <$> symbol FallthroughStatement <*> (Statement.Pattern <$> (makeTerm <$> location <*> (Syntax.Identifier <$> source)) <*> emptyTerm)
fallThroughStatement = makeTerm <$> symbol FallthroughStatement <*> (Statement.Pattern <$> (makeTerm <$> location <*> (Syntax.Identifier <$> (name <$> source))) <*> emptyTerm)
functionDeclaration :: Assignment
functionDeclaration = makeTerm <$> (symbol FunctionDeclaration <|> symbol FuncLiteral) <*> children (mkFunctionDeclaration <$> (term identifier <|> emptyTerm) <*> manyTerm parameters <*> (term types <|> term identifier <|> term returnParameters <|> emptyTerm) <*> (term block <|> emptyTerm))
@ -393,7 +394,7 @@ importDeclaration = makeTerm'' <$> symbol ImportDeclaration <*> children (manyTe
sideEffectImport = symbol BlankIdentifier *> source *> (Declaration.Import <$> expression <*> pure [])
namedImport = symbol PackageIdentifier >>= \loc -> do
s <- source
let alias = makeTerm loc (Syntax.Identifier s)
let alias = makeTerm loc (Syntax.Identifier (name s))
Declaration.QualifiedImport <$> expression <*> pure alias <*> pure []
plainImport = symbol InterpretedStringLiteral >>= \loc -> do
s <- source
@ -401,7 +402,7 @@ importDeclaration = makeTerm'' <$> symbol ImportDeclaration <*> children (manyTe
let alias = makeTerm loc (Syntax.Identifier (baseName s))
Declaration.QualifiedImport <$> pure from <*> pure alias <*> pure []
baseName bs = Prelude.last (B.split (toEnum (fromEnum '/')) (stripQuotes bs))
baseName bs = name $ Prelude.last (B.split (toEnum (fromEnum '/')) (stripQuotes bs))
stripQuotes = fromMaybe' (B.stripSuffix "\"") . fromMaybe' (B.stripPrefix "\"")
fromMaybe' f x = fromMaybe x (f x)
@ -567,7 +568,7 @@ keyedElement :: Assignment
keyedElement = makeTerm <$> symbol KeyedElement <*> children (Literal.KeyValue <$> expression <*> expression)
labelName :: Assignment
labelName = makeTerm <$> symbol LabelName <*> (Syntax.Identifier <$> source)
labelName = makeTerm <$> symbol LabelName <*> (Syntax.Identifier <$> (name <$> source))
labeledStatement :: Assignment
labeledStatement = makeTerm <$> (symbol LabeledStatement <|> symbol LabeledStatement') <*> children (Go.Syntax.Label <$> expression <*> (expression <|> emptyTerm))

View File

@ -6,21 +6,22 @@ module Language.PHP.Assignment
, Term
) where
import Prologue
import Assigning.Assignment hiding (Assignment, Error)
import Data.Record
import qualified Data.Term as Term
import Data.Syntax (emptyTerm, handleError, parseError, infixContext, makeTerm, makeTerm', makeTerm1, contextualize, postContextualize)
import Language.PHP.Grammar as Grammar
import Prologue
import qualified Assigning.Assignment as Assignment
import qualified Data.Abstract.FreeVariables as FV
import qualified Data.Syntax as Syntax
import qualified Language.PHP.Syntax as Syntax
import qualified Data.Syntax.Comment as Comment
import qualified Data.Syntax.Declaration as Declaration
import qualified Data.Syntax.Expression as Expression
import qualified Data.Syntax.Literal as Literal
import qualified Data.Syntax.Statement as Statement
import qualified Data.Syntax.Type as Type
import Assigning.Assignment hiding (Assignment, Error)
import qualified Assigning.Assignment as Assignment
import Language.PHP.Grammar as Grammar
import qualified Data.Term as Term
import qualified Language.PHP.Syntax as Syntax
type Syntax = '[
Comment.Comment
@ -428,7 +429,7 @@ classConstDeclaration :: Assignment
classConstDeclaration = makeTerm <$> symbol ClassConstDeclaration <*> children (Syntax.ClassConstDeclaration <$> (term visibilityModifier <|> emptyTerm) <*> manyTerm constElement)
visibilityModifier :: Assignment
visibilityModifier = makeTerm <$> symbol VisibilityModifier <*> (Syntax.Identifier <$> source)
visibilityModifier = makeTerm <$> symbol VisibilityModifier <*> (Syntax.Identifier <$> (FV.name <$> source))
constElement :: Assignment
constElement = makeTerm <$> symbol ConstElement <*> children (Statement.Assignment [] <$> term name <*> term expression)
@ -634,7 +635,7 @@ propertyDeclaration :: Assignment
propertyDeclaration = makeTerm <$> symbol PropertyDeclaration <*> children (Syntax.PropertyDeclaration <$> term propertyModifier <*> someTerm propertyElement)
propertyModifier :: Assignment
propertyModifier = (makeTerm <$> symbol PropertyModifier <*> children (Syntax.PropertyModifier <$> (term visibilityModifier <|> emptyTerm) <*> (term staticModifier <|> emptyTerm))) <|> term (makeTerm <$> symbol PropertyModifier <*> (Syntax.Identifier <$> source))
propertyModifier = (makeTerm <$> symbol PropertyModifier <*> children (Syntax.PropertyModifier <$> (term visibilityModifier <|> emptyTerm) <*> (term staticModifier <|> emptyTerm))) <|> term (makeTerm <$> symbol PropertyModifier <*> (Syntax.Identifier <$> (FV.name <$> source)))
propertyElement :: Assignment
propertyElement = makeTerm <$> symbol PropertyElement <*> children (Statement.Assignment [] <$> term variableName <*> term propertyInitializer) <|> (symbol PropertyElement *> children (term variableName))
@ -695,7 +696,7 @@ namespaceAliasingClause = makeTerm <$> symbol NamespaceAliasingClause <*> childr
-- | TODO Do something better than Identifier
namespaceFunctionOrConst :: Assignment
namespaceFunctionOrConst = makeTerm <$> symbol NamespaceFunctionOrConst <*> (Syntax.Identifier <$> source)
namespaceFunctionOrConst = makeTerm <$> symbol NamespaceFunctionOrConst <*> (Syntax.Identifier <$> (FV.name <$> source))
globalDeclaration :: Assignment
globalDeclaration = makeTerm <$> symbol GlobalDeclaration <*> children (Syntax.GlobalDeclaration <$> manyTerm simpleVariable')
@ -731,7 +732,7 @@ variableName :: Assignment
variableName = makeTerm <$> symbol VariableName <*> children (Syntax.VariableName <$> term name)
name :: Assignment
name = makeTerm <$> (symbol Name <|> symbol Name') <*> (Syntax.Identifier <$> source)
name = makeTerm <$> (symbol Name <|> symbol Name') <*> (Syntax.Identifier <$> (FV.name <$> source))
functionStaticDeclaration :: Assignment
functionStaticDeclaration = makeTerm <$> symbol FunctionStaticDeclaration <*> children (Declaration.VariableDeclaration <$> manyTerm staticVariableDeclaration)

View File

@ -7,6 +7,7 @@ module Language.Python.Assignment
) where
import Assigning.Assignment hiding (Assignment, Error)
import Data.Abstract.FreeVariables
import Data.Functor (void)
import Data.List.NonEmpty (some1)
import Data.Maybe (fromMaybe)
@ -79,7 +80,6 @@ type Syntax =
, Syntax.Empty
, Syntax.Error
, Syntax.Identifier
, Syntax.QualifiedIdentifier
, Syntax.Program
, Type.Annotation
, []
@ -127,7 +127,6 @@ expressionChoices =
, deleteStatement
, dictionary
, dictionarySplat
, dottedName
, ellipsis
, exceptClause
, execStatement
@ -183,10 +182,10 @@ expressionList :: Assignment
expressionList = makeTerm'' <$> symbol ExpressionList <*> children (someTerm expression)
listSplat :: Assignment
listSplat = makeTerm <$> symbol ListSplat <*> (Syntax.Identifier <$> source)
listSplat = makeTerm <$> symbol ListSplat <*> (Syntax.Identifier <$> (name <$> source))
dictionarySplat :: Assignment
dictionarySplat = makeTerm <$> symbol DictionarySplat <*> (Syntax.Identifier <$> source)
dictionarySplat = makeTerm <$> symbol DictionarySplat <*> (Syntax.Identifier <$> (name <$> source))
keywordArgument :: Assignment
keywordArgument = makeTerm <$> symbol KeywordArgument <*> children (Statement.Assignment [] <$> term expression <*> term expression)
@ -253,7 +252,7 @@ functionDefinition
makeAsyncFunctionDeclaration loc (async', functionName', functionParameters, ty, functionBody) = makeTerm loc $ Type.Annotation (makeTerm loc $ Type.Annotation (makeTerm loc $ Declaration.Function [] functionName' functionParameters functionBody) (maybe (makeTerm loc Syntax.Empty) id ty)) async'
async' :: Assignment
async' = makeTerm <$> symbol AnonAsync <*> (Syntax.Identifier <$> source)
async' = makeTerm <$> symbol AnonAsync <*> (Syntax.Identifier <$> (name <$> source))
classDefinition :: Assignment
classDefinition = makeTerm <$> symbol ClassDefinition <*> children (Declaration.Class <$> pure [] <*> term expression <*> argumentList <*> expressions)
@ -266,9 +265,6 @@ type' = symbol Type *> children (term expression)
finallyClause :: Assignment
finallyClause = makeTerm <$> symbol FinallyClause <*> children (Statement.Finally <$> expressions)
dottedName :: Assignment
dottedName = makeTerm <$> symbol DottedName <*> children (Expression.ScopeResolution <$> manyTerm expression)
ellipsis :: Assignment
ellipsis = makeTerm <$> token Grammar.Ellipsis <*> pure Python.Syntax.Ellipsis
@ -344,8 +340,17 @@ assignment' = makeTerm <$> symbol Assignment <*> children (Statement.Assignmen
yield :: Assignment
yield = makeTerm <$> symbol Yield <*> (Statement.Yield <$> children (term ( expression <|> emptyTerm )))
-- Identifiers and qualified identifiers (e.g. `a.b.c`) from things like DottedName and Attribute
identifier :: Assignment
identifier = makeTerm <$> (symbol Identifier <|> symbol Identifier') <*> (Syntax.Identifier <$> source)
identifier = makeTerm <$> (symbol Identifier <|> symbol Identifier') <*> (Syntax.Identifier <$> (name <$> source))
<|> makeQualifiedIdentifier <$> symbol Attribute <*> children (attribute <|> identifierPair)
<|> makeQualifiedIdentifier <$> symbol DottedName <*> children (some identifier')
<|> symbol DottedName *> children identifier
where
attribute = (\a b -> a <> [b]) <$> (symbol Attribute *> children (attribute <|> identifierPair)) <*> identifier'
identifierPair = (\a b -> [a, b]) <$> identifier' <*> identifier'
identifier' = (symbol Identifier <|> symbol Identifier') *> source
makeQualifiedIdentifier loc xs = makeTerm loc (Syntax.Identifier (qualifiedName xs))
set :: Assignment
set = makeTerm <$> symbol Set <*> children (Literal.Set <$> manyTerm expression)
@ -376,24 +381,27 @@ comment = makeTerm <$> symbol Comment <*> (Comment.Comment <$> source)
import' :: Assignment
import' = makeTerm'' <$> symbol ImportStatement <*> children (manyTerm (aliasedImport <|> plainImport))
<|> makeTerm <$> symbol ImportFromStatement <*> children (Declaration.QualifiedImport <$> (dottedName <|> emptyTerm) <*> emptyTerm <*> some (aliasImportSymbol <|> importSymbol))
<|> makeTerm <$> symbol ImportFromStatement <*> children (Declaration.WildcardImport <$> dottedName <*> wildcard)
<|> makeTerm <$> symbol ImportFromStatement <*> children (Declaration.QualifiedImport <$> (identifier <|> emptyTerm) <*> emptyTerm <*> some (aliasImportSymbol <|> importSymbol))
<|> makeTerm <$> symbol ImportFromStatement <*> children (Declaration.WildcardImport <$> identifier <*> wildcard)
where
rawIdentifier = (symbol Identifier <|> symbol Identifier' <|> symbol DottedName) *> source
rawIdentifier = (name <$> identifier') <|> (qualifiedName <$> dottedName')
dottedName' = symbol DottedName *> children (some identifier')
identifier' = (symbol Identifier <|> symbol Identifier') *> source
makeNameAliasPair from (Just alias) = (from, alias)
makeNameAliasPair from Nothing = (from, from)
importSymbol = makeNameAliasPair <$> rawIdentifier <*> pure Nothing
aliasImportSymbol = symbol AliasedImport *> children (makeNameAliasPair <$> rawIdentifier <*> (Just <$> rawIdentifier))
wildcard = makeTerm <$> symbol WildcardImport <*> (Syntax.Identifier <$> source)
wildcard = makeTerm <$> symbol WildcardImport <*> (Syntax.Identifier <$> (name <$> source))
aliasedImport = makeImport <$> symbol AliasedImport <*> children ((,) <$> expression <*> (Just <$> expression))
plainImport = makeImport <$> symbol DottedName <*> children ((,) <$> expressions <*> pure Nothing)
plainImport = makeImport <$> location <*> ((,) <$> identifier <*> pure Nothing)
makeImport loc (from, Just alias) = makeTerm loc (Declaration.QualifiedImport from alias [])
makeImport loc (from, Nothing) = makeTerm loc (Declaration.QualifiedImport from from [])
assertStatement :: Assignment
assertStatement = makeTerm <$> symbol AssertStatement <*> children (Expression.Call <$> pure [] <*> (makeTerm <$> symbol AnonAssert <*> (Syntax.Identifier <$> source)) <*> manyTerm expression <*> emptyTerm)
assertStatement = makeTerm <$> symbol AssertStatement <*> children (Expression.Call <$> pure [] <*> (makeTerm <$> symbol AnonAssert <*> (Syntax.Identifier <$> (name <$> source))) <*> manyTerm expression <*> emptyTerm)
printStatement :: Assignment
printStatement = do
@ -402,25 +410,25 @@ printStatement = do
print <- term printKeyword
term (redirectCallTerm location print <|> printCallTerm location print)
where
printKeyword = makeTerm <$> symbol AnonPrint <*> (Syntax.Identifier <$> source)
printKeyword = makeTerm <$> symbol AnonPrint <*> (Syntax.Identifier <$> (name <$> source))
redirectCallTerm location identifier = makeTerm location <$ symbol Chevron <*> (flip Python.Syntax.Redirect <$> children (term expression) <*> term (printCallTerm location identifier))
printCallTerm location identifier = makeTerm location <$> (Expression.Call [] identifier <$> manyTerm expression <*> emptyTerm)
nonlocalStatement :: Assignment
nonlocalStatement = makeTerm <$> symbol NonlocalStatement <*> children (Expression.Call <$> pure [] <*> term (makeTerm <$> symbol AnonNonlocal <*> (Syntax.Identifier <$> source)) <*> manyTerm expression <*> emptyTerm)
nonlocalStatement = makeTerm <$> symbol NonlocalStatement <*> children (Expression.Call <$> pure [] <*> term (makeTerm <$> symbol AnonNonlocal <*> (Syntax.Identifier <$> (name <$> source))) <*> manyTerm expression <*> emptyTerm)
globalStatement :: Assignment
globalStatement = makeTerm <$> symbol GlobalStatement <*> children (Expression.Call <$> pure [] <*> term (makeTerm <$> symbol AnonGlobal <*> (Syntax.Identifier <$> source)) <*> manyTerm expression <*> emptyTerm)
globalStatement = makeTerm <$> symbol GlobalStatement <*> children (Expression.Call <$> pure [] <*> term (makeTerm <$> symbol AnonGlobal <*> (Syntax.Identifier <$> (name <$> source))) <*> manyTerm expression <*> emptyTerm)
await :: Assignment
await = makeTerm <$> symbol Await <*> children (Expression.Call <$> pure [] <*> term (makeTerm <$> symbol AnonAwait <*> (Syntax.Identifier <$> source)) <*> manyTerm expression <*> emptyTerm)
await = makeTerm <$> symbol Await <*> children (Expression.Call <$> pure [] <*> term (makeTerm <$> symbol AnonAwait <*> (Syntax.Identifier <$> (name <$> source))) <*> manyTerm expression <*> emptyTerm)
returnStatement :: Assignment
returnStatement = makeTerm <$> symbol ReturnStatement <*> children (Statement.Return <$> term (expressionList <|> emptyTerm))
deleteStatement :: Assignment
deleteStatement = makeTerm <$> symbol DeleteStatement <*> children (Expression.Call <$> pure [] <*> term deleteIdentifier <* symbol ExpressionList <*> children (manyTerm expression) <*> emptyTerm)
where deleteIdentifier = makeTerm <$> symbol AnonDel <*> (Syntax.Identifier <$> source)
where deleteIdentifier = makeTerm <$> symbol AnonDel <*> (Syntax.Identifier <$> (name <$> source))
raiseStatement :: Assignment
raiseStatement = makeTerm <$> symbol RaiseStatement <*> children (Statement.Throw <$> expressions)
@ -431,7 +439,7 @@ ifStatement = makeTerm <$> symbol IfStatement <*> children (Statement.If <$> ter
makeElif (loc, makeIf) rest = makeTerm loc (makeIf rest)
execStatement :: Assignment
execStatement = makeTerm <$> symbol ExecStatement <*> children (Expression.Call <$> pure [] <*> term (makeTerm <$> location <*> (Syntax.Identifier <$> source)) <*> manyTerm (string <|> expression) <*> emptyTerm)
execStatement = makeTerm <$> symbol ExecStatement <*> children (Expression.Call <$> pure [] <*> term (makeTerm <$> location <*> (Syntax.Identifier <$> (name <$> source))) <*> manyTerm (string <|> expression) <*> emptyTerm)
passStatement :: Assignment
passStatement = makeTerm <$> symbol PassStatement <*> (Statement.NoOp <$> emptyTerm <* advance)
@ -455,16 +463,7 @@ slice = makeTerm <$> symbol Slice <*> children
<*> (term expression <|> emptyTerm))
call :: Assignment
call = makeTerm <$> symbol Call <*> children (Expression.Call <$> pure [] <*> term qualifiedIdentifier <*> (symbol ArgumentList *> children (manyTerm expression) <|> someTerm comprehension) <*> emptyTerm)
where
qualifiedIdentifier = makeQualifiedIdentifier <$> symbol Attribute <*> children (attribute <|> identifierPair)
<|> makeTerm <$> location <*> (Syntax.QualifiedIdentifier <$> identifier)
attribute = (\a b -> a <> [b]) <$> (symbol Attribute *> children (attribute <|> identifierPair)) <*> identifier
identifierPair = (\a b -> [a, b]) <$> identifier <*> identifier
makeQualifiedIdentifier loc xs = makeTerm loc (Syntax.QualifiedIdentifier (makeTerm' loc (inj xs)))
call = makeTerm <$> symbol Call <*> children (Expression.Call <$> pure [] <*> term identifier <*> (symbol ArgumentList *> children (manyTerm expression) <|> someTerm comprehension) <*> emptyTerm)
boolean :: Assignment
boolean = makeTerm <$> token Grammar.True <*> pure Literal.true

View File

@ -6,11 +6,13 @@ module Language.Ruby.Assignment
, Term
) where
import Prologue hiding (for)
import Assigning.Assignment hiding (Assignment, Error)
import Data.Record
import Data.Abstract.FreeVariables
import Data.List (elem)
import Data.Record
import Data.Syntax (contextualize, postContextualize, emptyTerm, parseError, handleError, infixContext, makeTerm, makeTerm', makeTerm'', makeTerm1)
import Language.Ruby.Grammar as Grammar
import Prologue hiding (for)
import qualified Assigning.Assignment as Assignment
import qualified Data.Syntax as Syntax
import qualified Data.Syntax.Comment as Comment
@ -19,7 +21,6 @@ import qualified Data.Syntax.Expression as Expression
import qualified Data.Syntax.Literal as Literal
import qualified Data.Syntax.Statement as Statement
import qualified Data.Term as Term
import Language.Ruby.Grammar as Grammar
-- | The type of Ruby syntax.
type Syntax = '[
@ -156,7 +157,7 @@ identifier =
<|> mk BlockArgument
<|> mk ReservedIdentifier
<|> mk Uninterpreted
where mk s = makeTerm <$> symbol s <*> (Syntax.Identifier <$> source)
where mk s = makeTerm <$> symbol s <*> (Syntax.Identifier <$> (name <$> source))
-- TODO: Handle interpolation in all literals that support it (strings, regexes, symbols, subshells, etc).
literal :: Assignment
@ -187,7 +188,7 @@ keyword =
mk KeywordFILE
<|> mk KeywordLINE
<|> mk KeywordENCODING
where mk s = makeTerm <$> symbol s <*> (Syntax.Identifier <$> source)
where mk s = makeTerm <$> symbol s <*> (Syntax.Identifier <$> (name <$> source))
beginBlock :: Assignment
beginBlock = makeTerm <$> symbol BeginBlock <*> children (Statement.ScopeEntry <$> many expression)
@ -217,7 +218,7 @@ parameter =
<|> mk OptionalParameter
<|> makeTerm <$> symbol DestructuredParameter <*> children (many parameter)
<|> expression
where mk s = makeTerm <$> symbol s <*> (Syntax.Identifier <$> source)
where mk s = makeTerm <$> symbol s <*> (Syntax.Identifier <$> (name <$> source))
method :: Assignment
method = makeTerm <$> symbol Method <*> children (Declaration.Method <$> pure [] <*> emptyTerm <*> expression <*> params <*> expressions')
@ -243,12 +244,12 @@ comment :: Assignment
comment = makeTerm <$> symbol Comment <*> (Comment.Comment <$> source)
alias :: Assignment
alias = makeTerm <$> symbol Alias <*> children (Expression.Call <$> pure [] <*> name <*> some expression <*> emptyTerm)
where name = makeTerm <$> location <*> (Syntax.Identifier <$> source)
alias = makeTerm <$> symbol Alias <*> children (Expression.Call <$> pure [] <*> name' <*> some expression <*> emptyTerm)
where name' = makeTerm <$> location <*> (Syntax.Identifier <$> (name <$> source))
undef :: Assignment
undef = makeTerm <$> symbol Undef <*> children (Expression.Call <$> pure [] <*> name <*> some expression <*> emptyTerm)
where name = makeTerm <$> location <*> (Syntax.Identifier <$> source)
undef = makeTerm <$> symbol Undef <*> children (Expression.Call <$> pure [] <*> name' <*> some expression <*> emptyTerm)
where name' = makeTerm <$> location <*> (Syntax.Identifier <$> (name <$> source))
if' :: Assignment
if' = ifElsif If
@ -346,7 +347,7 @@ assignment' = makeTerm <$> symbol Assignment <*> children (Statement.As
lhs = makeTerm <$> symbol LeftAssignmentList <*> children (many expr) <|> expr
rhs = makeTerm <$> symbol RightAssignmentList <*> children (many expr) <|> expr
expr = makeTerm <$> symbol RestAssignment <*> (Syntax.Identifier <$> source)
expr = makeTerm <$> symbol RestAssignment <*> (Syntax.Identifier <$> (name <$> source))
<|> makeTerm <$> symbol DestructuredLeftAssignment <*> children (many expr)
<|> expression
@ -355,7 +356,7 @@ unary = symbol Unary >>= \ location ->
makeTerm location . Expression.Complement <$> children ( symbol AnonTilde *> expression )
<|> makeTerm location . Expression.Not <$> children ( symbol AnonBang *> expression )
<|> makeTerm location . Expression.Not <$> children ( symbol AnonNot *> expression )
<|> makeTerm location <$> children (Expression.Call <$> pure [] <*> (makeTerm <$> symbol AnonDefinedQuestion <*> (Syntax.Identifier <$> source)) <*> some expression <*> emptyTerm)
<|> makeTerm location <$> children (Expression.Call <$> pure [] <*> (makeTerm <$> symbol AnonDefinedQuestion <*> (Syntax.Identifier <$> (name <$> source))) <*> some expression <*> emptyTerm)
<|> makeTerm location . Expression.Negate <$> children ( symbol AnonMinus' *> expression )
<|> children ( symbol AnonPlus *> expression )

View File

@ -6,11 +6,13 @@ module Language.TypeScript.Assignment
, Term
) where
import Prologue
import Assigning.Assignment hiding (Assignment, Error)
import qualified Assigning.Assignment as Assignment
import Data.Abstract.FreeVariables
import Data.Record
import Data.Syntax (emptyTerm, handleError, parseError, infixContext, makeTerm, makeTerm', makeTerm'', makeTerm1, contextualize, postContextualize)
import Language.TypeScript.Grammar as Grammar
import Prologue
import qualified Assigning.Assignment as Assignment
import qualified Data.Syntax as Syntax
import qualified Data.Syntax.Comment as Comment
import qualified Data.Syntax.Declaration as Declaration
@ -18,9 +20,8 @@ import qualified Data.Syntax.Expression as Expression
import qualified Data.Syntax.Literal as Literal
import qualified Data.Syntax.Statement as Statement
import qualified Data.Syntax.Type as Type
import Language.TypeScript.Grammar as Grammar
import qualified Language.TypeScript.Syntax as TypeScript.Syntax
import qualified Data.Term as Term
import qualified Language.TypeScript.Syntax as TypeScript.Syntax
-- | The type of TypeScript syntax.
type Syntax = '[
@ -337,7 +338,7 @@ false :: Assignment
false = makeTerm <$> symbol Grammar.False <*> (Literal.false <$ source)
identifier :: Assignment
identifier = makeTerm <$> (symbol Identifier <|> symbol Identifier') <*> (Syntax.Identifier <$> source)
identifier = makeTerm <$> (symbol Identifier <|> symbol Identifier') <*> (Syntax.Identifier <$> (name <$> source))
class' :: Assignment
class' = makeClass <$> symbol Class <*> children ((,,,,) <$> manyTerm decorator <*> term identifier <*> (symbol TypeParameters *> children (manyTerm typeParameter') <|> pure []) <*> (classHeritage' <|> pure []) <*> classBodyStatements)
@ -390,7 +391,7 @@ jsxAttribute = makeTerm <$> symbol Grammar.JsxAttribute <*> children (TypeScript
where jsxAttributeValue = choice [ string, jsxExpression', jsxElement', jsxFragment ]
propertyIdentifier :: Assignment
propertyIdentifier = makeTerm <$> symbol PropertyIdentifier <*> (Syntax.Identifier <$> source)
propertyIdentifier = makeTerm <$> symbol PropertyIdentifier <*> (Syntax.Identifier <$> (name <$> source))
sequenceExpression :: Assignment
sequenceExpression = makeTerm <$> symbol Grammar.SequenceExpression <*> children (Expression.SequenceExpression <$> term expression <*> term expressions)
@ -405,7 +406,7 @@ parameter =
<|> optionalParameter
accessibilityModifier' :: Assignment
accessibilityModifier' = makeTerm <$> symbol AccessibilityModifier <*> children (Syntax.Identifier <$> source)
accessibilityModifier' = makeTerm <$> symbol AccessibilityModifier <*> children (Syntax.Identifier <$> (name <$> source))
destructuringPattern :: Assignment
destructuringPattern = object <|> array
@ -628,7 +629,7 @@ labeledStatement :: Assignment
labeledStatement = makeTerm <$> symbol Grammar.LabeledStatement <*> children (TypeScript.Syntax.LabeledStatement <$> statementIdentifier <*> term statement)
statementIdentifier :: Assignment
statementIdentifier = makeTerm <$> symbol StatementIdentifier <*> (Syntax.Identifier <$> source)
statementIdentifier = makeTerm <$> symbol StatementIdentifier <*> (Syntax.Identifier <$> (name <$> source))
importStatement :: Assignment
importStatement = makeImportTerm <$> symbol Grammar.ImportStatement <*> children ((,) <$> importClause <*> term string)
@ -661,7 +662,7 @@ importStatement = makeImportTerm <$> symbol Grammar.ImportStatement <*> children
namespaceImport = symbol Grammar.NamespaceImport *> children ((,,) <$> pure Prelude.True <*> (Just <$> (term identifier)) <*> pure []) -- import * as name from "./foo"
importSymbol = symbol Grammar.ImportSpecifier *> children (makeNameAliasPair <$> rawIdentifier <*> (Just <$> rawIdentifier))
<|> symbol Grammar.ImportSpecifier *> children (makeNameAliasPair <$> rawIdentifier <*> (pure Nothing))
rawIdentifier = (symbol Identifier <|> symbol Identifier') *> source
rawIdentifier = (symbol Identifier <|> symbol Identifier') *> (name <$> source)
makeNameAliasPair from (Just alias) = (from, alias)
makeNameAliasPair from Nothing = (from, from)
@ -724,7 +725,7 @@ propertySignature = makePropertySignature <$> symbol Grammar.PropertySignature <
where makePropertySignature loc (modifier, readonly, propertyName, annotation) = makeTerm loc (TypeScript.Syntax.PropertySignature [modifier, readonly, annotation] propertyName)
propertyName :: Assignment
propertyName = (makeTerm <$> symbol PropertyIdentifier <*> (Syntax.Identifier <$> source)) <|> term string <|> term number <|> term computedPropertyName
propertyName = (makeTerm <$> symbol PropertyIdentifier <*> (Syntax.Identifier <$> (name <$> source))) <|> term string <|> term number <|> term computedPropertyName
computedPropertyName :: Assignment
computedPropertyName = makeTerm <$> symbol Grammar.ComputedPropertyName <*> children (TypeScript.Syntax.ComputedPropertyName <$> term expression)

View File

@ -47,6 +47,7 @@ import qualified Data.Syntax as Syntax
import qualified Data.Syntax.Comment as Comment
import qualified Data.Syntax.Declaration as Declaration
import qualified Data.Syntax.Statement as Statement
import qualified Data.Abstract.FreeVariables as FV
import Data.Term
import Data.Text as T (Text, pack)
import qualified Data.Text.Encoding as T
@ -256,6 +257,8 @@ type ListableSyntax = Union
, []
]
instance Listable FV.Name where
tiers = cons1 FV.Name
instance Listable1 Gram where
liftTiers tiers = liftCons2 (liftTiers (liftTiers tiers)) (liftTiers (liftTiers tiers)) Gram

View File

@ -1,6 +1,7 @@
{-# LANGUAGE DataKinds #-}
module Diffing.Algorithm.RWS.Spec where
import Data.Abstract.FreeVariables
import Analysis.Decorator
import Data.Array.IArray
import Data.Bifunctor
@ -36,7 +37,7 @@ spec = parallel $ do
(beforeTerm diff, afterTerm diff) `shouldBe` (Just (wrap (stripTerm <$> tas)), Just (wrap (stripTerm <$> tbs)))
it "produces unbiased insertions within branches" $
let (a, b) = (decorate (termIn Nil (inj [ termIn Nil (inj (Syntax.Identifier "a")) ])), decorate (termIn Nil (inj [ termIn Nil (inj (Syntax.Identifier "b")) ]))) in
let (a, b) = (decorate (termIn Nil (inj [ termIn Nil (inj (Syntax.Identifier (name "a"))) ])), decorate (termIn Nil (inj [ termIn Nil (inj (Syntax.Identifier (name "b"))) ]))) in
fmap (bimap stripTerm stripTerm) (rws comparableTerms (equalTerms comparableTerms) [ b ] [ a, b ]) `shouldBe` fmap (bimap stripTerm stripTerm) [ That a, These b b ]
where decorate = defaultFeatureVectorDecorator constructorNameAndConstantFields

View File

@ -1,15 +1,16 @@
{-# LANGUAGE DataKinds #-}
module Diffing.Interpreter.Spec where
import Data.Abstract.FreeVariables
import Data.Diff
import Data.Functor.Both
import Data.Functor.Foldable hiding (Nil)
import Data.Functor.Listable
import Data.Record
import qualified Data.Syntax as Syntax
import Data.Term
import Data.Union
import Diffing.Interpreter
import qualified Data.Syntax as Syntax
import Test.Hspec (Spec, describe, it, parallel)
import Test.Hspec.Expectations.Pretty
import Test.Hspec.LeanCheck
@ -18,8 +19,8 @@ spec :: Spec
spec = parallel $ 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
let termA = termIn Nil (inj (Syntax.Identifier (name "t\776")))
termB = termIn Nil (inj (Syntax.Identifier (name "\7831"))) in
diffTerms termA termB `shouldBe` replacing termA (termB :: Term ListableSyntax (Record '[]))
prop "produces correct diffs" $
@ -31,7 +32,7 @@ spec = parallel $ do
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 '[])
let term s = termIn Nil (inj [ termIn Nil (inj (Syntax.Identifier (name s))) ]) :: Term ListableSyntax (Record '[])
wrap = termIn Nil . inj in
diffTerms (wrap [ term "b" ]) (wrap [ term "a", term "b" ]) `shouldBe` merge (Nil, Nil) (inj [ inserting (term "a"), merging (term "b") ])

View File

@ -3,6 +3,7 @@ module Rendering.TOC.Spec where
import Analysis.Decorator (constructorNameAndConstantFields)
import Analysis.Declaration
import Data.Abstract.FreeVariables
import Data.Aeson
import Data.Bifunctor
import Data.Blob
@ -188,14 +189,14 @@ programWithChange :: Term' -> Diff'
programWithChange body = merge (programInfo, programInfo) (inj [ function' ])
where
function' = merge (Just (FunctionDeclaration "foo" mempty Nothing) :. emptyInfo, Just (FunctionDeclaration "foo" mempty Nothing) :. emptyInfo) (inj (Declaration.Function [] name' [] (merge (Nothing :. emptyInfo, Nothing :. emptyInfo) (inj [ inserting body ]))))
name' = let info = Nothing :. emptyInfo in merge (info, info) (inj (Syntax.Identifier "foo"))
name' = let info = Nothing :. emptyInfo in merge (info, info) (inj (Syntax.Identifier (name "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) (inj [ function', term' ])
where
function' = merge (Just (FunctionDeclaration "foo" mempty Nothing) :. emptyInfo, Just (FunctionDeclaration "foo" mempty Nothing) :. emptyInfo) (inj (Declaration.Function [] name' [] (merge (Nothing :. emptyInfo, Nothing :. emptyInfo) (inj []))))
name' = let info = Nothing :. emptyInfo in merge (info, info) (inj (Syntax.Identifier "foo"))
name' = let info = Nothing :. emptyInfo in merge (info, info) (inj (Syntax.Identifier (name "foo")))
term' = inserting term
programWithInsert :: Text -> Term' -> Diff'
@ -211,9 +212,9 @@ programOf :: Diff' -> Diff'
programOf diff = merge (programInfo, programInfo) (inj [ diff ])
functionOf :: Text -> Term' -> Term'
functionOf name body = termIn (Just (FunctionDeclaration name mempty Nothing) :. emptyInfo) (inj (Declaration.Function [] name' [] (termIn (Nothing :. emptyInfo) (inj [body]))))
functionOf n body = termIn (Just (FunctionDeclaration n mempty Nothing) :. emptyInfo) (inj (Declaration.Function [] name' [] (termIn (Nothing :. emptyInfo) (inj [body]))))
where
name' = termIn (Nothing :. emptyInfo) (inj (Syntax.Identifier (encodeUtf8 name)))
name' = termIn (Nothing :. emptyInfo) (inj (Syntax.Identifier (name (encodeUtf8 n))))
programInfo :: Record '[Maybe Declaration, Range, Span]
programInfo = Nothing :. emptyInfo
@ -240,7 +241,7 @@ blobsForPaths :: Both FilePath -> IO BlobPair
blobsForPaths = readFilePair . fmap ("test/fixtures/toc/" <>)
blankDiff :: Diff'
blankDiff = merge (arrayInfo, arrayInfo) (inj [ inserting (termIn literalInfo (inj (Syntax.Identifier "\"a\""))) ])
blankDiff = merge (arrayInfo, arrayInfo) (inj [ inserting (termIn literalInfo (inj (Syntax.Identifier (name "\"a\"")))) ])
where
arrayInfo = Nothing :. Range 0 3 :. Span (Pos 1 1) (Pos 1 5) :. Nil
literalInfo = Nothing :. Range 1 2 :. Span (Pos 1 2) (Pos 1 4) :. Nil