diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/PropertyTranslator.kt b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/PropertyTranslator.kt index 249d77cd408..d0388fb15fe 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/PropertyTranslator.kt +++ b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/PropertyTranslator.kt @@ -28,8 +28,11 @@ import org.jetbrains.k2js.translate.general.AbstractTranslator import org.jetbrains.k2js.translate.general.Translation import org.jetbrains.k2js.translate.utils.JsDescriptorUtils -import org.jetbrains.k2js.translate.context.Namer.getDelegateNameRef +import org.jetbrains.k2js.translate.context.Namer.* +import org.jetbrains.k2js.translate.utils.ast.* import org.jetbrains.k2js.translate.utils.TranslationUtils.* +import org.jetbrains.k2js.translate.utils.JsDescriptorUtils.isExtension +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall /** * Translates single property /w accessors. @@ -113,12 +116,36 @@ private class PropertyTranslator( private fun generateDefaultGetterFunction(getterDescriptor: PropertyGetterDescriptor): JsFunction { val delegatedCall = bindingContext().get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, getterDescriptor) - val value = if (delegatedCall != null) - CallTranslator.translate(context(), delegatedCall, getDelegateNameRef(propertyName)) - else - backingFieldReference(context(), this.descriptor) + if (delegatedCall != null) { + return generateDelegatedGetterFunction(getterDescriptor, delegatedCall) + } - return simpleReturnFunction(context().getScopeForDescriptor(getterDescriptor.getContainingDeclaration()), value) + val scope = context().getScopeForDescriptor(getterDescriptor.getContainingDeclaration()) + val result = backingFieldReference(context(), descriptor) + val body = JsBlock(JsReturn(result)) + + return JsFunction(scope, body, accessorDescription(getterDescriptor)) + } + + private fun generateDelegatedGetterFunction( + getterDescriptor: PropertyGetterDescriptor, + delegatedCall: ResolvedCall + ): JsFunction { + val scope = context().getScopeForDescriptor(getterDescriptor.getContainingDeclaration()) + val function = JsFunction(scope, JsBlock(), accessorDescription(getterDescriptor)) + + val delegateRef = getDelegateNameRef(propertyName) + val delegatedJsCall = CallTranslator.translate(context(), delegatedCall, delegateRef) + + if (isExtension(getterDescriptor)) { + val receiver = function.addParameter(getReceiverParameterName()).getName() + val arguments = (delegatedJsCall as JsInvocation).getArguments() + arguments.set(0, receiver.makeRef()) + } + + val returnResult = JsReturn(delegatedJsCall) + function.addStatement(returnResult) + return function } private fun generateDefaultSetter(): JsPropertyInitializer { @@ -127,25 +154,29 @@ private class PropertyTranslator( } private fun generateDefaultSetterFunction(setterDescriptor: PropertySetterDescriptor): JsFunction { - val jsFunction = JsFunction(context().getScopeForDescriptor(setterDescriptor.getContainingDeclaration()), - "setter for " + setterDescriptor.getName().asString()) + val containingScope = context().getScopeForDescriptor(setterDescriptor.getContainingDeclaration()) + val function = JsFunction(containingScope, JsBlock(), accessorDescription(setterDescriptor)) assert(setterDescriptor.getValueParameters().size() == 1, "Setter must have 1 parameter") - val valueParameterDescriptor = setterDescriptor.getValueParameters().get(0) - val defaultParameter = JsParameter(jsFunction.getScope().declareTemporary()) - val defaultParameterRef = defaultParameter.getName().makeRef() - val contextWithAliased = context().innerContextWithAliased(valueParameterDescriptor, defaultParameterRef) + val correspondingPropertyName = setterDescriptor.getCorrespondingProperty().getName().asString() + val valueParameter = function.addParameter(correspondingPropertyName).getName() + val withAliased = context().innerContextWithAliased(setterDescriptor.getValueParameters().get(0), valueParameter.makeRef()) + val delegatedCall = context().bindingContext().get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, setterDescriptor) - val delegatedCall = bindingContext().get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, setterDescriptor) + if (delegatedCall != null) { + val delegatedJsCall = CallTranslator.translate(withAliased, delegatedCall, getDelegateNameRef(correspondingPropertyName)) + function.addStatement(delegatedJsCall.makeStmt()) - val setExpression = if (delegatedCall != null) - CallTranslator.translate(contextWithAliased, delegatedCall, getDelegateNameRef(propertyName)) - else - assignmentToBackingField(contextWithAliased, descriptor, defaultParameterRef) + if (isExtension(setterDescriptor)) { + val receiver = function.addParameter(getReceiverParameterName(), 0).getName() + (delegatedJsCall as JsInvocation).getArguments().set(0, receiver.makeRef()) + } + } else { + val assignment = assignmentToBackingField(withAliased, descriptor, valueParameter.makeRef()) + function.addStatement(assignment.makeStmt()) + } - jsFunction.getParameters().add(defaultParameter) - jsFunction.setBody(JsBlock(setExpression.makeStmt())) - return jsFunction + return function } private fun generateDefaultAccessor(accessorDescriptor: PropertyAccessorDescriptor, function: JsFunction): JsPropertyInitializer = @@ -153,4 +184,19 @@ private class PropertyTranslator( private fun translateCustomAccessor(expression: JetPropertyAccessor): JsPropertyInitializer = Translation.functionTranslator(expression, context()).translateAsEcma5PropertyDescriptor() + + private fun accessorDescription(accessorDescriptor: PropertyAccessorDescriptor): String { + val accessorType = + when(accessorDescriptor) { + is PropertyGetterDescriptor -> + "getter" + is PropertySetterDescriptor -> + "setter" + else -> + throw IllegalArgumentException("Unknown accessor type ${accessorDescriptor.javaClass}") + } + + val name = accessorDescriptor.getName().asString() + return "$accessorType for $name" + } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/astUtils.kt b/js/js.translator/src/org/jetbrains/k2js/translate/utils/astUtils.kt new file mode 100644 index 00000000000..eeb3a9af81f --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/astUtils.kt @@ -0,0 +1,38 @@ +/* + * 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.utils.ast + +import com.google.dart.compiler.backend.js.ast.JsFunction +import com.google.dart.compiler.backend.js.ast.JsStatement +import com.google.dart.compiler.backend.js.ast.JsParameter + +public fun JsFunction.addStatement(stmt: JsStatement) { + getBody().getStatements().add(stmt) +} + +public fun JsFunction.addParameter(identifier: String, index: Int? = null): JsParameter { + val name = getScope().declareFreshName(identifier) + val parameter = JsParameter(name) + + if (index == null) { + getParameters().add(parameter) + } else { + getParameters().add(index, parameter) + } + + return parameter +}