From e713a17ca97016160f3205bb9c83283a1115bf57 Mon Sep 17 00:00:00 2001 From: joshvera Date: Wed, 21 Mar 2018 11:41:41 -0400 Subject: [PATCH 01/48] Add resumable exceptions --- src/Analysis/Abstract/Evaluating.hs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Analysis/Abstract/Evaluating.hs b/src/Analysis/Abstract/Evaluating.hs index cb89fea6a..79fecc947 100644 --- a/src/Analysis/Abstract/Evaluating.hs +++ b/src/Analysis/Abstract/Evaluating.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE DataKinds, GeneralizedNewtypeDeriving, MultiParamTypeClasses, ScopedTypeVariables, StandaloneDeriving, TypeApplications, TypeFamilies, TypeOperators, UndecidableInstances #-} +{-# LANGUAGE DataKinds, GeneralizedNewtypeDeriving, MultiParamTypeClasses, ScopedTypeVariables, StandaloneDeriving, TypeApplications, TypeFamilies, TypeOperators, UndecidableInstances, GADTs #-} module Analysis.Abstract.Evaluating ( type Evaluating , evaluate @@ -6,6 +6,7 @@ module Analysis.Abstract.Evaluating ) where import Control.Abstract.Evaluator +import Control.Monad.Effect.Internal (Arrow, relay, interpose) import Control.Monad.Effect import Control.Monad.Effect.Fail import Control.Monad.Effect.Reader @@ -87,6 +88,24 @@ type EvaluatingEffects term value , State (IntMap.IntMap term) -- For jumps ] +data ResumeExc exc v a where + ResumeExc :: exc -> ResumeExc exc v v + +throwError :: forall exc v e. (ResumeExc exc v :< e) => exc -> Eff e v +throwError e = send (ResumeExc e :: ResumeExc exc v v) + +runError :: Eff (ResumeExc exc v ': e) a -> Eff e (Either exc a) +runError = + relay (pure . Right) (\ (ResumeExc e) _k -> pure (Left e)) + +resumeError :: forall v exc e a. (ResumeExc exc v :< e) => + Eff e a -> (Arrow e v a -> exc -> Eff e a) -> Eff e a +resumeError m handle = interpose @(ResumeExc exc v) pure (\(ResumeExc e) yield -> handle yield e) m + +catchError :: forall v exc e proxy a. (ResumeExc exc v :< e) => + proxy v -> Eff e a -> (exc -> Eff e a) -> Eff e a +catchError _ m handle = resumeError @v m (\k e -> handle e) + instance Members '[Fail, State (IntMap.IntMap term)] effects => MonadControl term (Evaluating term value effects) where label term = do m <- raise get From 86f8ce5eab64bf54506c6a48b818211cc945065c Mon Sep 17 00:00:00 2001 From: joshvera Date: Wed, 21 Mar 2018 12:13:17 -0400 Subject: [PATCH 02/48] Add MonadResume --- src/Control/Abstract/Evaluator.hs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Control/Abstract/Evaluator.hs b/src/Control/Abstract/Evaluator.hs index f7456094b..e64cd12c4 100644 --- a/src/Control/Abstract/Evaluator.hs +++ b/src/Control/Abstract/Evaluator.hs @@ -13,6 +13,7 @@ module Control.Abstract.Evaluator , MonadModuleTable(..) , modifyModuleTable , MonadControl(..) + , MonadResume(..) ) where import Data.Abstract.Address @@ -147,3 +148,6 @@ class Monad m => MonadControl term m where label :: term -> m Label -- | “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 + +class Monad m => MonadResume exc v m | m -> exc where + throwException :: exc -> m v From 8b13d98a250e75712591c43096d5e4362bee04a7 Mon Sep 17 00:00:00 2001 From: joshvera Date: Wed, 21 Mar 2018 12:13:29 -0400 Subject: [PATCH 03/48] Use MonadResume in eval --- src/Data/Abstract/Evaluatable.hs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index adf41de29..5f1d2dab9 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -28,10 +28,11 @@ class Evaluatable constr where , MonadAnalysis term value m , MonadValue value m , Show (LocationFor value) + , MonadResume Prelude.String value m ) => SubtermAlgebra constr term (m value) - default eval :: (MonadFail m, Show1 constr) => SubtermAlgebra constr term (m value) - eval expr = fail $ "Eval unspecialized for " ++ liftShowsPrec (const (const id)) (const id) 0 expr "" + default eval :: (MonadResume Prelude.String value m, Show1 constr) => SubtermAlgebra constr term (m value) + eval expr = throwException $ "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'. instance Apply Evaluatable fs => Evaluatable (Union fs) where From ffea66cdca3d2be7e1b76cf8d3120a78271ec7aa Mon Sep 17 00:00:00 2001 From: joshvera Date: Wed, 21 Mar 2018 12:13:48 -0400 Subject: [PATCH 04/48] Add RunEffect instance for ResumeExc --- src/Analysis/Abstract/Evaluating.hs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Analysis/Abstract/Evaluating.hs b/src/Analysis/Abstract/Evaluating.hs index 79fecc947..ca968204c 100644 --- a/src/Analysis/Abstract/Evaluating.hs +++ b/src/Analysis/Abstract/Evaluating.hs @@ -106,6 +106,11 @@ catchError :: forall v exc e proxy a. (ResumeExc exc v :< e) => proxy v -> Eff e a -> (exc -> Eff e a) -> Eff e a catchError _ m handle = resumeError @v m (\k e -> handle e) +-- | 'ResumeExc' effects are interpreted into 'Either' s.t. failures are in 'Left' and successful results are in 'Right'. +instance RunEffect (ResumeExc exc v) a where + type Result (ResumeExc exc v) a = Either exc a + runEffect = runError + instance Members '[Fail, State (IntMap.IntMap term)] effects => MonadControl term (Evaluating term value effects) where label term = do m <- raise get From 2cdd9fa183d4d943d535ead6c32ba9a0a9a07b9f Mon Sep 17 00:00:00 2001 From: joshvera Date: Wed, 21 Mar 2018 12:14:04 -0400 Subject: [PATCH 05/48] Add MonadResume instance for effects --- src/Analysis/Abstract/Evaluating.hs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Analysis/Abstract/Evaluating.hs b/src/Analysis/Abstract/Evaluating.hs index ca968204c..6086f5ab0 100644 --- a/src/Analysis/Abstract/Evaluating.hs +++ b/src/Analysis/Abstract/Evaluating.hs @@ -111,6 +111,9 @@ instance RunEffect (ResumeExc exc v) a where type Result (ResumeExc exc v) a = Either exc a runEffect = runError +instance Members '[ResumeExc Prelude.String value] effects => MonadResume Prelude.String value (Evaluating term value effects) where + throwException = raise . throwError + instance Members '[Fail, State (IntMap.IntMap term)] effects => MonadControl term (Evaluating term value effects) where label term = do m <- raise get From 5ca8367dff1f0991c7936871034e64fe2f502907 Mon Sep 17 00:00:00 2001 From: joshvera Date: Wed, 21 Mar 2018 12:15:12 -0400 Subject: [PATCH 06/48] Use resumeError in analyzeTerm --- src/Analysis/Abstract/Evaluating.hs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Analysis/Abstract/Evaluating.hs b/src/Analysis/Abstract/Evaluating.hs index 6086f5ab0..0ca33911f 100644 --- a/src/Analysis/Abstract/Evaluating.hs +++ b/src/Analysis/Abstract/Evaluating.hs @@ -21,7 +21,7 @@ import qualified Data.IntMap as IntMap import Data.Language import Data.List.Split (splitWhen) import Prelude hiding (fail) -import Prologue +import Prologue hiding (throwError) import qualified Data.ByteString.Char8 as BC import qualified Data.Map as Map import System.FilePath.Posix @@ -86,6 +86,7 @@ type EvaluatingEffects term value , 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 + , ResumeExc Prelude.String value ] data ResumeExc exc v a where @@ -162,4 +163,4 @@ instance ( Evaluatable (Base term) => MonadAnalysis term value (Evaluating term value effects) where type RequiredEffects term value (Evaluating term value effects) = EvaluatingEffects term value - analyzeTerm = eval + analyzeTerm term = let evaled = eval term in raise $ resumeError @value (lower evaled) (\yield exc -> lower (string (BC.pack exc) `asTypeOf` evaled) >>= yield) From 750f66d31ae2401b93982668d6635150a8094250 Mon Sep 17 00:00:00 2001 From: joshvera Date: Wed, 21 Mar 2018 12:26:17 -0400 Subject: [PATCH 07/48] Add a resumeException function to wrap nonsense --- src/Analysis/Abstract/Evaluating.hs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Analysis/Abstract/Evaluating.hs b/src/Analysis/Abstract/Evaluating.hs index 0ca33911f..68272329b 100644 --- a/src/Analysis/Abstract/Evaluating.hs +++ b/src/Analysis/Abstract/Evaluating.hs @@ -103,6 +103,9 @@ resumeError :: forall v exc e a. (ResumeExc exc v :< e) => Eff e a -> (Arrow e v a -> exc -> Eff e a) -> Eff e a resumeError m handle = interpose @(ResumeExc exc v) pure (\(ResumeExc e) yield -> handle yield e) m +resumeException :: forall v m exc e a. (Effectful m, ResumeExc 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))) + catchError :: forall v exc e proxy a. (ResumeExc exc v :< e) => proxy v -> Eff e a -> (exc -> Eff e a) -> Eff e a catchError _ m handle = resumeError @v m (\k e -> handle e) @@ -163,4 +166,4 @@ instance ( Evaluatable (Base term) => MonadAnalysis term value (Evaluating term value effects) where type RequiredEffects term value (Evaluating term value effects) = EvaluatingEffects term value - analyzeTerm term = let evaled = eval term in raise $ resumeError @value (lower evaled) (\yield exc -> lower (string (BC.pack exc) `asTypeOf` evaled) >>= yield) + analyzeTerm term = resumeException @value (eval term) (\yield exc -> string (BC.pack exc) >>= yield) From 6ac73a7a5a5242eb7f6e707a8831074bd7078dae Mon Sep 17 00:00:00 2001 From: Timothy Clem Date: Wed, 21 Mar 2018 10:22:38 -0700 Subject: [PATCH 08/48] Start to work out evaluating of php namespaces Co-Authored-By: Patrick Thomson --- src/Language/PHP/Syntax.hs | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/src/Language/PHP/Syntax.hs b/src/Language/PHP/Syntax.hs index 2361a5a30..c071c52e1 100644 --- a/src/Language/PHP/Syntax.hs +++ b/src/Language/PHP/Syntax.hs @@ -1,10 +1,12 @@ -{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveAnyClass, ViewPatterns #-} module Language.PHP.Syntax where import Analysis.Abstract.Evaluating import Data.Abstract.Evaluatable +import Data.Abstract.Environment as Env import Data.Abstract.Path import Diffing.Algorithm +import Prelude hiding (fail) import Prologue hiding (Text) @@ -177,13 +179,18 @@ instance Ord1 RelativeScope where liftCompare = genericLiftCompare instance Show1 RelativeScope where liftShowsPrec = genericLiftShowsPrec instance Evaluatable RelativeScope -data QualifiedName a = QualifiedName a a +data QualifiedName a = QualifiedName !a !a 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 + +instance Evaluatable QualifiedName where + eval (fmap subtermValue -> QualifiedName name iden) = do + lhs <- name >>= objectEnvironment + localEnv (mappend lhs) iden + newtype NamespaceName a = NamespaceName [a] deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable) @@ -191,7 +198,13 @@ newtype NamespaceName a = NamespaceName [a] instance Eq1 NamespaceName where liftEq = genericLiftEq instance Ord1 NamespaceName where liftCompare = genericLiftCompare instance Show1 NamespaceName where liftShowsPrec = genericLiftShowsPrec -instance Evaluatable NamespaceName + +instance Evaluatable NamespaceName where + eval (NamespaceName []) = fail "nonempty NamespaceName not allowed" + eval (NamespaceName [x]) = subtermValue x + eval (NamespaceName (x:xs)) = do + x' <- subtermValue x >>= objectEnvironment + localEnv (mappend x') (eval (NamespaceName xs)) newtype ConstDeclaration a = ConstDeclaration [a] deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable) @@ -344,7 +357,16 @@ data Namespace a = Namespace { namespaceName :: a, namespaceBody :: a} instance Eq1 Namespace where liftEq = genericLiftEq instance Ord1 Namespace where liftCompare = genericLiftCompare instance Show1 Namespace where liftShowsPrec = genericLiftShowsPrec -instance Evaluatable Namespace + +instance Evaluatable Namespace where + eval Namespace{..} = do + -- TODO: Need a version of letrec that takes list of names/free variables + let name = freeVariable (subterm namespaceName) + (v, addr) <- letrec name $ do + void $ subtermValue namespaceBody + namespaceEnv <- Env.head <$> getEnv + klass name namespaceEnv + v <$ modifyEnv (Env.insert name addr) data TraitDeclaration a = TraitDeclaration { traitName :: a, traitStatements :: [a] } deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable) From 104e9f801f909930daf0e3a6d7d0dc19af8e22b2 Mon Sep 17 00:00:00 2001 From: joshvera Date: Wed, 21 Mar 2018 14:24:20 -0400 Subject: [PATCH 09/48] ++effects --- vendor/effects | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/effects b/vendor/effects index 6aaaa39f1..32abee310 160000 --- a/vendor/effects +++ b/vendor/effects @@ -1 +1 @@ -Subproject commit 6aaaa39f18f38628a91d3ffd155c7f4099131d9e +Subproject commit 32abee310c180ed40edb69d8a455a98994fa0034 From 3cdfb819913f03d586082bd1f21251fce9e7997c Mon Sep 17 00:00:00 2001 From: joshvera Date: Wed, 21 Mar 2018 14:33:17 -0400 Subject: [PATCH 10/48] Move Resumable to effects package --- src/Analysis/Abstract/Evaluating.hs | 30 +++++++---------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/src/Analysis/Abstract/Evaluating.hs b/src/Analysis/Abstract/Evaluating.hs index 68272329b..8880ed6b7 100644 --- a/src/Analysis/Abstract/Evaluating.hs +++ b/src/Analysis/Abstract/Evaluating.hs @@ -11,6 +11,7 @@ import Control.Monad.Effect import Control.Monad.Effect.Fail import Control.Monad.Effect.Reader import Control.Monad.Effect.State +import Control.Monad.Effect.Resumable import Data.Abstract.Configuration import qualified Data.Abstract.Environment as Env import Data.Abstract.Evaluatable @@ -86,36 +87,19 @@ type EvaluatingEffects term value , 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 - , ResumeExc Prelude.String value + , Resumable Prelude.String value ] -data ResumeExc exc v a where - ResumeExc :: exc -> ResumeExc exc v v -throwError :: forall exc v e. (ResumeExc exc v :< e) => exc -> Eff e v -throwError e = send (ResumeExc e :: ResumeExc exc v v) - -runError :: Eff (ResumeExc exc v ': e) a -> Eff e (Either exc a) -runError = - relay (pure . Right) (\ (ResumeExc e) _k -> pure (Left e)) - -resumeError :: forall v exc e a. (ResumeExc exc v :< e) => - Eff e a -> (Arrow e v a -> exc -> Eff e a) -> Eff e a -resumeError m handle = interpose @(ResumeExc exc v) pure (\(ResumeExc e) yield -> handle yield e) m - -resumeException :: forall v m exc e a. (Effectful m, ResumeExc exc v :< e) => m e a -> ((v -> m e a) -> exc -> m e a) -> m e a +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))) -catchError :: forall v exc e proxy a. (ResumeExc exc v :< e) => - proxy v -> Eff e a -> (exc -> Eff e a) -> Eff e a -catchError _ m handle = resumeError @v m (\k e -> handle e) - --- | 'ResumeExc' effects are interpreted into 'Either' s.t. failures are in 'Left' and successful results are in 'Right'. -instance RunEffect (ResumeExc exc v) a where - type Result (ResumeExc exc v) a = Either exc a +-- | '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 + type Result (Resumable exc v) a = Either exc a runEffect = runError -instance Members '[ResumeExc Prelude.String value] effects => MonadResume Prelude.String value (Evaluating term value effects) where +instance Members '[Resumable Prelude.String value] effects => MonadResume Prelude.String value (Evaluating term value effects) where throwException = raise . throwError instance Members '[Fail, State (IntMap.IntMap term)] effects => MonadControl term (Evaluating term value effects) where From c067736a5543e2122ba5b397eb833e72f5a4a11f Mon Sep 17 00:00:00 2001 From: joshvera Date: Wed, 21 Mar 2018 14:58:45 -0400 Subject: [PATCH 11/48] Move NonDetEff stuff to effects and clean up imports --- src/Analysis/Abstract/Evaluating.hs | 3 --- src/Control/Effect.hs | 7 ++----- src/Control/Effect/NonDet.hs | 6 ++---- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/Analysis/Abstract/Evaluating.hs b/src/Analysis/Abstract/Evaluating.hs index 8880ed6b7..b8eb31768 100644 --- a/src/Analysis/Abstract/Evaluating.hs +++ b/src/Analysis/Abstract/Evaluating.hs @@ -8,9 +8,6 @@ module Analysis.Abstract.Evaluating import Control.Abstract.Evaluator import Control.Monad.Effect.Internal (Arrow, relay, interpose) import Control.Monad.Effect -import Control.Monad.Effect.Fail -import Control.Monad.Effect.Reader -import Control.Monad.Effect.State import Control.Monad.Effect.Resumable import Data.Abstract.Configuration import qualified Data.Abstract.Environment as Env diff --git a/src/Control/Effect.hs b/src/Control/Effect.hs index 9709615ae..061baedbf 100644 --- a/src/Control/Effect.hs +++ b/src/Control/Effect.hs @@ -1,9 +1,8 @@ {-# LANGUAGE DataKinds, MultiParamTypeClasses, TypeFamilies, TypeOperators, UndecidableInstances #-} module Control.Effect where -import qualified Control.Monad.Effect as Effect +import Control.Monad.Effect as Effect import Control.Monad.Effect.Fail -import Control.Monad.Effect.Internal import Control.Monad.Effect.NonDetEff import Control.Monad.Effect.Reader import Control.Monad.Effect.State @@ -61,9 +60,7 @@ instance Monoid w => RunEffect (Writer w) a where -- | 'NonDetEff' effects are interpreted into a nondeterministic set of result values. instance Ord a => RunEffect NonDetEff a where type Result NonDetEff a = Set a - runEffect = relay (pure . unit) (\ m k -> case m of - MZero -> pure mempty - MPlus -> mappend <$> k True <*> k False) + runEffect = runNonDetEff unit -- | Types wrapping 'Eff' actions. diff --git a/src/Control/Effect/NonDet.hs b/src/Control/Effect/NonDet.hs index 34c23f74d..f5178a900 100644 --- a/src/Control/Effect/NonDet.hs +++ b/src/Control/Effect/NonDet.hs @@ -5,7 +5,7 @@ module Control.Effect.NonDet ) where import Control.Monad.Effect.Internal -import Control.Monad.Effect.NonDetEff +import Control.Monad.Effect.NonDetEff as NonDetEff import Prologue -- | 'Monad's offering local isolation of nondeterminism effects. @@ -18,6 +18,4 @@ class (Alternative m, Monad m) => MonadNonDet m where -- | Effect stacks containing 'NonDetEff' offer a 'MonadNonDet' instance which implements 'gather' by interpreting the requests for nondeterminism locally, without removing 'NonDetEff' from the stack—i.e. the _capacity_ for nondeterminism is still present in the effect stack, but any local nondeterminism has been applied. instance (NonDetEff :< fs) => MonadNonDet (Eff fs) where - gather f = interpose (pure . f) (\ m k -> case m of - MZero -> pure mempty - MPlus -> mappend <$> k True <*> k False) + gather = NonDetEff.gather From c5988bfe57cb41b5aa3bc80a47784736e62849cb Mon Sep 17 00:00:00 2001 From: joshvera Date: Wed, 21 Mar 2018 14:59:28 -0400 Subject: [PATCH 12/48] ++effects --- vendor/effects | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/effects b/vendor/effects index 32abee310..b823e3bbb 160000 --- a/vendor/effects +++ b/vendor/effects @@ -1 +1 @@ -Subproject commit 32abee310c180ed40edb69d8a455a98994fa0034 +Subproject commit b823e3bbb38154771e74fdf76515be3722269375 From 85bcdb62819000e2a2960349e7e224d1ff1b4123 Mon Sep 17 00:00:00 2001 From: joshvera Date: Wed, 21 Mar 2018 15:14:09 -0400 Subject: [PATCH 13/48] Remove unused import --- src/Analysis/Abstract/Evaluating.hs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Analysis/Abstract/Evaluating.hs b/src/Analysis/Abstract/Evaluating.hs index b8eb31768..782c323da 100644 --- a/src/Analysis/Abstract/Evaluating.hs +++ b/src/Analysis/Abstract/Evaluating.hs @@ -6,7 +6,6 @@ module Analysis.Abstract.Evaluating ) where import Control.Abstract.Evaluator -import Control.Monad.Effect.Internal (Arrow, relay, interpose) import Control.Monad.Effect import Control.Monad.Effect.Resumable import Data.Abstract.Configuration From ec39a8bdd9b6b35af79cde7e2b1a58fcefa1fdc9 Mon Sep 17 00:00:00 2001 From: joshvera Date: Wed, 21 Mar 2018 15:14:24 -0400 Subject: [PATCH 14/48] Move RunnEffect Resumable instance --- src/Analysis/Abstract/Evaluating.hs | 7 +------ src/Control/Effect.hs | 5 +++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Analysis/Abstract/Evaluating.hs b/src/Analysis/Abstract/Evaluating.hs index 782c323da..47f7cf1ce 100644 --- a/src/Analysis/Abstract/Evaluating.hs +++ b/src/Analysis/Abstract/Evaluating.hs @@ -90,12 +90,7 @@ type EvaluatingEffects term value 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))) --- | '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 - type Result (Resumable exc v) a = Either exc a - runEffect = runError - -instance Members '[Resumable Prelude.String value] effects => MonadResume Prelude.String value (Evaluating term value effects) where +instance Members '[Resumable Prelude.String value] effects => MonadThrow Prelude.String value (Evaluating term value effects) where throwException = raise . throwError instance Members '[Fail, State (IntMap.IntMap term)] effects => MonadControl term (Evaluating term value effects) where diff --git a/src/Control/Effect.hs b/src/Control/Effect.hs index 061baedbf..e412ebc7a 100644 --- a/src/Control/Effect.hs +++ b/src/Control/Effect.hs @@ -62,6 +62,11 @@ instance Ord a => RunEffect NonDetEff a where type Result NonDetEff a = Set a runEffect = runNonDetEff unit +-- | '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 + type Result (Resumable exc v) a = Either exc a + runEffect = runError + -- | Types wrapping 'Eff' actions. -- From 2d7c54ba5471d452129b88693c2b660c53e9d6a0 Mon Sep 17 00:00:00 2001 From: joshvera Date: Wed, 21 Mar 2018 15:14:35 -0400 Subject: [PATCH 15/48] Rename MonadResume to MonadThrow --- src/Control/Abstract/Evaluator.hs | 4 ++-- src/Data/Abstract/Evaluatable.hs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Control/Abstract/Evaluator.hs b/src/Control/Abstract/Evaluator.hs index e64cd12c4..f9009135a 100644 --- a/src/Control/Abstract/Evaluator.hs +++ b/src/Control/Abstract/Evaluator.hs @@ -13,7 +13,7 @@ module Control.Abstract.Evaluator , MonadModuleTable(..) , modifyModuleTable , MonadControl(..) - , MonadResume(..) + , MonadThrow(..) ) where import Data.Abstract.Address @@ -149,5 +149,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). goto :: Label -> m term -class Monad m => MonadResume exc v m | m -> exc where +class Monad m => MonadThrow exc v m | m -> exc where throwException :: exc -> m v diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 5f1d2dab9..3caaaabe1 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -28,10 +28,10 @@ class Evaluatable constr where , MonadAnalysis term value m , MonadValue value m , Show (LocationFor value) - , MonadResume Prelude.String value m + , MonadThrow Prelude.String value m ) => SubtermAlgebra constr term (m value) - default eval :: (MonadResume Prelude.String value m, Show1 constr) => SubtermAlgebra constr term (m value) + default eval :: (MonadThrow Prelude.String value m, Show1 constr) => SubtermAlgebra constr term (m value) eval expr = throwException $ "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'. From 310a2d9e6d37fae72cf72aea0a03d89d8435221c Mon Sep 17 00:00:00 2001 From: joshvera Date: Wed, 21 Mar 2018 15:23:44 -0400 Subject: [PATCH 16/48] Missing import --- src/Control/Effect.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Control/Effect.hs b/src/Control/Effect.hs index e412ebc7a..7d5298c31 100644 --- a/src/Control/Effect.hs +++ b/src/Control/Effect.hs @@ -7,6 +7,7 @@ import Control.Monad.Effect.NonDetEff import Control.Monad.Effect.Reader import Control.Monad.Effect.State import Control.Monad.Effect.Writer +import Control.Monad.Effect.Resumable import Data.Semigroup.Reducer import Prologue From 7cc460fab1bf1bc4f4a626bbb9449cfacc964601 Mon Sep 17 00:00:00 2001 From: joshvera Date: Wed, 21 Mar 2018 15:51:36 -0400 Subject: [PATCH 17/48] Move Resumable to the top of the effect stack --- src/Analysis/Abstract/Evaluating.hs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Analysis/Abstract/Evaluating.hs b/src/Analysis/Abstract/Evaluating.hs index 47f7cf1ce..008f81d6f 100644 --- a/src/Analysis/Abstract/Evaluating.hs +++ b/src/Analysis/Abstract/Evaluating.hs @@ -76,14 +76,15 @@ 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 + = '[ + Resumable Prelude.String 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 , 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 - , Resumable Prelude.String value ] From 2bf23e7a082e5ef4da3cb24bfd27c9a12ecaec35 Mon Sep 17 00:00:00 2001 From: joshvera Date: Wed, 21 Mar 2018 16:01:27 -0400 Subject: [PATCH 18/48] no need to import prelude --- src/Data/Abstract/Evaluatable.hs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 3caaaabe1..a0ab76e44 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -17,7 +17,6 @@ import Data.Functor.Classes import Data.Proxy import Data.Semigroup.Foldable import Data.Term -import Prelude hiding (fail) import Prologue From 6591c81e4ee59271b2d20182f8186def8be6fa06 Mon Sep 17 00:00:00 2001 From: Timothy Clem Date: Wed, 21 Mar 2018 16:18:58 -0700 Subject: [PATCH 19/48] Proper nesting of namespace environments (this is messy) Co-Authored-By: Josh Vera --- src/Language/PHP/Syntax.hs | 45 +++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/src/Language/PHP/Syntax.hs b/src/Language/PHP/Syntax.hs index c071c52e1..ef241b3de 100644 --- a/src/Language/PHP/Syntax.hs +++ b/src/Language/PHP/Syntax.hs @@ -200,11 +200,13 @@ instance Ord1 NamespaceName where liftCompare = genericLiftCompare instance Show1 NamespaceName where liftShowsPrec = genericLiftShowsPrec instance Evaluatable NamespaceName where - eval (NamespaceName []) = fail "nonempty NamespaceName not allowed" - eval (NamespaceName [x]) = subtermValue x - eval (NamespaceName (x:xs)) = do - x' <- subtermValue x >>= objectEnvironment - localEnv (mappend x') (eval (NamespaceName xs)) + eval (NamespaceName xs) = go xs + where + go [] = fail "nonempty NamespaceName not allowed" + go [x] = subtermValue x + go (x:xs) = do + env <- subtermValue x >>= objectEnvironment + localEnv (mappend env) (go xs) newtype ConstDeclaration a = ConstDeclaration [a] deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable) @@ -359,14 +361,31 @@ instance Ord1 Namespace where liftCompare = genericLiftCompare instance Show1 Namespace where liftShowsPrec = genericLiftShowsPrec instance Evaluatable Namespace where - eval Namespace{..} = do - -- TODO: Need a version of letrec that takes list of names/free variables - let name = freeVariable (subterm namespaceName) - (v, addr) <- letrec name $ do - void $ subtermValue namespaceBody - namespaceEnv <- Env.head <$> getEnv - klass name namespaceEnv - v <$ modifyEnv (Env.insert name addr) + eval Namespace{..} = go names + where + names = toList (freeVariables (subterm namespaceName)) + + go [] = fail "gotta fix this" + go [name] = do + v <- localEnv id $ do + void $ subtermValue namespaceBody + namespaceEnv <- Env.head <$> getEnv + klass name namespaceEnv + + addr <- lookupOrAlloc name + assign addr v + v <$ modifyEnv (Env.insert name addr) + go (name:xs) = do + (v, res) <- localEnv id $ do + res <- go xs + namespaceEnv <- Env.head <$> getEnv + v <- klass name namespaceEnv + pure (v, res) + + addr <- trace (show name) (lookupOrAlloc name) + assign addr v + modifyEnv (insert name addr) + pure res data TraitDeclaration a = TraitDeclaration { traitName :: a, traitStatements :: [a] } deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable) From a8c9c815ef31eb7270e0af0d8c14de8a626c23d0 Mon Sep 17 00:00:00 2001 From: joshvera Date: Thu, 22 Mar 2018 10:35:25 -0400 Subject: [PATCH 20/48] Rename NonDetEff to NonDet --- src/Analysis/Abstract/Caching.hs | 2 +- src/Analysis/Abstract/Evaluating.hs | 4 ++-- src/Control/Effect.hs | 10 +++++----- src/Control/Effect/NonDet.hs | 10 +++++----- test/Analysis/Go/Spec.hs | 1 + vendor/effects | 2 +- 6 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/Analysis/Abstract/Caching.hs b/src/Analysis/Abstract/Caching.hs index 0d0d3f3e4..e1e2d47a2 100644 --- a/src/Analysis/Abstract/Caching.hs +++ b/src/Analysis/Abstract/Caching.hs @@ -13,7 +13,7 @@ import Prologue -- | The effects necessary for caching analyses. type CachingEffects term value effects = Fresh -- For 'MonadFresh'. - ': NonDetEff -- For 'Alternative' and 'MonadNonDet'. + ': NonDet -- For 'Alternative' and 'MonadNonDet'. ': Reader (CacheFor term value) -- The in-cache used as an oracle while converging on a result. ': State (CacheFor term value) -- The out-cache used to record results in each iteration of convergence. ': effects diff --git a/src/Analysis/Abstract/Evaluating.hs b/src/Analysis/Abstract/Evaluating.hs index 008f81d6f..68ce801e5 100644 --- a/src/Analysis/Abstract/Evaluating.hs +++ b/src/Analysis/Abstract/Evaluating.hs @@ -71,8 +71,8 @@ newtype Evaluating term value effects a = Evaluating (Eff effects a) deriving instance Member Fail effects => MonadFail (Evaluating term value effects) deriving instance Member Fresh effects => MonadFresh (Evaluating term value effects) -deriving instance Member NonDetEff effects => Alternative (Evaluating term value effects) -deriving instance Member NonDetEff effects => MonadNonDet (Evaluating term value effects) +deriving instance Member NonDet effects => Alternative (Evaluating term value effects) +deriving instance Member NonDet effects => MonadNonDet (Evaluating term value effects) -- | Effects necessary for evaluating (whether concrete or abstract). type EvaluatingEffects term value diff --git a/src/Control/Effect.hs b/src/Control/Effect.hs index 7d5298c31..daf143539 100644 --- a/src/Control/Effect.hs +++ b/src/Control/Effect.hs @@ -3,7 +3,7 @@ module Control.Effect where import Control.Monad.Effect as Effect import Control.Monad.Effect.Fail -import Control.Monad.Effect.NonDetEff +import Control.Monad.Effect.NonDet import Control.Monad.Effect.Reader import Control.Monad.Effect.State import Control.Monad.Effect.Writer @@ -58,10 +58,10 @@ instance Monoid w => RunEffect (Writer w) a where type Result (Writer w) a = (a, w) runEffect = runWriter --- | 'NonDetEff' effects are interpreted into a nondeterministic set of result values. -instance Ord a => RunEffect NonDetEff a where - type Result NonDetEff a = Set a - runEffect = runNonDetEff unit +-- | 'NonDet' effects are interpreted into a nondeterministic set of result values. +instance Ord a => RunEffect NonDet a where + type Result NonDet a = Set a + runEffect = runNonDet unit -- | '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 diff --git a/src/Control/Effect/NonDet.hs b/src/Control/Effect/NonDet.hs index f5178a900..4d1da86a1 100644 --- a/src/Control/Effect/NonDet.hs +++ b/src/Control/Effect/NonDet.hs @@ -1,11 +1,11 @@ {-# LANGUAGE TypeFamilies, TypeOperators, UndecidableInstances #-} module Control.Effect.NonDet ( MonadNonDet(..) -, NonDetEff +, NonDet ) where import Control.Monad.Effect.Internal -import Control.Monad.Effect.NonDetEff as NonDetEff +import Control.Monad.Effect.NonDet as NonDet import Prologue -- | 'Monad's offering local isolation of nondeterminism effects. @@ -16,6 +16,6 @@ class (Alternative m, Monad m) => MonadNonDet m where -> m a -- ^ The computation to run locally-nondeterministically. -> m b -- ^ A _deterministic_ computation producing the 'Monoid'al accumulation of the _locally-nondeterministic_ result values. --- | Effect stacks containing 'NonDetEff' offer a 'MonadNonDet' instance which implements 'gather' by interpreting the requests for nondeterminism locally, without removing 'NonDetEff' from the stack—i.e. the _capacity_ for nondeterminism is still present in the effect stack, but any local nondeterminism has been applied. -instance (NonDetEff :< fs) => MonadNonDet (Eff fs) where - gather = NonDetEff.gather +-- | Effect stacks containing 'NonDet' offer a 'MonadNonDet' instance which implements 'gather' by interpreting the requests for nondeterminism locally, without removing 'NonDet' from the stack—i.e. the _capacity_ for nondeterminism is still present in the effect stack, but any local nondeterminism has been applied. +instance (NonDet :< fs) => MonadNonDet (Eff fs) where + gather = NonDet.gather diff --git a/test/Analysis/Go/Spec.hs b/test/Analysis/Go/Spec.hs index 4611cb4bb..449c40473 100644 --- a/test/Analysis/Go/Spec.hs +++ b/test/Analysis/Go/Spec.hs @@ -3,6 +3,7 @@ module Analysis.Go.Spec (spec) where import Data.Abstract.Value import Data.Map +import Data.Either import SpecHelpers diff --git a/vendor/effects b/vendor/effects index b823e3bbb..5bb3381c4 160000 --- a/vendor/effects +++ b/vendor/effects @@ -1 +1 @@ -Subproject commit b823e3bbb38154771e74fdf76515be3722269375 +Subproject commit 5bb3381c4cf70ed418b8138d69d051e1957ae2f3 From 73a821f856bb75d34ae2dbb503a434c13103484d Mon Sep 17 00:00:00 2001 From: joshvera Date: Thu, 22 Mar 2018 11:42:20 -0400 Subject: [PATCH 21/48] ++effects --- vendor/effects | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/effects b/vendor/effects index 5bb3381c4..7d4525db7 160000 --- a/vendor/effects +++ b/vendor/effects @@ -1 +1 @@ -Subproject commit 5bb3381c4cf70ed418b8138d69d051e1957ae2f3 +Subproject commit 7d4525db7b6a12c0a34da5f70a97db137c144c60 From c96cdc5fbffce6edac02ae2314802b064c5f396d Mon Sep 17 00:00:00 2001 From: joshvera Date: Thu, 22 Mar 2018 11:42:27 -0400 Subject: [PATCH 22/48] No need for GADTs --- src/Analysis/Abstract/Evaluating.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Analysis/Abstract/Evaluating.hs b/src/Analysis/Abstract/Evaluating.hs index 68ce801e5..2b0e1026b 100644 --- a/src/Analysis/Abstract/Evaluating.hs +++ b/src/Analysis/Abstract/Evaluating.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE DataKinds, GeneralizedNewtypeDeriving, MultiParamTypeClasses, ScopedTypeVariables, StandaloneDeriving, TypeApplications, TypeFamilies, TypeOperators, UndecidableInstances, GADTs #-} +{-# LANGUAGE DataKinds, GeneralizedNewtypeDeriving, MultiParamTypeClasses, ScopedTypeVariables, StandaloneDeriving, TypeApplications, TypeFamilies, TypeOperators, UndecidableInstances #-} module Analysis.Abstract.Evaluating ( type Evaluating , evaluate From 1f97a184513ce30cefc2c8dcd25a8fffc2ca8435 Mon Sep 17 00:00:00 2001 From: joshvera Date: Thu, 22 Mar 2018 11:43:14 -0400 Subject: [PATCH 23/48] Move resumeException to Control.Effect --- src/Analysis/Abstract/Evaluating.hs | 3 --- src/Control/Effect.hs | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Analysis/Abstract/Evaluating.hs b/src/Analysis/Abstract/Evaluating.hs index 2b0e1026b..0c3722cff 100644 --- a/src/Analysis/Abstract/Evaluating.hs +++ b/src/Analysis/Abstract/Evaluating.hs @@ -88,9 +88,6 @@ type EvaluatingEffects term value ] -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))) - instance Members '[Resumable Prelude.String value] effects => MonadThrow Prelude.String value (Evaluating term value effects) where throwException = raise . throwError diff --git a/src/Control/Effect.hs b/src/Control/Effect.hs index daf143539..92629b39a 100644 --- a/src/Control/Effect.hs +++ b/src/Control/Effect.hs @@ -68,6 +68,9 @@ instance RunEffect (Resumable exc v) a where type Result (Resumable exc v) a = Either exc a 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. -- From 7d87571c7a30d55b6fd56c5311e00b7b25627033 Mon Sep 17 00:00:00 2001 From: joshvera Date: Thu, 22 Mar 2018 12:05:28 -0400 Subject: [PATCH 24/48] Add ScopedTypeVariables --- src/Control/Effect.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Control/Effect.hs b/src/Control/Effect.hs index 92629b39a..fa4577e58 100644 --- a/src/Control/Effect.hs +++ b/src/Control/Effect.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE DataKinds, MultiParamTypeClasses, TypeFamilies, TypeOperators, UndecidableInstances #-} +{-# LANGUAGE DataKinds, MultiParamTypeClasses, TypeFamilies, TypeOperators, UndecidableInstances, ScopedTypeVariables #-} module Control.Effect where import Control.Monad.Effect as Effect From b7657bdbaea74c727964ef3ac179832990beec4d Mon Sep 17 00:00:00 2001 From: Timothy Clem Date: Thu, 22 Mar 2018 09:17:32 -0700 Subject: [PATCH 25/48] Remove tracing Co-Authored-By: Josh Vera --- src/Language/PHP/Syntax.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Language/PHP/Syntax.hs b/src/Language/PHP/Syntax.hs index ef241b3de..c6ef6bce4 100644 --- a/src/Language/PHP/Syntax.hs +++ b/src/Language/PHP/Syntax.hs @@ -382,7 +382,7 @@ instance Evaluatable Namespace where v <- klass name namespaceEnv pure (v, res) - addr <- trace (show name) (lookupOrAlloc name) + addr <- lookupOrAlloc name assign addr v modifyEnv (insert name addr) pure res From f2169e09a9f4aa461007f5831dac43d4ed9910ea Mon Sep 17 00:00:00 2001 From: joshvera Date: Thu, 22 Mar 2018 12:23:11 -0400 Subject: [PATCH 26/48] Move MultiParamTypeClasses, StandaloneDeriving, and DataKinds to default-extensions --- .stylish-haskell.yaml | 2 ++ semantic.cabal | 15 +++++++++++++-- src/Analysis/Abstract/Caching.hs | 2 +- src/Analysis/Abstract/Collecting.hs | 2 +- src/Analysis/Abstract/Dead.hs | 2 +- src/Analysis/Abstract/Tracing.hs | 2 +- src/Analysis/ConstructorName.hs | 2 +- src/Analysis/Declaration.hs | 2 +- src/Analysis/IdentifierName.hs | 2 +- src/Analysis/ModuleDef.hs | 2 +- src/Control/Abstract/Analysis.hs | 2 +- src/Control/Effect.hs | 2 +- src/Data/Term.hs | 2 +- src/Rendering/Imports.hs | 2 +- src/Rendering/Symbol.hs | 2 +- test/Doctests.hs | 5 ++++- 16 files changed, 32 insertions(+), 16 deletions(-) diff --git a/.stylish-haskell.yaml b/.stylish-haskell.yaml index c924bf512..a18a1954b 100644 --- a/.stylish-haskell.yaml +++ b/.stylish-haskell.yaml @@ -225,6 +225,8 @@ language_extensions: - FlexibleContexts - FlexibleInstances - MultiParamTypeClasses + - StandaloneDeriving + - DataKinds - OverloadedStrings - RecordWildCards - StrictData diff --git a/semantic.cabal b/semantic.cabal index 132722e06..af78cdc58 100644 --- a/semantic.cabal +++ b/semantic.cabal @@ -181,14 +181,17 @@ library , tree-sitter-ruby , tree-sitter-typescript default-language: Haskell2010 - default-extensions: DeriveFoldable + default-extensions: DataKinds + , DeriveFoldable , DeriveFunctor , DeriveGeneric , DeriveTraversable , FlexibleContexts , FlexibleInstances + , MultiParamTypeClasses , OverloadedStrings , RecordWildCards + , StandaloneDeriving , StrictData ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints -fno-warn-name-shadowing -O -j ghc-prof-options: -fprof-auto @@ -256,7 +259,15 @@ test-suite test , these ghc-options: -threaded -rtsopts -with-rtsopts=-N -j default-language: Haskell2010 - default-extensions: DeriveFunctor, DeriveGeneric, FlexibleContexts, FlexibleInstances, OverloadedStrings, RecordWildCards + default-extensions: DataKinds + , DeriveFunctor + , DeriveGeneric + , FlexibleContexts + , FlexibleInstances + , MultiParamTypeClasses + , OverloadedStrings + , RecordWildCards + , StandaloneDeriving test-suite doctests type: exitcode-stdio-1.0 diff --git a/src/Analysis/Abstract/Caching.hs b/src/Analysis/Abstract/Caching.hs index e1e2d47a2..4b0e0920a 100644 --- a/src/Analysis/Abstract/Caching.hs +++ b/src/Analysis/Abstract/Caching.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE DataKinds, GeneralizedNewtypeDeriving, MultiParamTypeClasses, ScopedTypeVariables, StandaloneDeriving, TypeFamilies, TypeOperators, UndecidableInstances #-} +{-# LANGUAGE GeneralizedNewtypeDeriving, ScopedTypeVariables, TypeFamilies, TypeOperators, UndecidableInstances #-} module Analysis.Abstract.Caching ( type Caching ) where diff --git a/src/Analysis/Abstract/Collecting.hs b/src/Analysis/Abstract/Collecting.hs index 54a975688..82bf9051f 100644 --- a/src/Analysis/Abstract/Collecting.hs +++ b/src/Analysis/Abstract/Collecting.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE DataKinds, GeneralizedNewtypeDeriving, MultiParamTypeClasses, StandaloneDeriving, TypeFamilies, TypeOperators, UndecidableInstances #-} +{-# LANGUAGE GeneralizedNewtypeDeriving, TypeFamilies, TypeOperators, UndecidableInstances #-} module Analysis.Abstract.Collecting ( type Collecting ) where diff --git a/src/Analysis/Abstract/Dead.hs b/src/Analysis/Abstract/Dead.hs index cf004925d..b1d9be521 100644 --- a/src/Analysis/Abstract/Dead.hs +++ b/src/Analysis/Abstract/Dead.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE DataKinds, GeneralizedNewtypeDeriving, MultiParamTypeClasses, StandaloneDeriving, TypeFamilies, TypeOperators #-} +{-# LANGUAGE GeneralizedNewtypeDeriving, TypeFamilies, TypeOperators #-} module Analysis.Abstract.Dead ( type DeadCode ) where diff --git a/src/Analysis/Abstract/Tracing.hs b/src/Analysis/Abstract/Tracing.hs index d21f8b3c3..f00405cdb 100644 --- a/src/Analysis/Abstract/Tracing.hs +++ b/src/Analysis/Abstract/Tracing.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE DataKinds, GeneralizedNewtypeDeriving, MultiParamTypeClasses, StandaloneDeriving, TypeFamilies, TypeOperators, UndecidableInstances #-} +{-# LANGUAGE GeneralizedNewtypeDeriving, TypeFamilies, TypeOperators, UndecidableInstances #-} module Analysis.Abstract.Tracing ( type Tracing ) where diff --git a/src/Analysis/ConstructorName.hs b/src/Analysis/ConstructorName.hs index 94e8dfd0b..6e49780a1 100644 --- a/src/Analysis/ConstructorName.hs +++ b/src/Analysis/ConstructorName.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE DataKinds, MultiParamTypeClasses, ScopedTypeVariables, TypeFamilies, TypeOperators, UndecidableInstances #-} +{-# LANGUAGE ScopedTypeVariables, TypeFamilies, TypeOperators, UndecidableInstances #-} module Analysis.ConstructorName ( ConstructorName(..) , ConstructorLabel(..) diff --git a/src/Analysis/Declaration.hs b/src/Analysis/Declaration.hs index c83a0d6a1..1ac1f98f8 100644 --- a/src/Analysis/Declaration.hs +++ b/src/Analysis/Declaration.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE DataKinds, MultiParamTypeClasses, TypeOperators, ScopedTypeVariables, TypeFamilies, UndecidableInstances #-} +{-# LANGUAGE TypeOperators, ScopedTypeVariables, TypeFamilies, UndecidableInstances #-} module Analysis.Declaration ( Declaration(..) , HasDeclaration diff --git a/src/Analysis/IdentifierName.hs b/src/Analysis/IdentifierName.hs index f9176316c..43c55e729 100644 --- a/src/Analysis/IdentifierName.hs +++ b/src/Analysis/IdentifierName.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE DataKinds, MultiParamTypeClasses, ScopedTypeVariables, TypeFamilies, TypeOperators, UndecidableInstances #-} +{-# LANGUAGE ScopedTypeVariables, TypeFamilies, TypeOperators, UndecidableInstances #-} module Analysis.IdentifierName ( IdentifierName(..) , IdentifierLabel(..) diff --git a/src/Analysis/ModuleDef.hs b/src/Analysis/ModuleDef.hs index 25de84043..925cb7cc4 100644 --- a/src/Analysis/ModuleDef.hs +++ b/src/Analysis/ModuleDef.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE DataKinds, MultiParamTypeClasses, ScopedTypeVariables, TypeFamilies, UndecidableInstances #-} +{-# LANGUAGE ScopedTypeVariables, TypeFamilies, UndecidableInstances #-} module Analysis.ModuleDef ( ModuleDef(..) , HasModuleDef diff --git a/src/Control/Abstract/Analysis.hs b/src/Control/Abstract/Analysis.hs index 8b215ee07..48fed0c23 100644 --- a/src/Control/Abstract/Analysis.hs +++ b/src/Control/Abstract/Analysis.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE DataKinds, MultiParamTypeClasses, TypeFamilies #-} +{-# LANGUAGE TypeFamilies #-} {-# OPTIONS_GHC -Wno-redundant-constraints #-} -- For runAnalysis module Control.Abstract.Analysis ( MonadAnalysis(..) diff --git a/src/Control/Effect.hs b/src/Control/Effect.hs index fa4577e58..570cafb16 100644 --- a/src/Control/Effect.hs +++ b/src/Control/Effect.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE DataKinds, MultiParamTypeClasses, TypeFamilies, TypeOperators, UndecidableInstances, ScopedTypeVariables #-} +{-# LANGUAGE TypeFamilies, TypeOperators, UndecidableInstances, ScopedTypeVariables #-} module Control.Effect where import Control.Monad.Effect as Effect diff --git a/src/Data/Term.hs b/src/Data/Term.hs index 38353b54d..953ac25a4 100644 --- a/src/Data/Term.hs +++ b/src/Data/Term.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE DataKinds, MultiParamTypeClasses, RankNTypes, TypeFamilies, TypeOperators #-} +{-# LANGUAGE RankNTypes, TypeFamilies, TypeOperators #-} module Data.Term ( Term(..) , termIn diff --git a/src/Rendering/Imports.hs b/src/Rendering/Imports.hs index 4e1e28e4b..c3a5fc563 100644 --- a/src/Rendering/Imports.hs +++ b/src/Rendering/Imports.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE DataKinds, MultiParamTypeClasses, RankNTypes, ScopedTypeVariables, TypeFamilies, TypeOperators, UndecidableInstances #-} +{-# LANGUAGE RankNTypes, ScopedTypeVariables, TypeFamilies, TypeOperators, UndecidableInstances #-} module Rendering.Imports ( renderToImports , ImportSummary(..) diff --git a/src/Rendering/Symbol.hs b/src/Rendering/Symbol.hs index 9fe11ad71..0bf87d1f8 100644 --- a/src/Rendering/Symbol.hs +++ b/src/Rendering/Symbol.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE DataKinds, MultiParamTypeClasses, RankNTypes, ScopedTypeVariables, TypeFamilies, TypeOperators, UndecidableInstances #-} +{-# LANGUAGE RankNTypes, ScopedTypeVariables, TypeFamilies, TypeOperators, UndecidableInstances #-} module Rendering.Symbol ( renderSymbolTerms , renderToSymbols diff --git a/test/Doctests.hs b/test/Doctests.hs index 1fa391e81..b5108f932 100644 --- a/test/Doctests.hs +++ b/test/Doctests.hs @@ -12,13 +12,16 @@ main = do extensions :: [String] extensions = - [ "DeriveFoldable" + [ "DataKinds" + , "DeriveFoldable" , "DeriveFunctor" , "DeriveGeneric" , "DeriveTraversable" , "FlexibleContexts" , "FlexibleInstances" + , "MultiParamTypeClasses" , "OverloadedStrings" , "RecordWildCards" + , "StandaloneDeriving" , "StrictData" ] From adc5a54d455613001d3a711d003fe922f79545fc Mon Sep 17 00:00:00 2001 From: joshvera Date: Thu, 22 Mar 2018 13:01:25 -0400 Subject: [PATCH 27/48] Beautify Prologue to test --- src/Prologue.hs | 46 +++++++++++++++------------------------------- 1 file changed, 15 insertions(+), 31 deletions(-) diff --git a/src/Prologue.hs b/src/Prologue.hs index aa991c474..d927a1a4a 100644 --- a/src/Prologue.hs +++ b/src/Prologue.hs @@ -10,64 +10,48 @@ module Prologue import Data.Bifunctor.Join as X import Data.Bits as X import Data.ByteString as X (ByteString) -import Data.Functor.Both as X (Both, runBothWith, both) +import Data.Functor.Both as X (Both, both, runBothWith) import Data.IntMap as X (IntMap) import Data.IntSet as X (IntSet) -import Data.Ix as X (Ix(..)) +import Data.Ix as X (Ix (..)) +import Data.List.NonEmpty as X (NonEmpty (..), nonEmpty, some1) import Data.Map as X (Map) -import Data.Monoid (Alt(..)) import Data.Maybe as X +import Data.Monoid (Alt (..)) import Data.Sequence as X (Seq) import Data.Set as X (Set) import Data.Text as X (Text) import Data.These as X import Data.Union as X -import Data.List.NonEmpty as X ( - NonEmpty(..) - , nonEmpty - , some1 - ) import Debug.Trace as X -import Control.Exception as X hiding ( - evaluate - , throw - , throwIO - , throwTo - , assert - , Handler(..) - ) +import Control.Exception as X hiding (Handler (..), assert, evaluate, throw, throwIO, throwTo) -- Typeclasses import Control.Applicative as X import Control.Arrow as X ((&&&), (***)) import Control.Monad as X hiding (fail, return, unless, when) -import Control.Monad.Except as X (MonadError(..)) -import Control.Monad.Fail as X (MonadFail(..)) +import Control.Monad.Except as X (MonadError (..)) +import Control.Monad.Fail as X (MonadFail (..)) import Data.Algebra as X import Data.Align.Generic as X (GAlign) import Data.Bifoldable as X -import Data.Bifunctor as X (Bifunctor(..)) +import Data.Bifunctor as X (Bifunctor (..)) import Data.Bitraversable as X -import Data.Foldable as X hiding (product , sum) -import Data.Functor as X (($>), void) +import Data.Foldable as X hiding (product, sum) import Data.Function as X (fix, on, (&)) +import Data.Functor as X (void, ($>)) import Data.Functor.Classes as X import Data.Functor.Classes.Generic as X -import Data.Functor.Foldable as X (Base, Recursive(..), Corecursive(..)) +import Data.Functor.Foldable as X (Base, Corecursive (..), Recursive (..)) +import Data.Hashable as X (Hashable, hash, hashUsing, hashWithSalt) import Data.Mergeable as X (Mergeable) -import Data.Monoid as X (Monoid(..), First(..), Last(..)) -import Data.Proxy as X (Proxy(..)) -import Data.Semigroup as X (Semigroup(..)) +import Data.Monoid as X (First (..), Last (..), Monoid (..)) +import Data.Proxy as X (Proxy (..)) +import Data.Semigroup as X (Semigroup (..)) import Data.Traversable as X import Data.Typeable as X (Typeable) -import Data.Hashable as X ( - Hashable - , hash - , hashWithSalt - , hashUsing - ) -- Generics import GHC.Generics as X hiding (moduleName) From d816fceaf373ef6b7634b39a554e0d1e6991b5d5 Mon Sep 17 00:00:00 2001 From: joshvera Date: Thu, 22 Mar 2018 13:02:10 -0400 Subject: [PATCH 28/48] Beautify IdentifierName to test --- src/Analysis/IdentifierName.hs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Analysis/IdentifierName.hs b/src/Analysis/IdentifierName.hs index 43c55e729..13374a9f2 100644 --- a/src/Analysis/IdentifierName.hs +++ b/src/Analysis/IdentifierName.hs @@ -5,13 +5,13 @@ module Analysis.IdentifierName , identifierLabel ) where -import Data.Abstract.FreeVariables -import Data.Aeson -import Data.JSON.Fields -import Data.Term -import Data.Text.Encoding (decodeUtf8) -import Prologue +import Data.Abstract.FreeVariables +import Data.Aeson +import Data.JSON.Fields import qualified Data.Syntax +import Data.Term +import Data.Text.Encoding (decodeUtf8) +import Prologue -- | Compute a 'IdentifierLabel' label for a 'Term'. identifierLabel :: IdentifierName syntax => TermF syntax a b -> Maybe IdentifierLabel From 37d7eb8b9f5d7690cfdb93e10093c0e60ff75311 Mon Sep 17 00:00:00 2001 From: joshvera Date: Thu, 22 Mar 2018 13:06:22 -0400 Subject: [PATCH 29/48] Remove unused lang extension --- test/Analysis/Go/Spec.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Analysis/Go/Spec.hs b/test/Analysis/Go/Spec.hs index 449c40473..6980b710e 100644 --- a/test/Analysis/Go/Spec.hs +++ b/test/Analysis/Go/Spec.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE OverloadedLists, TypeApplications #-} +{-# LANGUAGE OverloadedLists #-} module Analysis.Go.Spec (spec) where import Data.Abstract.Value From fdfca338f5c9c5c285fcf1b5c1e9703ff921405c Mon Sep 17 00:00:00 2001 From: joshvera Date: Thu, 22 Mar 2018 13:07:32 -0400 Subject: [PATCH 30/48] unused constraint --- test/Data/Functor/Listable.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Data/Functor/Listable.hs b/test/Data/Functor/Listable.hs index 944e6c4de..344d6e671 100644 --- a/test/Data/Functor/Listable.hs +++ b/test/Data/Functor/Listable.hs @@ -156,7 +156,7 @@ instance Listable1 f => Listable2 (FreeF f) where instance (Listable1 f, Listable a) => Listable1 (FreeF f a) where liftTiers = liftTiers2 tiers -instance (Functor f, Listable1 f) => Listable1 (Free.Free f) where +instance Listable1 f => Listable1 (Free.Free f) where liftTiers pureTiers = go where go = liftCons1 (liftTiers2 pureTiers go) free free (FreeF.Free f) = Free.Free f From bfee652f1465eaf8cd5035c7ba0d870619ec623e Mon Sep 17 00:00:00 2001 From: joshvera Date: Thu, 22 Mar 2018 13:07:42 -0400 Subject: [PATCH 31/48] redundant lang extension --- test/SpecHelpers.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/SpecHelpers.hs b/test/SpecHelpers.hs index d2f819c6a..e653b433c 100644 --- a/test/SpecHelpers.hs +++ b/test/SpecHelpers.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE DataKinds, GADTs, ScopedTypeVariables, TypeFamilies, TypeOperators, TypeApplications #-} +{-# LANGUAGE GADTs, ScopedTypeVariables, TypeFamilies, TypeOperators, TypeApplications #-} module SpecHelpers ( module X , diffFilePaths From f23139a19456618e3bea18cdea63b249a78afd7a Mon Sep 17 00:00:00 2001 From: Timothy Clem Date: Thu, 22 Mar 2018 13:37:35 -0700 Subject: [PATCH 32/48] Introduce a namespace value that mappends environments --- src/Control/Abstract/Value.hs | 16 ++++++++++++++++ src/Data/Abstract/Value.hs | 10 ++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/Control/Abstract/Value.hs b/src/Control/Abstract/Value.hs index 2bd15f435..b03ef2ffe 100644 --- a/src/Control/Abstract/Value.hs +++ b/src/Control/Abstract/Value.hs @@ -89,6 +89,9 @@ class (Monad m, Show value) => MonadValue value m where -- | Build a class value from a name and environment. klass :: Name -> EnvironmentFor value -> m value + -- | Build a namespace value from a name and environment stack + namespace :: Name -> EnvironmentFor value -> m value + -- | Extract the environment from a class. objectEnvironment :: value -> m (EnvironmentFor value) @@ -154,8 +157,21 @@ instance ( Monad m klass n = pure . injValue . Class n + namespace n env = do + maybeAddr <- lookupEnv n + + ns <- maybe (pure (Namespace n env)) (\addr -> do + v <- prjValue <$> deref addr + case v of + Just (Namespace n env') -> pure (Namespace n (env' <> env)) + Nothing -> fail ("tried to extend, but " <> show v <> " is not a namespace") + ) maybeAddr + pure (injValue ns) + + -- TODO: Rename to scopedEnvironment objectEnvironment o | Just (Class _ env) <- prjValue o = pure env + | Just (Namespace _ env) <- prjValue o = pure env | otherwise = fail ("non-object type passed to objectEnvironment: " <> show o) asString v diff --git a/src/Data/Abstract/Value.hs b/src/Data/Abstract/Value.hs index 14751967d..430fb3f42 100644 --- a/src/Data/Abstract/Value.hs +++ b/src/Data/Abstract/Value.hs @@ -22,6 +22,7 @@ type ValueConstructors , Closure , Float , Integer + , Namespace , String , Rational , Symbol @@ -145,6 +146,15 @@ instance Eq1 Class where liftEq = genericLiftEq instance Ord1 Class where liftCompare = genericLiftCompare instance Show1 Class where liftShowsPrec = genericLiftShowsPrec +data Namespace value = Namespace + { namespaceName :: Name + , namespaceScope :: Environment Precise value + } deriving (Eq, Generic1, Ord, Show) + +instance Eq1 Namespace where liftEq = genericLiftEq +instance Ord1 Namespace where liftCompare = genericLiftCompare +instance Show1 Namespace where liftShowsPrec = genericLiftShowsPrec + -- | The environment for an abstract value type. type EnvironmentFor v = Environment (LocationFor v) v From 201aa936d6b89b3cf69dee961f8cf55c53e55074 Mon Sep 17 00:00:00 2001 From: Timothy Clem Date: Thu, 22 Mar 2018 13:38:41 -0700 Subject: [PATCH 33/48] PHP namespaces evaluation with extending environments --- src/Language/PHP/Syntax.hs | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/Language/PHP/Syntax.hs b/src/Language/PHP/Syntax.hs index 842d5bbdd..aa3e92eff 100644 --- a/src/Language/PHP/Syntax.hs +++ b/src/Language/PHP/Syntax.hs @@ -353,7 +353,7 @@ instance Ord1 NamespaceUseGroupClause where liftCompare = genericLiftCompare instance Show1 NamespaceUseGroupClause where liftShowsPrec = genericLiftShowsPrec instance Evaluatable NamespaceUseGroupClause -data Namespace a = Namespace { namespaceName :: a, namespaceBody :: a} +data Namespace a = Namespace { namespaceName :: a, namespaceBody :: a } deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable) instance Eq1 Namespace where liftEq = genericLiftEq @@ -365,27 +365,29 @@ instance Evaluatable Namespace where where names = toList (freeVariables (subterm namespaceName)) - go [] = fail "gotta fix this" + go [] = fail "expected at least one free variable in namespaceName, found none" go [name] = do - v <- localEnv id $ do + (v, addr) <- letrec' name $ do void $ subtermValue namespaceBody namespaceEnv <- Env.head <$> getEnv - klass name namespaceEnv - - addr <- lookupOrAlloc name - assign addr v - v <$ modifyEnv (Env.insert name addr) + namespace name namespaceEnv + v <$ modifyEnv (insert name addr) go (name:xs) = do - (v, res) <- localEnv id $ do - res <- go xs - namespaceEnv <- Env.head <$> getEnv - v <- klass name namespaceEnv - pure (v, res) + (rest, addr) <- localEnv id $ do + rest <- go xs + namespaceEnv <- Env.head <$> getEnv + addr <- lookupOrAlloc name + v <- namespace name namespaceEnv + assign addr v + pure (rest, addr) + + rest <$ modifyEnv (insert name addr) + letrec' name body = do addr <- lookupOrAlloc name + v <- localEnv id body assign addr v - modifyEnv (insert name addr) - pure res + pure (v, addr) data TraitDeclaration a = TraitDeclaration { traitName :: a, traitStatements :: [a] } deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable) From 901cd319a2e19274246258eeb8542fa22c0aa20b Mon Sep 17 00:00:00 2001 From: joshvera Date: Thu, 22 Mar 2018 16:39:53 -0400 Subject: [PATCH 34/48] fix ruby test --- test/Analysis/Ruby/Spec.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Analysis/Ruby/Spec.hs b/test/Analysis/Ruby/Spec.hs index 52eab9fd2..bf74410a5 100644 --- a/test/Analysis/Ruby/Spec.hs +++ b/test/Analysis/Ruby/Spec.hs @@ -28,7 +28,7 @@ spec = parallel $ do it "subclass" $ do res <- evaluate' "subclass.rb" - fst res `shouldBe` Right (injValue (String "\"\"")) + fst res `shouldBe` Right (Right $ injValue (String "\"\"")) where addr = Address . Precise From fb658447a4172b4aa83af55501d38b187219f3a0 Mon Sep 17 00:00:00 2001 From: Timothy Clem Date: Thu, 22 Mar 2018 14:27:21 -0700 Subject: [PATCH 35/48] Refactor this a bit --- src/Control/Abstract/Value.hs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Control/Abstract/Value.hs b/src/Control/Abstract/Value.hs index b03ef2ffe..972b5b098 100644 --- a/src/Control/Abstract/Value.hs +++ b/src/Control/Abstract/Value.hs @@ -159,14 +159,11 @@ instance ( Monad m namespace n env = do maybeAddr <- lookupEnv n - - ns <- maybe (pure (Namespace n env)) (\addr -> do - v <- prjValue <$> deref addr - case v of - Just (Namespace n env') -> pure (Namespace n (env' <> env)) - Nothing -> fail ("tried to extend, but " <> show v <> " is not a namespace") - ) maybeAddr - pure (injValue ns) + env' <- maybe (pure mempty) (asNamespaceEnv <=< deref) maybeAddr + pure (injValue (Namespace n (env' <> env))) + where asNamespaceEnv v + | Just (Namespace _ env') <- prjValue v = pure env' + | otherwise = fail ("expected " <> show v <> " to be a namespace") -- TODO: Rename to scopedEnvironment objectEnvironment o From 016aec9e10cedee385b4c78cb7bff7c45fc4d191 Mon Sep 17 00:00:00 2001 From: Timothy Clem Date: Thu, 22 Mar 2018 14:27:33 -0700 Subject: [PATCH 36/48] implement namespace for types --- src/Control/Abstract/Value.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Control/Abstract/Value.hs b/src/Control/Abstract/Value.hs index 972b5b098..b035edd26 100644 --- a/src/Control/Abstract/Value.hs +++ b/src/Control/Abstract/Value.hs @@ -274,7 +274,7 @@ instance (Alternative m, MonadEnvironment Type m, MonadFail m, MonadFresh m, Mon multiple = pure . Type.Product array = pure . Type.Array klass _ _ = pure Object - + namespace _ _ = pure Type.Unit objectEnvironment _ = pure mempty asString _ = fail "Must evaluate to Value to use asString" From 80e8b86cb10cc23e30e3b36f79b1e9cbe9798e34 Mon Sep 17 00:00:00 2001 From: Timothy Clem Date: Thu, 22 Mar 2018 16:26:21 -0700 Subject: [PATCH 37/48] Making things pretty one baby step at a time --- src/Language/PHP/Syntax.hs | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/src/Language/PHP/Syntax.hs b/src/Language/PHP/Syntax.hs index aa3e92eff..68d2a24d3 100644 --- a/src/Language/PHP/Syntax.hs +++ b/src/Language/PHP/Syntax.hs @@ -366,28 +366,19 @@ instance Evaluatable Namespace where names = toList (freeVariables (subterm namespaceName)) go [] = fail "expected at least one free variable in namespaceName, found none" - go [name] = do - (v, addr) <- letrec' name $ do - void $ subtermValue namespaceBody - namespaceEnv <- Env.head <$> getEnv - namespace name namespaceEnv - v <$ modifyEnv (insert name addr) - go (name:xs) = do - (rest, addr) <- localEnv id $ do - rest <- go xs - - namespaceEnv <- Env.head <$> getEnv - addr <- lookupOrAlloc name - v <- namespace name namespaceEnv - assign addr v - pure (rest, addr) - - rest <$ modifyEnv (insert name addr) + go [name] = letrec' name $ \addr -> + makeNamespace name addr <* subtermValue namespaceBody + go (name:xs) = letrec' name $ \addr -> + go xs <* makeNamespace name addr + makeNamespace name addr = do + namespaceEnv <- Env.head <$> getEnv + v <- namespace name namespaceEnv + assign addr v + pure v letrec' name body = do addr <- lookupOrAlloc name - v <- localEnv id body - assign addr v - pure (v, addr) + v <- localEnv id (body addr) + v <$ modifyEnv (insert name addr) data TraitDeclaration a = TraitDeclaration { traitName :: a, traitStatements :: [a] } deriving (Diffable, Eq, Foldable, Functor, FreeVariables1, GAlign, Generic1, Mergeable, Ord, Show, Traversable) From 2e794e92a5367985a27de97ce9d93c52c6f476b2 Mon Sep 17 00:00:00 2001 From: joshvera Date: Thu, 22 Mar 2018 19:31:08 -0400 Subject: [PATCH 38/48] align --- src/Analysis/Abstract/Caching.hs | 2 +- src/Analysis/Abstract/Evaluating.hs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Analysis/Abstract/Caching.hs b/src/Analysis/Abstract/Caching.hs index e1e2d47a2..ae84dcad3 100644 --- a/src/Analysis/Abstract/Caching.hs +++ b/src/Analysis/Abstract/Caching.hs @@ -13,7 +13,7 @@ import Prologue -- | The effects necessary for caching analyses. type CachingEffects term value effects = Fresh -- For 'MonadFresh'. - ': NonDet -- For 'Alternative' and 'MonadNonDet'. + ': NonDet -- For 'Alternative' and 'MonadNonDet'. ': Reader (CacheFor term value) -- The in-cache used as an oracle while converging on a result. ': State (CacheFor term value) -- The out-cache used to record results in each iteration of convergence. ': effects diff --git a/src/Analysis/Abstract/Evaluating.hs b/src/Analysis/Abstract/Evaluating.hs index bf0249f6b..d26ee6f25 100644 --- a/src/Analysis/Abstract/Evaluating.hs +++ b/src/Analysis/Abstract/Evaluating.hs @@ -116,8 +116,8 @@ newtype Evaluating term value effects a = Evaluating (Eff effects a) deriving instance Member Fail effects => MonadFail (Evaluating term value effects) deriving instance Member Fresh effects => MonadFresh (Evaluating term value effects) -deriving instance Member NonDet effects => Alternative (Evaluating term value effects) -deriving instance Member NonDet effects => MonadNonDet (Evaluating term value effects) +deriving instance Member NonDet effects => Alternative (Evaluating term value effects) +deriving instance Member NonDet effects => MonadNonDet (Evaluating term value effects) -- | Effects necessary for evaluating (whether concrete or abstract). type EvaluatingEffects term value From 235818735759b033a87e2b48783905c7e778068e Mon Sep 17 00:00:00 2001 From: joshvera Date: Thu, 22 Mar 2018 19:31:47 -0400 Subject: [PATCH 39/48] align --- src/Analysis/Abstract/Evaluating.hs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Analysis/Abstract/Evaluating.hs b/src/Analysis/Abstract/Evaluating.hs index d26ee6f25..216a59bfd 100644 --- a/src/Analysis/Abstract/Evaluating.hs +++ b/src/Analysis/Abstract/Evaluating.hs @@ -121,8 +121,7 @@ deriving instance Member NonDet effects => MonadNonDet (Evaluating term value -- | Effects necessary for evaluating (whether concrete or abstract). type EvaluatingEffects term value - = '[ - Resumable Prelude.String value + = '[ Resumable Prelude.String value , Fail -- Failure with an error message , State (EnvironmentFor value) -- Environments (both local and global) , State (HeapFor value) -- The heap From 54c11bf6295c0c71acd999bc077b09c0b6e2ef33 Mon Sep 17 00:00:00 2001 From: joshvera Date: Thu, 22 Mar 2018 19:31:51 -0400 Subject: [PATCH 40/48] join fst --- test/Analysis/Ruby/Spec.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Analysis/Ruby/Spec.hs b/test/Analysis/Ruby/Spec.hs index bf74410a5..e20e0b8a8 100644 --- a/test/Analysis/Ruby/Spec.hs +++ b/test/Analysis/Ruby/Spec.hs @@ -28,7 +28,7 @@ spec = parallel $ do it "subclass" $ do res <- evaluate' "subclass.rb" - fst res `shouldBe` Right (Right $ injValue (String "\"\"")) + join (fst res) `shouldBe` Right (injValue (String "\"\"") where addr = Address . Precise From 52c50c89560652fb83f95161ba307eed200d1dc1 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 23 Mar 2018 10:16:34 -0400 Subject: [PATCH 41/48] :fire: ghc-mod. --- .gitmodules | 3 --- vendor/ghc-mod | 1 - 2 files changed, 4 deletions(-) delete mode 160000 vendor/ghc-mod diff --git a/.gitmodules b/.gitmodules index 4d87b13d8..a51ba2fb2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,6 +25,3 @@ [submodule "vendor/freer-cofreer"] path = vendor/freer-cofreer url = https://github.com/robrix/freer-cofreer.git -[submodule "vendor/ghc-mod"] - path = vendor/ghc-mod - url = https://github.com/joshvera/ghc-mod diff --git a/vendor/ghc-mod b/vendor/ghc-mod deleted file mode 160000 index 7fb380dae..000000000 --- a/vendor/ghc-mod +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7fb380dae0ae877a24ac8258fcd193cd6256a171 From 1c84f73e482ccb45d1ea8b1362fc7e07608b9413 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 23 Mar 2018 10:16:56 -0400 Subject: [PATCH 42/48] :fire: a couple of redundant .gitmodules entries. --- .gitmodules | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.gitmodules b/.gitmodules index a51ba2fb2..0df34351a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,12 +13,6 @@ [submodule "vendor/effects"] path = vendor/effects url = https://github.com/joshvera/effects.git -[submodule "languages/c/vendor/tree-sitter-c"] - path = languages/c/vendor/tree-sitter-c - url = https://github.com/tree-sitter/tree-sitter-c.git -[submodule "languages/javascript/vendor/tree-sitter-javascript"] - path = languages/javascript/vendor/tree-sitter-javascript - url = https://github.com/tree-sitter/tree-sitter-javascript.git [submodule "vendor/haskell-tree-sitter"] path = vendor/haskell-tree-sitter url = https://github.com/tree-sitter/haskell-tree-sitter.git From 5905c8505290e093b333baf268ac92fd5d45bd8c Mon Sep 17 00:00:00 2001 From: joshvera Date: Fri, 23 Mar 2018 10:29:01 -0400 Subject: [PATCH 43/48] Add join to tests --- test/Analysis/Python/Spec.hs | 4 ++-- test/Analysis/Ruby/Spec.hs | 2 +- test/SpecHelpers.hs | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/test/Analysis/Python/Spec.hs b/test/Analysis/Python/Spec.hs index 64a76a9d5..ab0c92f6c 100644 --- a/test/Analysis/Python/Spec.hs +++ b/test/Analysis/Python/Spec.hs @@ -36,11 +36,11 @@ spec = parallel $ do it "subclasses" $ do res <- evaluate' "subclass.py" - fst res `shouldBe` Right (injValue (String "\"bar\"")) + join (fst res) `shouldBe` Right (injValue (String "\"bar\"")) it "handles multiple inheritance left-to-right" $ do res <- evaluate' "multiple_inheritance.py" - fst res `shouldBe` Right (injValue (String "\"foo!\"")) + join (fst res) `shouldBe` Right (injValue (String "\"foo!\"")) where addr = Address . Precise diff --git a/test/Analysis/Ruby/Spec.hs b/test/Analysis/Ruby/Spec.hs index e20e0b8a8..8bdee6c28 100644 --- a/test/Analysis/Ruby/Spec.hs +++ b/test/Analysis/Ruby/Spec.hs @@ -28,7 +28,7 @@ spec = parallel $ do it "subclass" $ do res <- evaluate' "subclass.rb" - join (fst res) `shouldBe` Right (injValue (String "\"\"") + join (fst res) `shouldBe` Right (injValue (String "\"\"")) where addr = Address . Precise diff --git a/test/SpecHelpers.hs b/test/SpecHelpers.hs index d2f819c6a..350a3b9ca 100644 --- a/test/SpecHelpers.hs +++ b/test/SpecHelpers.hs @@ -34,6 +34,7 @@ import Data.Functor.Both as X (Both, runBothWith, both) import Data.Maybe as X import Data.Monoid as X (Monoid(..), First(..), Last(..)) import Data.Semigroup as X (Semigroup(..)) +import Control.Monad as X import Test.Hspec as X (Spec, SpecWith, context, describe, it, xit, parallel, pendingWith, around, runIO) import Test.Hspec.Expectations.Pretty as X From 8c90975a48a096da1e40d84ef1a87aafd677737c Mon Sep 17 00:00:00 2001 From: Timothy Clem Date: Fri, 23 Mar 2018 08:57:02 -0700 Subject: [PATCH 44/48] Write a test, fix a bug --- src/Language/PHP/Syntax.hs | 4 +-- test/Analysis/PHP/Spec.hs | 32 ++++++++++++++++------- test/fixtures/php/analysis/namespaces.php | 28 ++++++++++++++++++++ 3 files changed, 52 insertions(+), 12 deletions(-) create mode 100644 test/fixtures/php/analysis/namespaces.php diff --git a/src/Language/PHP/Syntax.hs b/src/Language/PHP/Syntax.hs index 68d2a24d3..ab6b7b125 100644 --- a/src/Language/PHP/Syntax.hs +++ b/src/Language/PHP/Syntax.hs @@ -366,8 +366,8 @@ instance Evaluatable Namespace where names = toList (freeVariables (subterm namespaceName)) go [] = fail "expected at least one free variable in namespaceName, found none" - go [name] = letrec' name $ \addr -> - makeNamespace name addr <* subtermValue namespaceBody + go [name] = letrec' name $ \addr -> do + subtermValue namespaceBody *> makeNamespace name addr go (name:xs) = letrec' name $ \addr -> go xs <* makeNamespace name addr makeNamespace name addr = do diff --git a/test/Analysis/PHP/Spec.hs b/test/Analysis/PHP/Spec.hs index 1094af671..340a06969 100644 --- a/test/Analysis/PHP/Spec.hs +++ b/test/Analysis/PHP/Spec.hs @@ -3,29 +3,41 @@ module Analysis.PHP.Spec (spec) where import Data.Abstract.Value import Data.Map +import Data.Map.Monoidal as Map import SpecHelpers spec :: Spec spec = parallel $ do - describe "evalutes PHP" $ do - it "include and require" $ do + describe "PHP" $ do + it "evaluates include and require" $ do env <- evaluate "main.php" - let expectedEnv = [ (qualifiedName ["foo"], addr 0) - , (qualifiedName ["bar"], addr 1) ] - env `shouldBe` expectedEnv + env `shouldBe` [ (name "foo", addr 0) + , (name "bar", addr 1) ] - it "include_once and require_once" $ do + it "evaluates include_once and require_once" $ do env <- evaluate "main_once.php" - let expectedEnv = [ (qualifiedName ["foo"], addr 0) - , (qualifiedName ["bar"], addr 1) ] - env `shouldBe` expectedEnv + env `shouldBe` [ (name "foo", addr 0) + , (name "bar", addr 1) ] + + it "evaluates namespaces" $ do + ((_, env), Heap heap) <- evaluate' "namespaces.php" + env `shouldBe` [ (name "NS1", addr 0) + , (name "Foo", addr 6) ] + Map.lookup (Precise 0) heap `shouldBe` ns "NS1" [ (name "Sub1", addr 1) + , (name "b", addr 4) + , (name "c", addr 5) + ] + Map.lookup (Precise 1) heap `shouldBe` ns "Sub1" [ (name "Sub2", addr 2) ] + Map.lookup (Precise 2) heap `shouldBe` ns "Sub2" [ (name "f", addr 3) ] where + ns n = Just . Latest . Just . injValue . Namespace (name n) addr = Address . Precise fixtures = "test/fixtures/php/analysis/" - evaluate entry = snd . fst . fst . fst . fst <$> + evaluate entry = snd . fst <$> evaluate' entry + evaluate' entry = fst . fst . fst <$> evaluateFiles phpParser [ fixtures <> entry , fixtures <> "foo.php" diff --git a/test/fixtures/php/analysis/namespaces.php b/test/fixtures/php/analysis/namespaces.php new file mode 100644 index 000000000..6dac97447 --- /dev/null +++ b/test/fixtures/php/analysis/namespaces.php @@ -0,0 +1,28 @@ + Date: Fri, 23 Mar 2018 09:04:11 -0700 Subject: [PATCH 45/48] Little formatting/cleanup for clarity --- src/Language/PHP/Syntax.hs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Language/PHP/Syntax.hs b/src/Language/PHP/Syntax.hs index ab6b7b125..c7acee877 100644 --- a/src/Language/PHP/Syntax.hs +++ b/src/Language/PHP/Syntax.hs @@ -364,17 +364,16 @@ instance Evaluatable Namespace where eval Namespace{..} = go names where names = toList (freeVariables (subterm namespaceName)) - go [] = fail "expected at least one free variable in namespaceName, found none" - go [name] = letrec' name $ \addr -> do + go [name] = letrec' name $ \addr -> subtermValue namespaceBody *> makeNamespace name addr go (name:xs) = letrec' name $ \addr -> go xs <* makeNamespace name addr + makeNamespace name addr = do namespaceEnv <- Env.head <$> getEnv v <- namespace name namespaceEnv - assign addr v - pure v + v <$ assign addr v letrec' name body = do addr <- lookupOrAlloc name v <- localEnv id (body addr) From c1bee38e747b48761434a1aa8cfa375004706866 Mon Sep 17 00:00:00 2001 From: Timothy Clem Date: Fri, 23 Mar 2018 09:04:20 -0700 Subject: [PATCH 46/48] Document construction of namespace value --- src/Control/Abstract/Value.hs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Control/Abstract/Value.hs b/src/Control/Abstract/Value.hs index ad58ca434..478d929a4 100644 --- a/src/Control/Abstract/Value.hs +++ b/src/Control/Abstract/Value.hs @@ -93,7 +93,11 @@ class (Monad m, Show value) => MonadValue value m where -> m value -- | Build a namespace value from a name and environment stack - namespace :: Name -> EnvironmentFor value -> m value + -- + -- Namespaces model monoidal environments. + namespace :: Name -- ^ The namespace's identifier + -> EnvironmentFor value -- ^ The environment to mappend + -> m value -- | Extract the environment from a class. objectEnvironment :: value -> m (EnvironmentFor value) From 19592c72c21a6f82f69f573bbc240646404db1b8 Mon Sep 17 00:00:00 2001 From: Timothy Clem Date: Fri, 23 Mar 2018 09:07:28 -0700 Subject: [PATCH 47/48] s/objectEnvironment/scopedEnvironment --- src/Control/Abstract/Value.hs | 15 +++++++-------- src/Data/Syntax/Expression.hs | 2 +- src/Language/PHP/Syntax.hs | 4 ++-- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/Control/Abstract/Value.hs b/src/Control/Abstract/Value.hs index 478d929a4..4bb799025 100644 --- a/src/Control/Abstract/Value.hs +++ b/src/Control/Abstract/Value.hs @@ -94,13 +94,13 @@ class (Monad m, Show value) => MonadValue value m where -- | Build a namespace value from a name and environment stack -- - -- Namespaces model monoidal environments. + -- Namespaces model closures with monoidal environments. namespace :: Name -- ^ The namespace's identifier -> EnvironmentFor value -- ^ The environment to mappend -> m value - -- | Extract the environment from a class. - objectEnvironment :: value -> m (EnvironmentFor value) + -- | Extract the environment from any scoped object (e.g. classes, namespaces, etc). + scopedEnvironment :: value -> m (EnvironmentFor value) -- | Evaluate an abstraction (a binder like a lambda or method definition). abstract :: (FreeVariables term, MonadControl term m) => [Name] -> Subterm term (m value) -> m value @@ -164,7 +164,7 @@ instance ( Monad m klass n [] env = pure . injValue $ Class n env klass n supers env = do - product <- mconcat <$> traverse objectEnvironment supers + product <- mconcat <$> traverse scopedEnvironment supers pure . injValue $ Class n (Env.push product <> env) @@ -176,11 +176,10 @@ instance ( Monad m | Just (Namespace _ env') <- prjValue v = pure env' | otherwise = fail ("expected " <> show v <> " to be a namespace") - -- TODO: Rename to scopedEnvironment - objectEnvironment o + scopedEnvironment o | Just (Class _ env) <- prjValue o = pure env | Just (Namespace _ env) <- prjValue o = pure env - | otherwise = fail ("non-object type passed to objectEnvironment: " <> show o) + | otherwise = fail ("non-object type passed to scopedEnvironment: " <> show o) asString v | Just (Value.String n) <- prjValue v = pure n @@ -288,7 +287,7 @@ instance (Alternative m, MonadEnvironment Type m, MonadFail m, MonadFresh m, Mon klass _ _ _ = pure Object namespace _ _ = pure Type.Unit - objectEnvironment _ = pure mempty + scopedEnvironment _ = pure mempty asString _ = fail "Must evaluate to Value to use asString" diff --git a/src/Data/Syntax/Expression.hs b/src/Data/Syntax/Expression.hs index c29e1421a..e597889a2 100644 --- a/src/Data/Syntax/Expression.hs +++ b/src/Data/Syntax/Expression.hs @@ -193,7 +193,7 @@ instance Show1 MemberAccess where liftShowsPrec = genericLiftShowsPrec instance Evaluatable MemberAccess where eval (fmap subtermValue -> MemberAccess mem acc) = do - lhs <- mem >>= objectEnvironment + lhs <- mem >>= scopedEnvironment localEnv (mappend lhs) acc -- | Subscript (e.g a[1]) diff --git a/src/Language/PHP/Syntax.hs b/src/Language/PHP/Syntax.hs index c7acee877..5c9ef4908 100644 --- a/src/Language/PHP/Syntax.hs +++ b/src/Language/PHP/Syntax.hs @@ -188,7 +188,7 @@ instance Show1 QualifiedName where liftShowsPrec = genericLiftShowsPrec instance Evaluatable QualifiedName where eval (fmap subtermValue -> QualifiedName name iden) = do - lhs <- name >>= objectEnvironment + lhs <- name >>= scopedEnvironment localEnv (mappend lhs) iden @@ -205,7 +205,7 @@ instance Evaluatable NamespaceName where go [] = fail "nonempty NamespaceName not allowed" go [x] = subtermValue x go (x:xs) = do - env <- subtermValue x >>= objectEnvironment + env <- subtermValue x >>= scopedEnvironment localEnv (mappend env) (go xs) newtype ConstDeclaration a = ConstDeclaration [a] From b5f4c1e94ffbe0a984e6c74a6989e8a6367986e1 Mon Sep 17 00:00:00 2001 From: Timothy Clem Date: Fri, 23 Mar 2018 09:09:25 -0700 Subject: [PATCH 48/48] Slightly more helpful failure message --- src/Control/Abstract/Value.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Control/Abstract/Value.hs b/src/Control/Abstract/Value.hs index 4bb799025..26b753b9c 100644 --- a/src/Control/Abstract/Value.hs +++ b/src/Control/Abstract/Value.hs @@ -179,7 +179,7 @@ instance ( Monad m scopedEnvironment o | Just (Class _ env) <- prjValue o = pure env | Just (Namespace _ env) <- prjValue o = pure env - | otherwise = fail ("non-object type passed to scopedEnvironment: " <> show o) + | otherwise = fail ("object type passed to scopedEnvironment doesn't have an environment: " <> show o) asString v | Just (Value.String n) <- prjValue v = pure n