LazyParsley

parsley.Parsley.LazyParsley
final implicit class LazyParsley[A](p: => Parsley[A])

This class enables the prefix ~ combinator, which allows a parser in an otherwise strict position to be made lazy.

Value parameters

p

the parser that ~ is enabled on.

Attributes

Constructor

This constructor should not be called manually, it is designed to be used via Scala's implicit resolution.

Since

4.0.0

Source
Parsley.scala
Graph
Supertypes
class Object
trait Matchable
class Any

Members list

Grouped members

special

def unary_~: Parsley[A]

This combinator makes a parser lazy.

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 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 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.

Attributes

Returns

the parser p, but guaranteed to be lazy.

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
Source
Parsley.scala