packages feed

grammatical-parsers 0.1 → 0.2

raw patch · 13 files changed

+1093/−499 lines, 13 filesdep ~grammatical-parsersdep ~rank2classesPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: grammatical-parsers, rank2classes

API changes (from Hackage documentation)

- Text.Grampa.ContextFree.LeftRecursive: data Parser g s a
- Text.Grampa.ContextFree.LeftRecursive: instance (GHC.Show.Show s, Data.Monoid.Textual.TextualMonoid s) => Text.Parser.Char.CharParsing (Text.Grampa.ContextFree.LeftRecursive.Parser g s)
- Text.Grampa.ContextFree.LeftRecursive: instance (GHC.Show.Show s, Data.Monoid.Textual.TextualMonoid s) => Text.Parser.Token.TokenParsing (Text.Grampa.ContextFree.LeftRecursive.Parser g s)
- Text.Grampa.ContextFree.LeftRecursive: instance (Rank2.Distributive g, Rank2.Traversable g) => Data.Functor.Classes.Show1 (Text.Grampa.ContextFree.LeftRecursive.Parser g s)
- Text.Grampa.ContextFree.LeftRecursive: instance (Rank2.Distributive g, Rank2.Traversable g) => GHC.Show.Show (Text.Grampa.ContextFree.LeftRecursive.Parser g s a)
- Text.Grampa.ContextFree.LeftRecursive: instance Data.Monoid.Null.MonoidNull s => Text.Parser.Combinators.Parsing (Text.Grampa.ContextFree.LeftRecursive.Parser g s)
- Text.Grampa.ContextFree.LeftRecursive: instance Data.Monoid.Null.MonoidNull s => Text.Parser.LookAhead.LookAheadParsing (Text.Grampa.ContextFree.LeftRecursive.Parser g s)
- Text.Grampa.ContextFree.LeftRecursive: instance GHC.Base.Alternative (Text.Grampa.ContextFree.LeftRecursive.Parser g s)
- Text.Grampa.ContextFree.LeftRecursive: instance GHC.Base.Applicative (Text.Grampa.ContextFree.LeftRecursive.Parser g s)
- Text.Grampa.ContextFree.LeftRecursive: instance GHC.Base.Functor (Text.Grampa.ContextFree.LeftRecursive.Parser g s)
- Text.Grampa.ContextFree.LeftRecursive: instance GHC.Base.Monad (Text.Grampa.ContextFree.LeftRecursive.Parser g s)
- Text.Grampa.ContextFree.LeftRecursive: instance GHC.Base.MonadPlus (Text.Grampa.ContextFree.LeftRecursive.Parser g s)
- Text.Grampa.ContextFree.LeftRecursive: instance GHC.Base.Monoid x => GHC.Base.Monoid (Text.Grampa.ContextFree.LeftRecursive.Parser g s x)
- Text.Grampa.ContextFree.LeftRecursive: instance GHC.Show.Show (f a) => GHC.Show.Show (Text.Grampa.ContextFree.LeftRecursive.Couple f a)
- Text.Grampa.ContextFree.LeftRecursive: instance GHC.Show.Show Text.Grampa.ContextFree.LeftRecursive.AdvanceFront
- Text.Grampa.ContextFree.LeftRecursive: instance Text.Grampa.Class.GrammarParsing Text.Grampa.ContextFree.LeftRecursive.Parser
- Text.Grampa.ContextFree.LeftRecursive: instance Text.Grampa.Class.MonoidParsing (Text.Grampa.ContextFree.LeftRecursive.Parser g)
- Text.Grampa.ContextFree.LeftRecursive: instance Text.Grampa.Class.MultiParsing Text.Grampa.ContextFree.LeftRecursive.Parser
- Text.Grampa.ContextFree.Memoizing: instance GHC.Base.Monoid Text.Grampa.ContextFree.Memoizing.FailureInfo
- Text.Grampa.ContextFree.Memoizing: instance GHC.Classes.Eq Text.Grampa.ContextFree.Memoizing.FailureInfo
- Text.Grampa.ContextFree.Memoizing: instance GHC.Show.Show Text.Grampa.ContextFree.Memoizing.FailureInfo
- Text.Grampa.PEG.Backtrack: data Parser g s r
- Text.Grampa.PEG.Backtrack: instance GHC.Classes.Eq Text.Grampa.PEG.Backtrack.FailureInfo
- Text.Grampa.PEG.Backtrack: instance GHC.Show.Show Text.Grampa.PEG.Backtrack.FailureInfo
- Text.Grampa.PEG.Packrat: data Parser g s r
- Text.Grampa.PEG.Packrat: instance GHC.Classes.Eq Text.Grampa.PEG.Packrat.FailureInfo
- Text.Grampa.PEG.Packrat: instance GHC.Show.Show Text.Grampa.PEG.Packrat.FailureInfo
+ Text.Grampa: notSatisfy :: (MonoidParsing m, FactorialMonoid s) => (s -> Bool) -> m s ()
+ Text.Grampa: notSatisfyChar :: (MonoidParsing m, TextualMonoid s) => (Char -> Bool) -> m s ()
+ Text.Grampa: satisfyCharInput :: (MonoidParsing m, TextualMonoid s) => (Char -> Bool) -> m s s
+ Text.Grampa.ContextFree.LeftRecursive: (<<|>) :: Parser g s a -> Parser g s a -> Parser g s a
+ Text.Grampa.ContextFree.LeftRecursive: BackParser :: p g s a -> SeparatedParser p g s a
+ Text.Grampa.ContextFree.LeftRecursive: CycleParser :: p g s a -> p g s a -> g (Const Bool) -> SeparatedParser p g s a
+ Text.Grampa.ContextFree.LeftRecursive: FrontParser :: (p g s a) -> SeparatedParser p g s a
+ Text.Grampa.ContextFree.LeftRecursive: [backParser] :: SeparatedParser p g s a -> p g s a
+ Text.Grampa.ContextFree.LeftRecursive: [cycleParser] :: SeparatedParser p g s a -> p g s a
+ Text.Grampa.ContextFree.LeftRecursive: [dependencies] :: SeparatedParser p g s a -> g (Const Bool)
+ Text.Grampa.ContextFree.LeftRecursive: data Fixed p g s a
+ Text.Grampa.ContextFree.LeftRecursive: data SeparatedParser p g s a
+ Text.Grampa.ContextFree.LeftRecursive: infixl 3 <<|>
+ Text.Grampa.ContextFree.LeftRecursive: instance (GHC.Base.Alternative (p g s), GHC.Base.Monad (p g s)) => GHC.Base.Monad (Text.Grampa.ContextFree.LeftRecursive.Fixed p g s)
+ Text.Grampa.ContextFree.LeftRecursive: instance (GHC.Base.Alternative (p g s), GHC.Base.Monoid x) => GHC.Base.Monoid (Text.Grampa.ContextFree.LeftRecursive.Fixed p g s x)
+ Text.Grampa.ContextFree.LeftRecursive: instance (Rank2.Apply g, Rank2.Distributive g) => GHC.Base.Monoid (Text.Grampa.ContextFree.LeftRecursive.Union g)
+ Text.Grampa.ContextFree.LeftRecursive: instance (Text.Parser.LookAhead.LookAheadParsing (p g s), Text.Grampa.Class.MonoidParsing (Text.Grampa.ContextFree.LeftRecursive.Fixed p g)) => Text.Parser.Combinators.Parsing (Text.Grampa.ContextFree.LeftRecursive.Fixed p g s)
+ Text.Grampa.ContextFree.LeftRecursive: instance (Text.Parser.LookAhead.LookAheadParsing (p g s), Text.Grampa.Class.MonoidParsing (Text.Grampa.ContextFree.LeftRecursive.Fixed p g)) => Text.Parser.LookAhead.LookAheadParsing (Text.Grampa.ContextFree.LeftRecursive.Fixed p g s)
+ Text.Grampa.ContextFree.LeftRecursive: instance (Text.Parser.LookAhead.LookAheadParsing (p g s), Text.Grampa.Class.MonoidParsing (Text.Grampa.ContextFree.LeftRecursive.Fixed p g), GHC.Show.Show s, Data.Monoid.Textual.TextualMonoid s) => Text.Parser.Char.CharParsing (Text.Grampa.ContextFree.LeftRecursive.Fixed p g s)
+ Text.Grampa.ContextFree.LeftRecursive: instance (Text.Parser.LookAhead.LookAheadParsing (p g s), Text.Parser.Token.TokenParsing (p g s), Text.Grampa.Class.MonoidParsing (Text.Grampa.ContextFree.LeftRecursive.Fixed p g), GHC.Show.Show s, Data.Monoid.Textual.TextualMonoid s) => Text.Parser.Token.TokenParsing (Text.Grampa.ContextFree.LeftRecursive.Fixed p g s)
+ Text.Grampa.ContextFree.LeftRecursive: instance GHC.Base.Alternative (p g s) => GHC.Base.Alternative (Text.Grampa.ContextFree.LeftRecursive.Fixed p g s)
+ Text.Grampa.ContextFree.LeftRecursive: instance GHC.Base.Alternative (p g s) => GHC.Base.Applicative (Text.Grampa.ContextFree.LeftRecursive.Fixed p g s)
+ Text.Grampa.ContextFree.LeftRecursive: instance GHC.Base.Functor (p g s) => GHC.Base.Functor (Text.Grampa.ContextFree.LeftRecursive.Fixed p g s)
+ Text.Grampa.ContextFree.LeftRecursive: instance GHC.Base.MonadPlus (p g s) => GHC.Base.MonadPlus (Text.Grampa.ContextFree.LeftRecursive.Fixed p g s)
+ Text.Grampa.ContextFree.LeftRecursive: instance GHC.Show.Show (g (Data.Functor.Const.Const GHC.Types.Bool)) => GHC.Show.Show (Text.Grampa.ContextFree.LeftRecursive.ParserFlags g)
+ Text.Grampa.ContextFree.LeftRecursive: instance Text.Grampa.Class.GrammarParsing (Text.Grampa.ContextFree.LeftRecursive.Fixed Text.Grampa.ContextFree.Memoizing.Parser)
+ Text.Grampa.ContextFree.LeftRecursive: instance Text.Grampa.Class.MonoidParsing (Text.Grampa.ContextFree.LeftRecursive.Fixed Text.Grampa.ContextFree.Memoizing.Parser g)
+ Text.Grampa.ContextFree.LeftRecursive: instance Text.Grampa.Class.MonoidParsing (Text.Grampa.ContextFree.LeftRecursive.Fixed Text.Grampa.PEG.Backtrack.Length.Parser g)
+ Text.Grampa.ContextFree.LeftRecursive: instance Text.Grampa.Class.MultiParsing (Text.Grampa.ContextFree.LeftRecursive.Fixed Text.Grampa.ContextFree.Memoizing.Parser)
+ Text.Grampa.ContextFree.LeftRecursive: longest :: FactorialMonoid s => Fixed Parser g s a -> Fixed Parser g [(s, g (ResultList g s))] a
+ Text.Grampa.ContextFree.LeftRecursive: parseSeparated :: forall g s. (Apply g, Foldable g, FactorialMonoid s) => g (SeparatedParser Parser g s) -> s -> [(s, g (ResultList g s))]
+ Text.Grampa.ContextFree.LeftRecursive: peg :: Fixed Parser g [(s, g (ResultList g s))] a -> Fixed Parser g s a
+ Text.Grampa.ContextFree.LeftRecursive: separated :: forall g s. (Apply g, Distributive g, Traversable g) => g (Parser g s) -> g (SeparatedParser Parser g s)
+ Text.Grampa.ContextFree.LeftRecursive: terminalPEG :: Monoid s => Fixed Parser g s a -> Fixed Parser g s a
+ Text.Grampa.ContextFree.LeftRecursive: type Parser = Fixed Parser
+ Text.Grampa.ContextFree.Memoizing: (<<|>) :: Parser g s a -> Parser g s a -> Parser g s a
+ Text.Grampa.ContextFree.Memoizing: EmptyTree :: BinTree a
+ Text.Grampa.ContextFree.Memoizing: Fork :: !(BinTree a) -> !(BinTree a) -> BinTree a
+ Text.Grampa.ContextFree.Memoizing: Leaf :: !a -> BinTree a
+ Text.Grampa.ContextFree.Memoizing: data BinTree a
+ Text.Grampa.ContextFree.Memoizing: infixl 3 <<|>
+ Text.Grampa.ContextFree.Memoizing: longest :: FactorialMonoid s => Parser g s a -> Parser g [(s, g (ResultList g s))] a
+ Text.Grampa.ContextFree.Memoizing: peg :: Parser g [(s, g (ResultList g s))] a -> Parser g s a
+ Text.Grampa.ContextFree.Memoizing: terminalPEG :: Monoid s => Parser g s a -> Parser g s a
+ Text.Grampa.PEG.Backtrack: NoParse :: FailureInfo -> Result s v
+ Text.Grampa.PEG.Backtrack: Parsed :: !v -> !s -> Result s v
+ Text.Grampa.PEG.Backtrack: Parser :: (s -> Result g s r) -> Parser g s r
+ Text.Grampa.PEG.Backtrack: [applyParser] :: Parser g s r -> s -> Result g s r
+ Text.Grampa.PEG.Backtrack: [parsedPrefix] :: Result s v -> !v
+ Text.Grampa.PEG.Backtrack: [parsedSuffix] :: Result s v -> !s
+ Text.Grampa.PEG.Backtrack: alt :: Parser g s a -> Parser g s a -> Parser g s a
+ Text.Grampa.PEG.Backtrack: data Result (g :: (* -> *) -> *) s v
+ Text.Grampa.PEG.Backtrack: instance (GHC.Show.Show s, Data.Monoid.Textual.TextualMonoid s) => Text.Parser.Char.CharParsing (Text.Grampa.PEG.Backtrack.Parser g s)
+ Text.Grampa.PEG.Backtrack: instance (GHC.Show.Show s, Data.Monoid.Textual.TextualMonoid s) => Text.Parser.Token.TokenParsing (Text.Grampa.PEG.Backtrack.Parser g s)
+ Text.Grampa.PEG.Backtrack: instance Data.Monoid.Factorial.FactorialMonoid s => Text.Parser.LookAhead.LookAheadParsing (Text.Grampa.PEG.Backtrack.Parser g s)
+ Text.Grampa.PEG.Backtrack: newtype Parser g s r
+ Text.Grampa.PEG.Packrat: NoParse :: FailureInfo -> Result g s v
+ Text.Grampa.PEG.Packrat: Parsed :: !v -> ![(s, g (Result g s))] -> Result g s v
+ Text.Grampa.PEG.Packrat: Parser :: ([(s, g (Result g s))] -> Result g s r) -> Parser g s r
+ Text.Grampa.PEG.Packrat: [applyParser] :: Parser g s r -> [(s, g (Result g s))] -> Result g s r
+ Text.Grampa.PEG.Packrat: [parsedPrefix] :: Result g s v -> !v
+ Text.Grampa.PEG.Packrat: [parsedSuffix] :: Result g s v -> ![(s, g (Result g s))]
+ Text.Grampa.PEG.Packrat: data Result g s v
+ Text.Grampa.PEG.Packrat: instance (GHC.Show.Show s, Data.Monoid.Textual.TextualMonoid s) => Text.Parser.Char.CharParsing (Text.Grampa.PEG.Packrat.Parser g s)
+ Text.Grampa.PEG.Packrat: instance (GHC.Show.Show s, Data.Monoid.Textual.TextualMonoid s) => Text.Parser.Token.TokenParsing (Text.Grampa.PEG.Packrat.Parser g s)
+ Text.Grampa.PEG.Packrat: instance Data.Monoid.Factorial.FactorialMonoid s => Text.Parser.LookAhead.LookAheadParsing (Text.Grampa.PEG.Packrat.Parser g s)
+ Text.Grampa.PEG.Packrat: newtype Parser g s r
- Text.Grampa: fixGrammar :: forall g s. (GrammarParsing m, Distributive g) => (g (m g s) -> g (m g s)) -> g (m g s)
+ Text.Grampa: fixGrammar :: forall g s. (GrammarParsing m, GrammarConstraint m g, Distributive g) => (g (m g s) -> g (m g s)) -> g (m g s)
- Text.Grampa: getInput :: (MonoidParsing m, MonoidNull s) => m s s
+ Text.Grampa: getInput :: (MonoidParsing m, FactorialMonoid s) => m s s
- Text.Grampa: nonTerminal :: GrammarParsing m => (g (GrammarFunctor m g s) -> GrammarFunctor m g s a) -> m g s a
+ Text.Grampa: nonTerminal :: (GrammarParsing m, GrammarConstraint m g) => (g (GrammarFunctor m g s) -> GrammarFunctor m g s a) -> m g s a
- Text.Grampa: selfReferring :: (GrammarParsing m, Distributive g) => g (m g s)
+ Text.Grampa: selfReferring :: (GrammarParsing m, GrammarConstraint m g, Distributive g) => g (m g s)
- Text.Grampa.ContextFree.Memoizing: ResultList :: ![ResultInfo g s r] -> {-# UNPACK #-} !FailureInfo -> ResultList g s r
+ Text.Grampa.ContextFree.Memoizing: ResultList :: !(BinTree (ResultInfo g s r)) -> {-# UNPACK #-} !FailureInfo -> ResultList g s r
- Text.Grampa.ContextFree.Parallel: ResultList :: ![ResultInfo s r] -> {-# UNPACK #-} !FailureInfo -> ResultList s r
+ Text.Grampa.ContextFree.Parallel: ResultList :: !(BinTree (ResultInfo s r)) -> {-# UNPACK #-} !FailureInfo -> ResultList s r

Files

README.md view
@@ -1,7 +1,7 @@ Grammatical Parsers =================== -Behold, yet another parser combinator library in Haskell.+Behold, yet another parser combinator library in Haskell. Except this one is capable of working with grammars rather than mere parsers. A more in-depth description is available in the [paper](../Grampa.lhs.pdf) from Haskell Symposium 2017, what follows is a short tutorial.  You can apply the usual [Applicative](http://hackage.haskell.org/package/base/docs/Control-Applicative.html#t:Applicative),
examples/Arithmetic.hs view
@@ -67,12 +67,9 @@ instance Rank2.Applicative (Arithmetic e) where    pure f = Arithmetic f f f f f +instance Rank2.DistributiveTraversable (Arithmetic e)+ instance Rank2.Distributive (Arithmetic e) where-   distributeM f = Arithmetic{expr= f >>= expr,-                              sum= f >>= sum,-                              product= f >>= product,-                              factor= f >>= factor,-                              primary= f >>= primary}    distributeWith w f = Arithmetic{expr= w (expr <$> f),                                    sum= w (sum <$> f),                                    product= w (product <$> f),
examples/Comparisons.hs view
@@ -48,9 +48,9 @@ instance Rank2.Applicative (Comparisons c e) where    pure f = Comparisons f f +instance Rank2.DistributiveTraversable (Comparisons c e)+ instance Rank2.Distributive (Comparisons c e) where-   distributeM f = Comparisons{test= f >>= test,-                               term= f >>= term}    distributeWith w f = Comparisons{test= w (test <$> f),                                     term= w (term <$> f)} 
grammatical-parsers.cabal view
@@ -1,5 +1,5 @@ name:                grammatical-parsers-version:             0.1+version:             0.2 synopsis:            parsers that can combine into grammars description:   /Gram/matical-/pa/rsers, or Grampa for short, is a library of parser types whose values are meant to be assigned@@ -27,16 +27,16 @@                        Text.Grampa.PEG.Backtrack, Text.Grampa.PEG.Packrat,                        Text.Grampa.ContextFree.Parallel, Text.Grampa.ContextFree.Memoizing,                        Text.Grampa.ContextFree.LeftRecursive-  other-modules:       Text.Grampa.Class+  other-modules:       Text.Grampa.Class, Text.Grampa.Internal, Text.Grampa.PEG.Backtrack.Length   default-language:    Haskell2010   -- other-modules:   ghc-options:         -Wall   build-depends:       base >=4.7 && <5,-                       rank2classes < 1.0,                        containers >= 0.4 && < 0.6,                        transformers >= 0.5 && < 0.6,                        monoid-subclasses >=0.4 && <0.5,-                       parsers < 0.13+                       parsers < 0.13,+                       rank2classes < 1.0   -- hs-source-dirs:         default-language:    Haskell2010 @@ -46,7 +46,8 @@   other-modules:       Arithmetic, Boolean, Combined, Comparisons, Conditionals, Lambda, Utilities   default-language:    Haskell2010   build-depends:       base >=4.7 && <5, containers >= 0.5.7.0 && < 0.6,-                       rank2classes < 1.0, grammatical-parsers == 0.1,+                       parsers < 0.13,+                       rank2classes < 1.0, grammatical-parsers,                        monoid-subclasses >=0.4 && <0.5  test-suite           quicktests@@ -54,7 +55,7 @@   hs-source-dirs:    test, examples   x-uses-tf:         true   build-depends:     base >=4.7 && < 5, monoid-subclasses < 0.5, parsers < 0.13,-                     rank2classes < 1.0, grammatical-parsers == 0.1,+                     rank2classes < 1.0, grammatical-parsers,                      QuickCheck >= 2 && < 3, checkers >= 0.4.6 && < 0.5, testing-feat < 0.5,                      tasty >= 0.7, tasty-quickcheck >= 0.7   main-is:           Test.hs@@ -73,7 +74,7 @@   type:              exitcode-stdio-1.0   hs-source-dirs:    test, examples   ghc-options:       -O2 -Wall -rtsopts -main-is Benchmark.main-  Build-Depends:     base >=4.7 && < 5, rank2classes < 1.0, grammatical-parsers == 0.1, monoid-subclasses >=0.4 && <0.5,+  Build-Depends:     base >=4.7 && < 5, rank2classes < 1.0, grammatical-parsers, monoid-subclasses >=0.4 && <0.5,                      criterion >= 1.0, deepseq >= 1.1, containers >= 0.5.7.0 && < 0.6, text >= 1.1   main-is:           Benchmark.hs   other-modules:     Arithmetic
src/Text/Grampa.hs view
@@ -18,7 +18,6 @@ import Text.Parser.Combinators (Parsing((<?>), notFollowedBy, skipMany, skipSome, unexpected)) import Text.Parser.LookAhead (LookAheadParsing(lookAhead)) -import Data.Functor.Compose (Compose(..)) import qualified Rank2 import Text.Grampa.Class (MultiParsing(..), GrammarParsing(..), MonoidParsing(..), ParseResults, ParseFailure(..)) @@ -34,6 +33,5 @@    = g (p g' s) -> g (p g' s)  -- | Apply the given 'parse' function to the given grammar-free parser and its input.-simply :: (Rank2.Only r (p (Rank2.Only r) s) -> s -> Rank2.Only r f)-            -> p (Rank2.Only r) s r -> s -> f r+simply :: (Rank2.Only r (p (Rank2.Only r) s) -> s -> Rank2.Only r f) -> p (Rank2.Only r) s r -> s -> f r simply parseGrammar p input = Rank2.fromOnly (parseGrammar (Rank2.Only p) input)
src/Text/Grampa/Class.hs view
@@ -10,7 +10,6 @@ import Data.Monoid.Factorial (FactorialMonoid) import Data.Monoid.Textual (TextualMonoid) import GHC.Exts (Constraint)-import Text.Parser.Combinators (Parsing)  import qualified Rank2 @@ -33,8 +32,7 @@    type GrammarConstraint m (g :: (* -> *) -> *) :: Constraint    type GrammarConstraint m g = Rank2.Functor g    -- | Given a rank-2 record of parsers and input, produce a record of parses of the complete input.-   parseComplete :: (GrammarConstraint m g, FactorialMonoid s) =>-                    g (m g s) -> s -> g (ResultFunctor m)+   parseComplete :: (GrammarConstraint m g, FactorialMonoid s) => g (m g s) -> s -> g (ResultFunctor m)    -- | Given a rank-2 record of parsers and input, produce a record of prefix parses paired with the remaining input    -- suffix.    parsePrefix :: (GrammarConstraint m g, FactorialMonoid s) =>@@ -44,11 +42,11 @@ class MultiParsing m => GrammarParsing m where    type GrammarFunctor m :: ((* -> *) -> *) -> * -> * -> *    -- | Used to reference a grammar production, only necessary from outside the grammar itself-   nonTerminal :: (g (GrammarFunctor m g s) -> GrammarFunctor m g s a) -> m g s a+   nonTerminal :: GrammarConstraint m g => (g (GrammarFunctor m g s) -> GrammarFunctor m g s a) -> m g s a    -- | Construct a grammar whose every production refers to itself.-   selfReferring :: Rank2.Distributive g => g (m g s)+   selfReferring :: (GrammarConstraint m g, Rank2.Distributive g) => g (m g s)    -- | Convert a self-referring grammar function to a grammar.-   fixGrammar :: forall g s. Rank2.Distributive g => (g (m g s) -> g (m g s)) -> g (m g s)+   fixGrammar :: forall g s. (GrammarConstraint m g, Rank2.Distributive g) => (g (m g s) -> g (m g s)) -> g (m g s)    -- | Mark a parser that relies on primitive recursion to prevent an infinite loop in 'fixGrammar'.    recursive :: m g s a -> m g s a @@ -61,7 +59,7 @@    -- | A parser that fails on any input and succeeds at its end.    endOfInput :: FactorialMonoid s => m s ()    -- | Always sucessful parser that returns the remaining input without consuming it.-   getInput :: MonoidNull s => m s s+   getInput :: FactorialMonoid s => m s s     -- | A parser that accepts any single input atom.    anyToken :: FactorialMonoid s => m s s@@ -69,9 +67,17 @@    token :: (Eq s, FactorialMonoid s) => s -> m s s    -- | A parser that accepts an input atom only if it satisfies the given predicate.    satisfy :: FactorialMonoid s => (s -> Bool) -> m s s-   -- | Specialization of 'satisfy' on 'TextualMonoid' inputs, accepting an input character only if it satisfies the-   -- given predicate.+   -- | Specialization of 'satisfy' on 'TextualMonoid' inputs, accepting and returning an input character only if it+   -- satisfies the given predicate.    satisfyChar :: TextualMonoid s => (Char -> Bool) -> m s Char+   -- | Specialization of 'satisfy' on 'TextualMonoid' inputs, accepting an input character only if it satisfies the+   -- given predicate, and returning the input atom that represents the character. A faster version of @singleton <$>+   -- satisfyChar p@ and of @satisfy (fromMaybe False p . characterPrefix)@.+   satisfyCharInput :: TextualMonoid s => (Char -> Bool) -> m s s+   -- | A parser that succeeds exactly when satisfy doesn't, equivalent to @notFollowedBy . satisfy@+   notSatisfy :: FactorialMonoid s => (s -> Bool) -> m s ()+   -- | A parser that succeeds exactly when satisfyChar doesn't, equivalent to @notFollowedBy . satisfyChar@+   notSatisfyChar :: TextualMonoid s => (Char -> Bool) -> m s ()     -- | A stateful scanner. The predicate modifies a state argument, and each transformed state is passed to successive    -- invocations of the predicate on each token of the input until one returns 'Nothing' or the input ends.
src/Text/Grampa/ContextFree/LeftRecursive.hs view
@@ -1,23 +1,17 @@-{-# LANGUAGE FlexibleContexts, GADTs, InstanceSigs, GeneralizedNewtypeDeriving,-             RankNTypes, ScopedTypeVariables, StandaloneDeriving, TypeFamilies #-}+{-# LANGUAGE FlexibleContexts, FlexibleInstances, GeneralizedNewtypeDeriving, InstanceSigs,+             RankNTypes, ScopedTypeVariables, StandaloneDeriving, TypeFamilies, UndecidableInstances #-} {-# OPTIONS -fno-full-laziness #-}-module Text.Grampa.ContextFree.LeftRecursive (Parser)+module Text.Grampa.ContextFree.LeftRecursive (Fixed, Parser, SeparatedParser(..), longest, peg, terminalPEG, +                                              parseSeparated, separated, (<<|>)) where  import Control.Applicative-import Control.Arrow((&&&)) import Control.Monad (Monad(..), MonadPlus(..)) import Control.Monad.Trans.State.Lazy (State, evalState, get, put)  import Data.Char (isSpace)-import Data.Functor.Classes (Show1(..)) import Data.Functor.Compose (Compose(..))-import Data.IntMap (IntMap)-import Data.IntSet (IntSet)-import Data.Maybe (isJust, maybe)--import qualified Data.IntMap as IntMap-import qualified Data.IntSet as IntSet+import Data.Maybe (isJust)  import Data.Monoid (Monoid(mempty), All(..), Any(..), (<>)) import Data.Monoid.Null (MonoidNull(null))@@ -35,42 +29,87 @@  import qualified Rank2 import Text.Grampa.Class (GrammarParsing(..), MonoidParsing(..), MultiParsing(..), ParseResults)+import Text.Grampa.Internal (BinTree(EmptyTree)) import Text.Grampa.ContextFree.Memoizing (ResultList(..), fromResultList) import qualified Text.Grampa.ContextFree.Memoizing as Memoizing+import qualified Text.Grampa.PEG.Backtrack.Length as Backtrack -import Prelude hiding (null, showsPrec, span, takeWhile)+import Prelude hiding (cycle, null, span, takeWhile) -data Parser g s a where-   NonTerminal   :: (g (Parser g s) -> Parser g s a) -> Parser g s a-   Primitive     :: String -> Maybe (Memoizing.Parser g s a) -> Maybe (Memoizing.Parser g s a)-                 -> Memoizing.Parser g s a -> Parser g s a-   Recursive     :: Parser g s a -> Parser g s a-   Map           :: (a -> b) -> Parser g s a -> Parser g s b-   Ap            :: Parser g s (a -> b) -> Parser g s a -> Parser g s b-   Pure          :: a -> Parser g s a-   Empty         :: Parser g s a-   Bind          :: Parser g s a -> (a -> Parser g s b) -> Parser g s b-   Choice        :: Parser g s a -> Parser g s a -> Parser g s a-   Try           :: Parser g s a -> Parser g s a-   Describe      :: Parser g s a -> String -> Parser g s a-   NotFollowedBy :: Show a => Parser g s a -> Parser g s ()-   Lookahead     :: Parser g s a -> Parser g s a-   Many          :: Parser g s a -> Parser g s [a]-   Some          :: Parser g s a -> Parser g s [a]-   ConcatMany    :: Monoid a => Parser g s a -> Parser g s a-   ResultsWrap   :: ResultList g s a -> Parser g s a-   Index         :: Int -> Parser g s a+type Parser = Fixed Memoizing.Parser --- | Parser of general context-free grammars, including left recursion. O(n³) performance.+data Fixed p g s a =+   Parser {+      complete, direct, direct0, direct1, indirect :: p g s a,+      cyclicDescendants :: Rank2.Apply g => g (Const (ParserFlags g)) -> ParserFlags g}+   | DirectParser {+      complete, direct0, direct1 :: p g s a}+   | PositiveDirectParser {+      complete :: p g s a}++data SeparatedParser p g s a = FrontParser (p g s a)+                             | CycleParser {+                                  cycleParser  :: p g s a,+                                  backParser   :: p g s a,+                                  dependencies :: g (Const Bool)}+                             | BackParser {+                                  backParser :: p g s a}++data ParserFlags g = ParserFlags {+   nullable :: Bool,+   dependsOn :: g (Const Bool)}++deriving instance Show (g (Const Bool)) => Show (ParserFlags g)++data ParserFunctor g s a = ParserResultsFunctor {parserResults :: ResultList g s a}+                         | ParserFlagsFunctor {parserFlags :: ParserFlags g}++newtype Union (g :: (* -> *) -> *) = Union{getUnion :: g (Const Bool)}++--instance Rank2.Applicative g => Monoid (Union g) where+--   mempty = Union (Rank2.pure $ Const False)++instance (Rank2.Apply g, Rank2.Distributive g) => Monoid (Union g) where+   mempty = Union (Rank2.distributeWith (Const . getConst) (Const False))+   mappend (Union g1) (Union g2) = Union (Rank2.liftA2 union g1 g2)++general, general' :: Alternative (p g s) => Fixed p g s a -> Fixed p g s a++general p = Parser{+   complete= complete p,+   direct = direct p',+   direct0= direct0 p',+   direct1= direct1 p',+   indirect= indirect p',+   cyclicDescendants= cyclicDescendants p'}+   where p' = general' p++general' p@PositiveDirectParser{} = Parser{+   complete= complete p,+   direct = complete p,+   direct0= empty,+   direct1= complete p,+   indirect= empty,+   cyclicDescendants= \cd-> ParserFlags False (const (Const False) Rank2.<$> cd)}+general' p@DirectParser{} = Parser{+   complete= complete p,+   direct = complete p,+   direct0= direct0 p,+   direct1= direct1 p,+   indirect= empty,+   cyclicDescendants= \cd-> ParserFlags True (const (Const False) Rank2.<$> cd)}+general' p@Parser{} = p++-- | Parser of general context-free grammars, including left recursion. -- -- @ -- 'parseComplete' :: ("Rank2".'Rank2.Apply' g, "Rank2".'Rank2.Traversable' g, 'FactorialMonoid' s) =>---                  g (LeftRecursive.'Parser' g s) -> s -> g ('Compose' 'ParseResults' [])+--                  g (LeftRecursive.'Fixed g s) -> s -> g ('Compose' 'ParseResults' []) -- @-instance MultiParsing Parser where-   type GrammarConstraint Parser g = (Rank2.Apply g, Rank2.Distributive g, Rank2.Traversable g)-   type ResultFunctor Parser = Compose ParseResults []-   parsePrefix :: (Rank2.Apply g, Rank2.Traversable g, FactorialMonoid s) =>+instance MultiParsing (Fixed Memoizing.Parser) where+   type GrammarConstraint (Fixed Memoizing.Parser) g = (Rank2.Apply g, Rank2.Distributive g, Rank2.Traversable g)+   type ResultFunctor (Fixed Memoizing.Parser) = Compose ParseResults []+   parsePrefix :: (Rank2.Apply g, Rank2.Distributive g, Rank2.Traversable g, FactorialMonoid s) =>                   g (Parser g s) -> s -> g (Compose (Compose ParseResults []) ((,) s))    parsePrefix g input = Rank2.fmap (Compose . Compose . fromResultList input)                                     (snd $ head $ parseRecursive g input)@@ -80,369 +119,530 @@                                       (snd $ head $ Memoizing.reparseTails close $ parseRecursive g input)       where close = Rank2.fmap (<* endOfInput) selfReferring -instance GrammarParsing Parser where-   type GrammarFunctor Parser = Parser-   nonTerminal = NonTerminal-   recursive = Recursive+instance GrammarParsing (Fixed Memoizing.Parser) where+   type GrammarFunctor (Fixed Memoizing.Parser) = ParserFunctor+   nonTerminal :: forall g s a. (Rank2.Apply g, Rank2.Distributive g, Rank2.Traversable g)+                  => (g (ParserFunctor g s) -> ParserFunctor g s a) -> Parser g s a+   nonTerminal f = Parser{+      complete= ind,+      direct= empty,+      direct0= empty,+      direct1= empty,+      indirect= ind,+      cyclicDescendants= parserFlags . f . Rank2.fmap (ParserFlagsFunctor . getConst) . addSelf}+      where ind = nonTerminal (parserResults . f . Rank2.fmap ParserResultsFunctor)+            addSelf g = Rank2.liftA2 adjust bits g+            adjust :: forall b. Const (g (Const Bool)) b -> Const (ParserFlags g) b -> Const (ParserFlags g) b+            adjust (Const bit) (Const (ParserFlags n d)) =+               Const ParserFlags{+                  nullable= n, +                  dependsOn= Rank2.liftA2 union bit d}+   {-# INLINE nonTerminal #-}+   recursive = general -instance (Rank2.Distributive g, Rank2.Traversable g) => Show (Parser g s a) where-   show (NonTerminal accessor) = "nt" ++ show i-      where Index i = accessor orderedSelfReferring-   show (Primitive name _ _ _) = name-   show Recursive{} = "recursive"-   show (Map _ ast) = "(f <$> " ++ shows ast ")"-   show (Ap f p) = "(" ++ show f ++ " <*> " ++ shows p ")"-   show (Pure _) = "pure x"-   show Empty = "empty"-   show (Bind ast _) = "(" ++ show ast ++ " >>= " ++ ")"-   show (Choice l r) = "(" ++ show l ++ " <|> " ++ shows r ")"-   show (Try ast) = "(try " ++ shows ast ")"-   show (Describe ast msg) = "(" ++ shows ast (" <?> " ++ shows msg ")")-   show (NotFollowedBy ast) = "(notFollowedBy " ++ shows ast ")"-   show (Lookahead ast) = "(lookAhead " ++ shows ast ")"-   show (Many ast) = "(many " ++ shows ast ")"-   show (Some ast) = "(some " ++ shows ast ")"-   show (ConcatMany ast) = "(concatMany " ++ shows ast ")"-   show Index{} = error "Index should be temporary only"-   show ResultsWrap{} = error "ResultsWrap should be temporary only"+bits :: forall (g :: (* -> *) -> *). (Rank2.Distributive g, Rank2.Traversable g) => g (Const (g (Const Bool)))+bits = start `seq` Rank2.fmap oneBit start+   where start = evalState (Rank2.traverse next (Rank2.distributeJoin Nothing)) 0+         oneBit :: Const Int a -> Const (g (Const Bool)) a+         next :: f a -> State Int (Const Int a)+         oneBit (Const i) = Const (Rank2.fmap (Const . (i ==) . getConst) start)+         next _ = do {i <- get; let {i' = succ i}; seq i' (put i'); return (Const i)} -instance (Rank2.Distributive g, Rank2.Traversable g) => Show1 (Parser g s) where-   liftShowsPrec _showsPrec _showList _prec (NonTerminal accessor) _rest = "nt" ++ show i-      where Index i = accessor orderedSelfReferring-   liftShowsPrec _showsPrec _showL _prec (Primitive name _ _ _) rest = name ++ rest-   liftShowsPrec _showsPrec _showL _prec Recursive{} rest = "recursive" ++ rest-   liftShowsPrec _showsPrec _showL _prec (Map _ ast) rest = "(f <$> " ++ shows ast (")" ++ rest)-   liftShowsPrec _showsPrec _showL _prec (Ap f p) rest = "(" ++ show f ++ " <*> " ++ shows p (")" ++ rest)-   liftShowsPrec  showsPrec _showL  prec (Pure x) rest = "pure " ++ showsPrec prec x rest-   liftShowsPrec _showsPrec _showL _prec Empty _rest = "empty"-   liftShowsPrec _showsPrec _showL _prec (Bind ast _) rest = "(" ++ shows ast (" >>= " ++ ")" ++ rest)-   liftShowsPrec _showsPrec _showL _prec (Choice l r) rest = "(" ++ show l ++ " <|> " ++ shows r (")" ++ rest)-   liftShowsPrec _showsPrec _showL _prec (Try ast) rest = "(try " ++ shows ast (")" ++ rest)-   liftShowsPrec _showsPrec _showL _prec (Describe ast msg) rest = "(" ++ shows ast (" <?> " ++ shows msg (")" ++ rest))-   liftShowsPrec _showsPrec _showL _prec (NotFollowedBy ast) rest = "(notFollowedBy " ++ shows ast (")" ++ rest)-   liftShowsPrec _showsPrec _showL _prec (Lookahead ast) rest = "(lookAhead " ++ shows ast (")" ++ rest)-   liftShowsPrec _showsPrec _showL _prec (Many ast) rest = "(many " ++ shows ast (")" ++ rest)-   liftShowsPrec _showsPrec _showL _prec (Some ast) rest = "(some " ++ shows ast (")" ++ rest)-   liftShowsPrec _showsPrec _showL _prec (ConcatMany ast) rest = "(concatMany " ++ shows ast (")" ++ rest)-   liftShowsPrec _showsPrec _showL _prec Index{} _rest = error "Index should be temporary only"-   liftShowsPrec _showsPrec _showL _prec ResultsWrap{} _rest = error "ResultsWrap should be temporary only"+instance Functor (p g s) => Functor (Fixed p g s) where+   fmap f (PositiveDirectParser p) = PositiveDirectParser (fmap f p)+   fmap f p@DirectParser{} = DirectParser{+      complete= fmap f (complete p),+      direct0= fmap f (direct0 p),+      direct1= fmap f (direct1 p)}+   fmap f p@Parser{} = p{+      complete= fmap f (complete p),+      direct= fmap f (direct p),+      direct0= fmap f (direct0 p),+      direct1= fmap f (direct1 p),+      indirect= fmap f (indirect p)}+   {-# INLINABLE fmap #-} -instance Functor (Parser g s) where-   fmap _ Empty = Empty-   fmap f ast = Map f ast+instance Alternative (p g s) => Applicative (Fixed p g s) where+   pure a = DirectParser{complete= pure a,+                         direct0= pure a,+                         direct1= empty}+   p@PositiveDirectParser{} <*> q = PositiveDirectParser{+      complete= complete p <*> complete q}+   p@DirectParser{} <*> q@PositiveDirectParser{} = PositiveDirectParser{+      complete= complete p <*> complete q}+   p@DirectParser{} <*> q@DirectParser{} = DirectParser{+      complete= complete p <*> complete q,+      direct0= direct0 p <*> direct0 q,+      direct1= direct0 p <*> direct1 q <|> direct1 p <*> complete q}+   p <*> q@Parser{} = Parser{+      complete= complete p' <*> complete q,+      direct= direct0 p' <*> direct q <|> direct1 p' <*> complete q,+      direct0= direct0 p' <*> direct0 q,+      direct1= direct0 p' <*> direct1 q <|> direct1 p' <*> complete q,+      indirect= direct0 p' <*> indirect q <|> indirect p' <*> complete q,+      cyclicDescendants= \deps-> let+           pcd@(ParserFlags pn pd) = cyclicDescendants p' deps+           ParserFlags qn qd = cyclicDescendants q deps+        in if pn+           then ParserFlags qn (Rank2.liftA2 union pd qd)+           else pcd}+      where p'@Parser{} = general' p+   p <*> q = Parser{+      complete= complete p' <*> complete q',+      direct= direct p' <*> complete q',+      direct0= direct0 p' <*> direct0 q',+      direct1= direct0 p' <*> direct1 q' <|> direct1 p' <*> complete q',+      indirect= indirect p' <*> complete q',+      cyclicDescendants= \deps-> let+           pcd@(ParserFlags pn pd) = cyclicDescendants p' deps+           ParserFlags qn qd = cyclicDescendants q' deps+        in if pn+           then ParserFlags qn (Rank2.liftA2 union pd qd)+           else pcd}+      where p'@Parser{} = general' p+            q'@Parser{} = general' q+   {-# INLINABLE pure #-}+   {-# INLINABLE (<*>) #-} -instance Applicative (Parser g s) where-   pure = Pure-   Empty <*> _ = Empty-   _ <*> Empty = Empty-   p <*> q = Ap p q+instance Alternative (p g s) => Alternative (Fixed p g s) where+   empty = PositiveDirectParser{complete= empty}+   p@PositiveDirectParser{} <|> q@PositiveDirectParser{} = PositiveDirectParser{complete= complete p <|> complete q}+   p@PositiveDirectParser{} <|> q@DirectParser{} = DirectParser{+      complete= complete p <|> complete q,+      direct0 = direct0 q,+      direct1= complete p <|> direct1 q}+   p@DirectParser{} <|> q@PositiveDirectParser{} = DirectParser{+      complete= complete p <|> complete q,+      direct0 = direct0 p,+      direct1= direct1 p <|> complete q}+   p@DirectParser{} <|> q@DirectParser{} = DirectParser{+      complete= complete p <|> complete q,+      direct0 = direct0 p <|> direct0 q,+      direct1= direct1 p <|> direct1 q}+   p <|> q = Parser{complete= complete p' <|> complete q',+                    direct= direct p' <|> direct q',+                    direct0= direct0 p' <|> direct0 q',+                    direct1= direct1 p' <|> direct1 q',+                    indirect= indirect p' <|> indirect q',+                    cyclicDescendants= \deps-> let+                         ParserFlags pn pd = cyclicDescendants p' deps+                         ParserFlags qn qd = cyclicDescendants q' deps+                      in ParserFlags (pn || qn) (Rank2.liftA2 union pd qd)}+      where p'@Parser{} = general p+            q'@Parser{} = general q+   many (PositiveDirectParser p) = DirectParser{+      complete= many p,+      direct0= pure [],+      direct1= some p}+   many p@DirectParser{} = DirectParser{+      complete= many (complete p),+      direct0= pure [] <|> (:[]) <$> direct0 p,+      direct1= (:) <$> direct1 p <*> many (complete p)}+   many p@Parser{} = Parser{+      complete= mcp,+      direct= d0 <|> d1,+      direct0= d0,+      direct1= d1,+      indirect= (:) <$> indirect p <*> mcp,+      cyclicDescendants= \deps-> (cyclicDescendants p deps){nullable= True}}+      where d0 = pure [] <|> (:[]) <$> direct0 p+            d1 = (:) <$> direct1 p <*> mcp+            mcp = many (complete p)+   some (PositiveDirectParser p) = PositiveDirectParser{complete= some p}+   some p@DirectParser{} = DirectParser{+      complete= some (complete p),+      direct0= (:[]) <$> direct0 p,+      direct1= (:) <$> direct1 p <*> many (complete p)}+   some p@Parser{} = Parser{+      complete= some (complete p),+      direct= d0 <|> d1,+      direct0= d0,+      direct1= d1,+      indirect= (:) <$> indirect p <*> many (complete p),+      cyclicDescendants= cyclicDescendants p}+      where d0 = (:[]) <$> direct0 p+            d1= (:) <$> direct1 p <*> many (complete p)+   {-# INLINABLE (<|>) #-}+   {-# INLINABLE many #-}+   {-# INLINABLE some #-} -instance Alternative (Parser g s) where-   empty = Empty-   Empty <|> ast = ast-   ast <|> Empty = ast-   p <|> q = Choice p q-   many Empty = pure []-   many ast = Many ast-   some Empty = Empty-   some ast = Some ast+infixl 3 <<|>+(<<|>) :: Parser g s a -> Parser g s a -> Parser g s a+p@DirectParser{} <<|> q@PositiveDirectParser{} = DirectParser{+   complete= complete p Memoizing.<<|> complete q,+   direct0 = direct0 p,+   direct1= direct1 p Memoizing.<<|> complete q}+p@DirectParser{} <<|> q@DirectParser{} = DirectParser{+   complete= complete p Memoizing.<<|> complete q,+   direct0 = direct0 p Memoizing.<<|> direct0 q,+   direct1= direct1 p Memoizing.<<|> direct1 q}+p <<|> q = Parser{complete= complete p' Memoizing.<<|> complete q',+                 direct= direct p' Memoizing.<<|> direct q',+                 direct0= direct0 p' Memoizing.<<|> direct0 q',+                 direct1= direct1 p' Memoizing.<<|> direct1 q',+                 indirect= indirect p' Memoizing.<<|> indirect q',+                 cyclicDescendants= \deps-> let+                         ParserFlags pn pd = cyclicDescendants p' deps+                         ParserFlags qn qd = cyclicDescendants q' deps+                      in ParserFlags (pn || qn) (Rank2.liftA2 union pd qd)}+   where p'@Parser{} = general p+         q'@Parser{} = general q -instance Monad (Parser g s) where+union :: Const Bool x -> Const Bool x -> Const Bool x+union (Const False) d = d+union (Const True) _ = Const True++instance (Alternative (p g s), Monad (p g s)) => Monad (Fixed p g s) where    return = pure    (>>) = (*>)-   Empty >>= _ = Empty-   ast >>= cont = Bind ast cont+   PositiveDirectParser p >>= cont = PositiveDirectParser (p >>= complete . cont)+   p@DirectParser{} >>= cont = Parser{+      complete= complete p >>= complete . cont,+      direct= d0 <|> d1,+      direct0= d0,+      direct1= d1,+      indirect= direct0 p >>= indirect . general' . cont,+      cyclicDescendants= \cd-> (ParserFlags True $ Rank2.fmap (const $ Const True) cd)}+      where d0 = direct0 p >>= direct0 . general' . cont+            d1 = (direct0 p >>= direct1 . general' . cont) <|> (direct1 p >>= complete . cont)+   p >>= cont = Parser{+      complete= complete p >>= complete . cont,+      direct= d0 <|> d1,+      direct0= d0,+      direct1= d1,+      indirect= (indirect p >>= complete . cont) <|> (direct0 p >>= indirect . general' . cont),+      cyclicDescendants= \cd-> (ParserFlags True $ Rank2.fmap (const $ Const True) cd)}+      where d0 = direct0 p >>= direct0 . general' . cont+            d1 = (direct0 p >>= direct1 . general' . cont) <|> (direct1 p >>= complete . cont) -instance MonadPlus (Parser g s) where+instance MonadPlus (p g s) => MonadPlus (Fixed p g s) where    mzero = empty    mplus = (<|>) -instance Monoid x => Monoid (Parser g s x) where+instance (Alternative (p g s), Monoid x) => Monoid (Fixed p g s x) where    mempty = pure mempty    mappend = liftA2 mappend -instance MonoidNull s => Parsing (Parser g s) where-   eof = Primitive "eof" (Just eof) Nothing eof-   try Empty = Empty-   try ast = Try ast-   Empty <?> _ = Empty-   ast <?> msg = Describe ast msg-   notFollowedBy = NotFollowedBy-   unexpected msg = Primitive "unexpected" Nothing (Just $ unexpected msg) (unexpected msg)-   skipMany = ConcatMany . (() <$)+primitive :: String -> p g s a -> p g s a -> p g s a -> Fixed p g s a+primitive _name d0 d1 d = DirectParser{complete= d,+                                       direct0= d0,+                                       direct1= d1} -instance MonoidNull s => LookAheadParsing (Parser g s) where-   lookAhead = Lookahead+positivePrimitive :: String -> p g s a -> Fixed p g s a+positivePrimitive _name p = PositiveDirectParser{complete= p} -instance (Show s, TextualMonoid s) => CharParsing (Parser g s) where-   satisfy = satisfyChar-   string s = Textual.toString (error "unexpected non-character") <$> string (fromString s)-   char = satisfyChar . (==)-   notChar = satisfyChar . (/=)-   anyChar = satisfyChar (const True)-   text t = (fromString . Textual.toString (error "unexpected non-character")) <$> string (Textual.fromText t)+instance (LookAheadParsing (p g s), MonoidParsing (Fixed p g)) => Parsing (Fixed p g s) where+   eof = primitive "eof" eof empty eof+   try (PositiveDirectParser p) = PositiveDirectParser (try p)+   try p@DirectParser{} = DirectParser{+      complete= try (complete p),+      direct0= try (direct0 p),+      direct1= try (direct1 p)}+   try p@Parser{} = p{+      complete= try (complete p),+      direct= try (direct p),+      direct0= try (direct0 p),+      direct1= try (direct1 p),+      indirect= try (indirect p)}+   PositiveDirectParser p <?> msg = PositiveDirectParser (p <?> msg)+   p@DirectParser{} <?> msg = DirectParser{+      complete= complete p <?> msg,+      direct0= direct0 p <?> msg,+      direct1= direct1 p <?> msg}+   p@Parser{} <?> msg = p{+      complete= complete p <?> msg,+      direct= direct p <?> msg,+      direct0= direct0 p <?> msg,+      direct1= direct1 p <?> msg,+      indirect= indirect p <?> msg}+   notFollowedBy p@PositiveDirectParser{} = DirectParser{+      complete= notFollowedBy (complete p),+      direct0= notFollowedBy (complete p),+      direct1= empty}+   notFollowedBy p@DirectParser{} = DirectParser{+      complete= notFollowedBy (complete p),+      direct0= notFollowedBy (complete p),+      direct1= empty}+   notFollowedBy p@Parser{} = Parser{+      complete= notFollowedBy (complete p),+      direct= notFollowedBy (direct p),+      direct0= notFollowedBy (direct p),+      direct1= empty,+      indirect= notFollowedBy (indirect p),+      cyclicDescendants= \deps-> (cyclicDescendants p deps){nullable= True}}+   unexpected msg = positivePrimitive "unexpected" (unexpected msg)+   skipMany p = concatMany (() <$ p) -instance (Show s, TextualMonoid s) => TokenParsing (Parser g s) where-   someSpace = () <$ takeCharsWhile1 isSpace+instance (LookAheadParsing (p g s), MonoidParsing (Fixed p g)) => LookAheadParsing (Fixed p g s) where+   lookAhead p@PositiveDirectParser{} = DirectParser{+      complete= lookAhead (complete p),+      direct0= lookAhead (complete p),+      direct1= empty}+   lookAhead p@DirectParser{} = DirectParser{+      complete= lookAhead (complete p),+      direct0= lookAhead (complete p),+      direct1= empty}+   lookAhead p@Parser{} = Parser{+      complete= lookAhead (complete p),+      direct= lookAhead (direct p),+      direct0= lookAhead (direct p),+      direct1= empty,+      indirect= lookAhead (indirect p),+      cyclicDescendants= \deps-> (cyclicDescendants p deps){nullable= True}} -instance MonoidParsing (Parser g) where-   endOfInput = Primitive "endOfInput" (Just endOfInput) Nothing endOfInput-   getInput = Primitive "getInput" (Just $ eof *> getInput) (Just $ notFollowedBy eof *> getInput) getInput-   anyToken = Primitive "anyToken" Nothing (Just anyToken) anyToken-   token x = Primitive "token" Nothing (Just $ token x) (token x)-   satisfy predicate = Primitive "satisfy" Nothing (Just $ satisfy predicate) (satisfy predicate)-   satisfyChar predicate = Primitive "satisfyChar" Nothing (Just $ satisfyChar predicate) (satisfyChar predicate)-   scan s0 f = Primitive "scan" (Just $ mempty <$ notFollowedBy (() <$ p1)) (Just $ lookAhead p1 *> p) p+instance MonoidParsing (Fixed Memoizing.Parser g) where+   endOfInput = primitive "endOfInput" endOfInput empty endOfInput+   getInput = primitive "getInput" (endOfInput *> getInput) (notFollowedBy endOfInput *> getInput) getInput+   anyToken = positivePrimitive "anyToken" anyToken+   token x = positivePrimitive "token" (token x)+   satisfy predicate = positivePrimitive "satisfy" (satisfy predicate)+   satisfyChar predicate = positivePrimitive "satisfyChar" (satisfyChar predicate)+   satisfyCharInput predicate = positivePrimitive "satisfyCharInput" (satisfyCharInput predicate)+   notSatisfy predicate = primitive "notSatisfy" (notSatisfy predicate) empty (notSatisfy predicate)+   notSatisfyChar predicate = primitive "notSatisfyChar" (notSatisfyChar predicate) empty (notSatisfyChar predicate)+   scan s0 f = primitive "scan" (mempty <$ notSatisfy test) (lookAhead (satisfy test) *> p) p       where p = scan s0 f-            p1 = satisfy (isJust . f s0)-   scanChars s0 f = Primitive "scanChars" (Just $ mempty <$ notFollowedBy p1) (Just $ lookAhead p1 *> p) p+            test = isJust . f s0+   scanChars s0 f = primitive "scanChars" (mempty <$ notSatisfyChar test) (lookAhead (satisfyChar test) *> p) p       where p = scanChars s0 f-            p1 = satisfyChar (isJust . f s0)+            test = isJust . f s0    string s-      | null s = Primitive ("(string " ++ shows s ")") (Just $ string s) Nothing (string s)-      | otherwise = Primitive ("(string " ++ shows s ")") Nothing (Just $ string s) (string s)-   takeWhile predicate = Primitive "takeWhile" (Just $ mempty <$ notFollowedBy (() <$ satisfy predicate))-                                               (Just $ takeWhile1 predicate) (takeWhile predicate)-   takeWhile1 predicate = Primitive "takeWhile1" Nothing (Just $ takeWhile1 predicate) (takeWhile1 predicate)-   takeCharsWhile predicate = Primitive "takeCharsWhile" (Just $ mempty <$ notFollowedBy (satisfyChar predicate))-                                                         (Just $ takeCharsWhile1 predicate) (takeCharsWhile predicate)-   takeCharsWhile1 predicate = Primitive "takeCharsWhile1" Nothing (Just $ takeCharsWhile1 predicate)-                                                           (takeCharsWhile1 predicate)-   whiteSpace = Primitive "whiteSpace" (Just $ notFollowedBy whiteSpace) (Just whiteSpace) whiteSpace-   concatMany = ConcatMany--toParser :: (Rank2.Functor g, FactorialMonoid s) => Parser g s a -> Memoizing.Parser g s a-toParser (NonTerminal accessor) = nonTerminal (unwrap . accessor . Rank2.fmap ResultsWrap)-   where unwrap (ResultsWrap x) = x-         unwrap _ = error "should have been wrapped"-toParser (Primitive _ _ _ p) = p-toParser (Recursive ast) = toParser ast-toParser (Map f ast) = f <$> toParser ast-toParser (Ap f a) = toParser f <*> toParser a-toParser (Pure x) = pure x-toParser Empty = empty-toParser (Bind ast cont) = toParser ast >>= toParser . cont-toParser (Choice l r) = toParser l <|> toParser r-toParser (Try ast) = try (toParser ast)-toParser (Describe ast msg) = toParser ast <?> msg-toParser (NotFollowedBy ast) = notFollowedBy (toParser ast)-toParser (Lookahead ast) = lookAhead (toParser ast)-toParser (Many ast) = many (toParser ast)-toParser (Some ast) = some (toParser ast)-toParser (ConcatMany ast) = concatMany (toParser ast)-toParser Index{} = error "Index should be temporary only"-toParser ResultsWrap{} = error "ResultsWrap should be temporary only"--splitDirect :: (Rank2.Functor g, FactorialMonoid s) => Parser g s a -> (Parser g s a, Parser g s a)-splitDirect ast@NonTerminal{} = (empty, ast)-splitDirect ast@Primitive{} = (ast, empty)-splitDirect (Recursive ast) = both Recursive (splitDirect ast)-splitDirect (Map f ast) = both (f <$>) (splitDirect ast)-splitDirect (Ap f a)-   | Empty <- an = (fd <*> a, fn <*> a)-   | otherwise = (fd0 <*> ad <|> fd1 <*> a, fd0 <*> an <|> fn <*> a)-   where (fd, fn) = splitDirect f-         (ad, an) = splitDirect a-         (fd0, fd1) = splitNullable fd-splitDirect ast@Pure{} = (ast, empty)-splitDirect Empty = (Empty, Empty)-splitDirect (Bind ast cont) = (d0cd <|> (d1 >>= cont), d0cn <|> (n >>= cont))-   where (d, n) = splitDirect ast-         (d0, d1) = splitNullable d-         (d0cd, d0cn) = splitDirect (d0 >>= cont)-splitDirect (Choice l r) = (ld <|> rd, ln <|> rn)-   where (ld, ln) = splitDirect l-         (rd, rn) = splitDirect r-splitDirect (Try ast) = both try (splitDirect ast)-splitDirect (Describe ast msg) = both (<?> msg) (splitDirect ast)-splitDirect (NotFollowedBy ast) = both notFollowedBy (splitDirect ast)-splitDirect (Lookahead ast) = both lookAhead (splitDirect ast)-splitDirect ast@(Many ast1) = (pure [] <|> (:) <$> d <*> ast, (:) <$> n <*> ast)-   where (d, n) = splitDirect ast1-splitDirect (Some ast) = ((:) <$> d <*> ast', (:) <$> n <*> ast')-   where (d, n) = splitDirect ast-         ast' = Many ast-splitDirect ast@(ConcatMany ast1) = (pure mempty <|> (<>) <$> d <*> ast, (<>) <$> n <*> ast)-   where (d, n) = splitDirect ast1-splitDirect Index{} = error "Index should be temporary only"-splitDirect ResultsWrap{} = error "ResultsWrap should be temporary only"--splitNullable :: MonoidNull s => Parser g s a -> (Parser g s a, Parser g s a)-splitNullable ast@NonTerminal{} = (ast, empty)-splitNullable (Primitive name p0 p1 _) = (maybe empty (\p-> Primitive name (Just p) Nothing p) p0,-                                          maybe empty (\p-> Primitive name Nothing (Just p) p) p1)-splitNullable (Recursive ast) = both Recursive (splitNullable ast)-splitNullable (Map f ast) = both (f <$>) (splitNullable ast)-splitNullable (Ap f a)-   | Empty <- f0 = (empty, f <*> a)-   | Empty <- a0 = (empty, f <*> a)-   | otherwise = (f0 <*> a0, f1 <*> a <|> f <*> a1)-   where (f0, f1) = splitNullable f-         (a0, a1) = splitNullable a-splitNullable ast@Pure{} = (ast, empty)-splitNullable Empty = (empty, empty)-splitNullable (Bind ast cont) = (fst c0, snd c0 <|> (ast1 >>= cont))-   where (ast0, ast1) = splitNullable ast-         c0 = splitNullable (ast0 >>= cont)-splitNullable (Choice l r) = (l0 <|> r0, l1 <|> r1)-   where (l0, l1) = splitNullable l-         (r0, r1) = splitNullable r-splitNullable (Try ast) = both try (splitNullable ast)-splitNullable (Describe ast msg) = both (<?> msg) (splitNullable ast)-splitNullable ast@NotFollowedBy{} = (ast, empty)-splitNullable ast@Lookahead{} = (ast, empty)-splitNullable (Many ast) = (pure [] <|> (:[]) <$> ast0, (:) <$> ast1 <*> many ast)-   where (ast0, ast1) = splitNullable ast-splitNullable (Some ast) = ((:[]) <$> ast0, (:) <$> ast1 <*> many ast)-   where (ast0, ast1) = splitNullable ast-splitNullable (ConcatMany ast) = (pure mempty <|> ast0, (<>) <$> ast1 <*> concatMany ast)-   where (ast0, ast1) = splitNullable ast-splitNullable (ResultsWrap _) = error "ResultsWrap should be temporary only"-splitNullable (Index _) = error "Index should be temporary only"+      | null s = primitive ("(string " ++ shows s ")") (string s) empty (string s)+      | otherwise = positivePrimitive ("(string " ++ shows s ")") (string s)+   takeWhile predicate = primitive "takeWhile" (mempty <$ notSatisfy predicate)+                                               (takeWhile1 predicate) (takeWhile predicate)+   takeWhile1 predicate = positivePrimitive "takeWhile1" (takeWhile1 predicate)+   takeCharsWhile predicate = primitive "takeCharsWhile" (mempty <$ notSatisfyChar predicate)+                                                         (takeCharsWhile1 predicate) (takeCharsWhile predicate)+   takeCharsWhile1 predicate = positivePrimitive "takeCharsWhile1" (takeCharsWhile1 predicate)+   whiteSpace = primitive "whiteSpace" (notSatisfyChar isSpace) (satisfyChar isSpace *> whiteSpace) whiteSpace+   concatMany p@PositiveDirectParser{} = DirectParser{+      complete= cmp,+      direct0= d0,+      direct1= d1}+      where d0 = pure mempty+            d1 = (<>) <$> complete p <*> cmp+            cmp = concatMany (complete p)+   concatMany p@DirectParser{} = DirectParser{+      complete= cmp,+      direct0= d0,+      direct1= d1}+      where d0 = pure mempty <|> direct0 p+            d1 = (<>) <$> direct1 p <*> cmp+            cmp = concatMany (complete p)+   concatMany p@Parser{} = Parser{+      complete= cmp,+      direct= d0 <|> d1,+      direct0= d0,+      direct1= d1,+      indirect= (<>) <$> indirect p <*> cmp,+      cyclicDescendants= \deps-> (cyclicDescendants p deps){nullable= True}}+      where d0 = pure mempty <|> direct0 p+            d1 = (<>) <$> direct1 p <*> cmp+            cmp = concatMany (complete p)+   {-# INLINABLE string #-} -both :: (a -> b) -> (a, a) -> (b, b)-both f (x, y) = (f x, f y)+instance MonoidParsing (Fixed Backtrack.Parser g) where+   endOfInput = primitive "endOfInput" endOfInput empty endOfInput+   getInput = primitive "getInput" (endOfInput *> getInput) (notFollowedBy endOfInput *> getInput) getInput+   anyToken = positivePrimitive "anyToken" anyToken+   token x = positivePrimitive "token" (token x)+   satisfy predicate = positivePrimitive "satisfy" (satisfy predicate)+   satisfyChar predicate = positivePrimitive "satisfyChar" (satisfyChar predicate)+   satisfyCharInput predicate = positivePrimitive "satisfyCharInput" (satisfyCharInput predicate)+   notSatisfy predicate = primitive "notSatisfy" (notSatisfy predicate) empty (notSatisfy predicate)+   notSatisfyChar predicate = primitive "notSatisfyChar" (notSatisfyChar predicate) empty (notSatisfyChar predicate)+   scan s0 f = primitive "scan" (mempty <$ notSatisfy test) (lookAhead (satisfy test) *> p) p+      where p = scan s0 f+            test = isJust . f s0+   scanChars s0 f = primitive "scanChars" (mempty <$ notSatisfyChar test) (lookAhead (satisfyChar test) *> p) p+      where p = scanChars s0 f+            test = isJust . f s0+   string s+      | null s = primitive ("(string " ++ shows s ")") (string s) empty (string s)+      | otherwise = positivePrimitive ("(string " ++ shows s ")") (string s)+   takeWhile predicate = primitive "takeWhile" (mempty <$ notSatisfy predicate)+                                               (takeWhile1 predicate) (takeWhile predicate)+   takeWhile1 predicate = positivePrimitive "takeWhile1" (takeWhile1 predicate)+   takeCharsWhile predicate = primitive "takeCharsWhile" (mempty <$ notSatisfyChar predicate)+                                                         (takeCharsWhile1 predicate) (takeCharsWhile predicate)+   takeCharsWhile1 predicate = positivePrimitive "takeCharsWhile1" (takeCharsWhile1 predicate)+   whiteSpace = primitive "whiteSpace" (notSatisfyChar isSpace) (satisfyChar isSpace *> whiteSpace) whiteSpace+   concatMany p@PositiveDirectParser{} = DirectParser{+      complete= cmp,+      direct0= d0,+      direct1= d1}+      where d0 = pure mempty+            d1 = (<>) <$> complete p <*> cmp+            cmp = concatMany (complete p)+   concatMany p@DirectParser{} = DirectParser{+      complete= cmp,+      direct0= d0,+      direct1= d1}+      where d0 = pure mempty `Backtrack.alt` direct0 p+            d1 = (<>) <$> direct1 p <*> cmp+            cmp = concatMany (complete p)+   concatMany p@Parser{} = Parser{+      complete= cmp,+      direct= d0 `Backtrack.alt` d1,+      direct0= d0,+      direct1= d1,+      indirect= (<>) <$> indirect p <*> cmp,+      cyclicDescendants= \deps-> (cyclicDescendants p deps){nullable= True}}+      where d0 = pure mempty `Backtrack.alt` direct0 p+            d1 = (<>) <$> direct1 p <*> cmp+            cmp = concatMany (complete p)+   {-# INLINABLE string #-} -leftDescendants :: forall g s. (Rank2.Apply g, Rank2.Traversable g) => g (Parser g s) -> g (Const (Bool, g (Const Bool)))-leftDescendants g = evalState (Rank2.traverse (const replaceFromList) g) $ map (setToBools <$>) $-                    IntMap.elems $ calcLeftSets $ IntMap.fromList $ zip [0..] $ Rank2.foldMap successorSet g-   where replaceFromList :: State [x] (Const x y)-         replaceFromList = do next:rest <- get-                              put rest-                              return (Const next)-         setToBools :: IntSet -> g (Const Bool)-         setToBools = Rank2.traverse isElem enumeration-         isElem :: Parser g s a -> IntSet -> Const Bool a-         isElem (Index i) set = Const (IntSet.member i set)-         successorSet :: Parser g s a -> [IntSet]-         successorSet a = [leftRecursiveOn a]-         enumeration = ordered g-         universe = Rank2.foldMap (\(Index i)-> IntSet.singleton i) enumeration-         g0 = fixNullable g-         leftRecursiveOn :: Parser g s a -> IntSet-         leftRecursiveOn (NonTerminal accessor) = IntSet.singleton i-            where Index i = accessor enumeration-         leftRecursiveOn Primitive{} = mempty-         leftRecursiveOn (Recursive ast) = leftRecursiveOn ast-         leftRecursiveOn (Map _ ast) = leftRecursiveOn ast-         leftRecursiveOn (Ap f p) = leftRecursiveOn f <> if nullable g0 f then leftRecursiveOn p else mempty-         leftRecursiveOn Pure{} = mempty-         leftRecursiveOn Empty = mempty-         leftRecursiveOn (Bind ast _cont) = if nullable g0 ast then universe else leftRecursiveOn ast-         leftRecursiveOn (Choice l r) = leftRecursiveOn l <> leftRecursiveOn r-         leftRecursiveOn (Try ast) = leftRecursiveOn ast-         leftRecursiveOn (Describe ast _) = leftRecursiveOn ast-         leftRecursiveOn (NotFollowedBy ast) = leftRecursiveOn ast-         leftRecursiveOn (Lookahead ast) = leftRecursiveOn ast-         leftRecursiveOn (Many ast) = leftRecursiveOn ast-         leftRecursiveOn (Some ast) = leftRecursiveOn ast-         leftRecursiveOn (ConcatMany ast) = leftRecursiveOn ast+instance (LookAheadParsing (p g s), MonoidParsing (Fixed p g), Show s, TextualMonoid s) =>+         CharParsing (Fixed p g s) where+   satisfy = satisfyChar+   string s = Textual.toString (error "unexpected non-character") <$> string (fromString s)+   char = satisfyChar . (==)+   notChar = satisfyChar . (/=)+   anyChar = satisfyChar (const True)+   text t = (fromString . Textual.toString (error "unexpected non-character")) <$> string (Textual.fromText t) -nullable :: Rank2.Functor g => g (Const Bool) -> Parser g s a -> Bool-nullable gn (NonTerminal accessor) = n == 1-   where Index n = accessor (Rank2.fmap (\(Const z)-> Index $ if z then 1 else 0) gn)-nullable _  (Primitive _name z _ _) = isJust z-nullable gn (Recursive ast) = nullable gn ast-nullable gn (Map _ ast) = nullable gn ast-nullable gn (Ap f p) = nullable gn f && nullable gn p-nullable _  Pure{} = True-nullable _  Empty = False-nullable gn (Bind ast _cont) = nullable gn ast-nullable gn (Choice l r) = nullable gn l || nullable gn r-nullable gn (Try ast) = nullable gn ast-nullable gn (Describe ast _) = nullable gn ast-nullable _  NotFollowedBy{} = True-nullable _  Lookahead{} = True-nullable _  Many{} = True-nullable gn (Some ast) = nullable gn ast-nullable _  ConcatMany{} = True+instance (LookAheadParsing (p g s), TokenParsing (p g s), MonoidParsing (Fixed p g), Show s, TextualMonoid s) => +         TokenParsing (Fixed p g s) where+   someSpace = positivePrimitive "someSpace" someSpace -fixNullable :: (Rank2.Apply g, Rank2.Foldable g) => g (Parser g s) -> g (Const Bool)-fixNullable g = go (Rank2.fmap (const $ Const True) g)-   where go gn-            | getAll (Rank2.foldMap (All . getConst) $ Rank2.liftA2 agree gn gn') = gn-            | otherwise = go gn'-            where gn' = Rank2.fmap (Const . nullable gn) g-         agree x y = Const (x == y)+-- | Turns a context-free parser into a backtracking PEG parser that consumes the longest possible prefix of the list+-- of input tails, opposite of 'peg'+longest :: FactorialMonoid s => Fixed Memoizing.Parser g s a -> Fixed Backtrack.Parser g [(s, g (ResultList g s))] a+longest (PositiveDirectParser p) = PositiveDirectParser (Memoizing.longest p)+longest p@DirectParser{} = DirectParser{complete= Memoizing.longest (complete p),+                                        direct0=  Memoizing.longest (direct0 p),+                                        direct1=  Memoizing.longest (direct1 p)}+longest p@Parser{} = Parser{complete= Memoizing.longest (complete p),+                            direct=  Memoizing.longest (direct p),+                            direct0=  Memoizing.longest (direct0 p),+                            direct1=  Memoizing.longest (direct1 p),+                            indirect=  Memoizing.longest (indirect p),+                            cyclicDescendants= cyclicDescendants p} -orderedSelfReferring :: (Rank2.Distributive g, Rank2.Traversable g) => g (Parser g s)-orderedSelfReferring = ordered (Rank2.distributeWith NonTerminal id)+-- | Turns a backtracking PEG parser of the list of input tails into a context-free parser, opposite of 'longest'+peg :: Fixed Backtrack.Parser g [(s, g (ResultList g s))] a -> Fixed Memoizing.Parser g s a+peg (PositiveDirectParser p) = PositiveDirectParser (Memoizing.peg p)+peg p@DirectParser{} = DirectParser{complete= Memoizing.peg (complete p),+                                        direct0=  Memoizing.peg (direct0 p),+                                        direct1=  Memoizing.peg (direct1 p)}+peg p@Parser{} = Parser{complete= Memoizing.peg (complete p),+                        direct=  Memoizing.peg (direct p),+                        direct0=  Memoizing.peg (direct0 p),+                        direct1=  Memoizing.peg (direct1 p),+                        indirect=  Memoizing.peg (indirect p),+                        cyclicDescendants= cyclicDescendants p} -ordered :: Rank2.Traversable g => g (Parser g s) -> g (Parser g s)-ordered g = evalState (Rank2.traverse (const increment) g) 0-   where increment :: State Int (Parser g s a)-         increment = do {n <- get; put (n+1); return (Index n)}+-- | Turns a backtracking PEG parser into a context-free parser+terminalPEG :: Monoid s => Fixed Backtrack.Parser g s a -> Fixed Memoizing.Parser g s a+terminalPEG (PositiveDirectParser p) = PositiveDirectParser (Memoizing.terminalPEG p)+terminalPEG p@DirectParser{} = DirectParser{complete= Memoizing.terminalPEG (complete p),+                                            direct0=  Memoizing.terminalPEG (direct0 p),+                                            direct1=  Memoizing.terminalPEG (direct1 p)}+terminalPEG p@Parser{} = Parser{complete= Memoizing.terminalPEG (complete p),+                                direct=  Memoizing.terminalPEG (direct p),+                                direct0=  Memoizing.terminalPEG (direct0 p),+                                direct1=  Memoizing.terminalPEG (direct1 p),+                                indirect=  Memoizing.terminalPEG (indirect p),+                                cyclicDescendants= cyclicDescendants p} -data AdvanceFront = AdvanceFront{visited       :: IntSet,-                                 cyclic        :: Bool,-                                 front         :: IntSet}-                  deriving Show+parseRecursive :: forall g s. (Rank2.Apply g, Rank2.Distributive g, Rank2.Traversable g, FactorialMonoid s) =>+                  g (Parser g s) -> s -> [(s, g (ResultList g s))]+parseRecursive = parseSeparated . separated -calcLeftSets :: IntMap IntSet -> IntMap (Bool, IntSet)-calcLeftSets successors = (cyclic &&& visited) <$> expandPaths initialDepths-   where expandPaths :: IntMap AdvanceFront -> IntMap AdvanceFront-         expandPaths paths-            | all (IntSet.null . front) paths' = paths'-            | otherwise = expandPaths paths'-            where paths' = expandReachables <$> paths-                  expandReachables :: AdvanceFront -> AdvanceFront-                  expandReachables x = -                     AdvanceFront{visited= visited x <> front x,-                                  cyclic= cyclic x || not (IntSet.null $ IntSet.intersection (front x) (visited x)),-                                  front= IntSet.foldr' addSuccessors mempty (IntSet.difference (front x) (visited x))}-         addSuccessors :: Int -> IntSet -> IntSet-         addSuccessors node set = set <> successors IntMap.! node-         initialDepths = IntMap.mapWithKey setToFront successors-         setToFront root set = AdvanceFront{visited= mempty,-                                            cyclic= IntSet.member root set,-                                            front= set}+separated :: forall g s. (Rank2.Apply g, Rank2.Distributive g, Rank2.Traversable g) =>+             g (Parser g s) -> g (SeparatedParser Memoizing.Parser g s)+separated g = Rank2.liftA4 reseparate circulars cycleFollowers descendants g+   where descendants :: g (Const (g (Const Bool)))+         cycleFollowers, circulars :: g (Const Bool)+         cyclicDescendantses :: g (Const (ParserFlags g))+         leftRecursive :: forall a. Const (g (Const Bool)) a -> Const (ParserFlags g) a -> Const Bool a+         leftRecursiveDeps :: forall a. Const Bool a -> Const (ParserFlags g) a -> Const (g (Const Bool)) a+         reseparate :: forall a. Const Bool a -> Const Bool a -> Const (g (Const Bool)) a -> Parser g s a+                    -> SeparatedParser Memoizing.Parser g s a+         reseparate (Const circular) (Const follower) (Const deps) p+            | circular || leader && follower = CycleParser (indirect p) (direct p) deps+            | follower = BackParser (complete p)+            | otherwise = FrontParser (complete p)+            where leader = getAny (Rank2.foldMap (Any . getConst) $ Rank2.liftA2 intersection circulars deps)+         descendants = Rank2.fmap (Const . dependsOn . getConst) cyclicDescendantses+         cyclicDescendantses = fixDescendants (Rank2.fmap (Const . cyclicDescendants . general) g)+         circulars = Rank2.liftA2 leftRecursive bits cyclicDescendantses+         cycleFollowers = getUnion (Rank2.foldMap (Union . getConst) $+                                    Rank2.liftA2 leftRecursiveDeps circulars cyclicDescendantses)+         leftRecursive (Const bit) (Const flags) =+            Const (getAny $ Rank2.foldMap (Any . getConst) $ Rank2.liftA2 intersection bit $ dependsOn flags)+         leftRecursiveDeps (Const True) (Const flags) = Const (dependsOn flags)+         leftRecursiveDeps (Const False) (Const flags) = Const (Rank2.fmap (const $ Const False) (dependsOn flags))+         intersection (Const a) (Const b) = Const (a && b) -newtype Couple f a = Couple{unCouple :: (f a, f a)} deriving Show+fixDescendants :: forall g. (Rank2.Apply g, Rank2.Traversable g)+                     => g (Const (g (Const (ParserFlags g)) -> (ParserFlags g))) -> g (Const (ParserFlags g))+fixDescendants gf = go initial+   where go :: g (Const (ParserFlags g)) -> g (Const (ParserFlags g))+         go cd+            | getAll (Rank2.foldMap (All . getConst) $ Rank2.liftA2 agree cd cd') = cd+            | otherwise = go cd'+            where cd' = Rank2.liftA2 depsUnion cd (Rank2.fmap (\(Const f)-> Const (f cd)) gf)+         agree (Const (ParserFlags _xn xd)) (Const (ParserFlags _yn yd)) =+            Const (getAll (Rank2.foldMap (All . getConst) (Rank2.liftA2 agree' xd yd)))+         agree' (Const x) (Const y) = Const (x == y)+         depsUnion (Const ParserFlags{dependsOn= old}) (Const (ParserFlags n new)) = +            Const (ParserFlags n $ Rank2.liftA2 union old new)+         initial = Rank2.liftA2 (\_ (Const n)-> Const (ParserFlags n (const (Const False) Rank2.<$> gf))) gf nullabilities+         nullabilities = fixNullabilities gf -parseRecursive :: forall g s. (Rank2.Apply g, Rank2.Traversable g, FactorialMonoid s) =>-                  g (Parser g s) -> s -> [(s, g (ResultList g s))]-parseRecursive ast = parseSeparated descendants (Rank2.fmap toParser indirect) (Rank2.fmap toParser direct)-   where directRecursive = Rank2.fmap (Couple . splitDirect) ast-         cyclicDescendants = leftDescendants ast-         cyclic = Rank2.fmap (mapConst fst) cyclicDescendants-         descendants = Rank2.liftA3 cond cyclic (Rank2.fmap (mapConst snd) cyclicDescendants) noDescendants-         direct = Rank2.liftA3 cond cyclic (Rank2.fmap (fst . unCouple) directRecursive) ast-         indirect = Rank2.liftA3 cond cyclic (Rank2.fmap (snd . unCouple) directRecursive) emptyGrammar-         emptyGrammar :: g (Parser g s)-         emptyGrammar = Rank2.fmap (const empty) ast-         noDescendants = Rank2.fmap (const $ Const $ Rank2.fmap (const $ Const False) ast) ast-         cond (Const False) _t f = f-         cond (Const True) t _f = t-         mapConst f (Const c) = Const (f c)+fixNullabilities :: forall g. (Rank2.Apply g, Rank2.Traversable g)+                    => g (Const (g (Const (ParserFlags g)) -> (ParserFlags g))) -> g (Const Bool)+fixNullabilities gf = Rank2.fmap (Const . nullable . getConst) (go initial)+   where go :: g (Const (ParserFlags g)) -> g (Const (ParserFlags g))+         go cd+            | getAll (Rank2.foldMap (All . getConst) $ Rank2.liftA2 agree cd cd') = cd+            | otherwise = go cd'+            where cd' = Rank2.fmap (\(Const f)-> Const (f cd)) gf+         agree (Const flags1) (Const flags2) = Const (nullable flags1 == nullable flags2)+         initial = const (Const (ParserFlags True (const (Const False) Rank2.<$> gf))) Rank2.<$> gf  -- | Parse the given input using a context-free grammar separated into two parts: the first specifying all the -- left-recursive productions, the second all others. The first function argument specifies the left-recursive -- dependencies among the grammar productions. parseSeparated :: forall g s. (Rank2.Apply g, Rank2.Foldable g, FactorialMonoid s) =>-                  g (Const (g (Const Bool))) -> g (Memoizing.Parser g s) -> g (Memoizing.Parser g s) -> s-               -> [(s, g (ResultList g s))]-parseSeparated dependencies indirect direct input = foldr parseTail [] (Factorial.tails input)+                  g (SeparatedParser Memoizing.Parser g s) -> s -> [(s, g (ResultList g s))]+parseSeparated parsers input = foldr parseTail [] (Factorial.tails input)    where parseTail s parsedTail = parsed-            where parsed = (s,d'):parsedTail-                  d      = Rank2.fmap (($ (s,d):parsedTail) . Memoizing.applyParser) direct+            where parsed = (s,d''):parsedTail+                  d      = Rank2.fmap (($ (s,d):parsedTail) . Memoizing.applyParser) directs                   d'     = fixRecursive s parsedTail d-+                  d''    = Rank2.liftA2 f parsers d'+                  f :: forall a. SeparatedParser Memoizing.Parser g s a -> ResultList g s a -> ResultList g s a+                  f (FrontParser p) _ = Memoizing.applyParser p ((s,d''):parsedTail)+                  f _ result = result          fixRecursive :: s -> [(s, g (ResultList g s))] -> g (ResultList g s) -> g (ResultList g s)          whileAnyContinues :: g (ResultList g s) -> g (ResultList g s) -> g (ResultList g s)          recurseOnce :: s -> [(s, g (ResultList g s))] -> g (ResultList g s) -> g (ResultList g s)+         maybeDependencies :: g (Const (Maybe (g (Const Bool)))) +         directs = Rank2.fmap backParser parsers+         indirects = Rank2.fmap (\p-> case p of {CycleParser{}-> cycleParser p; _ -> empty}) parsers+         maybeDependencies = Rank2.fmap (Const . maybeDependency) parsers+         maybeDependency p@CycleParser{} = Just (dependencies p)+         maybeDependency _ = Nothing+                                                                             fixRecursive s parsedTail initial =             foldr1 whileAnyContinues (iterate (recurseOnce s parsedTail) initial) -         whileAnyContinues g1 g2 = Rank2.liftA3 choiceWhile dependencies g1 g2-            where choiceWhile :: Const (g (Const Bool)) x -> ResultList g i x -> ResultList g i x -> ResultList g i x+         whileAnyContinues g1 g2 = Rank2.liftA3 choiceWhile maybeDependencies g1 g2+            where choiceWhile :: Const (Maybe (g (Const Bool))) x -> ResultList g i x -> ResultList g i x +                                 -> ResultList g i x                   combine :: Const Bool x -> ResultList g i x -> Const Bool x-                  choiceWhile (Const deps) r1 r2+                  choiceWhile (Const Nothing) r1 _ = r1+                  choiceWhile (Const (Just deps)) r1 r2                      | getAny (Rank2.foldMap (Any . getConst) (Rank2.liftA2 combine deps g1)) = r1 <> r2                      | otherwise = r1                   combine (Const False) _ = Const False-                  combine (Const True) (ResultList [] _) = Const False+                  combine (Const True) (ResultList EmptyTree _) = Const False                   combine (Const True) _ = Const True -         recurseOnce s parsedTail initial = Rank2.fmap (($ parsed) . Memoizing.applyParser) indirect+         recurseOnce s parsedTail initial = Rank2.fmap (($ parsed) . Memoizing.applyParser) indirects             where parsed = (s, initial):parsedTail
src/Text/Grampa/ContextFree/Memoizing.hs view
@@ -1,14 +1,17 @@ {-# LANGUAGE FlexibleContexts, GeneralizedNewtypeDeriving, InstanceSigs,              RankNTypes, ScopedTypeVariables, TypeFamilies #-}-module Text.Grampa.ContextFree.Memoizing (FailureInfo(..), ResultList(..), Parser(..), fromResultList, reparseTails)+module Text.Grampa.ContextFree.Memoizing (FailureInfo(..), ResultList(..), Parser(..), BinTree(..), (<<|>),+                                          fromResultList, reparseTails, longest, peg, terminalPEG) where  import Control.Applicative import Control.Monad (Monad(..), MonadPlus(..)) import Data.Char (isSpace)+import Data.Function (on)+import Data.Foldable (toList) import Data.Functor.Classes (Show1(..)) import Data.Functor.Compose (Compose(..))-import Data.List (genericLength, nub)+import Data.List (genericLength, maximumBy, nub) import Data.Monoid (Monoid(mappend, mempty), (<>)) import Data.Monoid.Cancellative (LeftReductiveMonoid (isPrefixOf)) import Data.Monoid.Null (MonoidNull(null))@@ -17,7 +20,6 @@ import qualified Data.Monoid.Factorial as Factorial import qualified Data.Monoid.Textual as Textual import Data.String (fromString)-import Data.Word (Word64)  import qualified Text.Parser.Char import Text.Parser.Char (CharParsing)@@ -28,69 +30,74 @@ import qualified Rank2  import Text.Grampa.Class (GrammarParsing(..), MonoidParsing(..), MultiParsing(..), ParseResults, ParseFailure(..))+import Text.Grampa.Internal (BinTree(..), FailureInfo(..))+import qualified Text.Grampa.PEG.Backtrack.Length as Backtrack  import Prelude hiding (iterate, length, null, showList, span, takeWhile)  -- | Parser for a context-free grammar with packrat-like sharing of parse results. It does not support left-recursive -- grammars. newtype Parser g s r = Parser{applyParser :: [(s, g (ResultList g s))] -> ResultList g s r}-            -data ResultList g s r = ResultList ![ResultInfo g s r] {-# UNPACK #-} !FailureInfo-data ResultInfo g s r = ResultInfo ![(s, g (ResultList g s))] !r-data FailureInfo = FailureInfo !Int Word64 [String] deriving (Eq, Show) +data ResultList g s r = ResultList !(BinTree (ResultInfo g s r)) {-# UNPACK #-} !FailureInfo+data ResultInfo g s r = ResultInfo !Int ![(s, g (ResultList g s))] !r+ instance (Show s, Show r) => Show (ResultList g s r) where    show (ResultList l f) = "ResultList (" ++ shows l (") (" ++ shows f ")")  instance Show1 (ResultList g s) where-   liftShowsPrec _sp showList _prec (ResultList l f) rest = "ResultList " ++ showList (simplify <$> l) (shows f rest)-      where simplify (ResultInfo _ r) = r+   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 g s r) where-   show (ResultInfo t r) = "(ResultInfo @" ++ show (fst $ head t) ++ " " ++ shows r ")"+   show (ResultInfo l _ r) = "(ResultInfo @" ++ show l ++ " " ++ shows r ")"  instance Functor (ResultInfo g s) where-   fmap f (ResultInfo t r) = ResultInfo t (f r)+   fmap f (ResultInfo l t r) = ResultInfo l t (f r)  instance Functor (ResultList g s) where    fmap f (ResultList l failure) = ResultList ((f <$>) <$> l) failure  instance Monoid (ResultList g s r) where-   mempty = ResultList [] mempty+   mempty = ResultList mempty mempty    ResultList rl1 f1 `mappend` ResultList rl2 f2 = ResultList (rl1 <> rl2) (f1 <> f2) -instance Monoid FailureInfo where-   mempty = FailureInfo 0 maxBound []-   f1@(FailureInfo s1 pos1 exp1) `mappend` f2@(FailureInfo s2 pos2 exp2)-      | s1 < s2 = f2-      | s1 > s2 = f1-      | otherwise = FailureInfo s1 pos' exp'-      where (pos', exp') | pos1 < pos2 = (pos1, exp1)-                         | pos1 > pos2 = (pos2, exp2)-                         | otherwise = (pos1, exp1 <> exp2)- instance Functor (Parser g i) where    fmap f (Parser p) = Parser (fmap f . p)+   {-# INLINABLE fmap #-}  instance Applicative (Parser g i) where-   pure a = Parser (\rest-> ResultList [ResultInfo rest a] mempty)+   pure a = Parser (\rest-> ResultList (Leaf $ ResultInfo 0 rest a) mempty)    Parser p <*> Parser q = Parser r where       r rest = case p rest-               of ResultList results failure -> ResultList [] failure <> foldMap continue results-      continue (ResultInfo rest' f) = f <$> q rest'-+               of ResultList results failure -> ResultList mempty failure <> foldMap continue results+      continue (ResultInfo l rest' f) = continue' l f (q rest')+      continue' l f (ResultList rs failure) = ResultList (adjust l f <$> rs) failure+      adjust l f (ResultInfo l' rest' a) = ResultInfo (l+l') rest' (f a)+   {-# INLINABLE pure #-}+   {-# INLINABLE (<*>) #-}  instance Alternative (Parser g i) where-   empty = Parser (\rest-> ResultList [] $ FailureInfo 0 (genericLength rest) ["empty"])+   empty = Parser (\rest-> ResultList mempty $ FailureInfo 0 (genericLength rest) ["empty"])    Parser p <|> Parser q = Parser r where       r rest = p rest <> q rest+   {-# INLINABLE (<|>) #-} +infixl 3 <<|>+(<<|>) :: Parser g s a -> Parser g s a -> Parser g s a+Parser p <<|> Parser q = Parser r where+   r rest = case p rest+            of rl@(ResultList EmptyTree _failure) -> rl <> q rest+               rl -> rl+ instance Monad (Parser g i) where    return = pure    Parser p >>= f = Parser q where       q rest = case p rest-               of ResultList results failure -> ResultList [] failure <> foldMap continue results-      continue (ResultInfo rest' a) = applyParser (f a) rest'+               of ResultList results failure -> ResultList mempty failure <> foldMap continue results+      continue (ResultInfo l rest' a) = continue' l (applyParser (f a) rest')+      continue' l (ResultList rs failure) = ResultList (adjust l <$> rs) failure+      adjust l (ResultInfo l' rest' a) = ResultInfo (l+l') rest' a  instance MonadPlus (Parser g s) where    mzero = empty@@ -104,9 +111,11 @@    type GrammarFunctor Parser = ResultList    nonTerminal f = Parser p where       p ((_, d) : _) = f d-      p _ = ResultList [] (FailureInfo 1 0 ["NonTerminal at endOfInput"])+      p _ = ResultList mempty (FailureInfo 1 0 ["NonTerminal at endOfInput"])+   {-# INLINE nonTerminal #-} --- | Memoizing parser guarantees O(n²) performance, but provides no left recursion support.+-- | Memoizing parser guarantees O(n²) performance for grammars with unambiguous productions, but provides no left+-- recursion support. -- -- @ -- 'parseComplete' :: ("Rank2".'Rank2.Functor' g, 'FactorialMonoid' s) =>@@ -136,60 +145,80 @@ instance MonoidParsing (Parser g) where    endOfInput = eof    getInput = Parser p-      where p rest@((s, _):_) = ResultList [ResultInfo [last rest] s] mempty-            p [] = ResultList [ResultInfo [] mempty] mempty+      where p rest@((s, _):_) = ResultList (Leaf $ ResultInfo (length rest) [last rest] s) mempty+            p [] = ResultList (Leaf $ ResultInfo 0 [] mempty) mempty    anyToken = Parser p       where p rest@((s, _):t) = case splitPrimePrefix s-                                of Just (first, _) -> ResultList [ResultInfo t first] mempty-                                   _ -> ResultList [] (FailureInfo 1 (genericLength rest) ["anyToken"])-            p [] = ResultList [] (FailureInfo 1 0 ["anyToken"])+                                of Just (first, _) -> ResultList (Leaf $ ResultInfo 1 t first) mempty+                                   _ -> ResultList mempty (FailureInfo 1 (genericLength rest) ["anyToken"])+            p [] = ResultList mempty (FailureInfo 1 0 ["anyToken"])    satisfy predicate = Parser p       where p rest@((s, _):t) =                case splitPrimePrefix s-               of Just (first, _) | predicate first -> ResultList [ResultInfo t first] mempty-                  _ -> ResultList [] (FailureInfo 1 (genericLength rest) ["satisfy"])-            p [] = ResultList [] (FailureInfo 1 0 ["satisfy"])+               of Just (first, _) | predicate first -> ResultList (Leaf $ ResultInfo 1 t first) mempty+                  _ -> ResultList mempty (FailureInfo 1 (genericLength rest) ["satisfy"])+            p [] = ResultList mempty (FailureInfo 1 0 ["satisfy"])    satisfyChar predicate = Parser p       where p rest@((s, _):t) =-               case Textual.splitCharacterPrefix s-               of Just (first, _) | predicate first -> ResultList [ResultInfo t first] mempty-                  _ -> ResultList [] (FailureInfo 1 (genericLength rest) ["satisfyChar"])-            p [] = ResultList [] (FailureInfo 1 0 ["satisfyChar"])+               case Textual.characterPrefix s+               of Just first | predicate first -> ResultList (Leaf $ ResultInfo 1 t first) mempty+                  _ -> ResultList mempty (FailureInfo 1 (genericLength rest) ["satisfyChar"])+            p [] = ResultList mempty (FailureInfo 1 0 ["satisfyChar"])+   satisfyCharInput predicate = Parser p+      where p rest@((s, _):t) =+               case Textual.characterPrefix s+               of Just first | predicate first -> ResultList (Leaf $ ResultInfo 1 t $ Factorial.primePrefix s) mempty+                  _ -> ResultList mempty (FailureInfo 1 (genericLength rest) ["satisfyCharInput"])+            p [] = ResultList mempty (FailureInfo 1 0 ["satisfyCharInput"])    scan s0 f = Parser (p s0)-      where p s rest@((i, _) : _) = ResultList [ResultInfo (drop (Factorial.length prefix) rest) prefix] mempty+      where p s rest@((i, _) : _) = ResultList (Leaf $ ResultInfo l (drop l rest) prefix) mempty                where (prefix, _, _) = Factorial.spanMaybe' s f i-            p _ [] = ResultList [ResultInfo [] mempty] mempty+                     l = Factorial.length prefix+            p _ [] = ResultList (Leaf $ ResultInfo 0 [] mempty) mempty    scanChars s0 f = Parser (p s0)-      where p s rest@((i, _) : _) = ResultList [ResultInfo (drop (Factorial.length prefix) rest) prefix] mempty+      where p s rest@((i, _) : _) = ResultList (Leaf $ ResultInfo l (drop l rest) prefix) mempty                where (prefix, _, _) = Textual.spanMaybe_' s f i-            p _ [] = ResultList [ResultInfo [] mempty] mempty+                     l = Factorial.length prefix+            p _ [] = ResultList (Leaf $ ResultInfo 0 [] mempty) mempty    takeWhile predicate = Parser p       where p rest@((s, _) : _)-               | x <- Factorial.takeWhile predicate s =-                    ResultList [ResultInfo (drop (Factorial.length x) rest) x] mempty-            p [] = ResultList [ResultInfo [] mempty] mempty+               | x <- Factorial.takeWhile predicate s, l <- Factorial.length x =+                    ResultList (Leaf $ ResultInfo l (drop l rest) x) mempty+            p [] = ResultList (Leaf $ ResultInfo 0 [] mempty) mempty    takeWhile1 predicate = Parser p       where p rest@((s, _) : _)-               | x <- Factorial.takeWhile predicate s, not (null x) =-                    ResultList [ResultInfo (drop (Factorial.length x) rest) x] mempty-            p rest = ResultList [] (FailureInfo 1 (genericLength rest) ["takeWhile1"])+               | x <- Factorial.takeWhile predicate s, l <- Factorial.length x, l > 0 =+                    ResultList (Leaf $ ResultInfo l (drop l rest) x) mempty+            p rest = ResultList mempty (FailureInfo 1 (genericLength rest) ["takeWhile1"])    takeCharsWhile predicate = Parser p       where p rest@((s, _) : _)-               | x <- Textual.takeWhile_ False predicate s =-                    ResultList [ResultInfo (drop (Factorial.length x) rest) x] mempty-            p [] = ResultList [ResultInfo [] mempty] mempty+               | x <- Textual.takeWhile_ False predicate s, l <- Factorial.length x =+                    ResultList (Leaf $ ResultInfo l (drop l rest) x) mempty+            p [] = ResultList (Leaf $ ResultInfo 0 [] mempty) mempty    takeCharsWhile1 predicate = Parser p       where p rest@((s, _) : _)-               | x <- Textual.takeWhile_ False predicate s, not (null x) =-                    ResultList [ResultInfo (drop (Factorial.length x) rest) x] mempty-            p rest = ResultList [] (FailureInfo 1 (genericLength rest) ["takeCharsWhile1"])+               | x <- Textual.takeWhile_ False predicate s, l <- Factorial.length x, l > 0 =+                    ResultList (Leaf $ ResultInfo l (drop l rest) x) mempty+            p rest = ResultList mempty (FailureInfo 1 (genericLength rest) ["takeCharsWhile1"])    string s = Parser p where       p rest@((s', _) : _)-         | s `isPrefixOf` s' = ResultList [ResultInfo (Factorial.drop (Factorial.length s) rest) s] mempty-      p rest = ResultList [] (FailureInfo 1 (genericLength rest) ["string " ++ show s])+         | s `isPrefixOf` s' = ResultList (Leaf $ ResultInfo l (Factorial.drop l rest) s) mempty+      p rest = ResultList mempty (FailureInfo 1 (genericLength rest) ["string " ++ show s])+      l = Factorial.length s    whiteSpace = () <$ takeCharsWhile isSpace    concatMany p = go       where go = mempty <|> (<>) <$> p <*> go+   notSatisfy predicate = Parser p+      where p rest@((s, _):_)+               | Just (first, _) <- splitPrimePrefix s, +                 predicate first = ResultList mempty (FailureInfo 1 (genericLength rest) ["notSatisfy"])+            p rest = ResultList (Leaf $ ResultInfo 0 rest ()) mempty+   notSatisfyChar predicate = Parser p+      where p rest@((s, _):_)+               | Just first <- Textual.characterPrefix s, +                 predicate first = ResultList mempty (FailureInfo 1 (genericLength rest) ["notSatisfyChar"])+            p rest = ResultList (Leaf $ ResultInfo 0 rest ()) mempty+   {-# INLINABLE string #-}  instance MonoidNull s => Parsing (Parser g s) where    try (Parser p) = Parser (weakenResults . p)@@ -197,21 +226,21 @@    Parser p <?> msg  = Parser (strengthenResults . p)       where strengthenResults (ResultList rl (FailureInfo s pos _msgs)) = ResultList rl (FailureInfo (succ s) pos [msg])    notFollowedBy (Parser p) = Parser (\input-> rewind input (p input))-      where rewind t (ResultList [] _) = ResultList [ResultInfo t ()] mempty-            rewind t ResultList{} = ResultList [] (FailureInfo 1 (genericLength t) ["notFollowedBy"])+      where rewind t (ResultList EmptyTree _) = ResultList (Leaf $ ResultInfo 0 t ()) mempty+            rewind t ResultList{} = ResultList mempty (FailureInfo 1 (genericLength t) ["notFollowedBy"])    skipMany p = go       where go = pure () <|> p *> go-   unexpected msg = Parser (\t-> ResultList [] $ FailureInfo 0 (genericLength t) [msg])+   unexpected msg = Parser (\t-> ResultList mempty $ FailureInfo 0 (genericLength t) [msg])    eof = Parser f       where f rest@((s, _):_)-               | null s = ResultList [ResultInfo rest ()] mempty-               | otherwise = ResultList [] (FailureInfo 1 (genericLength rest) ["endOfInput"])-            f [] = ResultList [ResultInfo [] ()] mempty+               | null s = ResultList (Leaf $ ResultInfo 0 rest ()) mempty+               | otherwise = ResultList mempty (FailureInfo 1 (genericLength rest) ["endOfInput"])+            f [] = ResultList (Leaf $ ResultInfo 0 [] ()) mempty  instance MonoidNull 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+            rewindInput t (ResultInfo _ _ r) = ResultInfo 0 t r  instance (Show s, TextualMonoid s) => CharParsing (Parser g s) where    satisfy = satisfyChar@@ -225,8 +254,35 @@    someSpace = () <$ takeCharsWhile1 isSpace  fromResultList :: FactorialMonoid s => s -> ResultList g s r -> ParseResults [(s, r)]-fromResultList s (ResultList [] (FailureInfo _ pos msgs)) =+fromResultList s (ResultList EmptyTree (FailureInfo _ pos msgs)) =    Left (ParseFailure (length s - fromIntegral pos + 1) (nub msgs))-fromResultList _ (ResultList rl _failure) = Right (f <$> rl)-   where f (ResultInfo ((s, _):_) r) = (s, r)-         f (ResultInfo [] r) = (mempty, r)+fromResultList _ (ResultList rl _failure) = Right (f <$> toList rl)+   where f (ResultInfo _ ((s, _):_) r) = (s, r)+         f (ResultInfo _ [] r) = (mempty, r)++-- | Turns a context-free parser into a backtracking PEG parser that consumes the longest possible prefix of the list+-- of input tails, opposite of 'peg'+longest :: FactorialMonoid s => Parser g s a -> Backtrack.Parser g [(s, g (ResultList g s))] a+longest p = Backtrack.Parser q where+   q rest = case applyParser p rest+            of ResultList EmptyTree failure -> Backtrack.NoParse failure+               ResultList rs _ -> parsed (maximumBy (compare `on` resultLength) rs)+   resultLength (ResultInfo l _ _) = l+   parsed (ResultInfo l s r) = Backtrack.Parsed l r s++-- | Turns a backtracking PEG parser of the list of input tails into a context-free parser, opposite of 'longest'+peg :: Backtrack.Parser g [(s, g (ResultList g s))] a -> Parser g s a+peg p = Parser q where+   q rest = case Backtrack.applyParser p rest+            of Backtrack.Parsed l result suffix -> ResultList (Leaf $ ResultInfo l suffix result) mempty+               Backtrack.NoParse failure -> ResultList mempty failure++-- | Turns a backtracking PEG parser into a context-free parser+terminalPEG :: Monoid s => Backtrack.Parser g s a -> Parser g s a+terminalPEG p = Parser q where+   q [] = case Backtrack.applyParser p mempty+            of Backtrack.Parsed l result _ -> ResultList (Leaf $ ResultInfo l [] result) mempty+               Backtrack.NoParse failure -> ResultList mempty failure+   q rest@((s, _):_) = case Backtrack.applyParser p s+                       of Backtrack.Parsed l result _ -> ResultList (Leaf $ ResultInfo l (drop l rest) result) mempty+                          Backtrack.NoParse failure -> ResultList mempty failure
src/Text/Grampa/ContextFree/Parallel.hs view
@@ -6,6 +6,7 @@ import Control.Applicative import Control.Monad (Monad(..), MonadPlus(..)) import Data.Char (isSpace)+import Data.Foldable (toList) import Data.Functor.Classes (Show1(..)) import Data.Functor.Compose (Compose(..)) import Data.List (nub)@@ -27,7 +28,8 @@  import qualified Rank2 -import Text.Grampa.Class (MonoidParsing(..), MultiParsing(..), ParseResults, ParseFailure(..), completeParser)+import Text.Grampa.Class (MonoidParsing(..), MultiParsing(..), ParseResults, ParseFailure(..))+import Text.Grampa.Internal (BinTree(..))  import Prelude hiding (iterate, null, showList, span, takeWhile) @@ -35,7 +37,7 @@ -- support. newtype Parser (g :: (* -> *) -> *) s r = Parser{applyParser :: s -> ResultList s r} -data ResultList s r = ResultList ![ResultInfo s r] {-# UNPACK #-} !FailureInfo+data ResultList s r = ResultList !(BinTree (ResultInfo s r)) {-# UNPACK #-} !FailureInfo data ResultInfo s r = ResultInfo !s !r data FailureInfo = FailureInfo !Int Int [String] deriving (Eq, Show) @@ -43,7 +45,7 @@    show (ResultList l f) = "ResultList (" ++ shows l (") (" ++ shows f ")")  instance Show1 (ResultList s) where-   liftShowsPrec _sp showList _prec (ResultList l f) rest = "ResultList " ++ showList (simplify <$> l) (shows f rest)+   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@@ -56,7 +58,7 @@    fmap f (ResultList l failure) = ResultList ((f <$>) <$> l) failure  instance Monoid (ResultList s r) where-   mempty = ResultList [] mempty+   mempty = ResultList mempty mempty    ResultList rl1 f1 `mappend` ResultList rl2 f2 = ResultList (rl1 <> rl2) (f1 <> f2)  instance Monoid FailureInfo where@@ -73,15 +75,15 @@    fmap f (Parser p) = Parser (fmap f . p)  instance Applicative (Parser g s) where-   pure a = Parser (\rest-> ResultList [ResultInfo rest a] mempty)+   pure a = Parser (\rest-> ResultList (Leaf $ ResultInfo rest a) mempty)    Parser p <*> Parser q = Parser r where       r rest = case p rest-               of ResultList results failure -> ResultList [] failure <> foldMap continue results+               of ResultList results failure -> ResultList mempty failure <> foldMap continue results       continue (ResultInfo rest' f) = f <$> q rest'   instance FactorialMonoid s => Alternative (Parser g s) where-   empty = Parser (\s-> ResultList [] $ FailureInfo 0 (Factorial.length s) ["empty"])+   empty = Parser (\s-> ResultList mempty $ FailureInfo 0 (Factorial.length s) ["empty"])    Parser p <|> Parser q = Parser r where       r rest = p rest <> q rest @@ -89,7 +91,7 @@    return = pure    Parser p >>= f = Parser q where       q rest = case p rest-               of ResultList results failure -> ResultList [] failure <> foldMap continue results+               of ResultList results failure -> ResultList mempty failure <> foldMap continue results       continue (ResultInfo rest' a) = applyParser (f a) rest'  instance FactorialMonoid s => MonadPlus (Parser g s) where@@ -117,49 +119,65 @@  instance MonoidParsing (Parser g) where    endOfInput = Parser f-      where f s | null s = ResultList [ResultInfo s ()] mempty-                | otherwise = ResultList [] (FailureInfo 1 (Factorial.length s) ["endOfInput"])+      where f s | null s = ResultList (Leaf $ ResultInfo s ()) mempty+                | otherwise = ResultList mempty (FailureInfo 1 (Factorial.length s) ["endOfInput"])    getInput = Parser p-      where p s = ResultList [ResultInfo mempty s] mempty+      where p s = ResultList (Leaf $ ResultInfo mempty s) mempty    anyToken = Parser p       where p s = case Factorial.splitPrimePrefix s-                  of Just (first, rest) -> ResultList [ResultInfo rest first] mempty-                     _ -> ResultList [] (FailureInfo 1 (Factorial.length s) ["anyToken"])+                  of Just (first, rest) -> ResultList (Leaf $ ResultInfo rest first) mempty+                     _ -> ResultList mempty (FailureInfo 1 (Factorial.length s) ["anyToken"])    satisfy predicate = Parser p       where p s = case Factorial.splitPrimePrefix s-                  of Just (first, rest) | predicate first -> ResultList [ResultInfo rest first] mempty-                     _ -> ResultList [] (FailureInfo 1 (Factorial.length s) ["satisfy"])+                  of Just (first, rest) | predicate first -> ResultList (Leaf $ ResultInfo rest first) mempty+                     _ -> ResultList mempty (FailureInfo 1 (Factorial.length s) ["satisfy"])    satisfyChar predicate = Parser p       where p s =                case Textual.splitCharacterPrefix s-               of Just (first, rest) | predicate first -> ResultList [ResultInfo rest first] mempty-                  _ -> ResultList [] (FailureInfo 1 (Factorial.length s) ["satisfyChar"])+               of Just (first, rest) | predicate first -> ResultList (Leaf $ ResultInfo rest first) mempty+                  _ -> ResultList mempty (FailureInfo 1 (Factorial.length s) ["satisfyChar"])+   satisfyCharInput predicate = Parser p+      where p s =+               case Textual.splitCharacterPrefix s+               of Just (first, rest) | predicate first -> ResultList (Leaf $ ResultInfo rest $ Factorial.primePrefix s) mempty+                  _ -> ResultList mempty (FailureInfo 1 (Factorial.length s) ["satisfyChar"])+   notSatisfy predicate = Parser p+      where p s = case Factorial.splitPrimePrefix s+                  of Just (first, _) +                        | predicate first -> ResultList mempty (FailureInfo 1 (Factorial.length s) ["notSatisfy"])+                     _ -> ResultList (Leaf $ ResultInfo s ()) mempty+   notSatisfyChar predicate = Parser p+      where p s = case Textual.characterPrefix s+                  of Just first +                        | predicate first -> ResultList mempty (FailureInfo 1 (Factorial.length s) ["notSatisfyChar"])+                     _ -> ResultList (Leaf $ ResultInfo s ()) mempty    scan s0 f = Parser (p s0)-      where p s i = ResultList [ResultInfo suffix prefix] mempty+      where p s i = ResultList (Leaf $ ResultInfo suffix prefix) mempty                where (prefix, suffix, _) = Factorial.spanMaybe' s f i    scanChars s0 f = Parser (p s0)-      where p s i = ResultList [ResultInfo suffix prefix] mempty+      where p s i = ResultList (Leaf $ ResultInfo suffix prefix) mempty                where (prefix, suffix, _) = Textual.spanMaybe_' s f i    takeWhile predicate = Parser p-      where p s | (prefix, suffix) <- Factorial.span predicate s = ResultList [ResultInfo suffix prefix] mempty+      where p s | (prefix, suffix) <- Factorial.span predicate s = ResultList (Leaf $ ResultInfo suffix prefix) mempty    takeWhile1 predicate = Parser p       where p s | (prefix, suffix) <- Factorial.span predicate s =                 if Null.null prefix-               then ResultList [] (FailureInfo 1 (Factorial.length s) ["takeWhile1"])-               else ResultList [ResultInfo suffix prefix] mempty+               then ResultList mempty (FailureInfo 1 (Factorial.length s) ["takeWhile1"])+               else ResultList (Leaf $ ResultInfo suffix prefix) mempty    takeCharsWhile predicate = Parser p-      where p s | (prefix, suffix) <- Textual.span_ False predicate s = ResultList [ResultInfo suffix prefix] mempty+      where p s | (prefix, suffix) <- Textual.span_ False predicate s = +               ResultList (Leaf $ ResultInfo suffix prefix) mempty    takeCharsWhile1 predicate = Parser p       where p s | (prefix, suffix) <- Textual.span_ False predicate s =                if null prefix-               then ResultList [] (FailureInfo 1 (Factorial.length s) ["takeCharsWhile1"])-               else ResultList [ResultInfo suffix prefix] mempty+               then ResultList mempty (FailureInfo 1 (Factorial.length s) ["takeCharsWhile1"])+               else ResultList (Leaf $ ResultInfo suffix prefix) mempty    string s = Parser p where-      p s' | Just suffix <- Cancellative.stripPrefix s s' = ResultList [ResultInfo suffix s] mempty-           | otherwise = ResultList [] (FailureInfo 1 (Factorial.length s') ["string " ++ show s])+      p s' | Just suffix <- Cancellative.stripPrefix s s' = ResultList (Leaf $ ResultInfo suffix s) mempty+           | otherwise = ResultList mempty (FailureInfo 1 (Factorial.length s') ["string " ++ show s])    whiteSpace = () <$ takeCharsWhile isSpace    concatMany (Parser p) = Parser q-      where q s = ResultList [] failure <> foldMap continue rs+      where q s = ResultList mempty failure <> foldMap continue rs                where ResultList rs failure = p s             continue (ResultInfo suffix prefix) = (prefix <>) <$> q suffix @@ -169,11 +187,11 @@    Parser p <?> msg  = Parser (strengthenResults . p)       where strengthenResults (ResultList rl (FailureInfo s pos _msgs)) = ResultList rl (FailureInfo (succ s) pos [msg])    notFollowedBy (Parser p) = Parser (\input-> rewind input (p input))-      where rewind t (ResultList [] _) = ResultList [ResultInfo t ()] mempty-            rewind t ResultList{} = ResultList [] (FailureInfo 1 (Factorial.length t) ["notFollowedBy"])+      where rewind t (ResultList EmptyTree _) = ResultList (Leaf $ ResultInfo t ()) mempty+            rewind t ResultList{} = ResultList mempty (FailureInfo 1 (Factorial.length t) ["notFollowedBy"])    skipMany p = go       where go = pure () <|> p *> go-   unexpected msg = Parser (\t-> ResultList [] $ FailureInfo 0 (Factorial.length t) [msg])+   unexpected msg = Parser (\t-> ResultList mempty $ FailureInfo 0 (Factorial.length t) [msg])    eof = endOfInput  instance FactorialMonoid s => LookAheadParsing (Parser g s) where@@ -193,6 +211,7 @@    someSpace = () <$ takeCharsWhile1 isSpace  fromResultList :: FactorialMonoid s => s -> ResultList s r -> ParseResults [(s, r)]-fromResultList s (ResultList [] (FailureInfo _ pos msgs)) = Left (ParseFailure (Factorial.length s - pos) (nub msgs))-fromResultList _ (ResultList rl _failure) = Right (f <$> rl)+fromResultList s (ResultList EmptyTree (FailureInfo _ pos msgs)) = +   Left (ParseFailure (Factorial.length s - pos) (nub msgs))+fromResultList _ (ResultList rl _failure) = Right (f <$> toList rl)    where f (ResultInfo s r) = (s, r)
+ src/Text/Grampa/Internal.hs view
@@ -0,0 +1,37 @@+module Text.Grampa.Internal (BinTree(..), FailureInfo(..)) where++import Data.Monoid (Monoid(mappend, mempty), (<>))+import Data.Word (Word64)++data FailureInfo = FailureInfo !Int Word64 [String] deriving (Eq, Show)++data BinTree a = Fork !(BinTree a) !(BinTree a)+               | Leaf !a+               | EmptyTree+               deriving (Show)++instance Monoid FailureInfo where+   mempty = FailureInfo 0 maxBound []+   f1@(FailureInfo s1 pos1 exp1) `mappend` f2@(FailureInfo s2 pos2 exp2)+      | s1 < s2 = f2+      | s1 > s2 = f1+      | otherwise = FailureInfo s1 pos' exp'+      where (pos', exp') | pos1 < pos2 = (pos1, exp1)+                         | pos1 > pos2 = (pos2, exp2)+                         | otherwise = (pos1, exp1 <> exp2)++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 Foldable BinTree where+   foldMap f (Fork left right) = foldMap f left <> foldMap f right+   foldMap f (Leaf a) = f a+   foldMap _ EmptyTree = mempty++instance Monoid (BinTree a) where+   mempty = EmptyTree+   mappend EmptyTree t = t+   mappend t EmptyTree = t+   mappend l r = Fork l r
src/Text/Grampa/PEG/Backtrack.hs view
@@ -1,6 +1,6 @@ {-# LANGUAGE TypeFamilies #-} -- | Backtracking parser for Parsing Expression Grammars-module Text.Grampa.PEG.Backtrack (Parser) where+module Text.Grampa.PEG.Backtrack (Parser(..), Result(..), alt) where  import Control.Applicative (Applicative(..), Alternative(..), liftA2) import Control.Monad (Monad(..), MonadPlus(..))@@ -11,7 +11,7 @@ import Data.List (nub) import Data.Monoid (Monoid(mappend, mempty), (<>)) import Data.Monoid.Factorial(FactorialMonoid)-import Data.Word (Word64)+import Data.String (fromString)  import qualified Data.Monoid.Cancellative as Cancellative import qualified Data.Monoid.Factorial as Factorial@@ -20,13 +20,17 @@  import qualified Rank2 +import qualified Text.Parser.Char+import Text.Parser.Char (CharParsing) import Text.Parser.Combinators (Parsing(..))+import Text.Parser.LookAhead (LookAheadParsing(..))+import Text.Parser.Token (TokenParsing(someSpace)) import Text.Grampa.Class (MonoidParsing(..), MultiParsing(..), ParseResults, ParseFailure(..))+import Text.Grampa.Internal (FailureInfo(..)) -data Result (g :: (* -> *) -> *) s v = Parsed{ parsedPrefix :: v, -                                              _parsedSuffix :: s}+data Result (g :: (* -> *) -> *) s v = Parsed{parsedPrefix :: !v,+                                              parsedSuffix :: !s}                                      | NoParse FailureInfo-data FailureInfo = FailureInfo !Int Word64 [String] deriving (Eq, Show)  -- | Parser type for Parsing Expression Grammars that uses a backtracking algorithm, fast for grammars in LL(1) class -- but with potentially exponential performance for longer ambiguous prefixes.@@ -42,6 +46,7 @@     instance Functor (Parser g s) where    fmap f (Parser p) = Parser (fmap f . p)+   {-# INLINABLE fmap #-}  instance Applicative (Parser g s) where    pure a = Parser (Parsed a)@@ -49,10 +54,15 @@       r rest = case p rest                of Parsed f rest' -> f <$> q rest'                   NoParse failure -> NoParse failure+   {-# INLINABLE (<*>) #-}  instance Factorial.FactorialMonoid s => Alternative (Parser g s) where    empty = Parser (\rest-> NoParse $ FailureInfo 0 (fromIntegral $ Factorial.length rest) ["empty"])-   Parser p <|> Parser q = Parser r where+   (<|>) = alt++-- | A named and unconstrained version of the '<|>' operator+alt :: Parser g s a -> Parser g s a -> Parser g s a+Parser p `alt` Parser q = Parser r where       r rest = case p rest                of x@Parsed{} -> x                   NoParse{} -> q rest@@ -81,11 +91,27 @@       where rewind t Parsed{} = NoParse (FailureInfo 1 (fromIntegral $ Factorial.length t) ["notFollowedBy"])             rewind t NoParse{} = Parsed () t +instance Factorial.FactorialMonoid s => LookAheadParsing (Parser g s) where+   lookAhead (Parser p) = Parser (\input-> rewind input (p input))+      where rewind t (Parsed r _) = Parsed r t+            rewind _ r@NoParse{} = r++instance (Show s, Textual.TextualMonoid s) => CharParsing (Parser g s) where+   satisfy = satisfyChar+   string s = Textual.toString (error "unexpected non-character") <$> string (fromString s)+   char = satisfyChar . (==)+   notChar = satisfyChar . (/=)+   anyChar = satisfyChar (const True)+   text t = (fromString . Textual.toString (error "unexpected non-character")) <$> string (Textual.fromText t)++instance (Show s, Textual.TextualMonoid s) => TokenParsing (Parser g s) where+   someSpace = () <$ takeCharsWhile1 isSpace+ instance MonoidParsing (Parser g) where    endOfInput = Parser p-      where p rest = if Null.null rest-                     then NoParse (FailureInfo 1 (fromIntegral $ Factorial.length rest) ["endOfInput"])-                     else Parsed () rest+      where p rest+               | Null.null rest = Parsed () rest+               | otherwise = NoParse (FailureInfo 1 (fromIntegral $ Factorial.length rest) ["endOfInput"])    getInput = Parser p       where p rest = Parsed rest mempty    anyToken = Parser p@@ -102,6 +128,21 @@                case Textual.splitCharacterPrefix rest                of Just (first, suffix) | predicate first -> Parsed first suffix                   _ -> NoParse (FailureInfo 1 (fromIntegral $ Factorial.length rest) ["satisfyChar"])+   satisfyCharInput predicate = Parser p+      where p rest =+               case Textual.splitCharacterPrefix rest+               of Just (first, suffix) | predicate first -> Parsed (Factorial.primePrefix rest) suffix+                  _ -> NoParse (FailureInfo 1 (fromIntegral $ Factorial.length rest) ["satisfyChar"])+   notSatisfy predicate = Parser p+      where p s = case Factorial.splitPrimePrefix s+                  of Just (first, _) +                        | predicate first -> NoParse (FailureInfo 1 (fromIntegral $ Factorial.length s) ["notSatisfy"])+                     _ -> Parsed () s+   notSatisfyChar predicate = Parser p+      where p s = case Textual.characterPrefix s+                  of Just first | predicate first +                                  -> NoParse (FailureInfo 1 (fromIntegral $ Factorial.length s) ["notSatisfyChar"])+                     _ -> Parsed () s    scan s0 f = Parser (p s0)       where p s rest = Parsed prefix suffix                where (prefix, suffix, _) = Factorial.spanMaybe' s f rest@@ -131,6 +172,7 @@                      of Parsed prefix suffix -> let Parsed prefix' suffix' = q suffix                                                 in Parsed (prefix <> prefix') suffix'                         NoParse{} -> Parsed mempty rest+   {-# INLINABLE string #-}  -- | Backtracking PEG parser --
+ src/Text/Grampa/PEG/Backtrack/Length.hs view
@@ -0,0 +1,202 @@+{-# LANGUAGE TypeFamilies #-}+-- | Backtracking parser for Parsing Expression Grammars, tracking the consumed input length+module Text.Grampa.PEG.Backtrack.Length (Parser(..), Result(..), alt) where++import Control.Applicative (Applicative(..), Alternative(..), liftA2)+import Control.Monad (Monad(..), MonadPlus(..))++import Data.Char (isSpace)+import Data.Functor.Classes (Show1(..))+import Data.Functor.Compose (Compose(..))+import Data.List (nub)+import Data.Monoid (Monoid(mappend, mempty), (<>))+import Data.Monoid.Factorial(FactorialMonoid)+import Data.String (fromString)++import qualified Data.Monoid.Cancellative as Cancellative+import qualified Data.Monoid.Factorial as Factorial+import qualified Data.Monoid.Null as Null+import qualified Data.Monoid.Textual as Textual++import qualified Rank2++import qualified Text.Parser.Char+import Text.Parser.Char (CharParsing)+import Text.Parser.Combinators (Parsing(..))+import Text.Parser.LookAhead (LookAheadParsing(..))+import Text.Parser.Token (TokenParsing(someSpace))+import Text.Grampa.Class (MonoidParsing(..), MultiParsing(..), ParseResults, ParseFailure(..))+import Text.Grampa.Internal (FailureInfo(..))++data Result (g :: (* -> *) -> *) s v = Parsed{parsedLength :: !Int,+                                              parsedResult :: !v,+                                              parsedSuffix :: !s}+                                     | NoParse FailureInfo++-- | Parser type for Parsing Expression Grammars that uses a backtracking algorithm, fast for grammars in LL(1) class+-- but with potentially exponential performance for longer ambiguous prefixes.+newtype Parser g s r = Parser{applyParser :: s -> Result g s r}++instance Show1 (Result g s) where+   liftShowsPrec showsPrecSub _showList prec Parsed{parsedResult= r} rest = "Parsed " ++ showsPrecSub prec r rest+   liftShowsPrec _showsPrec _showList _prec (NoParse f) rest = "NoParse " ++ shows f rest++instance Functor (Result g s) where+   fmap f (Parsed l a rest) = Parsed l (f a) rest+   fmap _ (NoParse failure) = NoParse failure+   +instance Functor (Parser g s) where+   fmap f (Parser p) = Parser (fmap f . p)+   {-# INLINABLE fmap #-}++instance Applicative (Parser g s) where+   pure a = Parser (Parsed 0 a)+   Parser p <*> Parser q = Parser r where+      r rest = case p rest+               of Parsed l f rest' -> case q rest'+                                      of Parsed l' a rest'' -> Parsed (l+l') (f a) rest''+                                         NoParse failure -> NoParse failure+                  NoParse failure -> NoParse failure+   {-# INLINABLE (<*>) #-}++instance Factorial.FactorialMonoid s => Alternative (Parser g s) where+   empty = Parser (\rest-> NoParse $ FailureInfo 0 (fromIntegral $ Factorial.length rest) ["empty"])+   (<|>) = alt++-- | A named and unconstrained version of the '<|>' operator+alt :: Parser g s a -> Parser g s a -> Parser g s a+Parser p `alt` Parser q = Parser r where+      r rest = case p rest+               of x@Parsed{} -> x+                  NoParse{} -> q rest++instance Monad (Parser g s) where+   return = pure+   Parser p >>= f = Parser r where+      r rest = case p rest+               of Parsed l a rest' -> case applyParser (f a) rest'+                                      of Parsed l' b rest'' -> Parsed (l+l') b rest''+                                         NoParse failure -> NoParse failure+                  NoParse failure -> NoParse failure++instance Factorial.FactorialMonoid s => MonadPlus (Parser g s) where+   mzero = empty+   mplus = (<|>)++instance Monoid x => Monoid (Parser g s x) where+   mempty = pure mempty+   mappend = liftA2 mappend++instance Factorial.FactorialMonoid s => Parsing (Parser g s) where+   try = id+   (<?>) = const+   eof = endOfInput+   unexpected msg = Parser (\t-> NoParse $ FailureInfo 0 (fromIntegral $ Factorial.length t) [msg])+   notFollowedBy (Parser p) = Parser (\input-> rewind input (p input))+      where rewind t Parsed{} = NoParse (FailureInfo 1 (fromIntegral $ Factorial.length t) ["notFollowedBy"])+            rewind t NoParse{} = Parsed 0 () t++instance Factorial.FactorialMonoid s => LookAheadParsing (Parser g s) where+   lookAhead (Parser p) = Parser (\input-> rewind input (p input))+      where rewind t (Parsed _ r _) = Parsed 0 r t+            rewind _ r@NoParse{} = r++instance (Show s, Textual.TextualMonoid s) => CharParsing (Parser g s) where+   satisfy = satisfyChar+   string s = Textual.toString (error "unexpected non-character") <$> string (fromString s)+   char = satisfyChar . (==)+   notChar = satisfyChar . (/=)+   anyChar = satisfyChar (const True)+   text t = (fromString . Textual.toString (error "unexpected non-character")) <$> string (Textual.fromText t)++instance (Show s, Textual.TextualMonoid s) => TokenParsing (Parser g s) where+   someSpace = () <$ takeCharsWhile1 isSpace++instance MonoidParsing (Parser g) where+   endOfInput = Parser p+      where p rest+               | Null.null rest = Parsed 0 () rest+               | otherwise = NoParse (FailureInfo 1 (fromIntegral $ Factorial.length rest) ["endOfInput"])+   getInput = Parser p+      where p rest = Parsed (Factorial.length rest) rest mempty+   anyToken = Parser p+      where p rest = case Factorial.splitPrimePrefix rest+                     of Just (first, suffix) -> Parsed 1 first suffix+                        _ -> NoParse (FailureInfo 1 (fromIntegral $ Factorial.length rest) ["anyToken"])+   satisfy predicate = Parser p+      where p rest =+               case Factorial.splitPrimePrefix rest+               of Just (first, suffix) | predicate first -> Parsed 1 first suffix+                  _ -> NoParse (FailureInfo 1 (fromIntegral $ Factorial.length rest) ["satisfy"])+   satisfyChar predicate = Parser p+      where p rest =+               case Textual.splitCharacterPrefix rest+               of Just (first, suffix) | predicate first -> Parsed 1 first suffix+                  _ -> NoParse (FailureInfo 1 (fromIntegral $ Factorial.length rest) ["satisfyChar"])+   satisfyCharInput predicate = Parser p+      where p rest =+               case Textual.splitCharacterPrefix rest+               of Just (first, suffix) | predicate first -> Parsed 1 (Factorial.primePrefix rest) suffix+                  _ -> NoParse (FailureInfo 1 (fromIntegral $ Factorial.length rest) ["satisfyChar"])+   notSatisfy predicate = Parser p+      where p s = case Factorial.splitPrimePrefix s+                  of Just (first, _) +                        | predicate first -> NoParse (FailureInfo 1 (fromIntegral $ Factorial.length s) ["notSatisfy"])+                     _ -> Parsed 0 () s+   notSatisfyChar predicate = Parser p+      where p s = case Textual.characterPrefix s+                  of Just first | predicate first +                                  -> NoParse (FailureInfo 1 (fromIntegral $ Factorial.length s) ["notSatisfyChar"])+                     _ -> Parsed 0 () s+   scan s0 f = Parser (p s0)+      where p s rest = Parsed (Factorial.length prefix) prefix suffix+               where (prefix, suffix, _) = Factorial.spanMaybe' s f rest+   scanChars s0 f = Parser (p s0)+      where p s rest = Parsed (Factorial.length prefix) prefix suffix+               where (prefix, suffix, _) = Textual.spanMaybe_' s f rest+   takeWhile predicate = Parser p+      where p rest | (prefix, suffix) <- Factorial.span predicate rest =+               Parsed (Factorial.length prefix) prefix suffix+   takeWhile1 predicate = Parser p+      where p rest | (prefix, suffix) <- Factorial.span predicate rest =+                        if Null.null prefix+                        then NoParse (FailureInfo 1 (fromIntegral $ Factorial.length rest) ["takeWhile1"])+                        else Parsed (Factorial.length prefix) prefix suffix+   takeCharsWhile predicate = Parser p+      where p rest | (prefix, suffix) <- Textual.span_ False predicate rest = +               Parsed (Factorial.length prefix) prefix suffix+   takeCharsWhile1 predicate = Parser p+      where p rest | (prefix, suffix) <- Textual.span_ False predicate rest =+                     if Null.null prefix+                     then NoParse (FailureInfo 1 (fromIntegral $ Factorial.length rest) ["takeCharsWhile1"])+                     else Parsed (Factorial.length prefix) prefix suffix+   string s = Parser p where+      p s' | Just suffix <- Cancellative.stripPrefix s s' = Parsed l s suffix+           | otherwise = NoParse (FailureInfo 1 (fromIntegral $ Factorial.length s') ["string " ++ show s])+      l = Factorial.length s+   whiteSpace = () <$ takeCharsWhile isSpace+   concatMany (Parser p) = Parser q+      where q rest = case p rest+                     of Parsed l prefix suffix -> let Parsed l' prefix' suffix' = q suffix+                                                  in Parsed (l+l') (prefix <> prefix') suffix'+                        NoParse{} -> Parsed 0 mempty rest+   {-# INLINABLE string #-}++-- | Backtracking PEG parser+--+-- @+-- 'parseComplete' :: ("Rank2".'Rank2.Functor' g, 'FactorialMonoid' s) =>+--                  g (Backtrack.'Parser' g s) -> s -> g 'ParseResults'+-- @+instance MultiParsing Parser where+   type ResultFunctor Parser = ParseResults+   {-# NOINLINE parsePrefix #-}+   -- | Returns an input prefix parse paired with the remaining input suffix.+   parsePrefix g input = Rank2.fmap (Compose . fromResult input . (`applyParser` input)) g+   parseComplete g input = Rank2.fmap ((snd <$>) . fromResult input . (`applyParser` input))+                                      (Rank2.fmap (<* endOfInput) g)++fromResult :: FactorialMonoid s => s -> Result g s r -> ParseResults (s, r)+fromResult s (NoParse (FailureInfo _ pos msgs)) =+   Left (ParseFailure (Factorial.length s - fromIntegral pos + 1) (nub msgs))+fromResult _ (Parsed _ prefix suffix) = Right (suffix, prefix)
src/Text/Grampa/PEG/Packrat.hs view
@@ -1,6 +1,6 @@ {-# LANGUAGE TypeFamilies #-} -- | Packrat parser-module Text.Grampa.PEG.Packrat (Parser) where+module Text.Grampa.PEG.Packrat (Parser(..), Result(..)) where  import Control.Applicative (Applicative(..), Alternative(..), liftA2) import Control.Monad (Monad(..), MonadPlus(..))@@ -11,7 +11,7 @@ import Data.List (genericLength, nub) import Data.Monoid (Monoid(mappend, mempty), (<>)) import Data.Monoid.Factorial(FactorialMonoid)-import Data.Word (Word64)+import Data.String (fromString)  import qualified Data.Monoid.Cancellative as Cancellative import qualified Data.Monoid.Factorial as Factorial@@ -20,14 +20,18 @@  import qualified Rank2 +import qualified Text.Parser.Char+import Text.Parser.Char (CharParsing) import Text.Parser.Combinators (Parsing(..))+import Text.Parser.LookAhead (LookAheadParsing(..))+import Text.Parser.Token (TokenParsing(someSpace)) import Text.Grampa.Class (GrammarParsing(..), MonoidParsing(..), MultiParsing(..), ParseResults, ParseFailure(..))+import Text.Grampa.Internal (FailureInfo(..)) import qualified Text.Grampa.PEG.Backtrack as Backtrack (Parser) -data Result g s v = Parsed{parsedPrefix :: v, -                           parsedSuffix :: [(s, g (Result g s))]}+data Result g s v = Parsed{parsedPrefix :: !v, +                           parsedSuffix :: ![(s, g (Result g s))]}                   | NoParse FailureInfo-data FailureInfo = FailureInfo !Int Word64 [String] deriving (Eq, Show)  -- | Parser type for Parsing Expression Grammars that uses an improved packrat algorithm, with O(1) performance bounds -- but with worse constants and more memory consumption than 'Backtrack.Parser'. The 'parse' function returns an input@@ -83,6 +87,22 @@       where rewind t Parsed{} = NoParse (FailureInfo 1 (genericLength t) ["notFollowedBy"])             rewind t NoParse{} = Parsed () t +instance Factorial.FactorialMonoid s => LookAheadParsing (Parser g s) where+   lookAhead (Parser p) = Parser (\input-> rewind input (p input))+      where rewind t (Parsed r _) = Parsed r t+            rewind _ r@NoParse{} = r++instance (Show s, Textual.TextualMonoid s) => CharParsing (Parser g s) where+   satisfy = satisfyChar+   string s = Textual.toString (error "unexpected non-character") <$> string (fromString s)+   char = satisfyChar . (==)+   notChar = satisfyChar . (/=)+   anyChar = satisfyChar (const True)+   text t = (fromString . Textual.toString (error "unexpected non-character")) <$> string (Textual.fromText t)++instance (Show s, Textual.TextualMonoid s) => TokenParsing (Parser g s) where+   someSpace = () <$ takeCharsWhile1 isSpace+ instance GrammarParsing Parser where    type GrammarFunctor Parser = Result    nonTerminal f = Parser p where@@ -110,10 +130,26 @@             p [] = NoParse (FailureInfo 1 0 ["satisfy"])    satisfyChar predicate = Parser p       where p rest@((s, _):t) =-               case Textual.splitCharacterPrefix s-               of Just (first, _) | predicate first -> Parsed first t+               case Textual.characterPrefix s+               of Just first | predicate first -> Parsed first t                   _ -> NoParse (FailureInfo 1 (genericLength rest) ["satisfyChar"])             p [] = NoParse (FailureInfo 1 0 ["satisfyChar"])+   satisfyCharInput predicate = Parser p+      where p rest@((s, _):t) =+               case Textual.characterPrefix s+               of Just first | predicate first -> Parsed (Factorial.primePrefix s) t+                  _ -> NoParse (FailureInfo 1 (genericLength rest) ["satisfyChar"])+            p [] = NoParse (FailureInfo 1 0 ["satisfyChar"])+   notSatisfy predicate = Parser p+      where p rest@((s, _):_)+               | Just (first, _) <- Factorial.splitPrimePrefix s, +                 predicate first = NoParse (FailureInfo 1 (genericLength rest) ["notSatisfy"])+            p rest = Parsed () rest+   notSatisfyChar predicate = Parser p+      where p rest@((s, _):_)+               | Just first <- Textual.characterPrefix s, +                 predicate first = NoParse (FailureInfo 1 (genericLength rest) ["notSatisfyChar"])+            p rest = Parsed () rest    scan s0 f = Parser (p s0)       where p s ((i, _):t) = Parsed prefix (drop (Factorial.length prefix - 1) t)                where (prefix, _, _) = Factorial.spanMaybe' s f i