All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.redhat.ceylon.compiler.java.codegen.CeylonVisitor Maven / Gradle / Ivy

There is a newer version: 1.3.3
Show newest version
/*
 * Copyright Red Hat Inc. and/or its affiliates and other contributors
 * as indicated by the authors tag. All rights reserved.
 *
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
 * of the GNU General Public License version 2.
 * 
 * This particular file is subject to the "Classpath" exception as provided in the 
 * LICENSE file that accompanied this code.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT A
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License,
 * along with this distribution; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA  02110-1301, USA.
 */

package com.redhat.ceylon.compiler.java.codegen;

import static com.redhat.ceylon.langtools.tools.javac.code.Flags.FINAL;
import static com.redhat.ceylon.langtools.tools.javac.code.Flags.PRIVATE;
import static com.redhat.ceylon.langtools.tools.javac.code.Flags.PUBLIC;
import static com.redhat.ceylon.langtools.tools.javac.code.Flags.STATIC;
import static com.redhat.ceylon.langtools.tools.javac.code.Flags.TRANSIENT;

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

import com.redhat.ceylon.common.Backend;
import com.redhat.ceylon.compiler.java.codegen.Naming.DeclNameFlag;
import com.redhat.ceylon.compiler.java.codegen.Naming.SyntheticName;
import com.redhat.ceylon.compiler.java.codegen.recovery.Drop;
import com.redhat.ceylon.compiler.java.codegen.recovery.HasErrorException;
import com.redhat.ceylon.compiler.java.codegen.recovery.TransformationPlan;
import com.redhat.ceylon.compiler.typechecker.tree.CustomTree;
import com.redhat.ceylon.compiler.typechecker.tree.Node;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.Return;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.Statement;
import com.redhat.ceylon.compiler.typechecker.tree.Visitor;
import com.redhat.ceylon.compiler.typechecker.util.NativeUtil;
import com.redhat.ceylon.langtools.tools.javac.tree.JCTree;
import com.redhat.ceylon.langtools.tools.javac.tree.JCTree.JCExpression;
import com.redhat.ceylon.langtools.tools.javac.tree.JCTree.JCStatement;
import com.redhat.ceylon.langtools.tools.javac.util.List;
import com.redhat.ceylon.langtools.tools.javac.util.ListBuffer;
import com.redhat.ceylon.langtools.tools.javac.util.Name;
import com.redhat.ceylon.model.loader.NamingBase.Suffix;
import com.redhat.ceylon.model.loader.model.OutputElement;
import com.redhat.ceylon.model.typechecker.model.Class;
import com.redhat.ceylon.model.typechecker.model.ClassOrInterface;
import com.redhat.ceylon.model.typechecker.model.Constructor;
import com.redhat.ceylon.model.typechecker.model.Declaration;
import com.redhat.ceylon.model.typechecker.model.Interface;
import com.redhat.ceylon.model.typechecker.model.Parameter;
import com.redhat.ceylon.model.typechecker.model.Type;
import com.redhat.ceylon.model.typechecker.model.TypeDeclaration;
import com.redhat.ceylon.model.typechecker.model.TypeParameter;
import com.redhat.ceylon.model.typechecker.model.Value;

public class CeylonVisitor extends Visitor {
    protected final CeylonTransformer gen;
    private final ToplevelAttributesDefinitionBuilder topattrBuilder;
    ListBuffer defs;
    ClassDefinitionBuilder classBuilder;
    boolean inInitializer = false;
    final LabelVisitor lv;
    private final GetterSetterPairingVisitor getterSetterPairing;
    private Tree.CompilationUnit currentCompilationUnit = null;
    
    /** For compilation units 
     * @param lv */
    public CeylonVisitor(CeylonTransformer ceylonTransformer, ToplevelAttributesDefinitionBuilder topattrBuilder, LabelVisitor lv, GetterSetterPairingVisitor gspv) {
        this.gen = ceylonTransformer;
        this.gen.visitor = this;
        this.defs = new ListBuffer();
        this.topattrBuilder = topattrBuilder;
        this.classBuilder = null;
        this.lv = lv;
        this.getterSetterPairing = gspv;
    }



    public void handleException(Exception e, Node that) {
        if (e instanceof BugException) {
            ((BugException)e).addError(that);
        } else {
            that.addError(new CodeGenError(that, e.getMessage(), Backend.Java, e));
        }
    }

    /*
     * Compilation Unit
     */

    public void visit(Tree.TypeAliasDeclaration decl){
        TransformationPlan plan = gen.errors().hasDeclarationAndMarkBrokenness(decl);
        if (plan instanceof Drop) {
            return;
        }
        int annots = gen.checkCompilerAnnotations(decl, defs);

        if (Decl.withinClassOrInterface(decl)) {
            if (Decl.withinInterface(decl)) {
                classBuilder.getCompanionBuilder((Interface)decl.getDeclarationModel().getContainer()).defs(gen.classGen().transform(decl));
            } else {
                classBuilder.defs(gen.classGen().transform(decl));
            }
        } else {
            appendList(gen.classGen().transform(decl));
        }
        gen.resetCompilerAnnotations(annots);
    }

    public void visit(Tree.SequenceType that) {
        // Ignore sequence types
    }

