Search in sources :

Example 6 with SpecifierOrInitializerExpression

use of org.eclipse.ceylon.compiler.typechecker.tree.Tree.SpecifierOrInitializerExpression in project ceylon by eclipse.

the class GenerateJsVisitor method visit.

@Override
public void visit(final Tree.AttributeDeclaration that) {
    if (errVisitor.hasErrors(that) || !TypeUtils.acceptNative(that))
        return;
    final Value d = that.getDeclarationModel();
    // Check if the attribute corresponds to a class parameter
    // This is because of the new initializer syntax
    final Parameter param = d.isParameter() ? ((Functional) d.getContainer()).getParameter(d.getName()) : null;
    final boolean asprop = AttributeGenerator.defineAsProperty(d);
    if (d.isFormal()) {
        if (!opts.isOptimize()) {
            comment(that);
            AttributeGenerator.generateAttributeMetamodel(that, false, false, this);
        }
    } else if (!d.isStatic()) {
        SpecifierOrInitializerExpression specInitExpr = that.getSpecifierOrInitializerExpression();
        final boolean addGetter = specInitExpr != null || param != null || !d.isMember() || d.isVariable() || d.isLate();
        boolean setterGend = false;
        if (opts.isOptimize() && d.isClassOrInterfaceMember()) {
            // Stitch native member attribute declaration with no value
            final boolean eagerExpr = specInitExpr != null && !(specInitExpr instanceof LazySpecifierExpression);
            if (eagerExpr && !TypeUtils.isNativeExternal(d)) {
                comment(that);
                outerSelf(d);
                out(".", names.privateName(d), "=");
                if (d.isLate()) {
                    out("undefined");
                } else {
                    super.visit(specInitExpr);
                }
                endLine(true);
            }
        } else if (specInitExpr instanceof LazySpecifierExpression) {
            comment(that);
            if (asprop) {
                defineAttribute(names.self((TypeDeclaration) d.getContainer()), names.name(d));
                out("{");
            } else {
                out(function, names.getter(d, false), "(){");
            }
            initSelf(that);
            boolean genatr = true;
            if (TypeUtils.isNativeExternal(d)) {
                if (stitchNative(d, that)) {
                    if (verboseStitcher) {
                        spitOut("Stitching in native attribute " + d.getQualifiedNameString() + ", ignoring Ceylon declaration");
                    }
                    genatr = false;
                    out(";};");
                }
            }
            if (genatr) {
                out("return ");
                if (!isNaturalLiteral(specInitExpr.getExpression().getTerm())) {
                    visitSingleExpression(specInitExpr.getExpression());
                }
                out("}");
                if (asprop) {
                    Tree.AttributeSetterDefinition setterDef = null;
                    if (d.isVariable()) {
                        setterDef = associatedSetterDefinition(d);
                        if (setterDef != null) {
                            out(",function(", names.name(setterDef.getDeclarationModel().getParameter()), ")");
                            AttributeGenerator.setter(setterDef, this);
                        }
                    }
                    if (setterDef == null) {
                        out(",undefined");
                    }
                    out(",");
                    TypeUtils.encodeForRuntime(that, that.getDeclarationModel(), that.getAnnotationList(), this);
                    if (setterDef != null) {
                        out(",");
                        TypeUtils.encodeForRuntime(setterDef, setterDef.getDeclarationModel(), setterDef.getAnnotationList(), this);
                    }
                    out(")");
                    endLine(true);
                } else {
                    endLine(true);
                    shareGetter(d);
                }
            }
        } else if (!(d.isParameter() && d.getContainer() instanceof Function)) {
            if (addGetter) {
                AttributeGenerator.generateAttributeGetter(that, d, specInitExpr, names.name(param), this, directAccess, verboseStitcher);
            }
            if ((d.isVariable() || d.isLate()) && !asprop) {
                setterGend = AttributeGenerator.generateAttributeSetter(that, d, this);
            }
        }
        boolean addMeta = !opts.isOptimize() || d.isToplevel();
        if (!d.isToplevel()) {
            addMeta |= ModelUtil.getContainingDeclaration(d).isAnonymous();
        }
        if (addMeta) {
            AttributeGenerator.generateAttributeMetamodel(that, addGetter, setterGend, this);
        }
    }
}
Also used : Function(org.eclipse.ceylon.model.typechecker.model.Function) AttributeSetterDefinition(org.eclipse.ceylon.compiler.typechecker.tree.Tree.AttributeSetterDefinition) Value(org.eclipse.ceylon.model.typechecker.model.Value) FunctionOrValue(org.eclipse.ceylon.model.typechecker.model.FunctionOrValue) Parameter(org.eclipse.ceylon.model.typechecker.model.Parameter) TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) Tree(org.eclipse.ceylon.compiler.typechecker.tree.Tree) SpecifierOrInitializerExpression(org.eclipse.ceylon.compiler.typechecker.tree.Tree.SpecifierOrInitializerExpression) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) LazySpecifierExpression(org.eclipse.ceylon.compiler.typechecker.tree.Tree.LazySpecifierExpression)

