/* ____ ____ ____ ____ ______ *\ ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** ** /_____/\____/\___/\____/____/ ** \* */ // $Id$ // $OldId: ExplicitOuterClasses.java,v 1.22 2002/10/17 12:31:56 schinz Exp $ package scalac.transformer; import java.util.*; import scalac.*; import scalac.ast.*; import scalac.util.*; import scalac.parser.*; import scalac.symtab.*; import scalac.typechecker.*; import Tree.*; /** * Make links from nested classes to their enclosing class explicit. * * @author Michel Schinz * @version 1.0 */ public class ExplicitOuterClasses extends Transformer { protected final ExplicitOuterClassesPhase phase; // Mapping from class constructor symbols to owner field symbols. protected final HashMap/**/ outerMap; public ExplicitOuterClasses(Global global, ExplicitOuterClassesPhase phase) { super(global); this.phase = phase; this.outerMap = phase.outerMap; } protected LinkedList/**/ classStack = new LinkedList(); protected LinkedList/**/ outerLinks = new LinkedList(); /** * Return the number of outer links to follow to find the given * symbol. */ protected int outerLevel(Symbol sym) { Iterator classIt = classStack.iterator(); for (int level = 0; classIt.hasNext(); ++level) { Symbol classSym = (Symbol)classIt.next(); if (classSym == sym) return level; } return -1; } /** * Return a tree referencing the "level"th outer class. */ protected Tree outerRef(int level) { assert level >= 0 : level; if (level == 0) { Symbol thisSym = (Symbol)classStack.getFirst(); return gen.This(thisSym.pos, thisSym); } else { Iterator outerIt = outerLinks.iterator(); Tree root = gen.Ident((Symbol)outerIt.next()); for (int l = 1; l < level; ++l) { Symbol outerSym = (Symbol)outerIt.next(); root = gen.mkStable(gen.Select(root, outerSym)); } return root; } } protected LinkedList/*>*/ superSymsStack = new LinkedList(); protected Symbol outerSuperSym(int level, Symbol funSym) { assert level > 0 : level; HashMap symMap = (HashMap)superSymsStack.get(level); Symbol outerSuperSym = (Symbol)symMap.get(funSym); if (outerSuperSym == null) { Name outerSuperName = Name.fromString("super$" + funSym.name.toString()); outerSuperSym = new TermSymbol(funSym.pos, outerSuperName, (Symbol)classStack.get(level), Modifiers.PRIVATE); global.log("created forwarding symbol: " + Debug.show(outerSuperSym)); outerSuperSym.setInfo(funSym.info().cloneType(funSym, outerSuperSym)); symMap.put(funSym, outerSuperSym); } return outerSuperSym; } public Tree transform(Tree tree) { switch (tree) { case ClassDef(int mods, _, _, _, _, _) : { // Add outer link ClassDef classDef = (ClassDef) tree; Symbol classSym = classDef.symbol(); ValDef[][] newVParams; classStack.addFirst(classSym); superSymsStack.addFirst(new HashMap()); if (classStack.size() == 1 || Modifiers.Helper.isStatic(mods)) { outerLinks.addFirst(null); newVParams = classDef.vparams; } else { // Add the outer parameter to the tree (it is added to // the type by transformInfo). Symbol constSym = classSym.primaryConstructor(); Symbol outerSym = phase.outerSym(constSym); assert (outerSym.owner() == constSym) : outerSym; outerLinks.addFirst(outerSym); ValDef[][] vparams = classDef.vparams; ValDef[] newVParamsI; if (vparams.length == 0) newVParamsI = new ValDef[] { gen.mkParam(outerSym) }; else { newVParamsI = new ValDef[vparams[0].length + 1]; newVParamsI[0] = gen.mkParam(outerSym); System.arraycopy(vparams[0], 0, newVParamsI, 1, vparams[0].length); } newVParams = new ValDef[][] { newVParamsI }; classSym.flags |= Modifiers.STATIC; } // Add forwarding "super" methods and add them to the // class members. Scope newMembers = new Scope(classSym.members()); TreeList newBody = new TreeList(transform(classDef.impl.body)); HashMap/**/ symMap = (HashMap)superSymsStack.removeFirst(); Iterator symIt = symMap.entrySet().iterator(); while (symIt.hasNext()) { Map.Entry symPair = (Map.Entry)symIt.next(); Symbol funSym = (Symbol)symPair.getKey(); Symbol fwdSym = (Symbol)symPair.getValue(); Symbol[] argsSym = fwdSym.valueParams(); Tree[] args = new Tree[argsSym.length]; for (int i = 0; i < argsSym.length; ++i) args[i] = gen.mkRef(argsSym[i].pos, argsSym[i]); Tree fwdBody = gen.Apply(gen.Select(gen.Super(classSym.pos, classSym), funSym), args); newBody.append(gen.DefDef(fwdSym, fwdBody)); newMembers.enter(fwdSym); } classSym.updateInfo(Type.compoundType(classSym.parents(), newMembers, classSym)); Tree[] newParents = transform(classDef.impl.parents); outerLinks.removeFirst(); classStack.removeFirst(); return copy.ClassDef(classDef, classSym, transform(classDef.tparams), transform(newVParams), transform(classDef.tpe), copy.Template(classDef.impl, newParents, newBody.toArray())); } case Ident(_): { if (! tree.symbol().name.isTermName()) return super.transform(tree); // Follow "outer" links to fetch data in outer classes. int level = outerLevel(tree.symbol().classOwner()); if (level > 0) { Tree root = outerRef(level); return gen.mkStable(gen.Select(root, tree.symbol())); } else { return super.transform(tree); } } case This(_): { // If "this" refers to some outer class, replace it by // explicit reference to it. int level = outerLevel(tree.symbol()); if (level > 0) return outerRef(level); else return super.transform(tree); } case Select(Super(_, _), Name selector): { // If "super" refers to an outer class, access the value // (a method) through outer link(s). int level = outerLevel(((Select)tree).qualifier.symbol()); if (level > 0) return gen.Select(outerRef(level), outerSuperSym(level, tree.symbol())); else return super.transform(tree); } case Apply(Tree fun, Tree[] args): { // Add outer parameter to constructor calls. Tree realFun; Tree[] typeArgs; switch (fun) { case TypeApply(Tree fun2, Tree[] tArgs): realFun = fun2; typeArgs = tArgs; break; default: realFun = fun; typeArgs = null; break; } Tree newFun = null, newArg = null; if (realFun.hasSymbol() && realFun.symbol().isPrimaryConstructor()) { switch (transform(realFun)) { case Select(Tree qualifier, _): { if (! (qualifier.hasSymbol() && Modifiers.Helper.isNoVal(qualifier.symbol().flags))) { newFun = make.Ident(qualifier.pos, realFun.symbol()) .setType(realFun.type()); newArg = qualifier; } } break; case Ident(_): { int level = outerLevel(realFun.symbol().owner()); if (level >= 0) { newFun = realFun; newArg = outerRef(level); } } break; default: throw global.fail("unexpected node in constructor call"); } if (newFun != null && newArg != null) { Tree[] newArgs = new Tree[args.length + 1]; newArgs[0] = newArg; System.arraycopy(args, 0, newArgs, 1, args.length); Tree finalFun; if (typeArgs != null) finalFun = copy.TypeApply(fun, newFun, typeArgs); else finalFun = newFun; finalFun.type = phase.addValueParam(finalFun.type, phase.outerSym(realFun.symbol())); return copy.Apply(tree, finalFun, transform(newArgs)); } else return super.transform(tree); } else return super.transform(tree); } default: return super.transform(tree); } } }