Search code examples
scalaparser-combinators

Scala - combinator parser incorrect - repsep


I am trying to create a simple parser as below. However, I am not sure why combinator parser is complaining on not recognizing 'floatingPointNumber' when there are 'dates' format. It recognizes when it is 'ident'

Below is the code with error.

Many thanks for help!

import scala.util.parsing.combinator.JavaTokenParsers

class MyParser extends JavaTokenParsers {
  def dates = repsep(date, ";")
  def date = """\d{2}-[a-zA-Z]{3}-\d{4}""".r
  def value = ident | dates | date | floatingPointNumber
  def obj = "("~>repsep(value,",")<~")"
}
object MyParser extends MyParser { 
  def main(args: Array[String]): Unit = {   
    println(parseAll(obj, "(22-Jan-2016;09-Mar-2015)"))
    println(parseAll(obj, "(22-Jan-2016;09-Mar-2015,blah3)"))
    println(parseAll(obj, "(22-Jan-2016;09-Mar-2015,32)"))
  }
}

[1.26] parsed: List(List(22-Jan-2016, 09-Mar-2015))
[1.32] parsed: List(List(22-Jan-2016, 09-Mar-2015), blah3)
[1.26] failure: `)' expected but `3' found
(22-Jan-2016;09-Mar-2015,32)
                         ^

Solution

  • Assuming you want at least one date to be present in dates, using

    def dates = rep1sep(date, ";")
    

    seems to fix the problem.

    I believe the reason is that the dates parser is able to accept an empty string (i.e. "" would parse as Nil), and that causes the floatingPointNumber part of the value parser to never be evaluated. If you change dates so it cannot accept an empty input, the parse succeeds:

    def fixedDates = rep1sep(date, ";")
    def fixedValue = ident | fixedDates | date | floatingPointNumber
    def fixedObj = "("~>repsep(fixedValue,",")<~")"
    
    parseAll(fixedObj, "(22-Jan-2016;09-Mar-2015,32)")
    // MyParser.ParseResult[List[Object]] = 
    // [1.29] parsed: List(List(22-Jan-2016, 09-Mar-2015), 32)