parsley.Parsley.scala Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2020 Parsley Contributors
*
* SPDX-License-Identifier: BSD-3-Clause
*/
package parsley
import scala.collection.{Factory, mutable}
import parsley.combinator.option
import parsley.errors.ErrorBuilder
import parsley.expr.{chain, infix}
import parsley.internal.diagnostics.UserException
import parsley.internal.deepembedding.{frontend, singletons}
import parsley.internal.machine.Context
import Parsley.{emptyErr, pure, some}
import XCompat._ // substituteCo
/**
* This is the class that encapsulates the act of parsing and running an object of this class with `parse` will
* parse the string given as input to `parse`.
*
* @note In order to construct an object of this class you must use the combinators; the class itself is opaque.
*
* @author Jamie Willis
* @version 4.0.0
*
* @groupprio run 0
* @groupname run Running Parsers
* @groupdesc run These methods allow for a parser to be executed.
*
* @groupprio map 20
* @groupname map Result Changing Combinators
* @groupdesc map
* These combinators change the result of the parser they are called on into a value
* of a different type. This new result value may or may not be derived from the previous
* result.
*
* @groupprio alt 25
* @groupname alt Branching Combinators
* @groupdesc alt
* These combinators allow for parsing one alternative or another. All of these combinators
* are ''left-biased'', which means that the left-hand side of the combinator is tried first:
* the right-hand side of the combinator will only be tried when the left-hand one failed
* (and did not consume input in the process).
*
* @groupprio seq 25
* @groupname seq Sequencing Combinators
* @groupdesc seq
* These combinators all combine two parsers in sequence. The receiver of the combinator
* will be executed first, then the argument second. The results of both parsers are combined
* in some way (depending on the individual combinator). If one of the parsers fails, the
* combinator as a whole fails.
*
* @groupprio filter 50
* @groupname filter Filtering Combinators
* @groupdesc filter
* These combinators perform filtering on the results of a parser. This means that, given
* the result of a parser, they will perform some function on that result, and the success
* of that function effects whether or not the parser fails.
*
* @groupprio fold 50
* @groupname fold Folding Combinators
* @groupdesc fold
* These combinators repeatedly execute a parser (at least zero or one times depending on
* the specific combinator) until it fails. The results of the successes are then combined
* together using a folding function. An initial value for the accumulation may be given
* (for the `fold`s), or the first successful result is the initial accumulator (for the
* `reduce`s). These are implemented efficiently and do not need to construct any intermediate
* list with which to store the results.
*
* @groupprio monad 75
* @groupname monad Expensive Sequencing Combinators
* @groupdesc monad
* These combinators can sequence two parsers, where the first parser's result influences
* the structure of the second one. This may be because the second parser is generated
* from the result of the first, or that the first parser ''returns'' the second parser.
* Either way, the second parser cannot be known until runtime, when the first parser
* has been executed: this means that Parsley is forced to compile the second parser during
* parse-time, which is '''very''' expensive to do repeatedly. These combinators are only
* needed in exceptional circumstances, and should be avoided otherwise.
*
* @groupprio special 100
* @groupname special Special Methods
* @groupdesc special These are methods that should be rarely needed.
*
* @define attemptreason
* The reason for this behaviour is that it prevents space leaks and improves error messages. If this behaviour
* is not desired, use `atomic(this)` to rollback any input consumed on failure.
*
* @define or
* parses `q` if this parser fails '''without''' consuming input.
*
* If this parser is successful, then this combinator is successful and no further action is taken. Otherwise, if this parser
* fails '''without''' consuming input, then `q` is parsed instead. If this parser fails having consumed
* input, this combinator fails.
*
* @define orconst
* returns `x` if this parser fails '''without''' consuming input.
*
* If this parser is successful, then this combinator is successful and no further action is taken. Otherwise, if this parser
* fails '''without''' consuming input, then `x` is unconditionally returned. If this parser fails having consumed
* input, this combinator fails. Functionally the same as `this <|> pure(x)`.
*
* @define bind
* first performs this parser, then uses its result to generate and execute a new parser.
*
* First, this combinator runs this parser. If it succeeded, the result `x` is given to the function `f`
* to produce a new parser `f(x)`. This new parser is then executed and its result returned. If either
* of this parser or the new parser fails, then the entire combinator fails.
*
* This is a very powerful combinator (Turing-powerful, in fact): it is only necessary (and not ''all''
* the time) to use this for context-sensitive parsing. The idea is that it can make any form of
* decision based on the result of a parser, allowing it to perform a different parser for each
* possible output of another without exhaustively enumerating them all.
*
* @define autoAmend
* when this combinator fails (and not this parser itself), it will generate errors rooted at the start of the
* parse (as if [[parsley.errors.combinator$.amend `amend`]] had been used) and the caret will span the entire
* successful parse of this parser.
*/
final class Parsley[+A] private [parsley] (private [parsley] val internal: frontend.LazyParsley[A]) extends AnyVal {
/** This method is responsible for actually executing parsers. Given an input
* array, will parse the string with the parser. The result is either a `Success` or a `Failure`.
* @param input The input to run against
* @return Either a success with a value of type `A` or a failure with error message
* @since 3.0.0
* @group run
*/
def parse[Err: ErrorBuilder](input: String): Result[Err, A] = {
try new Context(internal.instrs, input, internal.numRegs, None).run()
catch {
// $COVERAGE-OFF$
case UserException(err) => throw err // scalastyle:ignore throw
// $COVERAGE-ON$
}
}
// RESULT CHANGING COMBINATORS
/** This combinator allows the result of this parser to be changed using a given function.
*
* When this parser succeeds, `map(f)` will adjust its result using the function `f`, which can
* potentially change its type. This can be used to build more complex results from parsers, instead
* of just characters or strings.
*
* ''In Haskell, this combinator is known as `fmap` or `(<$>)`''.
*
* @example {{{
* scala> import parsley.character.digit
* scala> digit.map(_.asDigit).parse("7")
* val res0 = Success(7)
* }}}
*
* @note This is subject to aggressive optimisations assuming purity; the compiler is permitted to optimise such
* that the application of `f` actually only happens once at compile time. In order to preserve the behaviour of
* impure functions, consider using the `unsafe` method before map; `p.unsafe.map(f)`.
* @param f the function to apply to the result of the parse
* @return a new parser that behaves the same as this parser, but with the given function `f` applied to its result.
* @group map
*/
def map[B](f: A => B): Parsley[B] = pure(f) <*> this
/** This combinator, pronounced "as", replaces the result of this parser, ignoring the old result.
*
* Similar to `map`, except the old result of this parser is not required to
* compute the new result. This is useful when the result is a constant value (or function!).
* Functionally the same as `this *> pure(x)` or `this.map(_ => x)`.
*
* ''In Haskell, this combinator is known as `($>)`''.
*
* @example {{{
* scala> import parsley.character.string
* scala> (string("true") #> true).parse("true")
* val res0 = Success(true)
* }}}
*
* @param x the new result of this parser.
* @return a new parser that behaves the same as this parser, but always succeeds with `x` as the result.
* @note just an alias for `as`.
* @group map
*/
def #>[B](x: B): Parsley[B] = this.as(x)
/** This combinator replaces the result of this parser, ignoring the old result.
*
* Similar to `map`, except the old result of this parser is not required to
* compute the new result. This is useful when the result is a constant value (or function!).
* Functionally the same as `this *> pure(x)` or `this.map(_ => x)`.
*
* ''In Haskell, this combinator is known as `($>)`''.
*
* @example {{{
* scala> import parsley.character.string
* scala> string("true").as(true).parse("true")
* val res0 = Success(true)
* }}}
*
* @param x the new result of this parser.
* @return a new parser that behaves the same as this parser, but always succeeds with `x` as the result.
* @group map
*/
def as[B](x: B): Parsley[B] = this *> pure(x)
/** Replaces the result of this parser with `()`.
*
* This combinator is useful when the result of this parser is not required, and the
* type must be `Parsley[Unit]`. Functionally the same as `this.as(())`.
*
* @return a new parser that behaves the same as this parser, but always returns `()` on success.
* @group map
*/
def void: Parsley[Unit] = this.as(())
// BRANCHING COMBINATORS
/** This combinator, pronounced "or", $or
*
* $attemptreason
*
* @example {{{
* scala> import parsley.character.string
* scala> val p = string("a") <|> string("b")
* scala> p.parse("a")
* val res0 = Success("a")
* scala> p.parse("b")
* val res1 = Success("b")
* scala> val q = string("ab") <|> string("ac")
* scala> q.parse("ac")
* val res2 = Failure(..) // first parser consumed an 'a'!
* }}}
*
* @param q the parser to run if this parser fails having not consumed input.
* @tparam Aʹ the type returned by `q`, which must be a supertype of the result type of this parser: this allows for weakening of the result type.
* @return a parser which either parses this parser or parses `q`.
* @group alt
*/
def <|>[Aʹ >: A](q: Parsley[Aʹ]): Parsley[Aʹ] = new Parsley(new frontend.<|>(this.internal, q.internal))
/** This combinator, pronounced "or", $or
*
* $attemptreason
*
* @example {{{
* scala> import parsley.character.string
* scala> val p = string("a") | string("b")
* scala> p.parse("a")
* val res0 = Success("a")
* scala> p.parse("b")
* val res1 = Success("b")
* scala> val q = string("ab") | string("ac")
* scala> q.parse("ac")
* val res2 = Failure(..) // first parser consumed an 'a'!
* }}}
*
* @since 4.0.0
* @param q the parser to run if this parser fails having not consumed input.
* @tparam Aʹ the type returned by `q`, which must be a supertype of the result type of this parser: this allows for weakening of the result type.
* @return a parser which either parses this parser or parses `q`.
* @note just an alias for `<|>`.
* @group alt
*/
def |[Aʹ >: A](q: Parsley[Aʹ]): Parsley[Aʹ] = this <|> q
/** This combinator $or
*
* $attemptreason
*
* @example {{{
* scala> import parsley.character.string
* scala> val p = string("a").orElse(string("b"))
* scala> p.parse("a")
* val res0 = Success("a")
* scala> p.parse("b")
* val res1 = Success("b")
* scala> val q = string("ab").orElse(string("ac"))
* scala> q.parse("ac")
* val res2 = Failure(..) // first parser consumed an 'a'!
* }}}
*
* @since 4.0.0
* @param q the parser to run if this parser fails having not consumed input.
* @tparam Aʹ the type returned by `q`, which must be a supertype of the result type of this parser: this allows for weakening of the result type.
* @return a parser which either parses this parser or parses `q`.
* @note just an alias for `<|>`.
* @group alt
*/
def orElse[Aʹ >: A](q: Parsley[Aʹ]): Parsley[Aʹ] = this <|> q
/** This combinator, pronounced "or constant", $orconst
*
* $attemptreason
*
* @example {{{
* scala> import parsley.character.string
* scala> val p = string("aa") > "b"
* scala> p.parse("aa")
* val res0 = Success("a")
* scala> p.parse("xyz")
* val res1 = Success("b")
* scala> p.parse("ab")
* val res2 = Failure(..) // first parser consumed an 'a'!
* }}}
*
* @param x the value to return if this parser fails having not consumed input.
* @tparam Aʹ the type of `x`, which must be a supertype of the result type of this parser: this allows for weakening of the result type.
* @return a parser which either parses this parser or returns `x`.
* @group alt
*/
def >[Aʹ >: A](x: Aʹ): Parsley[Aʹ] = this <|> pure(x)
/** This combinator, pronounced "sum", wraps this parser's result in `Left` if it succeeds, and parses `q` if it failed '''without''' consuming input,
* wrapping the result in `Right`.
*
* If this parser is successful, then its result is wrapped up using `Left(_)` and no further action is taken.
* Otherwise, if this parser fails '''without''' consuming input, then `q` is parsed instead and its result is
* wrapped up using `Right(_)`. If this parser fails having consumed input, this combinator fails.
* This is functionally equivalent to `this.map(Left(_)) <|> q.map(Right(_))`.
*
* $attemptreason
*
* @example {{{
* scala> import parsley.character.char
* scala> val p = string("abc") <+> char("xyz")
* scala> p.parse("abc")
* val res0 = Success(Left("abc"))
* scala> p.parse("xyz")
* val res1 = Success(Right("xyz"))
* scala> p.parse("ab")
* val res2 = Failure(..) // first parser consumed an 'a'!
* }}}
*
* @param q the parser to run if this parser fails having not consumed input.
* @return a parser which either parses this parser or parses `q` projecting their results into an `Either[A, B]`.
* @group alt
*/
def <+>[B](q: Parsley[B]): Parsley[Either[A, B]] = this.map(Left(_)) <|> q.map(Right(_))
// SEQUENCING COMBINATORS
/** This combinator, pronounced "ap", first parses this parser then parses `px`: if both succeed then the function
* returned by this parser is applied to the value returned by `px`.
*
* The implicit (compiler-provided) evidence proves that this parser really has type `Parsley[B => C]`.
* First, this parser is ran, yielding a function `f` on success, then `px` is ran, yielding a value `x`
* on success. If both are successful, then `f(x)` is returned. If either fail then the entire combinator
* fails.
*
* @example {{{
* scala> import parsley.Parsley, parsley.character.char
* scala> val sign: Parsley[Int => Int] = char('+').as(identity[Int] _) <|> char('-').as(x => -x)
* scala> val nat: Parsley[Int] = ..
* scala> val int = sign <*> nat
* scala> int.parse("-7")
* val res0 = Success(-7)
* scala> int.parse("+42")
* val res1 = Success(42)
* scala> int.parse("2")
* val res2 = Failure(..) // `sign` failed: no + or -
* scala> int.parse("-a")
* val res3 = Failure(..) // `nat` failed
* }}}
*
* @param px the parser to run second, which returns a value applicable to this parser's result.
* @param ev witnesses that the type of this parser, `A`, is actually `B => C`.
* @return a parser that sequences this parser with `px` and combines their results with function application.
* @note equivalent to `lift2((f, x) => f(x), this, px)`.
* @group seq
*/
def <*>[B, C](px: =>Parsley[B])
(implicit ev: A <:< (B=>C)): Parsley[C] = new Parsley(new frontend.<*>[B, C](ev.substituteParsley(this).internal, px.internal))
/** This combinator, pronounced "reverse ap", first parses this parser then parses `pf`: if both succeed then the value
* returned by this parser is applied to the function returned by `pf`.
*
* First, this parser is ran, yielding a value `x` on success, then `pf` is ran, yielding a function `f`
* on success. If both are successful, then `f(x)` is returned. If either fail then the entire combinator
* fails.
*
* Compared with `<*>`, this combinator is useful for left-factoring: when two branches of a parser share
* a common prefix, this can often be factored out; but the result of that factored prefix may be required
* to help generate the results of each branch. In this case, the branches can return functions that, when
* given the factored result, can produce the original results from before the factoring.
*
* @example {{{
* // this has a common prefix "term" and requires backtracking
* val expr1 = atomic(lift2(Add, term <* char('+'), expr2)) <|> term
* // common prefix factored out, and branches return a function to recombine
* val expr2 = term <**> (char('+') *> expr2.map(y => Add(_, y)) > (identity[Expr] _))
* }}}
*
* @param pf the parser to run second, which returns a function this parser's result can be applied to.
* @return a parser that sequences this parser with `pf` and combines their results with function application.
* @note equivalent to {{{lift2((x, f) => f(x), this, pf)}}}
* @group seq
*/
def <**>[B](pf: =>Parsley[A => B]): Parsley[B] = lift.lift2[A, A=>B, B]((x, f) => f(x), this, pf)
/** This combinator, pronounced "then", first parses this parser then parses `q`: if both succeed then the result
* of `q` is returned.
*
* First, this parser is ran, yielding `x` on success, then `q` is ran, yielding `y` on success. If both
* are successful then `y` is returned and `x` is ignored. If either fail then the entire combinator fails.
*
* ''Identical to `~>`: `*>` is more common in Haskell, whereas `~>` is more common in Scala.''
*
* @example {{{
* scala> import parsley.character.char
* scala> ('a' *> 'b').parse("ab")
* val res0 = Success('b')
* }}}
*
* @param q the parser to run second, which returns the result of this combinator.
* @return a parser that sequences this parser with `q` and returns `q`'s result.
* @group seq
*/
def *>[B](q: =>Parsley[B]): Parsley[B] = new Parsley(new frontend.*>(this.internal, q.internal))
/** This combinator, pronounced "then discard", first parses this parser then parses `q`: if both succeed then the result
* of this parser is returned.
*
* First, this parser is ran, yielding `x` on success, then `q` is ran, yielding `y` on success. If both
* are successful then `x` is returned and `y` is ignored. If either fail then the entire combinator fails.
*
* ''Identical to `<~`: `<*` is more common in Haskell, whereas `<~` is more common in Scala.''
*
* @example {{{
* scala> import parsley.character.char
* scala> ('a' <* 'b').parse("ab")
* val res0 = Success('a')
* }}}
*
* @param q the parser to run second, which returns the result of this combinator.
* @return a parser that sequences this parser with `q` and returns this parser's result.
* @group seq
*/
def <*[B](q: =>Parsley[B]): Parsley[A] = new Parsley(new frontend.<*(this.internal, q.internal))
/** This combinator, pronounced "then", first parses this parser then parses `q`: if both succeed then the result
* of `q` is returned.
*
* First, this parser is ran, yielding `x` on success, then `q` is ran, yielding `y` on success. If both
* are successful then `y` is returned and `x` is ignored. If either fail then the entire combinator fails.
*
* ''Identical to `*>`: `*>` is more common in Haskell, whereas `~>` is more common in Scala.''
*
* @example {{{
* scala> import parsley.character.char
* scala> ('a' ~> 'b').parse("ab")
* val res0 = Success('b')
* }}}
*
* @param q the parser to run second, which returns the result of this combinator.
* @return a parser that sequences this parser with `q` and returns `q`'s result.
* @since 2.4.0
* @group seq
*/
def ~>[B](q: =>Parsley[B]): Parsley[B] = this *> q
/** This combinator, pronounced "then discard", first parses this parser then parses `q`: if both succeed then the result
* of this parser is returned.
*
* First, this parser is ran, yielding `x` on success, then `q` is ran, yielding `y` on success. If both
* are successful then `x` is returned and `y` is ignored. If either fail then the entire combinator fails.
*
* ''Identical to `<*`: `<*` is more common in Haskell, whereas `<~` is more common in Scala.''
*
* @example {{{
* scala> import parsley.character.char
* scala> ('a' <~ 'b').parse("ab")
* val res0 = Success('a')
* }}}
*
* @param q the parser to run second, which returns the result of this combinator.
* @return a parser that sequences this parser with `q` and returns this parser's result.
* @since 2.4.0
* @group seq
*/
def <~[B](q: =>Parsley[B]): Parsley[A] = this <* q
/** This combinator, pronounced "prepend", first parses this parser then parses `ps`: if both succeed the result of this
* parser is prepended onto the result of `ps`.
*
* First, this parser is ran, yielding `x` on success, then `ps` is ran, yielding `xs` on success. If both
* are successful then `x +: xs` is returned. If either fail then the entire combinator fails.
*
* @example {{{
* def some[A](p: Parsley[A]): Parsley[List[A]] = {
* p <+:> many(p) // since List[A] <: Seq[A]
* }
* }}}
*
* @param ps the parser to run second, which returns a sequence.
* @tparam Aʹ the type of the elements in the result sequence, which must be a supertype of
* the result type of this parser: this allows for weakening of the result type.
* @return a parser that sequences this parser with `ps` and prepends its result onto `ps` result.
* @note equivalent to {{{lift2(_ +: _, this, ps)}}}
* @group seq
*/
def <+:>[Aʹ >: A](ps: =>Parsley[Seq[Aʹ]]): Parsley[Seq[Aʹ]] = lift.lift2[A, Seq[Aʹ], Seq[Aʹ]](_ +: _, this, ps)
/** This combinator, pronounced "cons", first parses this parser then parses `ps`: if both succeed the result of this
* parser is prepended onto the result of `ps`.
*
* First, this parser is ran, yielding `x` on success, then `ps` is ran, yielding `xs` on success. If both
* are successful then `x :: xs` is returned. If either fail then the entire combinator fails.
*
* @example {{{
* def some[A](p: Parsley[A]): Parsley[List[A]] = {
* p <::> many(p)
* }
* }}}
*
* @param ps the parser to run second, which returns a list.
* @tparam Aʹ the type of the elements in the result list, which must be a supertype of
* the result type of this parser: this allows for weakening of the result type.
* @return a parser that sequences this parser with `ps` and prepends its result onto `ps` result.
* @note equivalent to {{{lift2(_ :: _, this, ps)}}}
* @group seq
*/
def <::>[Aʹ >: A](ps: =>Parsley[List[Aʹ]]): Parsley[List[Aʹ]] = lift.lift2[A, List[Aʹ], List[Aʹ]](_ :: _, this, ps)
/** This combinator, pronounced "zip", first parses this parser then parses `q`: if both succeed the result of this
* parser is paired with the result of `q`.
*
* First, this parser is ran, yielding `x` on success, then `q` is ran, yielding `y` on success. If both
* are successful then `(x, y)` is returned. If either fail then the entire combinator fails.
*
* @example {{{
* scala> import parsley.character.char
* scala> val p = char('a') <~> char('b')
* scala> p.parse("ab")
* val res0 = Success(('a', 'b'))
* scala> p.parse("b")
* val res1 = Failure(..)
* scala> p.parse("a")
* val res2 = Failure(..)
* }}}
*
* @param q the parser to run second.
* @return a parser that sequences this parser with `q` and pairs their results together.
* @note equivalent to {{{lift2((_, _), this, q)}}}
* @group seq
*/
def <~>[B](q: =>Parsley[B]): Parsley[(A, B)] = lift.lift2[A, B, (A, B)]((_, _), this, q)
/** This combinator first parses this parser then parses `q`: if both succeed the result of this
* parser is paired with the result of `q`.
*
* First, this parser is ran, yielding `x` on success, then `q` is ran, yielding `y` on success. If both
* are successful then `(x, y)` is returned. If either fail then the entire combinator fails.
*
* @example {{{
* scala> import parsley.character.char
* scala> val p = char('a').zip(char('b'))
* scala> p.parse("ab")
* val res0 = Success(('a', 'b'))
* scala> p.parse("b")
* val res1 = Failure(..)
* scala> p.parse("a")
* val res2 = Failure(..)
* }}}
*
* @param q the parser to run second.
* @return a parser that sequences this parser with `q` and pairs their results together.
* @note alias for `<~>`.
* @since 2.3.0
* @group seq
*/
def zip[B](q: =>Parsley[B]): Parsley[(A, B)] = this <~> q
// FILTERING COMBINATORS
/** This combinator filters the result of this parser using a given predicate, succeeding only if the predicate returns `true`.
*
* First, parse this parser. If it succeeds then take its result `x` and apply it to the predicate `pred`. If `pred(x)` is
* true, then return `x`. Otherwise, the combinator fails.
*
* @example {{{
* scala> import parsley.character.letter
* scala> val keywords = Set("if", "then", "else")
* scala> val identifier = some(letter).map(_.mkString)
* .filter(!keywords.contains(_))
* scala> identifier.parse("hello")
* val res0 = Success("hello")
* scala> idenfitier.parse("if")
* val res1 = Failure(..)
* }}}
*
* @param pred the predicate that is tested against the parser result.
* @return a parser that returns the result of this parser if it passes the predicate.
* @see [[parsley.errors.combinator.ErrorMethods.filterOut `filterOut`]] for a version which can produce custom ''reasons'' on failure.
* @see [[parsley.errors.combinator.ErrorMethods.guardAgainst `guardAgainst`]] for a version which can produce custom error messages on failure.
* @note $autoAmend
* @group filter
*/
def filter(pred: A => Boolean): Parsley[A] = parsley.errors.combinator.filterWith(this)(pred, emptyErr)
/** This combinator filters the result of this parser using a given predicate, succeeding only if the predicate returns `false`.
*
* First, parse this parser. If it succeeds then take its result `x` and apply it to the predicate `pred`. If `pred(x) is
* false, then return `x`. Otherwise, the combinator fails.
*
* @example {{{
* scala> import parsley.character.letter
* scala> val keywords = Set("if", "then", "else")
* scala> val identifier = some(letter).map(_.mkString)
* .filterNot(keywords.contains(_))
* scala> identifier.parse("hello")
* val res0 = Success("hello")
* scala> identifier.parse("if")
* val res1 = Failure(..)
* }}}
*
* @param pred the predicate that is tested against the parser result.
* @return a parser that returns the result of this parser if it fails the predicate.
* @see [[parsley.errors.combinator.ErrorMethods.filterOut `filterOut`]] for a version that can produce custom ''reasons'' on failure.
* @see [[parsley.errors.combinator.ErrorMethods.guardAgainst `guardAgainst`]] for a version that can produce custom error messages on failure.
* @note $autoAmend
* @group filter
*/
def filterNot(pred: A => Boolean): Parsley[A] = this.filter(!pred(_))
/** This combinator applies a partial function `pf` to the result of this parser if its result
* is defined for `pf`, failing if it is not.
*
* First, parse this parser. If it succeeds, test whether its result `x` is in the
* domain of the partial function `pf`. If it is defined for `pf`, return `pf(x)`.
* If it is undefined, or this parser failed, then this combinator fails. Equivalent
* to a `filter` followed by a `map`.
*
* @example {{{
* scala> val int: Parsley[Int] = ..
* scala> val safeDiv: Parsley[Int] = (int <~> char(' ') *> int).collect {
* case (x, y) if y != 0 => x / y
* }
* scala> safeDiv.parse("7 0")
* val res0 = Failure(..) // y cannot be 0!
* scala> safeDiv.parse("10 2")
* val res1 = Success(5)
* }}}
*
* @param pf the partial function used to both filter the result of this parser and transform it.
* @return a parser that returns the result of this parser applied to `pf`, if possible.
* @see [[parsley.errors.combinator.ErrorMethods.collectMsg[B](msg0:String,msgs:String*)* `collectMsg(String, String*)`]]
* and [[parsley.errors.combinator.ErrorMethods.collectMsg[B](msggen:A=>Seq[String])* `collectMsg(A => Seq[String])`]]
* for versions that can produce custom error messages on failure.
* @since 2.0.0
* @note $autoAmend
* @group filter
*/
def collect[B](pf: PartialFunction[A, B]): Parsley[B] = parsley.errors.combinator.collectWith(this)(pf, emptyErr)
/** This combinator applies a function `f` to the result of this parser: if it returns a
* `Some(y)`, `y` is returned, otherwise the parser fails.
*
* First, parse this parser. If it succeeds, apply the function `f` to the result `x`. If
* `f(x)` returns `Some(y)`, return `y`. If `f(x)` returns `None`, or this parser failed
* then this combinator fails. Is a more efficient way of performing a `filter` and `map`
* at the same time.
*
* @example {{{
* scala> val int: Parsley[Int] = ..
* scala> val safeDiv: Parsley[Int] = (int <~> char(' ') *> int).collect {
* case (x, y) if y != 0 => Some(x / y)
* case _ => None
* }
* scala> safeDiv.parse("7 0")
* val res0 = Failure(..) // y cannot be 0!
* scala> safeDiv.parse("10 2")
* val res1 = Success(5)
* }}}
*
* @param f the function used to both filter the result of this parser and transform it.
* @return a parser that returns the result of this parser applied to `f`, if it yields a value.
* @since 4.0.0
* @note $autoAmend
* @group filter
*/
def mapFilter[B](f: A => Option[B]): Parsley[B] = parsley.errors.combinator.mapFilterWith(this)(f, emptyErr)
// FOLDING COMBINATORS
/** This combinator will parse this parser '''zero''' or more times combining the results with the function `f` and base value `k` from the right.
*
* This parser will continue to be parsed until it fails having '''not consumed''' input.
* All of the results generated by the successful parses are then combined in a right-to-left
* fashion using the function `f`: the right-most value provided to `f` is the value `k`.
* If this parser does fail at any point having consumed input, this combinator will fail.
*
* @example {{{
* // in reality, many is implemented more efficiently
* def many[A](p: Parsley[A]) = {
* p.foldRight(List.empty[A])(_ :: _)
* }
* }}}
*
* @param k value to use when this parser no longer succeeds.
* @param f function to apply to each value produced by this parser, starting at the right.
* @return a parser which parses this parser many times and folds the results together with `f` and `k` right-associatively.
* @group fold
*/
def foldRight[B](k: B)(f: (A, B) => B): Parsley[B] = chain.prefix(pure(k))(this.map(f.curried))
/** This combinator will parse this parser '''zero''' or more times combining the results with the function `f` and base value `k` from the left.
*
* This parser will continue to be parsed until it fails having '''not consumed''' input.
* All of the results generated by the successful parses are then combined in a left-to-right
* fashion using the function `f`: the accumulation is initialised with the value `k`.
* If this parser does fail at any point having consumed input, this combinator will fail.
*
* @example {{{
* // this is not an efficient implementation of stringOfMany
* def stringOfMany(pc: Parsley[Char]): Parsley[String] = {
* pc.foldLeft("")(_ + _)
* }
* }}}
*
* @param k initial accumulation value.
* @param f function to apply to each iteration's accumulator.
* @return a parser which parses this parser many times and folds the results together with `f` and `k` left-associatively.
* @group fold
*/
def foldLeft[B](k: B)(f: (B, A) => B): Parsley[B] = expr.infix.secretLeft1(pure(k), this, pure(f))
/** This combinator will parse this parser '''one''' or more times combining the results with the function `f` and base value `k` from the right.
*
* This parser will continue to be parsed until it fails having '''not consumed''' input.
* All of the results generated by the successful parses are then combined in a right-to-left
* fashion using the function `f`: the right-most value provided to `f` is the value `k`.
* If this parser does fail at any point having consumed input, this combinator will fail.
*
* @example {{{
* // in reality, some is implemented more efficiently
* def some[A](p: Parsley[A]) = {
* p.foldRight1(List.empty[A])(_ :: _)
* }
* }}}
*
* @param k value to use when this parser no longer succeeds.
* @param f function to apply to each value produced by this parser, starting at the right.
* @return a parser which parses this parser some times and folds the results together with `f` and `k` right-associatively.
* @since 2.1.0
* @group fold
*/
def foldRight1[B](k: B)(f: (A, B) => B): Parsley[B] = {
lift.lift2(f, this, this.foldRight(k)(f))
}
/** This combinator will parse this parser '''one''' or more times combining the results with the function `f` and base value `k` from the left.
*
* This parser will continue to be parsed until it fails having '''not consumed''' input.
* All of the results generated by the successful parses are then combined in a left-to-right
* fashion using the function `f`: the accumulation is initialised with the value `k`.
* If this parser does fail at any point having consumed input, this combinator will fail.
*
* @example {{{
* val natural: Parsley[Int] = digit.foldLeft1(0)((x, d) => x * 10 + d.toInt)
* }}}
*
* @param k initial accumulation value.
* @param f function to apply to each iteration's accumulator.
* @return a parser which parses this parser some times and folds the results together with `f` and `k` left-associatively.
* @since 2.1.0
* @group fold
*/
def foldLeft1[B](k: B)(f: (B, A) => B): Parsley[B] = expr.infix.secretLeft1(this.map(f(k, _)), this, pure(f))
/** This combinator will parse this parser '''one''' or more times combining the results right-associatively with the function `op`.
*
* This parser will continue to be parsed until it fails having '''not consumed''' input.
* All of the results generated by the successful parses are then combined in a right-to-left
* fashion using the function `op`. If this parser does fail at any point having consumed input,
* this combinator will fail.
*
* @example {{{
* stmt.reduceRight(Seq(_, _))
* }}}
*
* @param op function to apply to each value produced by this parser, starting from the right.
* @return a parser which parses this parser some times and folds the results together with `op` right-associatively.
* @since 2.3.0
* @group fold
*/
def reduceRight[B >: A](op: (A, B) => B): Parsley[B] = some(this).map(_.reduceRight(op))
/** This combinator will parse this parser '''zero''' or more times combining the results right-associatively with the function `op`.
*
* This parser will continue to be parsed until it fails having '''not consumed''' input.
* If this parser succeeded at least once, all of the results generated by the successful
* parses are then combined in a right-to-left fashion using the function `op` and returned
* in a `Some`. If no successful parses occurred, then `None` is returned. If this
* parser does fail at any point having consumed input, this combinator will fail.
*
* @example {{{
* arg.reduceRightOption(Sep(_, _))
* }}}
*
* @param op function to apply to each value produced by this parser, starting from the right.
* @return a parser which parses this parser many times and folds the results together with `op` right-associatively or returns None if no parses occured.
* @since 2.3.0
* @group fold
*/
def reduceRightOption[B >: A](op: (A, B) => B): Parsley[Option[B]] = option(this.reduceRight(op))
/** This combinator will parse this parser '''one''' or more times combining the results left-associatively with the function `op`.
*
* This parser will continue to be parsed until it fails having '''not consumed''' input.
* All of the results generated by the successful parses are then combined in a left-to-right
* fashion using the function `op`. If this parser does fail at any point having consumed input,
* this combinator will fail.
*
* @example {{{
* stmt.reduceLeft(Seq(_, _))
* }}}
*
* @param op function to apply to each value produced by this parser, starting from the left.
* @return a parser which parses this parser some times and folds the results together with `op` left-associatively.
* @since 2.3.0
* @group fold
*/
def reduceLeft[B >: A](op: (B, A) => B): Parsley[B] = infix.left1(this)(pure(op))
/** This combinator will parse this parser '''zero''' or more times combining the results left-associatively with the function `op`.
*
* This parser will continue to be parsed until it fails having '''not consumed''' input.
* If this parser succeeded at least once, all of the results generated by the successful
* parses are then combined in a left-to-right fashion using the function `op` and returned
* in a `Some`. If no successful parses occurred, then `None` is returned. If this
* parser does fail at any point having consumed input, this combinator will fail.
*
* @example {{{
* arg.reduceLeftOption(Sep(_, _))
* }}}
*
* @param op function to apply to each value produced by this parser, starting from the left.
* @return a parser which parses this parser many times and folds the results together with `op` left-associatively or returns None if no parses occured.
* @since 2.3.0
* @group fold
*/
def reduceLeftOption[B >: A](op: (B, A) => B): Parsley[Option[B]] = option(this.reduceLeft(op))
// EXPENSIVE SEQUENCING COMBINATORS
/** This combinator $bind
*
* ''In Haskell, this combinator is known as `(>>=)` (pronounced "bind")''.
*
* @example {{{
* // this is an inefficient implementation, but does work
* def filter(pred: A => Boolean): Parsley[A] = {
* this.flatMap { x =>
* if (pred(x)) pure(x)
* else empty
* }
* }
* }}}
*
* @note there is '''significant''' overhead for using `flatMap`: if possible try to avoid using it! This
* is because Parsley will need to generate, process, and compile each parser produced by the combinator
* during parse-time.
* @param f the function that produces the next parser.
* @return a new parser, which sequences this parser with the parser generated from its result.
* @group monad
*/
def flatMap[B](f: A => Parsley[B]): Parsley[B] = new Parsley(new frontend.>>=(this.internal, f.andThen(_.internal)))
/** This combinator collapses two layers of parsing structure into one.
*
* The implicit (compiler-provided) evidence proves that this parser really has type `Parsley[Parsley[B]]`.
* First, this parser is executed, which, if successful, will produce a new parser `p`. The parser `p` is
* then executed, and its result is returned. If either this parser or `p` fail, then the entire combinator
* fails.
*
* This is a very powerful combinator (Turing-powerful, in fact): it is only necessary (and not ''all''
* the time) to use this for context-sensitive parsing. The idea is that it can allow a parser to return
* any other parser as its result: this allows for an implementation of a later parser to be picked
* by an earlier one.
*
* ''In Haskell, this combinator is known as `join`''.
*
* @example imagine a parser for RegEx that first reads the description of the regular expression, then runs
* that against the remaining input string. It is possible to implement the parser for the regular
* expression itself as a `Parsley[Parsley[Unit]]`, which returns a parser that matches the regular
* expression. This can then be used to parse the remaining input by using `flatten` to incorporate
* it into the parser again:
* {{{
* scala> val regexDesc: Parsley[Parsley[Unit]] = ..
* // let's suppose "#" is the delimeter between expression and input
* scala> val regex: Parsley[Unit] = (regexDesc <* char('#')).flatten
* scala> regex.parse("a.(c*)#abccc")
* val res0 = Success(())
* scala> regex.parse("a.(c*)#a")
* val res1 = Failure(..)
* }}}
*
* @param ev witnesses that the result type of this parser, `A`, is really `Parsley[B]`.
* @return a new parser, which sequences this parser with its result parser.
* @note there is '''significant''' overhead for using `flatten`: if possible try to avoid using it! This
* is because Parsley will need to generate, process, and compile each parser produced by the combinator
* during parse-time.
* @group monad
*/
def flatten[B](implicit ev: A <:< Parsley[B]): Parsley[B] = this.flatMap[B](ev)
/** This combinator ignores the result of this parser and instead returns the input parsed by it.
*
* This combinator executes this parser: if it fails, this combinator fails. Otherwise, if this
* parser succeeded, its result is discarded and the input it consumed in the process of parsing
* is returned directly. This can be used to efficiently obtain the underlying string of some parser
* without having to reconstruct it. One potential application is to suppress complex results of
* things within the `Lexer` without having to re-implement its functionality. However, it should be
* used judiciously.
*
* @return a parser which returns the parsed input directly.
* @since 4.4.0
* @group map
*/
def span: Parsley[String] = new Parsley(new frontend.Span(this.internal))
// SPECIAL METHODS
// $COVERAGE-OFF$
/** Forces the compilation of a parser as opposed to the regular lazy evaluation.
*
* @group special
*/
def force(): Unit = internal.force()
/** Provides an indicator that this parser will likely stack-overflow and so a stack-safe
* construction should be used when "compiling" this parser.
*
* @group special
*/
def overflows(): Unit = internal.overflows()
/** This combinator signifies that the parser it is invoked on is impure and any optimisations which assume purity
* are disabled.
*
* @example Any parsers that make use of mutable state may need to use this combinator to control
* parsley's aggressive optimisations that remove results that are not needed: in this case,
* the optimiser cannot see that the result of a parser is mutating some value, and may remove it.
* @group special
*/
def impure: Parsley[A] = new Parsley(new frontend.Opaque(this.internal))
/** This is an alias for `p.filter(pred)`. It is needed to support for-comprehension syntax with `if`s.
*
* @since 4.0.0
* @see [[parsley.Parsley.filter `filter`]] for more information.
*/
def withFilter(pred: A => Boolean): Parsley[A] = this.filter(pred)
// $COVERAGE-ON$
}
/** This object contains the core "function-style" combinators: all parsers will likely require something from within!
*
* In particular, it contains combinators for: controlling how input is consumed; injecting values into
* the parser, or failing; extracting position information from the parser; conditional execution of
* parsers; and more.
*
* @groupprio cond 25
* @groupname cond Conditional Combinators
* @groupdesc cond
* These combinators will decide which branch to take next based on the result of another parser.
* This differs from combinators like `<|>` which make decisions based on the success/failure of
* a parser: here the result of a ''successful'' parse will direct which option is done. These
* are sometimes known as "selective" combinators.
*
* @groupprio prim 0
* @groupname prim Primitive Combinators
* @groupdesc prim
* These combinators are specific to parser combinators. In one way or another, they influence how a
* parser consumes input, or under what conditions a parser does or does not fail. These are really
* important for most practical parsing considerations, although `lookAhead` is much less well used.
*
* @groupprio basic 5
* @groupname basic Consumptionless Parsers
* @groupdesc basic
* These combinators and parsers do not consume input: they are the most primitive ways of producing
* successes and failures with the minimal possible effect on the parse. They are, however, reasonably
* useful; in particular, `pure` and `unit` can be put to good use in injecting results into a parser
* without needing to consume anything, or mapping another parser.
*
* @groupprio iter 10
* @groupname iter Iterative Combinators
* @groupdesc iter
* These combinators all execute a given parser an unbounded number of times, until either it fails, or another
* parser succeeds, depending on the combinator. All of the results produced by the
* repeated execution of the parser are returned in a `List`. These are almost essential for any practical parsing
* task.
*
* @groupprio item 15
* @groupname item Input Query Combinators
* @groupdesc item
* These combinators do not consume input, but they allow for querying of the input stream - specifically checking
* whether or not there is more input that can be consumed or not. In particular, most parsers should be making
* use of `eof` to ensure that the parser consumes all the input available at the end of the parse.
*/
object Parsley extends PlatformSpecific {
/** This class enables the prefix `~` combinator, which allows a parser in an otherwise strict
* position to be made lazy.
*
* @constructor This constructor should not be called manually, it is designed to be used via Scala's implicit resolution.
* @param p the parser that `~` is enabled on.
* @since 4.0.0
*/
implicit final class LazyParsley[A](p: =>Parsley[A]) {
/** This combinator makes a parser lazy.
*
* There are some combinators that are, due to Scala limitations,
* strict in all their parameters. Usually, a combinator is strict
* in its "first position", which is to say the first part of the
* combinator to be executed; and lazy in all other "positions".
* The rationale behind this is that recursion appearing in a
* "first position" ''will'' result in infinite recursion at parse-time,
* it is left-recursive after all, and so it makes little sense to
* waste efficiency and complicate the API to support laziness
* there. Since method receivers are strict and only
* arguments can be lazy under regular conditions, this works well.
*
* However, for combinators that are always strict, this poses a
* problem: a recursion point inside one of these strict fields
* will cause an infinite loop at runtime! This can be fixed by
* ensuring that this becomes part of a lazy argument. This is
* a solution described by the [[combinator.sequence `sequence`]]
* combinator, for instance: `p <::> sequence(q, .., r)` will ensure
* that the `sequence` is in a lazy position in `<::>` meaning that
* even if any of `q` to `r` must be lazy, they can go in the strict
* positions of skip because the `p <::>` provides the required
* laziness. However, if this isn't possible (for instance, with
* the [[syntax.zipped `zipped`]] combinators), then how can
* this problem be solved?
*
* This is the job of the `~` combinator: very simply it wraps up
* a parser in a lazy box, so that even if the box is forced by
* a strict position, the parser will remain lazy. This means it
* serves as an adequate solution to this problem.
*
* @example {{{
* // this works fine, even though all of `zipped`'s parsers are strict
* lazy val expr = (atomic(term) <* '+', ~expr).zipped(_ + _) <|> term
* // in this case, however, the following would fix the problem more elegantly:
* lazy val expr = (atomic(term), '+' *> expr).zipped(_ + _) <|> term
* }}}
*
* @return the parser `p`, but guaranteed to be lazy.
* @group special
*/
def unary_~ : Parsley[A] = unit *> p
}
/** This combinator produces a value without having any other effect.
*
* When this combinator is ran, no input is required, nor consumed, and
* the given value will always be successfully returned. It has no other
* effect on the state of the parser.
*
* @example {{{
* scala> import parsley.Parsley.pure
* scala> pure(7).parse("")
* val res0 = Success(7)
* scala> pure("hello!").parse("a")
* val res1 = Success("hello!")
* }}}
*
* @param x the value to be returned.
* @return a parser which consumes no input and produces a value `x`.
* @group basic
*/
def pure[A](x: A): Parsley[A] = new Parsley(new singletons.Pure(x))
/** This combinator produces a '''new''' value everytime it is parsed without having any other effect.
*
* When this combinator is ran, no input is required, nor consumed, and
* a '''new instance''' of the given value will always be successfully returned.
* It has no other effect on the state of the parser.
*
* This is useful primarily if mutable data is being threaded around a parser: this
* should not be needed for the ''vast'' majority of parsers.
*
* @example {{{
* scala> import parsley.Parsley.{pure, fresh}
* scala> val p = pure(new Object)
* scala> p.parse("")
* val res0 = Success(java.lang.Object@44a3ec6b)
* scala> p.parse("")
* val res1 = Success(java.lang.Object@44a3ec6b)
* scala> val q = fresh(new Object)
* scala> q.parse("")
* val res2 = Success(java.lang.Object@71623278)
* scala> q.parse("")
* val res3 = Success(java.lang.Object@768b970c)
* }}}
*
* @param x the value to be returned.
* @return a parser which consumes no input and produces a value `x`.
* @since 4.0.0
* @group basic
*/
def fresh[A](x: =>A): Parsley[A] = new Parsley(new singletons.Fresh(x))
/** This combinator parses its first argument `either`, and then parses either `left` or `right` depending on its result.
*
* First, `branch(either, left, right)` parses `either`, which, if successful, will produce either a `Left(x)` or a `Right(y)`.
* If a `Left(x)` is produced, the parser `left` is executed to produce a function `f`, and `f(x)` is returned. Otherwise,
* if a `Right(y)` is produced, the parser `right` is executed to produce a function `g`, and `g(y)` is returned. If either
* of the two executed parsers fail, the entire combinator fails.
*
* ''First introduced in [[https://www.staff.ncl.ac.uk/andrey.mokhov/selective-functors.pdf Selective Applicative Functors]] (Mokhov et al. 2019)''.
*
* @example {{{
* def ifP[A](b: Parsley[Boolean], t: =>Parsley[A], e: =>Parsley[A]): Parsley[A] = {
* val cond = b.map {
* case true => Left(())
* case false => Right(())
* }
* branch(cond, t.map[Unit => A](x => _ => x), e.map[Unit => A](x => _ => x))
* }
* }}}
*
* @param either the first parser to execute, its result decides which parser to execute next.
* @param left a parser to execute if `either` returns a `Left`.
* @param right a parser to execute if `either` returns a `Right`.
* @return a parser that will parse one of `left` or `right` depending on `either`'s result.
* @group cond
*/
def branch[A, B, C](either: Parsley[Either[A, B]], left: =>Parsley[A => C], right: =>Parsley[B => C]): Parsley[C] = {
new Parsley(new frontend.Branch(either.internal, left.internal, right.internal))
}
/** This combinator parses its first argument `p`, then parses `q` only if `p` returns a `Left`.
*
* First, `select(p, q)` parses `p`, which, if successful, will produce either a `Left(x)` or
* a `Right(y)`. If a `Left(x)` is produced, then the parser `q` is executed to produce a function
* `f`, and `f(x)` is returned. Otherwise, if a `Right(y)` is produced, `y` is returned unmodified
* and `q` is not parsed. If either `p` or `q` fails, the entire combinator fails. This is a special
* case of `branch` where the right branch is `pure(identity[B])`.
*
* ''First introduced in [[https://www.staff.ncl.ac.uk/andrey.mokhov/selective-functors.pdf Selective Applicative Functors]] (Mokhov et al. 2019)''.
*
* @example {{{
* def filter(pred: A => Boolean): Parsley[A] = {
* val p = this.map(x => if (pred(x)) Right(x) else Left(()))
* select(p, empty)
* }
* }}}
*
* @param p the first parser to execute, its result decides whether `q` is executed or not.
* @param q a parser to execute when `p` returns a `Left`.
* @return a parser that will parse `p` then possibly parse `q` to transform `p`'s result into a `B`.
* @group cond
*/
def select[A, B](p: Parsley[Either[A, B]], q: =>Parsley[A => B]): Parsley[B] = branch(p, q, pure(identity[B](_)))
/** This combinator parses its argument `p`, but rolls back any consumed input on failure.
*
* If the parser `p` succeeds, then `atomic(p)` has no effect. However, if `p` failed,
* then any input that it consumed is rolled back. This ensures that
* the parser `p` is all-or-nothing when consuming input. While there are many legimate
* uses for all-or-nothing behaviour, one notable, if discouraged, use is to allow the
* `<|>` combinator to backtrack -- recall it can only parse its alternative if the
* first failed ''without'' consuming input. This is discouraged, however, as it can
* affect the complexity of the parser and harm error messages.
*
* @example {{{
* scala> import parsley.character.string, parsley.Parsley.atomic
* scala> (string("abc") <|> string("abd")).parse("abd")
* val res0 = Failure(..) // first parser consumed a, so no backtrack
* scala> (atomic(string("abc")) <|> string("abd")).parse("abd")
* val res1 = Success("abd") // first parser does not consume input on failure now
* }}}
*
* @param p the parser to execute, if it fails, it will not have consumed input.
* @return a parser that tries `p`, but never consumes input if it fails.
* @since 4.4.0
* @group prim
*/
def atomic[A](p: Parsley[A]): Parsley[A] = new Parsley(new frontend.Attempt(p.internal))
/** This combinator parses its argument `p`, but does not consume input if it succeeds.
*
* If the parser `p` succeeds, then `lookAhead(p)` will roll back any input consumed
* whilst parsing `p`. If `p` fails, however, then the whole combinator fails and
* any input consumed '''remains consumed'''. If this behaviour is not desirable,
* consider pairing `lookAhead` with `atomic`.
*
* @example {{{
* scala> import parsley.Parsley.lookAhead, parsley.character.string
* scala> (lookAhead(string("aaa")) *> string("aaa")).parse("aaa")
* val res0 = Success("aaa")
* scala> (lookAhead(string("abc")) <|> string("abd")).parse("abd")
* val res1 = Failure(..) // lookAhead does not roll back input consumed on failure
* }}}
*
* @param p the parser to execute, if it succeeds, it will not have consumed input.
* @return a parser that parses `p` and never consumes input if it succeeds.
* @group prim
*/
def lookAhead[A](p: Parsley[A]): Parsley[A] = new Parsley(new frontend.Look(p.internal))
/** This combinator parses its argument `p`, and succeeds when `p` fails and vice-versa, never consuming input.
*
* If the parser `p` succeeds, then `notFollowedBy(p)` will fail, consuming no input.
* Otherwise, should `p` fail, then `notFollowedBy(p)` will succeed, consuming no input
* and returning `()`.
*
* @example one use for this combinator is to allow for "longest-match" behaviour.
* For instance, keywords are normally only considered keywords if they are not
* part of some larger valid identifier (i.e. the keyword "if" should not parse
* successfully given "ifp"). This can be accomplished as follows:
* {{{
* import parsley.character.{string, letterOrDigit}
* import parsley.Parsley.notFollowedBy
* def keyword(kw: String): Parsley[Unit] = atomic {
* string(kw) *> notFollowedBy(letterOrDigit)
* }
* }}}
*
* @param p the parser to execute, it should fail in order for this combinator to succeed.
* @return a parser which fails when `p` succeeds and succeeds otherwise, never consuming input.
* @group prim
*/
def notFollowedBy(p: Parsley[_]): Parsley[Unit] = new Parsley(new frontend.NotFollowedBy(p.internal))
/** This combinator fails immediately, with a caret of the given width and no other information.
*
* By producing basically no information, this combinator is principally for adjusting the
* caret-width of another error, rather than the value `empty`, which is used to fail with
* no effect on error content.
*
* @param caretWidth the width of the caret for the error produced by this combinator.
* @return a parser that fails.
* @since 4.4.0
* @group basic
*/
def empty(caretWidth: Int): Parsley[Nothing] = new Parsley(singletons.Empty(caretWidth))
/** This parser fails immediately, with an unknown parse error.
*
* @example {{{
* scala> import parsley.Parsley.empty
* scala> empty.parse("")
* val res0 = Failure(..)
* }}}
*
* @return a parser that fails.
* @note equivalent to `empty(0)`
* @group basic
*/
val empty: Parsley[Nothing] = empty(0)
/** This parser produces `()` without having any other effect.
*
* When this parser is ran, no input is required, nor consumed, and
* the given value will always be successfully returned. It has no other
* effect on the state of the parser.
*
* @example {{{
* scala> import parsley.Parsley.unit
* scala> unit.parse("")
* val res0 = Success(())
* scala> unit.parse("a")
* val res0 = Success(())
* }}}
*
* @param x the value to be returned.
* @return a parser which consumes no input and produces `()`.
* @note defined as `pure(())` as a simple convenience.
* @group basic
*/
val unit: Parsley[Unit] = pure(())
/** This parser only succeeds at the end of the input.
*
* Equivalent to `notFollowedBy(item)`.
*
* @example {{{
* scala> import parsley.combinator.eof
* scala> eof.parse("a")
* val res0 = Failure(..)
* scala> eof.parse("")
* val res1 = Success(())
* }}}
*
* @group item
* @since 4.5.0
*/
val eof: Parsley[Unit] = new Parsley(singletons.Eof)
private val emptyErr = new parsley.errors.VanillaGen[Any]
/** This combinator repeatedly parses a given parser '''zero''' or more times, collecting the results into a list.
*
* Parses a given parser, `p`, repeatedly until it fails. If `p` failed having consumed input,
* this combinator fails. Otherwise when `p` fails '''without consuming input''', this combinator
* will return all of the results, `x,,1,,` through `x,,n,,` (with `n >= 0`), in a list: `List(x,,1,,, .., x,,n,,)`.
* If `p` was never successful, the empty list is returned.
*
* @example {{{
* scala> import parsley.character.string
* scala> import parsley.Parsley.many
* scala> val p = many(string("ab"))
* scala> p.parse("")
* val res0 = Success(Nil)
* scala> p.parse("ab")
* val res1 = Success(List("ab"))
* scala> p.parse("abababab")
* val res2 = Success(List("ab", "ab", "ab", "ab"))
* scala> p.parse("aba")
* val res3 = Failure(..)
* }}}
*
* @param p the parser to execute multiple times.
* @return a parser that parses `p` until it fails, returning the list of all the successful results.
* @since 4.5.0
* @group iter
*/
def many[A](p: Parsley[A]): Parsley[List[A]] = many(p, List)
private [parsley] def many[A, C](p: Parsley[A], factory: Factory[A, C]): Parsley[C] = {
new Parsley(new frontend.Many(p.internal, factory))
}
/** This combinator repeatedly parses a given parser '''one''' or more times, collecting the results into a list.
*
* Parses a given parser, `p`, repeatedly until it fails. If `p` failed having consumed input,
* this combinator fails. Otherwise when `p` fails '''without consuming input''', this combinator
* will return all of the results, `x,,1,,` through `x,,n,,` (with `n >= 1`), in a list: `List(x,,1,,, .., x,,n,,)`.
* If `p` was not successful at least one time, this combinator fails.
*
* @example {{{
* scala> import parsley.character.string
* scala> import parsley.Parsley.some
* scala> val p = some(string("ab"))
* scala> p.parse("")
* val res0 = Failure(..)
* scala> p.parse("ab")
* val res1 = Success(List("ab"))
* scala> p.parse("abababab")
* val res2 = Success(List("ab", "ab", "ab", "ab"))
* scala> p.parse("aba")
* val res3 = Failure(..)
* }}}
*
* @param p the parser to execute multiple times.
* @return a parser that parses `p` until it fails, returning the list of all the successful results.
* @since 4.5.0
* @group iter
*/
def some[A](p: Parsley[A]): Parsley[List[A]] = p <::> many(p)
private [parsley] def some[A, C](p: Parsley[A], factory: Factory[A, C]): Parsley[C] = secretSome(p, p, factory)
// This could be generalised to be the new many, where many(p, factory) = secretSome(fresh(factory.newBuilder), p, factory)
private [parsley] def secretSome[A, C](init: Parsley[A], p: Parsley[A], factory: Factory[A, C]): Parsley[C] = {
secretSome(init.map(factory.newBuilder += _), p)
}
private [parsley] def secretSome[A, C](init: Parsley[mutable.Builder[A, C]], p: Parsley[A]): Parsley[C] = {
val pf = pure[(mutable.Builder[A, C], A) => mutable.Builder[A, C]](_ += _)
// Can't use the regular foldLeft1 here, because we need a fresh Builder each time.
expr.infix.secretLeft1(init, p, pf).map(_.result())
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy