Skip to content

Instantly share code, notes, and snippets.

@pr1001
Created January 23, 2012 16:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pr1001/1664232 to your computer and use it in GitHub Desktop.
Save pr1001/1664232 to your computer and use it in GitHub Desktop.
How to get Enumeration values back when using Scala parser combinators.
// ISO 3166-1 alpha-2 two letter country codes from http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
object Country extends Enumeration {
val Andorra = Value("ad") // Andorra
val UAE = Value("ae") // United Arab Emirates
val Afghanistan = Value("af") // Afghanistan
// ...
}
trait CountryParser extends JavaTokenParsers {
// would love to get rid of the silly regex
lazy val country: Parser[Country.Value] = """\w+""".r ^? ({
// if lower-cased
case str if Country.values.exists((ctry) => ctry.toString == str) => Country.withName(str)
// if upper-cased
case str if Country.values.exists((ctry) => ctry.toString.toUpperCase == str) => Country.withName(str.toLowerCase)
}, "Unknown country code: " + _)
}
@pr1001
Copy link
Author

pr1001 commented Jan 23, 2012

It'd be awesome if someone could figure out a generic version. This is along the lines:

def enumParser[T <% Enumeration, V <% Enumeration#Value](enum: T): Parser[V] = """\w+""".r ^? ({
  // if lower-cased
  case str if enum.values.exists((value: V) => value.toString == str) => enum.withName(str)
  // if upper-cased
  case str if enum.values.exists((value: V) => value.toString.toUpperCase == str) => enum.withName(str.toLowerCase)
}, "Unknown code: " + _)

But it doesn't work:

[info] Compiling 1 Scala source to target/scala-2.9.1/classes...
amb prefix: _13.type#class ValueSet _9.type#class ValueSet
amb prefix: _13.type#class ValueSet _9.type#class ValueSet
amb prefix: _13.type#class ValueSet _9.type#class ValueSet
amb prefix: _13.type#class ValueSet _9.type#class ValueSet
[error] /Users/peter/Projects/Miogiro/Code/sms/src/main/scala/SMSParsers.scala:16: overloaded method value exists with alternatives:
[error]   (p: Enumeration#Value => Boolean)Boolean <and>
[error]   (p: Enumeration#Value => Boolean)Boolean <and>
[error]   (p: Enumeration#Value => Boolean)Boolean <and>
[error]   (pred: Enumeration#Value => Boolean)Boolean
[error]  cannot be applied to (V => Boolean)
[error]     case str if enum.values.exists((value: V) => value.toString == str) => enum.withName(str)
[error]                             ^
[error] one error found

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment