From de63a2c4487bddcf9eeb5edef72813e2751feff5 Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Mon, 17 Jun 2013 12:06:13 -0400 Subject: [PATCH] SoftInvalid parser, which defers being invalid in order to preserve a failure message on empty input. --- .../src/main/scala/sbt/complete/Parser.scala | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/util/complete/src/main/scala/sbt/complete/Parser.scala b/util/complete/src/main/scala/sbt/complete/Parser.scala index 4ad4ded03..8a6081c14 100644 --- a/util/complete/src/main/scala/sbt/complete/Parser.scala +++ b/util/complete/src/main/scala/sbt/complete/Parser.scala @@ -257,6 +257,13 @@ trait ParserMain implicit def literalRichCharParser(c: Char): RichParser[Char] = richParser(c) implicit def literalRichStringParser(s: String): RichParser[String] = richParser(s) + /** Construct a parser that is valid, but has no valid result. This is used as a way + * to provide a definitive Failure when a parser doesn't match empty input. For example, + * in `softFailure(...) | p`, if `p` doesn't match the empty sequence, the failure will come + * from the Parser constructed by the `softFailure` method. */ + private[sbt] def softFailure(msg: => String, definitive: Boolean = false): Parser[Nothing] = + SoftInvalid( mkFailures(msg :: Nil, definitive) ) + def invalid(msgs: => Seq[String], definitive: Boolean = false): Parser[Nothing] = Invalid(mkFailures(msgs, definitive)) def failure(msg: => String, definitive: Boolean = false): Parser[Nothing] = invalid(msg :: Nil, definitive) def success[T](value: T): Parser[T] = new ValidParser[T] { @@ -441,6 +448,15 @@ private final case class Invalid(fail: Failure) extends Parser[Nothing] def ifValid[S](p: => Parser[S]): Parser[S] = this } +private final case class SoftInvalid(fail: Failure) extends ValidParser[Nothing] +{ + def result = None + def resultEmpty = fail + def derive(c: Char) = Invalid(fail) + def completions(level: Int) = Completions.nil + override def toString = fail.errors.mkString("; ") +} + private final class TrapAndFail[A](a: Parser[A]) extends ValidParser[A] { def result = try { a.result } catch { case e: Exception => None }