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

com.redhat.ceylon.compiler.java.codegen.CeylonTransformer 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.compiler.typechecker.tree.TreeUtil.isForBackend;

import java.util.Iterator;

import com.redhat.ceylon.common.Backend;
import com.redhat.ceylon.compiler.java.codegen.recovery.HasErrorException;
import com.redhat.ceylon.compiler.java.loader.SourceDeclarationVisitor;
import com.redhat.ceylon.compiler.typechecker.context.PhasedUnit;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.ClassOrInterface;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.CompilationUnit;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.Declaration;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.ModuleDescriptor;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.PackageDescriptor;
import com.redhat.ceylon.javax.tools.JavaFileObject;
import com.redhat.ceylon.langtools.tools.javac.code.Flags;
import com.redhat.ceylon.langtools.tools.javac.main.OptionName;
import com.redhat.ceylon.langtools.tools.javac.tree.JCTree;
import com.redhat.ceylon.langtools.tools.javac.tree.JCTree.JCAnnotation;
import com.redhat.ceylon.langtools.tools.javac.tree.JCTree.JCBlock;
import com.redhat.ceylon.langtools.tools.javac.tree.JCTree.JCCompilationUnit;
import com.redhat.ceylon.langtools.tools.javac.tree.JCTree.JCExpression;
import com.redhat.ceylon.langtools.tools.javac.tree.JCTree.JCImport;
import com.redhat.ceylon.langtools.tools.javac.tree.JCTree.JCMethodDecl;
import com.redhat.ceylon.langtools.tools.javac.tree.JCTree.JCModifiers;
import com.redhat.ceylon.langtools.tools.javac.tree.JCTree.JCNewClass;
import com.redhat.ceylon.langtools.tools.javac.tree.JCTree.JCStatement;
import com.redhat.ceylon.langtools.tools.javac.tree.JCTree.JCTypeParameter;
import com.redhat.ceylon.langtools.tools.javac.tree.JCTree.JCVariableDecl;
import com.redhat.ceylon.langtools.tools.javac.util.Context;
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.langtools.tools.javac.util.Options;
import com.redhat.ceylon.langtools.tools.javac.util.Position.LineMap;
import com.redhat.ceylon.compiler.typechecker.tree.TreeUtil;
import com.redhat.ceylon.model.loader.NamingBase.Suffix;
import com.redhat.ceylon.model.loader.model.OutputElement;
import com.redhat.ceylon.model.typechecker.model.FunctionOrValue;
import com.redhat.ceylon.model.typechecker.model.Parameter;
import com.redhat.ceylon.model.typechecker.model.Setter;
import com.redhat.ceylon.model.typechecker.model.TypedDeclaration;
import com.redhat.ceylon.model.typechecker.model.Value;

/**
 * Main transformer that delegates all transforming of ceylon to java to auxiliary classes.
 */
public class CeylonTransformer extends AbstractTransformer {
    private Options options;
    private LineMap map;
    private JavaFileObject fileObject;
    public int disableAnnotations = 0;
    static final int DISABLE_MODEL_ANNOS = 1<<0;
    static final int DISABLE_USER_ANNOS = 1<<1;
    CeylonVisitor visitor;
    
    public static CeylonTransformer getInstance(Context context) {
        CeylonTransformer trans = context.get(CeylonTransformer.class);
        if (trans == null) {
            trans = new CeylonTransformer(context);
            context.put(CeylonTransformer.class, trans);
        }
        return trans;
    }

    public CeylonTransformer(Context context) {
        super(context);
        setup(context);
    }

    private void setup(Context context) {
        options = Options.instance(context);
        // It's a bit weird to see "invokedynamic" set here,
        // but it has to be done before Resolve.instance().
        options.put("invokedynamic", "invokedynamic");
    }

    @Override
    public void setMap(LineMap map) {
        this.map = map;
    }

    @Override
    protected LineMap getMap() {
        return map;
    }

    public void setFileObject(JavaFileObject fileObject) {
        this.fileObject = fileObject;
    }
    
    public JavaFileObject getFileObject() {
        return fileObject;
    }

