Parser.failOnException method, don't let rhs of alias fail the parse. Fixes #572.

alias only parses the right hand side for tab completion help.
The assignment should happen whether or not the parse is successful because the
context may change by the time the alias is actually evaluated.
In particular, the 'set' command uses the loaded project for tab completion in 0.12.1.
When a .sbtrc file is processed, the project has not been loaded yet, so aliases
involving set fail.  Wrapping the rhs in failOnException addresses this.
This commit is contained in:
Mark Harrah 2012-10-15 12:42:27 -04:00
parent aee2742932
commit 1f88fe9d7c
1 changed files with 18 additions and 0 deletions

View File

@ -45,6 +45,9 @@ sealed trait RichParser[A]
/** Uses the specified message if the original Parser fails.*/
def !!!(msg: String): Parser[A]
/** If an exception is thrown by the original Parser,
* capture it and fail locally instead of allowing the exception to propagate up and terminate parsing.*/
def failOnException: Parser[A]
def unary_- : Parser[Unit]
def & (o: Parser[_]): Parser[A]
@ -173,6 +176,8 @@ object Parser extends ParserMain
def onFailure[T](delegate: Parser[T], msg: String): Parser[T] =
if(delegate.valid) new OnFailure(delegate, msg) else failure(msg)
def trapAndFail[T](delegate: Parser[T]): Parser[T] =
delegate.ifValid( new TrapAndFail(delegate) )
def zeroOrMore[T](p: Parser[T]): Parser[Seq[T]] = repeat(p, 0, Infinite)
def oneOrMore[T](p: Parser[T]): Parser[Seq[T]] = repeat(p, 1, Infinite)
@ -233,6 +238,7 @@ trait ParserMain
def <~[B](b: Parser[B]): Parser[A] = (a ~ b) map { case av ~ _ => av }
def ~>[B](b: Parser[B]): Parser[B] = (a ~ b) map { case _ ~ bv => bv }
def !!!(msg: String): Parser[A] = onFailure(a, msg)
def failOnException: Parser[A] = trapAndFail(a)
def unary_- = not(a)
def & (o: Parser[_]) = and(a, o)
@ -425,6 +431,18 @@ private final case class Invalid(fail: Failure) extends Parser[Nothing]
def valid = false
def ifValid[S](p: => Parser[S]): Parser[S] = this
}
private final class TrapAndFail[A](a: Parser[A]) extends ValidParser[A]
{
def result = try { a.result } catch { case e: Exception => None }
def resultEmpty = try { a.resultEmpty } catch { case e: Exception => fail(e) }
def derive(c: Char) = try { trapAndFail(a derive c) } catch { case e: Exception => Invalid(fail(e)) }
def completions(level: Int) = try { a.completions(level) } catch { case e: Exception => Completions.nil }
override def toString = "trap(" + a + ")"
override def isTokenStart = a.isTokenStart
private[this] def fail(e: Exception): Failure = mkFailure(e.toString)
}
private final class OnFailure[A](a: Parser[A], message: String) extends ValidParser[A]
{
def result = a.result