    public void visit(Tree.ImportList that) {
        //append(gen.transform(that));
    }

    public void visit(Tree.ClassOrInterface decl) {
        TransformationPlan plan = gen.errors().hasDeclarationAndMarkBrokenness(decl);
        if (plan instanceof Drop) {
            return;
        }
        if (skipHeaderMergeLater(decl)) {
            return;
        }
        // To accept this class it is either not native or native for this backend
        if (!acceptDeclaration(decl))
            return;
        int annots = gen.checkCompilerAnnotations(decl, defs);

        if (Decl.withinClassOrInterface(decl)) {
            if (Decl.withinInterface(decl)) {
                classBuilder.getCompanionBuilder((Interface)decl.getDeclarationModel().getContainer()).defs(gen.classGen().transform(decl));
            } else {
                classBuilder.defs(gen.classGen().transform(decl));
            }
        } else {
            appendList(gen.classGen().transform(decl));
        }
        gen.resetCompilerAnnotations(annots);
    }

    CtorDelegation ctorDelegation(Constructor ctorModel, Declaration delegatedDecl, HashMap broken) {
        CtorDelegation b = broken.get(delegatedDecl);
        if (b != null) {
            return b;
        } else {
            return new CtorDelegation(ctorModel, delegatedDecl);
        }
    }
    
    public void visit(Tree.ClassBody that) {
        // Transform executable statements and declarations in the body
        // except constructors. Record how constructors delegate.
        HashMap delegates = new HashMap();
        java.util.List stmts = getBodyStatements(that);
        HashMap broken = new HashMap();
        for (Tree.Statement stmt : stmts) {
            if (stmt instanceof Tree.Constructor) {
                Tree.Constructor ctor = (Tree.Constructor)stmt;
                Constructor ctorModel = ctor.getConstructor();
                if (gen.errors().hasDeclarationAndMarkBrokenness(ctor) instanceof Drop) {
                    broken.put(ctorModel, CtorDelegation.brokenDelegation(ctorModel));
                    continue;
                }
                classBuilder.getInitBuilder().constructor(ctor);
                if (ctor.getDelegatedConstructor() != null) {
                    // error recovery
                    if(ctor.getDelegatedConstructor().getInvocationExpression() != null){
                        Tree.ExtendedTypeExpression p = (Tree.ExtendedTypeExpression)ctor.getDelegatedConstructor().getInvocationExpression().getPrimary();
                        Declaration delegatedDecl = p.getDeclaration();
                        delegates.put(ctorModel, ctorDelegation(ctorModel, delegatedDecl, broken));
                    }
                } else {
                    // implicitly delegating to superclass initializer
                    Type et = Decl.getConstructedClass(ctorModel).getExtendedType();
                    if (et!=null) {
                        Declaration delegatedDecl = et.getDeclaration();
                        delegates.put(ctorModel, ctorDelegation(ctorModel, delegatedDecl, broken));
                    }
                }
            } else if (stmt instanceof Tree.Enumerated) {
                Tree.Enumerated singleton = (Tree.Enumerated)stmt;
                Constructor ctorModel = singleton.getEnumerated();
                if (gen.errors().hasDeclarationAndMarkBrokenness(singleton) instanceof Drop) {
                    broken.put(ctorModel, CtorDelegation.brokenDelegation(ctorModel));
                    continue;
                }
                classBuilder.getInitBuilder().singleton(singleton);
                
                 if (singleton.getDelegatedConstructor() != null) {
                    Tree.ExtendedTypeExpression p = (Tree.ExtendedTypeExpression)singleton.getDelegatedConstructor().getInvocationExpression().getPrimary();
                    Declaration delegatedDecl = p.getDeclaration();
                    delegates.put(ctorModel, ctorDelegation(ctorModel, delegatedDecl, broken));
                } else {
                    // implicitly delegating to superclass initializer
                    Type et = Decl.getConstructedClass(ctorModel).getExtendedType();
                    if (et!=null) {
                        Declaration delegatedDecl = et.getDeclaration();
                        delegates.put(ctorModel, ctorDelegation(ctorModel, delegatedDecl, broken));
                    }
                }
            } else if (stmt instanceof Tree.SpecifierStatement
                    && ((Tree.SpecifierStatement)stmt).getRefinement()) {
                HasErrorException error = gen.errors().getFirstErrorBlock(stmt);
                if (error != null) {
                    classBuilder.broken();
                }
                stmt.visit(this);
            } else {
                
                HasErrorException error = gen.errors().getFirstErrorInitializer(stmt);
                if (error != null) {
                    append(gen.makeThrowUnresolvedCompilationError(error));
                } else {
                    stmt.visit(this);
                }
            }
        }
        
        // Now transform constructors
        for (Tree.Statement stmt : stmts) {
            if (stmt instanceof Tree.Constructor) {
                Tree.Constructor ctor = (Tree.Constructor)stmt;
                if (gen.errors().hasDeclarationError(ctor) instanceof Drop) {
                    continue;
                }
                transformConstructor(ctor, 
                        ctor.getParameterList(), 
                        ctor.getDelegatedConstructor(),
                        ctor.getBlock(),
                        ctor.getConstructor(), 
                        delegates);
            } else if (stmt instanceof Tree.Enumerated) {
                Tree.Enumerated ctor = (Tree.Enumerated)stmt;
                if (gen.errors().hasDeclarationError(ctor) instanceof Drop) {
                    continue;
                }
                transformSingletonConstructor(delegates, ctor);
            }
        }
    }