    /**
     * In this pass we only make an empty placeholder which we'll fill in the
     * EnterCeylon phase later on
     */
    public JCCompilationUnit makeJCCompilationUnitPlaceholder(Tree.CompilationUnit t, JavaFileObject file, String pkgName, PhasedUnit phasedUnit) {
        JCExpression pkg = pkgName != null ? getPackage(pkgName) : null;
        at(t);
        
        List defs = makeDefs(t);
        
        JCCompilationUnit topLev = new CeylonCompilationUnit(List. nil(), pkg, defs, null, null, null, null, t, phasedUnit);

        topLev.lineMap = getMap();
        topLev.sourcefile = file;
        topLev.isCeylonProgram = true;

        return topLev;
    }

    private enum WantedDeclaration {
        Normal, Annotation, AnnotationSequence;
    }
    
    private List makeDefs(CompilationUnit t) {
        final ListBuffer defs = new ListBuffer();
        
        t.visit(new SourceDeclarationVisitor(){
            @Override
            public void loadFromSource(Declaration decl) {
                if(!checkNative(decl))
                    return;
                long flags = decl instanceof Tree.AnyInterface ? Flags.INTERFACE : 0;
                String name = Naming.toplevelClassName("", decl);
                
                defs.add(makeClassDef(decl, flags, name, WantedDeclaration.Normal));
                if(decl instanceof Tree.AnyInterface){
                    String implName = Naming.getImplClassName(name);
                    defs.add(makeClassDef(decl, 0, implName, WantedDeclaration.Normal));
                }
                // only do it for Bootstrap where we control the annotations, because it's so dodgy ATM
                if(options.get(OptionName.BOOTSTRAPCEYLON) != null
                        && decl instanceof Tree.AnyClass
                        && TreeUtil.hasAnnotation(decl.getAnnotationList(), "annotation", decl.getUnit())){
                    String annotationName = Naming.suffixName(Suffix.$annotation$, name);
                    defs.add(makeClassDef(decl, Flags.ANNOTATION, annotationName, WantedDeclaration.Annotation));
                    
                    for(Tree.StaticType sat : ((Tree.AnyClass)decl).getSatisfiedTypes().getTypes()){
                        if(sat instanceof Tree.BaseType 
                                && ((Tree.BaseType) sat).getIdentifier().getText().equals("SequencedAnnotation")){
                            String annotationsName = Naming.suffixName(Suffix.$annotations$, name);
                            defs.add(makeClassDef(decl, Flags.ANNOTATION, annotationsName, WantedDeclaration.AnnotationSequence));
                        }
                    }
                }
            }

            private JCTree makeClassDef(Declaration decl, long flags, String name, WantedDeclaration wantedDeclaration) {
                ListBuffer typarams = new ListBuffer();
                if(decl instanceof Tree.ClassOrInterface){
                    Tree.ClassOrInterface classDecl = (ClassOrInterface) decl;
                    if(classDecl.getTypeParameterList() != null){
                        for(Tree.TypeParameterDeclaration typeParamDecl : classDecl.getTypeParameterList().getTypeParameterDeclarations()){
                            // we don't need a valid name, just a name, and making it BOGUS helps us find it later if it turns out
                            // we failed to reset everything properly
                            typarams.add(make().TypeParameter(names().fromString("BOGUS-"+typeParamDecl.getIdentifier().getText()), List.nil()));
                        }
                    }
                }

                return make().ClassDef(make().Modifiers(flags | Flags.PUBLIC), names().fromString(name), 
                        typarams.toList(), null, List.nil(), makeClassBody(decl, wantedDeclaration));
            }

            private List makeClassBody(Declaration decl, WantedDeclaration wantedDeclaration) {
                // only do it for Bootstrap where we control the annotations, because it's so dodgy ATM
                if(wantedDeclaration == WantedDeclaration.Annotation){
                    ListBuffer body = new ListBuffer();
                    for(Tree.Parameter param : ((Tree.ClassDefinition)decl).getParameterList().getParameters()){
                        String name;
                        
                        JCExpression type = make().TypeArray(make().Type(syms().stringType));
                        if(param instanceof Tree.InitializerParameter)
                            name = ((Tree.InitializerParameter)param).getIdentifier().getText();
                        else if(param instanceof Tree.ParameterDeclaration){
                            Tree.TypedDeclaration typedDeclaration = ((Tree.ParameterDeclaration)param).getTypedDeclaration();
                            name = typedDeclaration.getIdentifier().getText();
                            type = getAnnotationTypeFor(typedDeclaration.getType());
                        }else
                            name = "ERROR";
                        JCMethodDecl method
                            = make().MethodDef(make().Modifiers(Flags.PUBLIC), names().fromString(name), 
                                type,
                                List.nil(), 
                                List.nil(),
                                List.nil(), 
                                null, 
                                null);
                        body.append(method);
                    }
                    return body.toList();
                }
                if(wantedDeclaration == WantedDeclaration.AnnotationSequence){
                    String name = Naming.toplevelClassName("", decl);
                    String annotationName = Naming.suffixName(Suffix.$annotation$, name);
                    JCExpression type = make().TypeArray(make().Ident(names().fromString(annotationName)));
                    JCMethodDecl method
                            = make().MethodDef(make().Modifiers(Flags.PUBLIC), names().fromString("value"), 
                                type,
                                List.nil(), 
                                List.nil(),
                                List.nil(), 
                                null, 
                                null);
                    return List.of(method);
                }
                return List.nil();
            }

            private JCExpression getAnnotationTypeFor(Tree.Type type) {
                if(type instanceof Tree.BaseType){
                    String name = ((Tree.BaseType) type).getIdentifier().getText();
                    if(name.equals("String") || name.equals("Declaration"))
                        return make().Type(syms().stringType);
                    if(name.equals("Boolean"))
                        return make().Type(syms().booleanType);
                    if(name.equals("Integer"))
                        return make().Type(syms().longType);
                    if(name.equals("Float"))
                        return make().Type(syms().doubleType);
                    if(name.equals("Byte"))
                        return make().Type(syms().byteType);
                    if(name.equals("Character"))
                        return make().Type(syms().charType);
                    if(name.equals("Declaration")
                            || name.equals("ClassDeclaration")
                            || name.equals("InterfaceDeclaration")
                            || name.equals("ClassOrInterfaceDeclaration"))
                        return make().Type(syms().stringType);
                }
                if(type instanceof Tree.SequencedType){
                    return make().TypeArray(getAnnotationTypeFor(((Tree.SequencedType) type).getType()));
                }
                if(type instanceof Tree.SequenceType){
                    return make().TypeArray(getAnnotationTypeFor(((Tree.SequenceType) type).getElementType()));
                }
                if(type instanceof Tree.IterableType){
                    return make().TypeArray(getAnnotationTypeFor(((Tree.IterableType) type).getElementType()));
                }
                if(type instanceof Tree.TupleType){
                    // can only be one, must be a SequencedType
                    Tree.Type sequencedType = ((Tree.TupleType) type).getElementTypes().get(0);
                    return getAnnotationTypeFor(sequencedType);
                }
                System.err.println("Unknown Annotation type: "+type);
                return make().TypeArray(make().Type(syms().stringType));
            }

            @Override
            public void loadFromSource(ModuleDescriptor that) {
                // don't think we care about these
            }

            @Override
            public void loadFromSource(PackageDescriptor that) {
                // don't think we care about these
            }
        });
        
        return defs.toList();
    }

