diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallInfo.kt b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallInfo.kt index 6d23ea76d32..fef2a7e51dc 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallInfo.kt +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallInfo.kt @@ -31,6 +31,9 @@ import org.jetbrains.jet.lang.descriptors.PropertyDescriptor import org.jetbrains.jet.lang.descriptors.VariableDescriptor import com.google.dart.compiler.backend.js.ast.JsName import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils +import com.google.dart.compiler.backend.js.ast.JsNameRef +import org.jetbrains.k2js.translate.utils.JsAstUtils +import org.jetbrains.k2js.translate.context.Namer trait CallInfo { @@ -48,7 +51,7 @@ trait CallInfo { } // if value == null, it is get access -class VariableAccessInfo(callInfo: CallInfo, val value: JsExpression? = null): CallInfo by callInfo +class VariableAccessInfo(callInfo: CallInfo, val value: JsExpression? = null) : CallInfo by callInfo class FunctionCallInfo(callInfo: CallInfo, val argumentsInfo: CallArgumentTranslator.ArgumentsInfo) : CallInfo by callInfo @@ -60,12 +63,12 @@ class FunctionCallInfo(callInfo: CallInfo, val argumentsInfo: CallArgumentTransl */ class ExplicitReceivers(val receiverOrThisObject: JsExpression?, val receiverObject: JsExpression? = null) -fun TranslationContext.getCallInfo(resolvedCall: ResolvedCall, receiver: JsExpression?): CallInfo { - return createCallInfo(resolvedCall, ExplicitReceivers(receiver)) +fun TranslationContext.getCallInfo(resolvedCall: ResolvedCall, receiverOrThisObject: JsExpression?): CallInfo { + return createCallInfo(resolvedCall, ExplicitReceivers(receiverOrThisObject)) } -fun TranslationContext.getCallInfo(resolvedCall: ResolvedCall, receiver: JsExpression?): FunctionCallInfo { - return getCallInfo(resolvedCall, ExplicitReceivers(receiver)); +fun TranslationContext.getCallInfo(resolvedCall: ResolvedCall, receiverOrThisObject: JsExpression?): FunctionCallInfo { + return getCallInfo(resolvedCall, ExplicitReceivers(receiverOrThisObject)); } // two receiver need only for FunctionCall in VariableAsFunctionResolvedCall @@ -75,24 +78,20 @@ fun TranslationContext.getCallInfo(resolvedCall: ResolvedCall explicitReceivers.receiverObject - else -> explicitReceivers.receiverOrThisObject - } - } return object : CallInfo { override val context: TranslationContext = this@createCallInfo override val resolvedCall: ResolvedCall = resolvedCall diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.kt b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.kt index bf2f2f2d5a1..005abfbc7ab 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.kt +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.kt @@ -34,21 +34,18 @@ import org.jetbrains.k2js.translate.utils.AnnotationsUtils import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils -val functionCallCases: CallCaseDispatcher = createFunctionCases() -val variableAccessCases: CallCaseDispatcher = createVariableAccessCases() - fun TranslationContext.buildCall(resolvedCall: ResolvedCall, receiverOrThisObject: JsExpression? = null): JsExpression { return buildCall(resolvedCall, ExplicitReceivers(receiverOrThisObject)) } fun TranslationContext.buildGet(resolvedCall: ResolvedCall, receiverOrThisObject: JsExpression? = null): JsExpression { val variableAccessInfo = VariableAccessInfo(getCallInfo(resolvedCall, receiverOrThisObject), null); - return variableAccessCases.translate(variableAccessInfo) + return variableAccessInfo.translateVariableAccess() } fun TranslationContext.buildSet(resolvedCall: ResolvedCall, value: JsExpression, receiverOrThisObject: JsExpression? = null): JsExpression { val variableAccessInfo = VariableAccessInfo(getCallInfo(resolvedCall, receiverOrThisObject), value); - return variableAccessCases.translate(variableAccessInfo) + return variableAccessInfo.translateVariableAccess() } fun TranslationContext.buildFakeCall(functionDescriptor: FunctionDescriptor, args: List, thisObject: JsExpression?): JsExpression { @@ -57,13 +54,13 @@ fun TranslationContext.buildFakeCall(functionDescriptor: FunctionDescriptor, arg val isNative = AnnotationsUtils.isNativeObject(functionDescriptor) val hasSpreadOperator = false if (thisObject != null) { - return DefaultCallCase.buildDefaultCallWithThisObject(argumentsInfo, thisObject, functionName, isNative, hasSpreadOperator) + return DefaultFunctionCallCase.buildDefaultCallWithThisObject(argumentsInfo, thisObject, functionName, isNative, hasSpreadOperator) } else { - return DefaultCallCase.buildDefaultCallWithoutReceiver(this, argumentsInfo, functionDescriptor, functionName, isNative, hasSpreadOperator) + return DefaultFunctionCallCase.buildDefaultCallWithoutReceiver(this, argumentsInfo, functionDescriptor, functionName, isNative, hasSpreadOperator) } } -fun ResolvedCall.expectedReceivers(): Boolean { +private fun ResolvedCall.expectedReceivers(): Boolean { return this.getExplicitReceiverKind() != NO_EXPLICIT_RECEIVER } @@ -84,34 +81,23 @@ private fun TranslationContext.buildCall(resolvedCall: ResolvedCall { - val callInfo: I - protected fun unsupported(message: String = "") : Nothing { - throw UnsupportedOperationException("this case unsopported. $callInfo") - } + protected fun I.unsupported(message: String = "") : Nothing = throw UnsupportedOperationException("this case unsopported. $this") - protected fun I.noReceivers(): JsExpression { - unsupported() - } + protected fun I.noReceivers(): JsExpression = unsupported() - protected fun I.thisObject(): JsExpression { - unsupported() - } + protected fun I.thisObject(): JsExpression = unsupported() - protected fun I.receiverArgument(): JsExpression { - unsupported() - } + protected fun I.receiverArgument(): JsExpression = unsupported() - protected fun I.bothReceivers(): JsExpression { - unsupported() - } + protected fun I.bothReceivers(): JsExpression = unsupported() - final fun translate(): JsExpression { + final fun translate(callInfo: I): JsExpression { val result = if (callInfo.thisObject == null) { if (callInfo.receiverObject == null) callInfo.noReceivers() @@ -128,62 +114,23 @@ trait CallCase { } } -open class FunctionCallCase(override val callInfo: FunctionCallInfo) : CallCase +trait FunctionCallCase : CallCase -open class VariableAccessCase(override val callInfo: VariableAccessInfo) : CallCase { - protected fun VariableAccessInfo.getAccessFunctionName(): String { - return Namer.getNameForAccessor(variableName.getIdent()!!, isGetAccess(), false) - } +trait VariableAccessCase : CallCase - protected fun VariableAccessInfo.constructAccessExpression(ref: JsNameRef): JsExpression { - if (isGetAccess()) { - return ref - } else { - return JsAstUtils.assignment(ref, value!!) - } - } -} - -class CallCaseDispatcher, I : CallInfo> { - private val cases: MutableList<(I) -> JsExpression?> = ArrayList() - - fun addCase(canBeApplyCase: (I) -> JsExpression?) { - cases.add(canBeApplyCase) - } - - fun addCase(caseConstructor: (I) -> C, canApply: (I) -> Boolean) { - cases.add({ - if (canApply(it)) - caseConstructor(it).translate() - else - null - }) - } - - fun translate(callInfo: I): JsExpression { - for (case in cases) { - val result = case(callInfo) - if (result != null) - return result - } - throw UnsupportedOperationException("This case of call unsopported. CallInfo: $callInfo") - } -} - -trait DelegateIntrinsic : CallCase { +trait DelegateIntrinsic { fun I.canBeApply(): Boolean = true - fun I.getReceiver(): JsExpression? { - return when (resolvedCall.getExplicitReceiverKind()) { - THIS_OBJECT -> thisObject - RECEIVER_ARGUMENT, BOTH_RECEIVERS -> receiverObject - else -> null - } - } - fun I.getDescriptor(): CallableDescriptor fun I.getArgs(): List - fun I.intrinsic(): JsExpression? { + fun intrinsic(callInfo: I): JsExpression? { + return if (callInfo.canBeApply()) + callInfo.getIntrinsic() + else + null + } + + private fun I.getIntrinsic(): JsExpression? { val descriptor = getDescriptor(); // Now intrinsic support only FunctionDescriptor. See DelegatePropertyAccessIntrinsic.getDescriptor() @@ -195,11 +142,4 @@ trait DelegateIntrinsic : CallCase { } return null } - - fun intrinsic(): JsExpression? { - return if (callInfo.canBeApply()) - callInfo.intrinsic() - else - null - } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/FunctionCallCases.kt b/js/js.translator/src/org/jetbrains/k2js/translate/reference/FunctionCallCases.kt index ae819f21025..bebf2b5903e 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/FunctionCallCases.kt +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/FunctionCallCases.kt @@ -48,44 +48,42 @@ public fun addReceiverToArgs(receiver: JsExpression, arguments: List { +object DelegateFunctionIntrinsic : DelegateIntrinsic { override fun FunctionCallInfo.getArgs(): List { return argumentsInfo.getTranslateArguments() } @@ -124,18 +122,16 @@ class DelegateFunctionIntrinsic(callInfo: FunctionCallInfo) : FunctionCallCase(c } } -class InvokeIntrinsic(callInfo: FunctionCallInfo) : FunctionCallCase(callInfo) { - class object { - fun canApply(callInfo: FunctionCallInfo): Boolean { - if (!callInfo.callableDescriptor.getName().asString().equals("invoke")) - return false - val parameterCount = callInfo.callableDescriptor.getValueParameters().size() - val funDeclaration = callInfo.callableDescriptor.getContainingDeclaration() - return funDeclaration == ((if (callInfo.callableDescriptor.getReceiverParameter() == null) - KotlinBuiltIns.getInstance().getFunction(parameterCount) - else - KotlinBuiltIns.getInstance().getExtensionFunction(parameterCount))) - } +object InvokeIntrinsic : FunctionCallCase { + fun canApply(callInfo: FunctionCallInfo): Boolean { + if (!callInfo.callableDescriptor.getName().asString().equals("invoke")) + return false + val parameterCount = callInfo.callableDescriptor.getValueParameters().size() + val funDeclaration = callInfo.callableDescriptor.getContainingDeclaration() + return funDeclaration == ((if (callInfo.callableDescriptor.getReceiverParameter() == null) + KotlinBuiltIns.getInstance().getFunction(parameterCount) + else + KotlinBuiltIns.getInstance().getExtensionFunction(parameterCount))) } override fun FunctionCallInfo.thisObject(): JsExpression { @@ -146,7 +142,11 @@ class InvokeIntrinsic(callInfo: FunctionCallInfo) : FunctionCallCase(callInfo) { } } -class ConstructorCallCase(callInfo: FunctionCallInfo) : FunctionCallCase(callInfo) { +object ConstructorCallCase : FunctionCallCase { + fun canApply(callInfo: FunctionCallInfo): Boolean { + return callInfo.callableDescriptor is ConstructorDescriptor + } + override fun FunctionCallInfo.noReceivers(): JsExpression { if (isNative()) { return JsNew(JsNameRef(functionName), argumentsInfo.getTranslateArguments()) @@ -155,16 +155,14 @@ class ConstructorCallCase(callInfo: FunctionCallInfo) : FunctionCallCase(callInf } } -class ExpressionAsFunctionDescriptorIntrinsic(callInfo: FunctionCallInfo) : FunctionCallCase(callInfo) { - class object { - fun canApply(callInfo: FunctionCallInfo): Boolean { - return callInfo.callableDescriptor is ExpressionAsFunctionDescriptor - } +object ExpressionAsFunctionDescriptorIntrinsic : FunctionCallCase { + fun canApply(callInfo: FunctionCallInfo): Boolean { + return callInfo.callableDescriptor is ExpressionAsFunctionDescriptor } override fun FunctionCallInfo.noReceivers(): JsExpression { if (callableDescriptor !is ExpressionAsFunctionDescriptor) { - throw IllegalStateException("callableDescriptor must be ExpressionAsFunctionDescriptor $callInfo") + throw IllegalStateException("callableDescriptor must be ExpressionAsFunctionDescriptor $this") } val funRef = Translation.translateAsExpression((callableDescriptor as ExpressionAsFunctionDescriptor).getExpression()!!, context) return JsInvocation(funRef, argumentsInfo.getTranslateArguments()) @@ -172,11 +170,9 @@ class ExpressionAsFunctionDescriptorIntrinsic(callInfo: FunctionCallInfo) : Func } } -class SuperCallCase(callInfo: FunctionCallInfo) : FunctionCallCase(callInfo) { - class object { - fun canApply(callInfo: FunctionCallInfo): Boolean { - return callInfo.isSuperInvocation() - } +object SuperCallCase : FunctionCallCase { + fun canApply(callInfo: FunctionCallInfo): Boolean { + return callInfo.isSuperInvocation() } override fun FunctionCallInfo.thisObject(): JsExpression { // TODO: spread operator @@ -186,17 +182,21 @@ class SuperCallCase(callInfo: FunctionCallInfo) : FunctionCallCase(callInfo) { } } -fun createFunctionCases(): CallCaseDispatcher { - val caseDispatcher = CallCaseDispatcher() +fun FunctionCallInfo.translateFunctionCall(): JsExpression { + val intrinsic = DelegateFunctionIntrinsic.intrinsic(this) - caseDispatcher.addCase(::ExpressionAsFunctionDescriptorIntrinsic) {ExpressionAsFunctionDescriptorIntrinsic.canApply(it)} - caseDispatcher.addCase(::InvokeIntrinsic) {InvokeIntrinsic.canApply(it)} - - caseDispatcher.addCase { DelegateFunctionIntrinsic(it).intrinsic() } - - caseDispatcher.addCase(::ConstructorCallCase) {it.callableDescriptor is ConstructorDescriptor} - caseDispatcher.addCase(::SuperCallCase) {SuperCallCase.canApply(it)} - - caseDispatcher.addCase(::DefaultCallCase) { true } // TODO: fix this - return caseDispatcher + return when { + intrinsic != null -> + intrinsic + ExpressionAsFunctionDescriptorIntrinsic.canApply(this) -> + ExpressionAsFunctionDescriptorIntrinsic.translate(this) + InvokeIntrinsic.canApply(this) -> + InvokeIntrinsic.translate(this) + ConstructorCallCase.canApply(this) -> + ConstructorCallCase.translate(this) + SuperCallCase.canApply(this) -> + SuperCallCase.translate(this) + else -> + DefaultFunctionCallCase.translate(this) + } } \ No newline at end of file diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/VarialbeCallCases.kt b/js/js.translator/src/org/jetbrains/k2js/translate/reference/VarialbeCallCases.kt index a78f480506a..8c7ea1c32f1 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/VarialbeCallCases.kt +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/VarialbeCallCases.kt @@ -29,8 +29,7 @@ import org.jetbrains.jet.lang.resolve.DescriptorFactory import org.jetbrains.jet.lang.descriptors.PropertyDescriptor -class NativeVariableAccessCase(callInfo: VariableAccessInfo) : VariableAccessCase(callInfo) { - +object NativeVariableAccessCase : VariableAccessCase { override fun VariableAccessInfo.receiverArgument(): JsExpression { return constructAccessExpression(JsNameRef(variableName, receiverObject!!)) } @@ -44,8 +43,7 @@ class NativeVariableAccessCase(callInfo: VariableAccessInfo) : VariableAccessCas } } -class DefaultVariableAccessCase(callInfo: VariableAccessInfo) : VariableAccessCase(callInfo) { - +object DefaultVariableAccessCase : VariableAccessCase { override fun VariableAccessInfo.noReceivers(): JsExpression { return constructAccessExpression(context.getQualifiedReference(variableDescriptor)) } @@ -73,7 +71,7 @@ class DefaultVariableAccessCase(callInfo: VariableAccessInfo) : VariableAccessCa } } -class DelegatePropertyAccessIntrinsic(callInfo: VariableAccessInfo) : VariableAccessCase(callInfo), DelegateIntrinsic { +object DelegatePropertyAccessIntrinsic : DelegateIntrinsic { override fun VariableAccessInfo.canBeApply(): Boolean { if(variableDescriptor is PropertyDescriptor) { return isGetAccess() || (variableDescriptor as PropertyDescriptor).isVar() @@ -98,7 +96,7 @@ class DelegatePropertyAccessIntrinsic(callInfo: VariableAccessInfo) : VariableAc } } -class SuperPropertyAccessCase(callInfo: VariableAccessInfo) : VariableAccessCase(callInfo) { +object SuperPropertyAccessCase : VariableAccessCase { override fun VariableAccessInfo.thisObject(): JsExpression { val variableName = context.program().getStringLiteral(this.variableName.getIdent()) return if (isGetAccess()) @@ -108,12 +106,17 @@ class SuperPropertyAccessCase(callInfo: VariableAccessInfo) : VariableAccessCase } } -fun createVariableAccessCases(): CallCaseDispatcher { - val caseDispatcher = CallCaseDispatcher() +fun VariableAccessInfo.translateVariableAccess(): JsExpression { + val intrinsic = DelegatePropertyAccessIntrinsic.intrinsic(this) - caseDispatcher.addCase { DelegatePropertyAccessIntrinsic(it).intrinsic() } - caseDispatcher.addCase(::SuperPropertyAccessCase) { it.isSuperInvocation() } - caseDispatcher.addCase(::NativeVariableAccessCase) { it.isNative() } - caseDispatcher.addCase(::DefaultVariableAccessCase) { true } // TODO: fix this - return caseDispatcher + return when { + intrinsic != null -> + intrinsic + isSuperInvocation() -> + SuperPropertyAccessCase.translate(this) + isNative() -> + NativeVariableAccessCase.translate(this) + else -> + DefaultVariableAccessCase.translate(this) + } }