Example 7 with SpecifierOrInitializerExpression

use of org.eclipse.ceylon.compiler.typechecker.tree.Tree.SpecifierOrInitializerExpression in project ceylon by eclipse.

the class ClassGenerator method classDefinition.

static void classDefinition(final Tree.ClassDefinition that, final GenerateJsVisitor gen, InitDeferrer initDeferrer) {
    // Don't even bother with nodes that have errors
    if (TypeGenerator.errVisitor.hasErrors(that))
        return;
    final Class d = that.getDeclarationModel();
    // If it's inside a dynamic interface, don't generate anything
    if (d.isClassOrInterfaceMember() && ((ClassOrInterface) d.getContainer()).isDynamic())
        return;
    final Class natd = (Class) ModelUtil.getNativeDeclaration(d, Backend.JavaScript);
    final boolean headerWithoutBackend = NativeUtil.isHeaderWithoutBackend(that, Backend.JavaScript);
    if (natd != null && (headerWithoutBackend || NativeUtil.isNativeHeader(that))) {
        // It's a native header, remember it for later when we deal with its implementation
        gen.saveNativeHeader(that);
        return;
    }
    if (!(NativeUtil.isForBackend(that, Backend.JavaScript) || headerWithoutBackend)) {
        return;
    }
    final Tree.ParameterList plist = that.getParameterList();
    // final Tree.SatisfiedTypes sats = that.getSatisfiedTypes();
    final List<Tree.Statement> stmts;
    if (NativeUtil.isForBackend(d, Backend.JavaScript)) {
        Tree.Declaration nh = gen.getNativeHeader(d);
        if (nh == null && NativeUtil.hasNativeMembers(d)) {
            nh = that;
        }
        stmts = NativeUtil.mergeStatements(that.getClassBody(), nh, Backend.JavaScript);
    } else {
        stmts = that.getClassBody().getStatements();
    }
    // Find the constructors, if any
    final List<Tree.Constructor> constructors;
    Tree.Constructor defconstr = null;
    final boolean hasConstructors = d.hasConstructors() || (natd != null && natd.hasConstructors());
    final boolean hasEnumerated = d.hasEnumerated() || (natd != null && natd.hasEnumerated());
    if (hasConstructors) {
        constructors = new ArrayList<>(3);
        for (Tree.Statement st : stmts) {
            if (st instanceof Tree.Constructor) {
                Tree.Constructor constr = (Tree.Constructor) st;
                constructors.add(constr);
                if (constr.getDeclarationModel().getName() == null) {
                    defconstr = constr;
                }
            }
        }
    } else {
        constructors = null;
    }
    gen.comment(that);
    final boolean isAbstractNative = d.isNativeHeader() && natd != null;
    final String typeName = gen.getNames().name(d);
    if (TypeUtils.isNativeExternal(d)) {
        boolean bye = false;
        if (hasConstructors && defconstr == null) {
            gen.out(GenerateJsVisitor.function, typeName);
            gen.out("(){");
            gen.generateThrow("Exception", d.getQualifiedNameString() + " has no default constructor.", that);
            gen.out(";}");
            gen.endLine();
        }
        if (gen.stitchNative(d, that)) {
            if (d.isShared()) {
                gen.share(d);
            }
            TypeGenerator.initializeType(that, gen, initDeferrer);
            bye = true;
        }
        if (hasConstructors) {
            for (Tree.Constructor cnstr : constructors) {
                Constructors.classConstructor(cnstr, that, constructors, gen);
            }
        }
        if (bye)
            return;
    }
    gen.out(GenerateJsVisitor.function, typeName);
    // If there's a default constructor, create a different function with this code
    if (hasConstructors || hasEnumerated) {
        if (defconstr == null) {
            gen.out("(){");
            gen.generateThrow("Exception", d.getQualifiedNameString() + " has no default constructor.", that);
            gen.out(";}");
            gen.endLine();
            gen.out(GenerateJsVisitor.function, typeName);
        }
        gen.out("$$c");
    }
    // counterparts
    if (isAbstractNative) {
        if (plist != null) {
            for (Parameter p : d.getParameterList().getParameters()) {
                gen.getNames().forceName(natd.getParameter(p.getName()).getModel(), gen.getNames().name(p));
            }
        }
        for (Declaration hd : d.getMembers()) {
            if (!hd.isShared()) {
                gen.getNames().forceName(natd.getMember(hd.getName(), null, false), gen.getNames().name(hd));
            }
        }
    }
    final boolean withTargs = TypeGenerator.generateParameters(that.getTypeParameterList(), plist, d, gen);
    gen.beginBlock();
    if (!hasConstructors) {
        // This takes care of top-level attributes defined before the class definition
        gen.out("$init$", typeName, "();");
        gen.endLine();
        gen.declareSelf(d);
        gen.referenceOuter(d);
    }
    final String me = gen.getNames().self(d);
    if (withTargs) {
        gen.out(gen.getClAlias(), "set_type_args(", me, ",$$targs$$);");
        gen.endLine();
    }
    addFunctionTypeArguments(d, me, gen);
    List<Tree.Parameter> defparams = null;
    if (plist != null) {
        defparams = gen.initParameters(plist, d, null);
    }
    callSupertypes(that, d, typeName, gen);
    if (!gen.opts.isOptimize() && plist != null) {
        // Fix #231 for lexical scope
        for (Tree.Parameter p : plist.getParameters()) {
            if (!p.getParameterModel().isHidden()) {
                gen.generateAttributeForParameter(that, d, p.getParameterModel());
            }
        }
    }
    if (!hasConstructors) {
        if (TypeUtils.isNativeExternal(d)) {
            gen.stitchConstructorHelper(that, "_cons_before");
        }
        gen.visitStatements(stmts);
        if (TypeUtils.isNativeExternal(d)) {
            gen.stitchConstructorHelper(that, "_cons_after");
        }
        gen.out("return ", me, ";");
    }
    gen.endBlockNewLine();
    if (defconstr != null) {
        // Define a function as the class and call the default constructor in there
        String _this = "undefined";
        if (!d.isToplevel()) {
            final ClassOrInterface coi = ModelUtil.getContainingClassOrInterface(d.getContainer());
            if (coi != null) {
                if (d.isClassOrInterfaceMember()) {
                    _this = "this";
                } else {
                    _this = gen.getNames().self(coi);
                }
            }
        }
        gen.out(GenerateJsVisitor.function, typeName, "(){return ", typeName, gen.getNames().constructorSeparator(defconstr.getDeclarationModel()), gen.getNames().name(defconstr.getDeclarationModel()), ".apply(", _this, ",arguments);}");
        gen.endLine();
    }
    if (hasConstructors) {
        for (Tree.Constructor cnstr : constructors) {
            Constructors.classConstructor(cnstr, that, constructors, gen);
        }
    }
    if (hasEnumerated) {
        for (Tree.Statement st : stmts) {
            if (st instanceof Tree.Enumerated) {
                Singletons.valueConstructor(that, (Tree.Enumerated) st, gen);
            }
        }
    }
    if (defparams != null) {
        for (Tree.Parameter p : defparams) {
            final SpecifierOrInitializerExpression expr = gen.getDefaultExpression(p);
            if (expr != null) {
                // Optimizing for certain expressions such as null and literals is tempting
                // but we need to put them in functions if we want them to work in subtypes
                gen.out(typeName, ".$defs$", p.getParameterModel().getName(), "=function(", me);
                for (Parameter otherP : d.getParameterList().getParameters()) {
                    if (!otherP.equals(p.getParameterModel())) {
                        gen.out(",", gen.getNames().name(otherP));
                    }
                }
                gen.out("){return ");
                gen.generateParameterExpression(p, expr, d);
                gen.out("};");
            }
        }
    }
    // Add reference to metamodel
    gen.out(typeName, ".$crtmm$=");
    TypeUtils.encodeForRuntime(that, d, that.getAnnotationList(), gen);
    gen.endLine(true);
    if (!isAbstractNative) {
        gen.share(d);
    }
    TypeGenerator.initializeType(that, gen, initDeferrer);
    if (d.isSerializable()) {
        SerializationHelper.addDeserializer(that, d, gen);
    }
}
Also used : ClassOrInterface(org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) SpecifierOrInitializerExpression(org.eclipse.ceylon.compiler.typechecker.tree.Tree.SpecifierOrInitializerExpression) Tree(org.eclipse.ceylon.compiler.typechecker.tree.Tree) Parameter(org.eclipse.ceylon.model.typechecker.model.Parameter) Class(org.eclipse.ceylon.model.typechecker.model.Class) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration)

