JS backend: refactoring support for binary intrinsic operations
This commit is contained in:
-31
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2013 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.intrinsic.operation;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetBinaryExpression;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
|
||||
public interface BinaryOperationIntrinsic {
|
||||
|
||||
boolean isApplicable(@NotNull JetBinaryExpression expression, @NotNull TranslationContext context);
|
||||
|
||||
@NotNull
|
||||
JsExpression apply(@NotNull JetBinaryExpression expression, @NotNull JsExpression left,
|
||||
@NotNull JsExpression right, @NotNull TranslationContext context);
|
||||
}
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2013 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.intrinsic.operation;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.psi.JetBinaryExpression;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public final class BinaryOperationIntrinsics {
|
||||
|
||||
@NotNull
|
||||
private final List<BinaryOperationIntrinsic> intrinsics = Lists.newArrayList();
|
||||
|
||||
{
|
||||
intrinsics.add(new EqualsIntrinsic());
|
||||
intrinsics.add(new CompareToInstrinsic());
|
||||
}
|
||||
|
||||
public BinaryOperationIntrinsics() {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public BinaryOperationIntrinsic getIntrinsic(@NotNull JetBinaryExpression expression, @NotNull TranslationContext context) {
|
||||
for (BinaryOperationIntrinsic intrinsic : intrinsics) {
|
||||
if (intrinsic.isApplicable(expression, context)) {
|
||||
return intrinsic;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.intrinsic.operation
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.*
|
||||
import org.jetbrains.jet.lang.psi.JetBinaryExpression
|
||||
import org.jetbrains.jet.lang.types.expressions.OperatorConventions
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext
|
||||
import org.jetbrains.k2js.translate.operation.OperatorTable
|
||||
import org.jetbrains.k2js.translate.utils.JsDescriptorUtils
|
||||
|
||||
import org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken
|
||||
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.jet.lexer.JetToken
|
||||
import com.google.common.collect.ImmutableSet
|
||||
|
||||
|
||||
object CompareToBOIF : BinaryOperationIntrinsicFactory {
|
||||
|
||||
private object CompareToIntrinsic : AbstractBinaryOperationIntrinsic() {
|
||||
override fun apply(expression: JetBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsExpression {
|
||||
val operator = OperatorTable.getBinaryOperator(getOperationToken(expression))
|
||||
return JsBinaryOperation(operator, left, right)
|
||||
}
|
||||
}
|
||||
|
||||
override public fun getSupportTokens(): ImmutableSet<JetToken> = OperatorConventions.COMPARISON_OPERATIONS
|
||||
|
||||
override public fun getIntrinsic(descriptor: FunctionDescriptor): BinaryOperationIntrinsic? {
|
||||
return if (JsDescriptorUtils.isBuiltin(descriptor)) CompareToIntrinsic else null
|
||||
}
|
||||
}
|
||||
-54
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2013 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.intrinsic.operation;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsBinaryOperation;
|
||||
import com.google.dart.compiler.backend.js.ast.JsBinaryOperator;
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetBinaryExpression;
|
||||
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.operation.OperatorTable;
|
||||
import org.jetbrains.k2js.translate.utils.JsDescriptorUtils;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getCallableDescriptorForOperationExpression;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken;
|
||||
|
||||
public final class CompareToInstrinsic implements BinaryOperationIntrinsic {
|
||||
@Override
|
||||
public boolean isApplicable(@NotNull JetBinaryExpression expression, @NotNull TranslationContext context) {
|
||||
if (!OperatorConventions.COMPARISON_OPERATIONS.contains(getOperationToken(expression))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CallableDescriptor descriptor = getCallableDescriptorForOperationExpression(context.bindingContext(), expression);
|
||||
assert descriptor != null;
|
||||
return JsDescriptorUtils.isBuiltin(descriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression apply(@NotNull JetBinaryExpression expression,
|
||||
@NotNull JsExpression left,
|
||||
@NotNull JsExpression right,
|
||||
@NotNull TranslationContext context) {
|
||||
JsBinaryOperator operator = OperatorTable.getBinaryOperator(getOperationToken(expression));
|
||||
return new JsBinaryOperation(operator, left, right);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.intrinsic.operation
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.*
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.jet.lang.psi.JetBinaryExpression
|
||||
import org.jetbrains.jet.lang.types.expressions.OperatorConventions
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext
|
||||
import org.jetbrains.k2js.translate.intrinsic.functions.factories.TopLevelFIF
|
||||
import org.jetbrains.k2js.translate.intrinsic.functions.patterns.NamePredicate
|
||||
import org.jetbrains.k2js.translate.utils.JsAstUtils
|
||||
import org.jetbrains.k2js.translate.utils.JsDescriptorUtils
|
||||
import org.jetbrains.k2js.translate.utils.TranslationUtils
|
||||
|
||||
import java.util.Arrays
|
||||
|
||||
import org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken
|
||||
import org.jetbrains.jet.lexer.JetToken
|
||||
import org.jetbrains.jet.lexer.JetTokens
|
||||
import com.google.common.collect.ImmutableSet
|
||||
|
||||
object EqualsBOIF : BinaryOperationIntrinsicFactory {
|
||||
|
||||
private object EqualsIntrinsic : AbstractBinaryOperationIntrinsic() {
|
||||
override fun apply(expression: JetBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsExpression {
|
||||
val isNegated = getOperationToken(expression) == JetTokens.EXCLEQ
|
||||
if (right == JsLiteral.NULL || left == JsLiteral.NULL) {
|
||||
return TranslationUtils.nullCheck(if (right == JsLiteral.NULL) left else right, isNegated)
|
||||
}
|
||||
else if (canUseSimpleEquals(expression, context)) {
|
||||
return JsBinaryOperation(if (isNegated) JsBinaryOperator.REF_NEQ else JsBinaryOperator.REF_EQ, left, right)
|
||||
}
|
||||
|
||||
val result = TopLevelFIF.KOTLIN_EQUALS.apply(left, Arrays.asList<JsExpression>(right), context)
|
||||
return if (isNegated) JsAstUtils.negated(result) else result
|
||||
}
|
||||
|
||||
private fun canUseSimpleEquals(expression: JetBinaryExpression, context: TranslationContext): Boolean {
|
||||
val left = expression.getLeft()
|
||||
assert(left != null) { "No left-hand side: " + expression.getText() }
|
||||
val typeName = JsDescriptorUtils.getNameIfStandardType(left!!, context)
|
||||
return typeName != null && NamePredicate.PRIMITIVE_NUMBERS.apply(typeName)
|
||||
}
|
||||
}
|
||||
|
||||
override public fun getSupportTokens(): ImmutableSet<JetToken> = OperatorConventions.EQUALS_OPERATIONS
|
||||
|
||||
override public fun getIntrinsic(descriptor: FunctionDescriptor): BinaryOperationIntrinsic? {
|
||||
if (JsDescriptorUtils.isBuiltin(descriptor) || TopLevelFIF.EQUALS_IN_ANY.apply(descriptor)) {
|
||||
return EqualsIntrinsic
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
-80
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2013 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.intrinsic.operation;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsBinaryOperation;
|
||||
import com.google.dart.compiler.backend.js.ast.JsBinaryOperator;
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.backend.js.ast.JsLiteral;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetBinaryExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.intrinsic.functions.factories.TopLevelFIF;
|
||||
import org.jetbrains.k2js.translate.intrinsic.functions.patterns.NamePredicate;
|
||||
import org.jetbrains.k2js.translate.utils.JsAstUtils;
|
||||
import org.jetbrains.k2js.translate.utils.JsDescriptorUtils;
|
||||
import org.jetbrains.k2js.translate.utils.TranslationUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getCallableDescriptorForOperationExpression;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken;
|
||||
|
||||
public final class EqualsIntrinsic implements BinaryOperationIntrinsic {
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(@NotNull JetBinaryExpression expression, @NotNull TranslationContext context) {
|
||||
if (!OperatorConventions.EQUALS_OPERATIONS.contains(getOperationToken(expression))) {
|
||||
return false;
|
||||
}
|
||||
CallableDescriptor functionDescriptor = getCallableDescriptorForOperationExpression(context.bindingContext(), expression);
|
||||
if (!(functionDescriptor instanceof FunctionDescriptor)) return false;
|
||||
|
||||
return JsDescriptorUtils.isBuiltin(functionDescriptor) || TopLevelFIF.EQUALS_IN_ANY.apply((FunctionDescriptor) functionDescriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsExpression apply(@NotNull JetBinaryExpression expression,
|
||||
@NotNull JsExpression left,
|
||||
@NotNull JsExpression right,
|
||||
@NotNull TranslationContext context) {
|
||||
boolean isNegated = getOperationToken(expression).equals(JetTokens.EXCLEQ);
|
||||
if (right == JsLiteral.NULL || left == JsLiteral.NULL) {
|
||||
return TranslationUtils.nullCheck(right == JsLiteral.NULL ? left : right, isNegated);
|
||||
}
|
||||
else if (canUseSimpleEquals(expression, context)) {
|
||||
return new JsBinaryOperation(isNegated ? JsBinaryOperator.REF_NEQ : JsBinaryOperator.REF_EQ, left, right);
|
||||
}
|
||||
|
||||
JsExpression result = TopLevelFIF.KOTLIN_EQUALS.apply(left, Arrays.asList(right), context);
|
||||
return isNegated ? JsAstUtils.negated(result) : result;
|
||||
}
|
||||
|
||||
private static boolean canUseSimpleEquals(@NotNull JetBinaryExpression expression, @NotNull TranslationContext context) {
|
||||
JetExpression left = expression.getLeft();
|
||||
assert left != null : "No left-hand side: " + expression.getText();
|
||||
Name typeName = JsDescriptorUtils.getNameIfStandardType(left, context);
|
||||
return typeName != null && NamePredicate.PRIMITIVE_NUMBERS.apply(typeName);
|
||||
}
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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.intrinsic.operation
|
||||
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.jet.lang.psi.JetBinaryExpression
|
||||
import org.jetbrains.jet.lexer.JetToken
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext
|
||||
|
||||
import org.jetbrains.k2js.translate.utils.BindingUtils.getCallableDescriptorForOperationExpression
|
||||
import org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken
|
||||
import gnu.trove.THashMap
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression
|
||||
import com.google.common.collect.ImmutableSet
|
||||
|
||||
public trait BinaryOperationIntrinsic {
|
||||
|
||||
fun apply(expression: JetBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsExpression
|
||||
|
||||
fun exists(): Boolean
|
||||
}
|
||||
|
||||
public class BinaryOperationIntrinsics {
|
||||
|
||||
private val intrinsicCache = THashMap<Pair<JetToken, FunctionDescriptor>, BinaryOperationIntrinsic>()
|
||||
|
||||
private val factories = listOf(EqualsBOIF, CompareToBOIF)
|
||||
|
||||
public fun getIntrinsic(expression: JetBinaryExpression, context: TranslationContext): BinaryOperationIntrinsic {
|
||||
val token = getOperationToken(expression)
|
||||
val descriptor = getCallableDescriptorForOperationExpression(context.bindingContext(), expression)
|
||||
if (descriptor == null || descriptor !is FunctionDescriptor) {
|
||||
return NO_INTRINSIC
|
||||
}
|
||||
|
||||
return lookUpCache(token, descriptor) ?: computeAndCacheIntrinsic(token, descriptor)
|
||||
}
|
||||
|
||||
private fun lookUpCache(token: JetToken, descriptor: FunctionDescriptor): BinaryOperationIntrinsic? =
|
||||
intrinsicCache.get(Pair(token, descriptor))
|
||||
|
||||
private fun computeAndCacheIntrinsic(token: JetToken, descriptor: FunctionDescriptor): BinaryOperationIntrinsic {
|
||||
val result = computeIntrinsic(token, descriptor)
|
||||
intrinsicCache.put(Pair(token, descriptor), result)
|
||||
return result
|
||||
}
|
||||
|
||||
private fun computeIntrinsic(token: JetToken, descriptor: FunctionDescriptor): BinaryOperationIntrinsic {
|
||||
for (factory in factories) {
|
||||
if (factory.getSupportTokens().contains(token)) {
|
||||
val intrinsic = factory.getIntrinsic(descriptor)
|
||||
if (intrinsic != null) {
|
||||
return intrinsic
|
||||
}
|
||||
}
|
||||
}
|
||||
return NO_INTRINSIC
|
||||
}
|
||||
}
|
||||
|
||||
trait BinaryOperationIntrinsicFactory {
|
||||
|
||||
public fun getSupportTokens(): ImmutableSet<JetToken>
|
||||
|
||||
public fun getIntrinsic(descriptor: FunctionDescriptor): BinaryOperationIntrinsic?
|
||||
}
|
||||
|
||||
abstract class AbstractBinaryOperationIntrinsic : BinaryOperationIntrinsic {
|
||||
|
||||
public override abstract fun apply(expression: JetBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsExpression
|
||||
|
||||
public override fun exists(): Boolean = true
|
||||
}
|
||||
|
||||
object NO_INTRINSIC : AbstractBinaryOperationIntrinsic() {
|
||||
override fun exists(): Boolean = false
|
||||
|
||||
override fun apply(expression: JetBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsExpression =
|
||||
throw UnsupportedOperationException("BinaryOperationIntrinsic#NO_INTRINSIC_#apply")
|
||||
}
|
||||
+2
-2
@@ -89,7 +89,7 @@ public final class BinaryOperationTranslator extends AbstractTranslator {
|
||||
@NotNull
|
||||
private JsExpression translate() {
|
||||
BinaryOperationIntrinsic intrinsic = getIntrinsicForExpression();
|
||||
if (intrinsic != null) {
|
||||
if (intrinsic.exists()) {
|
||||
return applyIntrinsic(intrinsic);
|
||||
}
|
||||
if (getOperationToken(expression).equals(JetTokens.ELVIS)) {
|
||||
@@ -149,7 +149,7 @@ public final class BinaryOperationTranslator extends AbstractTranslator {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@NotNull
|
||||
private BinaryOperationIntrinsic getIntrinsicForExpression() {
|
||||
return context().intrinsics().getBinaryOperationIntrinsics().getIntrinsic(expression, context());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user