Search code examples
scalaparser-combinators

Scala parser gets stuck in infinite loop


I'm trying to write a simple parser in scala but when I add a repeated token Scala seems to get stuck in an infinite loop...

object RewriteRuleParsers extends RegexParsers {
  private def space = regex(new Regex("[ \\n]+"))
  private def number = regex(new Regex("[0-9]+")) 
  private def equals = (space?)~"="~(space?)
  private def word   = regex(new Regex("[a-zA-Z][a-zA-Z0-9-]*")) 
  private def string = regex(new Regex("[0-9]+")) >> { len => ":" ~> regex(new Regex(".{" + len + "}")) }  

  private def matchTokenPartContent: Parser[Any] = (space?)~word~equals~word<~ space?  
  private def matchTokenPart: Parser[Any] = ((space?) ~> "{" ~> matchTokenPartContent <~ "}"<~ space?)  
  private def matchTokenParts = (matchTokenPart *)  
  private def matchToken: Parser[Any] = ("[" ~> matchTokenParts ~ "]")

  def parseMatchToken(str: String): ParseResult[Any] = parse(matchToken, str)
}

and the code to call it

val parseResult = RewriteRuleParsers.parseMatchToken("[{tag=hello}]")

Any advice gratefull received


Solution

  • The problem is the precedence of ?. Take the following, for example:

    object simpleParser extends RegexParsers {
      val a = literal("a")
      val b = literal("b")
      def apply(s: String) = this.parseAll(a <~ b?, s)
    }
    

    The a <~ b? here is interpreted as (a <~ b)?, so it will accept "ab" or "", but not "a". We'd need to write a <~ (b?) if we want it to accept "a".

    In your case you can just parenthesize space? at the end of matchTokenPartContent and matchTokenPart and it'll work as expected.