1
1
mirror of https://github.com/github/semantic.git synced 2024-11-27 12:57:49 +03:00

Merge remote-tracking branch 'origin/master' into lts-12.0

This commit is contained in:
Patrick Thomson 2018-07-13 15:41:09 -04:00
commit dea4f10f9b
19 changed files with 126 additions and 71 deletions

View File

@ -105,7 +105,6 @@ convergingModules recur m = do
withOracle prevCache (gatherM (const ()) (recur m)))
TermEvaluator (address =<< runTermEvaluator (maybe empty scatter (cacheLookup c cache)))
-- | Iterate a monadic action starting from some initial seed until the results converge.
--
-- This applies the Kleene fixed-point theorem to finitize a monotone action. cf https://en.wikipedia.org/wiki/Kleene_fixed-point_theorem

View File

@ -49,7 +49,7 @@ graphingTerms :: ( Element Syntax.Identifier syntax
, Member (Reader ModuleInfo) effects
, Member (Env (Hole (Located address))) effects
, Member (State (Graph Vertex)) effects
, term ~ Term (Sum syntax) ann
, Base term ~ TermF (Sum syntax) ann
)
=> SubtermAlgebra (Base term) term (TermEvaluator term (Hole (Located address)) value effects a)
-> SubtermAlgebra (Base term) term (TermEvaluator term (Hole (Located address)) value effects a)

View File

@ -30,7 +30,7 @@ import Prologue
getEnv :: Member (Env address) effects => Evaluator address value effects (Environment address)
getEnv = send GetEnv
-- | Replace the environment.
-- | Replace the environment. This is only for use in Analysis.Abstract.Caching.
putEnv :: Member (Env address) effects => Environment address -> Evaluator address value effects ()
putEnv = send . PutEnv

View File

@ -32,6 +32,9 @@ cacheSet key value = Cache . Monoidal.insert key value . unCache
cacheInsert :: Cacheable term address cell value => Configuration term address cell value -> Cached address cell value -> Cache term address cell value -> Cache term address cell value
cacheInsert = curry cons
-- | Return all 'Configuration's in the provided cache.
cacheKeys :: Cache term address cell value -> [Configuration term address cell value]
cacheKeys = Monoidal.keys . unCache
instance (Show term, Show address, Show (cell value), Show value) => Show (Cache term address cell value) where
showsPrec d = showsUnaryWith showsPrec "Cache" d . map (second toList) . Monoidal.pairs . unCache

View File

@ -151,5 +151,8 @@ addresses = fromAddresses . map snd . flatPairs
instance Lower (Environment address) where lowerBound = Environment (lowerBound :| [])
-- N.B. this show instance drops some information to avoid generating
-- an infinite string in certain cases. As such, two unequal
-- environments may produce equal outputs over Show.
instance Show address => Show (Environment address) where
showsPrec d = showsUnaryWith showsPrec "Environment" d . flatPairs

View File

@ -52,15 +52,15 @@ class (Show1 constr, Foldable constr) => Evaluatable constr where
, Member (Env address) effects
, Member (Exc (LoopControl address)) effects
, Member (Exc (Return address)) effects
, Member Fresh effects
, Member (Modules address) effects
, Member (Reader ModuleInfo) effects
, Member (Reader PackageInfo) effects
, Member (Reader Span) effects
, Member (Resumable (EnvironmentError address)) effects
, Member (Resumable (Unspecialized value)) effects
, Member (Resumable EvalError) effects
, Member (Resumable ResolutionError) effects
, Member (Resumable (Unspecialized value)) effects
, Member Fresh effects
, Member Trace effects
)
=> SubtermAlgebra constr term (Evaluator address value effects (ValueRef address))
@ -154,24 +154,24 @@ instance HasPrelude 'PHP
instance HasPrelude 'Python where
definePrelude _ =
define "print" builtInPrint
define (name "print") builtInPrint
instance HasPrelude 'Ruby where
definePrelude _ = do
define "puts" builtInPrint
define (name "puts") builtInPrint
defineClass "Object" [] $ do
define "inspect" (lambda (const (box (string "<object>"))))
defineClass (name "Object") [] $ do
define (name "inspect") (lambda (const (box (string "<object>"))))
instance HasPrelude 'TypeScript where
definePrelude _ =
defineNamespace "console" $ do
define "log" builtInPrint
defineNamespace (name "console") $ do
define (name "log") builtInPrint
instance HasPrelude 'JavaScript where
definePrelude _ = do
defineNamespace "console" $ do
define "log" builtInPrint
defineNamespace (name "console") $ do
define (name "log") builtInPrint
-- Postludes

View File

