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



                                                                          






                                                                          

                         
 









                                
 






                                                                    
                                                        























                                                                              












                                               
                                      




                                                

     










                                                                      
 




                                                                             
     














                                                                              
                                                                                       



































































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

// $OldId: ExpandMixinsPhase.java,v 1.8 2002/05/02 10:59:35 schinz Exp $
// $Id$

package scalac.transformer;

import java.util.Map;
import java.util.HashMap;

import scalac.PhaseDescriptor;
import scalac.Global;
import scalac.Unit;
import scalac.ast.Tree;
import scalac.ast.Tree.Template;
import scalac.ast.Traverser;
import scalac.ast.Transformer;
import scalac.symtab.Symbol;
import scalac.symtab.Type;
import scalac.util.Debug;

// TODO do not copy hidden members which are not accessible via
// "super".

/**
 * A phase to expand mixins using code copying. We assume that links
 * to outer classes have been made explicit by a previous phase.
 */
public class ExpandMixinsPhase extends PhaseDescriptor {

    //########################################################################
    // Private Fields

    /** The global environment */
    private Global global;

    /** A map from classes to their interface */
    private Map interfaces;

    /** A map from classes to their expanded template */
    private final Map/*<Symbol,Template>*/ expansions = new HashMap();

    /** A map from classes to their original (unexpanded) template */
    private final Map/*<Symbol,Template>*/ templates = new HashMap();

    /** A traverser that collects class definitions */
    private Traverser collector;

    /** A transformer that expands classes that have mixins */
    private Transformer expander;

    //########################################################################
    // Public Methods

    public String name () {
        return "expandmixins";
    }

    public String description () {
        return "expand mixins by code copying";
    }

    public String taskDescription() {
        return "expanded mixins";
    }

    public void apply(Global global) {
        apply(global, global.units);
    }

    public void apply(Unit unit) {
        apply(unit.global, new Unit[] { unit });
    }

    public void apply(Global global, Unit[] units) {
        if (this.global == null) {
            this.global = global;
            this.interfaces = global.PHASE.ADDINTERFACES.classToIFace;
            this.collector = new Collector();
            this.expander = new Expander(global);
        }
        collector.traverse(units);
        expander.apply(units);
        assert templates.isEmpty() : templates.keySet();
    }

    public Type transformInfo(Symbol symbol, Type type) {
        // !!! make this work and remove *1 in ClassExpander
        // if (!symbol.isJava() && symbol.isClass() && !symbol.isInterface())
        //     type = getExpandedTemplate(symbol).type();
        return type;
    }

    // !!!
    // public Checker[] postCheckers(Global global) {
    //     return new Checker[] {
    //         new CheckSymbols(global),
    //         new CheckTypes(global),
    //         new CheckOwners(global),
    //      new CheckNames(global)
    //     };
    // }

    //########################################################################
    // Private Methods

    private Template getExpandedTemplate(Symbol clasz) {
	if (global.debug) global.log("get expanded " + clasz + " in " + clasz.owner());
        Template template = (Template)expansions.get(clasz);
        if (template == null) {
            template = (Template)templates.remove(clasz);
            assert template != null : Debug.show(clasz);
            template = expandTemplate(clasz, expander.transform(template));
            expansions.put(clasz, template);
        }
        return template;
    }

    private Template expandTemplate(Symbol clasz, Template template) {
        assert Debug.log("expanding ", clasz);
        ClassExpander expander = null;
        Type[] parents = clasz.parents();
        for (int i = parents.length - 1; i > 0; --i) {
            Symbol parent = parents[i].symbol();
            if (parent.isInterface()) continue;
            if (expander == null)
                expander = new ClassExpander(global, clasz, template);
            assert Debug.log("expanding ", clasz, ": inlining ", parent);
            expander.inlineMixin(i, parents[i], (Symbol)interfaces.get(parent),
                getExpandedTemplate(parent));
        }
        return expander == null ? template : expander.getTemplate();
    }

    //########################################################################
    // Private Class - Collector

    private class Collector extends Traverser {
        public void traverse(Tree tree) {
            switch(tree) {
            case ClassDef(_, _, _, _, _, Template template):
                Symbol clasz = tree.symbol();
                if (!clasz.isInterface()) templates.put(clasz, template);
                traverse(template.body);
                return;
            case PackageDef(_, Template(_, Tree[] body)):
                traverse(body);
                return;
            }
        }
    }

    //########################################################################
    // Private Class - Expander

    private class Expander extends Transformer {
        public Expander(Global global) {
            super(global);
        }
        public Tree transform(Tree tree) {
            switch (tree) {
            case ClassDef(_, _, _, _, _, _):
                Symbol clasz = tree.symbol();
                if (clasz.isInterface()) return super.transform(tree);
                return gen.ClassDef(tree.pos,clasz,getExpandedTemplate(clasz));
            case PackageDef(_, _):
                return super.transform(tree);
            case Template(_, _):
                return super.transform(tree);
            default:
                return tree;
            }
        }
    }

    //########################################################################
}