    /**
     * This runs after _some_ typechecking has been done
     */
    @SuppressWarnings("unchecked")
    public ListBuffer transformAfterTypeChecking(Tree.CompilationUnit t) {
        disableAnnotations = 0;
        
        GetterSetterPairingVisitor gspv = new GetterSetterPairingVisitor();
        t.visit(gspv);
        
        ToplevelAttributesDefinitionBuilder builder = new ToplevelAttributesDefinitionBuilder(this);
        LabelVisitor lv = new LabelVisitor();
        CeylonVisitor visitor = new CeylonVisitor(this, builder, lv, gspv);
        t.visit(lv);
        t.visit(visitor);
        
        
        ListBuffer result = ListBuffer.lb();
        result.appendList((ListBuffer) visitor.getResult());
        result.appendList(builder.build());
        
        return result;
    }

    // Make a name from a list of strings, using only the first component.
    Name makeName(Iterable components) {
        Iterator iterator = components.iterator();
        String s = iterator.next();
        assert (!iterator.hasNext());
        return names().fromString(s);
    }

    String toFlatName(Iterable components) {
        StringBuffer buf = new StringBuffer();
        Iterator iterator;

        for (iterator = components.iterator(); iterator.hasNext();) {
            buf.append(iterator.next());
            if (iterator.hasNext())
                buf.append('.');
        }

        return buf.toString();
    }

