sirthias / parboiled2

A macro-based PEG parser generator for Scala 2.10+
Other
717 stars 86 forks source link

valueMap does not backtrack correctly #136

Closed thesamet closed 7 years ago

thesamet commented 9 years ago

If the map contains two strings where one is a prefix of the other and valueMap tries the shorter one first, it will never backtrack and try the longer one. Example:

import org.parboiled2._
import scala.util._

class TestParser(val input: ParserInput) extends Parser {
  val values = Map("12" -> 12, "123" -> 123)

  def InputLine = rule {
    valueMap(values) ~ EOI
  }
}

object Hello extends App {
  val parser = new TestParser("123")
  parser.InputLine.run() match {
    case Success(x) => println(x)
    case Failure(e: ParseError) => sys.error(parser.formatError(e, new ErrorFormatter(showTraces = true)))
    case x => println(x)
  }
}

The expectation is to parse "123" successfully, but this example fails with:

java.lang.RuntimeException: Invalid input '3', expected 'EOI' (line 1, column 3):
123
  ^

As a side note, since the order we try the pairs in the map matters (even if backtracking worked), it would be nice to have a version that takes Seq[(String, T)]

sirthias commented 9 years ago

Yes, this is clearly a bug. Thanks for reporting!

sirthias commented 8 years ago

Just coming back to this: I don't think there is a clean fix that doesn't touch the API. I'd recommend using a ListMap for now, but ultimately allowing for a valueMap as in the current design is simply a bad idea. We'll have to remove the feature and replace it with one that takes a Seq[(String, T)] as you already recommended.