Skip to content
This repository was archived by the owner on Apr 1, 2025. It is now read-only.

Commit 4296244

Browse files
committed
Merge branch 'generalize-analyses-over-the-term-type' into scope-graphs
1 parent 99a4f8e commit 4296244

12 files changed

Lines changed: 245 additions & 169 deletions

File tree

semantic-core/semantic-core.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ test-suite spec
8484
other-modules: Generators
8585
build-depends: base
8686
, semantic-core
87+
, fused-effects
8788
, hedgehog ^>= 1
8889
, tasty >= 1.2 && <2
8990
, tasty-hedgehog ^>= 1.0.0.1

semantic-core/src/Analysis/Concrete.hs

Lines changed: 49 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{-# LANGUAGE DerivingVia, FlexibleContexts, FlexibleInstances, LambdaCase, MultiParamTypeClasses, NamedFieldPuns, OverloadedStrings, RecordWildCards, TypeOperators, UndecidableInstances #-}
1+
{-# LANGUAGE DerivingVia, FlexibleContexts, FlexibleInstances, LambdaCase, MultiParamTypeClasses, NamedFieldPuns, OverloadedStrings, RankNTypes, RecordWildCards, TypeOperators, UndecidableInstances #-}
22
module Analysis.Concrete
33
( Concrete(..)
44
, concrete
@@ -20,7 +20,6 @@ import Control.Effect.NonDet
2020
import Control.Effect.Reader hiding (Local)
2121
import Control.Effect.State
2222
import Control.Monad ((<=<), guard)
23-
import qualified Data.Core as Core
2423
import Data.File
2524
import Data.Function (fix)
2625
import qualified Data.IntMap as IntMap
@@ -30,7 +29,6 @@ import qualified Data.Map as Map
3029
import Data.Name
3130
import Data.Semigroup (Last (..))
3231
import qualified Data.Set as Set
33-
import Data.Term
3432
import Data.Text (Text, pack)
3533
import Data.Traversable (for)
3634
import Prelude hiding (fail)
@@ -41,16 +39,16 @@ type Env = Map.Map User Precise
4139
newtype FrameId = FrameId { unFrameId :: Precise }
4240
deriving (Eq, Ord, Show)
4341

44-
data Concrete
45-
= Closure Loc User (Term Core.Core User) Env
42+
data Concrete term
43+
= Closure Loc User term Env
4644
| Unit
4745
| Bool Bool
4846
| String Text
4947
| Record Env
5048
deriving (Eq, Ord, Show)
51-
deriving Semigroup via Last Concrete
49+
deriving Semigroup via Last (Concrete term)
5250

53-
recordFrame :: Concrete -> Maybe Env
51+
recordFrame :: Concrete term -> Maybe Env
5452
recordFrame (Record frame) = Just frame
5553
recordFrame _ = Nothing
5654

@@ -59,44 +57,64 @@ newtype Frame = Frame
5957
}
6058
deriving (Eq, Ord, Show)
6159

62-
type Heap = IntMap.IntMap Concrete
60+
type Heap term = IntMap.IntMap (Concrete term)
6361

6462
data Edge = Lexical | Import
6563
deriving (Eq, Ord, Show)
6664

6765

6866
-- | Concrete evaluation of a term to a value.
6967
--
70-
-- >>> map fileBody (snd (concrete [File (Loc "bool" emptySpan) (Core.bool True)]))
68+
-- >>> map fileBody (snd (concrete eval [File (Loc "bool" emptySpan) (Core.bool True)]))
7169
-- [Right (Bool True)]
72-
concrete :: [File (Term Core.Core User)] -> (Heap, [File (Either (Loc, String) Concrete)])
7370
concrete
71+
:: (Foldable term, Show (term User))
72+
=> (forall sig m
73+
. (Carrier sig m, Member (Reader Loc) sig, MonadFail m)
74+
=> Analysis (term User) Precise (Concrete (term User)) m
75+
-> (term User -> m (Concrete (term User)))
76+
-> (term User -> m (Concrete (term User)))
77+
)
78+
-> [File (term User)]
79+
-> (Heap (term User), [File (Either (Loc, String) (Concrete (term User)))])
80+
concrete eval
7481
= run
7582
. runFresh
7683
. runHeap
77-
. traverse runFile
78-
79-
runFile :: ( Carrier sig m
80-
, Effect sig
81-
, Member Fresh sig
82-
, Member (State Heap) sig
83-
)
84-
=> File (Term Core.Core User)
85-
-> m (File (Either (Loc, String) Concrete))
86-
runFile file = traverse run file
84+
. traverse (runFile eval)
85+
86+
runFile
87+
:: ( Carrier sig m
88+
, Effect sig
89+
, Foldable term
90+
, Member Fresh sig
91+
, Member (State (Heap (term User))) sig
92+
, Show (term User)
93+
)
94+
=> (forall sig m
95+
. (Carrier sig m, Member (Reader Loc) sig, MonadFail m)
96+
=> Analysis (term User) Precise (Concrete (term User)) m
97+
-> (term User -> m (Concrete (term User)))
98+
-> (term User -> m (Concrete (term User)))
99+
)
100+
-> File (term User)
101+
-> m (File (Either (Loc, String) (Concrete (term User))))
102+
runFile eval file = traverse run file
87103
where run = runReader (fileLoc file)
88104
. runFailWithLoc
89105
. runReader (mempty :: Env)
90106
. fix (eval concreteAnalysis)
91107

92108
concreteAnalysis :: ( Carrier sig m
109+
, Foldable term
93110
, Member Fresh sig
94111
, Member (Reader Env) sig
95112
, Member (Reader Loc) sig
96-
, Member (State Heap) sig
113+
, Member (State (Heap (term User))) sig
97114
, MonadFail m
115+
, Show (term User)
98116
)
99-
=> Analysis Precise Concrete m
117+
=> Analysis (term User) Precise (Concrete (term User)) m
100118
concreteAnalysis = Analysis{..}
101119
where alloc _ = fresh
102120
bind name addr m = local (Map.insert name addr) m
@@ -132,7 +150,7 @@ concreteAnalysis = Analysis{..}
132150
pure (val >>= lookupConcrete heap n)
133151

134152

135-
lookupConcrete :: Heap -> User -> Concrete -> Maybe Precise
153+
lookupConcrete :: Heap term -> User -> Concrete term -> Maybe Precise
136154
lookupConcrete heap name = run . evalState IntSet.empty . runNonDet . inConcrete
137155
where -- look up the name in a concrete value
138156
inConcrete = inFrame <=< maybeA . recordFrame
@@ -149,7 +167,7 @@ lookupConcrete heap name = run . evalState IntSet.empty . runNonDet . inConcrete
149167
maybeA = maybe empty pure
150168

151169

152-
runHeap :: StateC Heap m a -> m (Heap, a)
170+
runHeap :: StateC (Heap term) m a -> m (Heap term, a)
153171
runHeap = runState mempty
154172

155173

@@ -158,7 +176,7 @@ runHeap = runState mempty
158176
-- > λ let (heap, res) = concrete [ruby]
159177
-- > λ writeFile "/Users/rob/Desktop/heap.dot" (export (addressStyle heap) (heapAddressGraph heap))
160178
-- > λ :!dot -Tsvg < ~/Desktop/heap.dot > ~/Desktop/heap.svg
161-
heapGraph :: (Precise -> Concrete -> a) -> (Either Edge User -> Precise -> G.Graph a) -> Heap -> G.Graph a
179+
heapGraph :: (Precise -> Concrete term -> a) -> (Either Edge User -> Precise -> G.Graph a) -> Heap term -> G.Graph a
162180
heapGraph vertex edge h = foldr (uncurry graph) G.empty (IntMap.toList h)
163181
where graph k v rest = (G.vertex (vertex k v) `G.connect` outgoing v) `G.overlay` rest
164182
outgoing = \case
@@ -168,14 +186,14 @@ heapGraph vertex edge h = foldr (uncurry graph) G.empty (IntMap.toList h)
168186
Closure _ _ _ env -> foldr (G.overlay . edge (Left Lexical)) G.empty env
169187
Record frame -> foldr (G.overlay . uncurry (edge . Right)) G.empty (Map.toList frame)
170188

171-
heapValueGraph :: Heap -> G.Graph Concrete
189+
heapValueGraph :: Heap term -> G.Graph (Concrete term)
172190
heapValueGraph h = heapGraph (const id) (const fromAddr) h
173191
where fromAddr addr = maybe G.empty G.vertex (IntMap.lookup addr h)
174192

175-
heapAddressGraph :: Heap -> G.Graph (EdgeType, Precise)
193+
heapAddressGraph :: Heap term -> G.Graph (EdgeType term, Precise)
176194
heapAddressGraph = heapGraph (\ addr v -> (Value v, addr)) (fmap G.vertex . (,) . either Edge Slot)
177195

178-
addressStyle :: Heap -> G.Style (EdgeType, Precise) Text
196+
addressStyle :: Heap term -> G.Style (EdgeType term, Precise) Text
179197
addressStyle heap = (G.defaultStyle vertex) { G.edgeAttributes }
180198
where vertex (_, addr) = pack (show addr) <> " = " <> maybe "?" fromConcrete (IntMap.lookup addr heap)
181199
edgeAttributes _ (Slot name, _) = ["label" G.:= name]
@@ -190,12 +208,13 @@ addressStyle heap = (G.defaultStyle vertex) { G.edgeAttributes }
190208
Record _ -> "{}"
191209
showPos (Pos l c) = pack (show l) <> ":" <> pack (show c)
192210

193-
data EdgeType
211+
data EdgeType term
194212
= Edge Edge
195213
| Slot User
196-
| Value Concrete
214+
| Value (Concrete term)
197215
deriving (Eq, Ord, Show)
198216

199217

200218
-- $setup
201219
-- >>> :seti -XOverloadedStrings
220+
-- >>> import qualified Data.Core as Core

semantic-core/src/Analysis/Eval.hs

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{-# LANGUAGE FlexibleContexts, LambdaCase, OverloadedStrings, RankNTypes, RecordWildCards #-}
1+
{-# LANGUAGE FlexibleContexts, LambdaCase, OverloadedStrings, RankNTypes, RecordWildCards, TypeOperators #-}
22
module Analysis.Eval
33
( eval
44
, prog1
@@ -12,6 +12,7 @@ module Analysis.Eval
1212
) where
1313

1414
import Control.Applicative (Alternative (..))
15+
import Control.Effect.Carrier
1516
import Control.Effect.Fail
1617
import Control.Effect.Reader
1718
import Control.Monad ((>=>))
@@ -32,12 +33,12 @@ eval :: ( Carrier sig m
3233
, MonadFail m
3334
, Semigroup value
3435
)
35-
=> Analysis address value m
36-
-> (Term Core User -> m value)
37-
-> (Term Core User -> m value)
36+
=> Analysis (Term (Ann :+: Core) User) address value m
37+
-> (Term (Ann :+: Core) User -> m value)
38+
-> (Term (Ann :+: Core) User -> m value)
3839
eval Analysis{..} eval = \case
3940
Var n -> lookupEnv' n >>= deref' n
40-
Term c -> case c of
41+
Term (R c) -> case c of
4142
Rec (Named (Ignored n) b) -> do
4243
addr <- alloc n
4344
v <- bind n addr (eval (instantiate1 (pure n) b))
@@ -68,7 +69,7 @@ eval Analysis{..} eval = \case
6869
b' <- eval b
6970
addr <- ref a
7071
b' <$ assign addr b'
71-
Ann loc c -> local (const loc) (eval c)
72+
Term (L (Ann loc c)) -> local (const loc) (eval c)
7273
where freeVariable s = fail ("free variable: " <> s)
7374
uninitialized s = fail ("uninitialized variable: " <> s)
7475
invalidRef s = fail ("invalid ref: " <> s)
@@ -78,41 +79,41 @@ eval Analysis{..} eval = \case
7879

7980
ref = \case
8081
Var n -> lookupEnv' n
81-
Term c -> case c of
82+
Term (R c) -> case c of
8283
If c t e -> do
8384
c' <- eval c >>= asBool
8485
if c' then ref t else ref e
8586
a :. b -> do
8687
a' <- ref a
8788
a' ... b >>= maybe (freeVariable (show b)) pure
88-
Ann loc c -> local (const loc) (ref c)
8989
c -> invalidRef (show c)
90+
Term (L (Ann loc c)) -> local (const loc) (ref c)
9091

9192

92-
prog1 :: File (Term Core User)
93+
prog1 :: (Carrier sig t, Member Core sig) => File (t User)
9394
prog1 = fromBody $ lam (named' "foo")
9495
( named' "bar" :<- pure "foo"
9596
>>>= Core.if' (pure "bar")
9697
(Core.bool False)
9798
(Core.bool True))
9899

99-
prog2 :: File (Term Core User)
100+
prog2 :: (Carrier sig t, Member Core sig) => File (t User)
100101
prog2 = fromBody $ fileBody prog1 $$ Core.bool True
101102

102-
prog3 :: File (Term Core User)
103+
prog3 :: (Carrier sig t, Member Core sig) => File (t User)
103104
prog3 = fromBody $ lams [named' "foo", named' "bar", named' "quux"]
104105
(Core.if' (pure "quux")
105106
(pure "bar")
106107
(pure "foo"))
107108

108-
prog4 :: File (Term Core User)
109+
prog4 :: (Carrier sig t, Member Core sig) => File (t User)
109110
prog4 = fromBody
110111
( named' "foo" :<- Core.bool True
111112
>>>= Core.if' (pure "foo")
112113
(Core.bool True)
113114
(Core.bool False))
114115

115-
prog5 :: File (Term Core User)
116+
prog5 :: (Carrier sig t, Member Ann sig, Member Core sig) => File (t User)
116117
prog5 = fromBody $ ann (do'
117118
[ Just (named' "mkPoint") :<- lams [named' "_x", named' "_y"] (ann (Core.record
118119
[ ("x", ann (pure "_x"))
@@ -123,7 +124,7 @@ prog5 = fromBody $ ann (do'
123124
, Nothing :<- ann (ann (pure "point") Core.... "y") .= ann (ann (pure "point") Core.... "x")
124125
])
125126

126-
prog6 :: [File (Term Core User)]
127+
prog6 :: (Carrier sig t, Member Core sig) => [File (t User)]
127128
prog6 =
128129
[ File (Loc "dep" (locSpan (fromJust here))) $ Core.record
129130
[ ("dep", Core.record [ ("var", Core.bool True) ]) ]
@@ -133,7 +134,7 @@ prog6 =
133134
])
134135
]
135136

136-
ruby :: File (Term Core User)
137+
ruby :: (Carrier sig t, Member Ann sig, Member Core sig) => File (t User)
137138
ruby = fromBody $ annWith callStack (rec (named' __semantic_global) (do' statements))
138139
where statements =
139140
[ Just "Class" :<- record
@@ -210,14 +211,14 @@ ruby = fromBody $ annWith callStack (rec (named' __semantic_global) (do' stateme
210211
__semantic_truthy = "__semantic_truthy"
211212

212213

213-
data Analysis address value m = Analysis
214+
data Analysis term address value m = Analysis
214215
{ alloc :: User -> m address
215216
, bind :: forall a . User -> address -> m a -> m a
216217
, lookupEnv :: User -> m (Maybe address)
217218
, deref :: address -> m (Maybe value)
218219
, assign :: address -> value -> m ()
219-
, abstract :: (Term Core User -> m value) -> User -> Term Core User -> m value
220-
, apply :: (Term Core User -> m value) -> value -> value -> m value
220+
, abstract :: (term -> m value) -> User -> term -> m value
221+
, apply :: (term -> m value) -> value -> value -> m value
221222
, unit :: m value
222223
, bool :: Bool -> m value
223224
, asBool :: value -> m Bool

0 commit comments

Comments
 (0)