    // FIXME: port handleOverloadedToplevelClasses when I figure out what it
    // does

    private JCExpression getPackage(String fullname) {
        return makeQuotedQualIdentFromString(fullname);
    }

    public JCImport transform(Tree.ImportPath that) {
        String[] names = new String[that.getIdentifiers().size()];
        int i = 0;
        for (Tree.Identifier component : that.getIdentifiers()) {
            names[i++] = component.getText();
        }
        return at(that).Import(makeQuotedQualIdent(null, names), false);
    }
    
    public List transform(Tree.AnyAttribute decl) {
        return transformAttribute(decl, null);
    }

    public List transform(Tree.AttributeSetterDefinition decl) {
        return transformAttribute(decl, null);
    }
    
    public List transformAttribute(Tree.TypedDeclaration decl, Tree.AttributeSetterDefinition setterDecl) {
        at(decl);
        TypedDeclaration declarationModel = decl.getDeclarationModel(); 
        final String attrName = declarationModel.getName();
        final String attrClassName = Naming.getAttrClassName(declarationModel, 0);
        final Tree.SpecifierOrInitializerExpression expression;
        final Tree.Block block;
        if (decl instanceof Tree.AttributeDeclaration) {
            Tree.AttributeDeclaration adecl = (Tree.AttributeDeclaration)decl;
            expression = adecl.getSpecifierOrInitializerExpression();
            block = null;
        } else if (decl instanceof Tree.AttributeGetterDefinition) {
            expression = null;
            Tree.AttributeGetterDefinition gdef = (Tree.AttributeGetterDefinition)decl;
            block = gdef.getBlock();
        } else if (decl instanceof Tree.AttributeSetterDefinition) {
            Tree.AttributeSetterDefinition sdef = (Tree.AttributeSetterDefinition)decl;
            block = sdef.getBlock();
            expression = sdef.getSpecifierExpression();
            if (Decl.isLocal(decl)) {
                declarationModel = ((Tree.AttributeSetterDefinition)decl).getDeclarationModel().getParameter().getModel();
            }
        } else {
            throw new RuntimeException();
        }
        return transformAttribute(declarationModel, attrName, attrClassName,
                decl, block, expression, decl, setterDecl);
    }

