417 lines
11 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
-- ( -- * Monad
2020-06-17 22:05:44 +04:00
-- CollectM
-- , evalCollectM
-- , collectEnv
-- -- * Scope
-- , Env(..)
-- , ScopedDecl(..)
-- , Kind(..)
-- , HasEnv(..)
-- , lookupEnv
-- -- * Methods
-- , enter
-- , leave
-- , define
-- , defType
-- , def
-- )
2020-06-04 13:48:04 +04:00
where
2020-06-17 22:05:44 +04:00
import Control.Arrow (second)
import Control.Monad.State
2020-06-17 22:05:44 +04:00
import Control.Monad.Writer.Strict hiding (Alt, Product)
2020-06-17 22:05:44 +04:00
import Data.Function
import qualified Data.Map as Map
import Data.Map (Map)
import Data.Text (Text)
import qualified Data.Text as Text
2020-06-17 22:05:44 +04:00
import Data.Maybe (fromJust, listToMaybe)
import qualified Data.List as List
import Range
import AST.Types
import AST.Parser
import Parser
2020-06-01 18:17:33 +04:00
import Tree
import Comment
2020-06-01 18:17:33 +04:00
import Pretty
2020-06-09 15:56:11 +04:00
import Product
2020-06-17 22:05:44 +04:00
import Lattice
import Debug.Trace
2020-06-17 22:05:44 +04:00
class HasLocalScope x where
getLocalScope :: x -> [ScopedDecl]
2020-06-17 22:05:44 +04:00
instance Contains [ScopedDecl] xs => HasLocalScope (Product xs) where
getLocalScope = getElem
2020-06-04 17:40:38 +04:00
2020-06-17 22:05:44 +04:00
type CollectM = State (Product [FullEnv, [Range]])
2020-06-17 22:05:44 +04:00
type AddRefsM = State FullEnv
2020-06-17 22:05:44 +04:00
type FullEnv = Map Range [ScopedDecl]
2020-06-09 15:56:11 +04:00
2020-06-17 22:05:44 +04:00
addLocalScopes
:: HasRange (Product xs)
=> Pascal (Product xs)
-> Pascal (Product ([ScopedDecl] : xs))
addLocalScopes tree =
fmap (\xs -> Cons (envAt envWithREfs $ getRange xs) xs) tree
where
envWithREfs = flip execState env do
flip traverseOnly tree \r (Name t) -> do
modify $ addRef (getRange r) t
return (Name t)
env
= execCollectM
$ traverseTree pure tree
envAt :: FullEnv -> Range -> [ScopedDecl]
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-06-17 22:05:44 +04:00
addRef :: Range -> Text -> FullEnv -> FullEnv
addRef r n env = Map.union (go range) env
where
go (r' : rest) =
let decls = env Map.! r'
in
case updateOnly n r addRefToDecl decls of
(True, decls) -> Map.singleton r' decls
(False, decls) -> Map.insert r' decls (go rest)
go [] = Map.empty
range
= List.sortBy partOrder
$ filter (r <?)
$ Map.keys env
-- decls' list = do
-- r' <- range
-- decls <- Map.lookup r' env
-- return $ (r', updateOnly n r addRefToDecl decls)
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 :)
define :: ScopedDecl -> CollectM ()
define sd = do
r <- gets (head . getElem)
modify
$ modElem @FullEnv
$ Map.insertWith (++) r [sd]
leave :: CollectM ()
leave = modify $ modElem @[Range] tail
-- | Run the computation with scope starting from empty scope.
execCollectM :: CollectM a -> FullEnv
execCollectM action = getElem $ execState action $ Cons Map.empty (Cons [] Nil)
instance {-# OVERLAPS #-} Pretty FullEnv where
pp = block . map aux . Map.toList
where
aux (r, decls) =
pp r `indent` block decls
2020-06-04 17:40:38 +04:00
-- | The type/value declaration.
data ScopedDecl = ScopedDecl
2020-06-17 22:05:44 +04:00
{ _sdName :: Pascal ()
, _sdOrigin :: Range
, _sdBody :: Maybe Range
, _sdType :: Maybe (Either (Pascal ()) Kind)
, _sdRefs :: [Range]
}
deriving Show via PP ScopedDecl
2020-06-09 15:56:11 +04:00
instance Pretty ScopedDecl where
2020-06-17 22:05:44 +04:00
pp (ScopedDecl n o b 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
2020-06-04 17:40:38 +04:00
-- | The kind.
data Kind = Star
2020-06-09 15:56:11 +04:00
deriving Show via PP Kind
instance Pretty Kind where
2020-06-17 22:05:44 +04:00
pp _ = "TYPE"
-- observe :: String -> CollectM a -> CollectM a
-- observe what act = do
-- s <- get
-- traceShowM (what, "BEFORE", s)
-- a <- act
-- s1 <- get
-- traceShowM (what, "AFTER", s1)
-- return a
lookupEnv :: Text -> [ScopedDecl] -> Maybe ScopedDecl
lookupEnv name = listToMaybe . filter ((name ==) . ppToText . _sdName)
-- -- | Make a new scope out of enclosing parent one.
-- enter :: Range -> CollectM ()
-- enter r = observe "enter" do
-- modify \rest ->
-- mk r (ScopeTree Map.empty []) : rest
-- -- | Leave current scope, return to parent one.
-- leave :: CollectM ()
-- leave = observe "leave" do
-- modify \case
-- (a : parent : rest) ->
-- fromJust do
-- -- traceShowM ("MOVE", a)
-- -- traceShowM ("TO ", parent)
-- (r, ScopeTree e cs) <- match parent
-- -- traceShowM ("== ", mk r (ScopeTree e (a : cs)))
-- -- traceShowM ("--")
-- return $ mk r (ScopeTree e (a : cs)) : rest
-- [x] -> error $ "trying to leave \n" ++ show x
-- -- | Add a declaration to the current scope.
-- define :: Text -> ScopedDecl -> CollectM ()
-- define name d = observe "define" do
-- s <- get
-- traceShowM ("DEFINE", s)
-- modify \(top : rest) ->
-- fromJust do
-- (r, ScopeTree a cs) <- match top
-- return $ mk r (ScopeTree (Map.insert name d a) cs) : rest
2020-06-01 18:17:33 +04:00
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-06-17 22:05:44 +04:00
define
$ ScopedDecl
2020-06-17 22:05:44 +04:00
(void name)
(getRange $ infoOf name)
(Just $ getRange $ infoOf body)
(Just (Right kind))
[]
2020-06-17 22:05:44 +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
-- addRef
-- :: Pascal ()
-- -> Range
-- -> FullEnv
-- -> FullEnv
-- addRef name pos (AppendMap envs) =
-- AppendMap $ envs <> affected''
-- where
-- ranges = Map.keys envs
-- (affected, other) = List.partition (pos <?) ranges
-- affected' = foldMap (\r -> Map.singleton r (envs Map.! r)) affected
-- affected'' = Map.map (\decls -> observe "addRef" decls $ addRefScopedDecls decls) affected'
-- addRefScopedDecls :: [ScopedDecl] -> [ScopedDecl]
-- addRefScopedDecls decls =
-- case after of
-- decl : after -> before ++ [addRefScopedDecl decl] ++ after
-- [] -> before
-- where
-- (before, after) = break (\sd -> ppToText (_sdName sd) == ppName) decls
-- addRefScopedDecl :: ScopedDecl -> ScopedDecl
-- addRefScopedDecl decl = decl { _sdRefs = pos : _sdRefs decl }
-- ppName = ppToText name
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-06-17 22:05:44 +04:00
define
$ 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)
instance UpdateOver CollectM Name (Pascal a) where
before range (Name raw) = do
2020-06-17 22:05:44 +04:00
-- traceShowM ("name", raw)
skip
-- modify $ modElem $ addRef range (mk () (Name raw))
-- class HasEnv a where
-- getEnv :: a -> Env
-- instance HasEnv Env where
-- getEnv = id
-- instance Contains Env xs => HasEnv (Product xs) where
-- getEnv = getElem
-- data Scope = Scope { unScope :: [Text] }
-- instance HasComments Scope where
-- getComments = unScope
-- -- pinEnv :: Product xs -> CollectM (Product (Env : xs))
-- -- pinEnv xs = (`Cons` xs) <$> gets head
-- collectEnv :: Contains Range xs => Product xs -> CollectM (Product (Scopes : xs))
-- collectEnv xs = do
-- gets \case
-- st : _ -> Cons st xs
-- [] -> Cons (mk (getRange xs) $ ScopeTree Map.empty []) xs
-- instance UpdateOver (State [Env]) ScopeTree Scopes where
-- before r (ScopeTree e _) = modify (e :)
-- after r _ = modify tail
-- distributeEnv :: ScopeTree Scopes -> State [Env] (ScopeTree Scopes)
-- distributeEnv (ScopeTree e' cs) = do
-- e <- gets (Map.unions . (e' :))
-- return $ ScopeTree e cs
-- pinEnv :: Contains Range xs => Scopes -> Product xs -> CollectM (Product (Env : xs))
-- pinEnv scopes info = do
-- let (_, ScopeTree e _) = fromJust $ match =<< lookupTree (getElem info) scopes
-- return (Cons e info)
-- instance HasComments Range where
-- getComments _ = []
-- instance Pretty (Product xs) => HasComments (Product xs) where
-- getComments xs = if Text.null $ Text.strip x then [] else [x]
-- where
-- x = ppToText $ color 3 $ pp $ xs
-- ascribeEnv :: (Contains Range xs, Pretty (Product xs)) => Pascal (Product xs) -> Scopes -- Pascal (Product (Env : xs))
-- ascribeEnv tree =
-- let
-- scopes =
-- evalCollectM do
-- traverseTree collectEnv tree
-- gets head
-- -- distributed = evalState (traverseOnly distributeEnv scopes) []
-- in
-- scopes
-- -- distributed
-- -- evalCollectM $ traverseTree (pinEnv distributed) tree