EDIT: Solved, see "FIX" below
I am trying to setup a scala parser combinator to parse either a float or an integer depending on the complexity of the number. Here is what I have currently:
import scala.util.parsing.combinator.JavaTokenParsers
trait NumberLiteral
case class IntegerLiteral(i:Int) extends NumberLiteral
case class FloatLiteral(f:Float) extends NumberLiteral
class Parser extends JavaTokenParsers {
def integer:Parser[IntegerLiteral] = wholeNumber ^^ {i => new IntegerLiteral(i.toInt)}
def float:Parser[FloatLiteral] = floatingPointNumber ^^ {f => new FloatLiteral(f.toFloat)}
//FIX: def float:Parser[FloatLiteral] = """[+-]?[0-9]*((\.[0-9]+([eE][+-]?[0-9]+)?[fF]?)|([fF])|([eE][+-]?[0-9]+))\b""".r ^^ {f => new FloatLiteral(f.toFloat)}
def number:Parser[NumberLiteral] = integer | float;
//FIX: def number:Parser[NumberLiteral] = float | integer;
}
I set up scalatest to test both the integer and float parsers and they both work. Here is what my testing class looks like:
import org.scalatest._
class ParserSpec extends FlatSpec with Matchers {
val parser = new Parser()
"Parser" should "parse IntegerLiteral" in {
parser.parseAll(parser.integer, "0").get should equal (new IntegerLiteral(0))
parser.parseAll(parser.integer, "4").get should equal (new IntegerLiteral(4))
parser.parseAll(parser.integer, "4448338").get should equal (new IntegerLiteral(4448338))
parser.parseAll(parser.integer, "-33").get should equal (new IntegerLiteral(-33))
parser.parseAll(parser.integer, "-10101010").get should equal (new IntegerLiteral(-10101010))
parser.parseAll(parser.integer, "004").get should equal (new IntegerLiteral(4))
}
it should "parse FloatLiteral" in {
parser.parseAll(parser.float, "1.0").get should equal (new FloatLiteral(1.0f))
parser.parseAll(parser.float, "0").get should equal (new FloatLiteral(0))
parser.parseAll(parser.float, "32.3").get should equal (new FloatLiteral(32.3f))
parser.parseAll(parser.float, "3.4e3").get should equal (new FloatLiteral(3400))
parser.parseAll(parser.float, "-10").get should equal (new FloatLiteral(-10))
parser.parseAll(parser.float, "-4e-4").get should equal (new FloatLiteral(-0.0004f))
parser.parseAll(parser.float, "003.4").get should equal (new FloatLiteral(3.4f))
parser.parseAll(parser.float, "4f").get should equal (new FloatLiteral(4))
}
it should "parse NumberLiteral" in {
parser.parseAll(parser.number, "32").get should equal (new IntegerLiteral(32))
parser.parseAll(parser.number, "32.3").get should equal (new FloatLiteral(32.3f))
parser.parseAll(parser.number, "32f").get should equal (new FloatLiteral(32))
parser.parseAll(parser.number, "0.33").get should equal (new FloatLiteral(0.33f))
parser.parseAll(parser.number, "32e2").get should equal (new IntegerLiteral(3200))
parser.parseAll(parser.number, "0").get should equal (new IntegerLiteral(32))
parser.parseAll(parser.number, "32.3e1").get should equal (new IntegerLiteral(323))
}
}
Both the IntegerLiteral and FloatLiteral tests work perfectly. As you can see, I want to parse the number as either an IntegerLiteral or FloatLiteral depending on whether it can be parsed as an int or a float. The first line in the NumberLiteral test works however I get the following error on the second line: java.lang.RuntimeException: no result when parsing failed. I can't figure out why the parser is throwing this error as the float parser can parse 32.3. Am I doing something wrong in the number parser with the integer | float?