From 6f84da590eda25f5e0f498e3d1d9fdab83dc3724 Mon Sep 17 00:00:00 2001 From: Pavel Talanov Date: Wed, 22 Feb 2012 21:44:25 +0400 Subject: [PATCH] added dirty implementation for iterating over range literals --- .../foreach/ArrayForTranslator.java | 2 +- .../expression/foreach/ForTranslator.java | 20 ++- .../foreach/IteratorForTranslator.java | 1 - .../foreach/RangeForTranslator.java | 1 - .../foreach/RangeLiteralForTranslator.java | 121 ++++++++++++++++++ .../range/cases/iteratingOverRanges.kt | 41 ++++++ .../org/jetbrains/k2js/test/RangeTest.java | 3 + 7 files changed, 185 insertions(+), 4 deletions(-) create mode 100644 translator/src/org/jetbrains/k2js/translate/expression/foreach/RangeLiteralForTranslator.java create mode 100644 translator/testFiles/range/cases/iteratingOverRanges.kt diff --git a/translator/src/org/jetbrains/k2js/translate/expression/foreach/ArrayForTranslator.java b/translator/src/org/jetbrains/k2js/translate/expression/foreach/ArrayForTranslator.java index f60547f29cc..d7a43c6a2e6 100644 --- a/translator/src/org/jetbrains/k2js/translate/expression/foreach/ArrayForTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/expression/foreach/ArrayForTranslator.java @@ -89,7 +89,7 @@ public final class ArrayForTranslator extends ForTranslator { @NotNull private JsStatement getBody(@NotNull TemporaryVariable index) { JsArrayAccess arrayAccess = new JsArrayAccess(rangeExpression.reference(), index.reference()); - JsStatement currentVar = AstUtil.newVar(declareParameter(), arrayAccess); + JsStatement currentVar = AstUtil.newVar(parameterName, arrayAccess); JsStatement realBody = Translation.translateAsStatement(getLoopBody(expression), context()); return AstUtil.newBlock(currentVar, realBody); } diff --git a/translator/src/org/jetbrains/k2js/translate/expression/foreach/ForTranslator.java b/translator/src/org/jetbrains/k2js/translate/expression/foreach/ForTranslator.java index 1d8d782730b..77342eb941f 100644 --- a/translator/src/org/jetbrains/k2js/translate/expression/foreach/ForTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/expression/foreach/ForTranslator.java @@ -23,17 +23,24 @@ import org.jetbrains.jet.lang.psi.JetForExpression; import org.jetbrains.jet.lang.psi.JetParameter; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.general.AbstractTranslator; +import org.jetbrains.k2js.translate.general.Translation; +import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopBody; import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopParameter; /** * @author Pavel Talanov */ + +//TODO: create util class for managing stuff like binary operations public abstract class ForTranslator extends AbstractTranslator { @NotNull public static JsStatement translate(@NotNull JetForExpression expression, @NotNull TranslationContext context) { + if (RangeLiteralForTranslator.isApplicable(expression, context)) { + return RangeLiteralForTranslator.translate(expression, context); + } if (ArrayForTranslator.isApplicable(expression, context)) { return ArrayForTranslator.translate(expression, context); } @@ -45,15 +52,26 @@ public abstract class ForTranslator extends AbstractTranslator { @NotNull protected final JetForExpression expression; + @NotNull + protected final JsName parameterName; protected ForTranslator(@NotNull JetForExpression forExpression, @NotNull TranslationContext context) { super(context); this.expression = forExpression; + this.parameterName = declareParameter(); } @NotNull - protected JsName declareParameter() { + private JsName declareParameter() { JetParameter loopParameter = getLoopParameter(expression); return context().getNameForElement(loopParameter); } + + //TODO: look for should-be-usages + @NotNull + protected JsStatement translateOriginalBodyExpression() { + return Translation.translateAsStatement(getLoopBody(expression), context()); + } + + } diff --git a/translator/src/org/jetbrains/k2js/translate/expression/foreach/IteratorForTranslator.java b/translator/src/org/jetbrains/k2js/translate/expression/foreach/IteratorForTranslator.java index 72b44a6cb31..66be0be538c 100644 --- a/translator/src/org/jetbrains/k2js/translate/expression/foreach/IteratorForTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/expression/foreach/IteratorForTranslator.java @@ -50,7 +50,6 @@ public final class IteratorForTranslator extends ForTranslator { @NotNull private JsBlock translate() { - JsName parameterName = declareParameter(); TemporaryVariable iterator = context().declareTemporary(iteratorMethodInvocation()); JsBlock bodyBlock = generateCycleBody(parameterName, iterator); JsWhile cycle = new JsWhile(hasNextMethodInvocation(iterator), bodyBlock); diff --git a/translator/src/org/jetbrains/k2js/translate/expression/foreach/RangeForTranslator.java b/translator/src/org/jetbrains/k2js/translate/expression/foreach/RangeForTranslator.java index c4568589d66..97730a69f11 100644 --- a/translator/src/org/jetbrains/k2js/translate/expression/foreach/RangeForTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/expression/foreach/RangeForTranslator.java @@ -81,7 +81,6 @@ public final class RangeForTranslator extends ForTranslator { @NotNull TemporaryVariable start, @NotNull TemporaryVariable end) { JsFor result = new JsFor(); - JsName parameterName = declareParameter(); result.setInitVars(initExpression(start, parameterName)); result.setCondition(getCondition(end, parameterName)); result.setIncrExpr(getIncrExpression(incrVar, parameterName)); diff --git a/translator/src/org/jetbrains/k2js/translate/expression/foreach/RangeLiteralForTranslator.java b/translator/src/org/jetbrains/k2js/translate/expression/foreach/RangeLiteralForTranslator.java new file mode 100644 index 00000000000..2dccbe985f9 --- /dev/null +++ b/translator/src/org/jetbrains/k2js/translate/expression/foreach/RangeLiteralForTranslator.java @@ -0,0 +1,121 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.k2js.translate.expression.foreach; + +import com.google.common.collect.Lists; +import com.google.dart.compiler.backend.js.ast.*; +import com.google.dart.compiler.util.AstUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.psi.JetBinaryExpression; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lang.psi.JetForExpression; +import org.jetbrains.jet.lexer.JetTokens; +import org.jetbrains.k2js.translate.context.TemporaryVariable; +import org.jetbrains.k2js.translate.context.TranslationContext; + +import java.util.List; + +import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopRange; +import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateLeftExpression; +import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateRightExpression; + +/** + * @author Pavel Talanov + */ + +// TODO: respect reverse semantics +public final class RangeLiteralForTranslator extends ForTranslator { + + @NotNull + public static JsStatement translate(@NotNull JetForExpression expression, + @NotNull TranslationContext context) { + return (new RangeLiteralForTranslator(expression, context).translate()); + } + + public static boolean isApplicable(@NotNull JetForExpression expression, + @NotNull TranslationContext context) { + JetExpression loopRange = getLoopRange(expression); + if (!(loopRange instanceof JetBinaryExpression)) { + return false; + } + boolean isRangeToOperation = ((JetBinaryExpression) loopRange).getOperationToken() == JetTokens.RANGE; + return isRangeToOperation && RangeForTranslator.isApplicable(expression, context); + } + + @NotNull + private final TemporaryVariable rangeStart; + + @NotNull + private final TemporaryVariable rangeEnd; + + private RangeLiteralForTranslator(@NotNull JetForExpression forExpression, @NotNull TranslationContext context) { + super(forExpression, context); + JetExpression loopRange = getLoopRange(expression); + assert loopRange instanceof JetBinaryExpression; + JetBinaryExpression loopRangeAsBinary = ((JetBinaryExpression) loopRange); + rangeStart = context.declareTemporary(translateLeftExpression(context, loopRangeAsBinary)); + rangeEnd = context.declareTemporary(getRangeEnd(loopRangeAsBinary)); + } + + @NotNull + private JsExpression getRangeEnd(@NotNull JetBinaryExpression loopRangeAsBinary) { + JsExpression rightExpression = translateRightExpression(context(), loopRangeAsBinary); + return new JsBinaryOperation(JsBinaryOperator.ADD, rightExpression, program().getNumberLiteral(1)); + } + + @NotNull + private JsBlock translate() { + List blockStatements = temporariesInitialization(rangeEnd, rangeStart); + blockStatements.add(generateForExpression()); + return AstUtil.newBlock(blockStatements); + } + + @NotNull + private JsFor generateForExpression() { + JsFor result = new JsFor(); + result.setInitVars(initExpression()); + result.setCondition(getCondition()); + result.setIncrExpr(getIncrExpression()); + result.setBody(translateOriginalBodyExpression()); + return result; + } + + @NotNull + private JsVars initExpression() { + return AstUtil.newVar(parameterName, rangeStart.reference()); + } + + @NotNull + private JsExpression getCondition() { + return AstUtil.notEqual(parameterName.makeRef(), rangeEnd.reference()); + } + + @NotNull + private JsExpression getIncrExpression() { + return new JsPrefixOperation(JsUnaryOperator.INC, parameterName.makeRef()); + } + + //TODO : UTIL!! + @NotNull + private List temporariesInitialization(@NotNull TemporaryVariable... temporaries) { + List result = Lists.newArrayList(); + for (TemporaryVariable temporary : temporaries) { + result.add(temporary.assignmentExpression().makeStmt()); + } + return result; + } +} diff --git a/translator/testFiles/range/cases/iteratingOverRanges.kt b/translator/testFiles/range/cases/iteratingOverRanges.kt new file mode 100644 index 00000000000..a0a4ccc95ad --- /dev/null +++ b/translator/testFiles/range/cases/iteratingOverRanges.kt @@ -0,0 +1,41 @@ +package foo + +import js.* + +fun box() : Boolean { + + var d = 0 + for (i in 1..6) { + d += i + } + if (d != 21) return false; + + for (x in 100..199) { + d += 1 + } + if (d != 121) { + return false; + } + + for (y in 1..1) { + d = 100 + } + + if (d != 100) { + return false; + } + + for (c in 100..100) { + d += 1; + } + + if (d != 101) { + return false; + } + return true + +} + +fun main() { + box() +} \ No newline at end of file diff --git a/translatorTests/test/org/jetbrains/k2js/test/RangeTest.java b/translatorTests/test/org/jetbrains/k2js/test/RangeTest.java index e3dced5c1a3..fe3b89d2756 100644 --- a/translatorTests/test/org/jetbrains/k2js/test/RangeTest.java +++ b/translatorTests/test/org/jetbrains/k2js/test/RangeTest.java @@ -43,4 +43,7 @@ public final class RangeTest extends TranslationTest { testFooBoxIsTrue("intInRange.kt"); } + public void testIteratingOverRanges() throws Exception { + testFooBoxIsTrue("iteratingOverRanges.kt"); + } }