grammatical-parsers-0.7: src/Text/Grampa/ContextFree/Parallel.hs
{-# LANGUAGE CPP, FlexibleContexts, InstanceSigs, GeneralizedNewtypeDeriving,
RankNTypes, ScopedTypeVariables, TypeFamilies, UndecidableInstances #-}
-- | A context-free, non-memoizing parser that handles all alternatives in parallel.
module Text.Grampa.ContextFree.Parallel (ResultList(..), Parser)
where
import Control.Applicative
import Control.Monad (Monad(..), MonadPlus(..))
#if MIN_VERSION_base(4,13,0)
import Control.Monad (MonadFail(fail))
#endif
import Data.Foldable (toList)
import Data.Functor.Classes (Show1(..))
import Data.Functor.Compose (Compose(..))
import Data.Kind (Type)
import Data.List (intercalate)
import Data.Semigroup (Semigroup(..))
import qualified Data.Semigroup.Cancellative as Cancellative
import Data.Monoid (Monoid(mappend, mempty))
import Data.Monoid.Null (MonoidNull(null))
import Data.Monoid.Factorial (FactorialMonoid)
import Data.Monoid.Textual (TextualMonoid)
import qualified Data.Monoid.Null as Null
import qualified Data.Monoid.Factorial as Factorial
import qualified Data.Monoid.Textual as Textual
import Data.String (fromString)
import Debug.Trace (trace)
import Witherable (Filterable(mapMaybe))
import qualified Text.Parser.Char
import Text.Parser.Char (CharParsing)
import Text.Parser.Combinators (Parsing(..))
import Text.Parser.LookAhead (LookAheadParsing(..))
import Text.Parser.Input.Position (fromEnd)
import qualified Rank2
import Text.Grampa.Class (CommittedParsing(..), DeterministicParsing(..),
InputParsing(..), InputCharParsing(..), MultiParsing(..),
ParseResults, ParseFailure(..), Pos)
import Text.Grampa.Internal (BinTree(..), emptyFailure, erroneous, expected, expectedInput, replaceExpected, noFailure,
TraceableParsing(..))
import Prelude hiding (iterate, null, showList, span, takeWhile)
-- | Parser type for context-free grammars using a parallel parsing algorithm with no result sharing nor left recursion
-- support.
newtype Parser (g :: (Type -> Type) -> Type) s r = Parser{applyParser :: s -> ResultList s r}
data ResultList s r = ResultList !(BinTree (ResultInfo s r)) (ParseFailure Pos s)
data ResultInfo s r = ResultInfo !s !r
instance (Show s, Show r) => Show (ResultList s r) where
show (ResultList l f) = "ResultList (" ++ shows l (") (" ++ shows f ")")
instance Show s => Show1 (ResultList s) where
liftShowsPrec _sp showList _prec (ResultList l f) rest = "ResultList " ++ showList (simplify <$> toList l) (shows f rest)
where simplify (ResultInfo _ r) = r
instance (Show s, Show r) => Show (ResultInfo s r) where
show (ResultInfo s r) = "(ResultInfo @" ++ show s ++ " " ++ shows r ")"
instance Functor (ResultInfo s) where
fmap f (ResultInfo s r) = ResultInfo s (f r)
instance Foldable (ResultInfo s) where
foldMap f (ResultInfo _ r) = f r
instance Traversable (ResultInfo s) where
traverse f (ResultInfo s r) = ResultInfo s <$> f r
instance Filterable (ResultList s) where
mapMaybe f (ResultList l failure) = ResultList (mapMaybe (traverse f) l) failure
instance Functor (ResultList s) where
fmap f (ResultList l failure) = ResultList ((f <$>) <$> l) failure
instance Ord s => Semigroup (ResultList s r) where
ResultList rl1 f1 <> ResultList rl2 f2 = ResultList (rl1 <> rl2) (f1 <> f2)
instance Ord s => Monoid (ResultList s r) where
mempty = ResultList mempty noFailure
mappend = (<>)
instance Functor (Parser g s) where
fmap f (Parser p) = Parser (fmap f . p)
instance Ord s => Applicative (Parser g s) where
pure a = Parser (\rest-> ResultList (Leaf $ ResultInfo rest a) noFailure)
Parser p <*> Parser q = Parser r where
r rest = case p rest
of ResultList results failure -> ResultList mempty failure <> foldMap continue results
continue (ResultInfo rest' f) = f <$> q rest'
instance (FactorialMonoid s, Ord s) => Alternative (Parser g s) where
empty = Parser (ResultList mempty . emptyFailure . fromEnd . Factorial.length)
Parser p <|> Parser q = Parser r where
r rest = p rest <> q rest
instance FactorialMonoid s => Filterable (Parser g s) where
mapMaybe f (Parser p) = Parser (mapMaybe f . p)
#if MIN_VERSION_base(4,13,0)
instance Ord s => Monad (Parser g s) where
#else
instance (Factorial.FactorialMonoid s, Ord s) => Monad (Parser g s) where
#endif
return = pure
Parser p >>= f = Parser q where
q rest = case p rest
of ResultList results failure -> ResultList mempty failure <> foldMap continue results
continue (ResultInfo rest' a) = applyParser (f a) rest'
#if MIN_VERSION_base(4,13,0)
instance (FactorialMonoid s, Ord s) => MonadFail (Parser g s) where
#endif
fail msg = Parser (\s-> ResultList mempty $ erroneous (fromEnd $ Factorial.length s) msg)
instance (FactorialMonoid s, Ord s) => MonadPlus (Parser g s) where
mzero = empty
mplus = (<|>)
instance (Ord s, Semigroup x) => Semigroup (Parser g s x) where
(<>) = liftA2 (<>)
instance (Monoid x, Ord s) => Monoid (Parser g s x) where
mempty = pure mempty
mappend = (<>)
-- | Parallel parser produces a list of all possible parses.
--
-- @
-- 'parseComplete' :: ("Rank2".'Rank2.Functor' g, Eq s, 'FactorialMonoid' s) =>
-- g (Parallel.'Parser' g s) -> s -> g ('Compose' ('ParseResults' s) [])
-- @
instance (Cancellative.LeftReductive s, FactorialMonoid s, Ord s) => MultiParsing (Parser g s) where
type ResultFunctor (Parser g s) = Compose (ParseResults s) []
-- | Returns the list of all possible input prefix parses paired with the remaining input suffix.
parsePrefix g input = Rank2.fmap (Compose . Compose . fromResultList . (`applyParser` input)) g
-- | Returns the list of all possible parses of complete input.
parseComplete :: (Rank2.Functor g', Eq s, FactorialMonoid s) =>
g' (Parser g s) -> s -> g' (Compose (ParseResults s) [])
parseComplete g input = Rank2.fmap ((snd <$>) . getCompose) (parsePrefix (Rank2.fmap (<* eof) g) input)
instance (Cancellative.LeftReductive s, FactorialMonoid s, Ord s) => InputParsing (Parser g s) where
type ParserInput (Parser g s) = s
getInput = Parser p
where p s = ResultList (Leaf $ ResultInfo s s) noFailure
anyToken = Parser p
where p s = case Factorial.splitPrimePrefix s
of Just (first, rest) -> ResultList (Leaf $ ResultInfo rest first) noFailure
_ -> ResultList mempty (expected (fromEnd $ Factorial.length s) "anyToken")
satisfy predicate = Parser p
where p s = case Factorial.splitPrimePrefix s
of Just (first, rest) | predicate first -> ResultList (Leaf $ ResultInfo rest first) noFailure
_ -> ResultList mempty (expected (fromEnd $ Factorial.length s) "satisfy")
notSatisfy predicate = Parser p
where p s = case Factorial.splitPrimePrefix s
of Just (first, _)
| predicate first -> ResultList mempty (expected (fromEnd $ Factorial.length s) "notSatisfy")
_ -> ResultList (Leaf $ ResultInfo s ()) noFailure
scan s0 f = Parser (p s0)
where p s i = ResultList (Leaf $ ResultInfo suffix prefix) noFailure
where (prefix, suffix, _) = Factorial.spanMaybe' s f i
take n = Parser p
where p s
| (prefix, suffix) <- Factorial.splitAt n s,
Factorial.length prefix == n = ResultList (Leaf $ ResultInfo suffix prefix) noFailure
| otherwise = ResultList mempty (expected (fromEnd $ Factorial.length s) $ "take " ++ show n)
takeWhile predicate = Parser p
where p s = ResultList (Leaf $ ResultInfo suffix prefix) noFailure
where (prefix, suffix) = Factorial.span predicate s
takeWhile1 predicate = Parser p
where p s | (prefix, suffix) <- Factorial.span predicate s =
if Null.null prefix
then ResultList mempty (expected (fromEnd $ Factorial.length s) "takeWhile1")
else ResultList (Leaf $ ResultInfo suffix prefix) noFailure
string s = Parser p where
p s' | Just suffix <- Cancellative.stripPrefix s s' = ResultList (Leaf $ ResultInfo suffix s) noFailure
| otherwise = ResultList mempty (expectedInput (fromEnd $ Factorial.length s') s)
instance (FactorialMonoid s, InputParsing (Parser g s)) => TraceableParsing (Parser g s) where
traceInput description (Parser p) = Parser q
where q s = case trace ("Parsing " <> description s) (p s)
of rl@(ResultList EmptyTree _) -> trace ("Failed " <> description s) rl
rl@(ResultList rs _) ->
trace ("Parsed [" <> intercalate ", " (describeResult <$> toList rs) <> "]") rl
where describeResult (ResultInfo s' _) =
description (Factorial.take (Factorial.length s - Factorial.length s') s)
instance (Ord s, TextualMonoid s) => InputCharParsing (Parser g s) where
satisfyCharInput predicate = Parser p
where p s =
case Textual.splitCharacterPrefix s
of Just (first, rest)
| predicate first -> ResultList (Leaf $ ResultInfo rest $ Factorial.primePrefix s) noFailure
_ -> ResultList mempty (expected (fromEnd $ Factorial.length s) "satisfyCharInput")
notSatisfyChar predicate = Parser p
where p s = case Textual.characterPrefix s
of Just first | predicate first
-> ResultList mempty (expected (fromEnd $ Factorial.length s) "notSatisfyChar")
_ -> ResultList (Leaf $ ResultInfo s ()) noFailure
scanChars s0 f = Parser (p s0)
where p s i = ResultList (Leaf $ ResultInfo suffix prefix) noFailure
where (prefix, suffix, _) = Textual.spanMaybe_' s f i
takeCharsWhile predicate = Parser p
where p s | (prefix, suffix) <- Textual.span_ False predicate s =
ResultList (Leaf $ ResultInfo suffix prefix) noFailure
takeCharsWhile1 predicate = Parser p
where p s | (prefix, suffix) <- Textual.span_ False predicate s =
if null prefix
then ResultList mempty (expected (fromEnd $ Factorial.length s) "takeCharsWhile1")
else ResultList (Leaf $ ResultInfo suffix prefix) noFailure
instance (FactorialMonoid s, Ord s) => Parsing (Parser g s) where
try (Parser p) = Parser q
where q rest = rewindFailure (p rest)
where rewindFailure (ResultList rl _) = ResultList rl (emptyFailure $ fromEnd $ Factorial.length rest)
Parser p <?> msg = Parser q
where q rest = replaceFailure (p rest)
where replaceFailure (ResultList EmptyTree f) =
ResultList EmptyTree (replaceExpected (fromEnd $ Factorial.length rest) msg f)
replaceFailure rl = rl
notFollowedBy (Parser p) = Parser (\input-> rewind input (p input))
where rewind t (ResultList EmptyTree _) = ResultList (Leaf $ ResultInfo t ()) noFailure
rewind t ResultList{} = ResultList mempty (expected (fromEnd $ Factorial.length t) "notFollowedBy")
skipMany p = go
where go = pure () <|> try p *> go
unexpected msg = Parser (\t-> ResultList mempty $ erroneous (fromEnd $ Factorial.length t) msg)
eof = Parser f
where f s | null s = ResultList (Leaf $ ResultInfo s ()) noFailure
| otherwise = ResultList mempty (expected (fromEnd $ Factorial.length s) "end of input")
instance (FactorialMonoid s, Ord s) => DeterministicParsing (Parser g s) where
Parser p <<|> Parser q = Parser r where
r rest = case p rest
of rl@(ResultList EmptyTree _failure) -> rl <> q rest
rl -> rl
takeSome p = (:) <$> p <*> takeMany p
takeMany (Parser p) = Parser (q id) where
q acc rest = case p rest
of ResultList EmptyTree _failure -> ResultList (Leaf $ ResultInfo rest (acc [])) mempty
ResultList rl _ -> foldMap continue rl
where continue (ResultInfo rest' result) = q (acc . (result:)) rest'
skipAll (Parser p) = Parser q where
q rest = case p rest
of ResultList EmptyTree _failure -> ResultList (Leaf $ ResultInfo rest ()) mempty
ResultList rl _failure -> foldMap continue rl
where continue (ResultInfo rest' _) = q rest'
instance (FactorialMonoid s, Ord s) => CommittedParsing (Parser g s) where
type CommittedResults (Parser g s) = ParseResults s
commit (Parser p) = Parser q
where q rest = case p rest
of ResultList EmptyTree failure -> ResultList (Leaf $ ResultInfo rest $ Left failure) mempty
ResultList rl failure -> ResultList (fmap Right <$> rl) failure
admit (Parser p) = Parser q
where q rest = case p rest
of ResultList EmptyTree failure -> ResultList EmptyTree failure
ResultList rl failure -> foldMap expose rl <> ResultList EmptyTree failure
expose (ResultInfo _ (Left failure)) = ResultList EmptyTree failure
expose (ResultInfo rest (Right r)) = ResultList (Leaf $ ResultInfo rest r) mempty
instance (FactorialMonoid s, Ord s) => LookAheadParsing (Parser g s) where
lookAhead (Parser p) = Parser (\input-> rewind input (p input))
where rewind t (ResultList rl failure) = ResultList (rewindInput t <$> rl) failure
rewindInput t (ResultInfo _ r) = ResultInfo t r
instance (TextualMonoid s, Ord s) => CharParsing (Parser g s) where
satisfy predicate = Parser p
where p s =
case Textual.splitCharacterPrefix s
of Just (first, rest) | predicate first -> ResultList (Leaf $ ResultInfo rest first) noFailure
_ -> ResultList mempty (expected (fromEnd $ Factorial.length s) "Char.satisfy")
string s = Textual.toString (error "unexpected non-character") <$> string (fromString s)
text t = (fromString . Textual.toString (error "unexpected non-character")) <$> string (Textual.fromText t)
fromResultList :: (Eq s, FactorialMonoid s) => ResultList s r -> ParseResults s [(s, r)]
fromResultList (ResultList EmptyTree failure) = Left failure
fromResultList (ResultList rl _failure) = Right (f <$> toList rl)
where f (ResultInfo s r) = (s, r)