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)