summaryrefslogblamecommitdiff
path: root/sources/scalac/atree/ATreeFromSTree.java
blob: 042dab59fe0bb034575959a74de548b408e243e0 (plain) (tree)
1
2
3
4
5
6
7
8
9
10









                                                                          


                           
                   
                       
                             
                                
                                 
                            
                         


























                                                                              































































                                                                              
                                                                      




                                                    


                                                                              




                                                                               
                                                     



































                                                                               


















































































                                                                             
                                                        








































                                                                                                              


                                                                              
























                                                                                              
















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

// $Id$

package scalac.atree;

import java.util.List;
import java.util.ArrayList;

import scalac.Unit;
import scalac.ast.Tree;
import scalac.ast.Tree.Ident;
import scalac.ast.Tree.Template;
import scalac.symtab.Definitions;
import scalac.symtab.Symbol;
import scalac.util.Debug;

/** This class translates syntax trees into attributed trees. */
public class ATreeFromSTree {

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

    /** The global definitions */
    private final Definitions definitions;

    /** The attributed tree factory */
    private final ATreeFactory make;

    //########################################################################
    // Public Constructors

    /** Initializes this instance. */
    public ATreeFromSTree(Definitions definitions) {
        this.definitions = definitions;
        this.make = new ATreeFactory();
    }

    //########################################################################
    // Public Methods - Translating units

    /** Translates the unit's body and stores the result in it. */
    public void translate(Unit unit) {
        template(unit.repository = new ARepository(), unit.body);
    }

    //########################################################################
    // Private Methods - Translating templates

    /** Translates the templates and adds them to the repository. */
    private void template(ARepository repository, Tree[] trees) {
        for (int i = 0; i < trees.length; i++) template(repository, trees[i]);
    }

    /** Translates the template and adds it to the repository. */
    private void template(ARepository repository, Tree tree) {
        switch (tree) {

        case Empty:
            return;

        case ClassDef(_, _, _, _, _, Template(_, Tree[] body)):
            AClass clasz = new AClass(tree.symbol());
            repository.addClass(clasz);
            member(clasz, body);
            return;

        case PackageDef(_, Template(_, Tree[] body)):
            template(repository, body);
            return;

        case ValDef(_, _, _, Tree rhs):
            // !!!
            return;

        default:
            throw Debug.abort("illegal case", tree);
        }
    }

    //########################################################################
    // Private Methods - Translating members

    /** Translates the members and adds them to the class. */
    private void member(AClass clasz, Tree[] trees) {
        for (int i = 0; i < trees.length; i++) member(clasz, trees[i]);
    }

    /** Translates the member and adds it to the class. */
    private void member(AClass clasz, Tree tree) {
        switch (tree) {

        case Empty:
            return;

        case ClassDef(_, _, _, _, _, _):
            template(clasz, tree);
            return;

        case ValDef(_, _, _, Tree rhs):
            AField field = new AField(tree.symbol(), false);
            clasz.addField(field);
            return;

        case DefDef(_, _, _, _, _, Tree rhs):
            AMethod method = new AMethod(tree.symbol(), false);
            clasz.addMethod(method);
            if (!method.isAbstract()) method.setCode(expression(rhs));
            return;

        default:
            throw Debug.abort("illegal case", tree);
        }
    }

    //########################################################################
    // Private Methods - Translating statements

     /** Translates the statements. */
    private ACode[] statement(List locals, Tree[] trees, int start, int count){
        List codes = new ArrayList();
        for (int i = start; i < start + count; i++) {
            ACode code = statement(locals, trees[i]);
            if (code != ACode.Void) codes.add(code);
        }
        return (ACode[])codes.toArray(new ACode[codes.size()]);
    }

    /** Translates the statement. */
    private ACode statement(List locals, Tree tree) {
        switch (tree) {

        case Empty:
            return make.Void;

        case ValDef(_, _, _, Tree rhs):
            Symbol symbol = tree.symbol();
            locals.add(symbol);
            ALocation location = ALocation.Local(symbol, false);
            return make.Store(tree, location, expression(rhs));

        default:
            return ACode.Drop(expression(tree), tree.type());
        }
    }

    //########################################################################
    // Private Methods - Translating expressions

    /** Translates the expressions. */
    private ACode[] expression(Tree[] trees) {
        ACode[] codes = new ACode[trees.length];
        for (int i = 0; i < codes.length; i++) codes[i] = expression(trees[i]);
        return codes;
    }

