1- {-# LANGUAGE FlexibleContexts, FlexibleInstances, LambdaCase, MultiParamTypeClasses, NamedFieldPuns, OverloadedStrings, RecordWildCards, TypeOperators, UndecidableInstances #-}
1+ {-# LANGUAGE FlexibleContexts, FlexibleInstances, LambdaCase, MultiParamTypeClasses, NamedFieldPuns, OverloadedStrings, RecordWildCards, TypeApplications, TypeOperators, UndecidableInstances #-}
22module Analysis.Concrete
33( Concrete (.. )
44, concrete
@@ -27,10 +27,11 @@ import qualified Data.IntMap as IntMap
2727import qualified Data.IntSet as IntSet
2828import Data.Loc
2929import qualified Data.Map as Map
30- import Data.Monoid (Alt (.. ))
3130import Data.Name
31+ import qualified Data.Set as Set
3232import Data.Term
3333import Data.Text (Text , pack )
34+ import Data.Traversable (for )
3435import Prelude hiding (fail )
3536
3637type Precise = Int
@@ -40,25 +41,27 @@ newtype FrameId = FrameId { unFrameId :: Precise }
4041 deriving (Eq , Ord , Show )
4142
4243data Concrete
43- = Closure Loc User (Term Core. Core User ) Precise
44+ = Closure Loc User (Term Core. Core User ) Env
4445 | Unit
4546 | Bool Bool
4647 | String Text
47- | Obj Frame
48+ | Record Env
4849 deriving (Eq , Ord , Show )
4950
50- objectFrame :: Concrete -> Maybe Frame
51- objectFrame ( Obj frame) = Just frame
52- objectFrame _ = Nothing
51+ recordFrame :: Concrete -> Maybe Env
52+ recordFrame ( Record frame) = Just frame
53+ recordFrame _ = Nothing
5354
54- data Frame = Frame
55- { frameEdges :: [(Core. Edge , Precise )]
56- , frameSlots :: Env
55+ newtype Frame = Frame
56+ { frameSlots :: Env
5757 }
5858 deriving (Eq , Ord , Show )
5959
6060type Heap = IntMap. IntMap Concrete
6161
62+ data Edge = Lexical | Import
63+ deriving (Eq , Ord , Show )
64+
6265
6366-- | Concrete evaluation of a term to a value.
6467--
@@ -74,46 +77,39 @@ concrete
7477runFile :: ( Carrier sig m
7578 , Effect sig
7679 , Member Fresh sig
77- , Member (Reader FrameId ) sig
7880 , Member (State Heap ) sig
7981 )
8082 => File (Term Core. Core User )
8183 -> m (File (Either (Loc , String ) Concrete ))
8284runFile file = traverse run file
8385 where run = runReader (fileLoc file)
8486 . runFailWithLoc
87+ . runReader @ Env mempty
8588 . fix (eval concreteAnalysis)
8689
8790concreteAnalysis :: ( Carrier sig m
8891 , Member Fresh sig
92+ , Member (Reader Env ) sig
8993 , Member (Reader Loc ) sig
90- , Member (Reader FrameId ) sig
9194 , Member (State Heap ) sig
9295 , MonadFail m
9396 )
9497 => Analysis Precise Concrete m
9598concreteAnalysis = Analysis {.. }
9699 where alloc _ = fresh
97- bind name addr = modifyCurrentFrame (updateFrameSlots (Map. insert name addr))
98- lookupEnv n = do
99- FrameId frameAddr <- ask
100- val <- deref frameAddr
101- heap <- get
102- pure (val >>= lookupConcrete heap n)
100+ bind name addr m = local (Map. insert name addr) m
101+ lookupEnv n = asks (Map. lookup n)
103102 deref = gets . IntMap. lookup
104103 assign addr value = modify (IntMap. insert addr value)
105104 abstract _ name body = do
106105 loc <- ask
107- FrameId parentAddr <- ask
108- pure (Closure loc name body parentAddr)
109- apply eval (Closure loc name body parentAddr) a = do
110- frameAddr <- fresh
111- assign frameAddr (Obj (Frame [(Core. Lexical , parentAddr)] mempty ))
112- local (const loc) . (frameAddr ... ) $ do
106+ env <- asks (flip Map. restrictKeys (Set. delete name (foldMap Set. singleton body)))
107+ pure (Closure loc name body env)
108+ apply eval (Closure loc name body env) a = do
109+ local (const loc) $ do
113110 addr <- alloc name
114111 assign addr a
115- bind name addr
116- eval body
112+ local (const (Map. insert name addr env)) (eval body)
117113 apply _ f _ = fail $ " Cannot coerce " <> show f <> " to function"
118114 unit = pure Unit
119115 bool b = pure (Bool b)
@@ -122,30 +118,24 @@ concreteAnalysis = Analysis{..}
122118 string s = pure (String s)
123119 asString (String s) = pure s
124120 asString v = fail $ " Cannot coerce " <> show v <> " to String"
125- -- FIXME: differential inheritance (reference fields instead of copying)
126- -- FIXME: copy non-lexical parents deeply?
127- frame = do
128- lexical <- asks unFrameId
129- pure (Obj (Frame [(Core. Lexical , lexical)] mempty ))
130- -- FIXME: throw an error
131- -- FIXME: support dynamic imports
132- edge e addr = modifyCurrentFrame (\ (Frame ps fs) -> Frame ((e, addr) : ps) fs)
133- addr ... m = local (const (FrameId addr)) m
134-
135- updateFrameSlots f frame = frame { frameSlots = f (frameSlots frame) }
136-
137- modifyCurrentFrame f = do
138- addr <- asks unFrameId
139- Just (Obj frame) <- deref addr
140- assign addr (Obj (f frame))
121+ record fields = do
122+ fields' <- for fields $ \ (name, value) -> do
123+ addr <- alloc name
124+ assign addr value
125+ pure (name, addr)
126+ pure (Record (Map. fromList fields'))
127+ addr ... n = do
128+ val <- deref addr
129+ heap <- get
130+ pure (val >>= lookupConcrete heap n)
141131
142132
143133lookupConcrete :: Heap -> User -> Concrete -> Maybe Precise
144134lookupConcrete heap name = run . evalState IntSet. empty . runNonDet . inConcrete
145135 where -- look up the name in a concrete value
146- inConcrete = inFrame <=< maybeA . objectFrame
136+ inConcrete = inFrame <=< maybeA . recordFrame
147137 -- look up the name in a specific 'Frame', with slots taking precedence over parents
148- inFrame ( Frame ps fs) = maybeA (Map. lookup name fs) <|> getAlt ( foldMap ( Alt . inAddress . snd ) ps )
138+ inFrame fs = maybeA (Map. lookup name fs) <|> (maybeA ( Map. lookup " __semantic_super " fs) >>= inAddress )
149139 -- look up the name in the value an address points to, if we haven’t already visited it
150140 inAddress addr = do
151141 visited <- get
@@ -157,27 +147,24 @@ lookupConcrete heap name = run . evalState IntSet.empty . runNonDet . inConcrete
157147 maybeA = maybe empty pure
158148
159149
160- runHeap :: (Carrier sig m , Member Fresh sig ) => ReaderC FrameId (StateC Heap m ) a -> m (Heap , a )
161- runHeap m = do
162- addr <- fresh
163- runState (IntMap. singleton addr (Obj (Frame [] mempty ))) (runReader (FrameId addr) m)
150+ runHeap :: StateC Heap m a -> m (Heap , a )
151+ runHeap = runState mempty
164152
165153
166154-- | 'heapGraph', 'heapValueGraph', and 'heapAddressGraph' allow us to conveniently export SVGs of the heap:
167155--
168156-- > λ let (heap, res) = concrete [ruby]
169157-- > λ writeFile "/Users/rob/Desktop/heap.dot" (export (addressStyle heap) (heapAddressGraph heap))
170158-- > λ :!dot -Tsvg < ~/Desktop/heap.dot > ~/Desktop/heap.svg
171- heapGraph :: (Precise -> Concrete -> a ) -> (Either Core. Edge User -> Precise -> G. Graph a ) -> Heap -> G. Graph a
159+ heapGraph :: (Precise -> Concrete -> a ) -> (Either Edge User -> Precise -> G. Graph a ) -> Heap -> G. Graph a
172160heapGraph vertex edge h = foldr (uncurry graph) G. empty (IntMap. toList h)
173161 where graph k v rest = (G. vertex (vertex k v) `G.connect` outgoing v) `G.overlay` rest
174162 outgoing = \ case
175163 Unit -> G. empty
176164 Bool _ -> G. empty
177165 String _ -> G. empty
178- Closure _ _ _ parentAddr -> edge (Left Core. Lexical ) parentAddr
179- Obj frame -> fromFrame frame
180- fromFrame (Frame es ss) = foldr (G. overlay . uncurry (edge . Left )) (foldr (G. overlay . uncurry (edge . Right )) G. empty (Map. toList ss)) es
166+ Closure _ _ _ env -> foldr (G. overlay . edge (Left Lexical )) G. empty env
167+ Record frame -> Map. foldrWithKey (\ k -> G. overlay . edge (Right k)) G. empty frame
181168
182169heapValueGraph :: Heap -> G. Graph Concrete
183170heapValueGraph h = heapGraph (const id ) (const fromAddr) h
@@ -189,20 +176,20 @@ heapAddressGraph = heapGraph (\ addr v -> (Value v, addr)) (fmap G.vertex . (,)
189176addressStyle :: Heap -> G. Style (EdgeType , Precise ) Text
190177addressStyle heap = (G. defaultStyle vertex) { G. edgeAttributes }
191178 where vertex (_, addr) = pack (show addr) <> " = " <> maybe " ?" fromConcrete (IntMap. lookup addr heap)
192- edgeAttributes _ (Slot name, _) = [" label" G. := name]
193- edgeAttributes _ (Edge Core. Import , _) = [" color" G. := " blue" ]
194- edgeAttributes _ (Edge Core. Lexical , _) = [" color" G. := " green" ]
195- edgeAttributes _ _ = []
179+ edgeAttributes _ (Slot name, _) = [" label" G. := name]
180+ edgeAttributes _ (Edge Import , _) = [" color" G. := " blue" ]
181+ edgeAttributes _ (Edge Lexical , _) = [" color" G. := " green" ]
182+ edgeAttributes _ _ = []
196183 fromConcrete = \ case
197184 Unit -> " ()"
198185 Bool b -> pack $ show b
199186 String s -> pack $ show s
200187 Closure (Loc p (Span s e)) n _ _ -> " \\\\ " <> n <> " [" <> p <> " :" <> showPos s <> " -" <> showPos e <> " ]"
201- Obj _ -> " {}"
188+ Record _ -> " {}"
202189 showPos (Pos l c) = pack (show l) <> " :" <> pack (show c)
203190
204191data EdgeType
205- = Edge Core. Edge
192+ = Edge Edge
206193 | Slot User
207194 | Value Concrete
208195 deriving (Eq , Ord , Show )
0 commit comments