support for in operation syntax, refactor, test, range sugar syntax
This commit is contained in:
@@ -328,8 +328,11 @@ public class AstUtil {
|
||||
return equals(expression, program.getTrueLiteral());
|
||||
}
|
||||
|
||||
|
||||
public static JsBinaryOperation sum(JsExpression left, JsExpression right) {
|
||||
return new JsBinaryOperation(JsBinaryOperator.ADD, left, right);
|
||||
}
|
||||
|
||||
public static JsBinaryOperation subtract(JsExpression left, JsExpression right) {
|
||||
return new JsBinaryOperation(JsBinaryOperator.SUB, left, right);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,21 +4,18 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.types.JetStandardLibrary;
|
||||
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
|
||||
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.PrimitiveBinaryOperationIntrinsic;
|
||||
import org.jetbrains.k2js.translate.intrinsic.primitive.PrimitiveCompareToIntrinsic;
|
||||
import org.jetbrains.k2js.translate.intrinsic.primitive.PrimitiveEqualsIntrinsic;
|
||||
import org.jetbrains.k2js.translate.intrinsic.primitive.PrimitiveUnaryOperationIntrinsic;
|
||||
import org.jetbrains.k2js.translate.intrinsic.primitive.*;
|
||||
import org.jetbrains.k2js.translate.operation.OperatorTable;
|
||||
import org.jetbrains.k2js.translate.utils.DescriptorUtils;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
@@ -55,6 +52,7 @@ public final class Intrinsics {
|
||||
private void declareOperatorIntrinsics() {
|
||||
IntrinsicDeclarationVisitor visitor = new IntrinsicDeclarationVisitor(this);
|
||||
for (DeclarationDescriptor descriptor : library.getLibraryScope().getAllDescriptors()) {
|
||||
//noinspection NullableProblems
|
||||
descriptor.accept(visitor, null);
|
||||
}
|
||||
}
|
||||
@@ -75,25 +73,33 @@ public final class Intrinsics {
|
||||
addEqualsIntrinsics(descriptor);
|
||||
addUnaryIntrinsics(descriptor);
|
||||
addBinaryIntrinsics(descriptor);
|
||||
addRangeToIntrinsics(descriptor);
|
||||
}
|
||||
|
||||
private void addRangeToIntrinsics(@NotNull FunctionDescriptor descriptor) {
|
||||
String functionName = descriptor.getName();
|
||||
if (functionName.equals("rangeTo")) {
|
||||
functionIntrinsics.put(descriptor, PrimitiveRangeToIntrinsic.newInstance());
|
||||
}
|
||||
}
|
||||
|
||||
private void addCompareToIntrinsics(@NotNull FunctionDescriptor descriptor) {
|
||||
String functionName = descriptor.getName();
|
||||
if (functionName.equals("compareTo")) {
|
||||
if (functionName.equals(COMPARE_TO)) {
|
||||
compareToIntrinsics.put(descriptor, PrimitiveCompareToIntrinsic.newInstance());
|
||||
}
|
||||
}
|
||||
|
||||
private void addEqualsIntrinsics(@NotNull FunctionDescriptor descriptor) {
|
||||
String functionName = descriptor.getName();
|
||||
if (functionName.equals("equals")) {
|
||||
if (functionName.equals(EQUALS)) {
|
||||
equalsIntrinsics.put(descriptor, PrimitiveEqualsIntrinsic.newInstance());
|
||||
}
|
||||
}
|
||||
|
||||
private void addUnaryIntrinsics(@NotNull FunctionDescriptor descriptor) {
|
||||
String functionName = descriptor.getName();
|
||||
JetToken token = OperatorConventions.UNARY_OPERATION_NAMES.inverse().get(functionName);
|
||||
JetToken token = UNARY_OPERATION_NAMES.inverse().get(functionName);
|
||||
if (token == null) return;
|
||||
boolean isUnary = !DescriptorUtils.hasParameters(descriptor);
|
||||
if (!isUnary) return;
|
||||
@@ -105,9 +111,9 @@ public final class Intrinsics {
|
||||
String functionName = descriptor.getName();
|
||||
boolean isUnary = !DescriptorUtils.hasParameters(descriptor);
|
||||
if (isUnary) return;
|
||||
JetToken token = OperatorConventions.BINARY_OPERATION_NAMES.inverse().get(functionName);
|
||||
JetToken token = BINARY_OPERATION_NAMES.inverse().get(functionName);
|
||||
if (token == null) return;
|
||||
//TODO: implement range and contains intrinsic
|
||||
//TODO: implement contains intrinsic
|
||||
if (!OperatorTable.hasCorrespondingBinaryOperator(token)) return;
|
||||
functionIntrinsics.put(descriptor, PrimitiveBinaryOperationIntrinsic.newInstance(token));
|
||||
}
|
||||
|
||||
+3
@@ -20,6 +20,9 @@ public final class PrimitiveCompareToIntrinsic extends CompareToIntrinsic {
|
||||
return new PrimitiveCompareToIntrinsic();
|
||||
}
|
||||
|
||||
private PrimitiveCompareToIntrinsic() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression apply(@NotNull JsExpression receiver, @NotNull List<JsExpression> arguments,
|
||||
@NotNull TranslationContext context) {
|
||||
|
||||
+3
@@ -18,6 +18,9 @@ public final class PrimitiveEqualsIntrinsic extends EqualsIntrinsic {
|
||||
return new PrimitiveEqualsIntrinsic();
|
||||
}
|
||||
|
||||
private PrimitiveEqualsIntrinsic() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression apply(@NotNull JsExpression receiver, @NotNull List<JsExpression> arguments,
|
||||
@NotNull TranslationContext context) {
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package org.jetbrains.k2js.translate.intrinsic.primitive;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsBinaryOperation;
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.backend.js.ast.JsNew;
|
||||
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.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Talanov Pavel
|
||||
*/
|
||||
public final class PrimitiveRangeToIntrinsic implements FunctionIntrinsic {
|
||||
|
||||
@NotNull
|
||||
public static PrimitiveRangeToIntrinsic newInstance() {
|
||||
return new PrimitiveRangeToIntrinsic();
|
||||
}
|
||||
|
||||
private PrimitiveRangeToIntrinsic() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression apply(@NotNull JsExpression rangeStart, @NotNull List<JsExpression> arguments,
|
||||
@NotNull TranslationContext context) {
|
||||
assert arguments.size() == 1 : "RangeTo must have one argument.";
|
||||
JsExpression rangeEnd = arguments.get(0);
|
||||
JsBinaryOperation rangeSize = AstUtil.subtract(rangeEnd, rangeStart);
|
||||
//TODO: provide a way not to hard code this value
|
||||
JsNew numberRangeConstructorInvocation
|
||||
= new JsNew(AstUtil.newQualifiedNameRef("Kotlin.NumberRange"));
|
||||
numberRangeConstructorInvocation.setArguments(Arrays.asList(rangeStart, rangeSize));
|
||||
return numberRangeConstructorInvocation;
|
||||
}
|
||||
}
|
||||
+11
-3
@@ -17,6 +17,8 @@ import org.jetbrains.k2js.translate.reference.CallTranslator;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.jetbrains.k2js.translate.operation.AssignmentTranslator.isAssignmentOperator;
|
||||
import static org.jetbrains.k2js.translate.operation.CompareToTranslator.isCompareToCall;
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptorForOperationExpression;
|
||||
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.isEquals;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken;
|
||||
@@ -51,21 +53,27 @@ public final class BinaryOperationTranslator extends AbstractTranslator {
|
||||
|
||||
@NotNull
|
||||
private JsExpression translate() {
|
||||
if (AssignmentTranslator.isAssignmentOperator(expression)) {
|
||||
if (isAssignmentOperator(expression)) {
|
||||
return AssignmentTranslator.translate(expression, context());
|
||||
}
|
||||
if (operationDescriptor == null) {
|
||||
if (isNotOverloadable()) {
|
||||
return translateAsUnOverloadableBinaryOperation();
|
||||
}
|
||||
if (CompareToTranslator.isCompareToCall(expression, context())) {
|
||||
if (isCompareToCall(expression, context())) {
|
||||
return CompareToTranslator.translate(expression, context());
|
||||
}
|
||||
assert operationDescriptor != null :
|
||||
"Overloadable operations must have not null descriptor";
|
||||
if (isEquals(operationDescriptor)) {
|
||||
return translateAsEqualsCall();
|
||||
}
|
||||
return CallTranslator.translate(expression, context());
|
||||
}
|
||||
|
||||
private boolean isNotOverloadable() {
|
||||
return operationDescriptor == null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translateAsEqualsCall() {
|
||||
assert operationDescriptor != null : "Equals operation must resolve to descriptor.";
|
||||
|
||||
@@ -23,11 +23,13 @@ import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForRe
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptorForCallExpression;
|
||||
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getVariableDescriptorForVariableAsFunction;
|
||||
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.isConstructorDescriptor;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.isInOperation;
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.*;
|
||||
|
||||
/**
|
||||
* @author Talanov Pavel
|
||||
*/
|
||||
//TODO: move translate() static method into builder (consider!)
|
||||
//TODO: write tests on calling backing fields as functions
|
||||
public final class CallTranslator extends AbstractTranslator {
|
||||
|
||||
@@ -38,14 +40,14 @@ public final class CallTranslator extends AbstractTranslator {
|
||||
DeclarationDescriptor descriptor = getDescriptorForReferenceExpression
|
||||
(context.bindingContext(), unaryExpression.getOperationReference());
|
||||
assert descriptor instanceof FunctionDescriptor;
|
||||
return (new CallTranslator(receiver, arguments, (FunctionDescriptor) descriptor, context)).translate();
|
||||
return translate(context, receiver, arguments, (FunctionDescriptor) descriptor);
|
||||
}
|
||||
|
||||
//TODO: method too long
|
||||
public static JsExpression translate(@NotNull JetDotQualifiedExpression dotExpression,
|
||||
@NotNull TranslationContext context) {
|
||||
//TODO: look for duplication
|
||||
JsExpression receiver = translateReceiver(context, dotExpression);
|
||||
//TODO: util?
|
||||
JetExpression selectorExpression = dotExpression.getSelectorExpression();
|
||||
assert selectorExpression instanceof JetCallExpression;
|
||||
JetCallExpression callExpression = (JetCallExpression) selectorExpression;
|
||||
@@ -53,7 +55,7 @@ public final class CallTranslator extends AbstractTranslator {
|
||||
translateArgumentList(context, callExpression.getValueArguments());
|
||||
FunctionDescriptor descriptor =
|
||||
getFunctionDescriptorForCallExpression(context.bindingContext(), callExpression);
|
||||
return (new CallTranslator(receiver, arguments, descriptor, context)).translate();
|
||||
return translate(context, receiver, arguments, descriptor);
|
||||
}
|
||||
|
||||
public static JsExpression translate(@NotNull JetCallExpression callExpression,
|
||||
@@ -62,18 +64,39 @@ public final class CallTranslator extends AbstractTranslator {
|
||||
getFunctionDescriptorForCallExpression(context.bindingContext(), callExpression);
|
||||
JsExpression receiver = getImplicitReceiver(context, descriptor);
|
||||
List<JsExpression> arguments = translateArgumentList(context, callExpression.getValueArguments());
|
||||
return (new CallTranslator(receiver, arguments, (FunctionDescriptor) descriptor, context)).translate();
|
||||
return translate(context, receiver, arguments, (FunctionDescriptor) descriptor);
|
||||
}
|
||||
|
||||
//TODO: refactor
|
||||
public static JsExpression translate(@NotNull JetBinaryExpression binaryExpression,
|
||||
@NotNull TranslationContext context) {
|
||||
JsExpression receiver = translateLeftExpression(context, binaryExpression);
|
||||
List<JsExpression> arguments = Arrays.asList(translateRightExpression(context, binaryExpression));
|
||||
//TODO: use PSI util method to get operation reference
|
||||
DeclarationDescriptor descriptor = getDescriptorForReferenceExpression
|
||||
(context.bindingContext(), binaryExpression.getOperationReference());
|
||||
assert descriptor instanceof FunctionDescriptor;
|
||||
return (new CallTranslator(receiver, arguments, (FunctionDescriptor) descriptor, context)).translate();
|
||||
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
|
||||
if (isInOperation(binaryExpression)) {
|
||||
return translateWithReceiverAndArgumentSwapped(context, receiver, arguments, functionDescriptor);
|
||||
}
|
||||
return translate(context, receiver, arguments, functionDescriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static JsExpression translateWithReceiverAndArgumentSwapped(@NotNull TranslationContext context,
|
||||
@NotNull JsExpression receiver,
|
||||
@NotNull List<JsExpression> arguments,
|
||||
@NotNull FunctionDescriptor functionDescriptor) {
|
||||
assert arguments.size() == 1 : "Must have one argument.";
|
||||
return translate(context, arguments.get(0), Arrays.asList(receiver), functionDescriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static JsExpression translate(@NotNull TranslationContext context,
|
||||
@Nullable JsExpression receiver,
|
||||
@NotNull List<JsExpression> arguments,
|
||||
@NotNull FunctionDescriptor functionDescriptor) {
|
||||
return (new CallTranslator(receiver, arguments, functionDescriptor, context)).translate();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -52,6 +52,10 @@ public final class PsiUtils {
|
||||
return expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER;
|
||||
}
|
||||
|
||||
public static boolean isInOperation(@NotNull JetBinaryExpression binaryExpression) {
|
||||
return binaryExpression.getOperationToken() == JetTokens.IN_KEYWORD;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
/*package*/ static JetExpression getCallee(@NotNull JetCallExpression expression) {
|
||||
JetExpression calleeExpression = expression.getCalleeExpression();
|
||||
|
||||
@@ -19,5 +19,15 @@ public final class RangeTest extends TranslationTest {
|
||||
testFooBoxIsTrue("explicitRange.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rangeSugarSyntax() throws Exception {
|
||||
testFooBoxIsTrue("rangeSugarSyntax.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void intInRange() throws Exception {
|
||||
testFooBoxIsTrue("intInRange.kt");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace foo
|
||||
|
||||
fun box() : Boolean {
|
||||
|
||||
if (1 in -2..1) return false;
|
||||
if (1 in -10..0) return false;
|
||||
if (!(1 in 0..2)) return false;
|
||||
|
||||
if (!(1 in 1..2)) return false;
|
||||
if (!(1 in -2..5)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
namespace foo
|
||||
|
||||
fun box() : Boolean {
|
||||
|
||||
var oneToFive = 1..5
|
||||
|
||||
if (oneToFive.contains(5)) return false;
|
||||
if (oneToFive.contains(0)) return false;
|
||||
if (oneToFive.contains(-100)) return false;
|
||||
if (oneToFive.contains(10)) return false;
|
||||
if (!oneToFive.contains(1)) return false;
|
||||
if (!oneToFive.contains(2)) return false;
|
||||
if (!oneToFive.contains(3)) return false;
|
||||
if (!oneToFive.contains(4)) return false;
|
||||
if (!(oneToFive.start == 1)) return false;
|
||||
if (!(oneToFive.size == 4)) return false;
|
||||
if (!(oneToFive.end == 5)) return false;
|
||||
|
||||
var sum = 0;
|
||||
for (i in oneToFive) {
|
||||
sum += i;
|
||||
}
|
||||
for (i in oneToFive) {
|
||||
System.out?.print(i)
|
||||
}
|
||||
|
||||
if (sum != 10) return false;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user