mirror of
https://github.com/github/semantic.git
synced 2024-12-25 16:02:43 +03:00
Port over Environment, Primitive, Type, Value
This commit is contained in:
parent
f27ecb61cb
commit
d1ad4d6318
@ -15,10 +15,14 @@ library
|
|||||||
hs-source-dirs: src
|
hs-source-dirs: src
|
||||||
exposed-modules: Algorithm
|
exposed-modules: Algorithm
|
||||||
, Alignment
|
, Alignment
|
||||||
|
, Abstract.Environment
|
||||||
, Abstract.Eval
|
, Abstract.Eval
|
||||||
, Abstract.FreeVariables
|
, Abstract.FreeVariables
|
||||||
|
, Abstract.Primitive
|
||||||
, Abstract.Set
|
, Abstract.Set
|
||||||
, Abstract.Store
|
, Abstract.Store
|
||||||
|
, Abstract.Type
|
||||||
|
, Abstract.Value
|
||||||
, Control.Effect
|
, Control.Effect
|
||||||
, Category
|
, Category
|
||||||
, Data.Align.Generic
|
, Data.Align.Generic
|
||||||
|
54
src/Abstract/Environment.hs
Normal file
54
src/Abstract/Environment.hs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
{-# LANGUAGE TypeOperators, MultiParamTypeClasses, FlexibleInstances, FlexibleContexts, UndecidableInstances, DeriveFoldable, DeriveFunctor, DeriveTraversable, DeriveGeneric, GeneralizedNewtypeDeriving #-}
|
||||||
|
module Abstract.Environment where
|
||||||
|
|
||||||
|
import Abstract.Store
|
||||||
|
import Abstract.FreeVariables
|
||||||
|
import Data.Term
|
||||||
|
import Control.Monad.Effect
|
||||||
|
import Control.Monad.Effect.Reader
|
||||||
|
import Data.Functor.Classes
|
||||||
|
import Data.Functor.Classes.Show.Generic
|
||||||
|
import Data.Pointed
|
||||||
|
import Data.Semigroup
|
||||||
|
import GHC.Generics
|
||||||
|
import qualified Data.Map as Map
|
||||||
|
|
||||||
|
|
||||||
|
newtype Environment l a = Environment { unEnvironment :: Map.Map Name (Address l a) }
|
||||||
|
deriving (Eq, Foldable, Functor, Monoid, Ord, Semigroup, Show, Traversable, Generic1)
|
||||||
|
|
||||||
|
envLookup :: Name -> Environment l a -> Maybe (Address l a)
|
||||||
|
envLookup = (. unEnvironment) . Map.lookup
|
||||||
|
|
||||||
|
envInsert :: Name -> Address l a -> Environment l a -> Environment l a
|
||||||
|
envInsert name value (Environment m) = Environment (Map.insert name value m)
|
||||||
|
|
||||||
|
envRoots :: (Foldable t, Ord l) => Environment l a -> t Name -> Set (Address l a)
|
||||||
|
envRoots env = foldr ((<>) . maybe mempty point . flip envLookup env) mempty
|
||||||
|
|
||||||
|
|
||||||
|
class Monad m => MonadEnv l a m where
|
||||||
|
askEnv :: m (Environment l a)
|
||||||
|
localEnv :: (Environment l a -> Environment l a) -> m b -> m b
|
||||||
|
|
||||||
|
instance (Reader (Environment l a) :< fs) => MonadEnv l a (Eff fs) where
|
||||||
|
askEnv = ask
|
||||||
|
localEnv = local
|
||||||
|
|
||||||
|
|
||||||
|
-- Instances
|
||||||
|
|
||||||
|
instance Eq2 Environment where
|
||||||
|
liftEq2 eqL eqA (Environment m1) (Environment m2) = liftEq (liftEq2 eqL eqA) m1 m2
|
||||||
|
|
||||||
|
instance Eq l => Eq1 (Environment l) where
|
||||||
|
liftEq = liftEq2 (==)
|
||||||
|
|
||||||
|
instance Ord2 Environment where
|
||||||
|
liftCompare2 compareL compareA (Environment m1) (Environment m2) = liftCompare (liftCompare2 compareL compareA) m1 m2
|
||||||
|
|
||||||
|
instance Ord l => Ord1 (Environment l) where
|
||||||
|
liftCompare = liftCompare2 compare
|
||||||
|
|
||||||
|
instance Show l => Show1 (Environment l) where
|
||||||
|
liftShowsPrec = genericLiftShowsPrec
|
141
src/Abstract/Primitive.hs
Normal file
141
src/Abstract/Primitive.hs
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, TypeOperators, UndecidableInstances #-}
|
||||||
|
module Abstract.Primitive where
|
||||||
|
|
||||||
|
import Abstract.Type
|
||||||
|
import Control.Applicative
|
||||||
|
import Control.Monad hiding (fail)
|
||||||
|
import Control.Monad.Fail
|
||||||
|
import Prelude hiding (fail)
|
||||||
|
|
||||||
|
data Op1 = Negate | Abs | Signum | Not
|
||||||
|
deriving (Eq, Ord, Show)
|
||||||
|
|
||||||
|
data Op2 = Plus | Minus | Times | DividedBy | Quotient | Remainder | Modulus | And | Or | Eq | Lt | LtE | Gt | GtE
|
||||||
|
deriving (Eq, Ord, Show)
|
||||||
|
|
||||||
|
arithmeticOperators :: [Op2]
|
||||||
|
arithmeticOperators = [Plus, Minus, Times, DividedBy, Quotient, Remainder, Modulus]
|
||||||
|
|
||||||
|
booleanOperators :: [Op2]
|
||||||
|
booleanOperators = [And, Or]
|
||||||
|
|
||||||
|
relationOperators :: [Op2]
|
||||||
|
relationOperators = [Eq, Lt, LtE, Gt, GtE]
|
||||||
|
|
||||||
|
|
||||||
|
data Prim
|
||||||
|
= PInt {-# UNPACK #-} !Int
|
||||||
|
| PBool !Bool
|
||||||
|
deriving (Eq, Ord, Show)
|
||||||
|
|
||||||
|
class Monad m => MonadPrim a m where
|
||||||
|
delta1 :: Op1 -> a -> m a
|
||||||
|
delta2 :: Op2 -> a -> a -> m a
|
||||||
|
truthy :: a -> m Bool
|
||||||
|
|
||||||
|
|
||||||
|
divisionByZero :: MonadFail m => m a
|
||||||
|
divisionByZero = fail "division by zero"
|
||||||
|
|
||||||
|
nonNumeric :: MonadFail m => m a
|
||||||
|
nonNumeric = fail "numeric operation on non-numeric value"
|
||||||
|
|
||||||
|
nonBoolean :: MonadFail m => m a
|
||||||
|
nonBoolean = fail "boolean operation on non-boolean value"
|
||||||
|
|
||||||
|
disjointComparison :: MonadFail m => m a
|
||||||
|
disjointComparison = fail "comparison of disjoint values"
|
||||||
|
|
||||||
|
undefinedComparison :: MonadFail m => m a
|
||||||
|
undefinedComparison = fail "undefined comparison"
|
||||||
|
|
||||||
|
|
||||||
|
isZero :: (Num a, MonadPrim a m) => a -> m Bool
|
||||||
|
isZero = truthy <=< delta2 Eq 0
|
||||||
|
|
||||||
|
instance MonadFail m => MonadPrim Prim m where
|
||||||
|
delta1 o a = case (o, a) of
|
||||||
|
(Negate, PInt a) -> pure (PInt (negate a))
|
||||||
|
(Abs, PInt a) -> pure (PInt (abs a))
|
||||||
|
(Signum, PInt a) -> pure (PInt (signum a))
|
||||||
|
(Not, PBool a) -> pure (PBool (not a))
|
||||||
|
(Not, _) -> nonBoolean
|
||||||
|
_ -> nonNumeric
|
||||||
|
|
||||||
|
delta2 o (PInt a) (PInt b) = case o of
|
||||||
|
Plus -> pure (PInt (a + b))
|
||||||
|
Minus -> pure (PInt (a - b))
|
||||||
|
Times -> pure (PInt (a * b))
|
||||||
|
DividedBy -> isZero (PInt b) >>= flip when divisionByZero >> pure (PInt (a `div` b))
|
||||||
|
Quotient -> isZero (PInt b) >>= flip when divisionByZero >> pure (PInt (a `quot` b))
|
||||||
|
Remainder -> isZero (PInt b) >>= flip when divisionByZero >> pure (PInt (a `rem` b))
|
||||||
|
Modulus -> isZero (PInt b) >>= flip when divisionByZero >> pure (PInt (a `mod` b))
|
||||||
|
Eq -> pure (PBool (a == b))
|
||||||
|
Lt -> pure (PBool (a < b))
|
||||||
|
LtE -> pure (PBool (a <= b))
|
||||||
|
Gt -> pure (PBool (a > b))
|
||||||
|
GtE -> pure (PBool (a >= b))
|
||||||
|
_ -> nonBoolean
|
||||||
|
delta2 o (PBool a) (PBool b) = case o of
|
||||||
|
And -> pure (PBool (a && b))
|
||||||
|
Or -> pure (PBool (a || b))
|
||||||
|
Eq -> pure (PBool (a == b))
|
||||||
|
Lt -> pure (PBool (a < b))
|
||||||
|
LtE -> pure (PBool (a <= b))
|
||||||
|
Gt -> pure (PBool (a > b))
|
||||||
|
GtE -> pure (PBool (a >= b))
|
||||||
|
_ -> nonNumeric
|
||||||
|
delta2 _ _ _ = disjointComparison
|
||||||
|
|
||||||
|
truthy (PBool a) = pure a
|
||||||
|
truthy _ = nonBoolean
|
||||||
|
|
||||||
|
instance (MonadFail m, Alternative m) => MonadPrim Type m where
|
||||||
|
delta1 Not Bool = pure Bool
|
||||||
|
delta1 Not _ = nonBoolean
|
||||||
|
delta1 _ Int = pure Int
|
||||||
|
delta1 _ _ = nonNumeric
|
||||||
|
|
||||||
|
delta2 o a b
|
||||||
|
| o `elem` booleanOperators = case (a, b) of
|
||||||
|
(Bool, Bool) -> pure Bool
|
||||||
|
(TVar _, Bool) -> pure Bool
|
||||||
|
(Bool, TVar _) -> pure Bool
|
||||||
|
(TVar _, TVar _) -> pure Bool
|
||||||
|
_ -> nonBoolean
|
||||||
|
| o `elem` relationOperators = case (a, b) of
|
||||||
|
_ | a == b -> pure Bool
|
||||||
|
(TVar _, _) -> pure Bool
|
||||||
|
(_, TVar _) -> pure Bool
|
||||||
|
_ -> disjointComparison
|
||||||
|
| o `elem` arithmeticOperators = case (a, b) of
|
||||||
|
(Int, Int) -> pure Int
|
||||||
|
(TVar _, Int) -> pure Int
|
||||||
|
(Int, TVar _) -> pure Int
|
||||||
|
(TVar _, TVar _) -> pure Int
|
||||||
|
_ -> nonNumeric
|
||||||
|
delta2 DividedBy Int Int = pure Int <|> divisionByZero
|
||||||
|
delta2 Quotient Int Int = pure Int <|> divisionByZero
|
||||||
|
delta2 Remainder Int Int = pure Int <|> divisionByZero
|
||||||
|
delta2 Modulus Int Int = pure Int <|> divisionByZero
|
||||||
|
delta2 _ _ _ = nonNumeric
|
||||||
|
|
||||||
|
truthy Bool = pure True <|> pure False
|
||||||
|
truthy (TVar _) = pure True <|> pure False
|
||||||
|
truthy _ = nonBoolean
|
||||||
|
|
||||||
|
|
||||||
|
instance Num Prim where
|
||||||
|
fromInteger = PInt . fromInteger
|
||||||
|
|
||||||
|
negate (PInt a) = PInt (negate a)
|
||||||
|
negate _ = error "negate of non-integer"
|
||||||
|
abs (PInt a) = PInt (abs a)
|
||||||
|
abs _ = error "abs of non-integer"
|
||||||
|
signum (PInt a) = PInt (signum a)
|
||||||
|
signum _ = error "signum of non-integer"
|
||||||
|
|
||||||
|
PInt a + PInt b = PInt (a + b)
|
||||||
|
_ + _ = error "(+) of non-integer"
|
||||||
|
PInt a * PInt b = PInt (a * b)
|
||||||
|
_ * _ = error "(*) of non-integer"
|
41
src/Abstract/Type.hs
Normal file
41
src/Abstract/Type.hs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{-# LANGUAGE FlexibleContexts, FlexibleInstances, GADTs, MultiParamTypeClasses, TypeOperators, UndecidableInstances #-}
|
||||||
|
module Abstract.Type where
|
||||||
|
|
||||||
|
import Control.Effect
|
||||||
|
import Control.Monad.Effect.Internal
|
||||||
|
import Control.Monad.Fail
|
||||||
|
import Prelude hiding (fail)
|
||||||
|
|
||||||
|
type TName = Int
|
||||||
|
|
||||||
|
data Type = Int | Bool | Type :-> Type | Type :* Type | TVar TName
|
||||||
|
deriving (Eq, Ord, Show)
|
||||||
|
|
||||||
|
|
||||||
|
unify :: MonadFail m => Type -> Type -> m Type
|
||||||
|
unify Int Int = pure Int
|
||||||
|
unify Bool Bool = pure Bool
|
||||||
|
unify (a1 :-> b1) (a2 :-> b2) = (:->) <$> unify a1 a2 <*> unify b1 b2
|
||||||
|
unify (a1 :* b1) (a2 :* b2) = (:*) <$> unify a1 a2 <*> unify b1 b2
|
||||||
|
unify (TVar _) b = pure b
|
||||||
|
unify a (TVar _) = pure a
|
||||||
|
unify t1 t2 = fail ("cannot unify " ++ show t1 ++ " with " ++ show t2)
|
||||||
|
|
||||||
|
|
||||||
|
data Fresh a where
|
||||||
|
Reset :: Int -> Fresh ()
|
||||||
|
Fresh :: Fresh Int
|
||||||
|
|
||||||
|
class Monad m => MonadFresh m where
|
||||||
|
fresh :: m TName
|
||||||
|
reset :: TName -> m ()
|
||||||
|
|
||||||
|
instance (Fresh :< fs) => MonadFresh (Eff fs) where
|
||||||
|
fresh = send Fresh
|
||||||
|
reset = send . Reset
|
||||||
|
|
||||||
|
|
||||||
|
instance RunEffect Fresh a where
|
||||||
|
runEffect = relayState (0 :: TName) (const pure) (\ s action k -> case action of
|
||||||
|
Fresh -> k (succ s) s
|
||||||
|
Reset s' -> k s' ())
|
80
src/Abstract/Value.hs
Normal file
80
src/Abstract/Value.hs
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
{-# LANGUAGE ConstraintKinds, FunctionalDependencies, AllowAmbiguousTypes, FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, ScopedTypeVariables, TypeOperators, UndecidableInstances #-}
|
||||||
|
module Abstract.Value where
|
||||||
|
|
||||||
|
import Abstract.Environment
|
||||||
|
import Abstract.Primitive
|
||||||
|
import Abstract.Set
|
||||||
|
import Abstract.Store
|
||||||
|
import Abstract.Type
|
||||||
|
import Abstract.FreeVariables
|
||||||
|
import Data.Term
|
||||||
|
import Control.Monad hiding (fail)
|
||||||
|
import Control.Monad.Fail
|
||||||
|
import Data.Functor.Classes
|
||||||
|
import Data.Semigroup
|
||||||
|
import Prelude hiding (fail)
|
||||||
|
|
||||||
|
|
||||||
|
data Value syntax ann l
|
||||||
|
= I Prim
|
||||||
|
| Closure Name (Term syntax ann) (Environment l (Value syntax ann l))
|
||||||
|
deriving (Eq, Ord, Show)
|
||||||
|
|
||||||
|
|
||||||
|
-- Instances
|
||||||
|
|
||||||
|
instance (Eq1 syntax, Eq ann) => Eq1 (Value syntax ann) where
|
||||||
|
liftEq eqL = go
|
||||||
|
where go v1 v2 = case (v1, v2) of
|
||||||
|
(I a, I b) -> a == b
|
||||||
|
(Closure s1 t1 e1, Closure s2 t2 e2) -> s1 == s2 && t1 == t2 && liftEq2 eqL go e1 e2
|
||||||
|
_ -> False
|
||||||
|
|
||||||
|
instance (Ord1 syntax, Ord ann) => Ord1 (Value syntax ann) where
|
||||||
|
liftCompare compareL = go
|
||||||
|
where go v1 v2 = case (v1, v2) of
|
||||||
|
(I a, I b) -> compare a b
|
||||||
|
(Closure s1 t1 e1, Closure s2 t2 e2) -> compare s1 s2 <> compare t1 t2 <> liftCompare2 compareL go e1 e2
|
||||||
|
(I _, _) -> LT
|
||||||
|
_ -> GT
|
||||||
|
|
||||||
|
instance MonadFail m => MonadPrim (Value s a l) m where
|
||||||
|
delta1 o (I a) = fmap I (delta1 o a)
|
||||||
|
delta1 Not _ = nonBoolean
|
||||||
|
delta1 _ _ = nonNumeric
|
||||||
|
|
||||||
|
delta2 o (I a) (I b) = fmap I (delta2 o a b)
|
||||||
|
delta2 And _ _ = nonBoolean
|
||||||
|
delta2 Or _ _ = nonBoolean
|
||||||
|
delta2 Eq Closure{} Closure{} = undefinedComparison
|
||||||
|
delta2 Eq _ _ = disjointComparison
|
||||||
|
delta2 Lt Closure{} Closure{} = undefinedComparison
|
||||||
|
delta2 Lt _ _ = disjointComparison
|
||||||
|
delta2 LtE Closure{} Closure{} = undefinedComparison
|
||||||
|
delta2 LtE _ _ = disjointComparison
|
||||||
|
delta2 Gt Closure{} Closure{} = undefinedComparison
|
||||||
|
delta2 Gt _ _ = disjointComparison
|
||||||
|
delta2 GtE Closure{} Closure{} = undefinedComparison
|
||||||
|
delta2 GtE _ _ = disjointComparison
|
||||||
|
delta2 _ _ _ = nonNumeric
|
||||||
|
|
||||||
|
truthy (I a) = truthy a
|
||||||
|
truthy _ = nonBoolean
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class AbstractValue l v | v -> l where
|
||||||
|
literal :: Prim -> v
|
||||||
|
valueRoots :: v -> Set (Address l v)
|
||||||
|
|
||||||
|
instance (FreeVariables1 (TermF syntax ann), Functor syntax, Ord l) => AbstractValue l (Value syntax ann l) where
|
||||||
|
valueRoots (I _) = mempty
|
||||||
|
valueRoots (Closure name body env) = envRoots env (delete name (freeVariables body))
|
||||||
|
|
||||||
|
literal = I
|
||||||
|
|
||||||
|
instance AbstractValue Monovariant Type where
|
||||||
|
valueRoots _ = mempty
|
||||||
|
|
||||||
|
literal (PInt _) = Int
|
||||||
|
literal (PBool _) = Bool
|
Loading…
Reference in New Issue
Block a user