diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/OperatorConventions.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/OperatorConventions.java index 2c49c31b3ab..33e0591edfd 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/OperatorConventions.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/OperatorConventions.java @@ -98,6 +98,12 @@ public class OperatorConventions { .put(JetTokens.PLUSEQ, JetTokens.PLUS) .put(JetTokens.MINUSEQ, JetTokens.MINUS) .build(); + + //TODO: use these across frontend + public static final ImmutableBiMap BOOLEAN_OPERATIONS = ImmutableBiMap.builder() + .put(JetTokens.ANDAND, Name.identifier("and")) + .put(JetTokens.OROR, Name.identifier("or")) + .build(); @Nullable public static Name getNameForOperationSymbol(@NotNull JetToken token) { diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/context/StaticContext.java b/js/js.translator/src/org/jetbrains/k2js/translate/context/StaticContext.java index 4d714ff8f02..7a646db1c70 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/context/StaticContext.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/context/StaticContext.java @@ -23,7 +23,6 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.DescriptorUtils; -import org.jetbrains.jet.lang.types.lang.JetStandardLibrary; import org.jetbrains.k2js.config.EcmaVersion; import org.jetbrains.k2js.translate.context.generator.Generator; import org.jetbrains.k2js.translate.context.generator.Rule; @@ -45,14 +44,12 @@ import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.*; */ public final class StaticContext { - public static StaticContext generateStaticContext(@NotNull JetStandardLibrary library, - @NotNull BindingContext bindingContext, - @NotNull EcmaVersion ecmaVersion) { + public static StaticContext generateStaticContext(@NotNull BindingContext bindingContext, @NotNull EcmaVersion ecmaVersion) { JsProgram program = new JsProgram("main"); JsRootScope jsRootScope = program.getRootScope(); Namer namer = Namer.newInstance(jsRootScope); NamingScope scope = NamingScope.rootScope(jsRootScope); - Intrinsics intrinsics = Intrinsics.standardLibraryIntrinsics(library); + Intrinsics intrinsics = new Intrinsics(); StandardClasses standardClasses = StandardClasses.bindImplementations(namer.getKotlinScope()); return new StaticContext(program, bindingContext, namer, intrinsics, standardClasses, scope, ecmaVersion); } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/expression/foreach/ArrayForTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/expression/foreach/ArrayForTranslator.java index 44e96506847..21f47a7f731 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/expression/foreach/ArrayForTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/expression/foreach/ArrayForTranslator.java @@ -26,7 +26,7 @@ import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.k2js.translate.context.TemporaryVariable; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.general.Translation; -import org.jetbrains.k2js.translate.intrinsic.FunctionIntrinsic; +import org.jetbrains.k2js.translate.intrinsic.functions.factories.ArrayFIF; import org.jetbrains.k2js.translate.utils.BindingUtils; import java.util.Collections; @@ -44,12 +44,12 @@ public final class ArrayForTranslator extends ForTranslator { @NotNull public static JsStatement doTranslate(@NotNull JetForExpression expression, - @NotNull TranslationContext context) { + @NotNull TranslationContext context) { return (new ArrayForTranslator(expression, context).translate()); } public static boolean isApplicable(@NotNull JetForExpression expression, - @NotNull TranslationContext context) { + @NotNull TranslationContext context) { JetExpression loopRange = getLoopRange(expression); JetType rangeType = BindingUtils.getTypeForExpression(context.bindingContext(), loopRange); //TODO: better check @@ -70,10 +70,10 @@ public final class ArrayForTranslator extends ForTranslator { private ArrayForTranslator(@NotNull JetForExpression forExpression, @NotNull TranslationContext context) { super(forExpression, context); loopRange = context.declareTemporary(Translation.translateAsExpression(getLoopRange(expression), context)); - FunctionIntrinsic lengthPropertyIntrinsic = context().intrinsics().getLengthPropertyIntrinsic(); - JsExpression length = lengthPropertyIntrinsic.apply(loopRange.reference(), - Collections.emptyList(), - context()); + + JsExpression length = ArrayFIF.ARRAY_LENGTH_INTRINSIC.apply(loopRange.reference(), + Collections.emptyList(), + context()); end = context().declareTemporary(length); index = context().declareTemporary(program().getNumberLiteral(0)); } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/general/Translation.java b/js/js.translator/src/org/jetbrains/k2js/translate/general/Translation.java index f379841a45e..3ad5d8b0c92 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/general/Translation.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/general/Translation.java @@ -25,7 +25,6 @@ import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; -import org.jetbrains.jet.lang.types.lang.JetStandardLibrary; import org.jetbrains.k2js.config.Config; import org.jetbrains.k2js.facade.MainCallParameters; import org.jetbrains.k2js.facade.exceptions.MainFunctionNotFoundException; @@ -167,8 +166,7 @@ public final class Translation { @NotNull MainCallParameters mainCallParameters, @NotNull Config config) throws MainFunctionNotFoundException { //TODO: move some of the code somewhere - JetStandardLibrary standardLibrary = JetStandardLibrary.getInstance(); - StaticContext staticContext = StaticContext.generateStaticContext(standardLibrary, bindingContext, config.getTarget()); + StaticContext staticContext = StaticContext.generateStaticContext(bindingContext, config.getTarget()); JsProgram program = staticContext.getProgram(); JsBlock block = program.getGlobalBlock(); diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/CompareToIntrinsic.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/CompareToIntrinsic.java deleted file mode 100644 index c280e2f4e95..00000000000 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/CompareToIntrinsic.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2010-2012 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; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.types.expressions.OperatorConventions; -import org.jetbrains.jet.lexer.JetToken; - -/** - * @author Pavel Talanov - */ -public abstract class CompareToIntrinsic implements FunctionIntrinsic { - - private JetToken comparisonToken = null; - - @NotNull - protected JetToken getComparisonToken() { - assert comparisonToken != null : "Should use set token first"; - return comparisonToken; - } - - public void setComparisonToken(@NotNull JetToken comparisonToken) { - assert OperatorConventions.COMPARISON_OPERATIONS.contains(comparisonToken) - : "Should be a comparison operation"; - this.comparisonToken = comparisonToken; - } -} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/Intrinsics.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/Intrinsics.java index ebeb819b09b..7f36644936c 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/Intrinsics.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/Intrinsics.java @@ -16,36 +16,9 @@ package org.jetbrains.k2js.translate.intrinsic; -import com.google.common.collect.Lists; -import com.google.dart.compiler.backend.js.ast.JsBinaryOperator; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.descriptors.*; -import org.jetbrains.jet.lang.resolve.name.Name; -import org.jetbrains.jet.lang.resolve.scopes.JetScope; -import org.jetbrains.jet.lang.types.JetType; -import org.jetbrains.jet.lang.types.lang.JetStandardClasses; -import org.jetbrains.jet.lang.types.lang.JetStandardLibrary; -import org.jetbrains.jet.lang.types.lang.PrimitiveType; -import org.jetbrains.jet.lexer.JetToken; -import org.jetbrains.jet.lexer.JetTokens; -import org.jetbrains.k2js.translate.intrinsic.array.ArrayGetIntrinsic; -import org.jetbrains.k2js.translate.intrinsic.array.ArraySetIntrinsic; -import org.jetbrains.k2js.translate.intrinsic.primitive.*; -import org.jetbrains.k2js.translate.intrinsic.string.CharAtIntrinsic; -import org.jetbrains.k2js.translate.intrinsic.tuple.TupleAccessIntrinsic; -import org.jetbrains.k2js.translate.operation.OperatorTable; -import org.jetbrains.k2js.translate.utils.JsDescriptorUtils; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static org.jetbrains.jet.lang.types.expressions.OperatorConventions.*; -import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getFunctionByName; -import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getPropertyByName; - -//TODO: class is monstrous, should be refactored. +import org.jetbrains.k2js.translate.intrinsic.functions.FunctionIntrinsics; +import org.jetbrains.k2js.translate.intrinsic.operation.BinaryOperationIntrinsics; /** * @author Pavel Talanov @@ -55,249 +28,18 @@ import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getPropertyBy public final class Intrinsics { @NotNull - private final Map functionIntrinsics = - new HashMap(); + private final FunctionIntrinsics functionIntrinsics = new FunctionIntrinsics(); @NotNull - private final Map equalsIntrinsics = - new HashMap(); - - @NotNull - private final Map compareToIntrinsics = - new HashMap(); - - @NotNull - private final FunctionIntrinsic lengthPropertyIntrinsic = new BuiltInPropertyIntrinsic("length"); - - public static Intrinsics standardLibraryIntrinsics(@NotNull JetStandardLibrary library) { - return new Intrinsics(library); + public BinaryOperationIntrinsics getBinaryOperationIntrinsics() { + return binaryOperationIntrinsics; } @NotNull - private final JetStandardLibrary library; - - private Intrinsics(@NotNull JetStandardLibrary library) { - this.library = library; - declareOperatorIntrinsics(); - declareStringIntrinsics(); - declareTuplesIntrinsics(); - declareArrayIntrinsics(); - declareBooleanIntrinsics(); - FunctionDescriptor intToDouble = getFunctionByName(library.getInt().getDefaultType().getMemberScope(), Name.identifier("toDouble")); - functionIntrinsics.put(intToDouble, ReturnReceiverIntrinsic.INSTANCE); - FunctionDescriptor doubleToInt = getFunctionByName(library.getDouble().getDefaultType().getMemberScope(), Name.identifier("toInt")); - functionIntrinsics.put(doubleToInt, new CallStandardMethodIntrinsic("Math.floor", true, 0)); - FunctionDescriptor toStringFunction = getFunctionByName(library.getLibraryScope(), Name.identifier("toString")); - functionIntrinsics.put(toStringFunction, new BuiltInFunctionIntrinsic("toString")); - } - - private void declareBooleanIntrinsics() { - FunctionDescriptor andFunction = getFunctionByName(library.getBoolean().getDefaultType().getMemberScope(), Name.identifier("and")); - functionIntrinsics.put(andFunction, PrimitiveBinaryOperationIntrinsic.newInstance(JetTokens.ANDAND)); - - FunctionDescriptor orFunction = getFunctionByName(library.getBoolean().getDefaultType().getMemberScope(), Name.identifier("or")); - functionIntrinsics.put(orFunction, PrimitiveBinaryOperationIntrinsic.newInstance(JetTokens.OROR)); - - FunctionDescriptor notFunction = getFunctionByName(library.getBoolean().getDefaultType().getMemberScope(), Name.identifier("not")); - functionIntrinsics.put(notFunction, PrimitiveUnaryOperationIntrinsic.newInstance(JetTokens.EXCL)); - - FunctionDescriptor xorFunction = getFunctionByName(library.getBoolean().getDefaultType().getMemberScope(), Name.identifier("xor")); - functionIntrinsics.put(xorFunction, PrimitiveBinaryOperationIntrinsic.newInstance(JsBinaryOperator.BIT_XOR)); - } + private final BinaryOperationIntrinsics binaryOperationIntrinsics = new BinaryOperationIntrinsics(); @NotNull - public FunctionIntrinsic getLengthPropertyIntrinsic() { - return lengthPropertyIntrinsic; - } - - private void declareTuplesIntrinsics() { - for (int tupleSize = 0; tupleSize <= JetStandardClasses.MAX_TUPLE_ORDER; ++tupleSize) { - declareTupleIntrinsics(tupleSize); - } - } - - //TODO: provide generic mechanism or refactor - private void declareArrayIntrinsics() { - - List arrayTypes = getLibraryArrayTypes(); - - for (JetType arrayType : arrayTypes) { - declareIntrinsicsForArrayType(arrayType); - } - declareNullConstructorIntrinsic(); - } - - private void declareNullConstructorIntrinsic() { - FunctionDescriptor nullArrayConstructor = library.getLibraryScope().getFunctions(Name.identifier("arrayOfNulls")).iterator().next(); - functionIntrinsics.put(nullArrayConstructor, new CallStandardMethodIntrinsic("Kotlin.nullArray", false, 1)); - } - - //TODO: some dangerous operation unchecked here - private void declareIntrinsicsForArrayType(@NotNull JetType arrayType) { - JetScope arrayMemberScope = arrayType.getMemberScope(); - FunctionDescriptor setFunction = getFunctionByName(arrayMemberScope, Name.identifier("set")); - functionIntrinsics.put(setFunction, ArraySetIntrinsic.INSTANCE); - FunctionDescriptor getFunction = getFunctionByName(arrayMemberScope, Name.identifier("get")); - functionIntrinsics.put(getFunction, ArrayGetIntrinsic.INSTANCE); - PropertyDescriptor sizeProperty = getPropertyByName(arrayMemberScope, Name.identifier("size")); - functionIntrinsics.put(sizeProperty.getGetter(), lengthPropertyIntrinsic); - //TODO: excessive object creation - PropertyDescriptor indicesProperty = getPropertyByName(arrayMemberScope, Name.identifier("indices")); - functionIntrinsics.put(indicesProperty.getGetter(), new CallStandardMethodIntrinsic("Kotlin.arrayIndices", true, 0)); - FunctionDescriptor iteratorFunction = getFunctionByName(arrayMemberScope, Name.identifier("iterator")); - functionIntrinsics.put(iteratorFunction, new CallStandardMethodIntrinsic("Kotlin.arrayIterator", true, 0)); - ConstructorDescriptor arrayConstructor = - ((ClassDescriptor) arrayMemberScope.getContainingDeclaration()).getConstructors().iterator().next(); - functionIntrinsics.put(arrayConstructor, new CallStandardMethodIntrinsic("Kotlin.arrayFromFun", false, 2)); - } - - private List getLibraryArrayTypes() { - List arrayTypes = Lists.newArrayList(); - for (PrimitiveType type : PrimitiveType.values()) { - arrayTypes.add(library.getPrimitiveArrayJetType(type)); - } - arrayTypes.add(library.getArray().getDefaultType()); - return arrayTypes; - } - - private void declareTupleIntrinsics(int tupleSize) { - JetScope libraryScope = library.getLibraryScope(); - assert libraryScope != null; - ClassifierDescriptor tupleDescriptor = libraryScope.getClassifier(Name.identifier("Tuple" + tupleSize)); - assert tupleDescriptor != null; - declareTupleIntrinsicAccessors(tupleDescriptor, tupleSize); - } - - private void declareStringIntrinsics() { - //TODO: same intrinsic for 2 different methods - PropertyDescriptor stringLengthProperty = - getPropertyByName(library.getString().getDefaultType().getMemberScope(), Name.identifier("length")); - functionIntrinsics.put(stringLengthProperty.getGetter(), lengthPropertyIntrinsic); - PropertyDescriptor charSequenceLengthProperty = - getPropertyByName(library.getCharSequence().getDefaultType().getMemberScope(), Name.identifier("length")); - functionIntrinsics.put(charSequenceLengthProperty.getGetter(), lengthPropertyIntrinsic); - FunctionDescriptor getFunction = - getFunctionByName(library.getString().getDefaultType().getMemberScope(), Name.identifier("get")); - functionIntrinsics.put(getFunction, CharAtIntrinsic.INSTANCE); - } - - private void declareTupleIntrinsicAccessors(@NotNull ClassifierDescriptor tupleDescriptor, - int tupleSize) { - for (int elementIndex = 0; elementIndex < tupleSize; ++elementIndex) { - Name accessorName = Name.identifier("_" + (elementIndex + 1)); - PropertyDescriptor propertyDescriptor = - getPropertyByName(tupleDescriptor.getDefaultType().getMemberScope(), accessorName); - functionIntrinsics.put(propertyDescriptor.getGetter(), new TupleAccessIntrinsic(elementIndex)); - } - } - - private void declareOperatorIntrinsics() { - IntrinsicDeclarationVisitor visitor = new IntrinsicDeclarationVisitor(); - for (DeclarationDescriptor descriptor : library.getLibraryScope().getAllDescriptors()) { - //noinspection NullableProblems - descriptor.accept(visitor, null); - } - } - - public boolean isIntrinsic(@NotNull DeclarationDescriptor descriptor) { - //NOTE: that if we want to add other intrinsics we have to modify this method - if (descriptor instanceof FunctionDescriptor) { - FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor.getOriginal(); - return (equalsIntrinsics.containsKey(functionDescriptor) || - compareToIntrinsics.containsKey(functionDescriptor) || - functionIntrinsics.containsKey(functionDescriptor)); - } - return false; - } - - //NOTE: that if we want to add other intrinsics we have to modify this method - @NotNull - public FunctionIntrinsic getIntrinsic(@NotNull FunctionDescriptor descriptor) { - FunctionIntrinsic intrinsic = functionIntrinsics.get(descriptor.getOriginal()); - if (intrinsic == null) { - intrinsic = equalsIntrinsics.get(descriptor.getOriginal()); - } - if (intrinsic == null) { - intrinsic = compareToIntrinsics.get(descriptor.getOriginal()); - } - return intrinsic; - } - - @NotNull - public CompareToIntrinsic getCompareToIntrinsic(@NotNull FunctionDescriptor descriptor) { - return compareToIntrinsics.get(descriptor.getOriginal()); - } - - @NotNull - public EqualsIntrinsic getEqualsIntrinsic(@NotNull FunctionDescriptor descriptor) { - return equalsIntrinsics.get(descriptor.getOriginal()); - } - - @SuppressWarnings("ConstantConditions") - private final class IntrinsicDeclarationVisitor extends DeclarationDescriptorVisitorEmptyBodies { - - @Override - public Void visitClassDescriptor(@NotNull ClassDescriptor descriptor, @Nullable Void nothing) { - for (DeclarationDescriptor memberDescriptor : - descriptor.getDefaultType().getMemberScope().getAllDescriptors()) { - //noinspection NullableProblems - memberDescriptor.accept(this, null); - } - return null; - } - - @Override - public Void visitFunctionDescriptor(@NotNull FunctionDescriptor descriptor, @Nullable Void nothing) { - if (!isIntrinsic(descriptor)) { - declareOperatorIntrinsic(descriptor); - } - return null; - } - - - /*package*/ void declareOperatorIntrinsic(@NotNull FunctionDescriptor descriptor) { - tryResolveAsEqualsCompareToOrRangeToIntrinsic(descriptor); - tryResolveAsUnaryIntrinsics(descriptor); - tryResolveAsBinaryIntrinsics(descriptor); - } - - private void tryResolveAsEqualsCompareToOrRangeToIntrinsic(@NotNull FunctionDescriptor descriptor) { - Name functionName = descriptor.getName(); - if (functionName.equals(COMPARE_TO)) { - compareToIntrinsics.put(descriptor, PrimitiveCompareToIntrinsic.newInstance()); - } - if (functionName.equals(EQUALS)) { - equalsIntrinsics.put(descriptor, PrimitiveEqualsIntrinsic.newInstance()); - } - if (functionName.equals(Name.identifier("rangeTo"))) { - functionIntrinsics.put(descriptor, PrimitiveRangeToIntrinsic.newInstance()); - } - } - - private void tryResolveAsUnaryIntrinsics(@NotNull FunctionDescriptor descriptor) { - Name functionName = descriptor.getName(); - JetToken token = UNARY_OPERATION_NAMES.inverse().get(functionName); - - if (token == null) return; - if (!isUnaryOperation(descriptor)) return; - - functionIntrinsics.put(descriptor, PrimitiveUnaryOperationIntrinsic.newInstance(token)); - } - - private void tryResolveAsBinaryIntrinsics(@NotNull FunctionDescriptor descriptor) { - Name functionName = descriptor.getName(); - - if (isUnaryOperation(descriptor)) return; - - JetToken token = BINARY_OPERATION_NAMES.inverse().get(functionName); - if (token == null) return; - - if (!OperatorTable.hasCorrespondingBinaryOperator(token)) return; - functionIntrinsics.put(descriptor, PrimitiveBinaryOperationIntrinsic.newInstance(token)); - } - - private boolean isUnaryOperation(@NotNull FunctionDescriptor descriptor) { - return !JsDescriptorUtils.hasParameters(descriptor); - } + public FunctionIntrinsics getFunctionIntrinsics() { + return functionIntrinsics; } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/array/ArrayGetIntrinsic.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/array/ArrayGetIntrinsic.java deleted file mode 100644 index 02cc306e749..00000000000 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/array/ArrayGetIntrinsic.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2010-2012 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.array; - -import com.google.dart.compiler.backend.js.ast.JsArrayAccess; -import com.google.dart.compiler.backend.js.ast.JsExpression; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.k2js.translate.context.TranslationContext; -import org.jetbrains.k2js.translate.intrinsic.FunctionIntrinsic; - -import java.util.List; - -/** - * @author Pavel Talanov - */ -public enum ArrayGetIntrinsic implements FunctionIntrinsic { - - INSTANCE; - - @NotNull - @Override - public JsExpression apply(@Nullable JsExpression receiver, @NotNull List arguments, - @NotNull TranslationContext context) { - assert receiver != null; - assert arguments.size() == 1 : "Array get expression must have one argument."; - JsExpression indexExpression = arguments.get(0); - return new JsArrayAccess(receiver, indexExpression); - } -} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/array/ArraySetIntrinsic.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/array/ArraySetIntrinsic.java deleted file mode 100644 index 32756d7c4a5..00000000000 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/array/ArraySetIntrinsic.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2010-2012 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.array; - -import com.google.dart.compiler.backend.js.ast.JsArrayAccess; -import com.google.dart.compiler.backend.js.ast.JsExpression; -import com.google.dart.compiler.util.AstUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.k2js.translate.context.TranslationContext; -import org.jetbrains.k2js.translate.intrinsic.FunctionIntrinsic; - -import java.util.List; - -/** - * @author Pavel Talanov - */ -public enum ArraySetIntrinsic implements FunctionIntrinsic { - - INSTANCE; - - @NotNull - @Override - public JsExpression apply(@Nullable JsExpression receiver, @NotNull List arguments, - @NotNull TranslationContext context) { - assert receiver != null; - assert arguments.size() == 2 : "Array set expression must have two arguments."; - JsExpression indexExpression = arguments.get(0); - JsExpression value = arguments.get(1); - JsArrayAccess arrayAccess = AstUtil.newArrayAccess(receiver, indexExpression); - return AstUtil.newAssignment(arrayAccess, value); - } -} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/FunctionIntrinsics.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/FunctionIntrinsics.java new file mode 100644 index 00000000000..fe17f2beada --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/FunctionIntrinsics.java @@ -0,0 +1,107 @@ +/* + * Copyright 2010-2012 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.functions; + +import closurecompiler.internal.com.google.common.collect.Lists; +import closurecompiler.internal.com.google.common.collect.Maps; +import com.google.dart.compiler.backend.js.ast.JsExpression; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.k2js.translate.context.TranslationContext; +import org.jetbrains.k2js.translate.intrinsic.functions.basic.FunctionIntrinsic; +import org.jetbrains.k2js.translate.intrinsic.functions.factories.*; + +import java.util.List; +import java.util.Map; + +/** + * @author Pavel Talanov + */ +public final class FunctionIntrinsics { + + @NotNull + private static final FunctionIntrinsic NO_INTRINSIC = new FunctionIntrinsic() { + @Override + public boolean exists() { + return false; + } + + @NotNull + @Override + public JsExpression apply(@Nullable JsExpression receiver, + @NotNull List arguments, + @NotNull TranslationContext context) { + throw new UnsupportedOperationException("FunctionIntrinsic#NO_INTRINSIC_#apply"); + } + }; + + @NotNull + private final Map intrinsicCache = Maps.newHashMap(); + + @NotNull + private final List factories = Lists.newArrayList(); + + public FunctionIntrinsics() { + registerFactories(); + } + + private void registerFactories() { + register(PrimitiveUnaryOperationFIF.INSTANCE); + register(PrimitiveBinaryOperationFIF.INSTANCE); + register(TupleGetterFIF.INSTANCE); + register(StringOperationFIF.INSTANCE); + register(ArrayFIF.INSTANCE); + register(TopLevelFIF.INSTANCE); + } + + private boolean register(@NotNull FunctionIntrinsicFactory instance) { + return factories.add(instance); + } + + @NotNull + public FunctionIntrinsic getIntrinsic(@NotNull FunctionDescriptor descriptor) { + FunctionIntrinsic intrinsic = lookUpCache(descriptor); + if (intrinsic != null) { + return intrinsic; + } + intrinsic = computeAndCacheIntrinsic(descriptor); + return intrinsic; + } + + @Nullable + private FunctionIntrinsic lookUpCache(@NotNull FunctionDescriptor descriptor) { + return intrinsicCache.get(descriptor); + } + + @NotNull + private FunctionIntrinsic computeAndCacheIntrinsic(@NotNull FunctionDescriptor descriptor) { + FunctionIntrinsic result = computeIntrinsic(descriptor); + intrinsicCache.put(descriptor, result); + return result; + } + + @NotNull + private FunctionIntrinsic computeIntrinsic(@NotNull FunctionDescriptor descriptor) { + for (FunctionIntrinsicFactory factory : factories) { + if (factory.getPattern().apply(descriptor)) { + return factory.getIntrinsic(descriptor); + } + } + return NO_INTRINSIC; + } +} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/BuiltInFunctionIntrinsic.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/basic/BuiltInFunctionIntrinsic.java similarity index 92% rename from js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/BuiltInFunctionIntrinsic.java rename to js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/basic/BuiltInFunctionIntrinsic.java index c4b9712d2ff..3a226d57428 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/BuiltInFunctionIntrinsic.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/basic/BuiltInFunctionIntrinsic.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jetbrains.k2js.translate.intrinsic; +package org.jetbrains.k2js.translate.intrinsic.functions.basic; import com.google.dart.compiler.backend.js.ast.JsExpression; import com.google.dart.compiler.backend.js.ast.JsNameRef; @@ -31,7 +31,7 @@ import static org.jetbrains.k2js.translate.utils.JsAstUtils.setQualifier; /** * @author Pavel Talanov */ -public final class BuiltInFunctionIntrinsic implements FunctionIntrinsic { +public final class BuiltInFunctionIntrinsic extends FunctionIntrinsic { @NotNull private final String functionName; diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/BuiltInPropertyIntrinsic.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/basic/BuiltInPropertyIntrinsic.java similarity index 89% rename from js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/BuiltInPropertyIntrinsic.java rename to js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/basic/BuiltInPropertyIntrinsic.java index 5440cd036cd..dbea4dbdba4 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/BuiltInPropertyIntrinsic.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/basic/BuiltInPropertyIntrinsic.java @@ -1,4 +1,4 @@ -package org.jetbrains.k2js.translate.intrinsic; +package org.jetbrains.k2js.translate.intrinsic.functions.basic; import com.google.dart.compiler.backend.js.ast.JsExpression; import com.google.dart.compiler.backend.js.ast.JsNameRef; @@ -15,7 +15,7 @@ import static org.jetbrains.k2js.translate.utils.JsAstUtils.setQualifier; * @author Pavel Talanov */ //TODO: find should be usages -public final class BuiltInPropertyIntrinsic implements FunctionIntrinsic { +public final class BuiltInPropertyIntrinsic extends FunctionIntrinsic { @NotNull private final String propertyName; diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/CallStandardMethodIntrinsic.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/basic/CallStandardMethodIntrinsic.java similarity index 92% rename from js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/CallStandardMethodIntrinsic.java rename to js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/basic/CallStandardMethodIntrinsic.java index a33392b7207..9c7eedb77e7 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/CallStandardMethodIntrinsic.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/basic/CallStandardMethodIntrinsic.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jetbrains.k2js.translate.intrinsic; +package org.jetbrains.k2js.translate.intrinsic.functions.basic; import com.google.common.collect.Lists; import com.google.dart.compiler.Source; @@ -33,7 +33,7 @@ import static org.jetbrains.k2js.translate.utils.JsAstUtils.newInvocation; /** * @author Pavel Talanov */ -public final class CallStandardMethodIntrinsic implements FunctionIntrinsic { +public final class CallStandardMethodIntrinsic extends FunctionIntrinsic { @NotNull private final String methodName; @@ -50,8 +50,8 @@ public final class CallStandardMethodIntrinsic implements FunctionIntrinsic { @NotNull @Override public JsExpression apply(@Nullable JsExpression receiver, - @NotNull List arguments, - @NotNull TranslationContext context) { + @NotNull List arguments, + @NotNull TranslationContext context) { assert (receiver != null == receiverShouldBeNotNull); assert arguments.size() == expectedParamsNumber : "Incorrect number of arguments " + arguments.size() + " when expected " + expectedParamsNumber + " on method " + methodName + " " + atLocation(receiver, arguments); JsNameRef iteratorFunName = AstUtil.newQualifiedNameRef(methodName); diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/FunctionIntrinsic.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/basic/FunctionIntrinsic.java similarity index 75% rename from js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/FunctionIntrinsic.java rename to js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/basic/FunctionIntrinsic.java index 27e7343fcf3..19d8cc6e95b 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/FunctionIntrinsic.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/basic/FunctionIntrinsic.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jetbrains.k2js.translate.intrinsic; +package org.jetbrains.k2js.translate.intrinsic.functions.basic; import com.google.dart.compiler.backend.js.ast.JsExpression; import org.jetbrains.annotations.NotNull; @@ -28,9 +28,13 @@ import java.util.List; *

* Base for intrinsics that substitute standard function calls like Int#plus, Float#minus ... etc */ -public interface FunctionIntrinsic { +public abstract class FunctionIntrinsic { @NotNull - JsExpression apply(@Nullable JsExpression receiver, @NotNull List arguments, - @NotNull TranslationContext context); + public abstract JsExpression apply(@Nullable JsExpression receiver, @NotNull List arguments, + @NotNull TranslationContext context); + + public boolean exists() { + return true; + } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/ArrayFIF.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/ArrayFIF.java new file mode 100644 index 00000000000..8df8c3e882a --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/ArrayFIF.java @@ -0,0 +1,99 @@ +/* + * Copyright 2010-2012 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.functions.factories; + +import closurecompiler.internal.com.google.common.collect.Lists; +import com.google.dart.compiler.backend.js.ast.JsArrayAccess; +import com.google.dart.compiler.backend.js.ast.JsExpression; +import com.google.dart.compiler.util.AstUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.resolve.name.Name; +import org.jetbrains.jet.lang.types.lang.PrimitiveType; +import org.jetbrains.k2js.translate.context.TranslationContext; +import org.jetbrains.k2js.translate.intrinsic.functions.basic.BuiltInPropertyIntrinsic; +import org.jetbrains.k2js.translate.intrinsic.functions.basic.CallStandardMethodIntrinsic; +import org.jetbrains.k2js.translate.intrinsic.functions.basic.FunctionIntrinsic; +import org.jetbrains.k2js.translate.intrinsic.functions.patterns.NameChecker; + +import java.util.List; + +import static org.jetbrains.k2js.translate.intrinsic.functions.patterns.PatternBuilder.pattern; + +/** + * @author Pavel Talanov + */ +public final class ArrayFIF { + + @NotNull + private static final NameChecker ARRAYS; + + static { + List arrayTypeNames = Lists.newArrayList(); + for (PrimitiveType type : PrimitiveType.values()) { + arrayTypeNames.add(type.getArrayTypeName()); + } + arrayTypeNames.add(Name.identifier("Array")); + ARRAYS = new NameChecker(arrayTypeNames); + } + + @NotNull + private static final FunctionIntrinsic GET_INTRINSIC = new FunctionIntrinsic() { + @NotNull + @Override + public JsExpression apply(@Nullable JsExpression receiver, + @NotNull List arguments, + @NotNull TranslationContext context) { + assert receiver != null; + assert arguments.size() == 1 : "Array get expression must have one argument."; + JsExpression indexExpression = arguments.get(0); + return new JsArrayAccess(receiver, indexExpression); + } + }; + + @NotNull + private static final FunctionIntrinsic SET_INTRINSIC = new FunctionIntrinsic() { + @NotNull + @Override + public JsExpression apply(@Nullable JsExpression receiver, + @NotNull List arguments, + @NotNull TranslationContext context) { + assert receiver != null; + assert arguments.size() == 2 : "Array set expression must have two arguments."; + JsExpression indexExpression = arguments.get(0); + JsExpression value = arguments.get(1); + JsArrayAccess arrayAccess = AstUtil.newArrayAccess(receiver, indexExpression); + return AstUtil.newAssignment(arrayAccess, value); + } + }; + + @NotNull + public static final BuiltInPropertyIntrinsic ARRAY_LENGTH_INTRINSIC = new BuiltInPropertyIntrinsic("length"); + + @NotNull + public static final FunctionIntrinsicFactory INSTANCE = FIFBuilder.start() + .add(pattern(ARRAYS, "get"), GET_INTRINSIC) + .add(pattern(ARRAYS, "set"), SET_INTRINSIC) + .add(pattern(ARRAYS, ""), ARRAY_LENGTH_INTRINSIC) + .add(pattern(ARRAYS, ""), new CallStandardMethodIntrinsic("Kotlin.arrayIndices", true, 0)) + .add(pattern(ARRAYS, "iterator"), new CallStandardMethodIntrinsic("Kotlin.arrayIterator", true, 0)) + .add(pattern(ARRAYS, ""), new CallStandardMethodIntrinsic("Kotlin.arrayFromFun", false, 2)) + .build(); + + private ArrayFIF() { + } +} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/FIFBuilder.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/FIFBuilder.java new file mode 100644 index 00000000000..795c0fe97db --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/FIFBuilder.java @@ -0,0 +1,73 @@ +/* + * Copyright 2010-2012 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.functions.factories; + +import com.google.common.collect.Maps; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.k2js.translate.intrinsic.functions.basic.FunctionIntrinsic; +import org.jetbrains.k2js.translate.intrinsic.functions.patterns.Pattern; +import org.jetbrains.k2js.translate.intrinsic.functions.patterns.PatternBuilder; + +import java.util.Collection; +import java.util.Map; + +/** + * @author Pavel Talanov + */ +public final class FIFBuilder { + + @NotNull final Map patternToIntrinsic = Maps.newHashMap(); + + private FIFBuilder() { + } + + @NotNull + public static FIFBuilder start() { + return new FIFBuilder(); + } + + @NotNull + public FIFBuilder add(@NotNull Pattern pattern, @NotNull FunctionIntrinsic intrinsic) { + patternToIntrinsic.put(pattern, intrinsic); + return this; + } + + @NotNull + public FunctionIntrinsicFactory build() { + return new FunctionIntrinsicFactory() { + + @NotNull + @Override + public Pattern getPattern() { + Collection patterns = patternToIntrinsic.keySet(); + return PatternBuilder.any(patterns.toArray(new Pattern[patterns.size()])); + } + + @NotNull + @Override + public FunctionIntrinsic getIntrinsic(@NotNull FunctionDescriptor descriptor) { + for (Pattern pattern : patternToIntrinsic.keySet()) { + if (pattern.apply(descriptor)) { + return patternToIntrinsic.get(pattern); + } + } + throw new IllegalStateException("Must have intrinsic for pattern."); + } + }; + } +} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/EqualsIntrinsic.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/FunctionIntrinsicFactory.java similarity index 61% rename from js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/EqualsIntrinsic.java rename to js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/FunctionIntrinsicFactory.java index 88d35e42963..e1887502598 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/EqualsIntrinsic.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/FunctionIntrinsicFactory.java @@ -14,23 +14,21 @@ * limitations under the License. */ -package org.jetbrains.k2js.translate.intrinsic; +package org.jetbrains.k2js.translate.intrinsic.functions.factories; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.k2js.translate.intrinsic.functions.basic.FunctionIntrinsic; +import org.jetbrains.k2js.translate.intrinsic.functions.patterns.Pattern; /** * @author Pavel Talanov */ -public abstract class EqualsIntrinsic implements FunctionIntrinsic { +public interface FunctionIntrinsicFactory { @NotNull - private Boolean isNegated = false; + Pattern getPattern(); - public void setNegated(boolean isNegated) { - this.isNegated = isNegated; - } - - protected boolean isNegated() { - return isNegated; - } + @NotNull + FunctionIntrinsic getIntrinsic(@NotNull FunctionDescriptor descriptor); } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/PrimitiveBinaryOperationFIF.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/PrimitiveBinaryOperationFIF.java new file mode 100644 index 00000000000..3474805e93f --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/PrimitiveBinaryOperationFIF.java @@ -0,0 +1,108 @@ +/* + * Copyright 2010-2012 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.functions.factories; + +import com.google.dart.compiler.backend.js.ast.*; +import com.google.dart.compiler.util.AstUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.resolve.name.Name; +import org.jetbrains.jet.lang.types.expressions.OperatorConventions; +import org.jetbrains.jet.lexer.JetToken; +import org.jetbrains.k2js.translate.context.TranslationContext; +import org.jetbrains.k2js.translate.intrinsic.functions.basic.FunctionIntrinsic; +import org.jetbrains.k2js.translate.intrinsic.functions.patterns.NameChecker; +import org.jetbrains.k2js.translate.intrinsic.functions.patterns.Pattern; +import org.jetbrains.k2js.translate.intrinsic.functions.patterns.PatternBuilder; +import org.jetbrains.k2js.translate.operation.OperatorTable; + +import java.util.List; + +import static org.jetbrains.k2js.translate.intrinsic.functions.patterns.PatternBuilder.pattern; +import static org.jetbrains.k2js.translate.utils.JsAstUtils.*; + +/** + * @author Pavel Talanov + */ +public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory { + INSTANCE; + + @NotNull + private static final FunctionIntrinsic RANGE_TO_INTRINSIC = new FunctionIntrinsic() { + + @NotNull + @Override + public JsExpression apply(@Nullable JsExpression rangeStart, @NotNull List arguments, + @NotNull TranslationContext context) { + assert arguments.size() == 1 : "RangeTo must have one argument."; + assert rangeStart != null; + JsExpression rangeEnd = arguments.get(0); + JsBinaryOperation rangeSize = sum(subtract(rangeEnd, rangeStart), + context.program().getNumberLiteral(1)); + JsNameRef expr = AstUtil.newQualifiedNameRef("Kotlin.NumberRange"); + HasArguments numberRangeConstructorInvocation = context.isEcma5() ? AstUtil.newInvocation(expr) : new JsNew(expr); + //TODO: add tests and correct expression for reversed ranges. + JsBooleanLiteral isRangeReversed = context.program().getFalseLiteral(); + setArguments(numberRangeConstructorInvocation, rangeStart, rangeSize, isRangeReversed); + return (JsExpression) numberRangeConstructorInvocation; + } + }; + @NotNull + private static final NameChecker BINARY_OPERATIONS = new NameChecker(OperatorConventions.BINARY_OPERATION_NAMES.values()); + + @NotNull + @Override + public Pattern getPattern() { + //TODO: check that it is binary operation + return PatternBuilder.any(pattern(NameChecker.PRIMITIVE_NUMBERS, BINARY_OPERATIONS), + pattern("Boolean.or|and|xor"), + pattern("String.plus")); + } + + @NotNull + @Override + public FunctionIntrinsic getIntrinsic(@NotNull FunctionDescriptor descriptor) { + if (descriptor.getName().equals(Name.identifier("rangeTo"))) { + return RANGE_TO_INTRINSIC; + } + final JsBinaryOperator operator = getOperator(descriptor); + return new FunctionIntrinsic() { + @NotNull + @Override + public JsExpression apply(@Nullable JsExpression receiver, + @NotNull List arguments, + @NotNull TranslationContext context) { + assert arguments.size() == 1 : "Binary operator should have a receiver and one argument"; + return new JsBinaryOperation(operator, receiver, arguments.get(0)); + } + }; + } + + @NotNull + private static JsBinaryOperator getOperator(@NotNull FunctionDescriptor descriptor) { + JetToken token = OperatorConventions.BINARY_OPERATION_NAMES.inverse().get(descriptor.getName()); + if (token == null) { + token = OperatorConventions.BOOLEAN_OPERATIONS.inverse().get(descriptor.getName()); + } + if (token == null) { + assert descriptor.getName().getName().equals("xor"); + return JsBinaryOperator.BIT_XOR; + } + return OperatorTable.getBinaryOperator(token); + } +} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/PrimitiveUnaryOperationFIF.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/PrimitiveUnaryOperationFIF.java new file mode 100644 index 00000000000..b6a3ce9c37b --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/PrimitiveUnaryOperationFIF.java @@ -0,0 +1,86 @@ +/* + * Copyright 2010-2012 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.functions.factories; + +import com.google.dart.compiler.backend.js.ast.JsExpression; +import com.google.dart.compiler.backend.js.ast.JsPrefixOperation; +import com.google.dart.compiler.backend.js.ast.JsUnaryOperator; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.resolve.name.Name; +import org.jetbrains.jet.lang.types.expressions.OperatorConventions; +import org.jetbrains.jet.lexer.JetToken; +import org.jetbrains.k2js.translate.context.TranslationContext; +import org.jetbrains.k2js.translate.intrinsic.functions.basic.FunctionIntrinsic; +import org.jetbrains.k2js.translate.intrinsic.functions.patterns.NameChecker; +import org.jetbrains.k2js.translate.intrinsic.functions.patterns.Pattern; +import org.jetbrains.k2js.translate.operation.OperatorTable; +import org.jetbrains.k2js.translate.utils.JsDescriptorUtils; + +import java.util.List; + +import static org.jetbrains.k2js.translate.intrinsic.functions.patterns.NameChecker.PRIMITIVE_NUMBERS; +import static org.jetbrains.k2js.translate.intrinsic.functions.patterns.PatternBuilder.*; + +/** + * @author Pavel Talanov + */ +public enum PrimitiveUnaryOperationFIF implements FunctionIntrinsicFactory { + + INSTANCE; + + private static final NameChecker UNARY_OPERATIONS = new NameChecker(OperatorConventions.UNARY_OPERATION_NAMES.values()); + @NotNull + private static final Pattern UNARY_OPERATION_FOR_PRIMITIVE_NUMBER = + pattern(PRIMITIVE_NUMBERS, UNARY_OPERATIONS); + @NotNull + private static final Pattern NO_PARAMETERS = new Pattern() { + @Override + public boolean apply(@NotNull FunctionDescriptor descriptor) { + return !JsDescriptorUtils.hasParameters(descriptor); + } + }; + + @NotNull + @Override + public Pattern getPattern() { + Pattern primitiveUnaryOperationNames = any(UNARY_OPERATION_FOR_PRIMITIVE_NUMBER, pattern("Boolean.not")); + return all(primitiveUnaryOperationNames, NO_PARAMETERS); + } + + @NotNull + @Override + public FunctionIntrinsic getIntrinsic(@NotNull FunctionDescriptor descriptor) { + Name name = descriptor.getName(); + JetToken jetToken = OperatorConventions.UNARY_OPERATION_NAMES.inverse().get(name); + final JsUnaryOperator jsOperator = OperatorTable.getUnaryOperator(jetToken); + return new FunctionIntrinsic() { + @NotNull + @Override + public JsExpression apply(@Nullable JsExpression receiver, + @NotNull List arguments, + @NotNull TranslationContext context) { + assert receiver != null; + assert arguments.size() == 0 : "Unary operator should not have arguments."; + //NOTE: cannot use this for increment/decrement + return new JsPrefixOperation(jsOperator, receiver); + } + }; + } + +} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/StringOperationFIF.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/StringOperationFIF.java new file mode 100644 index 00000000000..dcab99a0e55 --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/StringOperationFIF.java @@ -0,0 +1,68 @@ +/* + * Copyright 2010-2012 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.functions.factories; + +import com.google.dart.compiler.backend.js.ast.JsExpression; +import com.google.dart.compiler.backend.js.ast.JsNameRef; +import com.google.dart.compiler.util.AstUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.k2js.translate.context.TranslationContext; +import org.jetbrains.k2js.translate.intrinsic.functions.basic.BuiltInPropertyIntrinsic; +import org.jetbrains.k2js.translate.intrinsic.functions.basic.FunctionIntrinsic; +import org.jetbrains.k2js.translate.intrinsic.functions.patterns.Pattern; + +import java.util.List; + +import static org.jetbrains.k2js.translate.intrinsic.functions.patterns.PatternBuilder.pattern; +import static org.jetbrains.k2js.translate.utils.JsAstUtils.newInvocation; +import static org.jetbrains.k2js.translate.utils.JsAstUtils.setQualifier; + +/** + * @author Pavel Talanov + */ +public final class StringOperationFIF { + + @NotNull + private static final Pattern GET_PATTERN = pattern("String.get"); + + @NotNull + private static final FunctionIntrinsic GET_INTRINSIC = new FunctionIntrinsic() { + @NotNull + @Override + public JsExpression apply(@Nullable JsExpression receiver, + @NotNull List arguments, + @NotNull TranslationContext context) { + assert receiver != null; + assert arguments.size() == 1 : "String#get expression must have 1 argument."; + //TODO: provide better way + JsNameRef charAtReference = AstUtil.newQualifiedNameRef("charAt"); + setQualifier(charAtReference, receiver); + return newInvocation(charAtReference, arguments); + } + }; + + @NotNull + public static final FunctionIntrinsicFactory INSTANCE = FIFBuilder.start() + .add(GET_PATTERN, GET_INTRINSIC) + .add(pattern("String."), new BuiltInPropertyIntrinsic("length")) + .add(pattern("CharSequence."), new BuiltInPropertyIntrinsic("length")) + .build(); + + private StringOperationFIF() { + } +} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/TopLevelFIF.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/TopLevelFIF.java new file mode 100644 index 00000000000..b13114551d0 --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/TopLevelFIF.java @@ -0,0 +1,43 @@ +/* + * Copyright 2010-2012 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.functions.factories; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.k2js.translate.intrinsic.functions.basic.BuiltInFunctionIntrinsic; +import org.jetbrains.k2js.translate.intrinsic.functions.basic.CallStandardMethodIntrinsic; +import org.jetbrains.k2js.translate.intrinsic.functions.patterns.Pattern; + +import static org.jetbrains.k2js.translate.intrinsic.functions.patterns.PatternBuilder.pattern; + +/** + * @author Pavel Talanov + */ +public final class TopLevelFIF { + + @NotNull + private static final Pattern EXT_TO_STRING = pattern("toString"); + + @NotNull + public static final FunctionIntrinsicFactory INSTANCE = FIFBuilder.start() + .add(EXT_TO_STRING, new BuiltInFunctionIntrinsic("toString")) + //TODO: add intrinsic for calling equals explicitly + .add(pattern("arrayOfNulls"), new CallStandardMethodIntrinsic("Kotlin.nullArray", false, 1)) + .build(); + + private TopLevelFIF() { + } +} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/TupleGetterFIF.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/TupleGetterFIF.java new file mode 100644 index 00000000000..f078269f72c --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/TupleGetterFIF.java @@ -0,0 +1,85 @@ +/* + * Copyright 2010-2012 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.functions.factories; + +import closurecompiler.internal.com.google.common.collect.Lists; +import com.google.dart.compiler.backend.js.ast.JsExpression; +import com.google.dart.compiler.util.AstUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.types.lang.JetStandardClasses; +import org.jetbrains.k2js.translate.context.TranslationContext; +import org.jetbrains.k2js.translate.intrinsic.functions.basic.FunctionIntrinsic; +import org.jetbrains.k2js.translate.intrinsic.functions.patterns.NameChecker; +import org.jetbrains.k2js.translate.intrinsic.functions.patterns.Pattern; +import org.jetbrains.k2js.translate.intrinsic.functions.patterns.PatternBuilder; + +import java.util.List; + +/** + * @author Pavel Talanov + */ +public enum TupleGetterFIF implements FunctionIntrinsicFactory { + INSTANCE; + + @NotNull + private static final NameChecker TUPLES; + + static { + List tupleNames = Lists.newArrayList(); + for (int tupleSize = 0; tupleSize <= JetStandardClasses.MAX_TUPLE_ORDER; ++tupleSize) { + tupleNames.add("Tuple" + tupleSize); + } + TUPLES = new NameChecker(tupleNames); + } + + @NotNull + private static final NameChecker TUPLE_UNDERSCORE_ACCESSORS; + + static { + List accessorNames = Lists.newArrayList(); + for (int tupleSize = 0; tupleSize <= JetStandardClasses.MAX_TUPLE_ORDER; ++tupleSize) { + accessorNames.add(""); + } + TUPLE_UNDERSCORE_ACCESSORS = new NameChecker(accessorNames); + } + + @NotNull + @Override + public Pattern getPattern() { + return PatternBuilder.pattern(TUPLES, TUPLE_UNDERSCORE_ACCESSORS); + } + + @NotNull + @Override + public FunctionIntrinsic getIntrinsic(@NotNull FunctionDescriptor descriptor) { + String nameString = descriptor.getName().getName(); + String elementIndexSubString = nameString.substring(6, nameString.length() - 1); + final int elementIndex = Integer.parseInt(elementIndexSubString) - 1; + return new FunctionIntrinsic() { + @NotNull + @Override + public JsExpression apply(@Nullable JsExpression receiver, + @NotNull List arguments, + @NotNull TranslationContext context) { + assert arguments.isEmpty() : "Tuple access expression should not have any arguments."; + return AstUtil.newArrayAccess(receiver, context.program().getNumberLiteral(elementIndex)); + } + }; + } +} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/patterns/NameChecker.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/patterns/NameChecker.java new file mode 100644 index 00000000000..bf77fff7ed0 --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/patterns/NameChecker.java @@ -0,0 +1,60 @@ +/* + * Copyright 2010-2012 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.functions.patterns; + +import closurecompiler.internal.com.google.common.collect.Lists; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.resolve.name.Name; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +/** + * @author Pavel Talanov + */ +public final class NameChecker { + + @NotNull + public static final NameChecker PRIMITIVE_NUMBERS = new NameChecker("Int", "Double", "Float", "Long", "Short"); + + @NotNull + private final List validNames = Lists.newArrayList(); + + public NameChecker(@NotNull String... validNames) { + this(Arrays.asList(validNames)); + } + + public NameChecker(@NotNull List validNames) { + for (String validName : validNames) { + this.validNames.add(Name.guess(validName)); + } + } + + public NameChecker(@NotNull Collection validNames) { + this.validNames.addAll(validNames); + } + + public boolean isValid(@NotNull Name name) { + for (Name validName : validNames) { + if (name.equals(validName)) { + return true; + } + } + return false; + } +} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/FunctionIntrinsicFactory.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/patterns/Pattern.java similarity index 72% rename from js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/FunctionIntrinsicFactory.java rename to js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/patterns/Pattern.java index 91c8950cfe6..4f437b27678 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/FunctionIntrinsicFactory.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/patterns/Pattern.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jetbrains.k2js.translate.intrinsic; +package org.jetbrains.k2js.translate.intrinsic.functions.patterns; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; @@ -22,10 +22,7 @@ import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; /** * @author Pavel Talanov */ -public abstract class FunctionIntrinsicFactory { +public interface Pattern { - public abstract boolean isApplicable(@NotNull FunctionDescriptor descriptor); - - @NotNull - public abstract FunctionIntrinsic createIntrinsic(@NotNull FunctionDescriptor descriptor); + boolean apply(@NotNull FunctionDescriptor descriptor); } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/patterns/PatternBuilder.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/patterns/PatternBuilder.java new file mode 100644 index 00000000000..f2c9f3404fc --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/patterns/PatternBuilder.java @@ -0,0 +1,134 @@ +/* + * Copyright 2010-2012 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.functions.patterns; + +import closurecompiler.internal.com.google.common.collect.Lists; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.resolve.DescriptorUtils; +import org.jetbrains.jet.lang.resolve.name.Name; + +import java.util.Arrays; +import java.util.List; + +/** + * @author Pavel Talanov + */ +public final class PatternBuilder { + + public static final NameChecker JET = new NameChecker("jet"); + + private PatternBuilder() { + } + + @NotNull + public static Pattern pattern(@NotNull NameChecker checker, @NotNull String stringWithPattern) { + List checkers = Lists.newArrayList(checker); + checkers.addAll(parseStringAsCheckerList(stringWithPattern)); + return pattern(checkers); + } + + @NotNull + public static Pattern pattern(@NotNull String string) { + List checkers = parseStringAsCheckerList(string); + return pattern(checkers); + } + + @NotNull + private static List parseStringAsCheckerList(@NotNull String stringWithPattern) { + String[] subPatterns = stringWithPattern.split("\\."); + List checkers = Lists.newArrayList(); + for (String subPattern : subPatterns) { + String[] validNames = subPattern.split("\\|"); + checkers.add(new NameChecker(validNames)); + } + return checkers; + } + + @NotNull + private static Pattern pattern(@NotNull List checkers) { + final List checkersWithPrefixChecker = Lists.newArrayList(JET); + checkersWithPrefixChecker.addAll(checkers); + return new Pattern() { + @Override + public boolean apply(@NotNull FunctionDescriptor descriptor) { + //TODO: no need to wrap if we check beforehand + try { + return doApply(descriptor); + } + catch (IllegalArgumentException e) { + return false; + } + } + + private boolean doApply(@NotNull FunctionDescriptor descriptor) { + List nameParts = DescriptorUtils.getFQName(descriptor).pathSegments(); + if (nameParts.size() != checkersWithPrefixChecker.size()) { + return false; + } + if (!allNamePartsValid(nameParts)) return false; + return true; + } + + private boolean allNamePartsValid(@NotNull List nameParts) { + for (int i = 0; i < nameParts.size(); ++i) { + Name namePart = nameParts.get(i); + NameChecker correspondingPredicate = checkersWithPrefixChecker.get(i); + if (!correspondingPredicate.isValid(namePart)) { + return false; + } + } + return true; + } + }; + } + + @NotNull + public static Pattern pattern(@NotNull final NameChecker... checkers) { + return pattern(Arrays.asList(checkers)); + } + + @NotNull + public static Pattern any(@NotNull final Pattern... patterns) { + return new Pattern() { + @Override + public boolean apply(@NotNull FunctionDescriptor descriptor) { + for (Pattern pattern : patterns) { + if (pattern.apply(descriptor)) { + return true; + } + } + return false; + } + }; + } + + @NotNull + public static Pattern all(@NotNull final Pattern... patterns) { + return new Pattern() { + @Override + public boolean apply(@NotNull FunctionDescriptor descriptor) { + for (Pattern pattern : patterns) { + if (!pattern.apply(descriptor)) { + return false; + } + } + return true; + } + }; + } +} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/ReturnReceiverIntrinsic.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/BinaryOperationIntrinsic.java similarity index 63% rename from js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/ReturnReceiverIntrinsic.java rename to js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/BinaryOperationIntrinsic.java index 039e7b42f5a..89f788e2ca8 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/ReturnReceiverIntrinsic.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/BinaryOperationIntrinsic.java @@ -14,27 +14,20 @@ * limitations under the License. */ -package org.jetbrains.k2js.translate.intrinsic; +package org.jetbrains.k2js.translate.intrinsic.operation; import com.google.dart.compiler.backend.js.ast.JsExpression; 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; - /** * @author Pavel Talanov */ -public enum ReturnReceiverIntrinsic implements FunctionIntrinsic { +public interface BinaryOperationIntrinsic { - INSTANCE; + boolean isApplicable(@NotNull JetBinaryExpression expression, @NotNull TranslationContext context); - @NotNull - @Override - public JsExpression apply(@Nullable JsExpression receiver, @NotNull List arguments, - @NotNull TranslationContext context) { - assert receiver != null; - return receiver; - } + 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/tuple/TupleAccessIntrinsic.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/BinaryOperationIntrinsics.java similarity index 50% rename from js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/tuple/TupleAccessIntrinsic.java rename to js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/BinaryOperationIntrinsics.java index 474ddb1cd17..aca40d8fc76 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/tuple/TupleAccessIntrinsic.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/BinaryOperationIntrinsics.java @@ -14,33 +14,39 @@ * limitations under the License. */ -package org.jetbrains.k2js.translate.intrinsic.tuple; +package org.jetbrains.k2js.translate.intrinsic.operation; -import com.google.dart.compiler.backend.js.ast.JsExpression; -import com.google.dart.compiler.util.AstUtil; +import closurecompiler.internal.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 org.jetbrains.k2js.translate.intrinsic.FunctionIntrinsic; import java.util.List; /** * @author Pavel Talanov */ -public final class TupleAccessIntrinsic implements FunctionIntrinsic { - - private final int elementIndex; - - public TupleAccessIntrinsic(int elementIndex) { - this.elementIndex = elementIndex; - } +public final class BinaryOperationIntrinsics { @NotNull - @Override - public JsExpression apply(@Nullable JsExpression receiver, @NotNull List arguments, - @NotNull TranslationContext context) { - assert arguments.isEmpty() : "Tuple access expression should not have any arguments."; - return AstUtil.newArrayAccess(receiver, context.program().getNumberLiteral(elementIndex)); + 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/CompareToInstrinsic.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/CompareToInstrinsic.java new file mode 100644 index 00000000000..4690f8fcb98 --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/CompareToInstrinsic.java @@ -0,0 +1,55 @@ +/* + * Copyright 2010-2012 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.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.operation.OperatorTable; +import org.jetbrains.k2js.translate.utils.JsDescriptorUtils; + +import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptorForOperationExpression; +import static org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken; + +/** + * @author Pavel Talanov + */ +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; + } + FunctionDescriptor functionDescriptor = getFunctionDescriptorForOperationExpression(context.bindingContext(), expression); + assert functionDescriptor != null; + return JsDescriptorUtils.isStandardDeclaration(functionDescriptor); + } + + @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/EqualsIntrinsic.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/EqualsIntrinsic.java new file mode 100644 index 00000000000..81d223e349c --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/EqualsIntrinsic.java @@ -0,0 +1,68 @@ +/* + * Copyright 2010-2012 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.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.psi.JetBinaryExpression; +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.utils.JsDescriptorUtils; + +import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptorForOperationExpression; +import static org.jetbrains.k2js.translate.utils.JsAstUtils.equality; +import static org.jetbrains.k2js.translate.utils.JsAstUtils.inequality; +import static org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken; +import static org.jetbrains.k2js.translate.utils.TranslationUtils.isNullLiteral; +import static org.jetbrains.k2js.translate.utils.TranslationUtils.nullCheck; + +/** + * @author Pavel Talanov + */ +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; + } + FunctionDescriptor functionDescriptor = getFunctionDescriptorForOperationExpression(context.bindingContext(), expression); + assert functionDescriptor != null; + return JsDescriptorUtils.isStandardDeclaration(functionDescriptor); + } + + @Override + public JsExpression apply(@NotNull JetBinaryExpression expression, + @NotNull JsExpression left, + @NotNull JsExpression right, + @NotNull TranslationContext context) { + boolean isNegated = getOperationToken(expression).equals(JetTokens.EXCLEQ); + if (isNullLiteral(context, right)) { + return nullCheck(context, left, !isNegated); + } + if (isNullLiteral(context, left)) { + return nullCheck(context, right, !isNegated); + } + if (isNegated) { + return inequality(left, right); + } + else { + return equality(left, right); + } + } +} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/primitive/PrimitiveBinaryOperationIntrinsic.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/primitive/PrimitiveBinaryOperationIntrinsic.java deleted file mode 100644 index 03debc96b5c..00000000000 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/primitive/PrimitiveBinaryOperationIntrinsic.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2010-2012 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.primitive; - -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.annotations.Nullable; -import org.jetbrains.jet.lexer.JetToken; -import org.jetbrains.k2js.translate.context.TranslationContext; -import org.jetbrains.k2js.translate.intrinsic.FunctionIntrinsic; -import org.jetbrains.k2js.translate.operation.OperatorTable; - -import java.util.List; - -/** - * @author Pavel Talanov - */ -public final class PrimitiveBinaryOperationIntrinsic implements FunctionIntrinsic { - - @NotNull - public static PrimitiveBinaryOperationIntrinsic newInstance(@NotNull JetToken token) { - JsBinaryOperator operator = OperatorTable.getBinaryOperator(token); - return new PrimitiveBinaryOperationIntrinsic(operator); - } - - @NotNull - public static PrimitiveBinaryOperationIntrinsic newInstance(@NotNull JsBinaryOperator operator) { - return new PrimitiveBinaryOperationIntrinsic(operator); - } - - - @NotNull - private final JsBinaryOperator operator; - - private PrimitiveBinaryOperationIntrinsic(@NotNull JsBinaryOperator operator) { - this.operator = operator; - } - - @NotNull - @Override - public JsExpression apply(@Nullable JsExpression receiver, @NotNull List arguments, - @NotNull TranslationContext context) { - assert arguments.size() == 1 : "Binary operator should have a receiver and one argument"; - return new JsBinaryOperation(operator, receiver, arguments.get(0)); - } -} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/primitive/PrimitiveCompareToIntrinsic.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/primitive/PrimitiveCompareToIntrinsic.java deleted file mode 100644 index cba82f38df6..00000000000 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/primitive/PrimitiveCompareToIntrinsic.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2010-2012 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.primitive; - -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.annotations.Nullable; -import org.jetbrains.k2js.translate.context.TranslationContext; -import org.jetbrains.k2js.translate.intrinsic.CompareToIntrinsic; -import org.jetbrains.k2js.translate.operation.OperatorTable; - -import java.util.List; - -/** - * @author Pavel Talanov - */ -public final class PrimitiveCompareToIntrinsic extends CompareToIntrinsic { - - @NotNull - public static PrimitiveCompareToIntrinsic newInstance() { - return new PrimitiveCompareToIntrinsic(); - } - - private PrimitiveCompareToIntrinsic() { - } - - @NotNull - public JsExpression apply(@Nullable JsExpression receiver, @NotNull List arguments, - @NotNull TranslationContext context) { - assert arguments.size() == 1 : "Equals operation should have one argument"; - JsBinaryOperator operator = OperatorTable.getBinaryOperator(getComparisonToken()); - JsExpression argument = arguments.get(0); - return new JsBinaryOperation(operator, receiver, argument); - } - -} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/primitive/PrimitiveEqualsIntrinsic.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/primitive/PrimitiveEqualsIntrinsic.java deleted file mode 100644 index 76d40dfa8c9..00000000000 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/primitive/PrimitiveEqualsIntrinsic.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2010-2012 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.primitive; - -import com.google.dart.compiler.backend.js.ast.JsExpression; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.k2js.translate.context.TranslationContext; -import org.jetbrains.k2js.translate.intrinsic.EqualsIntrinsic; - -import java.util.List; - -import static org.jetbrains.k2js.translate.utils.JsAstUtils.equality; -import static org.jetbrains.k2js.translate.utils.JsAstUtils.inequality; -import static org.jetbrains.k2js.translate.utils.TranslationUtils.isNullLiteral; -import static org.jetbrains.k2js.translate.utils.TranslationUtils.nullCheck; - -/** - * @author Pavel Talanov - */ -public final class PrimitiveEqualsIntrinsic extends EqualsIntrinsic { - - @NotNull - public static PrimitiveEqualsIntrinsic newInstance() { - return new PrimitiveEqualsIntrinsic(); - } - - private PrimitiveEqualsIntrinsic() { - } - - @Override - @NotNull - public JsExpression apply(@Nullable JsExpression receiver, @NotNull List arguments, - @NotNull TranslationContext context) { - assert arguments.size() == 1 : "Equals operation should have one argument"; - assert receiver != null; - JsExpression argument = arguments.get(0); - if (isNullLiteral(context, argument)) { - return nullCheck(context, receiver, !isNegated()); - } - if (isNullLiteral(context, receiver)) { - return nullCheck(context, argument, !isNegated()); - } - if (isNegated()) { - return inequality(receiver, argument); - } - else { - return equality(receiver, argument); - } - } -} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/primitive/PrimitiveRangeToIntrinsic.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/primitive/PrimitiveRangeToIntrinsic.java deleted file mode 100644 index a7a066a4f01..00000000000 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/primitive/PrimitiveRangeToIntrinsic.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2010-2012 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.primitive; - -import com.google.dart.compiler.backend.js.ast.*; -import com.google.dart.compiler.util.AstUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.k2js.translate.context.TranslationContext; -import org.jetbrains.k2js.translate.intrinsic.FunctionIntrinsic; - -import java.util.List; - -import static org.jetbrains.k2js.translate.utils.JsAstUtils.*; - -/** - * @author Pavel Talanov - */ -public final class PrimitiveRangeToIntrinsic implements FunctionIntrinsic { - - @NotNull - public static PrimitiveRangeToIntrinsic newInstance() { - return new PrimitiveRangeToIntrinsic(); - } - - private PrimitiveRangeToIntrinsic() { - } - - @NotNull - @Override - public JsExpression apply(@Nullable JsExpression rangeStart, @NotNull List arguments, - @NotNull TranslationContext context) { - assert arguments.size() == 1 : "RangeTo must have one argument."; - assert rangeStart != null; - JsExpression rangeEnd = arguments.get(0); - JsBinaryOperation rangeSize = sum(subtract(rangeEnd, rangeStart), - context.program().getNumberLiteral(1)); - //TODO: provide a way not to hard code this value - JsNameRef expr = AstUtil.newQualifiedNameRef("Kotlin.NumberRange"); - HasArguments numberRangeConstructorInvocation = context.isEcma5() ? AstUtil.newInvocation(expr) : new JsNew(expr); - //TODO: add tests and correct expression for reversed ranges. - JsBooleanLiteral isRangeReversed = context.program().getFalseLiteral(); - setArguments(numberRangeConstructorInvocation, rangeStart, rangeSize, isRangeReversed); - return (JsExpression) numberRangeConstructorInvocation; - } -} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/primitive/PrimitiveUnaryOperationIntrinsic.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/primitive/PrimitiveUnaryOperationIntrinsic.java deleted file mode 100644 index 4287dff6bf4..00000000000 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/primitive/PrimitiveUnaryOperationIntrinsic.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2010-2012 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.primitive; - -import com.google.dart.compiler.backend.js.ast.JsExpression; -import com.google.dart.compiler.backend.js.ast.JsPrefixOperation; -import com.google.dart.compiler.backend.js.ast.JsUnaryOperator; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lexer.JetToken; -import org.jetbrains.k2js.translate.context.TranslationContext; -import org.jetbrains.k2js.translate.intrinsic.FunctionIntrinsic; -import org.jetbrains.k2js.translate.operation.OperatorTable; - -import java.util.List; - -/** - * @author Pavel Talanov - */ -public final class PrimitiveUnaryOperationIntrinsic implements FunctionIntrinsic { - - @NotNull - public static PrimitiveUnaryOperationIntrinsic newInstance(@NotNull JetToken token) { - JsUnaryOperator operator = OperatorTable.getUnaryOperator(token); - return new PrimitiveUnaryOperationIntrinsic(operator); - } - - @NotNull - private final JsUnaryOperator operator; - - private PrimitiveUnaryOperationIntrinsic(@NotNull JsUnaryOperator operator) { - this.operator = operator; - } - - @NotNull - @Override - public JsExpression apply(@Nullable JsExpression receiver, @NotNull List arguments, - @NotNull TranslationContext context) { - assert receiver != null; - assert arguments.size() == 0 : "Unary operator should not have arguments."; - //NOTE: cannot use this for increment/decrement - return new JsPrefixOperation(operator, receiver); - } -} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/string/CharAtIntrinsic.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/string/CharAtIntrinsic.java deleted file mode 100644 index 801133f36de..00000000000 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/string/CharAtIntrinsic.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2010-2012 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.string; - -import com.google.dart.compiler.backend.js.ast.JsExpression; -import com.google.dart.compiler.backend.js.ast.JsNameRef; -import com.google.dart.compiler.util.AstUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.k2js.translate.context.TranslationContext; -import org.jetbrains.k2js.translate.intrinsic.FunctionIntrinsic; - -import java.util.List; - -import static org.jetbrains.k2js.translate.utils.JsAstUtils.newInvocation; -import static org.jetbrains.k2js.translate.utils.JsAstUtils.setQualifier; - -/** - * @author Pavel Talanov - */ -public enum CharAtIntrinsic implements FunctionIntrinsic { - - INSTANCE; - - @NotNull - @Override - public JsExpression apply(@Nullable JsExpression receiver, @NotNull List arguments, - @NotNull TranslationContext context) { - assert receiver != null; - assert arguments.size() == 1 : "get Char expression must have 1 arguments."; - //TODO: provide better way - JsNameRef charAtReference = AstUtil.newQualifiedNameRef("charAt"); - setQualifier(charAtReference, receiver); - return newInvocation(charAtReference, arguments); - } -} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/operation/AssignmentTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/operation/AssignmentTranslator.java index 9d09c498eee..6504dcb1d0b 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/operation/AssignmentTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/operation/AssignmentTranslator.java @@ -29,7 +29,7 @@ import org.jetbrains.k2js.translate.reference.AccessTranslator; import static org.jetbrains.k2js.translate.utils.BindingUtils.isVariableReassignment; import static org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken; import static org.jetbrains.k2js.translate.utils.PsiUtils.isAssignment; -import static org.jetbrains.k2js.translate.utils.TranslationUtils.isIntrinsicOperation; +import static org.jetbrains.k2js.translate.utils.TranslationUtils.hasCorrespondingFunctionIntrinsic; import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateRightExpression; /** @@ -46,7 +46,7 @@ public abstract class AssignmentTranslator extends AbstractTranslator { @NotNull public static JsExpression translate(@NotNull JetBinaryExpression expression, @NotNull TranslationContext context) { - if (isIntrinsicOperation(context, expression)) { + if (hasCorrespondingFunctionIntrinsic(context, expression)) { return IntrinsicAssignmentTranslator.doTranslate(expression, context); } return OverloadedAssignmentTranslator.doTranslate(expression, context); 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 c55be86d03a..777f4ecd151 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 @@ -30,7 +30,7 @@ import org.jetbrains.jet.lexer.JetToken; import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.general.AbstractTranslator; -import org.jetbrains.k2js.translate.intrinsic.EqualsIntrinsic; +import org.jetbrains.k2js.translate.intrinsic.operation.BinaryOperationIntrinsic; import org.jetbrains.k2js.translate.reference.CallBuilder; import org.jetbrains.k2js.translate.reference.CallType; import org.jetbrains.k2js.translate.utils.JsAstUtils; @@ -40,9 +40,9 @@ import static org.jetbrains.k2js.translate.operation.CompareToTranslator.isCompa import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptorForOperationExpression; import static org.jetbrains.k2js.translate.utils.BindingUtils.getResolvedCall; import static org.jetbrains.k2js.translate.utils.JsAstUtils.not; -import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.isEquals; import static org.jetbrains.k2js.translate.utils.PsiUtils.*; -import static org.jetbrains.k2js.translate.utils.TranslationUtils.*; +import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateLeftExpression; +import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateRightExpression; /** @@ -78,6 +78,10 @@ public final class BinaryOperationTranslator extends AbstractTranslator { @NotNull private JsExpression translate() { + BinaryOperationIntrinsic intrinsic = getIntrinsicForExpression(); + if (intrinsic != null) { + return applyIntrinsic(intrinsic); + } if (isElvisOperator(expression)) { return translateAsElvisOperator(expression); } @@ -92,12 +96,22 @@ public final class BinaryOperationTranslator extends AbstractTranslator { } assert operationDescriptor != null : "Overloadable operations must have not null descriptor"; - if (isEquals(operationDescriptor) && context().intrinsics().isIntrinsic(operationDescriptor)) { - return translateAsEqualsIntrinsic(); - } return translateAsOverloadedBinaryOperation(); } + @Nullable + private BinaryOperationIntrinsic getIntrinsicForExpression() { + return context().intrinsics().getBinaryOperationIntrinsics().getIntrinsic(expression, context()); + } + + @NotNull + private JsExpression applyIntrinsic(@NotNull BinaryOperationIntrinsic intrinsic) { + return intrinsic.apply(expression, + translateLeftExpression(context(), expression), + translateRightExpression(context(), expression), + context()); + } + private static boolean isElvisOperator(@NotNull JetBinaryExpression expression) { return getOperationToken(expression).equals(JetTokens.ELVIS); } @@ -115,14 +129,6 @@ public final class BinaryOperationTranslator extends AbstractTranslator { return operationDescriptor == null; } - @NotNull - private JsExpression translateAsEqualsIntrinsic() { - assert operationDescriptor != null : "Equals operation must resolve to descriptor."; - EqualsIntrinsic intrinsic = context().intrinsics().getEqualsIntrinsic(operationDescriptor); - intrinsic.setNegated(expression.getOperationToken().equals(JetTokens.EXCLEQ)); - return applyIntrinsicToBinaryExpression(context(), intrinsic, expression); - } - @NotNull private JsExpression translateAsUnOverloadableBinaryOperation() { JetToken token = getOperationToken(expression); diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/operation/CompareToTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/operation/CompareToTranslator.java index 5e6c63b6d6e..04e1ea961d2 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/operation/CompareToTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/operation/CompareToTranslator.java @@ -23,17 +23,13 @@ import org.jetbrains.annotations.NotNull; 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.jet.lexer.JetToken; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.general.AbstractTranslator; -import org.jetbrains.k2js.translate.intrinsic.CompareToIntrinsic; import org.jetbrains.k2js.translate.utils.TranslationUtils; import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptorForOperationExpression; import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.isCompareTo; import static org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken; -import static org.jetbrains.k2js.translate.utils.TranslationUtils.applyIntrinsicToBinaryExpression; -import static org.jetbrains.k2js.translate.utils.TranslationUtils.isIntrinsicOperation; /** * @author Pavel Talanov @@ -41,7 +37,7 @@ import static org.jetbrains.k2js.translate.utils.TranslationUtils.isIntrinsicOpe public final class CompareToTranslator extends AbstractTranslator { public static boolean isCompareToCall(@NotNull JetBinaryExpression expression, - @NotNull TranslationContext context) { + @NotNull TranslationContext context) { FunctionDescriptor operationDescriptor = getFunctionDescriptorForOperationExpression(context.bindingContext(), expression); @@ -52,47 +48,27 @@ public final class CompareToTranslator extends AbstractTranslator { @NotNull public static JsExpression translate(@NotNull JetBinaryExpression expression, - @NotNull TranslationContext context) { + @NotNull TranslationContext context) { return (new CompareToTranslator(expression, context)).translate(); } @NotNull private final JetBinaryExpression expression; - @NotNull - private final FunctionDescriptor descriptor; - private CompareToTranslator(@NotNull JetBinaryExpression expression, - @NotNull TranslationContext context) { + @NotNull TranslationContext context) { super(context); this.expression = expression; FunctionDescriptor functionDescriptor = getFunctionDescriptorForOperationExpression(context.bindingContext(), expression); assert functionDescriptor != null : "CompareTo should always have a descriptor"; - this.descriptor = functionDescriptor; assert (OperatorConventions.COMPARISON_OPERATIONS.contains(getOperationToken(expression))); } @NotNull private JsExpression translate() { - if (isIntrinsicOperation(context(), expression)) { - return intrinsicCompareTo(); - } - return overloadedCompareTo(); - } - - @NotNull - private JsExpression overloadedCompareTo() { JsBinaryOperator correspondingOperator = OperatorTable.getBinaryOperator(getOperationToken(expression)); JsExpression methodCall = BinaryOperationTranslator.translateAsOverloadedCall(expression, context()); return new JsBinaryOperation(correspondingOperator, methodCall, TranslationUtils.zeroLiteral(context())); } - - @NotNull - private JsExpression intrinsicCompareTo() { - CompareToIntrinsic intrinsic = context().intrinsics().getCompareToIntrinsic(descriptor); - intrinsic.setComparisonToken((JetToken) expression.getOperationToken()); - return applyIntrinsicToBinaryExpression(context(), intrinsic, expression); - } - } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/operation/IncrementTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/operation/IncrementTranslator.java index ccbaa7056ba..2a6dcdc3433 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/operation/IncrementTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/operation/IncrementTranslator.java @@ -34,7 +34,7 @@ import static org.jetbrains.k2js.translate.reference.AccessTranslationUtils.getC import static org.jetbrains.k2js.translate.utils.JsAstUtils.newSequence; import static org.jetbrains.k2js.translate.utils.PsiUtils.*; import static org.jetbrains.k2js.translate.utils.TemporariesUtils.temporariesInitialization; -import static org.jetbrains.k2js.translate.utils.TranslationUtils.isIntrinsicOperation; +import static org.jetbrains.k2js.translate.utils.TranslationUtils.hasCorrespondingFunctionIntrinsic; /** * @author Pavel Talanov @@ -49,7 +49,7 @@ public abstract class IncrementTranslator extends AbstractTranslator { @NotNull public static JsExpression translate(@NotNull JetUnaryExpression expression, @NotNull TranslationContext context) { - if (isIntrinsicOperation(context, expression)) { + if (hasCorrespondingFunctionIntrinsic(context, expression)) { return IntrinsicIncrementTranslator.doTranslate(expression, context); } return (new OverloadedIncrementTranslator(expression, context)).translateIncrementExpression(); diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.java index 6a996ee06ed..da3a8a80ce3 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.java @@ -27,7 +27,7 @@ import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.jet.lang.resolve.calls.VariableAsFunctionResolvedCall; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.general.AbstractTranslator; -import org.jetbrains.k2js.translate.intrinsic.FunctionIntrinsic; +import org.jetbrains.k2js.translate.intrinsic.functions.basic.FunctionIntrinsic; import org.jetbrains.k2js.translate.utils.AnnotationsUtils; import org.jetbrains.k2js.translate.utils.ErrorReportingUtils; @@ -119,14 +119,19 @@ public final class CallTranslator extends AbstractTranslator { } private boolean isIntrinsic() { - return context().intrinsics().isIntrinsic(descriptor); + if (descriptor instanceof FunctionDescriptor) { + FunctionIntrinsic intrinsic = context().intrinsics().getFunctionIntrinsics().getIntrinsic((FunctionDescriptor) descriptor); + return intrinsic.exists(); + } + return false; } @NotNull private JsExpression intrinsicInvocation() { assert descriptor instanceof FunctionDescriptor; try { - FunctionIntrinsic intrinsic = context().intrinsics().getIntrinsic((FunctionDescriptor) descriptor); + FunctionIntrinsic intrinsic = context().intrinsics().getFunctionIntrinsics().getIntrinsic((FunctionDescriptor) descriptor); + assert intrinsic.exists(); return intrinsic.apply(callParameters.getThisOrReceiverOrNull(), arguments, context()); } catch (RuntimeException e) { diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsDescriptorUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsDescriptorUtils.java index e2af7076984..8f66cdc5a84 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsDescriptorUtils.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsDescriptorUtils.java @@ -25,17 +25,19 @@ import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.DescriptorUtils; -import org.jetbrains.jet.lang.resolve.name.Name; -import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; +import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.expressions.OperatorConventions; +import org.jetbrains.jet.lang.types.lang.JetStandardLibrary; import org.jetbrains.k2js.config.LibrarySourcesConfig; +import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Set; import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isClassObject; +import static org.jetbrains.k2js.translate.utils.BindingUtils.isNotAny; /** * @author Pavel Talanov @@ -53,10 +55,6 @@ public final class JsDescriptorUtils { return (valueParametersCount(functionDescriptor) > 0); } - public static boolean isEquals(@NotNull FunctionDescriptor functionDescriptor) { - return (functionDescriptor.getName().equals(OperatorConventions.EQUALS)); - } - public static boolean isCompareTo(@NotNull FunctionDescriptor functionDescriptor) { return (functionDescriptor.getName().equals(OperatorConventions.COMPARE_TO)); } @@ -65,34 +63,6 @@ public final class JsDescriptorUtils { return (descriptor instanceof ConstructorDescriptor); } - @NotNull - public static FunctionDescriptor getFunctionByName(@NotNull JetScope scope, - @NotNull Name name) { - Collection functionDescriptors = scope.getFunctions(name); - assert functionDescriptors.size() == 1 : - "In scope " + scope + " supposed to be exactly one " + name + " function.\n" + - "Found: " + functionDescriptors.size(); - //noinspection LoopStatementThatDoesntLoop - for (FunctionDescriptor descriptor : functionDescriptors) { - return descriptor; - } - throw new AssertionError("In scope " + scope - + " supposed to be exactly one " + name + " function."); - } - - //TODO: some strange stuff happening to this method - //TODO: inspect - @NotNull - public static PropertyDescriptor getPropertyByName(@NotNull JetScope scope, - @NotNull Name name) { - Collection variables = scope.getProperties(name); - assert variables.size() == 1 : "Actual size: " + variables.size(); - VariableDescriptor variable = variables.iterator().next(); - PropertyDescriptor descriptor = (PropertyDescriptor)variable; - assert descriptor != null : "Must have a descriptor."; - return descriptor; - } - @Nullable public static ClassDescriptor findAncestorClass(@NotNull List superclassDescriptors) { for (ClassDescriptor descriptor : superclassDescriptors) { @@ -103,9 +73,31 @@ public final class JsDescriptorUtils { return null; } + @NotNull + public static List getSuperclassDescriptors(@NotNull ClassDescriptor classDescriptor) { + Collection superclassTypes = classDescriptor.getTypeConstructor().getSupertypes(); + List superClassDescriptors = new ArrayList(); + for (JetType type : superclassTypes) { + ClassDescriptor result = getClassDescriptorForType(type); + if (isNotAny(result)) { + superClassDescriptors.add(result); + } + } + return superClassDescriptors; + } + @Nullable public static ClassDescriptor getSuperclass(@NotNull ClassDescriptor classDescriptor) { - return findAncestorClass(DescriptorUtils.getSuperclassDescriptors(classDescriptor)); + return findAncestorClass(getSuperclassDescriptors(classDescriptor)); + } + + @NotNull + public static ClassDescriptor getClassDescriptorForType(@NotNull JetType type) { + DeclarationDescriptor superClassDescriptor = + type.getConstructor().getDeclarationDescriptor(); + assert superClassDescriptor instanceof ClassDescriptor + : "Superclass descriptor of a type should be of type ClassDescriptor"; + return (ClassDescriptor) superClassDescriptor; } @@ -132,9 +124,9 @@ public final class JsDescriptorUtils { @NotNull public static DeclarationDescriptor getDeclarationDescriptorForReceiver - (@NotNull ReceiverDescriptor receiverParameter) { + (@NotNull ReceiverDescriptor receiverParameter) { DeclarationDescriptor declarationDescriptor = - receiverParameter.getType().getConstructor().getDeclarationDescriptor(); + receiverParameter.getType().getConstructor().getDeclarationDescriptor(); //TODO: WHY assert? assert declarationDescriptor != null; return declarationDescriptor.getOriginal(); @@ -155,13 +147,26 @@ public final class JsDescriptorUtils { DeclarationDescriptor containing = descriptor.getContainingDeclaration(); while (containing != null) { if (containing instanceof ClassDescriptor && !isClassObject(containing)) { - return (ClassDescriptor)containing; + return (ClassDescriptor) containing; } containing = containing.getContainingDeclaration(); } return null; } + @Nullable + public static NamespaceDescriptor getContainingNamespace(@NotNull DeclarationDescriptor descriptor) { + return DescriptorUtils.getParentOfType(descriptor, NamespaceDescriptor.class); + } + + public static boolean isStandardDeclaration(@NotNull DeclarationDescriptor descriptor) { + NamespaceDescriptor namespace = getContainingNamespace(descriptor); + if (namespace == null) { + return false; + } + return namespace.equals(JetStandardLibrary.getInstance().getLibraryScope().getContainingDeclaration()); + } + @NotNull public static List getNestedNamespaces(@NotNull NamespaceDescriptor namespaceDescriptor, @NotNull BindingContext context) { @@ -232,7 +237,7 @@ public final class JsDescriptorUtils { while (!(current.getContainingDeclaration() instanceof ModuleDescriptor)) { result.add(current); if (current.getContainingDeclaration() instanceof NamespaceDescriptor) { - current = (NamespaceDescriptor)current.getContainingDeclaration(); + current = (NamespaceDescriptor) current.getContainingDeclaration(); assert current != null; } else { diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java index cc9c59e5ba1..5068c1e0338 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java @@ -26,10 +26,8 @@ import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.general.Translation; -import org.jetbrains.k2js.translate.intrinsic.FunctionIntrinsic; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import static com.google.dart.compiler.util.AstUtil.newAssignment; @@ -205,13 +203,12 @@ public final class TranslationUtils { return Translation.translateAsExpression(rightExpression, context); } - public static boolean isIntrinsicOperation(@NotNull TranslationContext context, + public static boolean hasCorrespondingFunctionIntrinsic(@NotNull TranslationContext context, @NotNull JetOperationExpression expression) { - FunctionDescriptor operationDescriptor = - BindingUtils.getFunctionDescriptorForOperationExpression(context.bindingContext(), expression); + FunctionDescriptor operationDescriptor = getFunctionDescriptorForOperationExpression(context.bindingContext(), expression); if (operationDescriptor == null) return true; - if (context.intrinsics().isIntrinsic(operationDescriptor)) return true; + if (context.intrinsics().getFunctionIntrinsics().getIntrinsic(operationDescriptor).exists()) return true; return false; } @@ -232,15 +229,6 @@ public final class TranslationUtils { return context.program().getNumberLiteral(0); } - @NotNull - public static JsExpression applyIntrinsicToBinaryExpression(@NotNull TranslationContext context, - @NotNull FunctionIntrinsic intrinsic, - @NotNull JetBinaryExpression binaryExpression) { - JsExpression left = translateLeftExpression(context, binaryExpression); - JsExpression right = translateRightExpression(context, binaryExpression); - return intrinsic.apply(left, Arrays.asList(right), context); - } - @Nullable public static JsExpression resolveThisObjectForResolvedCall(@NotNull ResolvedCall call, @NotNull TranslationContext context) {