mirror of
https://github.com/github/semantic.git
synced 2025-01-04 13:34:31 +03:00
Merge remote-tracking branch 'origin/master' into typescript-exports
This commit is contained in:
commit
f93243f5b5
@ -26,6 +26,9 @@ type CacheFor term value = Cache (LocationFor value) term value
|
|||||||
newtype Caching m term value (effects :: [* -> *]) a = Caching (m term value effects a)
|
newtype Caching m term value (effects :: [* -> *]) a = Caching (m term value effects a)
|
||||||
deriving (Alternative, Applicative, Functor, Effectful, Monad, MonadFail, MonadFresh, MonadNonDet)
|
deriving (Alternative, Applicative, Functor, Effectful, Monad, MonadFail, MonadFresh, MonadNonDet)
|
||||||
|
|
||||||
|
deriving instance MonadEnvironment value (m term value effects) => MonadEnvironment value (Caching m term value effects)
|
||||||
|
deriving instance MonadStore value (m term value effects) => MonadStore value (Caching m term value effects)
|
||||||
|
deriving instance MonadModuleTable term value (m term value effects) => MonadModuleTable term value (Caching m term value effects)
|
||||||
deriving instance MonadEvaluator term value (m term value effects) => MonadEvaluator term value (Caching m term value effects)
|
deriving instance MonadEvaluator term value (m term value effects) => MonadEvaluator term value (Caching m term value effects)
|
||||||
|
|
||||||
-- | Functionality used to perform caching analysis. This is not exported, and exists primarily for organizational reasons.
|
-- | Functionality used to perform caching analysis. This is not exported, and exists primarily for organizational reasons.
|
||||||
|
@ -12,6 +12,9 @@ import Prologue
|
|||||||
newtype DeadCode m term value (effects :: [* -> *]) a = DeadCode (m term value effects a)
|
newtype DeadCode m term value (effects :: [* -> *]) a = DeadCode (m term value effects a)
|
||||||
deriving (Alternative, Applicative, Functor, Effectful, Monad, MonadFail, MonadFresh, MonadNonDet)
|
deriving (Alternative, Applicative, Functor, Effectful, Monad, MonadFail, MonadFresh, MonadNonDet)
|
||||||
|
|
||||||
|
deriving instance MonadEnvironment value (m term value effects) => MonadEnvironment value (DeadCode m term value effects)
|
||||||
|
deriving instance MonadStore value (m term value effects) => MonadStore value (DeadCode m term value effects)
|
||||||
|
deriving instance MonadModuleTable term value (m term value effects) => MonadModuleTable term value (DeadCode m term value effects)
|
||||||
deriving instance MonadEvaluator term value (m term value effects) => MonadEvaluator term value (DeadCode m term value effects)
|
deriving instance MonadEvaluator term value (m term value effects) => MonadEvaluator term value (DeadCode m term value effects)
|
||||||
|
|
||||||
-- | A set of “dead” (unreachable) terms.
|
-- | A set of “dead” (unreachable) terms.
|
||||||
|
@ -12,6 +12,7 @@ import Control.Monad.Effect.Fresh
|
|||||||
import Control.Monad.Effect.NonDet
|
import Control.Monad.Effect.NonDet
|
||||||
import Control.Monad.Effect.Reader
|
import Control.Monad.Effect.Reader
|
||||||
import Control.Monad.Effect.State
|
import Control.Monad.Effect.State
|
||||||
|
import Data.Abstract.Configuration
|
||||||
import Data.Abstract.Evaluatable
|
import Data.Abstract.Evaluatable
|
||||||
import Data.Abstract.Address
|
import Data.Abstract.Address
|
||||||
import Data.Abstract.ModuleTable
|
import Data.Abstract.ModuleTable
|
||||||
@ -80,7 +81,7 @@ type EvaluatingEffects term value
|
|||||||
, State (Map Name (Name, Maybe (Address (LocationFor value) value))) -- Set of exports
|
, State (Map Name (Name, Maybe (Address (LocationFor value) value))) -- Set of exports
|
||||||
]
|
]
|
||||||
|
|
||||||
instance Members (EvaluatingEffects term value) effects => MonadEvaluator term value (Evaluating term value effects) where
|
instance Members '[Reader (EnvironmentFor value), State (EnvironmentFor value)] effects => MonadEnvironment value (Evaluating term value effects) where
|
||||||
getGlobalEnv = raise get
|
getGlobalEnv = raise get
|
||||||
putGlobalEnv = raise . put
|
putGlobalEnv = raise . put
|
||||||
withGlobalEnv s = raise . localState s . lower
|
withGlobalEnv s = raise . localState s . lower
|
||||||
@ -92,15 +93,20 @@ instance Members (EvaluatingEffects term value) effects => MonadEvaluator term v
|
|||||||
askLocalEnv = raise ask
|
askLocalEnv = raise ask
|
||||||
localEnv f a = raise (local f (lower a))
|
localEnv f a = raise (local f (lower a))
|
||||||
|
|
||||||
|
instance Member (State (StoreFor value)) effects => MonadStore value (Evaluating term value effects) where
|
||||||
getStore = raise get
|
getStore = raise get
|
||||||
putStore = raise . put
|
putStore = raise . put
|
||||||
|
|
||||||
|
instance Members '[Reader (ModuleTable term), State (ModuleTable (EnvironmentFor value))] effects => MonadModuleTable term value (Evaluating term value effects) where
|
||||||
getModuleTable = raise get
|
getModuleTable = raise get
|
||||||
modifyModuleTable f = raise (modify f)
|
putModuleTable = raise . put
|
||||||
|
|
||||||
askModuleTable = raise ask
|
askModuleTable = raise ask
|
||||||
localModuleTable f a = raise (local f (lower a))
|
localModuleTable f a = raise (local f (lower a))
|
||||||
|
|
||||||
|
instance Members (EvaluatingEffects term value) effects => MonadEvaluator term value (Evaluating term value effects) where
|
||||||
|
getConfiguration term = Configuration term mempty <$> askLocalEnv <*> getStore
|
||||||
|
|
||||||
instance ( Evaluatable (Base term)
|
instance ( Evaluatable (Base term)
|
||||||
, FreeVariables term
|
, FreeVariables term
|
||||||
, Members (EvaluatingEffects term value) effects
|
, Members (EvaluatingEffects term value) effects
|
||||||
|
@ -17,6 +17,9 @@ import Prologue hiding (trace)
|
|||||||
newtype Tracing (trace :: * -> *) m term value (effects :: [* -> *]) a = Tracing (m term value effects a)
|
newtype Tracing (trace :: * -> *) m term value (effects :: [* -> *]) a = Tracing (m term value effects a)
|
||||||
deriving (Alternative, Applicative, Functor, Effectful, Monad, MonadFail, MonadFresh, MonadNonDet)
|
deriving (Alternative, Applicative, Functor, Effectful, Monad, MonadFail, MonadFresh, MonadNonDet)
|
||||||
|
|
||||||
|
deriving instance MonadEnvironment value (m term value effects) => MonadEnvironment value (Tracing trace m term value effects)
|
||||||
|
deriving instance MonadStore value (m term value effects) => MonadStore value (Tracing trace m term value effects)
|
||||||
|
deriving instance MonadModuleTable term value (m term value effects) => MonadModuleTable term value (Tracing trace m term value effects)
|
||||||
deriving instance MonadEvaluator term value (m term value effects) => MonadEvaluator term value (Tracing trace m term value effects)
|
deriving instance MonadEvaluator term value (m term value effects) => MonadEvaluator term value (Tracing trace m term value effects)
|
||||||
|
|
||||||
instance ( Corecursive term
|
instance ( Corecursive term
|
||||||
|
@ -25,7 +25,7 @@ class (Monad m, Ord l, l ~ LocationFor value, Reducer value (Cell l value)) => M
|
|||||||
-- The term is expected to contain one and only one free 'Name', meaning that care should be taken to apply this only to e.g. identifiers.
|
-- The term is expected to contain one and only one free 'Name', meaning that care should be taken to apply this only to e.g. identifiers.
|
||||||
lookupOrAlloc :: ( FreeVariables term
|
lookupOrAlloc :: ( FreeVariables term
|
||||||
, MonadAddressable (LocationFor value) value m
|
, MonadAddressable (LocationFor value) value m
|
||||||
, MonadEvaluator term value m
|
, MonadStore value m
|
||||||
, Semigroup (CellFor value)
|
, Semigroup (CellFor value)
|
||||||
)
|
)
|
||||||
=> term
|
=> term
|
||||||
@ -38,7 +38,7 @@ lookupOrAlloc term = let [name] = toList (freeVariables term) in
|
|||||||
-- | Look up or allocate an address for a 'Name' & assign it a given value, returning the 'Name' paired with the address.
|
-- | Look up or allocate an address for a 'Name' & assign it a given value, returning the 'Name' paired with the address.
|
||||||
lookupOrAlloc' :: ( Semigroup (CellFor value)
|
lookupOrAlloc' :: ( Semigroup (CellFor value)
|
||||||
, MonadAddressable (LocationFor value) value m
|
, MonadAddressable (LocationFor value) value m
|
||||||
, MonadEvaluator term value m
|
, MonadStore value m
|
||||||
)
|
)
|
||||||
=> Name
|
=> Name
|
||||||
-> value
|
-> value
|
||||||
@ -49,21 +49,11 @@ lookupOrAlloc' name v env = do
|
|||||||
assign a v
|
assign a v
|
||||||
pure (name, a)
|
pure (name, a)
|
||||||
|
|
||||||
-- | Write a value to the given 'Address' in the 'Store'.
|
|
||||||
assign :: ( Ord (LocationFor value)
|
|
||||||
, MonadEvaluator term value m
|
|
||||||
, Reducer value (CellFor value)
|
|
||||||
)
|
|
||||||
=> Address (LocationFor value) value
|
|
||||||
-> value
|
|
||||||
-> m ()
|
|
||||||
assign address = modifyStore . storeInsert address
|
|
||||||
|
|
||||||
|
|
||||||
-- Instances
|
-- Instances
|
||||||
|
|
||||||
-- | 'Precise' locations are always 'alloc'ated a fresh 'Address', and 'deref'erence to the 'Latest' value written.
|
-- | 'Precise' locations are always 'alloc'ated a fresh 'Address', and 'deref'erence to the 'Latest' value written.
|
||||||
instance (Monad m, LocationFor value ~ Precise, MonadEvaluator term value m) => MonadAddressable Precise value m where
|
instance (MonadFail m, LocationFor value ~ Precise, MonadStore value m) => MonadAddressable Precise value m where
|
||||||
deref = maybe uninitializedAddress (pure . unLatest) <=< flip fmap getStore . storeLookup
|
deref = maybe uninitializedAddress (pure . unLatest) <=< flip fmap getStore . storeLookup
|
||||||
where
|
where
|
||||||
-- | Fail with a message denoting an uninitialized address (i.e. one which was 'alloc'ated, but never 'assign'ed a value before being 'deref'erenced).
|
-- | Fail with a message denoting an uninitialized address (i.e. one which was 'alloc'ated, but never 'assign'ed a value before being 'deref'erenced).
|
||||||
@ -74,7 +64,7 @@ instance (Monad m, LocationFor value ~ Precise, MonadEvaluator term value m) =>
|
|||||||
|
|
||||||
|
|
||||||
-- | 'Monovariant' locations 'alloc'ate one 'Address' per unique variable name, and 'deref'erence once per stored value, nondeterministically.
|
-- | 'Monovariant' locations 'alloc'ate one 'Address' per unique variable name, and 'deref'erence once per stored value, nondeterministically.
|
||||||
instance (Alternative m, Monad m, LocationFor value ~ Monovariant, MonadEvaluator term value m, Ord value) => MonadAddressable Monovariant value m where
|
instance (Alternative m, LocationFor value ~ Monovariant, MonadStore value m, Ord value) => MonadAddressable Monovariant value m where
|
||||||
deref = asum . maybe [] (map pure . toList) <=< flip fmap getStore . storeLookup
|
deref = asum . maybe [] (map pure . toList) <=< flip fmap getStore . storeLookup
|
||||||
|
|
||||||
alloc = pure . Address . Monovariant
|
alloc = pure . Address . Monovariant
|
||||||
|
@ -1,12 +1,23 @@
|
|||||||
{-# LANGUAGE ConstrainedClassMethods, FunctionalDependencies #-}
|
{-# LANGUAGE ConstrainedClassMethods, FunctionalDependencies #-}
|
||||||
module Control.Abstract.Evaluator where
|
module Control.Abstract.Evaluator
|
||||||
|
( MonadEvaluator(..)
|
||||||
|
, MonadEnvironment(..)
|
||||||
|
, modifyGlobalEnv
|
||||||
|
, MonadStore(..)
|
||||||
|
, modifyStore
|
||||||
|
, assign
|
||||||
|
, MonadModuleTable(..)
|
||||||
|
, modifyModuleTable
|
||||||
|
) where
|
||||||
|
|
||||||
import Data.Abstract.Address
|
import Data.Abstract.Address
|
||||||
import Data.Abstract.Configuration
|
import Data.Abstract.Configuration
|
||||||
import Data.Abstract.FreeVariables
|
import Data.Abstract.FreeVariables
|
||||||
import Data.Abstract.Live
|
import Data.Abstract.Live
|
||||||
import Data.Abstract.ModuleTable
|
import Data.Abstract.ModuleTable
|
||||||
|
import Data.Abstract.Store
|
||||||
import Data.Abstract.Value
|
import Data.Abstract.Value
|
||||||
|
import Data.Semigroup.Reducer
|
||||||
import Prelude hiding (fail)
|
import Prelude hiding (fail)
|
||||||
import Prologue
|
import Prologue
|
||||||
|
|
||||||
@ -16,7 +27,17 @@ import Prologue
|
|||||||
-- - environments binding names to addresses
|
-- - environments binding names to addresses
|
||||||
-- - a heap mapping addresses to (possibly sets of) values
|
-- - a heap mapping addresses to (possibly sets of) values
|
||||||
-- - tables of modules available for import
|
-- - tables of modules available for import
|
||||||
class MonadFail m => MonadEvaluator term value m | m -> term, m -> value where
|
class ( MonadEnvironment value m
|
||||||
|
, MonadFail m
|
||||||
|
, MonadModuleTable term value m
|
||||||
|
, MonadStore value m
|
||||||
|
)
|
||||||
|
=> MonadEvaluator term value m | m -> term, m -> value where
|
||||||
|
-- | Get the current 'Configuration' with a passed-in term.
|
||||||
|
getConfiguration :: Ord (LocationFor value) => term -> m (ConfigurationFor term value)
|
||||||
|
|
||||||
|
-- | A 'Monad' abstracting local and global environments.
|
||||||
|
class Monad m => MonadEnvironment value m | m -> value where
|
||||||
-- | Retrieve the global environment.
|
-- | Retrieve the global environment.
|
||||||
getGlobalEnv :: m (EnvironmentFor value)
|
getGlobalEnv :: m (EnvironmentFor value)
|
||||||
-- | Set the global environment
|
-- | Set the global environment
|
||||||
@ -35,33 +56,51 @@ class MonadFail m => MonadEvaluator term value m | m -> term, m -> value where
|
|||||||
-- | Run an action with a locally-modified environment.
|
-- | Run an action with a locally-modified environment.
|
||||||
localEnv :: (EnvironmentFor value -> EnvironmentFor value) -> m a -> m a
|
localEnv :: (EnvironmentFor value -> EnvironmentFor value) -> m a -> m a
|
||||||
|
|
||||||
|
-- | Update the global environment.
|
||||||
|
modifyGlobalEnv :: MonadEvaluator term value m => (EnvironmentFor value -> EnvironmentFor value) -> m ()
|
||||||
|
modifyGlobalEnv f = do
|
||||||
|
env <- getGlobalEnv
|
||||||
|
putGlobalEnv $! f env
|
||||||
|
|
||||||
|
|
||||||
|
-- | A 'Monad' abstracting a heap of values.
|
||||||
|
class Monad m => MonadStore value m | m -> value where
|
||||||
-- | Retrieve the heap.
|
-- | Retrieve the heap.
|
||||||
getStore :: m (StoreFor value)
|
getStore :: m (StoreFor value)
|
||||||
-- | Set the heap.
|
-- | Set the heap.
|
||||||
putStore :: StoreFor value -> m ()
|
putStore :: StoreFor value -> m ()
|
||||||
|
|
||||||
|
-- | Update the heap.
|
||||||
|
modifyStore :: MonadStore value m => (StoreFor value -> StoreFor value) -> m ()
|
||||||
|
modifyStore f = do
|
||||||
|
s <- getStore
|
||||||
|
putStore $! f s
|
||||||
|
|
||||||
|
-- | Write a value to the given 'Address' in the 'Store'.
|
||||||
|
assign :: ( Ord (LocationFor value)
|
||||||
|
, MonadStore value m
|
||||||
|
, Reducer value (CellFor value)
|
||||||
|
)
|
||||||
|
=> Address (LocationFor value) value
|
||||||
|
-> value
|
||||||
|
-> m ()
|
||||||
|
assign address = modifyStore . storeInsert address
|
||||||
|
|
||||||
|
|
||||||
|
-- | A 'Monad' abstracting tables of modules available for import.
|
||||||
|
class Monad m => MonadModuleTable term value m | m -> term, m -> value where
|
||||||
-- | Retrieve the table of evaluated modules.
|
-- | Retrieve the table of evaluated modules.
|
||||||
getModuleTable :: m (ModuleTable (EnvironmentFor value))
|
getModuleTable :: m (ModuleTable (EnvironmentFor value))
|
||||||
-- | Update the table of evaluated modules.
|
-- | Set the table of evaluated modules.
|
||||||
modifyModuleTable :: (ModuleTable (EnvironmentFor value) -> ModuleTable (EnvironmentFor value)) -> m ()
|
putModuleTable :: ModuleTable (EnvironmentFor value) -> m ()
|
||||||
|
|
||||||
-- | Retrieve the table of unevaluated modules.
|
-- | Retrieve the table of unevaluated modules.
|
||||||
askModuleTable :: m (ModuleTable term)
|
askModuleTable :: m (ModuleTable term)
|
||||||
-- | Run an action with a locally-modified table of unevaluated modules.
|
-- | Run an action with a locally-modified table of unevaluated modules.
|
||||||
localModuleTable :: (ModuleTable term -> ModuleTable term) -> m a -> m a
|
localModuleTable :: (ModuleTable term -> ModuleTable term) -> m a -> m a
|
||||||
|
|
||||||
-- | Retrieve the current root set.
|
-- | Update the evaluated module table.
|
||||||
askRoots :: Ord (LocationFor value) => m (Live (LocationFor value) value)
|
modifyModuleTable :: MonadModuleTable term value m => (ModuleTable (EnvironmentFor value) -> ModuleTable (EnvironmentFor value)) -> m ()
|
||||||
askRoots = pure mempty
|
modifyModuleTable f = do
|
||||||
|
table <- getModuleTable
|
||||||
-- | Get the current 'Configuration' with a passed-in term.
|
putModuleTable $! f table
|
||||||
getConfiguration :: Ord (LocationFor value) => term -> m (Configuration (LocationFor value) term value)
|
|
||||||
getConfiguration term = Configuration term <$> askRoots <*> askLocalEnv <*> getStore
|
|
||||||
|
|
||||||
-- | Update the global environment.
|
|
||||||
modifyGlobalEnv :: MonadEvaluator term value m => (EnvironmentFor value -> EnvironmentFor value) -> m ()
|
|
||||||
modifyGlobalEnv f = getGlobalEnv >>= putGlobalEnv . f
|
|
||||||
|
|
||||||
-- | Update the heap.
|
|
||||||
modifyStore :: MonadEvaluator term value m => (StoreFor value -> StoreFor value) -> m ()
|
|
||||||
modifyStore f = getStore >>= putStore . f
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{-# LANGUAGE MultiParamTypeClasses, UndecidableInstances, TypeApplications #-}
|
{-# LANGUAGE MultiParamTypeClasses, Rank2Types, TypeFamilies, TypeOperators, UndecidableInstances #-}
|
||||||
module Control.Abstract.Value where
|
module Control.Abstract.Value where
|
||||||
|
|
||||||
import Control.Abstract.Addressable
|
import Control.Abstract.Addressable
|
||||||
@ -7,8 +7,8 @@ import Data.Abstract.Environment
|
|||||||
import Data.Abstract.FreeVariables
|
import Data.Abstract.FreeVariables
|
||||||
import Data.Abstract.Type as Type
|
import Data.Abstract.Type as Type
|
||||||
import Data.Abstract.Value as Value
|
import Data.Abstract.Value as Value
|
||||||
import Data.Scientific (Scientific)
|
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
|
import Data.Scientific (Scientific, fromFloatDigits, toRealFloat)
|
||||||
import Prelude hiding (fail)
|
import Prelude hiding (fail)
|
||||||
import Prologue
|
import Prologue
|
||||||
|
|
||||||
@ -23,6 +23,18 @@ class (MonadAnalysis term value m, Show value) => MonadValue term value m where
|
|||||||
-- | Construct an abstract integral value.
|
-- | Construct an abstract integral value.
|
||||||
integer :: Prelude.Integer -> m value
|
integer :: Prelude.Integer -> m value
|
||||||
|
|
||||||
|
-- | Lift a unary operator over a 'Num' to a function on 'value's.
|
||||||
|
liftNumeric :: (forall a . Num a => a -> a)
|
||||||
|
-> (value -> m value)
|
||||||
|
|
||||||
|
-- | Lift a pair of binary operators to a function on 'value's.
|
||||||
|
-- You usually pass the same operator as both arguments, except in the cases where
|
||||||
|
-- Haskell provides different functions for integral and fractional operations, such
|
||||||
|
-- as division, exponentiation, and modulus.
|
||||||
|
liftNumeric2 :: (forall a . (Real a, Floating a) => a -> a -> a)
|
||||||
|
-> (forall b . Integral b => b -> b -> b)
|
||||||
|
-> (value -> value -> m value)
|
||||||
|
|
||||||
-- | Construct an abstract boolean value.
|
-- | Construct an abstract boolean value.
|
||||||
boolean :: Bool -> m value
|
boolean :: Bool -> m value
|
||||||
|
|
||||||
@ -39,7 +51,7 @@ class (MonadAnalysis term value m, Show value) => MonadValue term value m where
|
|||||||
interface :: value -> m value
|
interface :: value -> m value
|
||||||
|
|
||||||
-- | Eliminate boolean values. TODO: s/boolean/truthy
|
-- | Eliminate boolean values. TODO: s/boolean/truthy
|
||||||
ifthenelse :: value -> m value -> m value -> m value
|
ifthenelse :: value -> m a -> m a -> m a
|
||||||
|
|
||||||
-- | Evaluate an abstraction (a binder like a lambda or method definition).
|
-- | Evaluate an abstraction (a binder like a lambda or method definition).
|
||||||
abstract :: [Name] -> Subterm term (m value) -> m value
|
abstract :: [Name] -> Subterm term (m value) -> m value
|
||||||
@ -49,6 +61,10 @@ class (MonadAnalysis term value m, Show value) => MonadValue term value m where
|
|||||||
-- | Extract the environment from an interface value.
|
-- | Extract the environment from an interface value.
|
||||||
environment :: value -> m (EnvironmentFor value)
|
environment :: value -> m (EnvironmentFor value)
|
||||||
|
|
||||||
|
-- | Attempt to extract a 'Prelude.Bool' from a given value.
|
||||||
|
toBool :: MonadValue term value m => value -> m Bool
|
||||||
|
toBool v = ifthenelse v (pure True) (pure False)
|
||||||
|
|
||||||
-- | Construct a 'Value' wrapping the value arguments (if any).
|
-- | Construct a 'Value' wrapping the value arguments (if any).
|
||||||
instance ( MonadAddressable location (Value location term) m
|
instance ( MonadAddressable location (Value location term) m
|
||||||
, MonadAnalysis term (Value location term) m
|
, MonadAnalysis term (Value location term) m
|
||||||
@ -78,6 +94,26 @@ instance ( MonadAddressable location (Value location term) m
|
|||||||
| Just (Boolean b) <- prjValue cond = if b then if' else else'
|
| Just (Boolean b) <- prjValue cond = if b then if' else else'
|
||||||
| otherwise = fail ("not defined for non-boolean conditions: " <> show cond)
|
| otherwise = fail ("not defined for non-boolean conditions: " <> show cond)
|
||||||
|
|
||||||
|
liftNumeric f arg
|
||||||
|
| Just (Integer i) <- prjValue arg = pure . injValue . Integer $ f i
|
||||||
|
| Just (Value.Float i) <- prjValue arg = pure . injValue . Value.Float $ f i
|
||||||
|
| otherwise = fail ("Invalid operand to liftNumeric: " <> show arg)
|
||||||
|
|
||||||
|
liftNumeric2 f g left right
|
||||||
|
| Just (Integer i, Integer j) <- prjPair pair = pure . injValue . Integer $ g i j
|
||||||
|
| Just (Integer i, Value.Float j) <- prjPair pair = pure . injValue . float $ f (fromIntegral i) (munge j)
|
||||||
|
| Just (Value.Float i, Value.Float j) <- prjPair pair = pure . injValue . float $ f (munge i) (munge j)
|
||||||
|
| Just (Value.Float i, Integer j) <- prjPair pair = pure . injValue . float $ f (munge i) (fromIntegral j)
|
||||||
|
| otherwise = fail ("Invalid operands to liftNumeric2: " <> show pair)
|
||||||
|
where
|
||||||
|
-- Yucky hack to work around the lack of a Floating instance for Scientific.
|
||||||
|
-- This may possibly lose precision, but there's little we can do about that.
|
||||||
|
munge :: Scientific -> Double
|
||||||
|
munge = toRealFloat
|
||||||
|
float :: Double -> Value.Float a
|
||||||
|
float = Value.Float . fromFloatDigits
|
||||||
|
pair = (left, right)
|
||||||
|
|
||||||
abstract names (Subterm body _) = injValue . Closure names body <$> askLocalEnv
|
abstract names (Subterm body _) = injValue . Closure names body <$> askLocalEnv
|
||||||
|
|
||||||
apply op params = do
|
apply op params = do
|
||||||
@ -116,6 +152,16 @@ instance (Alternative m, MonadAnalysis term Type m, MonadFresh m) => MonadValue
|
|||||||
|
|
||||||
ifthenelse cond if' else' = unify cond Bool *> (if' <|> else')
|
ifthenelse cond if' else' = unify cond Bool *> (if' <|> else')
|
||||||
|
|
||||||
|
liftNumeric _ Type.Float = pure Type.Float
|
||||||
|
liftNumeric _ Int = pure Int
|
||||||
|
liftNumeric _ _ = fail "Invalid type in unary numeric operation"
|
||||||
|
|
||||||
|
liftNumeric2 _ _ left right = case (left, right) of
|
||||||
|
(Type.Float, Int) -> pure Type.Float
|
||||||
|
(Int, Type.Float) -> pure Type.Float
|
||||||
|
_ -> unify left right
|
||||||
|
|
||||||
|
|
||||||
apply op params = do
|
apply op params = do
|
||||||
tvar <- fresh
|
tvar <- fresh
|
||||||
paramTypes <- traverse subtermValue params
|
paramTypes <- traverse subtermValue params
|
||||||
|
@ -37,6 +37,13 @@ injValue = Value . inj
|
|||||||
prjValue :: (f :< ValueConstructors location term) => Value location term -> Maybe (f (Value location term))
|
prjValue :: (f :< ValueConstructors location term) => Value location term -> Maybe (f (Value location term))
|
||||||
prjValue = prj . deValue
|
prjValue = prj . deValue
|
||||||
|
|
||||||
|
-- | Convenience function for projecting two values.
|
||||||
|
prjPair :: ( f :< ValueConstructors loc term1 , g :< ValueConstructors loc term2)
|
||||||
|
=> (Value loc term1, Value loc term2)
|
||||||
|
-> Maybe (f (Value loc term1), g (Value loc term2))
|
||||||
|
prjPair = bitraverse prjValue prjValue
|
||||||
|
|
||||||
|
|
||||||
-- TODO: Parameterize Value by the set of constructors s.t. each language can have a distinct value union.
|
-- TODO: Parameterize Value by the set of constructors s.t. each language can have a distinct value union.
|
||||||
|
|
||||||
-- | A function value consisting of a list of parameters, the body of the function, and an environment of bindings captured by the body.
|
-- | A function value consisting of a list of parameters, the body of the function, and an environment of bindings captured by the body.
|
||||||
|
@ -2,7 +2,9 @@
|
|||||||
module Data.Syntax.Expression where
|
module Data.Syntax.Expression where
|
||||||
|
|
||||||
import Data.Abstract.Evaluatable
|
import Data.Abstract.Evaluatable
|
||||||
|
import Data.Fixed
|
||||||
import Diffing.Algorithm
|
import Diffing.Algorithm
|
||||||
|
import Prelude hiding (fail)
|
||||||
import Prologue hiding (apply)
|
import Prologue hiding (apply)
|
||||||
|
|
||||||
-- | Typical prefix function application, like `f(x)` in many languages, or `f x` in Haskell.
|
-- | Typical prefix function application, like `f(x)` in many languages, or `f x` in Haskell.
|
||||||
@ -51,8 +53,15 @@ instance Ord1 Arithmetic where liftCompare = genericLiftCompare
|
|||||||
instance Show1 Arithmetic where liftShowsPrec = genericLiftShowsPrec
|
instance Show1 Arithmetic where liftShowsPrec = genericLiftShowsPrec
|
||||||
|
|
||||||
-- TODO: Implement Eval instance for Arithmetic
|
-- TODO: Implement Eval instance for Arithmetic
|
||||||
instance Evaluatable Arithmetic
|
instance Evaluatable Arithmetic where
|
||||||
|
eval = traverse subtermValue >=> go where
|
||||||
|
go (Plus a b) = liftNumeric2 (+) (+) a b
|
||||||
|
go (Minus a b) = liftNumeric2 (-) (-) a b
|
||||||
|
go (Times a b) = liftNumeric2 (*) (*) a b
|
||||||
|
go (DividedBy a b) = liftNumeric2 (/) div a b
|
||||||
|
go (Modulo a b) = liftNumeric2 mod' mod a b
|
||||||
|
go (Power a b) = liftNumeric2 (**) (^) a b
|
||||||
|
go (Negate a) = liftNumeric negate a
|
||||||
|
|
||||||
-- | Boolean operators.
|
-- | Boolean operators.
|
||||||
data Boolean a
|
data Boolean a
|
||||||
@ -66,9 +75,17 @@ instance Eq1 Boolean where liftEq = genericLiftEq
|
|||||||
instance Ord1 Boolean where liftCompare = genericLiftCompare
|
instance Ord1 Boolean where liftCompare = genericLiftCompare
|
||||||
instance Show1 Boolean where liftShowsPrec = genericLiftShowsPrec
|
instance Show1 Boolean where liftShowsPrec = genericLiftShowsPrec
|
||||||
|
|
||||||
-- TODO: Implement Eval instance for Boolean
|
instance Evaluatable Boolean where
|
||||||
instance Evaluatable Boolean
|
-- N.B. we have to use Monad rather than Applicative/Traversable on 'And' and 'Or' so that we don't evaluate both operands
|
||||||
|
eval = go . fmap subtermValue where
|
||||||
|
go (And a b) = do
|
||||||
|
cond <- a
|
||||||
|
ifthenelse cond b (pure cond)
|
||||||
|
go (Or a b) = do
|
||||||
|
cond <- a
|
||||||
|
ifthenelse cond (pure cond) b
|
||||||
|
go (Not a) = a >>= toBool >>= boolean . not
|
||||||
|
go (XOr a b) = liftA2 (/=) (a >>= toBool) (b >>= toBool) >>= boolean
|
||||||
|
|
||||||
-- | Javascript delete operator
|
-- | Javascript delete operator
|
||||||
newtype Delete a = Delete a
|
newtype Delete a = Delete a
|
||||||
|
Loading…
Reference in New Issue
Block a user