1
1
mirror of https://github.com/github/semantic.git synced 2024-12-01 09:15:01 +03:00

Merge remote-tracking branch 'origin/master' into enhanced-json-output

This commit is contained in:
Timothy Clem 2018-05-30 07:50:29 -07:00
commit 51394186f9
30 changed files with 137 additions and 163 deletions

View File

@ -60,7 +60,7 @@ cachingTerms :: ( Cacheable term location (Cell location) value
, Corecursive term , Corecursive term
, Member NonDet effects , Member NonDet effects
, Member (Reader (Cache term location (Cell location) value)) effects , Member (Reader (Cache term location (Cell location) value)) effects
, Member (Reader (Live location value)) effects , Member (Reader (Live location)) effects
, Member (State (Cache term location (Cell location) value)) effects , Member (State (Cache term location (Cell location) value)) effects
, Member (State (Environment location)) effects , Member (State (Environment location)) effects
, Member (State (Heap location (Cell location) value)) effects , Member (State (Heap location (Cell location) value)) effects
@ -83,7 +83,7 @@ convergingModules :: ( AbstractValue location value effects
, Member NonDet effects , Member NonDet effects
, Member (Reader (Cache term location (Cell location) value)) effects , Member (Reader (Cache term location (Cell location) value)) effects
, Member (Reader (Environment location)) effects , Member (Reader (Environment location)) effects
, Member (Reader (Live location value)) effects , Member (Reader (Live location)) effects
, Member (Resumable (EnvironmentError location)) effects , Member (Resumable (EnvironmentError location)) effects
, Member (State (Cache term location (Cell location) value)) effects , Member (State (Cache term location (Cell location) value)) effects
, Member (State (Environment location)) effects , Member (State (Environment location)) effects

View File

@ -12,7 +12,7 @@ import Prologue
-- | An analysis performing GC after every instruction. -- | An analysis performing GC after every instruction.
collectingTerms :: ( Foldable (Cell location) collectingTerms :: ( Foldable (Cell location)
, Member (Reader (Live location value)) effects , Member (Reader (Live location)) effects
, Member (State (Heap location (Cell location) value)) effects , Member (State (Heap location (Cell location) value)) effects
, Ord location , Ord location
, ValueRoots location value , ValueRoots location value
@ -29,7 +29,7 @@ gc :: ( Ord location
, Foldable (Cell location) , Foldable (Cell location)
, ValueRoots location value , ValueRoots location value
) )
=> Live location value -- ^ The set of addresses to consider rooted. => Live location -- ^ The set of addresses to consider rooted.
-> Heap location (Cell location) value -- ^ A heap to collect unreachable addresses within. -> Heap location (Cell location) value -- ^ A heap to collect unreachable addresses within.
-> Heap location (Cell location) value -- ^ A garbage-collected heap. -> Heap location (Cell location) value -- ^ A garbage-collected heap.
gc roots heap = heapRestrict heap (reachable roots heap) gc roots heap = heapRestrict heap (reachable roots heap)
@ -39,9 +39,9 @@ reachable :: ( Ord location
, Foldable (Cell location) , Foldable (Cell location)
, ValueRoots location value , ValueRoots location value
) )
=> Live location value -- ^ The set of root addresses. => Live location -- ^ The set of root addresses.
-> Heap location (Cell location) value -- ^ The heap to trace addresses through. -> Heap location (Cell location) value -- ^ The heap to trace addresses through.
-> Live location value -- ^ The set of addresses reachable from the root set. -> Live location -- ^ The set of addresses reachable from the root set.
reachable roots heap = go mempty roots reachable roots heap = go mempty roots
where go seen set = case liveSplit set of where go seen set = case liveSplit set of
Nothing -> seen Nothing -> seen
@ -50,5 +50,5 @@ reachable roots heap = go mempty roots
_ -> seen) _ -> seen)
providingLiveSet :: Effectful (m location value) => m location value (Reader (Live location value) ': effects) a -> m location value effects a providingLiveSet :: Effectful (m location value) => m location value (Reader (Live location) ': effects) a -> m location value effects a
providingLiveSet = runReader lowerBound providingLiveSet = runReader lowerBound

View File