    public List transformAttribute(
            TypedDeclaration declarationModel,
            String attrName, String attrClassName,
            final Tree.Declaration annotated,
            final Tree.Block block,
            final Tree.SpecifierOrInitializerExpression expression, 
            final Tree.TypedDeclaration decl,
            final Tree.AttributeSetterDefinition setterDecl) {
        
        // For everything else generate a getter/setter method
        AttributeDefinitionBuilder builder = AttributeDefinitionBuilder
            .wrapped(this, attrClassName, null, attrName, declarationModel, declarationModel.isToplevel())
            .is(Flags.PUBLIC, declarationModel.isShared());
        
        final JCExpression initialValue;
        final HasErrorException expressionError;
        if (expression != null) {
            expressionError = errors().getFirstExpressionErrorAndMarkBrokenness(expression.getExpression());
            if (expressionError != null) {
                initialValue = make().Erroneous();
            } else {
                initialValue = transformValueInit(
                        declarationModel, attrName, expression);
            }
        } else {
            expressionError = null;
            initialValue = transformValueInit(
                    declarationModel, attrName, expression);
        }
        
        
        // For captured local variable Values, use a VariableBox
        if (Decl.isBoxedVariable(declarationModel)) {
            if (expressionError != null) {
                return List.of(this.makeThrowUnresolvedCompilationError(expressionError));
            } else {
                return List.of(makeVariableBoxDecl(
                        initialValue, declarationModel));
            }
        }
        
        // For late-bound getters we only generate a declaration
        if (block == null && expression == null && !Decl.isToplevel(declarationModel)) {
            JCExpression typeExpr = makeJavaType(getGetterInterfaceType(declarationModel));
            JCTree.JCVariableDecl var = makeVar(attrClassName, typeExpr, null);
            return List.of(var);
        }
        
        // Set the local declarations annotation
        if(decl != null){
            List scopeAnnotations;
            if(Decl.isToplevel(declarationModel) && setterDecl != null){
                scopeAnnotations = makeAtLocalDeclarations(decl, setterDecl);
            }else{
                scopeAnnotations = makeAtLocalDeclarations(decl);
            }
            builder.classAnnotations(scopeAnnotations);
        }else if(block != null){
            List scopeAnnotations = makeAtLocalDeclarations(block);
            builder.classAnnotations(scopeAnnotations);
        }

        // Remember the setter class if we generate a getter
        if(Decl.isGetter(declarationModel)
                && declarationModel.isVariable()
                && Decl.isLocal(declarationModel)){
            // we must have a setter class
            Setter setter = ((Value)declarationModel).getSetter();
            if(setter != null){
                String setterClassName = Naming.getAttrClassName(setter, 0);
                JCExpression setterClassNameExpr = naming.makeUnquotedIdent(setterClassName);
                builder.setterClass(makeSelect(setterClassNameExpr, "class"));
            }
        }
        
        if (declarationModel instanceof Setter
                || (declarationModel instanceof FunctionOrValue 
                    && ((FunctionOrValue)declarationModel).isParameter())) {
            // For local setters
            JCBlock setterBlock = makeSetterBlock(declarationModel, block, expression);
            builder.setterBlock(setterBlock);
            builder.skipGetter();
            if(Decl.isLocal(decl)){
                // we need to find back the Setter model for local setters, because 
                // in transformAttribute(Tree.TypedDeclaration decl, Tree.AttributeSetterDefinition setterDecl)
                // we turn the declaration model from the Setter to its single parameter
                Setter setter = (Setter) declarationModel.getContainer();
                String getterClassName = Naming.getAttrClassName(setter.getGetter(), 0);
                JCExpression getterClassNameExpr = naming.makeUnquotedIdent(getterClassName);
                builder.isSetter(makeSelect(getterClassNameExpr, "class"));
            }
        } else {
            if (Decl.isValue(declarationModel)) {
                // For local and toplevel value attributes
                if (!declarationModel.isVariable() && !declarationModel.isLate()) {
                    builder.immutable();
                }
            } else {
                // For local and toplevel getters
                boolean prevSyntheticClassBody;
                if (Decl.isLocal(declarationModel)) {
                    prevSyntheticClassBody = expressionGen().withinSyntheticClassBody(true);
                } else {
                    prevSyntheticClassBody = expressionGen().isWithinSyntheticClassBody();
                }
                JCBlock getterBlock = makeGetterBlock(declarationModel, block, expression);
                prevSyntheticClassBody = expressionGen().withinSyntheticClassBody(prevSyntheticClassBody);
                builder.getterBlock(getterBlock);
                
                if (Decl.isLocal(declarationModel)) {
                    // For local getters
                    builder.immutable();
                } else {
                    // For toplevel getters
                    if (setterDecl != null) {
                        JCBlock setterBlock = makeSetterBlock(setterDecl.getDeclarationModel(),
                                setterDecl.getBlock(), setterDecl.getSpecifierExpression());
                        builder.setterBlock(setterBlock);
                        //builder.userAnnotationsSetter(expressionGen().transformAnnotations(true, OutputElement.METHOD, setterDecl));
                        builder.userAnnotationsSetter(expressionGen().transformAnnotations(OutputElement.SETTER, setterDecl));
                    } else {
                        builder.immutable();
                    }
                }
            }
        }
        
        if (annotated != null) {
            builder.userAnnotations(expressionGen().transformAnnotations(OutputElement.GETTER, annotated));
        }
        
        if (Decl.isLocal(declarationModel)) {
            if (expressionError != null) {
                return List.of(this.makeThrowUnresolvedCompilationError(expressionError));
            }
            builder.classAnnotations(makeAtLocalDeclaration(declarationModel.getQualifier(), false));
            if(initialValue != null)
                builder.valueConstructor();
            JCExpression typeExpr;
            if (declarationModel instanceof Setter 
                    || (declarationModel instanceof FunctionOrValue
                        && ((FunctionOrValue)declarationModel).isParameter())) {
                typeExpr = makeQuotedIdent(attrClassName);
            } else {
                typeExpr = makeJavaType(getGetterInterfaceType(declarationModel));
            }
            return builder.build().append(makeLocalIdentityInstance(
                    typeExpr,
                    attrClassName, 
                    attrClassName, declarationModel.isShared(), initialValue));
        } else {
            if (expressionError != null) {
                builder.initialValueError(expressionError);
            } else if(initialValue != null) {
                builder.initialValue(initialValue);
            }
            builder.is(Flags.STATIC, true);
            return builder.build();
        }
    }
    
