134 lines
3.5 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
( Tree
, spineTo
, updateTree
, mk
, infoOf
)
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 Update
import Lattice
import HasComments
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 :: 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
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
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
( Functor (Union layers)
2020-06-01 18:17:33 +04:00
, HasComments info
, 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
, 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
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
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
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
go (Fix rest) = foldMap go rest