    private java.util.List getBodyStatements(Tree.Body that) {
        java.util.List stmts = that.getStatements();
        if (classBuilder.getForDefinition().isNative()) {
            // In case of a native implementation we look for its header
            Tree.Declaration hdr = getHeaderDeclaration(classBuilder.getForDefinition());
            if (hdr != null) {
                stmts = NativeUtil.mergeStatements(that, hdr, Backend.Java);
            }
        }
        return stmts;
    }

    protected void transformSingletonConstructor(
            HashMap delegates, Tree.Enumerated ctor) {
        // generate a constructor
        transformConstructor(ctor, 
                null,//ctor.getParameterList(), 
                ctor.getDelegatedConstructor(),
                ctor.getBlock(),
                ctor.getEnumerated(), 
                delegates);
        Class clz = Decl.getConstructedClass(ctor.getEnumerated());
        Value singletonModel = ctor.getDeclarationModel();
        // generate a field
        AttributeDefinitionBuilder adb = AttributeDefinitionBuilder
        .singleton(gen, 
                null,//gen.naming.makeTypeDeclarationName(Decl.getConstructedClass(ctor.getEnumerated())), 
                null, 
                singletonModel.getName(), singletonModel, false);
        adb.modelAnnotations(gen.makeAtEnumerated());
        adb.modelAnnotations(gen.makeAtIgnore());
        adb.userAnnotations(gen.expressionGen().transformAnnotations(OutputElement.GETTER, ctor));
        adb.fieldAnnotations(gen.expressionGen().transformAnnotations(OutputElement.FIELD, ctor));
        adb.immutable();// not setter
        SyntheticName field = gen.naming.getValueConstructorFieldName(singletonModel);
        if (clz.isToplevel()) {
            adb.modifiers((singletonModel.isShared() ? PUBLIC : PRIVATE) | STATIC | FINAL);
            adb.initialValue(gen.make().NewClass(null, null, 
                    gen.naming.makeTypeDeclarationExpression(null, Decl.getConstructedClass(ctor.getEnumerated())), 
                    List.of(
                            gen.make().TypeCast(
                                    gen.naming.makeNamedConstructorType(ctor.getEnumerated(), false),
                            gen.makeNull())), null));
            classBuilder.defs(adb.build());
        } else if (clz.isClassMember()){
            adb.modifiers(singletonModel.isShared() ? 0 : PRIVATE);
            // lazy
            adb.initialValue(gen.makeNull());
            List l = List.of(
            gen.make().If(gen.make().Binary(JCTree.EQ, field.makeIdent(), gen.makeNull()),
                    gen.make().Exec(gen.make().Assign(field.makeIdent(),
                            gen.make().NewClass(null, null, 
                                    gen.naming.makeTypeDeclarationExpression(null, Decl.getConstructedClass(ctor.getEnumerated())), 
                                    List.of(
                                            gen.make().TypeCast(
                                                    gen.naming.makeNamedConstructorType(ctor.getEnumerated(), false),
                                            gen.makeNull())), null))),
                    null),
            gen.make().Return(field.makeIdent()));
            adb.getterBlock(gen.make().Block(0, l));
            classBuilder.getContainingClassBuilder().defs(gen.makeVar(PRIVATE | TRANSIENT, field, gen.naming.makeTypeDeclarationExpression(null, Decl.getConstructedClass(ctor.getEnumerated())), gen.makeNull()));
            classBuilder.getContainingClassBuilder().defs(adb.build());
        } else {
            // LOCAL
            
            classBuilder.after(gen.makeVar(FINAL, field, 
                    gen.naming.makeTypeDeclarationExpression(null, Decl.getConstructedClass(ctor.getEnumerated())), 
                    gen.make().NewClass(null, null, 
                            gen.naming.makeTypeDeclarationExpression(null, Decl.getConstructedClass(ctor.getEnumerated())), 
                            List.of(
                                    gen.make().TypeCast(
                                            gen.naming.makeNamedConstructorType(ctor.getEnumerated(), false),
                                    gen.makeNull())), null)));
            gen.naming.addVariableSubst(singletonModel, field.getName());
        }
    }
    
