-- | Binary tree, useful to build /Abstract Syntax Tree/ (AST)
-- made of applications of tokens.
module Language.Symantic.Grammar.BinTree where

import Data.Semigroup (Semigroup(..))

-- * Type 'BinTree'
-- | /Binary Tree/.
data BinTree a
 =   BinTree0 a
 |   BinTree2 (BinTree a) (BinTree a)
 deriving (Eq, Show)

instance Semigroup (BinTree a) where
	(<>) = BinTree2
instance Functor BinTree where
	fmap f (BinTree0 a)   = BinTree0 (f a)
	fmap f (BinTree2 x y) = BinTree2 (fmap f x) (fmap f y)
instance Applicative BinTree where
	pure = BinTree0
	BinTree0 f     <*> BinTree0 a   = BinTree0 (f a)
	BinTree0 f     <*> BinTree2 x y = BinTree2 (f  <$> x) (f  <$> y)
	BinTree2 fx fy <*> a            = BinTree2 (fx <*> a) (fy <*> a)
instance Monad BinTree where
	return = BinTree0
	BinTree0 a   >>= f = f a
	BinTree2 x y >>= f = BinTree2 (x >>= f) (y >>= f)
instance Foldable BinTree where
	foldMap f (BinTree0 a)   = f a
	foldMap f (BinTree2 x y) = foldMap f x `mappend` foldMap f y
	foldr f acc (BinTree0 a)   = f a acc
	foldr f acc (BinTree2 x y) = foldr f (foldr f acc y) x
	foldl f acc (BinTree0 a)   = f acc a
	foldl f acc (BinTree2 x y) = foldl f (foldl f acc x) y
instance Traversable BinTree where
	traverse f (BinTree0 a)   = BinTree0 <$> f a
	traverse f (BinTree2 x y) = BinTree2 <$> traverse f x <*> traverse f y

-- | Collapse depth-first given 'BinTree' with given function.
--
-- Useful to apply all arguments.
collapseBT :: (a -> a -> a) -> BinTree a -> a
collapseBT _f (BinTree0 x) = x
collapseBT f (BinTree2 x y) = collapseBT f x `f` collapseBT f y