[WIP] Implement a loader of Env from a ScopeTree

This commit is contained in:
Kirill Andreev 2020-06-10 22:37:02 +04:00
parent 9f124bf5af
commit 8d61a36918
No known key found for this signature in database
GPG Key ID: CF7DA79DE4785A47
10 changed files with 309 additions and 103 deletions

View File

@ -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 ()

View File

@ -3,6 +3,7 @@ name: squirrel
dependencies: dependencies:
- base - base
- bytestring - bytestring
- containers
- data-default - data-default
- mtl - mtl
- pretty - pretty

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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)

View File

@ -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