    private void transformConstructor(
            Tree.Declaration ctor, 
            Tree.ParameterList parameterList,
            Tree.DelegatedConstructor delegatedCtor, 
            Tree.Block block,
            Constructor ctorModel, Map delegates) {
        TransformationPlan plan = gen.errors().hasDeclarationAndMarkBrokenness(ctor);
        if (plan instanceof Drop) {
            return;
        }
        
        if (parameterList != null) {
            for (Parameter param : parameterList.getModel().getParameters()) {
                if (Naming.aliasConstructorParameterName(param.getModel())) {
                    gen.naming.addVariableSubst(param.getModel(), gen.naming.suffixName(Suffix.$param$, param.getName()));
                }
            }
        }
        
        final CtorDelegation delegation = delegates.get(ctorModel);
        
        ListBuffer stmts = ListBuffer.lb();
        boolean delegatedTo = CtorDelegation.isDelegatedTo(delegates, ctorModel);
        if (delegatedTo
                && !ctorModel.isAbstract()) {
            Tree.InvocationExpression chainedCtorInvocation;
            if (delegatedCtor != null) {
                chainedCtorInvocation = delegatedCtor.getInvocationExpression();
            } else {
                chainedCtorInvocation = null;
                
            }
            // We need to generate $delegation$ delegation constructor
            makeDelegationConstructor(ctor, parameterList, delegatedCtor, block, ctorModel,
                    delegation, chainedCtorInvocation);

            JCStatement delegateExpr;
            if (chainedCtorInvocation != null) {
                delegateExpr = gen.expressionGen().transformConstructorDelegation(chainedCtorInvocation, 
                        delegation.isSelfDelegation() ? delegation : new CtorDelegation(ctorModel, ctorModel), 
                        chainedCtorInvocation, classBuilder, !delegation.isSelfDelegation());
            } else {
                // In this case there is no extends clause in the source code
                // so we have to construct the argument list "by hand".
                ListBuffer arguments = ListBuffer.lb();
                for (TypeParameter tp : ((Class)delegation.getConstructor().getContainer()).getTypeParameters()) {
                    arguments.add(gen.makeReifiedTypeArgument(tp.getType()));
                }
                arguments.add(gen.naming.makeNamedConstructorName(delegation.getConstructor(), true));
                
                for (Parameter p : delegation.getConstructor().getFirstParameterList().getParameters()) {
                    arguments.add(gen.naming.makeName(p.getModel(), Naming.NA_IDENT));
                }
                delegateExpr = gen.make().Exec(gen.make().Apply(null, 
                        gen.naming.makeThis(),
                        arguments.toList()));
            }
            stmts.add(delegateExpr);
            
        } else if (delegatedCtor != null) {
            stmts.add(gen.expressionGen().transformConstructorDelegation(
                    delegatedCtor, delegation, delegatedCtor.getInvocationExpression(), classBuilder, false));
        } else {
            // no explicit extends clause
        }
        final boolean addBody;
        if (delegatedTo
                && (delegation.isAbstractSelfOrSuperDelegation())) {
            if (delegation.getConstructor().isAbstract()) {
                stmts.addAll(classBuilder.getInitBuilder().copyStatementsBetween(null, ctorModel));
                addBody = true;
            } else if (delegation.getExtendingConstructor() != null && delegation.getExtendingConstructor().isAbstract()){
                stmts.addAll(classBuilder.getInitBuilder().copyStatementsBetween(delegation.getExtendingConstructor(), ctorModel));
                addBody = true;
            } else {
                addBody = false;
            }
        } else if (delegation.isAbstractSelfDelegation()) {// delegating to abstract
            stmts.addAll(classBuilder.getInitBuilder().copyStatementsBetween(delegation.getExtendingConstructor(), ctorModel));
            addBody = true;
        } else if (delegation.isConcreteSelfDelegation()) {
            stmts.addAll(classBuilder.getInitBuilder().copyStatementsBetween(delegation.getExtendingConstructor(), ctorModel));
            addBody = true;
        } else {// super delegation
            stmts.addAll(classBuilder.getInitBuilder().copyStatementsBetween(null, ctorModel));
            addBody = true;
        }
        if (ctorModel.isAbstract() && !delegatedTo) {
            stmts.add(
                    gen.make().Throw(gen.make().NewClass(null,
                            List.nil(),
                            gen.make().QualIdent(gen.syms().ceylonUninvokableErrorType.tsym),
                            List.nil(),
                            null)));
        }
        List following = ctorModel.isAbstract() ? List.nil() : classBuilder.getInitBuilder().copyStatementsBetween(ctorModel, null);
        if (addBody) {
            if (following.isEmpty()) {
                stmts.addAll(gen.statementGen().transformBlock(block));
            } else {
                Name label = gen.naming.aliasName(Naming.Unfix.$return$.toString());
                Transformer prev = gen.statementGen().returnTransformer(gen.statementGen().new ConstructorReturnTransformer(label));
                try {
                    stmts.add(gen.make().Labelled(label,
                            gen.make().DoLoop(
                            gen.make().Block(0, gen.statementGen().transformBlock(block, true)), 
                            gen.make().Literal(false))));
                } finally {
                    gen.statementGen().returnTransformer(prev);
                }
            }
        }
        
        ThrowVisitor visitor = new ThrowVisitor();
        block.visit(visitor);
        if (!visitor.getDefinitelyReturnsViaThrow()) {
            stmts.addAll(following);
        }
        
        String ctorName = !Decl.isDefaultConstructor(ctorModel) ? gen.naming.makeTypeDeclarationName(ctorModel) : null;
        classBuilder.defs(gen.classGen().makeNamedConstructor(ctor, parameterList, ctorModel, classBuilder, Strategy.generateInstantiator(ctorModel),
                gen.classGen().transformConstructorDeclFlags(ctorModel), false,
                ctorName, stmts.toList(),
                DeclNameFlag.QUALIFIED));
    }