Aggregations

SpecifierOrInitializerExpression (org.eclipse.ceylon.compiler.typechecker.tree.Tree.SpecifierOrInitializerExpression)7 Tree (org.eclipse.ceylon.compiler.typechecker.tree.Tree)5 Parameter (org.eclipse.ceylon.model.typechecker.model.Parameter)5 TypeParameter (org.eclipse.ceylon.model.typechecker.model.TypeParameter)3 Class (org.eclipse.ceylon.model.typechecker.model.Class)2 Function (org.eclipse.ceylon.model.typechecker.model.Function)2 FunctionOrValue (org.eclipse.ceylon.model.typechecker.model.FunctionOrValue)2 Value (org.eclipse.ceylon.model.typechecker.model.Value)2 ArrayList (java.util.ArrayList)1 CName (org.eclipse.ceylon.compiler.java.codegen.Naming.CName)1 SyntheticName (org.eclipse.ceylon.compiler.java.codegen.Naming.SyntheticName)1 HasErrorException (org.eclipse.ceylon.compiler.java.codegen.recovery.HasErrorException)1 AttributeDeclaration (org.eclipse.ceylon.compiler.typechecker.tree.Tree.AttributeDeclaration)1 AttributeSetterDefinition (org.eclipse.ceylon.compiler.typechecker.tree.Tree.AttributeSetterDefinition)1 LazySpecifierExpression (org.eclipse.ceylon.compiler.typechecker.tree.Tree.LazySpecifierExpression)1 JCAnnotation (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCAnnotation)1 JCExpression (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression)1 JCStatement (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement)1 ListBuffer (org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer)1 Name (org.eclipse.ceylon.langtools.tools.javac.util.Name)1