From 46b7ab194a52393141f2d73c15244efeafd72385 Mon Sep 17 00:00:00 2001 From: Pavel Talanov Date: Tue, 24 Jan 2012 19:54:38 +0400 Subject: [PATCH] tuple support and tests --- .../translate/context/StandardClasses.java | 13 +++++ .../expression/ExpressionVisitor.java | 11 +++++ .../k2js/translate/intrinsic/Intrinsics.java | 47 +++++++++++-------- .../intrinsic/tuple/TupleAccessIntrinsic.java | 29 ++++++++++++ .../k2js/translate/utils/DescriptorUtils.java | 2 +- .../org/jetbrains/k2js/test/TupleTest.java | 19 +++++--- .../testFiles/tuple/cases/multipleMembers.kt | 15 ++++++ .../testFiles/tuple/cases/twoElements.kt | 4 +- 8 files changed, 112 insertions(+), 28 deletions(-) create mode 100644 translator/src/org/jetbrains/k2js/translate/intrinsic/tuple/TupleAccessIntrinsic.java create mode 100644 translator/testFiles/tuple/cases/multipleMembers.kt diff --git a/translator/src/org/jetbrains/k2js/translate/context/StandardClasses.java b/translator/src/org/jetbrains/k2js/translate/context/StandardClasses.java index b8093a44726..54214fb5f3c 100644 --- a/translator/src/org/jetbrains/k2js/translate/context/StandardClasses.java +++ b/translator/src/org/jetbrains/k2js/translate/context/StandardClasses.java @@ -38,9 +38,22 @@ public final class StandardClasses { declareJavaCollection(standardClasses); declareMap(standardClasses); declareInteger(standardClasses); + // declareTuples(standardClasses); return standardClasses; } +// private static void declareTuples(@NotNull StandardClasses standardClasses) { +// for (int tupleId = 0; tupleId <= JetStandardClasses.TUPLE_COUNT) { +// declareTuple(standardClasses, tupleId); +// } +// } +// +// private static void declareTuple(@NotNull StandardClasses standardClasses, +// int tupleId) { +// String tupleFQName = "jet.Tuple" + tupleId; +// +// } + private static void declareMap(@NotNull StandardClasses standardClasses) { String hashMapFQName = "java.util.Map"; standardClasses.declareStandardTopLevelObject(hashMapFQName, "Map"); diff --git a/translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java b/translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java index cb62ce510a5..64b50d48345 100644 --- a/translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java +++ b/translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java @@ -343,4 +343,15 @@ public final class ExpressionVisitor extends TranslatorVisitor { @NotNull TranslationContext context) { return TryTranslator.translate(expression, context); } + + @Override + @NotNull + public JsNode visitTupleExpression(@NotNull JetTupleExpression expression, + @NotNull TranslationContext context) { + JsArrayLiteral result = new JsArrayLiteral(); + for (JetExpression entry : expression.getEntries()) { + result.getExpressions().add(Translation.translateAsExpression(entry, context)); + } + return result; + } } \ No newline at end of file diff --git a/translator/src/org/jetbrains/k2js/translate/intrinsic/Intrinsics.java b/translator/src/org/jetbrains/k2js/translate/intrinsic/Intrinsics.java index cf5fca0da83..753d1458c1b 100644 --- a/translator/src/org/jetbrains/k2js/translate/intrinsic/Intrinsics.java +++ b/translator/src/org/jetbrains/k2js/translate/intrinsic/Intrinsics.java @@ -3,13 +3,13 @@ package org.jetbrains.k2js.translate.intrinsic; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.types.JetStandardClasses; import org.jetbrains.jet.lang.types.JetStandardLibrary; import org.jetbrains.jet.lexer.JetToken; -import org.jetbrains.k2js.translate.intrinsic.array.ArrayGetIntrinsic; -import org.jetbrains.k2js.translate.intrinsic.array.ArrayNullConstructorIntrinsic; -import org.jetbrains.k2js.translate.intrinsic.array.ArraySetIntrinsic; import org.jetbrains.k2js.translate.intrinsic.primitive.*; import org.jetbrains.k2js.translate.intrinsic.string.LengthIntrinsic; +import org.jetbrains.k2js.translate.intrinsic.tuple.TupleAccessIntrinsic; import org.jetbrains.k2js.translate.operation.OperatorTable; import org.jetbrains.k2js.translate.utils.DescriptorUtils; @@ -17,7 +17,6 @@ import java.util.HashMap; import java.util.Map; import static org.jetbrains.jet.lang.types.expressions.OperatorConventions.*; -import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getFunctionByName; import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getPropertyByName; /** @@ -48,8 +47,21 @@ public final class Intrinsics { this.library = library; declareOperatorIntrinsics(); declareStringIntrinsics(); - //TODO: array intrinsic are under consideration - //declareArrayIntrinsics(); + declareTuplesIntrinsics(); + } + + private void declareTuplesIntrinsics() { + for (int tupleSize = 0; tupleSize < JetStandardClasses.TUPLE_COUNT; ++tupleSize) { + declareTupleIntrinsics(tupleSize); + } + } + + private void declareTupleIntrinsics(int tupleSize) { + JetScope libraryScope = library.getLibraryScope(); + assert libraryScope != null; + ClassifierDescriptor tupleDescriptor = libraryScope.getClassifier("Tuple" + tupleSize); + assert tupleDescriptor != null; + declareTupleIntrinsicAccessors(tupleDescriptor, tupleSize); } private void declareStringIntrinsics() { @@ -58,6 +70,16 @@ public final class Intrinsics { functionIntrinsics.put(lengthProperty.getGetter(), LengthIntrinsic.INSTANCE); } + private void declareTupleIntrinsicAccessors(@NotNull ClassifierDescriptor tupleDescriptor, + int tupleSize) { + for (int elementIndex = 0; elementIndex < tupleSize; ++elementIndex) { + String accessorName = "_" + (elementIndex + 1); + PropertyDescriptor propertyDescriptor = + getPropertyByName(tupleDescriptor.getDefaultType().getMemberScope(), accessorName); + functionIntrinsics.put(propertyDescriptor.getGetter(), new TupleAccessIntrinsic(elementIndex)); + } + } + private void declareOperatorIntrinsics() { IntrinsicDeclarationVisitor visitor = new IntrinsicDeclarationVisitor(); for (DeclarationDescriptor descriptor : library.getLibraryScope().getAllDescriptors()) { @@ -66,19 +88,6 @@ public final class Intrinsics { } } - //TODO: delete or include - private void declareArrayIntrinsics() { - FunctionDescriptor constructorFunction = getFunctionByName(library.getLibraryScope(), "Array"); - functionIntrinsics.put(constructorFunction, ArrayNullConstructorIntrinsic.INSTANCE); - - FunctionDescriptor getFunction = getFunctionByName(library.getArray(), "get"); - functionIntrinsics.put(getFunction, ArrayGetIntrinsic.INSTANCE); - - FunctionDescriptor setFunction = getFunctionByName(library.getArray(), "set"); - functionIntrinsics.put(setFunction, ArraySetIntrinsic.INSTANCE); - - } - public boolean isIntrinsic(@NotNull DeclarationDescriptor descriptor) { //NOTE: that if we want to add other intrinsics we have to modify this method if (descriptor instanceof FunctionDescriptor) { diff --git a/translator/src/org/jetbrains/k2js/translate/intrinsic/tuple/TupleAccessIntrinsic.java b/translator/src/org/jetbrains/k2js/translate/intrinsic/tuple/TupleAccessIntrinsic.java new file mode 100644 index 00000000000..afb08b5dee3 --- /dev/null +++ b/translator/src/org/jetbrains/k2js/translate/intrinsic/tuple/TupleAccessIntrinsic.java @@ -0,0 +1,29 @@ +package org.jetbrains.k2js.translate.intrinsic.tuple; + +import com.google.dart.compiler.backend.js.ast.JsExpression; +import com.google.dart.compiler.util.AstUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.k2js.translate.context.TranslationContext; +import org.jetbrains.k2js.translate.intrinsic.FunctionIntrinsic; + +import java.util.List; + +/** + * @author Pavel Talanov + */ +public final class TupleAccessIntrinsic implements FunctionIntrinsic { + + private final int elementIndex; + + public TupleAccessIntrinsic(int elementIndex) { + this.elementIndex = elementIndex; + } + + @NotNull + @Override + public JsExpression apply(@NotNull JsExpression receiver, @NotNull List arguments, + @NotNull TranslationContext context) { + assert arguments.isEmpty() : "Tuple access expression should not have any arguments."; + return AstUtil.newArrayAccess(receiver, context.program().getNumberLiteral(elementIndex)); + } +} diff --git a/translator/src/org/jetbrains/k2js/translate/utils/DescriptorUtils.java b/translator/src/org/jetbrains/k2js/translate/utils/DescriptorUtils.java index b5eea0f0951..af2ea09b5d6 100644 --- a/translator/src/org/jetbrains/k2js/translate/utils/DescriptorUtils.java +++ b/translator/src/org/jetbrains/k2js/translate/utils/DescriptorUtils.java @@ -91,7 +91,7 @@ public final class DescriptorUtils { variable = scope.getPropertyByFieldReference("$" + name); } Set variables = scope.getProperties(name); - assert variables.size() == 1; + assert variables.size() == 1 : "Actual size: " + variables.size(); variable = variables.iterator().next(); PropertyDescriptor descriptor = (PropertyDescriptor) variable; assert descriptor != null : "Must have a descriptor."; diff --git a/translator/test/org/jetbrains/k2js/test/TupleTest.java b/translator/test/org/jetbrains/k2js/test/TupleTest.java index 670c41e1899..7442e097e62 100644 --- a/translator/test/org/jetbrains/k2js/test/TupleTest.java +++ b/translator/test/org/jetbrains/k2js/test/TupleTest.java @@ -1,9 +1,11 @@ package org.jetbrains.k2js.test; +import org.junit.Test; + /** * @author Pavel Talanov */ -public class TupleTest extends TranslationTest { +public final class TupleTest extends TranslationTest { final private static String MAIN = "tuple/"; @@ -12,11 +14,16 @@ public class TupleTest extends TranslationTest { return MAIN; } - //TODO: excluded because Tuples are not implemented -// @Test -// public void twoElements() throws Exception { -// testFooBoxIsTrue("twoElements.kt"); -// } + @Test + public void twoElements() throws Exception { + testFooBoxIsTrue("twoElements.kt"); + } + + @Test + public void multipleMembers() throws Exception { + testFooBoxIsTrue("multipleMembers.kt"); + } + } diff --git a/translator/testFiles/tuple/cases/multipleMembers.kt b/translator/testFiles/tuple/cases/multipleMembers.kt new file mode 100644 index 00000000000..3bf9c6eb000 --- /dev/null +++ b/translator/testFiles/tuple/cases/multipleMembers.kt @@ -0,0 +1,15 @@ +package foo + +fun box() : Boolean { + if (#(1, 2, 3)._1 != 1) return false; + if (#("a", "b")._2 != "b") return false; + val x = #("1", 2, "3", 4, "5", 6); + if (x._1 != "1") return false; + if (x._2 != 2) return false; + if (x._2 != 2) return false; + if (x._6 != 6) return false; + if (x._5 != "5") return false; + if (x._3 != "3") return false; + if (#(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)._21 != 1) return false; + return true; +} \ No newline at end of file diff --git a/translator/testFiles/tuple/cases/twoElements.kt b/translator/testFiles/tuple/cases/twoElements.kt index c8643d93e23..d0ab07e1916 100644 --- a/translator/testFiles/tuple/cases/twoElements.kt +++ b/translator/testFiles/tuple/cases/twoElements.kt @@ -1,6 +1,6 @@ package foo fun box() : Boolean { - val a : (Int, Int) = (1, 2) - return (a._1 == 1) + val a : #(Int, Int) = #(1, 2) + return ((a._1 == 1) && (a._2 == 2)) } \ No newline at end of file