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:
commit
51394186f9
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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 ()
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -7,7 +7,7 @@ import Data.Abstract.Live
|
|||||||
-- | A single point in a program’s execution.
|
-- | A single point in a program’s 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.
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
@ -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)]
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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 ()
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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 }
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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"
|
||||||
|
Loading…
Reference in New Issue
Block a user