154 lines
3.7 KiB
Haskell
Raw Normal View History

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
, traverseTree
2020-06-01 22:02:16 +04:00
, 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 Union
import Lattice
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
{ unTree :: Either (Error info) (info, Union layers (Tree layers info))
2020-06-01 18:17:33 +04:00
}
instance (Functor (Union layers)) => Functor (Tree layers) where
fmap f = go
2020-06-01 18:17:33 +04:00
where
go (Tree (Left err)) = Tree $ Left $ fmap f err
go (Tree (Right (a, rest))) = Tree $ Right (f a, fmap go rest)
2020-06-01 18:17:33 +04:00
2020-06-04 13:48:04 +04:00
instance (Functor (Union layers), Foldable (Union layers)) => Foldable (Tree layers) where
foldMap f = go
2020-06-04 13:48:04 +04:00
where
go (Tree (Left err)) = foldMap f err
go (Tree (Right (a, rest))) = f a <> foldMap go rest
2020-06-04 13:48:04 +04:00
2020-06-01 18:17:33 +04:00
instance
( Functor (Union layers)
2020-06-01 18:17:33 +04:00
, HasComments info
, Pretty1 (Union layers)
, Pretty info
2020-06-01 18:17:33 +04:00
)
=>
Show (Tree layers info)
where
show = show . pp
instance {-# OVERLAPS #-}
( HasComments info
, Functor (Union fs)
, Pretty1 (Union fs)
, Pretty info
2020-06-01 18:17:33 +04:00
)
=>
Pretty (Tree fs info)
where
pp = go
2020-06-01 18:17:33 +04:00
where
go (Tree (Left err)) = pp err
go (Tree (Right (info, fTree))) = c info $ pp fTree
2020-06-01 18:17:33 +04:00
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
2020-06-01 18:17:33 +04:00
where
go tree@(Tree (Right (info', fres))) =
2020-06-01 18:17:33 +04:00
if info <? info'
then tree : foldMap go fres
2020-06-01 18:17:33 +04:00
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.
--
traverseTree
2020-06-01 18:17:33 +04:00
:: ( 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)
traverseTree act = go
2020-06-01 18:17:33 +04:00
where
go (Tree (Right (a, union))) = do
2020-06-01 18:17:33 +04:00
b <- act a
before union
2020-06-01 18:17:33 +04:00
union' <- traverse go union
after union
return (Tree (Right (b, union')))
2020-06-01 18:17:33 +04:00
go (Tree (Left err)) = do
err' <- traverse act err
return (Tree (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 $ Right (i, inj fx)
2020-06-01 18:17:33 +04:00
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 . unTree
2020-06-01 18:17:33 +04:00
instance Stubbed (Tree fs info) info where
stub = Tree . Left
2020-06-01 18:17:33 +04:00
instance Foldable (Union fs) => HasErrors (Tree fs info) info where
errors = go
2020-06-01 18:17:33 +04:00
where
go (Tree (Left err)) = pure err
go (Tree (Right (_, rest))) = foldMap go rest
2020-06-04 17:40:38 +04:00
-- | 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