scala - Apply parser combinator to case class -


i'm looking @ using scala's parser combinators parse string (no newlines, contrived example).

the string made of many different parts want extract separately , populate case class.

case class myrecord(foo: string, bar: string, baz: string, bam: string, bat: string)  object myparser extends scala.util.parsing.combinator.regexparsers {    val foo: parser[string] = "foo"   val bar: parser[string] = "bar"   val baz: parser[string] = "baz"   val bam: parser[string] = "bam"   val bat: parser[string] = "bat"    val expression: parser[myrecord] =     foo ~ bar ~ baz ~ bam ~ bat ^^ {       case foo ~ bar ~ baz ~ bam ~ bat => myrecord(foo, bar, baz, bam, bat)     }  } 

this works well, there way apply parts of matched results directly case class without deconstructing?

val expression: parser[myrecord] =   foo ~ bar ~ baz ~ bam ~ bat ^^ myrecord 

further information: string i'm parsing quite long , complex (in reality, it's whole file full of long complex strings) changing regexp out of question.

it's possible shapeless2 library. given:

 object myparser extends scala.util.parsing.combinator.regexparsers     import myparser._        val foo: parser[string] = "foo"  val bar: parser[string] = "bar"  val car: parser[string] = "car"   case class record(f: string, b: string, c: string) 

you can combine parsers using generic foldright intead of ~:

 import shapeless._  object f extends poly2 {    implicit def parser[t, u <: hlist] =     at[parser[t], parser[u]]{(a, b) =>       {aa <- a; bb <- b} yield aa :: bb      }  }   val p: parser[record] = (foo :: bar :: car :: hnil)     .foldright(success(hnil))(f).map(generic[record].from) 

result:

 scala> parseall(p, "foo bar car").get  res50: record = record(foo,bar,car) 

p.s. problem built-in scala functionality built ~-based typed binary tree, hard traverse , flatten tuple. shapeless solves problem - has it's own ::-based binary tree called hlist, it's simmilar has interesting operations, convertion tuples or case classes (probably macro-based). in example use foldleft build shapeless-hlist , for-comprehension (expands flatmap on parser) combine parsers have monadic nature. in shapeless have define foldleft's handler set of generic implicits, can process generic input (like t or u).

you can reuse f object combine parsers in typesafe way (you can combine different types here - that's fine).


second, less generic, way is:

implicit class as2[a, b](t: parser[a ~ b]){ def ^^^^[t] (co: (a, b) => t) = t map {tt => val (a ~ b) = tt; co(a, b)} } implicit class as3[a, b, c](t: parser[a ~ b ~ c]){ def ^^^^[t] (co: (a, b, c) => t) = t map {tt => val (a ~ b ~ c) = tt; co(a, b, c)} } ... implicit class as21 ... 

usage:

scala> val p = foo ~ bar ~ car ^^^^ record p: myparser.parser[record] = parser ()  scala> parseall(p, "foo bar car").get res53: record = record(foo,bar,car) 

it's not cool, doesn't require external libraries.


Comments