[WIP] Implement a loader of Env from a ScopeTree
This commit is contained in:
parent
9f124bf5af
commit
8d61a36918
@ -7,6 +7,7 @@ import Control.Monad
|
|||||||
|
|
||||||
import Data.Default
|
import Data.Default
|
||||||
import qualified Data.Text as Text
|
import qualified Data.Text as Text
|
||||||
|
import Data.Text (Text)
|
||||||
import Data.String.Interpolate (i)
|
import Data.String.Interpolate (i)
|
||||||
|
|
||||||
import qualified Language.Haskell.LSP.Control as CTRL
|
import qualified Language.Haskell.LSP.Control as CTRL
|
||||||
@ -23,7 +24,9 @@ import qualified System.Log as L
|
|||||||
|
|
||||||
import Parser
|
import Parser
|
||||||
import Range
|
import Range
|
||||||
|
import Product
|
||||||
import AST hiding (def)
|
import AST hiding (def)
|
||||||
|
import qualified AST.Find as Find
|
||||||
import Error
|
import Error
|
||||||
import Tree
|
import Tree
|
||||||
|
|
||||||
@ -150,11 +153,32 @@ eventLoop funs chan = do
|
|||||||
(J.uriToFilePath doc)
|
(J.uriToFilePath doc)
|
||||||
(Just 0)
|
(Just 0)
|
||||||
|
|
||||||
-- ReqDefinition req -> do
|
ReqDefinition req -> do
|
||||||
|
let uri = req^.J.params.J.textDocument.J.uri
|
||||||
|
let pos = posToRange $ req^.J.params.J.position
|
||||||
|
tree <- loadByURI uri
|
||||||
|
case Find.definitionOf pos tree of
|
||||||
|
Just defPos -> do
|
||||||
|
error "do later"
|
||||||
|
-- Core.sendFunc funs $ RspDefinition $ _ $ J.SingleLoc $ J.Location uri $ rangeToLoc defPos
|
||||||
|
|
||||||
_ -> U.logs "unknown msg"
|
_ -> U.logs "unknown msg"
|
||||||
|
|
||||||
|
posToRange :: J.Position -> Range
|
||||||
|
posToRange (J.Position l c) = Range (l, c, 0) (l, c, 0)
|
||||||
|
|
||||||
|
rangeToJRange :: Range -> J.Range
|
||||||
|
rangeToJRange (Range (a, b, _) (c, d, _)) = J.Range (J.Position a b) (J.Position c d)
|
||||||
|
|
||||||
|
rangeToLoc :: Range -> J.Range
|
||||||
|
rangeToLoc (Range (a, b, _) (c, d, _)) = J.Range (J.Position a b) (J.Position c d)
|
||||||
|
|
||||||
|
loadByURI :: J.Uri -> IO (Pascal (Product [Env, Range, [Text]]))
|
||||||
|
loadByURI uri = do
|
||||||
|
case J.uriToFilePath uri of
|
||||||
|
Just fin -> do
|
||||||
|
(tree, _) <- runParser contract fin
|
||||||
|
return $ ascribeEnv tree
|
||||||
|
|
||||||
collectErrors
|
collectErrors
|
||||||
:: Core.LspFuncs ()
|
:: Core.LspFuncs ()
|
||||||
|
@ -3,6 +3,7 @@ name: squirrel
|
|||||||
dependencies:
|
dependencies:
|
||||||
- base
|
- base
|
||||||
- bytestring
|
- bytestring
|
||||||
|
- containers
|
||||||
- data-default
|
- data-default
|
||||||
- mtl
|
- mtl
|
||||||
- pretty
|
- pretty
|
||||||
|
@ -5,10 +5,13 @@ import Control.Monad
|
|||||||
|
|
||||||
import AST.Types
|
import AST.Types
|
||||||
import AST.Scope
|
import AST.Scope
|
||||||
|
import AST.Parser
|
||||||
|
|
||||||
|
import Parser
|
||||||
import Tree
|
import Tree
|
||||||
import Range
|
import Range
|
||||||
import Lattice
|
import Lattice
|
||||||
|
import Pretty
|
||||||
|
|
||||||
import Debug.Trace
|
import Debug.Trace
|
||||||
|
|
||||||
@ -20,9 +23,9 @@ findScopedDecl
|
|||||||
-> Pascal info
|
-> Pascal info
|
||||||
-> Maybe ScopedDecl
|
-> Maybe ScopedDecl
|
||||||
findScopedDecl pos tree = do
|
findScopedDecl pos tree = do
|
||||||
point <- lookupTree (\info -> pos <? getRange info) tree
|
point <- lookupTree pos tree
|
||||||
let env = getEnv (infoOf point)
|
let env = getEnv (infoOf point)
|
||||||
lookupEnv (void point) env
|
lookupEnv (ppToText $ void point) env
|
||||||
|
|
||||||
definitionOf
|
definitionOf
|
||||||
:: ( HasEnv info
|
:: ( HasEnv info
|
||||||
@ -53,3 +56,13 @@ implementationOf
|
|||||||
-> Maybe Range
|
-> Maybe Range
|
||||||
implementationOf pos tree =
|
implementationOf pos tree =
|
||||||
_sdBody =<< findScopedDecl pos tree
|
_sdBody =<< findScopedDecl pos tree
|
||||||
|
|
||||||
|
referencesOf
|
||||||
|
:: ( HasEnv info
|
||||||
|
, HasRange info
|
||||||
|
)
|
||||||
|
=> Range
|
||||||
|
-> Pascal info
|
||||||
|
-> Maybe [Range]
|
||||||
|
referencesOf pos tree =
|
||||||
|
_sdRefs <$> findScopedDecl pos tree
|
||||||
|
@ -845,8 +845,8 @@ typeTuple = do
|
|||||||
-- example = "../../../src/test/contracts/address.ligo"
|
-- example = "../../../src/test/contracts/address.ligo"
|
||||||
-- example = "../../../src/test/contracts/amount.ligo"
|
-- example = "../../../src/test/contracts/amount.ligo"
|
||||||
-- example = "../../../src/test/contracts/annotation.ligo"
|
-- example = "../../../src/test/contracts/annotation.ligo"
|
||||||
-- example = "../../../src/test/contracts/arithmetic.ligo"
|
example = "../../../src/test/contracts/arithmetic.ligo"
|
||||||
example = "../../../src/test/contracts/assign.ligo"
|
-- example = "../../../src/test/contracts/assign.ligo"
|
||||||
-- example = "../../../src/test/contracts/attributes.ligo"
|
-- example = "../../../src/test/contracts/attributes.ligo"
|
||||||
-- example = "../../../src/test/contracts/bad_timestamp.ligo"
|
-- example = "../../../src/test/contracts/bad_timestamp.ligo"
|
||||||
-- example = "../../../src/test/contracts/bad_type_operator.ligo"
|
-- example = "../../../src/test/contracts/bad_type_operator.ligo"
|
||||||
|
@ -3,65 +3,88 @@
|
|||||||
-}
|
-}
|
||||||
|
|
||||||
module AST.Scope
|
module AST.Scope
|
||||||
( -- * Monad
|
-- ( -- * Monad
|
||||||
ScopeM
|
-- ScopeM
|
||||||
, evalScopeM
|
-- , evalScopeM
|
||||||
, pinEnv
|
-- , collectEnv
|
||||||
|
|
||||||
-- * Scope
|
-- -- * Scope
|
||||||
, Env(..)
|
-- , Env(..)
|
||||||
, ScopedDecl(..)
|
-- , ScopedDecl(..)
|
||||||
, Kind(..)
|
-- , Kind(..)
|
||||||
, HasEnv(..)
|
-- , HasEnv(..)
|
||||||
, lookupEnv
|
-- , lookupEnv
|
||||||
|
|
||||||
-- * Methods
|
-- -- * Methods
|
||||||
, enter
|
-- , enter
|
||||||
, leave
|
-- , leave
|
||||||
, define
|
-- , define
|
||||||
, defType
|
-- , defType
|
||||||
, def
|
-- , def
|
||||||
)
|
-- )
|
||||||
where
|
where
|
||||||
|
|
||||||
import Control.Monad.State
|
import Control.Monad.State
|
||||||
|
|
||||||
import Data.Text (Text)
|
import qualified Data.Map as Map
|
||||||
|
import Data.Map (Map)
|
||||||
|
import Data.Text (Text)
|
||||||
|
import qualified Data.Text as Text
|
||||||
|
import Data.Maybe (fromJust)
|
||||||
|
|
||||||
import Range
|
import Range
|
||||||
import AST.Types
|
import AST.Types
|
||||||
|
import AST.Parser
|
||||||
|
import Parser
|
||||||
import Tree
|
import Tree
|
||||||
import Comment
|
import Comment
|
||||||
import Pretty
|
import Pretty
|
||||||
import Product
|
import Product
|
||||||
|
|
||||||
|
import Debug.Trace
|
||||||
|
|
||||||
-- | Scope-holding monad.
|
-- | Scope-holding monad.
|
||||||
type ScopeM = State [Env]
|
type ScopeM = State [Scopes]
|
||||||
|
|
||||||
-- | Run the computation with scope starting from empty scope.
|
-- | Run the computation with scope starting from empty scope.
|
||||||
evalScopeM :: ScopeM a -> a
|
evalScopeM :: ScopeM a -> a
|
||||||
evalScopeM action = evalState action [Env []]
|
evalScopeM action = evalState action []
|
||||||
|
|
||||||
-- | The environment.
|
type Scopes = Tree '[ScopeTree] Range
|
||||||
newtype Env = Env
|
|
||||||
{ _eDecls :: [ScopedDecl]
|
|
||||||
}
|
|
||||||
deriving newtype (Semigroup, Monoid)
|
|
||||||
deriving Show via PP Env
|
|
||||||
|
|
||||||
instance Pretty Env where
|
data ScopeTree it
|
||||||
pp = vcat . map pp . _eDecls
|
= ScopeTree Env [it]
|
||||||
|
deriving stock (Functor, Foldable, Traversable)
|
||||||
|
deriving stock Show
|
||||||
|
|
||||||
|
instance Pretty1 ScopeTree where
|
||||||
|
pp1 (ScopeTree e cs) =
|
||||||
|
pp e `indent` block cs
|
||||||
|
|
||||||
|
instance {-# OVERLAPS #-} Pretty (Map Text ScopedDecl) where
|
||||||
|
pp = block . map aux . Map.toList
|
||||||
|
where
|
||||||
|
aux (n, ScopedDecl o b t rs) =
|
||||||
|
pp o <+> (pp n <> ":") <+> pp t <+> "=" <+> pp b <+> "/" <+> (list rs <> ";")
|
||||||
|
|
||||||
|
-- | The environment.
|
||||||
|
type Env = Map Text ScopedDecl
|
||||||
|
-- deriving Show via PP Env
|
||||||
|
|
||||||
|
-- instance Pretty Env where
|
||||||
|
-- pp = vcat . map pp . _eDecls
|
||||||
|
|
||||||
-- | The type/value declaration.
|
-- | The type/value declaration.
|
||||||
data ScopedDecl = ScopedDecl
|
data ScopedDecl = ScopedDecl
|
||||||
{ _sdName :: (Pascal ())
|
{ _sdOrigin :: Range
|
||||||
, _sdOrigin :: Range
|
|
||||||
, _sdBody :: Maybe Range
|
, _sdBody :: Maybe Range
|
||||||
, _sdType :: Maybe (Either (Pascal ()) Kind)
|
, _sdType :: Maybe (Either (Pascal ()) Kind)
|
||||||
|
, _sdRefs :: [Range]
|
||||||
}
|
}
|
||||||
|
deriving Show via PP ScopedDecl
|
||||||
|
|
||||||
instance Pretty ScopedDecl where
|
instance Pretty ScopedDecl where
|
||||||
pp (ScopedDecl n o b t) = pp o <+> "-" <+> (pp n <> ":") <+> maybe "?" (either pp pp) t <+> "=" <+> pp o
|
pp (ScopedDecl o b t refs) = pp o <+> "-" <+> maybe "?" (either pp pp) t <+> "=" <+> pp o
|
||||||
|
|
||||||
-- | The kind.
|
-- | The kind.
|
||||||
data Kind = Star
|
data Kind = Star
|
||||||
@ -70,34 +93,60 @@ data Kind = Star
|
|||||||
instance Pretty Kind where
|
instance Pretty Kind where
|
||||||
pp _ = "*"
|
pp _ = "*"
|
||||||
|
|
||||||
lookupEnv :: Pascal () -> Env -> Maybe ScopedDecl
|
lookupEnv :: Text -> Env -> Maybe ScopedDecl
|
||||||
lookupEnv name = go . _eDecls
|
lookupEnv name = Map.lookup name
|
||||||
where
|
|
||||||
go (sd@(ScopedDecl {_sdName}) : rest)
|
|
||||||
| ppToText _sdName == ppToText name = Just sd
|
|
||||||
| otherwise = go rest
|
|
||||||
go _ = Nothing
|
|
||||||
|
|
||||||
-- | Make a new scope out of enclosing parent one.
|
-- | Make a new scope out of enclosing parent one.
|
||||||
enter :: ScopeM ()
|
enter :: Range -> ScopeM ()
|
||||||
enter = modify \(a : b) -> a : a : b
|
enter r =
|
||||||
|
modify \rest ->
|
||||||
|
mk r (ScopeTree Map.empty []) : rest
|
||||||
|
|
||||||
-- | Leave current scope, return to parent one.
|
-- | Leave current scope, return to parent one.
|
||||||
leave :: ScopeM ()
|
leave :: ScopeM ()
|
||||||
leave = modify tail
|
leave =
|
||||||
|
modify \(a : parent : rest) ->
|
||||||
|
fromJust do
|
||||||
|
(r, ScopeTree e cs) <- match parent
|
||||||
|
return $ mk r (ScopeTree e (a : cs)) : rest
|
||||||
|
|
||||||
-- | Add a declaration to the current scope.
|
-- | Add a declaration to the current scope.
|
||||||
define :: ScopedDecl -> ScopeM ()
|
define :: Text -> ScopedDecl -> ScopeM ()
|
||||||
define d = modify \(Env a : b) -> Env (d : a) : b
|
define name d =
|
||||||
|
modify \(top : rest) ->
|
||||||
|
fromJust do
|
||||||
|
(r, ScopeTree a cs) <- match top
|
||||||
|
return $ mk r (ScopeTree (Map.insert name d a) cs) : rest
|
||||||
|
|
||||||
-- | Add a type declaration to the current scope.
|
-- | Add a type declaration to the current scope.
|
||||||
defType :: HasRange a => Pascal a -> Kind -> Pascal a -> ScopeM ()
|
defType :: HasRange a => Pascal a -> Kind -> Pascal a -> ScopeM ()
|
||||||
defType name kind body = do
|
defType name kind body = do
|
||||||
define $ ScopedDecl
|
define (ppToText $ void name)
|
||||||
(void name)
|
$ ScopedDecl
|
||||||
(getRange $ infoOf name)
|
(getRange $ infoOf name)
|
||||||
(Just $ getRange $ infoOf body)
|
(Just $ getRange $ infoOf body)
|
||||||
(Just (Right kind))
|
(Just (Right kind))
|
||||||
|
[]
|
||||||
|
|
||||||
|
addRef :: Text -> Range -> [Scopes] -> [Scopes]
|
||||||
|
addRef _ _ [] = error "addRef: empty env stack"
|
||||||
|
addRef name pos stack@(topmost : _)
|
||||||
|
| Just (r, ScopeTree top cs) <- match topmost =
|
||||||
|
case Map.lookup name top of
|
||||||
|
Just ScopedDecl {_sdOrigin} -> go _sdOrigin stack
|
||||||
|
Nothing -> stack
|
||||||
|
|
||||||
|
where
|
||||||
|
go _ [] = []
|
||||||
|
go range initial@(topmost : rest)
|
||||||
|
| Just (r, ScopeTree e cs) <- match topmost =
|
||||||
|
case Map.lookup name e of
|
||||||
|
Just it | _sdOrigin it == range ->
|
||||||
|
mk r (ScopeTree (pushRef pos e) cs) : go range rest
|
||||||
|
_ ->
|
||||||
|
initial
|
||||||
|
|
||||||
|
pushRef pos' = Map.adjust (\sd -> sd { _sdRefs = pos' : _sdRefs sd }) name
|
||||||
|
|
||||||
-- | Add a value declaration to the current scope.
|
-- | Add a value declaration to the current scope.
|
||||||
def
|
def
|
||||||
@ -107,29 +156,32 @@ def
|
|||||||
-> Maybe (Pascal a)
|
-> Maybe (Pascal a)
|
||||||
-> ScopeM ()
|
-> ScopeM ()
|
||||||
def name ty body = do
|
def name ty body = do
|
||||||
define $ ScopedDecl
|
define (ppToText $ void name)
|
||||||
(void name)
|
$ ScopedDecl
|
||||||
(getRange $ infoOf name)
|
(getRange $ infoOf name)
|
||||||
((getRange . infoOf) <$> body)
|
((getRange . infoOf) <$> body)
|
||||||
((Left . void) <$> ty)
|
((Left . void) <$> ty)
|
||||||
|
[]
|
||||||
|
|
||||||
instance UpdateOver ScopeM Contract (Pascal a)
|
instance UpdateOver ScopeM Contract (Pascal a) where
|
||||||
|
before r _ = enter r
|
||||||
|
after _ _ = leave
|
||||||
|
|
||||||
instance HasRange a => UpdateOver ScopeM Declaration (Pascal a) where
|
instance HasRange a => UpdateOver ScopeM Declaration (Pascal a) where
|
||||||
before = \case
|
before _ = \case
|
||||||
TypeDecl ty body -> defType ty Star body
|
TypeDecl ty body -> defType ty Star body
|
||||||
_ -> skip
|
_ -> skip
|
||||||
|
|
||||||
instance HasRange a => UpdateOver ScopeM Binding (Pascal a) where
|
instance HasRange a => UpdateOver ScopeM Binding (Pascal a) where
|
||||||
before = \case
|
before r = \case
|
||||||
Function recur name _args ty body -> do
|
Function recur name _args ty body -> do
|
||||||
when recur do
|
when recur do
|
||||||
def name (Just ty) (Just body)
|
def name (Just ty) (Just body)
|
||||||
enter
|
enter r
|
||||||
|
|
||||||
_ -> enter
|
_ -> enter r
|
||||||
|
|
||||||
after = \case
|
after _ = \case
|
||||||
Irrefutable name body -> do leave; def name Nothing (Just body)
|
Irrefutable name body -> do leave; def name Nothing (Just body)
|
||||||
Var name ty body -> do leave; def name (Just ty) (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)
|
Const name ty body -> do leave; def name (Just ty) (Just body)
|
||||||
@ -139,7 +191,7 @@ instance HasRange a => UpdateOver ScopeM Binding (Pascal a) where
|
|||||||
def name (Just ty) (Just body)
|
def name (Just ty) (Just body)
|
||||||
|
|
||||||
instance HasRange a => UpdateOver ScopeM VarDecl (Pascal a) where
|
instance HasRange a => UpdateOver ScopeM VarDecl (Pascal a) where
|
||||||
after (Decl _ name ty) = def name (Just ty) Nothing
|
after _ (Decl _ name ty) = def name (Just ty) Nothing
|
||||||
|
|
||||||
instance UpdateOver ScopeM Mutable (Pascal a)
|
instance UpdateOver ScopeM Mutable (Pascal a)
|
||||||
instance UpdateOver ScopeM Type (Pascal a)
|
instance UpdateOver ScopeM Type (Pascal a)
|
||||||
@ -147,21 +199,21 @@ instance UpdateOver ScopeM Variant (Pascal a)
|
|||||||
instance UpdateOver ScopeM TField (Pascal a)
|
instance UpdateOver ScopeM TField (Pascal a)
|
||||||
|
|
||||||
instance HasRange a => UpdateOver ScopeM Expr (Pascal a) where
|
instance HasRange a => UpdateOver ScopeM Expr (Pascal a) where
|
||||||
before = \case
|
before r = \case
|
||||||
Let {} -> enter
|
Let {} -> enter r
|
||||||
Lambda {} -> enter
|
Lambda {} -> enter r
|
||||||
ForLoop k _ _ _ -> do
|
ForLoop k _ _ _ -> do
|
||||||
enter
|
enter r
|
||||||
def k Nothing Nothing
|
def k Nothing Nothing
|
||||||
|
|
||||||
ForBox k mv _ _ _ -> do
|
ForBox k mv _ _ _ -> do
|
||||||
enter
|
enter r
|
||||||
def k Nothing Nothing
|
def k Nothing Nothing
|
||||||
maybe skip (\v -> def v Nothing Nothing) mv
|
maybe skip (\v -> def v Nothing Nothing) mv
|
||||||
|
|
||||||
_ -> skip
|
_ -> skip
|
||||||
|
|
||||||
after = \case
|
after _ = \case
|
||||||
Let {} -> leave
|
Let {} -> leave
|
||||||
Lambda {} -> leave
|
Lambda {} -> leave
|
||||||
ForLoop {} -> leave
|
ForLoop {} -> leave
|
||||||
@ -169,8 +221,8 @@ instance HasRange a => UpdateOver ScopeM Expr (Pascal a) where
|
|||||||
_ -> skip
|
_ -> skip
|
||||||
|
|
||||||
instance HasRange a => UpdateOver ScopeM Alt (Pascal a) where
|
instance HasRange a => UpdateOver ScopeM Alt (Pascal a) where
|
||||||
before _ = enter
|
before r _ = enter r
|
||||||
after _ = leave
|
after _ _ = leave
|
||||||
|
|
||||||
instance UpdateOver ScopeM LHS (Pascal a)
|
instance UpdateOver ScopeM LHS (Pascal a)
|
||||||
instance UpdateOver ScopeM MapBinding (Pascal a)
|
instance UpdateOver ScopeM MapBinding (Pascal a)
|
||||||
@ -179,13 +231,15 @@ instance UpdateOver ScopeM FieldAssignment (Pascal a)
|
|||||||
instance UpdateOver ScopeM Constant (Pascal a)
|
instance UpdateOver ScopeM Constant (Pascal a)
|
||||||
|
|
||||||
instance HasRange a => UpdateOver ScopeM Pattern (Pascal a) where
|
instance HasRange a => UpdateOver ScopeM Pattern (Pascal a) where
|
||||||
before = \case
|
before _ = \case
|
||||||
IsVar n -> def n Nothing Nothing
|
IsVar n -> def n Nothing Nothing
|
||||||
_ -> skip
|
_ -> skip
|
||||||
|
|
||||||
instance UpdateOver ScopeM QualifiedName (Pascal a)
|
instance UpdateOver ScopeM QualifiedName (Pascal a)
|
||||||
instance UpdateOver ScopeM Path (Pascal a)
|
instance UpdateOver ScopeM Path (Pascal a)
|
||||||
instance UpdateOver ScopeM Name (Pascal a)
|
instance UpdateOver ScopeM Name (Pascal a) where
|
||||||
|
before range (Name raw) = do
|
||||||
|
modify $ addRef raw range
|
||||||
|
|
||||||
class HasEnv a where
|
class HasEnv a where
|
||||||
getEnv :: a -> Env
|
getEnv :: a -> Env
|
||||||
@ -201,5 +255,43 @@ data Scope = Scope { unScope :: [Text] }
|
|||||||
instance HasComments Scope where
|
instance HasComments Scope where
|
||||||
getComments = unScope
|
getComments = unScope
|
||||||
|
|
||||||
pinEnv :: Product xs -> ScopeM (Product (Env : xs))
|
-- pinEnv :: Product xs -> ScopeM (Product (Env : xs))
|
||||||
pinEnv xs = (`Cons` xs) <$> gets head
|
-- pinEnv xs = (`Cons` xs) <$> gets head
|
||||||
|
|
||||||
|
collectEnv :: Contains Range xs => Product xs -> ScopeM (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' :))
|
||||||
|
traceShowM ("distribute", e', e)
|
||||||
|
return $ ScopeTree e cs
|
||||||
|
|
||||||
|
pinEnv :: Contains Range xs => Scopes -> Product xs -> ScopeM (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) -> Pascal (Product (Env : xs))
|
||||||
|
ascribeEnv tree =
|
||||||
|
let
|
||||||
|
Cons scopes _ = traceShowId $ infoOf $ evalScopeM $ traverseTree collectEnv tree
|
||||||
|
distributed = evalState (traverseOnly distributeEnv scopes) []
|
||||||
|
in
|
||||||
|
-- distributed
|
||||||
|
evalScopeM $ traverseTree (pinEnv distributed) tree
|
@ -34,5 +34,5 @@ c i d =
|
|||||||
instance HasComments () where
|
instance HasComments () where
|
||||||
getComments () = []
|
getComments () = []
|
||||||
|
|
||||||
instance (Contains [Text] xs) => HasComments (Product xs) where
|
-- instance (Contains [Text] xs) => HasComments (Product xs) where
|
||||||
getComments = getElem
|
-- getComments = getElem
|
||||||
|
@ -23,6 +23,7 @@ module Pretty
|
|||||||
, sepByDot
|
, sepByDot
|
||||||
, mb
|
, mb
|
||||||
, sparseBlock
|
, sparseBlock
|
||||||
|
, color
|
||||||
|
|
||||||
-- * Full might of pretty printing
|
-- * Full might of pretty printing
|
||||||
, module Text.PrettyPrint
|
, module Text.PrettyPrint
|
||||||
@ -69,6 +70,12 @@ instance (Pretty1 p, Functor p, Pretty a) => Pretty (p a) where
|
|||||||
instance Pretty1 [] where
|
instance Pretty1 [] where
|
||||||
pp1 = list
|
pp1 = list
|
||||||
|
|
||||||
|
instance Pretty1 Maybe where
|
||||||
|
pp1 = maybe empty pp
|
||||||
|
|
||||||
|
instance {-# OVERLAPS #-} (Pretty a, Pretty b) => Pretty (Either a b) where
|
||||||
|
pp = either pp pp
|
||||||
|
|
||||||
-- | Common instance.
|
-- | Common instance.
|
||||||
instance Pretty Text where
|
instance Pretty Text where
|
||||||
pp = text . Text.unpack
|
pp = text . Text.unpack
|
||||||
@ -113,4 +120,12 @@ mb f = maybe empty (f . pp)
|
|||||||
|
|
||||||
-- | Pretty print as a vertical with elements separated by newline.
|
-- | Pretty print as a vertical with elements separated by newline.
|
||||||
sparseBlock :: Pretty a => [a] -> Doc
|
sparseBlock :: Pretty a => [a] -> Doc
|
||||||
sparseBlock = vcat . punctuate "\n" . map (($$ empty) . pp)
|
sparseBlock = vcat . punctuate "\n" . map (($$ empty) . pp)
|
||||||
|
|
||||||
|
type Color = Int
|
||||||
|
|
||||||
|
color :: Color -> Doc -> Doc
|
||||||
|
color c d = zeroWidthText begin <> d <> zeroWidthText end
|
||||||
|
where
|
||||||
|
begin = "\x1b[" ++ show (30 + c) ++ "m"
|
||||||
|
end = "\x1b[0m"
|
@ -1,6 +1,8 @@
|
|||||||
|
|
||||||
module Product where
|
module Product where
|
||||||
|
|
||||||
|
import qualified Data.Text as Text
|
||||||
|
|
||||||
import Pretty
|
import Pretty
|
||||||
|
|
||||||
data Product xs where
|
data Product xs where
|
||||||
@ -29,4 +31,9 @@ instance Pretty (Product '[]) where
|
|||||||
pp _ = "{}"
|
pp _ = "{}"
|
||||||
|
|
||||||
instance (Pretty x, Pretty (Product xs)) => Pretty (Product (x : xs)) where
|
instance (Pretty x, Pretty (Product xs)) => Pretty (Product (x : xs)) where
|
||||||
pp (Cons x xs) = pp x <+> "&" <+> pp xs
|
pp (Cons x xs) =
|
||||||
|
if Text.null $ Text.strip ppx
|
||||||
|
then pp xs
|
||||||
|
else pp ppx <+> "&" <+> pp xs
|
||||||
|
where
|
||||||
|
ppx = ppToText x
|
@ -39,6 +39,9 @@ instance Pretty Range where
|
|||||||
class HasRange a where
|
class HasRange a where
|
||||||
getRange :: a -> Range
|
getRange :: a -> Range
|
||||||
|
|
||||||
|
instance HasRange Range where
|
||||||
|
getRange = id
|
||||||
|
|
||||||
instance Contains Range xs => HasRange (Product xs) where
|
instance Contains Range xs => HasRange (Product xs) where
|
||||||
getRange = getElem
|
getRange = getElem
|
||||||
|
|
||||||
@ -54,3 +57,7 @@ instance Lattice Range where
|
|||||||
Range (ll1, lc1, _) (ll2, lc2, _) <? Range (rl1, rc1, _) (rl2, rc2, _) =
|
Range (ll1, lc1, _) (ll2, lc2, _) <? Range (rl1, rc1, _) (rl2, rc2, _) =
|
||||||
(rl1 < ll1 || rl1 == ll1 && rc1 <= lc1) &&
|
(rl1 < ll1 || rl1 == ll1 && rc1 <= lc1) &&
|
||||||
(rl2 > ll2 || rl2 == ll2 && rc2 >= lc2)
|
(rl2 > ll2 || rl2 == ll2 && rc2 >= lc2)
|
||||||
|
|
||||||
|
instance Eq Range where
|
||||||
|
Range (l, c, _) (r, d, _) == Range (l1, c1, _) (r1, d1, _) =
|
||||||
|
(l, c, r, d) == (l1, c1, r1, d1)
|
@ -10,17 +10,17 @@
|
|||||||
-}
|
-}
|
||||||
|
|
||||||
module Tree
|
module Tree
|
||||||
( -- * Tree type
|
-- ( -- * Tree type
|
||||||
Tree
|
-- Tree
|
||||||
, lookupTree
|
-- , lookupTree
|
||||||
, traverseTree
|
-- , traverseTree
|
||||||
, mk
|
-- , mk
|
||||||
, infoOf
|
-- , infoOf
|
||||||
|
|
||||||
-- * Callbacks on update
|
-- -- * Callbacks on update
|
||||||
, UpdateOver (..)
|
-- , UpdateOver (..)
|
||||||
, skip
|
-- , skip
|
||||||
)
|
-- )
|
||||||
where
|
where
|
||||||
|
|
||||||
import Data.Foldable
|
import Data.Foldable
|
||||||
@ -32,6 +32,7 @@ import Lattice
|
|||||||
import Comment
|
import Comment
|
||||||
import Pretty
|
import Pretty
|
||||||
import Error
|
import Error
|
||||||
|
import Range
|
||||||
|
|
||||||
import Debug.Trace
|
import Debug.Trace
|
||||||
|
|
||||||
@ -97,20 +98,22 @@ lookupTree
|
|||||||
:: forall fs info
|
:: forall fs info
|
||||||
. ( Apply Foldable fs
|
. ( Apply Foldable fs
|
||||||
, Apply Functor fs
|
, Apply Functor fs
|
||||||
|
, HasRange info
|
||||||
)
|
)
|
||||||
=> (info -> Bool)
|
=> Range
|
||||||
-> Tree fs info
|
-> Tree fs info
|
||||||
-> Maybe (Tree fs info)
|
-> Maybe (Tree fs info)
|
||||||
lookupTree rightInfo = go
|
lookupTree target = go
|
||||||
where
|
where
|
||||||
go :: Tree fs info -> Maybe (Tree fs info)
|
go :: Tree fs info -> Maybe (Tree fs info)
|
||||||
go tree = do
|
go tree = do
|
||||||
if rightInfo (infoOf tree)
|
if target <? getRange (infoOf tree)
|
||||||
then getFirst $ foldMap (First . go) (layers tree) <> First (Just tree)
|
then getFirst $ foldMap (First . go) (layers tree) <> First (Just tree)
|
||||||
else Nothing
|
else Nothing
|
||||||
|
|
||||||
layers :: (Apply Foldable fs) => Tree fs info -> [Tree fs info]
|
layers :: (Apply Foldable fs) => Tree fs info -> [Tree fs info]
|
||||||
layers (Tree (Right (_, ls))) = toList ls
|
layers (Tree (Right (_, ls))) = toList ls
|
||||||
|
|
||||||
-- | Traverse the tree over some monad that exports its methods.
|
-- | Traverse the tree over some monad that exports its methods.
|
||||||
--
|
--
|
||||||
-- For each tree piece, will call `before` and `after` callbacks.
|
-- For each tree piece, will call `before` and `after` callbacks.
|
||||||
@ -120,25 +123,69 @@ traverseTree
|
|||||||
, Apply Foldable fs
|
, Apply Foldable fs
|
||||||
, Apply Functor fs
|
, Apply Functor fs
|
||||||
, Apply Traversable fs
|
, Apply Traversable fs
|
||||||
|
, HasRange a
|
||||||
)
|
)
|
||||||
=> (a -> m b) -> Tree fs a -> m (Tree fs b)
|
=> (a -> m b) -> Tree fs a -> m (Tree fs b)
|
||||||
traverseTree act = go
|
traverseTree act = go
|
||||||
where
|
where
|
||||||
go (Tree (Right (a, union))) = do
|
go (Tree (Right (a, union))) = do
|
||||||
b <- act a
|
b <- act a
|
||||||
before union
|
before (getRange a) union
|
||||||
union' <- traverse go union
|
union' <- traverse go union
|
||||||
after union
|
after (getRange a) union
|
||||||
return (Tree (Right (b, union')))
|
return (Tree (Right (b, union')))
|
||||||
|
|
||||||
go (Tree (Left err)) = do
|
go (Tree (Left err)) = do
|
||||||
err' <- traverse act err
|
err' <- traverse act err
|
||||||
return (Tree (Left err'))
|
return (Tree (Left err'))
|
||||||
|
|
||||||
|
traverseOnly
|
||||||
|
:: forall f fs m a
|
||||||
|
. ( UpdateOver m f (Tree fs a)
|
||||||
|
, UpdateOver m (Sum fs) (Tree fs a)
|
||||||
|
, Element f fs
|
||||||
|
, Apply Foldable fs
|
||||||
|
, Apply Functor fs
|
||||||
|
, Apply Traversable fs
|
||||||
|
, Traversable f
|
||||||
|
, HasRange a
|
||||||
|
, Show (f (Tree fs a))
|
||||||
|
, Show a
|
||||||
|
)
|
||||||
|
=> (f (Tree fs a) -> m (f (Tree fs a)))
|
||||||
|
-> Tree fs a -> m (Tree fs a)
|
||||||
|
traverseOnly act = go
|
||||||
|
where
|
||||||
|
go (match -> Just (r, fa)) = do
|
||||||
|
traceShowM ("traversingA", fa)
|
||||||
|
before (getRange r) fa
|
||||||
|
fb <- act fa
|
||||||
|
fc <- traverse go fb
|
||||||
|
after (getRange r) fa
|
||||||
|
return $ mk r fc
|
||||||
|
|
||||||
|
go tree@(Tree (Right (r, union))) = do
|
||||||
|
traceShowM ("traversingB", ())
|
||||||
|
before (getRange r) union
|
||||||
|
union' <- traverse go union
|
||||||
|
after (getRange r) union
|
||||||
|
return $ Tree $ Right (r, union')
|
||||||
|
|
||||||
|
go tree = return tree
|
||||||
|
|
||||||
-- | Make a tree out of a layer and an info.
|
-- | Make a tree out of a layer and an info.
|
||||||
mk :: (Functor f, Element f fs) => info -> f (Tree fs info) -> Tree fs info
|
mk :: (Functor f, Element f fs) => info -> f (Tree fs info) -> Tree fs info
|
||||||
mk i fx = Tree $ Right (i, inject fx)
|
mk i fx = Tree $ Right (i, inject fx)
|
||||||
|
|
||||||
|
match
|
||||||
|
:: (Functor f, Element f fs)
|
||||||
|
=> Tree fs info
|
||||||
|
-> Maybe (info, f (Tree fs info))
|
||||||
|
match (Tree (Left _)) = Nothing
|
||||||
|
match (Tree (Right (r, it))) = do
|
||||||
|
f <- project it
|
||||||
|
return (r, f)
|
||||||
|
|
||||||
-- | Get info from the tree.
|
-- | Get info from the tree.
|
||||||
infoOf :: Tree fs info -> info
|
infoOf :: Tree fs info -> info
|
||||||
infoOf = either eInfo fst . unTree
|
infoOf = either eInfo fst . unTree
|
||||||
@ -154,11 +201,11 @@ instance Apply Foldable fs => HasErrors (Tree fs info) info where
|
|||||||
|
|
||||||
-- | Update callbacks for a @f a@ while working inside monad @m@.
|
-- | Update callbacks for a @f a@ while working inside monad @m@.
|
||||||
class Monad m => UpdateOver m f a where
|
class Monad m => UpdateOver m f a where
|
||||||
before :: f a -> m ()
|
before :: Range -> f a -> m ()
|
||||||
after :: f a -> m ()
|
after :: Range -> f a -> m ()
|
||||||
|
|
||||||
before _ = skip
|
before _ _ = skip
|
||||||
after _ = skip
|
after _ _ = skip
|
||||||
|
|
||||||
-- | Do nothing.
|
-- | Do nothing.
|
||||||
skip :: Monad m => m ()
|
skip :: Monad m => m ()
|
||||||
@ -169,5 +216,5 @@ instance Monad m => UpdateOver m (Sum '[]) a where
|
|||||||
after = error "Sum.empty"
|
after = error "Sum.empty"
|
||||||
|
|
||||||
instance (UpdateOver m f a, UpdateOver m (Sum fs) a) => UpdateOver m (Sum (f : fs)) a where
|
instance (UpdateOver m f a, UpdateOver m (Sum fs) a) => UpdateOver m (Sum (f : fs)) a where
|
||||||
before = either before before . decompose
|
before r = either (before r) (before r) . decompose
|
||||||
after = either after after . decompose
|
after r = either (after r) (after r) . decompose
|
||||||
|
Loading…
Reference in New Issue
Block a user