From 4075070506b7a06ee7b5d4eaeca87751ff2538ba Mon Sep 17 00:00:00 2001 From: Pavel Talanov Date: Wed, 22 Feb 2012 20:55:08 +0400 Subject: [PATCH] modified Config to implement multifile action implemented optimisation of the for expression (quite dirty for now) --- .../src/org/jetbrains/k2js/config/Config.java | 74 +--------- .../org/jetbrains/k2js/config/IDEAConfig.java | 10 ++ .../org/jetbrains/k2js/config/TestConfig.java | 76 +++++++++++ .../jetbrains/k2js/facade/K2JSTranslator.java | 20 ++- .../translate/context/TemporaryVariable.java | 2 +- .../expression/ExpressionVisitor.java | 5 +- .../translate/expression/WhenTranslator.java | 10 +- .../foreach/ArrayForTranslator.java | 121 +++++++++++++++++ .../expression/foreach/ForTranslator.java | 59 ++++++++ .../IteratorForTranslator.java} | 41 ++---- .../foreach/RangeForTranslator.java | 127 ++++++++++++++++++ .../operation/IncrementTranslator.java | 12 +- .../k2js/translate/reference/CallType.java | 4 +- .../k2js/translate/utils/BindingUtils.java | 8 ++ .../k2js/translate/utils/PsiUtils.java | 7 + 15 files changed, 453 insertions(+), 123 deletions(-) create mode 100644 translator/src/org/jetbrains/k2js/translate/expression/foreach/ArrayForTranslator.java create mode 100644 translator/src/org/jetbrains/k2js/translate/expression/foreach/ForTranslator.java rename translator/src/org/jetbrains/k2js/translate/expression/{ForTranslator.java => foreach/IteratorForTranslator.java} (75%) create mode 100644 translator/src/org/jetbrains/k2js/translate/expression/foreach/RangeForTranslator.java diff --git a/translator/src/org/jetbrains/k2js/config/Config.java b/translator/src/org/jetbrains/k2js/config/Config.java index 0dc6d6b3cf9..9bef13e1220 100644 --- a/translator/src/org/jetbrains/k2js/config/Config.java +++ b/translator/src/org/jetbrains/k2js/config/Config.java @@ -17,18 +17,9 @@ package org.jetbrains.k2js.config; import com.intellij.openapi.project.Project; -import core.Dummy; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.psi.JetFile; -import org.jetbrains.k2js.utils.JetFileUtils; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.util.ArrayList; -import java.util.Arrays; import java.util.List; /** @@ -38,73 +29,10 @@ import java.util.List; */ public abstract class Config { - - //TODO: provide some generic way to get the files of the project - @NotNull - private static final List LIB_FILE_NAMES = Arrays.asList( - "/core/annotations.kt", - "/jquery/common.kt", - "/jquery/ui.kt", - "/core/javautil.kt", - "/core/javalang.kt", - "/core/core.kt", - "/core/math.kt", - "/core/json.kt", - "/raphael/raphael.kt", - "/html5/canvas.kt", - "/html5/files.kt", - "/html5/image.kt", - "/helper/ip.kt", - "/pixastic/pixastic.kt" - ); - - - @NotNull - private static List initLibFiles(@NotNull Project project) { - List libFiles = new ArrayList(); - for (String libFileName : LIB_FILE_NAMES) { - InputStream stream = Dummy.class.getResourceAsStream(libFileName); - //noinspection IOResourceOpenedButNotSafelyClosed - JetFile file = null; - try { - String text = readString(stream); - file = JetFileUtils.createPsiFile(libFileName, text, project); - } catch (IOException e) { - e.printStackTrace(); - } - libFiles.add(file); - } - return libFiles; - } - - - @Nullable - private /*var*/ List jsLibFiles = null; - @NotNull public abstract Project getProject(); @NotNull - public List getLibFiles() { - if (jsLibFiles == null) { - jsLibFiles = initLibFiles(getProject()); - } - - return jsLibFiles; - } - - static String readString(InputStream is) throws IOException { - char[] buf = new char[2048]; - Reader r = new InputStreamReader(is, "UTF-8"); - StringBuilder s = new StringBuilder(); - while (true) { - int n = r.read(buf); - if (n < 0) - break; - s.append(buf, 0, n); - } - return s.toString(); - } - + public abstract List getLibFiles(); } diff --git a/translator/src/org/jetbrains/k2js/config/IDEAConfig.java b/translator/src/org/jetbrains/k2js/config/IDEAConfig.java index f72d8668acd..b421601c274 100644 --- a/translator/src/org/jetbrains/k2js/config/IDEAConfig.java +++ b/translator/src/org/jetbrains/k2js/config/IDEAConfig.java @@ -18,6 +18,10 @@ package org.jetbrains.k2js.config; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.psi.JetFile; + +import java.util.Collections; +import java.util.List; /** * @author Pavel Talanov @@ -36,4 +40,10 @@ public final class IDEAConfig extends Config { public Project getProject() { return project; } + + @NotNull + @Override + public List getLibFiles() { + return Collections.emptyList(); + } } diff --git a/translator/src/org/jetbrains/k2js/config/TestConfig.java b/translator/src/org/jetbrains/k2js/config/TestConfig.java index 22d57e9931a..df968ea5879 100644 --- a/translator/src/org/jetbrains/k2js/config/TestConfig.java +++ b/translator/src/org/jetbrains/k2js/config/TestConfig.java @@ -18,15 +18,46 @@ package org.jetbrains.k2js.config; import com.intellij.openapi.Disposable; import com.intellij.openapi.project.Project; +import core.Dummy; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.compiler.JetCoreEnvironment; +import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.k2js.utils.JetFileUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; /** * @author Pavel Talanov */ +//TODO: review/refactor public final class TestConfig extends Config { + //TODO: provide some generic way to get the files of the project + @NotNull + private static final List LIB_FILE_NAMES = Arrays.asList( + "/core/annotations.kt", + "/jquery/common.kt", + "/jquery/ui.kt", + "/core/javautil.kt", + "/core/javalang.kt", + "/core/core.kt", + "/core/math.kt", + "/core/json.kt", + "/raphael/raphael.kt", + "/html5/canvas.kt", + "/html5/files.kt", + "/html5/image.kt", + "/helper/ip.kt", + "/pixastic/pixastic.kt" + ); + @NotNull private static JetCoreEnvironment getTestEnvironment() { if (testOnlyEnvironment == null) { @@ -42,6 +73,10 @@ public final class TestConfig extends Config { @Nullable private static /*var*/ JetCoreEnvironment testOnlyEnvironment = null; + + @Nullable + private /*var*/ List jsLibFiles = null; + public TestConfig() { } @@ -50,4 +85,45 @@ public final class TestConfig extends Config { public Project getProject() { return getTestEnvironment().getProject(); } + + @NotNull + private static List initLibFiles(@NotNull Project project) { + List libFiles = new ArrayList(); + for (String libFileName : LIB_FILE_NAMES) { + InputStream stream = Dummy.class.getResourceAsStream(libFileName); + //noinspection IOResourceOpenedButNotSafelyClosed + JetFile file = null; + try { + String text = readString(stream); + file = JetFileUtils.createPsiFile(libFileName, text, project); + } catch (IOException e) { + e.printStackTrace(); + } + libFiles.add(file); + } + return libFiles; + } + + @NotNull + public List getLibFiles() { + if (jsLibFiles == null) { + jsLibFiles = initLibFiles(getProject()); + } + + return jsLibFiles; + } + + @NotNull + private static String readString(@NotNull InputStream is) throws IOException { + char[] buf = new char[2048]; + Reader r = new InputStreamReader(is, "UTF-8"); + StringBuilder s = new StringBuilder(); + while (true) { + int n = r.read(buf); + if (n < 0) + break; + s.append(buf, 0, n); + } + return s.toString(); + } } diff --git a/translator/src/org/jetbrains/k2js/facade/K2JSTranslator.java b/translator/src/org/jetbrains/k2js/facade/K2JSTranslator.java index ec186cc9e7f..954d972d368 100644 --- a/translator/src/org/jetbrains/k2js/facade/K2JSTranslator.java +++ b/translator/src/org/jetbrains/k2js/facade/K2JSTranslator.java @@ -22,6 +22,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.plugin.JetMainDetector; import org.jetbrains.k2js.analyze.Analyzer; import org.jetbrains.k2js.config.Config; import org.jetbrains.k2js.config.IDEAConfig; @@ -49,12 +50,16 @@ import static org.jetbrains.k2js.utils.JetFileUtils.createPsiFileList; */ public final class K2JSTranslator { - public static void translateWithCallToMainAndSaveToFile(@NotNull JetFile file, + public static void translateWithCallToMainAndSaveToFile(@NotNull List files, @NotNull String outputPath, @NotNull Project project) throws Exception { K2JSTranslator translator = new K2JSTranslator(new IDEAConfig(project)); - String programCode = translator.generateProgramCode(file) + "\n"; - String callToMain = translator.generateCallToMain(file, ""); + String programCode = translator.generateProgramCode(files) + "\n"; + JetFile fileWithMain = JetMainDetector.getFileWithMain(files); + if (fileWithMain == null) { + throw new RuntimeException("No file with main detected."); + } + String callToMain = translator.generateCallToMain(fileWithMain, ""); FileWriter writer = new FileWriter(new File(outputPath)); writer.write(programCode + callToMain); writer.close(); @@ -86,6 +91,7 @@ public final class K2JSTranslator { this.config = config; } + //TODO: refactor @NotNull public String translateStringWithCallToMain(@NotNull String programText, @NotNull String argumentsString) { JetFile file = JetFileUtils.createPsiFile("test", programText, getProject()); @@ -103,6 +109,13 @@ public final class K2JSTranslator { return generator.generateToString(program); } + @NotNull + private String generateProgramCode(@NotNull List files) { + JsProgram program = generateProgram(files); + CodeGenerator generator = new CodeGenerator(); + return generator.generateToString(program); + } + @NotNull public BindingContext analyzeProgramCode(@NotNull String programText) { JetFile file = JetFileUtils.createPsiFile("test", programText, getProject()); @@ -137,7 +150,6 @@ public final class K2JSTranslator { return result; } - @NotNull private Project getProject() { return config.getProject(); diff --git a/translator/src/org/jetbrains/k2js/translate/context/TemporaryVariable.java b/translator/src/org/jetbrains/k2js/translate/context/TemporaryVariable.java index 09c6929cf9d..265d2653d7b 100644 --- a/translator/src/org/jetbrains/k2js/translate/context/TemporaryVariable.java +++ b/translator/src/org/jetbrains/k2js/translate/context/TemporaryVariable.java @@ -38,7 +38,7 @@ public final class TemporaryVariable { } @NotNull - public JsNameRef nameReference() { + public JsNameRef reference() { return variableName.makeRef(); } diff --git a/translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java b/translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java index f1b74b5b9d1..ba564959d8a 100644 --- a/translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java +++ b/translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java @@ -28,6 +28,7 @@ import org.jetbrains.jet.lang.resolve.constants.NullValue; 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.general.Translation; import org.jetbrains.k2js.translate.general.TranslatorVisitor; import org.jetbrains.k2js.translate.operation.BinaryOperationTranslator; @@ -160,12 +161,12 @@ public final class ExpressionVisitor extends TranslatorVisitor { } TemporaryVariable result = context.declareTemporary(context.program().getNullLiteral()); AstUtil.SaveLastExpressionMutator saveResultToTemporaryMutator = - new AstUtil.SaveLastExpressionMutator(result.nameReference()); + new AstUtil.SaveLastExpressionMutator(result.reference()); JsNode mutatedIfStatement = AstUtil.mutateLastExpression(ifStatement, saveResultToTemporaryMutator); JsStatement resultingStatement = AstUtil.convertToStatement(mutatedIfStatement); context.addStatementToCurrentBlock(resultingStatement); - return result.nameReference(); + return result.reference(); } @Override diff --git a/translator/src/org/jetbrains/k2js/translate/expression/WhenTranslator.java b/translator/src/org/jetbrains/k2js/translate/expression/WhenTranslator.java index 0010081b70f..ffc4e69b5be 100644 --- a/translator/src/org/jetbrains/k2js/translate/expression/WhenTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/expression/WhenTranslator.java @@ -65,7 +65,7 @@ public class WhenTranslator extends AbstractTranslator { List entries = translateEntries(); resultingFor.setBody(AstUtil.newBlock(entries)); context().addStatementToCurrentBlock(resultingFor); - return result.nameReference(); + return result.reference(); } @NotNull @@ -80,7 +80,7 @@ public class WhenTranslator extends AbstractTranslator { @NotNull private JsStatement surroundWithDummyIf(@NotNull JsStatement entryStatement) { JsExpression stepNumberEqualsCurrentEntryNumber = new JsBinaryOperation(JsBinaryOperator.EQ, - dummyCounter.nameReference(), context().program().getNumberLiteral(currentEntryNumber)); + dummyCounter.reference(), context().program().getNumberLiteral(currentEntryNumber)); currentEntryNumber++; return new JsIf(stepNumberEqualsCurrentEntryNumber, entryStatement, null); } @@ -97,12 +97,12 @@ public class WhenTranslator extends AbstractTranslator { @NotNull private JsBinaryOperation generateConditionStatement() { JsNumberLiteral entriesNumber = program().getNumberLiteral(whenExpression.getEntries().size()); - return new JsBinaryOperation(JsBinaryOperator.LT, dummyCounter.nameReference(), entriesNumber); + return new JsBinaryOperation(JsBinaryOperator.LT, dummyCounter.reference(), entriesNumber); } @NotNull private JsPrefixOperation generateIncrementStatement() { - return new JsPrefixOperation(JsUnaryOperator.INC, dummyCounter.nameReference()); + return new JsPrefixOperation(JsUnaryOperator.INC, dummyCounter.reference()); } @NotNull @@ -119,7 +119,7 @@ public class WhenTranslator extends AbstractTranslator { JsStatement withReturnValueCaptured(@NotNull JsNode node) { return AstUtil.convertToStatement(AstUtil.mutateLastExpression(node, - new AstUtil.SaveLastExpressionMutator(result.nameReference()))); + new AstUtil.SaveLastExpressionMutator(result.reference()))); } @NotNull diff --git a/translator/src/org/jetbrains/k2js/translate/expression/foreach/ArrayForTranslator.java b/translator/src/org/jetbrains/k2js/translate/expression/foreach/ArrayForTranslator.java new file mode 100644 index 00000000000..f60547f29cc --- /dev/null +++ b/translator/src/org/jetbrains/k2js/translate/expression/foreach/ArrayForTranslator.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.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.string.LengthIntrinsic; +import org.jetbrains.k2js.translate.utils.BindingUtils; + +import java.util.Collections; +import java.util.List; + +import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getClassDescriptorForType; +import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopBody; +import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopRange; + +/** + * @author Pavel Talanov + */ +public final class ArrayForTranslator extends ForTranslator { + + @NotNull + public static JsStatement translate(@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().equals("Array") + || getClassDescriptorForType(rangeType).getName().equals("IntArray"); + } + + @NotNull + private final TemporaryVariable rangeExpression; + + private ArrayForTranslator(@NotNull JetForExpression forExpression, @NotNull TranslationContext context) { + super(forExpression, context); + rangeExpression = context.declareTemporary(Translation.translateAsExpression(getLoopRange(expression), context)); + } + + @NotNull + private JsBlock translate() { + JsExpression length = LengthIntrinsic.INSTANCE.apply(rangeExpression.reference(), Collections.emptyList(), context()); + TemporaryVariable end = context().declareTemporary(length); + List blockStatements = temporariesInitialization(rangeExpression, end); + blockStatements.add(generateForExpression(end)); + return AstUtil.newBlock(blockStatements); + } + + @NotNull + private JsFor generateForExpression(@NotNull TemporaryVariable end) { + JsFor result = new JsFor(); + //TODO: make index instance variable + TemporaryVariable indexVar = context().declareTemporary(program().getNumberLiteral(0)); + result.setInitVars(initExpression(indexVar)); + result.setCondition(getCondition(end, indexVar)); + result.setIncrExpr(getIncrExpression(indexVar)); + result.setBody(getBody(indexVar)); + return result; + } + + @NotNull + private JsStatement getBody(@NotNull TemporaryVariable index) { + JsArrayAccess arrayAccess = new JsArrayAccess(rangeExpression.reference(), index.reference()); + JsStatement currentVar = AstUtil.newVar(declareParameter(), arrayAccess); + JsStatement realBody = Translation.translateAsStatement(getLoopBody(expression), context()); + return AstUtil.newBlock(currentVar, realBody); + } + + @NotNull + private JsVars initExpression(TemporaryVariable start) { + return AstUtil.newVar(start.name(), program().getNumberLiteral(0)); + } + + @NotNull + private JsExpression getCondition(TemporaryVariable end, TemporaryVariable index) { + return AstUtil.notEqual(index.reference(), end.reference()); + } + + @NotNull + private JsExpression getIncrExpression(@NotNull TemporaryVariable index) { + return new JsPrefixOperation(JsUnaryOperator.INC, index.reference()); + } + + //TODO: move somewhere util + @NotNull + private List temporariesInitialization(TemporaryVariable... temporaries) { + List result = Lists.newArrayList(); + for (TemporaryVariable temporary : temporaries) { + result.add(temporary.assignmentExpression().makeStmt()); + } + return result; + } +} diff --git a/translator/src/org/jetbrains/k2js/translate/expression/foreach/ForTranslator.java b/translator/src/org/jetbrains/k2js/translate/expression/foreach/ForTranslator.java new file mode 100644 index 00000000000..1d8d782730b --- /dev/null +++ b/translator/src/org/jetbrains/k2js/translate/expression/foreach/ForTranslator.java @@ -0,0 +1,59 @@ +/* + * 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.dart.compiler.backend.js.ast.JsName; +import com.google.dart.compiler.backend.js.ast.JsStatement; +import org.jetbrains.annotations.NotNull; +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 static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopParameter; + +/** + * @author Pavel Talanov + */ +public abstract class ForTranslator extends AbstractTranslator { + + @NotNull + public static JsStatement translate(@NotNull JetForExpression expression, + @NotNull TranslationContext context) { + if (ArrayForTranslator.isApplicable(expression, context)) { + return ArrayForTranslator.translate(expression, context); + } + if (RangeForTranslator.isApplicable(expression, context)) { + return RangeForTranslator.translate(expression, context); + } + return IteratorForTranslator.translate(expression, context); + } + + @NotNull + protected final JetForExpression expression; + + protected ForTranslator(@NotNull JetForExpression forExpression, @NotNull TranslationContext context) { + super(context); + this.expression = forExpression; + } + + @NotNull + protected JsName declareParameter() { + JetParameter loopParameter = getLoopParameter(expression); + return context().getNameForElement(loopParameter); + } +} diff --git a/translator/src/org/jetbrains/k2js/translate/expression/ForTranslator.java b/translator/src/org/jetbrains/k2js/translate/expression/foreach/IteratorForTranslator.java similarity index 75% rename from translator/src/org/jetbrains/k2js/translate/expression/ForTranslator.java rename to translator/src/org/jetbrains/k2js/translate/expression/foreach/IteratorForTranslator.java index c0eb4e6c17e..72b44a6cb31 100644 --- a/translator/src/org/jetbrains/k2js/translate/expression/ForTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/expression/foreach/IteratorForTranslator.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jetbrains.k2js.translate.expression; +package org.jetbrains.k2js.translate.expression.foreach; import com.google.dart.compiler.backend.js.ast.*; import com.google.dart.compiler.util.AstUtil; @@ -24,34 +24,28 @@ import org.jetbrains.jet.lang.descriptors.CallableDescriptor; 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.psi.JetParameter; import org.jetbrains.k2js.translate.context.TemporaryVariable; import org.jetbrains.k2js.translate.context.TranslationContext; -import org.jetbrains.k2js.translate.general.AbstractTranslator; import org.jetbrains.k2js.translate.general.Translation; import org.jetbrains.k2js.translate.reference.CallBuilder; import static org.jetbrains.k2js.translate.utils.BindingUtils.*; import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopBody; -import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopParameter; +import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopRange; /** * @author Pavel Talanov */ -public final class ForTranslator extends AbstractTranslator { +public final class IteratorForTranslator extends ForTranslator { @NotNull public static JsStatement translate(@NotNull JetForExpression expression, @NotNull TranslationContext context) { - return (new ForTranslator(expression, context).translate()); + return (new IteratorForTranslator(expression, context).translate()); } - @NotNull - private final JetForExpression expression; - - private ForTranslator(@NotNull JetForExpression forExpression, @NotNull TranslationContext context) { - super(context); - this.expression = forExpression; + private IteratorForTranslator(@NotNull JetForExpression forExpression, @NotNull TranslationContext context) { + super(forExpression, context); } @NotNull @@ -63,12 +57,6 @@ public final class ForTranslator extends AbstractTranslator { return AstUtil.newBlock(iterator.assignmentExpression().makeStmt(), cycle); } - @NotNull - private JsName declareParameter() { - JetParameter loopParameter = getLoopParameter(expression); - return context().getNameForElement(loopParameter); - } - @NotNull private JsBlock generateCycleBody(@NotNull JsName parameterName, @NotNull TemporaryVariable iterator) { JsBlock cycleBody = new JsBlock(); @@ -82,31 +70,24 @@ public final class ForTranslator extends AbstractTranslator { @NotNull private JsExpression nextMethodInvocation(@NotNull TemporaryVariable iterator) { - FunctionDescriptor nextFunction = getNextFunction(context().bindingContext(), getLoopRange()); - return translateMethodInvocation(iterator.nameReference(), nextFunction); + FunctionDescriptor nextFunction = getNextFunction(context().bindingContext(), getLoopRange(expression)); + return translateMethodInvocation(iterator.reference(), nextFunction); } @NotNull private JsExpression hasNextMethodInvocation(@NotNull TemporaryVariable iterator) { - CallableDescriptor hasNextFunction = getHasNextCallable(context().bindingContext(), getLoopRange()); - return translateMethodInvocation(iterator.nameReference(), hasNextFunction); + CallableDescriptor hasNextFunction = getHasNextCallable(context().bindingContext(), getLoopRange(expression)); + return translateMethodInvocation(iterator.reference(), hasNextFunction); } @NotNull private JsExpression iteratorMethodInvocation() { - JetExpression rangeExpression = getLoopRange(); + JetExpression rangeExpression = getLoopRange(expression); JsExpression range = Translation.translateAsExpression(rangeExpression, context()); FunctionDescriptor iteratorFunction = getIteratorFunction(context().bindingContext(), rangeExpression); return translateMethodInvocation(range, iteratorFunction); } - @NotNull - private JetExpression getLoopRange() { - JetExpression rangeExpression = expression.getLoopRange(); - assert rangeExpression != null; - return rangeExpression; - } - @NotNull private JsExpression translateMethodInvocation(@Nullable JsExpression receiver, @NotNull CallableDescriptor descriptor) { diff --git a/translator/src/org/jetbrains/k2js/translate/expression/foreach/RangeForTranslator.java b/translator/src/org/jetbrains/k2js/translate/expression/foreach/RangeForTranslator.java new file mode 100644 index 00000000000..c4568589d66 --- /dev/null +++ b/translator/src/org/jetbrains/k2js/translate/expression/foreach/RangeForTranslator.java @@ -0,0 +1,127 @@ +/* + * 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.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 java.util.List; + +import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getClassDescriptorForType; +import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopBody; +import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopRange; + +/** + * @author Pavel Talanov + */ +public final class RangeForTranslator extends ForTranslator { + + @NotNull + public static JsStatement translate(@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 + return getClassDescriptorForType(rangeType).getName().equals("IntRange"); + } + + @NotNull + private final TemporaryVariable rangeExpression; + + private RangeForTranslator(@NotNull JetForExpression forExpression, @NotNull TranslationContext context) { + super(forExpression, context); + rangeExpression = context.declareTemporary(Translation.translateAsExpression(getLoopRange(expression), context)); + } + + @NotNull + private JsBlock translate() { + //TODO: make fields + JsExpression isReversed = callFunction("get_reversed"); + JsConditional incrVarValue = new JsConditional(isReversed, + program().getNumberLiteral(-1), + program().getNumberLiteral(1)); + TemporaryVariable incrVar = context().declareTemporary(incrVarValue); + TemporaryVariable start = context().declareTemporary(callFunction("get_start")); + TemporaryVariable end = context().declareTemporary(new JsBinaryOperation(JsBinaryOperator.ADD, callFunction("get_end"), incrVar.reference())); + List blockStatements = temporariesInitialization(rangeExpression, incrVar, start, end); + blockStatements.add(generateForExpression(incrVar, start, end)); + return AstUtil.newBlock(blockStatements); + } + + @NotNull + private JsFor generateForExpression(@NotNull TemporaryVariable incrVar, + @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)); + result.setBody(Translation.translateAsStatement(getLoopBody(expression), context())); + return result; + } + + @NotNull + private JsVars initExpression(TemporaryVariable start, JsName parameterName) { + return AstUtil.newVar(parameterName, start.reference()); + } + + @NotNull + private JsExpression getCondition(TemporaryVariable end, JsName parameterName) { + return AstUtil.notEqual(parameterName.makeRef(), end.reference()); + } + + @NotNull + private JsExpression getIncrExpression(@NotNull TemporaryVariable incrVar, @NotNull JsName parameterName) { + return new JsBinaryOperation(JsBinaryOperator.ASG_ADD, parameterName.makeRef(), incrVar.reference()); + } + + @NotNull + private JsExpression getField(@NotNull String fieldName) { + JsNameRef nameRef = AstUtil.newQualifiedNameRef(fieldName); + AstUtil.setQualifier(nameRef, rangeExpression.reference()); + return nameRef; + } + + @NotNull + private JsExpression callFunction(@NotNull String funName) { + return AstUtil.newInvocation(getField(funName)); + } + + @NotNull + private List temporariesInitialization(TemporaryVariable... temporaries) { + List result = Lists.newArrayList(); + for (TemporaryVariable temporary : temporaries) { + result.add(temporary.assignmentExpression().makeStmt()); + } + return result; + } +} diff --git a/translator/src/org/jetbrains/k2js/translate/operation/IncrementTranslator.java b/translator/src/org/jetbrains/k2js/translate/operation/IncrementTranslator.java index 1e81b5f78a8..a04a59768c5 100644 --- a/translator/src/org/jetbrains/k2js/translate/operation/IncrementTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/operation/IncrementTranslator.java @@ -97,10 +97,10 @@ public abstract class IncrementTranslator extends AbstractTranslator { // code fragment: expr(a++) // generate: expr( (t1 = a, t2 = t1, a = t1.inc(), t2) ) TemporaryVariable t1 = context().declareTemporary(accessTranslator.translateAsGet()); - TemporaryVariable t2 = context().declareTemporary(t1.nameReference()); - JsExpression variableReassignment = variableReassignment(t1.nameReference()); + TemporaryVariable t2 = context().declareTemporary(t1.reference()); + JsExpression variableReassignment = variableReassignment(t1.reference()); return AstUtil.newSequence(t1.assignmentExpression(), t2.assignmentExpression(), - variableReassignment, t2.nameReference()); + variableReassignment, t2.reference()); } //TODO: TEST @@ -109,9 +109,9 @@ public abstract class IncrementTranslator extends AbstractTranslator { // code fragment: expr(a++) // generate: expr( (t1 = a, t2 = t1, t2.inc(), t1) ) TemporaryVariable t1 = context().declareTemporary(accessTranslator.translateAsGet()); - TemporaryVariable t2 = context().declareTemporary(t1.nameReference()); - JsExpression methodCall = operationExpression(t2.nameReference()); - JsExpression returnedValue = t1.nameReference(); + TemporaryVariable t2 = context().declareTemporary(t1.reference()); + JsExpression methodCall = operationExpression(t2.reference()); + JsExpression returnedValue = t1.reference(); return AstUtil.newSequence(t1.assignmentExpression(), t2.assignmentExpression(), methodCall, returnedValue); } diff --git a/translator/src/org/jetbrains/k2js/translate/reference/CallType.java b/translator/src/org/jetbrains/k2js/translate/reference/CallType.java index cc8f14b0960..73f4c4842b4 100644 --- a/translator/src/org/jetbrains/k2js/translate/reference/CallType.java +++ b/translator/src/org/jetbrains/k2js/translate/reference/CallType.java @@ -44,9 +44,9 @@ public enum CallType { TemporaryVariable temporaryVariable = context.declareTemporary(receiver); JsNullLiteral nullLiteral = context.program().getNullLiteral(); //TODO: find similar not null checks - JsBinaryOperation notNullCheck = AstUtil.notEqual(temporaryVariable.nameReference(), nullLiteral); + JsBinaryOperation notNullCheck = AstUtil.notEqual(temporaryVariable.reference(), nullLiteral); JsConditional callMethodIfNotNullElseNull = - new JsConditional(notNullCheck, constructor.construct(temporaryVariable.nameReference()), nullLiteral); + new JsConditional(notNullCheck, constructor.construct(temporaryVariable.reference()), nullLiteral); return newSequence(temporaryVariable.assignmentExpression(), callMethodIfNotNullElseNull); } }, diff --git a/translator/src/org/jetbrains/k2js/translate/utils/BindingUtils.java b/translator/src/org/jetbrains/k2js/translate/utils/BindingUtils.java index eb319974ee6..636d0e6b9ff 100644 --- a/translator/src/org/jetbrains/k2js/translate/utils/BindingUtils.java +++ b/translator/src/org/jetbrains/k2js/translate/utils/BindingUtils.java @@ -330,4 +330,12 @@ public final class BindingUtils { } return descriptorSet; } + + @NotNull + public static JetType getTypeForExpression(@NotNull BindingContext context, + @NotNull JetExpression expression) { + JetType type = context.get(BindingContext.EXPRESSION_TYPE, expression); + assert type != null; + return type; + } } diff --git a/translator/src/org/jetbrains/k2js/translate/utils/PsiUtils.java b/translator/src/org/jetbrains/k2js/translate/utils/PsiUtils.java index 41940ad61cf..1625d013acb 100644 --- a/translator/src/org/jetbrains/k2js/translate/utils/PsiUtils.java +++ b/translator/src/org/jetbrains/k2js/translate/utils/PsiUtils.java @@ -153,4 +153,11 @@ public final class PsiUtils { } return name; } + + @NotNull + public static JetExpression getLoopRange(@NotNull JetForExpression expression) { + JetExpression rangeExpression = expression.getLoopRange(); + assert rangeExpression != null; + return rangeExpression; + } }