From 327a3387d953be9b069b4de92894e21ac983658e Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 15 Jun 2018 14:04:44 -0400 Subject: [PATCH 001/169] Stub in a datatype representing a load order. --- src/Data/Abstract/Evaluatable.hs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index d32f93e93..a3d9e7fa9 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -61,6 +61,10 @@ class Show1 constr => Evaluatable constr where eval expr = rvalBox =<< throwResumable (Unspecialized ("Eval unspecialized for " ++ liftShowsPrec (const (const id)) (const id) 0 expr "")) +data LoadOrder a b + = Done (NonEmpty b) + | Load (NonEmpty a) (NonEmpty b -> LoadOrder a b) + -- | Evaluate a given package. evaluatePackageWith :: forall address term value inner inner' inner'' outer . ( AbstractValue address value inner From 0d3bec92ad06b10888e96c53a1e8f655dbdd9829 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 15 Jun 2018 14:05:36 -0400 Subject: [PATCH 002/169] Stub in an evaluate function mapping modules to results. --- src/Data/Abstract/Evaluatable.hs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index a3d9e7fa9..33a9a14d9 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -65,6 +65,10 @@ data LoadOrder a b = Done (NonEmpty b) | Load (NonEmpty a) (NonEmpty b -> LoadOrder a b) +evaluate :: LoadOrder (Module term) (Module (address, Environment address)) + -> Eff effects (NonEmpty (Module (address, Environment address))) +evaluate (Done results) = pure results + -- | Evaluate a given package. evaluatePackageWith :: forall address term value inner inner' inner'' outer . ( AbstractValue address value inner From 3b2cb5c0fdacd33e75e063081a081deac91ab3fb Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 15 Jun 2018 14:12:55 -0400 Subject: [PATCH 003/169] Factor NonEmpty out of LoadOrder. Co-Authored-By: Rick Winfrey --- src/Data/Abstract/Evaluatable.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 33a9a14d9..4d79c55a0 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -62,10 +62,10 @@ class Show1 constr => Evaluatable constr where data LoadOrder a b - = Done (NonEmpty b) - | Load (NonEmpty a) (NonEmpty b -> LoadOrder a b) + = Done b + | Load a (b -> LoadOrder a b) -evaluate :: LoadOrder (Module term) (Module (address, Environment address)) +evaluate :: LoadOrder (NonEmpty (Module term)) (NonEmpty (Module (address, Environment address))) -> Eff effects (NonEmpty (Module (address, Environment address))) evaluate (Done results) = pure results From c925925dd821165c2e94ca21bae881ee0379b398 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 15 Jun 2018 14:57:35 -0400 Subject: [PATCH 004/169] Evaluate a single tier of modules. Co-Authored-By: Rick Winfrey --- src/Data/Abstract/Evaluatable.hs | 40 +++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 4d79c55a0..f0603e846 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -15,7 +15,7 @@ module Data.Abstract.Evaluatable , Cell ) where -import Control.Abstract +import Control.Abstract hiding (Load) import Control.Abstract.Context as X import Control.Abstract.Environment as X hiding (runEnvironmentError, runEnvironmentErrorWith) import Control.Abstract.Evaluator as X hiding (LoopControl(..), Return(..), catchLoopControl, runLoopControl, catchReturn, runReturn) @@ -65,9 +65,43 @@ data LoadOrder a b = Done b | Load a (b -> LoadOrder a b) -evaluate :: LoadOrder (NonEmpty (Module term)) (NonEmpty (Module (address, Environment address))) - -> Eff effects (NonEmpty (Module (address, Environment address))) +evaluate :: forall address term value effects + . ( AbstractValue address value (LoopControl address ': Return address ': Env address ': Allocator address value ': Reader ModuleInfo ': Modules address value ': effects) + , Addressable address (Reader ModuleInfo ': Modules address value ': effects) + , Declarations term + , Evaluatable (Base term) + , Foldable (Cell address) + , FreeVariables term + , Member (Reader PackageInfo) effects + , Member (Reader Span) effects + , Member (Resumable (AddressError address value)) effects + , Member (Resumable (EnvironmentError address)) effects + , Member (Resumable EvalError) effects + , Member (Resumable (LoadError address value)) effects + , Member (Resumable ResolutionError) effects + , Member (Resumable (Unspecialized value)) effects + , Member (State (Heap address (Cell address) value)) effects + , Member (State (ModuleTable (Maybe (address, Environment address)))) effects + , Member Trace effects + , Recursive term + , Reducer value (Cell address value) + , ValueRoots address value + ) + => LoadOrder (NonEmpty (Module term)) (NonEmpty (address, Environment address)) + -> Evaluator address value effects (NonEmpty (address, Environment address)) evaluate (Done results) = pure results +evaluate (Load modules continue) + = runReader lowerBound + . runModules evalModule + $ traverse evalModule modules + where evalModule :: Module term -> Evaluator address value (Modules address value ': effects) (address, Environment address) + evalModule m + = runReader (moduleInfo m) + . runAllocator + . runEnv lowerBound + . runReturn + . runLoopControl + $ foldSubterms eval (moduleBody m) >>= address -- | Evaluate a given package. evaluatePackageWith :: forall address term value inner inner' inner'' outer From 3d45ab462391dd1a86209956f9bf1846c0d85996 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 15 Jun 2018 15:00:25 -0400 Subject: [PATCH 005/169] Evaluate following tiers recursively. Co-Authored-By: Rick Winfrey --- src/Data/Abstract/Evaluatable.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index f0603e846..d134cfb80 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -91,7 +91,8 @@ evaluate :: forall address term value effects -> Evaluator address value effects (NonEmpty (address, Environment address)) evaluate (Done results) = pure results evaluate (Load modules continue) - = runReader lowerBound + = (>>= evaluate . continue) + . runReader lowerBound . runModules evalModule $ traverse evalModule modules where evalModule :: Module term -> Evaluator address value (Modules address value ': effects) (address, Environment address) From 05933691d402d60ff88698679c0c02cacdff60ab Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 15 Jun 2018 15:08:36 -0400 Subject: [PATCH 006/169] Preserve the Modules during evaluation. Co-Authored-By: Rick Winfrey --- src/Data/Abstract/Evaluatable.hs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index d134cfb80..6226edbc1 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -87,14 +87,14 @@ evaluate :: forall address term value effects , Reducer value (Cell address value) , ValueRoots address value ) - => LoadOrder (NonEmpty (Module term)) (NonEmpty (address, Environment address)) - -> Evaluator address value effects (NonEmpty (address, Environment address)) + => LoadOrder (NonEmpty (Module term)) (NonEmpty (Module (address, Environment address))) + -> Evaluator address value effects (NonEmpty (Module (address, Environment address))) evaluate (Done results) = pure results evaluate (Load modules continue) = (>>= evaluate . continue) . runReader lowerBound . runModules evalModule - $ traverse evalModule modules + $ traverse evalModuleAndRetain modules where evalModule :: Module term -> Evaluator address value (Modules address value ': effects) (address, Environment address) evalModule m = runReader (moduleInfo m) @@ -104,6 +104,8 @@ evaluate (Load modules continue) . runLoopControl $ foldSubterms eval (moduleBody m) >>= address + evalModuleAndRetain m = (<$ m) <$> evalModule m + -- | Evaluate a given package. evaluatePackageWith :: forall address term value inner inner' inner'' outer . ( AbstractValue address value inner From 2387683c121436f217577184103d97e24d1599b1 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 15 Jun 2018 15:22:18 -0400 Subject: [PATCH 007/169] Make the modules available during the rest of the load. Co-Authored-By: Rick Winfrey --- src/Data/Abstract/Evaluatable.hs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 6226edbc1..1fc086fa8 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -72,6 +72,7 @@ evaluate :: forall address term value effects , Evaluatable (Base term) , Foldable (Cell address) , FreeVariables term + , Member (Reader (ModuleTable (NonEmpty (Module (address, Environment address))))) effects , Member (Reader PackageInfo) effects , Member (Reader Span) effects , Member (Resumable (AddressError address value)) effects @@ -91,7 +92,7 @@ evaluate :: forall address term value effects -> Evaluator address value effects (NonEmpty (Module (address, Environment address))) evaluate (Done results) = pure results evaluate (Load modules continue) - = (>>= evaluate . continue) + = runRestOfLoadOrder . runReader lowerBound . runModules evalModule $ traverse evalModuleAndRetain modules @@ -106,6 +107,10 @@ evaluate (Load modules continue) evalModuleAndRetain m = (<$ m) <$> evalModule m + runRestOfLoadOrder action = do + results <- action + local (<> ModuleTable.fromModules (toList results)) (evaluate (continue results)) + -- | Evaluate a given package. evaluatePackageWith :: forall address term value inner inner' inner'' outer . ( AbstractValue address value inner From 94b74325b0f65feaecae0eb51297e18b5a201f31 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 15 Jun 2018 15:44:17 -0400 Subject: [PATCH 008/169] Give LoadOrder a separate parameter for the completed value. Co-Authored-By: Rick Winfrey --- src/Data/Abstract/Evaluatable.hs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 1fc086fa8..7d683997d 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -30,6 +30,7 @@ import Data.Abstract.ModuleTable as ModuleTable import Data.Abstract.Name as X import Data.Abstract.Package as Package import Data.Abstract.Ref as X +import Data.Graph import Data.Scientific (Scientific) import Data.Semigroup.App import Data.Semigroup.Foldable @@ -61,9 +62,9 @@ class Show1 constr => Evaluatable constr where eval expr = rvalBox =<< throwResumable (Unspecialized ("Eval unspecialized for " ++ liftShowsPrec (const (const id)) (const id) 0 expr "")) -data LoadOrder a b - = Done b - | Load a (b -> LoadOrder a b) +data LoadOrder a b c + = Done c + | Load a (b -> LoadOrder a b c) evaluate :: forall address term value effects . ( AbstractValue address value (LoopControl address ': Return address ': Env address ': Allocator address value ': Reader ModuleInfo ': Modules address value ': effects) @@ -88,7 +89,7 @@ evaluate :: forall address term value effects , Reducer value (Cell address value) , ValueRoots address value ) - => LoadOrder (NonEmpty (Module term)) (NonEmpty (Module (address, Environment address))) + => LoadOrder (NonEmpty (Module term)) (NonEmpty (Module (address, Environment address))) (NonEmpty (Module (address, Environment address))) -> Evaluator address value effects (NonEmpty (Module (address, Environment address))) evaluate (Done results) = pure results evaluate (Load modules continue) From 0ba6f54f4213a06abbd8ebb57c45fe0cfe606c77 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 15 Jun 2018 15:44:28 -0400 Subject: [PATCH 009/169] Derive a Functor instance for LoadOrder. Co-Authored-By: Rick Winfrey --- src/Data/Abstract/Evaluatable.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 7d683997d..f52c92abc 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -65,6 +65,7 @@ class Show1 constr => Evaluatable constr where data LoadOrder a b c = Done c | Load a (b -> LoadOrder a b c) + deriving (Functor) evaluate :: forall address term value effects . ( AbstractValue address value (LoopControl address ': Return address ': Env address ': Allocator address value ': Reader ModuleInfo ': Modules address value ': effects) From 7183dcf033ce9001426dec3bc2864fea2f7cf6b2 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 15 Jun 2018 16:43:24 -0400 Subject: [PATCH 010/169] Implement topological sorts. Co-Authored-By: Rick Winfrey --- src/Data/Abstract/Evaluatable.hs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index f52c92abc..6a4704d74 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -15,6 +15,7 @@ module Data.Abstract.Evaluatable , Cell ) where +import Algebra.Graph.Class (foldg) import Control.Abstract hiding (Load) import Control.Abstract.Context as X import Control.Abstract.Environment as X hiding (runEnvironmentError, runEnvironmentErrorWith) @@ -31,6 +32,10 @@ import Data.Abstract.Name as X import Data.Abstract.Package as Package import Data.Abstract.Ref as X import Data.Graph +import Data.List (groupBy, nub, sortBy) +import qualified Data.Monoid as Monoid +import qualified Data.Map.Monoidal as Map +import Data.Ord (comparing) import Data.Scientific (Scientific) import Data.Semigroup.App import Data.Semigroup.Foldable @@ -62,6 +67,33 @@ class Show1 constr => Evaluatable constr where eval expr = rvalBox =<< throwResumable (Unspecialized ("Eval unspecialized for " ++ liftShowsPrec (const (const id)) (const id) 0 expr "")) +topologicalSort :: Ord v => Graph v -> [[v]] +topologicalSort + = groupByInEdgeCount + . allVertices + . labelWithInEdgeCounts + +labelWithInEdgeCounts :: Ord v => Graph v -> Graph (Monoid.Sum Int, v) +labelWithInEdgeCounts + = uncurry mapGraph + . foldg + (lowerBound, lowerBound) + ((,) lowerBound . vertex) + (<>) + (\ (outM, outG) (inM, inG) -> + ( outM <> inM <> foldMap (flip Map.singleton (Monoid.Sum (length outG))) (allVertices inG) + , outG `connect` inG + )) + where mapGraph edgeCountsByVertex g = pairWithCountIn edgeCountsByVertex <$> g + pairWithCountIn edgeCountsByVertex vertex = (fromMaybe 0 (Map.lookup vertex edgeCountsByVertex), vertex) + +allVertices :: Eq v => Graph v -> [v] +allVertices = nub . toList + +groupByInEdgeCount :: Ord sum => [(sum, v)] -> [[v]] +groupByInEdgeCount = map (map snd) . groupBy ((==) `on` fst) . sortBy (comparing fst) + + data LoadOrder a b c = Done c | Load a (b -> LoadOrder a b c) From 0192c85918cfd4beac1f7dd3b877a3928a4b0e74 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 15 Jun 2018 16:45:16 -0400 Subject: [PATCH 011/169] Group into NonEmpty lists. Co-Authored-By: Rick Winfrey --- src/Data/Abstract/Evaluatable.hs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 6a4704d74..fe353827f 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -33,6 +33,7 @@ import Data.Abstract.Package as Package import Data.Abstract.Ref as X import Data.Graph import Data.List (groupBy, nub, sortBy) +import qualified Data.List.NonEmpty as NonEmpty (fromList) import qualified Data.Monoid as Monoid import qualified Data.Map.Monoidal as Map import Data.Ord (comparing) @@ -67,7 +68,7 @@ class Show1 constr => Evaluatable constr where eval expr = rvalBox =<< throwResumable (Unspecialized ("Eval unspecialized for " ++ liftShowsPrec (const (const id)) (const id) 0 expr "")) -topologicalSort :: Ord v => Graph v -> [[v]] +topologicalSort :: Ord v => Graph v -> [NonEmpty v] topologicalSort = groupByInEdgeCount . allVertices @@ -90,8 +91,8 @@ labelWithInEdgeCounts allVertices :: Eq v => Graph v -> [v] allVertices = nub . toList -groupByInEdgeCount :: Ord sum => [(sum, v)] -> [[v]] -groupByInEdgeCount = map (map snd) . groupBy ((==) `on` fst) . sortBy (comparing fst) +groupByInEdgeCount :: Ord sum => [(sum, v)] -> [NonEmpty v] +groupByInEdgeCount = map (NonEmpty.fromList . map snd) . groupBy ((==) `on` fst) . sortBy (comparing fst) data LoadOrder a b c From 529232ee28b883b0f0a1db5a793b628ae3127efe Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 15 Jun 2018 16:49:07 -0400 Subject: [PATCH 012/169] Revert "Give LoadOrder a separate parameter for the completed value." This reverts commit c4f886cb8e2eb2f4530c19334df0e96d34d75337. Co-Authored-By: Rick Winfrey --- src/Data/Abstract/Evaluatable.hs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index fe353827f..d50a7b60a 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -95,10 +95,9 @@ groupByInEdgeCount :: Ord sum => [(sum, v)] -> [NonEmpty v] groupByInEdgeCount = map (NonEmpty.fromList . map snd) . groupBy ((==) `on` fst) . sortBy (comparing fst) -data LoadOrder a b c - = Done c - | Load a (b -> LoadOrder a b c) - deriving (Functor) +data LoadOrder a b + = Done b + | Load a (b -> LoadOrder a b) evaluate :: forall address term value effects . ( AbstractValue address value (LoopControl address ': Return address ': Env address ': Allocator address value ': Reader ModuleInfo ': Modules address value ': effects) @@ -123,7 +122,7 @@ evaluate :: forall address term value effects , Reducer value (Cell address value) , ValueRoots address value ) - => LoadOrder (NonEmpty (Module term)) (NonEmpty (Module (address, Environment address))) (NonEmpty (Module (address, Environment address))) + => LoadOrder (NonEmpty (Module term)) (NonEmpty (Module (address, Environment address))) -> Evaluator address value effects (NonEmpty (Module (address, Environment address))) evaluate (Done results) = pure results evaluate (Load modules continue) From d1cc819ed205f8697bafe97d73b6e8b6a89caee5 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 15 Jun 2018 16:53:48 -0400 Subject: [PATCH 013/169] Simplify evaluate to not use LoadOrder. Co-Authored-By: Rick Winfrey --- src/Data/Abstract/Evaluatable.hs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index d50a7b60a..70c768c54 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -95,10 +95,6 @@ groupByInEdgeCount :: Ord sum => [(sum, v)] -> [NonEmpty v] groupByInEdgeCount = map (NonEmpty.fromList . map snd) . groupBy ((==) `on` fst) . sortBy (comparing fst) -data LoadOrder a b - = Done b - | Load a (b -> LoadOrder a b) - evaluate :: forall address term value effects . ( AbstractValue address value (LoopControl address ': Return address ': Env address ': Allocator address value ': Reader ModuleInfo ': Modules address value ': effects) , Addressable address (Reader ModuleInfo ': Modules address value ': effects) @@ -122,10 +118,10 @@ evaluate :: forall address term value effects , Reducer value (Cell address value) , ValueRoots address value ) - => LoadOrder (NonEmpty (Module term)) (NonEmpty (Module (address, Environment address))) - -> Evaluator address value effects (NonEmpty (Module (address, Environment address))) -evaluate (Done results) = pure results -evaluate (Load modules continue) + => [NonEmpty (Module term)] + -> Evaluator address value effects (ModuleTable (NonEmpty (Module (address, Environment address)))) +evaluate [] = ask +evaluate (modules : rest) = runRestOfLoadOrder . runReader lowerBound . runModules evalModule @@ -143,7 +139,7 @@ evaluate (Load modules continue) runRestOfLoadOrder action = do results <- action - local (<> ModuleTable.fromModules (toList results)) (evaluate (continue results)) + local (<> ModuleTable.fromModules (toList results)) (evaluate rest) -- | Evaluate a given package. evaluatePackageWith :: forall address term value inner inner' inner'' outer From 6740542592d19fcf15d5cbdc42d81307eef42627 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 18 Jun 2018 09:34:21 -0400 Subject: [PATCH 014/169] Move the graph operations into Data.Graph. --- src/Data/Abstract/Evaluatable.hs | 34 -------------------------------- src/Data/Graph.hs | 33 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 34 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 70c768c54..7ccef662d 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -15,7 +15,6 @@ module Data.Abstract.Evaluatable , Cell ) where -import Algebra.Graph.Class (foldg) import Control.Abstract hiding (Load) import Control.Abstract.Context as X import Control.Abstract.Environment as X hiding (runEnvironmentError, runEnvironmentErrorWith) @@ -31,12 +30,6 @@ import Data.Abstract.ModuleTable as ModuleTable import Data.Abstract.Name as X import Data.Abstract.Package as Package import Data.Abstract.Ref as X -import Data.Graph -import Data.List (groupBy, nub, sortBy) -import qualified Data.List.NonEmpty as NonEmpty (fromList) -import qualified Data.Monoid as Monoid -import qualified Data.Map.Monoidal as Map -import Data.Ord (comparing) import Data.Scientific (Scientific) import Data.Semigroup.App import Data.Semigroup.Foldable @@ -68,33 +61,6 @@ class Show1 constr => Evaluatable constr where eval expr = rvalBox =<< throwResumable (Unspecialized ("Eval unspecialized for " ++ liftShowsPrec (const (const id)) (const id) 0 expr "")) -topologicalSort :: Ord v => Graph v -> [NonEmpty v] -topologicalSort - = groupByInEdgeCount - . allVertices - . labelWithInEdgeCounts - -labelWithInEdgeCounts :: Ord v => Graph v -> Graph (Monoid.Sum Int, v) -labelWithInEdgeCounts - = uncurry mapGraph - . foldg - (lowerBound, lowerBound) - ((,) lowerBound . vertex) - (<>) - (\ (outM, outG) (inM, inG) -> - ( outM <> inM <> foldMap (flip Map.singleton (Monoid.Sum (length outG))) (allVertices inG) - , outG `connect` inG - )) - where mapGraph edgeCountsByVertex g = pairWithCountIn edgeCountsByVertex <$> g - pairWithCountIn edgeCountsByVertex vertex = (fromMaybe 0 (Map.lookup vertex edgeCountsByVertex), vertex) - -allVertices :: Eq v => Graph v -> [v] -allVertices = nub . toList - -groupByInEdgeCount :: Ord sum => [(sum, v)] -> [NonEmpty v] -groupByInEdgeCount = map (NonEmpty.fromList . map snd) . groupBy ((==) `on` fst) . sortBy (comparing fst) - - evaluate :: forall address term value effects . ( AbstractValue address value (LoopControl address ': Return address ': Env address ': Allocator address value ': Reader ModuleInfo ': Modules address value ': effects) , Addressable address (Reader ModuleInfo ': Modules address value ': effects) diff --git a/src/Data/Graph.hs b/src/Data/Graph.hs index f8e6e263d..2d196e481 100644 --- a/src/Data/Graph.hs +++ b/src/Data/Graph.hs @@ -6,11 +6,17 @@ module Data.Graph , Class.vertex , Lower(..) , simplify +, topologicalSort ) where import qualified Algebra.Graph as G import qualified Algebra.Graph.Class as Class import Data.Aeson +import Data.List (groupBy, nub, sortBy) +import qualified Data.List.NonEmpty as NonEmpty (fromList) +import qualified Data.Map.Monoidal as Monoidal +import qualified Data.Monoid as Monoid +import Data.Ord (comparing) import Prologue -- | An algebraic graph with 'Ord', 'Semigroup', and 'Monoid' instances. @@ -22,6 +28,33 @@ simplify :: Ord vertex => Graph vertex -> Graph vertex simplify (Graph graph) = Graph (G.simplify graph) +topologicalSort :: Ord v => Graph v -> [NonEmpty v] +topologicalSort + = groupByInEdgeCount + . allVertices + . labelWithInEdgeCounts + +labelWithInEdgeCounts :: Ord v => Graph v -> Graph (Monoid.Sum Int, v) +labelWithInEdgeCounts + = uncurry mapGraph + . Class.foldg + (lowerBound, lowerBound) + ((,) lowerBound . Class.vertex) + (<>) + (\ (outM, outG) (inM, inG) -> + ( outM <> inM <> foldMap (flip Monoidal.singleton (Monoid.Sum (length outG))) (allVertices inG) + , outG `Class.connect` inG + )) + where mapGraph edgeCountsByVertex g = pairWithCountIn edgeCountsByVertex <$> g + pairWithCountIn edgeCountsByVertex vertex = (fromMaybe 0 (Monoidal.lookup vertex edgeCountsByVertex), vertex) + +allVertices :: Eq v => Graph v -> [v] +allVertices = nub . toList + +groupByInEdgeCount :: Ord sum => [(sum, v)] -> [NonEmpty v] +groupByInEdgeCount = map (NonEmpty.fromList . map snd) . groupBy ((==) `on` fst) . sortBy (comparing fst) + + instance Lower (Graph vertex) where lowerBound = Class.empty From 092f117defc047e30b73d94339c4090808539774 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 18 Jun 2018 09:35:51 -0400 Subject: [PATCH 015/169] Fix the alignment of the analysis functions. --- src/Data/Abstract/Evaluatable.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 7ccef662d..959c38411 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -133,7 +133,7 @@ evaluatePackageWith :: forall address term value inner inner' inner'' outer , inner' ~ (Reader ModuleInfo ': inner'') , inner'' ~ (Modules address value ': Reader Span ': Reader PackageInfo ': outer) ) - => (SubtermAlgebra Module term (TermEvaluator term address value inner address) -> SubtermAlgebra Module term (TermEvaluator term address value inner address)) + => (SubtermAlgebra Module term (TermEvaluator term address value inner address) -> SubtermAlgebra Module term (TermEvaluator term address value inner address)) -> (SubtermAlgebra (Base term) term (TermEvaluator term address value inner (ValueRef address)) -> SubtermAlgebra (Base term) term (TermEvaluator term address value inner (ValueRef address))) -> Package term -> TermEvaluator term address value outer [(address, Environment address)] From 2717582524701ecf813cfbbe266101a5a3810d9d Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 18 Jun 2018 09:37:31 -0400 Subject: [PATCH 016/169] evalModule returns its results in a Module. --- src/Control/Abstract/Modules.hs | 4 ++-- src/Data/Abstract/Evaluatable.hs | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Control/Abstract/Modules.hs b/src/Control/Abstract/Modules.hs index 4123c7475..db16864b6 100644 --- a/src/Control/Abstract/Modules.hs +++ b/src/Control/Abstract/Modules.hs @@ -64,7 +64,7 @@ runModules :: forall term address value effects a , Member (State (ModuleTable (Maybe (address, Environment address)))) effects , Member Trace effects ) - => (Module term -> Evaluator address value (Modules address value ': effects) (address, Environment address)) + => (Module term -> Evaluator address value (Modules address value ': effects) (Module (address, Environment address))) -> Evaluator address value (Modules address value ': effects) a -> Evaluator address value (Reader (ModuleTable (NonEmpty (Module term))) ': effects) a runModules evaluateModule = go @@ -80,7 +80,7 @@ runModules evaluateModule = go else do _ <- cacheModule name Nothing result <- trace ("load (evaluating): " <> show mPath) *> go (evaluateModule x) <* trace ("load done:" <> show mPath) - cacheModule name (Just result) + cacheModule name (Just (moduleBody result)) loadingModule path = isJust . ModuleTable.lookup path <$> getModuleTable Lookup path -> ModuleTable.lookup path <$> get diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 959c38411..0e59a4fce 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -91,18 +91,17 @@ evaluate (modules : rest) = runRestOfLoadOrder . runReader lowerBound . runModules evalModule - $ traverse evalModuleAndRetain modules - where evalModule :: Module term -> Evaluator address value (Modules address value ': effects) (address, Environment address) + $ traverse evalModule modules + where evalModule :: Module term -> Evaluator address value (Modules address value ': effects) (Module (address, Environment address)) evalModule m - = runReader (moduleInfo m) + = fmap (<$ m) + . runReader (moduleInfo m) . runAllocator . runEnv lowerBound . runReturn . runLoopControl $ foldSubterms eval (moduleBody m) >>= address - evalModuleAndRetain m = (<$ m) <$> evalModule m - runRestOfLoadOrder action = do results <- action local (<> ModuleTable.fromModules (toList results)) (evaluate rest) @@ -148,7 +147,8 @@ evaluatePackageWith analyzeModule analyzeTerm package $ ModuleTable.toPairs (packageEntryPoints (packageBody package)) where evalModule preludeEnv m - = runInModule preludeEnv (moduleInfo m) + = fmap (<$ m) + . runInModule preludeEnv (moduleInfo m) . analyzeModule (subtermRef . moduleBody) $ evalTerm <$> m evalTerm term = Subterm term (TermEvaluator (address =<< runTermEvaluator (foldSubterms (analyzeTerm (TermEvaluator . eval . fmap (second runTermEvaluator))) term))) @@ -169,7 +169,7 @@ evaluatePackageWith analyzeModule analyzeTerm package evalPrelude prelude = raiseHandler (runModules (runTermEvaluator . evalModule lowerBound)) $ do (_, builtinsEnv) <- runInModule lowerBound moduleInfoFromCallStack (TermEvaluator (defineBuiltins *> box unit)) - second (mergeEnvs builtinsEnv) <$> evalModule builtinsEnv prelude + second (mergeEnvs builtinsEnv) . moduleBody <$> evalModule builtinsEnv prelude withPrelude Nothing f = f lowerBound withPrelude (Just prelude) f = do From 2d259d5e0eb95f06c143366971b60fb362835e8e Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 18 Jun 2018 09:38:51 -0400 Subject: [PATCH 017/169] Pass rest in instead of closing over it. --- src/Data/Abstract/Evaluatable.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 0e59a4fce..b36454e0d 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -88,7 +88,7 @@ evaluate :: forall address term value effects -> Evaluator address value effects (ModuleTable (NonEmpty (Module (address, Environment address)))) evaluate [] = ask evaluate (modules : rest) - = runRestOfLoadOrder + = runRest rest . runReader lowerBound . runModules evalModule $ traverse evalModule modules @@ -102,7 +102,7 @@ evaluate (modules : rest) . runLoopControl $ foldSubterms eval (moduleBody m) >>= address - runRestOfLoadOrder action = do + runRest rest action = do results <- action local (<> ModuleTable.fromModules (toList results)) (evaluate rest) From 1e0a1c147774e577bfc46872801e86fecaa39419 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 18 Jun 2018 12:52:13 -0400 Subject: [PATCH 018/169] :fire: the value parameter. --- src/Control/Abstract/Modules.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Control/Abstract/Modules.hs b/src/Control/Abstract/Modules.hs index db16864b6..d48cd81ce 100644 --- a/src/Control/Abstract/Modules.hs +++ b/src/Control/Abstract/Modules.hs @@ -99,14 +99,14 @@ askModuleTable :: Member (Reader (ModuleTable (NonEmpty (Module term)))) effects askModuleTable = ask -newtype Merging m address value = Merging { runMerging :: m (Maybe (address, Environment address)) } +newtype Merging m address = Merging { runMerging :: m (Maybe (address, Environment address)) } -instance Applicative m => Semigroup (Merging m address value) where +instance Applicative m => Semigroup (Merging m address) where Merging a <> Merging b = Merging (merge <$> a <*> b) where merge a b = mergeJusts <$> a <*> b <|> a <|> b mergeJusts (_, env1) (v, env2) = (v, mergeEnvs env1 env2) -instance Applicative m => Monoid (Merging m address value) where +instance Applicative m => Monoid (Merging m address) where mappend = (<>) mempty = Merging (pure Nothing) From dfebd14ad75b0e650e9aa4380dddbba29d5487da Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 18 Jun 2018 13:01:45 -0400 Subject: [PATCH 019/169] Define an alternative interpreter for Modules relying on us having loaded the necessary modules already. --- src/Control/Abstract/Modules.hs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/Control/Abstract/Modules.hs b/src/Control/Abstract/Modules.hs index d48cd81ce..ec4bdd437 100644 --- a/src/Control/Abstract/Modules.hs +++ b/src/Control/Abstract/Modules.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE GADTs, RankNTypes, ScopedTypeVariables, TypeOperators #-} +{-# LANGUAGE GADTs, LambdaCase, RankNTypes, ScopedTypeVariables, TypeOperators #-} module Control.Abstract.Modules ( lookupModule , resolve @@ -7,6 +7,7 @@ module Control.Abstract.Modules , load , Modules(..) , runModules +, runModules' , LoadError(..) , moduleNotFound , resumeLoadError @@ -23,6 +24,7 @@ import Data.Abstract.Environment import Data.Abstract.Module import Data.Abstract.ModuleTable as ModuleTable import Data.Language +import Data.Semigroup.Foldable (foldMap1) import Prologue -- | Retrieve an evaluated module, if any. The outer 'Maybe' indicates whether we’ve begun loading the module or not, while the inner 'Maybe' indicates whether we’ve completed loading it or not. Thus, @Nothing@ means we’ve never tried to load it, @Just Nothing@ means we’ve started but haven’t yet finished loading it, and @Just (Just (env, value))@ indicates the result of a completed load. @@ -89,6 +91,17 @@ runModules evaluateModule = go pure (find isMember names) List dir -> modulePathsInDir dir <$> askModuleTable @term) +runModules' :: Member (Reader (ModuleTable (NonEmpty (Module (address, Environment address))))) effects + => Evaluator address value (Modules address value ': effects) a + -> Evaluator address value effects a +runModules' = interpret $ \case + Load name -> fmap (runMerging' . foldMap1 (Merging' . moduleBody)) . ModuleTable.lookup name <$> askModuleTable' + Lookup path -> fmap (Just . runMerging' . foldMap1 (Merging' . moduleBody)) . ModuleTable.lookup path <$> askModuleTable' + Resolve names -> do + isMember <- flip ModuleTable.member <$> askModuleTable' + pure (find isMember names) + List dir -> modulePathsInDir dir <$> askModuleTable' + getModuleTable :: Member (State (ModuleTable (Maybe (address, Environment address)))) effects => Evaluator address value effects (ModuleTable (Maybe (address, Environment address))) getModuleTable = get @@ -98,6 +111,9 @@ cacheModule path result = modify' (ModuleTable.insert path result) $> result askModuleTable :: Member (Reader (ModuleTable (NonEmpty (Module term)))) effects => Evaluator address value effects (ModuleTable (NonEmpty (Module term))) askModuleTable = ask +askModuleTable' :: Member (Reader (ModuleTable (NonEmpty (Module (address, Environment address))))) effects => Evaluator address value effects (ModuleTable (NonEmpty (Module (address, Environment address)))) +askModuleTable' = ask + newtype Merging m address = Merging { runMerging :: m (Maybe (address, Environment address)) } @@ -111,6 +127,12 @@ instance Applicative m => Monoid (Merging m address) where mempty = Merging (pure Nothing) +newtype Merging' address = Merging' { runMerging' :: (address, Environment address) } + +instance Semigroup (Merging' address) where + Merging' (_, env1) <> Merging' (addr, env2) = Merging' (addr, mergeEnvs env1 env2) + + -- | An error thrown when loading a module from the list of provided modules. Indicates we weren't able to find a module with the given name. data LoadError address value resume where ModuleNotFound :: ModulePath -> LoadError address value (Maybe (address, Environment address)) From 60d299d24f322b849149084271c9f84f818d9069 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 18 Jun 2018 13:02:10 -0400 Subject: [PATCH 020/169] Use the new Modules handler in evaluate. --- src/Data/Abstract/Evaluatable.hs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 41d4cc6bd..dc51e1eea 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -92,8 +92,7 @@ evaluate :: forall address term value effects evaluate [] = ask evaluate (modules : rest) = runRest rest - . runReader lowerBound - . runModules evalModule + . runModules' $ traverse evalModule modules where evalModule :: Module term -> Evaluator address value (Modules address value ': effects) (Module (address, Environment address)) evalModule m From b8691d589622079571628e329c6e6f34949c5345 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 18 Jun 2018 13:05:53 -0400 Subject: [PATCH 021/169] :fire: an unnecessary signature. --- src/Data/Abstract/Evaluatable.hs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index dc51e1eea..7f11ea81e 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -94,8 +94,7 @@ evaluate (modules : rest) = runRest rest . runModules' $ traverse evalModule modules - where evalModule :: Module term -> Evaluator address value (Modules address value ': effects) (Module (address, Environment address)) - evalModule m + where evalModule m = fmap (<$ m) . runReader (moduleInfo m) . runAllocator From 17c8e024bd27d805e2b55fcf48105c7f8ccb76ba Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 18 Jun 2018 13:12:51 -0400 Subject: [PATCH 022/169] :fire: a redundant constraint. --- 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 7f11ea81e..7ee3a6efb 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -81,7 +81,6 @@ evaluate :: forall address term value effects , Member (Resumable ResolutionError) effects , Member (Resumable (Unspecialized value)) effects , Member (State (Heap address (Cell address) value)) effects - , Member (State (ModuleTable (Maybe (address, Environment address)))) effects , Member Trace effects , Recursive term , Reducer value (Cell address value) From 9bf816db3b203404c7addad18e37fe16cc4bc2ea Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 18 Jun 2018 13:15:10 -0400 Subject: [PATCH 023/169] :fire: the value parameter from LoadError. --- src/Control/Abstract/Modules.hs | 24 ++++++++++++------------ src/Data/Abstract/Evaluatable.hs | 4 ++-- src/Semantic/Graph.hs | 4 ++-- src/Semantic/Util.hs | 2 +- test/SpecHelpers.hs | 6 +++--- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Control/Abstract/Modules.hs b/src/Control/Abstract/Modules.hs index ec4bdd437..52cd1d846 100644 --- a/src/Control/Abstract/Modules.hs +++ b/src/Control/Abstract/Modules.hs @@ -62,7 +62,7 @@ sendModules :: Member (Modules address value) effects => Modules address value r sendModules = send runModules :: forall term address value effects a - . ( Member (Resumable (LoadError address value)) effects + . ( Member (Resumable (LoadError address)) effects , Member (State (ModuleTable (Maybe (address, Environment address)))) effects , Member Trace effects ) @@ -134,26 +134,26 @@ instance Semigroup (Merging' address) where -- | An error thrown when loading a module from the list of provided modules. Indicates we weren't able to find a module with the given name. -data LoadError address value resume where - ModuleNotFound :: ModulePath -> LoadError address value (Maybe (address, Environment address)) +data LoadError address resume where + ModuleNotFound :: ModulePath -> LoadError address (Maybe (address, Environment address)) -deriving instance Eq (LoadError address value resume) -deriving instance Show (LoadError address value resume) -instance Show1 (LoadError address value) where +deriving instance Eq (LoadError address resume) +deriving instance Show (LoadError address resume) +instance Show1 (LoadError address) where liftShowsPrec _ _ = showsPrec -instance Eq1 (LoadError address value) where +instance Eq1 (LoadError address) where liftEq _ (ModuleNotFound a) (ModuleNotFound b) = a == b -moduleNotFound :: forall address value effects . Member (Resumable (LoadError address value)) effects => ModulePath -> Evaluator address value effects (Maybe (address, Environment address)) -moduleNotFound = throwResumable . ModuleNotFound @address @value +moduleNotFound :: Member (Resumable (LoadError address)) effects => ModulePath -> Evaluator address value effects (Maybe (address, Environment address)) +moduleNotFound = throwResumable . ModuleNotFound -resumeLoadError :: Member (Resumable (LoadError address value)) effects => Evaluator address value effects a -> (forall resume . LoadError address value resume -> Evaluator address value effects resume) -> Evaluator address value effects a +resumeLoadError :: Member (Resumable (LoadError address)) effects => Evaluator address value effects a -> (forall resume . LoadError address resume -> Evaluator address value effects resume) -> Evaluator address value effects a resumeLoadError = catchResumable -runLoadError :: Effectful (m address value) => m address value (Resumable (LoadError address value) ': effects) a -> m address value effects (Either (SomeExc (LoadError address value)) a) +runLoadError :: Effectful (m address value) => m address value (Resumable (LoadError address) ': effects) a -> m address value effects (Either (SomeExc (LoadError address)) a) runLoadError = runResumable -runLoadErrorWith :: Effectful (m address value) => (forall resume . LoadError address value resume -> m address value effects resume) -> m address value (Resumable (LoadError address value) ': effects) a -> m address value effects a +runLoadErrorWith :: Effectful (m address value) => (forall resume . LoadError address resume -> m address value effects resume) -> m address value (Resumable (LoadError address) ': effects) a -> m address value effects a runLoadErrorWith = runResumableWith diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 7ee3a6efb..897017730 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -77,7 +77,7 @@ evaluate :: forall address term value effects , Member (Resumable (AddressError address value)) effects , Member (Resumable (EnvironmentError address)) effects , Member (Resumable EvalError) effects - , Member (Resumable (LoadError address value)) effects + , Member (Resumable (LoadError address)) effects , Member (Resumable ResolutionError) effects , Member (Resumable (Unspecialized value)) effects , Member (State (Heap address (Cell address) value)) effects @@ -120,7 +120,7 @@ evaluatePackageWith :: forall proxy lang address term value inner inner' inner'' , Member (Resumable (AddressError address value)) outer , Member (Resumable (EnvironmentError address)) outer , Member (Resumable EvalError) outer - , Member (Resumable (LoadError address value)) outer + , Member (Resumable (LoadError address)) outer , Member (Resumable ResolutionError) outer , Member (Resumable (Unspecialized value)) outer , Member (State (Heap address (Cell address) value)) outer diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index 78f81ace1..58cb217b7 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -85,7 +85,7 @@ newtype GraphEff address a = GraphEff , Resumable EvalError , Resumable (EnvironmentError address) , Resumable (Unspecialized (Value address (GraphEff address))) - , Resumable (LoadError address (Value address (GraphEff address))) + , Resumable (LoadError address) , Trace , Fresh , State (Heap address Latest (Value address (GraphEff address))) @@ -130,7 +130,7 @@ resumingResolutionError = runResolutionErrorWith (\ err -> trace ("ResolutionErr NotFoundError nameToResolve _ _ -> pure nameToResolve GoImportError pathToResolve -> pure [pathToResolve]) -resumingLoadError :: Member Trace effects => Evaluator address value (Resumable (LoadError address value) ': effects) a -> Evaluator address value effects a +resumingLoadError :: Member Trace effects => Evaluator address value (Resumable (LoadError address) ': effects) a -> Evaluator address value effects a resumingLoadError = runLoadErrorWith (\ (ModuleNotFound path) -> trace ("LoadError: " <> path) $> Nothing) resumingEvalError :: Member Trace effects => Evaluator address value (Resumable EvalError ': effects) a -> Evaluator address value effects a diff --git a/src/Semantic/Util.hs b/src/Semantic/Util.hs index 1c404204e..f9834edb9 100644 --- a/src/Semantic/Util.hs +++ b/src/Semantic/Util.hs @@ -56,7 +56,7 @@ newtype UtilEff address a = UtilEff , Resumable (EnvironmentError address) , Resumable ResolutionError , Resumable (Unspecialized (Value address (UtilEff address))) - , Resumable (LoadError address (Value address (UtilEff address))) + , Resumable (LoadError address) , Trace , Fresh , State (Heap address Latest (Value address (UtilEff address))) diff --git a/test/SpecHelpers.hs b/test/SpecHelpers.hs index 79db79118..edf39923b 100644 --- a/test/SpecHelpers.hs +++ b/test/SpecHelpers.hs @@ -88,7 +88,7 @@ testEvaluating :: TermEvaluator term Precise , Resumable EvalError, Resumable (EnvironmentError Precise) , Resumable ResolutionError , Resumable (Unspecialized Val) - , Resumable (LoadError Precise Val) + , Resumable (LoadError Precise) , Fresh , State (Heap Precise Latest Val) , State (ModuleTable (Maybe (Precise, Environment Precise))) @@ -104,7 +104,7 @@ testEvaluating :: TermEvaluator term Precise , EnvironmentError Precise , ResolutionError , Unspecialized Val - , LoadError Precise Val + , LoadError Precise ])) [(Value Precise TestEff, Environment Precise)], EvaluatingState Precise Val), @@ -140,7 +140,7 @@ newtype TestEff a = TestEff , Resumable (EnvironmentError Precise) , Resumable ResolutionError , Resumable (Unspecialized Val) - , Resumable (LoadError Precise Val) + , Resumable (LoadError Precise) , Fresh , State (Heap Precise Latest Val) , State (ModuleTable (Maybe (Precise, Environment Precise))) From 1b245278a1d851bb6154fdef4cbacc2ade8b3429 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 18 Jun 2018 13:18:20 -0400 Subject: [PATCH 024/169] :fire: the value parameter from Modules. --- src/Analysis/Abstract/Graph.hs | 4 ++-- src/Control/Abstract/Modules.hs | 34 +++++++++++++++---------------- src/Data/Abstract/Evaluatable.hs | 8 ++++---- src/Language/Go/Syntax.hs | 2 +- src/Language/PHP/Syntax.hs | 4 ++-- src/Language/Python/Syntax.hs | 4 ++-- src/Language/Ruby/Syntax.hs | 8 ++++---- src/Language/TypeScript/Syntax.hs | 10 ++++----- src/Semantic/Graph.hs | 2 +- src/Semantic/Util.hs | 2 +- test/SpecHelpers.hs | 2 +- 11 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/Analysis/Abstract/Graph.hs b/src/Analysis/Abstract/Graph.hs index 4939e036b..28d9f5b6d 100644 --- a/src/Analysis/Abstract/Graph.hs +++ b/src/Analysis/Abstract/Graph.hs @@ -76,13 +76,13 @@ graphingPackages recur m = packageInclusion (moduleVertex (moduleInfo m)) *> rec -- | Add vertices to the graph for evaluated modules and the packages containing them. graphingModules :: forall term address value effects a - . ( Member (Modules address value) effects + . ( Member (Modules address) effects , Member (Reader ModuleInfo) effects , Member (State (Graph Vertex)) effects ) => SubtermAlgebra Module term (TermEvaluator term address value effects a) -> SubtermAlgebra Module term (TermEvaluator term address value effects a) -graphingModules recur m = interpose @(Modules address value) pure (\ m yield -> case m of +graphingModules recur m = interpose @(Modules address) pure (\ m yield -> case m of Load path -> moduleInclusion (moduleVertex (ModuleInfo path)) >> send m >>= yield Lookup path -> moduleInclusion (moduleVertex (ModuleInfo path)) >> send m >>= yield _ -> send m >>= yield) diff --git a/src/Control/Abstract/Modules.hs b/src/Control/Abstract/Modules.hs index 52cd1d846..de4a7d829 100644 --- a/src/Control/Abstract/Modules.hs +++ b/src/Control/Abstract/Modules.hs @@ -28,37 +28,37 @@ import Data.Semigroup.Foldable (foldMap1) import Prologue -- | Retrieve an evaluated module, if any. The outer 'Maybe' indicates whether we’ve begun loading the module or not, while the inner 'Maybe' indicates whether we’ve completed loading it or not. Thus, @Nothing@ means we’ve never tried to load it, @Just Nothing@ means we’ve started but haven’t yet finished loading it, and @Just (Just (env, value))@ indicates the result of a completed load. -lookupModule :: Member (Modules address value) effects => ModulePath -> Evaluator address value effects (Maybe (Maybe (address, Environment address))) +lookupModule :: Member (Modules address) effects => ModulePath -> Evaluator address value effects (Maybe (Maybe (address, Environment address))) lookupModule = sendModules . Lookup -- | Resolve a list of module paths to a possible module table entry. -resolve :: forall address value effects . Member (Modules address value) effects => [FilePath] -> Evaluator address value effects (Maybe ModulePath) -resolve = sendModules . Resolve @address @value +resolve :: Member (Modules address) effects => [FilePath] -> Evaluator address value effects (Maybe ModulePath) +resolve = sendModules . Resolve -listModulesInDir :: forall address value effects . Member (Modules address value) effects => FilePath -> Evaluator address value effects [ModulePath] -listModulesInDir = sendModules . List @address @value +listModulesInDir :: Member (Modules address) effects => FilePath -> Evaluator address value effects [ModulePath] +listModulesInDir = sendModules . List -- | Require/import another module by name and return its environment and value. -- -- Looks up the module's name in the cache of evaluated modules first, returns if found, otherwise loads/evaluates the module. -require :: Member (Modules address value) effects => ModulePath -> Evaluator address value effects (Maybe (address, Environment address)) +require :: Member (Modules address) effects => ModulePath -> Evaluator address value effects (Maybe (address, Environment address)) require path = lookupModule path >>= maybeM (load path) -- | Load another module by name and return its environment and value. -- -- Always loads/evaluates. -load :: Member (Modules address value) effects => ModulePath -> Evaluator address value effects (Maybe (address, Environment address)) +load :: Member (Modules address) effects => ModulePath -> Evaluator address value effects (Maybe (address, Environment address)) load path = sendModules (Load path) -data Modules address value return where - Load :: ModulePath -> Modules address value (Maybe (address, Environment address)) - Lookup :: ModulePath -> Modules address value (Maybe (Maybe (address, Environment address))) - Resolve :: [FilePath] -> Modules address value (Maybe ModulePath) - List :: FilePath -> Modules address value [ModulePath] +data Modules address return where + Load :: ModulePath -> Modules address (Maybe (address, Environment address)) + Lookup :: ModulePath -> Modules address (Maybe (Maybe (address, Environment address))) + Resolve :: [FilePath] -> Modules address (Maybe ModulePath) + List :: FilePath -> Modules address [ModulePath] -sendModules :: Member (Modules address value) effects => Modules address value return -> Evaluator address value effects return +sendModules :: Member (Modules address) effects => Modules address return -> Evaluator address value effects return sendModules = send runModules :: forall term address value effects a @@ -66,11 +66,11 @@ runModules :: forall term address value effects a , Member (State (ModuleTable (Maybe (address, Environment address)))) effects , Member Trace effects ) - => (Module term -> Evaluator address value (Modules address value ': effects) (Module (address, Environment address))) - -> Evaluator address value (Modules address value ': effects) a + => (Module term -> Evaluator address value (Modules address ': effects) (Module (address, Environment address))) + -> Evaluator address value (Modules address ': effects) a -> Evaluator address value (Reader (ModuleTable (NonEmpty (Module term))) ': effects) a runModules evaluateModule = go - where go :: forall a . Evaluator address value (Modules address value ': effects) a -> Evaluator address value (Reader (ModuleTable (NonEmpty (Module term))) ': effects) a + where go :: forall a . Evaluator address value (Modules address ': effects) a -> Evaluator address value (Reader (ModuleTable (NonEmpty (Module term))) ': effects) a go = reinterpret (\ m -> case m of Load name -> askModuleTable @term >>= maybe (moduleNotFound name) (runMerging . foldMap (Merging . evalAndCache)) . ModuleTable.lookup name where @@ -92,7 +92,7 @@ runModules evaluateModule = go List dir -> modulePathsInDir dir <$> askModuleTable @term) runModules' :: Member (Reader (ModuleTable (NonEmpty (Module (address, Environment address))))) effects - => Evaluator address value (Modules address value ': effects) a + => Evaluator address value (Modules address ': effects) a -> Evaluator address value effects a runModules' = interpret $ \case Load name -> fmap (runMerging' . foldMap1 (Merging' . moduleBody)) . ModuleTable.lookup name <$> askModuleTable' diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 897017730..2ef1f4f8e 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -49,7 +49,7 @@ class Show1 constr => Evaluatable constr where , Member (Allocator address value) effects , Member (Env address) effects , Member (LoopControl address) effects - , Member (Modules address value) effects + , Member (Modules address) effects , Member (Reader ModuleInfo) effects , Member (Reader PackageInfo) effects , Member (Reader Span) effects @@ -65,8 +65,8 @@ class Show1 constr => Evaluatable constr where evaluate :: forall address term value effects - . ( AbstractValue address value (LoopControl address ': Return address ': Env address ': Allocator address value ': Reader ModuleInfo ': Modules address value ': effects) - , Addressable address (Reader ModuleInfo ': Modules address value ': effects) + . ( AbstractValue address value (LoopControl address ': Return address ': Env address ': Allocator address value ': Reader ModuleInfo ': Modules address ': effects) + , Addressable address (Reader ModuleInfo ': Modules address ': effects) , Declarations term , Evaluatable (Base term) , Foldable (Cell address) @@ -131,7 +131,7 @@ evaluatePackageWith :: forall proxy lang address term value inner inner' inner'' , ValueRoots address value , inner ~ (LoopControl address ': Return address ': Env address ': Allocator address value ': inner') , inner' ~ (Reader ModuleInfo ': inner'') - , inner'' ~ (Modules address value ': Reader Span ': Reader PackageInfo ': outer) + , inner'' ~ (Modules address ': Reader Span ': Reader PackageInfo ': outer) ) => proxy lang -> (SubtermAlgebra Module term (TermEvaluator term address value inner address) -> SubtermAlgebra Module term (TermEvaluator term address value inner address)) diff --git a/src/Language/Go/Syntax.hs b/src/Language/Go/Syntax.hs index de0378bf3..75a1e57fc 100644 --- a/src/Language/Go/Syntax.hs +++ b/src/Language/Go/Syntax.hs @@ -27,7 +27,7 @@ importPath str = let path = stripQuotes str in ImportPath (T.unpack path) (pathT defaultAlias :: ImportPath -> Name defaultAlias = name . T.pack . takeFileName . unPath -resolveGoImport :: ( Member (Modules address value) effects +resolveGoImport :: ( Member (Modules address) effects , Member (Reader ModuleInfo) effects , Member (Reader Package.PackageInfo) effects , Member (Resumable ResolutionError) effects diff --git a/src/Language/PHP/Syntax.hs b/src/Language/PHP/Syntax.hs index 254e91223..08a7f1e9c 100644 --- a/src/Language/PHP/Syntax.hs +++ b/src/Language/PHP/Syntax.hs @@ -35,7 +35,7 @@ instance Evaluatable VariableName -- file, the complete contents of the included file are treated as though it -- were defined inside that function. -resolvePHPName :: ( Member (Modules address value) effects +resolvePHPName :: ( Member (Modules address) effects , Member (Resumable ResolutionError) effects ) => T.Text @@ -49,7 +49,7 @@ resolvePHPName n = do include :: ( AbstractValue address value effects , Member (Allocator address value) effects , Member (Env address) effects - , Member (Modules address value) effects + , Member (Modules address) effects , Member (Resumable ResolutionError) effects , Member (Resumable (EnvironmentError address)) effects , Member Trace effects diff --git a/src/Language/Python/Syntax.hs b/src/Language/Python/Syntax.hs index b968fb218..ed8c6e70f 100644 --- a/src/Language/Python/Syntax.hs +++ b/src/Language/Python/Syntax.hs @@ -50,7 +50,7 @@ relativeQualifiedName prefix paths = RelativeQualifiedName (T.unpack prefix) (Ju -- Subsequent imports of `parent.two` or `parent.three` will execute -- `parent/two/__init__.py` and -- `parent/three/__init__.py` respectively. -resolvePythonModules :: ( Member (Modules address value) effects +resolvePythonModules :: ( Member (Modules address) effects , Member (Reader ModuleInfo) effects , Member (Resumable ResolutionError) effects , Member Trace effects @@ -126,7 +126,7 @@ instance Evaluatable Import where evalQualifiedImport :: ( AbstractValue address value effects , Member (Allocator address value) effects , Member (Env address) effects - , Member (Modules address value) effects + , Member (Modules address) effects ) => Name -> ModulePath -> Evaluator address value effects value evalQualifiedImport name path = letrec' name $ \addr -> do diff --git a/src/Language/Ruby/Syntax.hs b/src/Language/Ruby/Syntax.hs index 821eb026f..06edaadc0 100644 --- a/src/Language/Ruby/Syntax.hs +++ b/src/Language/Ruby/Syntax.hs @@ -16,7 +16,7 @@ import System.FilePath.Posix -- TODO: Fully sort out ruby require/load mechanics -- -- require "json" -resolveRubyName :: ( Member (Modules address value) effects +resolveRubyName :: ( Member (Modules address) effects , Member (Resumable ResolutionError) effects ) => Text @@ -28,7 +28,7 @@ resolveRubyName name = do maybeM (throwResumable $ NotFoundError name' paths Language.Ruby) modulePath -- load "/root/src/file.rb" -resolveRubyPath :: ( Member (Modules address value) effects +resolveRubyPath :: ( Member (Modules address) effects , Member (Resumable ResolutionError) effects ) => Text @@ -73,7 +73,7 @@ instance Evaluatable Require where rvalBox v -- Returns True if the file was loaded, False if it was already loaded. http://ruby-doc.org/core-2.5.0/Kernel.html#method-i-require doRequire :: ( AbstractValue address value effects - , Member (Modules address value) effects + , Member (Modules address) effects ) => M.ModulePath -> Evaluator address value effects (value, Environment address) @@ -102,7 +102,7 @@ instance Evaluatable Load where doLoad :: ( AbstractValue address value effects , Member (Env address) effects - , Member (Modules address value) effects + , Member (Modules address) effects , Member (Resumable ResolutionError) effects , Member Trace effects ) diff --git a/src/Language/TypeScript/Syntax.hs b/src/Language/TypeScript/Syntax.hs index c218876e1..ff708fc30 100644 --- a/src/Language/TypeScript/Syntax.hs +++ b/src/Language/TypeScript/Syntax.hs @@ -35,7 +35,7 @@ toName = name . T.pack . unPath -- -- NB: TypeScript has a couple of different strategies, but the main one (and the -- only one we support) mimics Node.js. -resolveWithNodejsStrategy :: ( Member (Modules address value) effects +resolveWithNodejsStrategy :: ( Member (Modules address) effects , Member (Reader M.ModuleInfo) effects , Member (Reader PackageInfo) effects , Member (Resumable ResolutionError) effects @@ -54,7 +54,7 @@ resolveWithNodejsStrategy (ImportPath path NonRelative) exts = resolveNonRelativ -- /root/src/moduleB.ts -- /root/src/moduleB/package.json (if it specifies a "types" property) -- /root/src/moduleB/index.ts -resolveRelativePath :: ( Member (Modules address value) effects +resolveRelativePath :: ( Member (Modules address) effects , Member (Reader M.ModuleInfo) effects , Member (Reader PackageInfo) effects , Member (Resumable ResolutionError) effects @@ -82,7 +82,7 @@ resolveRelativePath relImportPath exts = do -- -- /root/node_modules/moduleB.ts, etc -- /node_modules/moduleB.ts, etc -resolveNonRelativePath :: ( Member (Modules address value) effects +resolveNonRelativePath :: ( Member (Modules address) effects , Member (Reader M.ModuleInfo) effects , Member (Reader PackageInfo) effects , Member (Resumable ResolutionError) effects @@ -107,7 +107,7 @@ resolveNonRelativePath name exts = do notFound xs = throwResumable $ NotFoundError name xs Language.TypeScript -- | Resolve a module name to a ModulePath. -resolveModule :: ( Member (Modules address value) effects +resolveModule :: ( Member (Modules address) effects , Member (Reader PackageInfo) effects , Member Trace effects ) @@ -133,7 +133,7 @@ javascriptExtensions = ["js"] evalRequire :: ( AbstractValue address value effects , Member (Allocator address value) effects , Member (Env address) effects - , Member (Modules address value) effects + , Member (Modules address) effects ) => M.ModulePath -> Name diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index 58cb217b7..ab1b3181d 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -75,7 +75,7 @@ newtype GraphEff address a = GraphEff , Env address , Allocator address (Value address (GraphEff address)) , Reader ModuleInfo - , Modules address (Value address (GraphEff address)) + , Modules address , Reader Span , Reader PackageInfo , State (Graph Vertex) diff --git a/src/Semantic/Util.hs b/src/Semantic/Util.hs index f9834edb9..6d9455d1e 100644 --- a/src/Semantic/Util.hs +++ b/src/Semantic/Util.hs @@ -47,7 +47,7 @@ newtype UtilEff address a = UtilEff , Env address , Allocator address (Value address (UtilEff address)) , Reader ModuleInfo - , Modules address (Value address (UtilEff address)) + , Modules address , Reader Span , Reader PackageInfo , Resumable (ValueError address (UtilEff address)) diff --git a/test/SpecHelpers.hs b/test/SpecHelpers.hs index edf39923b..4450c8e01 100644 --- a/test/SpecHelpers.hs +++ b/test/SpecHelpers.hs @@ -131,7 +131,7 @@ newtype TestEff a = TestEff , Env Precise , Allocator Precise Val , Reader ModuleInfo - , Modules Precise Val + , Modules Precise , Reader Span , Reader PackageInfo , Resumable (ValueError Precise TestEff) From ead0ea3d16e3ac3b4e214c94eca948a128c90175 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 18 Jun 2018 13:21:35 -0400 Subject: [PATCH 025/169] :fire: another redundant effect constraint. --- 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 2ef1f4f8e..19589e97b 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -77,7 +77,6 @@ evaluate :: forall address term value effects , Member (Resumable (AddressError address value)) effects , Member (Resumable (EnvironmentError address)) effects , Member (Resumable EvalError) effects - , Member (Resumable (LoadError address)) effects , Member (Resumable ResolutionError) effects , Member (Resumable (Unspecialized value)) effects , Member (State (Heap address (Cell address) value)) effects From 92295f3b7a25f6252122f4187465a2289d1d4c82 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 18 Jun 2018 15:26:29 -0400 Subject: [PATCH 026/169] :fire: a couple of redundant signatures. --- src/Data/Abstract/Evaluatable.hs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 24d343add..f7be62c78 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -161,16 +161,12 @@ evaluatePackageWith lang analyzeModule analyzeTerm package . raiseHandler runReturn . raiseHandler runLoopControl - evaluateEntryPoint :: Environment address -> ModulePath -> Maybe Name -> TermEvaluator term address value inner'' (address, Environment address) evaluateEntryPoint preludeEnv m sym = runInModule preludeEnv (ModuleInfo m) . TermEvaluator $ do addr <- box unit -- TODO don't *always* allocate - use maybeM instead (ptr, env) <- fromMaybe (addr, lowerBound) <$> require m bindAll env maybe (pure ptr) ((`call` []) <=< deref <=< variable) sym - withPrelude :: Package term - -> (Environment address -> TermEvaluator term address value (Reader (ModuleTable (NonEmpty (Module term))) ': Reader Span ': Reader PackageInfo ': outer) a) - -> TermEvaluator term address value (Reader (ModuleTable (NonEmpty (Module term))) ': Reader Span ': Reader PackageInfo ': outer) a withPrelude _ f = do (_, preludeEnv) <- raiseHandler (runModules (runTermEvaluator . evalModule lowerBound)) . runInModule lowerBound moduleInfoFromCallStack . TermEvaluator $ do defineBuiltins From daf4e9195921b6e2f121bf733aa1b4ac0fa9a38f Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 18 Jun 2018 15:27:15 -0400 Subject: [PATCH 027/169] :fire: ScopedTypeVariables :tada: --- src/Data/Abstract/Evaluatable.hs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index f7be62c78..3e39183c3 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE GADTs, KindSignatures, RankNTypes, ScopedTypeVariables, TypeOperators, UndecidableInstances #-} +{-# LANGUAGE GADTs, KindSignatures, RankNTypes, TypeOperators, UndecidableInstances #-} module Data.Abstract.Evaluatable ( module X , Evaluatable(..) @@ -64,8 +64,7 @@ class Show1 constr => Evaluatable constr where eval expr = rvalBox =<< throwResumable (Unspecialized ("Eval unspecialized for " ++ liftShowsPrec (const (const id)) (const id) 0 expr "")) -evaluate :: forall address term value effects - . ( AbstractValue address value (LoopControl address ': Return address ': Env address ': Allocator address value ': Reader ModuleInfo ': Modules address ': effects) +evaluate :: ( AbstractValue address value (LoopControl address ': Return address ': Env address ': Allocator address value ': Reader ModuleInfo ': Modules address ': effects) , Addressable address (Reader ModuleInfo ': Modules address ': effects) , Declarations term , Evaluatable (Base term) @@ -106,8 +105,7 @@ evaluate (modules : rest) local (<> ModuleTable.fromModules (toList results)) (evaluate rest) -- | Evaluate a given package. -evaluatePackageWith :: forall proxy lang address term value inner inner' inner'' outer - . ( AbstractValue address value inner +evaluatePackageWith :: ( AbstractValue address value inner -- FIXME: It’d be nice if we didn’t have to mention 'Addressable' here at all, but 'Located' locations require knowledge of 'currentModule' to run. Can we fix that? , Addressable address inner' , Declarations term From 5a9ea5e61babab3a40807d8464bea28eb7da969b Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Tue, 19 Jun 2018 12:47:11 -0400 Subject: [PATCH 028/169] Add a convenience to compute the keys in a Monoidal Map. --- src/Data/Map/Monoidal.hs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Data/Map/Monoidal.hs b/src/Data/Map/Monoidal.hs index 34192cb2b..0c1a64d65 100644 --- a/src/Data/Map/Monoidal.hs +++ b/src/Data/Map/Monoidal.hs @@ -8,6 +8,7 @@ module Data.Map.Monoidal , insert , filterWithKey , pairs +, keys , module Reducer ) where @@ -41,6 +42,9 @@ filterWithKey f = Map . Map.filterWithKey f . unMap pairs :: Map key value -> [(key, value)] pairs = Map.toList . unMap +keys :: Map key value -> [key] +keys = Map.keys . unMap + instance (Ord key, Semigroup value) => Semigroup (Map key value) where Map a <> Map b = Map (Map.unionWith (<>) a b) From 1bdb613edda742a195dcc8cbe977aff920cb0bf9 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Tue, 19 Jun 2018 12:49:51 -0400 Subject: [PATCH 029/169] Vertices are initially zero, rather than unset. --- src/Data/Graph.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Data/Graph.hs b/src/Data/Graph.hs index 2d196e481..bce5d666e 100644 --- a/src/Data/Graph.hs +++ b/src/Data/Graph.hs @@ -39,7 +39,7 @@ labelWithInEdgeCounts = uncurry mapGraph . Class.foldg (lowerBound, lowerBound) - ((,) lowerBound . Class.vertex) + ((,) . flip Monoidal.singleton 0 <*> Class.vertex) (<>) (\ (outM, outG) (inM, inG) -> ( outM <> inM <> foldMap (flip Monoidal.singleton (Monoid.Sum (length outG))) (allVertices inG) From 3451a0c264e42f228d8f4db09eb857db96de4fa2 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Tue, 19 Jun 2018 12:49:59 -0400 Subject: [PATCH 030/169] Get the vertices from the map. --- src/Data/Graph.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Data/Graph.hs b/src/Data/Graph.hs index bce5d666e..0f9b11f95 100644 --- a/src/Data/Graph.hs +++ b/src/Data/Graph.hs @@ -42,7 +42,7 @@ labelWithInEdgeCounts ((,) . flip Monoidal.singleton 0 <*> Class.vertex) (<>) (\ (outM, outG) (inM, inG) -> - ( outM <> inM <> foldMap (flip Monoidal.singleton (Monoid.Sum (length outG))) (allVertices inG) + ( outM <> inM <> foldMap (flip Monoidal.singleton (Monoid.Sum (length outG))) (Monoidal.keys inM) , outG `Class.connect` inG )) where mapGraph edgeCountsByVertex g = pairWithCountIn edgeCountsByVertex <$> g From 5bfa7f632685a50544174b4a60599a6c957afbf5 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Tue, 19 Jun 2018 12:57:59 -0400 Subject: [PATCH 031/169] Simplify the topological sort by returning the map. --- src/Data/Graph.hs | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/src/Data/Graph.hs b/src/Data/Graph.hs index 0f9b11f95..afdb64695 100644 --- a/src/Data/Graph.hs +++ b/src/Data/Graph.hs @@ -12,7 +12,7 @@ module Data.Graph import qualified Algebra.Graph as G import qualified Algebra.Graph.Class as Class import Data.Aeson -import Data.List (groupBy, nub, sortBy) +import Data.List (groupBy, sortBy) import qualified Data.List.NonEmpty as NonEmpty (fromList) import qualified Data.Map.Monoidal as Monoidal import qualified Data.Monoid as Monoid @@ -31,28 +31,18 @@ simplify (Graph graph) = Graph (G.simplify graph) topologicalSort :: Ord v => Graph v -> [NonEmpty v] topologicalSort = groupByInEdgeCount - . allVertices - . labelWithInEdgeCounts + . Monoidal.pairs + . edgeCountsByVertex -labelWithInEdgeCounts :: Ord v => Graph v -> Graph (Monoid.Sum Int, v) -labelWithInEdgeCounts - = uncurry mapGraph - . Class.foldg - (lowerBound, lowerBound) - ((,) . flip Monoidal.singleton 0 <*> Class.vertex) - (<>) - (\ (outM, outG) (inM, inG) -> - ( outM <> inM <> foldMap (flip Monoidal.singleton (Monoid.Sum (length outG))) (Monoidal.keys inM) - , outG `Class.connect` inG - )) - where mapGraph edgeCountsByVertex g = pairWithCountIn edgeCountsByVertex <$> g - pairWithCountIn edgeCountsByVertex vertex = (fromMaybe 0 (Monoidal.lookup vertex edgeCountsByVertex), vertex) +edgeCountsByVertex :: Ord v => Graph v -> Monoidal.Map v (Monoid.Sum Int) +edgeCountsByVertex = Class.foldg + lowerBound + (flip Monoidal.singleton 0) + (<>) + (\ outM inM -> outM <> inM <> foldMap (flip Monoidal.singleton (Monoid.Sum (length outM))) (Monoidal.keys inM)) -allVertices :: Eq v => Graph v -> [v] -allVertices = nub . toList - -groupByInEdgeCount :: Ord sum => [(sum, v)] -> [NonEmpty v] -groupByInEdgeCount = map (NonEmpty.fromList . map snd) . groupBy ((==) `on` fst) . sortBy (comparing fst) +groupByInEdgeCount :: Ord sum => [(v, sum)] -> [NonEmpty v] +groupByInEdgeCount = map (NonEmpty.fromList . map fst) . groupBy ((==) `on` snd) . sortBy (comparing snd) instance Lower (Graph vertex) where From 2211013c40e3cc42f400bb05537f1a7a1112ada3 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Tue, 19 Jun 2018 13:37:02 -0400 Subject: [PATCH 032/169] =?UTF-8?q?withPrelude=20doesn=E2=80=99t=20need=20?= =?UTF-8?q?to=20take=20the=20package.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Data/Abstract/Evaluatable.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 6f5964317..845fb7da6 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -139,7 +139,7 @@ evaluatePackageWith lang analyzeModule analyzeTerm package = runReader (packageInfo package) . runReader lowerBound . runReader (packageModules (packageBody package)) - . withPrelude package + . withPrelude $ \ preludeEnv -> raiseHandler (runModules (runTermEvaluator . evalModule preludeEnv)) . traverse (uncurry (evaluateEntryPoint preludeEnv)) @@ -165,7 +165,7 @@ evaluatePackageWith lang analyzeModule analyzeTerm package bindAll env maybe (pure ptr) ((`call` []) <=< deref <=< variable) sym - withPrelude _ f = do + withPrelude f = do (_, preludeEnv) <- raiseHandler (runModules (runTermEvaluator . evalModule lowerBound)) . runInModule lowerBound moduleInfoFromCallStack . TermEvaluator $ do defineBuiltins definePrelude lang From 001127b54b5f750913fd444149e69b028f3e3ad2 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Tue, 19 Jun 2018 13:37:10 -0400 Subject: [PATCH 033/169] Pass evalModule a preludeEnv. --- src/Data/Abstract/Evaluatable.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 845fb7da6..371b36426 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -90,12 +90,12 @@ evaluate [] = ask evaluate (modules : rest) = runRest rest . runModules' - $ traverse evalModule modules - where evalModule m + $ traverse (evalModule lowerBound) modules + where evalModule preludeEnv m = fmap (<$ m) . runReader (moduleInfo m) . runAllocator - . runEnv lowerBound + . runEnv preludeEnv . runReturn . runLoopControl $ foldSubterms eval (moduleBody m) >>= address From a00d59eeb2b4477eb24092712287a319459bcf16 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Tue, 19 Jun 2018 13:38:08 -0400 Subject: [PATCH 034/169] Stub in a withPrelude function. --- src/Data/Abstract/Evaluatable.hs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 371b36426..bea0bc736 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -90,7 +90,8 @@ evaluate [] = ask evaluate (modules : rest) = runRest rest . runModules' - $ traverse (evalModule lowerBound) modules + . withPrelude $ \ preludeEnv -> + traverse (evalModule preludeEnv) modules where evalModule preludeEnv m = fmap (<$ m) . runReader (moduleInfo m) @@ -100,6 +101,9 @@ evaluate (modules : rest) . runLoopControl $ foldSubterms eval (moduleBody m) >>= address + withPrelude f = do + f lowerBound + runRest rest action = do results <- action local (<> ModuleTable.fromModules (toList results)) (evaluate rest) From f4186ba26694340886092b3a244467e899ef6925 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Tue, 19 Jun 2018 13:38:54 -0400 Subject: [PATCH 035/169] Extract a runInModule helper. --- src/Data/Abstract/Evaluatable.hs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index bea0bc736..aadc5b1b9 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -94,12 +94,15 @@ evaluate (modules : rest) traverse (evalModule preludeEnv) modules where evalModule preludeEnv m = fmap (<$ m) - . runReader (moduleInfo m) + . runInModule preludeEnv m + $ foldSubterms eval (moduleBody m) >>= address + + runInModule preludeEnv m + = runReader (moduleInfo m) . runAllocator . runEnv preludeEnv . runReturn . runLoopControl - $ foldSubterms eval (moduleBody m) >>= address withPrelude f = do f lowerBound From a233b39ae38c2cb5a2328a6ade5e875026a45b1c Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Tue, 19 Jun 2018 13:50:56 -0400 Subject: [PATCH 036/169] Define builtins & preludes in evaluate. --- src/Data/Abstract/Evaluatable.hs | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index aadc5b1b9..30dacfd6e 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -70,6 +70,8 @@ evaluate :: ( AbstractValue address value (LoopControl address ': Return address , Evaluatable (Base term) , Foldable (Cell address) , FreeVariables term + , HasPrelude lang + , Member Fresh effects , Member (Reader (ModuleTable (NonEmpty (Module (address, Environment address))))) effects , Member (Reader PackageInfo) effects , Member (Reader Span) effects @@ -84,32 +86,37 @@ evaluate :: ( AbstractValue address value (LoopControl address ': Return address , Reducer value (Cell address value) , ValueRoots address value ) - => [NonEmpty (Module term)] + => proxy lang + -> [NonEmpty (Module term)] -> Evaluator address value effects (ModuleTable (NonEmpty (Module (address, Environment address)))) -evaluate [] = ask -evaluate (modules : rest) - = runRest rest +evaluate _ [] = ask +evaluate lang (modules : rest) + = runRest lang rest . runModules' . withPrelude $ \ preludeEnv -> traverse (evalModule preludeEnv) modules where evalModule preludeEnv m = fmap (<$ m) - . runInModule preludeEnv m + . runInModule preludeEnv (moduleInfo m) $ foldSubterms eval (moduleBody m) >>= address - runInModule preludeEnv m - = runReader (moduleInfo m) + runInModule preludeEnv info + = runReader info . runAllocator . runEnv preludeEnv . runReturn . runLoopControl withPrelude f = do - f lowerBound + (_, preludeEnv) <- runInModule lowerBound moduleInfoFromCallStack $ do + defineBuiltins + definePrelude lang + box unit + f preludeEnv - runRest rest action = do + runRest lang rest action = do results <- action - local (<> ModuleTable.fromModules (toList results)) (evaluate rest) + local (<> ModuleTable.fromModules (toList results)) (evaluate lang rest) -- | Evaluate a given package. evaluatePackageWith :: ( AbstractValue address value inner From 2df8880e4e14903385d17bd1c226204821e23cc2 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Tue, 19 Jun 2018 14:42:54 -0400 Subject: [PATCH 037/169] Pass the analysis functions to evaluate. --- src/Data/Abstract/Evaluatable.hs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 30dacfd6e..ac6e1f6ce 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -32,6 +32,7 @@ import Data.Abstract.ModuleTable as ModuleTable import Data.Abstract.Name as X import Data.Abstract.Package as Package import Data.Abstract.Ref as X +import Data.Coerce import Data.Language import Data.Scientific (Scientific) import Data.Semigroup.App @@ -64,7 +65,7 @@ class Show1 constr => Evaluatable constr where eval expr = rvalBox =<< throwResumable (Unspecialized ("Eval unspecialized for " ++ liftShowsPrec (const (const id)) (const id) 0 expr "")) -evaluate :: ( AbstractValue address value (LoopControl address ': Return address ': Env address ': Allocator address value ': Reader ModuleInfo ': Modules address ': effects) +evaluate :: ( AbstractValue address value inner , Addressable address (Reader ModuleInfo ': Modules address ': effects) , Declarations term , Evaluatable (Base term) @@ -85,20 +86,26 @@ evaluate :: ( AbstractValue address value (LoopControl address ': Return address , Recursive term , Reducer value (Cell address value) , ValueRoots address value + , inner ~ (LoopControl address ': Return address ': Env address ': Allocator address value ': Reader ModuleInfo ': Modules address ': effects) ) => proxy lang + -> (SubtermAlgebra Module term (TermEvaluator term address value inner address) -> SubtermAlgebra Module term (TermEvaluator term address value inner address)) + -> (SubtermAlgebra (Base term) term (TermEvaluator term address value inner (ValueRef address)) -> SubtermAlgebra (Base term) term (TermEvaluator term address value inner (ValueRef address))) -> [NonEmpty (Module term)] - -> Evaluator address value effects (ModuleTable (NonEmpty (Module (address, Environment address)))) -evaluate _ [] = ask -evaluate lang (modules : rest) + -> TermEvaluator term address value effects (ModuleTable (NonEmpty (Module (address, Environment address)))) +evaluate _ _ _ [] = ask +evaluate lang analyzeModule analyzeTerm (modules : rest) = runRest lang rest - . runModules' + . raiseHandler runModules' . withPrelude $ \ preludeEnv -> traverse (evalModule preludeEnv) modules where evalModule preludeEnv m = fmap (<$ m) - . runInModule preludeEnv (moduleInfo m) - $ foldSubterms eval (moduleBody m) >>= address + . coerce (runInModule preludeEnv (moduleInfo m)) + . analyzeModule (subtermRef . moduleBody) + $ evalTerm <$> m + + evalTerm term = Subterm term (TermEvaluator (address =<< runTermEvaluator (foldSubterms (analyzeTerm (TermEvaluator . eval . fmap (second runTermEvaluator))) term))) runInModule preludeEnv info = runReader info @@ -108,7 +115,7 @@ evaluate lang (modules : rest) . runLoopControl withPrelude f = do - (_, preludeEnv) <- runInModule lowerBound moduleInfoFromCallStack $ do + (_, preludeEnv) <- TermEvaluator . runInModule lowerBound moduleInfoFromCallStack $ do defineBuiltins definePrelude lang box unit @@ -116,7 +123,7 @@ evaluate lang (modules : rest) runRest lang rest action = do results <- action - local (<> ModuleTable.fromModules (toList results)) (evaluate lang rest) + local (<> ModuleTable.fromModules (toList results)) (evaluate lang analyzeModule analyzeTerm rest) -- | Evaluate a given package. evaluatePackageWith :: ( AbstractValue address value inner From 0fe868b38f853e12642a73763b8f1a265a9b2ff2 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Tue, 19 Jun 2018 14:45:38 -0400 Subject: [PATCH 038/169] Close over the analysis functions. --- src/Data/Abstract/Evaluatable.hs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index ac6e1f6ce..577f0a66a 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -93,13 +93,15 @@ evaluate :: ( AbstractValue address value inner -> (SubtermAlgebra (Base term) term (TermEvaluator term address value inner (ValueRef address)) -> SubtermAlgebra (Base term) term (TermEvaluator term address value inner (ValueRef address))) -> [NonEmpty (Module term)] -> TermEvaluator term address value effects (ModuleTable (NonEmpty (Module (address, Environment address)))) -evaluate _ _ _ [] = ask -evaluate lang analyzeModule analyzeTerm (modules : rest) - = runRest lang rest - . raiseHandler runModules' - . withPrelude $ \ preludeEnv -> - traverse (evalModule preludeEnv) modules - where evalModule preludeEnv m +evaluate lang analyzeModule analyzeTerm = go + where go [] = ask + go (modules : rest) + = runRest lang rest + . raiseHandler runModules' + . withPrelude $ \ preludeEnv -> + traverse (evalModule preludeEnv) modules + + evalModule preludeEnv m = fmap (<$ m) . coerce (runInModule preludeEnv (moduleInfo m)) . analyzeModule (subtermRef . moduleBody) @@ -123,7 +125,7 @@ evaluate lang analyzeModule analyzeTerm (modules : rest) runRest lang rest action = do results <- action - local (<> ModuleTable.fromModules (toList results)) (evaluate lang analyzeModule analyzeTerm rest) + local (<> ModuleTable.fromModules (toList results)) (go rest) -- | Evaluate a given package. evaluatePackageWith :: ( AbstractValue address value inner From f17bfbcf7778b6cd99c0044b8f5fff2c6fb1b0e1 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Tue, 19 Jun 2018 14:47:39 -0400 Subject: [PATCH 039/169] Close over the proxy. --- src/Data/Abstract/Evaluatable.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index f3467c5a1..5f02fa8d5 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -96,7 +96,7 @@ evaluate :: ( AbstractValue address value inner evaluate lang analyzeModule analyzeTerm = go where go [] = ask go (modules : rest) - = runRest lang rest + = runRest rest . raiseHandler runModules' . withPrelude $ \ preludeEnv -> traverse (evalModule preludeEnv) modules @@ -123,7 +123,7 @@ evaluate lang analyzeModule analyzeTerm = go box unit f preludeEnv - runRest lang rest action = do + runRest rest action = do results <- action local (<> ModuleTable.fromModules (toList results)) (go rest) From d457248da6f8fa4006e57d72d355ba5b476c14b3 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Tue, 19 Jun 2018 14:54:22 -0400 Subject: [PATCH 040/169] Define evaluate as a fold. --- src/Data/Abstract/Evaluatable.hs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 5f02fa8d5..7a4449ffa 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -93,13 +93,11 @@ evaluate :: ( AbstractValue address value inner -> (SubtermAlgebra (Base term) term (TermEvaluator term address value inner (ValueRef address)) -> SubtermAlgebra (Base term) term (TermEvaluator term address value inner (ValueRef address))) -> [NonEmpty (Module term)] -> TermEvaluator term address value effects (ModuleTable (NonEmpty (Module (address, Environment address)))) -evaluate lang analyzeModule analyzeTerm = go - where go [] = ask - go (modules : rest) - = runRest rest - . raiseHandler runModules' - . withPrelude $ \ preludeEnv -> +evaluate lang analyzeModule analyzeTerm = foldr run ask + where run modules rest = do + evaluated <- raiseHandler runModules' . withPrelude $ \ preludeEnv -> traverse (evalModule preludeEnv) modules + local (<> ModuleTable.fromModules (toList evaluated)) rest evalModule preludeEnv m = fmap (<$ m) @@ -123,10 +121,6 @@ evaluate lang analyzeModule analyzeTerm = go box unit f preludeEnv - runRest rest action = do - results <- action - local (<> ModuleTable.fromModules (toList results)) (go rest) - -- | Evaluate a given package. evaluatePackageWith :: ( AbstractValue address value inner -- FIXME: It’d be nice if we didn’t have to mention 'Addressable' here at all, but 'Located' locations require knowledge of 'currentModule' to run. Can we fix that? From 3933b6472080f4917f87a87120ffd11276288703 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Tue, 19 Jun 2018 14:54:57 -0400 Subject: [PATCH 041/169] Inline withPrelude. --- src/Data/Abstract/Evaluatable.hs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 7a4449ffa..24a02af17 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -95,7 +95,11 @@ evaluate :: ( AbstractValue address value inner -> TermEvaluator term address value effects (ModuleTable (NonEmpty (Module (address, Environment address)))) evaluate lang analyzeModule analyzeTerm = foldr run ask where run modules rest = do - evaluated <- raiseHandler runModules' . withPrelude $ \ preludeEnv -> + evaluated <- raiseHandler runModules' $ do + (_, preludeEnv) <- TermEvaluator . runInModule lowerBound moduleInfoFromCallStack $ do + defineBuiltins + definePrelude lang + box unit traverse (evalModule preludeEnv) modules local (<> ModuleTable.fromModules (toList evaluated)) rest @@ -114,13 +118,6 @@ evaluate lang analyzeModule analyzeTerm = foldr run ask . runReturn . runLoopControl - withPrelude f = do - (_, preludeEnv) <- TermEvaluator . runInModule lowerBound moduleInfoFromCallStack $ do - defineBuiltins - definePrelude lang - box unit - f preludeEnv - -- | Evaluate a given package. evaluatePackageWith :: ( AbstractValue address value inner -- FIXME: It’d be nice if we didn’t have to mention 'Addressable' here at all, but 'Located' locations require knowledge of 'currentModule' to run. Can we fix that? From efdd37e6841d920b8855824e7a982e65479b4aae Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Tue, 19 Jun 2018 15:03:55 -0400 Subject: [PATCH 042/169] Only evaluate the builtins and prelude once. --- src/Data/Abstract/Evaluatable.hs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 24a02af17..43de619c8 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -93,14 +93,14 @@ evaluate :: ( AbstractValue address value inner -> (SubtermAlgebra (Base term) term (TermEvaluator term address value inner (ValueRef address)) -> SubtermAlgebra (Base term) term (TermEvaluator term address value inner (ValueRef address))) -> [NonEmpty (Module term)] -> TermEvaluator term address value effects (ModuleTable (NonEmpty (Module (address, Environment address)))) -evaluate lang analyzeModule analyzeTerm = foldr run ask - where run modules rest = do - evaluated <- raiseHandler runModules' $ do - (_, preludeEnv) <- TermEvaluator . runInModule lowerBound moduleInfoFromCallStack $ do - defineBuiltins - definePrelude lang - box unit - traverse (evalModule preludeEnv) modules +evaluate lang analyzeModule analyzeTerm modules = do + (_, preludeEnv) <- TermEvaluator . runModules' . runInModule lowerBound moduleInfoFromCallStack $ do + defineBuiltins + definePrelude lang + box unit + foldr (run preludeEnv) ask modules + where run preludeEnv modules rest = do + evaluated <- raiseHandler runModules' $ traverse (evalModule preludeEnv) modules local (<> ModuleTable.fromModules (toList evaluated)) rest evalModule preludeEnv m From d7a55fd1c37beb380b3ed2d822d3a8ab40e63b4e Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Tue, 19 Jun 2018 15:13:35 -0400 Subject: [PATCH 043/169] Factor the Modules effect handler out. --- src/Data/Abstract/Evaluatable.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 43de619c8..343fec917 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -93,14 +93,14 @@ evaluate :: ( AbstractValue address value inner -> (SubtermAlgebra (Base term) term (TermEvaluator term address value inner (ValueRef address)) -> SubtermAlgebra (Base term) term (TermEvaluator term address value inner (ValueRef address))) -> [NonEmpty (Module term)] -> TermEvaluator term address value effects (ModuleTable (NonEmpty (Module (address, Environment address)))) -evaluate lang analyzeModule analyzeTerm modules = do - (_, preludeEnv) <- TermEvaluator . runModules' . runInModule lowerBound moduleInfoFromCallStack $ do +evaluate lang analyzeModule analyzeTerm modules = raiseHandler runModules' $ do + (_, preludeEnv) <- TermEvaluator . runInModule lowerBound moduleInfoFromCallStack $ do defineBuiltins definePrelude lang box unit foldr (run preludeEnv) ask modules where run preludeEnv modules rest = do - evaluated <- raiseHandler runModules' $ traverse (evalModule preludeEnv) modules + evaluated <- traverse (evalModule preludeEnv) modules local (<> ModuleTable.fromModules (toList evaluated)) rest evalModule preludeEnv m From e92c68913906c6e28eb21348d40be4876505ea58 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Tue, 19 Jun 2018 15:24:07 -0400 Subject: [PATCH 044/169] Factor the Modules effect out of evaluate. --- src/Data/Abstract/Evaluatable.hs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 343fec917..16a816319 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -66,13 +66,14 @@ class Show1 constr => Evaluatable constr where evaluate :: ( AbstractValue address value inner - , Addressable address (Reader ModuleInfo ': Modules address ': effects) + , Addressable address (Reader ModuleInfo ': effects) , Declarations term , Evaluatable (Base term) , Foldable (Cell address) , FreeVariables term , HasPrelude lang , Member Fresh effects + , Member (Modules address) effects , Member (Reader (ModuleTable (NonEmpty (Module (address, Environment address))))) effects , Member (Reader PackageInfo) effects , Member (Reader Span) effects @@ -86,14 +87,14 @@ evaluate :: ( AbstractValue address value inner , Recursive term , Reducer value (Cell address value) , ValueRoots address value - , inner ~ (LoopControl address ': Return address ': Env address ': Allocator address value ': Reader ModuleInfo ': Modules address ': effects) + , inner ~ (LoopControl address ': Return address ': Env address ': Allocator address value ': Reader ModuleInfo ': effects) ) => proxy lang -> (SubtermAlgebra Module term (TermEvaluator term address value inner address) -> SubtermAlgebra Module term (TermEvaluator term address value inner address)) -> (SubtermAlgebra (Base term) term (TermEvaluator term address value inner (ValueRef address)) -> SubtermAlgebra (Base term) term (TermEvaluator term address value inner (ValueRef address))) -> [NonEmpty (Module term)] -> TermEvaluator term address value effects (ModuleTable (NonEmpty (Module (address, Environment address)))) -evaluate lang analyzeModule analyzeTerm modules = raiseHandler runModules' $ do +evaluate lang analyzeModule analyzeTerm modules = do (_, preludeEnv) <- TermEvaluator . runInModule lowerBound moduleInfoFromCallStack $ do defineBuiltins definePrelude lang From 94dd99c2236b616b61d23d68eedb8f20eb0368ff Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Tue, 19 Jun 2018 15:29:26 -0400 Subject: [PATCH 045/169] Simplify the wrapping/unwrapping. --- src/Data/Abstract/Evaluatable.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 16a816319..bf836592b 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -110,7 +110,7 @@ evaluate lang analyzeModule analyzeTerm modules = do . analyzeModule (subtermRef . moduleBody) $ evalTerm <$> m - evalTerm term = Subterm term (TermEvaluator (address =<< runTermEvaluator (foldSubterms (analyzeTerm (TermEvaluator . eval . fmap (second runTermEvaluator))) term))) + evalTerm term = Subterm term (foldSubterms (analyzeTerm (TermEvaluator . eval . fmap (second runTermEvaluator))) term >>= TermEvaluator . address) runInModule preludeEnv info = runReader info From ef70595e9f0c756b20cdad40ba51c1001e5bbac2 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Tue, 19 Jun 2018 17:12:02 -0400 Subject: [PATCH 046/169] Extract a synonym for the classes necessary for analysis. --- src/Semantic/Graph.hs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index ab1b3181d..eaab6d51c 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -38,14 +38,15 @@ import Semantic.Task as Task data GraphType = ImportGraph | CallGraph +type AnalysisClasses = '[ Declarations1, Eq1, Evaluatable, FreeVariables1, Functor, Ord1, Show1 ] + runGraph :: ( Member (Distribute WrappedTask) effs, Member Resolution effs, Member Task effs, Member Trace effs) => GraphType -> Bool -> Project -> Eff effs (Graph Vertex) runGraph graphType includePackages project - | SomeAnalysisParser parser lang <- someAnalysisParser - (Proxy :: Proxy '[ Evaluatable, Declarations1, FreeVariables1, Functor, Eq1, Ord1, Show1 ]) (projectLanguage project) = do + | SomeAnalysisParser parser lang <- someAnalysisParser (Proxy :: Proxy AnalysisClasses) (projectLanguage project) = do package <- parsePackage parser project let analyzeTerm = withTermSpans . case graphType of ImportGraph -> id From 8c175b52b8cfa184b4bf7d266ad102d6a9518909 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Tue, 19 Jun 2018 17:13:28 -0400 Subject: [PATCH 047/169] Export evaluate. --- src/Data/Abstract/Evaluatable.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index bf836592b..d7c0907d6 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -2,6 +2,7 @@ module Data.Abstract.Evaluatable ( module X , Evaluatable(..) +, evaluate , evaluatePackageWith , traceResolve -- * Preludes From 66d9f0b88784e91c5b8614ef9a11bf45b3fe8044 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Tue, 19 Jun 2018 17:15:59 -0400 Subject: [PATCH 048/169] Redefine runModules' as handleModules. --- src/Control/Abstract/Modules.hs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Control/Abstract/Modules.hs b/src/Control/Abstract/Modules.hs index de4a7d829..885e8f8f2 100644 --- a/src/Control/Abstract/Modules.hs +++ b/src/Control/Abstract/Modules.hs @@ -7,7 +7,7 @@ module Control.Abstract.Modules , load , Modules(..) , runModules -, runModules' +, handleModules , LoadError(..) , moduleNotFound , resumeLoadError @@ -91,10 +91,10 @@ runModules evaluateModule = go pure (find isMember names) List dir -> modulePathsInDir dir <$> askModuleTable @term) -runModules' :: Member (Reader (ModuleTable (NonEmpty (Module (address, Environment address))))) effects - => Evaluator address value (Modules address ': effects) a - -> Evaluator address value effects a -runModules' = interpret $ \case +handleModules :: Member (Reader (ModuleTable (NonEmpty (Module (address, Environment address))))) effects + => Modules address a + -> Evaluator address value effects a +handleModules = \case Load name -> fmap (runMerging' . foldMap1 (Merging' . moduleBody)) . ModuleTable.lookup name <$> askModuleTable' Lookup path -> fmap (Just . runMerging' . foldMap1 (Merging' . moduleBody)) . ModuleTable.lookup path <$> askModuleTable' Resolve names -> do From bff7700357c67a3dfc69ae159eb445fdc1f911c1 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Tue, 19 Jun 2018 17:18:24 -0400 Subject: [PATCH 049/169] Simplify extractGraph. --- src/Semantic/Graph.hs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index eaab6d51c..5aa582950 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -52,9 +52,8 @@ runGraph graphType includePackages project ImportGraph -> id CallGraph -> graphingTerms analyzeModule = (if includePackages then graphingPackages else id) . graphingModules - analyze runGraphAnalysis (evaluatePackageWith lang analyzeModule analyzeTerm package) >>= extractGraph - where extractGraph result = case result of - (((_, graph), _), _) -> pure (simplify graph) + extractGraph <$> analyze runGraphAnalysis (evaluatePackageWith lang analyzeModule analyzeTerm package) + where extractGraph (((_, graph), _), _) = simplify graph runGraphAnalysis = run . evaluating From 0f107ca2b1b2b958911d410c5fd48a2ba3d35b4f Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 20 Jun 2018 10:12:04 -0400 Subject: [PATCH 050/169] Define a new function to compute import graphs. --- src/Semantic/Graph.hs | 61 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index 5aa582950..bf710b077 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -1,10 +1,12 @@ -{-# LANGUAGE GADTs, TypeOperators #-} +{-# LANGUAGE GADTs, ScopedTypeVariables, TypeOperators #-} module Semantic.Graph ( runGraph +, runImportGraph , GraphType(..) , Graph , Vertex , GraphEff(..) +, ImportGraphEff(..) , style , parsePackage , withTermSpans @@ -26,6 +28,7 @@ import Data.Abstract.Evaluatable import Data.Abstract.Module import Data.Abstract.Package as Package import Data.Abstract.Value (Value, ValueError (..), runValueErrorWith) +import Data.AST (Location) import Data.Graph import Data.Project import Data.Record @@ -93,6 +96,62 @@ newtype GraphEff address a = GraphEff ] a } + +runImportGraph :: ( Member (Distribute WrappedTask) effs, Member Resolution effs, Member Task effs, Member Trace effs) + => Project + -> Eff effs (Graph (Module (SomeTerm AnalysisClasses (Record Location)))) +runImportGraph project + | SomeAnalysisParser (parser :: Parser (Term (Sum syntaxes) (Record Location))) lang <- someAnalysisParser (Proxy :: Proxy AnalysisClasses) (projectLanguage project) = do + package <- parsePackage parser project + let analyzeTerm = id + analyzeModule = id + extractGraph (((_, graph), _), _) = fmap SomeTerm <$> graph + runImportGraphAnalysis packageInfo + = run + . runState lowerBound + . runFresh 0 + . runIgnoringTrace + . resumingLoadError + . resumingUnspecialized + . resumingEnvironmentError + . resumingEvalError + . resumingResolutionError + . resumingAddressError + . resumingValueError + . runReader lowerBound + . interpret handleModules + . runTermEvaluator @_ @_ @(Value (Hole Precise) (ImportGraphEff (Term (Sum syntaxes) (Record Location)) (Hole Precise))) + . runState lowerBound + . runReader packageInfo + . runReader lowerBound + extractGraph <$> analyze (runImportGraphAnalysis (packageInfo package)) (evaluate @_ @_ @_ @_ @(Term (Sum syntaxes) (Record Location)) lang analyzeModule analyzeTerm []) + +newtype ImportGraphEff term address a = ImportGraphEff + { runImportGraphEff :: Eff '[ LoopControl address + , Return address + , Env address + , Allocator address (Value address (ImportGraphEff term address)) + , Reader ModuleInfo + , Reader Span + , Reader PackageInfo + , State (Graph (Module term)) + , Modules address + , Reader (ModuleTable (NonEmpty (Module (address, Environment address)))) + , Resumable (ValueError address (ImportGraphEff term address)) + , Resumable (AddressError address (Value address (ImportGraphEff term address))) + , Resumable ResolutionError + , Resumable EvalError + , Resumable (EnvironmentError address) + , Resumable (Unspecialized (Value address (ImportGraphEff term address))) + , Resumable (LoadError address) + , Trace + , Fresh + , State (Heap address Latest (Value address (ImportGraphEff term address))) + ] a + } + + + -- | Parse a list of files into a 'Package'. parsePackage :: (Member (Distribute WrappedTask) effs, Member Resolution effs, Member Trace effs) => Parser term -- ^ A parser. From 4352f1866e79c820c680acb21f15f2cc317ce68d Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 20 Jun 2018 10:18:31 -0400 Subject: [PATCH 051/169] Move the graph state after the modules effect. --- src/Semantic/Graph.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index bf710b077..5adc2673e 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -118,10 +118,10 @@ runImportGraph project . resumingResolutionError . resumingAddressError . resumingValueError + . runState lowerBound . runReader lowerBound . interpret handleModules . runTermEvaluator @_ @_ @(Value (Hole Precise) (ImportGraphEff (Term (Sum syntaxes) (Record Location)) (Hole Precise))) - . runState lowerBound . runReader packageInfo . runReader lowerBound extractGraph <$> analyze (runImportGraphAnalysis (packageInfo package)) (evaluate @_ @_ @_ @_ @(Term (Sum syntaxes) (Record Location)) lang analyzeModule analyzeTerm []) @@ -134,9 +134,9 @@ newtype ImportGraphEff term address a = ImportGraphEff , Reader ModuleInfo , Reader Span , Reader PackageInfo - , State (Graph (Module term)) , Modules address , Reader (ModuleTable (NonEmpty (Module (address, Environment address)))) + , State (Graph (Module term)) , Resumable (ValueError address (ImportGraphEff term address)) , Resumable (AddressError address (Value address (ImportGraphEff term address))) , Resumable ResolutionError From e0dc9a2c3a36b47e0bb506ac73aa64df1776ea14 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 20 Jun 2018 10:24:35 -0400 Subject: [PATCH 052/169] Spacing. --- src/Semantic/Graph.hs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index 5adc2673e..54fa947a4 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -151,7 +151,6 @@ newtype ImportGraphEff term address a = ImportGraphEff } - -- | Parse a list of files into a 'Package'. parsePackage :: (Member (Distribute WrappedTask) effs, Member Resolution effs, Member Trace effs) => Parser term -- ^ A parser. From ce8069d7f674a3fcbfbffdfbd803fad768c5e861 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 20 Jun 2018 11:39:25 -0400 Subject: [PATCH 053/169] =?UTF-8?q?Compute=20the=20import=20graph=20using?= =?UTF-8?q?=20the=20package=E2=80=99s=20modules.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Semantic/Graph.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index 54fa947a4..da92eed8e 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -26,6 +26,7 @@ import Control.Monad.Effect (reinterpret) import Data.Abstract.Address import Data.Abstract.Evaluatable import Data.Abstract.Module +import qualified Data.Abstract.ModuleTable as ModuleTable import Data.Abstract.Package as Package import Data.Abstract.Value (Value, ValueError (..), runValueErrorWith) import Data.AST (Location) @@ -124,7 +125,7 @@ runImportGraph project . runTermEvaluator @_ @_ @(Value (Hole Precise) (ImportGraphEff (Term (Sum syntaxes) (Record Location)) (Hole Precise))) . runReader packageInfo . runReader lowerBound - extractGraph <$> analyze (runImportGraphAnalysis (packageInfo package)) (evaluate @_ @_ @_ @_ @(Term (Sum syntaxes) (Record Location)) lang analyzeModule analyzeTerm []) + extractGraph <$> analyze (runImportGraphAnalysis (packageInfo package)) (evaluate @_ @_ @_ @_ @(Term (Sum syntaxes) (Record Location)) lang analyzeModule analyzeTerm (map snd (ModuleTable.toPairs (packageModules (packageBody package))))) newtype ImportGraphEff term address a = ImportGraphEff { runImportGraphEff :: Eff '[ LoopControl address From e972abd2e3a207d842792cabacd24ce1fc97aa4a Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 20 Jun 2018 12:17:46 -0400 Subject: [PATCH 054/169] Factor runFresh out of evaluating. --- src/Analysis/Abstract/Evaluating.hs | 4 +--- src/Semantic/Graph.hs | 1 + src/Semantic/Util.hs | 2 ++ test/Control/Abstract/Evaluator/Spec.hs | 1 + test/SpecHelpers.hs | 1 + 5 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Analysis/Abstract/Evaluating.hs b/src/Analysis/Abstract/Evaluating.hs index 6da064c3b..6794a95c3 100644 --- a/src/Analysis/Abstract/Evaluating.hs +++ b/src/Analysis/Abstract/Evaluating.hs @@ -19,8 +19,7 @@ deriving instance (Show (Cell address value), Show address, Show value) => Show evaluating :: Evaluator address value - ( Fresh - ': State (Heap address (Cell address) value) + ( State (Heap address (Cell address) value) ': State (ModuleTable (Maybe (address, Environment address))) ': effects) result -> Evaluator address value effects (result, EvaluatingState address value) @@ -28,4 +27,3 @@ evaluating = fmap (\ ((result, heap), modules) -> (result, EvaluatingState heap modules)) . runState lowerBound -- State (ModuleTable (Maybe (address, Environment address))) . runState lowerBound -- State (Heap address (Cell address) value) - . runFresh 0 diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index da92eed8e..90f29c25f 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -61,6 +61,7 @@ runGraph graphType includePackages project runGraphAnalysis = run . evaluating + . runFresh 0 . runIgnoringTrace . resumingLoadError . resumingUnspecialized diff --git a/src/Semantic/Util.hs b/src/Semantic/Util.hs index be0c0aba0..5fcb45152 100644 --- a/src/Semantic/Util.hs +++ b/src/Semantic/Util.hs @@ -30,6 +30,7 @@ import Text.Show.Pretty (ppShow) justEvaluating = runM . evaluating + . runFresh 0 . runPrintingTrace . fmap reassociate . runLoadError @@ -68,6 +69,7 @@ newtype UtilEff address a = UtilEff checking = runM @_ @IO . evaluating + . runFresh 0 . runPrintingTrace . runTermEvaluator @_ @Monovariant @Type . caching @[] diff --git a/test/Control/Abstract/Evaluator/Spec.hs b/test/Control/Abstract/Evaluator/Spec.hs index a0f21fa8c..c556be6de 100644 --- a/test/Control/Abstract/Evaluator/Spec.hs +++ b/test/Control/Abstract/Evaluator/Spec.hs @@ -31,6 +31,7 @@ spec = parallel $ do evaluate = runM . evaluating @Precise @Val + . runFresh 0 . runReader (PackageInfo (name "test") Nothing mempty) . runReader (ModuleInfo "test/Control/Abstract/Evaluator/Spec.hs") . fmap reassociate diff --git a/test/SpecHelpers.hs b/test/SpecHelpers.hs index 4450c8e01..ce290f19c 100644 --- a/test/SpecHelpers.hs +++ b/test/SpecHelpers.hs @@ -113,6 +113,7 @@ testEvaluating = run . runReturningTrace . evaluating + . runFresh 0 . fmap reassociate . runLoadError . runUnspecialized From 251cacda79797baef9e4f8f883783ba3df9960ee Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 20 Jun 2018 12:20:26 -0400 Subject: [PATCH 055/169] Define an EdgeCounts datatype. --- src/Data/Graph.hs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Data/Graph.hs b/src/Data/Graph.hs index afdb64695..024ce9e98 100644 --- a/src/Data/Graph.hs +++ b/src/Data/Graph.hs @@ -41,6 +41,12 @@ edgeCountsByVertex = Class.foldg (<>) (\ outM inM -> outM <> inM <> foldMap (flip Monoidal.singleton (Monoid.Sum (length outM))) (Monoidal.keys inM)) +data EdgeCounts = EdgeCounts + { inEdgeCount :: {-# UNPACK #-} !Int + , outEdgeCount :: {-# UNPACK #-} !Int + } + deriving (Eq, Ord, Show) + groupByInEdgeCount :: Ord sum => [(v, sum)] -> [NonEmpty v] groupByInEdgeCount = map (NonEmpty.fromList . map fst) . groupBy ((==) `on` snd) . sortBy (comparing snd) From 64c0e24cc0b3a1fb28fc41ff7a0525b87296f667 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 20 Jun 2018 12:21:12 -0400 Subject: [PATCH 056/169] Define a Semigroup instance for EdgeCounts. --- src/Data/Graph.hs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Data/Graph.hs b/src/Data/Graph.hs index 024ce9e98..21185ec56 100644 --- a/src/Data/Graph.hs +++ b/src/Data/Graph.hs @@ -47,6 +47,9 @@ data EdgeCounts = EdgeCounts } deriving (Eq, Ord, Show) +instance Semigroup EdgeCounts where + EdgeCounts in1 out1 <> EdgeCounts in2 out2 = EdgeCounts (in1 + in2) (out1 + out2) + groupByInEdgeCount :: Ord sum => [(v, sum)] -> [NonEmpty v] groupByInEdgeCount = map (NonEmpty.fromList . map fst) . groupBy ((==) `on` snd) . sortBy (comparing snd) From ba921bcdf4f220602637c0d2211098292c5423ce Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 20 Jun 2018 12:21:48 -0400 Subject: [PATCH 057/169] Define a Monoid instance for EdgeCounts. --- src/Data/Graph.hs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Data/Graph.hs b/src/Data/Graph.hs index 21185ec56..6b2a68a8c 100644 --- a/src/Data/Graph.hs +++ b/src/Data/Graph.hs @@ -50,6 +50,10 @@ data EdgeCounts = EdgeCounts instance Semigroup EdgeCounts where EdgeCounts in1 out1 <> EdgeCounts in2 out2 = EdgeCounts (in1 + in2) (out1 + out2) +instance Monoid EdgeCounts where + mempty = EdgeCounts 0 0 + mappend = (<>) + groupByInEdgeCount :: Ord sum => [(v, sum)] -> [NonEmpty v] groupByInEdgeCount = map (NonEmpty.fromList . map fst) . groupBy ((==) `on` snd) . sortBy (comparing snd) From 4be53bc5530d87b7813006be7f2c13de203ba893 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 20 Jun 2018 12:24:54 -0400 Subject: [PATCH 058/169] Compute both in- and out-edge counts. --- src/Data/Graph.hs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Data/Graph.hs b/src/Data/Graph.hs index 6b2a68a8c..0e2fbc177 100644 --- a/src/Data/Graph.hs +++ b/src/Data/Graph.hs @@ -15,7 +15,6 @@ import Data.Aeson import Data.List (groupBy, sortBy) import qualified Data.List.NonEmpty as NonEmpty (fromList) import qualified Data.Map.Monoidal as Monoidal -import qualified Data.Monoid as Monoid import Data.Ord (comparing) import Prologue @@ -34,12 +33,16 @@ topologicalSort . Monoidal.pairs . edgeCountsByVertex -edgeCountsByVertex :: Ord v => Graph v -> Monoidal.Map v (Monoid.Sum Int) +edgeCountsByVertex :: Ord v => Graph v -> Monoidal.Map v EdgeCounts edgeCountsByVertex = Class.foldg lowerBound - (flip Monoidal.singleton 0) + (flip Monoidal.singleton mempty) (<>) - (\ outM inM -> outM <> inM <> foldMap (flip Monoidal.singleton (Monoid.Sum (length outM))) (Monoidal.keys inM)) + (\ outM inM + -> outM + <> inM + <> foldMap (flip Monoidal.singleton (EdgeCounts 0 (length outM))) (Monoidal.keys inM) + <> foldMap (flip Monoidal.singleton (EdgeCounts (length inM) 0)) (Monoidal.keys outM)) data EdgeCounts = EdgeCounts { inEdgeCount :: {-# UNPACK #-} !Int From 3b4fc281a980e46c45485dc0bd4153e5f2994105 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 20 Jun 2018 12:27:42 -0400 Subject: [PATCH 059/169] Generalize the group by functionality. --- src/Data/Graph.hs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Data/Graph.hs b/src/Data/Graph.hs index 0e2fbc177..808632ddf 100644 --- a/src/Data/Graph.hs +++ b/src/Data/Graph.hs @@ -29,7 +29,8 @@ simplify (Graph graph) = Graph (G.simplify graph) topologicalSort :: Ord v => Graph v -> [NonEmpty v] topologicalSort - = groupByInEdgeCount + = map (fmap fst) + . sortAndGroupBy (inEdgeCount . snd) . Monoidal.pairs . edgeCountsByVertex @@ -57,8 +58,8 @@ instance Monoid EdgeCounts where mempty = EdgeCounts 0 0 mappend = (<>) -groupByInEdgeCount :: Ord sum => [(v, sum)] -> [NonEmpty v] -groupByInEdgeCount = map (NonEmpty.fromList . map fst) . groupBy ((==) `on` snd) . sortBy (comparing snd) +sortAndGroupBy :: Ord b => (a -> b) -> [a] -> [NonEmpty a] +sortAndGroupBy by = map NonEmpty.fromList . groupBy ((==) `on` by) . sortBy (comparing by) instance Lower (Graph vertex) where From 16c21c9c7b905aa090ba379f768e29c4b5488722 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 20 Jun 2018 12:28:09 -0400 Subject: [PATCH 060/169] Export EdgeCounts. --- src/Data/Graph.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Data/Graph.hs b/src/Data/Graph.hs index 808632ddf..b22dfb827 100644 --- a/src/Data/Graph.hs +++ b/src/Data/Graph.hs @@ -7,6 +7,7 @@ module Data.Graph , Lower(..) , simplify , topologicalSort +, EdgeCounts(..) ) where import qualified Algebra.Graph as G From 85311cd9a33819054da0c1907ce075212181b4cc Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 20 Jun 2018 12:28:16 -0400 Subject: [PATCH 061/169] Sort and group by the out-edge count. --- src/Data/Graph.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Data/Graph.hs b/src/Data/Graph.hs index b22dfb827..c736ec346 100644 --- a/src/Data/Graph.hs +++ b/src/Data/Graph.hs @@ -31,7 +31,7 @@ simplify (Graph graph) = Graph (G.simplify graph) topologicalSort :: Ord v => Graph v -> [NonEmpty v] topologicalSort = map (fmap fst) - . sortAndGroupBy (inEdgeCount . snd) + . sortAndGroupBy (outEdgeCount . snd) . Monoidal.pairs . edgeCountsByVertex From 70047c3b489b814e58e58864caffcfd6d8fb0cc0 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 20 Jun 2018 12:32:34 -0400 Subject: [PATCH 062/169] Correct a couple of doc comments. --- src/Analysis/Abstract/Graph.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Analysis/Abstract/Graph.hs b/src/Analysis/Abstract/Graph.hs index 28d9f5b6d..5474365bd 100644 --- a/src/Analysis/Abstract/Graph.hs +++ b/src/Analysis/Abstract/Graph.hs @@ -67,6 +67,7 @@ graphingTerms recur term@(In _ syntax) = do _ -> pure () recur term +-- | Add vertices to the graph for evaluated modules and the packages containing them. graphingPackages :: ( Member (Reader PackageInfo) effects , Member (State (Graph Vertex)) effects ) @@ -74,7 +75,7 @@ graphingPackages :: ( Member (Reader PackageInfo) effects -> SubtermAlgebra Module term (TermEvaluator term address value effects a) graphingPackages recur m = packageInclusion (moduleVertex (moduleInfo m)) *> recur m --- | Add vertices to the graph for evaluated modules and the packages containing them. +-- | Add vertices to the graph for imported modules. graphingModules :: forall term address value effects a . ( Member (Modules address) effects , Member (Reader ModuleInfo) effects From 86d29304555651424f67f07f1d3d399e88194528 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 20 Jun 2018 12:35:50 -0400 Subject: [PATCH 063/169] Generalize appendGraph. --- src/Analysis/Abstract/Graph.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Analysis/Abstract/Graph.hs b/src/Analysis/Abstract/Graph.hs index 5474365bd..3d317b608 100644 --- a/src/Analysis/Abstract/Graph.hs +++ b/src/Analysis/Abstract/Graph.hs @@ -130,7 +130,7 @@ variableDefinition name = do graph <- maybe lowerBound (maybe lowerBound (vertex . moduleVertex . addressModule) . toMaybe) <$> TermEvaluator (lookupEnv name) appendGraph (vertex (Variable (formatName name)) `connect` graph) -appendGraph :: (Effectful m, Member (State (Graph Vertex)) effects) => Graph Vertex -> m effects () +appendGraph :: (Effectful m, Member (State (Graph v)) effects) => Graph v -> m effects () appendGraph = modify' . (<>) From 948e4f57b0c29f64fa642dfc683206cec050453d Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 20 Jun 2018 12:37:58 -0400 Subject: [PATCH 064/169] Fix some indentation. --- src/Analysis/Abstract/Graph.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Analysis/Abstract/Graph.hs b/src/Analysis/Abstract/Graph.hs index 3d317b608..9b2447d4c 100644 --- a/src/Analysis/Abstract/Graph.hs +++ b/src/Analysis/Abstract/Graph.hs @@ -81,8 +81,8 @@ graphingModules :: forall term address value effects a , Member (Reader ModuleInfo) effects , Member (State (Graph Vertex)) effects ) - => SubtermAlgebra Module term (TermEvaluator term address value effects a) - -> SubtermAlgebra Module term (TermEvaluator term address value effects a) + => SubtermAlgebra Module term (TermEvaluator term address value effects a) + -> SubtermAlgebra Module term (TermEvaluator term address value effects a) graphingModules recur m = interpose @(Modules address) pure (\ m yield -> case m of Load path -> moduleInclusion (moduleVertex (ModuleInfo path)) >> send m >>= yield Lookup path -> moduleInclusion (moduleVertex (ModuleInfo path)) >> send m >>= yield From e86380294461086f93348dd1b4056d6359a8939f Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 20 Jun 2018 12:38:05 -0400 Subject: [PATCH 065/169] Add an analysis to graph module paths. --- src/Analysis/Abstract/Graph.hs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/Analysis/Abstract/Graph.hs b/src/Analysis/Abstract/Graph.hs index 9b2447d4c..1e358534f 100644 --- a/src/Analysis/Abstract/Graph.hs +++ b/src/Analysis/Abstract/Graph.hs @@ -10,6 +10,7 @@ module Analysis.Abstract.Graph , graphingTerms , graphingPackages , graphingModules +, graphingModulePaths , graphing ) where @@ -89,6 +90,23 @@ graphingModules recur m = interpose @(Modules address) pure (\ m yield -> case m _ -> send m >>= yield) (recur m) +-- | Add vertices to the graph for imported modules. +graphingModulePaths :: forall term address value effects a + . ( Member (Modules address) effects + , Member (Reader ModuleInfo) effects + , Member (State (Graph ModuleInfo)) effects + ) + => SubtermAlgebra Module term (TermEvaluator term address value effects a) + -> SubtermAlgebra Module term (TermEvaluator term address value effects a) +graphingModulePaths recur m = interpose @(Modules address) pure (\ eff yield -> case eff of + Load path -> do + moduleInfo <- ask + appendGraph (vertex moduleInfo `connect` vertex (ModuleInfo path)) + result <- send eff + yield result + _ -> send eff >>= yield) + (recur m) + packageVertex :: PackageInfo -> Vertex packageVertex = Package . formatName . packageName From d472adab2bc39931c0ada29df798084e72050bc6 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 20 Jun 2018 12:40:01 -0400 Subject: [PATCH 066/169] Derive an Applicative instance for Graph. --- src/Data/Graph.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Data/Graph.hs b/src/Data/Graph.hs index c736ec346..9d193a130 100644 --- a/src/Data/Graph.hs +++ b/src/Data/Graph.hs @@ -21,7 +21,7 @@ import Prologue -- | An algebraic graph with 'Ord', 'Semigroup', and 'Monoid' instances. newtype Graph vertex = Graph (G.Graph vertex) - deriving (Eq, Foldable, Functor, Class.Graph, Show, Class.ToGraph, Traversable) + deriving (Applicative, Eq, Foldable, Functor, Class.Graph, Show, Class.ToGraph, Traversable) simplify :: Ord vertex => Graph vertex -> Graph vertex From ffe84b1dd2cd88edf508b5ed77df08a7090dcf16 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 20 Jun 2018 12:40:16 -0400 Subject: [PATCH 067/169] Derive an Alternative instance for Graph. --- src/Data/Graph.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Data/Graph.hs b/src/Data/Graph.hs index 9d193a130..702d26cdf 100644 --- a/src/Data/Graph.hs +++ b/src/Data/Graph.hs @@ -21,7 +21,7 @@ import Prologue -- | An algebraic graph with 'Ord', 'Semigroup', and 'Monoid' instances. newtype Graph vertex = Graph (G.Graph vertex) - deriving (Applicative, Eq, Foldable, Functor, Class.Graph, Show, Class.ToGraph, Traversable) + deriving (Alternative, Applicative, Eq, Foldable, Functor, Class.Graph, Show, Class.ToGraph, Traversable) simplify :: Ord vertex => Graph vertex -> Graph vertex From 19e35b3f52805ca90974d06f46619aebcad3d96d Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 20 Jun 2018 12:40:33 -0400 Subject: [PATCH 068/169] Derive a Monad instance for Graph. --- src/Data/Graph.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Data/Graph.hs b/src/Data/Graph.hs index 702d26cdf..3c0b77d29 100644 --- a/src/Data/Graph.hs +++ b/src/Data/Graph.hs @@ -21,7 +21,7 @@ import Prologue -- | An algebraic graph with 'Ord', 'Semigroup', and 'Monoid' instances. newtype Graph vertex = Graph (G.Graph vertex) - deriving (Alternative, Applicative, Eq, Foldable, Functor, Class.Graph, Show, Class.ToGraph, Traversable) + deriving (Alternative, Applicative, Eq, Foldable, Functor, Class.Graph, Monad, Show, Class.ToGraph, Traversable) simplify :: Ord vertex => Graph vertex -> Graph vertex From 5b2f0c2c1cb315547a8c6fc3ffacb6b09fda42b7 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 20 Jun 2018 14:39:45 -0400 Subject: [PATCH 069/169] Compute a graph of ModuleInfo, which we use to construct actual Modules. --- src/Semantic/Graph.hs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index 90f29c25f..edb9e72e3 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -107,7 +107,11 @@ runImportGraph project package <- parsePackage parser project let analyzeTerm = id analyzeModule = id - extractGraph (((_, graph), _), _) = fmap SomeTerm <$> graph + extractGraph (((_, graph), _), _) = do + info <- graph + case ModuleTable.lookup (modulePath info) (packageModules (packageBody package)) of + Nothing -> lowerBound + Just m -> foldMapA pure (fmap SomeTerm <$> m) runImportGraphAnalysis packageInfo = run . runState lowerBound @@ -138,7 +142,7 @@ newtype ImportGraphEff term address a = ImportGraphEff , Reader PackageInfo , Modules address , Reader (ModuleTable (NonEmpty (Module (address, Environment address)))) - , State (Graph (Module term)) + , State (Graph ModuleInfo) , Resumable (ValueError address (ImportGraphEff term address)) , Resumable (AddressError address (Value address (ImportGraphEff term address))) , Resumable ResolutionError From 4e6c11faec24c7e8427bcf5188ee2b71a3bcad44 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 20 Jun 2018 14:43:14 -0400 Subject: [PATCH 070/169] Rename graphingModulePaths to graphingModuleInfo. --- src/Analysis/Abstract/Graph.hs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Analysis/Abstract/Graph.hs b/src/Analysis/Abstract/Graph.hs index 1e358534f..4d684595b 100644 --- a/src/Analysis/Abstract/Graph.hs +++ b/src/Analysis/Abstract/Graph.hs @@ -10,7 +10,7 @@ module Analysis.Abstract.Graph , graphingTerms , graphingPackages , graphingModules -, graphingModulePaths +, graphingModuleInfo , graphing ) where @@ -91,14 +91,14 @@ graphingModules recur m = interpose @(Modules address) pure (\ m yield -> case m (recur m) -- | Add vertices to the graph for imported modules. -graphingModulePaths :: forall term address value effects a - . ( Member (Modules address) effects - , Member (Reader ModuleInfo) effects - , Member (State (Graph ModuleInfo)) effects - ) - => SubtermAlgebra Module term (TermEvaluator term address value effects a) - -> SubtermAlgebra Module term (TermEvaluator term address value effects a) -graphingModulePaths recur m = interpose @(Modules address) pure (\ eff yield -> case eff of +graphingModuleInfo :: forall term address value effects a + . ( Member (Modules address) effects + , Member (Reader ModuleInfo) effects + , Member (State (Graph ModuleInfo)) effects + ) + => SubtermAlgebra Module term (TermEvaluator term address value effects a) + -> SubtermAlgebra Module term (TermEvaluator term address value effects a) +graphingModuleInfo recur m = interpose @(Modules address) pure (\ eff yield -> case eff of Load path -> do moduleInfo <- ask appendGraph (vertex moduleInfo `connect` vertex (ModuleInfo path)) From 10a7405a0dd0626a4cbb5d7b9e3d45d6b002d7e8 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 20 Jun 2018 14:43:38 -0400 Subject: [PATCH 071/169] Graph module info for the import graph. --- src/Semantic/Graph.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index edb9e72e3..3c94b8588 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -106,7 +106,7 @@ runImportGraph project | SomeAnalysisParser (parser :: Parser (Term (Sum syntaxes) (Record Location))) lang <- someAnalysisParser (Proxy :: Proxy AnalysisClasses) (projectLanguage project) = do package <- parsePackage parser project let analyzeTerm = id - analyzeModule = id + analyzeModule = graphingModuleInfo extractGraph (((_, graph), _), _) = do info <- graph case ModuleTable.lookup (modulePath info) (packageModules (packageBody package)) of From 1cc372ab67c018726f999912c2b2a42e9c8d2e04 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 10:42:47 -0400 Subject: [PATCH 072/169] Export moduleVertex. --- src/Analysis/Abstract/Graph.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Analysis/Abstract/Graph.hs b/src/Analysis/Abstract/Graph.hs index 4d684595b..dceb559bc 100644 --- a/src/Analysis/Abstract/Graph.hs +++ b/src/Analysis/Abstract/Graph.hs @@ -2,6 +2,7 @@ module Analysis.Abstract.Graph ( Graph(..) , Vertex(..) +, moduleVertex , style , appendGraph , variableDefinition From 37cd4fb4ada0a7db0a74e046d3ec438de6934441 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 10:43:11 -0400 Subject: [PATCH 073/169] Run import graphs using the new code path. --- src/Semantic/Graph.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index 3c94b8588..7f8f9caca 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -20,7 +20,7 @@ module Semantic.Graph ) where import Analysis.Abstract.Evaluating -import Analysis.Abstract.Graph +import Analysis.Abstract.Graph as Graph import Control.Abstract import Control.Monad.Effect (reinterpret) import Data.Abstract.Address @@ -49,6 +49,7 @@ runGraph :: ( Member (Distribute WrappedTask) effs, Member Resolution effs, Memb -> Bool -> Project -> Eff effs (Graph Vertex) +runGraph ImportGraph _ project = fmap (Graph.moduleVertex . moduleInfo) <$> runImportGraph project runGraph graphType includePackages project | SomeAnalysisParser parser lang <- someAnalysisParser (Proxy :: Proxy AnalysisClasses) (projectLanguage project) = do package <- parsePackage parser project From 0e265cc4f635ab9f515bce2c25d4344f1321d383 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 10:50:24 -0400 Subject: [PATCH 074/169] Add edges for lookups. --- src/Analysis/Abstract/Graph.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Analysis/Abstract/Graph.hs b/src/Analysis/Abstract/Graph.hs index dceb559bc..fdecad93a 100644 --- a/src/Analysis/Abstract/Graph.hs +++ b/src/Analysis/Abstract/Graph.hs @@ -105,6 +105,7 @@ graphingModuleInfo recur m = interpose @(Modules address) pure (\ eff yield -> c appendGraph (vertex moduleInfo `connect` vertex (ModuleInfo path)) result <- send eff yield result + Lookup path -> ask >>= appendGraph . (`connect` vertex (ModuleInfo path)) . vertex >> send eff >>= yield _ -> send eff >>= yield) (recur m) From b2a816805986a9783e50728a6d88b4539e67ee6f Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 10:50:52 -0400 Subject: [PATCH 075/169] Abbreviate the Load edge construction. --- src/Analysis/Abstract/Graph.hs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Analysis/Abstract/Graph.hs b/src/Analysis/Abstract/Graph.hs index fdecad93a..67547d615 100644 --- a/src/Analysis/Abstract/Graph.hs +++ b/src/Analysis/Abstract/Graph.hs @@ -100,11 +100,7 @@ graphingModuleInfo :: forall term address value effects a => SubtermAlgebra Module term (TermEvaluator term address value effects a) -> SubtermAlgebra Module term (TermEvaluator term address value effects a) graphingModuleInfo recur m = interpose @(Modules address) pure (\ eff yield -> case eff of - Load path -> do - moduleInfo <- ask - appendGraph (vertex moduleInfo `connect` vertex (ModuleInfo path)) - result <- send eff - yield result + Load path -> ask >>= appendGraph . (`connect` vertex (ModuleInfo path)) . vertex >> send eff >>= yield Lookup path -> ask >>= appendGraph . (`connect` vertex (ModuleInfo path)) . vertex >> send eff >>= yield _ -> send eff >>= yield) (recur m) From b9b52b55daf70e54fd8d120532e2bb83212be0c0 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 11:02:27 -0400 Subject: [PATCH 076/169] Use the currentModule synonym to clarify intent. --- src/Analysis/Abstract/Graph.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Analysis/Abstract/Graph.hs b/src/Analysis/Abstract/Graph.hs index 67547d615..5e7ea8ac9 100644 --- a/src/Analysis/Abstract/Graph.hs +++ b/src/Analysis/Abstract/Graph.hs @@ -100,8 +100,8 @@ graphingModuleInfo :: forall term address value effects a => SubtermAlgebra Module term (TermEvaluator term address value effects a) -> SubtermAlgebra Module term (TermEvaluator term address value effects a) graphingModuleInfo recur m = interpose @(Modules address) pure (\ eff yield -> case eff of - Load path -> ask >>= appendGraph . (`connect` vertex (ModuleInfo path)) . vertex >> send eff >>= yield - Lookup path -> ask >>= appendGraph . (`connect` vertex (ModuleInfo path)) . vertex >> send eff >>= yield + Load path -> currentModule >>= appendGraph . (`connect` vertex (ModuleInfo path)) . vertex >> send eff >>= yield + Lookup path -> currentModule >>= appendGraph . (`connect` vertex (ModuleInfo path)) . vertex >> send eff >>= yield _ -> send eff >>= yield) (recur m) From f9d56b846bc0498c29b8618972dd1d830e8ecf92 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 11:45:42 -0400 Subject: [PATCH 077/169] Add a function computing the set of module paths in a ModuleTable. --- src/Data/Abstract/ModuleTable.hs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Data/Abstract/ModuleTable.hs b/src/Data/Abstract/ModuleTable.hs index 1522ad635..57a2670a5 100644 --- a/src/Data/Abstract/ModuleTable.hs +++ b/src/Data/Abstract/ModuleTable.hs @@ -5,6 +5,7 @@ module Data.Abstract.ModuleTable , singleton , lookup , member +, modulePaths , modulePathsInDir , insert , keys @@ -26,6 +27,9 @@ newtype ModuleTable a = ModuleTable { unModuleTable :: Map.Map ModulePath a } singleton :: ModulePath -> a -> ModuleTable a singleton name = ModuleTable . Map.singleton name +modulePaths :: ModuleTable a -> Set ModulePath +modulePaths = Map.keysSet . unModuleTable + modulePathsInDir :: FilePath -> ModuleTable a -> [ModulePath] modulePathsInDir k = filter (\e -> k == takeDirectory e) . Map.keys . unModuleTable From dea2241d14fcdc2ca943771ef1e1b384bb392317 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 11:45:58 -0400 Subject: [PATCH 078/169] Pass module paths to handleModules. --- src/Control/Abstract/Modules.hs | 5 +++-- src/Semantic/Graph.hs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Control/Abstract/Modules.hs b/src/Control/Abstract/Modules.hs index 885e8f8f2..491739ab2 100644 --- a/src/Control/Abstract/Modules.hs +++ b/src/Control/Abstract/Modules.hs @@ -92,9 +92,10 @@ runModules evaluateModule = go List dir -> modulePathsInDir dir <$> askModuleTable @term) handleModules :: Member (Reader (ModuleTable (NonEmpty (Module (address, Environment address))))) effects - => Modules address a + => Set ModulePath + -> Modules address a -> Evaluator address value effects a -handleModules = \case +handleModules _ = \case Load name -> fmap (runMerging' . foldMap1 (Merging' . moduleBody)) . ModuleTable.lookup name <$> askModuleTable' Lookup path -> fmap (Just . runMerging' . foldMap1 (Merging' . moduleBody)) . ModuleTable.lookup path <$> askModuleTable' Resolve names -> do diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index 7f8f9caca..36c3ac86c 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -127,7 +127,7 @@ runImportGraph project . resumingValueError . runState lowerBound . runReader lowerBound - . interpret handleModules + . interpret (handleModules (ModuleTable.modulePaths (packageModules (packageBody package)))) . runTermEvaluator @_ @_ @(Value (Hole Precise) (ImportGraphEff (Term (Sum syntaxes) (Record Location)) (Hole Precise))) . runReader packageInfo . runReader lowerBound From e7cc57a3eb84708f6f887747556033dbed962d85 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 11:47:53 -0400 Subject: [PATCH 079/169] Resolve names against package paths. --- src/Control/Abstract/Modules.hs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Control/Abstract/Modules.hs b/src/Control/Abstract/Modules.hs index 491739ab2..758df4396 100644 --- a/src/Control/Abstract/Modules.hs +++ b/src/Control/Abstract/Modules.hs @@ -25,6 +25,7 @@ import Data.Abstract.Module import Data.Abstract.ModuleTable as ModuleTable import Data.Language import Data.Semigroup.Foldable (foldMap1) +import qualified Data.Set as Set import Prologue -- | Retrieve an evaluated module, if any. The outer 'Maybe' indicates whether we’ve begun loading the module or not, while the inner 'Maybe' indicates whether we’ve completed loading it or not. Thus, @Nothing@ means we’ve never tried to load it, @Just Nothing@ means we’ve started but haven’t yet finished loading it, and @Just (Just (env, value))@ indicates the result of a completed load. @@ -95,12 +96,10 @@ handleModules :: Member (Reader (ModuleTable (NonEmpty (Module (address, Environ => Set ModulePath -> Modules address a -> Evaluator address value effects a -handleModules _ = \case +handleModules paths = \case Load name -> fmap (runMerging' . foldMap1 (Merging' . moduleBody)) . ModuleTable.lookup name <$> askModuleTable' Lookup path -> fmap (Just . runMerging' . foldMap1 (Merging' . moduleBody)) . ModuleTable.lookup path <$> askModuleTable' - Resolve names -> do - isMember <- flip ModuleTable.member <$> askModuleTable' - pure (find isMember names) + Resolve names -> pure (find (flip Set.member paths) names) List dir -> modulePathsInDir dir <$> askModuleTable' getModuleTable :: Member (State (ModuleTable (Maybe (address, Environment address)))) effects => Evaluator address value effects (ModuleTable (Maybe (address, Environment address))) From 85d8b57e837c8ecbbfbd1a035fb8441c01b6eb01 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 11:49:42 -0400 Subject: [PATCH 080/169] List paths using the package paths. --- src/Control/Abstract/Modules.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Control/Abstract/Modules.hs b/src/Control/Abstract/Modules.hs index 758df4396..220d8ba45 100644 --- a/src/Control/Abstract/Modules.hs +++ b/src/Control/Abstract/Modules.hs @@ -27,6 +27,7 @@ import Data.Language import Data.Semigroup.Foldable (foldMap1) import qualified Data.Set as Set import Prologue +import System.FilePath.Posix (takeDirectory) -- | Retrieve an evaluated module, if any. The outer 'Maybe' indicates whether we’ve begun loading the module or not, while the inner 'Maybe' indicates whether we’ve completed loading it or not. Thus, @Nothing@ means we’ve never tried to load it, @Just Nothing@ means we’ve started but haven’t yet finished loading it, and @Just (Just (env, value))@ indicates the result of a completed load. lookupModule :: Member (Modules address) effects => ModulePath -> Evaluator address value effects (Maybe (Maybe (address, Environment address))) @@ -100,7 +101,7 @@ handleModules paths = \case Load name -> fmap (runMerging' . foldMap1 (Merging' . moduleBody)) . ModuleTable.lookup name <$> askModuleTable' Lookup path -> fmap (Just . runMerging' . foldMap1 (Merging' . moduleBody)) . ModuleTable.lookup path <$> askModuleTable' Resolve names -> pure (find (flip Set.member paths) names) - List dir -> modulePathsInDir dir <$> askModuleTable' + List dir -> pure (filter ((dir ==) . takeDirectory) (toList paths)) getModuleTable :: Member (State (ModuleTable (Maybe (address, Environment address)))) effects => Evaluator address value effects (ModuleTable (Maybe (address, Environment address))) getModuleTable = get From 68474868a7ff42011fa02f47fdebb523c640d4bf Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 11:55:25 -0400 Subject: [PATCH 081/169] =?UTF-8?q?We=E2=80=99re=20dealing=20with=20call-g?= =?UTF-8?q?raphs=20only=20in=20this=20branch.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Semantic/Graph.hs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index 36c3ac86c..388f12afc 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -50,12 +50,10 @@ runGraph :: ( Member (Distribute WrappedTask) effs, Member Resolution effs, Memb -> Project -> Eff effs (Graph Vertex) runGraph ImportGraph _ project = fmap (Graph.moduleVertex . moduleInfo) <$> runImportGraph project -runGraph graphType includePackages project +runGraph CallGraph includePackages project | SomeAnalysisParser parser lang <- someAnalysisParser (Proxy :: Proxy AnalysisClasses) (projectLanguage project) = do package <- parsePackage parser project - let analyzeTerm = withTermSpans . case graphType of - ImportGraph -> id - CallGraph -> graphingTerms + let analyzeTerm = withTermSpans . graphingTerms analyzeModule = (if includePackages then graphingPackages else id) . graphingModules extractGraph <$> analyze runGraphAnalysis (evaluatePackageWith lang analyzeModule analyzeTerm package) where extractGraph (((_, graph), _), _) = simplify graph From c32f8c4e0c3e10bb21561fb99d6bf1474385417c Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 12:14:36 -0400 Subject: [PATCH 082/169] Pass the package to runImportGraph. --- src/Semantic/Graph.hs | 75 +++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 34 deletions(-) diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index 388f12afc..96bbf12af 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -29,7 +29,6 @@ import Data.Abstract.Module import qualified Data.Abstract.ModuleTable as ModuleTable import Data.Abstract.Package as Package import Data.Abstract.Value (Value, ValueError (..), runValueErrorWith) -import Data.AST (Location) import Data.Graph import Data.Project import Data.Record @@ -49,7 +48,10 @@ runGraph :: ( Member (Distribute WrappedTask) effs, Member Resolution effs, Memb -> Bool -> Project -> Eff effs (Graph Vertex) -runGraph ImportGraph _ project = fmap (Graph.moduleVertex . moduleInfo) <$> runImportGraph project +runGraph ImportGraph _ project + | SomeAnalysisParser parser lang <- someAnalysisParser (Proxy :: Proxy AnalysisClasses) (projectLanguage project) = do + package <- parsePackage parser project + fmap (Graph.moduleVertex . moduleInfo) <$> runImportGraph lang package runGraph CallGraph includePackages project | SomeAnalysisParser parser lang <- someAnalysisParser (Proxy :: Proxy AnalysisClasses) (projectLanguage project) = do package <- parsePackage parser project @@ -98,38 +100,43 @@ newtype GraphEff address a = GraphEff } -runImportGraph :: ( Member (Distribute WrappedTask) effs, Member Resolution effs, Member Task effs, Member Trace effs) - => Project - -> Eff effs (Graph (Module (SomeTerm AnalysisClasses (Record Location)))) -runImportGraph project - | SomeAnalysisParser (parser :: Parser (Term (Sum syntaxes) (Record Location))) lang <- someAnalysisParser (Proxy :: Proxy AnalysisClasses) (projectLanguage project) = do - package <- parsePackage parser project - let analyzeTerm = id - analyzeModule = graphingModuleInfo - extractGraph (((_, graph), _), _) = do - info <- graph - case ModuleTable.lookup (modulePath info) (packageModules (packageBody package)) of - Nothing -> lowerBound - Just m -> foldMapA pure (fmap SomeTerm <$> m) - runImportGraphAnalysis packageInfo - = run - . runState lowerBound - . runFresh 0 - . runIgnoringTrace - . resumingLoadError - . resumingUnspecialized - . resumingEnvironmentError - . resumingEvalError - . resumingResolutionError - . resumingAddressError - . resumingValueError - . runState lowerBound - . runReader lowerBound - . interpret (handleModules (ModuleTable.modulePaths (packageModules (packageBody package)))) - . runTermEvaluator @_ @_ @(Value (Hole Precise) (ImportGraphEff (Term (Sum syntaxes) (Record Location)) (Hole Precise))) - . runReader packageInfo - . runReader lowerBound - extractGraph <$> analyze (runImportGraphAnalysis (packageInfo package)) (evaluate @_ @_ @_ @_ @(Term (Sum syntaxes) (Record Location)) lang analyzeModule analyzeTerm (map snd (ModuleTable.toPairs (packageModules (packageBody package))))) +runImportGraph :: ( Declarations term + , Evaluatable (Base term) + , FreeVariables term + , HasPrelude lang + , Member Task effs + , Recursive term + ) + => Proxy lang + -> Package term + -> Eff effs (Graph (Module term)) +runImportGraph lang (package :: Package term) = do + let analyzeTerm = id + analyzeModule = graphingModuleInfo + extractGraph (((_, graph), _), _) = do + info <- graph + case ModuleTable.lookup (modulePath info) (packageModules (packageBody package)) of + Nothing -> lowerBound + Just m -> foldMapA pure m + runImportGraphAnalysis packageInfo + = run + . runState lowerBound + . runFresh 0 + . runIgnoringTrace + . resumingLoadError + . resumingUnspecialized + . resumingEnvironmentError + . resumingEvalError + . resumingResolutionError + . resumingAddressError + . resumingValueError + . runState lowerBound + . runReader lowerBound + . interpret (handleModules (ModuleTable.modulePaths (packageModules (packageBody package)))) + . runTermEvaluator @_ @_ @(Value (Hole Precise) (ImportGraphEff term (Hole Precise))) + . runReader packageInfo + . runReader lowerBound + extractGraph <$> analyze (runImportGraphAnalysis (packageInfo package)) (evaluate @_ @_ @_ @_ @term lang analyzeModule analyzeTerm (map snd (ModuleTable.toPairs (packageModules (packageBody package))))) newtype ImportGraphEff term address a = ImportGraphEff { runImportGraphEff :: Eff '[ LoopControl address From 4a7e54cee5cfaaafe20ac9eb95c5ea4d36fdc50c Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 12:26:04 -0400 Subject: [PATCH 083/169] Use the import graph as the load order for the call graph. --- src/Semantic/Graph.hs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index 96bbf12af..fcebde1b2 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -55,11 +55,12 @@ runGraph ImportGraph _ project runGraph CallGraph includePackages project | SomeAnalysisParser parser lang <- someAnalysisParser (Proxy :: Proxy AnalysisClasses) (projectLanguage project) = do package <- parsePackage parser project + modules <- runImportGraph lang package let analyzeTerm = withTermSpans . graphingTerms analyzeModule = (if includePackages then graphingPackages else id) . graphingModules - extractGraph <$> analyze runGraphAnalysis (evaluatePackageWith lang analyzeModule analyzeTerm package) + extractGraph <$> analyze (runGraphAnalysis package) (evaluate lang analyzeModule analyzeTerm (topologicalSort modules)) where extractGraph (((_, graph), _), _) = simplify graph - runGraphAnalysis + runGraphAnalysis package = run . evaluating . runFresh 0 @@ -73,6 +74,10 @@ runGraph CallGraph includePackages project . resumingValueError . runTermEvaluator @_ @_ @(Value (Hole (Located Precise)) (GraphEff _)) . graphing + . runReader (packageInfo package) + . runReader lowerBound + . runReader lowerBound + . raiseHandler (interpret (handleModules (ModuleTable.modulePaths (packageModules (packageBody package))))) -- | The full list of effects in flight during the evaluation of terms. This, and other @newtype@s like it, are necessary to type 'Value', since the bodies of closures embed evaluators. This would otherwise require cycles in the effect list (i.e. references to @effects@ within @effects@ itself), which the typechecker forbids. newtype GraphEff address a = GraphEff @@ -82,6 +87,7 @@ newtype GraphEff address a = GraphEff , Allocator address (Value address (GraphEff address)) , Reader ModuleInfo , Modules address + , Reader (ModuleTable (NonEmpty (Module (address, Environment address)))) , Reader Span , Reader PackageInfo , State (Graph Vertex) From 0bbd0f5448df5572e2ddf731873214b3f013e13b Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 12:27:00 -0400 Subject: [PATCH 084/169] Close over the package. --- src/Semantic/Graph.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index fcebde1b2..cccf2ea16 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -124,7 +124,7 @@ runImportGraph lang (package :: Package term) = do case ModuleTable.lookup (modulePath info) (packageModules (packageBody package)) of Nothing -> lowerBound Just m -> foldMapA pure m - runImportGraphAnalysis packageInfo + runImportGraphAnalysis = run . runState lowerBound . runFresh 0 @@ -140,9 +140,9 @@ runImportGraph lang (package :: Package term) = do . runReader lowerBound . interpret (handleModules (ModuleTable.modulePaths (packageModules (packageBody package)))) . runTermEvaluator @_ @_ @(Value (Hole Precise) (ImportGraphEff term (Hole Precise))) - . runReader packageInfo + . runReader (packageInfo package) . runReader lowerBound - extractGraph <$> analyze (runImportGraphAnalysis (packageInfo package)) (evaluate @_ @_ @_ @_ @term lang analyzeModule analyzeTerm (map snd (ModuleTable.toPairs (packageModules (packageBody package))))) + extractGraph <$> analyze runImportGraphAnalysis (evaluate @_ @_ @_ @_ @term lang analyzeModule analyzeTerm (map snd (ModuleTable.toPairs (packageModules (packageBody package))))) newtype ImportGraphEff term address a = ImportGraphEff { runImportGraphEff :: Eff '[ LoopControl address From a2d8397d3e849dc92058e28961beb1479ecc4149 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 12:28:13 -0400 Subject: [PATCH 085/169] Close over the package here as well. --- src/Semantic/Graph.hs | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index cccf2ea16..cc9670fe7 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -58,26 +58,26 @@ runGraph CallGraph includePackages project modules <- runImportGraph lang package let analyzeTerm = withTermSpans . graphingTerms analyzeModule = (if includePackages then graphingPackages else id) . graphingModules - extractGraph <$> analyze (runGraphAnalysis package) (evaluate lang analyzeModule analyzeTerm (topologicalSort modules)) - where extractGraph (((_, graph), _), _) = simplify graph - runGraphAnalysis package - = run - . evaluating - . runFresh 0 - . runIgnoringTrace - . resumingLoadError - . resumingUnspecialized - . resumingEnvironmentError - . resumingEvalError - . resumingResolutionError - . resumingAddressError - . resumingValueError - . runTermEvaluator @_ @_ @(Value (Hole (Located Precise)) (GraphEff _)) - . graphing - . runReader (packageInfo package) - . runReader lowerBound - . runReader lowerBound - . raiseHandler (interpret (handleModules (ModuleTable.modulePaths (packageModules (packageBody package))))) + extractGraph (((_, graph), _), _) = simplify graph + runGraphAnalysis + = run + . evaluating + . runFresh 0 + . runIgnoringTrace + . resumingLoadError + . resumingUnspecialized + . resumingEnvironmentError + . resumingEvalError + . resumingResolutionError + . resumingAddressError + . resumingValueError + . runTermEvaluator @_ @_ @(Value (Hole (Located Precise)) (GraphEff _)) + . graphing + . runReader (packageInfo package) + . runReader lowerBound + . runReader lowerBound + . raiseHandler (interpret (handleModules (ModuleTable.modulePaths (packageModules (packageBody package))))) + extractGraph <$> analyze runGraphAnalysis (evaluate lang analyzeModule analyzeTerm (topologicalSort modules)) -- | The full list of effects in flight during the evaluation of terms. This, and other @newtype@s like it, are necessary to type 'Value', since the bodies of closures embed evaluators. This would otherwise require cycles in the effect list (i.e. references to @effects@ within @effects@ itself), which the typechecker forbids. newtype GraphEff address a = GraphEff From 199bc12d866f0ea57a0ac1d4ed92be45c02296c4 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 12:42:25 -0400 Subject: [PATCH 086/169] :fire: the ModuleTable state effect. --- src/Semantic/Graph.hs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index cc9670fe7..ddb2d1c44 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -19,7 +19,6 @@ module Semantic.Graph , resumingEnvironmentError ) where -import Analysis.Abstract.Evaluating import Analysis.Abstract.Graph as Graph import Control.Abstract import Control.Monad.Effect (reinterpret) @@ -61,7 +60,7 @@ runGraph CallGraph includePackages project extractGraph (((_, graph), _), _) = simplify graph runGraphAnalysis = run - . evaluating + . runState lowerBound . runFresh 0 . runIgnoringTrace . resumingLoadError @@ -101,7 +100,6 @@ newtype GraphEff address a = GraphEff , Trace , Fresh , State (Heap address Latest (Value address (GraphEff address))) - , State (ModuleTable (Maybe (address, Environment address))) ] a } From e84c5a52445ca9a1518c611eb692eca69099c0ba Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 13:06:27 -0400 Subject: [PATCH 087/169] Align the path variables. --- src/Semantic/Util.hs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Semantic/Util.hs b/src/Semantic/Util.hs index 5fcb45152..72d28e28a 100644 --- a/src/Semantic/Util.hs +++ b/src/Semantic/Util.hs @@ -83,10 +83,10 @@ checking . runAddressError . runTypeError -evalGoProject path = justEvaluating =<< evaluateProject (Proxy :: Proxy 'Language.Go) goParser Language.Go path -evalRubyProject path = justEvaluating =<< evaluateProject (Proxy :: Proxy 'Language.Ruby) rubyParser Language.Ruby path -evalPHPProject path = justEvaluating =<< evaluateProject (Proxy :: Proxy 'Language.PHP) phpParser Language.PHP path -evalPythonProject path = justEvaluating =<< evaluateProject (Proxy :: Proxy 'Language.Python) pythonParser Language.Python path +evalGoProject path = justEvaluating =<< evaluateProject (Proxy :: Proxy 'Language.Go) goParser Language.Go path +evalRubyProject path = justEvaluating =<< evaluateProject (Proxy :: Proxy 'Language.Ruby) rubyParser Language.Ruby path +evalPHPProject path = justEvaluating =<< evaluateProject (Proxy :: Proxy 'Language.PHP) phpParser Language.PHP path +evalPythonProject path = justEvaluating =<< evaluateProject (Proxy :: Proxy 'Language.Python) pythonParser Language.Python path evalJavaScriptProject path = justEvaluating =<< evaluateProject (Proxy :: Proxy 'Language.JavaScript) typescriptParser Language.JavaScript path evalTypeScriptProject path = justEvaluating =<< evaluateProject (Proxy :: Proxy 'Language.TypeScript) typescriptParser Language.TypeScript path From 1e26865c65ddd003ca5df220e26f517502213bf9 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 13:19:24 -0400 Subject: [PATCH 088/169] :fire: evaluatePackageWith. --- src/Data/Abstract/Evaluatable.hs | 70 -------------------------------- src/Semantic/Util.hs | 34 ++++++++++++---- test/SpecHelpers.hs | 2 +- 3 files changed, 28 insertions(+), 78 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index d7c0907d6..aeb1dc062 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -3,7 +3,6 @@ module Data.Abstract.Evaluatable ( module X , Evaluatable(..) , evaluate -, evaluatePackageWith , traceResolve -- * Preludes , HasPrelude(..) @@ -31,7 +30,6 @@ import Data.Abstract.FreeVariables as X import Data.Abstract.Module import Data.Abstract.ModuleTable as ModuleTable import Data.Abstract.Name as X -import Data.Abstract.Package as Package import Data.Abstract.Ref as X import Data.Coerce import Data.Language @@ -120,74 +118,6 @@ evaluate lang analyzeModule analyzeTerm modules = do . runReturn . runLoopControl --- | Evaluate a given package. -evaluatePackageWith :: ( AbstractValue address value inner - -- FIXME: It’d be nice if we didn’t have to mention 'Addressable' here at all, but 'Located' locations require knowledge of 'currentModule' to run. Can we fix that? - , Addressable address inner' - , Declarations term - , Evaluatable (Base term) - , Foldable (Cell address) - , FreeVariables term - , HasPrelude lang - , Member Fresh outer - , Member (Resumable (AddressError address value)) outer - , Member (Resumable (EnvironmentError address)) outer - , Member (Resumable EvalError) outer - , Member (Resumable (LoadError address)) outer - , Member (Resumable ResolutionError) outer - , Member (Resumable (Unspecialized value)) outer - , Member (State (Heap address (Cell address) value)) outer - , Member (State (ModuleTable (Maybe (address, Environment address)))) outer - , Member Trace outer - , Recursive term - , Reducer value (Cell address value) - , ValueRoots address value - , inner ~ (LoopControl address ': Return address ': Env address ': Allocator address value ': inner') - , inner' ~ (Reader ModuleInfo ': inner'') - , inner'' ~ (Modules address ': Reader Span ': Reader PackageInfo ': outer) - ) - => proxy lang - -> (SubtermAlgebra Module term (TermEvaluator term address value inner address) -> SubtermAlgebra Module term (TermEvaluator term address value inner address)) - -> (SubtermAlgebra (Base term) term (TermEvaluator term address value inner (ValueRef address)) -> SubtermAlgebra (Base term) term (TermEvaluator term address value inner (ValueRef address))) - -> Package term - -> TermEvaluator term address value outer [(address, Environment address)] -evaluatePackageWith lang analyzeModule analyzeTerm package - = runReader (packageInfo package) - . runReader lowerBound - . runReader (packageModules (packageBody package)) - . withPrelude - $ \ preludeEnv - -> raiseHandler (runModules (runTermEvaluator . evalModule preludeEnv)) - . traverse (uncurry (evaluateEntryPoint preludeEnv)) - $ ModuleTable.toPairs (packageEntryPoints (packageBody package)) - where - evalModule preludeEnv m - = fmap (<$ m) - . runInModule preludeEnv (moduleInfo m) - . analyzeModule (subtermRef . moduleBody) - $ evalTerm <$> m - evalTerm term = Subterm term (TermEvaluator (address =<< runTermEvaluator (foldSubterms (analyzeTerm (TermEvaluator . eval . fmap (second runTermEvaluator))) term))) - - runInModule preludeEnv info - = runReader info - . raiseHandler runAllocator - . raiseHandler (runEnv preludeEnv) - . raiseHandler runReturn - . raiseHandler runLoopControl - - evaluateEntryPoint preludeEnv m sym = runInModule preludeEnv (ModuleInfo m) . TermEvaluator $ do - addr <- box unit -- TODO don't *always* allocate - use maybeM instead - (ptr, env) <- fromMaybe (addr, lowerBound) <$> require m - bindAll env - maybe (pure ptr) ((`call` []) <=< deref <=< variable) sym - - withPrelude f = do - (_, preludeEnv) <- raiseHandler (runModules (runTermEvaluator . evalModule lowerBound)) . runInModule lowerBound moduleInfoFromCallStack . TermEvaluator $ do - defineBuiltins - definePrelude lang - box unit - f preludeEnv - traceResolve :: (Show a, Show b, Member Trace effects) => a -> b -> Evaluator address value effects () traceResolve name path = trace ("resolved " <> show name <> " -> " <> show path) diff --git a/src/Semantic/Util.hs b/src/Semantic/Util.hs index 72d28e28a..9a68093fa 100644 --- a/src/Semantic/Util.hs +++ b/src/Semantic/Util.hs @@ -4,14 +4,17 @@ module Semantic.Util where import Analysis.Abstract.Caching import Analysis.Abstract.Collecting -import Analysis.Abstract.Evaluating import Control.Abstract import Control.Monad.Effect.Trace (runPrintingTrace) import Data.Abstract.Address import Data.Abstract.Evaluatable import Data.Abstract.Value +import Data.Abstract.Module +import qualified Data.Abstract.ModuleTable as ModuleTable +import Data.Abstract.Package import Data.Abstract.Type import Data.Blob +import Data.Graph (topologicalSort) import Data.Project import Data.Functor.Foldable import qualified Data.Language as Language @@ -29,7 +32,7 @@ import Text.Show.Pretty (ppShow) justEvaluating = runM - . evaluating + . runState lowerBound . runFresh 0 . runPrintingTrace . fmap reassociate @@ -39,7 +42,6 @@ justEvaluating . runEnvironmentError . runEvalError . runAddressError - . runTermEvaluator @_ @Precise @(Value Precise (UtilEff _)) . runValueError newtype UtilEff address a = UtilEff @@ -49,6 +51,7 @@ newtype UtilEff address a = UtilEff , Allocator address (Value address (UtilEff address)) , Reader ModuleInfo , Modules address + , Reader (ModuleTable (NonEmpty (Module (address, Environment address)))) , Reader Span , Reader PackageInfo , Resumable (ValueError address (UtilEff address)) @@ -61,14 +64,13 @@ newtype UtilEff address a = UtilEff , Trace , Fresh , State (Heap address Latest (Value address (UtilEff address))) - , State (ModuleTable (Maybe (address, Environment address))) , IO ] a } checking = runM @_ @IO - . evaluating + . runState (lowerBound @(Heap Monovariant All Type)) . runFresh 0 . runPrintingTrace . runTermEvaluator @_ @Monovariant @Type @@ -93,8 +95,26 @@ evalTypeScriptProject path = justEvaluating =<< evaluateProject (Proxy :: Proxy typecheckGoFile path = checking =<< evaluateProjectWithCaching (Proxy :: Proxy 'Language.Go) goParser Language.Go path -- Evaluate a project, starting at a single entrypoint. -evaluateProject proxy parser lang path = evaluatePackageWith proxy id withTermSpans . fmap quieterm <$> runTask (readProject Nothing path lang [] >>= parsePackage parser) -evaluateProjectWithCaching proxy parser lang path = evaluatePackageWith proxy convergingModules (withTermSpans . cachingTerms) . fmap quieterm <$> runTask (readProject Nothing path lang [] >>= parsePackage parser) +evaluateProject proxy parser lang path = runTask $ do + project <- readProject Nothing path lang [] + package <- fmap quieterm <$> parsePackage parser project + modules <- runImportGraph proxy package + pure (runTermEvaluator @_ @_ @(Value Precise (UtilEff Precise)) + (runReader (packageInfo package) + (runReader (lowerBound @Span) + (runReader (lowerBound @(ModuleTable (NonEmpty (Module (Precise, Environment Precise))))) + (raiseHandler (interpret (handleModules (ModuleTable.modulePaths (packageModules (packageBody package))))) + (evaluate proxy id withTermSpans (topologicalSort modules))))))) + +evaluateProjectWithCaching proxy parser lang path = runTask $ do + project <- readProject Nothing path lang [] + package <- fmap quieterm <$> parsePackage parser project + modules <- runImportGraph proxy package + pure (runReader (packageInfo package) + (runReader (lowerBound @Span) + (runReader (lowerBound @(ModuleTable (NonEmpty (Module (Monovariant, Environment Monovariant))))) + (raiseHandler (interpret (handleModules (ModuleTable.modulePaths (packageModules (packageBody package))))) + (evaluate proxy id withTermSpans (topologicalSort modules)))))) parseFile :: Parser term -> FilePath -> IO term diff --git a/test/SpecHelpers.hs b/test/SpecHelpers.hs index ce290f19c..5161b09b4 100644 --- a/test/SpecHelpers.hs +++ b/test/SpecHelpers.hs @@ -112,7 +112,7 @@ testEvaluating :: TermEvaluator term Precise testEvaluating = run . runReturningTrace - . evaluating + . runState lowerBound . runFresh 0 . fmap reassociate . runLoadError From e0f5d4ee229fa4d6930895363c7c86f846b67c69 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 13:22:58 -0400 Subject: [PATCH 089/169] =?UTF-8?q?Don=E2=80=99t=20use=20evaluating.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/Analysis/Go/Spec.hs | 8 ++++---- test/Analysis/PHP/Spec.hs | 12 ++++++------ test/Analysis/Python/Spec.hs | 12 ++++++------ test/Analysis/Ruby/Spec.hs | 10 +++++----- test/Analysis/TypeScript/Spec.hs | 6 +++--- test/Control/Abstract/Evaluator/Spec.hs | 3 +-- test/SpecHelpers.hs | 2 -- 7 files changed, 25 insertions(+), 28 deletions(-) diff --git a/test/Analysis/Go/Spec.hs b/test/Analysis/Go/Spec.hs index 08a4ebf3c..0c8ac17b6 100644 --- a/test/Analysis/Go/Spec.hs +++ b/test/Analysis/Go/Spec.hs @@ -11,16 +11,16 @@ spec :: Spec spec = parallel $ do describe "evaluates Go" $ do it "imports and wildcard imports" $ do - ((Right [(_, env)], state), _) <- evaluate "main.go" + ((Right [(_, env)], heap), _) <- evaluate "main.go" Env.names env `shouldBe` [ "Bar", "Rab", "foo", "main" ] - (derefQName (heap state) ("foo" :| []) env >>= deNamespace) `shouldBe` Just ("foo", ["New"]) + (derefQName heap ("foo" :| []) env >>= deNamespace) `shouldBe` Just ("foo", ["New"]) it "imports with aliases (and side effects only)" $ do - ((Right [(_, env)], state), _) <- evaluate "main1.go" + ((Right [(_, env)], heap), _) <- evaluate "main1.go" Env.names env `shouldBe` [ "f", "main" ] - (derefQName (heap state) ("f" :| []) env >>= deNamespace) `shouldBe` Just ("f", ["New"]) + (derefQName heap ("f" :| []) env >>= deNamespace) `shouldBe` Just ("f", ["New"]) where fixtures = "test/fixtures/go/analysis/" diff --git a/test/Analysis/PHP/Spec.hs b/test/Analysis/PHP/Spec.hs index d6bb2e589..7ba1c64c3 100644 --- a/test/Analysis/PHP/Spec.hs +++ b/test/Analysis/PHP/Spec.hs @@ -12,22 +12,22 @@ spec :: Spec spec = parallel $ do describe "PHP" $ do it "evaluates include and require" $ do - ((Right [(res, env)], state), _) <- evaluate "main.php" + ((Right [(res, env)], heap), _) <- evaluate "main.php" res `shouldBe` unit Env.names env `shouldBe` [ "bar", "foo" ] it "evaluates include_once and require_once" $ do - ((Right [(res, env)], state), _) <- evaluate "main_once.php" + ((Right [(res, env)], heap), _) <- evaluate "main_once.php" res `shouldBe` unit Env.names env `shouldBe` [ "bar", "foo" ] it "evaluates namespaces" $ do - ((Right [(_, env)], state), _) <- evaluate "namespaces.php" + ((Right [(_, env)], heap), _) <- evaluate "namespaces.php" Env.names env `shouldBe` [ "Foo", "NS1" ] - (derefQName (heap state) ("NS1" :| []) env >>= deNamespace) `shouldBe` Just ("NS1", ["Sub1", "b", "c"]) - (derefQName (heap state) ("NS1" :| ["Sub1"]) env >>= deNamespace) `shouldBe` Just ("Sub1", ["Sub2"]) - (derefQName (heap state) ("NS1" :| ["Sub1", "Sub2"]) env >>= deNamespace) `shouldBe` Just ("Sub2", ["f"]) + (derefQName heap ("NS1" :| []) env >>= deNamespace) `shouldBe` Just ("NS1", ["Sub1", "b", "c"]) + (derefQName heap ("NS1" :| ["Sub1"]) env >>= deNamespace) `shouldBe` Just ("Sub1", ["Sub2"]) + (derefQName heap ("NS1" :| ["Sub1", "Sub2"]) env >>= deNamespace) `shouldBe` Just ("Sub2", ["f"]) where fixtures = "test/fixtures/php/analysis/" diff --git a/test/Analysis/Python/Spec.hs b/test/Analysis/Python/Spec.hs index 753da4932..0386b130a 100644 --- a/test/Analysis/Python/Spec.hs +++ b/test/Analysis/Python/Spec.hs @@ -14,12 +14,12 @@ spec :: Spec spec = parallel $ do describe "evaluates Python" $ do it "imports" $ do - ((Right [(_, env)], state), _) <- evaluate "main.py" + ((Right [(_, env)], heap), _) <- evaluate "main.py" Env.names env `shouldContain` [ "a", "b" ] - (derefQName (heap state) ("a" :| []) env >>= deNamespace) `shouldBe` Just ("a", ["foo"]) - (derefQName (heap state) ("b" :| []) env >>= deNamespace) `shouldBe` Just ("b", ["c"]) - (derefQName (heap state) ("b" :| ["c"]) env >>= deNamespace) `shouldBe` Just ("c", ["baz"]) + (derefQName heap ("a" :| []) env >>= deNamespace) `shouldBe` Just ("a", ["foo"]) + (derefQName heap ("b" :| []) env >>= deNamespace) `shouldBe` Just ("b", ["c"]) + (derefQName heap ("b" :| ["c"]) env >>= deNamespace) `shouldBe` Just ("c", ["baz"]) it "imports with aliases" $ do ((Right [(_, env)], _), _) <- evaluate "main1.py" @@ -30,9 +30,9 @@ spec = parallel $ do Env.names env `shouldContain` [ "bar", "foo" ] it "imports with relative syntax" $ do - ((Right [(_, env)], state), _) <- evaluate "main3.py" + ((Right [(_, env)], heap), _) <- evaluate "main3.py" Env.names env `shouldContain` [ "utils" ] - (derefQName (heap state) ("utils" :| []) env >>= deNamespace) `shouldBe` Just ("utils", ["to_s"]) + (derefQName heap ("utils" :| []) env >>= deNamespace) `shouldBe` Just ("utils", ["to_s"]) it "subclasses" $ do ((res, _), _) <- evaluate "subclass.py" diff --git a/test/Analysis/Ruby/Spec.hs b/test/Analysis/Ruby/Spec.hs index 72cb00929..cd009e72e 100644 --- a/test/Analysis/Ruby/Spec.hs +++ b/test/Analysis/Ruby/Spec.hs @@ -20,7 +20,7 @@ spec :: Spec spec = parallel $ do describe "Ruby" $ do it "evaluates require_relative" $ do - ((Right [(res, env)], state), _) <- evaluate "main.rb" + ((Right [(res, env)], heap), _) <- evaluate "main.rb" res `shouldBe` Value.Integer (Number.Integer 1) Env.names env `shouldContain` ["foo"] @@ -29,18 +29,18 @@ spec = parallel $ do Env.names env `shouldContain` ["foo"] it "evaluates load with wrapper" $ do - ((res, state), _) <- evaluate "load-wrap.rb" + ((res, heap), _) <- evaluate "load-wrap.rb" res `shouldBe` Left (SomeExc (inject @(EnvironmentError Precise) (FreeVariable "foo"))) it "evaluates subclass" $ do - ((Right [(res, env)], state), _) <- evaluate "subclass.rb" + ((Right [(res, env)], heap), _) <- evaluate "subclass.rb" res `shouldBe` String "\"\"" Env.names env `shouldContain` [ "Bar", "Foo" ] - (derefQName (heap state) ("Bar" :| []) env >>= deNamespace) `shouldBe` Just ("Bar", ["baz", "foo", "inspect"]) + (derefQName heap ("Bar" :| []) env >>= deNamespace) `shouldBe` Just ("Bar", ["baz", "foo", "inspect"]) it "evaluates modules" $ do - ((Right [(res, env)], state), _) <- evaluate "modules.rb" + ((Right [(res, env)], heap), _) <- evaluate "modules.rb" res `shouldBe` String "\"\"" Env.names env `shouldContain` [ "Bar" ] diff --git a/test/Analysis/TypeScript/Spec.hs b/test/Analysis/TypeScript/Spec.hs index 7dca4e0aa..58aea6849 100644 --- a/test/Analysis/TypeScript/Spec.hs +++ b/test/Analysis/TypeScript/Spec.hs @@ -19,11 +19,11 @@ spec = parallel $ do Env.names env `shouldBe` [ "bar", "quz" ] it "imports with qualified names" $ do - ((Right [(_, env)], state), _) <- evaluate "main1.ts" + ((Right [(_, env)], heap), _) <- evaluate "main1.ts" Env.names env `shouldBe` [ "b", "z" ] - (derefQName (heap state) ("b" :| []) env >>= deNamespace) `shouldBe` Just ("b", [ "baz", "foo" ]) - (derefQName (heap state) ("z" :| []) env >>= deNamespace) `shouldBe` Just ("z", [ "baz", "foo" ]) + (derefQName heap ("b" :| []) env >>= deNamespace) `shouldBe` Just ("b", [ "baz", "foo" ]) + (derefQName heap ("z" :| []) env >>= deNamespace) `shouldBe` Just ("z", [ "baz", "foo" ]) it "side effect only imports" $ do ((res, _), _) <- evaluate "main2.ts" diff --git a/test/Control/Abstract/Evaluator/Spec.hs b/test/Control/Abstract/Evaluator/Spec.hs index c556be6de..5a26ac80d 100644 --- a/test/Control/Abstract/Evaluator/Spec.hs +++ b/test/Control/Abstract/Evaluator/Spec.hs @@ -4,7 +4,6 @@ module Control.Abstract.Evaluator.Spec , SpecEff(..) ) where -import Analysis.Abstract.Evaluating (evaluating) import Control.Abstract import Data.Abstract.Module import qualified Data.Abstract.Number as Number @@ -30,7 +29,7 @@ spec = parallel $ do evaluate = runM - . evaluating @Precise @Val + . runState (lowerBound @(Heap Precise Latest Val)) . runFresh 0 . runReader (PackageInfo (name "test") Nothing mempty) . runReader (ModuleInfo "test/Control/Abstract/Evaluator/Spec.hs") diff --git a/test/SpecHelpers.hs b/test/SpecHelpers.hs index 5161b09b4..b7cd13140 100644 --- a/test/SpecHelpers.hs +++ b/test/SpecHelpers.hs @@ -13,8 +13,6 @@ module SpecHelpers , Verbatim(..) ) where -import Analysis.Abstract.Evaluating -import Analysis.Abstract.Evaluating as X (EvaluatingState(..)) import Control.Abstract import Control.Arrow ((&&&)) import Control.Monad.Effect.Trace as X (runIgnoringTrace, runReturningTrace) From dda4c00cb538a61d29d6c2e76c50fbd30d760df6 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 13:26:22 -0400 Subject: [PATCH 090/169] :fire: Evaluating. --- semantic.cabal | 1 - src/Analysis/Abstract/Evaluating.hs | 29 ----------------------------- 2 files changed, 30 deletions(-) delete mode 100644 src/Analysis/Abstract/Evaluating.hs diff --git a/semantic.cabal b/semantic.cabal index f14a44b12..e713aa78d 100644 --- a/semantic.cabal +++ b/semantic.cabal @@ -22,7 +22,6 @@ library Analysis.Abstract.Caching , Analysis.Abstract.Collecting , Analysis.Abstract.Dead - , Analysis.Abstract.Evaluating , Analysis.Abstract.Graph , Analysis.Abstract.Tracing , Analysis.ConstructorName diff --git a/src/Analysis/Abstract/Evaluating.hs b/src/Analysis/Abstract/Evaluating.hs deleted file mode 100644 index 6794a95c3..000000000 --- a/src/Analysis/Abstract/Evaluating.hs +++ /dev/null @@ -1,29 +0,0 @@ -{-# LANGUAGE ScopedTypeVariables, TypeFamilies, TypeOperators, UndecidableInstances #-} -module Analysis.Abstract.Evaluating -( EvaluatingState(..) -, evaluating -) where - -import Control.Abstract -import Prologue - --- | An analysis evaluating @term@s to @value@s with a list of @effects@ using 'Evaluatable', and producing incremental results of type @a@. -data EvaluatingState address value = EvaluatingState - { heap :: Heap address (Cell address) value - , modules :: ModuleTable (Maybe (address, Environment address)) - } - -deriving instance (Eq (Cell address value), Eq address, Eq value) => Eq (EvaluatingState address value) -deriving instance (Ord (Cell address value), Ord address, Ord value) => Ord (EvaluatingState address value) -deriving instance (Show (Cell address value), Show address, Show value) => Show (EvaluatingState address value) - - -evaluating :: Evaluator address value - ( State (Heap address (Cell address) value) - ': State (ModuleTable (Maybe (address, Environment address))) - ': effects) result - -> Evaluator address value effects (result, EvaluatingState address value) -evaluating - = fmap (\ ((result, heap), modules) -> (result, EvaluatingState heap modules)) - . runState lowerBound -- State (ModuleTable (Maybe (address, Environment address))) - . runState lowerBound -- State (Heap address (Cell address) value) From f490cddddd71020c216872cfa739fcc6975f5fee Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 13:31:45 -0400 Subject: [PATCH 091/169] :fire: package entry points. --- src/Data/Abstract/Package.hs | 12 ++++-------- src/Semantic/Graph.hs | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/Data/Abstract/Package.hs b/src/Data/Abstract/Package.hs index e604698e2..d25e05ed8 100644 --- a/src/Data/Abstract/Package.hs +++ b/src/Data/Abstract/Package.hs @@ -20,9 +20,8 @@ data PackageInfo = PackageInfo newtype Version = Version { versionString :: String } deriving (Eq, Ord, Show) -data PackageBody term = PackageBody - { packageModules :: ModuleTable (NonEmpty (Module term)) - , packageEntryPoints :: ModuleTable (Maybe Name) +newtype PackageBody term = PackageBody + { packageModules :: ModuleTable (NonEmpty (Module term)) } deriving (Eq, Functor, Ord, Show) @@ -34,8 +33,5 @@ data Package term = Package } deriving (Eq, Functor, Ord, Show) -fromModules :: PackageName -> Maybe Version -> Int -> [Module term] -> Map.Map FilePath FilePath -> Package term -fromModules name version entryPoints modules resolutions = - Package (PackageInfo name version resolutions) (PackageBody (ModuleTable.fromModules modules) entryPoints') - where - entryPoints' = ModuleTable . Map.fromList $ (,Nothing) . modulePath . moduleInfo <$> if entryPoints == 0 then modules else take entryPoints modules +fromModules :: PackageName -> Maybe Version -> [Module term] -> Map.Map FilePath FilePath -> Package term +fromModules name version modules resolutions = Package (PackageInfo name version resolutions) (PackageBody (ModuleTable.fromModules modules)) diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index ddb2d1c44..409182a23 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -175,7 +175,7 @@ parsePackage :: (Member (Distribute WrappedTask) effs, Member Resolution effs, M parsePackage parser project@Project{..} = do p <- parseModules parser project resMap <- Task.resolutionMap project - let pkg = Package.fromModules n Nothing (length projectEntryPoints) p resMap + let pkg = Package.fromModules n Nothing p resMap pkg <$ trace ("project: " <> show pkg) where From 19eb04c51e3b0ff07acd055945a96af9024f5c6e Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 13:33:12 -0400 Subject: [PATCH 092/169] :fire: project entry points. --- src/Data/Project.hs | 1 - src/Semantic/Graph.hs | 2 +- src/Semantic/IO.hs | 10 +++++----- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/Data/Project.hs b/src/Data/Project.hs index 1c75ccc2e..4dfdbf76d 100644 --- a/src/Data/Project.hs +++ b/src/Data/Project.hs @@ -9,7 +9,6 @@ data Project = Project { projectRootDir :: FilePath , projectFiles :: [File] , projectLanguage :: Language - , projectEntryPoints :: [File] , projectExcludeDirs :: [FilePath] } deriving (Eq, Ord, Show) diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index 409182a23..fce7256e7 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -183,7 +183,7 @@ parsePackage parser project@Project{..} = do -- | Parse all files in a project into 'Module's. parseModules :: Member (Distribute WrappedTask) effs => Parser term -> Project -> Eff effs [Module term] - parseModules parser Project{..} = distributeFor (projectEntryPoints <> projectFiles) (WrapTask . parseModule parser (Just projectRootDir)) + parseModules parser Project{..} = distributeFor projectFiles (WrapTask . parseModule parser (Just projectRootDir)) -- | Parse a file into a 'Module'. parseModule :: (Member Files effs, Member Task effs) => Parser term -> Maybe FilePath -> File -> Eff effs (Module term) diff --git a/src/Semantic/IO.hs b/src/Semantic/IO.hs index 28169b290..c800eb587 100644 --- a/src/Semantic/IO.hs +++ b/src/Semantic/IO.hs @@ -100,12 +100,12 @@ readBlobFromPath file = do readProjectFromPaths :: MonadIO m => Maybe FilePath -> FilePath -> Language -> [FilePath] -> m Project readProjectFromPaths maybeRoot path lang excludeDirs = do isDir <- isDirectory path - let (filterFun, entryPoints, rootDir) = if isDir - then (id, [], fromMaybe path maybeRoot) - else (filter (/= path), [toFile path], fromMaybe (takeDirectory path) maybeRoot) + let rootDir = if isDir + then fromMaybe path maybeRoot + else fromMaybe (takeDirectory path) maybeRoot - paths <- liftIO $ filterFun <$> findFilesInDir rootDir exts excludeDirs - pure $ Project rootDir (toFile <$> paths) lang entryPoints excludeDirs + paths <- liftIO $ findFilesInDir rootDir exts excludeDirs + pure $ Project rootDir (toFile <$> paths) lang excludeDirs where toFile path = File path lang exts = extensionsForLanguage lang From 0c082082655e8542b968228953376c2281e6e5c2 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 13:34:05 -0400 Subject: [PATCH 093/169] Clarify the usage around graphing projects. --- src/Semantic/CLI.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Semantic/CLI.hs b/src/Semantic/CLI.hs index 77572ffd9..2d220d9d9 100644 --- a/src/Semantic/CLI.hs +++ b/src/Semantic/CLI.hs @@ -83,7 +83,7 @@ arguments = info (version <*> helper <*> ((,) <$> optionsParser <*> argumentsPar filesOrStdin <- Right <$> some (argument filePathReader (metavar "FILES...")) <|> pure (Left stdin) pure $ Task.readBlobs filesOrStdin >>= AST.runASTParse format - graphCommand = command "graph" (info graphArgumentsParser (progDesc "Compute a graph for a directory or entry point")) + graphCommand = command "graph" (info graphArgumentsParser (progDesc "Compute a graph for a directory or from a top-level entry point module")) graphArgumentsParser = do graphType <- flag Graph.ImportGraph Graph.ImportGraph (long "imports" <> help "Compute an import graph (default)") <|> flag' Graph.CallGraph (long "calls" <> help "Compute a call graph") From 418b15077ab18c30538a3cd8ea41be10e9e71fb6 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 13:34:42 -0400 Subject: [PATCH 094/169] Not EvaluatingState. --- test/SpecHelpers.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/SpecHelpers.hs b/test/SpecHelpers.hs index b7cd13140..67ff0c4d5 100644 --- a/test/SpecHelpers.hs +++ b/test/SpecHelpers.hs @@ -105,7 +105,7 @@ testEvaluating :: TermEvaluator term Precise , LoadError Precise ])) [(Value Precise TestEff, Environment Precise)], - EvaluatingState Precise Val), + Heap Precise Latest Val), [String]) testEvaluating = run From 4e57d32e91160c46d5f89049a0b9822f96f8e43d Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 13:36:11 -0400 Subject: [PATCH 095/169] :fire: the outdated reference to the module table state. --- test/SpecHelpers.hs | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/SpecHelpers.hs b/test/SpecHelpers.hs index 67ff0c4d5..bf330647e 100644 --- a/test/SpecHelpers.hs +++ b/test/SpecHelpers.hs @@ -89,7 +89,6 @@ testEvaluating :: TermEvaluator term Precise , Resumable (LoadError Precise) , Fresh , State (Heap Precise Latest Val) - , State (ModuleTable (Maybe (Precise, Environment Precise))) , Trace ] [(Precise, Environment Precise)] @@ -142,7 +141,6 @@ newtype TestEff a = TestEff , Resumable (LoadError Precise) , Fresh , State (Heap Precise Latest Val) - , State (ModuleTable (Maybe (Precise, Environment Precise))) , Trace ] a } From 84eb2beaa51c2f9bba6e67ee56c99be5836688b5 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 13:37:23 -0400 Subject: [PATCH 096/169] =?UTF-8?q?This=20doesn=E2=80=99t=20have=20module?= =?UTF-8?q?=20table=20state=20any=20more=20either.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/Control/Abstract/Evaluator/Spec.hs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/Control/Abstract/Evaluator/Spec.hs b/test/Control/Abstract/Evaluator/Spec.hs index 5a26ac80d..f35431564 100644 --- a/test/Control/Abstract/Evaluator/Spec.hs +++ b/test/Control/Abstract/Evaluator/Spec.hs @@ -59,7 +59,6 @@ newtype SpecEff a = SpecEff , Reader PackageInfo , Fresh , State (Heap Precise Latest Val) - , State (ModuleTable (Maybe (Precise, Environment Precise))) , IO ] a } From 07a0277b0027c246c855cf341bee99408a128c3d Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 13:42:03 -0400 Subject: [PATCH 097/169] Fix up the Evaluator spec. --- test/Control/Abstract/Evaluator/Spec.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Control/Abstract/Evaluator/Spec.hs b/test/Control/Abstract/Evaluator/Spec.hs index f35431564..a151174bb 100644 --- a/test/Control/Abstract/Evaluator/Spec.hs +++ b/test/Control/Abstract/Evaluator/Spec.hs @@ -37,7 +37,7 @@ evaluate . runValueError . runEnvironmentError . runAddressError - . runAllocator + . runAllocator @Precise @_ @Val . (>>= deref . fst) . runEnv lowerBound . runReturn From 3c537e3337d4f5051565c0900f10ac5d3d9820fe Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 13:44:58 -0400 Subject: [PATCH 098/169] =?UTF-8?q?We=E2=80=99re=20in=20Evaluator,=20not?= =?UTF-8?q?=20TermEvaluator.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/SpecHelpers.hs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/SpecHelpers.hs b/test/SpecHelpers.hs index bf330647e..d87b6e1f1 100644 --- a/test/SpecHelpers.hs +++ b/test/SpecHelpers.hs @@ -79,7 +79,7 @@ readFilePair :: Both FilePath -> IO BlobPair readFilePair paths = let paths' = fmap file paths in runBothWith IO.readFilePair paths' -testEvaluating :: TermEvaluator term Precise +testEvaluating :: Evaluator Precise Val '[ Resumable (ValueError Precise TestEff) , Resumable (AddressError Precise Val) @@ -118,9 +118,8 @@ testEvaluating . runEnvironmentError . runEvalError . runAddressError - . runValueError + . runValueError @_ @Precise @TestEff . (>>= traverse deref1) - . runTermEvaluator @_ @_ @Val type Val = Value Precise TestEff newtype TestEff a = TestEff From 6abd29a65ddbc209d2e64010343a4e002a1b9017 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 13:46:28 -0400 Subject: [PATCH 099/169] Reuse UtilEff. --- test/SpecHelpers.hs | 32 +++++--------------------------- 1 file changed, 5 insertions(+), 27 deletions(-) diff --git a/test/SpecHelpers.hs b/test/SpecHelpers.hs index d87b6e1f1..569a252d9 100644 --- a/test/SpecHelpers.hs +++ b/test/SpecHelpers.hs @@ -9,7 +9,6 @@ module SpecHelpers , derefQName , verbatim , TermEvaluator(..) -, TestEff(..) , Verbatim(..) ) where @@ -81,7 +80,7 @@ readFilePair paths = let paths' = fmap file paths in testEvaluating :: Evaluator Precise Val - '[ Resumable (ValueError Precise TestEff) + '[ Resumable (ValueError Precise (UtilEff Precise)) , Resumable (AddressError Precise Val) , Resumable EvalError, Resumable (EnvironmentError Precise) , Resumable ResolutionError @@ -95,7 +94,7 @@ testEvaluating :: Evaluator Precise -> ((Either (SomeExc (Data.Sum.Sum - '[ ValueError Precise TestEff + '[ ValueError Precise (UtilEff Precise) , AddressError Precise Val , EvalError , EnvironmentError Precise @@ -103,7 +102,7 @@ testEvaluating :: Evaluator Precise , Unspecialized Val , LoadError Precise ])) - [(Value Precise TestEff, Environment Precise)], + [(Value Precise (UtilEff Precise), Environment Precise)], Heap Precise Latest Val), [String]) testEvaluating @@ -118,31 +117,10 @@ testEvaluating . runEnvironmentError . runEvalError . runAddressError - . runValueError @_ @Precise @TestEff + . runValueError @_ @Precise @(UtilEff Precise) . (>>= traverse deref1) -type Val = Value Precise TestEff -newtype TestEff a = TestEff - { runTestEff :: Eff '[ LoopControl Precise - , Return Precise - , Env Precise - , Allocator Precise Val - , Reader ModuleInfo - , Modules Precise - , Reader Span - , Reader PackageInfo - , Resumable (ValueError Precise TestEff) - , Resumable (AddressError Precise Val) - , Resumable EvalError - , Resumable (EnvironmentError Precise) - , Resumable ResolutionError - , Resumable (Unspecialized Val) - , Resumable (LoadError Precise) - , Fresh - , State (Heap Precise Latest Val) - , Trace - ] a - } +type Val = Value Precise (UtilEff Precise) deref1 (ptr, env) = runAllocator $ do val <- deref ptr From eedc8f4b7ea32b8478c6073e34a0b3804c6782ec Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Thu, 21 Jun 2018 14:52:08 -0400 Subject: [PATCH 100/169] Rearrange the spec helper to match Util. --- test/Analysis/Go/Spec.hs | 2 +- test/Analysis/PHP/Spec.hs | 2 +- test/Analysis/Python/Spec.hs | 2 +- test/Analysis/Ruby/Spec.hs | 2 +- test/Analysis/TypeScript/Spec.hs | 2 +- test/SpecHelpers.hs | 16 +++++++++++----- 6 files changed, 16 insertions(+), 10 deletions(-) diff --git a/test/Analysis/Go/Spec.hs b/test/Analysis/Go/Spec.hs index 0c8ac17b6..c8d532ff7 100644 --- a/test/Analysis/Go/Spec.hs +++ b/test/Analysis/Go/Spec.hs @@ -25,4 +25,4 @@ spec = parallel $ do where fixtures = "test/fixtures/go/analysis/" evaluate entry = evalGoProject (fixtures <> entry) - evalGoProject path = testEvaluating <$> evaluateProject (Proxy :: Proxy 'Language.Go) goParser Language.Go path + evalGoProject path = testEvaluating =<< evaluateProject (Proxy :: Proxy 'Language.Go) goParser Language.Go path diff --git a/test/Analysis/PHP/Spec.hs b/test/Analysis/PHP/Spec.hs index 7ba1c64c3..be94b59e9 100644 --- a/test/Analysis/PHP/Spec.hs +++ b/test/Analysis/PHP/Spec.hs @@ -32,4 +32,4 @@ spec = parallel $ do where fixtures = "test/fixtures/php/analysis/" evaluate entry = evalPHPProject (fixtures <> entry) - evalPHPProject path = testEvaluating <$> evaluateProject (Proxy :: Proxy 'Language.PHP) phpParser Language.PHP path + evalPHPProject path = testEvaluating =<< evaluateProject (Proxy :: Proxy 'Language.PHP) phpParser Language.PHP path diff --git a/test/Analysis/Python/Spec.hs b/test/Analysis/Python/Spec.hs index 0386b130a..fa7e016eb 100644 --- a/test/Analysis/Python/Spec.hs +++ b/test/Analysis/Python/Spec.hs @@ -46,4 +46,4 @@ spec = parallel $ do ns n = Just . Latest . Last . Just . Namespace n fixtures = "test/fixtures/python/analysis/" evaluate entry = evalPythonProject (fixtures <> entry) - evalPythonProject path = testEvaluating <$> evaluateProject (Proxy :: Proxy 'Language.Python) pythonParser Language.Python path + evalPythonProject path = testEvaluating =<< evaluateProject (Proxy :: Proxy 'Language.Python) pythonParser Language.Python path diff --git a/test/Analysis/Ruby/Spec.hs b/test/Analysis/Ruby/Spec.hs index cd009e72e..8bf1a2cb6 100644 --- a/test/Analysis/Ruby/Spec.hs +++ b/test/Analysis/Ruby/Spec.hs @@ -77,4 +77,4 @@ spec = parallel $ do ns n = Just . Latest . Last . Just . Namespace n fixtures = "test/fixtures/ruby/analysis/" evaluate entry = evalRubyProject (fixtures <> entry) - evalRubyProject path = testEvaluating <$> evaluateProject (Proxy :: Proxy 'Language.Ruby) rubyParser Language.Ruby path + evalRubyProject path = testEvaluating =<< evaluateProject (Proxy :: Proxy 'Language.Ruby) rubyParser Language.Ruby path diff --git a/test/Analysis/TypeScript/Spec.hs b/test/Analysis/TypeScript/Spec.hs index 58aea6849..74e629d4a 100644 --- a/test/Analysis/TypeScript/Spec.hs +++ b/test/Analysis/TypeScript/Spec.hs @@ -40,4 +40,4 @@ spec = parallel $ do where fixtures = "test/fixtures/typescript/analysis/" evaluate entry = evalTypeScriptProject (fixtures <> entry) - evalTypeScriptProject path = testEvaluating <$> evaluateProject (Proxy :: Proxy 'Language.TypeScript) typescriptParser Language.TypeScript path + evalTypeScriptProject path = testEvaluating =<< evaluateProject (Proxy :: Proxy 'Language.TypeScript) typescriptParser Language.TypeScript path diff --git a/test/SpecHelpers.hs b/test/SpecHelpers.hs index 569a252d9..bf83ff636 100644 --- a/test/SpecHelpers.hs +++ b/test/SpecHelpers.hs @@ -10,6 +10,7 @@ module SpecHelpers , verbatim , TermEvaluator(..) , Verbatim(..) +, toList ) where import Control.Abstract @@ -21,6 +22,7 @@ import Data.Abstract.Environment as Env import Data.Abstract.Evaluatable import Data.Abstract.FreeVariables as X import Data.Abstract.Heap as X +import Data.Abstract.Module as X import Data.Abstract.ModuleTable as X hiding (lookup) import Data.Abstract.Name as X import Data.Abstract.Value (Value(..), ValueError, runValueError) @@ -30,6 +32,7 @@ import Data.ByteString.Builder (toLazyByteString) import Data.ByteString.Lazy (toStrict) import Data.Project as X import Data.Proxy as X +import Data.Foldable (toList) import Data.Functor.Listable as X import Data.Language as X import Data.List.NonEmpty as X (NonEmpty(..)) @@ -86,12 +89,13 @@ testEvaluating :: Evaluator Precise , Resumable ResolutionError , Resumable (Unspecialized Val) , Resumable (LoadError Precise) + , Trace , Fresh , State (Heap Precise Latest Val) - , Trace + , IO ] - [(Precise, Environment Precise)] - -> ((Either + (ModuleTable (NonEmpty (Module (Precise, Environment Precise)))) + -> IO ((Either (SomeExc (Data.Sum.Sum '[ ValueError Precise (UtilEff Precise) @@ -106,10 +110,11 @@ testEvaluating :: Evaluator Precise Heap Precise Latest Val), [String]) testEvaluating - = run - . runReturningTrace + = runM + . fmap (\ ((res, traces), heap) -> ((res, heap), traces)) . runState lowerBound . runFresh 0 + . runReturningTrace . fmap reassociate . runLoadError . runUnspecialized @@ -119,6 +124,7 @@ testEvaluating . runAddressError . runValueError @_ @Precise @(UtilEff Precise) . (>>= traverse deref1) + . fmap ((>>= map moduleBody . toList . snd) . toPairs) type Val = Value Precise (UtilEff Precise) From 4ec77ee8606ba5369a8422d88e3b05fff9272342 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 08:51:09 -0400 Subject: [PATCH 101/169] :fire: Package versions. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don’t have any way to populate this currently. --- src/Data/Abstract/Package.hs | 8 ++------ src/Semantic/Graph.hs | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Data/Abstract/Package.hs b/src/Data/Abstract/Package.hs index d25e05ed8..29ed3549e 100644 --- a/src/Data/Abstract/Package.hs +++ b/src/Data/Abstract/Package.hs @@ -12,14 +12,10 @@ type PackageName = Name -- | Metadata for a package (name and version). data PackageInfo = PackageInfo { packageName :: PackageName - , packageVersion :: Maybe Version , packageResolutions :: Map.Map FilePath FilePath } deriving (Eq, Ord, Show) -newtype Version = Version { versionString :: String } - deriving (Eq, Ord, Show) - newtype PackageBody term = PackageBody { packageModules :: ModuleTable (NonEmpty (Module term)) } @@ -33,5 +29,5 @@ data Package term = Package } deriving (Eq, Functor, Ord, Show) -fromModules :: PackageName -> Maybe Version -> [Module term] -> Map.Map FilePath FilePath -> Package term -fromModules name version modules resolutions = Package (PackageInfo name version resolutions) (PackageBody (ModuleTable.fromModules modules)) +fromModules :: PackageName -> [Module term] -> Map.Map FilePath FilePath -> Package term +fromModules name modules resolutions = Package (PackageInfo name resolutions) (PackageBody (ModuleTable.fromModules modules)) diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index fce7256e7..e1e149001 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -175,7 +175,7 @@ parsePackage :: (Member (Distribute WrappedTask) effs, Member Resolution effs, M parsePackage parser project@Project{..} = do p <- parseModules parser project resMap <- Task.resolutionMap project - let pkg = Package.fromModules n Nothing p resMap + let pkg = Package.fromModules n p resMap pkg <$ trace ("project: " <> show pkg) where From dfb43674d0cc44495e7cbbe6c080f75c9a2ace11 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 08:53:16 -0400 Subject: [PATCH 102/169] =?UTF-8?q?Don=E2=80=99t=20bother=20with=20do-nota?= =?UTF-8?q?tion.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Semantic/Graph.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index e1e149001..797029661 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -114,7 +114,7 @@ runImportGraph :: ( Declarations term => Proxy lang -> Package term -> Eff effs (Graph (Module term)) -runImportGraph lang (package :: Package term) = do +runImportGraph lang (package :: Package term) = let analyzeTerm = id analyzeModule = graphingModuleInfo extractGraph (((_, graph), _), _) = do @@ -140,7 +140,7 @@ runImportGraph lang (package :: Package term) = do . runTermEvaluator @_ @_ @(Value (Hole Precise) (ImportGraphEff term (Hole Precise))) . runReader (packageInfo package) . runReader lowerBound - extractGraph <$> analyze runImportGraphAnalysis (evaluate @_ @_ @_ @_ @term lang analyzeModule analyzeTerm (map snd (ModuleTable.toPairs (packageModules (packageBody package))))) + in extractGraph <$> analyze runImportGraphAnalysis (evaluate @_ @_ @_ @_ @term lang analyzeModule analyzeTerm (map snd (ModuleTable.toPairs (packageModules (packageBody package))))) newtype ImportGraphEff term address a = ImportGraphEff { runImportGraphEff :: Eff '[ LoopControl address From 764c2130a845c7c6999ec7571d1eb6a6edc4ea10 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 08:55:45 -0400 Subject: [PATCH 103/169] :fire: PackageBody. --- src/Data/Abstract/Package.hs | 10 ++-------- src/Semantic/Graph.hs | 8 ++++---- src/Semantic/Util.hs | 4 ++-- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/Data/Abstract/Package.hs b/src/Data/Abstract/Package.hs index 29ed3549e..5ee89b265 100644 --- a/src/Data/Abstract/Package.hs +++ b/src/Data/Abstract/Package.hs @@ -16,18 +16,12 @@ data PackageInfo = PackageInfo } deriving (Eq, Ord, Show) -newtype PackageBody term = PackageBody - { packageModules :: ModuleTable (NonEmpty (Module term)) - } - deriving (Eq, Functor, Ord, Show) - - -- | A package represents the unit of dependency, i.e. something which can depend upon, or be depended upon by, other packages. Packages have modules and may have entry points from which evaluation can proceed. data Package term = Package { packageInfo :: PackageInfo - , packageBody :: PackageBody term + , packageModules :: ModuleTable (NonEmpty (Module term)) } deriving (Eq, Functor, Ord, Show) fromModules :: PackageName -> [Module term] -> Map.Map FilePath FilePath -> Package term -fromModules name modules resolutions = Package (PackageInfo name resolutions) (PackageBody (ModuleTable.fromModules modules)) +fromModules name modules resolutions = Package (PackageInfo name resolutions) (ModuleTable.fromModules modules) diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index 797029661..64a31dc7a 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -75,7 +75,7 @@ runGraph CallGraph includePackages project . runReader (packageInfo package) . runReader lowerBound . runReader lowerBound - . raiseHandler (interpret (handleModules (ModuleTable.modulePaths (packageModules (packageBody package))))) + . raiseHandler (interpret (handleModules (ModuleTable.modulePaths (packageModules package)))) extractGraph <$> analyze runGraphAnalysis (evaluate lang analyzeModule analyzeTerm (topologicalSort modules)) -- | The full list of effects in flight during the evaluation of terms. This, and other @newtype@s like it, are necessary to type 'Value', since the bodies of closures embed evaluators. This would otherwise require cycles in the effect list (i.e. references to @effects@ within @effects@ itself), which the typechecker forbids. @@ -119,7 +119,7 @@ runImportGraph lang (package :: Package term) = analyzeModule = graphingModuleInfo extractGraph (((_, graph), _), _) = do info <- graph - case ModuleTable.lookup (modulePath info) (packageModules (packageBody package)) of + case ModuleTable.lookup (modulePath info) (packageModules package) of Nothing -> lowerBound Just m -> foldMapA pure m runImportGraphAnalysis @@ -136,11 +136,11 @@ runImportGraph lang (package :: Package term) = . resumingValueError . runState lowerBound . runReader lowerBound - . interpret (handleModules (ModuleTable.modulePaths (packageModules (packageBody package)))) + . interpret (handleModules (ModuleTable.modulePaths (packageModules package))) . runTermEvaluator @_ @_ @(Value (Hole Precise) (ImportGraphEff term (Hole Precise))) . runReader (packageInfo package) . runReader lowerBound - in extractGraph <$> analyze runImportGraphAnalysis (evaluate @_ @_ @_ @_ @term lang analyzeModule analyzeTerm (map snd (ModuleTable.toPairs (packageModules (packageBody package))))) + in extractGraph <$> analyze runImportGraphAnalysis (evaluate @_ @_ @_ @_ @term lang analyzeModule analyzeTerm (map snd (ModuleTable.toPairs (packageModules package)))) newtype ImportGraphEff term address a = ImportGraphEff { runImportGraphEff :: Eff '[ LoopControl address diff --git a/src/Semantic/Util.hs b/src/Semantic/Util.hs index 9a68093fa..d1b097956 100644 --- a/src/Semantic/Util.hs +++ b/src/Semantic/Util.hs @@ -103,7 +103,7 @@ evaluateProject proxy parser lang path = runTask $ do (runReader (packageInfo package) (runReader (lowerBound @Span) (runReader (lowerBound @(ModuleTable (NonEmpty (Module (Precise, Environment Precise))))) - (raiseHandler (interpret (handleModules (ModuleTable.modulePaths (packageModules (packageBody package))))) + (raiseHandler (interpret (handleModules (ModuleTable.modulePaths (packageModules package)))) (evaluate proxy id withTermSpans (topologicalSort modules))))))) evaluateProjectWithCaching proxy parser lang path = runTask $ do @@ -113,7 +113,7 @@ evaluateProjectWithCaching proxy parser lang path = runTask $ do pure (runReader (packageInfo package) (runReader (lowerBound @Span) (runReader (lowerBound @(ModuleTable (NonEmpty (Module (Monovariant, Environment Monovariant))))) - (raiseHandler (interpret (handleModules (ModuleTable.modulePaths (packageModules (packageBody package))))) + (raiseHandler (interpret (handleModules (ModuleTable.modulePaths (packageModules package)))) (evaluate proxy id withTermSpans (topologicalSort modules)))))) From 7bed885279abaaca176485597771183b655df589 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 09:05:05 -0400 Subject: [PATCH 104/169] Skip graphing imports in the single module case. --- src/Semantic/Graph.hs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index 64a31dc7a..c0121a9bf 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -109,12 +109,16 @@ runImportGraph :: ( Declarations term , FreeVariables term , HasPrelude lang , Member Task effs + , Member Trace effs , Recursive term ) => Proxy lang -> Package term -> Eff effs (Graph (Module term)) -runImportGraph lang (package :: Package term) = +runImportGraph lang (package :: Package term) + -- Optimization for the common (when debugging) case of one-and-only-one module. + | [m :| []] <- toList (packageModules package) = vertex m <$ trace ("single module, skipping import graph computation for " <> modulePath (moduleInfo m)) + | otherwise = let analyzeTerm = id analyzeModule = graphingModuleInfo extractGraph (((_, graph), _), _) = do From 5efa9eb56d028309d5eb693f06b0425b82a8cc78 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 09:29:21 -0400 Subject: [PATCH 105/169] We no longer use tuple sections here. --- src/Data/Abstract/Package.hs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Data/Abstract/Package.hs b/src/Data/Abstract/Package.hs index 5ee89b265..38136f0c9 100644 --- a/src/Data/Abstract/Package.hs +++ b/src/Data/Abstract/Package.hs @@ -1,4 +1,3 @@ -{-# LANGUAGE TupleSections #-} module Data.Abstract.Package where import Data.Abstract.Module From cac0043c68b60cbb3084875c77fcc7a6b9f65e8f Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 09:30:14 -0400 Subject: [PATCH 106/169] Re-export Options & defaultOptions. --- src/Semantic/Task.hs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Semantic/Task.hs b/src/Semantic/Task.hs index 7b17a303a..be39421b6 100644 --- a/src/Semantic/Task.hs +++ b/src/Semantic/Task.hs @@ -32,6 +32,8 @@ module Semantic.Task , distributeFoldMap -- * Configuration , defaultConfig +, defaultOptions +, Options(..) , terminalFormatter , logfmtFormatter -- * Interpreting From b981b0c2e55cd6cf1bcee9dce0cfc38706a5231b Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 09:31:32 -0400 Subject: [PATCH 107/169] Add default options for debugging. --- src/Semantic/Config.hs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Semantic/Config.hs b/src/Semantic/Config.hs index 2ba260cc2..1c2a2c560 100644 --- a/src/Semantic/Config.hs +++ b/src/Semantic/Config.hs @@ -44,6 +44,9 @@ data Options defaultOptions :: Options defaultOptions = Options (Just Warning) Nothing False +debugOptions :: Options +debugOptions = Options (Just Debug) Nothing False + defaultConfig :: Options -> IO Config defaultConfig options@Options{..} = do pid <- getProcessID From bd12fd92f94eea818cf763acd63cc025a26727f2 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 09:31:37 -0400 Subject: [PATCH 108/169] Re-export debugOptions. --- src/Semantic/Task.hs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Semantic/Task.hs b/src/Semantic/Task.hs index be39421b6..277367372 100644 --- a/src/Semantic/Task.hs +++ b/src/Semantic/Task.hs @@ -31,9 +31,8 @@ module Semantic.Task , distributeFor , distributeFoldMap -- * Configuration +, debugOptions , defaultConfig -, defaultOptions -, Options(..) , terminalFormatter , logfmtFormatter -- * Interpreting From 0c882fba877cafcde17cdbdeb56648e61e596059 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 09:32:37 -0400 Subject: [PATCH 109/169] Run in ghci & the tests with debug options. --- src/Semantic/Util.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Semantic/Util.hs b/src/Semantic/Util.hs index d1b097956..5455ceaa2 100644 --- a/src/Semantic/Util.hs +++ b/src/Semantic/Util.hs @@ -95,7 +95,7 @@ evalTypeScriptProject path = justEvaluating =<< evaluateProject (Proxy :: Proxy typecheckGoFile path = checking =<< evaluateProjectWithCaching (Proxy :: Proxy 'Language.Go) goParser Language.Go path -- Evaluate a project, starting at a single entrypoint. -evaluateProject proxy parser lang path = runTask $ do +evaluateProject proxy parser lang path = runTaskWithOptions debugOptions $ do project <- readProject Nothing path lang [] package <- fmap quieterm <$> parsePackage parser project modules <- runImportGraph proxy package @@ -106,7 +106,7 @@ evaluateProject proxy parser lang path = runTask $ do (raiseHandler (interpret (handleModules (ModuleTable.modulePaths (packageModules package)))) (evaluate proxy id withTermSpans (topologicalSort modules))))))) -evaluateProjectWithCaching proxy parser lang path = runTask $ do +evaluateProjectWithCaching proxy parser lang path = runTaskWithOptions debugOptions $ do project <- readProject Nothing path lang [] package <- fmap quieterm <$> parsePackage parser project modules <- runImportGraph proxy package From c0fe998bd51133d9e9caf0e1b64c55bd5ad92ae6 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 10:07:35 -0400 Subject: [PATCH 110/169] Spacing. --- src/Semantic/Graph.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index c0121a9bf..36074c70f 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -42,7 +42,7 @@ data GraphType = ImportGraph | CallGraph type AnalysisClasses = '[ Declarations1, Eq1, Evaluatable, FreeVariables1, Functor, Ord1, Show1 ] -runGraph :: ( Member (Distribute WrappedTask) effs, Member Resolution effs, Member Task effs, Member Trace effs) +runGraph :: (Member (Distribute WrappedTask) effs, Member Resolution effs, Member Task effs, Member Trace effs) => GraphType -> Bool -> Project From 8cabd289111a272e7c5e8b94aa80d993c2c5dd4c Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 10:29:53 -0400 Subject: [PATCH 111/169] We can foldMap instead of foldMapA. --- src/Semantic/Graph.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index 36074c70f..d6797f063 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -125,7 +125,7 @@ runImportGraph lang (package :: Package term) info <- graph case ModuleTable.lookup (modulePath info) (packageModules package) of Nothing -> lowerBound - Just m -> foldMapA pure m + Just m -> foldMap vertex m runImportGraphAnalysis = run . runState lowerBound From 47411feb730e52db56dc3e06bc9c9ad446aa61f6 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 10:30:58 -0400 Subject: [PATCH 112/169] Tighten up the module table lookup. --- src/Semantic/Graph.hs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index d6797f063..7d45409fe 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -123,9 +123,7 @@ runImportGraph lang (package :: Package term) analyzeModule = graphingModuleInfo extractGraph (((_, graph), _), _) = do info <- graph - case ModuleTable.lookup (modulePath info) (packageModules package) of - Nothing -> lowerBound - Just m -> foldMap vertex m + maybe lowerBound (foldMap vertex) (ModuleTable.lookup (modulePath info) (packageModules package)) runImportGraphAnalysis = run . runState lowerBound From 9fa1befecb405ca5f534c268614bdc8a6b2c5c83 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 10:33:29 -0400 Subject: [PATCH 113/169] =?UTF-8?q?Graph=20modules=20which=20don=E2=80=99t?= =?UTF-8?q?=20import,=20and=20aren=E2=80=99t=20imported=20by,=20other=20mo?= =?UTF-8?q?dules.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Analysis/Abstract/Graph.hs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Analysis/Abstract/Graph.hs b/src/Analysis/Abstract/Graph.hs index 5e7ea8ac9..a4538acb5 100644 --- a/src/Analysis/Abstract/Graph.hs +++ b/src/Analysis/Abstract/Graph.hs @@ -99,11 +99,13 @@ graphingModuleInfo :: forall term address value effects a ) => SubtermAlgebra Module term (TermEvaluator term address value effects a) -> SubtermAlgebra Module term (TermEvaluator term address value effects a) -graphingModuleInfo recur m = interpose @(Modules address) pure (\ eff yield -> case eff of - Load path -> currentModule >>= appendGraph . (`connect` vertex (ModuleInfo path)) . vertex >> send eff >>= yield - Lookup path -> currentModule >>= appendGraph . (`connect` vertex (ModuleInfo path)) . vertex >> send eff >>= yield - _ -> send eff >>= yield) - (recur m) +graphingModuleInfo recur m = do + appendGraph (vertex (moduleInfo m)) + interpose @(Modules address) pure (\ eff yield -> case eff of + Load path -> currentModule >>= appendGraph . (`connect` vertex (ModuleInfo path)) . vertex >> send eff >>= yield + Lookup path -> currentModule >>= appendGraph . (`connect` vertex (ModuleInfo path)) . vertex >> send eff >>= yield + _ -> send eff >>= yield) + (recur m) packageVertex :: PackageInfo -> Vertex From 92d50024eeb4596859bf4d4db7ac26b7f7e431fc Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 10:34:24 -0400 Subject: [PATCH 114/169] Ditto for the call graph. --- src/Analysis/Abstract/Graph.hs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Analysis/Abstract/Graph.hs b/src/Analysis/Abstract/Graph.hs index a4538acb5..fcbfa5e55 100644 --- a/src/Analysis/Abstract/Graph.hs +++ b/src/Analysis/Abstract/Graph.hs @@ -85,11 +85,13 @@ graphingModules :: forall term address value effects a ) => SubtermAlgebra Module term (TermEvaluator term address value effects a) -> SubtermAlgebra Module term (TermEvaluator term address value effects a) -graphingModules recur m = interpose @(Modules address) pure (\ m yield -> case m of - Load path -> moduleInclusion (moduleVertex (ModuleInfo path)) >> send m >>= yield - Lookup path -> moduleInclusion (moduleVertex (ModuleInfo path)) >> send m >>= yield - _ -> send m >>= yield) - (recur m) +graphingModules recur m = do + appendGraph (vertex (moduleVertex (moduleInfo m))) + interpose @(Modules address) pure (\ m yield -> case m of + Load path -> moduleInclusion (moduleVertex (ModuleInfo path)) >> send m >>= yield + Lookup path -> moduleInclusion (moduleVertex (ModuleInfo path)) >> send m >>= yield + _ -> send m >>= yield) + (recur m) -- | Add vertices to the graph for imported modules. graphingModuleInfo :: forall term address value effects a From 12c5dc32b269bcec7318bf74f7952dc37cec1c43 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 10:38:03 -0400 Subject: [PATCH 115/169] :fire: an errant package version. --- test/Control/Abstract/Evaluator/Spec.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Control/Abstract/Evaluator/Spec.hs b/test/Control/Abstract/Evaluator/Spec.hs index a151174bb..0d54f31b9 100644 --- a/test/Control/Abstract/Evaluator/Spec.hs +++ b/test/Control/Abstract/Evaluator/Spec.hs @@ -31,7 +31,7 @@ evaluate = runM . runState (lowerBound @(Heap Precise Latest Val)) . runFresh 0 - . runReader (PackageInfo (name "test") Nothing mempty) + . runReader (PackageInfo (name "test") mempty) . runReader (ModuleInfo "test/Control/Abstract/Evaluator/Spec.hs") . fmap reassociate . runValueError From 18b0b37e2ed8a085e8dd33e8f2f9f2331e7bf67c Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 11:20:35 -0400 Subject: [PATCH 116/169] Define a better Show instance for ModuleInfo. --- src/Data/Abstract/Module.hs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Data/Abstract/Module.hs b/src/Data/Abstract/Module.hs index ed1880605..a9cafb042 100644 --- a/src/Data/Abstract/Module.hs +++ b/src/Data/Abstract/Module.hs @@ -32,7 +32,10 @@ moduleForBlob rootDir Blob{..} = Module info type ModulePath = FilePath newtype ModuleInfo = ModuleInfo { modulePath :: ModulePath } - deriving (Eq, Ord, Show) + deriving (Eq, Ord) + +instance Show ModuleInfo where + showsPrec d = showsUnaryWith showsPrec "ModuleInfo" d . modulePath moduleInfoFromSrcLoc :: SrcLoc -> ModuleInfo moduleInfoFromSrcLoc = ModuleInfo . srcLocModule From d97e23583324d96c32afba20247e4442db2aec5d Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 11:21:10 -0400 Subject: [PATCH 117/169] Rename the term parameter to body. --- src/Data/Abstract/Module.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Data/Abstract/Module.hs b/src/Data/Abstract/Module.hs index a9cafb042..60c060bd8 100644 --- a/src/Data/Abstract/Module.hs +++ b/src/Data/Abstract/Module.hs @@ -12,10 +12,10 @@ import GHC.Stack import Prologue import System.FilePath.Posix -data Module term = Module { moduleInfo :: ModuleInfo, moduleBody :: term } +data Module body = Module { moduleInfo :: ModuleInfo, moduleBody :: body } deriving (Eq, Foldable, Functor, Ord, Traversable) -instance Show (Module term) where +instance Show (Module body) where showsPrec _ Module{..} = shows moduleInfo From 05cf17d258b3086234214668f4cd8d212bd675b3 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 11:22:33 -0400 Subject: [PATCH 118/169] Show Module bodies. --- src/Data/Abstract/Module.hs | 4 ++-- src/Semantic/Graph.hs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Data/Abstract/Module.hs b/src/Data/Abstract/Module.hs index 60c060bd8..574640f7d 100644 --- a/src/Data/Abstract/Module.hs +++ b/src/Data/Abstract/Module.hs @@ -15,8 +15,8 @@ import System.FilePath.Posix data Module body = Module { moduleInfo :: ModuleInfo, moduleBody :: body } deriving (Eq, Foldable, Functor, Ord, Traversable) -instance Show (Module body) where - showsPrec _ Module{..} = shows moduleInfo +instance Show body => Show (Module body) where + showsPrec d Module{..} = showsBinaryWith showsPrec showsPrec "Module" d moduleInfo moduleBody -- | Construct a 'Module' for a 'Blob' and @term@, relative to some root 'FilePath'. diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index 7d45409fe..8e75d8556 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -178,7 +178,7 @@ parsePackage parser project@Project{..} = do p <- parseModules parser project resMap <- Task.resolutionMap project let pkg = Package.fromModules n p resMap - pkg <$ trace ("project: " <> show pkg) + pkg <$ trace ("project: " <> show (() <$ pkg)) where n = name (projectName project) From c7c2d208067c6cef138e83ac5bf100966fd21678 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 11:23:07 -0400 Subject: [PATCH 119/169] AAbbreviate the Show instance for Module a little further. --- src/Data/Abstract/Module.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Data/Abstract/Module.hs b/src/Data/Abstract/Module.hs index 574640f7d..5d495ecbf 100644 --- a/src/Data/Abstract/Module.hs +++ b/src/Data/Abstract/Module.hs @@ -16,7 +16,7 @@ data Module body = Module { moduleInfo :: ModuleInfo, moduleBody :: body } deriving (Eq, Foldable, Functor, Ord, Traversable) instance Show body => Show (Module body) where - showsPrec d Module{..} = showsBinaryWith showsPrec showsPrec "Module" d moduleInfo moduleBody + showsPrec d Module{..} = showsBinaryWith showsPrec showsPrec "Module" d (modulePath moduleInfo) moduleBody -- | Construct a 'Module' for a 'Blob' and @term@, relative to some root 'FilePath'. From 11bdda42ce551186620e8e213abfeef75ee23318 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 11:28:49 -0400 Subject: [PATCH 120/169] :fire: runModules & friends. --- src/Control/Abstract/Modules.hs | 52 --------------------------------- 1 file changed, 52 deletions(-) diff --git a/src/Control/Abstract/Modules.hs b/src/Control/Abstract/Modules.hs index 220d8ba45..a17668ac3 100644 --- a/src/Control/Abstract/Modules.hs +++ b/src/Control/Abstract/Modules.hs @@ -6,7 +6,6 @@ module Control.Abstract.Modules , require , load , Modules(..) -, runModules , handleModules , LoadError(..) , moduleNotFound @@ -63,36 +62,6 @@ data Modules address return where sendModules :: Member (Modules address) effects => Modules address return -> Evaluator address value effects return sendModules = send -runModules :: forall term address value effects a - . ( Member (Resumable (LoadError address)) effects - , Member (State (ModuleTable (Maybe (address, Environment address)))) effects - , Member Trace effects - ) - => (Module term -> Evaluator address value (Modules address ': effects) (Module (address, Environment address))) - -> Evaluator address value (Modules address ': effects) a - -> Evaluator address value (Reader (ModuleTable (NonEmpty (Module term))) ': effects) a -runModules evaluateModule = go - where go :: forall a . Evaluator address value (Modules address ': effects) a -> Evaluator address value (Reader (ModuleTable (NonEmpty (Module term))) ': effects) a - go = reinterpret (\ m -> case m of - Load name -> askModuleTable @term >>= maybe (moduleNotFound name) (runMerging . foldMap (Merging . evalAndCache)) . ModuleTable.lookup name - where - evalAndCache x = do - let mPath = modulePath (moduleInfo x) - loading <- loadingModule mPath - if loading - then trace ("load (skip evaluating, circular load): " <> show mPath) $> Nothing - else do - _ <- cacheModule name Nothing - result <- trace ("load (evaluating): " <> show mPath) *> go (evaluateModule x) <* trace ("load done:" <> show mPath) - cacheModule name (Just (moduleBody result)) - - loadingModule path = isJust . ModuleTable.lookup path <$> getModuleTable - Lookup path -> ModuleTable.lookup path <$> get - Resolve names -> do - isMember <- flip ModuleTable.member <$> askModuleTable @term - pure (find isMember names) - List dir -> modulePathsInDir dir <$> askModuleTable @term) - handleModules :: Member (Reader (ModuleTable (NonEmpty (Module (address, Environment address))))) effects => Set ModulePath -> Modules address a @@ -103,31 +72,10 @@ handleModules paths = \case Resolve names -> pure (find (flip Set.member paths) names) List dir -> pure (filter ((dir ==) . takeDirectory) (toList paths)) -getModuleTable :: Member (State (ModuleTable (Maybe (address, Environment address)))) effects => Evaluator address value effects (ModuleTable (Maybe (address, Environment address))) -getModuleTable = get - -cacheModule :: Member (State (ModuleTable (Maybe (address, Environment address)))) effects => ModulePath -> Maybe (address, Environment address) -> Evaluator address value effects (Maybe (address, Environment address)) -cacheModule path result = modify' (ModuleTable.insert path result) $> result - -askModuleTable :: Member (Reader (ModuleTable (NonEmpty (Module term)))) effects => Evaluator address value effects (ModuleTable (NonEmpty (Module term))) -askModuleTable = ask - askModuleTable' :: Member (Reader (ModuleTable (NonEmpty (Module (address, Environment address))))) effects => Evaluator address value effects (ModuleTable (NonEmpty (Module (address, Environment address)))) askModuleTable' = ask -newtype Merging m address = Merging { runMerging :: m (Maybe (address, Environment address)) } - -instance Applicative m => Semigroup (Merging m address) where - Merging a <> Merging b = Merging (merge <$> a <*> b) - where merge a b = mergeJusts <$> a <*> b <|> a <|> b - mergeJusts (_, env1) (v, env2) = (v, mergeEnvs env1 env2) - -instance Applicative m => Monoid (Merging m address) where - mappend = (<>) - mempty = Merging (pure Nothing) - - newtype Merging' address = Merging' { runMerging' :: (address, Environment address) } instance Semigroup (Merging' address) where From d3fad310f34d2e0e47b5a14de6ece7e530bd7826 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 11:31:02 -0400 Subject: [PATCH 121/169] Repackage handleModules as a complete handler. --- src/Control/Abstract/Modules.hs | 12 ++++++------ src/Semantic/Graph.hs | 4 ++-- src/Semantic/Util.hs | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Control/Abstract/Modules.hs b/src/Control/Abstract/Modules.hs index a17668ac3..e7abe2458 100644 --- a/src/Control/Abstract/Modules.hs +++ b/src/Control/Abstract/Modules.hs @@ -6,7 +6,7 @@ module Control.Abstract.Modules , require , load , Modules(..) -, handleModules +, runModules , LoadError(..) , moduleNotFound , resumeLoadError @@ -62,11 +62,11 @@ data Modules address return where sendModules :: Member (Modules address) effects => Modules address return -> Evaluator address value effects return sendModules = send -handleModules :: Member (Reader (ModuleTable (NonEmpty (Module (address, Environment address))))) effects - => Set ModulePath - -> Modules address a - -> Evaluator address value effects a -handleModules paths = \case +runModules :: Member (Reader (ModuleTable (NonEmpty (Module (address, Environment address))))) effects + => Set ModulePath + -> Evaluator address value (Modules address ': effects) a + -> Evaluator address value effects a +runModules paths = interpret $ \case Load name -> fmap (runMerging' . foldMap1 (Merging' . moduleBody)) . ModuleTable.lookup name <$> askModuleTable' Lookup path -> fmap (Just . runMerging' . foldMap1 (Merging' . moduleBody)) . ModuleTable.lookup path <$> askModuleTable' Resolve names -> pure (find (flip Set.member paths) names) diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index 8e75d8556..1e0180a85 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -75,7 +75,7 @@ runGraph CallGraph includePackages project . runReader (packageInfo package) . runReader lowerBound . runReader lowerBound - . raiseHandler (interpret (handleModules (ModuleTable.modulePaths (packageModules package)))) + . raiseHandler (runModules (ModuleTable.modulePaths (packageModules package))) extractGraph <$> analyze runGraphAnalysis (evaluate lang analyzeModule analyzeTerm (topologicalSort modules)) -- | The full list of effects in flight during the evaluation of terms. This, and other @newtype@s like it, are necessary to type 'Value', since the bodies of closures embed evaluators. This would otherwise require cycles in the effect list (i.e. references to @effects@ within @effects@ itself), which the typechecker forbids. @@ -138,7 +138,7 @@ runImportGraph lang (package :: Package term) . resumingValueError . runState lowerBound . runReader lowerBound - . interpret (handleModules (ModuleTable.modulePaths (packageModules package))) + . runModules (ModuleTable.modulePaths (packageModules package)) . runTermEvaluator @_ @_ @(Value (Hole Precise) (ImportGraphEff term (Hole Precise))) . runReader (packageInfo package) . runReader lowerBound diff --git a/src/Semantic/Util.hs b/src/Semantic/Util.hs index 5455ceaa2..58ddf80af 100644 --- a/src/Semantic/Util.hs +++ b/src/Semantic/Util.hs @@ -103,7 +103,7 @@ evaluateProject proxy parser lang path = runTaskWithOptions debugOptions $ do (runReader (packageInfo package) (runReader (lowerBound @Span) (runReader (lowerBound @(ModuleTable (NonEmpty (Module (Precise, Environment Precise))))) - (raiseHandler (interpret (handleModules (ModuleTable.modulePaths (packageModules package)))) + (raiseHandler (runModules (ModuleTable.modulePaths (packageModules package))) (evaluate proxy id withTermSpans (topologicalSort modules))))))) evaluateProjectWithCaching proxy parser lang path = runTaskWithOptions debugOptions $ do @@ -113,7 +113,7 @@ evaluateProjectWithCaching proxy parser lang path = runTaskWithOptions debugOpti pure (runReader (packageInfo package) (runReader (lowerBound @Span) (runReader (lowerBound @(ModuleTable (NonEmpty (Module (Monovariant, Environment Monovariant))))) - (raiseHandler (interpret (handleModules (ModuleTable.modulePaths (packageModules package)))) + (raiseHandler (runModules (ModuleTable.modulePaths (packageModules package))) (evaluate proxy id withTermSpans (topologicalSort modules)))))) From f3802ba569aec329b869eb5c8b7a5fd4e96decf3 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 11:31:42 -0400 Subject: [PATCH 122/169] Rename askModuleTable' to askModuleTable. --- src/Control/Abstract/Modules.hs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Control/Abstract/Modules.hs b/src/Control/Abstract/Modules.hs index e7abe2458..c6238132f 100644 --- a/src/Control/Abstract/Modules.hs +++ b/src/Control/Abstract/Modules.hs @@ -67,13 +67,13 @@ runModules :: Member (Reader (ModuleTable (NonEmpty (Module (address, Environmen -> Evaluator address value (Modules address ': effects) a -> Evaluator address value effects a runModules paths = interpret $ \case - Load name -> fmap (runMerging' . foldMap1 (Merging' . moduleBody)) . ModuleTable.lookup name <$> askModuleTable' - Lookup path -> fmap (Just . runMerging' . foldMap1 (Merging' . moduleBody)) . ModuleTable.lookup path <$> askModuleTable' + Load name -> fmap (runMerging' . foldMap1 (Merging' . moduleBody)) . ModuleTable.lookup name <$> askModuleTable + Lookup path -> fmap (Just . runMerging' . foldMap1 (Merging' . moduleBody)) . ModuleTable.lookup path <$> askModuleTable Resolve names -> pure (find (flip Set.member paths) names) List dir -> pure (filter ((dir ==) . takeDirectory) (toList paths)) -askModuleTable' :: Member (Reader (ModuleTable (NonEmpty (Module (address, Environment address))))) effects => Evaluator address value effects (ModuleTable (NonEmpty (Module (address, Environment address)))) -askModuleTable' = ask +askModuleTable :: Member (Reader (ModuleTable (NonEmpty (Module (address, Environment address))))) effects => Evaluator address value effects (ModuleTable (NonEmpty (Module (address, Environment address)))) +askModuleTable = ask newtype Merging' address = Merging' { runMerging' :: (address, Environment address) } From e5546e8c86681e036e11abb9acfffceb9e522f93 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 11:31:56 -0400 Subject: [PATCH 123/169] Rename Merging' to Merging. --- src/Control/Abstract/Modules.hs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Control/Abstract/Modules.hs b/src/Control/Abstract/Modules.hs index c6238132f..674c1e5ab 100644 --- a/src/Control/Abstract/Modules.hs +++ b/src/Control/Abstract/Modules.hs @@ -67,8 +67,8 @@ runModules :: Member (Reader (ModuleTable (NonEmpty (Module (address, Environmen -> Evaluator address value (Modules address ': effects) a -> Evaluator address value effects a runModules paths = interpret $ \case - Load name -> fmap (runMerging' . foldMap1 (Merging' . moduleBody)) . ModuleTable.lookup name <$> askModuleTable - Lookup path -> fmap (Just . runMerging' . foldMap1 (Merging' . moduleBody)) . ModuleTable.lookup path <$> askModuleTable + Load name -> fmap (runMerging . foldMap1 (Merging . moduleBody)) . ModuleTable.lookup name <$> askModuleTable + Lookup path -> fmap (Just . runMerging . foldMap1 (Merging . moduleBody)) . ModuleTable.lookup path <$> askModuleTable Resolve names -> pure (find (flip Set.member paths) names) List dir -> pure (filter ((dir ==) . takeDirectory) (toList paths)) @@ -76,10 +76,10 @@ askModuleTable :: Member (Reader (ModuleTable (NonEmpty (Module (address, Enviro askModuleTable = ask -newtype Merging' address = Merging' { runMerging' :: (address, Environment address) } +newtype Merging address = Merging { runMerging :: (address, Environment address) } -instance Semigroup (Merging' address) where - Merging' (_, env1) <> Merging' (addr, env2) = Merging' (addr, mergeEnvs env1 env2) +instance Semigroup (Merging address) where + Merging (_, env1) <> Merging (addr, env2) = Merging (addr, mergeEnvs env1 env2) -- | An error thrown when loading a module from the list of provided modules. Indicates we weren't able to find a module with the given name. From 88f820251dc40a40df3650414d18756547f4a8ae Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 15:06:31 -0400 Subject: [PATCH 124/169] Partially apply eval*Project. --- src/Semantic/Util.hs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Semantic/Util.hs b/src/Semantic/Util.hs index 58ddf80af..6332ef34f 100644 --- a/src/Semantic/Util.hs +++ b/src/Semantic/Util.hs @@ -85,12 +85,12 @@ checking . runAddressError . runTypeError -evalGoProject path = justEvaluating =<< evaluateProject (Proxy :: Proxy 'Language.Go) goParser Language.Go path -evalRubyProject path = justEvaluating =<< evaluateProject (Proxy :: Proxy 'Language.Ruby) rubyParser Language.Ruby path -evalPHPProject path = justEvaluating =<< evaluateProject (Proxy :: Proxy 'Language.PHP) phpParser Language.PHP path -evalPythonProject path = justEvaluating =<< evaluateProject (Proxy :: Proxy 'Language.Python) pythonParser Language.Python path -evalJavaScriptProject path = justEvaluating =<< evaluateProject (Proxy :: Proxy 'Language.JavaScript) typescriptParser Language.JavaScript path -evalTypeScriptProject path = justEvaluating =<< evaluateProject (Proxy :: Proxy 'Language.TypeScript) typescriptParser Language.TypeScript path +evalGoProject = justEvaluating <=< evaluateProject (Proxy :: Proxy 'Language.Go) goParser Language.Go +evalRubyProject = justEvaluating <=< evaluateProject (Proxy :: Proxy 'Language.Ruby) rubyParser Language.Ruby +evalPHPProject = justEvaluating <=< evaluateProject (Proxy :: Proxy 'Language.PHP) phpParser Language.PHP +evalPythonProject = justEvaluating <=< evaluateProject (Proxy :: Proxy 'Language.Python) pythonParser Language.Python +evalJavaScriptProject = justEvaluating <=< evaluateProject (Proxy :: Proxy 'Language.JavaScript) typescriptParser Language.JavaScript +evalTypeScriptProject = justEvaluating <=< evaluateProject (Proxy :: Proxy 'Language.TypeScript) typescriptParser Language.TypeScript typecheckGoFile path = checking =<< evaluateProjectWithCaching (Proxy :: Proxy 'Language.Go) goParser Language.Go path From 19f3d720c1aa5832ae18aec9b37178a416d618e6 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 15:10:03 -0400 Subject: [PATCH 125/169] Partially apply typecheckGoFile. --- src/Semantic/Util.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Semantic/Util.hs b/src/Semantic/Util.hs index 6332ef34f..7896b693a 100644 --- a/src/Semantic/Util.hs +++ b/src/Semantic/Util.hs @@ -92,7 +92,7 @@ evalPythonProject = justEvaluating <=< evaluateProject (Proxy :: Proxy 'Lang evalJavaScriptProject = justEvaluating <=< evaluateProject (Proxy :: Proxy 'Language.JavaScript) typescriptParser Language.JavaScript evalTypeScriptProject = justEvaluating <=< evaluateProject (Proxy :: Proxy 'Language.TypeScript) typescriptParser Language.TypeScript -typecheckGoFile path = checking =<< evaluateProjectWithCaching (Proxy :: Proxy 'Language.Go) goParser Language.Go path +typecheckGoFile = checking <=< evaluateProjectWithCaching (Proxy :: Proxy 'Language.Go) goParser Language.Go -- Evaluate a project, starting at a single entrypoint. evaluateProject proxy parser lang path = runTaskWithOptions debugOptions $ do From 32f83378f3e858a7572268931b532d593091b532 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 15:26:46 -0400 Subject: [PATCH 126/169] evaluateProject takes a list of paths. --- src/Semantic/Util.hs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Semantic/Util.hs b/src/Semantic/Util.hs index 7896b693a..f3d822c96 100644 --- a/src/Semantic/Util.hs +++ b/src/Semantic/Util.hs @@ -14,10 +14,11 @@ import qualified Data.Abstract.ModuleTable as ModuleTable import Data.Abstract.Package import Data.Abstract.Type import Data.Blob -import Data.Graph (topologicalSort) -import Data.Project import Data.Functor.Foldable +import Data.Graph (topologicalSort) import qualified Data.Language as Language +import Data.List (uncons) +import Data.Project import Data.Sum (weaken) import Data.Term import Language.Haskell.HsColour @@ -27,6 +28,7 @@ import Prologue hiding (weaken) import Semantic.Graph import Semantic.IO as IO import Semantic.Task +import System.FilePath.Posix (takeDirectory) import Text.Show (showListWith) import Text.Show.Pretty (ppShow) @@ -94,10 +96,9 @@ evalTypeScriptProject = justEvaluating <=< evaluateProject (Proxy :: Proxy 'Lang typecheckGoFile = checking <=< evaluateProjectWithCaching (Proxy :: Proxy 'Language.Go) goParser Language.Go --- Evaluate a project, starting at a single entrypoint. -evaluateProject proxy parser lang path = runTaskWithOptions debugOptions $ do - project <- readProject Nothing path lang [] - package <- fmap quieterm <$> parsePackage parser project +-- Evaluate a project consisting of the listed paths. +evaluateProject proxy parser lang paths = runTaskWithOptions debugOptions $ do + package <- fmap quieterm <$> parsePackage parser (Project (takeDirectory (maybe "/" fst (uncons paths))) (flip File lang <$> paths) lang []) modules <- runImportGraph proxy package pure (runTermEvaluator @_ @_ @(Value Precise (UtilEff Precise)) (runReader (packageInfo package) From 98348908e60eb999585422ed12962988f545fc64 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 15:37:38 -0400 Subject: [PATCH 127/169] :fire: some redundant imports. --- test/Analysis/Python/Spec.hs | 1 - test/Analysis/Ruby/Spec.hs | 2 -- 2 files changed, 3 deletions(-) diff --git a/test/Analysis/Python/Spec.hs b/test/Analysis/Python/Spec.hs index fa7e016eb..259079718 100644 --- a/test/Analysis/Python/Spec.hs +++ b/test/Analysis/Python/Spec.hs @@ -3,7 +3,6 @@ module Analysis.Python.Spec (spec) where import Data.Abstract.Environment as Env import Data.Abstract.Evaluatable (EvalError(..)) import Data.Abstract.Value -import Data.Map import qualified Language.Python.Assignment as Python import qualified Data.Language as Language diff --git a/test/Analysis/Ruby/Spec.hs b/test/Analysis/Ruby/Spec.hs index 8bf1a2cb6..ab2f4baa9 100644 --- a/test/Analysis/Ruby/Spec.hs +++ b/test/Analysis/Ruby/Spec.hs @@ -7,8 +7,6 @@ import Data.Abstract.Number as Number import Data.AST import Control.Monad.Effect (SomeExc(..)) import Data.List.NonEmpty (NonEmpty(..)) -import Data.Map -import Data.Map.Monoidal as Map import Data.Sum import qualified Language.Ruby.Assignment as Ruby import qualified Data.Language as Language From 2ed8688c2857507a47e90d4e08682444d3e42423 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 15:45:42 -0400 Subject: [PATCH 128/169] Update the tests to pass a list of paths. --- test/Analysis/Go/Spec.hs | 8 ++++---- test/Analysis/PHP/Spec.hs | 10 +++++----- test/Analysis/Python/Spec.hs | 16 ++++++++-------- test/Analysis/Ruby/Spec.hs | 28 ++++++++++++++-------------- test/Analysis/TypeScript/Spec.hs | 14 +++++++------- 5 files changed, 38 insertions(+), 38 deletions(-) diff --git a/test/Analysis/Go/Spec.hs b/test/Analysis/Go/Spec.hs index c8d532ff7..62e4b77a6 100644 --- a/test/Analysis/Go/Spec.hs +++ b/test/Analysis/Go/Spec.hs @@ -11,18 +11,18 @@ spec :: Spec spec = parallel $ do describe "evaluates Go" $ do it "imports and wildcard imports" $ do - ((Right [(_, env)], heap), _) <- evaluate "main.go" + ((Right [(_, env)], heap), _) <- evaluate ["main.go"] Env.names env `shouldBe` [ "Bar", "Rab", "foo", "main" ] (derefQName heap ("foo" :| []) env >>= deNamespace) `shouldBe` Just ("foo", ["New"]) it "imports with aliases (and side effects only)" $ do - ((Right [(_, env)], heap), _) <- evaluate "main1.go" + ((Right [(_, env)], heap), _) <- evaluate ["main1.go"] Env.names env `shouldBe` [ "f", "main" ] (derefQName heap ("f" :| []) env >>= deNamespace) `shouldBe` Just ("f", ["New"]) where fixtures = "test/fixtures/go/analysis/" - evaluate entry = evalGoProject (fixtures <> entry) - evalGoProject path = testEvaluating =<< evaluateProject (Proxy :: Proxy 'Language.Go) goParser Language.Go path + evaluate = evalGoProject . map (fixtures <>) + evalGoProject = testEvaluating <=< evaluateProject (Proxy :: Proxy 'Language.Go) goParser Language.Go diff --git a/test/Analysis/PHP/Spec.hs b/test/Analysis/PHP/Spec.hs index be94b59e9..a83182098 100644 --- a/test/Analysis/PHP/Spec.hs +++ b/test/Analysis/PHP/Spec.hs @@ -12,17 +12,17 @@ spec :: Spec spec = parallel $ do describe "PHP" $ do it "evaluates include and require" $ do - ((Right [(res, env)], heap), _) <- evaluate "main.php" + ((Right [(res, env)], heap), _) <- evaluate ["main.php"] res `shouldBe` unit Env.names env `shouldBe` [ "bar", "foo" ] it "evaluates include_once and require_once" $ do - ((Right [(res, env)], heap), _) <- evaluate "main_once.php" + ((Right [(res, env)], heap), _) <- evaluate ["main_once.php"] res `shouldBe` unit Env.names env `shouldBe` [ "bar", "foo" ] it "evaluates namespaces" $ do - ((Right [(_, env)], heap), _) <- evaluate "namespaces.php" + ((Right [(_, env)], heap), _) <- evaluate ["namespaces.php"] Env.names env `shouldBe` [ "Foo", "NS1" ] (derefQName heap ("NS1" :| []) env >>= deNamespace) `shouldBe` Just ("NS1", ["Sub1", "b", "c"]) @@ -31,5 +31,5 @@ spec = parallel $ do where fixtures = "test/fixtures/php/analysis/" - evaluate entry = evalPHPProject (fixtures <> entry) - evalPHPProject path = testEvaluating =<< evaluateProject (Proxy :: Proxy 'Language.PHP) phpParser Language.PHP path + evaluate = evalPHPProject . map (fixtures <>) + evalPHPProject = testEvaluating <=< evaluateProject (Proxy :: Proxy 'Language.PHP) phpParser Language.PHP diff --git a/test/Analysis/Python/Spec.hs b/test/Analysis/Python/Spec.hs index 259079718..d33a43390 100644 --- a/test/Analysis/Python/Spec.hs +++ b/test/Analysis/Python/Spec.hs @@ -13,7 +13,7 @@ spec :: Spec spec = parallel $ do describe "evaluates Python" $ do it "imports" $ do - ((Right [(_, env)], heap), _) <- evaluate "main.py" + ((Right [(_, env)], heap), _) <- evaluate ["main.py"] Env.names env `shouldContain` [ "a", "b" ] (derefQName heap ("a" :| []) env >>= deNamespace) `shouldBe` Just ("a", ["foo"]) @@ -21,28 +21,28 @@ spec = parallel $ do (derefQName heap ("b" :| ["c"]) env >>= deNamespace) `shouldBe` Just ("c", ["baz"]) it "imports with aliases" $ do - ((Right [(_, env)], _), _) <- evaluate "main1.py" + ((Right [(_, env)], _), _) <- evaluate ["main1.py"] Env.names env `shouldContain` [ "b", "e" ] it "imports using 'from' syntax" $ do - ((Right [(_, env)], _), _) <- evaluate "main2.py" + ((Right [(_, env)], _), _) <- evaluate ["main2.py"] Env.names env `shouldContain` [ "bar", "foo" ] it "imports with relative syntax" $ do - ((Right [(_, env)], heap), _) <- evaluate "main3.py" + ((Right [(_, env)], heap), _) <- evaluate ["main3.py"] Env.names env `shouldContain` [ "utils" ] (derefQName heap ("utils" :| []) env >>= deNamespace) `shouldBe` Just ("utils", ["to_s"]) it "subclasses" $ do - ((res, _), _) <- evaluate "subclass.py" + ((res, _), _) <- evaluate ["subclass.py"] fmap fst <$> res `shouldBe` Right [String "\"bar\""] it "handles multiple inheritance left-to-right" $ do - ((res, _), _) <- evaluate "multiple_inheritance.py" + ((res, _), _) <- evaluate ["multiple_inheritance.py"] fmap fst <$> res `shouldBe` Right [String "\"foo!\""] where ns n = Just . Latest . Last . Just . Namespace n fixtures = "test/fixtures/python/analysis/" - evaluate entry = evalPythonProject (fixtures <> entry) - evalPythonProject path = testEvaluating =<< evaluateProject (Proxy :: Proxy 'Language.Python) pythonParser Language.Python path + evaluate = evalPythonProject . map (fixtures <>) + evalPythonProject = testEvaluating <=< evaluateProject (Proxy :: Proxy 'Language.Python) pythonParser Language.Python diff --git a/test/Analysis/Ruby/Spec.hs b/test/Analysis/Ruby/Spec.hs index ab2f4baa9..8c8decc14 100644 --- a/test/Analysis/Ruby/Spec.hs +++ b/test/Analysis/Ruby/Spec.hs @@ -18,61 +18,61 @@ spec :: Spec spec = parallel $ do describe "Ruby" $ do it "evaluates require_relative" $ do - ((Right [(res, env)], heap), _) <- evaluate "main.rb" + ((Right [(res, env)], heap), _) <- evaluate ["main.rb"] res `shouldBe` Value.Integer (Number.Integer 1) Env.names env `shouldContain` ["foo"] it "evaluates load" $ do - ((Right [(_, env)], _), _) <- evaluate "load.rb" + ((Right [(_, env)], _), _) <- evaluate ["load.rb"] Env.names env `shouldContain` ["foo"] it "evaluates load with wrapper" $ do - ((res, heap), _) <- evaluate "load-wrap.rb" + ((res, heap), _) <- evaluate ["load-wrap.rb"] res `shouldBe` Left (SomeExc (inject @(EnvironmentError Precise) (FreeVariable "foo"))) it "evaluates subclass" $ do - ((Right [(res, env)], heap), _) <- evaluate "subclass.rb" + ((Right [(res, env)], heap), _) <- evaluate ["subclass.rb"] res `shouldBe` String "\"\"" Env.names env `shouldContain` [ "Bar", "Foo" ] (derefQName heap ("Bar" :| []) env >>= deNamespace) `shouldBe` Just ("Bar", ["baz", "foo", "inspect"]) it "evaluates modules" $ do - ((Right [(res, env)], heap), _) <- evaluate "modules.rb" + ((Right [(res, env)], heap), _) <- evaluate ["modules.rb"] res `shouldBe` String "\"\"" Env.names env `shouldContain` [ "Bar" ] it "handles break correctly" $ do - ((res, _), _) <- evaluate "break.rb" + ((res, _), _) <- evaluate ["break.rb"] fmap fst <$> res `shouldBe` Right [Value.Integer (Number.Integer 3)] it "handles break correctly" $ do - ((res, _), _) <- evaluate "next.rb" + ((res, _), _) <- evaluate ["next.rb"] fmap fst <$> res `shouldBe` Right [Value.Integer (Number.Integer 8)] it "calls functions with arguments" $ do - ((res, _), _) <- evaluate "call.rb" + ((res, _), _) <- evaluate ["call.rb"] fmap fst <$> res `shouldBe` Right [Value.Integer (Number.Integer 579)] it "evaluates early return statements" $ do - ((res, _), _) <- evaluate "early-return.rb" + ((res, _), _) <- evaluate ["early-return.rb"] fmap fst <$> res `shouldBe` Right [Value.Integer (Number.Integer 123)] it "has prelude" $ do - ((res, _), _) <- evaluate "preluded.rb" + ((res, _), _) <- evaluate ["preluded.rb"] fmap fst <$> res `shouldBe` Right [String "\"\""] it "evaluates __LINE__" $ do - ((res, _), _) <- evaluate "line.rb" + ((res, _), _) <- evaluate ["line.rb"] fmap fst <$> res `shouldBe` Right [Value.Integer (Number.Integer 4)] it "resolves builtins used in the prelude" $ do - ((res, _), traces) <- evaluate "puts.rb" + ((res, _), traces) <- evaluate ["puts.rb"] fmap fst <$> res `shouldBe` Right [Unit] traces `shouldContain` [ "\"hello\"" ] where ns n = Just . Latest . Last . Just . Namespace n fixtures = "test/fixtures/ruby/analysis/" - evaluate entry = evalRubyProject (fixtures <> entry) - evalRubyProject path = testEvaluating =<< evaluateProject (Proxy :: Proxy 'Language.Ruby) rubyParser Language.Ruby path + evaluate = evalRubyProject . map (fixtures <>) + evalRubyProject = testEvaluating <=< evaluateProject (Proxy :: Proxy 'Language.Ruby) rubyParser Language.Ruby diff --git a/test/Analysis/TypeScript/Spec.hs b/test/Analysis/TypeScript/Spec.hs index 74e629d4a..15fab5713 100644 --- a/test/Analysis/TypeScript/Spec.hs +++ b/test/Analysis/TypeScript/Spec.hs @@ -15,29 +15,29 @@ spec :: Spec spec = parallel $ do describe "evaluates TypeScript" $ do it "imports with aliased symbols" $ do - ((Right [(_, env)], _), _) <- evaluate "main.ts" + ((Right [(_, env)], _), _) <- evaluate ["main.ts", "foo.ts", "a.ts", "foo/b.ts"] Env.names env `shouldBe` [ "bar", "quz" ] it "imports with qualified names" $ do - ((Right [(_, env)], heap), _) <- evaluate "main1.ts" + ((Right [(_, env)], heap), _) <- evaluate ["main1.ts", "foo.ts", "a.ts"] Env.names env `shouldBe` [ "b", "z" ] (derefQName heap ("b" :| []) env >>= deNamespace) `shouldBe` Just ("b", [ "baz", "foo" ]) (derefQName heap ("z" :| []) env >>= deNamespace) `shouldBe` Just ("z", [ "baz", "foo" ]) it "side effect only imports" $ do - ((res, _), _) <- evaluate "main2.ts" + ((res, _), _) <- evaluate ["main2.ts", "a.ts", "foo.ts"] fmap snd <$> res `shouldBe` Right [lowerBound] it "fails exporting symbols not defined in the module" $ do - ((res, _), _) <- evaluate "bad-export.ts" + ((res, _), _) <- evaluate ["bad-export.ts", "pip.ts", "a.ts", "foo.ts"] res `shouldBe` Left (SomeExc (inject @EvalError (ExportError "foo.ts" (name "pip")))) it "evaluates early return statements" $ do - ((res, _), _) <- evaluate "early-return.ts" + ((res, _), _) <- evaluate ["early-return.ts"] fmap fst <$> res `shouldBe` Right [Value.Float (Number.Decimal 123.0)] where fixtures = "test/fixtures/typescript/analysis/" - evaluate entry = evalTypeScriptProject (fixtures <> entry) - evalTypeScriptProject path = testEvaluating =<< evaluateProject (Proxy :: Proxy 'Language.TypeScript) typescriptParser Language.TypeScript path + evaluate = evalTypeScriptProject . map (fixtures <>) + evalTypeScriptProject = testEvaluating <=< evaluateProject (Proxy :: Proxy 'Language.TypeScript) typescriptParser Language.TypeScript From 428b5a31dce3cdc4ad0d36e525a0811837afcadc Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 15:47:31 -0400 Subject: [PATCH 129/169] These all import foo. --- test/Analysis/Ruby/Spec.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/Analysis/Ruby/Spec.hs b/test/Analysis/Ruby/Spec.hs index 8c8decc14..8122d7b97 100644 --- a/test/Analysis/Ruby/Spec.hs +++ b/test/Analysis/Ruby/Spec.hs @@ -18,16 +18,16 @@ spec :: Spec spec = parallel $ do describe "Ruby" $ do it "evaluates require_relative" $ do - ((Right [(res, env)], heap), _) <- evaluate ["main.rb"] + ((Right [(res, env)], heap), _) <- evaluate ["main.rb", "foo.rb"] res `shouldBe` Value.Integer (Number.Integer 1) Env.names env `shouldContain` ["foo"] it "evaluates load" $ do - ((Right [(_, env)], _), _) <- evaluate ["load.rb"] + ((Right [(_, env)], _), _) <- evaluate ["load.rb", "foo.rb"] Env.names env `shouldContain` ["foo"] it "evaluates load with wrapper" $ do - ((res, heap), _) <- evaluate ["load-wrap.rb"] + ((res, heap), _) <- evaluate ["load-wrap.rb", "foo.rb"] res `shouldBe` Left (SomeExc (inject @(EnvironmentError Precise) (FreeVariable "foo"))) it "evaluates subclass" $ do From 903f04888907f10dd1f9329a11bc132aee3167d0 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 15:57:12 -0400 Subject: [PATCH 130/169] =?UTF-8?q?Don=E2=80=99t=20bind=20the=20heap=20whe?= =?UTF-8?q?n=20we=20aren=E2=80=99t=20using=20it.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/Analysis/PHP/Spec.hs | 4 ++-- test/Analysis/Ruby/Spec.hs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/Analysis/PHP/Spec.hs b/test/Analysis/PHP/Spec.hs index a83182098..3f6c8f72b 100644 --- a/test/Analysis/PHP/Spec.hs +++ b/test/Analysis/PHP/Spec.hs @@ -12,12 +12,12 @@ spec :: Spec spec = parallel $ do describe "PHP" $ do it "evaluates include and require" $ do - ((Right [(res, env)], heap), _) <- evaluate ["main.php"] + ((Right [(res, env)], _), _) <- evaluate ["main.php"] res `shouldBe` unit Env.names env `shouldBe` [ "bar", "foo" ] it "evaluates include_once and require_once" $ do - ((Right [(res, env)], heap), _) <- evaluate ["main_once.php"] + ((Right [(res, env)], _), _) <- evaluate ["main_once.php"] res `shouldBe` unit Env.names env `shouldBe` [ "bar", "foo" ] diff --git a/test/Analysis/Ruby/Spec.hs b/test/Analysis/Ruby/Spec.hs index 8122d7b97..44148727a 100644 --- a/test/Analysis/Ruby/Spec.hs +++ b/test/Analysis/Ruby/Spec.hs @@ -18,7 +18,7 @@ spec :: Spec spec = parallel $ do describe "Ruby" $ do it "evaluates require_relative" $ do - ((Right [(res, env)], heap), _) <- evaluate ["main.rb", "foo.rb"] + ((Right [(res, env)], _), _) <- evaluate ["main.rb", "foo.rb"] res `shouldBe` Value.Integer (Number.Integer 1) Env.names env `shouldContain` ["foo"] @@ -27,7 +27,7 @@ spec = parallel $ do Env.names env `shouldContain` ["foo"] it "evaluates load with wrapper" $ do - ((res, heap), _) <- evaluate ["load-wrap.rb", "foo.rb"] + ((res, _), _) <- evaluate ["load-wrap.rb", "foo.rb"] res `shouldBe` Left (SomeExc (inject @(EnvironmentError Precise) (FreeVariable "foo"))) it "evaluates subclass" $ do @@ -38,7 +38,7 @@ spec = parallel $ do (derefQName heap ("Bar" :| []) env >>= deNamespace) `shouldBe` Just ("Bar", ["baz", "foo", "inspect"]) it "evaluates modules" $ do - ((Right [(res, env)], heap), _) <- evaluate ["modules.rb"] + ((Right [(res, env)], _), _) <- evaluate ["modules.rb"] res `shouldBe` String "\"\"" Env.names env `shouldContain` [ "Bar" ] From 346fad10975e6d22451d4b0b19c49e2498301cd2 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 16:00:36 -0400 Subject: [PATCH 131/169] fmap the topo sort over the import graph. --- src/Semantic/Util.hs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Semantic/Util.hs b/src/Semantic/Util.hs index f3d822c96..51eecac7f 100644 --- a/src/Semantic/Util.hs +++ b/src/Semantic/Util.hs @@ -99,23 +99,23 @@ typecheckGoFile = checking <=< evaluateProjectWithCaching (Proxy :: Proxy 'Langu -- Evaluate a project consisting of the listed paths. evaluateProject proxy parser lang paths = runTaskWithOptions debugOptions $ do package <- fmap quieterm <$> parsePackage parser (Project (takeDirectory (maybe "/" fst (uncons paths))) (flip File lang <$> paths) lang []) - modules <- runImportGraph proxy package + modules <- topologicalSort <$> runImportGraph proxy package pure (runTermEvaluator @_ @_ @(Value Precise (UtilEff Precise)) (runReader (packageInfo package) (runReader (lowerBound @Span) (runReader (lowerBound @(ModuleTable (NonEmpty (Module (Precise, Environment Precise))))) (raiseHandler (runModules (ModuleTable.modulePaths (packageModules package))) - (evaluate proxy id withTermSpans (topologicalSort modules))))))) + (evaluate proxy id withTermSpans modules)))))) evaluateProjectWithCaching proxy parser lang path = runTaskWithOptions debugOptions $ do project <- readProject Nothing path lang [] package <- fmap quieterm <$> parsePackage parser project - modules <- runImportGraph proxy package + modules <- topologicalSort <$> runImportGraph proxy package pure (runReader (packageInfo package) (runReader (lowerBound @Span) (runReader (lowerBound @(ModuleTable (NonEmpty (Module (Monovariant, Environment Monovariant))))) (raiseHandler (runModules (ModuleTable.modulePaths (packageModules package))) - (evaluate proxy id withTermSpans (topologicalSort modules)))))) + (evaluate proxy id withTermSpans modules))))) parseFile :: Parser term -> FilePath -> IO term From c3a0adafaaa1ee1999f0622d736730ee1e7f8ad5 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 16:05:54 -0400 Subject: [PATCH 132/169] I guess this was literally backwards --- src/Data/Graph.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Data/Graph.hs b/src/Data/Graph.hs index 3c0b77d29..f84047ca7 100644 --- a/src/Data/Graph.hs +++ b/src/Data/Graph.hs @@ -31,7 +31,7 @@ simplify (Graph graph) = Graph (G.simplify graph) topologicalSort :: Ord v => Graph v -> [NonEmpty v] topologicalSort = map (fmap fst) - . sortAndGroupBy (outEdgeCount . snd) + . sortAndGroupBy (inEdgeCount . snd) . Monoidal.pairs . edgeCountsByVertex From d586d6dc09c03ab28d6d3b7f7fa15f3a4d84d00f Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Fri, 22 Jun 2018 16:06:27 -0400 Subject: [PATCH 133/169] Show the load order. --- src/Semantic/Util.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Semantic/Util.hs b/src/Semantic/Util.hs index 51eecac7f..1b2674a74 100644 --- a/src/Semantic/Util.hs +++ b/src/Semantic/Util.hs @@ -100,6 +100,7 @@ typecheckGoFile = checking <=< evaluateProjectWithCaching (Proxy :: Proxy 'Langu evaluateProject proxy parser lang paths = runTaskWithOptions debugOptions $ do package <- fmap quieterm <$> parsePackage parser (Project (takeDirectory (maybe "/" fst (uncons paths))) (flip File lang <$> paths) lang []) modules <- topologicalSort <$> runImportGraph proxy package + trace $ "evaluating with load order: " <> show (map (modulePath . moduleInfo) . toList <$> modules) pure (runTermEvaluator @_ @_ @(Value Precise (UtilEff Precise)) (runReader (packageInfo package) (runReader (lowerBound @Span) From 23ae10d847a27350def752ead8635d64abb8e05e Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 09:26:31 -0400 Subject: [PATCH 134/169] Make more effort to show the errors in the TypeScript spec. --- test/Analysis/TypeScript/Spec.hs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/Analysis/TypeScript/Spec.hs b/test/Analysis/TypeScript/Spec.hs index 15fab5713..87a847080 100644 --- a/test/Analysis/TypeScript/Spec.hs +++ b/test/Analysis/TypeScript/Spec.hs @@ -15,12 +15,12 @@ spec :: Spec spec = parallel $ do describe "evaluates TypeScript" $ do it "imports with aliased symbols" $ do - ((Right [(_, env)], _), _) <- evaluate ["main.ts", "foo.ts", "a.ts", "foo/b.ts"] - Env.names env `shouldBe` [ "bar", "quz" ] + ((res, _), _) <- evaluate ["main.ts", "foo.ts", "a.ts", "foo/b.ts"] + (>>= Env.names . snd) <$> res `shouldBe` Right [ "bar", "quz" ] it "imports with qualified names" $ do - ((Right [(_, env)], heap), _) <- evaluate ["main1.ts", "foo.ts", "a.ts"] - Env.names env `shouldBe` [ "b", "z" ] + ((res@(~(Right [(_, env)])), heap), _) <- evaluate ["main1.ts", "foo.ts", "a.ts"] + (>>= Env.names . snd) <$> res `shouldBe` Right [ "b", "z" ] (derefQName heap ("b" :| []) env >>= deNamespace) `shouldBe` Just ("b", [ "baz", "foo" ]) (derefQName heap ("z" :| []) env >>= deNamespace) `shouldBe` Just ("z", [ "baz", "foo" ]) From 613e6b79bb539ab9b075bd7869207abb653039a8 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 09:30:54 -0400 Subject: [PATCH 135/169] Make more effort to show the errors in the Ruby spec. --- test/Analysis/Ruby/Spec.hs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/test/Analysis/Ruby/Spec.hs b/test/Analysis/Ruby/Spec.hs index 44148727a..53a0971be 100644 --- a/test/Analysis/Ruby/Spec.hs +++ b/test/Analysis/Ruby/Spec.hs @@ -18,12 +18,13 @@ spec :: Spec spec = parallel $ do describe "Ruby" $ do it "evaluates require_relative" $ do - ((Right [(res, env)], _), _) <- evaluate ["main.rb", "foo.rb"] - res `shouldBe` Value.Integer (Number.Integer 1) + ((res@(~(Right [(_, env)])), _), _) <- evaluate ["main.rb", "foo.rb"] + map fst <$> res `shouldBe` Right [Value.Integer (Number.Integer 1)] Env.names env `shouldContain` ["foo"] it "evaluates load" $ do - ((Right [(_, env)], _), _) <- evaluate ["load.rb", "foo.rb"] + ((res@(~(Right [(_, env)])), _), _) <- evaluate ["load.rb", "foo.rb"] + map fst <$> res `shouldBe` Right [Value.Integer (Number.Integer 1)] Env.names env `shouldContain` ["foo"] it "evaluates load with wrapper" $ do @@ -31,15 +32,15 @@ spec = parallel $ do res `shouldBe` Left (SomeExc (inject @(EnvironmentError Precise) (FreeVariable "foo"))) it "evaluates subclass" $ do - ((Right [(res, env)], heap), _) <- evaluate ["subclass.rb"] - res `shouldBe` String "\"\"" + ((res@(~(Right [(_, env)])), heap), _) <- evaluate ["subclass.rb"] + map fst <$> res `shouldBe` Right [String "\"\""] Env.names env `shouldContain` [ "Bar", "Foo" ] (derefQName heap ("Bar" :| []) env >>= deNamespace) `shouldBe` Just ("Bar", ["baz", "foo", "inspect"]) it "evaluates modules" $ do - ((Right [(res, env)], _), _) <- evaluate ["modules.rb"] - res `shouldBe` String "\"\"" + ((res@(~(Right [(_, env)])), _), _) <- evaluate ["modules.rb"] + map fst <$> res `shouldBe` Right [String "\"\""] Env.names env `shouldContain` [ "Bar" ] it "handles break correctly" $ do From c5e15e7283360927e32ade46c57b04f5e8faf414 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 10:47:59 -0400 Subject: [PATCH 136/169] load & require are total (modulo exceptions). --- src/Control/Abstract/Modules.hs | 31 +++++++++++++++++-------------- src/Language/Go/Syntax.hs | 4 ++-- src/Language/PHP/Syntax.hs | 5 ++--- src/Language/Python/Syntax.hs | 6 +++--- src/Language/Ruby/Syntax.hs | 6 +++--- src/Language/TypeScript/Syntax.hs | 6 +++--- src/Semantic/Graph.hs | 4 ++-- 7 files changed, 32 insertions(+), 30 deletions(-) diff --git a/src/Control/Abstract/Modules.hs b/src/Control/Abstract/Modules.hs index 674c1e5ab..4ad140a59 100644 --- a/src/Control/Abstract/Modules.hs +++ b/src/Control/Abstract/Modules.hs @@ -18,8 +18,8 @@ module Control.Abstract.Modules , ModuleTable ) where -import Control.Abstract.Evaluator -import Data.Abstract.Environment +import Control.Abstract.Evaluator hiding (trace) +import Data.Abstract.Environment as Env import Data.Abstract.Module import Data.Abstract.ModuleTable as ModuleTable import Data.Language @@ -27,9 +27,10 @@ import Data.Semigroup.Foldable (foldMap1) import qualified Data.Set as Set import Prologue import System.FilePath.Posix (takeDirectory) +import Debug.Trace (trace) -- | Retrieve an evaluated module, if any. The outer 'Maybe' indicates whether we’ve begun loading the module or not, while the inner 'Maybe' indicates whether we’ve completed loading it or not. Thus, @Nothing@ means we’ve never tried to load it, @Just Nothing@ means we’ve started but haven’t yet finished loading it, and @Just (Just (env, value))@ indicates the result of a completed load. -lookupModule :: Member (Modules address) effects => ModulePath -> Evaluator address value effects (Maybe (Maybe (address, Environment address))) +lookupModule :: Member (Modules address) effects => ModulePath -> Evaluator address value effects (Maybe (address, Environment address)) lookupModule = sendModules . Lookup -- | Resolve a list of module paths to a possible module table entry. @@ -43,34 +44,36 @@ listModulesInDir = sendModules . List -- | Require/import another module by name and return its environment and value. -- -- Looks up the module's name in the cache of evaluated modules first, returns if found, otherwise loads/evaluates the module. -require :: Member (Modules address) effects => ModulePath -> Evaluator address value effects (Maybe (address, Environment address)) +require :: Member (Modules address) effects => ModulePath -> Evaluator address value effects (address, Environment address) require path = lookupModule path >>= maybeM (load path) -- | Load another module by name and return its environment and value. -- -- Always loads/evaluates. -load :: Member (Modules address) effects => ModulePath -> Evaluator address value effects (Maybe (address, Environment address)) +load :: Member (Modules address) effects => ModulePath -> Evaluator address value effects (address, Environment address) load path = sendModules (Load path) data Modules address return where - Load :: ModulePath -> Modules address (Maybe (address, Environment address)) - Lookup :: ModulePath -> Modules address (Maybe (Maybe (address, Environment address))) + Load :: ModulePath -> Modules address (address, Environment address) + Lookup :: ModulePath -> Modules address (Maybe (address, Environment address)) Resolve :: [FilePath] -> Modules address (Maybe ModulePath) List :: FilePath -> Modules address [ModulePath] sendModules :: Member (Modules address) effects => Modules address return -> Evaluator address value effects return sendModules = send -runModules :: Member (Reader (ModuleTable (NonEmpty (Module (address, Environment address))))) effects +runModules :: ( Member (Reader (ModuleTable (NonEmpty (Module (address, Environment address))))) effects + , Member (Resumable (LoadError address)) effects + ) => Set ModulePath -> Evaluator address value (Modules address ': effects) a -> Evaluator address value effects a runModules paths = interpret $ \case - Load name -> fmap (runMerging . foldMap1 (Merging . moduleBody)) . ModuleTable.lookup name <$> askModuleTable - Lookup path -> fmap (Just . runMerging . foldMap1 (Merging . moduleBody)) . ModuleTable.lookup path <$> askModuleTable + Load name -> fmap (runMerging . foldMap1 (Merging . moduleBody)) . ModuleTable.lookup name <$> askModuleTable >>= maybeM (moduleNotFound name) + Lookup path -> fmap (runMerging . foldMap1 (Merging . moduleBody)) . ModuleTable.lookup path <$> askModuleTable Resolve names -> pure (find (flip Set.member paths) names) - List dir -> pure (filter ((dir ==) . takeDirectory) (toList paths)) + List dir -> pure (filter ((dir ==) . takeDirectory) (toList paths)) askModuleTable :: Member (Reader (ModuleTable (NonEmpty (Module (address, Environment address))))) effects => Evaluator address value effects (ModuleTable (NonEmpty (Module (address, Environment address)))) askModuleTable = ask @@ -79,12 +82,12 @@ askModuleTable = ask newtype Merging address = Merging { runMerging :: (address, Environment address) } instance Semigroup (Merging address) where - Merging (_, env1) <> Merging (addr, env2) = Merging (addr, mergeEnvs env1 env2) + Merging (_, env1) <> Merging (addr, env2) = trace ("env1: " <> show (Env.names env1) <> ", env2: " <> show (Env.names env2)) $ Merging (addr, mergeEnvs env1 env2) -- | An error thrown when loading a module from the list of provided modules. Indicates we weren't able to find a module with the given name. data LoadError address resume where - ModuleNotFound :: ModulePath -> LoadError address (Maybe (address, Environment address)) + ModuleNotFound :: ModulePath -> LoadError address (address, Environment address) deriving instance Eq (LoadError address resume) deriving instance Show (LoadError address resume) @@ -93,7 +96,7 @@ instance Show1 (LoadError address) where instance Eq1 (LoadError address) where liftEq _ (ModuleNotFound a) (ModuleNotFound b) = a == b -moduleNotFound :: Member (Resumable (LoadError address)) effects => ModulePath -> Evaluator address value effects (Maybe (address, Environment address)) +moduleNotFound :: Member (Resumable (LoadError address)) effects => ModulePath -> Evaluator address value effects (address, Environment address) moduleNotFound = throwResumable . ModuleNotFound resumeLoadError :: Member (Resumable (LoadError address)) effects => Evaluator address value effects a -> (forall resume . LoadError address resume -> Evaluator address value effects resume) -> Evaluator address value effects a diff --git a/src/Language/Go/Syntax.hs b/src/Language/Go/Syntax.hs index 75f85812c..1f7cb5dac 100644 --- a/src/Language/Go/Syntax.hs +++ b/src/Language/Go/Syntax.hs @@ -66,7 +66,7 @@ instance Evaluatable Import where paths <- resolveGoImport importPath for_ paths $ \path -> do traceResolve (unPath importPath) path - importedEnv <- maybe lowerBound snd <$> require path + importedEnv <- snd <$> require path bindAll importedEnv rvalBox unit @@ -88,7 +88,7 @@ instance Evaluatable QualifiedImport where void . letrec' alias $ \addr -> do for_ paths $ \p -> do traceResolve (unPath importPath) p - importedEnv <- maybe lowerBound snd <$> require p + importedEnv <- snd <$> require p bindAll importedEnv makeNamespace alias addr Nothing rvalBox unit diff --git a/src/Language/PHP/Syntax.hs b/src/Language/PHP/Syntax.hs index 08a7f1e9c..6d65ec2c0 100644 --- a/src/Language/PHP/Syntax.hs +++ b/src/Language/PHP/Syntax.hs @@ -55,14 +55,13 @@ include :: ( AbstractValue address value effects , Member Trace effects ) => Subterm term (Evaluator address value effects (ValueRef address)) - -> (ModulePath -> Evaluator address value effects (Maybe (address, Environment address))) + -> (ModulePath -> Evaluator address value effects (address, Environment address)) -> Evaluator address value effects (ValueRef address) include pathTerm f = do name <- subtermValue pathTerm >>= asString path <- resolvePHPName name traceResolve name path - unitPtr <- box unit -- TODO don't always allocate, use maybeM - (v, importedEnv) <- fromMaybe (unitPtr, lowerBound) <$> f path + (v, importedEnv) <- f path bindAll importedEnv pure (Rval v) diff --git a/src/Language/Python/Syntax.hs b/src/Language/Python/Syntax.hs index ed8c6e70f..c79eb1dcb 100644 --- a/src/Language/Python/Syntax.hs +++ b/src/Language/Python/Syntax.hs @@ -113,7 +113,7 @@ instance Evaluatable Import where -- Last module path is the one we want to import let path = NonEmpty.last modulePaths - importedEnv <- maybe lowerBound snd <$> require path + importedEnv <- snd <$> require path bindAll (select importedEnv) rvalBox unit where @@ -130,7 +130,7 @@ evalQualifiedImport :: ( AbstractValue address value effects ) => Name -> ModulePath -> Evaluator address value effects value evalQualifiedImport name path = letrec' name $ \addr -> do - importedEnv <- maybe lowerBound snd <$> require path + importedEnv <- snd <$> require path bindAll importedEnv unit <$ makeNamespace name addr Nothing @@ -174,7 +174,7 @@ instance Evaluatable QualifiedAliasedImport where alias <- either (throwEvalError . FreeVariablesError) pure (freeVariable $ subterm aliasTerm) rvalBox =<< letrec' alias (\addr -> do let path = NonEmpty.last modulePaths - importedEnv <- maybe lowerBound snd <$> require path + importedEnv <- snd <$> require path bindAll importedEnv unit <$ makeNamespace alias addr Nothing) diff --git a/src/Language/Ruby/Syntax.hs b/src/Language/Ruby/Syntax.hs index 06edaadc0..ab894e430 100644 --- a/src/Language/Ruby/Syntax.hs +++ b/src/Language/Ruby/Syntax.hs @@ -78,9 +78,9 @@ doRequire :: ( AbstractValue address value effects => M.ModulePath -> Evaluator address value effects (value, Environment address) doRequire path = do - result <- join <$> lookupModule path + result <- lookupModule path case result of - Nothing -> (,) (boolean True) . maybe lowerBound snd <$> load path + Nothing -> (,) (boolean True) . snd <$> load path Just (_, env) -> pure (boolean False, env) @@ -112,7 +112,7 @@ doLoad :: ( AbstractValue address value effects doLoad path shouldWrap = do path' <- resolveRubyPath path traceResolve path path' - importedEnv <- maybe lowerBound snd <$> load path' + importedEnv <- snd <$> load path' unless shouldWrap $ bindAll importedEnv pure (boolean Prelude.True) -- load always returns true. http://ruby-doc.org/core-2.5.0/Kernel.html#method-i-load diff --git a/src/Language/TypeScript/Syntax.hs b/src/Language/TypeScript/Syntax.hs index ff708fc30..575229d04 100644 --- a/src/Language/TypeScript/Syntax.hs +++ b/src/Language/TypeScript/Syntax.hs @@ -139,7 +139,7 @@ evalRequire :: ( AbstractValue address value effects -> Name -> Evaluator address value effects value evalRequire modulePath alias = letrec' alias $ \addr -> do - importedEnv <- maybe lowerBound snd <$> require modulePath + importedEnv <- snd <$> require modulePath bindAll importedEnv unit <$ makeNamespace alias addr Nothing @@ -154,7 +154,7 @@ instance Show1 Import where liftShowsPrec = genericLiftShowsPrec instance Evaluatable Import where eval (Import symbols importPath) = do modulePath <- resolveWithNodejsStrategy importPath typescriptExtensions - importedEnv <- maybe lowerBound snd <$> require modulePath + importedEnv <- snd <$> require modulePath bindAll (renamed importedEnv) rvalBox unit where @@ -230,7 +230,7 @@ instance Show1 QualifiedExportFrom where liftShowsPrec = genericLiftShowsPrec instance Evaluatable QualifiedExportFrom where eval (QualifiedExportFrom importPath exportSymbols) = do modulePath <- resolveWithNodejsStrategy importPath typescriptExtensions - importedEnv <- maybe lowerBound snd <$> require modulePath + importedEnv <- snd <$> require modulePath -- Look up addresses in importedEnv and insert the aliases with addresses into the exports. for_ exportSymbols $ \(name, alias) -> do let address = Env.lookup name importedEnv diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index 1e0180a85..73094042c 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -206,8 +206,8 @@ resumingResolutionError = runResolutionErrorWith (\ err -> trace ("ResolutionErr NotFoundError nameToResolve _ _ -> pure nameToResolve GoImportError pathToResolve -> pure [pathToResolve]) -resumingLoadError :: Member Trace effects => Evaluator address value (Resumable (LoadError address) ': effects) a -> Evaluator address value effects a -resumingLoadError = runLoadErrorWith (\ (ModuleNotFound path) -> trace ("LoadError: " <> path) $> Nothing) +resumingLoadError :: (Member Trace effects, AbstractHole address) => Evaluator address value (Resumable (LoadError address) ': effects) a -> Evaluator address value effects a +resumingLoadError = runLoadErrorWith (\ (ModuleNotFound path) -> trace ("LoadError: " <> path) $> (hole, lowerBound)) resumingEvalError :: Member Trace effects => Evaluator address value (Resumable EvalError ': effects) a -> Evaluator address value effects a resumingEvalError = runEvalErrorWith (\ err -> trace ("EvalError" <> show err) *> case err of From 9e698cba12a16975a03675725636804cd10a1d2d Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 10:48:52 -0400 Subject: [PATCH 137/169] Correct the docs for lookupModule. --- src/Control/Abstract/Modules.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Control/Abstract/Modules.hs b/src/Control/Abstract/Modules.hs index 4ad140a59..761a90354 100644 --- a/src/Control/Abstract/Modules.hs +++ b/src/Control/Abstract/Modules.hs @@ -29,7 +29,7 @@ import Prologue import System.FilePath.Posix (takeDirectory) import Debug.Trace (trace) --- | Retrieve an evaluated module, if any. The outer 'Maybe' indicates whether we’ve begun loading the module or not, while the inner 'Maybe' indicates whether we’ve completed loading it or not. Thus, @Nothing@ means we’ve never tried to load it, @Just Nothing@ means we’ve started but haven’t yet finished loading it, and @Just (Just (env, value))@ indicates the result of a completed load. +-- | Retrieve an evaluated module, if any. @Nothing@ means we’ve never tried to load it, and @Just (env, value)@ indicates the result of a completed load. lookupModule :: Member (Modules address) effects => ModulePath -> Evaluator address value effects (Maybe (address, Environment address)) lookupModule = sendModules . Lookup From 01b00d3c7b2d27488c33024d244adc2bb4d6fce6 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 10:56:53 -0400 Subject: [PATCH 138/169] Whoops. --- src/Control/Abstract/Modules.hs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Control/Abstract/Modules.hs b/src/Control/Abstract/Modules.hs index 761a90354..1c5aae6ed 100644 --- a/src/Control/Abstract/Modules.hs +++ b/src/Control/Abstract/Modules.hs @@ -18,8 +18,8 @@ module Control.Abstract.Modules , ModuleTable ) where -import Control.Abstract.Evaluator hiding (trace) -import Data.Abstract.Environment as Env +import Control.Abstract.Evaluator +import Data.Abstract.Environment import Data.Abstract.Module import Data.Abstract.ModuleTable as ModuleTable import Data.Language @@ -27,7 +27,6 @@ import Data.Semigroup.Foldable (foldMap1) import qualified Data.Set as Set import Prologue import System.FilePath.Posix (takeDirectory) -import Debug.Trace (trace) -- | Retrieve an evaluated module, if any. @Nothing@ means we’ve never tried to load it, and @Just (env, value)@ indicates the result of a completed load. lookupModule :: Member (Modules address) effects => ModulePath -> Evaluator address value effects (Maybe (address, Environment address)) @@ -82,7 +81,7 @@ askModuleTable = ask newtype Merging address = Merging { runMerging :: (address, Environment address) } instance Semigroup (Merging address) where - Merging (_, env1) <> Merging (addr, env2) = trace ("env1: " <> show (Env.names env1) <> ", env2: " <> show (Env.names env2)) $ Merging (addr, mergeEnvs env1 env2) + Merging (_, env1) <> Merging (addr, env2) = Merging (addr, mergeEnvs env1 env2) -- | An error thrown when loading a module from the list of provided modules. Indicates we weren't able to find a module with the given name. From 7552099085e2c321618ad770f17c582dd65d6df0 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 11:38:05 -0400 Subject: [PATCH 139/169] Use a State effect to work around https://github.com/joshvera/effects/issues/47 --- src/Control/Abstract/Modules.hs | 6 +++--- src/Data/Abstract/Evaluatable.hs | 6 +++--- src/Semantic/Graph.hs | 12 ++++++++---- src/Semantic/Util.hs | 14 +++++++++----- 4 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/Control/Abstract/Modules.hs b/src/Control/Abstract/Modules.hs index 1c5aae6ed..eda51bb7c 100644 --- a/src/Control/Abstract/Modules.hs +++ b/src/Control/Abstract/Modules.hs @@ -62,7 +62,7 @@ data Modules address return where sendModules :: Member (Modules address) effects => Modules address return -> Evaluator address value effects return sendModules = send -runModules :: ( Member (Reader (ModuleTable (NonEmpty (Module (address, Environment address))))) effects +runModules :: ( Member (State (ModuleTable (NonEmpty (Module (address, Environment address))))) effects -- FIXME: This should really be a Reader effect but for https://github.com/joshvera/effects/issues/47 , Member (Resumable (LoadError address)) effects ) => Set ModulePath @@ -74,8 +74,8 @@ runModules paths = interpret $ \case Resolve names -> pure (find (flip Set.member paths) names) List dir -> pure (filter ((dir ==) . takeDirectory) (toList paths)) -askModuleTable :: Member (Reader (ModuleTable (NonEmpty (Module (address, Environment address))))) effects => Evaluator address value effects (ModuleTable (NonEmpty (Module (address, Environment address)))) -askModuleTable = ask +askModuleTable :: Member (State (ModuleTable (NonEmpty (Module (address, Environment address))))) effects => Evaluator address value effects (ModuleTable (NonEmpty (Module (address, Environment address)))) +askModuleTable = get newtype Merging address = Merging { runMerging :: (address, Environment address) } diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index aeb1dc062..1cebd6005 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -73,7 +73,7 @@ evaluate :: ( AbstractValue address value inner , HasPrelude lang , Member Fresh effects , Member (Modules address) effects - , Member (Reader (ModuleTable (NonEmpty (Module (address, Environment address))))) effects + , Member (State (ModuleTable (NonEmpty (Module (address, Environment address))))) effects , Member (Reader PackageInfo) effects , Member (Reader Span) effects , Member (Resumable (AddressError address value)) effects @@ -98,10 +98,10 @@ evaluate lang analyzeModule analyzeTerm modules = do defineBuiltins definePrelude lang box unit - foldr (run preludeEnv) ask modules + foldr (run preludeEnv) get modules where run preludeEnv modules rest = do evaluated <- traverse (evalModule preludeEnv) modules - local (<> ModuleTable.fromModules (toList evaluated)) rest + localState (<> ModuleTable.fromModules (toList evaluated)) rest evalModule preludeEnv m = fmap (<$ m) diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index 73094042c..ed88d5a46 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -74,7 +74,8 @@ runGraph CallGraph includePackages project . graphing . runReader (packageInfo package) . runReader lowerBound - . runReader lowerBound + . fmap fst + . runState lowerBound . raiseHandler (runModules (ModuleTable.modulePaths (packageModules package))) extractGraph <$> analyze runGraphAnalysis (evaluate lang analyzeModule analyzeTerm (topologicalSort modules)) @@ -86,7 +87,8 @@ newtype GraphEff address a = GraphEff , Allocator address (Value address (GraphEff address)) , Reader ModuleInfo , Modules address - , Reader (ModuleTable (NonEmpty (Module (address, Environment address)))) + -- FIXME: This should really be a Reader effect but for https://github.com/joshvera/effects/issues/47 + , State (ModuleTable (NonEmpty (Module (address, Environment address)))) , Reader Span , Reader PackageInfo , State (Graph Vertex) @@ -137,7 +139,8 @@ runImportGraph lang (package :: Package term) . resumingAddressError . resumingValueError . runState lowerBound - . runReader lowerBound + . fmap fst + . runState lowerBound . runModules (ModuleTable.modulePaths (packageModules package)) . runTermEvaluator @_ @_ @(Value (Hole Precise) (ImportGraphEff term (Hole Precise))) . runReader (packageInfo package) @@ -153,7 +156,8 @@ newtype ImportGraphEff term address a = ImportGraphEff , Reader Span , Reader PackageInfo , Modules address - , Reader (ModuleTable (NonEmpty (Module (address, Environment address)))) + -- FIXME: This should really be a Reader effect but for https://github.com/joshvera/effects/issues/47 + , State (ModuleTable (NonEmpty (Module (address, Environment address)))) , State (Graph ModuleInfo) , Resumable (ValueError address (ImportGraphEff term address)) , Resumable (AddressError address (Value address (ImportGraphEff term address))) diff --git a/src/Semantic/Util.hs b/src/Semantic/Util.hs index 1b2674a74..d644fd96f 100644 --- a/src/Semantic/Util.hs +++ b/src/Semantic/Util.hs @@ -53,7 +53,7 @@ newtype UtilEff address a = UtilEff , Allocator address (Value address (UtilEff address)) , Reader ModuleInfo , Modules address - , Reader (ModuleTable (NonEmpty (Module (address, Environment address)))) + , State (ModuleTable (NonEmpty (Module (address, Environment address)))) , Reader Span , Reader PackageInfo , Resumable (ValueError address (UtilEff address)) @@ -104,9 +104,11 @@ evaluateProject proxy parser lang paths = runTaskWithOptions debugOptions $ do pure (runTermEvaluator @_ @_ @(Value Precise (UtilEff Precise)) (runReader (packageInfo package) (runReader (lowerBound @Span) - (runReader (lowerBound @(ModuleTable (NonEmpty (Module (Precise, Environment Precise))))) + -- FIXME: This should really be a Reader effect but for https://github.com/joshvera/effects/issues/47 + (fmap fst + (runState (lowerBound @(ModuleTable (NonEmpty (Module (Precise, Environment Precise))))) (raiseHandler (runModules (ModuleTable.modulePaths (packageModules package))) - (evaluate proxy id withTermSpans modules)))))) + (evaluate proxy id withTermSpans modules))))))) evaluateProjectWithCaching proxy parser lang path = runTaskWithOptions debugOptions $ do project <- readProject Nothing path lang [] @@ -114,9 +116,11 @@ evaluateProjectWithCaching proxy parser lang path = runTaskWithOptions debugOpti modules <- topologicalSort <$> runImportGraph proxy package pure (runReader (packageInfo package) (runReader (lowerBound @Span) - (runReader (lowerBound @(ModuleTable (NonEmpty (Module (Monovariant, Environment Monovariant))))) + -- FIXME: This should really be a Reader effect but for https://github.com/joshvera/effects/issues/47 + (fmap fst + (runState (lowerBound @(ModuleTable (NonEmpty (Module (Monovariant, Environment Monovariant))))) (raiseHandler (runModules (ModuleTable.modulePaths (packageModules package))) - (evaluate proxy id withTermSpans modules))))) + (evaluate proxy id withTermSpans modules)))))) parseFile :: Parser term -> FilePath -> IO term From 7ae66f18eaa28a4fb9cdef9610f8cf17eeaf3561 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 11:51:17 -0400 Subject: [PATCH 140/169] Just say Python. --- test/Analysis/Python/Spec.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Analysis/Python/Spec.hs b/test/Analysis/Python/Spec.hs index d33a43390..762d3a86f 100644 --- a/test/Analysis/Python/Spec.hs +++ b/test/Analysis/Python/Spec.hs @@ -11,7 +11,7 @@ import SpecHelpers spec :: Spec spec = parallel $ do - describe "evaluates Python" $ do + describe "Python" $ do it "imports" $ do ((Right [(_, env)], heap), _) <- evaluate ["main.py"] Env.names env `shouldContain` [ "a", "b" ] From 65d85e682df3871ff50f48fc26592228ade9c1a7 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 11:55:00 -0400 Subject: [PATCH 141/169] Use irrefutable patterns in the Python import specs. --- test/Analysis/Python/Spec.hs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/test/Analysis/Python/Spec.hs b/test/Analysis/Python/Spec.hs index 762d3a86f..276795482 100644 --- a/test/Analysis/Python/Spec.hs +++ b/test/Analysis/Python/Spec.hs @@ -13,7 +13,8 @@ spec :: Spec spec = parallel $ do describe "Python" $ do it "imports" $ do - ((Right [(_, env)], heap), _) <- evaluate ["main.py"] + ((res@(~(Right [(_, env)])), heap), _) <- evaluate ["main.py", "a.py", "b/__init__.py", "b/c.py"] + fmap (() <$) res `shouldBe` Right [()] Env.names env `shouldContain` [ "a", "b" ] (derefQName heap ("a" :| []) env >>= deNamespace) `shouldBe` Just ("a", ["foo"]) @@ -21,15 +22,18 @@ spec = parallel $ do (derefQName heap ("b" :| ["c"]) env >>= deNamespace) `shouldBe` Just ("c", ["baz"]) it "imports with aliases" $ do - ((Right [(_, env)], _), _) <- evaluate ["main1.py"] + ((res@(~(Right [(_, env)])), _), _) <- evaluate ["main1.py", "a.py", "b/__init__.py", "b/c.py"] + fmap (() <$) res `shouldBe` Right [()] Env.names env `shouldContain` [ "b", "e" ] it "imports using 'from' syntax" $ do - ((Right [(_, env)], _), _) <- evaluate ["main2.py"] + ((res@(~(Right [(_, env)])), _), _) <- evaluate ["main2.py", "a.py", "b/__init__.py", "b/c.py"] + fmap (() <$) res `shouldBe` Right [()] Env.names env `shouldContain` [ "bar", "foo" ] it "imports with relative syntax" $ do - ((Right [(_, env)], heap), _) <- evaluate ["main3.py"] + ((res@(~(Right [(_, env)])), heap), _) <- evaluate ["main3.py", "c/__init__.py", "c/utils.py"] + fmap (() <$) res `shouldBe` Right [()] Env.names env `shouldContain` [ "utils" ] (derefQName heap ("utils" :| []) env >>= deNamespace) `shouldBe` Just ("utils", ["to_s"]) From bfd79c062dbdbd98e9a268023344dd0703c9f844 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 11:55:54 -0400 Subject: [PATCH 142/169] =?UTF-8?q?:fire:=20the=20=E2=80=9Cevaluates?= =?UTF-8?q?=E2=80=9D=20prefix.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/Analysis/Go/Spec.hs | 2 +- test/Analysis/TypeScript/Spec.hs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Analysis/Go/Spec.hs b/test/Analysis/Go/Spec.hs index 62e4b77a6..1200e76a9 100644 --- a/test/Analysis/Go/Spec.hs +++ b/test/Analysis/Go/Spec.hs @@ -9,7 +9,7 @@ import SpecHelpers spec :: Spec spec = parallel $ do - describe "evaluates Go" $ do + describe "Go" $ do it "imports and wildcard imports" $ do ((Right [(_, env)], heap), _) <- evaluate ["main.go"] Env.names env `shouldBe` [ "Bar", "Rab", "foo", "main" ] diff --git a/test/Analysis/TypeScript/Spec.hs b/test/Analysis/TypeScript/Spec.hs index 87a847080..9da64cdd6 100644 --- a/test/Analysis/TypeScript/Spec.hs +++ b/test/Analysis/TypeScript/Spec.hs @@ -13,7 +13,7 @@ import SpecHelpers spec :: Spec spec = parallel $ do - describe "evaluates TypeScript" $ do + describe "TypeScript" $ do it "imports with aliased symbols" $ do ((res, _), _) <- evaluate ["main.ts", "foo.ts", "a.ts", "foo/b.ts"] (>>= Env.names . snd) <$> res `shouldBe` Right [ "bar", "quz" ] From 525f025e73cf2e1270a5ffbab7f0833b78d1e06c Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 11:56:42 -0400 Subject: [PATCH 143/169] Use irrefutable patterns in the Go specs. --- test/Analysis/Go/Spec.hs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/Analysis/Go/Spec.hs b/test/Analysis/Go/Spec.hs index 1200e76a9..972c1f6ae 100644 --- a/test/Analysis/Go/Spec.hs +++ b/test/Analysis/Go/Spec.hs @@ -11,13 +11,15 @@ spec :: Spec spec = parallel $ do describe "Go" $ do it "imports and wildcard imports" $ do - ((Right [(_, env)], heap), _) <- evaluate ["main.go"] + ((res@(~(Right [(_, env)])), heap), _) <- evaluate ["main.go"] + fmap (() <$) res `shouldBe` Right [()] Env.names env `shouldBe` [ "Bar", "Rab", "foo", "main" ] (derefQName heap ("foo" :| []) env >>= deNamespace) `shouldBe` Just ("foo", ["New"]) it "imports with aliases (and side effects only)" $ do - ((Right [(_, env)], heap), _) <- evaluate ["main1.go"] + ((res@(~(Right [(_, env)])), heap), _) <- evaluate ["main1.go"] + fmap (() <$) res `shouldBe` Right [()] Env.names env `shouldBe` [ "f", "main" ] (derefQName heap ("f" :| []) env >>= deNamespace) `shouldBe` Just ("f", ["New"]) From cb4938ef924a45d73b83accd211a056bcdfc6d9c Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 11:59:27 -0400 Subject: [PATCH 144/169] Add all the modules to the Go specs. --- test/Analysis/Go/Spec.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Analysis/Go/Spec.hs b/test/Analysis/Go/Spec.hs index 972c1f6ae..a08d9efb1 100644 --- a/test/Analysis/Go/Spec.hs +++ b/test/Analysis/Go/Spec.hs @@ -11,14 +11,14 @@ spec :: Spec spec = parallel $ do describe "Go" $ do it "imports and wildcard imports" $ do - ((res@(~(Right [(_, env)])), heap), _) <- evaluate ["main.go"] + ((res@(~(Right [(_, env)])), heap), _) <- evaluate ["main.go", "foo/foo.go", "bar/bar.go", "bar/rab.go"] fmap (() <$) res `shouldBe` Right [()] Env.names env `shouldBe` [ "Bar", "Rab", "foo", "main" ] (derefQName heap ("foo" :| []) env >>= deNamespace) `shouldBe` Just ("foo", ["New"]) it "imports with aliases (and side effects only)" $ do - ((res@(~(Right [(_, env)])), heap), _) <- evaluate ["main1.go"] + ((res@(~(Right [(_, env)])), heap), _) <- evaluate ["main1.go", "foo/foo.go", "bar/bar.go", "bar/rab.go"] fmap (() <$) res `shouldBe` Right [()] Env.names env `shouldBe` [ "f", "main" ] From 76185ed45017e1e499e272dbbfc56a1e847eaf6a Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 12:02:50 -0400 Subject: [PATCH 145/169] Use irrefutable patterns in the PHP specs. --- test/Analysis/PHP/Spec.hs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/Analysis/PHP/Spec.hs b/test/Analysis/PHP/Spec.hs index 3f6c8f72b..d528ca4f8 100644 --- a/test/Analysis/PHP/Spec.hs +++ b/test/Analysis/PHP/Spec.hs @@ -12,13 +12,13 @@ spec :: Spec spec = parallel $ do describe "PHP" $ do it "evaluates include and require" $ do - ((Right [(res, env)], _), _) <- evaluate ["main.php"] - res `shouldBe` unit + ((res@(~(Right [(_, env)])), _), _) <- evaluate ["main.php", "foo.php", "bar.php"] + map fst <$> res `shouldBe` Right [unit] Env.names env `shouldBe` [ "bar", "foo" ] it "evaluates include_once and require_once" $ do - ((Right [(res, env)], _), _) <- evaluate ["main_once.php"] - res `shouldBe` unit + ((res@(~(Right [(_, env)])), _), _) <- evaluate ["main_once.php", "foo.php", "bar.php"] + map fst <$> res `shouldBe` Right [unit] Env.names env `shouldBe` [ "bar", "foo" ] it "evaluates namespaces" $ do From 3fb45b5d50bb2a57feeb5f5bd9862bbb87b8633f Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 12:27:30 -0400 Subject: [PATCH 146/169] =?UTF-8?q?Preserve=20the=20structure=20of=20the?= =?UTF-8?q?=20data=20we=E2=80=99re=20testing=20against.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/SpecHelpers.hs | 60 ++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/test/SpecHelpers.hs b/test/SpecHelpers.hs index bf83ff636..b4823e846 100644 --- a/test/SpecHelpers.hs +++ b/test/SpecHelpers.hs @@ -81,34 +81,33 @@ readFilePair :: Both FilePath -> IO BlobPair readFilePair paths = let paths' = fmap file paths in runBothWith IO.readFilePair paths' -testEvaluating :: Evaluator Precise - Val - '[ Resumable (ValueError Precise (UtilEff Precise)) - , Resumable (AddressError Precise Val) - , Resumable EvalError, Resumable (EnvironmentError Precise) - , Resumable ResolutionError - , Resumable (Unspecialized Val) - , Resumable (LoadError Precise) - , Trace - , Fresh - , State (Heap Precise Latest Val) - , IO - ] - (ModuleTable (NonEmpty (Module (Precise, Environment Precise)))) - -> IO ((Either - (SomeExc - (Data.Sum.Sum - '[ ValueError Precise (UtilEff Precise) - , AddressError Precise Val - , EvalError - , EnvironmentError Precise - , ResolutionError - , Unspecialized Val - , LoadError Precise - ])) - [(Value Precise (UtilEff Precise), Environment Precise)], - Heap Precise Latest Val), - [String]) +type TestEvaluatingEffects = '[ Resumable (ValueError Precise (UtilEff Precise)) + , Resumable (AddressError Precise Val) + , Resumable EvalError, Resumable (EnvironmentError Precise) + , Resumable ResolutionError + , Resumable (Unspecialized Val) + , Resumable (LoadError Precise) + , Trace + , Fresh + , State (Heap Precise Latest Val) + , IO + ] +type TestEvaluatingErrors = '[ ValueError Precise (UtilEff Precise) + , AddressError Precise Val + , EvalError + , EnvironmentError Precise + , ResolutionError + , Unspecialized Val + , LoadError Precise + ] +testEvaluating :: Evaluator Precise Val TestEvaluatingEffects (ModuleTable (NonEmpty (Module (Precise, Environment Precise)))) + -> IO + ( ( Either (SomeExc (Data.Sum.Sum TestEvaluatingErrors)) + (ModuleTable (NonEmpty (Module (Precise, Environment Precise)))) + , Heap Precise Latest Val + ) + , [String] + ) testEvaluating = runM . fmap (\ ((res, traces), heap) -> ((res, heap), traces)) @@ -123,14 +122,9 @@ testEvaluating . runEvalError . runAddressError . runValueError @_ @Precise @(UtilEff Precise) - . (>>= traverse deref1) - . fmap ((>>= map moduleBody . toList . snd) . toPairs) type Val = Value Precise (UtilEff Precise) -deref1 (ptr, env) = runAllocator $ do - val <- deref ptr - pure (val, env) deNamespace :: Value Precise term -> Maybe (Name, [Name]) deNamespace (Namespace name scope) = Just (name, Env.names scope) From 95bad9931910cd94f8827f079c4829fec263da15 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 12:53:33 -0400 Subject: [PATCH 147/169] Just modify for now. --- src/Data/Abstract/Evaluatable.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 1cebd6005..0824d5699 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -101,7 +101,8 @@ evaluate lang analyzeModule analyzeTerm modules = do foldr (run preludeEnv) get modules where run preludeEnv modules rest = do evaluated <- traverse (evalModule preludeEnv) modules - localState (<> ModuleTable.fromModules (toList evaluated)) rest + modify' (<> ModuleTable.fromModules (toList evaluated)) + rest evalModule preludeEnv m = fmap (<$ m) From f451d2bacdae84de0c3b41adfb2161ba75f0a9ce Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 12:57:12 -0400 Subject: [PATCH 148/169] :memo: topologicalSort. --- src/Data/Graph.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Data/Graph.hs b/src/Data/Graph.hs index f84047ca7..6a939e62e 100644 --- a/src/Data/Graph.hs +++ b/src/Data/Graph.hs @@ -28,6 +28,7 @@ simplify :: Ord vertex => Graph vertex -> Graph vertex simplify (Graph graph) = Graph (G.simplify graph) +-- | Sort a graph’s vertices by the number of in-edges. topologicalSort :: Ord v => Graph v -> [NonEmpty v] topologicalSort = map (fmap fst) From 2e3636c0151c863da087a11ab4b50806c148b92b Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 13:02:37 -0400 Subject: [PATCH 149/169] Test topological sort on a -> b. --- src/Data/Graph.hs | 3 +++ test/Doctests.hs | 1 + 2 files changed, 4 insertions(+) diff --git a/src/Data/Graph.hs b/src/Data/Graph.hs index 6a939e62e..64f019e38 100644 --- a/src/Data/Graph.hs +++ b/src/Data/Graph.hs @@ -29,6 +29,9 @@ simplify (Graph graph) = Graph (G.simplify graph) -- | Sort a graph’s vertices by the number of in-edges. +-- +-- >>> topologicalSort (Class.path "ab") +-- ['b' :| "",'a' :| ""] topologicalSort :: Ord v => Graph v -> [NonEmpty v] topologicalSort = map (fmap fst) diff --git a/test/Doctests.hs b/test/Doctests.hs index 395677757..8aa098b51 100644 --- a/test/Doctests.hs +++ b/test/Doctests.hs @@ -9,6 +9,7 @@ defaultFiles = [ "src/Data/Abstract/Address.hs" , "src/Data/Abstract/Environment.hs" , "src/Data/Abstract/Name.hs" + , "src/Data/Graph.hs" , "src/Data/Range.hs" , "src/Data/Semigroup/App.hs" ] From 091a341de44c1b2dcad299cbf89159ea77d19cfc Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 13:02:49 -0400 Subject: [PATCH 150/169] Test topological sort on a -> b -> c. This test fails. --- src/Data/Graph.hs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Data/Graph.hs b/src/Data/Graph.hs index 64f019e38..4070c9109 100644 --- a/src/Data/Graph.hs +++ b/src/Data/Graph.hs @@ -32,6 +32,9 @@ simplify (Graph graph) = Graph (G.simplify graph) -- -- >>> topologicalSort (Class.path "ab") -- ['b' :| "",'a' :| ""] +-- +-- >>> topologicalSort (Class.path "abc") +-- ['c' :| "",'b' :| "",'a' :| ""] topologicalSort :: Ord v => Graph v -> [NonEmpty v] topologicalSort = map (fmap fst) From 1ac4b8d006998c930cf8037bac239b0f8ee39bea Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 13:05:22 -0400 Subject: [PATCH 151/169] Inline the definitiion of edgeCountsByVertex. --- src/Data/Graph.hs | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/Data/Graph.hs b/src/Data/Graph.hs index 4070c9109..45e41b7fd 100644 --- a/src/Data/Graph.hs +++ b/src/Data/Graph.hs @@ -40,18 +40,15 @@ topologicalSort = map (fmap fst) . sortAndGroupBy (inEdgeCount . snd) . Monoidal.pairs - . edgeCountsByVertex - -edgeCountsByVertex :: Ord v => Graph v -> Monoidal.Map v EdgeCounts -edgeCountsByVertex = Class.foldg - lowerBound - (flip Monoidal.singleton mempty) - (<>) - (\ outM inM - -> outM - <> inM - <> foldMap (flip Monoidal.singleton (EdgeCounts 0 (length outM))) (Monoidal.keys inM) - <> foldMap (flip Monoidal.singleton (EdgeCounts (length inM) 0)) (Monoidal.keys outM)) + . Class.foldg + lowerBound + (flip Monoidal.singleton mempty) + (<>) + (\ outM inM + -> outM + <> inM + <> foldMap (flip Monoidal.singleton (EdgeCounts 0 (length outM))) (Monoidal.keys inM) + <> foldMap (flip Monoidal.singleton (EdgeCounts (length inM) 0)) (Monoidal.keys outM)) data EdgeCounts = EdgeCounts { inEdgeCount :: {-# UNPACK #-} !Int From abc872af8627fa1277aca363e592626824332029 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 15:52:27 -0400 Subject: [PATCH 152/169] Correct the docs for topologicalSort. Co-Authored-By: Rick Winfrey --- src/Data/Graph.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Data/Graph.hs b/src/Data/Graph.hs index 45e41b7fd..61305a3f3 100644 --- a/src/Data/Graph.hs +++ b/src/Data/Graph.hs @@ -28,7 +28,7 @@ simplify :: Ord vertex => Graph vertex -> Graph vertex simplify (Graph graph) = Graph (G.simplify graph) --- | Sort a graph’s vertices by the number of in-edges. +-- | Sort a graph’s vertices topologically. -- -- >>> topologicalSort (Class.path "ab") -- ['b' :| "",'a' :| ""] From c9d340affbac29d2e851a4b9d6b98235d889478c Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 15:55:49 -0400 Subject: [PATCH 153/169] Define topologicalSort using the depth-first algorithm. Co-Authored-By: Rick Winfrey --- src/Data/Graph.hs | 73 ++++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/src/Data/Graph.hs b/src/Data/Graph.hs index 61305a3f3..60d99b6c3 100644 --- a/src/Data/Graph.hs +++ b/src/Data/Graph.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE GeneralizedNewtypeDeriving, TypeFamilies, UndecidableInstances #-} +{-# LANGUAGE GeneralizedNewtypeDeriving, ScopedTypeVariables, TypeFamilies, UndecidableInstances #-} module Data.Graph ( Graph(..) , Class.overlay @@ -7,20 +7,19 @@ module Data.Graph , Lower(..) , simplify , topologicalSort -, EdgeCounts(..) ) where import qualified Algebra.Graph as G +import qualified Algebra.Graph.AdjacencyMap as A import qualified Algebra.Graph.Class as Class +import Control.Monad.Effect +import Control.Monad.Effect.State import Data.Aeson -import Data.List (groupBy, sortBy) -import qualified Data.List.NonEmpty as NonEmpty (fromList) -import qualified Data.Map.Monoidal as Monoidal -import Data.Ord (comparing) +import qualified Data.Set as Set import Prologue -- | An algebraic graph with 'Ord', 'Semigroup', and 'Monoid' instances. -newtype Graph vertex = Graph (G.Graph vertex) +newtype Graph vertex = Graph { unGraph :: G.Graph vertex } deriving (Alternative, Applicative, Eq, Foldable, Functor, Class.Graph, Monad, Show, Class.ToGraph, Traversable) @@ -31,40 +30,44 @@ simplify (Graph graph) = Graph (G.simplify graph) -- | Sort a graph’s vertices topologically. -- -- >>> topologicalSort (Class.path "ab") --- ['b' :| "",'a' :| ""] +-- "ba" -- -- >>> topologicalSort (Class.path "abc") --- ['c' :| "",'b' :| "",'a' :| ""] -topologicalSort :: Ord v => Graph v -> [NonEmpty v] -topologicalSort - = map (fmap fst) - . sortAndGroupBy (inEdgeCount . snd) - . Monoidal.pairs - . Class.foldg - lowerBound - (flip Monoidal.singleton mempty) - (<>) - (\ outM inM - -> outM - <> inM - <> foldMap (flip Monoidal.singleton (EdgeCounts 0 (length outM))) (Monoidal.keys inM) - <> foldMap (flip Monoidal.singleton (EdgeCounts (length inM) 0)) (Monoidal.keys outM)) +-- "cba" +-- +-- >>> topologicalSort (Class.path "abc") +-- "cba" +topologicalSort :: forall v . Ord v => Graph v -> [v] +topologicalSort = go . toAdjacencyMap . G.transpose . unGraph + where go :: A.AdjacencyMap v -> [v] + go graph + = visitedOrder . snd + . run + . runState (Visited lowerBound []) + . traverse_ visit + . A.vertexList + $ graph + where visit :: v -> Eff '[State (Visited v)] () + visit v = do + isMarked <- Set.member v . visitedVertices <$> get + if isMarked then + pure () + else do + modify' (extendVisited (Set.insert v)) + traverse_ visit (Set.toList (A.postSet v graph)) + modify' (extendOrder (v :)) -data EdgeCounts = EdgeCounts - { inEdgeCount :: {-# UNPACK #-} !Int - , outEdgeCount :: {-# UNPACK #-} !Int - } - deriving (Eq, Ord, Show) +data Visited v = Visited { visitedVertices :: !(Set v), visitedOrder :: [v] } -instance Semigroup EdgeCounts where - EdgeCounts in1 out1 <> EdgeCounts in2 out2 = EdgeCounts (in1 + in2) (out1 + out2) +extendVisited :: (Set v -> Set v) -> Visited v -> Visited v +extendVisited f (Visited a b) = Visited (f a) b -instance Monoid EdgeCounts where - mempty = EdgeCounts 0 0 - mappend = (<>) +extendOrder :: ([v] -> [v]) -> Visited v -> Visited v +extendOrder f (Visited a b) = Visited a (f b) -sortAndGroupBy :: Ord b => (a -> b) -> [a] -> [NonEmpty a] -sortAndGroupBy by = map NonEmpty.fromList . groupBy ((==) `on` by) . sortBy (comparing by) + +toAdjacencyMap :: Ord v => G.Graph v -> A.AdjacencyMap v +toAdjacencyMap = Class.toGraph instance Lower (Graph vertex) where From 935ac3015f7acd1613bcf38916cc304083ed3fe8 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 15:56:00 -0400 Subject: [PATCH 154/169] Line the types up. Co-Authored-By: Rick Winfrey --- src/Data/Abstract/Evaluatable.hs | 8 ++++---- src/Semantic/Graph.hs | 2 +- src/Semantic/Util.hs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 0824d5699..1fbf5875c 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -91,7 +91,7 @@ evaluate :: ( AbstractValue address value inner => proxy lang -> (SubtermAlgebra Module term (TermEvaluator term address value inner address) -> SubtermAlgebra Module term (TermEvaluator term address value inner address)) -> (SubtermAlgebra (Base term) term (TermEvaluator term address value inner (ValueRef address)) -> SubtermAlgebra (Base term) term (TermEvaluator term address value inner (ValueRef address))) - -> [NonEmpty (Module term)] + -> [Module term] -> TermEvaluator term address value effects (ModuleTable (NonEmpty (Module (address, Environment address)))) evaluate lang analyzeModule analyzeTerm modules = do (_, preludeEnv) <- TermEvaluator . runInModule lowerBound moduleInfoFromCallStack $ do @@ -99,9 +99,9 @@ evaluate lang analyzeModule analyzeTerm modules = do definePrelude lang box unit foldr (run preludeEnv) get modules - where run preludeEnv modules rest = do - evaluated <- traverse (evalModule preludeEnv) modules - modify' (<> ModuleTable.fromModules (toList evaluated)) + where run preludeEnv m rest = do + evaluated <- evalModule preludeEnv m + modify' (ModuleTable.insert (modulePath (moduleInfo evaluated)) (evaluated :| [])) rest evalModule preludeEnv m diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index ed88d5a46..6887979ed 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -145,7 +145,7 @@ runImportGraph lang (package :: Package term) . runTermEvaluator @_ @_ @(Value (Hole Precise) (ImportGraphEff term (Hole Precise))) . runReader (packageInfo package) . runReader lowerBound - in extractGraph <$> analyze runImportGraphAnalysis (evaluate @_ @_ @_ @_ @term lang analyzeModule analyzeTerm (map snd (ModuleTable.toPairs (packageModules package)))) + in extractGraph <$> analyze runImportGraphAnalysis (evaluate @_ @_ @_ @_ @term lang analyzeModule analyzeTerm (ModuleTable.toPairs (packageModules package) >>= toList . snd)) newtype ImportGraphEff term address a = ImportGraphEff { runImportGraphEff :: Eff '[ LoopControl address diff --git a/src/Semantic/Util.hs b/src/Semantic/Util.hs index d644fd96f..658171262 100644 --- a/src/Semantic/Util.hs +++ b/src/Semantic/Util.hs @@ -100,7 +100,7 @@ typecheckGoFile = checking <=< evaluateProjectWithCaching (Proxy :: Proxy 'Langu evaluateProject proxy parser lang paths = runTaskWithOptions debugOptions $ do package <- fmap quieterm <$> parsePackage parser (Project (takeDirectory (maybe "/" fst (uncons paths))) (flip File lang <$> paths) lang []) modules <- topologicalSort <$> runImportGraph proxy package - trace $ "evaluating with load order: " <> show (map (modulePath . moduleInfo) . toList <$> modules) + trace $ "evaluating with load order: " <> show (map (modulePath . moduleInfo) modules) pure (runTermEvaluator @_ @_ @(Value Precise (UtilEff Precise)) (runReader (packageInfo package) (runReader (lowerBound @Span) From f70974e2063bb16a726bddeb7d2344bc710247a0 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 15:57:04 -0400 Subject: [PATCH 155/169] Fix up the TypeScript specs. Co-Authored-By: Rick Winfrey --- test/Analysis/Go/Spec.hs | 27 ++++---- test/Analysis/PHP/Spec.hs | 35 +++++----- test/Analysis/Python/Spec.hs | 65 +++++++++--------- test/Analysis/Ruby/Spec.hs | 109 ++++++++++++++++--------------- test/Analysis/TypeScript/Spec.hs | 29 +++++--- 5 files changed, 139 insertions(+), 126 deletions(-) diff --git a/test/Analysis/Go/Spec.hs b/test/Analysis/Go/Spec.hs index a08d9efb1..b755f98e5 100644 --- a/test/Analysis/Go/Spec.hs +++ b/test/Analysis/Go/Spec.hs @@ -10,19 +10,20 @@ import SpecHelpers spec :: Spec spec = parallel $ do describe "Go" $ do - it "imports and wildcard imports" $ do - ((res@(~(Right [(_, env)])), heap), _) <- evaluate ["main.go", "foo/foo.go", "bar/bar.go", "bar/rab.go"] - fmap (() <$) res `shouldBe` Right [()] - Env.names env `shouldBe` [ "Bar", "Rab", "foo", "main" ] - - (derefQName heap ("foo" :| []) env >>= deNamespace) `shouldBe` Just ("foo", ["New"]) - - it "imports with aliases (and side effects only)" $ do - ((res@(~(Right [(_, env)])), heap), _) <- evaluate ["main1.go", "foo/foo.go", "bar/bar.go", "bar/rab.go"] - fmap (() <$) res `shouldBe` Right [()] - Env.names env `shouldBe` [ "f", "main" ] - - (derefQName heap ("f" :| []) env >>= deNamespace) `shouldBe` Just ("f", ["New"]) + pure () + -- it "imports and wildcard imports" $ do + -- ((res@(~(Right [(_, env)])), heap), _) <- evaluate ["main.go", "foo/foo.go", "bar/bar.go", "bar/rab.go"] + -- fmap (() <$) res `shouldBe` Right [()] + -- Env.names env `shouldBe` [ "Bar", "Rab", "foo", "main" ] + -- + -- (derefQName heap ("foo" :| []) env >>= deNamespace) `shouldBe` Just ("foo", ["New"]) + -- + -- it "imports with aliases (and side effects only)" $ do + -- ((res@(~(Right [(_, env)])), heap), _) <- evaluate ["main1.go", "foo/foo.go", "bar/bar.go", "bar/rab.go"] + -- fmap (() <$) res `shouldBe` Right [()] + -- Env.names env `shouldBe` [ "f", "main" ] + -- + -- (derefQName heap ("f" :| []) env >>= deNamespace) `shouldBe` Just ("f", ["New"]) where fixtures = "test/fixtures/go/analysis/" diff --git a/test/Analysis/PHP/Spec.hs b/test/Analysis/PHP/Spec.hs index d528ca4f8..21b1fb6f1 100644 --- a/test/Analysis/PHP/Spec.hs +++ b/test/Analysis/PHP/Spec.hs @@ -11,23 +11,24 @@ import SpecHelpers spec :: Spec spec = parallel $ do describe "PHP" $ do - it "evaluates include and require" $ do - ((res@(~(Right [(_, env)])), _), _) <- evaluate ["main.php", "foo.php", "bar.php"] - map fst <$> res `shouldBe` Right [unit] - Env.names env `shouldBe` [ "bar", "foo" ] - - it "evaluates include_once and require_once" $ do - ((res@(~(Right [(_, env)])), _), _) <- evaluate ["main_once.php", "foo.php", "bar.php"] - map fst <$> res `shouldBe` Right [unit] - Env.names env `shouldBe` [ "bar", "foo" ] - - it "evaluates namespaces" $ do - ((Right [(_, env)], heap), _) <- evaluate ["namespaces.php"] - Env.names env `shouldBe` [ "Foo", "NS1" ] - - (derefQName heap ("NS1" :| []) env >>= deNamespace) `shouldBe` Just ("NS1", ["Sub1", "b", "c"]) - (derefQName heap ("NS1" :| ["Sub1"]) env >>= deNamespace) `shouldBe` Just ("Sub1", ["Sub2"]) - (derefQName heap ("NS1" :| ["Sub1", "Sub2"]) env >>= deNamespace) `shouldBe` Just ("Sub2", ["f"]) + pure () + -- it "evaluates include and require" $ do + -- ((res@(~(Right [(_, env)])), _), _) <- evaluate ["main.php", "foo.php", "bar.php"] + -- map fst <$> res `shouldBe` Right [unit] + -- Env.names env `shouldBe` [ "bar", "foo" ] + -- + -- it "evaluates include_once and require_once" $ do + -- ((res@(~(Right [(_, env)])), _), _) <- evaluate ["main_once.php", "foo.php", "bar.php"] + -- map fst <$> res `shouldBe` Right [unit] + -- Env.names env `shouldBe` [ "bar", "foo" ] + -- + -- it "evaluates namespaces" $ do + -- ((Right [(_, env)], heap), _) <- evaluate ["namespaces.php"] + -- Env.names env `shouldBe` [ "Foo", "NS1" ] + -- + -- (derefQName heap ("NS1" :| []) env >>= deNamespace) `shouldBe` Just ("NS1", ["Sub1", "b", "c"]) + -- (derefQName heap ("NS1" :| ["Sub1"]) env >>= deNamespace) `shouldBe` Just ("Sub1", ["Sub2"]) + -- (derefQName heap ("NS1" :| ["Sub1", "Sub2"]) env >>= deNamespace) `shouldBe` Just ("Sub2", ["f"]) where fixtures = "test/fixtures/php/analysis/" diff --git a/test/Analysis/Python/Spec.hs b/test/Analysis/Python/Spec.hs index 276795482..0d793590b 100644 --- a/test/Analysis/Python/Spec.hs +++ b/test/Analysis/Python/Spec.hs @@ -12,38 +12,39 @@ import SpecHelpers spec :: Spec spec = parallel $ do describe "Python" $ do - it "imports" $ do - ((res@(~(Right [(_, env)])), heap), _) <- evaluate ["main.py", "a.py", "b/__init__.py", "b/c.py"] - fmap (() <$) res `shouldBe` Right [()] - Env.names env `shouldContain` [ "a", "b" ] - - (derefQName heap ("a" :| []) env >>= deNamespace) `shouldBe` Just ("a", ["foo"]) - (derefQName heap ("b" :| []) env >>= deNamespace) `shouldBe` Just ("b", ["c"]) - (derefQName heap ("b" :| ["c"]) env >>= deNamespace) `shouldBe` Just ("c", ["baz"]) - - it "imports with aliases" $ do - ((res@(~(Right [(_, env)])), _), _) <- evaluate ["main1.py", "a.py", "b/__init__.py", "b/c.py"] - fmap (() <$) res `shouldBe` Right [()] - Env.names env `shouldContain` [ "b", "e" ] - - it "imports using 'from' syntax" $ do - ((res@(~(Right [(_, env)])), _), _) <- evaluate ["main2.py", "a.py", "b/__init__.py", "b/c.py"] - fmap (() <$) res `shouldBe` Right [()] - Env.names env `shouldContain` [ "bar", "foo" ] - - it "imports with relative syntax" $ do - ((res@(~(Right [(_, env)])), heap), _) <- evaluate ["main3.py", "c/__init__.py", "c/utils.py"] - fmap (() <$) res `shouldBe` Right [()] - Env.names env `shouldContain` [ "utils" ] - (derefQName heap ("utils" :| []) env >>= deNamespace) `shouldBe` Just ("utils", ["to_s"]) - - it "subclasses" $ do - ((res, _), _) <- evaluate ["subclass.py"] - fmap fst <$> res `shouldBe` Right [String "\"bar\""] - - it "handles multiple inheritance left-to-right" $ do - ((res, _), _) <- evaluate ["multiple_inheritance.py"] - fmap fst <$> res `shouldBe` Right [String "\"foo!\""] + pure () + -- it "imports" $ do + -- ((res@(~(Right [(_, env)])), heap), _) <- evaluate ["main.py", "a.py", "b/__init__.py", "b/c.py"] + -- fmap (() <$) res `shouldBe` Right [()] + -- Env.names env `shouldContain` [ "a", "b" ] + -- + -- (derefQName heap ("a" :| []) env >>= deNamespace) `shouldBe` Just ("a", ["foo"]) + -- (derefQName heap ("b" :| []) env >>= deNamespace) `shouldBe` Just ("b", ["c"]) + -- (derefQName heap ("b" :| ["c"]) env >>= deNamespace) `shouldBe` Just ("c", ["baz"]) + -- + -- it "imports with aliases" $ do + -- ((res@(~(Right [(_, env)])), _), _) <- evaluate ["main1.py", "a.py", "b/__init__.py", "b/c.py"] + -- fmap (() <$) res `shouldBe` Right [()] + -- Env.names env `shouldContain` [ "b", "e" ] + -- + -- it "imports using 'from' syntax" $ do + -- ((res@(~(Right [(_, env)])), _), _) <- evaluate ["main2.py", "a.py", "b/__init__.py", "b/c.py"] + -- fmap (() <$) res `shouldBe` Right [()] + -- Env.names env `shouldContain` [ "bar", "foo" ] + -- + -- it "imports with relative syntax" $ do + -- ((res@(~(Right [(_, env)])), heap), _) <- evaluate ["main3.py", "c/__init__.py", "c/utils.py"] + -- fmap (() <$) res `shouldBe` Right [()] + -- Env.names env `shouldContain` [ "utils" ] + -- (derefQName heap ("utils" :| []) env >>= deNamespace) `shouldBe` Just ("utils", ["to_s"]) + -- + -- it "subclasses" $ do + -- ((res, _), _) <- evaluate ["subclass.py"] + -- fmap fst <$> res `shouldBe` Right [String "\"bar\""] + -- + -- it "handles multiple inheritance left-to-right" $ do + -- ((res, _), _) <- evaluate ["multiple_inheritance.py"] + -- fmap fst <$> res `shouldBe` Right [String "\"foo!\""] where ns n = Just . Latest . Last . Just . Namespace n diff --git a/test/Analysis/Ruby/Spec.hs b/test/Analysis/Ruby/Spec.hs index 53a0971be..fb5294cc0 100644 --- a/test/Analysis/Ruby/Spec.hs +++ b/test/Analysis/Ruby/Spec.hs @@ -17,60 +17,61 @@ import SpecHelpers spec :: Spec spec = parallel $ do describe "Ruby" $ do - it "evaluates require_relative" $ do - ((res@(~(Right [(_, env)])), _), _) <- evaluate ["main.rb", "foo.rb"] - map fst <$> res `shouldBe` Right [Value.Integer (Number.Integer 1)] - Env.names env `shouldContain` ["foo"] - - it "evaluates load" $ do - ((res@(~(Right [(_, env)])), _), _) <- evaluate ["load.rb", "foo.rb"] - map fst <$> res `shouldBe` Right [Value.Integer (Number.Integer 1)] - Env.names env `shouldContain` ["foo"] - - it "evaluates load with wrapper" $ do - ((res, _), _) <- evaluate ["load-wrap.rb", "foo.rb"] - res `shouldBe` Left (SomeExc (inject @(EnvironmentError Precise) (FreeVariable "foo"))) - - it "evaluates subclass" $ do - ((res@(~(Right [(_, env)])), heap), _) <- evaluate ["subclass.rb"] - map fst <$> res `shouldBe` Right [String "\"\""] - Env.names env `shouldContain` [ "Bar", "Foo" ] - - (derefQName heap ("Bar" :| []) env >>= deNamespace) `shouldBe` Just ("Bar", ["baz", "foo", "inspect"]) - - it "evaluates modules" $ do - ((res@(~(Right [(_, env)])), _), _) <- evaluate ["modules.rb"] - map fst <$> res `shouldBe` Right [String "\"\""] - Env.names env `shouldContain` [ "Bar" ] - - it "handles break correctly" $ do - ((res, _), _) <- evaluate ["break.rb"] - fmap fst <$> res `shouldBe` Right [Value.Integer (Number.Integer 3)] - - it "handles break correctly" $ do - ((res, _), _) <- evaluate ["next.rb"] - fmap fst <$> res `shouldBe` Right [Value.Integer (Number.Integer 8)] - - it "calls functions with arguments" $ do - ((res, _), _) <- evaluate ["call.rb"] - fmap fst <$> res `shouldBe` Right [Value.Integer (Number.Integer 579)] - - it "evaluates early return statements" $ do - ((res, _), _) <- evaluate ["early-return.rb"] - fmap fst <$> res `shouldBe` Right [Value.Integer (Number.Integer 123)] - - it "has prelude" $ do - ((res, _), _) <- evaluate ["preluded.rb"] - fmap fst <$> res `shouldBe` Right [String "\"\""] - - it "evaluates __LINE__" $ do - ((res, _), _) <- evaluate ["line.rb"] - fmap fst <$> res `shouldBe` Right [Value.Integer (Number.Integer 4)] - - it "resolves builtins used in the prelude" $ do - ((res, _), traces) <- evaluate ["puts.rb"] - fmap fst <$> res `shouldBe` Right [Unit] - traces `shouldContain` [ "\"hello\"" ] + pure () + -- it "evaluates require_relative" $ do + -- ((res@(~(Right [(_, env)])), _), _) <- evaluate ["main.rb", "foo.rb"] + -- map fst <$> res `shouldBe` Right [Value.Integer (Number.Integer 1)] + -- Env.names env `shouldContain` ["foo"] + -- + -- it "evaluates load" $ do + -- ((res@(~(Right [(_, env)])), _), _) <- evaluate ["load.rb", "foo.rb"] + -- map fst <$> res `shouldBe` Right [Value.Integer (Number.Integer 1)] + -- Env.names env `shouldContain` ["foo"] + -- + -- it "evaluates load with wrapper" $ do + -- ((res, _), _) <- evaluate ["load-wrap.rb", "foo.rb"] + -- res `shouldBe` Left (SomeExc (inject @(EnvironmentError Precise) (FreeVariable "foo"))) + -- + -- it "evaluates subclass" $ do + -- ((res@(~(Right [(_, env)])), heap), _) <- evaluate ["subclass.rb"] + -- map fst <$> res `shouldBe` Right [String "\"\""] + -- Env.names env `shouldContain` [ "Bar", "Foo" ] + -- + -- (derefQName heap ("Bar" :| []) env >>= deNamespace) `shouldBe` Just ("Bar", ["baz", "foo", "inspect"]) + -- + -- it "evaluates modules" $ do + -- ((res@(~(Right [(_, env)])), _), _) <- evaluate ["modules.rb"] + -- map fst <$> res `shouldBe` Right [String "\"\""] + -- Env.names env `shouldContain` [ "Bar" ] + -- + -- it "handles break correctly" $ do + -- ((res, _), _) <- evaluate ["break.rb"] + -- fmap fst <$> res `shouldBe` Right [Value.Integer (Number.Integer 3)] + -- + -- it "handles break correctly" $ do + -- ((res, _), _) <- evaluate ["next.rb"] + -- fmap fst <$> res `shouldBe` Right [Value.Integer (Number.Integer 8)] + -- + -- it "calls functions with arguments" $ do + -- ((res, _), _) <- evaluate ["call.rb"] + -- fmap fst <$> res `shouldBe` Right [Value.Integer (Number.Integer 579)] + -- + -- it "evaluates early return statements" $ do + -- ((res, _), _) <- evaluate ["early-return.rb"] + -- fmap fst <$> res `shouldBe` Right [Value.Integer (Number.Integer 123)] + -- + -- it "has prelude" $ do + -- ((res, _), _) <- evaluate ["preluded.rb"] + -- fmap fst <$> res `shouldBe` Right [String "\"\""] + -- + -- it "evaluates __LINE__" $ do + -- ((res, _), _) <- evaluate ["line.rb"] + -- fmap fst <$> res `shouldBe` Right [Value.Integer (Number.Integer 4)] + -- + -- it "resolves builtins used in the prelude" $ do + -- ((res, _), traces) <- evaluate ["puts.rb"] + -- fmap fst <$> res `shouldBe` Right [Unit] + -- traces `shouldContain` [ "\"hello\"" ] where ns n = Just . Latest . Last . Just . Namespace n diff --git a/test/Analysis/TypeScript/Spec.hs b/test/Analysis/TypeScript/Spec.hs index 9da64cdd6..2f422ded3 100644 --- a/test/Analysis/TypeScript/Spec.hs +++ b/test/Analysis/TypeScript/Spec.hs @@ -3,12 +3,12 @@ module Analysis.TypeScript.Spec (spec) where import Control.Arrow ((&&&)) import Data.Abstract.Environment as Env import Data.Abstract.Evaluatable -import qualified Language.TypeScript.Assignment as TypeScript import Data.Abstract.Value as Value import Data.Abstract.Number as Number +import qualified Data.Abstract.ModuleTable as ModuleTable import qualified Data.Language as Language +import qualified Data.List.NonEmpty as NonEmpty import Data.Sum - import SpecHelpers spec :: Spec @@ -16,26 +16,35 @@ spec = parallel $ do describe "TypeScript" $ do it "imports with aliased symbols" $ do ((res, _), _) <- evaluate ["main.ts", "foo.ts", "a.ts", "foo/b.ts"] - (>>= Env.names . snd) <$> res `shouldBe` Right [ "bar", "quz" ] + case ModuleTable.lookup "main.ts" <$> res of + Right (Just (Module _ (_, env) :| [])) -> Env.names env `shouldBe` [ "bar", "quz" ] + other -> expectationFailure (show other) it "imports with qualified names" $ do - ((res@(~(Right [(_, env)])), heap), _) <- evaluate ["main1.ts", "foo.ts", "a.ts"] - (>>= Env.names . snd) <$> res `shouldBe` Right [ "b", "z" ] + ((res, heap), _) <- evaluate ["main1.ts", "foo.ts", "a.ts"] + case ModuleTable.lookup "main1.ts" <$> res of + Right (Just (Module _ (_, env) :| [])) -> do + Env.names env `shouldBe` [ "b", "z" ] - (derefQName heap ("b" :| []) env >>= deNamespace) `shouldBe` Just ("b", [ "baz", "foo" ]) - (derefQName heap ("z" :| []) env >>= deNamespace) `shouldBe` Just ("z", [ "baz", "foo" ]) + (derefQName heap ("b" :| []) env >>= deNamespace) `shouldBe` Just ("b", [ "baz", "foo" ]) + (derefQName heap ("z" :| []) env >>= deNamespace) `shouldBe` Just ("z", [ "baz", "foo" ]) + other -> expectationFailure (show other) it "side effect only imports" $ do ((res, _), _) <- evaluate ["main2.ts", "a.ts", "foo.ts"] - fmap snd <$> res `shouldBe` Right [lowerBound] + case ModuleTable.lookup "main2.ts" <$> res of + Right (Just (Module _ (_, env) :| [])) -> env `shouldBe` lowerBound + other -> expectationFailure (show other) it "fails exporting symbols not defined in the module" $ do ((res, _), _) <- evaluate ["bad-export.ts", "pip.ts", "a.ts", "foo.ts"] res `shouldBe` Left (SomeExc (inject @EvalError (ExportError "foo.ts" (name "pip")))) it "evaluates early return statements" $ do - ((res, _), _) <- evaluate ["early-return.ts"] - fmap fst <$> res `shouldBe` Right [Value.Float (Number.Decimal 123.0)] + ((res, heap), _) <- evaluate ["early-return.ts"] + case ModuleTable.lookup "early-return.ts" <$> res of + Right (Just (Module _ (addr, _) :| [])) -> heapLookupAll addr heap `shouldBe` Just [Value.Float (Number.Decimal 123.0)] + other -> expectationFailure (show other) where fixtures = "test/fixtures/typescript/analysis/" From e3b06dada82e860f75b1ceb32b3d8f2f135ce1c2 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 16:06:08 -0400 Subject: [PATCH 156/169] Import the graph constructors unqualified. Co-Authored-By: Rick Winfrey --- src/Data/Graph.hs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Data/Graph.hs b/src/Data/Graph.hs index 60d99b6c3..578f9c5eb 100644 --- a/src/Data/Graph.hs +++ b/src/Data/Graph.hs @@ -1,9 +1,9 @@ {-# LANGUAGE GeneralizedNewtypeDeriving, ScopedTypeVariables, TypeFamilies, UndecidableInstances #-} module Data.Graph ( Graph(..) -, Class.overlay -, Class.connect -, Class.vertex +, overlay +, connect +, vertex , Lower(..) , simplify , topologicalSort @@ -11,6 +11,7 @@ module Data.Graph import qualified Algebra.Graph as G import qualified Algebra.Graph.AdjacencyMap as A +import Algebra.Graph.Class (connect, overlay, vertex) import qualified Algebra.Graph.Class as Class import Control.Monad.Effect import Control.Monad.Effect.State @@ -74,7 +75,7 @@ instance Lower (Graph vertex) where lowerBound = Class.empty instance Semigroup (Graph vertex) where - (<>) = Class.overlay + (<>) = overlay instance Monoid (Graph vertex) where mempty = Class.empty From d346a36559db1b089a9cde0a8fe95587e10ada9d Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 16:07:54 -0400 Subject: [PATCH 157/169] Add some more doctests. Co-Authored-By: Rick Winfrey --- src/Data/Graph.hs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Data/Graph.hs b/src/Data/Graph.hs index 578f9c5eb..cb65a4b0d 100644 --- a/src/Data/Graph.hs +++ b/src/Data/Graph.hs @@ -36,7 +36,13 @@ simplify (Graph graph) = Graph (G.simplify graph) -- >>> topologicalSort (Class.path "abc") -- "cba" -- --- >>> topologicalSort (Class.path "abc") +-- >>> topologicalSort ((vertex 'a' `connect` vertex 'b') `connect` vertex 'c') +-- "cba" +-- +-- >>> topologicalSort (vertex 'a' `connect` (vertex 'b' `connect` vertex 'c')) +-- "cba" +-- +-- >>> topologicalSort ((vertex 'a' `connect` vertex 'b') <> (vertex 'a' `connect` vertex 'c')) -- "cba" topologicalSort :: forall v . Ord v => Graph v -> [v] topologicalSort = go . toAdjacencyMap . G.transpose . unGraph From 4943a58d43492798eee4a708f8d27f6510cd840c Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 16:09:55 -0400 Subject: [PATCH 158/169] Test a diamond graph. Co-Authored-By: Rick Winfrey --- src/Data/Graph.hs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Data/Graph.hs b/src/Data/Graph.hs index cb65a4b0d..bfcd112c3 100644 --- a/src/Data/Graph.hs +++ b/src/Data/Graph.hs @@ -44,6 +44,9 @@ simplify (Graph graph) = Graph (G.simplify graph) -- -- >>> topologicalSort ((vertex 'a' `connect` vertex 'b') <> (vertex 'a' `connect` vertex 'c')) -- "cba" +-- +-- >>> topologicalSort (Class.path "abd" <> Class.path "acd") +-- "dcba" topologicalSort :: forall v . Ord v => Graph v -> [v] topologicalSort = go . toAdjacencyMap . G.transpose . unGraph where go :: A.AdjacencyMap v -> [v] From fbc4d3f2fb7b7ef2aa52dc70eff166ba45153704 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 16:11:36 -0400 Subject: [PATCH 159/169] Test a cyclic graph. Co-Authored-By: Rick Winfrey --- src/Data/Graph.hs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Data/Graph.hs b/src/Data/Graph.hs index bfcd112c3..499ece76d 100644 --- a/src/Data/Graph.hs +++ b/src/Data/Graph.hs @@ -47,6 +47,9 @@ simplify (Graph graph) = Graph (G.simplify graph) -- -- >>> topologicalSort (Class.path "abd" <> Class.path "acd") -- "dcba" +-- +-- >>> topologicalSort (Class.path "aba") +-- "ab" topologicalSort :: forall v . Ord v => Graph v -> [v] topologicalSort = go . toAdjacencyMap . G.transpose . unGraph where go :: A.AdjacencyMap v -> [v] From dad58e7c20f38e0d4bba0457e2492869c2895fdc Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 17:28:35 -0400 Subject: [PATCH 160/169] Fix the Ruby specs. --- test/Analysis/Ruby/Spec.hs | 137 ++++++++++++++++++++++--------------- 1 file changed, 82 insertions(+), 55 deletions(-) diff --git a/test/Analysis/Ruby/Spec.hs b/test/Analysis/Ruby/Spec.hs index fb5294cc0..e935e437e 100644 --- a/test/Analysis/Ruby/Spec.hs +++ b/test/Analysis/Ruby/Spec.hs @@ -3,6 +3,7 @@ module Analysis.Ruby.Spec (spec) where import Data.Abstract.Environment as Env import Data.Abstract.Evaluatable import Data.Abstract.Value as Value +import qualified Data.Abstract.ModuleTable as ModuleTable import Data.Abstract.Number as Number import Data.AST import Control.Monad.Effect (SomeExc(..)) @@ -17,61 +18,87 @@ import SpecHelpers spec :: Spec spec = parallel $ do describe "Ruby" $ do - pure () - -- it "evaluates require_relative" $ do - -- ((res@(~(Right [(_, env)])), _), _) <- evaluate ["main.rb", "foo.rb"] - -- map fst <$> res `shouldBe` Right [Value.Integer (Number.Integer 1)] - -- Env.names env `shouldContain` ["foo"] - -- - -- it "evaluates load" $ do - -- ((res@(~(Right [(_, env)])), _), _) <- evaluate ["load.rb", "foo.rb"] - -- map fst <$> res `shouldBe` Right [Value.Integer (Number.Integer 1)] - -- Env.names env `shouldContain` ["foo"] - -- - -- it "evaluates load with wrapper" $ do - -- ((res, _), _) <- evaluate ["load-wrap.rb", "foo.rb"] - -- res `shouldBe` Left (SomeExc (inject @(EnvironmentError Precise) (FreeVariable "foo"))) - -- - -- it "evaluates subclass" $ do - -- ((res@(~(Right [(_, env)])), heap), _) <- evaluate ["subclass.rb"] - -- map fst <$> res `shouldBe` Right [String "\"\""] - -- Env.names env `shouldContain` [ "Bar", "Foo" ] - -- - -- (derefQName heap ("Bar" :| []) env >>= deNamespace) `shouldBe` Just ("Bar", ["baz", "foo", "inspect"]) - -- - -- it "evaluates modules" $ do - -- ((res@(~(Right [(_, env)])), _), _) <- evaluate ["modules.rb"] - -- map fst <$> res `shouldBe` Right [String "\"\""] - -- Env.names env `shouldContain` [ "Bar" ] - -- - -- it "handles break correctly" $ do - -- ((res, _), _) <- evaluate ["break.rb"] - -- fmap fst <$> res `shouldBe` Right [Value.Integer (Number.Integer 3)] - -- - -- it "handles break correctly" $ do - -- ((res, _), _) <- evaluate ["next.rb"] - -- fmap fst <$> res `shouldBe` Right [Value.Integer (Number.Integer 8)] - -- - -- it "calls functions with arguments" $ do - -- ((res, _), _) <- evaluate ["call.rb"] - -- fmap fst <$> res `shouldBe` Right [Value.Integer (Number.Integer 579)] - -- - -- it "evaluates early return statements" $ do - -- ((res, _), _) <- evaluate ["early-return.rb"] - -- fmap fst <$> res `shouldBe` Right [Value.Integer (Number.Integer 123)] - -- - -- it "has prelude" $ do - -- ((res, _), _) <- evaluate ["preluded.rb"] - -- fmap fst <$> res `shouldBe` Right [String "\"\""] - -- - -- it "evaluates __LINE__" $ do - -- ((res, _), _) <- evaluate ["line.rb"] - -- fmap fst <$> res `shouldBe` Right [Value.Integer (Number.Integer 4)] - -- - -- it "resolves builtins used in the prelude" $ do - -- ((res, _), traces) <- evaluate ["puts.rb"] - -- fmap fst <$> res `shouldBe` Right [Unit] - -- traces `shouldContain` [ "\"hello\"" ] + it "evaluates require_relative" $ do + ((res, heap), _) <- evaluate ["main.rb", "foo.rb"] + case ModuleTable.lookup "main.rb" <$> res of + Right (Just (Module _ (addr, env) :| [])) -> do + heapLookupAll addr heap `shouldBe` Just [Value.Integer (Number.Integer 1)] + Env.names env `shouldContain` [ "foo" ] + other -> expectationFailure (show other) + + it "evaluates load" $ do + ((res, heap), _) <- evaluate ["load.rb", "foo.rb"] + case ModuleTable.lookup "load.rb" <$> res of + Right (Just (Module _ (addr, env) :| [])) -> do + heapLookupAll addr heap `shouldBe` Just [Value.Integer (Number.Integer 1)] + Env.names env `shouldContain` [ "foo" ] + other -> expectationFailure (show other) + + it "evaluates load with wrapper" $ do + ((res, _), _) <- evaluate ["load-wrap.rb", "foo.rb"] + res `shouldBe` Left (SomeExc (inject @(EnvironmentError Precise) (FreeVariable "foo"))) + + it "evaluates subclass" $ do + ((res, heap), _) <- evaluate ["subclass.rb"] + case ModuleTable.lookup "subclass.rb" <$> res of + Right (Just (Module _ (addr, env) :| [])) -> do + heapLookupAll addr heap `shouldBe` Just [String "\"\""] + Env.names env `shouldContain` [ "Bar", "Foo" ] + + (derefQName heap ("Bar" :| []) env >>= deNamespace) `shouldBe` Just ("Bar", ["baz", "foo", "inspect"]) + other -> expectationFailure (show other) + + it "evaluates modules" $ do + ((res, heap), _) <- evaluate ["modules.rb"] + case ModuleTable.lookup "modules.rb" <$> res of + Right (Just (Module _ (addr, env) :| [])) -> do + heapLookupAll addr heap `shouldBe` Just [String "\"\""] + Env.names env `shouldContain` [ "Bar" ] + other -> expectationFailure (show other) + + it "handles break correctly" $ do + ((res, heap), _) <- evaluate ["break.rb"] + case ModuleTable.lookup "break.rb" <$> res of + Right (Just (Module _ (addr, env) :| [])) -> heapLookupAll addr heap `shouldBe` Just [Value.Integer (Number.Integer 3)] + other -> expectationFailure (show other) + + it "handles next correctly" $ do + ((res, heap), _) <- evaluate ["next.rb"] + case ModuleTable.lookup "next.rb" <$> res of + Right (Just (Module _ (addr, env) :| [])) -> heapLookupAll addr heap `shouldBe` Just [Value.Integer (Number.Integer 8)] + other -> expectationFailure (show other) + + it "calls functions with arguments" $ do + ((res, heap), _) <- evaluate ["call.rb"] + case ModuleTable.lookup "call.rb" <$> res of + Right (Just (Module _ (addr, env) :| [])) -> heapLookupAll addr heap `shouldBe` Just [Value.Integer (Number.Integer 579)] + other -> expectationFailure (show other) + + it "evaluates early return statements" $ do + ((res, heap), _) <- evaluate ["early-return.rb"] + case ModuleTable.lookup "early-return.rb" <$> res of + Right (Just (Module _ (addr, env) :| [])) -> heapLookupAll addr heap `shouldBe` Just [Value.Integer (Number.Integer 123)] + other -> expectationFailure (show other) + + it "has prelude" $ do + ((res, heap), _) <- evaluate ["preluded.rb"] + case ModuleTable.lookup "preluded.rb" <$> res of + Right (Just (Module _ (addr, env) :| [])) -> heapLookupAll addr heap `shouldBe` Just [String "\"\""] + other -> expectationFailure (show other) + + it "evaluates __LINE__" $ do + ((res, heap), _) <- evaluate ["line.rb"] + case ModuleTable.lookup "line.rb" <$> res of + Right (Just (Module _ (addr, env) :| [])) -> heapLookupAll addr heap `shouldBe` Just [Value.Integer (Number.Integer 4)] + other -> expectationFailure (show other) + + it "resolves builtins used in the prelude" $ do + ((res, heap), traces) <- evaluate ["puts.rb"] + case ModuleTable.lookup "puts.rb" <$> res of + Right (Just (Module _ (addr, env) :| [])) -> do + heapLookupAll addr heap `shouldBe` Just [Unit] + traces `shouldContain` [ "\"hello\"" ] + other -> expectationFailure (show other) where ns n = Just . Latest . Last . Just . Namespace n From 1f129a6a50f679133ecd41dbfbfc1d08230ecfab Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 17:33:38 -0400 Subject: [PATCH 161/169] Fix the Python specs. --- test/Analysis/Python/Spec.hs | 75 +++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 32 deletions(-) diff --git a/test/Analysis/Python/Spec.hs b/test/Analysis/Python/Spec.hs index 0d793590b..26773fa53 100644 --- a/test/Analysis/Python/Spec.hs +++ b/test/Analysis/Python/Spec.hs @@ -2,6 +2,7 @@ module Analysis.Python.Spec (spec) where import Data.Abstract.Environment as Env import Data.Abstract.Evaluatable (EvalError(..)) +import qualified Data.Abstract.ModuleTable as ModuleTable import Data.Abstract.Value import qualified Language.Python.Assignment as Python import qualified Data.Language as Language @@ -13,38 +14,48 @@ spec :: Spec spec = parallel $ do describe "Python" $ do pure () - -- it "imports" $ do - -- ((res@(~(Right [(_, env)])), heap), _) <- evaluate ["main.py", "a.py", "b/__init__.py", "b/c.py"] - -- fmap (() <$) res `shouldBe` Right [()] - -- Env.names env `shouldContain` [ "a", "b" ] - -- - -- (derefQName heap ("a" :| []) env >>= deNamespace) `shouldBe` Just ("a", ["foo"]) - -- (derefQName heap ("b" :| []) env >>= deNamespace) `shouldBe` Just ("b", ["c"]) - -- (derefQName heap ("b" :| ["c"]) env >>= deNamespace) `shouldBe` Just ("c", ["baz"]) - -- - -- it "imports with aliases" $ do - -- ((res@(~(Right [(_, env)])), _), _) <- evaluate ["main1.py", "a.py", "b/__init__.py", "b/c.py"] - -- fmap (() <$) res `shouldBe` Right [()] - -- Env.names env `shouldContain` [ "b", "e" ] - -- - -- it "imports using 'from' syntax" $ do - -- ((res@(~(Right [(_, env)])), _), _) <- evaluate ["main2.py", "a.py", "b/__init__.py", "b/c.py"] - -- fmap (() <$) res `shouldBe` Right [()] - -- Env.names env `shouldContain` [ "bar", "foo" ] - -- - -- it "imports with relative syntax" $ do - -- ((res@(~(Right [(_, env)])), heap), _) <- evaluate ["main3.py", "c/__init__.py", "c/utils.py"] - -- fmap (() <$) res `shouldBe` Right [()] - -- Env.names env `shouldContain` [ "utils" ] - -- (derefQName heap ("utils" :| []) env >>= deNamespace) `shouldBe` Just ("utils", ["to_s"]) - -- - -- it "subclasses" $ do - -- ((res, _), _) <- evaluate ["subclass.py"] - -- fmap fst <$> res `shouldBe` Right [String "\"bar\""] - -- - -- it "handles multiple inheritance left-to-right" $ do - -- ((res, _), _) <- evaluate ["multiple_inheritance.py"] - -- fmap fst <$> res `shouldBe` Right [String "\"foo!\""] + it "imports" $ do + ((res, heap), _) <- evaluate ["main.py", "a.py", "b/__init__.py", "b/c.py"] + case ModuleTable.lookup "main.py" <$> res of + Right (Just (Module _ (addr, env) :| [])) -> do + Env.names env `shouldContain` [ "a", "b" ] + + (derefQName heap ("a" :| []) env >>= deNamespace) `shouldBe` Just ("a", ["foo"]) + (derefQName heap ("b" :| []) env >>= deNamespace) `shouldBe` Just ("b", ["c"]) + (derefQName heap ("b" :| ["c"]) env >>= deNamespace) `shouldBe` Just ("c", ["baz"]) + other -> expectationFailure (show other) + + it "imports with aliases" $ do + ((res, _), _) <- evaluate ["main1.py", "a.py", "b/__init__.py", "b/c.py"] + case ModuleTable.lookup "main1.py" <$> res of + Right (Just (Module _ (addr, env) :| [])) -> Env.names env `shouldContain` [ "b", "e" ] + other -> expectationFailure (show other) + + it "imports using 'from' syntax" $ do + ((res, _), _) <- evaluate ["main2.py", "a.py", "b/__init__.py", "b/c.py"] + case ModuleTable.lookup "main2.py" <$> res of + Right (Just (Module _ (addr, env) :| [])) -> Env.names env `shouldContain` [ "bar", "foo" ] + other -> expectationFailure (show other) + + it "imports with relative syntax" $ do + ((res, heap), _) <- evaluate ["main3.py", "c/__init__.py", "c/utils.py"] + case ModuleTable.lookup "main3.py" <$> res of + Right (Just (Module _ (addr, env) :| [])) -> do + Env.names env `shouldContain` [ "utils" ] + (derefQName heap ("utils" :| []) env >>= deNamespace) `shouldBe` Just ("utils", ["to_s"]) + other -> expectationFailure (show other) + + it "subclasses" $ do + ((res, heap), _) <- evaluate ["subclass.py"] + case ModuleTable.lookup "subclass.py" <$> res of + Right (Just (Module _ (addr, env) :| [])) -> heapLookupAll addr heap `shouldBe` Just [String "\"bar\""] + other -> expectationFailure (show other) + + it "handles multiple inheritance left-to-right" $ do + ((res, heap), _) <- evaluate ["multiple_inheritance.py"] + case ModuleTable.lookup "multiple_inheritance.py" <$> res of + Right (Just (Module _ (addr, env) :| [])) -> heapLookupAll addr heap `shouldBe` Just [String "\"foo!\""] + other -> expectationFailure (show other) where ns n = Just . Latest . Last . Just . Namespace n From 67463461f9e2ad89e2e7e177f4f8ef72ed9f4bbe Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 17:36:32 -0400 Subject: [PATCH 162/169] Fix the PHP specs. --- test/Analysis/PHP/Spec.hs | 44 ++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/test/Analysis/PHP/Spec.hs b/test/Analysis/PHP/Spec.hs index 21b1fb6f1..6a4d20dc1 100644 --- a/test/Analysis/PHP/Spec.hs +++ b/test/Analysis/PHP/Spec.hs @@ -4,6 +4,7 @@ import Control.Abstract import Data.Abstract.Environment as Env import Data.Abstract.Evaluatable (EvalError(..)) import qualified Data.Language as Language +import qualified Data.Abstract.ModuleTable as ModuleTable import qualified Language.PHP.Assignment as PHP import SpecHelpers @@ -12,23 +13,32 @@ spec :: Spec spec = parallel $ do describe "PHP" $ do pure () - -- it "evaluates include and require" $ do - -- ((res@(~(Right [(_, env)])), _), _) <- evaluate ["main.php", "foo.php", "bar.php"] - -- map fst <$> res `shouldBe` Right [unit] - -- Env.names env `shouldBe` [ "bar", "foo" ] - -- - -- it "evaluates include_once and require_once" $ do - -- ((res@(~(Right [(_, env)])), _), _) <- evaluate ["main_once.php", "foo.php", "bar.php"] - -- map fst <$> res `shouldBe` Right [unit] - -- Env.names env `shouldBe` [ "bar", "foo" ] - -- - -- it "evaluates namespaces" $ do - -- ((Right [(_, env)], heap), _) <- evaluate ["namespaces.php"] - -- Env.names env `shouldBe` [ "Foo", "NS1" ] - -- - -- (derefQName heap ("NS1" :| []) env >>= deNamespace) `shouldBe` Just ("NS1", ["Sub1", "b", "c"]) - -- (derefQName heap ("NS1" :| ["Sub1"]) env >>= deNamespace) `shouldBe` Just ("Sub1", ["Sub2"]) - -- (derefQName heap ("NS1" :| ["Sub1", "Sub2"]) env >>= deNamespace) `shouldBe` Just ("Sub2", ["f"]) + it "evaluates include and require" $ do + ((res, heap), _) <- evaluate ["main.php", "foo.php", "bar.php"] + case ModuleTable.lookup "main.php" <$> res of + Right (Just (Module _ (addr, env) :| [])) -> do + heapLookupAll addr heap `shouldBe` Just [unit] + Env.names env `shouldBe` [ "bar", "foo" ] + other -> expectationFailure (show other) + + it "evaluates include_once and require_once" $ do + ((res, heap), _) <- evaluate ["main_once.php", "foo.php", "bar.php"] + case ModuleTable.lookup "main_once.php" <$> res of + Right (Just (Module _ (addr, env) :| [])) -> do + heapLookupAll addr heap `shouldBe` Just [unit] + Env.names env `shouldBe` [ "bar", "foo" ] + other -> expectationFailure (show other) + + it "evaluates namespaces" $ do + ((res, heap), _) <- evaluate ["namespaces.php"] + case ModuleTable.lookup "namespaces.php" <$> res of + Right (Just (Module _ (addr, env) :| [])) -> do + Env.names env `shouldBe` [ "Foo", "NS1" ] + + (derefQName heap ("NS1" :| []) env >>= deNamespace) `shouldBe` Just ("NS1", ["Sub1", "b", "c"]) + (derefQName heap ("NS1" :| ["Sub1"]) env >>= deNamespace) `shouldBe` Just ("Sub1", ["Sub2"]) + (derefQName heap ("NS1" :| ["Sub1", "Sub2"]) env >>= deNamespace) `shouldBe` Just ("Sub2", ["f"]) + other -> expectationFailure (show other) where fixtures = "test/fixtures/php/analysis/" From a0dfbb449fd6ad4a619e5d58b2ebab6d5102f77d Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 17:36:56 -0400 Subject: [PATCH 163/169] Fix some errant pure ()s. --- test/Analysis/PHP/Spec.hs | 1 - test/Analysis/Python/Spec.hs | 1 - 2 files changed, 2 deletions(-) diff --git a/test/Analysis/PHP/Spec.hs b/test/Analysis/PHP/Spec.hs index 6a4d20dc1..7da92c101 100644 --- a/test/Analysis/PHP/Spec.hs +++ b/test/Analysis/PHP/Spec.hs @@ -12,7 +12,6 @@ import SpecHelpers spec :: Spec spec = parallel $ do describe "PHP" $ do - pure () it "evaluates include and require" $ do ((res, heap), _) <- evaluate ["main.php", "foo.php", "bar.php"] case ModuleTable.lookup "main.php" <$> res of diff --git a/test/Analysis/Python/Spec.hs b/test/Analysis/Python/Spec.hs index 26773fa53..cceabf849 100644 --- a/test/Analysis/Python/Spec.hs +++ b/test/Analysis/Python/Spec.hs @@ -13,7 +13,6 @@ import SpecHelpers spec :: Spec spec = parallel $ do describe "Python" $ do - pure () it "imports" $ do ((res, heap), _) <- evaluate ["main.py", "a.py", "b/__init__.py", "b/c.py"] case ModuleTable.lookup "main.py" <$> res of From a556930e9e0207956c79aa3976a0d2b51c27afc8 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 17:38:52 -0400 Subject: [PATCH 164/169] Fix the Go specs. --- test/Analysis/Go/Spec.hs | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/test/Analysis/Go/Spec.hs b/test/Analysis/Go/Spec.hs index b755f98e5..415ac2a78 100644 --- a/test/Analysis/Go/Spec.hs +++ b/test/Analysis/Go/Spec.hs @@ -2,6 +2,7 @@ module Analysis.Go.Spec (spec) where import Data.Abstract.Environment as Env import Data.Abstract.Evaluatable (EvalError(..)) +import qualified Data.Abstract.ModuleTable as ModuleTable import qualified Data.Language as Language import qualified Language.Go.Assignment as Go import SpecHelpers @@ -10,20 +11,21 @@ import SpecHelpers spec :: Spec spec = parallel $ do describe "Go" $ do - pure () - -- it "imports and wildcard imports" $ do - -- ((res@(~(Right [(_, env)])), heap), _) <- evaluate ["main.go", "foo/foo.go", "bar/bar.go", "bar/rab.go"] - -- fmap (() <$) res `shouldBe` Right [()] - -- Env.names env `shouldBe` [ "Bar", "Rab", "foo", "main" ] - -- - -- (derefQName heap ("foo" :| []) env >>= deNamespace) `shouldBe` Just ("foo", ["New"]) - -- - -- it "imports with aliases (and side effects only)" $ do - -- ((res@(~(Right [(_, env)])), heap), _) <- evaluate ["main1.go", "foo/foo.go", "bar/bar.go", "bar/rab.go"] - -- fmap (() <$) res `shouldBe` Right [()] - -- Env.names env `shouldBe` [ "f", "main" ] - -- - -- (derefQName heap ("f" :| []) env >>= deNamespace) `shouldBe` Just ("f", ["New"]) + it "imports and wildcard imports" $ do + ((res, heap), _) <- evaluate ["main.go", "foo/foo.go", "bar/bar.go", "bar/rab.go"] + case ModuleTable.lookup "main.go" <$> res of + Right (Just (Module _ (addr, env) :| [])) -> do + Env.names env `shouldBe` [ "Bar", "Rab", "foo", "main" ] + (derefQName heap ("foo" :| []) env >>= deNamespace) `shouldBe` Just ("foo", ["New"]) + other -> expectationFailure (show other) + + it "imports with aliases (and side effects only)" $ do + ((res, heap), _) <- evaluate ["main1.go", "foo/foo.go", "bar/bar.go", "bar/rab.go"] + case ModuleTable.lookup "main1.go" <$> res of + Right (Just (Module _ (addr, env) :| [])) -> do + Env.names env `shouldBe` [ "f", "main" ] + (derefQName heap ("f" :| []) env >>= deNamespace) `shouldBe` Just ("f", ["New"]) + other -> expectationFailure (show other) where fixtures = "test/fixtures/go/analysis/" From 9526d365d68d6ba19b8f4c35a0dcaf73d1d4f01e Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 17:40:09 -0400 Subject: [PATCH 165/169] Placate hlint. --- src/Control/Abstract/Modules.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Control/Abstract/Modules.hs b/src/Control/Abstract/Modules.hs index eda51bb7c..e60094c65 100644 --- a/src/Control/Abstract/Modules.hs +++ b/src/Control/Abstract/Modules.hs @@ -71,7 +71,7 @@ runModules :: ( Member (State (ModuleTable (NonEmpty (Module (address, Environme runModules paths = interpret $ \case Load name -> fmap (runMerging . foldMap1 (Merging . moduleBody)) . ModuleTable.lookup name <$> askModuleTable >>= maybeM (moduleNotFound name) Lookup path -> fmap (runMerging . foldMap1 (Merging . moduleBody)) . ModuleTable.lookup path <$> askModuleTable - Resolve names -> pure (find (flip Set.member paths) names) + Resolve names -> pure (find (`Set.member` paths) names) List dir -> pure (filter ((dir ==) . takeDirectory) (toList paths)) askModuleTable :: Member (State (ModuleTable (NonEmpty (Module (address, Environment address))))) effects => Evaluator address value effects (ModuleTable (NonEmpty (Module (address, Environment address)))) From 6a466c62e6d1b5a9693daf3df35de2f243428e73 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 17:50:01 -0400 Subject: [PATCH 166/169] Note a FIXME. --- src/Data/Abstract/Evaluatable.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 1fbf5875c..85fe80e84 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -101,6 +101,7 @@ evaluate lang analyzeModule analyzeTerm modules = do foldr (run preludeEnv) get modules where run preludeEnv m rest = do evaluated <- evalModule preludeEnv m + -- FIXME: this should be some sort of Monoidal insert à la the Heap to accommodate multiple Go files being part of the same module. modify' (ModuleTable.insert (modulePath (moduleInfo evaluated)) (evaluated :| [])) rest From fcb7ae815eb2f30710d9ebe14f36419d984eab2b Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 17:53:11 -0400 Subject: [PATCH 167/169] Inline evalModule into run. --- src/Data/Abstract/Evaluatable.hs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 85fe80e84..a1d836995 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -100,17 +100,14 @@ evaluate lang analyzeModule analyzeTerm modules = do box unit foldr (run preludeEnv) get modules where run preludeEnv m rest = do - evaluated <- evalModule preludeEnv m + evaluated <- coerce + (runInModule preludeEnv (moduleInfo m)) + (analyzeModule (subtermRef . moduleBody) + (evalTerm <$> m)) -- FIXME: this should be some sort of Monoidal insert à la the Heap to accommodate multiple Go files being part of the same module. - modify' (ModuleTable.insert (modulePath (moduleInfo evaluated)) (evaluated :| [])) + modify' (ModuleTable.insert (modulePath (moduleInfo m)) ((evaluated <$ m) :| [])) rest - evalModule preludeEnv m - = fmap (<$ m) - . coerce (runInModule preludeEnv (moduleInfo m)) - . analyzeModule (subtermRef . moduleBody) - $ evalTerm <$> m - evalTerm term = Subterm term (foldSubterms (analyzeTerm (TermEvaluator . eval . fmap (second runTermEvaluator))) term >>= TermEvaluator . address) runInModule preludeEnv info From fa68f6b8f337ef91a845f33472e8476060357ac9 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Mon, 25 Jun 2018 18:01:03 -0400 Subject: [PATCH 168/169] :fire: keys. --- src/Data/Map/Monoidal.hs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Data/Map/Monoidal.hs b/src/Data/Map/Monoidal.hs index 0c1a64d65..34192cb2b 100644 --- a/src/Data/Map/Monoidal.hs +++ b/src/Data/Map/Monoidal.hs @@ -8,7 +8,6 @@ module Data.Map.Monoidal , insert , filterWithKey , pairs -, keys , module Reducer ) where @@ -42,9 +41,6 @@ filterWithKey f = Map . Map.filterWithKey f . unMap pairs :: Map key value -> [(key, value)] pairs = Map.toList . unMap -keys :: Map key value -> [key] -keys = Map.keys . unMap - instance (Ord key, Semigroup value) => Semigroup (Map key value) where Map a <> Map b = Map (Map.unionWith (<>) a b) From 7842eef72a131632d432c347aeea7cbc3fe1aa1c Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Tue, 26 Jun 2018 12:22:40 -0400 Subject: [PATCH 169/169] Just say id. --- src/Semantic/Graph.hs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index 6887979ed..28686e14f 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -121,8 +121,7 @@ runImportGraph lang (package :: Package term) -- Optimization for the common (when debugging) case of one-and-only-one module. | [m :| []] <- toList (packageModules package) = vertex m <$ trace ("single module, skipping import graph computation for " <> modulePath (moduleInfo m)) | otherwise = - let analyzeTerm = id - analyzeModule = graphingModuleInfo + let analyzeModule = graphingModuleInfo extractGraph (((_, graph), _), _) = do info <- graph maybe lowerBound (foldMap vertex) (ModuleTable.lookup (modulePath info) (packageModules package)) @@ -145,7 +144,7 @@ runImportGraph lang (package :: Package term) . runTermEvaluator @_ @_ @(Value (Hole Precise) (ImportGraphEff term (Hole Precise))) . runReader (packageInfo package) . runReader lowerBound - in extractGraph <$> analyze runImportGraphAnalysis (evaluate @_ @_ @_ @_ @term lang analyzeModule analyzeTerm (ModuleTable.toPairs (packageModules package) >>= toList . snd)) + in extractGraph <$> analyze runImportGraphAnalysis (evaluate @_ @_ @_ @_ @term lang analyzeModule id (ModuleTable.toPairs (packageModules package) >>= toList . snd)) newtype ImportGraphEff term address a = ImportGraphEff { runImportGraphEff :: Eff '[ LoopControl address