    /**
     * Make a {@code ...$delegation$} constructor, returning
     * @param ctor
     * @param ctorModel
     * @param delegatedTo
     * @param chainedCtorInvocation
     * @return
     */
    protected void makeDelegationConstructor(
            Tree.Declaration ctor,
            Tree.ParameterList parameterList,
            Tree.DelegatedConstructor delegatedCtor,
            Tree.Block block,
            Constructor ctorModel, CtorDelegation delegation,
            Tree.InvocationExpression chainedCtorInvocation) {
        
        // if this constructor is delegating to another concrete 
        // constructor in this class we need to actually delegate to a 
        // 3rd constructor (which delegates to the actual constructor
        // given in the source and then adds the executable initializer 
        // statements between this constructor and the delegated-to constructor)
        // delegating to a constructor in this class
        ListBuffer stmts = ListBuffer.lb();
        
        if (chainedCtorInvocation != null) {
            stmts.add(gen.expressionGen().transformConstructorDelegation(
                    delegatedCtor, 
                    delegation, chainedCtorInvocation, classBuilder, false));
        }
        
        stmts.addAll(classBuilder.getInitBuilder().copyStatementsBetween(
                delegation.getExtendingConstructor(), ctorModel));
        stmts.addAll(gen.statementGen().transformBlock(block));
        String ctorName = (!Decl.isDefaultConstructor(ctorModel) ? gen.naming.makeTypeDeclarationName(ctorModel, DeclNameFlag.DELEGATION) : Naming.Suffix.$delegation$.toString());
        classBuilder.defs(gen.classGen().makeNamedConstructor(ctor, parameterList, ctorModel, classBuilder, false, PRIVATE, true, ctorName, stmts.toList(),
                DeclNameFlag.QUALIFIED, DeclNameFlag.DELEGATION));
        
    }
    public void visit(Tree.InterfaceBody that) {
        java.util.List stmts = getBodyStatements(that);
        for (Tree.Statement stmt : stmts) {
            if (stmt instanceof Tree.Declaration
                    || stmt instanceof Tree.SpecifierStatement) {
                stmt.visit(this);
            } else if (stmt instanceof Tree.ExecutableStatement) {
                // ignore it: the Tree is malformed.
            } else {
                throw BugException.unhandledCase(stmt);
            }
        }
    }

    public void visit(Tree.ObjectDefinition decl) {
        TransformationPlan plan = gen.errors().hasDeclarationAndMarkBrokenness(decl);
        if (plan instanceof Drop) {
            return;
        }
        if (skipHeaderMergeLater(decl)) {
            return;
        }
        // To accept this object it is either not native or native for this backend
        if (!acceptDeclaration(decl))
            return;
        int annots = gen.checkCompilerAnnotations(decl, defs);
        if (Decl.withinClass(decl)) {
            classBuilder.defs(gen.classGen().transformObjectDefinition(decl, classBuilder));
        } else {
            appendList(gen.classGen().transformObjectDefinition(decl, null));
        }
        gen.resetCompilerAnnotations(annots);
    }

    public void visit(Tree.AttributeDeclaration decl){
        TransformationPlan plan = gen.errors().hasDeclarationAndMarkBrokenness(decl);
        if (plan instanceof Drop) {
            return;
        }
        // To accept this method it is either not native, native for this
        // backend or it's a native header with an implementation and there
        // is no native implementation specifically for this backend
        boolean accept = acceptDeclaration(decl);
        if (!accept)
            return;
        int annots = gen.checkCompilerAnnotations(decl, defs);
        if (Decl.withinClassOrInterface(decl) && !Decl.isLocalToInitializer(decl)) {
            // Class attributes
            gen.classGen().transform(decl, classBuilder);
        } else if (Decl.isToplevel(decl)) {
            topattrBuilder.add(decl);
        } else if ((Decl.isLocal(decl)) 
                && ((Decl.isCaptured(decl) && Decl.isVariable(decl))
                        || Decl.isTransient(decl)
                        || Decl.hasSetter(decl))) {
            // Captured local attributes get turned into an inner getter/setter class
            appendList(gen.transform(decl));
        } else {
            // All other local attributes
            appendList(gen.statementGen().transform(decl));
        }
        gen.resetCompilerAnnotations(annots);
    }

    public void visit(Tree.AttributeGetterDefinition decl){
        TransformationPlan plan = gen.errors().hasDeclarationAndMarkBrokenness(decl);
        if (plan instanceof Drop) {
            return;
        }
        if (!acceptDeclaration(decl))
            return;
        int annots = gen.checkCompilerAnnotations(decl, defs);
        if (Decl.withinClass(decl) && !Decl.isLocalToInitializer(decl)) {
            classBuilder.attribute(gen.classGen().transform(decl, false));
        } else if (Decl.withinInterface(decl) && !Decl.isLocalToInitializer(decl)) {
            classBuilder.attribute(gen.classGen().transform(decl, false));
            AttributeDefinitionBuilder adb = gen.classGen().transform(decl, true);
            if (decl.getDeclarationModel().isShared()) {
                adb.ignoreAnnotations();
            }
            classBuilder.getCompanionBuilder((Interface)decl.getDeclarationModel().getContainer()).attribute(adb);
        } else if (Decl.isToplevel(decl)) {
            topattrBuilder.add(decl);
        } else {
            appendList(gen.transform(decl));
        }
        gen.resetCompilerAnnotations(annots);
    }

