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.JetBinaryExpression;
023    import org.jetbrains.jet.lang.psi.JetExpression;
024    import org.jetbrains.jet.lang.psi.JetForExpression;
025    import org.jetbrains.jet.lexer.JetTokens;
026    import org.jetbrains.k2js.translate.context.TemporaryVariable;
027    import org.jetbrains.k2js.translate.context.TranslationContext;
028    
029    import java.util.List;
030    
031    import static org.jetbrains.k2js.translate.utils.JsAstUtils.inequality;
032    import static org.jetbrains.k2js.translate.utils.JsAstUtils.newVar;
033    import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopRange;
034    import static org.jetbrains.k2js.translate.utils.TemporariesUtils.temporariesInitialization;
035    import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateLeftExpression;
036    import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateRightExpression;
037    
038    
039    // TODO: implement reverse semantics
040    public final class RangeLiteralForTranslator extends ForTranslator {
041    
042        @NotNull
043        public static JsStatement doTranslate(@NotNull JetForExpression expression,
044                                              @NotNull TranslationContext context) {
045            return (new RangeLiteralForTranslator(expression, context).translate());
046        }
047    
048        public static boolean isApplicable(@NotNull JetForExpression expression,
049                                           @NotNull TranslationContext context) {
050            JetExpression loopRange = getLoopRange(expression);
051            if (!(loopRange instanceof JetBinaryExpression)) {
052                return false;
053            }
054            boolean isRangeToOperation = ((JetBinaryExpression) loopRange).getOperationToken() == JetTokens.RANGE;
055            return isRangeToOperation && RangeForTranslator.isApplicable(expression, context);
056        }
057    
058        @NotNull
059        private final JsExpression rangeStart;
060    
061        @NotNull
062        private final TemporaryVariable rangeEnd;
063    
064        private RangeLiteralForTranslator(@NotNull JetForExpression forExpression, @NotNull TranslationContext context) {
065            super(forExpression, context);
066            JetExpression loopRange = getLoopRange(expression);
067            assert loopRange instanceof JetBinaryExpression;
068            JetBinaryExpression loopRangeAsBinary = ((JetBinaryExpression) loopRange);
069            rangeStart = translateLeftExpression(context, loopRangeAsBinary);
070            rangeEnd = context.declareTemporary(getRangeEnd(loopRangeAsBinary));
071        }
072    
073        @NotNull
074        private JsExpression getRangeEnd(@NotNull JetBinaryExpression loopRangeAsBinary) {
075            JsExpression rightExpression = translateRightExpression(context(), loopRangeAsBinary);
076            return new JsBinaryOperation(JsBinaryOperator.ADD, rightExpression, program().getNumberLiteral(1));
077        }
078    
079        @NotNull
080        private JsBlock translate() {
081            List<JsStatement> blockStatements = Lists.newArrayList();
082            blockStatements.add(temporariesInitialization(rangeEnd).makeStmt());
083            blockStatements.add(new JsFor(initExpression(), getCondition(), getIncrExpression(), translateBody(null)));
084            return new JsBlock(blockStatements);
085        }
086    
087        @NotNull
088        private JsVars initExpression() {
089            return newVar(parameterName, rangeStart);
090        }
091    
092        @NotNull
093        private JsExpression getCondition() {
094            return inequality(parameterName.makeRef(), rangeEnd.reference());
095        }
096    
097        @NotNull
098        private JsExpression getIncrExpression() {
099            return new JsPostfixOperation(JsUnaryOperator.INC, parameterName.makeRef());
100        }
101    }