diff --git a/src/Control/Abstract/Modules.hs b/src/Control/Abstract/Modules.hs index c5f69d81f..a1f00316f 100644 --- a/src/Control/Abstract/Modules.hs +++ b/src/Control/Abstract/Modules.hs @@ -30,8 +30,9 @@ import qualified Data.Set as Set import Data.Span import Prologue import System.FilePath.Posix (takeDirectory) +import Data.Abstract.ScopeGraph -type ModuleResult address = (Bindings address, address) +type ModuleResult address = (ScopeGraph address, (Bindings address, address)) -- | 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 (ModuleResult address)) @@ -94,7 +95,7 @@ askModuleTable = ask newtype Merging address = Merging { runMerging :: ModuleResult address } instance Semigroup (Merging address) where - Merging (binds1, _) <> Merging (binds2, addr) = Merging (binds1 <> binds2, addr) + Merging (_, (binds1, _)) <> Merging (graph2, (binds2, addr)) = Merging (graph2, (binds1 <> binds2, addr)) -- | 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. diff --git a/src/Control/Abstract/ScopeGraph.hs b/src/Control/Abstract/ScopeGraph.hs index b0e33430a..a86595266 100644 --- a/src/Control/Abstract/ScopeGraph.hs +++ b/src/Control/Abstract/ScopeGraph.hs @@ -2,6 +2,7 @@ module Control.Abstract.ScopeGraph (runScopeEnv, ScopeEnv) where import Control.Abstract.Evaluator +import Control.Abstract.Heap import Data.Abstract.Name import Data.Span import Data.Abstract.ScopeGraph as ScopeGraph @@ -20,29 +21,31 @@ instance Effect (ScopeEnv address) where handleState c dist (Request (Reference ref decl) k) = Request (Reference ref decl) (dist . (<$ c) . k) handleState c dist (Request (Create edges) k) = Request (Create edges) (dist . (<$ c) . k) -runScopeEnv :: (Ord scope, Effects effects, Member Fresh effects) - => scope - -> Evaluator address value (ScopeEnv scope ': effects) a - -> Evaluator address value effects (ScopeGraph scope, a) -runScopeEnv scope = runState (ScopeGraph.emptyGraph scope) . reinterpret handleScopeEnv +runScopeEnv :: (Ord address, Effects effects, Member Fresh effects, Member (Allocator address) effects) + => Evaluator address value (ScopeEnv address ': effects) a + -> Evaluator address value effects (ScopeGraph address, a) +runScopeEnv evaluator = do + name <- gensym + address <- alloc name + runState (ScopeGraph.emptyGraph address) (reinterpret handleScopeEnv evaluator) -handleScopeEnv :: forall scope address value effects a. (Ord scope, Member Fresh effects) - => ScopeEnv scope (Eff (ScopeEnv scope ': effects)) a - -> Evaluator address value (State (ScopeGraph scope) ': effects) a +handleScopeEnv :: forall address value effects a. (Ord address, Member Fresh effects) + => ScopeEnv address (Eff (ScopeEnv address ': effects)) a + -> Evaluator address value (State (ScopeGraph address) ': effects) a handleScopeEnv = \case Lookup ref -> do - graph <- get @(ScopeGraph scope) + graph <- get @(ScopeGraph address) pure (ScopeGraph.scopeOfRef ref graph) Declare decl ddata -> do graph <- get - put @(ScopeGraph scope) (ScopeGraph.declare decl ddata graph) + put @(ScopeGraph address) (ScopeGraph.declare decl ddata graph) pure () Reference ref decl -> do graph <- get - put @(ScopeGraph scope) (ScopeGraph.reference ref decl graph) + put @(ScopeGraph address) (ScopeGraph.reference ref decl graph) pure () Create edges -> do - graph <- get @(ScopeGraph scope) + graph <- get @(ScopeGraph address) scope <- gensym put (ScopeGraph.create scope edges graph) pure () diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 88d842edf..e96c25ad7 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -28,6 +28,7 @@ import Control.Abstract.Evaluator as X hiding (LoopControl(..), Return(..), catc import Control.Abstract.Heap as X hiding (runAddressError, runAddressErrorWith) import Control.Abstract.Modules as X (Modules, ModuleResult, ResolutionError(..), load, lookupModule, listModulesInDir, require, resolve, throwResolutionError) import Control.Abstract.Value as X hiding (Boolean(..), Function(..)) +import Control.Abstract.ScopeGraph import Data.Abstract.Declarations as X import Data.Abstract.Environment as X import Data.Abstract.BaseError as X @@ -53,6 +54,7 @@ class (Show1 constr, Foldable constr) => Evaluatable constr where , Member (Allocator address) effects , Member (Boolean value) effects , Member (Deref value) effects + , Member (ScopeEnv address) effects , Member (Env address) effects , Member (Exc (LoopControl address)) effects , Member (Exc (Return address)) effects @@ -82,6 +84,7 @@ type ModuleEffects address value rest = Exc (LoopControl address) ': Exc (Return address) ': Env address + ': ScopeEnv address ': Deref value ': Allocator address ': Reader ModuleInfo @@ -124,7 +127,7 @@ evaluate :: ( AbstractValue address value valueEffects -> [Module term] -> TermEvaluator term address value effects (ModuleTable (NonEmpty (Module (ModuleResult address)))) evaluate lang analyzeModule analyzeTerm runAllocDeref runValue modules = do - (preludeBinds, _) <- TermEvaluator . runInModule lowerBound moduleInfoFromCallStack . runValue $ do + (scopeGraph, (preludeBinds, _)) <- TermEvaluator . runInModule lowerBound moduleInfoFromCallStack . runValue $ do definePrelude lang box unit foldr (run preludeBinds) ask modules @@ -143,6 +146,7 @@ evaluate lang analyzeModule analyzeTerm runAllocDeref runValue modules = do runInModule preludeBinds info = runReader info . runAllocDeref + . runScopeEnv . runEnv (EvalContext Nothing (X.push (newEnv preludeBinds))) . runReturn . runLoopControl diff --git a/src/Language/Go/Syntax.hs b/src/Language/Go/Syntax.hs index 5baf87579..d8adfe144 100644 --- a/src/Language/Go/Syntax.hs +++ b/src/Language/Go/Syntax.hs @@ -69,7 +69,7 @@ instance Evaluatable Import where paths <- resolveGoImport importPath for_ paths $ \path -> do traceResolve (unPath importPath) path - importedEnv <- fst <$> require path + importedEnv <- fst . snd <$> require path bindAll importedEnv rvalBox unit @@ -91,7 +91,7 @@ instance Evaluatable QualifiedImport where void . letrec' alias $ \addr -> do makeNamespace alias addr Nothing . for_ paths $ \p -> do traceResolve (unPath importPath) p - importedEnv <- fst <$> require p + importedEnv <- fst . snd <$> require p bindAll importedEnv rvalBox unit diff --git a/src/Language/PHP/Syntax.hs b/src/Language/PHP/Syntax.hs index 9cf201ef7..72d44f122 100644 --- a/src/Language/PHP/Syntax.hs +++ b/src/Language/PHP/Syntax.hs @@ -70,7 +70,7 @@ include pathTerm f = do name <- subtermValue pathTerm >>= asString path <- resolvePHPName name traceResolve name path - (importedEnv, v) <- f path + (_, (importedEnv, v)) <- f path bindAll importedEnv pure (Rval v) diff --git a/src/Language/Python/Syntax.hs b/src/Language/Python/Syntax.hs index 575531f27..4e4d668b8 100644 --- a/src/Language/Python/Syntax.hs +++ b/src/Language/Python/Syntax.hs @@ -145,7 +145,7 @@ instance Evaluatable Import where -- Last module path is the one we want to import let path = NonEmpty.last modulePaths - importedBinds <- fst <$> require path + importedBinds <- fst . snd <$> require path bindAll (select importedBinds) rvalBox unit where @@ -165,7 +165,7 @@ evalQualifiedImport :: ( AbstractValue address value effects ) => Name -> ModulePath -> Evaluator address value effects value evalQualifiedImport name path = letrec' name $ \addr -> do - unit <$ makeNamespace name addr Nothing (bindAll . fst =<< require path) + unit <$ makeNamespace name addr Nothing (bindAll . fst . snd =<< require path) newtype QualifiedImport a = QualifiedImport { qualifiedImportFrom :: NonEmpty FilePath } deriving (Declarations1, Diffable, Eq, Foldable, FreeVariables1, Functor, Generic1, Hashable1, Named1, Ord, Show, ToJSONFields1, Traversable) @@ -218,7 +218,7 @@ instance Evaluatable QualifiedAliasedImport where alias <- maybeM (throwEvalError NoNameError) (declaredName (subterm aliasTerm)) rvalBox =<< letrec' alias (\addr -> do let path = NonEmpty.last modulePaths - unit <$ makeNamespace alias addr Nothing (void (bindAll . fst =<< require path))) + unit <$ makeNamespace alias addr Nothing (void (bindAll . fst . snd =<< require path))) -- | Ellipsis (used in splice expressions and alternatively can be used as a fill in expression, like `undefined` in Haskell) data Ellipsis a = Ellipsis diff --git a/src/Language/Ruby/Syntax.hs b/src/Language/Ruby/Syntax.hs index 6a7a9a840..209efa628 100644 --- a/src/Language/Ruby/Syntax.hs +++ b/src/Language/Ruby/Syntax.hs @@ -98,8 +98,8 @@ doRequire :: ( Member (Boolean value) effects doRequire path = do result <- lookupModule path case result of - Nothing -> (,) . fst <$> load path <*> boolean True - Just (env, _) -> (env,) <$> boolean False + Nothing -> (,) . fst . snd <$> load path <*> boolean True + Just (_, (env, _)) -> (env,) <$> boolean False data Load a = Load { loadPath :: a, loadWrap :: Maybe a } @@ -132,7 +132,7 @@ doLoad :: ( Member (Boolean value) effects doLoad path shouldWrap = do path' <- resolveRubyPath path traceResolve path path' - importedEnv <- fst <$> load path' + importedEnv <- fst . snd <$> load path' unless shouldWrap $ bindAll importedEnv 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/Resolution.hs b/src/Language/TypeScript/Resolution.hs index 1d44d6c84..543b350e2 100644 --- a/src/Language/TypeScript/Resolution.hs +++ b/src/Language/TypeScript/Resolution.hs @@ -175,4 +175,4 @@ evalRequire :: ( AbstractValue address value effects -> Name -> Evaluator address value effects value evalRequire modulePath alias = letrec' alias $ \addr -> - unit <$ makeNamespace alias addr Nothing (bindAll . fst =<< require modulePath) + unit <$ makeNamespace alias addr Nothing (bindAll . fst . snd =<< require modulePath) diff --git a/src/Language/TypeScript/Syntax/TypeScript.hs b/src/Language/TypeScript/Syntax/TypeScript.hs index 18383dc59..92c6c14f2 100644 --- a/src/Language/TypeScript/Syntax/TypeScript.hs +++ b/src/Language/TypeScript/Syntax/TypeScript.hs @@ -25,7 +25,7 @@ instance Show1 Import where liftShowsPrec = genericLiftShowsPrec instance Evaluatable Import where eval (Import symbols importPath) = do modulePath <- resolveWithNodejsStrategy importPath typescriptExtensions - importedBinds <- fst <$> require modulePath + importedBinds <- fst . snd <$> require modulePath bindAll (renamed importedBinds) rvalBox unit where @@ -92,7 +92,7 @@ instance Show1 QualifiedExportFrom where liftShowsPrec = genericLiftShowsPrec instance Evaluatable QualifiedExportFrom where eval (QualifiedExportFrom importPath exportSymbols) = do modulePath <- resolveWithNodejsStrategy importPath typescriptExtensions - importedBinds <- fst <$> require modulePath + importedBinds <- fst . snd <$> require modulePath -- Look up addresses in importedEnv and insert the aliases with addresses into the exports. for_ exportSymbols $ \Alias{..} -> do let address = Env.lookup aliasValue importedBinds diff --git a/src/Semantic/Graph.hs b/src/Semantic/Graph.hs index f4b588054..a1d91afee 100644 --- a/src/Semantic/Graph.hs +++ b/src/Semantic/Graph.hs @@ -347,7 +347,7 @@ resumingLoadError :: ( Applicative (m address value effects) => m address value (Resumable (BaseError (LoadError address)) ': effects) a -> m address value effects a resumingLoadError = runLoadErrorWith (\ baseError -> traceError "LoadError" baseError *> case baseErrorException baseError of - ModuleNotFoundError _ -> pure (lowerBound, hole)) + ModuleNotFoundError _ -> pure (undefined, (lowerBound, hole))) resumingEvalError :: ( Applicative (m effects) , Effectful m