HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Validation macro

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
macrovalidationstackoverflow

Problem

I would like a review of a Scala validation library I am writing. For now we can focus on the regular expression component.

  • The usage is described in RegexExample.scala



  • There is an outline of the interface in RegexRuntime.scala



  • But the macro and most of the craziness lives in RegexValidator.scala



The idea being, if compilation breaks spectacularly the user can change imports from the validated RegexValidator, to the unvalidated RegexRuntime. Like how you can switch between the mutable and immutable collections library. I'd be really interested better names if someone can come up with any.

Here is an abridged version of the macro code:

``
object RegexValidator {

implicit class RegexHelper(val sc: StringContext) extends AnyVal {
def r(args: Any*): Pattern = macro RegexHelperimpl
}

def RegexHelperimpl(c: Context)(args: c.Expr[Any]*): c.Expr[Pattern] = {
import c.universe._

c.prefix.tree match {
// access data of string interpolation
case Apply(_, List(Apply(_, rawParts))) =>

//
parts` contain the strings a string interpolation is built from
val parts = rawParts map { case t @ Literal(Constant(const: String)) => (const, t.pos) }

parts match {
// if there is only one string literal
case List((raw, pos)) => {

//compiletime validation here
try {
val p = Pattern.compile(raw)
} catch {
case ex: PatternSyntaxException => {

//fancyness with underlineing

//TODO: this seems a little iffy...
val rpos = pos.asInstanceOf[scala.reflect.internal.util.OffsetPosition]

//TODO: better class?
val outpos = new RangePosition(rpos.source, rpos.start + ex.getIndex, rpos.start + ex.getIndex, rpos.start + ex.getIndex)

c.error(outpos.asInstanceOf[c.universe.Position], ex.getDescription())
}

//... catch other er

Solution

I highly recommend using quasiquotes wherever possible - they make the macro much more readable/maintainable.

For debugging I found that the REPL was much more useful than my IDE, especially when I made heavy use of Context.abort commands to pinpoint errors. This also helps make the code somewhat self-documenting.

Context

StackExchange Code Review Q#93062, answer score: 2

Revisions (0)

No revisions yet.