{-# LANGUAGE ScopedTypeVariables, DeriveFunctor #-}
-- Most of this module follows the Haskell report, https://www.haskell.org/onlinereport/lexemes.html
module Paren(Paren(..), parens, unparens) where
import Data.Tuple.Extra
import Lexer(Lexeme(..))
-- | A list of items which are paranthesised.
data Paren a
= Item a -- Indiviaaul item
| Paren a [Paren a] a -- parenthesise, open, inner, close
deriving (Show,Eq,Functor)
parenOn :: forall a b . Eq b => (a -> b) -> [(b, b)] -> [a] -> [Paren a]
parenOn proj pairs = fst . go Nothing
where
-- invariant: if first argument is Nothing, second component of result will be Nothing
go :: Maybe b -> [a] -> ([Paren a], Maybe (a, [a]))
go (Just close) (x:xs) | close == proj x = ([], Just (x, xs))
go close (start:xs)
| Just end <- lookup (proj start) pairs
, (inner, res) <- go (Just end) xs
= case res of
Nothing -> (Item start : inner, Nothing)
Just (end, xs) -> first (Paren start inner end :) $ go close xs
go close (x:xs) = first (Item x :) $ go close xs
go close [] = ([], Nothing)
parens :: [Lexeme] -> [Paren Lexeme]
parens = parenOn lexeme [("(",")"),("[","]"),("{","}"),("`","`")]
unparens :: [Paren a] -> [a]
unparens = concatMap unparen
unparen :: Paren a -> [a]
unparen (Item x) = [x]
unparen (Paren a b c) = [a] ++ unparens b ++ [c]