001    /*
002     * Copyright 2010-2016 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.kotlin.js.translate.initializer;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
021    import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
022    import org.jetbrains.kotlin.js.backend.ast.*;
023    import org.jetbrains.kotlin.js.translate.context.Namer;
024    import org.jetbrains.kotlin.js.translate.context.TranslationContext;
025    import org.jetbrains.kotlin.js.translate.declaration.PropertyTranslatorKt;
026    import org.jetbrains.kotlin.js.translate.general.TranslatorVisitor;
027    import org.jetbrains.kotlin.js.translate.utils.BindingUtils;
028    import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
029    import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils;
030    import org.jetbrains.kotlin.js.translate.utils.TranslationUtils;
031    import org.jetbrains.kotlin.psi.*;
032    import org.jetbrains.kotlin.resolve.BindingContext;
033    import org.jetbrains.kotlin.types.KotlinType;
034    
035    import static org.jetbrains.kotlin.js.translate.general.Translation.translateAsStatementAndMergeInBlockIfNeeded;
036    import static org.jetbrains.kotlin.js.translate.initializer.InitializerUtils.generateInitializerForDelegate;
037    import static org.jetbrains.kotlin.js.translate.initializer.InitializerUtils.generateInitializerForProperty;
038    
039    public final class InitializerVisitor extends TranslatorVisitor<Void> {
040        @Override
041        protected Void emptyResult(@NotNull TranslationContext context) {
042            return null;
043        }
044    
045        @Override
046        public final Void visitProperty(@NotNull KtProperty property, @NotNull TranslationContext context) {
047            PropertyDescriptor descriptor = BindingUtils.getPropertyDescriptor(context.bindingContext(), property);
048            JsExpression value = PropertyTranslatorKt.translateDelegateOrInitializerExpression(context, property);
049            JsStatement statement = null;
050    
051            KtExpression initializer = property.getInitializer();
052            KtExpression delegate = property.getDelegateExpression();
053            if (initializer != null) {
054                assert value != null;
055                statement = generateInitializerForProperty(context, descriptor, value);
056            }
057            else if (delegate != null) {
058                assert value != null;
059                statement = generateInitializerForDelegate(descriptor, value);
060            }
061            else if (Boolean.TRUE.equals(context.bindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, descriptor))) {
062                JsExpression defaultValue = generateDefaultValue(descriptor, context);
063                statement = TranslationUtils.assignmentToBackingField(context, descriptor, defaultValue).makeStmt();
064            }
065            else if (JsDescriptorUtils.isSimpleFinalProperty(descriptor)) {
066                JsExpression defaultValue = generateDefaultValue(descriptor, context);
067                JsName propertyName = context.getNameForDescriptor(descriptor);
068                statement = JsAstUtils.assignment(new JsNameRef(propertyName, JsLiteral.THIS), defaultValue).makeStmt();
069            }
070    
071            if (statement != null && !JsAstUtils.isEmptyStatement(statement)) {
072                context.addStatementsToCurrentBlock(JsAstUtils.flattenStatement(statement));
073            }
074    
075            return null;
076        }
077    
078        @NotNull
079        private static JsExpression generateDefaultValue(@NotNull PropertyDescriptor property, @NotNull TranslationContext context) {
080            if (property.isLateInit()) return Namer.getUndefinedExpression();
081    
082            KotlinType type = property.getType();
083            if (KotlinBuiltIns.isInt(type) || KotlinBuiltIns.isFloat(type) || KotlinBuiltIns.isDouble(type) ||
084                KotlinBuiltIns.isByte(type) || KotlinBuiltIns.isShort(type)
085            ) {
086                return context.program().getNumberLiteral(0);
087            }
088            else if (KotlinBuiltIns.isBoolean(type)) {
089                return JsLiteral.FALSE;
090            }
091            else {
092                return JsLiteral.NULL;
093            }
094        }
095    
096        @Override
097        public Void visitAnonymousInitializer(@NotNull KtAnonymousInitializer initializer, @NotNull TranslationContext context) {
098            KtExpression initializerBody = initializer.getBody();
099            if (initializerBody != null) {
100                context.addStatementsToCurrentBlock(JsAstUtils.flattenStatement(
101                        translateAsStatementAndMergeInBlockIfNeeded(initializerBody, context)));
102            }
103            return null;
104        }
105    
106        @Override
107        // Not interested in other types of declarations, they do not contain initializers.
108        public Void visitDeclaration(@NotNull KtDeclaration expression, @NotNull TranslationContext context) {
109            return null;
110        }
111    
112        @Override
113        public Void visitSecondaryConstructor(@NotNull KtSecondaryConstructor constructor, TranslationContext data) {
114            return null;
115        }
116    }