2020-06-01 18:17:33 +04:00
|
|
|
|
2020-06-04 13:48:04 +04:00
|
|
|
{- | The carrier type for AST.
|
|
|
|
|
|
|
|
"Untypedness" of the tree is a payoff to ablity to stop and navigate
|
|
|
|
anywhere, not just inside the expression context.
|
|
|
|
|
|
|
|
Is a `Functor` and `Foldable` over its @info@ parameter.
|
|
|
|
Is not `Traversable`, because this will definitely not preserve scope.
|
|
|
|
Use `updateTree` instead of `traverse`/`for`.
|
|
|
|
-}
|
|
|
|
|
2020-06-01 22:02:16 +04:00
|
|
|
module Tree
|
2020-06-04 17:40:38 +04:00
|
|
|
( -- * Tree type
|
|
|
|
Tree
|
2020-06-01 22:02:16 +04:00
|
|
|
, spineTo
|
|
|
|
, updateTree
|
|
|
|
, mk
|
|
|
|
, infoOf
|
2020-06-04 17:40:38 +04:00
|
|
|
|
|
|
|
-- * Callbacks on update
|
|
|
|
, UpdateOver (..)
|
|
|
|
, skip
|
2020-06-01 22:02:16 +04:00
|
|
|
)
|
|
|
|
where
|
2020-06-01 18:17:33 +04:00
|
|
|
|
|
|
|
import Data.Fix
|
|
|
|
import Data.Functor.Compose
|
2020-06-04 13:48:04 +04:00
|
|
|
import Data.Foldable
|
2020-06-01 18:17:33 +04:00
|
|
|
|
|
|
|
import Union
|
|
|
|
import Lattice
|
2020-06-04 19:15:14 +04:00
|
|
|
import Comment
|
2020-06-01 18:17:33 +04:00
|
|
|
import Pretty
|
|
|
|
import Error
|
|
|
|
|
2020-06-01 22:02:16 +04:00
|
|
|
-- | A tree, where each layer is one of @layers@ `Functor`s.
|
|
|
|
--
|
|
|
|
-- Is equipped with @info@.
|
|
|
|
--
|
|
|
|
-- Can contain `Error` instead of all the above.
|
|
|
|
--
|
2020-06-01 18:17:33 +04:00
|
|
|
newtype Tree layers info = Tree
|
2020-06-04 16:29:06 +04:00
|
|
|
{ unTree :: Fix (Either (Error info) `Compose` (,) info `Compose` Union layers)
|
2020-06-01 18:17:33 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
instance (Functor (Union layers)) => Functor (Tree layers) where
|
|
|
|
fmap f (Tree fixpoint) = Tree $ cata (Fix . go) fixpoint
|
|
|
|
where
|
2020-06-04 16:29:06 +04:00
|
|
|
go (Compose (Left err)) = Compose $ Left $ fmap f err
|
2020-06-01 18:17:33 +04:00
|
|
|
go (Compose (Right (Compose (a, rest)))) =
|
|
|
|
Compose $ Right $ Compose (f a, rest)
|
|
|
|
|
2020-06-04 13:48:04 +04:00
|
|
|
instance (Functor (Union layers), Foldable (Union layers)) => Foldable (Tree layers) where
|
|
|
|
foldMap f (Tree fixpoint) = cata go fixpoint
|
|
|
|
where
|
2020-06-04 16:29:06 +04:00
|
|
|
go (Compose (Left err)) = foldMap f err
|
2020-06-04 13:48:04 +04:00
|
|
|
go (Compose (Right (Compose (a, rest)))) = f a <> fold rest
|
|
|
|
|
2020-06-01 18:17:33 +04:00
|
|
|
instance
|
2020-06-04 16:29:06 +04:00
|
|
|
( Functor (Union layers)
|
2020-06-01 18:17:33 +04:00
|
|
|
, HasComments info
|
2020-06-04 16:29:06 +04:00
|
|
|
, Pretty (Union layers Doc)
|
|
|
|
, Pretty info
|
2020-06-01 18:17:33 +04:00
|
|
|
)
|
|
|
|
=>
|
|
|
|
Show (Tree layers info)
|
|
|
|
where
|
|
|
|
show = show . pp
|
|
|
|
|
|
|
|
instance {-# OVERLAPS #-}
|
|
|
|
( HasComments info
|
2020-06-04 16:29:06 +04:00
|
|
|
, Functor (Union fs)
|
|
|
|
, Pretty (Union fs Doc)
|
|
|
|
, Pretty info
|
2020-06-01 18:17:33 +04:00
|
|
|
)
|
|
|
|
=>
|
|
|
|
Pretty (Tree fs info)
|
|
|
|
where
|
|
|
|
pp (Tree it) = cata aux it
|
|
|
|
where
|
|
|
|
aux (Compose (Left err)) = pp err
|
|
|
|
aux (Compose (Right (Compose (info, fTree)))) = c info $ pp fTree
|
|
|
|
|
2020-06-01 22:02:16 +04:00
|
|
|
-- | Return all subtrees that cover the range, ascending in size.
|
2020-06-01 18:17:33 +04:00
|
|
|
spineTo
|
|
|
|
:: ( Lattice info
|
|
|
|
, Foldable (Union fs)
|
|
|
|
)
|
|
|
|
=> info
|
|
|
|
-> Tree fs info
|
|
|
|
-> [Tree fs info]
|
|
|
|
spineTo info = reverse . go . unTree
|
|
|
|
where
|
|
|
|
go tree@(Fix (Compose (Right (Compose (info', fres))))) =
|
|
|
|
if info <? info'
|
|
|
|
then Tree tree : foldMap go fres
|
|
|
|
else []
|
|
|
|
|
|
|
|
go _ = []
|
|
|
|
|
2020-06-04 13:48:04 +04:00
|
|
|
-- | Traverse the tree over some monad that exports its methods.
|
2020-06-01 22:02:16 +04:00
|
|
|
--
|
|
|
|
-- For each tree piece, will call `before` and `after` callbacks.
|
|
|
|
--
|
2020-06-01 18:17:33 +04:00
|
|
|
updateTree
|
|
|
|
:: ( UpdateOver m (Union fs) (Tree fs a)
|
|
|
|
, Traversable (Union fs)
|
|
|
|
)
|
2020-06-04 13:48:04 +04:00
|
|
|
=> (a -> m b) -> Tree fs a -> m (Tree fs b)
|
2020-06-01 18:17:33 +04:00
|
|
|
updateTree act = fmap Tree . go . unTree
|
|
|
|
where
|
|
|
|
go (Fix (Compose (Right (Compose (a, union))))) = do
|
|
|
|
b <- act a
|
|
|
|
before (Tree <$> union)
|
|
|
|
union' <- traverse go union
|
|
|
|
after (Tree <$> union)
|
|
|
|
return (Fix (Compose (Right (Compose (b, union')))))
|
|
|
|
|
|
|
|
go (Fix (Compose (Left err))) = do
|
2020-06-04 16:29:06 +04:00
|
|
|
err' <- traverse act err
|
|
|
|
return (Fix (Compose (Left err')))
|
2020-06-01 18:17:33 +04:00
|
|
|
|
|
|
|
-- | Make a tree out of a layer and an info.
|
|
|
|
mk :: (Functor f, Member f fs) => info -> f (Tree fs info) -> Tree fs info
|
|
|
|
mk i fx = Tree $ Fix $ Compose $ Right $ Compose (i, inj $ fmap unTree fx)
|
|
|
|
|
2020-06-01 22:02:16 +04:00
|
|
|
-- | Get info from the tree.
|
2020-06-04 16:34:58 +04:00
|
|
|
infoOf :: Tree fs info -> info
|
|
|
|
infoOf = either eInfo (fst . getCompose) . getCompose . unFix . unTree
|
2020-06-01 18:17:33 +04:00
|
|
|
|
2020-06-04 16:29:06 +04:00
|
|
|
instance Stubbed (Tree fs info) info where
|
2020-06-01 22:02:16 +04:00
|
|
|
stub = Tree . Fix . Compose . Left
|
2020-06-01 18:17:33 +04:00
|
|
|
|
2020-06-04 16:29:06 +04:00
|
|
|
instance Foldable (Union fs) => HasErrors (Tree fs info) info where
|
2020-06-01 18:17:33 +04:00
|
|
|
errors = go . unTree
|
|
|
|
where
|
|
|
|
go (Fix (Compose (Left err))) = pure err
|
2020-06-04 17:40:38 +04:00
|
|
|
go (Fix rest) = foldMap go rest
|
|
|
|
|
|
|
|
-- | Update callbacks for a @f a@ while working inside monad @m@.
|
|
|
|
class Monad m => UpdateOver m f a where
|
|
|
|
before :: f a -> m ()
|
|
|
|
after :: f a -> m ()
|
|
|
|
|
|
|
|
before _ = skip
|
|
|
|
after _ = skip
|
|
|
|
|
|
|
|
-- | Do nothing.
|
|
|
|
skip :: Monad m => m ()
|
|
|
|
skip = return ()
|
|
|
|
|
|
|
|
instance Monad m => UpdateOver m (Union '[]) a where
|
|
|
|
before = error "Union.empty"
|
|
|
|
after = error "Union.empty"
|
|
|
|
|
|
|
|
instance (UpdateOver m f a, UpdateOver m (Union fs) a) => UpdateOver m (Union (f : fs)) a where
|
|
|
|
before = eliminate before before
|
|
|
|
after = eliminate after after
|