{-# LANGUAGE ConstrainedClassMethods, FlexibleContexts, FlexibleInstances, GADTs,
RankNTypes, StandaloneDeriving, TypeOperators, UndecidableInstances #-}
module Text.Grampa.Internal (BinTree(..), ResultList(..), ResultsOfLength(..), FallibleResults(..),
AmbiguousAlternative(..), AmbiguityDecidable(..), AmbiguityWitness(..),
ParserFlags (ParserFlags, nullable, dependsOn),
Dependencies (DynamicDependencies, StaticDependencies),
TraceableParsing(..),
emptyFailure, erroneous, expected, expectedInput, replaceExpected, noFailure) where
import Control.Applicative (Applicative(..), Alternative(..))
import Data.Foldable (toList)
import Data.Functor.Classes (Show1(..))
import Data.Functor.Const (Const)
import Data.List.NonEmpty (NonEmpty, nonEmpty)
import Data.Monoid (Monoid(mappend, mempty))
import Data.Ord (Down(Down))
import Data.Semigroup (Semigroup((<>)))
import Data.Type.Equality ((:~:)(Refl))
import Witherable (Filterable(mapMaybe))
import Text.Grampa.Class (Ambiguous(..), FailureDescription(..), ParseFailure(..), InputParsing(..), Pos)
import Prelude hiding (length, showList)
data ResultsOfLength g s r = ResultsOfLength !Int ![(s, g (ResultList g s))] {-# UNPACK #-} !(NonEmpty r)
data ResultList g s r = ResultList ![ResultsOfLength g s r] (ParseFailure Pos s)
data BinTree a = Fork !(BinTree a) !(BinTree a)
| Leaf !a
| EmptyTree
deriving (Show)
data ParserFlags g = ParserFlags {
nullable :: Bool,
dependsOn :: Dependencies g}
data Dependencies g = DynamicDependencies
| StaticDependencies (g (Const Bool))
deriving instance Show (g (Const Bool)) => Show (Dependencies g)
data AmbiguityWitness a where
AmbiguityWitness :: (a :~: Ambiguous b) -> AmbiguityWitness a
class AmbiguityDecidable a where
ambiguityWitness :: Maybe (AmbiguityWitness a)
instance {-# overlappable #-} AmbiguityDecidable a where
ambiguityWitness = Nothing
instance AmbiguityDecidable (Ambiguous a) where
ambiguityWitness = Just (AmbiguityWitness Refl)
noFailure :: ParseFailure Pos s
noFailure = emptyFailure (Down maxBound)
emptyFailure :: Pos -> ParseFailure Pos s
emptyFailure pos = ParseFailure pos (FailureDescription [] []) []
expected :: Pos -> String -> ParseFailure Pos s
expected pos msg = ParseFailure pos (FailureDescription [msg] []) []
expectedInput :: Pos -> s -> ParseFailure Pos s
expectedInput pos s = ParseFailure pos (FailureDescription [] [s]) []
erroneous :: Pos -> String -> ParseFailure Pos s
erroneous pos msg = ParseFailure pos (FailureDescription [] []) [msg]
replaceExpected :: Pos -> String -> ParseFailure Pos s -> ParseFailure Pos s
replaceExpected pos msg (ParseFailure pos' msgs errs) = ParseFailure pos' msgs' errs
where msgs' | pos == pos' = FailureDescription [msg] []
| otherwise = msgs
instance (Show s, Show r) => Show (ResultList g s r) where
show (ResultList l f) = "ResultList (" ++ shows l (") (" ++ shows f ")")
instance Show s => Show1 (ResultList g s) where
liftShowsPrec _sp showList _prec (ResultList rol f) rest =
"ResultList " ++ shows (simplify <$> toList rol) (shows f rest)
where simplify (ResultsOfLength l _ r) = "ResultsOfLength " <> show l <> " _ " <> showList (toList r) ""
instance Show r => Show (ResultsOfLength g s r) where
show (ResultsOfLength l _ r) = "(ResultsOfLength @" ++ show l ++ " " ++ shows r ")"
instance Functor (ResultsOfLength g s) where
fmap f (ResultsOfLength l t r) = ResultsOfLength l t (f <$> r)
{-# INLINE fmap #-}
instance Functor (ResultList g s) where
fmap f (ResultList l failure) = ResultList ((f <$>) <$> l) failure
{-# INLINE fmap #-}
instance Ord s => Applicative (ResultsOfLength g s) where
pure = ResultsOfLength 0 mempty . pure
ResultsOfLength l1 _ fs <*> ResultsOfLength l2 t2 xs = ResultsOfLength (l1 + l2) t2 (fs <*> xs)
instance Ord s => Applicative (ResultList g s) where
pure a = ResultList [pure a] mempty
ResultList rl1 f1 <*> ResultList rl2 f2 = ResultList ((<*>) <$> rl1 <*> rl2) (f1 <> f2)
instance Ord s => Alternative (ResultList g s) where
empty = ResultList mempty mempty
(<|>) = (<>)
instance Filterable (ResultList g s) where
mapMaybe f (ResultList rols failure) = ResultList (mapMaybe maybeROL rols) failure
where maybeROL (ResultsOfLength l t rs) = ResultsOfLength l t <$> nonEmpty (mapMaybe f $ toList rs)
{-# INLINE mapMaybe #-}
instance Ord s => Semigroup (ResultList g s r) where
ResultList rl1 f1 <> ResultList rl2 f2 = ResultList (merge rl1 rl2) (f1 <> f2)
where merge [] rl = rl
merge rl [] = rl
merge rl1'@(rol1@(ResultsOfLength l1 s1 r1) : rest1) rl2'@(rol2@(ResultsOfLength l2 _ r2) : rest2)
| l1 < l2 = rol1 : merge rest1 rl2'
| l1 > l2 = rol2 : merge rl1' rest2
| otherwise = ResultsOfLength l1 s1 (r1 <> r2) : merge rest1 rest2
instance Ord s => AmbiguousAlternative (ResultList g s) where
ambiguousOr (ResultList rl1 f1) (ResultList rl2 f2) = ResultList (merge rl1 rl2) (f1 <> f2)
where merge [] rl = rl
merge rl [] = rl
merge rl1'@(rol1@(ResultsOfLength l1 s1 r1) : rest1) rl2'@(rol2@(ResultsOfLength l2 _ r2) : rest2)
| l1 < l2 = rol1 : merge rest1 rl2'
| l1 > l2 = rol2 : merge rl1' rest2
| otherwise = ResultsOfLength l1 s1 (liftA2 collect r1 r2) : merge rest1 rest2
collect (Ambiguous xs) (Ambiguous ys) = Ambiguous (xs <> ys)
class Alternative f => AmbiguousAlternative f where
ambiguousOr :: f (Ambiguous a) -> f (Ambiguous a) -> f (Ambiguous a)
instance Ord s => Monoid (ResultList g s r) where
mempty = ResultList mempty mempty
mappend = (<>)
instance Functor BinTree where
fmap f (Fork left right) = Fork (fmap f left) (fmap f right)
fmap f (Leaf a) = Leaf (f a)
fmap _ EmptyTree = EmptyTree
instance Applicative BinTree where
pure = Leaf
EmptyTree <*> _ = EmptyTree
Leaf f <*> t = f <$> t
Fork f1 f2 <*> t = Fork (f1 <*> t) (f2 <*> t)
instance Foldable BinTree where
foldMap f (Fork left right) = foldMap f left `mappend` foldMap f right
foldMap f (Leaf a) = f a
foldMap _ EmptyTree = mempty
instance Traversable BinTree where
traverse f (Fork left right) = Fork <$> traverse f left <*> traverse f right
traverse f (Leaf a) = Leaf <$> f a
traverse _ EmptyTree = pure EmptyTree
instance Filterable BinTree where
mapMaybe f (Fork left right) = mapMaybe f left <> mapMaybe f right
mapMaybe f (Leaf a) = maybe EmptyTree Leaf (f a)
mapMaybe _ EmptyTree = EmptyTree
instance Semigroup (BinTree a) where
EmptyTree <> t = t
t <> EmptyTree = t
l <> r = Fork l r
instance Monoid (BinTree a) where
mempty = EmptyTree
mappend = (<>)
class FallibleResults f where
hasSuccess :: f s a -> Bool
failureOf :: f s a -> ParseFailure Pos s
failWith :: ParseFailure Pos s -> f s a
instance FallibleResults (ResultList g) where
hasSuccess (ResultList [] _) = False
hasSuccess _ = True
failureOf (ResultList _ failure) = failure
failWith = ResultList []
class InputParsing m => TraceableParsing m where
traceInput :: (ParserInput m -> String) -> m a -> m a
traceAs :: Show (ParserInput m) => String -> m a -> m a
traceAs description = traceInput (\input-> description <> " @ " <> show input)