diff --git a/main/command/BasicCommands.scala b/main/command/BasicCommands.scala index c0f435816..18fe40d90 100644 --- a/main/command/BasicCommands.scala +++ b/main/command/BasicCommands.scala @@ -169,7 +169,7 @@ object BasicCommands val name = token(OpOrID.examples( aliasNames(s) : _*) ) val assign = token(OptSpace ~ '=' ~ OptSpace) val sfree = removeAliases(s) - val to = matched(sfree.combinedParser, partial = true) | any.+.string + val to = matched(sfree.combinedParser, partial = true).failOnException | any.+.string val base = (OptSpace ~> (name ~ (assign ~> to.?).?).?) applyEffect(base)(t => runAlias(s, t) ) } diff --git a/sbt/src/sbt-test/actions/aliasrc/.sbtrc b/sbt/src/sbt-test/actions/aliasrc/.sbtrc new file mode 100644 index 000000000..3d7d3773e --- /dev/null +++ b/sbt/src/sbt-test/actions/aliasrc/.sbtrc @@ -0,0 +1 @@ +alias info= set logLevel := Level.Info diff --git a/sbt/src/sbt-test/actions/aliasrc/test b/sbt/src/sbt-test/actions/aliasrc/test new file mode 100644 index 000000000..2ae698547 --- /dev/null +++ b/sbt/src/sbt-test/actions/aliasrc/test @@ -0,0 +1 @@ +> info diff --git a/util/complete/Parser.scala b/util/complete/Parser.scala index 7f0fba5db..a10d1bdcb 100644 --- a/util/complete/Parser.scala +++ b/util/complete/Parser.scala @@ -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