    public void visit(final Tree.AttributeSetterDefinition decl) {
        TransformationPlan plan = gen.errors().hasDeclarationAndMarkBrokenness(decl);
        if (plan instanceof Drop) {
            return;
        }
        TransformationPlan getterPlan = gen.errors().hasDeclarationAndMarkBrokenness(getterSetterPairing.getGetter(decl));
        if (getterPlan instanceof Drop) {
            // For setters we also give up if the getter has a declaration error
            // because there's little chance we'll be able to generate a correct setter
            return;
        }
        if (!acceptDeclaration(decl))
            return;
        int annots = gen.checkCompilerAnnotations(decl, defs);
        if (Decl.withinClass(decl) && !Decl.isLocalToInitializer(decl)) {
            classBuilder.attribute(gen.classGen().transform(decl, false));
        } else if (Decl.withinInterface(decl)) {
            classBuilder.attribute(gen.classGen().transform(decl, false));
            AttributeDefinitionBuilder adb = gen.classGen().transform(decl, true);
            if (decl.getDeclarationModel().isShared()) {
                adb.ignoreAnnotations();
            }
            classBuilder.getCompanionBuilder((Interface)decl.getDeclarationModel().getContainer()).attribute(adb);
        } else if (Decl.isToplevel(decl)) {
            topattrBuilder.add(decl);
        } else {
            appendList(gen.transform(decl));
        }
        gen.resetCompilerAnnotations(annots);
    }

    public void visit(Tree.AnyMethod decl) {
        TransformationPlan plan = gen.errors().hasDeclarationAndMarkBrokenness(decl);
        if (plan instanceof Drop) {
            return;
        }
        if (!acceptDeclaration(decl))
            return;
        int annots = gen.checkCompilerAnnotations(decl, defs);
        if (Decl.withinClassOrInterface(decl)
                && (!Decl.isDeferred(decl) || Decl.isCaptured(decl))) {
            classBuilder.method(decl, plan);
        } else {
            appendList(gen.classGen().transformWrappedMethod(decl, plan));
        }
        gen.resetCompilerAnnotations(annots);
    }

    /*
     * Class or Interface
     */

    // Class Initializer parameter
    public void visit(Tree.Parameter param) {
        // Ignore
    }

    public void visit(Tree.Block b) {
        b.visitChildren(this);
    }

    public void visit(Tree.Annotation ann) {
        // Handled in AbstractTransformer.makeAtAnnotations
    }
    public void visit(Tree.AnonymousAnnotation ann) {
        // Handled in AbstractTransformer.makeAtAnnotations
    }

    // FIXME: also support Tree.SequencedTypeParameter
    public void visit(Tree.TypeParameterDeclaration param) {
        TypeDeclaration container = (TypeDeclaration)param.getDeclarationModel().getContainer();
        classBuilder.typeParameter(param);
        ClassDefinitionBuilder companionBuilder = classBuilder.getCompanionBuilder(container);
        if(companionBuilder != null)
            companionBuilder.typeParameter(param);
    }

    public void visit(Tree.ExtendedType extendedType) {
        ClassOrInterface forDefinition = classBuilder.getForDefinition();
        Type thisType = forDefinition != null ? forDefinition.getType() : null;
        Type extended = extendedType.getType().getTypeModel();
        if (extended.getDeclaration() instanceof Constructor) {
            extended = extended.getQualifyingType();
        }
        classBuilder.extending(thisType, extended);
        gen.expressionGen().transformSuperInvocation(extendedType, classBuilder);
    }

    public void visit(Tree.ClassSpecifier extendedType) {
        // ignore this bit entirely, that's for class aliases and we don't reflect this in the AST,
        // only in type model annotations and that info comes from the model
    }

    // FIXME: implement
    public void visit(Tree.TypeConstraint l) {
    }

    public void visit(Tree.CaseTypes t){
        // FIXME: ignore for now, probably we'll need to add an annotation for it in M2.
        // no need to warn here since the typechecker already warns for M1's unsupported status
        // we do need to avoid visiting its children since that leads to invalid code otherwise as
        // other node types are handled as if they were the body of the class
    }

    /*
     * Statements
     */

    public void visit(Tree.Return ret) {
        append(gen.statementGen().transform(ret));
    }

    public void visit(Tree.IfStatement stat) {
        appendList(gen.statementGen().transform(stat));
    }

    public void visit(Tree.WhileStatement stat) {
        appendList(gen.statementGen().transform(stat));
    }

    //    public void visit(Tree.DoWhileStatement stat) {
    //        append(gen.statementGen().transform(stat));
    //    }

    public void visit(Tree.ForStatement stat) {
        appendList(gen.statementGen().transform(stat));
    }

    public void visit(Tree.Break stat) {
        appendList(gen.statementGen().transform(stat));
    }

    public void visit(Tree.Continue stat) {
        append(gen.statementGen().transform(stat));
    }

    public void visit(Tree.SpecifierStatement op) {
        appendList(gen.classGen().transformRefinementSpecifierStatement(op, classBuilder));
    }

    public void visit(Tree.OperatorExpression op) {
        // FIXME: Do we really have operators not handled elsewhere than here?
        append(gen.at(op).Exec(gen.expressionGen().transformExpression(op)));
    }

    public void visit(Tree.Expression tree) {
        // FIXME: Do we really have expressions not handled elsewhere than here?
        append(gen.at(tree).Exec(gen.expressionGen().transformExpression(tree)));
    }