    private JCTree.JCExpression transformValueInit(
            TypedDeclaration declarationModel, String attrName,
            final Tree.SpecifierOrInitializerExpression expression) {
        JCTree.JCExpression initialValue = null;
        if (Decl.isNonTransientValue(declarationModel)
                && !(expression instanceof Tree.LazySpecifierExpression)) {
            if (expression != null) {
                initialValue = expressionGen().transform(
                        expression, 
                        CodegenUtil.getBoxingStrategy(declarationModel),
                        declarationModel.getType());
            } else {
                Parameter p = CodegenUtil.findParamForDecl(attrName, declarationModel);
                if (p != null) {
                    initialValue = naming.makeName(p.getModel(), Naming.NA_MEMBER | Naming.NA_ALIASED);
                }
            }
        }
        return initialValue;
    }

    public JCExpression transformAttributeGetter(
            TypedDeclaration declarationModel,
            final JCExpression expression) {
        
        final String attrName = declarationModel.getName();
        final String attrClassName = Naming.getAttrClassName(declarationModel, 0);
        
        JCBlock getterBlock = makeGetterBlock(expression);
        
        // For everything else generate a getter/setter method
        AttributeDefinitionBuilder builder = AttributeDefinitionBuilder
            .indirect(this, attrClassName, attrName, declarationModel, declarationModel.isToplevel())
            .getterBlock(getterBlock)
            .immutable();
        
        List attr =  builder.build();
        JCNewClass newExpr = makeNewClass(attrClassName, false, null);
        JCExpression result = makeLetExpr(naming.temp(), List.of((JCStatement)attr.get(0)), newExpr);
        return result;
    }
    
    /** Creates a module class in the package, with the Module annotation required by the runtime. */
    public List transformModuleDescriptor(Tree.ModuleDescriptor module) {
        at(null);
        
        ClassDefinitionBuilder builder = ClassDefinitionBuilder
                .klass(this, Naming.MODULE_DESCRIPTOR_CLASS_NAME, null, false);
        builder.modifiers(Flags.FINAL)
                .annotations(makeAtModule(module));
        builder.getInitBuilder().modifiers(Flags.PRIVATE);
        builder.annotations(expressionGen().transformAnnotations(OutputElement.TYPE, module));
        for (Tree.ImportModule imported : module.getImportModuleList().getImportModules()) {
            if (!isForBackend(imported.getAnnotationList(), Backend.Java, imported.getUnit())) {
                continue;
            }
            String quotedName;
            if (imported.getImportPath() != null) {
                StringBuilder sb = new StringBuilder();
                for (Tree.Identifier part : imported.getImportPath().getIdentifiers()) {
                    sb.append(part.getText()).append('$');
                }
                quotedName = sb.substring(0, sb.length()-1);
            } else if (imported.getQuotedLiteral() != null) {
                quotedName = imported.getQuotedLiteral().getText();
                quotedName = quotedName.substring(1, quotedName.length()-1);
                quotedName = quotedName.replace('.', '$');
            } else {
                throw new BugException(imported, "unhandled module import");
            }
            List importAnnotations = expressionGen().transformAnnotations(OutputElement.FIELD, imported);
            JCModifiers mods = make().Modifiers(Flags.PUBLIC | Flags.STATIC | Flags.FINAL, importAnnotations);
            Name fieldName = names().fromString(quotedName);
            builder.defs(List.of(make().VarDef(mods, fieldName, make().Type(syms().stringType), makeNull())));
        }
        return builder.build();
    }

    public List transformPackageDescriptor(Tree.PackageDescriptor pack) {
        at(null);
        ClassDefinitionBuilder builder = ClassDefinitionBuilder
                .klass(this, Naming.PACKAGE_DESCRIPTOR_CLASS_NAME, null, false)
                .modifiers(Flags.FINAL)
                .annotations(makeAtPackage(pack.getUnit().getPackage()));
        builder.getInitBuilder().modifiers(Flags.PRIVATE);
        builder.annotations(expressionGen().transformAnnotations(OutputElement.TYPE, pack));
        return builder.build();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy