Skip to content

Commit

Permalink
Fixed bug where Chainl instruction did not wrap properly on failure
Browse files Browse the repository at this point in the history
  • Loading branch information
j-mie6 committed Jan 16, 2021
1 parent 6ccf3e4 commit e283670
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 5 deletions.
2 changes: 1 addition & 1 deletion src/main/scala/parsley/internal/instructions/Context.scala
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ private [parsley] final class Context(private [instructions] var instrs: Array[I
}*/

@tailrec @inline private [parsley] def runParser[A](): Result[A] = {
//println(this)
//println(pretty)
if (status eq Failed) Failure(errorMessage)
else if (pc < instrs.length) {
instrs(pc)(this)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,9 @@ private [internal] final class Chainl[A, B](var label: Int, _wrap: A => B) exten
else {
ctx.catchNoConsumed {
// if acc is null this is first entry, p already on the stack!
if (acc != null) ctx.stack.push(acc)
ctx.inc()
if (acc != null) ctx.pushAndContinue(acc)
// but p does need to be wrapped
else ctx.exchangeAndContinue(wrap(ctx.stack.upeek))
}
acc = null
}
Expand Down
21 changes: 19 additions & 2 deletions src/test/scala/parsley/ExpressionParserTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -161,11 +161,28 @@ class ExpressionParserTests extends ParsleyTest {
case class Num(x: Int) extends Atom
lazy val atom: Parsley[Atom] = digit.map(_.asDigit).map(Num) <|> ('(' *> expr.map(Parens) <* ')')
lazy val expr = precedence[Atom, Expr](atom,
GOps[Atom, Term](InfixR)('*' #> Mul.apply)(TermOf) +:
GOps[Term, Expr](InfixL)('+' #> Add.apply)(ExprOf) +:
GOps[Atom, Term](InfixR)('*' #> Mul)(TermOf) +:
GOps[Term, Expr](InfixL)('+' #> Add)(ExprOf) +:
Levels.empty[Expr])
expr.runParser("(7+8)*2+3+6*2") should be (Success(Add(Add(ExprOf(Mul(Parens(Add(ExprOf(TermOf(Num(7))), TermOf(Num(8)))), TermOf(Num(2)))), TermOf(Num(3))), Mul(Num(6), TermOf(Num(2))))))
}
they should "generalise to non-monolithic structures with most than one chainl1" in {
sealed trait Expr
case class Add(x: Expr, y: Term) extends Expr
case class ExprOf(x: Term) extends Expr
sealed trait Term
case class Mul(x: Term, y: Atom) extends Term
case class TermOf(x: Atom) extends Term
sealed trait Atom
case class Parens(x: Expr) extends Atom
case class Num(x: Int) extends Atom
lazy val atom: Parsley[Atom] = digit.map(_.asDigit).map(Num) <|> ('(' *> expr.map(Parens) <* ')')
lazy val expr = precedence[Atom, Expr](atom,
GOps[Atom, Term](InfixL)('*' #> Mul)(TermOf) +:
GOps[Term, Expr](InfixL)('+' #> Add)(ExprOf) +:
Levels.empty[Expr])
expr.runParser("1*(2+3)") shouldBe a [Success[_]]
}

"mixed expressions" should "also be parsable" in {
val lang = token.LanguageDef.plain.copy(
Expand Down

0 comments on commit e283670

Please sign in to comment.