summaryrefslogblamecommitdiff
path: root/sources/scalac/transformer/AddConstructors.java
blob: bb71b167df67f4957c0f913c20b148402860d3ce (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12



                                                                          







                                                                          
                         



















                                                               


                                                                




                                                                              


                                                                         
  

                                                            





                                                  




                                                 
 

                                                             
 

                                                                 

                                                         
                                                           




                                                                 

                                                                     


                                                       

                                                               
                                                                              

                                                                              
                    
                                                                                


                                             
                                                                

                                                                   
 
                                       

                                                  
                                                    
         
 





                                      
                                             
                       
                                                    
                                      
                                             
 








                                                                           

                                                        
                                                             
 




                                                                  

                                                        


                                            
                                                                                  













                                                                                

                                                                         
                                                         
                                                  






                                                                          

                              
                     

                                                                      

                                                                        
                                                             


                 
                                                       
                                                                      
                                          






                                                                                                  
                                                  
                                                  
                                                 
                                                 
                                                       
                                                                                
                          
                        
                                                                       
                 
             
 

                                                     












                                                                               
                                          





                                                                              

             

                                                                              


                                                        

                                                            

                                                        
                                                     

                                                                

                                         
                                                             
 
                                                                          





                                                                         
                                                  




                                                                







                                                                         
                                              





                                                                         




                             


                                                              








                                                                                   


                                                                   



                                                                                   

                  
                         
 


                                     
                          
/*     ____ ____  ____ ____  ______                                     *\
**    / __// __ \/ __// __ \/ ____/    SOcos COmpiles Scala             **
**  __\_ \/ /_/ / /__/ /_/ /\_ \       (c) 2002, LAMP/EPFL              **
** /_____/\____/\___/\____/____/                                        **
\*                                                                      */

// $Id$

package scalac.transformer;

import scalac.Global;
import scalac.util.Name;
import scalac.util.Names;

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 and the
 * owner is the constructed class. 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. Additional constructors are assigned new symbols owned by the class
 *
 * 3. The right hand sides of the ValDefs are left empty
 *
 * 4. Substitute the appropriate constructor symbol into the
 * 'new' expressions and constructor applications
 *
 * @author Nikolay Mihaylov
 * @version 1.2
*/

public class AddConstructors extends Transformer {

    // True iff we generate code for INT backend.
    protected final boolean forINT;
    // True iff we generate code for JVM backend.
    protected final boolean forJVM;


    protected final HashMap/*<Symbol, Symbol>*/ constructors;

    public AddConstructors(Global global, HashMap constructors) {
	super(global);
        this.constructors = constructors;
        this.forINT = global.target == global.TARGET_INT;
        this.forJVM = (global.target == global.TARGET_JVM);
    }

    /** return new constructor symbol if it isn't already defined
     */
    Symbol getConstructor(Symbol classConstr) {
   	assert classConstr.isConstructor() :
   	    "Class constructor expected: " + Debug.show(classConstr);
        Symbol owner = classConstr.constructorClass();
        Symbol[] tparamSyms = classConstr.typeParams();
        Symbol[] paramSyms = classConstr.valueParams();
	Symbol constr = (Symbol) constructors.get(classConstr);
	if (constr == null) {
	    assert !owner.isInterface() : Debug.show(owner) + " is interface";
            int flags =
                classConstr.flags & (Modifiers.PRIVATE | Modifiers.PROTECTED);
	    constr =
                new TermSymbol(classConstr.pos, classConstr.name, owner, flags);

	    Type constrType = Type.MethodType
		(paramSyms, forJVM ?
		 global.definitions.UNIT_TYPE() : owner.type());
            if (tparamSyms.length != 0)
                constrType = Type.PolyType(tparamSyms, constrType);

	    constr.setInfo(constrType);
	    constructors.put(classConstr, constr);
	    constructors.put(constr, constr);
            owner.members().enterOrOverload(constr);
	}

	return constr;
    }

    /** process the tree
     */
    public Tree transform(Tree tree) {
	final Symbol treeSym = tree.symbol();
	switch (tree) {
	case ClassDef(_, _, _, _, _, Template impl):
	    if (treeSym.isInterface())
		return super.transform(tree);

	    // expressions that go before the call to the super constructor
	    final ArrayList constrBody = new ArrayList();

	    // expressions that go after the call to the super constructor
	    final ArrayList constrBody2 = new ArrayList();

	    // the body of the class after the transformation
	    final ArrayList classBody = new ArrayList();

	    // the Symbol of the new primary constructor
	    final Symbol constrSym =
		getConstructor(treeSym.primaryConstructor());

	    assert constrSym.owner() == treeSym :
		"Wrong owner of the constructor: \n\tfound: " +
		Debug.show(constrSym.owner()) + "\n\texpected: " +
		Debug.show(treeSym);

	    for (int i = 0; i < impl.body.length; i++) {
		Tree t = impl.body[i];
		if (t.definesSymbol()) {
		    Symbol sym = t.symbol();
		    switch (t) {
		    // for ValDefs move the initialization code to the constructor
		    case ValDef(_, _, _, Tree rhs):
			if (rhs != Tree.Empty) {
			    Tree lhs =
			        gen.Select(gen.This(t.pos, treeSym), sym);
			    Tree assign =
				gen.Assign(t.pos, lhs, transform(rhs));
			    t = gen.ValDef(sym, Tree.Empty);
			    if (rhs.hasSymbol() && rhs.symbol().isParameter()) {
				constrBody.add(assign);
			    } else {
				constrBody2.add(assign);
			    }
			}
			break;

		    // assign new symbols to the alternative constructors
		    case DefDef(_, _, _, _, _, Tree rhs):
			if (sym.isConstructor()) {
                            // add result expression consistent with the
                            // result type of the constructor
                            Tree result = forJVM
                                ? gen.mkUnitLit(t.pos)
                                : gen.This(t.pos, treeSym);
                            rhs = gen.mkBlock(new Tree[] { rhs, result });
			    t = gen.DefDef(getConstructor(sym), rhs);
			}
			break;
		    }
		    // do not transform(t). It will be done at the end
		    classBody.add(t);
		} else {
		    // move class-level expressions into the constructor
		    constrBody2.add(transform(impl.body[i]));
		}
	    }

	    // inline the call to the super constructor
            if ( !forINT || !treeSym.parents()[0].symbol().isJava()) {
		switch (impl.parents[0]) {
		case Apply(TypeApply(Tree fun, Tree[] targs), Tree[] args):
		    int pos = impl.parents[0].pos;
		    Tree superConstr = gen.Select
			(gen.Super(pos, treeSym),
			 getConstructor(fun.symbol()));
		    constrBody.add(gen.mkApplyTV(superConstr, transform(targs), transform(args)));
		    break;
		case Apply(Tree fun, Tree[] args):
		    int pos = impl.parents[0].pos;
		    Tree superConstr = gen.Select
			(gen.Super(pos, treeSym),
			 getConstructor(fun.symbol()));
		    constrBody.add(gen.mkApply_V(superConstr, transform(args)));
		    break;
		default:
                    throw Debug.abort("illegal case", impl.parents[0]);
		}
	    }

	    // inline initialization of module values
            if (forINT && treeSym.isModuleClass()) {
                Symbol module = treeSym.module();
                if (module.isGlobalModule()) {
                    constrBody.add(
                        gen.Assign(
                            gen.mkRef(tree.pos, module),
                            gen.This(tree.pos, treeSym)));
                } else {
                    Symbol owner = module.owner();
                    Name module_eqname = module.name.append(Names._EQ);
                    Symbol module_eq = owner.lookup(module_eqname);
                    assert module != Symbol.NONE :Debug.show(treeSym.module());
                    if (owner.isModuleClass() && owner.module().isStable()) {
                        constrBody.add(
                            gen.mkApply_V(
                                gen.mkRef(tree.pos, module_eq),
                                new Tree[] {gen.This(tree.pos, treeSym)}));
                    } else {
                        // !!! module_eq must be accessed via some outer field
                    }
                }
            }

	    // add valdefs and class-level expression to the constructorr body
	    constrBody.addAll(constrBody2);

	    // add result expression consistent with the
	    // result type of the constructor
            if (! forJVM)
                constrBody.add(gen.This(tree.pos, treeSym));
            else
                constrBody.add(gen.mkUnitLit(tree.pos));
            Tree constrTree = constrBody.size() > 1 ?
                gen.Block((Tree[])constrBody.
			  toArray(new Tree[constrBody.size()])):
                (Tree) constrBody.get(0);

	    classBody.add(gen.DefDef(constrSym, constrTree));

	    Tree[] newBody = (Tree[]) classBody.toArray(Tree.EMPTY_ARRAY);

	    // transform the bodies of all members in order to substitute
	    // the constructor references with the new ones
	    for (int i = 0; i < newBody.length - 1; i ++)
		newBody[i] = transform(newBody[i]);

	    return gen.ClassDef(treeSym, newBody);

	// Substitute the constructor into the 'new' expressions
	case New(Template(Tree[] baseClasses, _)):
	    Tree base = baseClasses[0];
	    switch (base) {
	    case Apply(TypeApply(Tree fun, Tree[] targs), Tree[] args):
                return gen.New(
                    tree.pos,
                    gen.mkApplyTV(
                        base.pos,
                        gen.Ident(fun.pos, getConstructor(fun.symbol())),
                        transform(targs),
                        transform(args)));
	    case Apply(Tree fun, Tree[] args):
                return gen.New(
                    tree.pos,
                    gen.mkApply_V(
                        base.pos,
                        gen.Ident(fun.pos, getConstructor(fun.symbol())),
                        transform(args)));
	    default:
		assert false;
	    }
	    break;

	// Substitute the constructor aplication;
	// this only occurs within constructors that terminate
	// by a call to another constructor of the same class
	case Apply(TypeApply(Tree fun, Tree[] targs), Tree[] args):
	    Symbol constr = (Symbol)constructors.get(fun.symbol());
	    if (constr != null)
		return gen.mkApplyTV(
                    tree.pos,
                    gen.Select(fun.pos, gen.This(fun.pos, constr.owner()), constr),
                    transform(targs),
                    transform(args));
	    break;
	case Apply(Tree fun, Tree[] args):
	    Symbol constr = (Symbol)constructors.get(fun.symbol());
	    if (constr != null)
		return gen.mkApply_V(
                    tree.pos,
                    gen.Select(fun.pos, gen.This(fun.pos, constr.owner()), constr),
                    transform(args));
	    break;

	} // switch(tree)

	return super.transform(tree);
    } // transform()

} // class AddConstructors