2

In my DSL I want to be able to do like this:

val a = 5

Parse("TYPE") {
  a match {
    case 3 => info("almost")
    case s: String => error("wrong type")
    case 5 => info("you won!")
    case _ => error("omg")
  }
}

with output

[INFO] TYPE: you won!

where Parse is a function object, which has the apply(String), info(String) and error(String) methods:

object Parse {

  def apply(name: String)(parseF: => Unit) { parseF }
  def info(text: String) { println("[INFO] " + name + ": " + text) }
  def error(text: String) { println("[ERROR] " + name + ": " + text) }

}

The trick is that the output of the info and error methods should be somehow native to the Parse object and construct the message by the example as shown above. Therefore, they

  1. have to be accessible like in the example, without any imports.
  2. have to have the access to the first argument passed to Parse() ("TYPE" in the example).
  3. must not create any instances or extra objects during their working.

This is an ideal description. I think that it will require some more boilerplate. Please suggest, how can I acheive that?

EDIT: my initial guess to declare the info and error methods inside the apply method does not make them visible in the parseF method being passed. Well, unsurprisingly..

2 Answers 2

2

Maybe something like this:

object Parse {
  val currentName = new util.DynamicVariable("<none>")
  def apply(name: String)(parseF: => Unit) = currentName.withValue(name)(parseF)
  def info(text: String) = println("[INFO] %s: %s" format (currentName.value, text)
}

// usage
import Parse._ // there's no other way to get ability to call 'info' without 'Parse'.
Parse("TYPE") {
  // some code
  info("some info") // prints: [INFO] TYPE: some info
}

info("some other info") // prints: [INFO] <none>: some other info

If needed, it's easy to make info throw exception if it is called outside Parse {} block.

Sign up to request clarification or add additional context in comments.

Comments

1

There is no solution that satisfies 1-3. You can have 1 and 2 or 2 and 3 with slightly different syntax.

1 and 2)

class Parse(val s:String) {
  def info....

}

new Parse("TYPE") {

}

2 and 3)

object Parse {
  def apply(s:String)(f:String=>Unit) = ...
}

Parse("TYPE")(s => {

})

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.