    /** Translates the expression. */
    private ACode expression(Tree tree) {
        switch (tree) {

        case LabelDef(_, Ident[] idents, Tree rhs):
            Symbol[] locals = Tree.symbolOf(idents);
            return make.Label(tree, tree.symbol(), locals, expression(rhs));

        case Block(Tree[] statements):
            if (statements.length == 0) return make.Void;
            int statement_count = statements.length - 1;
            List locals = new ArrayList();
            ACode[] codes = statement(locals,statements,0, statement_count);
            ACode value = expression(statements[statement_count]);
            if (locals.size() == 0 && codes.length == 0) return value;
            Symbol[] symbols =
                (Symbol[])locals.toArray(new Symbol[locals.size()]);
            return make.Block(tree, symbols, codes, value);

        case Assign(Tree lhs, Tree rhs):
            return make.Block(tree, Symbol.EMPTY_ARRAY, new ACode[] {
                make.Store(tree, location(lhs), expression(rhs))},
                make.Void);

        case If(Tree cond, Tree thenp, Tree elsep):
            ACode test = expression(cond);
            return make.If(tree, test, expression(thenp), expression(elsep));

        case Switch(Tree test, int[] tags, Tree[] bodies, Tree otherwise):
            int[][] tagss = new int[tags.length][];
            for (int i = 0; i < tagss.length; i++)
                tagss[i] = new int[] {tags[i]};
            ACode[] codes = new ACode[bodies.length + 1];
            for (int i = 0; i < bodies.length; i++)
                codes[i] = expression(bodies[i]);
            codes[tags.length] = expression(otherwise);
            return make.Switch(tree, expression(test), tagss, codes);

        case Return(Tree value):
            return make.Return(tree, tree.symbol(), expression(value));

        case Throw(Tree value):
            return make.Throw(tree, expression(value));

        case New(Template(Tree[] bases, _)):
            switch (bases[0]) {
            case Apply(TypeApply(Tree fun, Tree[] targs), Tree[] vargs):
                return apply(tree, method(fun), targs, vargs);
            case Apply(Tree fun, Tree[] vargs):
                return apply(tree, method(fun), Tree.EMPTY_ARRAY, vargs);
            default:
                throw Debug.abort("illegal case", bases[0]);
            }

        case Apply(TypeApply(Tree fun, Tree[] targs), Tree[] vargs):
            return apply(tree, fun, targs, vargs);
        case Apply(Tree fun, Tree[] vargs):
            return apply(tree, fun, Tree.EMPTY_ARRAY, vargs);

        case Super(_, _):
        case This(_):
            return make.This(tree, tree.symbol());

        case Select(_, _):
            return make.Load(tree, location(tree));

        case Ident(_):
            if (tree.symbol() == definitions.NULL)
                return make.Constant(tree, make.NULL);
            if (tree.symbol() == definitions.ZERO)
                return make.Constant(tree, make.ZERO);
            return make.Load(tree, location(tree));

        case Literal(Object value):
            return make.Constant(tree, constant(value));

        default:
            throw Debug.abort("illegal case", tree);
        }
    }

    /** Translates the application. */
    private ACode apply(Tree tree, Tree fun, Tree[] targs, Tree[] vargs) {
        switch (fun) {
        case Ident(_):
            if ("".equals("")) return ACode.Void; // !!!
            Symbol symbol = tree.symbol();
            assert symbol.isLabel() && targs.length == 0: tree; // !!!
            return make.Goto(tree, symbol, expression(vargs));
        }
        return apply(tree, method(fun), targs, vargs);
    }

    /** Translates the application. */
    private ACode apply(Tree tree, AFunction function,Tree[]targs,Tree[]vargs){
        return make.Apply(tree, function,Tree.typeOf(targs),expression(vargs));
    }

    //########################################################################
    // Private Methods - Translating functions

    /** Translates the method. */
    private AFunction method(Tree tree) {
        switch (tree) {
        case Select(Tree qualifier, _):
            Symbol symbol = tree.symbol();
            if (symbol.isJava() && symbol.owner().isModuleClass())
                return AFunction.Method(make.Void, symbol, AInvokeStyle.Static); // !!! qualifier is ignored !
            ACode object = expression(qualifier);
            return AFunction.Method(object, symbol, invokeStyle(qualifier));
        case Ident(_):
            Symbol symbol = tree.symbol();
            assert symbol.isInitializer(); // !!!
            return AFunction.Method(make.Void, symbol, AInvokeStyle.New);
        default:
            throw Debug.abort("illegal case", tree);
        }
    }

    /** Returns the InvokeStyle to use for the qualifier. */
    private AInvokeStyle invokeStyle(Tree qualifier) {
        switch (qualifier) {
        case Super(_, _):
            return AInvokeStyle.Static;
        default:
            return AInvokeStyle.Dynamic;
        }
    }

    //########################################################################
    // Private Methods - Translating locations

    /** Translates the location. */
    private ALocation location(Tree tree) {
        switch (tree) {

        case Select(Tree qualifier, _):
            Symbol symbol = tree.symbol();
            if (symbol.isModule())
                return ALocation.Module(symbol); // !!! qualifier is ignored !
            if (symbol.isJava() && symbol.owner().isModuleClass())
                return ALocation.Field(make.Void, symbol, true); // !!! qualifier is ignored !
            return ALocation.Field(expression(qualifier), symbol, false);

        case Ident(_):
            Symbol symbol = tree.symbol();
            if (symbol.isModule()) return ALocation.Module(symbol);
            return ALocation.Local(symbol, symbol.isParameter());

        default:
            throw Debug.abort("illegal case", tree);
        }
    }

    //########################################################################
    // Private Methods - Translating constants

    /** Translates the constant. */
    private AConstant constant(Object value) {
        if (value instanceof Boolean  ) return make.BOOLEAN((Boolean  )value);
        if (value instanceof Byte     ) return make.BYTE   (((Byte    )value));
        if (value instanceof Short    ) return make.SHORT  ((Short    )value);
        if (value instanceof Character) return make.CHAR   ((Character)value);
        if (value instanceof Integer  ) return make.INT    ((Integer  )value);
        if (value instanceof Long     ) return make.LONG   ((Long     )value);
        if (value instanceof Float    ) return make.FLOAT  ((Float    )value);
        if (value instanceof Double   ) return make.DOUBLE ((Double   )value);
        if (value instanceof String   ) return make.STRING ((String   )value);
        throw Debug.abort("illegal constant", value +" -- "+ value.getClass());
    }

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