diff --git a/translator/src/org/jetbrains/k2js/translate/context/DeclarationVisitor.java b/translator/src/org/jetbrains/k2js/translate/context/DeclarationVisitor.java index bed353eb914..82b94cbafe9 100644 --- a/translator/src/org/jetbrains/k2js/translate/context/DeclarationVisitor.java +++ b/translator/src/org/jetbrains/k2js/translate/context/DeclarationVisitor.java @@ -5,6 +5,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; +import java.util.Set; + import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getNameForNamespace; import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getOwnDeclarations; @@ -41,6 +43,7 @@ public final class DeclarationVisitor extends DeclarationDescriptorVisitor overriddenDescriptors = descriptor.getOverriddenDescriptors(); + for (FunctionDescriptor overriddenDescriptor : overriddenDescriptors) { + if (declarations.hasDeclaredName(overriddenDescriptor)) { + declarations.putName(descriptor, declarations.getName(overriddenDescriptor)); + declareScope(descriptor, context, "function " + descriptor.getName()); + return true; + } + } + return false; + } + @Override public Void visitPropertyDescriptor(@NotNull PropertyDescriptor descriptor, @NotNull DeclarationContext context) { String propertyName = descriptor.getName(); diff --git a/translator/src/org/jetbrains/k2js/translate/context/StandardClasses.java b/translator/src/org/jetbrains/k2js/translate/context/StandardClasses.java index 64954422c55..1a1c8435542 100644 --- a/translator/src/org/jetbrains/k2js/translate/context/StandardClasses.java +++ b/translator/src/org/jetbrains/k2js/translate/context/StandardClasses.java @@ -33,9 +33,16 @@ public final class StandardClasses { declareJavaArrayList(standardClasses); declareJavaSystem(standardClasses); declareJavaInteger(standardClasses); + declareJavaUtilIterator(standardClasses); return standardClasses; } + private static void declareJavaUtilIterator(@NotNull StandardClasses standardClasses) { + String iteratorFQName = ".java.util.Iterator"; + standardClasses.declareStandardTopLevelObject(iteratorFQName, "Iterator"); + declareMethods(standardClasses, iteratorFQName, "next", "hasNext"); + } + private static void declareString(@NotNull StandardClasses standardClasses) { String stringFQName = "jet.String"; standardClasses.declareStandardTopLevelObject(stringFQName, "String"); diff --git a/translator/src/org/jetbrains/k2js/translate/context/StaticContext.java b/translator/src/org/jetbrains/k2js/translate/context/StaticContext.java index b992050c699..3bc2d357f51 100644 --- a/translator/src/org/jetbrains/k2js/translate/context/StaticContext.java +++ b/translator/src/org/jetbrains/k2js/translate/context/StaticContext.java @@ -119,9 +119,7 @@ public class StaticContext { @NotNull public JsName getGlobalName(@NotNull DeclarationDescriptor descriptor) { - JsName nameToDeclare = declarations.getName(descriptor); - //nameToDeclare.setObfuscatable(false); - return nameToDeclare; + return declarations.getName(descriptor); } public boolean isDeclared(@NotNull DeclarationDescriptor descriptor) { diff --git a/translator/src/org/jetbrains/k2js/translate/expression/ForTranslator.java b/translator/src/org/jetbrains/k2js/translate/expression/ForTranslator.java index aa61f420baf..e1a56755c2d 100644 --- a/translator/src/org/jetbrains/k2js/translate/expression/ForTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/expression/ForTranslator.java @@ -3,6 +3,8 @@ package org.jetbrains.k2js.translate.expression; import com.google.dart.compiler.backend.js.ast.*; import com.google.dart.compiler.util.AstUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.CallableDescriptor; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetForExpression; import org.jetbrains.jet.lang.psi.JetParameter; @@ -10,7 +12,9 @@ import org.jetbrains.k2js.translate.context.TemporaryVariable; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.general.AbstractTranslator; import org.jetbrains.k2js.translate.general.Translation; +import org.jetbrains.k2js.translate.reference.CallTranslator; +import static org.jetbrains.k2js.translate.utils.BindingUtils.*; import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopBody; import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopParameter; @@ -58,28 +62,22 @@ public final class ForTranslator extends AbstractTranslator { @NotNull private JsExpression nextMethodInvocation(@NotNull TemporaryVariable iterator) { - return callStandardMethodOnExpression("next", iterator.nameReference()); + FunctionDescriptor nextFunction = getNextFunction(context().bindingContext(), getLoopRange()); + return CallTranslator.translate(iterator.nameReference(), nextFunction, context()); } @NotNull private JsExpression hasNextMethodInvocation(@NotNull TemporaryVariable iterator) { - return callStandardMethodOnExpression("hasNext", iterator.nameReference()); - } - - @NotNull - private JsExpression callStandardMethodOnExpression(@NotNull String methodName, @NotNull JsNameRef expression) { - JsNameRef hasNext = AstUtil.newQualifiedNameRef(methodName); - AstUtil.setQualifier(hasNext, expression); - return AstUtil.newInvocation(hasNext); + CallableDescriptor hasNextFunction = getHasNextCallable(context().bindingContext(), getLoopRange()); + return CallTranslator.translate(iterator.nameReference(), hasNextFunction, context()); } @NotNull private JsExpression iteratorMethodInvocation() { JetExpression rangeExpression = getLoopRange(); JsExpression range = Translation.translateAsExpression(rangeExpression, context()); - JsNameRef iteratorMethodReference = AstUtil.newQualifiedNameRef("iterator"); - AstUtil.setQualifier(iteratorMethodReference, range); - return AstUtil.newInvocation(iteratorMethodReference); + FunctionDescriptor iteratorFunction = getIteratorFunction(context().bindingContext(), rangeExpression); + return CallTranslator.translate(range, iteratorFunction, context()); } @NotNull diff --git a/translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.java b/translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.java index 77df685d7a9..b3683741075 100644 --- a/translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.java @@ -126,6 +126,12 @@ public final class CallTranslator extends AbstractTranslator { } } + @NotNull + public static JsExpression translate(@NotNull JsExpression receiver, @NotNull CallableDescriptor functionDescriptor, + @NotNull TranslationContext context) { + return (new CallTranslator(receiver, Collections.emptyList(), functionDescriptor, context)).translate(); + } + @NotNull public static JsExpression translate(@NotNull JetUnaryExpression unaryExpression, @NotNull TranslationContext context) { @@ -173,14 +179,14 @@ public final class CallTranslator extends AbstractTranslator { private final List arguments; @NotNull - private final FunctionDescriptor functionDescriptor; + private final CallableDescriptor descriptor; private CallTranslator(@Nullable JsExpression receiver, @NotNull List arguments, - @NotNull FunctionDescriptor descriptor, @NotNull TranslationContext context) { + @NotNull CallableDescriptor descriptor, @NotNull TranslationContext context) { super(context); this.receiver = receiver; this.arguments = arguments; - this.functionDescriptor = descriptor; + this.descriptor = descriptor; } @NotNull @@ -206,12 +212,14 @@ public final class CallTranslator extends AbstractTranslator { } private boolean isExtensionFunction() { - return DescriptorUtils.isExtensionFunction(functionDescriptor); + return DescriptorUtils.isExtensionFunction(descriptor); } @NotNull private JsExpression intrinsicInvocation() { - FunctionIntrinsic functionIntrinsic = context().intrinsics().getFunctionIntrinsic(functionDescriptor); + assert descriptor instanceof FunctionDescriptor; + FunctionIntrinsic functionIntrinsic = + context().intrinsics().getFunctionIntrinsic((FunctionDescriptor) descriptor); assert receiver != null : "Functions that have functionIntrinsic implementation should have a receiver."; return functionIntrinsic.apply(receiver, arguments, context()); } @@ -222,25 +230,25 @@ public final class CallTranslator extends AbstractTranslator { } private boolean isConstructor() { - return isConstructorDescriptor(functionDescriptor); + return isConstructorDescriptor(descriptor); } private boolean isIntrinsic() { - return context().intrinsics().isIntrinsic(functionDescriptor); + return context().intrinsics().isIntrinsic(descriptor); } @NotNull private JsExpression calleeReference() { - if (DescriptorUtils.isVariableDescriptor(functionDescriptor)) { + if (DescriptorUtils.isVariableDescriptor(descriptor)) { //TODO: write tests on this cases VariableDescriptor variableDescriptor = - getVariableDescriptorForVariableAsFunction((VariableAsFunctionDescriptor) functionDescriptor); + getVariableDescriptorForVariableAsFunction((VariableAsFunctionDescriptor) descriptor); if (variableDescriptor instanceof PropertyDescriptor) { return getterCall((PropertyDescriptor) variableDescriptor); } return qualifiedMethodReference(variableDescriptor); } - return qualifiedMethodReference(functionDescriptor); + return qualifiedMethodReference(descriptor); } @NotNull @@ -261,7 +269,7 @@ public final class CallTranslator extends AbstractTranslator { @NotNull private JsExpression extensionFunctionReference(@NotNull JsExpression methodReference) { - JsExpression qualifier = TranslationUtils.getExtensionFunctionImplicitReceiver(context(), functionDescriptor); + JsExpression qualifier = TranslationUtils.getExtensionFunctionImplicitReceiver(context(), descriptor); if (qualifier != null) { AstUtil.setQualifier(methodReference, qualifier); } @@ -270,7 +278,7 @@ public final class CallTranslator extends AbstractTranslator { @NotNull private JsExpression constructorCall() { - JsNew constructorCall = new JsNew(qualifiedMethodReference(functionDescriptor)); + JsNew constructorCall = new JsNew(qualifiedMethodReference(descriptor)); constructorCall.setArguments(arguments); return constructorCall; } diff --git a/translator/src/org/jetbrains/k2js/translate/utils/BindingUtils.java b/translator/src/org/jetbrains/k2js/translate/utils/BindingUtils.java index e03ca37cbbc..a52d031cc4b 100644 --- a/translator/src/org/jetbrains/k2js/translate/utils/BindingUtils.java +++ b/translator/src/org/jetbrains/k2js/translate/utils/BindingUtils.java @@ -22,13 +22,13 @@ import static org.jetbrains.k2js.translate.utils.DescriptorUtils.isVariableDescr * @author Pavel Talanov *

* This class contains some code related to BindingContext use. Intention is not to pollute other classes. + * Every call to BindingContext.get() is supposed to be wrapped by this utility class. */ public final class BindingUtils { private BindingUtils() { } - @NotNull static private D getDescriptorForExpression(@NotNull BindingContext context, @NotNull E expression, Class descriptorClass) { @@ -298,4 +298,36 @@ public final class BindingUtils { return defaultValue; } + @NotNull + public static JetType getTypeForExpression(@NotNull BindingContext context, + @NotNull JetExpression expression) { + JetType jetType = context.get(BindingContext.EXPRESSION_TYPE, expression); + assert jetType != null : "Expression must have a type."; + return jetType; + } + + @NotNull + public static FunctionDescriptor getIteratorFunction(@NotNull BindingContext context, + @NotNull JetExpression rangeExpression) { + FunctionDescriptor functionDescriptor = context.get(BindingContext.LOOP_RANGE_ITERATOR, rangeExpression); + assert functionDescriptor != null : "Range expression must have a descriptor for iterator function."; + return functionDescriptor; + } + + @NotNull + public static FunctionDescriptor getNextFunction(@NotNull BindingContext context, + @NotNull JetExpression rangeExpression) { + FunctionDescriptor functionDescriptor = context.get(BindingContext.LOOP_RANGE_NEXT, rangeExpression); + assert functionDescriptor != null : "Range expression must have a descriptor for next function."; + return functionDescriptor; + } + + @NotNull + public static CallableDescriptor getHasNextCallable(@NotNull BindingContext context, + @NotNull JetExpression rangeExpression) { + CallableDescriptor hasNextDescriptor = context.get(BindingContext.LOOP_RANGE_HAS_NEXT, rangeExpression); + assert hasNextDescriptor != null : "Range expression must have a descriptor for hasNext function or property."; + return hasNextDescriptor; + } + } diff --git a/translator/src/org/jetbrains/k2js/translate/utils/DescriptorUtils.java b/translator/src/org/jetbrains/k2js/translate/utils/DescriptorUtils.java index 78e1894777a..2f093d991cc 100644 --- a/translator/src/org/jetbrains/k2js/translate/utils/DescriptorUtils.java +++ b/translator/src/org/jetbrains/k2js/translate/utils/DescriptorUtils.java @@ -35,7 +35,7 @@ public final class DescriptorUtils { return (functionDescriptor.getName().equals(OperatorConventions.COMPARE_TO)); } - public static boolean isConstructorDescriptor(@NotNull FunctionDescriptor descriptor) { + public static boolean isConstructorDescriptor(@NotNull CallableDescriptor descriptor) { return (descriptor instanceof ConstructorDescriptor); } @@ -71,7 +71,8 @@ public final class DescriptorUtils { @NotNull String name) { Set functionDescriptors = scope.getFunctions(name); assert functionDescriptors.size() == 1 : - "In scope " + scope + " supposed to be exactly one " + name + " function."; + "In scope " + scope + " supposed to be exactly one " + name + " function.\n" + + "Found: " + functionDescriptors.size(); //noinspection LoopStatementThatDoesntLoop for (FunctionDescriptor descriptor : functionDescriptors) { return descriptor; @@ -122,7 +123,7 @@ public final class DescriptorUtils { return containing; } - public static boolean isExtensionFunction(@NotNull FunctionDescriptor functionDescriptor) { + public static boolean isExtensionFunction(@NotNull CallableDescriptor functionDescriptor) { return (functionDescriptor.getReceiverParameter().exists()); } diff --git a/translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java b/translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java index ceb9ed94234..43825db283a 100644 --- a/translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java +++ b/translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java @@ -4,6 +4,7 @@ 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.CallableDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; @@ -210,7 +211,7 @@ public final class TranslationUtils { @Nullable public static JsExpression getExtensionFunctionImplicitReceiver(@NotNull TranslationContext context, - @NotNull FunctionDescriptor descriptor) { + @NotNull CallableDescriptor descriptor) { return getImplicitReceiverBasedOnOwner(context, descriptor); } diff --git a/translator/testFiles/kotlin_lib.js b/translator/testFiles/kotlin_lib.js index f5b1c000bcb..e62cd2728a6 100644 --- a/translator/testFiles/kotlin_lib.js +++ b/translator/testFiles/kotlin_lib.js @@ -16,7 +16,6 @@ function $A(iterable) { } - function keys(object) { if (Type(object) !== OBJECT_TYPE) { throw new TypeError(); @@ -284,7 +283,7 @@ Kotlin.Array = Class.create({ iterator:function () { return new Kotlin.ArrayIterator(this); }, - indices:function() { + indices:function () { return new Kotlin.NumberRange(0, this.size(), false); } }); @@ -398,8 +397,20 @@ Kotlin.System = function () { }; }(); +Kotlin.AbstractFunctionInvokationError = Class.create(); -Kotlin.ArrayIterator = Class.create({ +Kotlin.Iterator = Class.create({ + initialize:function () { + }, + next:function () { + throw new Kotlin.AbstractFunctionInvokationError(); + }, + hasNext:function () { + throw new Kotlin.AbstractFunctionInvokationError(); + } +}); + +Kotlin.ArrayIterator = Class.create(Kotlin.Iterator, { initialize:function (array) { this.array = array; this.index = 0; @@ -412,36 +423,37 @@ Kotlin.ArrayIterator = Class.create({ } }); -Kotlin.RangeIterator = Kotlin.Class.create({initialize:function (start, count, reversed) { - this.$start = start; - this.$count = count; - this.$reversed = reversed; - this.$i = this.get_start(); -}, get_start:function () { - return this.$start; -}, get_count:function () { - return this.$count; -}, set_count:function (tmp$0) { - this.$count = tmp$0; -}, get_reversed:function () { - return this.$reversed; -}, get_i:function () { - return this.$i; -}, set_i:function (tmp$0) { - this.$i = tmp$0; -}, next:function () { - this.set_count(this.get_count() - 1); - if (this.get_reversed()) { - this.set_i(this.get_i() - 1); - return this.get_i() + 1; +Kotlin.RangeIterator = Kotlin.Class.create(Kotlin.Iterator, { + initialize:function (start, count, reversed) { + this.$start = start; + this.$count = count; + this.$reversed = reversed; + this.$i = this.get_start(); + }, get_start:function () { + return this.$start; + }, get_count:function () { + return this.$count; + }, set_count:function (tmp$0) { + this.$count = tmp$0; + }, get_reversed:function () { + return this.$reversed; + }, get_i:function () { + return this.$i; + }, set_i:function (tmp$0) { + this.$i = tmp$0; + }, next:function () { + this.set_count(this.get_count() - 1); + if (this.get_reversed()) { + this.set_i(this.get_i() - 1); + return this.get_i() + 1; + } + else { + this.set_i(this.get_i() + 1); + return this.get_i() - 1; + } + }, hasNext:function () { + return this.get_count() > 0; } - else { - this.set_i(this.get_i() + 1); - return this.get_i() - 1; - } -}, hasNext:function () { - return this.get_count() > 0; -} }); Kotlin.NumberRange = Kotlin.Class.create({initialize:function (start, size, reversed) {