Apply parser combinator to case class

I am considering using Scala Parser Combinators to parse a string (without a new line, a far-fetched example).

The line consists of many different parts, which I want to extract separately and populate the 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 fine, but is there a way to apply parts of matching results directly to the case class without deconstructing?

val expression: Parser[MyRecord] =
  foo ~ bar ~ baz ~ bam ~ bat ^^ MyRecord

Additional Information: The line I am processing is quite long and complex (actually it is a whole file full of a long complex line), so a change in regexp is out of the question.

+4
source share
1 answer

Perhaps using Shapeless2 . For this:

 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)

, foldRight, ~:

 import shapeless._
 object f extends Poly2 { 
  implicit def parser[T, U <: HList] = 
   at[Parser[T], Parser[U]]{(a, b) => 
     for {aa <- a; bb <- b} yield aa :: bb  
   }
 }

 val p: Parser[Record] = (foo :: bar :: car :: HNil)
    .foldRight(success(HNil))(f).map(Generic[Record].from)

:

 scala> parseAll(p, "foo bar car").get
 res50: Record = Record(foo,bar,car)

P.S. scala , ~, . Shapeless - ::, HList, , , case (, ). foldLeft Shapeless-hlist - ( flatMap ) , . foldLeft , (, T U).

f, ( - ).


-, , :

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 ...

:

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)

, .

+5

All Articles