341 lines
9.1 KiB
Haskell
Raw Normal View History

2020-06-17 22:05:44 +04:00
{-# language Strict #-}
2020-06-04 13:48:04 +04:00
{- | /The/ scope resolution system.
-}
2020-06-04 13:48:04 +04:00
module AST.Scope
-- ( HasLocalScope (..)
-- , addLocalScopes
-- , lookupEnv
-- , Kind (..)
-- , ScopedDecl (..)
-- )
2020-06-04 13:48:04 +04:00
where
2020-07-01 16:56:21 +04:00
import Control.Arrow (second)
import Control.Monad.State
2020-07-01 16:56:21 +04:00
import qualified Data.List as List
2020-07-10 15:11:49 +04:00
import Data.Map (Map)
2020-07-01 16:56:21 +04:00
import qualified Data.Map as Map
2020-07-10 15:11:49 +04:00
import Data.Maybe (listToMaybe)
import Data.Sum (Element, Apply, Sum)
import Data.Text (Text)
2020-07-01 16:56:21 +04:00
2020-07-10 15:11:49 +04:00
-- import AST.Parser
2020-07-01 16:56:21 +04:00
import AST.Types
2020-07-10 15:11:49 +04:00
-- import Comment
2020-07-01 16:56:21 +04:00
import Lattice
2020-07-10 15:11:49 +04:00
-- import Parser
2020-07-01 16:56:21 +04:00
import Pretty
import Product
import Range
import Tree
2020-07-10 15:11:49 +04:00
-- import Debug.Trace
2020-06-04 17:40:38 +04:00
2020-06-17 22:05:44 +04:00
type CollectM = State (Product [FullEnv, [Range]])
2020-07-10 15:11:49 +04:00
type FullEnv = Product ["vars" := Env, "types" := Env]
type Env = Map Range [ScopedDecl]
2020-07-08 20:31:42 +04:00
data Category = Variable | Type
2020-07-10 15:11:49 +04:00
-- | The type/value declaration.
data ScopedDecl = ScopedDecl
{ _sdName :: Pascal ()
, _sdOrigin :: Range
, _sdBody :: Maybe Range
, _sdType :: Maybe (Either (Pascal ()) Kind)
, _sdRefs :: [Range]
}
deriving Show via PP ScopedDecl
2020-07-08 20:31:42 +04:00
2020-07-10 15:11:49 +04:00
-- | The kind.
data Kind = Star
deriving Show via PP Kind
2020-07-08 20:31:42 +04:00
2020-07-10 15:11:49 +04:00
emptyEnv :: FullEnv
emptyEnv
= Cons (Tag Map.empty)
$ Cons (Tag Map.empty)
Nil
2020-07-08 20:31:42 +04:00
2020-07-10 15:11:49 +04:00
with :: Category -> FullEnv -> (Env -> Env) -> FullEnv
with Variable env f = modTag @"vars" f env
with Type env f = modTag @"types" f env
2020-07-08 20:31:42 +04:00
2020-07-10 15:11:49 +04:00
ofCategory :: Category -> ScopedDecl -> Bool
2020-07-08 20:31:42 +04:00
ofCategory Variable ScopedDecl { _sdType = Just (Right Star) } = False
ofCategory Variable _ = True
ofCategory Type ScopedDecl { _sdType = Just (Right Star) } = True
ofCategory _ _ = False
2020-06-09 15:56:11 +04:00
2020-07-01 16:56:21 +04:00
-- | Calculate scopes and attach to all tree points declarations that are
-- visible there.
--
2020-06-17 22:05:44 +04:00
addLocalScopes
2020-07-08 20:31:42 +04:00
:: Contains Range xs
2020-06-17 22:05:44 +04:00
=> Pascal (Product xs)
2020-07-08 20:31:42 +04:00
-> Pascal (Product ([ScopedDecl] : Maybe Category : xs))
2020-06-17 22:05:44 +04:00
addLocalScopes tree =
2020-07-08 20:31:42 +04:00
fmap (\xs -> Cons (fullEnvAt envWithREfs (getRange xs)) xs) tree1
where
2020-07-08 20:31:42 +04:00
tree1 = addNameCategories tree
envWithREfs = getEnvTree tree
2020-07-08 20:31:42 +04:00
addNameCategories
:: Contains Range xs
=> Pascal (Product xs)
-> Pascal (Product (Maybe Category : xs))
addNameCategories tree = flip evalState emptyEnv do
traverseMany
[ Visit \r (Name t) -> do
modify $ getRange r `addRef` (Variable, t)
return $ (Cons (Just Variable) r, Name t)
, Visit \r (TypeName t) -> do
modify $ getRange r `addRef` (Type, t)
return $ (Cons (Just Type) r, TypeName t)
]
(Cons Nothing)
tree
2020-07-10 15:11:49 +04:00
getEnvTree
:: ( UpdateOver CollectM (Sum fs) (Tree fs b)
, Apply Foldable fs
, Apply Functor fs
, Apply Traversable fs
, HasRange b
, Element Name fs
, Element TypeName fs
)
=> Tree fs b
-> FullEnv
getEnvTree tree = envWithREfs
2020-06-17 22:05:44 +04:00
where
envWithREfs = flip execState env do
2020-07-08 20:31:42 +04:00
traverseMany
[ Visit \r (Name t) -> do
modify $ getRange r `addRef` (Variable, t)
return $ (r, Name t)
, Visit \r (TypeName t) -> do
modify $ getRange r `addRef` (Type, t)
return $ (r, TypeName t)
]
id
tree
2020-06-17 22:05:44 +04:00
env
= execCollectM
$ traverseTree pure tree
2020-07-08 20:31:42 +04:00
fullEnvAt :: FullEnv -> Range -> [ScopedDecl]
2020-07-10 15:11:49 +04:00
fullEnvAt fe r = envAt (getTag @"types" fe) r <> envAt (getTag @"vars" fe) r
2020-07-08 20:31:42 +04:00
envAt :: Env -> Range -> [ScopedDecl]
2020-06-17 22:05:44 +04:00
envAt env pos =
Map.elems scopes
where
ranges = List.sortBy partOrder $ filter isCovering $ Map.keys env
scopes = Map.unions $ (map.foldMap) toScopeMap $ map (env Map.!) ranges
2020-06-17 22:05:44 +04:00
isCovering = (pos <?)
toScopeMap sd@ScopedDecl {_sdName} = Map.singleton (ppToText _sdName) sd
2020-07-08 20:31:42 +04:00
addRef :: Range -> (Category, Text) -> FullEnv -> FullEnv
2020-07-10 15:11:49 +04:00
addRef r (categ, n) env =
with categ env \slice ->
2020-07-08 20:31:42 +04:00
Map.union
(go slice $ range slice)
slice
2020-06-17 22:05:44 +04:00
where
2020-07-08 20:31:42 +04:00
go slice (r' : rest) =
let decls = slice Map.! r'
2020-06-17 22:05:44 +04:00
in
case updateOnly n r addRefToDecl decls of
2020-07-10 15:11:49 +04:00
(True, decls') -> Map.singleton r' decls'
(False, decls') -> Map.insert r' decls' (go slice rest)
2020-07-08 20:31:42 +04:00
go _ [] = Map.empty
2020-06-17 22:05:44 +04:00
2020-07-08 20:31:42 +04:00
range slice
2020-06-17 22:05:44 +04:00
= List.sortBy partOrder
$ filter (r <?)
2020-07-08 20:31:42 +04:00
$ Map.keys slice
2020-06-17 22:05:44 +04:00
addRefToDecl sd = sd
{ _sdRefs = r : _sdRefs sd
}
updateOnly
:: Text
-> Range
-> (ScopedDecl -> ScopedDecl)
-> [ScopedDecl]
-> (Bool, [ScopedDecl])
updateOnly name r f = go
where
go = \case
d : ds
| ppToText (_sdName d) == name ->
if r == _sdOrigin d
then (True, d : ds)
else (True, f d : ds)
| otherwise -> second (d :) (go ds)
[] -> (False, [])
enter :: Range -> CollectM ()
enter r = do
modify $ modElem (r :)
2020-07-08 20:31:42 +04:00
define :: Category -> ScopedDecl -> CollectM ()
2020-07-10 15:11:49 +04:00
define categ sd = do
r <- gets (head . getElem @[Range])
2020-06-17 22:05:44 +04:00
modify
2020-07-08 20:31:42 +04:00
$ modElem @FullEnv \env ->
2020-07-10 15:11:49 +04:00
with categ env
2020-07-08 20:31:42 +04:00
$ Map.insertWith (++) r [sd]
2020-06-17 22:05:44 +04:00
leave :: CollectM ()
leave = modify $ modElem @[Range] tail
-- | Run the computation with scope starting from empty scope.
execCollectM :: CollectM a -> FullEnv
2020-07-08 20:31:42 +04:00
execCollectM action = getElem $ execState action $ Cons emptyEnv (Cons [] Nil)
2020-06-17 22:05:44 +04:00
instance {-# OVERLAPS #-} Pretty FullEnv where
2020-07-08 20:31:42 +04:00
pp = block . map aux . Map.toList . mergeFE
2020-06-17 22:05:44 +04:00
where
2020-07-08 20:31:42 +04:00
aux (r, fe) =
pp r `indent` block fe
2020-07-10 15:11:49 +04:00
mergeFE fe = getTag @"vars" @Env fe <> getTag @"types" fe
2020-06-09 15:56:11 +04:00
instance Pretty ScopedDecl where
2020-07-10 15:11:49 +04:00
pp (ScopedDecl n o _ t refs) = color 3 (pp n) <+> pp o <+> ":" <+> color 4 (maybe "?" (either pp pp) t) <+> "=" <+> pp refs
2020-06-09 15:56:11 +04:00
instance Pretty Kind where
2020-06-17 22:05:44 +04:00
pp _ = "TYPE"
2020-07-10 16:13:39 +04:00
instance Pretty Category where
pp Variable = "Variable"
pp Type = "Type"
2020-07-01 16:56:21 +04:00
-- | Search for a name inside a local scope.
2020-06-17 22:05:44 +04:00
lookupEnv :: Text -> [ScopedDecl] -> Maybe ScopedDecl
lookupEnv name = listToMaybe . filter ((name ==) . ppToText . _sdName)
2020-06-04 17:40:38 +04:00
-- | Add a type declaration to the current scope.
2020-06-17 22:05:44 +04:00
defType :: HasRange a => Pascal a -> Kind -> Pascal a -> CollectM ()
2020-06-01 18:17:33 +04:00
defType name kind body = do
2020-07-08 20:31:42 +04:00
define Type
$ ScopedDecl
2020-06-17 22:05:44 +04:00
(void name)
(getRange $ infoOf name)
(Just $ getRange $ infoOf body)
(Just (Right kind))
[]
2020-07-01 16:56:21 +04:00
-- observe :: Pretty i => Pretty res => Text -> i -> res -> res
-- observe msg i res
-- = traceShow (pp msg, "INPUT", pp i)
-- $ traceShow (pp msg, "OUTPUT", pp res)
-- $ res
2020-06-04 17:40:38 +04:00
-- | Add a value declaration to the current scope.
def
2020-06-01 18:17:33 +04:00
:: HasRange a
=> Pascal a
-> Maybe (Pascal a)
-> Maybe (Pascal a)
2020-06-17 22:05:44 +04:00
-> CollectM ()
2020-06-01 18:17:33 +04:00
def name ty body = do
2020-07-08 20:31:42 +04:00
define Variable
$ ScopedDecl
2020-06-17 22:05:44 +04:00
(void name)
(getRange $ infoOf name)
((getRange . infoOf) <$> body)
((Left . void) <$> ty)
[]
2020-06-01 18:17:33 +04:00
2020-06-17 22:05:44 +04:00
instance UpdateOver CollectM Contract (Pascal a) where
before r _ = enter r
2020-06-17 22:05:44 +04:00
after _ _ = skip
2020-06-01 18:17:33 +04:00
2020-06-17 22:05:44 +04:00
instance HasRange a => UpdateOver CollectM Declaration (Pascal a) where
before _ = \case
2020-06-01 18:17:33 +04:00
TypeDecl ty body -> defType ty Star body
_ -> skip
2020-06-17 22:05:44 +04:00
instance HasRange a => UpdateOver CollectM Binding (Pascal a) where
before r = \case
2020-06-04 17:16:04 +04:00
Function recur name _args ty body -> do
when recur do
2020-06-01 18:17:33 +04:00
def name (Just ty) (Just body)
enter r
_ -> enter r
after _ = \case
2020-06-01 18:17:33 +04:00
Irrefutable name body -> do leave; def name Nothing (Just body)
Var name ty body -> do leave; def name (Just ty) (Just body)
Const name ty body -> do leave; def name (Just ty) (Just body)
2020-06-04 17:16:04 +04:00
Function recur name _args ty body -> do
2020-06-01 18:17:33 +04:00
leave
unless recur do
2020-06-01 18:17:33 +04:00
def name (Just ty) (Just body)
2020-06-17 22:05:44 +04:00
instance HasRange a => UpdateOver CollectM VarDecl (Pascal a) where
after _ (Decl _ name ty) = def name (Just ty) Nothing
2020-06-01 18:17:33 +04:00
2020-06-17 22:05:44 +04:00
instance UpdateOver CollectM Mutable (Pascal a)
instance UpdateOver CollectM Type (Pascal a)
instance UpdateOver CollectM Variant (Pascal a)
instance UpdateOver CollectM TField (Pascal a)
2020-06-01 18:17:33 +04:00
2020-06-17 22:05:44 +04:00
instance HasRange a => UpdateOver CollectM Expr (Pascal a) where
before r = \case
Let {} -> enter r
Lambda {} -> enter r
2020-06-01 18:17:33 +04:00
ForLoop k _ _ _ -> do
enter r
2020-06-01 18:17:33 +04:00
def k Nothing Nothing
ForBox k mv _ _ _ -> do
enter r
2020-06-01 18:17:33 +04:00
def k Nothing Nothing
maybe skip (\v -> def v Nothing Nothing) mv
_ -> skip
after _ = \case
2020-06-01 18:17:33 +04:00
Let {} -> leave
Lambda {} -> leave
ForLoop {} -> leave
ForBox {} -> leave
_ -> skip
2020-06-17 22:05:44 +04:00
instance HasRange a => UpdateOver CollectM Alt (Pascal a) where
before r _ = enter r
after _ _ = leave
2020-06-01 18:17:33 +04:00
2020-06-17 22:05:44 +04:00
instance UpdateOver CollectM LHS (Pascal a)
instance UpdateOver CollectM MapBinding (Pascal a)
instance UpdateOver CollectM Assignment (Pascal a)
instance UpdateOver CollectM FieldAssignment (Pascal a)
instance UpdateOver CollectM Constant (Pascal a)
2020-06-01 18:17:33 +04:00
2020-06-17 22:05:44 +04:00
instance HasRange a => UpdateOver CollectM Pattern (Pascal a) where
before _ = \case
2020-06-01 18:17:33 +04:00
IsVar n -> def n Nothing Nothing
_ -> skip
2020-06-17 22:05:44 +04:00
instance UpdateOver CollectM QualifiedName (Pascal a)
instance UpdateOver CollectM Path (Pascal a)
2020-07-08 20:31:42 +04:00
instance UpdateOver CollectM Name (Pascal a)
instance UpdateOver CollectM TypeName (Pascal a)
instance UpdateOver CollectM FieldName (Pascal a)