Copy objects in scala but changing "children" for rewriting
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)
I use a modified version of the Kiama Rewriter
module. It adds a Constructable
trait that signifies that a value can deconstruct
itself (make an array holding its constituents / children) and reconstruct
a new instance from an array of constituents. When Kiama encounters a value that implements Constructable
in one of the methods dup
, child
, all
or some
, it avoids the reflective code and instead uses deconstruct
and construct
.
In addition to freeing the client code from the requirement that types amenable to rewriting be derived from Product
, it allows for a heterogeneous rewrite. In other words, the type coming out of a rewrite need not be precisely identical to the concrete type of the value that was rewritten.
The down-side is that the client code must define those deconstruct
and construct
methods.
(Lastly and not really germane to your question, I added an optimization that avoids building a new value if the result of transforming the sub-values (the non-atomic ones) were all equal to the original. I added this only in the branch that handles Constructable
s.)
I have created a small GitHub repository, RSchulz/sbtr, containing my modified Kiama Rewriter.scala
module. 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 started
Diff-ing the first two will disclose my modifications, which should be easily back-ported into the current Kiama Rewriter.scala
code.
The primary difference between the original and the 0.8 versions of the Rewriter.scala
source are the addition of queryf
, which I did carry over into SBTR
. 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).
精彩评论