@ -15,9 +15,8 @@ import qualified Data.Char as Char
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Text.Lazy as LT
import Data.String
import Prologue
import Proto3.Suite
import Proto3.Suite
import qualified Proto3.Wire.Decode as Decode
import qualified Proto3.Wire.Encode as Encode
@ -32,7 +31,7 @@ instance HasDefault Name where
instance Primitive Name where
encodePrimitive num (Name text) = Encode.text num (LT.fromStrict text)
encodePrimitive num (I index) = Encode.int num index
encodePrimitive num (I index) = Encode.int num index
decodePrimitive = Name . LT.toStrict <$> Decode.text <|> I <$> Decode.int
primType _ = Bytes
@ -55,9 +54,6 @@ formatName (I i) = Text.pack $ '_' : (alphabet !! a) : replicate n 'ʹ'
where alphabet = ['a'..'z']
(n, a) = i `divMod` length alphabet
instance IsString Name where
fromString = Name . Text.pack
-- $
-- >>> I 0
-- "_a"

View File

@ -48,8 +48,8 @@ instance ( Member (Allocator address Abstract) effects
instance ( Member (Allocator address Abstract) effects
, Member (Env address) effects
, Member (Exc (Return address)) effects
, Member Fresh effects
, Member NonDet effects
, Member Fresh effects
)
=> AbstractValue address Abstract effects where
array _ = pure Abstract

View File

@ -2,6 +2,7 @@
module Data.Abstract.Value.Type
( Type (..)
, TypeError (..)
, TypeMap
, runTypes
, runTypesWith
, unify
@ -108,6 +109,7 @@ runTypesWith :: ( Effectful m
-> m effects a
runTypesWith with = runTypeMap . runTypeErrorWith with
-- TODO: change my name?
newtype TypeMap = TypeMap { unTypeMap :: Map.Map TName Type }
emptyTypeMap :: TypeMap

View File

@ -8,6 +8,7 @@ module Data.Map.Monoidal
, insert
, filterWithKey
, pairs
, keys
, module Reducer
) where
@ -37,6 +38,8 @@ insert key value = Map . Map.insert key value . unMap
filterWithKey :: (key -> value -> Bool) -> Map key value -> Map key value
filterWithKey f = Map . Map.filterWithKey f . unMap
keys :: Map key value -> [key]
keys = map fst . pairs
pairs :: Map key value -> [(key, value)]
pairs = Map.toList . unMap

View File

@ -10,7 +10,7 @@ import Prologue
import Proto3.Suite.Class
data Function a = Function { functionContext :: ![a], functionName :: !a, functionParameters :: ![a], functionBody :: !a }
deriving (Eq, Ord, Show, Foldable, Traversable, Functor, Generic1, Hashable1, Mergeable, FreeVariables1, Declarations1, ToJSONFields1, Named1, Message1)
deriving (Eq, Ord, Show, Foldable, Traversable, Functor, Generic1, Hashable1, Mergeable, FreeVariables1, ToJSONFields1, Named1, Message1)
instance Diffable Function where
equivalentBySubterm = Just . functionName
@ -33,6 +33,11 @@ instance Evaluatable Function where
instance Declarations a => Declarations (Function a) where
declaredName Function{..} = declaredName functionName
instance Declarations1 Function where
liftDeclaredName declaredName Function{..} =
case declaredName functionName of
[] -> Nothing
(x:_) -> Just x
data Method a = Method { methodContext :: ![a], methodReceiver :: !a, methodName :: !a, methodParameters :: ![a], methodBody :: !a }
deriving (Eq, Ord, Show, Foldable, Traversable, Functor, Generic1, Hashable1, Mergeable, FreeVariables1, Declarations1, ToJSONFields1, Named1, Message1)

View File

@ -270,10 +270,10 @@ instance Show1 DefaultExport where liftShowsPrec = genericLiftShowsPrec
instance Evaluatable DefaultExport where
eval (DefaultExport term) = do
v <- subtermValue term
case declaredName term of
Just name -> do
addr <- lookupOrAlloc name
v <- subtermValue term
assign addr v
export name name Nothing
bind name addr

View File

@ -1,11 +1,11 @@
{-# LANGUAGE GADTs, ScopedTypeVariables, TypeOperators #-}
module Semantic.Graph
( runGraph
, runCallGraph
, runImportGraph
, GraphType(..)
, Graph
, Vertex
, GraphEff(..)
, ImportGraphEff(..)
, style
, parsePackage
@ -19,8 +19,11 @@ module Semantic.Graph
, resumingEnvironmentError
) where
import Prelude hiding (readFile)
import Analysis.Abstract.Caching
import Analysis.Abstract.Collecting
import Analysis.Abstract.Graph as Graph
import Control.Abstract
import Control.Monad.Effect (reinterpret)
@ -29,14 +32,16 @@ import Data.Abstract.Evaluatable
import Data.Abstract.Module
import qualified Data.Abstract.ModuleTable as ModuleTable
import Data.Abstract.Package as Package
import Data.Abstract.Value.Type
import Data.Abstract.Value.Concrete (Value, ValueError (..), runValueErrorWith)
import Data.Graph
import Data.Project
import Data.Record
import qualified Data.Syntax as Syntax
import Data.Term
import Data.Text (pack)
import Parsing.Parser
import Prologue hiding (MonadError (..))
import Prologue hiding (MonadError (..), TypeError (..))
import Semantic.Task as Task
data GraphType = ImportGraph | CallGraph
@ -55,52 +60,52 @@ runGraph ImportGraph _ project
runGraph CallGraph includePackages project
| SomeAnalysisParser parser lang <- someAnalysisParser (Proxy :: Proxy AnalysisClasses) (projectLanguage project) = do
package <- parsePackage parser project
modules <- runImportGraph lang package
let analyzeTerm = withTermSpans . graphingTerms
analyzeModule = (if includePackages then graphingPackages else id) . graphingModules
extractGraph (_, (_, (graph, _))) = simplify graph
runGraphAnalysis
= runState lowerBound
. runFresh 0
. resumingLoadError
. resumingUnspecialized
. resumingEnvironmentError
. resumingEvalError
. resumingResolutionError
. resumingAddressError
. resumingValueError
. runTermEvaluator @_ @_ @(Value (Hole (Located Precise)) (GraphEff _ effs))
. graphing
. runReader (packageInfo package)
. runReader lowerBound
. runReader lowerBound
. raiseHandler (runModules (ModuleTable.modulePaths (packageModules package)))
extractGraph <$> runEvaluator (runGraphAnalysis (evaluate lang analyzeModule analyzeTerm (topologicalSort modules)))
modules <- topologicalSort <$> runImportGraph lang package
runCallGraph lang includePackages modules package
runCallGraph :: ( HasField ann Span
, Element Syntax.Identifier syntax
, Base term ~ TermF (Sum syntax) (Record ann)
, Ord term
, Corecursive term
, Declarations term
, Evaluatable (Base term)
, FreeVariables term
, HasPrelude lang
, HasPostlude lang
, Member Trace effs
, Recursive term
, Effects effs
)
=> Proxy lang
-> Bool
-> [Module term]
-> Package term
-> Eff effs (Graph Vertex)
runCallGraph lang includePackages modules package = do
let analyzeTerm = withTermSpans . graphingTerms . cachingTerms
analyzeModule = (if includePackages then graphingPackages else id) . convergingModules . graphingModules
extractGraph (_, (_, (graph, _))) = simplify graph
runGraphAnalysis
= runState (lowerBound @(Heap (Hole (Located Monovariant)) All Type))
. runFresh 0
. resumingLoadError
. resumingUnspecialized
. resumingEnvironmentError
. resumingEvalError
. resumingResolutionError
. resumingAddressError
. runTermEvaluator @_ @(Hole (Located Monovariant)) @Type
. graphing
. caching @[]
. resumingTypeError
. runReader (packageInfo package)
. runReader (lowerBound @Span)
. providingLiveSet
. runReader (lowerBound @(ModuleTable (NonEmpty (Module (Environment (Hole (Located Monovariant)), Hole (Located Monovariant))))))
. raiseHandler (runModules (ModuleTable.modulePaths (packageModules package)))
extractGraph <$> runEvaluator (runGraphAnalysis (evaluate lang analyzeModule analyzeTerm modules))
-- | The full list of effects in flight during the evaluation of terms. This, and other @newtype@s like it, are necessary to type 'Value', since the bodies of closures embed evaluators. This would otherwise require cycles in the effect list (i.e. references to @effects@ within @effects@ itself), which the typechecker forbids.
newtype GraphEff address outerEffects a = GraphEff
{ runGraphEff :: Eff ( Exc (LoopControl address)
': Exc (Return address)
': Env address
': Allocator address (Value address (GraphEff address outerEffects))
': Reader ModuleInfo
': Modules address
': Reader (ModuleTable (NonEmpty (Module (Environment address, address))))
': Reader Span
': Reader PackageInfo
': State (Graph Vertex)
': Resumable (ValueError address (GraphEff address outerEffects))
': Resumable (AddressError address (Value address (GraphEff address outerEffects)))
': Resumable ResolutionError
': Resumable EvalError
': Resumable (EnvironmentError address)
': Resumable (Unspecialized (Value address (GraphEff address outerEffects)))
': Resumable (LoadError address)
': Fresh
': State (Heap address Latest (Value address (GraphEff address outerEffects)))
': outerEffects
) a
}
runImportGraph :: forall effs lang term.
@ -215,7 +220,7 @@ resumingEvalError = runEvalErrorWith (\ err -> trace ("EvalError" <> show err) *
IntegerFormatError{} -> pure 0
FloatFormatError{} -> pure 0
RationalFormatError{} -> pure 0
FreeVariablesError names -> pure (fromMaybeLast "unknown" names))
FreeVariablesError names -> pure (fromMaybeLast (name "unknown") names))
resumingUnspecialized :: (Member Trace effects, AbstractHole value, Effects effects) => Evaluator address value (Resumable (Unspecialized value) ': effects) a -> Evaluator address value effects a
resumingUnspecialized = runUnspecializedWith (\ err@(Unspecialized _) -> trace ("Unspecialized:" <> show err) $> hole)
@ -245,3 +250,14 @@ resumingEnvironmentError :: (AbstractHole address, Effects effects) => Evaluator
resumingEnvironmentError
= runState []
. reinterpret (\ (Resumable (FreeVariable name)) -> modify' (name :) $> hole)
resumingTypeError :: ( Alternative (m address Type (State TypeMap ': effects))
, Effects effects
, Effectful (m address Type)
, Member Trace effects
)
=> m address Type (Resumable TypeError ': State TypeMap ': effects) a
-> m address Type effects a
resumingTypeError = runTypesWith (\err -> trace ("TypeError " <> show err) *> case err of
UnificationError l r -> pure l <|> pure r
InfiniteType _ r -> pure r)

View File

@ -102,6 +102,16 @@ evalTypeScriptProject = justEvaluating <=< evaluateProject (Proxy :: Proxy 'Lang
typecheckGoFile = checking <=< evaluateProjectWithCaching (Proxy :: Proxy 'Language.Go) goParser Language.Go
callGraphRubyProject paths = runTaskWithOptions debugOptions $ do
let proxy = Proxy @'Language.Ruby
let lang = Language.Ruby
blobs <- catMaybes <$> traverse readFile (flip File lang <$> paths)
package <- parsePackage rubyParser (Project (takeDirectory (maybe "/" fst (uncons paths))) blobs lang [])
modules <- topologicalSort <$> runImportGraph proxy package
x <- runCallGraph proxy False modules package
pure (x, modules)
-- Evaluate a project consisting of the listed paths.
evaluateProject proxy parser lang paths = withOptions debugOptions $ \ config logger statter ->
evaluateProject' (TaskConfig config logger statter) proxy parser lang paths

View File

@ -12,8 +12,8 @@ import Data.Term
import Data.These
import Diffing.Algorithm
import Diffing.Algorithm.RWS
import Test.Hspec
import Test.Hspec.LeanCheck
import SpecHelpers
spec :: Spec
spec = parallel $ do

View File

@ -14,6 +14,7 @@ import Test.Hspec (Spec, describe, it, parallel)
import Test.Hspec.Expectations.Pretty
import Test.Hspec.LeanCheck
import Test.LeanCheck.Core
import SpecHelpers
spec :: Spec
spec = parallel $ do

View File

@ -1,3 +1,5 @@
{-# OPTIONS_GHC -fno-warn-orphans #-}
module SpecHelpers
( module X
, runBuilder
@ -44,6 +46,7 @@ import Data.Record as X
import Data.Semilattice.Lower as X
import Data.Source as X
import Data.Span as X
import Data.String
import Data.Sum
import Data.Term as X
import Parsing.Parser as X
@ -75,6 +78,11 @@ import Control.Exception (displayException)
runBuilder = toStrict . toLazyByteString
-- | This orphan instance is so we don't have to insert @name@ calls
-- in dozens and dozens of environment specs.
instance IsString Name where
fromString = name . fromString
-- | Returns an s-expression formatted diff for the specified FilePath pair.
diffFilePaths :: TaskConfig -> Both FilePath -> IO ByteString
diffFilePaths (TaskConfig config logger statter) paths = readFilePair paths >>= runTaskWithConfig config logger statter . runDiff SExpressionDiffRenderer . pure >>= either (die . displayException) (pure . runBuilder)

View File

@ -0,0 +1,6 @@
export function square(x) {
return x * x;
}
export function area(x, y) {
return x * y;
}

View File

@ -0,0 +1,3 @@
import { square, area } from 'lib';
console.log(square(11)); // 121
console.log(area(4, 3)); // 12