From 3c1b85f91e190c1c68f88ed0e4af50e220bf21c2 Mon Sep 17 00:00:00 2001 From: mihaylov Date: Fri, 21 Feb 2003 16:02:47 +0000 Subject: Initial import of the AddConstructors phase. --- sources/scalac/transformer/AddConstructors.java | 256 ++++++++++++++++++++++++ 1 file changed, 256 insertions(+) create mode 100644 sources/scalac/transformer/AddConstructors.java (limited to 'sources/scalac/transformer/AddConstructors.java') diff --git a/sources/scalac/transformer/AddConstructors.java b/sources/scalac/transformer/AddConstructors.java new file mode 100644 index 0000000000..63781c43cc --- /dev/null +++ b/sources/scalac/transformer/AddConstructors.java @@ -0,0 +1,256 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +\* */ + +// $Id$ + +package scalac.transformer; + +import scalac.Global; +import scalac.util.Name; + +import scalac.ast.Tree; +import Tree.*; +import scalac.ast.Transformer; + +import scalac.symtab.Type; +import scalac.symtab.Symbol; +import scalac.symtab.TermSymbol; +import scalac.symtab.Scope; +import scalac.symtab.Kinds; +import scalac.symtab.Modifiers; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.ArrayList; + +import scalac.util.Debug; + +/** + * 1. For each class add a single method (DefDef) designated as + * constructor whose parameters are the class parameters. The + * constructor contains: + * - call to the constructor of the supertype with the appropriate arguments + * - initialize the fields corresponding to the class ValDefs + * - the bodies of the class level expressions; + * they are also removed from the ClassDef body + * + * 2. The right hand sides of the ValDefs are left empty + * + * 3. Substitute the appropriate constructor symbol into the + * 'new' expressions + * + * @author Nikolay Mihaylov + * @version 1.2 +*/ + +public class AddConstructors extends Transformer { + public final static Name CTOR_N = Name.fromString(""); + + // True iff we generate code for INT backend. + protected final boolean forINT; + // True iff we generate code for JVM backend. + protected final boolean forJVM; + // True iff we generate code for MSIL backend. + protected final boolean forMSIL; + + final HashMap constructors; + + public AddConstructors(Global global, AddConstructorsPhase descr, HashMap constructors) { + super(global, descr); + this.constructors = constructors; + this.forINT = global.target == global.TARGET_INT; + this.forJVM = global.target == global.TARGET_JVM; + this.forMSIL = global.target == global.TARGET_MSIL; + } + + /** return new constructor symbol if it isn't already defined + */ + Symbol getConstructor(Symbol classConstr) { + return getConstructor(classConstr, + (((Type.MethodType)classConstr.info()).vparams)); + } + + Symbol getConstructor(Symbol classConstr, Symbol[] paramSyms) { + //assert (classConstr.flags & Modifiers.CONSTRUCTOR) != 0: +// assert classConstr.isConstructor() : +// "Constructor functions not implemented yet! " + +// Debug.show(classConstr); + Symbol constr = (Symbol) constructors.get(classConstr); + if (constr == null) { + Symbol clazz = classConstr.primaryConstructorClass(); + int flags = forJVM + ? classConstr.flags & (Modifiers.PRIVATE | Modifiers.PROTECTED) + : classConstr.flags; + constr = + new TermSymbol(classConstr.pos, CTOR_N, clazz, flags); + constr.setInfo(Type.MethodType + (paramSyms, //((Type.MethodType)classConstr.info()).vparams, + forJVM || forMSIL + ? global.definitions.UNIT_TYPE + : clazz.type()).erasure()); + constructors.put(classConstr, constr); + constructors.put(constr, constr); + } + return constr; + } + + /** process the tree + */ + public Tree transform(Tree tree) { + Symbol treeSym = tree.symbol(); + switch (tree) { + case ClassDef(_, _, _, ValDef[][] vparams, _, //: + Template(Tree[] baseClasses, Tree[] body)): + if (treeSym.isInterface()) + return tree; + + assert treeSym.name.isTypeName(); + + /* + System.out.println("Class parameters in the tree:"); + Param[] pparams = vparams[0]; + for (int i = 0; i < pparams.length; i++) + System.out.println("\t" + Debug.show(pparams[i].symbol())); + System.out.println("Class parameters in the constructor:"); + Symbol[] sparams = ((Type.MethodType)treeSym.constructor().info()).vparams; + for (int i = 0; i < sparams.length; i++) + System.out.println("\t" + Debug.show(sparams[i])); + */ + + Symbol[] paramSyms = new Symbol[vparams[0].length]; + for (int i = 0; i < paramSyms.length; i++) + paramSyms[i] = vparams[0][i].symbol(); + + ArrayList constrBody = new ArrayList(); + ArrayList classBody = new ArrayList(); + Symbol constrSym = getConstructor(treeSym.constructor(), paramSyms); + Scope classScope = new Scope(); + classScope.enter(constrSym); + + // inline the call to the super constructor + Type superType = treeSym.parents()[0]; + if ( !forINT || !superType.symbol().isJava()) + switch (baseClasses[0]) { + case Apply(Tree fun, Tree[] args): + int pos = baseClasses[0].pos; + Tree superConstr = gen.Select + (gen.Super(pos, superType), + getConstructor(fun.symbol())); + constrBody.add(gen.Apply(superConstr, transform(args))); + break; + default: assert false; + } + + // for every ValDef move the initialization code into the constructor + for (int i = 0; i < body.length; i++) { + Tree t = body[i]; + if (t.definesSymbol()) { + Symbol sym = t.symbol(); + switch (t) { + case ValDef(_,_,_,Tree rhs): + if (rhs != Tree.Empty) { + // !!!FIXME: revert to this.whatever when the bug is fixed + //Tree ident = gen.Select(gen.This(t.pos, treeSym), sym); + Tree ident = gen.Ident(sym); + + constrBody.add(gen.Assign(t.pos, ident, transform(rhs))); + t = gen.ValDef(sym, Tree.Empty); + } + break; + } + classBody.add(transform(t)); + classScope.enter(sym); + } else + // move every class-level expression into the constructor + constrBody.add(transform(t)); + } + + // add result expression consistent with the + // result type of the constructor + //if (! forJVM) + // constrBody.add(gen.This(tree.pos, treeSym)); + Tree constrTree = constrBody.size() > 1 ? + gen.Block((Tree[])constrBody.toArray(new Tree[constrBody.size()])): + (Tree) constrBody.get(0); + + // add constructor definition to the body of the class + classBody.add(gen.DefDef(tree.pos, constrSym, constrTree)); + + // strip off the class constructor from parameters + switch (treeSym.constructor().info()) { + case MethodType(_, Type result): + treeSym.constructor(). + updateInfo(Type.MethodType(Symbol.EMPTY_ARRAY, result)); + break; + default : assert false; + } + + Type classType = +// Type.CompoundType(treeSym.parents(), classScope); + Type.compoundType(treeSym.parents(), classScope, treeSym); + Symbol classSym = treeSym.updateInfo(classType); + //fixConstructor(classSym); + + Tree[] newBody = (Tree[]) classBody.toArray(Tree.EMPTY_ARRAY); + return gen.ClassDef(classSym, newBody); + + // Substitute the constructor into the 'new' expressions + case New(Template(Tree[] baseClasses, _)): + Tree base = baseClasses[0]; + switch (base) { + case Apply(Tree fun, Tree[] args): + return gen.New(copy.Apply + (base, + gen.Ident(base.pos, getConstructor(fun.symbol())), + transform(args))); + default: + assert false; + } + break; + + // is this still needed? + case Ident(Name name): + if (treeSym.isConstructor()) { + Debug.abort("Not implemented yet: using class constructor as function!"); + //return gen.mkId(tree.pos, getConstructor(treeSym)); + } + //System.out.println("Processing " + Debug.show(treeSym)); + break; + + // is this still needed? + case Select(Tree qualifier, Name selector): + if (treeSym.isConstructor()) { + Debug.abort("Not implemented yet: using class constructor as function!"); + //return gen.mkSel(tree.pos, transform(qualifier), getConstructor(treeSym)); + } + break; + + } // switch(tree) + return super.transform(tree); + } // transform() + +// /** Given a symbol of a class it strips off the parameters +// * from the MethodType of the constructor of that class +// * and all its superclasses +// */ +// public void fixConstructor(Symbol clazz) { +// if (clazz != global.definitions.ANY_CLASS) { +// switch (clazz.constructor().info()) { +// case MethodType(Symbol[] params, Type result): +// if (params.length > 0) { +// clazz.constructor().updateInfo +// (Type.MethodType(Symbol.EMPTY_ARRAY, result)); +// } +// //fixConstructor(clazz.basetypes()[0].symbol()); +// break; +// default: +// assert false : "Constructor should have a method type!"; +// } +// } +// } + +} // class AddConstructors -- cgit v1.2.3