diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/BinaryOperationIntrinsic.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/BinaryOperationIntrinsic.java deleted file mode 100644 index c2506eb6a16..00000000000 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/BinaryOperationIntrinsic.java +++ /dev/null @@ -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); -} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/BinaryOperationIntrinsics.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/BinaryOperationIntrinsics.java deleted file mode 100644 index 0f9ac2e734c..00000000000 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/BinaryOperationIntrinsics.java +++ /dev/null @@ -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 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; - } -} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/CompareToBOIF.kt b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/CompareToBOIF.kt new file mode 100644 index 00000000000..4ab2708910e --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/CompareToBOIF.kt @@ -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 = OperatorConventions.COMPARISON_OPERATIONS + + override public fun getIntrinsic(descriptor: FunctionDescriptor): BinaryOperationIntrinsic? { + return if (JsDescriptorUtils.isBuiltin(descriptor)) CompareToIntrinsic else null + } +} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/CompareToInstrinsic.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/CompareToInstrinsic.java deleted file mode 100644 index ac1c6776829..00000000000 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/CompareToInstrinsic.java +++ /dev/null @@ -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); - } -} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/EqualsBOIF.kt b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/EqualsBOIF.kt new file mode 100644 index 00000000000..f8435036b3c --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/EqualsBOIF.kt @@ -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(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 = OperatorConventions.EQUALS_OPERATIONS + + override public fun getIntrinsic(descriptor: FunctionDescriptor): BinaryOperationIntrinsic? { + if (JsDescriptorUtils.isBuiltin(descriptor) || TopLevelFIF.EQUALS_IN_ANY.apply(descriptor)) { + return EqualsIntrinsic + } + return null + } +} + diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/EqualsIntrinsic.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/EqualsIntrinsic.java deleted file mode 100644 index 3f101631701..00000000000 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/EqualsIntrinsic.java +++ /dev/null @@ -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); - } -} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/binaryOperationIntrinsics.kt b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/binaryOperationIntrinsics.kt new file mode 100644 index 00000000000..f3755905640 --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/binaryOperationIntrinsics.kt @@ -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, 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 + + 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") +} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/operation/BinaryOperationTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/operation/BinaryOperationTranslator.java index d4d1bebd528..5f6602b7cba 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/operation/BinaryOperationTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/operation/BinaryOperationTranslator.java @@ -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()); }