001    /*
002     * Copyright 2010-2013 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.k2js.translate.expression.foreach;
018    
019    import com.google.common.collect.Lists;
020    import com.google.dart.compiler.backend.js.ast.*;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.jet.lang.psi.JetExpression;
023    import org.jetbrains.jet.lang.psi.JetForExpression;
024    import org.jetbrains.jet.lang.types.JetType;
025    import org.jetbrains.k2js.translate.context.TemporaryVariable;
026    import org.jetbrains.k2js.translate.context.TranslationContext;
027    import org.jetbrains.k2js.translate.general.Translation;
028    import org.jetbrains.k2js.translate.utils.BindingUtils;
029    
030    import java.util.List;
031    
032    import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getClassDescriptorForType;
033    import static org.jetbrains.k2js.translate.utils.JsAstUtils.*;
034    import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopRange;
035    import static org.jetbrains.k2js.translate.utils.TemporariesUtils.temporariesInitialization;
036    
037    public final class RangeForTranslator extends ForTranslator {
038    
039        @NotNull
040        public static JsStatement doTranslate(@NotNull JetForExpression expression,
041                                              @NotNull TranslationContext context) {
042            return (new RangeForTranslator(expression, context).translate());
043        }
044    
045        public static boolean isApplicable(@NotNull JetForExpression expression,
046                                           @NotNull TranslationContext context) {
047            JetExpression loopRange = getLoopRange(expression);
048            JetType rangeType = BindingUtils.getTypeForExpression(context.bindingContext(), loopRange);
049            //TODO: better check
050            //TODO: long range?
051            return getClassDescriptorForType(rangeType).getName().asString().equals("IntRange");
052        }
053    
054        @NotNull
055        private final TemporaryVariable rangeExpression;
056        @NotNull
057        private final TemporaryVariable start;
058        @NotNull
059        private final TemporaryVariable end;
060        @NotNull
061        private final TemporaryVariable increment;
062    
063        private RangeForTranslator(@NotNull JetForExpression forExpression, @NotNull TranslationContext context) {
064            super(forExpression, context);
065            rangeExpression = context.declareTemporary(Translation.translateAsExpression(getLoopRange(expression), context));
066            start = context().declareTemporary(callFunction("get_start"));
067            end = context().declareTemporary(callFunction("get_end"));
068            increment = context().declareTemporary(callFunction("get_increment"));
069        }
070    
071        @NotNull
072        private JsBlock translate() {
073            List<JsStatement> blockStatements = Lists.newArrayList();
074            blockStatements.add(temporariesInitialization(rangeExpression, start, end, increment).makeStmt());
075            blockStatements.add(generateForExpression());
076            return new JsBlock(blockStatements);
077        }
078    
079        @NotNull
080        private JsFor generateForExpression() {
081            JsFor result = new JsFor(initExpression(), getCondition(), getIncrExpression());
082            result.setBody(translateOriginalBodyExpression());
083            return result;
084        }
085    
086        @NotNull
087        private JsVars initExpression() {
088            return newVar(parameterName, start.reference());
089        }
090    
091        @NotNull
092        private JsExpression getCondition() {
093            return lessThanEq(parameterName.makeRef(), end.reference());
094        }
095    
096        @NotNull
097        private JsExpression getIncrExpression() {
098            return addAssign(parameterName.makeRef(), increment.reference());
099        }
100    
101        @NotNull
102        private JsExpression callFunction(@NotNull String funName) {
103            return new JsInvocation(new JsNameRef(funName, rangeExpression.reference()));
104        }
105    }