1
1
mirror of https://github.com/github/semantic.git synced 2024-12-21 13:51:44 +03:00

Merge branch 'master' into imports,-graphed

This commit is contained in:
Rob Rix 2018-03-26 11:34:35 -04:00
commit bfd3aa8e0d
10 changed files with 91 additions and 49 deletions

View File

@ -218,6 +218,7 @@ newline: native
# command line instead of using language pragmas in the file. stylish-haskell # command line instead of using language pragmas in the file. stylish-haskell
# needs to be aware of these, so it can parse the file correctly. # needs to be aware of these, so it can parse the file correctly.
language_extensions: language_extensions:
- ExplicitNamespaces
- DeriveFoldable - DeriveFoldable
- DeriveFunctor - DeriveFunctor
- DeriveGeneric - DeriveGeneric

View File

@ -1,4 +1,6 @@
{-# LANGUAGE DataKinds, GeneralizedNewtypeDeriving, MultiParamTypeClasses, ScopedTypeVariables, StandaloneDeriving, TypeApplications, TypeFamilies, TypeOperators, UndecidableInstances #-} {-# LANGUAGE DataKinds, GADTs, GeneralizedNewtypeDeriving, MultiParamTypeClasses, Rank2Types, ScopedTypeVariables,
StandaloneDeriving, TypeApplications, TypeFamilies, TypeOperators, UndecidableInstances #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Analysis.Abstract.Evaluating module Analysis.Abstract.Evaluating
( type Evaluating ( type Evaluating
, findValue , findValue
@ -8,24 +10,24 @@ module Analysis.Abstract.Evaluating
, load , load
) where ) where
import Control.Abstract.Evaluator import Control.Abstract.Evaluator
import Control.Monad.Effect import Control.Monad.Effect
import Control.Monad.Effect.Resumable import Control.Monad.Effect.Resumable
import Data.Abstract.Configuration import Data.Abstract.Configuration
import Data.Abstract.Environment (Environment)
import qualified Data.Abstract.Environment as Env import qualified Data.Abstract.Environment as Env
import Data.Abstract.Environment (Environment) import Data.Abstract.Evaluatable
import Data.Abstract.Heap (Heap(..)) import Data.Abstract.Exports (Exports)
import qualified Data.Abstract.Exports as Export import qualified Data.Abstract.Exports as Export
import Data.Abstract.Exports (Exports) import Data.Abstract.Heap
import Data.Abstract.Evaluatable import Data.Abstract.Module
import Data.Abstract.Module import Data.Abstract.ModuleTable
import Data.Abstract.ModuleTable import Data.Abstract.Value
import Data.Abstract.Value
import qualified Data.IntMap as IntMap
import Prelude hiding (fail)
import Prologue hiding (throwError)
import qualified Data.ByteString.Char8 as BC import qualified Data.ByteString.Char8 as BC
import qualified Data.IntMap as IntMap
import qualified Data.Map.Monoidal as Monoidal import qualified Data.Map.Monoidal as Monoidal
import Prelude hiding (fail)
import Prologue hiding (throwError)
-- | Require/import another module by name and return it's environment and value. -- | Require/import another module by name and return it's environment and value.
-- --
@ -78,7 +80,8 @@ deriving instance Member NonDet effects => MonadNonDet (Evaluating term value
-- | Effects necessary for evaluating (whether concrete or abstract). -- | Effects necessary for evaluating (whether concrete or abstract).
type EvaluatingEffects term value type EvaluatingEffects term value
= '[ Resumable Prelude.String value = '[ Resumable ValueExc
, Resumable (Unspecialized value)
, Fail -- Failure with an error message , Fail -- Failure with an error message
, Reader [Module term] -- The stack of currently-evaluating modules. , Reader [Module term] -- The stack of currently-evaluating modules.
, State (EnvironmentFor value) -- Environments (both local and global) , State (EnvironmentFor value) -- Environments (both local and global)
@ -91,8 +94,8 @@ type EvaluatingEffects term value
] ]
-- | Find the value in the 'Final' result of running. -- | Find the value in the 'Final' result of running.
findValue :: forall value term effects . (effects ~ RequiredEffects term value (Evaluating term value effects)) findValue :: forall value term effects. (effects ~ RequiredEffects term value (Evaluating term value effects))
=> Final effects value -> Either Prelude.String (Either Prelude.String value) => Final effects value -> Either Prelude.String (Either (SomeExc (Unspecialized value)) (Either (SomeExc ValueExc) value))
findValue (((((v, _), _), _), _), _) = v findValue (((((v, _), _), _), _), _) = v
-- | Find the 'Environment' in the 'Final' result of running. -- | Find the 'Environment' in the 'Final' result of running.
@ -106,7 +109,11 @@ findHeap :: forall value term effects . (effects ~ RequiredEffects term value (E
findHeap (((((_, _), Heap heap), _), _), _) = heap findHeap (((((_, _), Heap heap), _), _), _) = heap
instance Members '[Resumable Prelude.String value] effects => MonadThrow Prelude.String value (Evaluating term value effects) where resumeException :: forall exc m e a. (Effectful m, Resumable exc :< e) => m e a -> (forall v. (v -> m e a) -> exc v -> m e a) -> m e a
resumeException m handle = raise (resumeError (lower m) (\yield -> lower . handle (raise . yield)))
instance (Monad (m effects), Effectful m, Members '[Resumable exc] effects) => MonadThrow exc (m effects) where
throwException = raise . throwError throwException = raise . throwError
instance Members '[Fail, State (IntMap.IntMap term)] effects => MonadControl term (Evaluating term value effects) where instance Members '[Fail, State (IntMap.IntMap term)] effects => MonadControl term (Evaluating term value effects) where
@ -165,7 +172,7 @@ instance ( Evaluatable (Base term)
=> MonadAnalysis term value (Evaluating term value effects) where => MonadAnalysis term value (Evaluating term value effects) where
type RequiredEffects term value (Evaluating term value effects) = EvaluatingEffects term value type RequiredEffects term value (Evaluating term value effects) = EvaluatingEffects term value
analyzeTerm term = resumeException @value (eval term) (\yield exc -> string (BC.pack exc) >>= yield) analyzeTerm term = resumeException @(Unspecialized value) (eval term) (\yield (Unspecialized str) -> string (BC.pack str) >>= yield)
analyzeModule m = pushModule (subterm <$> m) (subtermValue (moduleBody m)) analyzeModule m = pushModule (subterm <$> m) (subtermValue (moduleBody m))

View File

@ -168,5 +168,5 @@ class Monad m => MonadControl term m where
-- | “Jump” to a previously-allocated 'Label' (retrieving the @term@ at which it points, which can then be evaluated in e.g. a 'MonadAnalysis' instance). -- | “Jump” to a previously-allocated 'Label' (retrieving the @term@ at which it points, which can then be evaluated in e.g. a 'MonadAnalysis' instance).
goto :: Label -> m term goto :: Label -> m term
class Monad m => MonadThrow exc v m | m -> exc where class Monad m => MonadThrow exc m where
throwException :: exc -> m v throwException :: exc v -> m v

View File

@ -1,17 +1,18 @@
{-# LANGUAGE MultiParamTypeClasses, Rank2Types, TypeFamilies, TypeOperators, UndecidableInstances #-} {-# LANGUAGE GADTs, MultiParamTypeClasses, Rank2Types, StandaloneDeriving, TypeFamilies, TypeOperators,
UndecidableInstances #-}
module Control.Abstract.Value where module Control.Abstract.Value where
import Control.Abstract.Addressable import Control.Abstract.Addressable
import Control.Abstract.Analysis import Control.Abstract.Analysis
import qualified Data.Abstract.Environment as Env import qualified Data.Abstract.Environment as Env
import Data.Abstract.FreeVariables import Data.Abstract.FreeVariables
import Data.Abstract.Number as Number import Data.Abstract.Number as Number
import Data.Abstract.Type as Type import Data.Abstract.Type as Type
import Data.Abstract.Value as Value import Data.Abstract.Value as Value
import Data.Scientific (Scientific) import Data.Scientific (Scientific)
import qualified Data.Set as Set import qualified Data.Set as Set
import Prelude hiding (fail) import Prelude hiding (fail)
import Prologue import Prologue
-- | This datum is passed into liftComparison to handle the fact that Ruby and PHP -- | This datum is passed into liftComparison to handle the fact that Ruby and PHP
-- have built-in generalized-comparison ("spaceship") operators. If you want to -- have built-in generalized-comparison ("spaceship") operators. If you want to
@ -153,10 +154,26 @@ doWhile body cond = loop $ \ continue -> body *> do
this <- cond this <- cond
ifthenelse this continue unit ifthenelse this continue unit
-- The type of exceptions that can be thrown when constructing values in `MonadValue`.
data ValueExc v where
ValueExc :: Prelude.String -> ValueExc Value
StringExc :: Prelude.String -> ValueExc ByteString
instance Eq1 ValueExc where
liftEq _ (ValueExc a) (ValueExc b) = a == b
liftEq _ (StringExc a) (StringExc b) = a == b
liftEq _ _ _ = False
deriving instance Show (ValueExc v)
instance Show1 ValueExc where
liftShowsPrec _ _ = showsPrec
-- | Construct a 'Value' wrapping the value arguments (if any). -- | Construct a 'Value' wrapping the value arguments (if any).
instance ( Monad m instance ( Monad m
, MonadAddressable location Value m , MonadAddressable location Value m
, MonadAnalysis term Value m , MonadAnalysis term Value m
, MonadThrow ValueExc m
) )
=> MonadValue Value m where => MonadValue Value m where
@ -184,7 +201,6 @@ instance ( Monad m
product <- mconcat <$> traverse scopedEnvironment supers product <- mconcat <$> traverse scopedEnvironment supers
pure . injValue $ Class n (Env.push product <> env) pure . injValue $ Class n (Env.push product <> env)
namespace n env = do namespace n env = do
maybeAddr <- lookupEnv n maybeAddr <- lookupEnv n
env' <- maybe (pure mempty) (asNamespaceEnv <=< deref) maybeAddr env' <- maybe (pure mempty) (asNamespaceEnv <=< deref) maybeAddr
@ -200,7 +216,7 @@ instance ( Monad m
asString v asString v
| Just (Value.String n) <- prjValue v = pure n | Just (Value.String n) <- prjValue v = pure n
| otherwise = fail ("expected " <> show v <> " to be a string") | otherwise = throwException (StringExc ("expected " <> show v <> " to be a string"))
ifthenelse cond if' else' ifthenelse cond if' else'
| Just (Boolean b) <- prjValue cond = if b then if' else else' | Just (Boolean b) <- prjValue cond = if b then if' else else'

View File

@ -5,9 +5,9 @@ import Control.Monad.Effect as Effect
import Control.Monad.Effect.Fail import Control.Monad.Effect.Fail
import Control.Monad.Effect.NonDet import Control.Monad.Effect.NonDet
import Control.Monad.Effect.Reader import Control.Monad.Effect.Reader
import Control.Monad.Effect.Resumable
import Control.Monad.Effect.State import Control.Monad.Effect.State
import Control.Monad.Effect.Writer import Control.Monad.Effect.Writer
import Control.Monad.Effect.Resumable
import Data.Semigroup.Reducer import Data.Semigroup.Reducer
import Prologue import Prologue
@ -64,13 +64,10 @@ instance Ord a => RunEffect NonDet a where
runEffect = runNonDet unit runEffect = runNonDet unit
-- | 'Resumable' effects are interpreted into 'Either' s.t. failures are in 'Left' and successful results are in 'Right'. -- | 'Resumable' effects are interpreted into 'Either' s.t. failures are in 'Left' and successful results are in 'Right'.
instance RunEffect (Resumable exc v) a where instance RunEffect (Resumable exc) a where
type Result (Resumable exc v) a = Either exc a type Result (Resumable exc) a = Either (SomeExc exc) a
runEffect = runError runEffect = runError
resumeException :: forall v m exc e a. (Effectful m, Resumable exc v :< e) => m e a -> ((v -> m e a) -> exc -> m e a) -> m e a
resumeException m handle = raise (resumeError (lower m) (\yield -> lower . handle (raise . yield)))
-- | Types wrapping 'Eff' actions. -- | Types wrapping 'Eff' actions.
-- --

View File

@ -1,4 +1,4 @@
{-# LANGUAGE DefaultSignatures, MultiParamTypeClasses, UndecidableInstances #-} {-# LANGUAGE DefaultSignatures, MultiParamTypeClasses, UndecidableInstances, GADTs, StandaloneDeriving #-}
module Data.Abstract.Evaluatable module Data.Abstract.Evaluatable
( Evaluatable(..) ( Evaluatable(..)
, module Addressable , module Addressable
@ -6,6 +6,7 @@ module Data.Abstract.Evaluatable
, module FreeVariables , module FreeVariables
, module Value , module Value
, MonadEvaluator(..) , MonadEvaluator(..)
, Unspecialized(..)
) where ) where
import Control.Abstract.Addressable as Addressable import Control.Abstract.Addressable as Addressable
@ -20,6 +21,16 @@ import Data.Semigroup.App
import Data.Term import Data.Term
import Prologue import Prologue
data Unspecialized a b where
Unspecialized :: { getUnspecialized :: Prelude.String } -> Unspecialized value value
instance Eq1 (Unspecialized a) where
liftEq _ (Unspecialized a) (Unspecialized b) = a == b
deriving instance Eq (Unspecialized a b)
deriving instance Show (Unspecialized a b)
instance Show1 (Unspecialized a) where
liftShowsPrec _ _ = showsPrec
-- | The 'Evaluatable' class defines the necessary interface for a term to be evaluated. While a default definition of 'eval' is given, instances with computational content must implement 'eval' to perform their small-step operational semantics. -- | The 'Evaluatable' class defines the necessary interface for a term to be evaluated. While a default definition of 'eval' is given, instances with computational content must implement 'eval' to perform their small-step operational semantics.
class Evaluatable constr where class Evaluatable constr where
@ -28,11 +39,11 @@ class Evaluatable constr where
, MonadAnalysis term value m , MonadAnalysis term value m
, MonadValue value m , MonadValue value m
, Show (LocationFor value) , Show (LocationFor value)
, MonadThrow Prelude.String value m , MonadThrow (Unspecialized value) m
) )
=> SubtermAlgebra constr term (m value) => SubtermAlgebra constr term (m value)
default eval :: (MonadThrow Prelude.String value m, Show1 constr) => SubtermAlgebra constr term (m value) default eval :: (MonadThrow (Unspecialized value) m, Show1 constr) => SubtermAlgebra constr term (m value)
eval expr = throwException $ "Eval unspecialized for " ++ liftShowsPrec (const (const id)) (const id) 0 expr "" eval expr = throwException (Unspecialized ("Eval unspecialized for " ++ liftShowsPrec (const (const id)) (const id) 0 expr ""))
-- | If we can evaluate any syntax which can occur in a 'Union', we can evaluate the 'Union'. -- | If we can evaluate any syntax which can occur in a 'Union', we can evaluate the 'Union'.
instance Apply Evaluatable fs => Evaluatable (Union fs) where instance Apply Evaluatable fs => Evaluatable (Union fs) where

View File

@ -30,11 +30,11 @@ spec = parallel $ do
it "subclasses" $ do it "subclasses" $ do
v <- findValue <$> evaluate "subclass.py" v <- findValue <$> evaluate "subclass.py"
v `shouldBe` Right (Right (injValue (String "\"bar\""))) v `shouldBe` Right (Right (Right (injValue (String "\"bar\""))))
it "handles multiple inheritance left-to-right" $ do it "handles multiple inheritance left-to-right" $ do
v <- findValue <$> evaluate "multiple_inheritance.py" v <- findValue <$> evaluate "multiple_inheritance.py"
v `shouldBe` Right (Right (injValue (String "\"foo!\""))) v `shouldBe` Right (Right (Right (injValue (String "\"foo!\""))))
where where
addr = Address . Precise addr = Address . Precise

View File

@ -30,11 +30,11 @@ spec = parallel $ do
it "subclass" $ do it "subclass" $ do
res <- findValue <$> evaluate "subclass.rb" res <- findValue <$> evaluate "subclass.rb"
res `shouldBe` Right (Right (injValue (String "\"<bar>\""))) res `shouldBe` Right (Right (Right (injValue (String "\"<bar>\""))))
it "has prelude" $ do it "has prelude" $ do
res <- findValue <$> evaluate "preluded.rb" res <- findValue <$> evaluate "preluded.rb"
res `shouldBe` Right (Right (injValue (String "\"<foo>\""))) res `shouldBe` Right (Right (Right (injValue (String "\"<foo>\""))))
where where
addr = Address . Precise addr = Address . Precise

10
test/fixtures/ruby/analysis/src/main.rb vendored Normal file
View File

@ -0,0 +1,10 @@
require File.join(__FILE__, "../foo.rb")
require "foo"
bar()
# def foo
# return "in foo"
# end
foo()

2
vendor/effects vendored

@ -1 +1 @@
Subproject commit 7d4525db7b6a12c0a34da5f70a97db137c144c60 Subproject commit 74c1ca98ae9007e64fdc3f819b7d096ff7f802f7