mirror of
https://github.com/github/semantic.git
synced 2024-12-29 18:06:14 +03:00
Merge remote-tracking branch 'origin/master' into preludes-and-subclassing
This commit is contained in:
commit
1e2fc5f6d3
@ -72,6 +72,7 @@ library
|
||||
, Data.Patch
|
||||
, Data.Range
|
||||
, Data.Record
|
||||
, Data.Semigroup.App
|
||||
, Data.Source
|
||||
, Data.Span
|
||||
, Data.SplitDiff
|
||||
@ -211,6 +212,7 @@ test-suite test
|
||||
main-is: Spec.hs
|
||||
other-modules: Assigning.Assignment.Spec
|
||||
, Analysis.Go.Spec
|
||||
, Analysis.PHP.Spec
|
||||
, Analysis.Python.Spec
|
||||
, Analysis.Ruby.Spec
|
||||
, Analysis.TypeScript.Spec
|
||||
|
@ -4,6 +4,8 @@ module Analysis.Abstract.Evaluating
|
||||
, evaluate
|
||||
, evaluates
|
||||
, evaluateWith
|
||||
, require
|
||||
, load
|
||||
) where
|
||||
|
||||
import Control.Abstract.Evaluator
|
||||
@ -13,6 +15,9 @@ import Control.Monad.Effect.Reader
|
||||
import Control.Monad.Effect.State
|
||||
import Data.Abstract.Configuration
|
||||
import qualified Data.Abstract.Environment as Env
|
||||
import Data.Abstract.Environment (Environment)
|
||||
import qualified Data.Abstract.Exports as Export
|
||||
import Data.Abstract.Exports (Exports)
|
||||
import Data.Abstract.Evaluatable
|
||||
import Data.Abstract.ModuleTable
|
||||
import Data.Abstract.Value
|
||||
@ -90,6 +95,46 @@ withModules Blob{..} pairs = localModuleTable (const moduleTable)
|
||||
_ -> toName path
|
||||
toName str = qualifiedName (fmap BC.pack (splitWhen (== pathSeparator) str))
|
||||
|
||||
-- | Require/import another module by name and return it's environment and value.
|
||||
--
|
||||
-- Looks up the term's name in the cache of evaluated modules first, returns if found, otherwise loads/evaluates the module.
|
||||
require :: (MonadAnalysis term value m, MonadValue value m)
|
||||
=> ModuleName
|
||||
-> m (EnvironmentFor value, value)
|
||||
require name = getModuleTable >>= maybe (load name) pure . moduleTableLookup name
|
||||
|
||||
-- | Load another module by name and return it's environment and value.
|
||||
--
|
||||
-- Always loads/evaluates.
|
||||
load :: (MonadAnalysis term value m, MonadValue value m)
|
||||
=> ModuleName
|
||||
-> m (EnvironmentFor value, value)
|
||||
load name = askModuleTable >>= maybe notFound evalAndCache . moduleTableLookup name
|
||||
where
|
||||
notFound = fail ("cannot load module: " <> show name)
|
||||
evalAndCache :: (MonadAnalysis term value m, MonadValue value m) => [term] -> m (EnvironmentFor value, value)
|
||||
evalAndCache [] = (,) <$> pure mempty <*> unit
|
||||
evalAndCache [x] = evalAndCache' x
|
||||
evalAndCache (x:xs) = do
|
||||
(env, _) <- evalAndCache' x
|
||||
(env', v') <- evalAndCache xs
|
||||
pure (env <> env', v')
|
||||
|
||||
evalAndCache' :: (MonadAnalysis term value m) => term -> m (EnvironmentFor value, value)
|
||||
evalAndCache' x = do
|
||||
v <- evaluateModule x
|
||||
env <- filterEnv <$> getExports <*> getEnv
|
||||
modifyModuleTable (moduleTableInsert name (env, v))
|
||||
pure (env, v)
|
||||
|
||||
-- TODO: If the set of exports is empty because no exports have been
|
||||
-- defined, do we export all terms, or no terms? This behavior varies across
|
||||
-- languages. We need better semantics rather than doing it ad-hoc.
|
||||
filterEnv :: Exports l a -> Environment l a -> Environment l a
|
||||
filterEnv ports env
|
||||
| Export.null ports = env
|
||||
| otherwise = Export.toEnvironment ports <> Env.overwrite (Export.aliases ports) env
|
||||
|
||||
-- | An analysis evaluating @term@s to @value@s with a list of @effects@ using 'Evaluatable', and producing incremental results of type @a@.
|
||||
newtype Evaluating term value effects a = Evaluating (Eff effects a)
|
||||
deriving (Applicative, Functor, Effectful, Monad)
|
||||
@ -101,14 +146,14 @@ deriving instance Member NonDetEff effects => MonadNonDet (Evaluating term value
|
||||
|
||||
-- | Effects necessary for evaluating (whether concrete or abstract).
|
||||
type EvaluatingEffects term value
|
||||
= '[ Fail -- Failure with an error message
|
||||
, State (EnvironmentFor value) -- Environments (both local and global)
|
||||
, State (HeapFor value) -- The heap
|
||||
, Reader (ModuleTable [term]) -- Cache of unevaluated modules
|
||||
, Reader (EnvironmentFor value) -- Default environment used by evaluateModule
|
||||
, State (ModuleTable (EnvironmentFor value)) -- Cache of evaluated modules
|
||||
, State (ExportsFor value) -- Exports (used to filter environments when they are imported)
|
||||
, State (IntMap.IntMap term) -- For jumps
|
||||
= '[ Fail -- Failure with an error message
|
||||
, State (EnvironmentFor value) -- Environments (both local and global)
|
||||
, State (HeapFor value) -- The heap
|
||||
, Reader (ModuleTable [term]) -- Cache of unevaluated modules
|
||||
, Reader (EnvironmentFor value) -- Default environment used by evaluateModule
|
||||
, State (ModuleTable (EnvironmentFor value, value)) -- Cache of evaluated modules
|
||||
, State (ExportsFor value) -- Exports (used to filter environments when they are imported)
|
||||
, State (IntMap.IntMap term) -- For jumps
|
||||
]
|
||||
|
||||
instance Members '[Fail, State (IntMap.IntMap term)] effects => MonadControl term (Evaluating term value effects) where
|
||||
@ -144,7 +189,7 @@ instance Member (State (HeapFor value)) effects => MonadHeap value (Evaluating t
|
||||
getHeap = raise get
|
||||
putHeap = raise . put
|
||||
|
||||
instance Members '[Reader (ModuleTable [term]), State (ModuleTable (EnvironmentFor value))] effects => MonadModuleTable term value (Evaluating term value effects) where
|
||||
instance Members '[Reader (ModuleTable [term]), State (ModuleTable (EnvironmentFor value, value))] effects => MonadModuleTable term value (Evaluating term value effects) where
|
||||
getModuleTable = raise get
|
||||
putModuleTable = raise . put
|
||||
|
||||
|
@ -3,8 +3,6 @@
|
||||
module Control.Abstract.Analysis
|
||||
( MonadAnalysis(..)
|
||||
, evaluateTerm
|
||||
, require
|
||||
, load
|
||||
, liftAnalyze
|
||||
, runAnalysis
|
||||
, module X
|
||||
@ -20,14 +18,8 @@ import qualified Control.Monad.Effect as Effect
|
||||
import Control.Monad.Effect.Fail as X
|
||||
import Control.Monad.Effect.Reader as X
|
||||
import Control.Monad.Effect.State as X
|
||||
import Data.Abstract.Environment (Environment)
|
||||
import qualified Data.Abstract.Environment as Env
|
||||
import Data.Abstract.Exports (Exports)
|
||||
import qualified Data.Abstract.Exports as Export
|
||||
import Data.Abstract.ModuleTable
|
||||
import Data.Abstract.Value
|
||||
import Data.Coerce
|
||||
import Prelude hiding (fail)
|
||||
import Prelude
|
||||
import Prologue
|
||||
|
||||
-- | A 'Monad' in which one can evaluate some specific term type to some specific value type.
|
||||
@ -54,44 +46,6 @@ class (MonadEvaluator term value m, Recursive term) => MonadAnalysis term value
|
||||
evaluateTerm :: MonadAnalysis term value m => term -> m value
|
||||
evaluateTerm = foldSubterms analyzeTerm
|
||||
|
||||
|
||||
-- | Require/import another term/file and return an Effect.
|
||||
--
|
||||
-- Looks up the term's name in the cache of evaluated modules first, returns a value if found, otherwise loads/evaluates the module.
|
||||
require :: ( MonadAnalysis term value m
|
||||
, Ord (LocationFor value)
|
||||
)
|
||||
=> ModuleName
|
||||
-> m (EnvironmentFor value)
|
||||
require name = getModuleTable >>= maybe (load name) pure . moduleTableLookup name
|
||||
|
||||
-- | Load another term/file and return an Effect.
|
||||
--
|
||||
-- Always loads/evaluates.
|
||||
load :: ( MonadAnalysis term value m
|
||||
, Ord (LocationFor value)
|
||||
)
|
||||
=> ModuleName
|
||||
-> m (EnvironmentFor value)
|
||||
load name = askModuleTable >>= maybe notFound evalAndCache . moduleTableLookup name
|
||||
where
|
||||
notFound = fail ("cannot load module: " <> show name)
|
||||
evalAndCache :: (MonadAnalysis term value m, Ord (LocationFor value)) => [term] -> m (EnvironmentFor value)
|
||||
evalAndCache [] = pure mempty
|
||||
evalAndCache (x:xs) = do
|
||||
void $ evaluateModule x
|
||||
env <- filterEnv <$> getExports <*> getEnv
|
||||
modifyModuleTable (moduleTableInsert name env)
|
||||
(env <>) <$> evalAndCache xs
|
||||
|
||||
-- TODO: If the set of exports is empty because no exports have been
|
||||
-- defined, do we export all terms, or no terms? This behavior varies across
|
||||
-- languages. We need better semantics rather than doing it ad-hoc.
|
||||
filterEnv :: (Ord l) => Exports l a -> Environment l a -> Environment l a
|
||||
filterEnv ports env
|
||||
| Export.null ports = env
|
||||
| otherwise = Export.toEnvironment ports <> Env.overwrite (Export.aliases ports) env
|
||||
|
||||
-- | Lift a 'SubtermAlgebra' for an underlying analysis into a containing analysis. Use this when defining an analysis which can be composed onto other analyses to ensure that a call to 'analyzeTerm' occurs in the inner analysis and not the outer one.
|
||||
liftAnalyze :: ( Coercible ( m term value (effects :: [* -> *]) value) (t m term value effects value)
|
||||
, Coercible (t m term value effects value) ( m term value effects value)
|
||||
|
@ -129,9 +129,9 @@ assign address = modifyHeap . heapInsert address
|
||||
-- | A 'Monad' abstracting tables of modules available for import.
|
||||
class Monad m => MonadModuleTable term value m | m -> term, m -> value where
|
||||
-- | Retrieve the table of evaluated modules.
|
||||
getModuleTable :: m (ModuleTable (EnvironmentFor value))
|
||||
getModuleTable :: m (ModuleTable (EnvironmentFor value, value))
|
||||
-- | Set the table of evaluated modules.
|
||||
putModuleTable :: ModuleTable (EnvironmentFor value) -> m ()
|
||||
putModuleTable :: ModuleTable (EnvironmentFor value, value) -> m ()
|
||||
|
||||
-- | Retrieve the table of unevaluated modules.
|
||||
askModuleTable :: m (ModuleTable [term])
|
||||
@ -139,7 +139,7 @@ class Monad m => MonadModuleTable term value m | m -> term, m -> value where
|
||||
localModuleTable :: (ModuleTable [term] -> ModuleTable [term]) -> m a -> m a
|
||||
|
||||
-- | Update the evaluated module table.
|
||||
modifyModuleTable :: MonadModuleTable term value m => (ModuleTable (EnvironmentFor value) -> ModuleTable (EnvironmentFor value)) -> m ()
|
||||
modifyModuleTable :: MonadModuleTable term value m => (ModuleTable (EnvironmentFor value, value) -> ModuleTable (EnvironmentFor value, value)) -> m ()
|
||||
modifyModuleTable f = do
|
||||
table <- getModuleTable
|
||||
putModuleTable $! f table
|
||||
|
@ -88,7 +88,7 @@ class (Monad m, Show value) => MonadValue value m where
|
||||
|
||||
-- | Build a class value from a name and environment.
|
||||
klass :: Name -- ^ The new class's identifier
|
||||
-> Maybe value -- ^ A list of superclasses
|
||||
-> Maybe value -- ^ An optional superclass.
|
||||
-> EnvironmentFor value -- ^ The environment to capture
|
||||
-> m value
|
||||
|
||||
@ -236,7 +236,6 @@ instance ( Monad m
|
||||
injValue . Closure names l . Env.bind (foldr Set.delete (freeVariables body) names) <$> getEnv
|
||||
|
||||
apply op params
|
||||
| Just klass@Class{} <- prjValue op = pure . injValue $ klass
|
||||
| Just (Closure names label env) <- prjValue op = do
|
||||
bindings <- foldr (\ (name, param) rest -> do
|
||||
v <- param
|
||||
|
@ -16,6 +16,7 @@ import Data.Abstract.Value
|
||||
import Data.Functor.Classes
|
||||
import Data.Proxy
|
||||
import Data.Semigroup.Foldable
|
||||
import Data.Semigroup.App
|
||||
import Data.Term
|
||||
import Prelude hiding (fail)
|
||||
import Prologue
|
||||
@ -51,14 +52,4 @@ instance Evaluatable s => Evaluatable (TermF s a) where
|
||||
-- 3. Only the last statement’s return value is returned.
|
||||
instance Evaluatable [] where
|
||||
-- 'nonEmpty' and 'foldMap1' enable us to return the last statement’s result instead of 'unit' for non-empty lists.
|
||||
eval = maybe unit (runImperative . foldMap1 (Imperative . subtermValue)) . nonEmpty
|
||||
|
||||
-- | A 'Semigroup' providing an imperative context which extends the local environment with new bindings.
|
||||
newtype Imperative m a = Imperative { runImperative :: m a }
|
||||
|
||||
instance MonadEnvironment value m => Semigroup (Imperative m a) where
|
||||
Imperative a <> Imperative b = Imperative (a *> b)
|
||||
|
||||
instance (MonadEnvironment value m, MonadValue value m) => Monoid (Imperative m value) where
|
||||
mempty = Imperative unit
|
||||
mappend = (<>)
|
||||
eval = maybe unit (runApp . foldMap1 (App . subtermValue)) . nonEmpty
|
||||
|
@ -5,7 +5,6 @@ import Prologue
|
||||
import Data.Term
|
||||
import Data.ByteString (intercalate)
|
||||
import qualified Data.List.NonEmpty as NonEmpty
|
||||
import Data.Abstract.Path
|
||||
|
||||
-- | The type of variable names.
|
||||
type Name = NonEmpty ByteString
|
||||
@ -18,10 +17,6 @@ name x = x :| []
|
||||
qualifiedName :: [ByteString] -> Name
|
||||
qualifiedName = NonEmpty.fromList
|
||||
|
||||
-- | Construct a qualified 'Name' from a `/` delimited path.
|
||||
pathToQualifiedName :: ByteString -> Name
|
||||
pathToQualifiedName = qualifiedName . splitOnPathSeparator
|
||||
|
||||
-- | User friendly 'ByteString' of a qualified 'Name'.
|
||||
friendlyName :: Name -> ByteString
|
||||
friendlyName xs = intercalate "." (NonEmpty.toList xs)
|
||||
|
@ -3,17 +3,12 @@ module Data.Abstract.Path where
|
||||
import Prologue
|
||||
import qualified Data.ByteString.Char8 as BC
|
||||
import qualified Data.ByteString as B
|
||||
import Data.Char (ord)
|
||||
|
||||
-- | Split a 'ByteString' path on `/`, stripping quotes and any `./` prefix.
|
||||
splitOnPathSeparator :: ByteString -> [ByteString]
|
||||
splitOnPathSeparator = splitOnPathSeparator' id
|
||||
|
||||
splitOnPathSeparator' :: (ByteString -> ByteString) -> ByteString -> [ByteString]
|
||||
splitOnPathSeparator' f = BC.split '/' . f . dropRelativePrefix . stripQuotes
|
||||
splitOnPathSeparator = BC.split '/'
|
||||
|
||||
stripQuotes :: ByteString -> ByteString
|
||||
stripQuotes = B.filter (/= fromIntegral (ord '\"'))
|
||||
stripQuotes = B.filter (`B.notElem` "\'\"")
|
||||
|
||||
dropRelativePrefix :: ByteString -> ByteString
|
||||
dropRelativePrefix = BC.dropWhile (== '/') . BC.dropWhile (== '.')
|
||||
|
39
src/Data/Semigroup/App.hs
Normal file
39
src/Data/Semigroup/App.hs
Normal file
@ -0,0 +1,39 @@
|
||||
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
||||
module Data.Semigroup.App
|
||||
( App(..)
|
||||
, AppMerge(..)
|
||||
) where
|
||||
|
||||
import Control.Applicative
|
||||
import Data.Semigroup
|
||||
|
||||
-- $setup
|
||||
-- >>> import Test.QuickCheck
|
||||
-- >>> instance Arbitrary (f a) => Arbitrary (App f a) where arbitrary = App <$> arbitrary ; shrink = map App . shrink . runApp
|
||||
-- >>> instance Arbitrary (f a) => Arbitrary (AppMerge f a) where arbitrary = AppMerge <$> arbitrary ; shrink = map AppMerge . shrink . runAppMerge
|
||||
|
||||
-- | 'Semigroup' under '*>'.
|
||||
newtype App f a = App { runApp :: f a }
|
||||
deriving (Alternative, Applicative, Bounded, Enum, Eq, Foldable, Functor, Monad, Ord, Show, Traversable)
|
||||
|
||||
-- $ Associativity:
|
||||
-- prop> \ a b c -> a <> (b <> c) == (a <> b) <> (c :: App Maybe Integer)
|
||||
instance Applicative f => Semigroup (App f a) where
|
||||
App a <> App b = App (a *> b)
|
||||
|
||||
|
||||
-- | 'Semigroup' and 'Monoid' under '<*>' and '<>'.
|
||||
newtype AppMerge f a = AppMerge { runAppMerge :: f a }
|
||||
deriving (Alternative, Applicative, Bounded, Enum, Eq, Foldable, Functor, Monad, Ord, Show, Traversable)
|
||||
|
||||
-- $ Associativity:
|
||||
-- prop> \ a b c -> a <> (b <> c) == (a <> b) <> (c :: AppMerge Maybe String)
|
||||
instance (Applicative f, Semigroup a) => Semigroup (AppMerge f a) where
|
||||
AppMerge a <> AppMerge b = AppMerge ((<>) <$> a <*> b)
|
||||
|
||||
-- $ Identity:
|
||||
-- prop> \ a -> mempty <> a == (a :: AppMerge Maybe String)
|
||||
-- prop> \ a -> a <> mempty == (a :: AppMerge Maybe String)
|
||||
instance (Applicative f, Monoid a, Semigroup a) => Monoid (AppMerge f a) where
|
||||
mempty = AppMerge (pure mempty)
|
||||
mappend = (<>)
|
@ -1,6 +1,7 @@
|
||||
{-# LANGUAGE DeriveAnyClass, MultiParamTypeClasses, ScopedTypeVariables, UndecidableInstances #-}
|
||||
module Data.Syntax.Declaration where
|
||||
|
||||
import Analysis.Abstract.Evaluating
|
||||
import qualified Data.Abstract.Environment as Env
|
||||
import Data.Abstract.Evaluatable
|
||||
import Diffing.Algorithm
|
||||
@ -244,7 +245,7 @@ instance Show1 QualifiedExportFrom where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable QualifiedExportFrom where
|
||||
eval (QualifiedExportFrom from exportSymbols) = do
|
||||
let moduleName = freeVariable (subterm from)
|
||||
importedEnv <- isolate (require moduleName)
|
||||
(importedEnv, _) <- isolate (require moduleName)
|
||||
-- Look up addresses in importedEnv and insert the aliases with addresses into the exports.
|
||||
for_ exportSymbols $ \(name, alias) -> do
|
||||
let address = Env.lookup name importedEnv
|
||||
@ -277,7 +278,7 @@ instance Show1 QualifiedImport where liftShowsPrec = genericLiftShowsPrec
|
||||
|
||||
instance Evaluatable QualifiedImport where
|
||||
eval (QualifiedImport from alias xs) = do
|
||||
importedEnv <- isolate (require moduleName)
|
||||
(importedEnv, _) <- isolate (require moduleName)
|
||||
modifyEnv (mappend (Env.overwrite (renames importedEnv) importedEnv))
|
||||
unit
|
||||
where
|
||||
@ -300,7 +301,7 @@ instance Show1 Import where liftShowsPrec = genericLiftShowsPrec
|
||||
|
||||
instance Evaluatable Import where
|
||||
eval (Import from xs _) = do
|
||||
importedEnv <- isolate (require moduleName)
|
||||
(importedEnv, _) <- isolate (require moduleName)
|
||||
modifyEnv (mappend (renamed importedEnv))
|
||||
unit
|
||||
where
|
||||
|
@ -393,7 +393,7 @@ importDeclaration = makeTerm'' <$> symbol ImportDeclaration <*> children (manyTe
|
||||
namedImport = inj <$> (flip Declaration.QualifiedImport <$> packageIdentifier <*> importFromPath <*> pure [])
|
||||
-- `import "lib/Math"`
|
||||
plainImport = inj <$> (symbol InterpretedStringLiteral >>= \loc -> do
|
||||
names <- splitOnPathSeparator <$> source
|
||||
names <- toName <$> source
|
||||
let from = makeTerm loc (Syntax.Identifier (qualifiedName names))
|
||||
let alias = makeTerm loc (Syntax.Identifier (name (last names))) -- Go takes `import "lib/Math"` and uses `Math` as the qualified name (e.g. `Math.Sin()`)
|
||||
Declaration.QualifiedImport <$> pure from <*> pure alias <*> pure [])
|
||||
@ -403,7 +403,11 @@ importDeclaration = makeTerm'' <$> symbol ImportDeclaration <*> children (manyTe
|
||||
underscore = makeTerm <$> symbol BlankIdentifier <*> (Literal.TextElement <$> source)
|
||||
importSpec = makeTerm' <$> symbol ImportSpec <*> children (sideEffectImport <|> dotImport <|> namedImport <|> plainImport)
|
||||
importSpecList = makeTerm <$> symbol ImportSpecList <*> children (manyTerm (importSpec <|> comment))
|
||||
importFromPath = makeTerm <$> symbol InterpretedStringLiteral <*> (Syntax.Identifier <$> (pathToQualifiedName <$> source))
|
||||
importFromPath = makeTerm <$> symbol InterpretedStringLiteral <*> (Syntax.Identifier <$> (toQualifiedName <$> source))
|
||||
|
||||
toQualifiedName = qualifiedName . toName
|
||||
toName = splitOnPathSeparator . dropRelativePrefix . stripQuotes
|
||||
|
||||
|
||||
indexExpression :: Assignment
|
||||
indexExpression = makeTerm <$> symbol IndexExpression <*> children (Expression.Subscript <$> expression <*> manyTerm expression)
|
||||
|
@ -1,393 +1,491 @@
|
||||
{-# LANGUAGE DeriveAnyClass #-}
|
||||
module Language.PHP.Syntax where
|
||||
|
||||
import Prologue hiding (Text)
|
||||
import Analysis.Abstract.Evaluating
|
||||
import Data.Abstract.Evaluatable
|
||||
import Data.Abstract.Path
|
||||
import Diffing.Algorithm
|
||||
import Prologue hiding (Text)
|
||||
|
||||
|
||||
newtype Text a = Text ByteString
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 Text where liftEq = genericLiftEq
|
||||
instance Ord1 Text where liftCompare = genericLiftCompare
|
||||
instance Show1 Text where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable Text
|
||||
|
||||
|
||||
newtype VariableName a = VariableName a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 VariableName where liftEq = genericLiftEq
|
||||
instance Ord1 VariableName where liftCompare = genericLiftCompare
|
||||
instance Show1 VariableName where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable VariableName
|
||||
|
||||
newtype RequireOnce a = RequireOnce a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
-- TODO: Variables defined in an included file take on scope of the source line
|
||||
-- on which the inclusion occurs in the including file. However, functions and
|
||||
-- classes defined in the included file are always in global scope.
|
||||
|
||||
instance Eq1 RequireOnce where liftEq = genericLiftEq
|
||||
instance Ord1 RequireOnce where liftCompare = genericLiftCompare
|
||||
instance Show1 RequireOnce where liftShowsPrec = genericLiftShowsPrec
|
||||
-- TODO: If inclusion occurs inside a function definition within the including
|
||||
-- file, the complete contents of the included file are treated as though it
|
||||
-- were defined inside that function.
|
||||
|
||||
doInclude :: (MonadValue value m, MonadAnalysis term value m) => Subterm t (m value) -> m value
|
||||
doInclude path = do
|
||||
name <- toQualifiedName <$> (subtermValue path >>= asString)
|
||||
(importedEnv, v) <- isolate (load name)
|
||||
modifyEnv (mappend importedEnv)
|
||||
pure v
|
||||
|
||||
doIncludeOnce :: (MonadValue value m, MonadAnalysis term value m) => Subterm t (m value) -> m value
|
||||
doIncludeOnce path = do
|
||||
name <- toQualifiedName <$> (subtermValue path >>= asString)
|
||||
(importedEnv, v) <- isolate (require name)
|
||||
modifyEnv (mappend importedEnv)
|
||||
pure v
|
||||
|
||||
toQualifiedName :: ByteString -> Name
|
||||
toQualifiedName = qualifiedName . splitOnPathSeparator . dropExtension . dropRelativePrefix . stripQuotes
|
||||
|
||||
newtype Require a = Require a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 Require where liftEq = genericLiftEq
|
||||
instance Ord1 Require where liftCompare = genericLiftCompare
|
||||
instance Show1 Require where liftShowsPrec = genericLiftShowsPrec
|
||||
|
||||
instance Evaluatable Require where
|
||||
eval (Require path) = doInclude path
|
||||
|
||||
|
||||
newtype RequireOnce a = RequireOnce a
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 RequireOnce where liftEq = genericLiftEq
|
||||
instance Ord1 RequireOnce where liftCompare = genericLiftCompare
|
||||
instance Show1 RequireOnce where liftShowsPrec = genericLiftShowsPrec
|
||||
|
||||
instance Evaluatable RequireOnce where
|
||||
eval (RequireOnce path) = doIncludeOnce path
|
||||
|
||||
|
||||
newtype Include a = Include a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 Include where liftEq = genericLiftEq
|
||||
instance Ord1 Include where liftCompare = genericLiftCompare
|
||||
instance Show1 Include where liftShowsPrec = genericLiftShowsPrec
|
||||
|
||||
instance Evaluatable Include where
|
||||
eval (Include path) = doInclude path
|
||||
|
||||
|
||||
newtype IncludeOnce a = IncludeOnce a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 IncludeOnce where liftEq = genericLiftEq
|
||||
instance Ord1 IncludeOnce where liftCompare = genericLiftCompare
|
||||
instance Show1 IncludeOnce where liftShowsPrec = genericLiftShowsPrec
|
||||
|
||||
instance Evaluatable IncludeOnce where
|
||||
eval (IncludeOnce path) = doIncludeOnce path
|
||||
|
||||
|
||||
newtype ArrayElement a = ArrayElement a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 ArrayElement where liftEq = genericLiftEq
|
||||
instance Ord1 ArrayElement where liftCompare = genericLiftCompare
|
||||
instance Show1 ArrayElement where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable ArrayElement
|
||||
|
||||
newtype GlobalDeclaration a = GlobalDeclaration [a]
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 GlobalDeclaration where liftEq = genericLiftEq
|
||||
instance Ord1 GlobalDeclaration where liftCompare = genericLiftCompare
|
||||
instance Show1 GlobalDeclaration where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable GlobalDeclaration
|
||||
|
||||
newtype SimpleVariable a = SimpleVariable a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 SimpleVariable where liftEq = genericLiftEq
|
||||
instance Ord1 SimpleVariable where liftCompare = genericLiftCompare
|
||||
instance Show1 SimpleVariable where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable SimpleVariable
|
||||
|
||||
|
||||
-- | TODO: Unify with TypeScript's PredefinedType
|
||||
newtype CastType a = CastType { _castType :: ByteString }
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 CastType where liftEq = genericLiftEq
|
||||
instance Ord1 CastType where liftCompare = genericLiftCompare
|
||||
instance Show1 CastType where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable CastType
|
||||
|
||||
newtype ErrorControl a = ErrorControl a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 ErrorControl where liftEq = genericLiftEq
|
||||
instance Ord1 ErrorControl where liftCompare = genericLiftCompare
|
||||
instance Show1 ErrorControl where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable ErrorControl
|
||||
|
||||
newtype Clone a = Clone a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 Clone where liftEq = genericLiftEq
|
||||
instance Ord1 Clone where liftCompare = genericLiftCompare
|
||||
instance Show1 Clone where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable Clone
|
||||
|
||||
newtype ShellCommand a = ShellCommand ByteString
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 ShellCommand where liftEq = genericLiftEq
|
||||
instance Ord1 ShellCommand where liftCompare = genericLiftCompare
|
||||
instance Show1 ShellCommand where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable ShellCommand
|
||||
|
||||
-- | TODO: Combine with TypeScript update expression.
|
||||
newtype Update a = Update { _updateSubject :: a }
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 Update where liftEq = genericLiftEq
|
||||
instance Ord1 Update where liftCompare = genericLiftCompare
|
||||
instance Show1 Update where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable Update
|
||||
|
||||
newtype NewVariable a = NewVariable [a]
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 NewVariable where liftEq = genericLiftEq
|
||||
instance Ord1 NewVariable where liftCompare = genericLiftCompare
|
||||
instance Show1 NewVariable where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable NewVariable
|
||||
|
||||
newtype RelativeScope a = RelativeScope ByteString
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 RelativeScope where liftEq = genericLiftEq
|
||||
instance Ord1 RelativeScope where liftCompare = genericLiftCompare
|
||||
instance Show1 RelativeScope where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable RelativeScope
|
||||
|
||||
data QualifiedName a = QualifiedName a a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 QualifiedName where liftEq = genericLiftEq
|
||||
instance Ord1 QualifiedName where liftCompare = genericLiftCompare
|
||||
instance Show1 QualifiedName where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable QualifiedName
|
||||
|
||||
newtype NamespaceName a = NamespaceName [a]
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 NamespaceName where liftEq = genericLiftEq
|
||||
instance Ord1 NamespaceName where liftCompare = genericLiftCompare
|
||||
instance Show1 NamespaceName where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable NamespaceName
|
||||
|
||||
newtype ConstDeclaration a = ConstDeclaration [a]
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 ConstDeclaration where liftEq = genericLiftEq
|
||||
instance Ord1 ConstDeclaration where liftCompare = genericLiftCompare
|
||||
instance Show1 ConstDeclaration where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable ConstDeclaration
|
||||
|
||||
data ClassConstDeclaration a = ClassConstDeclaration a [a]
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 ClassConstDeclaration where liftEq = genericLiftEq
|
||||
instance Ord1 ClassConstDeclaration where liftCompare = genericLiftCompare
|
||||
instance Show1 ClassConstDeclaration where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable ClassConstDeclaration
|
||||
|
||||
newtype ClassInterfaceClause a = ClassInterfaceClause [a]
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 ClassInterfaceClause where liftEq = genericLiftEq
|
||||
instance Ord1 ClassInterfaceClause where liftCompare = genericLiftCompare
|
||||
instance Show1 ClassInterfaceClause where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable ClassInterfaceClause
|
||||
|
||||
newtype ClassBaseClause a = ClassBaseClause a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 ClassBaseClause where liftEq = genericLiftEq
|
||||
instance Ord1 ClassBaseClause where liftCompare = genericLiftCompare
|
||||
instance Show1 ClassBaseClause where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable ClassBaseClause
|
||||
|
||||
|
||||
newtype UseClause a = UseClause [a]
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 UseClause where liftEq = genericLiftEq
|
||||
instance Ord1 UseClause where liftCompare = genericLiftCompare
|
||||
instance Show1 UseClause where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable UseClause
|
||||
|
||||
newtype ReturnType a = ReturnType a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 ReturnType where liftEq = genericLiftEq
|
||||
instance Ord1 ReturnType where liftCompare = genericLiftCompare
|
||||
instance Show1 ReturnType where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable ReturnType
|
||||
|
||||
newtype TypeDeclaration a = TypeDeclaration a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 TypeDeclaration where liftEq = genericLiftEq
|
||||
instance Ord1 TypeDeclaration where liftCompare = genericLiftCompare
|
||||
instance Show1 TypeDeclaration where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable TypeDeclaration
|
||||
|
||||
newtype BaseTypeDeclaration a = BaseTypeDeclaration a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 BaseTypeDeclaration where liftEq = genericLiftEq
|
||||
instance Ord1 BaseTypeDeclaration where liftCompare = genericLiftCompare
|
||||
instance Show1 BaseTypeDeclaration where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable BaseTypeDeclaration
|
||||
|
||||
newtype ScalarType a = ScalarType ByteString
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 ScalarType where liftEq = genericLiftEq
|
||||
instance Ord1 ScalarType where liftCompare = genericLiftCompare
|
||||
instance Show1 ScalarType where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable ScalarType
|
||||
|
||||
newtype EmptyIntrinsic a = EmptyIntrinsic a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 EmptyIntrinsic where liftEq = genericLiftEq
|
||||
instance Ord1 EmptyIntrinsic where liftCompare = genericLiftCompare
|
||||
instance Show1 EmptyIntrinsic where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable EmptyIntrinsic
|
||||
|
||||
newtype ExitIntrinsic a = ExitIntrinsic a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 ExitIntrinsic where liftEq = genericLiftEq
|
||||
instance Ord1 ExitIntrinsic where liftCompare = genericLiftCompare
|
||||
instance Show1 ExitIntrinsic where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable ExitIntrinsic
|
||||
|
||||
newtype IssetIntrinsic a = IssetIntrinsic a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 IssetIntrinsic where liftEq = genericLiftEq
|
||||
instance Ord1 IssetIntrinsic where liftCompare = genericLiftCompare
|
||||
instance Show1 IssetIntrinsic where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable IssetIntrinsic
|
||||
|
||||
newtype EvalIntrinsic a = EvalIntrinsic a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 EvalIntrinsic where liftEq = genericLiftEq
|
||||
instance Ord1 EvalIntrinsic where liftCompare = genericLiftCompare
|
||||
instance Show1 EvalIntrinsic where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable EvalIntrinsic
|
||||
|
||||
newtype PrintIntrinsic a = PrintIntrinsic a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 PrintIntrinsic where liftEq = genericLiftEq
|
||||
instance Ord1 PrintIntrinsic where liftCompare = genericLiftCompare
|
||||
instance Show1 PrintIntrinsic where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable PrintIntrinsic
|
||||
|
||||
newtype NamespaceAliasingClause a = NamespaceAliasingClause a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 NamespaceAliasingClause where liftEq = genericLiftEq
|
||||
instance Ord1 NamespaceAliasingClause where liftCompare = genericLiftCompare
|
||||
instance Show1 NamespaceAliasingClause where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable NamespaceAliasingClause
|
||||
|
||||
newtype NamespaceUseDeclaration a = NamespaceUseDeclaration [a]
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 NamespaceUseDeclaration where liftEq = genericLiftEq
|
||||
instance Ord1 NamespaceUseDeclaration where liftCompare = genericLiftCompare
|
||||
instance Show1 NamespaceUseDeclaration where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable NamespaceUseDeclaration
|
||||
|
||||
newtype NamespaceUseClause a = NamespaceUseClause [a]
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 NamespaceUseClause where liftEq = genericLiftEq
|
||||
instance Ord1 NamespaceUseClause where liftCompare = genericLiftCompare
|
||||
instance Show1 NamespaceUseClause where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable NamespaceUseClause
|
||||
|
||||
newtype NamespaceUseGroupClause a = NamespaceUseGroupClause [a]
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 NamespaceUseGroupClause where liftEq = genericLiftEq
|
||||
instance Ord1 NamespaceUseGroupClause where liftCompare = genericLiftCompare
|
||||
instance Show1 NamespaceUseGroupClause where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable NamespaceUseGroupClause
|
||||
|
||||
data Namespace a = Namespace { namespaceName :: a, namespaceBody :: a}
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 Namespace where liftEq = genericLiftEq
|
||||
instance Ord1 Namespace where liftCompare = genericLiftCompare
|
||||
instance Show1 Namespace where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable Namespace
|
||||
|
||||
data TraitDeclaration a = TraitDeclaration { traitName :: a, traitStatements :: [a] }
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 TraitDeclaration where liftEq = genericLiftEq
|
||||
instance Ord1 TraitDeclaration where liftCompare = genericLiftCompare
|
||||
instance Show1 TraitDeclaration where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable TraitDeclaration
|
||||
|
||||
data AliasAs a = AliasAs { aliasAsName :: a, aliasAsModifier :: a, aliasAsClause :: a }
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 AliasAs where liftEq = genericLiftEq
|
||||
instance Ord1 AliasAs where liftCompare = genericLiftCompare
|
||||
instance Show1 AliasAs where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable AliasAs
|
||||
|
||||
data InsteadOf a = InsteadOf a a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 InsteadOf where liftEq = genericLiftEq
|
||||
instance Ord1 InsteadOf where liftCompare = genericLiftCompare
|
||||
instance Show1 InsteadOf where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable InsteadOf
|
||||
|
||||
newtype TraitUseSpecification a = TraitUseSpecification [a]
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 TraitUseSpecification where liftEq = genericLiftEq
|
||||
instance Ord1 TraitUseSpecification where liftCompare = genericLiftCompare
|
||||
instance Show1 TraitUseSpecification where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable TraitUseSpecification
|
||||
|
||||
data TraitUseClause a = TraitUseClause [a] a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 TraitUseClause where liftEq = genericLiftEq
|
||||
instance Ord1 TraitUseClause where liftCompare = genericLiftCompare
|
||||
instance Show1 TraitUseClause where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable TraitUseClause
|
||||
|
||||
data DestructorDeclaration a = DestructorDeclaration [a] a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 DestructorDeclaration where liftEq = genericLiftEq
|
||||
instance Ord1 DestructorDeclaration where liftCompare = genericLiftCompare
|
||||
instance Show1 DestructorDeclaration where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable DestructorDeclaration
|
||||
|
||||
newtype Static a = Static ByteString
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 Static where liftEq = genericLiftEq
|
||||
instance Ord1 Static where liftCompare = genericLiftCompare
|
||||
instance Show1 Static where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable Static
|
||||
|
||||
newtype ClassModifier a = ClassModifier ByteString
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 ClassModifier where liftEq = genericLiftEq
|
||||
instance Ord1 ClassModifier where liftCompare = genericLiftCompare
|
||||
instance Show1 ClassModifier where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable ClassModifier
|
||||
|
||||
data ConstructorDeclaration a = ConstructorDeclaration [a] [a] a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 ConstructorDeclaration where liftEq = genericLiftEq
|
||||
instance Ord1 ConstructorDeclaration where liftCompare = genericLiftCompare
|
||||
instance Show1 ConstructorDeclaration where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable ConstructorDeclaration
|
||||
|
||||
data PropertyDeclaration a = PropertyDeclaration a [a]
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 PropertyDeclaration where liftEq = genericLiftEq
|
||||
instance Ord1 PropertyDeclaration where liftCompare = genericLiftCompare
|
||||
instance Show1 PropertyDeclaration where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable PropertyDeclaration
|
||||
|
||||
data PropertyModifier a = PropertyModifier a a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 PropertyModifier where liftEq = genericLiftEq
|
||||
instance Ord1 PropertyModifier where liftCompare = genericLiftCompare
|
||||
instance Show1 PropertyModifier where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable PropertyModifier
|
||||
|
||||
data InterfaceDeclaration a = InterfaceDeclaration a a [a]
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 InterfaceDeclaration where liftEq = genericLiftEq
|
||||
instance Ord1 InterfaceDeclaration where liftCompare = genericLiftCompare
|
||||
instance Show1 InterfaceDeclaration where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable InterfaceDeclaration
|
||||
|
||||
newtype InterfaceBaseClause a = InterfaceBaseClause [a]
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 InterfaceBaseClause where liftEq = genericLiftEq
|
||||
instance Ord1 InterfaceBaseClause where liftCompare = genericLiftCompare
|
||||
instance Show1 InterfaceBaseClause where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable InterfaceBaseClause
|
||||
|
||||
newtype Echo a = Echo a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 Echo where liftEq = genericLiftEq
|
||||
instance Ord1 Echo where liftCompare = genericLiftCompare
|
||||
instance Show1 Echo where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable Echo
|
||||
|
||||
newtype Unset a = Unset a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 Unset where liftEq = genericLiftEq
|
||||
instance Ord1 Unset where liftCompare = genericLiftCompare
|
||||
instance Show1 Unset where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable Unset
|
||||
|
||||
data Declare a = Declare a a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 Declare where liftEq = genericLiftEq
|
||||
instance Ord1 Declare where liftCompare = genericLiftCompare
|
||||
instance Show1 Declare where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable Declare
|
||||
|
||||
newtype DeclareDirective a = DeclareDirective a
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 DeclareDirective where liftEq = genericLiftEq
|
||||
instance Ord1 DeclareDirective where liftCompare = genericLiftCompare
|
||||
instance Show1 DeclareDirective where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable DeclareDirective
|
||||
|
||||
newtype LabeledStatement a = LabeledStatement { _labeledStatementIdentifier :: a }
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable)
|
||||
|
||||
instance Eq1 LabeledStatement where liftEq = genericLiftEq
|
||||
instance Ord1 LabeledStatement where liftCompare = genericLiftCompare
|
||||
instance Show1 LabeledStatement where liftShowsPrec = genericLiftShowsPrec
|
||||
instance Evaluatable LabeledStatement
|
||||
|
@ -1,11 +1,13 @@
|
||||
{-# LANGUAGE DeriveAnyClass #-}
|
||||
module Language.Ruby.Syntax where
|
||||
|
||||
import Analysis.Abstract.Evaluating
|
||||
import Control.Monad (unless)
|
||||
import Control.Abstract.Value (MonadValue)
|
||||
import Data.Abstract.Evaluatable
|
||||
import Data.Abstract.ModuleTable
|
||||
import Data.Abstract.Path
|
||||
import Data.Abstract.Value (LocationFor)
|
||||
import Data.Abstract.Value (EnvironmentFor)
|
||||
import Diffing.Algorithm
|
||||
import Prelude hiding (fail)
|
||||
import Prologue
|
||||
@ -19,10 +21,22 @@ instance Show1 Require where liftShowsPrec = genericLiftShowsPrec
|
||||
|
||||
instance Evaluatable Require where
|
||||
eval (Require _ x) = do
|
||||
name <- pathToQualifiedName <$> (subtermValue x >>= asString)
|
||||
importedEnv <- isolate (require name)
|
||||
name <- toName <$> (subtermValue x >>= asString)
|
||||
(importedEnv, v) <- isolate (doRequire name)
|
||||
modifyEnv (mappend importedEnv)
|
||||
unit
|
||||
pure v -- Returns True if the file was loaded, False if it was already loaded. http://ruby-doc.org/core-2.5.0/Kernel.html#method-i-require
|
||||
where
|
||||
toName = qualifiedName . splitOnPathSeparator . dropRelativePrefix . stripQuotes
|
||||
|
||||
doRequire :: (MonadAnalysis term value m, MonadValue value m)
|
||||
=> ModuleName
|
||||
-> m (EnvironmentFor value, value)
|
||||
doRequire name = do
|
||||
moduleTable <- getModuleTable
|
||||
case moduleTableLookup name moduleTable of
|
||||
Nothing -> (,) <$> (fst <$> load name) <*> boolean True
|
||||
Just (env, _) -> (,) <$> pure env <*> boolean False
|
||||
|
||||
|
||||
newtype Load a = Load { loadArgs :: [a] }
|
||||
deriving (Diffable, Eq, Foldable, Functor, GAlign, Generic1, Mergeable, Ord, Show, Traversable, FreeVariables1)
|
||||
@ -41,12 +55,12 @@ instance Evaluatable Load where
|
||||
doLoad path shouldWrap
|
||||
eval (Load _) = fail "invalid argument supplied to load, path is required"
|
||||
|
||||
doLoad :: (MonadAnalysis term value m, MonadValue value m, Ord (LocationFor value)) => ByteString -> Bool -> m value
|
||||
doLoad :: (MonadAnalysis term value m, MonadValue value m) => ByteString -> Bool -> m value
|
||||
doLoad path shouldWrap = do
|
||||
let name = pathToQualifiedName path
|
||||
importedEnv <- isolate (load name)
|
||||
(importedEnv, _) <- isolate (load (toName path))
|
||||
unless shouldWrap $ modifyEnv (mappend importedEnv)
|
||||
unit
|
||||
where pathToQualifiedName = qualifiedName . splitOnPathSeparator' dropExtension
|
||||
boolean Prelude.True -- load always returns true. http://ruby-doc.org/core-2.5.0/Kernel.html#method-i-load
|
||||
where
|
||||
toName = qualifiedName . splitOnPathSeparator . dropExtension . dropRelativePrefix . stripQuotes
|
||||
|
||||
-- TODO: autoload
|
||||
|
@ -9,6 +9,7 @@ module Language.TypeScript.Assignment
|
||||
import Assigning.Assignment hiding (Assignment, Error)
|
||||
import qualified Assigning.Assignment as Assignment
|
||||
import Data.Abstract.FreeVariables
|
||||
import Data.Abstract.Path
|
||||
import Data.Record
|
||||
import Data.Syntax (emptyTerm, handleError, parseError, infixContext, makeTerm, makeTerm', makeTerm'', makeTerm1, contextualize, postContextualize)
|
||||
import qualified Data.Syntax as Syntax
|
||||
@ -672,7 +673,9 @@ importStatement = makeImportTerm <$> symbol Grammar.ImportStatement <*> childr
|
||||
makeNameAliasPair from Nothing = (from, from)
|
||||
|
||||
fromClause :: Assignment
|
||||
fromClause = makeTerm <$> symbol Grammar.String <*> (Syntax.Identifier <$> (pathToQualifiedName <$> source))
|
||||
fromClause = makeTerm <$> symbol Grammar.String <*> (Syntax.Identifier <$> (toName <$> source))
|
||||
where
|
||||
toName = qualifiedName . splitOnPathSeparator . dropRelativePrefix . stripQuotes
|
||||
|
||||
debuggerStatement :: Assignment
|
||||
debuggerStatement = makeTerm <$> symbol Grammar.DebuggerStatement <*> (TypeScript.Syntax.Debugger <$ source)
|
||||
|
@ -50,6 +50,10 @@ typecheckPythonFile path = runAnalysis @(Caching Evaluating Python.Term Type) .
|
||||
tracePythonFile path = runAnalysis @(Tracing [] Evaluating Python.Term Value) . evaluateModule . snd <$> parseFile pythonParser path
|
||||
evaluateDeadTracePythonFile path = runAnalysis @(DeadCode (Tracing [] Evaluating) Python.Term Value) . evaluateModule . snd <$> parseFile pythonParser path
|
||||
|
||||
-- PHP
|
||||
evaluatePHPFile = evaluateFile phpParser
|
||||
evaluatePHPFiles = evaluateFiles phpParser
|
||||
|
||||
-- TypeScript
|
||||
typecheckTypeScriptFile path = runAnalysis @(Caching Evaluating TypeScript.Term Type) . evaluateModule . snd <$> parseFile typescriptParser path
|
||||
evaluateTypeScriptFile = evaluateFile typescriptParser
|
||||
|
@ -1,4 +1,4 @@
|
||||
{-# LANGUAGE OverloadedLists, TypeApplications #-}
|
||||
{-# LANGUAGE OverloadedLists #-}
|
||||
module Analysis.Go.Spec (spec) where
|
||||
|
||||
import Data.Abstract.Value
|
||||
|
33
test/Analysis/PHP/Spec.hs
Normal file
33
test/Analysis/PHP/Spec.hs
Normal file
@ -0,0 +1,33 @@
|
||||
{-# LANGUAGE OverloadedLists #-}
|
||||
module Analysis.PHP.Spec (spec) where
|
||||
|
||||
import Data.Abstract.Value
|
||||
import Data.Map
|
||||
|
||||
import SpecHelpers
|
||||
|
||||
|
||||
spec :: Spec
|
||||
spec = parallel $ do
|
||||
describe "evalutes PHP" $ do
|
||||
it "include and require" $ do
|
||||
env <- evaluate "main.php"
|
||||
let expectedEnv = [ (qualifiedName ["foo"], addr 0)
|
||||
, (qualifiedName ["bar"], addr 1) ]
|
||||
env `shouldBe` expectedEnv
|
||||
|
||||
it "include_once and require_once" $ do
|
||||
env <- evaluate "main_once.php"
|
||||
let expectedEnv = [ (qualifiedName ["foo"], addr 0)
|
||||
, (qualifiedName ["bar"], addr 1) ]
|
||||
env `shouldBe` expectedEnv
|
||||
|
||||
where
|
||||
addr = Address . Precise
|
||||
fixtures = "test/fixtures/php/analysis/"
|
||||
evaluate entry = snd . fst . fst . fst . fst <$>
|
||||
evaluateFiles phpParser
|
||||
[ fixtures <> entry
|
||||
, fixtures <> "foo.php"
|
||||
, fixtures <> "bar.php"
|
||||
]
|
@ -26,6 +26,10 @@ spec = parallel $ do
|
||||
fst res `shouldBe` Left "free variable: \"foo\""
|
||||
snd res `shouldBe` []
|
||||
|
||||
it "subclass" $ do
|
||||
res <- evaluate' "subclass.rb"
|
||||
fst res `shouldBe` Right (injValue (String "\"<bar>\""))
|
||||
|
||||
where
|
||||
addr = Address . Precise
|
||||
fixtures = "test/fixtures/ruby/analysis/"
|
||||
|
@ -1,6 +1,7 @@
|
||||
module Main where
|
||||
|
||||
import qualified Analysis.Go.Spec
|
||||
import qualified Analysis.PHP.Spec
|
||||
import qualified Analysis.Python.Spec
|
||||
import qualified Analysis.Ruby.Spec
|
||||
import qualified Analysis.TypeScript.Spec
|
||||
@ -27,6 +28,7 @@ main = hspec $ do
|
||||
describe "Semantic.Stat" Semantic.Stat.Spec.spec
|
||||
parallel $ do
|
||||
describe "Analysis.Go" Analysis.Go.Spec.spec
|
||||
describe "Analysis.PHP" Analysis.PHP.Spec.spec
|
||||
describe "Analysis.Python" Analysis.Python.Spec.spec
|
||||
describe "Analysis.Ruby" Analysis.Ruby.Spec.spec
|
||||
describe "Analysis.TypeScript" Analysis.TypeScript.Spec.spec
|
||||
|
4
test/fixtures/php/analysis/bar.php
vendored
Normal file
4
test/fixtures/php/analysis/bar.php
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
<?php
|
||||
function bar() {
|
||||
return 1;
|
||||
}
|
4
test/fixtures/php/analysis/foo.php
vendored
Normal file
4
test/fixtures/php/analysis/foo.php
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
<?php
|
||||
function foo() {
|
||||
return 1;
|
||||
}
|
6
test/fixtures/php/analysis/main.php
vendored
Normal file
6
test/fixtures/php/analysis/main.php
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
include 'foo.php';
|
||||
require 'bar.php';
|
||||
|
||||
foo();
|
||||
bar();
|
6
test/fixtures/php/analysis/main_once.php
vendored
Normal file
6
test/fixtures/php/analysis/main_once.php
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
include_once 'foo.php';
|
||||
require_once 'bar.php';
|
||||
|
||||
foo();
|
||||
bar();
|
13
test/fixtures/ruby/analysis/subclass.rb
vendored
Normal file
13
test/fixtures/ruby/analysis/subclass.rb
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
class Foo
|
||||
def inspect
|
||||
"<foo>"
|
||||
end
|
||||
end
|
||||
|
||||
class Bar < Foo
|
||||
def inspect
|
||||
"<bar>"
|
||||
end
|
||||
end
|
||||
|
||||
Bar.inspect()
|
Loading…
Reference in New Issue
Block a user