2

I'm writing extractor object for functions expressions. Here is how it looks like:

object FunctionTemplate2 {
  private final val pattern = Pattern.compile("^(.+?)\\((.+?)\\,(.+?)\\)")
  //e.g. foo(1, "str_arg")
  def unapply(functionCallExpression: String): Option[(String, String, String)] = {
      //parse expression and extract
  }
}

And I can extract as follows:

"foo(1, \"str_arg\")" match {
  case FunctionTemplate2("foo", first, second) =>
    println(s"$first,$second")
}

But this is not as cute as it could be. I would like to have something like that:

case FunctionTemplate2("foo")(first, second) =>
  println(s"$first,$second")

Like curried extractor. So I tried this:

case class Function2Extractor(fooName: String){
  private final val pattern = Pattern.compile("^(.+?)\\((.+?)\\,(.+?)\\)")
  println("creating")
  def unapply(functionCallExpression: String): Option[(String, String, String)] = 
    //parse and extract as before
}

But it did not work:

"foo(1, \"str_arg\")" match {
  case Function2Extractor("foo")(first, second) =>
    println(s"$first,$second")
}

Is there a way to do this in Scala?

Some Name
  • 6,872
  • 4
  • 9
  • 32
  • It looks as if you are trying to prettify the irrelevant parts right now. A much more severe problem would be that your current approach does not scale beyond anything but non-nested functions with string arguments that don't contain commas, like `foo("bar", "baz")` but not `foo(bar("baz","cov"),"fefe")` or `foo("bar, baz", "bus")`. You could of course attempt to [parse nested parentheses with regex](https://stackoverflow.com/questions/47162098), but I doubt that it will be easier than using a proper parser. – Andrey Tyukin Feb 28 '18 at 12:28
  • @AndreyTyukin As I can see it can scale to nested functions. If we parse it recursively and build parse tree. – Some Name Feb 28 '18 at 14:15

1 Answers1

1

You can simply it by using some utilities in Scala toolset

Notice how pattern is used in match case.

Scala REPL

scala> val pattern = "^(.+?)\\((.+?)\\,(.+?)\\)".r
pattern: scala.util.matching.Regex = ^(.+?)\((.+?)\,(.+?)\)

scala> "foo(1, \"str_arg\")" match  { case pattern(x, y, z) => println(s"$x $y $z")}
foo 1  "str_arg"
pamu
  • 14,066
  • 2
  • 14
  • 35
  • Don't understand how it can help. We still have the same `pattern(x, y, z)`, but not `pattern(x)(y, z)`. Can you expand? – Some Name Feb 28 '18 at 11:18
  • `pattern(x)(y, z)` cannot be done and it is because of how unapply works in Scala – pamu Feb 28 '18 at 11:19
  • Why can't we make `pattern(x)` to be something like `case class pattern(x){ def unapply(y, z) = //...}`. So we have extractor method... – Some Name Feb 28 '18 at 11:22
  • Pattern matching works by tuple comparison. `pattern(x)(y, z)` is percieved as passing x as parameters while case matching. clearly will be compilation error – pamu Feb 28 '18 at 11:28