JS backend: support for reflection
This commit is contained in:
@@ -7,6 +7,7 @@ package com.google.dart.compiler.backend.js.ast;
|
||||
import gnu.trove.TDoubleObjectHashMap;
|
||||
import gnu.trove.THashMap;
|
||||
import gnu.trove.TIntObjectHashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -91,6 +92,7 @@ public final class JsProgram extends SourceInfoAwareJsNode {
|
||||
/**
|
||||
* Creates or retrieves a JsStringLiteral from an interned object pool.
|
||||
*/
|
||||
@NotNull
|
||||
public JsStringLiteral getStringLiteral(String value) {
|
||||
JsStringLiteral literal = stringLiteralMap.get(value);
|
||||
if (literal == null) {
|
||||
|
||||
+10
-3
@@ -34,6 +34,8 @@ import org.jetbrains.k2js.translate.reference.CallArgumentTranslator
|
||||
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.jet.lang.descriptors.Visibilities
|
||||
import org.jetbrains.jet.lang.psi.Call.CallType
|
||||
import org.jetbrains.k2js.translate.utils.JsDescriptorUtils
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils
|
||||
|
||||
public fun addReceiverToArgs(receiver: JsExpression, arguments: List<JsExpression>): List<JsExpression> {
|
||||
if (arguments.isEmpty())
|
||||
@@ -143,10 +145,15 @@ object InvokeIntrinsic : FunctionCallCase {
|
||||
return false
|
||||
val parameterCount = callInfo.callableDescriptor.getValueParameters().size()
|
||||
val funDeclaration = callInfo.callableDescriptor.getContainingDeclaration()
|
||||
return funDeclaration == ((if (callInfo.callableDescriptor.getReceiverParameter() == null)
|
||||
KotlinBuiltIns.getInstance().getFunction(parameterCount)
|
||||
|
||||
val reflectionTypes = callInfo.context.getReflectionTypes()
|
||||
return if (callInfo.callableDescriptor.getReceiverParameter() == null)
|
||||
funDeclaration == KotlinBuiltIns.getInstance().getFunction(parameterCount) ||
|
||||
funDeclaration == reflectionTypes.getKFunction(parameterCount)
|
||||
else
|
||||
KotlinBuiltIns.getInstance().getExtensionFunction(parameterCount)))
|
||||
funDeclaration == KotlinBuiltIns.getInstance().getExtensionFunction(parameterCount) ||
|
||||
funDeclaration == reflectionTypes.getKExtensionFunction(parameterCount) ||
|
||||
funDeclaration == reflectionTypes.getKMemberFunction(parameterCount)
|
||||
}
|
||||
|
||||
override fun FunctionCallInfo.thisObject(): JsExpression {
|
||||
|
||||
@@ -43,6 +43,12 @@ public final class Namer {
|
||||
private static final String TRAIT_OBJECT_NAME = "createTrait";
|
||||
private static final String OBJECT_OBJECT_NAME = "createObject";
|
||||
private static final String ENUM_ENTRIES_NAME = "createEnumEntries";
|
||||
private static final String CALLABLE_REF_FOR_MEMBER_FUNCTION_NAME = "getCallableRefForMemberFunction";
|
||||
private static final String CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME = "getCallableRefForExtensionFunction";
|
||||
private static final String CALLABLE_REF_FOR_CONSTRUCTOR_NAME = "getCallableRefForConstructor";
|
||||
private static final String CALLABLE_REF_FOR_TOP_LEVEL_PROPERTY = "getCallableRefForTopLevelProperty";
|
||||
private static final String CALLABLE_REF_FOR_MEMBER_PROPERTY = "getCallableRefForMemberProperty";
|
||||
private static final String CALLABLE_REF_FOR_EXTENSION_PROPERTY = "getCallableRefForExtensionProperty";
|
||||
|
||||
private static final String SETTER_PREFIX = "set_";
|
||||
private static final String GETTER_PREFIX = "get_";
|
||||
@@ -177,6 +183,18 @@ public final class Namer {
|
||||
@NotNull
|
||||
private final JsName enumEntriesName;
|
||||
@NotNull
|
||||
private final JsName callableRefForMemberFunctionName;
|
||||
@NotNull
|
||||
private final JsName callableRefForExtensionFunctionName;
|
||||
@NotNull
|
||||
private final JsName callableRefForConstructorName;
|
||||
@NotNull
|
||||
private final JsName callableRefForTopLevelProperty;
|
||||
@NotNull
|
||||
private final JsName callableRefForMemberProperty;
|
||||
@NotNull
|
||||
private final JsName callableRefForExtensionProperty;
|
||||
@NotNull
|
||||
private final JsExpression undefinedExpression;
|
||||
@NotNull
|
||||
private final JsExpression callGetProperty;
|
||||
@@ -200,6 +218,12 @@ public final class Namer {
|
||||
className = kotlinScope.declareName(CLASS_OBJECT_NAME);
|
||||
enumEntriesName = kotlinScope.declareName(ENUM_ENTRIES_NAME);
|
||||
objectName = kotlinScope.declareName(OBJECT_OBJECT_NAME);
|
||||
callableRefForMemberFunctionName = kotlinScope.declareName(CALLABLE_REF_FOR_MEMBER_FUNCTION_NAME);
|
||||
callableRefForExtensionFunctionName = kotlinScope.declareName(CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME);
|
||||
callableRefForConstructorName = kotlinScope.declareName(CALLABLE_REF_FOR_CONSTRUCTOR_NAME);
|
||||
callableRefForTopLevelProperty = kotlinScope.declareName(CALLABLE_REF_FOR_TOP_LEVEL_PROPERTY);
|
||||
callableRefForMemberProperty = kotlinScope.declareName(CALLABLE_REF_FOR_MEMBER_PROPERTY);
|
||||
callableRefForExtensionProperty = kotlinScope.declareName(CALLABLE_REF_FOR_EXTENSION_PROPERTY);
|
||||
|
||||
isTypeName = kotlinScope.declareName("isType");
|
||||
|
||||
@@ -236,6 +260,36 @@ public final class Namer {
|
||||
return kotlin(objectName);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression callableRefForMemberFunctionReference() {
|
||||
return kotlin(callableRefForMemberFunctionName);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression callableRefForExtensionFunctionReference() {
|
||||
return kotlin(callableRefForExtensionFunctionName);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression callableRefForConstructorReference() {
|
||||
return kotlin(callableRefForConstructorName);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression callableRefForTopLevelPropertyReference() {
|
||||
return kotlin(callableRefForTopLevelProperty);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression callableRefForMemberPropertyReference() {
|
||||
return kotlin(callableRefForMemberProperty);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression callableRefForExtensionPropertyReference() {
|
||||
return kotlin(callableRefForExtensionProperty);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression throwNPEFunctionRef() {
|
||||
return new JsNameRef(THROW_NPE_FUN_NAME, kotlinObject());
|
||||
|
||||
@@ -19,9 +19,7 @@ package org.jetbrains.k2js.translate.expression;
|
||||
import com.google.dart.compiler.backend.js.ast.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
||||
@@ -39,12 +37,8 @@ import org.jetbrains.k2js.translate.general.Translation;
|
||||
import org.jetbrains.k2js.translate.general.TranslatorVisitor;
|
||||
import org.jetbrains.k2js.translate.operation.BinaryOperationTranslator;
|
||||
import org.jetbrains.k2js.translate.operation.UnaryOperationTranslator;
|
||||
import org.jetbrains.k2js.translate.reference.AccessTranslationUtils;
|
||||
import org.jetbrains.k2js.translate.reference.CallExpressionTranslator;
|
||||
import org.jetbrains.k2js.translate.reference.QualifiedExpressionTranslator;
|
||||
import org.jetbrains.k2js.translate.reference.ReferenceTranslator;
|
||||
import org.jetbrains.k2js.translate.utils.JsAstUtils;
|
||||
import org.jetbrains.k2js.translate.utils.TranslationUtils;
|
||||
import org.jetbrains.k2js.translate.reference.*;
|
||||
import org.jetbrains.k2js.translate.utils.*;
|
||||
import org.jetbrains.k2js.translate.utils.mutator.AssignToExpressionMutator;
|
||||
|
||||
import java.util.List;
|
||||
@@ -168,6 +162,12 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
|
||||
return newVar(name, initializer).source(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitCallableReferenceExpression(@NotNull JetCallableReferenceExpression expression, @NotNull TranslationContext context) {
|
||||
return CallableReferenceTranslator.INSTANCE$.translate(expression, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitCallExpression(@NotNull JetCallExpression expression,
|
||||
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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.reference
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression
|
||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext
|
||||
import org.jetbrains.k2js.translate.utils.JsDescriptorUtils
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor
|
||||
import com.google.dart.compiler.backend.js.ast.JsInvocation
|
||||
import org.jetbrains.jet.lang.descriptors.Visibilities
|
||||
import org.jetbrains.k2js.translate.utils.AnnotationsUtils
|
||||
import org.jetbrains.jet.lang.psi.JetCallableReferenceExpression
|
||||
import org.jetbrains.k2js.translate.utils.BindingUtils
|
||||
import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor
|
||||
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.jet.lang.descriptors.PackageFragmentDescriptor
|
||||
import com.google.dart.compiler.backend.js.ast.JsLiteral
|
||||
import java.util.ArrayList
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils
|
||||
import com.google.dart.compiler.backend.js.ast.JsNameRef
|
||||
import org.jetbrains.k2js.translate.context.Namer
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
|
||||
|
||||
object CallableReferenceTranslator {
|
||||
|
||||
fun translate(expression: JetCallableReferenceExpression, context: TranslationContext): JsExpression {
|
||||
val descriptor = BindingUtils.getDescriptorForReferenceExpression(context.bindingContext(), expression.getCallableReference())
|
||||
return when (descriptor) {
|
||||
is PropertyDescriptor ->
|
||||
translateForProperty(descriptor as PropertyDescriptor, context)
|
||||
is FunctionDescriptor ->
|
||||
translateForFunction(descriptor as FunctionDescriptor, context)
|
||||
else ->
|
||||
throw IllegalArgumentException("Expected property or function: ${descriptor}, expression=${expression.getText()}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateForFunction(descriptor: FunctionDescriptor, context: TranslationContext): JsExpression {
|
||||
return when {
|
||||
// TODO Support for callable reference to builtin functions and members
|
||||
JsDescriptorUtils.isBuiltin(descriptor) ->
|
||||
throw UnsupportedOperationException("callable references for builtin functions are not supported yet")
|
||||
isConstructor(descriptor) ->
|
||||
translateForConstructor(descriptor, context)
|
||||
isExtension(descriptor) ->
|
||||
translateForExtensionFunction(descriptor, context)
|
||||
isMember(descriptor) ->
|
||||
translateForMemberFunction(descriptor, context)
|
||||
else ->
|
||||
ReferenceTranslator.translateAsFQReference(descriptor, context)
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateForProperty(descriptor: PropertyDescriptor, context: TranslationContext): JsExpression {
|
||||
return when {
|
||||
// TODO Support for callable reference to builtin properties
|
||||
JsDescriptorUtils.isBuiltin(descriptor) ->
|
||||
throw UnsupportedOperationException("callable references for builtin properties are not supported yet")
|
||||
isExtension(descriptor) ->
|
||||
translateForExtensionProperty(descriptor, context)
|
||||
isMember(descriptor) ->
|
||||
translateForMemberProperty(descriptor, context)
|
||||
else ->
|
||||
translateForTopLevelProperty(descriptor, context)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isConstructor(descriptor: CallableDescriptor): Boolean = descriptor is ConstructorDescriptor
|
||||
|
||||
private fun isExtension(descriptor: CallableDescriptor): Boolean = JsDescriptorUtils.isExtension(descriptor)
|
||||
|
||||
private fun isMember(descriptor: CallableDescriptor): Boolean = JsDescriptorUtils.getContainingDeclaration(descriptor) is ClassDescriptor
|
||||
|
||||
private fun isVar(descriptor: PropertyDescriptor): JsExpression = if (descriptor.isVar()) JsLiteral.TRUE else JsLiteral.FALSE
|
||||
|
||||
private fun translateForTopLevelProperty(descriptor: PropertyDescriptor, context: TranslationContext): JsExpression {
|
||||
val packageDescriptor = JsDescriptorUtils.getContainingDeclaration(descriptor)
|
||||
assert(packageDescriptor is PackageFragmentDescriptor, "Expected PackageFragmentDescriptor: ${packageDescriptor}")
|
||||
|
||||
val jsPackageNameRef = context.getQualifiedReference(packageDescriptor)
|
||||
val jsPropertyName = context.getNameForDescriptor(descriptor)
|
||||
val jsPropertyNameAsString = context.program().getStringLiteral(jsPropertyName.toString())
|
||||
|
||||
return JsInvocation(context.namer().callableRefForTopLevelPropertyReference(), jsPackageNameRef, jsPropertyNameAsString, isVar(descriptor))
|
||||
}
|
||||
|
||||
private fun translateForMemberProperty(descriptor: PropertyDescriptor, context: TranslationContext): JsExpression {
|
||||
val jsPropertyName = context.getNameForDescriptor(descriptor)
|
||||
val jsPropertyNameAsString = context.program().getStringLiteral(jsPropertyName.toString())
|
||||
return JsInvocation(context.namer().callableRefForMemberPropertyReference(), jsPropertyNameAsString, isVar(descriptor))
|
||||
}
|
||||
|
||||
private fun translateForExtensionProperty(descriptor: PropertyDescriptor, context: TranslationContext): JsExpression {
|
||||
val jsGetterNameRef = context.getQualifiedReference(descriptor.getGetter()!!)
|
||||
val propertyName = descriptor.getName()
|
||||
val jsPropertyNameAsString = context.program().getStringLiteral(propertyName.asString())
|
||||
val argumentList = ArrayList<JsExpression>(3)
|
||||
argumentList.add(jsPropertyNameAsString)
|
||||
argumentList.add(jsGetterNameRef)
|
||||
if (descriptor.isVar()) {
|
||||
val jsSetterNameRef = context.getQualifiedReference(descriptor.getSetter()!!)
|
||||
argumentList.add(jsSetterNameRef)
|
||||
}
|
||||
if (AnnotationsUtils.isNativeObject(descriptor))
|
||||
return translateForMemberProperty(descriptor, context)
|
||||
else
|
||||
return JsInvocation(context.namer().callableRefForExtensionPropertyReference(), argumentList)
|
||||
}
|
||||
|
||||
private fun translateForConstructor(descriptor: FunctionDescriptor, context: TranslationContext): JsExpression {
|
||||
val jsFunctionRef = ReferenceTranslator.translateAsFQReference(descriptor, context)
|
||||
return JsInvocation(context.namer().callableRefForConstructorReference(), jsFunctionRef)
|
||||
}
|
||||
|
||||
private fun translateForExtensionFunction(descriptor: FunctionDescriptor, context: TranslationContext): JsExpression {
|
||||
val receiverParameterDescriptor = descriptor.getReceiverParameter()
|
||||
assert(receiverParameterDescriptor != null, "receiverParameter for extension should not be null")
|
||||
|
||||
val jsFunctionRef = ReferenceTranslator.translateAsFQReference(descriptor, context)
|
||||
if (descriptor.getVisibility() == Visibilities.LOCAL)
|
||||
return jsFunctionRef
|
||||
else if (AnnotationsUtils.isNativeObject(descriptor)) {
|
||||
val jetType = receiverParameterDescriptor!!.getType()
|
||||
val receiverClassDescriptor = DescriptorUtils.getClassDescriptorForType(jetType)
|
||||
return translateAsMemberFunctionReference(descriptor, receiverClassDescriptor, context)
|
||||
}
|
||||
else
|
||||
return JsInvocation(context.namer().callableRefForExtensionFunctionReference(), jsFunctionRef)
|
||||
}
|
||||
|
||||
private fun translateForMemberFunction(descriptor: FunctionDescriptor, context: TranslationContext): JsExpression {
|
||||
val classDescriptor = JsDescriptorUtils.getContainingDeclaration(descriptor) as? ClassDescriptor ?: throw IllegalArgumentException("Expected ClassDescriptor: ${descriptor}")
|
||||
return translateAsMemberFunctionReference(descriptor, classDescriptor, context)
|
||||
}
|
||||
|
||||
private fun translateAsMemberFunctionReference(descriptor: CallableDescriptor, classDescriptor: ClassDescriptor, context: TranslationContext): JsExpression {
|
||||
val jsClassNameRef = context.getQualifiedReference(classDescriptor)
|
||||
val funName = context.getNameForDescriptor(descriptor)
|
||||
val funNameAsString = context.program().getStringLiteral(funName.toString())
|
||||
return JsInvocation(context.namer().callableRefForMemberFunctionReference(), jsClassNameRef, funNameAsString)
|
||||
}
|
||||
}
|
||||
@@ -294,7 +294,60 @@ var Kotlin = {};
|
||||
}
|
||||
};
|
||||
|
||||
// TODO Store callable references for members in class
|
||||
Kotlin.getCallableRefForMemberFunction = function (klass, memberName) {
|
||||
return function () {
|
||||
return this[memberName].apply(this, arguments);
|
||||
};
|
||||
};
|
||||
|
||||
// TODO Store callable references for extension functions in class
|
||||
// extFun expected receiver as the first argument
|
||||
Kotlin.getCallableRefForExtensionFunction = function (extFun) {
|
||||
return function () {
|
||||
var args = [this];
|
||||
Array.prototype.push.apply(args, arguments);
|
||||
return extFun.apply(null, args);
|
||||
};
|
||||
};
|
||||
|
||||
Kotlin.getCallableRefForConstructor = function (klass) {
|
||||
return function () {
|
||||
var obj = Object.create(klass.prototype);
|
||||
klass.apply(obj, arguments);
|
||||
return obj;
|
||||
};
|
||||
};
|
||||
|
||||
Kotlin.getCallableRefForTopLevelProperty = function(packageName, name, isVar) {
|
||||
var obj = {};
|
||||
obj.name = name;
|
||||
obj.get = function() { return packageName[name]; };
|
||||
if (isVar) {
|
||||
obj.set_za3rmp$ = function(value) { packageName[name] = value; };
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
Kotlin.getCallableRefForMemberProperty = function(name, isVar) {
|
||||
var obj = {};
|
||||
obj.name = name;
|
||||
obj.get_za3rmp$ = function(receiver) { return receiver[name]; };
|
||||
if (isVar) {
|
||||
obj.set_wn2jw4$ = function(receiver, value) { receiver[name] = value; };
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
Kotlin.getCallableRefForExtensionProperty = function(name, getFun, setFun) {
|
||||
var obj = {};
|
||||
obj.name = name;
|
||||
obj.get_za3rmp$ = getFun;
|
||||
if (setFun !== undefined) {
|
||||
obj.set_wn2jw4$ = setFun;
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
////////////////////////////////// packages & modules //////////////////////////////
|
||||
|
||||
Kotlin.modules = {};
|
||||
|
||||
Reference in New Issue
Block a user