Parser

trait Parser[Token, +A]

Parses a sequence of Token into an A.

The companion object provides standard parsers from which to start building larger ones. In particular, it contains the necessary tools to start writing a string parser, such as char and string.

In order to provide better error messages, developers are encouraged to use label to describe the kind of thing a parser will produce - a digit, for example, or an array, or...

An important thing to realise is that parsers are non-backtracking by default. See the | documentation for detailed information on the consequences of this design choice.

Companion:
object
class Object
trait Matchable
class Any

Value members

Concrete methods

def *>[B](p2: Parser[Token, B]): Parser[Token, B]
def <*[B](p2: Parser[Token, B]): Parser[Token, A]
def ?: Parser[Token, Option[A]]
def as[B](b: B): Parser[Token, B]
def backtrack: Parser[Token, A]
def between[Left, Right](left: Parser[Token, Left], right: Parser[Token, Right]): Parser[Token, A]
def collect[B](f: PartialFunction[A, B]): Parser[Token, B]

A filter and a map rolled into one.

A filter and a map rolled into one.

For similar reasons to filter, such parsers are backtracking. Consider the following example:

val parser = digit.collect {
 case c if c != '9' => c.toInt
} | char('9').as(9)

parser.run("9")

If collect didn't turn the parser backtracking, this would fail, even though 9 is valid input: digit would succeed and consume the 9, then collect would fail the parser with a consuming result - char('9') would not even be attempted.

def filter(f: A => Boolean): Parser[Token, A]

Fails any parser that does not match the specified predicate.

Fails any parser that does not match the specified predicate.

Note that such parsers are, of necessity, backtracking. Consider the following admitedly silly example:

val parser = digit.filter(_ != '9') | char('9')
parser.run("9")

If filter didn't turn digit backtracking, then this parser would fail, even though 9 is perfectly valid input for it. digit would succeed and consume the 9, then filter would fail the parser with a consuming result - char('9') would not even be attempted.

def filterNot(f: A => Boolean): Parser[Token, A]
def flatMap[B](f: A => Parser[Token, B]): Parser[Token, B]
def label(label: String): Parser[Token, A]

Sets the label of this parser.

Sets the label of this parser.

A parser's label is a simple description of what they're expecting to parse. Typically, a parser who means to parse a "true / false" value would have a boolean label.

This allows us to provide meaningful error messages, where instead of saying "expected [, { or true", we can have "expected array, object or boolean".

def map[B](f: A => B): Parser[Token, B]
def rep: Parser[Token, Seq[A]]
def rep0: Parser[Token, Seq[A]]
def repSep[Sep](sep: Parser[Token, Sep]): Parser[Token, Seq[A]]
def repSep0[Sep](sep: Parser[Token, Sep]): Parser[Token, Seq[A]]
def run[Source](input: Source)(implicit at: AsTokens[Source, Token], sm: SourceMap[Token]): Result[Token, A]
def surroundedBy[B](p: Parser[Token, B]): Parser[Token, A]
def withPosition: Parser[Token, Parsed[A]]
def |[AA >: A](p2: => Parser[Token, AA]): Parser[Token, AA]

Attempts either this parser or the specified one.

Attempts either this parser or the specified one.

Note that this is non-backtracking: the alternative parser will only be tried if this parser is non-consuming.

Consider the following example:

val parser =  string("foo") | string("bar")
parser.run("foa")

It's perfectly impossible for bar to be a valid match here, and we know that as soon as we've started successfuly parsing foo. A non-backtracking parser will not attempt bar, which yields:

  • performance improvement (we're not trying parses that we know will fail).
  • better error messages (the error isn't that we were expecting foo or bar, but that we were parsing foo and found an a where we expected an o).

It is sometimes necessary to override that behaviour. Take the following example:

val parser = string("foo") | string("foa")
parser.run("foa")

We want this to succeed, but since string("foo") is non-backtracking, string("foa") will not be attempted. In these scenarios, calling backtrack on string("foo") allows parser to attempt string("foa")

Finally, consider the following:

val parser = string("foo").backtrack | string("bar")
parser.run("bar")

This will succeed: non-consuming successes will still result in the alternative parser being attempted, to try and find the first result that actually consumes data.

def ~[B](p2: Parser[Token, B]): Parser[Token, (A, B)]