JS backend: cosmetic changes & remake fakeCall

This commit is contained in:
Erokhin Stanislav
2014-01-29 21:10:03 +04:00
parent f268f69cbf
commit 257d13e90b
4 changed files with 114 additions and 104 deletions
@@ -39,52 +39,53 @@ trait CallInfo {
val thisObject: JsExpression?
val receiverObject: JsExpression?
val nullableReceiverForSafeCall: JsExpression?
val callableDescriptor: CallableDescriptor
get() {
return resolvedCall.getResultingDescriptor().getOriginal()
}
fun isExtension(): Boolean = receiverObject != null
fun isMemberCall(): Boolean = thisObject != null
fun isSafeCall(): Boolean = nullableReceiverForSafeCall != null
fun isNative(): Boolean = AnnotationsUtils.isNativeObject(callableDescriptor)
fun isSuperInvocation() : Boolean {
val thisObject = resolvedCall.getThisObject()
return thisObject is ExpressionReceiver && ((thisObject as ExpressionReceiver)).getExpression() is JetSuperExpression
}
// TODO: toString for debug
}
// if setTo == null, it is get access
class VariableAccessInfo(callInfo: CallInfo, private val setTo: JsExpression? = null): CallInfo by callInfo {
val variableDescriptor = super.callableDescriptor as VariableDescriptor
val variableName : JsName
get() {
return context.getNameForDescriptor(variableDescriptor)
}
// if value == null, it is get access
class VariableAccessInfo(callInfo: CallInfo, val value: JsExpression? = null): CallInfo by callInfo
fun isGetAccess(): Boolean = setTo == null
class FunctionCallInfo(callInfo: CallInfo, val argumentsInfo: CallArgumentTranslator.ArgumentsInfo) : CallInfo by callInfo
fun getSetToExpression(): JsExpression {
if (isGetAccess()) {
throw IllegalStateException("This is get, setTo is null. callInfo: $this")
}
return setTo!!
val CallInfo.callableDescriptor: CallableDescriptor
get() {
return resolvedCall.getResultingDescriptor().getOriginal()
}
fun CallInfo.isExtension(): Boolean {
return receiverObject != null
}
fun CallInfo.isMemberCall(): Boolean {
return thisObject != null
}
fun CallInfo.isSafeCall(): Boolean {
return resolvedCall.isSafeCall()
}
fun CallInfo.isNative(): Boolean {
return AnnotationsUtils.isNativeObject(callableDescriptor)
}
fun CallInfo.isSuperInvocation() : Boolean {
val thisObject = resolvedCall.getThisObject()
return thisObject is ExpressionReceiver && ((thisObject as ExpressionReceiver)).getExpression() is JetSuperExpression
}
class FunctionCallInfo(callInfo: CallInfo, val argumentsInfo: CallArgumentTranslator.ArgumentsInfo) : CallInfo by callInfo {
val functionName : JsName
get() { // getter, because for several descriptors name is undefined. Example: {(a) -> a+1}(3)
return context.getNameForDescriptor(callableDescriptor)
}
fun hasSpreadOperator() : Boolean {
return argumentsInfo.isHasSpreadOperator()
val VariableAccessInfo.variableDescriptor: VariableDescriptor
get() {
return callableDescriptor as VariableDescriptor
}
val VariableAccessInfo.variableName : JsName
get() {
return context.getNameForDescriptor(variableDescriptor)
}
fun VariableAccessInfo.isGetAccess(): Boolean {
return value == null
}
val FunctionCallInfo.functionName : JsName
get() { // getter, because for several descriptors name is undefined. Example: {(a) -> a+1}(3)
return context.getNameForDescriptor(callableDescriptor)
}
fun FunctionCallInfo.hasSpreadOperator() : Boolean {
return argumentsInfo.isHasSpreadOperator()
}
private fun TranslationContext.getThisObject(receiverValue: ReceiverValue): JsExpression {
@@ -92,7 +93,7 @@ private fun TranslationContext.getThisObject(receiverValue: ReceiverValue): JsEx
return getThisObject(getDeclarationDescriptorForReceiver(receiverValue))
}
private fun TranslationContext.mainGetCallInfo(resolvedCall: ResolvedCall<out CallableDescriptor>, receiver1: JsExpression?, receiver2: JsExpression?): CallInfo {
private fun TranslationContext.createCallInfo(resolvedCall: ResolvedCall<out CallableDescriptor>, receiver1: JsExpression?, receiver2: JsExpression?): CallInfo {
val receiverKind = resolvedCall.getExplicitReceiverKind()
fun getNotNullReceiver1(): JsExpression {
assert(receiver1 != null, "ResolvedCall say, that receiver(1) must be not null")
@@ -136,7 +137,7 @@ private fun TranslationContext.mainGetCallInfo(resolvedCall: ResolvedCall<out Ca
}
}
return object : CallInfo {
override val context: TranslationContext = this@mainGetCallInfo
override val context: TranslationContext = this@createCallInfo
override val resolvedCall: ResolvedCall<out CallableDescriptor> = resolvedCall
override val thisObject: JsExpression? = getThisObject()
override val receiverObject: JsExpression? = getReceiverObject()
@@ -144,12 +145,8 @@ private fun TranslationContext.mainGetCallInfo(resolvedCall: ResolvedCall<out Ca
};
}
fun ResolvedCall<out CallableDescriptor>.expectedReceivers(): Boolean {
return this.getExplicitReceiverKind() != NO_EXPLICIT_RECEIVER
}
fun TranslationContext.getCallInfo(resolvedCall: ResolvedCall<out CallableDescriptor>, receiver: JsExpression?): CallInfo {
return mainGetCallInfo(resolvedCall, receiver, null)
return createCallInfo(resolvedCall, receiver, null)
}
fun TranslationContext.getCallInfo(resolvedCall: ResolvedCall<out FunctionDescriptor>, receiver: JsExpression?): FunctionCallInfo {
@@ -158,7 +155,7 @@ fun TranslationContext.getCallInfo(resolvedCall: ResolvedCall<out FunctionDescri
// two receiver need only for FunctionCall in VariableAsFunctionResolvedCall
fun TranslationContext.getCallInfo(resolvedCall: ResolvedCall<out FunctionDescriptor>, receiver1: JsExpression?, receiver2: JsExpression?): FunctionCallInfo {
val callInfo = mainGetCallInfo(resolvedCall, receiver1, receiver2)
val callInfo = createCallInfo(resolvedCall, receiver1, receiver2)
val receiverForArgsTranslator = if (resolvedCall.getExplicitReceiverKind() == BOTH_RECEIVERS) // TODO: remove this hack
receiver2
@@ -30,39 +30,40 @@ import com.google.dart.compiler.backend.js.ast.JsNameRef
import org.jetbrains.k2js.translate.utils.JsAstUtils
import org.jetbrains.k2js.translate.context.Namer
import org.jetbrains.k2js.translate.utils.ErrorReportingUtils
import org.jetbrains.k2js.translate.utils.AnnotationsUtils
val functionCallCases: CallCaseDispatcher<FunctionCallCase, FunctionCallInfo> = createFunctionCases()
val variableAccessCases: CallCaseDispatcher<VariableAccessCase, VariableAccessInfo> = createVariableAccessCases()
fun TranslationContext.buildCall(resolvedCall: ResolvedCall<out FunctionDescriptor>, receiver: JsExpression? = null): JsExpression {
return buildCall(resolvedCall, receiver, null)
fun TranslationContext.buildCall(resolvedCall: ResolvedCall<out FunctionDescriptor>, receiverOrThisObject: JsExpression? = null): JsExpression {
return buildCall(resolvedCall, receiverOrThisObject, null)
}
fun TranslationContext.buildGet(resolvedCall: ResolvedCall<out VariableDescriptor>, receiver: JsExpression? = null): JsExpression {
val variableAccessInfo = VariableAccessInfo(getCallInfo(resolvedCall, receiver), null);
fun TranslationContext.buildGet(resolvedCall: ResolvedCall<out VariableDescriptor>, receiverOrThisObject: JsExpression? = null): JsExpression {
val variableAccessInfo = VariableAccessInfo(getCallInfo(resolvedCall, receiverOrThisObject), null);
return variableAccessCases.translate(variableAccessInfo)
}
fun TranslationContext.buildSet(resolvedCall: ResolvedCall<out VariableDescriptor>, setTo: JsExpression, receiver: JsExpression? = null): JsExpression {
val variableAccessInfo = VariableAccessInfo(getCallInfo(resolvedCall, receiver), setTo);
fun TranslationContext.buildSet(resolvedCall: ResolvedCall<out VariableDescriptor>, value: JsExpression, receiverOrThisObject: JsExpression? = null): JsExpression {
val variableAccessInfo = VariableAccessInfo(getCallInfo(resolvedCall, receiverOrThisObject), value);
return variableAccessCases.translate(variableAccessInfo)
}
fun TranslationContext.buildFakeCall(functionDescriptor: FunctionDescriptor, args: List<JsExpression>, thisObject: JsExpression?): JsExpression {
val fakeCallInfo = object: CallInfo {
override val context: TranslationContext = this@buildFakeCall
override val resolvedCall: ResolvedCall<out CallableDescriptor>
get() {
throw UnsupportedOperationException("Resolved call for direct call unsupported")
}
override val callableDescriptor: CallableDescriptor = functionDescriptor
override val thisObject: JsExpression? = thisObject
override val receiverObject: JsExpression? = null
override val nullableReceiverForSafeCall: JsExpression? = null
val argumentsInfo = CallArgumentTranslator.ArgumentsInfo(args, false, null);
val functionName = getNameForDescriptor(functionDescriptor)
val isNative = AnnotationsUtils.isNativeObject(functionDescriptor)
val hasSpreadOperator = false
if (thisObject != null) {
return DefaultCallCase.buildDefaultCallWithThisObject(argumentsInfo, thisObject, functionName, isNative, hasSpreadOperator)
} else {
return DefaultCallCase.buildDefaultCallWithoutReceiver(this, argumentsInfo, functionDescriptor, functionName, isNative, hasSpreadOperator)
}
val fakeFunctionInfo = FunctionCallInfo(fakeCallInfo, CallArgumentTranslator.ArgumentsInfo(args, false, null));
return DefaultCallCase(fakeFunctionInfo).translate()
}
fun ResolvedCall<out CallableDescriptor>.expectedReceivers(): Boolean {
return this.getExplicitReceiverKind() != NO_EXPLICIT_RECEIVER
}
private fun TranslationContext.buildCall(resolvedCall: ResolvedCall<out FunctionDescriptor>, receiver1: JsExpression?, receiver2: JsExpression?): JsExpression {
@@ -151,7 +152,7 @@ open class VariableAccessCase(override val callInfo: VariableAccessInfo) : CallC
if (isGetAccess()) {
return ref
} else {
return JsAstUtils.assignment(ref, getSetToExpression())
return JsAstUtils.assignment(ref, value!!)
}
}
}
@@ -34,6 +34,7 @@ import org.jetbrains.k2js.translate.general.Translation
import org.jetbrains.k2js.translate.utils.PsiUtils
import com.google.dart.compiler.backend.js.ast.JsLiteral
import com.google.dart.compiler.backend.js.ast.JsName
import org.jetbrains.k2js.translate.context.TranslationContext
public fun addReceiverToArgs(receiver: JsExpression, arguments: List<JsExpression>) : List<JsExpression> {
if (arguments.isEmpty())
@@ -47,26 +48,52 @@ public fun addReceiverToArgs(receiver: JsExpression, arguments: List<JsExpressio
// call may be native and|or with spreadOperator
class DefaultCallCase(callInfo: FunctionCallInfo): FunctionCallCase(callInfo) { //TODO: check spreadOperator
class DefaultCallCase(callInfo: FunctionCallInfo): FunctionCallCase(callInfo) {
class object {
// TODO: refactor after fix ArgumentsInfo - duplicate code
private fun nativeSpreadFunWithThisObjectOrReceiver(argumentsInfo: CallArgumentTranslator.ArgumentsInfo, functionName: JsName): JsExpression {
val cachedReceiver = argumentsInfo.getCachedReceiver()!!
val functionCallRef = Namer.getFunctionApplyRef(JsNameRef(functionName, cachedReceiver.assignmentExpression()))
return JsInvocation(functionCallRef, argumentsInfo.getTranslateArguments())
}
override fun FunctionCallInfo.bothReceivers(): JsExpression { // TODO: think about crazy case: spreadOperator + native
val functionRef = JsNameRef(functionName, thisObject!!)
return JsInvocation(functionRef, addReceiverToArgs(receiverObject!!, argumentsInfo.getTranslateArguments()))
fun buildDefaultCallWithThisObject(argumentsInfo: CallArgumentTranslator.ArgumentsInfo,
thisObject: JsExpression,
functionName: JsName,
isNative: Boolean,
hasSpreadOperator: Boolean): JsExpression {
if (isNative && hasSpreadOperator) {
return nativeSpreadFunWithThisObjectOrReceiver(argumentsInfo, functionName)
}
val functionRef = JsNameRef(functionName, thisObject)
return JsInvocation(functionRef, argumentsInfo.getTranslateArguments())
}
fun buildDefaultCallWithoutReceiver(context: TranslationContext,
argumentsInfo: CallArgumentTranslator.ArgumentsInfo,
callableDescriptor: CallableDescriptor,
functionName: JsName,
isNative: Boolean,
hasSpreadOperator: Boolean): JsExpression {
if (isNative && hasSpreadOperator) {
val functionCallRef = Namer.getFunctionApplyRef(JsNameRef(functionName))
return JsInvocation(functionCallRef, argumentsInfo.getTranslateArguments())
}
if (isNative) {
return JsInvocation(JsNameRef(functionName), argumentsInfo.getTranslateArguments())
}
val qualifierForFunction = context.getQualifierForDescriptor(callableDescriptor)
val functionCall = JsNameRef(functionName, qualifierForFunction)
return JsInvocation(functionCall, argumentsInfo.getTranslateArguments())
}
}
// TODO: refactor after fix ArgumentsInfo - duplicate code
private fun nativeSpreadFunWithThisObjectOrReceiver(argumentsInfo: CallArgumentTranslator.ArgumentsInfo, functionName: JsName): JsExpression {
val cachedReceiver = argumentsInfo.getCachedReceiver()!!
val functionCallRef = Namer.getFunctionApplyRef(JsNameRef(functionName, cachedReceiver.assignmentExpression()))
return JsInvocation(functionCallRef, argumentsInfo.getTranslateArguments())
override fun FunctionCallInfo.noReceivers(): JsExpression {
return buildDefaultCallWithoutReceiver(context, argumentsInfo, callableDescriptor, functionName, isNative(), hasSpreadOperator())
}
override fun FunctionCallInfo.thisObject(): JsExpression {
if (isNative() && hasSpreadOperator()) {
return nativeSpreadFunWithThisObjectOrReceiver(argumentsInfo, functionName)
}
val functionRef = JsNameRef(functionName, thisObject!!)
return JsInvocation(functionRef, argumentsInfo.getTranslateArguments())
return buildDefaultCallWithThisObject(argumentsInfo, thisObject!!, functionName, isNative(), hasSpreadOperator())
}
override fun FunctionCallInfo.receiverArgument(): JsExpression {
@@ -80,17 +107,10 @@ class DefaultCallCase(callInfo: FunctionCallInfo): FunctionCallCase(callInfo) {
val functionCall = JsNameRef(functionName, qualifierForFunction) // TODO: remake to call
return JsInvocation(functionCall, addReceiverToArgs(receiverObject!!, argumentsInfo.getTranslateArguments()))
}
override fun FunctionCallInfo.noReceivers(): JsExpression {
if (isNative() && hasSpreadOperator()) {
val functionCallRef = Namer.getFunctionApplyRef(JsNameRef(functionName))
return JsInvocation(functionCallRef, argumentsInfo.getTranslateArguments())
}
if (isNative()) {
return JsInvocation(JsNameRef(functionName), argumentsInfo.getTranslateArguments())
}
val qualifierForFunction = context.getQualifierForDescriptor(callableDescriptor)
val functionCall = JsNameRef(functionName, qualifierForFunction)
return JsInvocation(functionCall, argumentsInfo.getTranslateArguments())
override fun FunctionCallInfo.bothReceivers(): JsExpression { // TODO: think about crazy case: spreadOperator + native
val functionRef = JsNameRef(functionName, thisObject!!)
return JsInvocation(functionRef, addReceiverToArgs(receiverObject!!, argumentsInfo.getTranslateArguments()))
}
}
@@ -59,7 +59,7 @@ class DefaultVariableAccessCase(callInfo: VariableAccessInfo) : VariableAccessCa
return if (isGetAccess()) {
JsInvocation(funRef, receiverObject!!)
} else {
JsInvocation(funRef, receiverObject!!, getSetToExpression())
JsInvocation(funRef, receiverObject!!, value!!)
}
}
@@ -68,18 +68,11 @@ class DefaultVariableAccessCase(callInfo: VariableAccessInfo) : VariableAccessCa
return if (isGetAccess()) {
JsInvocation(funRef, receiverObject!!)
} else {
JsInvocation(funRef, receiverObject!!, getSetToExpression())
JsInvocation(funRef, receiverObject!!, value!!)
}
}
}
class ValueParameterAccessCase(callInfo: VariableAccessInfo) : VariableAccessCase(callInfo) {
override fun VariableAccessInfo.noReceivers(): JsExpression {
assert(isGetAccess(), "It must be get access. CallInfo: $callInfo")
return variableName.makeRef()!!
}
}
class DelegatePropertyAccessIntrinsic(callInfo: VariableAccessInfo) : VariableAccessCase(callInfo), DelegateIntrinsic<VariableAccessInfo> {
override fun VariableAccessInfo.canBeApply(): Boolean {
return variableDescriptor is PropertyDescriptor
@@ -89,7 +82,7 @@ class DelegatePropertyAccessIntrinsic(callInfo: VariableAccessInfo) : VariableAc
return if (isGetAccess())
Collections.emptyList<JsExpression>()
else
Collections.singletonList(getSetToExpression())
Collections.singletonList(value!!)
}
override fun VariableAccessInfo.getDescriptor(): CallableDescriptor {
@@ -97,7 +90,7 @@ class DelegatePropertyAccessIntrinsic(callInfo: VariableAccessInfo) : VariableAc
return if (isGetAccess()) {
var getter = propertyDescriptor.getGetter()
if (getter == null) {
val getterImpl = DescriptorFactory.createDefaultGetter(variableDescriptor)
val getterImpl = DescriptorFactory.createDefaultGetter(propertyDescriptor)
getterImpl.initialize(propertyDescriptor.getType())
((propertyDescriptor as PropertyDescriptorImpl)).initialize(getterImpl, propertyDescriptor.getSetter())
getter = getterImpl
@@ -106,7 +99,7 @@ class DelegatePropertyAccessIntrinsic(callInfo: VariableAccessInfo) : VariableAc
} else {
var setter = propertyDescriptor.getSetter()
if (setter == null) {
val setterImpl = DescriptorFactory.createDefaultSetter(variableDescriptor)
val setterImpl = DescriptorFactory.createDefaultSetter(propertyDescriptor)
((propertyDescriptor as PropertyDescriptorImpl)).initialize(propertyDescriptor.getGetter(), setterImpl)
setter = setterImpl
}
@@ -121,7 +114,7 @@ class SuperPropertyAccessCase(callInfo: VariableAccessInfo) : VariableAccessCase
return if (isGetAccess())
JsInvocation(context.namer().getCallGetProperty(), JsLiteral.THIS, thisObject!!, variableName)
else
JsInvocation(context.namer().getCallSetProperty(), JsLiteral.THIS, thisObject!!, variableName, getSetToExpression())
JsInvocation(context.namer().getCallSetProperty(), JsLiteral.THIS, thisObject!!, variableName, value!!)
}
}
@@ -130,7 +123,6 @@ fun createVariableAccessCases(): CallCaseDispatcher<VariableAccessCase, Variable
caseDispatcher.addCase { DelegatePropertyAccessIntrinsic(it).intrinsic() }
caseDispatcher.addCase(::SuperPropertyAccessCase) { it.isSuperInvocation() }
//caseDispatcher.addCase(::ValueParameterAccessCase) { it.variableDescriptor is ValueParameterDescriptor}
caseDispatcher.addCase(::NativeVariableAccessCase) { it.isNative() }
caseDispatcher.addCase(::DefaultVariableAccessCase) { true } // TODO: fix this
return caseDispatcher