In kiama a generic “dup” method is defined which copies Product objects and applies a given function to each of the elements of the Product in order to support rewriting of Terms:
/**
* General product duplication function. Returns a product that applies
* the same constructor as the product t, but with the given children
* instead of t's children. Fails if a constructor cannot be found or
* if one of the children is not of the appropriate type.
*/
private def dup (t : Product, children : Array[AnyRef]) : Product = {
val ctor = (t.getClass.getConstructors())(0)
try {
val ret = ctor.newInstance (children : _*).asInstanceOf[Product]
ret
} catch {
case e : java.lang.ClassCastException =>
error ("dup cast failed: " + t)
case e : IllegalArgumentException =>
error ("dup illegal arguments: " + ctor + " (" +
children.deep.mkString (",") + "), expects " +
ctor.getParameterTypes.length)
}
}
Used like this:
private def childProduct (p : Product, i : Int, s : => Strategy) : Option[Term] = {
val numchildren = p.productArity
val ct = p.productElement (i-1)
val children = new Array[AnyRef](numchildren)
for (j <- 0 until numchildren)
children (j) = makechild (p.productElement (j))
s (ct) match {
case Some (ti) =>
children (i-1) = makechild (ti)
case None =>
return None
}
val ret = dup (p, children)
Some (ret)
This gives some limitations on the usage.
I know they are working on replacing this mechanism (Issue 2, Issue 31) but I think it might be interesting in hearing how you guys would do this?
For example will the Positional var(or any other var!) of scala parser combinators not be copied. In fact everything not part of the explict first constructor (and thereby also the default compiler generated unapply method).
I have been experimenting with providing some kind of trait or similar I could add to my terms that the dup/childProduct/etc methods could use, but to no luck yet. (I don’t see how case class copy could be used)
I have created a small GitHub repository, RSchulz/sbtr, containing my modified Kiama
Rewriter.scalamodule. In it you will find these files:src/main/scala/rrs/sbtr/SBTR.scala— My “Strategy-Based Term Rewriting” modulesrc/main/scala/rrs/sbtr/RewriterFmt.alacs— The original code after formatting for my style conventionssrc/main/scala/rrs/sbtr/Rewriter-0.8.alacs— The slightly updated 0.8 versionsrc/main/scala/rrs/sbtr/Rewriter.alacs— The original version from which I startedDiff-ing the first two will disclose my modifications, which should be easily back-ported into the current Kiama
Rewriter.scalacode.The primary difference between the original and the 0.8 versions of the
Rewriter.scalasource are the addition ofqueryf, which I did carry over intoSBTR. Changes subsequent to 0.8 have not been incorporated.The suffix
.alacs(scala spelled backwards) is used to keep those files from being compiled. To my knowledge, build tools and IDEs cannot be directed to ignore specific files (at least not easily).