ikryvorotenko
ikryvorotenko

Reputation: 1423

Not ordered parsers in Scala parser combinators

I need to parse the words in not ordered way. For now i can see that following

def first: Parser[String] = ???    
def second: Parser[String] = ???
def unordered = (first ~ second) | (second ~ first)

But i'm wondering if there's any native solution for that?

Upvotes: 2

Views: 176

Answers (2)

Enbugger
Enbugger

Reputation: 367

I achieved this by combining ~ and | parsers into custom parser named $

It looks similar to ~

trait ExtParsers extends JavaTokenParsers {
  def unordered[T,U](tp: Parser[T], tu: Parser[U]): Parser[$[T, U]] =
    tp ~ tu ^^ { case (x ~ y) => $(x, y) } | tu ~ tp ^^
      { case (x ~ y) => $(y, x) }

  case class $[+a, +b](_1: a, _2: b)

  implicit class ExtParser[+T](val parser: Parser[T]) {
    def $[U](tu: Parser[U]): Parser[$[T, U]] = unordered(parser, tu)
  }
}

object MyParser extends ExtParsers {
  def unord: Parser[String] =
    (ident $ stringLiteral $ wholeNumber $ floatingPointNumber) ^^ {
      case (id $ sl $ wn $ fpn) =>
      s"ident=$id string=$sl int=$wn float=$fpn"
    }
}

And passed test:

  @Test def test() {
    val expected = "ident=value string=\"test\" int=10 float=10.99"

    assertEquals(expected,
      MyParser.parseAll(MyParser.unord, "value \"test\" 10 10.99").get)

    assertEquals(expected,
      MyParser.parseAll(MyParser.unord,"\"test\" value  10 10.99").get)

    assertEquals(expected,
      MyParser.parseAll(MyParser.unord,"10 value \"test\" 10.99").get)
  }

Upvotes: 3

Joe K
Joe K

Reputation: 18424

The API isn't that big: https://static.javadoc.io/org.scala-lang.modules/scala-parser-combinators_2.12/1.0.6/scala/util/parsing/combinator/Parsers.html and https://static.javadoc.io/org.scala-lang.modules/scala-parser-combinators_2.12/1.0.6/scala/util/parsing/combinator/Parsers$Parser.html

Looking through this, it appears the answer is no, there is no way to do this more simply. This way doesn't seem bad at all, though.

Upvotes: 1

Related Questions