summaryrefslogtreecommitdiff
path: root/sources/scalac/transformer/AddConstructors.java
diff options
context:
space:
mode:
authormihaylov <mihaylov@epfl.ch>2003-02-21 16:02:47 +0000
committermihaylov <mihaylov@epfl.ch>2003-02-21 16:02:47 +0000
commit3c1b85f91e190c1c68f88ed0e4af50e220bf21c2 (patch)
tree1ceeb29cfc93bd07de6315d4341cbe351c28c1eb /sources/scalac/transformer/AddConstructors.java
parent0d9486124afb366cf35a52349ce3adc416a01757 (diff)
downloadscala-3c1b85f91e190c1c68f88ed0e4af50e220bf21c2.tar.gz
scala-3c1b85f91e190c1c68f88ed0e4af50e220bf21c2.tar.bz2
scala-3c1b85f91e190c1c68f88ed0e4af50e220bf21c2.zip
Initial import of the AddConstructors phase.
Diffstat (limited to 'sources/scalac/transformer/AddConstructors.java')
-rw-r--r--sources/scalac/transformer/AddConstructors.java256
1 files changed, 256 insertions, 0 deletions
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("<init>");
+
+ // 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