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 67e29cdc..086a9d0b 100644 --- a/shared/src/main/scala/scala/util/parsing/combinator/Parsers.scala +++ b/shared/src/main/scala/scala/util/parsing/combinator/Parsers.scala @@ -301,6 +301,16 @@ trait Parsers { (for(a <- this; b <- p) yield a).named("<~") } + /** + * A parser combinator for exceptions. + * + * `p - q` succeeds if `p` succeeds, and `q` fails on the same input given `p`. + * + * @param q a parser that will be executed before `p` (this parser). q will not consume the input. + * @return a `Parser` that returns the result of `p` (this parser) if it succeeds and q fails. If q succeeds, the parser will fail. + */ + def - [U](q: Parser[U]): Parser[T] = (not(q) ~> this).named("-") + /* 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) diff --git a/shared/src/test/scala/scala/util/parsing/combinator/t1229.scala b/shared/src/test/scala/scala/util/parsing/combinator/t1229.scala new file mode 100644 index 00000000..a4b06465 --- /dev/null +++ b/shared/src/test/scala/scala/util/parsing/combinator/t1229.scala @@ -0,0 +1,21 @@ +import scala.util.parsing.combinator.RegexParsers + +import org.junit.Test +import org.junit.Assert.assertEquals + +class t1229 extends RegexParsers { + val number = """0|[1-9]\d*""".r ^^ { _.toInt } + + val parser: Parser[Int] = number - "42" + + @Test + def test: Unit = { + assertEquals("[1.3] parsed: 21", parse(phrase(parser), "21").toString) + + val expected = """[1.1] failure: Expected failure + +42 +^""" + assertEquals(expected, parse(phrase(parser), "42").toString ) + } +}