    // FIXME: I think those should just go in transformExpression no?
    public void visit(Tree.PostfixOperatorExpression expr) {
        append(gen.expressionGen().transform(expr));
    }

    public void visit(Tree.PrefixOperatorExpression expr) {
        append(gen.expressionGen().transform(expr));
    }

    public void visit(Tree.ExpressionStatement tree) {
        append(gen.expressionGen().transform(tree));
    }

    /*
     * Expression - Invocations
     */

    public void visit(Tree.ObjectExpression expr) {
        append(gen.expressionGen().transform(expr));
    }

    public void visit(Tree.InvocationExpression expr) {
        append(gen.expressionGen().transform(expr));
    }

    public void visit(Tree.QualifiedMemberExpression access) {
        append(gen.expressionGen().transform(access));
    }

    public void visit(Tree.BaseMemberExpression access) {
        append(gen.expressionGen().transform(access));
    }

    public void visit(Tree.QualifiedTypeExpression access) {
        append(gen.expressionGen().transform(access));
    }

    public void visit(Tree.BaseTypeExpression access) {
        append(gen.expressionGen().transform(access));
    }

    /*
     * Expression - Terms
     */

    public void visit(Tree.IndexExpression access) {
        append(gen.expressionGen().transform(access));
    }

    public void visit(Tree.This expr) {
        append(gen.expressionGen().transform(expr));
    }

    public void visit(Tree.Super expr) {
        append(gen.expressionGen().transform(expr));
    }

    public void visit(Tree.Outer expr) {
        append(gen.expressionGen().transform(expr));
    }

    public void visit(Tree.Package that) {
        // this is only used as qualifier, and we can consider it a empty qualifier, so we ignore it
    }

    public void visit(Tree.IdenticalOp op) {
        append(gen.expressionGen().transform(op));
    }

    // FIXME: port dot operator?
    public void visit(Tree.NotEqualOp op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.NotOp op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.OfOp op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.AssignOp op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.IfExpression op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.LetExpression op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.SwitchExpression op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.IsOp op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.InOp op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.DefaultOp op) {
        append(gen.expressionGen().transform(op, null));
    }

    public void visit(Tree.ThenOp op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.Nonempty op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.Exists op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.RangeOp op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.SegmentOp op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.EntryOp op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.LogicalOp op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.UnaryOperatorExpression op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.PositiveOp op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.NegativeOp op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.EqualOp op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.ScaleOp op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.BitwiseOp op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.ComparisonOp op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.CompareOp op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.ArithmeticOp op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.PowerOp op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.SumOp op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.DifferenceOp op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.RemainderOp op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.WithinOp op) {
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.ArithmeticAssignmentOp op){
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.BitwiseAssignmentOp op){
        append(gen.expressionGen().transform(op));
    }

    public void visit(Tree.LogicalAssignmentOp op){
        append(gen.expressionGen().transform(op));
    }

    // NB spec 1.3.11 says "There are only two types of numeric
    // literals: literals for Integers and literals for Floats."
    public void visit(Tree.NaturalLiteral lit) {
        append(gen.expressionGen().transform(lit));
    }

    public void visit(Tree.FloatLiteral lit) {
        append(gen.expressionGen().transform(lit));
    }

    public void visit(Tree.CharLiteral lit) {
        append(gen.expressionGen().transform(lit));
    }

    public void visit(Tree.StringLiteral string) {
        append(gen.expressionGen().transform(string));
    }

    public void visit(Tree.QuotedLiteral string) {
        append(gen.expressionGen().transform(string));
    }

    public void visit(Tree.TypeLiteral that) {
        append(gen.expressionGen().transform(that));
    }

    public void visit(Tree.MemberLiteral that) {
        append(gen.expressionGen().transform(that));
    }

    public void visit(Tree.ModuleLiteral that) {
        append(gen.expressionGen().transform(that));
    }

    public void visit(Tree.PackageLiteral that) {
        append(gen.expressionGen().transform(that));
    }

    // FIXME: port TypeName?
    public void visit(Tree.InitializerExpression value) {
        // FIXME: is this even used?
        append(gen.expressionGen().transformExpression(value.getExpression()));
    }

    public void visit(Tree.SequenceEnumeration value) {
        append(gen.expressionGen().transform(value));
    }

    public void visit(Tree.Tuple value) {
        append(gen.expressionGen().transform(value));
    }

    // FIXME: port Null?
    // FIXME: port Condition?
    // FIXME: port Subscript?
    // FIXME: port LowerBoud?
    // FIXME: port EnumList?
    public void visit(Tree.StringTemplate expr) {
        append(gen.expressionGen().transformStringExpression(expr));
    }

    public void visit(Tree.Throw throw_) {
        append(gen.statementGen().transform(throw_));
    }

    public void visit(Tree.TryCatchStatement t) {
        append(gen.statementGen().transform(t));
    }

    public void visit(Tree.SwitchStatement switch_) {
        append(gen.statementGen().transform(switch_));
    }

    public void visit(Tree.FunctionArgument fn) {
        append(gen.expressionGen().transform(fn, fn.getTypeModel()));
    }

