174 lines
4.3 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-09 15:56:11 +04:00
, lookupTree
, 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
2020-06-09 15:56:11 +04:00
import Data.Foldable
import Data.List
2020-06-08 01:16:33 +04:00
import Data.Sum
2020-06-09 15:56:11 +04:00
import Data.Monoid (First(..), getFirst)
2020-06-08 01:16:33 +04:00
2020-06-01 18:17:33 +04:00
import Lattice
import Comment
2020-06-01 18:17:33 +04:00
import Pretty
import Error
2020-06-09 15:56:11 +04:00
import Debug.Trace
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-08 01:16:33 +04:00
{ unTree :: Either (Error info) (info, Sum layers (Tree layers info))
2020-06-01 18:17:33 +04:00
}
2020-06-09 15:56:11 +04:00
dumpTree
:: (Apply Functor layers, Apply Foldable layers, HasComments info, Pretty1 (Sum layers), Pretty info)
=> Tree layers info
-> Doc
dumpTree (Tree tree) =
case tree of
Left e -> "ERR"
Right (i, ls) ->
pp (Tree tree) `indent` block (dumpTree <$> toList ls)
2020-06-08 01:16:33 +04:00
instance Apply Functor 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-08 01:16:33 +04:00
instance Apply Foldable 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
2020-06-08 01:16:33 +04:00
( Apply Functor layers
2020-06-01 18:17:33 +04:00
, HasComments info
2020-06-08 01:16:33 +04:00
, Pretty1 (Sum layers)
, Pretty info
2020-06-01 18:17:33 +04:00
)
=>
Show (Tree layers info)
where
show = show . pp
instance {-# OVERLAPS #-}
( HasComments info
2020-06-08 01:16:33 +04:00
, Apply Functor fs
, Pretty1 (Sum 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-09 15:56:11 +04:00
lookupTree
:: forall fs info
. ( Apply Foldable fs
, Apply Functor fs
2020-06-01 18:17:33 +04:00
)
2020-06-09 15:56:11 +04:00
=> (info -> Bool)
2020-06-01 18:17:33 +04:00
-> Tree fs info
2020-06-09 15:56:11 +04:00
-> Maybe (Tree fs info)
lookupTree rightInfo = go
2020-06-01 18:17:33 +04:00
where
2020-06-09 15:56:11 +04:00
go :: Tree fs info -> Maybe (Tree fs info)
go tree = do
if rightInfo (infoOf tree)
then getFirst $ foldMap (First . go) (layers tree) <> First (Just tree)
else Nothing
layers :: (Apply Foldable fs) => Tree fs info -> [Tree fs info]
layers (Tree (Right (_, ls))) = toList ls
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-08 01:16:33 +04:00
:: ( UpdateOver m (Sum fs) (Tree fs a)
, Apply Foldable fs
, Apply Functor fs
, Apply Traversable fs
2020-06-01 18:17:33 +04:00
)
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.
2020-06-08 01:16:33 +04:00
mk :: (Functor f, Element f fs) => info -> f (Tree fs info) -> Tree fs info
mk i fx = Tree $ Right (i, inject 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
2020-06-08 01:16:33 +04:00
instance Apply Foldable 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 ()
2020-06-08 01:16:33 +04:00
instance Monad m => UpdateOver m (Sum '[]) a where
before = error "Sum.empty"
after = error "Sum.empty"
2020-06-04 17:40:38 +04:00
2020-06-08 01:16:33 +04:00
instance (UpdateOver m f a, UpdateOver m (Sum fs) a) => UpdateOver m (Sum (f : fs)) a where
before = either before before . decompose
after = either after after . decompose