|
| 1 | +{-# LANGUAGE FlexibleContexts, OverloadedStrings, RankNTypes, RecordWildCards, TypeApplications, TypeOperators #-} |
1 | 2 | module Analysis.ScopeGraph |
2 | | -( ScopeGraph |
3 | | -, Entry(..) |
| 3 | +( ScopeGraph(..) |
| 4 | +, Decl(..) |
| 5 | +, scopeGraph |
| 6 | +, scopeGraphAnalysis |
4 | 7 | ) where |
5 | 8 |
|
| 9 | +import Analysis.Eval |
| 10 | +import Analysis.FlowInsensitive |
| 11 | +import Control.Applicative (Alternative (..)) |
| 12 | +import Control.Effect.Carrier |
| 13 | +import Control.Effect.Fail |
| 14 | +import Control.Effect.Fresh |
| 15 | +import Control.Effect.Reader |
| 16 | +import Control.Effect.State |
| 17 | +import Control.Monad ((>=>)) |
| 18 | +import Data.File |
| 19 | +import Data.Foldable (fold) |
| 20 | +import Data.Function (fix) |
| 21 | +import Data.List.NonEmpty |
6 | 22 | import Data.Loc |
7 | 23 | import qualified Data.Map as Map |
| 24 | +import Data.Name |
| 25 | +import Data.Proxy |
8 | 26 | import qualified Data.Set as Set |
| 27 | +import Data.Text (Text) |
| 28 | +import Data.Traversable (for) |
| 29 | +import Prelude hiding (fail) |
9 | 30 |
|
10 | | -data Entry = Entry |
11 | | - { entrySymbol :: String -- FIXME: Text |
12 | | - , entryLoc :: Loc |
| 31 | +data Decl = Decl |
| 32 | + { declSymbol :: Text |
| 33 | + , declLoc :: Loc |
13 | 34 | } |
| 35 | + deriving (Eq, Ord, Show) |
14 | 36 |
|
15 | | -type ScopeGraph = Map.Map Entry (Set.Set Entry) |
| 37 | +newtype Ref = Ref Loc |
| 38 | + deriving (Eq, Ord, Show) |
| 39 | + |
| 40 | +newtype ScopeGraph = ScopeGraph { unScopeGraph :: Map.Map Decl (Set.Set Ref) } |
| 41 | + deriving (Eq, Ord, Show) |
| 42 | + |
| 43 | +instance Semigroup ScopeGraph where |
| 44 | + ScopeGraph a <> ScopeGraph b = ScopeGraph (Map.unionWith (<>) a b) |
| 45 | + |
| 46 | +instance Monoid ScopeGraph where |
| 47 | + mempty = ScopeGraph Map.empty |
| 48 | + |
| 49 | +scopeGraph |
| 50 | + :: Ord term |
| 51 | + => (forall sig m |
| 52 | + . (Carrier sig m, Member (Reader Loc) sig, MonadFail m) |
| 53 | + => Analysis term User ScopeGraph m |
| 54 | + -> (term -> m ScopeGraph) |
| 55 | + -> (term -> m ScopeGraph) |
| 56 | + ) |
| 57 | + -> [File term] |
| 58 | + -> (Heap User ScopeGraph, [File (Either (Loc, String) ScopeGraph)]) |
| 59 | +scopeGraph eval |
| 60 | + = run |
| 61 | + . runFresh |
| 62 | + . runHeap |
| 63 | + . traverse (runFile eval) |
| 64 | + |
| 65 | +runFile |
| 66 | + :: ( Carrier sig m |
| 67 | + , Effect sig |
| 68 | + , Member Fresh sig |
| 69 | + , Member (State (Heap User ScopeGraph)) sig |
| 70 | + , Ord term |
| 71 | + ) |
| 72 | + => (forall sig m |
| 73 | + . (Carrier sig m, Member (Reader Loc) sig, MonadFail m) |
| 74 | + => Analysis term User ScopeGraph m |
| 75 | + -> (term -> m ScopeGraph) |
| 76 | + -> (term -> m ScopeGraph) |
| 77 | + ) |
| 78 | + -> File term |
| 79 | + -> m (File (Either (Loc, String) ScopeGraph)) |
| 80 | +runFile eval file = traverse run file |
| 81 | + where run = runReader (fileLoc file) |
| 82 | + . runReader (Map.empty @User @Loc) |
| 83 | + . runFailWithLoc |
| 84 | + . fmap fold |
| 85 | + . convergeTerm (Proxy @User) (fix (cacheTerm . eval scopeGraphAnalysis)) |
| 86 | + |
| 87 | +scopeGraphAnalysis |
| 88 | + :: ( Alternative m |
| 89 | + , Carrier sig m |
| 90 | + , Member (Reader Loc) sig |
| 91 | + , Member (Reader (Map.Map User Loc)) sig |
| 92 | + , Member (State (Heap User ScopeGraph)) sig |
| 93 | + ) |
| 94 | + => Analysis term User ScopeGraph m |
| 95 | +scopeGraphAnalysis = Analysis{..} |
| 96 | + where alloc = pure |
| 97 | + bind name _ m = do |
| 98 | + loc <- ask @Loc |
| 99 | + local (Map.insert name loc) m |
| 100 | + lookupEnv = pure . Just |
| 101 | + deref addr = do |
| 102 | + ref <- asks Ref |
| 103 | + bindLoc <- asks (Map.lookup addr) |
| 104 | + cell <- gets (Map.lookup addr >=> nonEmpty . Set.toList) |
| 105 | + let extending = mappend (extendBinding addr ref bindLoc) |
| 106 | + maybe (pure Nothing) (foldMapA (pure . Just . extending)) cell |
| 107 | + assign addr v = do |
| 108 | + ref <- asks Ref |
| 109 | + bindLoc <- asks (Map.lookup addr) |
| 110 | + modify (Map.insertWith (<>) addr (Set.singleton (extendBinding addr ref bindLoc <> v))) |
| 111 | + abstract eval name body = do |
| 112 | + addr <- alloc name |
| 113 | + assign name (mempty @ScopeGraph) |
| 114 | + bind name addr (eval body) |
| 115 | + apply _ f a = pure (f <> a) |
| 116 | + unit = pure mempty |
| 117 | + bool _ = pure mempty |
| 118 | + asBool _ = pure True <|> pure False |
| 119 | + string _ = pure mempty |
| 120 | + asString _ = pure mempty |
| 121 | + record fields = do |
| 122 | + fields' <- for fields $ \ (k, v) -> do |
| 123 | + addr <- alloc k |
| 124 | + loc <- ask @Loc |
| 125 | + let v' = ScopeGraph (Map.singleton (Decl k loc) mempty) <> v |
| 126 | + (k, v') <$ assign addr v' |
| 127 | + pure (foldMap snd fields') |
| 128 | + _ ... m = pure (Just m) |
| 129 | + |
| 130 | + extendBinding addr ref bindLoc = ScopeGraph (maybe Map.empty (\ bindLoc -> Map.singleton (Decl addr bindLoc) (Set.singleton ref)) bindLoc) |
0 commit comments