In Scala 2.10.0-RC1 there's a wonderful feature, the String Interpolation.
This works like this:
scala> val x = 1
x: Int = 1
scala> val y = s"Interpolated String $x"
y: String = Interpolated String 1
But I'm building a internal DSL with Scala, and therefore I need to handle with a sort of forward references. That you have in mind, what the DSL looks like (it's for documentation generation):
object Main {
§ > "Heading"
§ >> "Subheading"
++ txt """
Lorem ipsum Abb. ${Main.fig.number} dolor sit amet, consetetur sadipscing elitr, sed diam
nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,
sed diam voluptua.
"""
val fig =
++ figure(
src="https://...",
desc="example figure"
)
}
But the problem looks semantically like this:
object X {
val y = s"$x with reverse reference"
val x = 3
}
And this doesn't work, because of the virtually forward reference. I can write x as lazy val, but the compiler moves x and makes it for y available. But for my DSL design the order of y and x must be preserved!
So far my solution is a closure, like this:
object X {
val y = () => s"$x with reverse reference"
val x = 3
}
This allows me to invoke X.y() at the end, when all variables are available. But the disadvantage is, the "ugliness", no domain-user will understand this kind of magic!
The domain user must write something like this (but it works!):
++ txt (() => s"""
Lorem ipsum Abb. ${Main.fig.number} dolor sit amet, consetetur sadipscing elitr, sed diam
nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,
sed diam voluptua.
""")
So the idea is to move the closure magic into my DSL api, but therefore I need to pass "$x with reverse reference" as ordinary String and resolve this String at the end as StringContext (s"..."), which resolves the $-references. But so far I found nothing, how to cast this. In short how can I cast "foo $x bar to s"foo $x bar"?
What I found is, how to individualize StringContext, but don't know how I can use this for my problem:
scala> case class StringContext(parts: String*) {
| def rr (args: Any*) = scala.StringContext(parts: _*).s(args: _*)
| }
defined class StringContext
scala> rr"hi"
res3: String = hi
scala> rr"hi $s"
res4: String = hi 1
The other idea is a less "noisy" lambda notation, but how can I write something like (or similar) this:
++ txt => s"""... ${Main.fig.number} ..."""
Such a notation would be reasonable. I don't necessarily to write my own String parser with reference resolving. Anybody an sneaky idea?
The DSL api is semantically built like this:
object ++ {
def txt (s: String) = ...
}
yas lazy?lazy val y = s"$x with reverse reference"yas lazy val as @pagoda_5b said.§or++register them self into a list, and this must happen in the right order. Don't focus so much on this lazy-thing, especially because I want to avoid to much magic at the "frontend" for the domain users. :)