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 Term
s:
/**
* 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)