@ -128,7 +128,7 @@ variableDefinition :: ( Member (Reader (Environment (Hole (Located location))))
=> Name => Name
-> TermEvaluator term (Hole (Located location)) value effects () -> TermEvaluator term (Hole (Located location)) value effects ()
variableDefinition name = do variableDefinition name = do
graph <- maybe lowerBound (maybe lowerBound (vertex . moduleVertex . locationModule) . toMaybe . unAddress) <$> TermEvaluator (lookupEnv name) graph <- maybe lowerBound (maybe lowerBound (vertex . moduleVertex . locationModule) . toMaybe) <$> TermEvaluator (lookupEnv name)
appendGraph (vertex (Variable (unName name)) `connect` graph) appendGraph (vertex (Variable (unName name)) `connect` graph)
appendGraph :: (Effectful m, Member (State (Graph Vertex)) effects) => Graph Vertex -> m effects () appendGraph :: (Effectful m, Member (State (Graph Vertex)) effects) => Graph Vertex -> m effects ()

View File

@ -13,7 +13,7 @@ import Prologue
-- --
-- Instantiating @trace@ to @[]@ yields a linear trace analysis, while @Set@ yields a reachable state analysis. -- Instantiating @trace@ to @[]@ yields a linear trace analysis, while @Set@ yields a reachable state analysis.
tracingTerms :: ( Corecursive term tracingTerms :: ( Corecursive term
, Member (Reader (Live location value)) effects , Member (Reader (Live location)) effects
, Member (State (Environment location)) effects , Member (State (Environment location)) effects
, Member (State (Heap location (Cell location) value)) effects , Member (State (Heap location (Cell location) value)) effects
, Member (Writer (trace (Configuration term location (Cell location) value))) effects , Member (Writer (trace (Configuration term location (Cell location) value))) effects

View File

@ -10,23 +10,23 @@ import Data.Abstract.Address
import Data.Abstract.Name import Data.Abstract.Name
import Prologue import Prologue
-- | Defines allocation and dereferencing of 'Address'es in a 'Heap'. -- | Defines allocation and dereferencing of addresses.
class (Ord location, Show location) => Addressable location effects where class (Ord location, Show location) => Addressable location effects where
-- | The type into which stored values will be written for a given location type. -- | The type into which stored values will be written for a given location type.
type family Cell location :: * -> * type family Cell location :: * -> *
allocCell :: Name -> Evaluator location value effects location allocCell :: Name -> Evaluator location value effects location
derefCell :: Address location value -> Cell location value -> Evaluator location value effects (Maybe value) derefCell :: location -> Cell location value -> Evaluator location value effects (Maybe value)
-- | 'Precise' locations are always allocated a fresh 'Address', and dereference to the 'Latest' value written. -- | 'Precise' locations are always allocated a fresh address, and dereference to the 'Latest' value written.
instance Member Fresh effects => Addressable Precise effects where instance Member Fresh effects => Addressable Precise effects where
type Cell Precise = Latest type Cell Precise = Latest
allocCell _ = Precise <$> fresh allocCell _ = Precise <$> fresh
derefCell _ = pure . getLast . unLatest derefCell _ = pure . getLast . unLatest
-- | 'Monovariant' locations allocate one 'Address' per unique variable name, and dereference once per stored value, nondeterministically. -- | 'Monovariant' locations allocate one address per unique variable name, and dereference once per stored value, nondeterministically.
instance Member NonDet effects => Addressable Monovariant effects where instance Member NonDet effects => Addressable Monovariant effects where
type Cell Monovariant = All type Cell Monovariant = All
@ -38,14 +38,14 @@ instance (Addressable location effects, Member (Reader ModuleInfo) effects, Memb
type Cell (Located location) = Cell location type Cell (Located location) = Cell location
allocCell name = relocate (Located <$> allocCell name <*> currentPackage <*> currentModule) allocCell name = relocate (Located <$> allocCell name <*> currentPackage <*> currentModule)
derefCell (Address (Located loc _ _)) = relocate . derefCell (Address loc) derefCell (Located loc _ _) = relocate . derefCell loc
instance Addressable location effects => Addressable (Hole location) effects where instance Addressable location effects => Addressable (Hole location) effects where
type Cell (Hole location) = Cell location type Cell (Hole location) = Cell location
allocCell name = relocate (Total <$> allocCell name) allocCell name = relocate (Total <$> allocCell name)
derefCell (Address (Total loc)) = relocate . derefCell (Address loc) derefCell (Total loc) = relocate . derefCell loc
derefCell (Address Partial) = const (pure Nothing) derefCell Partial = const (pure Nothing)
relocate :: Evaluator location1 value effects a -> Evaluator location2 value effects a relocate :: Evaluator location1 value effects a -> Evaluator location2 value effects a
relocate = raiseEff . lowerEff relocate = raiseEff . lowerEff

View File

@ -12,5 +12,5 @@ import Control.Abstract.TermEvaluator
import Data.Abstract.Configuration import Data.Abstract.Configuration
-- | Get the current 'Configuration' with a passed-in term. -- | Get the current 'Configuration' with a passed-in term.
getConfiguration :: (Member (Reader (Live location value)) effects, Member (State (Environment location)) effects, Member (State (Heap location (Cell location) value)) effects) => term -> TermEvaluator term location value effects (Configuration term location (Cell location) value) getConfiguration :: (Member (Reader (Live location)) effects, Member (State (Environment location)) effects, Member (State (Heap location (Cell location) value)) effects) => term -> TermEvaluator term location value effects (Configuration term location (Cell location) value)
getConfiguration term = Configuration term <$> TermEvaluator askRoots <*> TermEvaluator getEnv <*> TermEvaluator getHeap getConfiguration term = Configuration term <$> TermEvaluator askRoots <*> TermEvaluator getEnv <*> TermEvaluator getHeap

View File

@ -3,14 +3,12 @@ module Control.Abstract.Environment
( Environment ( Environment
, getEnv , getEnv
, putEnv , putEnv
, modifyEnv
, withEnv , withEnv
, defaultEnvironment
, withDefaultEnvironment , withDefaultEnvironment
, fullEnvironment
, localEnv
, localize
, lookupEnv , lookupEnv
, bind
, bindAll
, locally
, EnvironmentError(..) , EnvironmentError(..)
, freeVariableError , freeVariableError
, runEnvironmentError , runEnvironmentError
@ -18,7 +16,6 @@ module Control.Abstract.Environment
) where ) where
import Control.Abstract.Evaluator import Control.Abstract.Evaluator
import Data.Abstract.Address
import Data.Abstract.Environment as Env import Data.Abstract.Environment as Env
import Data.Abstract.Name import Data.Abstract.Name
import Prologue import Prologue
@ -49,26 +46,25 @@ defaultEnvironment = ask
withDefaultEnvironment :: Member (Reader (Environment location)) effects => Environment location -> Evaluator location value effects a -> Evaluator location value effects a withDefaultEnvironment :: Member (Reader (Environment location)) effects => Environment location -> Evaluator location value effects a -> Evaluator location value effects a
withDefaultEnvironment e = local (const e) withDefaultEnvironment e = local (const e)
-- | Obtain an environment that is the composition of the current and default environments.
-- Useful for debugging.
fullEnvironment :: (Member (Reader (Environment location)) effects, Member (State (Environment location)) effects) => Evaluator location value effects (Environment location)
fullEnvironment = mergeEnvs <$> getEnv <*> defaultEnvironment
-- | Run an action with a locally-modified environment.
localEnv :: Member (State (Environment location)) effects => (Environment location -> Environment location) -> Evaluator location value effects a -> Evaluator location value effects a
localEnv f a = do
modifyEnv (f . Env.push)
result <- a
result <$ modifyEnv Env.pop
-- | Run a computation in a new local environment.
localize :: Member (State (Environment location)) effects => Evaluator location value effects a -> Evaluator location value effects a
localize = localEnv id
-- | Look a 'Name' up in the current environment, trying the default environment if no value is found. -- | Look a 'Name' up in the current environment, trying the default environment if no value is found.
lookupEnv :: (Member (Reader (Environment location)) effects, Member (State (Environment location)) effects) => Name -> Evaluator location value effects (Maybe (Address location value)) lookupEnv :: (Member (Reader (Environment location)) effects, Member (State (Environment location)) effects) => Name -> Evaluator location value effects (Maybe location)
lookupEnv name = (<|>) <$> (Env.lookup name <$> getEnv) <*> (Env.lookup name <$> defaultEnvironment) lookupEnv name = (<|>) <$> (Env.lookup name <$> getEnv) <*> (Env.lookup name <$> defaultEnvironment)
-- | Bind a 'Name' to an 'Address' in the current scope.
bind :: Member (State (Environment location)) effects => Name -> location -> Evaluator location value effects ()
bind name = modifyEnv . Env.insert name
-- | Bind all of the names from an 'Environment' in the current scope.
bindAll :: Member (State (Environment location)) effects => Environment location -> Evaluator location value effects ()
bindAll = foldr ((>>) . uncurry bind) (pure ()) . pairs
-- | Run an action in a new local environment.
locally :: Member (State (Environment location)) effects => Evaluator location value effects a -> Evaluator location value effects a
locally a = do
modifyEnv Env.push
a' <- a
a' <$ modifyEnv Env.pop
-- | Errors involving the environment. -- | Errors involving the environment.
data EnvironmentError location return where data EnvironmentError location return where

View File

@ -8,7 +8,6 @@ module Control.Abstract.Exports
) where ) where
import Control.Abstract.Evaluator import Control.Abstract.Evaluator
import Data.Abstract.Address
import Data.Abstract.Exports import Data.Abstract.Exports
import Data.Abstract.Name import Data.Abstract.Name
@ -25,7 +24,7 @@ modifyExports :: Member (State (Exports location)) effects => (Exports location
modifyExports = modify' modifyExports = modify'
-- | Add an export to the global export state. -- | Add an export to the global export state.
addExport :: Member (State (Exports location)) effects => Name -> Name -> Maybe (Address location value) -> Evaluator location value effects () addExport :: Member (State (Exports location)) effects => Name -> Name -> Maybe location -> Evaluator location value effects ()
addExport name alias = modifyExports . insert name alias addExport name alias = modifyExports . insert name alias
-- | Sets the global export state for the lifetime of the given action. -- | Sets the global export state for the lifetime of the given action.

View File

@ -1,4 +1,4 @@
{-# LANGUAGE GADTs, RankNTypes, TypeFamilies, TypeOperators, UndecidableInstances #-} {-# LANGUAGE GADTs, RankNTypes, ScopedTypeVariables, TypeFamilies, TypeOperators, UndecidableInstances #-}
module Control.Abstract.Heap module Control.Abstract.Heap
( Heap ( Heap
, getHeap , getHeap
@ -23,8 +23,6 @@ import Control.Abstract.Addressable
import Control.Abstract.Environment import Control.Abstract.Environment
import Control.Abstract.Evaluator import Control.Abstract.Evaluator
import Control.Monad.Effect.Internal import Control.Monad.Effect.Internal
import Data.Abstract.Address
import Data.Abstract.Environment
import Data.Abstract.Heap import Data.Abstract.Heap
import Data.Abstract.Name import Data.Abstract.Name
import Data.Semigroup.Reducer import Data.Semigroup.Reducer
@ -43,20 +41,20 @@ modifyHeap :: Member (State (Heap location (Cell location) value)) effects => (H
modifyHeap = modify' modifyHeap = modify'
alloc :: Member (Allocator location value) effects => Name -> Evaluator location value effects (Address location value) alloc :: forall location value effects . Member (Allocator location value) effects => Name -> Evaluator location value effects location
alloc = send . Alloc alloc = send . Alloc @location @value
-- | Dereference the given 'Address'in the heap, or fail if the address is uninitialized. -- | Dereference the given address in the heap, or fail if the address is uninitialized.
deref :: Member (Allocator location value) effects => Address location value -> Evaluator location value effects value deref :: Member (Allocator location value) effects => location -> Evaluator location value effects value
deref = send . Deref deref = send . Deref
-- | Write a value to the given 'Address' in the 'Store'. -- | Write a value to the given address in the 'Store'.
assign :: ( Member (State (Heap location (Cell location) value)) effects assign :: ( Member (State (Heap location (Cell location) value)) effects
, Ord location , Ord location
, Reducer value (Cell location value) , Reducer value (Cell location value)
) )
=> Address location value => location
-> value -> value
-> Evaluator location value effects () -> Evaluator location value effects ()
assign address = modifyHeap . heapInsert address assign address = modifyHeap . heapInsert address
@ -68,7 +66,7 @@ lookupOrAlloc :: ( Member (Allocator location value) effects
, Member (State (Environment location)) effects , Member (State (Environment location)) effects
) )
=> Name => Name
-> Evaluator location value effects (Address location value) -> Evaluator location value effects location
lookupOrAlloc name = lookupEnv name >>= maybe (alloc name) pure lookupOrAlloc name = lookupEnv name >>= maybe (alloc name) pure
@ -81,10 +79,10 @@ letrec :: ( Member (Allocator location value) effects
) )
=> Name => Name
-> Evaluator location value effects value -> Evaluator location value effects value
-> Evaluator location value effects (value, Address location value) -> Evaluator location value effects (value, location)
letrec name body = do letrec name body = do
addr <- lookupOrAlloc name addr <- lookupOrAlloc name
v <- localEnv (insert name addr) body v <- locally (bind name addr *> body)
assign addr v assign addr v
pure (v, addr) pure (v, addr)
@ -94,12 +92,12 @@ letrec' :: ( Member (Allocator location value) effects
, Member (State (Environment location)) effects , Member (State (Environment location)) effects
) )
=> Name => Name
-> (Address location value -> Evaluator location value effects value) -> (location -> Evaluator location value effects value)
-> Evaluator location value effects value -> Evaluator location value effects value
letrec' name body = do letrec' name body = do
addr <- lookupOrAlloc name addr <- lookupOrAlloc name
v <- localEnv id (body addr) v <- locally (body addr)
v <$ modifyEnv (insert name addr) v <$ bind name addr
-- | Look up and dereference the given 'Name', throwing an exception for free variables. -- | Look up and dereference the given 'Name', throwing an exception for free variables.
@ -110,24 +108,24 @@ variable :: ( Member (Allocator location value) effects
) )
=> Name => Name
-> Evaluator location value effects value -> Evaluator location value effects value
variable name = lookupEnv name >>= maybeM (Address <$> freeVariableError name) >>= deref variable name = lookupEnv name >>= maybeM (freeVariableError name) >>= deref
-- Effects -- Effects
data Allocator location value return where data Allocator location value return where
Alloc :: Name -> Allocator location value (Address location value) Alloc :: Name -> Allocator location value location
Deref :: Address location value -> Allocator location value value Deref :: location -> Allocator location value value
runAllocator :: (Addressable location effects, Effectful (m location value), Member (Resumable (AddressError location value)) effects, Member (State (Heap location (Cell location) value)) effects) => m location value (Allocator location value ': effects) a -> m location value effects a runAllocator :: (Addressable location effects, Effectful (m location value), Member (Resumable (AddressError location value)) effects, Member (State (Heap location (Cell location) value)) effects) => m location value (Allocator location value ': effects) a -> m location value effects a
runAllocator = raiseHandler (interpret (\ eff -> case eff of runAllocator = raiseHandler (interpret (\ eff -> case eff of
Alloc name -> lowerEff $ Address <$> allocCell name Alloc name -> lowerEff $ allocCell name
Deref addr -> lowerEff $ heapLookup addr <$> get >>= maybeM (throwResumable (UnallocatedAddress addr)) >>= derefCell addr >>= maybeM (throwResumable (UninitializedAddress addr)))) Deref addr -> lowerEff $ heapLookup addr <$> get >>= maybeM (throwResumable (UnallocatedAddress addr)) >>= derefCell addr >>= maybeM (throwResumable (UninitializedAddress addr))))
data AddressError location value resume where data AddressError location value resume where
UnallocatedAddress :: Address location value -> AddressError location value (Cell location value) UnallocatedAddress :: location -> AddressError location value (Cell location value)
UninitializedAddress :: Address location value -> AddressError location value value UninitializedAddress :: location -> AddressError location value value
deriving instance Eq location => Eq (AddressError location value resume) deriving instance Eq location => Eq (AddressError location value resume)
deriving instance Show location => Show (AddressError location value resume) deriving instance Show location => Show (AddressError location value resume)

View File

@ -6,7 +6,6 @@ import Control.Abstract.Environment
import Control.Abstract.Evaluator import Control.Abstract.Evaluator
import Control.Abstract.Heap import Control.Abstract.Heap
import Control.Abstract.Value import Control.Abstract.Value
import Data.Abstract.Environment
import Data.Abstract.Name import Data.Abstract.Name
import Data.ByteString.Char8 (pack, unpack) import Data.ByteString.Char8 (pack, unpack)
import Data.Semigroup.Reducer hiding (unit) import Data.Semigroup.Reducer hiding (unit)
@ -28,7 +27,7 @@ builtin :: ( HasCallStack
builtin s def = withCurrentCallStack callStack $ do builtin s def = withCurrentCallStack callStack $ do
let name' = name (pack ("__semantic_" <> s)) let name' = name (pack ("__semantic_" <> s))
addr <- alloc name' addr <- alloc name'
modifyEnv (insert name' addr) bind name' addr
def >>= assign addr def >>= assign addr
lambda :: (AbstractFunction location value effects, Member Fresh effects) lambda :: (AbstractFunction location value effects, Member Fresh effects)

View File

@ -9,9 +9,9 @@ import Data.Abstract.Live
import Prologue import Prologue
-- | Retrieve the local 'Live' set. -- | Retrieve the local 'Live' set.
askRoots :: Member (Reader (Live location value)) effects => Evaluator location value effects (Live location value) askRoots :: Member (Reader (Live location)) effects => Evaluator location value effects (Live location)
askRoots = ask askRoots = ask
-- | Run a computation with the given 'Live' set added to the local root set. -- | Run a computation with the given 'Live' set added to the local root set.
extraRoots :: (Member (Reader (Live location value)) effects, Ord location) => Live location value -> Evaluator location value effects a -> Evaluator location value effects a extraRoots :: (Member (Reader (Live location)) effects, Ord location) => Live location -> Evaluator location value effects a -> Evaluator location value effects a
extraRoots roots = local (<> roots) extraRoots roots = local (<> roots)

View File

@ -19,7 +19,6 @@ import Control.Abstract.Addressable
import Control.Abstract.Environment import Control.Abstract.Environment
import Control.Abstract.Evaluator import Control.Abstract.Evaluator
import Control.Abstract.Heap import Control.Abstract.Heap
import Data.Abstract.Address (Address)
import Data.Abstract.Environment as Env import Data.Abstract.Environment as Env
import Data.Abstract.Live (Live) import Data.Abstract.Live (Live)
import Data.Abstract.Name import Data.Abstract.Name
@ -167,7 +166,7 @@ forLoop :: ( AbstractValue location value effects
-> Evaluator location value effects value -- ^ Body -> Evaluator location value effects value -- ^ Body
-> Evaluator location value effects value -> Evaluator location value effects value
forLoop initial cond step body = forLoop initial cond step body =
localize (initial *> while cond (body *> step)) locally (initial *> while cond (body *> step))
-- | The fundamental looping primitive, built on top of 'ifthenelse'. -- | The fundamental looping primitive, built on top of 'ifthenelse'.
while :: AbstractValue location value effects while :: AbstractValue location value effects
@ -194,7 +193,7 @@ makeNamespace :: ( AbstractValue location value effects
, Reducer value (Cell location value) , Reducer value (Cell location value)
) )
=> Name => Name
-> Address location value -> location
-> Maybe value -> Maybe value
-> Evaluator location value effects value -> Evaluator location value effects value
makeNamespace name addr super = do makeNamespace name addr super = do
@ -214,7 +213,7 @@ evaluateInScopedEnv :: ( AbstractValue location value effects
-> Evaluator location value effects value -> Evaluator location value effects value
evaluateInScopedEnv scopedEnvTerm term = do evaluateInScopedEnv scopedEnvTerm term = do
scopedEnv <- scopedEnvTerm >>= scopedEnvironment scopedEnv <- scopedEnvTerm >>= scopedEnvironment
maybe term (flip localEnv term . mergeEnvs) scopedEnv maybe term (\ env -> locally (bindAll env *> term)) scopedEnv
-- | Evaluates a 'Value' returning the referenced value -- | Evaluates a 'Value' returning the referenced value
@ -245,4 +244,4 @@ subtermValue = value <=< subtermRef
-- | Value types, e.g. closures, which can root a set of addresses. -- | Value types, e.g. closures, which can root a set of addresses.
class ValueRoots location value where class ValueRoots location value where
-- | Compute the set of addresses rooted by a given value. -- | Compute the set of addresses rooted by a given value.
valueRoots :: value -> Live location value valueRoots :: value -> Live location

View File

@ -10,18 +10,6 @@ import Data.Semilattice.Lower
import Data.Set as Set import Data.Set as Set
import Prologue import Prologue
-- | An abstract address with a @location@ pointing to a variable of type @value@.
newtype Address location value = Address { unAddress :: location }
deriving (Eq, Ord)
instance Eq location => Eq1 (Address location) where liftEq _ a b = unAddress a == unAddress b
instance Ord location => Ord1 (Address location) where liftCompare _ a b = unAddress a `compare` unAddress b
instance Show location => Show1 (Address location) where liftShowsPrec _ _ = showsPrec
instance Show location => Show (Address location value) where
showsPrec d = showsPrec d . unAddress
-- | 'Precise' models precise store semantics where only the 'Latest' value is taken. Everything gets it's own address (always makes a new allocation) which makes for a larger store. -- | 'Precise' models precise store semantics where only the 'Latest' value is taken. Everything gets it's own address (always makes a new allocation) which makes for a larger store.
newtype Precise = Precise { unPrecise :: Int } newtype Precise = Precise { unPrecise :: Int }
deriving (Eq, Ord) deriving (Eq, Ord)

View File

@ -7,7 +7,7 @@ import Data.Abstract.Live
-- | A single point in a programs execution. -- | A single point in a programs execution.
data Configuration term location cell value = Configuration data Configuration term location cell value = Configuration
{ configurationTerm :: term -- ^ The “instruction,” i.e. the current term to evaluate. { configurationTerm :: term -- ^ The “instruction,” i.e. the current term to evaluate.
, configurationRoots :: Live location value -- ^ The set of rooted addresses. , configurationRoots :: Live location -- ^ The set of rooted addresses.
, configurationEnvironment :: Environment location -- ^ The environment binding any free variables in 'configurationTerm'. , configurationEnvironment :: Environment location -- ^ The environment binding any free variables in 'configurationTerm'.
, configurationHeap :: Heap location cell value -- ^ The heap of values. , configurationHeap :: Heap location cell value -- ^ The heap of values.
} }

View File

@ -1,7 +1,7 @@
module Data.Abstract.Environment module Data.Abstract.Environment
( Environment(..) ( Environment(..)
, addresses , addresses
, bind , intersect
, delete , delete
, head , head
, emptyEnv , emptyEnv
@ -18,7 +18,6 @@ module Data.Abstract.Environment
, roots , roots
) where ) where
import Data.Abstract.Address
import Data.Abstract.Live import Data.Abstract.Live
import Data.Abstract.Name import Data.Abstract.Name
import Data.Align import Data.Align
@ -29,8 +28,9 @@ import Prelude hiding (head, lookup)
import Prologue import Prologue
-- $setup -- $setup
-- >>> let bright = push (insert (name "foo") (Address (Precise 0)) emptyEnv) -- >>> import Data.Abstract.Address
-- >>> let shadowed = insert (name "foo") (Address (Precise 1)) bright -- >>> let bright = push (insert (name "foo") (Precise 0) emptyEnv)
-- >>> let shadowed = insert (name "foo") (Precise 1) bright
-- | A LIFO stack of maps of names to addresses, representing a lexically-scoped evaluation environment. -- | A LIFO stack of maps of names to addresses, representing a lexically-scoped evaluation environment.
-- All behaviors can be assumed to be frontmost-biased: looking up "a" will check the most specific -- All behaviors can be assumed to be frontmost-biased: looking up "a" will check the most specific
@ -72,22 +72,22 @@ mergeNewer (Environment a) (Environment b) =
-- --
-- >>> pairs shadowed -- >>> pairs shadowed
-- [("foo",Precise 1)] -- [("foo",Precise 1)]
pairs :: Environment location -> [(Name, Address location value)] pairs :: Environment location -> [(Name, location)]
pairs = map (second Address) . Map.toList . fold . unEnvironment pairs = Map.toList . fold . unEnvironment
unpairs :: [(Name, Address location value)] -> Environment location unpairs :: [(Name, location)] -> Environment location
unpairs = Environment . pure . Map.fromList . map (second unAddress) unpairs = Environment . pure . Map.fromList
-- | Lookup a 'Name' in the environment. -- | Lookup a 'Name' in the environment.
-- --
-- >>> lookup (name "foo") shadowed -- >>> lookup (name "foo") shadowed
-- Just (Precise 1) -- Just (Precise 1)
lookup :: Name -> Environment location -> Maybe (Address location value) lookup :: Name -> Environment location -> Maybe location
lookup k = fmap Address . foldMapA (Map.lookup k) . unEnvironment lookup name = foldMapA (Map.lookup name) . unEnvironment
-- | Insert a 'Name' in the environment. -- | Insert a 'Name' in the environment.
insert :: Name -> Address location value -> Environment location -> Environment location insert :: Name -> location -> Environment location -> Environment location
insert name (Address value) (Environment (a :| as)) = Environment (Map.insert name value a :| as) insert name addr (Environment (a :| as)) = Environment (Map.insert name addr a :| as)
-- | Remove a 'Name' from the environment. -- | Remove a 'Name' from the environment.
-- --
@ -100,8 +100,8 @@ trim :: Environment location -> Environment location
trim (Environment (a :| as)) = Environment (a :| filtered) trim (Environment (a :| as)) = Environment (a :| filtered)
where filtered = filter (not . Map.null) as where filtered = filter (not . Map.null) as
bind :: Foldable t => t Name -> Environment location -> Environment location intersect :: Foldable t => t Name -> Environment location -> Environment location
bind names env = unpairs (mapMaybe lookupName (toList names)) intersect names env = unpairs (mapMaybe lookupName (toList names))
where where
lookupName name = (,) name <$> lookup name env lookupName name = (,) name <$> lookup name env
@ -118,10 +118,10 @@ overwrite pairs env = unpairs $ mapMaybe lookupAndAlias pairs
-- | Retrieve the 'Live' set of addresses to which the given free variable names are bound. -- | Retrieve the 'Live' set of addresses to which the given free variable names are bound.
-- --
-- Unbound names are silently dropped. -- Unbound names are silently dropped.
roots :: (Ord location, Foldable t) => Environment location -> t Name -> Live location value roots :: (Ord location, Foldable t) => Environment location -> t Name -> Live location
roots env = foldMap (maybe mempty liveSingleton . flip lookup env) roots env names = addresses (names `intersect` env)
addresses :: Ord location => Environment location -> Live location value addresses :: Ord location => Environment location -> Live location
addresses = fromAddresses . map snd . pairs addresses = fromAddresses . map snd . pairs

View File

@ -7,13 +7,12 @@ module Data.Abstract.Exports
, toEnvironment , toEnvironment
) where ) where
import Prelude hiding (null)
import Prologue hiding (null)
import Data.Abstract.Address
import Data.Abstract.Environment (Environment, unpairs) import Data.Abstract.Environment (Environment, unpairs)
import Data.Abstract.Name import Data.Abstract.Name
import qualified Data.Map as Map import qualified Data.Map as Map
import Data.Semilattice.Lower import Data.Semilattice.Lower
import Prelude hiding (null)
import Prologue hiding (null)
-- | A map of export names to an alias & address tuple. -- | A map of export names to an alias & address tuple.
newtype Exports location = Exports { unExports :: Map.Map Name (Name, Maybe location) } newtype Exports location = Exports { unExports :: Map.Map Name (Name, Maybe location) }
@ -23,10 +22,10 @@ null :: Exports location -> Bool
null = Map.null . unExports null = Map.null . unExports
toEnvironment :: Exports location -> Environment location toEnvironment :: Exports location -> Environment location
toEnvironment exports = unpairs (mapMaybe (traverse (fmap Address)) (toList (unExports exports))) toEnvironment exports = unpairs (mapMaybe sequenceA (toList (unExports exports)))
insert :: Name -> Name -> Maybe (Address location value) -> Exports location -> Exports location insert :: Name -> Name -> Maybe location -> Exports location -> Exports location
insert name alias address = Exports . Map.insert name (alias, unAddress <$> address) . unExports insert name alias address = Exports . Map.insert name (alias, address) . unExports
-- TODO: Should we filter for duplicates here? -- TODO: Should we filter for duplicates here?
aliases :: Exports location -> [(Name, Name)] aliases :: Exports location -> [(Name, Name)]

View File

@ -1,7 +1,6 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Data.Abstract.Heap where module Data.Abstract.Heap where
import Data.Abstract.Address
import Data.Abstract.Live import Data.Abstract.Live
import qualified Data.Map.Monoidal as Monoidal import qualified Data.Map.Monoidal as Monoidal
import Data.Semigroup.Reducer import Data.Semigroup.Reducer
@ -13,34 +12,34 @@ newtype Heap location cell value = Heap { unHeap :: Monoidal.Map location (cell
deriving (Eq, Foldable, Functor, Lower, Monoid, Ord, Semigroup, Traversable) deriving (Eq, Foldable, Functor, Lower, Monoid, Ord, Semigroup, Traversable)
-- | Look up the cell of values for an 'Address' in a 'Heap', if any. -- | Look up the cell of values for an 'Address' in a 'Heap', if any.
heapLookup :: Ord location => Address location value -> Heap location cell value -> Maybe (cell value) heapLookup :: Ord location => location -> Heap location cell value -> Maybe (cell value)
heapLookup (Address address) = Monoidal.lookup address . unHeap heapLookup address = Monoidal.lookup address . unHeap
-- | Look up the list of values stored for a given address, if any. -- | Look up the list of values stored for a given address, if any.
heapLookupAll :: (Ord location, Foldable cell) => Address location value -> Heap location cell value -> Maybe [value] heapLookupAll :: (Ord location, Foldable cell) => location -> Heap location cell value -> Maybe [value]
heapLookupAll address = fmap toList . heapLookup address heapLookupAll address = fmap toList . heapLookup address
-- | Append a value onto the cell for a given address, inserting a new cell if none existed. -- | Append a value onto the cell for a given address, inserting a new cell if none existed.
heapInsert :: (Ord location, Reducer value (cell value)) => Address location value -> value -> Heap location cell value -> Heap location cell value heapInsert :: (Ord location, Reducer value (cell value)) => location -> value -> Heap location cell value -> Heap location cell value
heapInsert address value = flip snoc (address, value) heapInsert address value = flip snoc (address, value)
-- | Manually insert a cell into the heap at a given address. -- | Manually insert a cell into the heap at a given address.
heapInit :: Ord location => Address location value -> cell value -> Heap location cell value -> Heap location cell value heapInit :: Ord location => location -> cell value -> Heap location cell value -> Heap location cell value
heapInit (Address address) cell (Heap h) = Heap (Monoidal.insert address cell h) heapInit address cell (Heap h) = Heap (Monoidal.insert address cell h)
-- | The number of addresses extant in a 'Heap'. -- | The number of addresses extant in a 'Heap'.
heapSize :: Heap location cell value -> Int heapSize :: Heap location cell value -> Int
heapSize = Monoidal.size . unHeap heapSize = Monoidal.size . unHeap
-- | Restrict a 'Heap' to only those 'Address'es in the given 'Live' set (in essence garbage collecting the rest). -- | Restrict a 'Heap' to only those addresses in the given 'Live' set (in essence garbage collecting the rest).
heapRestrict :: Ord location => Heap location cell value -> Live location value -> Heap location cell value heapRestrict :: Ord location => Heap location cell value -> Live location -> Heap location cell value
heapRestrict (Heap m) roots = Heap (Monoidal.filterWithKey (\ address _ -> Address address `liveMember` roots) m) heapRestrict (Heap m) roots = Heap (Monoidal.filterWithKey (\ address _ -> address `liveMember` roots) m)
instance (Ord location, Reducer value (cell value)) => Reducer (Address location value, value) (Heap location cell value) where instance (Ord location, Reducer value (cell value)) => Reducer (location, value) (Heap location cell value) where
unit = Heap . unit . first unAddress unit = Heap . unit
cons (Address key, a) (Heap heap) = Heap (cons (key, a) heap) cons (addr, a) (Heap heap) = Heap (cons (addr, a) heap)
snoc (Heap heap) (Address key, a) = Heap (snoc heap (key, a)) snoc (Heap heap) (addr, a) = Heap (snoc heap (addr, a))
instance (Show location, Show (cell value)) => Show (Heap location cell value) where instance (Show location, Show (cell value)) => Show (Heap location cell value) where
showsPrec d = showsUnaryWith showsPrec "Heap" d . Monoidal.pairs . unHeap showsPrec d = showsUnaryWith showsPrec "Heap" d . Monoidal.pairs . unHeap

View File

@ -1,42 +1,41 @@
{-# LANGUAGE DataKinds, GeneralizedNewtypeDeriving, TypeFamilies, TypeOperators #-} {-# LANGUAGE DataKinds, GeneralizedNewtypeDeriving, TypeFamilies, TypeOperators #-}
module Data.Abstract.Live where module Data.Abstract.Live where
import Data.Abstract.Address
import Data.Semilattice.Lower import Data.Semilattice.Lower
import Data.Set as Set import Data.Set as Set
import Prologue import Prologue
-- | A set of live addresses (whether roots or reachable). -- | A set of live addresses (whether roots or reachable).
newtype Live location value = Live { unLive :: Set location } newtype Live location = Live { unLive :: Set location }
deriving (Eq, Lower, Monoid, Ord, Semigroup) deriving (Eq, Lower, Monoid, Ord, Semigroup)
fromAddresses :: (Foldable t, Ord location) => t (Address location value) -> Live location value fromAddresses :: (Foldable t, Ord location) => t location -> Live location
fromAddresses = Prologue.foldr liveInsert lowerBound fromAddresses = Prologue.foldr liveInsert lowerBound
-- | Construct a 'Live' set containing only the given address. -- | Construct a 'Live' set containing only the given address.
liveSingleton :: Address location value -> Live location value liveSingleton :: location -> Live location
liveSingleton = Live . Set.singleton . unAddress liveSingleton = Live . Set.singleton
-- | Insert an address into a 'Live' set. -- | Insert an address into a 'Live' set.
liveInsert :: Ord location => Address location value -> Live location value -> Live location value liveInsert :: Ord location => location -> Live location -> Live location
liveInsert addr = Live . Set.insert (unAddress addr) . unLive liveInsert addr = Live . Set.insert addr . unLive
-- | Delete an address from a 'Live' set, if present. -- | Delete an address from a 'Live' set, if present.
liveDelete :: Ord location => Address location value -> Live location value -> Live location value liveDelete :: Ord location => location -> Live location -> Live location
liveDelete addr = Live . Set.delete (unAddress addr) . unLive liveDelete addr = Live . Set.delete addr . unLive
-- | Compute the (asymmetric) difference of two 'Live' sets, i.e. delete every element of the second set from the first set. -- | Compute the (asymmetric) difference of two 'Live' sets, i.e. delete every element of the second set from the first set.
liveDifference :: Ord location => Live location value -> Live location value -> Live location value liveDifference :: Ord location => Live location -> Live location -> Live location
liveDifference = fmap Live . (Set.difference `on` unLive) liveDifference = fmap Live . (Set.difference `on` unLive)
-- | Test whether an 'Address' is in a 'Live' set. -- | Test whether an address is in a 'Live' set.
liveMember :: Ord location => Address location value -> Live location value -> Bool liveMember :: Ord location => location -> Live location -> Bool
liveMember addr = Set.member (unAddress addr) . unLive liveMember addr = Set.member addr . unLive
-- | Decompose a 'Live' set into a pair of one member address and the remaining set, or 'Nothing' if empty. -- | Decompose a 'Live' set into a pair of one member address and the remaining set, or 'Nothing' if empty.
liveSplit :: Live location value -> Maybe (Address location value, Live location value) liveSplit :: Live location -> Maybe (location, Live location)
liveSplit = fmap (bimap Address Live) . Set.minView . unLive liveSplit = fmap (fmap Live) . Set.minView . unLive
instance Show location => Show (Live location value) where instance Show location => Show (Live location) where
showsPrec d = showsUnaryWith showsPrec "Live" d . Set.toList . unLive showsPrec d = showsUnaryWith showsPrec "Live" d . Set.toList . unLive

View File

@ -132,7 +132,7 @@ instance ( Member (Allocator location Type) effects
tvar <- Var <$> fresh tvar <- Var <$> fresh
assign a tvar assign a tvar
bimap (Env.insert name a) (tvar :) <$> rest) (pure (emptyEnv, [])) names bimap (Env.insert name a) (tvar :) <$> rest) (pure (emptyEnv, [])) names
(zeroOrMoreProduct tvars :->) <$> localEnv (mergeEnvs env) (body `catchReturn` \ (Return value) -> pure value) (zeroOrMoreProduct tvars :->) <$> locally (bindAll env *> body `catchReturn` \ (Return value) -> pure value)
call op params = do call op params = do
tvar <- fresh tvar <- fresh

View File

@ -72,7 +72,7 @@ instance ( Coercible body (Eff effects)
packageInfo <- currentPackage packageInfo <- currentPackage
moduleInfo <- currentModule moduleInfo <- currentModule
i <- fresh i <- fresh
Closure packageInfo moduleInfo parameters (ClosureBody i (coerce (lowerEff body))) . Env.bind (foldr Set.delete freeVariables parameters) <$> getEnv Closure packageInfo moduleInfo parameters (ClosureBody i (coerce (lowerEff body))) . Env.intersect (foldr Set.delete freeVariables parameters) <$> getEnv
call op params = do call op params = do
case op of case op of
@ -85,7 +85,7 @@ instance ( Coercible body (Eff effects)
a <- alloc name a <- alloc name
assign a v assign a v
Env.insert name a <$> rest) (pure env) (zip names params) Env.insert name a <$> rest) (pure env) (zip names params)
localEnv (mergeEnvs bindings) (raiseEff (coerce body) `catchReturn` \ (Return value) -> pure value) locally (bindAll bindings *> raiseEff (coerce body) `catchReturn` \ (Return value) -> pure value)
_ -> throwValueError (CallError op) _ -> throwValueError (CallError op)

View File

@ -27,7 +27,7 @@ instance Evaluatable Function where
eval Function{..} = do eval Function{..} = do
name <- either (throwEvalError . FreeVariablesError) pure (freeVariable $ subterm functionName) name <- either (throwEvalError . FreeVariablesError) pure (freeVariable $ subterm functionName)
(v, addr) <- letrec name (closure (paramNames functionParameters) (Set.fromList (freeVariables functionBody)) (subtermValue functionBody)) (v, addr) <- letrec name (closure (paramNames functionParameters) (Set.fromList (freeVariables functionBody)) (subtermValue functionBody))
modifyEnv (Env.insert name addr) bind name addr
pure (Rval v) pure (Rval v)
where paramNames = foldMap (freeVariables . subterm) where paramNames = foldMap (freeVariables . subterm)
@ -53,7 +53,7 @@ instance Evaluatable Method where
eval Method{..} = do eval Method{..} = do
name <- either (throwEvalError . FreeVariablesError) pure (freeVariable $ subterm methodName) name <- either (throwEvalError . FreeVariablesError) pure (freeVariable $ subterm methodName)
(v, addr) <- letrec name (closure (paramNames methodParameters) (Set.fromList (freeVariables methodBody)) (subtermValue methodBody)) (v, addr) <- letrec name (closure (paramNames methodParameters) (Set.fromList (freeVariables methodBody)) (subtermValue methodBody))
modifyEnv (Env.insert name addr) bind name addr
pure (Rval v) pure (Rval v)
where paramNames = foldMap (freeVariables . subterm) where paramNames = foldMap (freeVariables . subterm)
@ -187,7 +187,7 @@ instance Evaluatable Class where
void $ subtermValue classBody void $ subtermValue classBody
classEnv <- Env.head <$> getEnv classEnv <- Env.head <$> getEnv
klass name supers classEnv klass name supers classEnv
Rval <$> (v <$ modifyEnv (Env.insert name addr)) Rval v <$ bind name addr
-- | A decorator in Python -- | A decorator in Python
data Decorator a = Decorator { decoratorIdentifier :: !a, decoratorParamaters :: ![a], decoratorBody :: !a } data Decorator a = Decorator { decoratorIdentifier :: !a, decoratorParamaters :: ![a], decoratorBody :: !a }
@ -278,7 +278,7 @@ instance Evaluatable TypeAlias where
v <- subtermValue typeAliasKind v <- subtermValue typeAliasKind
addr <- lookupOrAlloc name addr <- lookupOrAlloc name
assign addr v assign addr v
Rval <$> (modifyEnv (Env.insert name addr) $> v) Rval v <$ bind name addr
instance Declarations a => Declarations (TypeAlias a) where instance Declarations a => Declarations (TypeAlias a) where
declaredName TypeAlias{..} = declaredName typeAliasIdentifier declaredName TypeAlias{..} = declaredName typeAliasIdentifier

View File

@ -1,7 +1,6 @@
{-# LANGUAGE DeriveAnyClass, MultiParamTypeClasses, ScopedTypeVariables, UndecidableInstances, ViewPatterns #-} {-# LANGUAGE DeriveAnyClass, MultiParamTypeClasses, ScopedTypeVariables, UndecidableInstances, ViewPatterns #-}
module Data.Syntax.Statement where module Data.Syntax.Statement where
import qualified Data.Abstract.Environment as Env
import Data.Abstract.Evaluatable import Data.Abstract.Evaluatable
import Data.ByteString.Char8 (unpack) import Data.ByteString.Char8 (unpack)
import Data.JSON.Fields import Data.JSON.Fields
@ -95,7 +94,7 @@ instance Evaluatable Let where
eval Let{..} = do eval Let{..} = do
name <- either (throwEvalError . FreeVariablesError) pure (freeVariable $ subterm letVariable) name <- either (throwEvalError . FreeVariablesError) pure (freeVariable $ subterm letVariable)
addr <- snd <$> letrec name (subtermValue letValue) addr <- snd <$> letrec name (subtermValue letValue)
Rval <$> localEnv (Env.insert name addr) (subtermValue letBody) Rval <$> locally (bind name addr *> subtermValue letBody)
-- Assignment -- Assignment
@ -119,7 +118,7 @@ instance Evaluatable Assignment where
LvalLocal nam -> do LvalLocal nam -> do
addr <- lookupOrAlloc nam addr <- lookupOrAlloc nam
assign addr rhs assign addr rhs
modifyEnv (Env.insert nam addr) bind nam addr
LvalMember _ _ -> LvalMember _ _ ->
-- we don't yet support mutable object properties: -- we don't yet support mutable object properties:
pure () pure ()

View File

@ -71,7 +71,7 @@ instance Evaluatable Import where
for_ paths $ \path -> do for_ paths $ \path -> do
traceResolve (unPath importPath) path traceResolve (unPath importPath) path
importedEnv <- maybe emptyEnv fst <$> isolate (require path) importedEnv <- maybe emptyEnv fst <$> isolate (require path)
modifyEnv (mergeEnvs importedEnv) bindAll importedEnv
pure (Rval unit) pure (Rval unit)
@ -95,7 +95,7 @@ instance Evaluatable QualifiedImport where
for_ paths $ \p -> do for_ paths $ \p -> do
traceResolve (unPath importPath) p traceResolve (unPath importPath) p
importedEnv <- maybe emptyEnv fst <$> isolate (require p) importedEnv <- maybe emptyEnv fst <$> isolate (require p)
modifyEnv (mergeEnvs importedEnv) bindAll importedEnv
makeNamespace alias addr Nothing makeNamespace alias addr Nothing
pure (Rval unit) pure (Rval unit)

View File

@ -70,7 +70,7 @@ include pathTerm f = do
path <- resolvePHPName name path <- resolvePHPName name
traceResolve name path traceResolve name path
(importedEnv, v) <- isolate (f path) >>= maybeM (pure (emptyEnv, unit)) (importedEnv, v) <- isolate (f path) >>= maybeM (pure (emptyEnv, unit))
modifyEnv (mergeEnvs importedEnv) bindAll importedEnv
pure (Rval v) pure (Rval v)
newtype Require a = Require a newtype Require a = Require a

View File

@ -118,7 +118,7 @@ instance Evaluatable Import where
-- Last module path is the one we want to import -- Last module path is the one we want to import
let path = NonEmpty.last modulePaths let path = NonEmpty.last modulePaths
importedEnv <- maybe emptyEnv fst <$> isolate (require path) importedEnv <- maybe emptyEnv fst <$> isolate (require path)
modifyEnv (mergeEnvs (select importedEnv)) bindAll (select importedEnv)
pure (Rval unit) pure (Rval unit)
where where
select importedEnv select importedEnv
@ -140,7 +140,7 @@ evalQualifiedImport :: ( AbstractValue location value effects
=> Name -> ModulePath -> Evaluator location value effects value => Name -> ModulePath -> Evaluator location value effects value
evalQualifiedImport name path = letrec' name $ \addr -> do evalQualifiedImport name path = letrec' name $ \addr -> do
importedEnv <- maybe emptyEnv fst <$> isolate (require path) importedEnv <- maybe emptyEnv fst <$> isolate (require path)
modifyEnv (mergeEnvs importedEnv) bindAll importedEnv
unit <$ makeNamespace name addr Nothing unit <$ makeNamespace name addr Nothing
newtype QualifiedImport a = QualifiedImport { qualifiedImportFrom :: QualifiedName } newtype QualifiedImport a = QualifiedImport { qualifiedImportFrom :: QualifiedName }
@ -189,7 +189,7 @@ instance Evaluatable QualifiedAliasedImport where
Rval <$> letrec' alias (\addr -> do Rval <$> letrec' alias (\addr -> do
let path = NonEmpty.last modulePaths let path = NonEmpty.last modulePaths
importedEnv <- maybe emptyEnv fst <$> isolate (require path) importedEnv <- maybe emptyEnv fst <$> isolate (require path)
modifyEnv (mergeEnvs importedEnv) bindAll importedEnv
unit <$ makeNamespace alias addr Nothing) unit <$ makeNamespace alias addr Nothing)
-- | Ellipsis (used in splice expressions and alternatively can be used as a fill in expression, like `undefined` in Haskell) -- | Ellipsis (used in splice expressions and alternatively can be used as a fill in expression, like `undefined` in Haskell)

View File

@ -74,7 +74,7 @@ instance Evaluatable Require where
path <- resolveRubyName name path <- resolveRubyName name
traceResolve name path traceResolve name path
(importedEnv, v) <- isolate (doRequire path) (importedEnv, v) <- isolate (doRequire path)
modifyEnv (`mergeNewer` importedEnv) bindAll importedEnv
pure (Rval 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 pure (Rval 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 location value effects doRequire :: ( AbstractValue location value effects
@ -122,7 +122,7 @@ doLoad path shouldWrap = do
path' <- resolveRubyPath path path' <- resolveRubyPath path
traceResolve path path' traceResolve path path'
importedEnv <- maybe emptyEnv fst <$> isolate (load path') importedEnv <- maybe emptyEnv fst <$> isolate (load path')
unless shouldWrap $ modifyEnv (mergeEnvs importedEnv) 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 pure (boolean Prelude.True) -- load always returns true. http://ruby-doc.org/core-2.5.0/Kernel.html#method-i-load
-- TODO: autoload -- TODO: autoload

View File

@ -148,7 +148,7 @@ evalRequire :: ( AbstractValue location value effects
-> Evaluator location value effects value -> Evaluator location value effects value
evalRequire modulePath alias = letrec' alias $ \addr -> do evalRequire modulePath alias = letrec' alias $ \addr -> do
importedEnv <- maybe emptyEnv fst <$> isolate (require modulePath) importedEnv <- maybe emptyEnv fst <$> isolate (require modulePath)
modifyEnv (mergeEnvs importedEnv) bindAll importedEnv
unit <$ makeNamespace alias addr Nothing unit <$ makeNamespace alias addr Nothing
data Import a = Import { importSymbols :: ![(Name, Name)], importFrom :: ImportPath } data Import a = Import { importSymbols :: ![(Name, Name)], importFrom :: ImportPath }
@ -165,7 +165,7 @@ instance Evaluatable Import where
eval (Import symbols importPath) = do eval (Import symbols importPath) = do
modulePath <- resolveWithNodejsStrategy importPath typescriptExtensions modulePath <- resolveWithNodejsStrategy importPath typescriptExtensions
importedEnv <- maybe emptyEnv fst <$> isolate (require modulePath) importedEnv <- maybe emptyEnv fst <$> isolate (require modulePath)
modifyEnv (mergeEnvs (renamed importedEnv)) $> Rval unit bindAll (renamed importedEnv) $> Rval unit
where where
renamed importedEnv renamed importedEnv
| Prologue.null symbols = importedEnv | Prologue.null symbols = importedEnv
@ -273,7 +273,7 @@ instance Evaluatable DefaultExport where
addr <- lookupOrAlloc name addr <- lookupOrAlloc name
assign addr v assign addr v
addExport name name Nothing addExport name name Nothing
void $ modifyEnv (Env.insert name addr) void $ bind name addr
Nothing -> throwEvalError DefaultExportError Nothing -> throwEvalError DefaultExportError
pure (Rval unit) pure (Rval unit)
@ -853,7 +853,7 @@ instance Evaluatable AbstractClass where
void $ subtermValue classBody void $ subtermValue classBody
classEnv <- Env.head <$> getEnv classEnv <- Env.head <$> getEnv
klass name supers classEnv klass name supers classEnv
Rval <$> (v <$ modifyEnv (Env.insert name addr)) Rval v <$ bind name addr
data JsxElement a = JsxElement { _jsxOpeningElement :: !a, _jsxElements :: ![a], _jsxClosingElement :: !a } data JsxElement a = JsxElement { _jsxOpeningElement :: !a, _jsxElements :: ![a], _jsxClosingElement :: !a }

View File

@ -44,7 +44,6 @@ spec = parallel $ do
where where
ns n = Just . Latest . Last . Just . Namespace n ns n = Just . Latest . Last . Just . Namespace n
addr = Address . Precise
fixtures = "test/fixtures/python/analysis/" fixtures = "test/fixtures/python/analysis/"
evaluate entry = evalPythonProject (fixtures <> entry) evaluate entry = evalPythonProject (fixtures <> entry)
evalPythonProject path = testEvaluating <$> evaluateProject pythonParser Language.Python pythonPrelude path evalPythonProject path = testEvaluating <$> evaluateProject pythonParser Language.Python pythonPrelude path

View File

@ -76,7 +76,6 @@ spec = parallel $ do
where where
ns n = Just . Latest . Last . Just . Namespace n ns n = Just . Latest . Last . Just . Namespace n
addr = Address . Precise
fixtures = "test/fixtures/ruby/analysis/" fixtures = "test/fixtures/ruby/analysis/"
evaluate entry = evalRubyProject (fixtures <> entry) evaluate entry = evalRubyProject (fixtures <> entry)
evalRubyProject path = testEvaluating <$> evaluateProject rubyParser Language.Ruby rubyPrelude path evalRubyProject path = testEvaluating <$> evaluateProject rubyParser Language.Ruby rubyPrelude path

View File

@ -6,7 +6,8 @@ import System.Environment
import Test.DocTest import Test.DocTest
defaultFiles = defaultFiles =
[ "src/Data/Abstract/Environment.hs" [ "src/Data/Abstract/Address.hs"
, "src/Data/Abstract/Environment.hs"
, "src/Data/Abstract/Name.hs" , "src/Data/Abstract/Name.hs"
, "src/Data/Range.hs" , "src/Data/Range.hs"
, "src/Data/Semigroup/App.hs" , "src/Data/Semigroup/App.hs"