diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java b/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java index 321c21d7207..eb7c927b5ca 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java @@ -32,7 +32,8 @@ import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.k2js.translate.context.TemporaryVariable; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.declaration.ClassTranslator; -import org.jetbrains.k2js.translate.expression.foreach.ForTranslator; +import org.jetbrains.k2js.translate.expression.loopTranslator.ForTranslator; +import org.jetbrains.k2js.translate.expression.loopTranslator.LoopTranslatorPackage; import org.jetbrains.k2js.translate.general.Translation; import org.jetbrains.k2js.translate.general.TranslatorVisitor; import org.jetbrains.k2js.translate.operation.BinaryOperationTranslator; @@ -215,17 +216,6 @@ public final class ExpressionVisitor extends TranslatorVisitor { return ReferenceTranslator.translateSimpleNameWithQualifier(expression, null, context).source(expression); } - @NotNull - private static JsStatement translateNullableExpressionAsNotNullStatement( - @Nullable JetExpression nullableExpression, - @NotNull TranslationContext context - ) { - if (nullableExpression == null) { - return context.program().getEmptyStatement(); - } - return Translation.translateAsStatement(nullableExpression, context); - } - @NotNull private JsExpression translateConditionExpression(@Nullable JetExpression expression, @NotNull TranslationContext context) { @@ -246,46 +236,13 @@ public final class ExpressionVisitor extends TranslatorVisitor { @Override @NotNull public JsNode visitWhileExpression(@NotNull JetWhileExpression expression, @NotNull TranslationContext context) { - return createWhile(false, expression, context); + return LoopTranslatorPackage.createWhile(false, expression, context); } @Override @NotNull public JsNode visitDoWhileExpression(@NotNull JetDoWhileExpression expression, @NotNull TranslationContext context) { - return createWhile(true, expression, context); - } - - private static JsNode createWhile(boolean doWhile, @NotNull JetWhileExpressionBase expression, @NotNull TranslationContext context) { - JetExpression conditionExpression = expression.getCondition(); - assert conditionExpression != null : "condition expression should not be null: " + expression.getText(); - - JsBlock conditionBlock = new JsBlock(); - JsExpression jsCondition = Translation.translateAsExpression(conditionExpression, context, conditionBlock); - JsStatement bodyStatement = translateNullableExpressionAsNotNullStatement(expression.getBody(), context); - if (!conditionBlock.isEmpty()) { - JsIf IfStatement = new JsIf(not(jsCondition), new JsBreak()); - JsBlock bodyBlock = JsAstUtils.convertToBlock(bodyStatement); - jsCondition = JsLiteral.TRUE; - if (doWhile) { - // translate to: tmpSecondRun = false; do { if(tmpSecondRun) { if(!tmpExprVar) break; } else tmpSecondRun=true; } while(true) - TemporaryVariable secondRun = context.declareTemporary(JsLiteral.FALSE); - context.addStatementToCurrentBlock(secondRun.assignmentExpression().makeStmt()); - conditionBlock.getStatements().add(IfStatement); - bodyBlock.getStatements().add(0, - new JsIf(secondRun.reference(), conditionBlock, - JsAstUtils.assignment(secondRun.reference(), JsLiteral.TRUE).makeStmt()) - ); - } else { - // translate to: while (true) { if(!tmpExprVar) break; } - conditionBlock.getStatements().add(IfStatement); - bodyBlock.getStatements().addAll(0, conditionBlock.getStatements()); - } - bodyStatement = bodyBlock; - } - JsWhile result = doWhile ? new JsDoWhile() : new JsWhile(); - result.setCondition(jsCondition); - result.setBody(bodyStatement); - return result.source(expression); + return LoopTranslatorPackage.createWhile(true, expression, context); } @Override @@ -471,7 +428,7 @@ public final class ExpressionVisitor extends TranslatorVisitor { @NotNull public JsNode visitForExpression(@NotNull JetForExpression expression, @NotNull TranslationContext context) { - return ForTranslator.translate(expression, context).source(expression); + return ForTranslator.OBJECT$.translate(expression, context).source(expression); } @Override diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/expression/LoopTranslator.kt b/js/js.translator/src/org/jetbrains/k2js/translate/expression/LoopTranslator.kt new file mode 100644 index 00000000000..4ed324a11c1 --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/translate/expression/LoopTranslator.kt @@ -0,0 +1,372 @@ +/* + * Copyright 2010-2014 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.loopTranslator + +import org.jetbrains.jet.lang.psi.JetWhileExpressionBase +import org.jetbrains.k2js.translate.context.TranslationContext +import com.google.dart.compiler.backend.js.ast.JsNode +import com.google.dart.compiler.backend.js.ast.JsBlock +import org.jetbrains.k2js.translate.general.Translation +import com.google.dart.compiler.backend.js.ast.JsIf +import org.jetbrains.k2js.translate.utils.JsAstUtils +import com.google.dart.compiler.backend.js.ast.JsLiteral +import com.google.dart.compiler.backend.js.ast.JsBreak +import com.google.dart.compiler.backend.js.ast.JsDoWhile +import com.google.dart.compiler.backend.js.ast.JsWhile +import com.google.dart.compiler.backend.js.ast.JsStatement +import org.jetbrains.jet.lang.psi.JetExpression +import org.jetbrains.jet.lang.psi.JetForExpression +import com.google.dart.compiler.backend.js.ast.JsExpression +import org.jetbrains.k2js.translate.context.TemporaryVariable +import org.jetbrains.jet.lang.psi.JetBinaryExpression +import org.jetbrains.k2js.translate.utils.PsiUtils.getLoopBody +import org.jetbrains.k2js.translate.utils.PsiUtils.getLoopParameter +import org.jetbrains.k2js.translate.utils.PsiUtils.getLoopRange +import org.jetbrains.k2js.translate.utils.TranslationUtils +import com.google.dart.compiler.backend.js.ast.JsFor +import com.google.dart.compiler.backend.js.ast.JsVars +import org.jetbrains.jet.lexer.JetTokens +import com.google.dart.compiler.backend.js.ast.JsUnaryOperator +import com.google.dart.compiler.backend.js.ast.JsPostfixOperation +import org.jetbrains.k2js.translate.utils.TemporariesUtils.temporariesInitialization +import com.google.dart.compiler.backend.js.ast.JsNameRef +import org.jetbrains.k2js.translate.utils.BindingUtils.* +import org.jetbrains.jet.lang.resolve.DescriptorUtils.getClassDescriptorForType +import org.jetbrains.k2js.translate.intrinsic.functions.factories.CompositeFIF +import com.google.dart.compiler.backend.js.ast.JsArrayAccess +import com.google.dart.compiler.backend.js.ast.JsPrefixOperation +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor +import org.jetbrains.k2js.translate.callTranslator.CallTranslator +import org.jetbrains.k2js.translate.general.AbstractTranslator +import com.google.dart.compiler.backend.js.ast.JsName +import org.jetbrains.jet.lang.psi.JetMultiDeclaration +import org.jetbrains.k2js.translate.expression.MultiDeclarationTranslator + +public fun createWhile(doWhile: Boolean, expression: JetWhileExpressionBase, context: TranslationContext): JsNode { + val conditionExpression = expression.getCondition() ?: + throw IllegalArgumentException("condition expression should not be null: ${expression.getText()}") + val conditionBlock = JsBlock() + var jsCondition = Translation.translateAsExpression(conditionExpression, context, conditionBlock) + var bodyStatement = translateNullableExpressionAsNotNullStatement(expression.getBody(), context) + if (!conditionBlock.isEmpty()) { + val IfStatement = JsIf(JsAstUtils.not(jsCondition), JsBreak()) + val bodyBlock = JsAstUtils.convertToBlock(bodyStatement) + jsCondition = JsLiteral.TRUE + if (doWhile) { + // translate to: tmpSecondRun = false; do { if(tmpSecondRun) { if(!tmpExprVar) break; } else tmpSecondRun=true; } while(true) + val secondRun = context.declareTemporary(JsLiteral.FALSE) + context.addStatementToCurrentBlock(secondRun.assignmentExpression().makeStmt()) + conditionBlock.getStatements().add(IfStatement) + bodyBlock.getStatements().add(0, JsIf(secondRun.reference(), + conditionBlock, + JsAstUtils.assignment(secondRun.reference(), JsLiteral.TRUE).makeStmt())) + } + else { + // translate to: while (true) { if(!tmpExprVar) break; } + conditionBlock.getStatements().add(IfStatement) + bodyBlock.getStatements().addAll(0, conditionBlock.getStatements()) + } + bodyStatement = bodyBlock + } + val result = if (doWhile) JsDoWhile() else JsWhile() + result.setCondition(jsCondition) + result.setBody(bodyStatement) + return result.source(expression)!! +} + +private fun translateNullableExpressionAsNotNullStatement(nullableExpression: JetExpression?, context: TranslationContext): JsStatement = + if (nullableExpression == null) + context.program().getEmptyStatement() + else + Translation.translateAsStatement(nullableExpression, context) + + +// TODO: implement reverse semantics +public class RangeLiteralForTranslator private(forExpression: JetForExpression, context: TranslationContext) : ForTranslator(forExpression, context) { + + private val rangeStart: JsExpression + + private val rangeEnd: TemporaryVariable + + { + val loopRange = getLoopRange(expression) + assert(loopRange is JetBinaryExpression) + val loopRangeAsBinary = (loopRange as JetBinaryExpression) + val startBlock = JsBlock() + var rangeStartExpression = TranslationUtils.translateLeftExpression(context, loopRangeAsBinary, startBlock) + val endBlock = JsBlock() + val rightExpression = TranslationUtils.translateRightExpression(context(), loopRangeAsBinary, endBlock) + if (TranslationUtils.isCacheNeeded(rangeStartExpression)) { + val startVar = context.declareTemporary(rangeStartExpression) + rangeStartExpression = startVar.reference() + context.addStatementToCurrentBlock(startVar.assignmentExpression().makeStmt()) + } + rangeStart = rangeStartExpression + context.addStatementsToCurrentBlockFrom(startBlock) + context.addStatementsToCurrentBlockFrom(endBlock) + rangeEnd = context.declareTemporary(rightExpression) + } + + private fun translate(): JsStatement { + context().addStatementToCurrentBlock(temporariesInitialization(rangeEnd).makeStmt()) + return JsFor(initExpression(), getCondition(), getIncrExpression(), translateBody(null)) + } + + private fun initExpression(): JsVars { + return JsAstUtils.newVar(parameterName, rangeStart) + } + + private fun getCondition(): JsExpression { + return JsAstUtils.lessThanEq(parameterName.makeRef(), rangeEnd.reference()) + } + + private fun getIncrExpression(): JsExpression { + return JsPostfixOperation(JsUnaryOperator.INC, parameterName.makeRef()) + } + + class object { + + public fun doTranslate(expression: JetForExpression, context: TranslationContext): JsStatement { + return (RangeLiteralForTranslator(expression, context).translate()) + } + + public fun isApplicable(expression: JetForExpression, context: TranslationContext): Boolean { + val loopRange = getLoopRange(expression) + if (loopRange !is JetBinaryExpression) { + return false + } + val isRangeToOperation = (loopRange as JetBinaryExpression).getOperationToken() == JetTokens.RANGE + return isRangeToOperation && RangeForTranslator.isApplicable(expression, context) + } + } +} + +public class RangeForTranslator private(forExpression: JetForExpression, context: TranslationContext) : ForTranslator(forExpression, context) { + + private val rangeExpression: TemporaryVariable + private val start: TemporaryVariable + private val end: TemporaryVariable + private val increment: TemporaryVariable + + { + rangeExpression = context.declareTemporary(Translation.translateAsExpression(getLoopRange(expression), context)) + start = context().declareTemporary(getProperty("start")) + end = context().declareTemporary(getProperty("end")) + increment = context().declareTemporary(getProperty("increment")) + } + + private fun translate(): JsStatement { + context().addStatementToCurrentBlock(temporariesInitialization(rangeExpression, start, end, increment).makeStmt()) + return generateForExpression() + } + + private fun generateForExpression(): JsFor { + val result = JsFor(initExpression(), getCondition(), getIncrExpression()) + result.setBody(translateBody(null)) + return result + } + + private fun initExpression(): JsVars { + return JsAstUtils.newVar(parameterName, start.reference()) + } + + private fun getCondition(): JsExpression { + return JsAstUtils.lessThanEq(parameterName.makeRef(), end.reference()) + } + + private fun getIncrExpression(): JsExpression { + return JsAstUtils.addAssign(parameterName.makeRef(), increment.reference()) + } + + private fun getProperty(funName: String): JsExpression { + return JsNameRef(funName, rangeExpression.reference()) + } + + class object { + + public fun doTranslate(expression: JetForExpression, context: TranslationContext): JsStatement { + return (RangeForTranslator(expression, context).translate()) + } + + public fun isApplicable(expression: JetForExpression, context: TranslationContext): Boolean { + val loopRange = getLoopRange(expression) + val rangeType = getTypeForExpression(context.bindingContext(), loopRange) + //TODO: better check + //TODO: long range? + return getClassDescriptorForType(rangeType).getName().asString() == "IntRange" + } + } +} + +public class ArrayForTranslator private(forExpression: JetForExpression, context: TranslationContext) : ForTranslator(forExpression, context) { + + private val loopRange: TemporaryVariable + + private val end: TemporaryVariable + + private val index: TemporaryVariable + + { + loopRange = context.declareTemporary(Translation.translateAsExpression(getLoopRange(expression), context)) + + val length = CompositeFIF.LENGTH_PROPERTY_INTRINSIC.apply(loopRange.reference(), listOf(), context()) + end = context().declareTemporary(length) + index = context().declareTemporary(program().getNumberLiteral(0)) + } + + private fun translate(): JsStatement { + context().addStatementToCurrentBlock(temporariesInitialization(loopRange, end).makeStmt()) + return JsFor(getInitExpression(), getCondition(), getIncrementExpression(), getBody()) + } + + + private fun getBody(): JsStatement { + val arrayAccess = JsArrayAccess(loopRange.reference(), index.reference()) + return translateBody(arrayAccess) + } + + private fun getInitExpression(): JsVars { + return JsAstUtils.newVar(index.name(), program().getNumberLiteral(0)) + } + + private fun getCondition(): JsExpression { + return JsAstUtils.inequality(index.reference(), end.reference()) + } + + private fun getIncrementExpression(): JsExpression { + return JsPrefixOperation(JsUnaryOperator.INC, index.reference()) + } + + class object { + + public fun doTranslate(expression: JetForExpression, context: TranslationContext): JsStatement { + return (ArrayForTranslator(expression, context).translate()) + } + + public fun isApplicable(expression: JetForExpression, context: TranslationContext): Boolean { + val loopRange = getLoopRange(expression) + val rangeType = getTypeForExpression(context.bindingContext(), loopRange) + //TODO: better check + //TODO: IMPORTANT! + return getClassDescriptorForType(rangeType).getName().asString() == "Array" || getClassDescriptorForType(rangeType).getName().asString() == "IntArray" + } + } +} + + +public class IteratorForTranslator private(forExpression: JetForExpression, context: TranslationContext) : ForTranslator(forExpression, context) { + private val iteratorVar: TemporaryVariable + + { + iteratorVar = context.declareTemporary(iteratorMethodInvocation()) + } + + private fun translate(): JsStatement { + context().addStatementToCurrentBlock(iteratorVar.assignmentExpression().makeStmt()) + return JsWhile(hasNextMethodInvocation(), translateBody(nextMethodInvocation())) + } + + private fun nextMethodInvocation(): JsExpression { + return translateMethodInvocation(iteratorVar.reference(), getNextFunction(bindingContext(), getLoopRange(expression))) + } + + private fun hasNextMethodInvocation(): JsExpression { + val resolvedCall = getHasNextCallable(bindingContext(), getLoopRange(expression)) + return translateMethodInvocation(iteratorVar.reference(), resolvedCall) + } + + private fun iteratorMethodInvocation(): JsExpression { + val rangeExpression = getLoopRange(expression) + val range = Translation.translateAsExpression(rangeExpression, context()) + val resolvedCall = getIteratorFunction(bindingContext(), rangeExpression) + return translateMethodInvocation(range, resolvedCall) + } + + private fun translateMethodInvocation(receiver: JsExpression?, resolvedCall: ResolvedCall): JsExpression { + return CallTranslator.translate(context(), resolvedCall, receiver) + } + + class object { + + public fun doTranslate(expression: JetForExpression, context: TranslationContext): JsStatement { + return (IteratorForTranslator(expression, context).translate()) + } + } +} + +public abstract class ForTranslator protected(protected val expression: JetForExpression, context: TranslationContext) : AbstractTranslator(context) { + protected val parameterName: JsName + protected val multiParameter: JetMultiDeclaration? + + { + this.multiParameter = expression.getMultiParameter() + this.parameterName = declareParameter() + } + + private fun declareParameter(): JsName { + val loopParameter = getLoopParameter(expression) + if (loopParameter != null) { + return context().getNameForElement(loopParameter) + } + assert(parameterIsMultiDeclaration(), "If loopParameter is null, multi parameter must be not null") + return context().scope().declareTemporary() + } + + private fun parameterIsMultiDeclaration(): Boolean { + return multiParameter != null + } + + private fun makeCurrentVarInit(itemValue: JsExpression?): JsStatement { + if (multiParameter == null) { + return JsAstUtils.newVar(parameterName, itemValue) + } + else { + return MultiDeclarationTranslator.translate(multiParameter!!, parameterName, itemValue, context()) + } + } + + protected fun translateBody(itemValue: JsExpression?): JsStatement { + val realBody = Translation.translateAsStatement(getLoopBody(expression), context()) + if (itemValue == null && !parameterIsMultiDeclaration()) { + return realBody + } + else { + val currentVarInit = makeCurrentVarInit(itemValue) + val block = JsAstUtils.convertToBlock(realBody) + block.getStatements().add(0, currentVarInit) + return block + } + } + + class object { + + public fun translate(expression: JetForExpression, context: TranslationContext): JsStatement { + if (RangeLiteralForTranslator.isApplicable(expression, context)) { + return RangeLiteralForTranslator.doTranslate(expression, context) + } + if (RangeForTranslator.isApplicable(expression, context)) { + return RangeForTranslator.doTranslate(expression, context) + } + if (ArrayForTranslator.isApplicable(expression, context)) { + return ArrayForTranslator.doTranslate(expression, context) + } + return IteratorForTranslator.doTranslate(expression, context) + } + } +} + diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/expression/foreach/ArrayForTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/expression/foreach/ArrayForTranslator.java deleted file mode 100644 index 554021cbd0a..00000000000 --- a/js/js.translator/src/org/jetbrains/k2js/translate/expression/foreach/ArrayForTranslator.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2010-2013 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.dart.compiler.backend.js.ast.*; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.psi.JetExpression; -import org.jetbrains.jet.lang.psi.JetForExpression; -import org.jetbrains.jet.lang.types.JetType; -import org.jetbrains.k2js.translate.context.TemporaryVariable; -import org.jetbrains.k2js.translate.context.TranslationContext; -import org.jetbrains.k2js.translate.general.Translation; -import org.jetbrains.k2js.translate.intrinsic.functions.factories.CompositeFIF; -import org.jetbrains.k2js.translate.utils.BindingUtils; - -import java.util.Collections; - -import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getClassDescriptorForType; -import static org.jetbrains.k2js.translate.utils.JsAstUtils.*; -import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopRange; -import static org.jetbrains.k2js.translate.utils.TemporariesUtils.temporariesInitialization; - -public final class ArrayForTranslator extends ForTranslator { - - @NotNull - public static JsStatement doTranslate(@NotNull JetForExpression expression, - @NotNull TranslationContext context) { - return (new ArrayForTranslator(expression, context).translate()); - } - - public static boolean isApplicable(@NotNull JetForExpression expression, - @NotNull TranslationContext context) { - JetExpression loopRange = getLoopRange(expression); - JetType rangeType = BindingUtils.getTypeForExpression(context.bindingContext(), loopRange); - //TODO: better check - //TODO: IMPORTANT! - return getClassDescriptorForType(rangeType).getName().asString().equals("Array") - || getClassDescriptorForType(rangeType).getName().asString().equals("IntArray"); - } - - @NotNull - private final TemporaryVariable loopRange; - - @NotNull - private final TemporaryVariable end; - - @NotNull - private final TemporaryVariable index; - - private ArrayForTranslator(@NotNull JetForExpression forExpression, @NotNull TranslationContext context) { - super(forExpression, context); - loopRange = context.declareTemporary(Translation.translateAsExpression(getLoopRange(expression), context)); - - JsExpression length = CompositeFIF.LENGTH_PROPERTY_INTRINSIC.apply(loopRange.reference(), - Collections.emptyList(), - context()); - end = context().declareTemporary(length); - index = context().declareTemporary(program().getNumberLiteral(0)); - } - - @NotNull - private JsStatement translate() { - context().addStatementToCurrentBlock(temporariesInitialization(loopRange, end).makeStmt()); - return new JsFor(getInitExpression(), getCondition(), getIncrementExpression(), getBody()); - } - - - @NotNull - private JsStatement getBody() { - JsArrayAccess arrayAccess = new JsArrayAccess(loopRange.reference(), index.reference()); - return translateBody(arrayAccess); - } - - @NotNull - private JsVars getInitExpression() { - return newVar(index.name(), program().getNumberLiteral(0)); - } - - @NotNull - private JsExpression getCondition() { - return inequality(index.reference(), end.reference()); - } - - @NotNull - private JsExpression getIncrementExpression() { - return new JsPrefixOperation(JsUnaryOperator.INC, index.reference()); - } -} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/expression/foreach/ForTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/expression/foreach/ForTranslator.java deleted file mode 100644 index f46c1c60c5d..00000000000 --- a/js/js.translator/src/org/jetbrains/k2js/translate/expression/foreach/ForTranslator.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2010-2013 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.dart.compiler.backend.js.ast.JsBlock; -import com.google.dart.compiler.backend.js.ast.JsExpression; -import com.google.dart.compiler.backend.js.ast.JsName; -import com.google.dart.compiler.backend.js.ast.JsStatement; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.psi.JetForExpression; -import org.jetbrains.jet.lang.psi.JetMultiDeclaration; -import org.jetbrains.jet.lang.psi.JetParameter; -import org.jetbrains.k2js.translate.context.TranslationContext; -import org.jetbrains.k2js.translate.expression.MultiDeclarationTranslator; -import org.jetbrains.k2js.translate.general.AbstractTranslator; -import org.jetbrains.k2js.translate.general.Translation; -import org.jetbrains.k2js.translate.utils.JsAstUtils; -import org.jetbrains.k2js.translate.utils.TranslationUtils; - -import static org.jetbrains.k2js.translate.utils.JsAstUtils.newVar; -import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopBody; -import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopParameter; - -public abstract class ForTranslator extends AbstractTranslator { - - @NotNull - public static JsStatement translate(@NotNull JetForExpression expression, - @NotNull TranslationContext context) { - if (RangeLiteralForTranslator.isApplicable(expression, context)) { - return RangeLiteralForTranslator.doTranslate(expression, context); - } - if (RangeForTranslator.isApplicable(expression, context)) { - return RangeForTranslator.doTranslate(expression, context); - } - if (ArrayForTranslator.isApplicable(expression, context)) { - return ArrayForTranslator.doTranslate(expression, context); - } - return IteratorForTranslator.doTranslate(expression, context); - } - - @NotNull - protected final JetForExpression expression; - @NotNull - protected final JsName parameterName; - @Nullable - protected final JetMultiDeclaration multiParameter; - - protected ForTranslator(@NotNull JetForExpression forExpression, @NotNull TranslationContext context) { - super(context); - this.expression = forExpression; - this.multiParameter = forExpression.getMultiParameter(); - this.parameterName = declareParameter(); - } - - @NotNull - private JsName declareParameter() { - JetParameter loopParameter = getLoopParameter(expression); - if (loopParameter != null) { - return context().getNameForElement(loopParameter); - } - assert parameterIsMultiDeclaration() : "If loopParameter is null, multi parameter must be not null"; - return context().scope().declareTemporary(); - } - - private boolean parameterIsMultiDeclaration() { - return multiParameter != null; - } - - @NotNull - private JsStatement makeCurrentVarInit(@Nullable JsExpression itemValue) { - if (multiParameter == null) { - return newVar(parameterName, itemValue); - } else { - return MultiDeclarationTranslator.translate(multiParameter, parameterName, itemValue, context()); - } - } - - @NotNull - protected JsStatement translateBody(@Nullable JsExpression itemValue) { - JsStatement realBody = Translation.translateAsStatement(getLoopBody(expression), context()); - if (itemValue == null && !parameterIsMultiDeclaration()) { - return realBody; - } else { - JsStatement currentVarInit = makeCurrentVarInit(itemValue); - JsBlock block = JsAstUtils.convertToBlock(realBody); - block.getStatements().add(0, currentVarInit); - return block; - } - } -} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/expression/foreach/IteratorForTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/expression/foreach/IteratorForTranslator.java deleted file mode 100644 index fdd7ae42cdb..00000000000 --- a/js/js.translator/src/org/jetbrains/k2js/translate/expression/foreach/IteratorForTranslator.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2010-2013 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.dart.compiler.backend.js.ast.*; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; -import org.jetbrains.jet.lang.psi.JetExpression; -import org.jetbrains.jet.lang.psi.JetForExpression; -import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; -import org.jetbrains.k2js.translate.callTranslator.CallTranslator; -import org.jetbrains.k2js.translate.context.TemporaryVariable; -import org.jetbrains.k2js.translate.context.TranslationContext; -import org.jetbrains.k2js.translate.general.Translation; - -import static org.jetbrains.k2js.translate.utils.BindingUtils.*; -import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopRange; - -public final class IteratorForTranslator extends ForTranslator { - @NotNull - private final TemporaryVariable iteratorVar; - - @NotNull - public static JsStatement doTranslate(@NotNull JetForExpression expression, - @NotNull TranslationContext context) { - return (new IteratorForTranslator(expression, context).translate()); - } - - private IteratorForTranslator(@NotNull JetForExpression forExpression, @NotNull TranslationContext context) { - super(forExpression, context); - iteratorVar = context.declareTemporary(iteratorMethodInvocation()); - } - - @NotNull - private JsStatement translate() { - context().addStatementToCurrentBlock(iteratorVar.assignmentExpression().makeStmt()); - return new JsWhile(hasNextMethodInvocation(), translateBody(nextMethodInvocation())); - } - - @NotNull - private JsExpression nextMethodInvocation() { - return translateMethodInvocation(iteratorVar.reference(), getNextFunction(bindingContext(), getLoopRange(expression))); - } - - @NotNull - private JsExpression hasNextMethodInvocation() { - ResolvedCall resolvedCall = getHasNextCallable(bindingContext(), getLoopRange(expression)); - return translateMethodInvocation(iteratorVar.reference(), resolvedCall); - } - - @NotNull - private JsExpression iteratorMethodInvocation() { - JetExpression rangeExpression = getLoopRange(expression); - JsExpression range = Translation.translateAsExpression(rangeExpression, context()); - ResolvedCall resolvedCall = getIteratorFunction(bindingContext(), rangeExpression); - return translateMethodInvocation(range, resolvedCall); - } - - @NotNull - private JsExpression translateMethodInvocation(@Nullable JsExpression receiver, - @NotNull ResolvedCall resolvedCall) { - return CallTranslator.INSTANCE$.translate(context(), resolvedCall, receiver); - } -} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/expression/foreach/RangeForTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/expression/foreach/RangeForTranslator.java deleted file mode 100644 index 1a9aa78ffc6..00000000000 --- a/js/js.translator/src/org/jetbrains/k2js/translate/expression/foreach/RangeForTranslator.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2010-2013 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.dart.compiler.backend.js.ast.*; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.psi.JetExpression; -import org.jetbrains.jet.lang.psi.JetForExpression; -import org.jetbrains.jet.lang.types.JetType; -import org.jetbrains.k2js.translate.context.TemporaryVariable; -import org.jetbrains.k2js.translate.context.TranslationContext; -import org.jetbrains.k2js.translate.general.Translation; -import org.jetbrains.k2js.translate.utils.BindingUtils; - -import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getClassDescriptorForType; -import static org.jetbrains.k2js.translate.utils.JsAstUtils.*; -import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopRange; -import static org.jetbrains.k2js.translate.utils.TemporariesUtils.temporariesInitialization; - -public final class RangeForTranslator extends ForTranslator { - - @NotNull - public static JsStatement doTranslate(@NotNull JetForExpression expression, - @NotNull TranslationContext context) { - return (new RangeForTranslator(expression, context).translate()); - } - - public static boolean isApplicable(@NotNull JetForExpression expression, - @NotNull TranslationContext context) { - JetExpression loopRange = getLoopRange(expression); - JetType rangeType = BindingUtils.getTypeForExpression(context.bindingContext(), loopRange); - //TODO: better check - //TODO: long range? - return getClassDescriptorForType(rangeType).getName().asString().equals("IntRange"); - } - - @NotNull - private final TemporaryVariable rangeExpression; - @NotNull - private final TemporaryVariable start; - @NotNull - private final TemporaryVariable end; - @NotNull - private final TemporaryVariable increment; - - private RangeForTranslator(@NotNull JetForExpression forExpression, @NotNull TranslationContext context) { - super(forExpression, context); - rangeExpression = context.declareTemporary(Translation.translateAsExpression(getLoopRange(expression), context)); - start = context().declareTemporary(getProperty("start")); - end = context().declareTemporary(getProperty("end")); - increment = context().declareTemporary(getProperty("increment")); - } - - @NotNull - private JsStatement translate() { - context().addStatementToCurrentBlock(temporariesInitialization(rangeExpression, start, end, increment).makeStmt()); - return generateForExpression(); - } - - @NotNull - private JsFor generateForExpression() { - JsFor result = new JsFor(initExpression(), getCondition(), getIncrExpression()); - result.setBody(translateBody(null)); - return result; - } - - @NotNull - private JsVars initExpression() { - return newVar(parameterName, start.reference()); - } - - @NotNull - private JsExpression getCondition() { - return lessThanEq(parameterName.makeRef(), end.reference()); - } - - @NotNull - private JsExpression getIncrExpression() { - return addAssign(parameterName.makeRef(), increment.reference()); - } - - @NotNull - private JsExpression getProperty(@NotNull String funName) { - return new JsNameRef(funName, rangeExpression.reference()); - } -} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/expression/foreach/RangeLiteralForTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/expression/foreach/RangeLiteralForTranslator.java deleted file mode 100644 index 333862466cd..00000000000 --- a/js/js.translator/src/org/jetbrains/k2js/translate/expression/foreach/RangeLiteralForTranslator.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2010-2013 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.dart.compiler.backend.js.ast.*; -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 org.jetbrains.k2js.translate.utils.TranslationUtils; - -import static org.jetbrains.k2js.translate.utils.JsAstUtils.lessThanEq; -import static org.jetbrains.k2js.translate.utils.JsAstUtils.newVar; -import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopRange; -import static org.jetbrains.k2js.translate.utils.TemporariesUtils.temporariesInitialization; -import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateLeftExpression; -import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateRightExpression; - - -// TODO: implement reverse semantics -public final class RangeLiteralForTranslator extends ForTranslator { - - @NotNull - public static JsStatement doTranslate(@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 JsExpression 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); - JsBlock startBlock = new JsBlock(); - JsExpression rangeStartExpression = translateLeftExpression(context, loopRangeAsBinary, startBlock); - JsBlock endBlock = new JsBlock(); - JsExpression rightExpression = translateRightExpression(context(), loopRangeAsBinary, endBlock); - if (TranslationUtils.isCacheNeeded(rangeStartExpression)) { - TemporaryVariable startVar = context.declareTemporary(rangeStartExpression); - rangeStartExpression = startVar.reference(); - context.addStatementToCurrentBlock(startVar.assignmentExpression().makeStmt()); - } - rangeStart = rangeStartExpression; - context.addStatementsToCurrentBlockFrom(startBlock); - context.addStatementsToCurrentBlockFrom(endBlock); - rangeEnd = context.declareTemporary(rightExpression); - } - - @NotNull - private JsStatement translate() { - context().addStatementToCurrentBlock(temporariesInitialization(rangeEnd).makeStmt()); - return new JsFor(initExpression(), getCondition(), getIncrExpression(), translateBody(null)); - } - - @NotNull - private JsVars initExpression() { - return newVar(parameterName, rangeStart); - } - - @NotNull - private JsExpression getCondition() { - return lessThanEq(parameterName.makeRef(), rangeEnd.reference()); - } - - @NotNull - private JsExpression getIncrExpression() { - return new JsPostfixOperation(JsUnaryOperator.INC, parameterName.makeRef()); - } -}