JS backend: added the support dynamic.
This commit is contained in:
@@ -179,7 +179,7 @@ object DynamicCallableDescriptors {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun DeclarationDescriptor.isDynamic(): Boolean {
|
public fun DeclarationDescriptor.isDynamic(): Boolean {
|
||||||
if (this !is CallableDescriptor) return false
|
if (this !is CallableDescriptor) return false
|
||||||
val dispatchReceiverParameter = getDispatchReceiverParameter()
|
val dispatchReceiverParameter = getDispatchReceiverParameter()
|
||||||
return dispatchReceiverParameter != null && dispatchReceiverParameter.getType().isDynamic()
|
return dispatchReceiverParameter != null && dispatchReceiverParameter.getType().isDynamic()
|
||||||
|
|||||||
@@ -35,6 +35,18 @@ import com.google.dart.compiler.backend.js.ast.JsArrayAccess
|
|||||||
import org.jetbrains.k2js.translate.utils.JsAstUtils
|
import org.jetbrains.k2js.translate.utils.JsAstUtils
|
||||||
import org.jetbrains.k2js.translate.utils.AnnotationsUtils
|
import org.jetbrains.k2js.translate.utils.AnnotationsUtils
|
||||||
import org.jetbrains.k2js.PredefinedAnnotation
|
import org.jetbrains.k2js.PredefinedAnnotation
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.tasks.isDynamic
|
||||||
|
import org.jetbrains.jet.lang.psi.Call
|
||||||
|
import org.jetbrains.k2js.translate.operation.OperatorTable
|
||||||
|
import com.google.dart.compiler.backend.js.ast.JsBinaryOperation
|
||||||
|
import org.jetbrains.jet.lang.psi.JetPrefixExpression
|
||||||
|
import com.google.dart.compiler.backend.js.ast.JsPrefixOperation
|
||||||
|
import org.jetbrains.jet.lang.psi.JetPostfixExpression
|
||||||
|
import com.google.dart.compiler.backend.js.ast.JsPostfixOperation
|
||||||
|
import org.jetbrains.jet.lang.psi.JetBinaryExpression
|
||||||
|
import org.jetbrains.jet.lexer.JetTokens
|
||||||
|
import org.jetbrains.jet.lang.psi.JetOperationExpression
|
||||||
|
import org.jetbrains.k2js.translate.utils.PsiUtils
|
||||||
|
|
||||||
public fun addReceiverToArgs(receiver: JsExpression, arguments: List<JsExpression>): List<JsExpression> {
|
public fun addReceiverToArgs(receiver: JsExpression, arguments: List<JsExpression>): List<JsExpression> {
|
||||||
if (arguments.isEmpty())
|
if (arguments.isEmpty())
|
||||||
@@ -230,6 +242,64 @@ object SuperCallCase : FunctionCallCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object DynamicInvokeAndBracketAccessCallCase : FunctionCallCase {
|
||||||
|
fun canApply(callInfo: FunctionCallInfo): Boolean =
|
||||||
|
callInfo.resolvedCall.getCall().getCallType() != Call.CallType.DEFAULT && callInfo.callableDescriptor.isDynamic()
|
||||||
|
|
||||||
|
override fun FunctionCallInfo.dispatchReceiver(): JsExpression {
|
||||||
|
val arguments = argumentsInfo.getTranslateArguments()
|
||||||
|
val callType = resolvedCall.getCall().getCallType()
|
||||||
|
return when (callType) {
|
||||||
|
Call.CallType.INVOKE ->
|
||||||
|
JsInvocation(dispatchReceiver, arguments)
|
||||||
|
Call.CallType.ARRAY_GET_METHOD ->
|
||||||
|
JsArrayAccess(dispatchReceiver, arguments[0])
|
||||||
|
Call.CallType.ARRAY_SET_METHOD ->
|
||||||
|
JsAstUtils.assignment(JsArrayAccess(dispatchReceiver, arguments[0]), arguments[1])
|
||||||
|
|
||||||
|
else ->
|
||||||
|
unsupported("Unsupported call type: $callType, callInfo: $this")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object DynamicOperatorCallCase : FunctionCallCase {
|
||||||
|
fun canApply(callInfo: FunctionCallInfo): Boolean =
|
||||||
|
callInfo.callableDescriptor.isDynamic() &&
|
||||||
|
callInfo.resolvedCall.getCall().getCallElement() let {
|
||||||
|
it is JetOperationExpression &&
|
||||||
|
PsiUtils.getOperationToken(it) let { (it == JetTokens.NOT_IN || OperatorTable.hasCorrespondingOperator(it)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun FunctionCallInfo.dispatchReceiver(): JsExpression {
|
||||||
|
val callElement = resolvedCall.getCall().getCallElement() as JetOperationExpression
|
||||||
|
val operationToken = PsiUtils.getOperationToken(callElement)
|
||||||
|
|
||||||
|
val arguments = argumentsInfo.getTranslateArguments()
|
||||||
|
|
||||||
|
return when (callElement) {
|
||||||
|
is JetBinaryExpression -> {
|
||||||
|
// `!in` translated as `in` and will be wrapped by negation operation in BinaryOperationTranslator#translateAsOverloadedBinaryOperation by mayBeWrapWithNegation
|
||||||
|
val operationTokenToFind = if (operationToken == JetTokens.NOT_IN) JetTokens.IN_KEYWORD else operationToken
|
||||||
|
val binaryOperator = OperatorTable.getBinaryOperator(operationTokenToFind)
|
||||||
|
|
||||||
|
if (operationTokenToFind == JetTokens.IN_KEYWORD)
|
||||||
|
JsBinaryOperation(binaryOperator, arguments[0], dispatchReceiver)
|
||||||
|
else
|
||||||
|
JsBinaryOperation(binaryOperator, dispatchReceiver, arguments[0])
|
||||||
|
}
|
||||||
|
is JetPrefixExpression -> {
|
||||||
|
JsPrefixOperation(OperatorTable.getUnaryOperator(operationToken), dispatchReceiver)
|
||||||
|
}
|
||||||
|
is JetPostfixExpression -> {
|
||||||
|
// TODO drop hack with ":JsExpression" when KT-5569 will be fixed
|
||||||
|
JsPostfixOperation(OperatorTable.getUnaryOperator(operationToken), dispatchReceiver): JsExpression
|
||||||
|
}
|
||||||
|
else -> unsupported("Unsupported callElement type: ${callElement.javaClass}, callElement: $callElement, callInfo: $this")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun FunctionCallInfo.translateFunctionCall(): JsExpression {
|
fun FunctionCallInfo.translateFunctionCall(): JsExpression {
|
||||||
val intrinsic = DelegateFunctionIntrinsic.intrinsic(this)
|
val intrinsic = DelegateFunctionIntrinsic.intrinsic(this)
|
||||||
|
|
||||||
@@ -250,6 +320,12 @@ fun FunctionCallInfo.translateFunctionCall(): JsExpression {
|
|||||||
ConstructorCallCase.translate(this)
|
ConstructorCallCase.translate(this)
|
||||||
SuperCallCase.canApply(this) ->
|
SuperCallCase.canApply(this) ->
|
||||||
SuperCallCase.translate(this)
|
SuperCallCase.translate(this)
|
||||||
|
|
||||||
|
DynamicInvokeAndBracketAccessCallCase.canApply(this) ->
|
||||||
|
DynamicInvokeAndBracketAccessCallCase.translate(this)
|
||||||
|
DynamicOperatorCallCase.canApply(this) ->
|
||||||
|
DynamicOperatorCallCase.translate(this)
|
||||||
|
|
||||||
else ->
|
else ->
|
||||||
DefaultFunctionCallCase.translate(this)
|
DefaultFunctionCallCase.translate(this)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import org.jetbrains.jet.lang.descriptors.*;
|
|||||||
import org.jetbrains.jet.lang.reflect.ReflectionTypes;
|
import org.jetbrains.jet.lang.reflect.ReflectionTypes;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.tasks.TasksPackage;
|
||||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||||
import org.jetbrains.k2js.config.Config;
|
import org.jetbrains.k2js.config.Config;
|
||||||
import org.jetbrains.k2js.config.EcmaVersion;
|
import org.jetbrains.k2js.config.EcmaVersion;
|
||||||
@@ -229,6 +230,21 @@ public final class StaticContext {
|
|||||||
private final class NameGenerator extends Generator<JsName> {
|
private final class NameGenerator extends Generator<JsName> {
|
||||||
|
|
||||||
public NameGenerator() {
|
public NameGenerator() {
|
||||||
|
Rule<JsName> namesForDynamic = new Rule<JsName>() {
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
|
||||||
|
if (TasksPackage.isDynamic(descriptor)) {
|
||||||
|
String name = descriptor.getName().asString();
|
||||||
|
JsScope scope = getEnclosingScope(descriptor);
|
||||||
|
assert scope instanceof JsFunctionScope;
|
||||||
|
return ((JsFunctionScope) scope).declareNameUnsafe(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Rule<JsName> namesForStandardClasses = new Rule<JsName>() {
|
Rule<JsName> namesForStandardClasses = new Rule<JsName>() {
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -332,6 +348,8 @@ public final class StaticContext {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
addRule(namesForDynamic);
|
||||||
addRule(namesForStandardClasses);
|
addRule(namesForStandardClasses);
|
||||||
addRule(constructorOrClassObjectHasTheSameNameAsTheClass);
|
addRule(constructorOrClassObjectHasTheSameNameAsTheClass);
|
||||||
addRule(propertyOrPropertyAccessor);
|
addRule(propertyOrPropertyAccessor);
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import org.jetbrains.k2js.translate.operation.OperatorTable
|
|||||||
import org.jetbrains.k2js.translate.utils.JsAstUtils
|
import org.jetbrains.k2js.translate.utils.JsAstUtils
|
||||||
import org.jetbrains.k2js.translate.utils.JsDescriptorUtils
|
import org.jetbrains.k2js.translate.utils.JsDescriptorUtils
|
||||||
import org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken
|
import org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.tasks.isDynamic
|
||||||
|
|
||||||
|
|
||||||
object CompareToBOIF : BinaryOperationIntrinsicFactory {
|
object CompareToBOIF : BinaryOperationIntrinsicFactory {
|
||||||
@@ -67,6 +68,8 @@ object CompareToBOIF : BinaryOperationIntrinsicFactory {
|
|||||||
override public fun getSupportTokens(): ImmutableSet<JetToken> = OperatorConventions.COMPARISON_OPERATIONS
|
override public fun getSupportTokens(): ImmutableSet<JetToken> = OperatorConventions.COMPARISON_OPERATIONS
|
||||||
|
|
||||||
override public fun getIntrinsic(descriptor: FunctionDescriptor): BinaryOperationIntrinsic? {
|
override public fun getIntrinsic(descriptor: FunctionDescriptor): BinaryOperationIntrinsic? {
|
||||||
|
if (descriptor.isDynamic()) return CompareToIntrinsic
|
||||||
|
|
||||||
if (!JsDescriptorUtils.isBuiltin(descriptor)) return null
|
if (!JsDescriptorUtils.isBuiltin(descriptor)) return null
|
||||||
|
|
||||||
return when {
|
return when {
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ import org.jetbrains.jet.lexer.JetToken
|
|||||||
import org.jetbrains.jet.lexer.JetTokens
|
import org.jetbrains.jet.lexer.JetTokens
|
||||||
import com.google.common.collect.ImmutableSet
|
import com.google.common.collect.ImmutableSet
|
||||||
import org.jetbrains.k2js.translate.intrinsic.functions.patterns.PatternBuilder.pattern
|
import org.jetbrains.k2js.translate.intrinsic.functions.patterns.PatternBuilder.pattern
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.callUtil.getResolvedCall
|
||||||
|
import org.jetbrains.jet.lang.types.isDynamic
|
||||||
|
|
||||||
object EqualsBOIF : BinaryOperationIntrinsicFactory {
|
object EqualsBOIF : BinaryOperationIntrinsicFactory {
|
||||||
|
|
||||||
@@ -57,6 +59,17 @@ object EqualsBOIF : BinaryOperationIntrinsicFactory {
|
|||||||
return JsBinaryOperation(if (isNegated) JsBinaryOperator.REF_NEQ else JsBinaryOperator.REF_EQ, left, right)
|
return JsBinaryOperation(if (isNegated) JsBinaryOperator.REF_NEQ else JsBinaryOperator.REF_EQ, left, right)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val resolvedCall = expression.getResolvedCall(context.bindingContext())
|
||||||
|
val appliedToDynamic =
|
||||||
|
resolvedCall != null &&
|
||||||
|
with(resolvedCall.getDispatchReceiver()) {
|
||||||
|
if (exists()) getType().isDynamic() else false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (appliedToDynamic) {
|
||||||
|
return JsBinaryOperation(if (isNegated) JsBinaryOperator.NEQ else JsBinaryOperator.EQ, left, right)
|
||||||
|
}
|
||||||
|
|
||||||
val result = TopLevelFIF.KOTLIN_EQUALS.apply(left, Arrays.asList<JsExpression>(right), context)
|
val result = TopLevelFIF.KOTLIN_EQUALS.apply(left, Arrays.asList<JsExpression>(right), context)
|
||||||
return if (isNegated) JsAstUtils.negated(result) else result
|
return if (isNegated) JsAstUtils.negated(result) else result
|
||||||
}
|
}
|
||||||
|
|||||||
+4
@@ -209,6 +209,10 @@ public final class BinaryOperationTranslator extends AbstractTranslator {
|
|||||||
if (rightBlock.isEmpty()) {
|
if (rightBlock.isEmpty()) {
|
||||||
return new JsBinaryOperation(operator, leftExpression, rightExpression);
|
return new JsBinaryOperation(operator, leftExpression, rightExpression);
|
||||||
}
|
}
|
||||||
|
else if (OperatorConventions.IDENTITY_EQUALS_OPERATIONS.contains(operationToken)) {
|
||||||
|
context().addStatementsToCurrentBlockFrom(rightBlock);
|
||||||
|
return new JsBinaryOperation(operator, leftExpression, rightExpression);
|
||||||
|
}
|
||||||
|
|
||||||
assert operationToken.equals(JetTokens.ANDAND) || operationToken.equals(JetTokens.OROR) : "Unsupported binary operation: " + expression.getText();
|
assert operationToken.equals(JetTokens.ANDAND) || operationToken.equals(JetTokens.OROR) : "Unsupported binary operation: " + expression.getText();
|
||||||
boolean isOror = operationToken.equals(JetTokens.OROR);
|
boolean isOror = operationToken.equals(JetTokens.OROR);
|
||||||
|
|||||||
+11
-2
@@ -23,8 +23,10 @@ import com.google.dart.compiler.backend.js.ast.JsExpression;
|
|||||||
import com.google.dart.compiler.util.AstUtil;
|
import com.google.dart.compiler.util.AstUtil;
|
||||||
import com.intellij.psi.tree.IElementType;
|
import com.intellij.psi.tree.IElementType;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||||
import org.jetbrains.jet.lang.psi.JetUnaryExpression;
|
import org.jetbrains.jet.lang.psi.JetUnaryExpression;
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.tasks.TasksPackage;
|
||||||
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
|
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
|
||||||
import org.jetbrains.k2js.translate.context.TemporaryVariable;
|
import org.jetbrains.k2js.translate.context.TemporaryVariable;
|
||||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||||
@@ -34,8 +36,10 @@ import org.jetbrains.k2js.translate.reference.CachedAccessTranslator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.jetbrains.k2js.translate.reference.AccessTranslationUtils.getCachedAccessTranslator;
|
import static org.jetbrains.k2js.translate.reference.AccessTranslationUtils.getCachedAccessTranslator;
|
||||||
|
import static org.jetbrains.k2js.translate.utils.BindingUtils.getCallableDescriptorForOperationExpression;
|
||||||
import static org.jetbrains.k2js.translate.utils.JsAstUtils.newSequence;
|
import static org.jetbrains.k2js.translate.utils.JsAstUtils.newSequence;
|
||||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.*;
|
import static org.jetbrains.k2js.translate.utils.PsiUtils.getBaseExpression;
|
||||||
|
import static org.jetbrains.k2js.translate.utils.PsiUtils.isPrefix;
|
||||||
import static org.jetbrains.k2js.translate.utils.TemporariesUtils.temporariesInitialization;
|
import static org.jetbrains.k2js.translate.utils.TemporariesUtils.temporariesInitialization;
|
||||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.hasCorrespondingFunctionIntrinsic;
|
import static org.jetbrains.k2js.translate.utils.TranslationUtils.hasCorrespondingFunctionIntrinsic;
|
||||||
|
|
||||||
@@ -50,7 +54,7 @@ public abstract class IncrementTranslator extends AbstractTranslator {
|
|||||||
@NotNull
|
@NotNull
|
||||||
public static JsExpression translate(@NotNull JetUnaryExpression expression,
|
public static JsExpression translate(@NotNull JetUnaryExpression expression,
|
||||||
@NotNull TranslationContext context) {
|
@NotNull TranslationContext context) {
|
||||||
if (hasCorrespondingFunctionIntrinsic(context, expression)) {
|
if (hasCorrespondingFunctionIntrinsic(context, expression) || isDynamic(context, expression)) {
|
||||||
return IntrinsicIncrementTranslator.doTranslate(expression, context);
|
return IntrinsicIncrementTranslator.doTranslate(expression, context);
|
||||||
}
|
}
|
||||||
return (new OverloadedIncrementTranslator(expression, context)).translateIncrementExpression();
|
return (new OverloadedIncrementTranslator(expression, context)).translateIncrementExpression();
|
||||||
@@ -121,4 +125,9 @@ public abstract class IncrementTranslator extends AbstractTranslator {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
abstract JsExpression operationExpression(@NotNull JsExpression receiver);
|
abstract JsExpression operationExpression(@NotNull JsExpression receiver);
|
||||||
|
|
||||||
|
private static boolean isDynamic(TranslationContext context, JetUnaryExpression expression) {
|
||||||
|
CallableDescriptor operationDescriptor = getCallableDescriptorForOperationExpression(context.bindingContext(), expression);
|
||||||
|
return TasksPackage.isDynamic(operationDescriptor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,9 @@ public final class OperatorTable {
|
|||||||
.put(JetTokens.DIVEQ, JsBinaryOperator.ASG_DIV)
|
.put(JetTokens.DIVEQ, JsBinaryOperator.ASG_DIV)
|
||||||
.put(JetTokens.MULTEQ, JsBinaryOperator.ASG_MUL)
|
.put(JetTokens.MULTEQ, JsBinaryOperator.ASG_MUL)
|
||||||
.put(JetTokens.PERCEQ, JsBinaryOperator.ASG_MOD)
|
.put(JetTokens.PERCEQ, JsBinaryOperator.ASG_MOD)
|
||||||
|
.put(JetTokens.IN_KEYWORD, JsBinaryOperator.INOP)
|
||||||
|
.put(JetTokens.EQEQEQ, JsBinaryOperator.REF_EQ)
|
||||||
|
.put(JetTokens.EXCLEQEQEQ, JsBinaryOperator.REF_NEQ)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
private static final ImmutableBiMap<JetToken, JsUnaryOperator> unaryOperatorsMap = ImmutableBiMap.<JetToken, JsUnaryOperator>builder()
|
private static final ImmutableBiMap<JetToken, JsUnaryOperator> unaryOperatorsMap = ImmutableBiMap.<JetToken, JsUnaryOperator>builder()
|
||||||
@@ -59,6 +62,9 @@ public final class OperatorTable {
|
|||||||
private OperatorTable() {
|
private OperatorTable() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean hasCorrespondingOperator(@NotNull JetToken token) {
|
||||||
|
return binaryOperatorsMap.containsKey(token) || unaryOperatorsMap.containsKey(token);
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean hasCorrespondingBinaryOperator(@NotNull JetToken token) {
|
public static boolean hasCorrespondingBinaryOperator(@NotNull JetToken token) {
|
||||||
return binaryOperatorsMap.containsKey(token);
|
return binaryOperatorsMap.containsKey(token);
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ public final class PsiUtils {
|
|||||||
public static JetToken getOperationToken(@NotNull JetOperationExpression expression) {
|
public static JetToken getOperationToken(@NotNull JetOperationExpression expression) {
|
||||||
JetSimpleNameExpression operationExpression = expression.getOperationReference();
|
JetSimpleNameExpression operationExpression = expression.getOperationReference();
|
||||||
IElementType elementType = operationExpression.getReferencedNameElementType();
|
IElementType elementType = operationExpression.getReferencedNameElementType();
|
||||||
assert elementType instanceof JetToken : "Unary expression should have operation token of type JetToken";
|
assert elementType instanceof JetToken : "Expected JetToken type, but " + elementType.getClass() + ", expression: " + expression.getText();
|
||||||
return (JetToken) elementType;
|
return (JetToken) elementType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user