| code |
// there are all those other files that I don't include, ask me for a tarball
trait NewMatchers requires (Trees with Typers with Reds with NewMatchers) {
def newtranslate(e: Tree): Tree = e match {
case PatternMatch(scrut,cases) =>
val pm = new NewMatcher();
pm.compile(scrut.tpe, cases);
pm.toTree(scrut)
}
class NewMatcher() {
// fresh names
var fcount = 0;
def fresh(prefix:String) = {
val i = fcount;
fcount = fcount + 1;
prefix+"$"+i.toString();
}
var lcount = 1;
def freshLabel = {
val i = lcount;
lcount = lcount + 1
i
}
abstract class Node{}
class Test(var tpe: Type, var casted:Ident) extends Node {
var thenp: Node = _
def this(tpe: Type, name: String) = this(tpe, Ident(name) setType tpe)
var vbles = List[String]();
def bindTo(vble:String): this.type = { vbles = vble::vbles; this }
override def toString() = tpe.name+"?"
}
class Load(var expr: Tree) extends Node {
def tpe = expr.tpe;
var thenp: PatNodeList = Snil
}
case class Return(b:Tree) extends Node {}
abstract class PatNodeList {};
case class Snoc(sx:PatNodeList, x:Test) extends PatNodeList;
case object Snil extends PatNodeList;
var root:Test = _;
def compile(etpe: Type, cases:List[Pair[Pattern,Tree]]) = {
this.root = new Test(etpe, fresh("y"))
root.thenp = new Load(root.casted)
val it = cases.elements
while(it.hasNext) {
val cse = it.next;
val target = enter(cse._1, -1, root, root.casted)
if(target.thenp == null)
target.thenp = Return(cse._2)
else
error("duplicate case");
}
}
//
def addToList(sx: PatNodeList, q: Test): Pair[Test,PatNodeList] =
sx match {
case Snil =>
Pair(q, Snoc(Snil, q))
case Snoc(sy, y) =>
if(same(q,y)) {
y.vbles = y.vbles ::: q.vbles
Pair(y, sx)
} else if (overlaps(y,q)) {
Pair(q, Snoc(sx, q))
} else {
addToList(sy, q) match {
case Pair(q1, sy1) =>
Pair(q1, Snoc(sy1, y))
}
}
}
// invariant (index == -1) iff (child == null)
// casted should be a symbol, really
def enter(p:Pattern, index: Int, target:Test, casted: Ident): Test = {
//Console.println("NEW enter("+p+","+index+","+target+","+casted+")")
//Console.println("patArgs = "+patArgs)
target.thenp match {
case null =>
assert(index != -1, "error entering "+casted)
val load = new Load(accessor(casted, index))
target.thenp = load;
val test = patternNode(p, load)
load.thenp = Snoc(load.thenp, test)
enterArgs(p, test, casted)
case load: Load =>
val test = patternNode(p, load)
addToList(load.thenp, test) match {
case Pair(ntest, thenp) =>
load.thenp = thenp
enterArgs(p, ntest, casted)
}
}
}
def enterArgs(p: Pattern, targ1: Test, cast1:Ident): Test = {
val pats = p match {case PApply(_, args) => args; case _ => List() };
var target = targ1;
var casted = target.casted;
/* // to what should I attach the variables??
var j = casted.tpe.args.elements;
var child = List[Tree]();
while(j > 0) {
j = j - 1
child = accessor(casted, i) :: child
}
*/
var i = 0;
var it = pats.elements
while(it.hasNext) {
target = enter(it.next, i, target, casted);
i = i + 1
}
target;
}
def same(p:Test, q:Test) = p.tpe == q.tpe;
def overlaps(p:Test, q:Test) =
(q.tpe isSubType p.tpe) || (p.tpe isSubType q.tpe);
def accessor(casted: Ident, index: Int) = {
val tpe = casted.tpe;
val fml = tpe.args(index);
checkSelect(Select(casted, fml._2))
}
def patternNode(p:Pattern, h:Load): Test = p match {
case PApply(tpestr, args) => new Test(ctable(tpestr), fresh("z"));
case PLeaf(tpestr, vble) => new Test(ctable(tpestr), vble)
case PWildcard() => new Test(h.tpe, fresh("_"));
}
var fail: Int = -1;
def toTree(scrut:Tree): Tree = {
val lab = Labeled(MatchErrorObject()) anchor fail;
toTree(root.thenp, fail) match {
case t :: ts => Block(Let(root.tpe.name, root.casted.name, scrut, t)::la
b::ts);
}
}
def toTree(patNode: Node, elseLa1: Int): List[Tree] = {
//Console.println("toTree("+patNode+","+elseLab+")")
patNode match {
case Return(b) => List(b);
case load: Load =>
//Console.println("load.thenp ="+load.thenp)
val tpe = load.tpe;
val selector = load.expr;
//Console.println("load.expr ="+load.expr)
var res = List[Tree]();
val v = fresh("y");
val vload = Ident(v) setType tpe;
var elseLab = elseLa1;
def listToTree(sx:PatNodeList): Unit = sx match {
case Snoc(Snil,y) =>
toTree(y, vload, elseLab) match {
case t :: ts =>
res = Let(tpe.name, v, selector, t) :: ts ::: res
}
case Snoc(ys,y) =>
val z = toTree(y, vload, elseLab) match {
case t::ts =>
elseLab = freshLabel
res = (Labeled(t) anchor elseLab) :: ts ::: res;
}
listToTree(ys)
}
listToTree(load.thenp)
res
}
}
def toTree(patNode: Test, vload:Ident, elseLab:Int): List[Tree] = {
//Console.println("toTree("+patNode+","+vload+","+elseLab+")")
if(patNode.tpe == vload.tpe) {
toTree(patNode.thenp, elseLab) match {
case t :: ts =>
Let(patNode.tpe.name, patNode.casted.name, vload, t) :: ts
}
} else {
var res = List[Tree]()
val thenp = toTree(patNode.thenp, elseLab) match {
case t::ts => res = ts; t
}
If(IsInstanceOf(vload, patNode.tpe.name) setType ctable("Boolean"),
Let(patNode.tpe.name, patNode.casted.name, vload, thenp) setType then
p.tpe,
Jump() to elseLab)::res
}
}
}
}
|