I’ve been having an issue getting the scala combinator parsers (specifically the RegexParsers via JavaTokenParsers) deciding between ints and floats. I must be missing something really basic here, since I can’t seem to find any mention of this particular issue anywhere. I’ve included a spec with the parser code in question (minus includes, of course).
@RunWith(classOf[JUnitRunner])
class SandboxSpec extends FlatSpec with ShouldMatchersForJUnit {
sealed trait PropertyValue
case class IntValue(value: Int) extends PropertyValue
case class RealValue(value: Float) extends PropertyValue
class Parser extends JavaTokenParsers {
def propertyLiteral : Parser[PropertyValue] = intValue | realValue
def realValue = floatingPointNumber ^^ {
s => RealValue(s.toFloat)
}
def intValue = wholeNumber ^^ {
s => IntValue(s.toInt)
}
}
"A java token parser" should "parse a float" in {
val p = new Parser()
val result = p.parseAll(p.propertyLiteral, "5.4") match {
case p.Success(x, _) => x
case p.NoSuccess(msg, _) => fail(msg)
}
result should be(RealValue(5.4f))
}
}
This fails with the following error message:
string matching regex `\z' expected but `.' found
One thought, based this thread, I placed a <~ not(not('.')) after the wholeNumber, but this didn’t seem to resolve the issue.
You are almost there – the only thing you need to change is
not(not('.'))tonot('.'). Why?The problem is that
intValuealways consumes the part before the dot. If you now writex ~ '.'you check if a dot follows and consume it together with the part before the dot. But you want to consume when a dot does not follow, thus you have to writex ~ not('.').When you write
x ~ not(not('.'))you have a double negation which is identical to no negation. The only difference here is that such a double negation allows you to lookup the next input without consuming it. That is because on a failure the input is not consumed in order to allow the following parser to parse it again. With a double failure you neither consume anything, but achieve the already mentioned lookup.