From 6ee1688745eb2a90221b67646f1a2effacb126d6 Mon Sep 17 00:00:00 2001 From: Philippus Date: Wed, 15 Aug 2018 19:25:05 +0200 Subject: [PATCH] Favour `p` to `q` in `|||` parser if consuming same #chars, fixes #72 --- .../util/parsing/combinator/Parsers.scala | 5 ++-- .../scala/util/parsing/combinator/gh72.scala | 28 +++++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 shared/src/test/scala/scala/util/parsing/combinator/gh72.scala 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 4783afea..8812eaac 100644 --- a/shared/src/main/scala/scala/util/parsing/combinator/Parsers.scala +++ b/shared/src/main/scala/scala/util/parsing/combinator/Parsers.scala @@ -365,7 +365,6 @@ trait Parsers { */ def | [U >: T](q: => Parser[U]): Parser[U] = append(q).named("|") - // TODO /** A parser combinator for alternative with longest match composition. * * `p ||| q` succeeds if `p` succeeds or `q` succeeds. @@ -382,11 +381,11 @@ trait Parsers { val res2 = q(in) (res1, res2) match { - case (s1 @ Success(_, next1), s2 @ Success(_, next2)) => if (next2.pos < next1.pos) s1 else s2 + case (s1 @ Success(_, next1), s2 @ Success(_, next2)) => if (next2.pos < next1.pos || next2.pos == next1.pos) s1 else s2 case (s1 @ Success(_, _), _) => s1 case (_, s2 @ Success(_, _)) => s2 case (e1 @ Error(_, _), _) => e1 - case (f1 @ Failure(_, next1), ns2 @ NoSuccess(_, next2)) => if (next2.pos < next1.pos) f1 else ns2 + case (f1 @ Failure(_, next1), ns2 @ NoSuccess(_, next2)) => if (next2.pos < next1.pos || next2.pos == next1.pos) f1 else ns2 } } override def toString = "|||" diff --git a/shared/src/test/scala/scala/util/parsing/combinator/gh72.scala b/shared/src/test/scala/scala/util/parsing/combinator/gh72.scala new file mode 100644 index 00000000..306fb331 --- /dev/null +++ b/shared/src/test/scala/scala/util/parsing/combinator/gh72.scala @@ -0,0 +1,28 @@ +import scala.util.parsing.combinator.Parsers +import scala.util.parsing.input.CharSequenceReader + +import org.junit.Test +import org.junit.Assert.assertEquals + +class gh72 { + class TestParsers extends Parsers { + type Elem = Char + val left: Parser[String] = 'a' ~ 'b' ~ 'c' ^^^ "left" withFailureMessage "failure on left" + val right: Parser[String] = 'a' ~ 'b' ~ 'c' ^^^ "right" withFailureMessage "failure on right" + def p: Parser[String] = left ||| right + } + + @Test + def test(): Unit = { + val tstParsers = new TestParsers + val s = new CharSequenceReader("abc") + assertEquals("[1.4] parsed: left", tstParsers.p(s).toString) + + val t = new CharSequenceReader("def") + val expectedFailure = """[1.1] failure: failure on left + +def +^""" + assertEquals(expectedFailure, tstParsers.p(t).toString) + } +}