Search code examples
scalagrammardslparser-combinators

Scala external DSL - infinite loop caused by alternative repetitions


I am trying to build a simple external DSL in Scala that would be able to parse strings like:

value = "john${tom}peter${greg}${sue}meg"

In general, a substring within quotation marks contains interlaced names and names put between ${ and }.

My grammar is as following:

class Grammar extends JavaTokenParsers {
  def workflow = "value" ~> "=" ~> "\"" ~> pair <~ "\""

  def pair = rep(str | token)

  def str = rep(char)

  def char: Parser[String] = """[a-z]""".r

  def token = "$" ~> "{" ~> str <~ "}"
}

and executed by:

var res = parseAll(workflow, str)
println(res)

I thought that a method def pair = rep(str | token) would make it possible to parse it properly. Not only it doesn't work but also it leads to an infinite loop within parseAll method.

How can I parse such a string then? It seems that an alternative repetition (rep) is not the right approach.


Solution

  • You should replace rep with rep1.

    rep is always successful (unless it is an Error), so in rep(char) | token right part (token) is useless - you'll get an empty successful result of rep(char).

    Also, you could either replace """[a-z]""".r with accept('a' to 'z') or define str as def str: Parser[String] = """[a-z]+""".r. Usage of Regex to match a single Char is an overkill.