JS backend: add support multi declaration
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.test.semantics;
|
||||
|
||||
import org.jetbrains.k2js.test.SingleFileTranslationTest;
|
||||
|
||||
public class MultiDeclarationTest extends SingleFileTranslationTest {
|
||||
public MultiDeclarationTest() {
|
||||
super("multideclaration/");
|
||||
}
|
||||
|
||||
// TODO: Add support Map.Entry
|
||||
public void TestMultiValForMap() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testMultiValOrVar() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testMultiValInFor() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testMultiValInIntFor() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testMultiValInIntRangeFor() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testMultiValForArray() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
// TODO: Add support ranges for user types
|
||||
public void TestMultiValForRange() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -115,6 +115,14 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
|
||||
return source(jsBlock, jetBlock);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsNode visitMultiDeclaration(@NotNull JetMultiDeclaration multiDeclaration, @NotNull TranslationContext context) {
|
||||
JetExpression jetInitializer = multiDeclaration.getInitializer();
|
||||
assert jetInitializer != null : "Initializer for multi declaration must be not null";
|
||||
JsExpression initializer = Translation.translateAsExpression(jetInitializer, context);
|
||||
return MultiDeclarationTranslator.translate(multiDeclaration, context.scope().declareTemporary(), initializer, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitReturnExpression(@NotNull JetReturnExpression jetReturnExpression,
|
||||
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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.JsNameRef;
|
||||
import com.google.dart.compiler.backend.js.ast.JsVars;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetMultiDeclaration;
|
||||
import org.jetbrains.jet.lang.psi.JetMultiDeclarationEntry;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.k2js.translate.reference.CallBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MultiDeclarationTranslator extends AbstractTranslator {
|
||||
|
||||
// if multiObjectName was init, initializer must be null
|
||||
@NotNull
|
||||
public static JsVars translate(
|
||||
@NotNull JetMultiDeclaration multiDeclaration,
|
||||
@NotNull JsName multiObjectName,
|
||||
@Nullable JsExpression initializer,
|
||||
@NotNull TranslationContext context
|
||||
) {
|
||||
return new MultiDeclarationTranslator(multiDeclaration, multiObjectName, initializer, context).translate();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final JetMultiDeclaration multiDeclaration;
|
||||
@NotNull
|
||||
private final JsName multiObjectName;
|
||||
@Nullable
|
||||
private final JsExpression initializer;
|
||||
|
||||
private MultiDeclarationTranslator(
|
||||
@NotNull JetMultiDeclaration multiDeclaration,
|
||||
@NotNull JsName multiObjectName,
|
||||
@Nullable JsExpression initializer,
|
||||
@NotNull TranslationContext context
|
||||
) {
|
||||
super(context);
|
||||
this.multiDeclaration = multiDeclaration;
|
||||
this.multiObjectName = multiObjectName;
|
||||
this.initializer = initializer;
|
||||
}
|
||||
|
||||
private JsVars translate() {
|
||||
List<JsVars.JsVar> jsVars = new ArrayList<JsVars.JsVar>();
|
||||
if (initializer != null) {
|
||||
jsVars.add(new JsVars.JsVar(multiObjectName, initializer));
|
||||
}
|
||||
|
||||
JsNameRef multiObjNameRef = multiObjectName.makeRef();
|
||||
for (JetMultiDeclarationEntry entry : multiDeclaration.getEntries()) {
|
||||
ResolvedCall<FunctionDescriptor> entryInitCall = context().bindingContext().get(BindingContext.COMPONENT_RESOLVED_CALL, entry);
|
||||
assert entryInitCall != null : "Entry init call must be not null";
|
||||
JsExpression entryInitializer = CallBuilder.build(context())
|
||||
.receiver(multiObjNameRef)
|
||||
.resolvedCall(entryInitCall)
|
||||
.translate();
|
||||
|
||||
VariableDescriptor descriptor = BindingContextUtils.getNotNull( context().bindingContext(), BindingContext.VARIABLE, entry);
|
||||
JsName name = context().getNameForDescriptor(descriptor);
|
||||
jsVars.add(new JsVars.JsVar(name, entryInitializer));
|
||||
}
|
||||
return new JsVars(jsVars, true);
|
||||
}
|
||||
}
|
||||
+1
-3
@@ -86,9 +86,7 @@ public final class ArrayForTranslator extends ForTranslator {
|
||||
@NotNull
|
||||
private JsStatement getBody() {
|
||||
JsArrayAccess arrayAccess = new JsArrayAccess(loopRange.reference(), index.reference());
|
||||
JsStatement currentVar = newVar(parameterName, arrayAccess);
|
||||
JsStatement realBody = translateOriginalBodyExpression();
|
||||
return new JsBlock(currentVar, realBody);
|
||||
return translateBody(arrayAccess);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+42
-18
@@ -21,8 +21,12 @@ 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;
|
||||
|
||||
@@ -51,34 +55,54 @@ public abstract class ForTranslator extends AbstractTranslator {
|
||||
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() {
|
||||
return context().getNameForElement(getLoopParameter(expression));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected JsStatement translateOriginalBodyExpression() {
|
||||
return Translation.translateAsStatement(getLoopBody(expression), context());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected JsStatement translateBody(JsExpression itemValue) {
|
||||
JsStatement currentVar = newVar(parameterName, itemValue);
|
||||
JsStatement realBody = translateOriginalBodyExpression();
|
||||
if (realBody instanceof JsBlock) {
|
||||
JsBlock block = (JsBlock) realBody;
|
||||
block.getStatements().add(0, currentVar);
|
||||
return block;
|
||||
JetParameter loopParameter = getLoopParameter(expression);
|
||||
if (loopParameter != null) {
|
||||
return context().getNameForElement(loopParameter);
|
||||
}
|
||||
else {
|
||||
return new JsBlock(currentVar, realBody);
|
||||
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);
|
||||
if (realBody instanceof JsBlock) {
|
||||
JsBlock block = (JsBlock) realBody;
|
||||
block.getStatements().add(0, currentVarInit);
|
||||
return block;
|
||||
}
|
||||
else {
|
||||
return new JsBlock(currentVarInit, realBody);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -79,7 +79,7 @@ public final class RangeForTranslator extends ForTranslator {
|
||||
@NotNull
|
||||
private JsFor generateForExpression() {
|
||||
JsFor result = new JsFor(initExpression(), getCondition(), getIncrExpression());
|
||||
result.setBody(translateOriginalBodyExpression());
|
||||
result.setBody(translateBody(null));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -82,7 +82,7 @@ public final class RangeLiteralForTranslator extends ForTranslator {
|
||||
blockStatements.add(generateForExpression(initExpression(),
|
||||
getCondition(),
|
||||
getIncrExpression(),
|
||||
translateOriginalBodyExpression()));
|
||||
translateBody(null)));
|
||||
return new JsBlock(blockStatements);
|
||||
}
|
||||
|
||||
|
||||
@@ -108,11 +108,9 @@ public final class PsiUtils {
|
||||
return body;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Nullable
|
||||
public static JetParameter getLoopParameter(@NotNull JetForExpression expression) {
|
||||
JetParameter loopParameter = expression.getLoopParameter();
|
||||
assert loopParameter != null;
|
||||
return loopParameter;
|
||||
return expression.getLoopParameter();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package foo
|
||||
class A {
|
||||
fun component1() : Int = 1
|
||||
}
|
||||
fun A.component2() : String = "n"
|
||||
|
||||
fun box(): String {
|
||||
val list = Array<A>(1, {A()})
|
||||
|
||||
var i = 0;
|
||||
var s = ""
|
||||
for ((a,b) in list) {
|
||||
i = a;
|
||||
s = b;
|
||||
}
|
||||
|
||||
if (i != 1) return "i != 1, it: " + i
|
||||
if (s != "n") return "s != 'n', it: " + s
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package foo
|
||||
|
||||
import java.util.HashMap
|
||||
|
||||
|
||||
public inline fun <K,V> Map<K,V>.iterator(): Iterator<Map.Entry<K,V>> {
|
||||
val entrySet = this.entrySet()
|
||||
return entrySet.iterator()
|
||||
}
|
||||
|
||||
/** Returns the key of the entry */
|
||||
fun <K,V> Map.Entry<K,V>.component1() : K {
|
||||
return getKey()
|
||||
}
|
||||
|
||||
/** Returns the value of the entry */
|
||||
fun <K,V> Map.Entry<K,V>.component2() : V {
|
||||
return getValue()
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val map = HashMap<Int, String>()
|
||||
map.put(1, "s1")
|
||||
map.put(2, "s2")
|
||||
|
||||
var s1 = ""
|
||||
var s2 = ""
|
||||
for ((k,v) in map) {
|
||||
when (k) {
|
||||
2 -> s2 = v
|
||||
1 -> s1 = v
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
if (s1 != "s1") return "s1 != 's1', it: ${s1}"
|
||||
if (s2 != "s2") return "s2 != 's2', it: ${s2}"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package foo
|
||||
class C(val i: Int): Comparable<C>, A() {
|
||||
public override fun compareTo(other: C): Int {
|
||||
return if (other is C) other.i - i else 0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun ComparableRange<C>.iterator() : Iterator<C> {
|
||||
var curI: Int = start.i - 1
|
||||
|
||||
return object :Iterator<C> {
|
||||
public override fun next(): C {
|
||||
curI++
|
||||
return C(curI)
|
||||
}
|
||||
public override fun hasNext(): Boolean {
|
||||
return curI < end.i
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
open class A {
|
||||
fun component1() : Int = 1
|
||||
}
|
||||
fun A.component2() : String = "n"
|
||||
|
||||
fun box(): String {
|
||||
var i = 0;
|
||||
var s = ""
|
||||
for ((a,b) in C(0)..C(2)) {
|
||||
i = a;
|
||||
s = b;
|
||||
}
|
||||
|
||||
if (i != 1) return "i != 1, it: " + i
|
||||
if (s != "n") return "s != 'n', it: " + s
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package foo
|
||||
|
||||
import java.util.ArrayList
|
||||
|
||||
class A {
|
||||
fun component1() : Int = 1
|
||||
}
|
||||
fun A.component2() : String = "n"
|
||||
|
||||
fun box(): String {
|
||||
val list = ArrayList<A>()
|
||||
list.add(A())
|
||||
|
||||
var i = 0;
|
||||
var s = ""
|
||||
for ((a,b) in list) {
|
||||
i = a;
|
||||
s = b;
|
||||
}
|
||||
|
||||
if (i != 1) return "i != 1, it: " + i
|
||||
if (s != "n") return "s != 'n', it: " + s
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package foo
|
||||
|
||||
fun Int.component1() : Int {
|
||||
return this + 10;
|
||||
}
|
||||
|
||||
fun Int.component2() : String = "b"
|
||||
|
||||
fun box(): String {
|
||||
var i = 0;
|
||||
var s = "";
|
||||
for ((a, b) in 1..4) {
|
||||
i = a
|
||||
s = b
|
||||
}
|
||||
|
||||
if (i != 14) return "i != 14, it: $i"
|
||||
if (s != "b") return "s != 'b', it: $s"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package foo
|
||||
|
||||
fun Int.component1() : Int {
|
||||
return this + 10;
|
||||
}
|
||||
|
||||
fun Int.component2() : String = "b"
|
||||
|
||||
fun box(): String {
|
||||
var i = 0;
|
||||
var s = "";
|
||||
val range = 1..4
|
||||
for ((a, b) in range) {
|
||||
i = a
|
||||
s = b
|
||||
}
|
||||
|
||||
if (i != 14) return "i != 14, it: $i"
|
||||
if (s != "b") return "s != 'b', it: $s"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package foo
|
||||
|
||||
class A {
|
||||
fun component1(): Int = 1
|
||||
}
|
||||
fun A.component2(): String = "n"
|
||||
|
||||
class B {
|
||||
fun component1(): Int = 1
|
||||
fun component2(): Int = 2
|
||||
fun component3(): Int = 3
|
||||
}
|
||||
|
||||
class C {
|
||||
fun component1(): Int = 42
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val (a, b) = A()
|
||||
if (a != 1) return "a != 1, it: $a"
|
||||
if (b != "n") return "b != 'n', it: $b"
|
||||
|
||||
var (x, y) = A()
|
||||
if (x != 1) return "x != 1, it: $x"
|
||||
if (y != "n") return "y != 'n', it: $y"
|
||||
|
||||
x = 3
|
||||
if (x != 3) return "x != 3, it: $x"
|
||||
y = "m"
|
||||
if (y != "m") return "y != 'm', it: $y"
|
||||
|
||||
var (b1, b2, b3) = B()
|
||||
if (b1 != 1) return "b1 != 1, it: $b1"
|
||||
if (b2 != 2) return "b2 != 2, it: $b2"
|
||||
if (b3 != 3) return "b3 != 3, it: $b3"
|
||||
|
||||
val (c) = C()
|
||||
if (c != 42) return "c != 42, it: $c"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
Reference in New Issue
Block a user