2

Is there a cleaner way to map a string to an Enumeration value in a parser combinator?

object Mode extends Enumeration {
  type Mode = Value
  val View, Add, Modify, Delete  = Value
}

import Mode._

object ModeParser extends JavaTokenParsers {
  def mode: Parser[Mode] = ("^(" + Mode.values.mkString("|") + ")$").r ^^ { 
    Mode.withName(_) 
  }
}

2 Answers 2

2

Parsers are composable, so as soon as you can build a parser reading one Mode.Value, you may compose all such variants with | :

object ModeParser extends JavaTokenParsers {
  val mode: Parser[Mode.Value] = Mode.values.toList map{m =>
    literal(m.toString) ^^^ m
  } reduceLeft {_ | _}
}

You would use it like so:

scala> ModeParser.parseAll(ModeParser.mode, "Viewx")
Sign up to request clarification or add additional context in comments.

4 Comments

A reduceLeft solution is what I was trying to experiment with but couldn't find. Thanks, I'll try that out!
literal(m.toString) allows both "Viewx" and "xView" to parse successfully. Changing it to use phrase(m.toString) instead fixes that.
I assumed you would use it as ModeParser.parseAll(ModeParser.mode, "Viewx"), just like the answer from @senia suggests
I wanted to test it first in isolation and then combine it with other parsers. I found that when I do mode ~ anotherParser then I have to use literal instead. So I've supported both usages by defining a modeLiteral parser using your solution and changed mine to call phrase(modeLiteral).
0

You could use ^? method to convert ident parser to mode parser:

object ModeParser extends JavaTokenParsers {
  val modes = Mode.values.map{v => v.toString -> v}.toMap
  def mode: Parser[Mode.Value] = ident ^? ( 
    { case s if modes.contains(s) => modes(s) },
    s => s"Mode expected, but '$s' found."
  )
}

Usage:

scala> ModeParser.parseAll(ModeParser.mode, "Modify")
res0: ModeParser.ParseResult[Mode.Value] = [1.7] parsed: Modify

scala> ModeParser.parseAll(ModeParser.mode, "modify")
res1: ModeParser.ParseResult[Mode.Value] =
[1.7] failure: Mode expected, but 'modify' found.

modify
      ^

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.