{-# LANGUAGE DefaultSignatures #-} {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE TemplateHaskell #-} module Symantic.Parser.Grammar.Combinators where import Data.Function ((.), flip, const) import Data.Bool (Bool(..), not, (||)) import Data.Char (Char) import Data.Either (Either(..)) import Data.Eq (Eq(..)) import Data.Int (Int) -- import Data.Kind (Type) import Data.Maybe (Maybe(..)) import Data.String (String) import Language.Haskell.TH (TExpQ) -- import qualified Data.Functor as F import qualified Prelude as Pre import qualified Data.List as List import Symantic.Base.Univariant import qualified Symantic.Parser.Staging as Hask -- * Class 'Applicable' class Applicable repr where (<$>) :: Hask.Runtime (a -> b) -> repr a -> repr b (<$>) f = (pure f <*>) (<&>) :: repr a -> Hask.Runtime (a -> b) -> repr b (<&>) = flip (<$>) (<$) :: Hask.Runtime a -> repr b -> repr a (<$) x = (pure x <*) ($>) :: repr a -> Hask.Runtime b -> repr b ($>) = flip (<$) --type Pure repr :: Type -> Type pure :: Hask.Runtime a -> repr a default pure :: Liftable repr => Applicable (Unlift repr) => Hask.Runtime a -> repr a pure = lift . pure (<*>) :: repr (a -> b) -> repr a -> repr b default (<*>) :: Liftable repr => Applicable (Unlift repr) => repr (a -> b) -> repr a -> repr b (<*>) = lift2 (<*>) liftA2 :: Hask.Runtime (a -> b -> c) -> repr a -> repr b -> repr c liftA2 f x = (<*>) (f <$> x) (*>) :: repr a -> repr b -> repr b x *> y = (Hask.id <$ x) <*> y (<*) :: repr a -> repr b -> repr a (<*) = liftA2 Hask.const {- (<**>) :: repr a -> repr (a -> b) -> repr b (<**>) = liftA2 (\a f -> f a) -} infixl 4 <$>, <&>, <$, $>, <*>, <*, *> infixl 4 <**> (<**>) :: Applicable repr => repr a -> repr (a -> b) -> repr b (<**>) = liftA2 (Hask.flip Hask..@ (Hask.$)) -- * Class 'Alternable' class Alternable repr where (<|>) :: repr a -> repr a -> repr a empty :: repr a try :: repr a -> repr a default (<|>) :: Liftable repr => Alternable (Unlift repr) => repr a -> repr a -> repr a default empty :: Liftable repr => Alternable (Unlift repr) => repr a default try :: Liftable repr => Alternable (Unlift repr) => repr a -> repr a (<|>) = lift2 (<|>) empty = lift empty try = lift1 try infixl 3 <|> infixl 3 <+> (<+>) :: Applicable repr => Alternable repr => repr a -> repr b -> repr (Either a b) p <+> q = Hask.Runtime (Hask.Eval Left) (Hask.Code [||Left||]) <$> p <|> Hask.Runtime (Hask.Eval Right) (Hask.Code [||Right||]) <$> q optionally :: Applicable repr => Alternable repr => repr a -> Hask.Runtime b -> repr b optionally p x = p $> x <|> pure x optional :: Applicable repr => Alternable repr => repr a -> repr () optional = flip optionally Hask.unit option :: Applicable repr => Alternable repr => Hask.Runtime a -> repr a -> repr a option x p = p <|> pure x choice :: Alternable repr => [repr a] -> repr a choice = List.foldr (<|>) empty maybeP :: Applicable repr => Alternable repr => repr a -> repr (Maybe a) maybeP p = option (Hask.Runtime (Hask.Eval Nothing) (Hask.Code [||Nothing||])) (Hask.Runtime (Hask.Eval Just) (Hask.Code [||Just||]) <$> p) manyTill :: Applicable repr => Alternable repr => repr a -> repr b -> repr [a] manyTill p end = let go = end $> Hask.nil <|> p <:> go in go -- * Class 'Selectable' class Selectable repr where branch :: repr (Either a b) -> repr (a -> c) -> repr (b -> c) -> repr c default branch :: Liftable repr => Selectable (Unlift repr) => repr (Either a b) -> repr (a -> c) -> repr (b -> c) -> repr c branch = lift3 branch class Matchable repr where conditional :: Eq a => [Hask.Runtime (a -> Bool)] -> [repr b] -> repr a -> repr b -> repr b default conditional :: Unliftable repr => Liftable repr => Matchable (Unlift repr) => Eq a => [Hask.Runtime (a -> Bool)] -> [repr b] -> repr a -> repr b -> repr b conditional cs bs = lift2 (conditional cs (unlift Pre.<$> bs)) match :: Eq a => [Hask.Runtime a] -> repr a -> (Hask.Runtime a -> repr b) -> repr b -> repr b match as a a2b = conditional (Hask.eq Pre.<$> as) (a2b Pre.<$> as) a -- * Class 'Foldable' class Foldable repr where chainPre :: repr (a -> a) -> repr a -> repr a chainPost :: repr a -> repr (a -> a) -> repr a default chainPre :: Liftable repr => Foldable (Unlift repr) => repr (a -> a) -> repr a -> repr a default chainPost :: Liftable repr => Foldable (Unlift repr) => repr a -> repr (a -> a) -> repr a chainPre = lift2 chainPre chainPost = lift2 chainPost {- conditional :: Selectable repr => [(Hask.Runtime (a -> Bool), repr b)] -> repr a -> repr b -> repr b conditional cs p def = match p fs qs def where (fs, qs) = List.unzip cs -} -- * Class 'Charable' class Charable repr where satisfy :: Hask.Runtime (Char -> Bool) -> repr Char default satisfy :: Liftable repr => Charable (Unlift repr) => Hask.Runtime (Char -> Bool) -> repr Char satisfy = lift . satisfy -- * Class 'Lookable' class Lookable repr where look :: repr a -> repr a negLook :: repr a -> repr () default look :: Liftable repr => Lookable (Unlift repr) => repr a -> repr a default negLook :: Liftable repr => Lookable (Unlift repr) => repr a -> repr () look = lift1 look negLook = lift1 negLook {-# INLINE (<:>) #-} infixl 4 <:> (<:>) :: Applicable repr => repr a -> repr [a] -> repr [a] (<:>) = liftA2 Hask.cons sequence :: Applicable repr => [repr a] -> repr [a] sequence = List.foldr (<:>) (pure Hask.nil) traverse :: Applicable repr => (a -> repr b) -> [a] -> repr [b] traverse f = sequence . List.map f repeat :: Applicable repr => Int -> repr a -> repr [a] repeat n p = traverse (const p) [1..n] between :: Applicable repr => repr o -> repr c -> repr a -> repr a between open close p = open *> p <* close string :: Applicable repr => Charable repr => String -> repr String string = traverse char -- oneOf :: [Char] -> repr Char -- oneOf cs = satisfy (makeQ (flip elem cs) [||\c -> $$(ofChars cs [||c||])||]) noneOf :: Charable repr => String -> repr Char noneOf cs = satisfy (Hask.Runtime (Hask.Eval (not . flip List.elem cs)) (Hask.Code [||\c -> not $$(ofChars cs [||c||])||])) ofChars :: String -> TExpQ Char -> TExpQ Bool ofChars = List.foldr (\c rest qc -> [|| c == $$qc || $$(rest qc) ||]) (const [||False||]) token :: Applicable repr => Alternable repr => Charable repr => String -> repr String token = try . string eof :: Charable repr => Lookable repr => repr () eof = negLook item more :: Applicable repr => Charable repr => Lookable repr => repr () more = look (void item) char :: Applicable repr => Charable repr => Char -> repr Char char c = satisfy (Hask.eq (Hask.char c)) $> Hask.char c item :: Charable repr => repr Char item = satisfy (Hask.const Hask..@ Hask.bool True) -- Composite Combinators -- someTill :: repr a -> repr b -> repr [a] -- someTill p end = negLook end *> (p <:> manyTill p end) void :: Applicable repr => repr a -> repr () void p = p *> unit unit :: Applicable repr => repr () unit = pure Hask.unit {- constp :: Applicable repr => repr a -> repr (b -> a) constp = (Hask.const <$>) -- Alias Operations infixl 1 >> (>>) :: Applicable repr => repr a -> repr b -> repr b (>>) = (*>) -- Monoidal Operations infixl 4 <~> (<~>) :: Applicable repr => repr a -> repr b -> repr (a, b) (<~>) = liftA2 (Hask.runtime (,)) infixl 4 <~ (<~) :: Applicable repr => repr a -> repr b -> repr a (<~) = (<*) infixl 4 ~> (~>) :: Applicable repr => repr a -> repr b -> repr b (~>) = (*>) -- Lift Operations liftA2 :: Applicable repr => Hask.Runtime (a -> b -> c) -> repr a -> repr b -> repr c liftA2 f x = (<*>) (fmap f x) liftA3 :: Applicable repr => Hask.Runtime (a -> b -> c -> d) -> repr a -> repr b -> repr c -> repr d liftA3 f a b c = liftA2 f a b <*> c -} -- Parser Folds pfoldr :: Applicable repr => Foldable repr => Hask.Runtime (a -> b -> b) -> Hask.Runtime b -> repr a -> repr b pfoldr f k p = chainPre (f <$> p) (pure k) pfoldr1 :: Applicable repr => Foldable repr => Hask.Runtime (a -> b -> b) -> Hask.Runtime b -> repr a -> repr b pfoldr1 f k p = f <$> p <*> pfoldr f k p pfoldl :: Applicable repr => Foldable repr => Hask.Runtime (b -> a -> b) -> Hask.Runtime b -> repr a -> repr b pfoldl f k p = chainPost (pure k) ((Hask.flip <$> pure f) <*> p) pfoldl1 :: Applicable repr => Foldable repr => Hask.Runtime (b -> a -> b) -> Hask.Runtime b -> repr a -> repr b pfoldl1 f k p = chainPost (f <$> pure k <*> p) ((Hask.flip <$> pure f) <*> p) -- Chain Combinators chainl1' :: Applicable repr => Foldable repr => Hask.Runtime (a -> b) -> repr a -> repr (b -> a -> b) -> repr b chainl1' f p op = chainPost (f <$> p) (Hask.flip <$> op <*> p) chainl1 :: Applicable repr => Foldable repr => repr a -> repr (a -> a -> a) -> repr a chainl1 = chainl1' Hask.id {- chainr1' :: ParserOps rep => rep (a -> b) -> repr a -> repr (a -> b -> b) -> repr b chainr1' f p op = newRegister_ Hask.id $ \acc -> let go = bind p $ \x -> modify acc (Hask.flip (Hask..@) <$> (op <*> x)) *> go <|> f <$> x in go <**> get acc chainr1 :: repr a -> repr (a -> a -> a) -> repr a chainr1 = chainr1' Hask.id chainr :: repr a -> repr (a -> a -> a) -> Hask.Runtime a -> repr a chainr p op x = option x (chainr1 p op) -} chainl :: Applicable repr => Alternable repr => Foldable repr => repr a -> repr (a -> a -> a) -> Hask.Runtime a -> repr a chainl p op x = option x (chainl1 p op) -- Derived Combinators many :: Applicable repr => Foldable repr => repr a -> repr [a] many = pfoldr Hask.cons Hask.nil manyN :: Applicable repr => Foldable repr => Int -> repr a -> repr [a] manyN n p = List.foldr (const (p <:>)) (many p) [1..n] some :: Applicable repr => Foldable repr => repr a -> repr [a] some = manyN 1 skipMany :: Applicable repr => Foldable repr => repr a -> repr () --skipMany p = let skipManyp = p *> skipManyp <|> unit in skipManyp skipMany = void . pfoldl Hask.const Hask.unit -- the void here will encourage the optimiser to recognise that the register is unused skipManyN :: Applicable repr => Foldable repr => Int -> repr a -> repr () skipManyN n p = List.foldr (const (p *>)) (skipMany p) [1..n] skipSome :: Applicable repr => Foldable repr => repr a -> repr () skipSome = skipManyN 1 sepBy :: Applicable repr => Alternable repr => Foldable repr => repr a -> repr b -> repr [a] sepBy p sep = option Hask.nil (sepBy1 p sep) sepBy1 :: Applicable repr => Alternable repr => Foldable repr => repr a -> repr b -> repr [a] sepBy1 p sep = p <:> many (sep *> p) endBy :: Applicable repr => Alternable repr => Foldable repr => repr a -> repr b -> repr [a] endBy p sep = many (p <* sep) endBy1 :: Applicable repr => Alternable repr => Foldable repr => repr a -> repr b -> repr [a] endBy1 p sep = some (p <* sep) sepEndBy :: Applicable repr => Alternable repr => Foldable repr => repr a -> repr b -> repr [a] sepEndBy p sep = option Hask.nil (sepEndBy1 p sep) sepEndBy1 :: Applicable repr => Alternable repr => Foldable repr => repr a -> repr b -> repr [a] sepEndBy1 p sep = let seb1 = p <**> (sep *> (Hask.flip Hask..@ Hask.cons <$> option Hask.nil seb1) <|> pure (Hask.flip Hask..@ Hask.cons Hask..@ Hask.nil)) in seb1 {- sepEndBy1 :: repr a -> repr b -> repr [a] sepEndBy1 p sep = newRegister_ Hask.id $ \acc -> let go = modify acc ((Hask.flip (Hask..)) Hask..@ Hask.cons <$> p) *> (sep *> (go <|> get acc) <|> get acc) in go <*> pure Hask.nil -}