packages feed

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)