    public void visit(Tree.ModuleDescriptor that) {
        appendList(gen.transformModuleDescriptor(that));
    }
    public void visit(Tree.PackageDescriptor that) {
        appendList(gen.transformPackageDescriptor(that));
    }

    public void visit(Tree.Assertion that) {
        appendList(gen.statementGen().transform(that));
    }

    public void visit(Tree.Destructure that) {
        appendList(gen.statementGen().transform(that));
    }

    public void visit(Tree.Dynamic that) {
        // We should never get here since the error should have been 
        // reported by the UnsupportedVisitor and the containing statement
        // replaced with a throw.
        append(makeDynamicUnsupportedError(that));
    }

    public void visit(Tree.DynamicModifier that) {
        // We should never get here since the error should have been 
        // reported by the UnsupportedVisitor and the containing statement
        // replaced with a throw.
        append(makeDynamicUnsupportedError(that));
    }

    public void visit(Tree.DynamicClause that) {
        // We should never get here since the error should have been 
        // reported by the UnsupportedVisitor and the containing statement
        // replaced with a throw.
        append(gen.at(that).Exec(makeDynamicUnsupportedError(that)));
    }

    public void visit(Tree.DynamicStatement that) {
        // We should never get here since the error should have been 
        // reported by the UnsupportedVisitor and the containing statement
        // replaced with a throw.
        append(gen.at(that).Exec(makeDynamicUnsupportedError(that)));
    }

    public void visit(Tree.Variable that) {
        if(that instanceof CustomTree.GuardedVariable)
            append(gen.statementGen().transform((CustomTree.GuardedVariable)that));
        else
            super.visit(that);
    }
    
    private JCExpression makeDynamicUnsupportedError(Node that) {
        return gen.makeErroneous(that, UnsupportedVisitor.DYNAMIC_UNSUPPORTED_ERR);
    }
    
    public void visit(Tree.CompilationUnit cu) {
        currentCompilationUnit = cu;
        // Figure out all the local ids
        gen.naming.assignNames(cu);
        super.visit(cu);
        currentCompilationUnit = null;
        String arg = CodegenUtil.getCompilerAnnotationArgument(cu, "die");
        if (arg != null) {
            if (arg.isEmpty()) {
                arg = "java.lang.RuntimeException";
            }
            try {
                java.lang.Class exceptionClass = (java.lang.Class)java.lang.Class.forName(arg, true, getClass().getClassLoader());
                Throwable exception = exceptionClass.newInstance();
                if (exception instanceof RuntimeException) {                    
                    throw (RuntimeException)exception;
                } else if (exception instanceof Error) {
                    throw (Error)exception;
                } else {
                    throw new RuntimeException(exception);
                }
            } catch (ReflectiveOperationException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public void visit(Tree.CompilerAnnotation ca) {
        // Don't end up visiting the String literal argument of the compiler annotation!
    }

    /**
     * Gets all the results which were appended during the visit
     * @return The results
     * 
     * @see #getSingleResult()
     */
    public ListBuffer getResult() {
        return defs;
    }

    /**
     * Returns the single result, or null if there was more than one result
     * @return The result
     * 
     * @see #getResult()
     */
    @SuppressWarnings("unchecked")
    public  K getSingleResult() {
        if (defs.size() != 1) {
            return null;
        }
        return (K) defs.first();
    }

    public boolean hasResult() {
        return (defs.size() > 0);
    }

    void append(JCTree x) {
        if (inInitializer) {
            classBuilder.getInitBuilder().init((JCTree.JCStatement)x);
        } else {
            defs.append(x);
        }
    }

    void appendList(List xs) {
        for (JCTree x : xs) {
            append(x);
        }
    }

    // To accept a declaration it is either not native, native for this
    // backend or it's a native header with an implementation and there
    // is no native implementation specifically for this backend
    private boolean acceptDeclaration(Tree.Declaration decl) {
        return NativeUtil.isForBackend(decl, Backend.Java)
                || (NativeUtil.isHeaderWithoutBackend(decl, Backend.Java)
                        && NativeUtil.isImplemented(decl));
    }
    
    private boolean skipHeaderMergeLater(Tree.Declaration decl) {
        if (NativeUtil.isNativeHeader(decl)) {
            if (NativeUtil.isHeaderWithoutBackend(decl, Backend.Java)
                    && NativeUtil.isImplemented(decl)) {
                return false;
            }
            return true;
        } else {
            return false;
        }
    }
    
    // Traverse the entire tree looking for the header node
    // that belongs to the given implementation declaration
    private Tree.Declaration getHeaderDeclaration(final Declaration decl) {
        class ClassVisitor extends Visitor {
            Tree.Declaration hdr = null;

            @Override
            public void visit(Tree.ClassOrInterface that) {
                checkForHeader(that);
                super.visit(that);
            }
            @Override
            public void visit(Tree.ObjectDefinition that) {
                checkForHeader(that);
                super.visit(that);
            }
            private void checkForHeader(Tree.Declaration that) {
                Declaration v = that.getDeclarationModel();
                if (v.isNativeHeader() &&
                        v.getQualifiedNameString().equals(decl.getQualifiedNameString())) {
                    hdr = that;
                }
            }
        };
        ClassVisitor v = new ClassVisitor();
        v.visit(currentCompilationUnit);
        return v.hdr;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy