diff --git a/shared/src/main/scala/scala/util/parsing/combinator/PackratParsers.scala b/shared/src/main/scala/scala/util/parsing/combinator/PackratParsers.scala index 2d03df02..b04794e4 100644 --- a/shared/src/main/scala/scala/util/parsing/combinator/PackratParsers.scala +++ b/shared/src/main/scala/scala/util/parsing/combinator/PackratParsers.scala @@ -104,7 +104,7 @@ trait PackratParsers extends Parsers { override def phrase[T](p: Parser[T]): PackratParser[T] = { val q = super.phrase(p) new PackratParser[T] { - def apply(in: Input) = in match { + def parse(in: Input) = in match { case in: PackratReader[_] => q(in) case in => q(new PackratReader(in)) } @@ -231,7 +231,7 @@ to update each parser involved in the recursion. */ def memo[T](p: super.Parser[T]): PackratParser[T] = { new PackratParser[T] { - def apply(in: Input) = { + def parse(in: Input) = { /* * transformed reader */ diff --git a/shared/src/main/scala/scala/util/parsing/combinator/Parsers.scala b/shared/src/main/scala/scala/util/parsing/combinator/Parsers.scala index 737244ba..b3308b7b 100644 --- a/shared/src/main/scala/scala/util/parsing/combinator/Parsers.scala +++ b/shared/src/main/scala/scala/util/parsing/combinator/Parsers.scala @@ -13,6 +13,7 @@ package scala package util.parsing.combinator +import scala.util.DynamicVariable import scala.util.parsing.input._ import scala.collection.mutable.ListBuffer import scala.annotation.tailrec @@ -221,7 +222,7 @@ trait Parsers { } def Parser[T](f: Input => ParseResult[T]): Parser[T] - = new Parser[T]{ def apply(in: Input) = f(in) } + = new Parser[T]{ def parse(in: Input) = f(in) } private[combinator] def Success[U](res: U, next: Input, failure: Option[Failure]): ParseResult[U] = new Success(res, next) { override val lastFailure: Option[Failure] = failure } @@ -236,8 +237,27 @@ trait Parsers { case _ => None } + val skipParser: DynamicVariable[Option[Parser[Any]]] = new DynamicVariable(None); + + final def skip(in: Input): Input = { + skipParser.value match { + case None => in + case Some(parser) => { + skipParser.withValue(None) { + parser(in) match { + case Success(_,next) => { + next + } + // A parser whose purpose is to skip shouldn't fail; it should just not skip stuff + case _ => in + } + } + } + } + } + def OnceParser[T](f: Input => ParseResult[T]): Parser[T] with OnceParser[T] - = new Parser[T] with OnceParser[T] { def apply(in: Input) = f(in) } + = new Parser[T] with OnceParser[T] { def parse(in: Input) = f(in) } /** The root class of parsers. * Parsers are functions from the Input type to ParseResult. @@ -248,7 +268,10 @@ trait Parsers { override def toString = s"Parser ($name)" /** An unspecified method that defines the behaviour of this parser. */ - def apply(in: Input): ParseResult[T] + def parse(in: Input): ParseResult[T] + def apply(in: Input): ParseResult[T] = { + parse(skip(in)) + } def flatMap[U](f: T => Parser[U]): Parser[U] = Parser{ in => this(in) flatMapWithNext(f)} @@ -268,6 +291,20 @@ trait Parsers { Parser{ in => this(in) append p(in)} } + /** A parser combinator that changes skipping behavior + */ + def << (toSkip: => Option[Parser[Any]]): Parser[T] = { + val originalParse: Input => ParseResult[T] = parse + new Parser[T] { + override def apply(in: Input): ParseResult[T] = { + skipParser.withValue(toSkip) { + parse(skip(in)) + } + } + def parse(in: Input): ParseResult[T] = originalParse(in) + }.named(name) + } + // the operator formerly known as +++, ++, &, but now, behold the venerable ~ // it's short, light (looks like whitespace), has few overloaded meaning (thanks to the recent change from ~ to unary_~) // and we love it! (or do we like `,` better?) @@ -324,7 +361,7 @@ trait Parsers { /* not really useful: V cannot be inferred because Parser is covariant in first type parameter (V is always trivially Nothing) def ~~ [U, V](q: => Parser[U])(implicit combine: (T, U) => V): Parser[V] = new Parser[V] { - def apply(in: Input) = seq(Parser.this, q)((x, y) => combine(x,y))(in) + def parse(in: Input) = seq(Parser.this, q)((x, y) => combine(x,y))(in) } */ /** A parser combinator for non-back-tracking sequential composition. @@ -391,7 +428,7 @@ trait Parsers { */ def ||| [U >: T](q0: => Parser[U]): Parser[U] = new Parser[U] { lazy val q = q0 // lazy argument - def apply(in: Input) = { + def parse(in: Input) = { val res1 = Parser.this(in) val res2 = q(in) @@ -427,7 +464,7 @@ trait Parsers { */ def ^^^ [U](v: => U): Parser[U] = new Parser[U] { lazy val v0 = v // lazy argument - def apply(in: Input) = Parser.this(in) map (x => v0) + def parse(in: Input) = Parser.this(in) map (x => v0) }.named(toString+"^^^") /** A parser combinator for partial function application. @@ -769,18 +806,18 @@ trait Parsers { def continue(in: Input, failure: Option[Failure]): ParseResult[List[T]] = { val p0 = p // avoid repeatedly re-evaluating by-name parser - @tailrec def applyp(in0: Input, failure: Option[Failure]): ParseResult[List[T]] = p0(in0) match { + @tailrec def parsep(in0: Input, failure: Option[Failure]): ParseResult[List[T]] = p0(in0) match { case s @ Success(x, rest) => val selectedFailure = selectLastFailure(s.lastFailure, failure) elems += x - applyp(rest, selectedFailure) + parsep(rest, selectedFailure) case e @ Error(_, _) => e // still have to propagate error case f: Failure => val selectedFailure = selectLastFailure(failure, Some(f)) Success(elems.toList, in0, selectedFailure) } - applyp(in, failure) + parsep(in, failure) } first(in) match { @@ -804,14 +841,14 @@ trait Parsers { val elems = new ListBuffer[T] val p0 = p // avoid repeatedly re-evaluating by-name parser - @tailrec def applyp(in0: Input, failure: Option[Failure]): ParseResult[List[T]] = + @tailrec def parsep(in0: Input, failure: Option[Failure]): ParseResult[List[T]] = if (elems.length == num) Success(elems.toList, in0, failure) else p0(in0) match { - case s @ Success(x, rest) => elems += x ; applyp(rest, s.lastFailure) + case s @ Success(x, rest) => elems += x ; parsep(rest, s.lastFailure) case ns: NoSuccess => ns } - applyp(in, None) + parsep(in, None) } /** A parser generator for a specified range of repetitions interleaved by a @@ -835,13 +872,13 @@ trait Parsers { def continue(in: Input): ParseResult[List[T]] = { val p0 = sep ~> p // avoid repeatedly re-evaluating by-name parser - @tailrec def applyp(in0: Input): ParseResult[List[T]] = p0(in0) match { - case Success(x, rest) => elems += x; if (elems.length == m) Success(elems.toList, rest, None) else applyp(rest) + @tailrec def parsep(in0: Input): ParseResult[List[T]] = p0(in0) match { + case Success(x, rest) => elems += x; if (elems.length == m) Success(elems.toList, rest, None) else parsep(rest) case e @ Error(_, _) => e // still have to propagate error case _ => Success(elems.toList, in0, None) } - applyp(in) + parsep(in) } mandatory(in) match { @@ -973,7 +1010,7 @@ trait Parsers { * if `p` consumed all the input. */ def phrase[T](p: Parser[T]) = new Parser[T] { - def apply(in: Input) = p(in) match { + def parse(in: Input) = p(in) match { case s @ Success(out, in1) => if (in1.atEnd) s else s.lastFailure match { diff --git a/shared/src/main/scala/scala/util/parsing/combinator/RegexParsers.scala b/shared/src/main/scala/scala/util/parsing/combinator/RegexParsers.scala index 25c959a3..6f110e19 100644 --- a/shared/src/main/scala/scala/util/parsing/combinator/RegexParsers.scala +++ b/shared/src/main/scala/scala/util/parsing/combinator/RegexParsers.scala @@ -48,7 +48,7 @@ import scala.language.implicitConversions * } * } * - * def apply(input: String): Double = parseAll(expr, input) match { + * def parse(input: String): Double = parseAll(expr, input) match { * case Success(result, _) => result * case failure : NoSuccess => scala.sys.error(failure.msg) * } @@ -83,7 +83,7 @@ trait RegexParsers extends Parsers { /** A parser that matches a literal string */ implicit def literal(s: String): Parser[String] = new Parser[String] { - def apply(in: Input) = { + def parse(in: Input) = { val source = in.source val offset = in.offset val start = handleWhiteSpace(source, offset) @@ -104,7 +104,7 @@ trait RegexParsers extends Parsers { /** A parser that matches a regex string */ implicit def regex(r: Regex): Parser[String] = new Parser[String] { - def apply(in: Input) = { + def parse(in: Input) = { val source = in.source val offset = in.offset val start = handleWhiteSpace(source, offset) @@ -131,7 +131,7 @@ trait RegexParsers extends Parsers { override def positioned[T <: Positional](p: => Parser[T]): Parser[T] = { val pp = super.positioned(p) new Parser[T] { - def apply(in: Input) = { + def parse(in: Input) = { val offset = in.offset val start = handleWhiteSpace(in.source, offset) pp(in.drop (start - offset)) @@ -141,7 +141,7 @@ trait RegexParsers extends Parsers { // we might want to make it public/protected in a future version private def ws[T](p: Parser[T]): Parser[T] = new Parser[T] { - def apply(in: Input) = { + def parse(in: Input) = { val offset = in.offset val start = handleWhiteSpace(in.source, offset) p(in.drop (start - offset)) diff --git a/shared/src/main/scala/scala/util/parsing/combinator/lexical/Scanners.scala b/shared/src/main/scala/scala/util/parsing/combinator/lexical/Scanners.scala index d86b00f6..c447f6e1 100644 --- a/shared/src/main/scala/scala/util/parsing/combinator/lexical/Scanners.scala +++ b/shared/src/main/scala/scala/util/parsing/combinator/lexical/Scanners.scala @@ -32,9 +32,6 @@ trait Scanners extends Parsers { /** A parser that produces a token (from a stream of characters). */ def token: Parser[Token] - /** A parser for white-space -- its result will be discarded. */ - def whitespace: Parser[Any] - /** `Scanner` is essentially¹ a parser that produces `Token`s * from a stream of characters. The tokens it produces are typically * passed to parsers in `TokenParsers`. @@ -44,21 +41,18 @@ trait Scanners extends Parsers { class Scanner(in: Reader[Char]) extends Reader[Token] { /** Convenience constructor (makes a character reader out of the given string) */ def this(in: String) = this(new CharArrayReader(in.toCharArray)) - private val (tok, rest1, rest2) = whitespace(in) match { - case Success(_, in1) => - token(in1) match { - case Success(tok, in2) => (tok, in1, in2) - case ns: NoSuccess => (errorToken(ns.msg), ns.next, skip(ns.next)) - } - case ns: NoSuccess => (errorToken(ns.msg), ns.next, skip(ns.next)) + private val in1 = skip(in) + private val (tok, rest1, rest2) = token(in1) match { + case Success(tok, in2) => (tok, in1, in2) + case ns: NoSuccess => (errorToken(ns.msg), ns.next, skipChar(ns.next)) } - private def skip(in: Reader[Char]) = if (in.atEnd) in else in.rest + private def skipChar(in: Reader[Char]) = if (in.atEnd) in else in.rest override def source: java.lang.CharSequence = in.source override def offset: Int = in.offset def first = tok def rest = new Scanner(rest2) def pos = rest1.pos - def atEnd = in.atEnd || (whitespace(in) match { case Success(_, in1) => in1.atEnd case _ => false }) + def atEnd = in.atEnd || skip(in).atEnd } }