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 cec4259636f..eeed6a3cb09 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 @@ -16,18 +16,25 @@ package org.jetbrains.k2js.translate.reference; -import com.google.dart.compiler.backend.js.ast.*; +import com.google.dart.compiler.backend.js.ast.JsExpression; +import com.google.dart.compiler.backend.js.ast.JsInvocation; +import com.google.dart.compiler.backend.js.ast.JsNameRef; +import com.google.dart.compiler.backend.js.ast.JsNew; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; -import org.jetbrains.jet.lang.resolve.calls.util.ExpressionAsFunctionDescriptor; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall; +import org.jetbrains.jet.lang.resolve.calls.util.ExpressionAsFunctionDescriptor; +import org.jetbrains.jet.lang.resolve.name.Name; +import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.general.AbstractTranslator; import org.jetbrains.k2js.translate.intrinsic.functions.basic.FunctionIntrinsic; +import org.jetbrains.k2js.translate.intrinsic.functions.patterns.NamePredicate; import org.jetbrains.k2js.translate.utils.AnnotationsUtils; import org.jetbrains.k2js.translate.utils.ErrorReportingUtils; +import org.jetbrains.k2js.translate.utils.JsDescriptorUtils; import java.util.ArrayList; import java.util.List; @@ -145,20 +152,37 @@ public final class CallTranslator extends AbstractTranslator { @NotNull private JsExpression constructorCall() { - JsExpression constructorReference = translateAsFunctionWithNoThisObject(descriptor); - JsExpression constructorCall = createConstructorCallExpression(constructorReference); - assert constructorCall instanceof HasArguments : "Constructor call should be expression with arguments."; - ((HasArguments) constructorCall).getArguments().addAll(arguments); - return constructorCall; + JsExpression constructorReference; + ClassDescriptor classDescriptor = (ClassDescriptor) descriptor.getContainingDeclaration(); + boolean isSet = false; + if (AnnotationsUtils.isLibraryObject(classDescriptor) && + (classDescriptor.getName().asString().equals("HashMap") || (isSet = classDescriptor.getName().asString().equals("HashSet")))) { + JetType keyType = resolvedCall.getTypeArguments().values().iterator().next(); + Name keyTypeName = JsDescriptorUtils.getNameIfStandardType(keyType); + String collectionClassName; + if (keyTypeName != null && (NamePredicate.PRIMITIVE_NUMBERS.apply(keyTypeName) || keyTypeName.asString().equals("String"))) { + collectionClassName = isSet ? "PrimitiveHashSet" : "PrimitiveHashMap"; + } + else { + collectionClassName = isSet ? "ComplexHashSet" : "ComplexHashMap"; + } + + constructorReference = context().namer().kotlin(collectionClassName); + } + else { + constructorReference = translateAsFunctionWithNoThisObject(descriptor); + } + + return createConstructorCallExpression(constructorReference); } @NotNull private JsExpression createConstructorCallExpression(@NotNull JsExpression constructorReference) { if (context().isEcma5() && !AnnotationsUtils.isNativeObject(resolvedCall.getCandidateDescriptor())) { - return new JsInvocation(constructorReference); + return new JsInvocation(constructorReference, arguments); } else { - return new JsNew(constructorReference); + return new JsNew(constructorReference, arguments); } } diff --git a/js/js.translator/testFiles/kotlin_lib.js b/js/js.translator/testFiles/kotlin_lib.js index cf4b0008f47..b325a5aa63b 100644 --- a/js/js.translator/testFiles/kotlin_lib.js +++ b/js/js.translator/testFiles/kotlin_lib.js @@ -75,6 +75,7 @@ var kotlin = {set:function (receiver, key, value) { Kotlin.Exception = Kotlin.$createClass(); Kotlin.RuntimeException = Kotlin.$createClass(Kotlin.Exception); + Kotlin.IndexOutOfBounds = Kotlin.$createClass(Kotlin.Exception); Kotlin.NullPointerException = Kotlin.$createClass(Kotlin.Exception); Kotlin.NoSuchElementException = Kotlin.$createClass(Kotlin.Exception); Kotlin.IllegalArgumentException = Kotlin.$createClass(Kotlin.Exception); @@ -139,34 +140,28 @@ var kotlin = {set:function (receiver, key, value) { Kotlin.Collection = Kotlin.$createClass(); - Kotlin.AbstractList = Kotlin.$createClass(Kotlin.Collection, { - iterator: function () { - return Kotlin.$new(ListIterator)(this); - }, - isEmpty: function () { - return this.size() === 0; + Kotlin.AbstractCollection = Kotlin.$createClass(Kotlin.Collection, { + size: function () { + return this.$size; }, addAll: function (collection) { var it = collection.iterator(); - var i = this.$size; + var i = this.size(); while (i-- > 0) { this.add(it.next()); } }, - remove: function (o) { - var index = this.indexOf(o); - if (index !== -1) { - this.removeAt(index); - } + isEmpty: function () { + return this.size() === 0; }, - contains: function (o) { - return this.indexOf(o) !== -1; + iterator: function () { + return Kotlin.$new(ArrayIterator)(this.toArray()); }, equals: function (o) { - if (this.$size === o.$size) { + if (this.size() === o.size()) { var iterator1 = this.iterator(); var iterator2 = o.iterator(); - var i = this.$size; + var i = this.size(); while (i-- > 0) { if (!Kotlin.equals(iterator1.next(), iterator2.next())) { return false; @@ -197,6 +192,21 @@ var kotlin = {set:function (receiver, key, value) { } }); + Kotlin.AbstractList = Kotlin.$createClass(Kotlin.AbstractCollection, { + iterator: function () { + return Kotlin.$new(ListIterator)(this); + }, + remove: function (o) { + var index = this.indexOf(o); + if (index !== -1) { + this.removeAt(index); + } + }, + contains: function (o) { + return this.indexOf(o) !== -1; + } + }); + //TODO: should be JS Array-like (https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Predefined_Core_Objects#Working_with_Array-like_objects) Kotlin.ArrayList = Kotlin.$createClass(Kotlin.AbstractList, { initialize: function () { @@ -211,9 +221,6 @@ var kotlin = {set:function (receiver, key, value) { this.checkRange(index); this.array[index] = value; }, - toArray: function () { - return this.array.slice(0, this.$size); - }, size: function () { return this.$size; }, @@ -252,6 +259,9 @@ var kotlin = {set:function (receiver, key, value) { } return -1; }, + toArray: function () { + return this.array.slice(0, this.$size); + }, toString: function () { return "[" + this.array.join(", ") + "]"; }, diff --git a/js/js.translator/testFiles/maps.js b/js/js.translator/testFiles/maps.js index 5a358b4d112..75d078d4363 100644 --- a/js/js.translator/testFiles/maps.js +++ b/js/js.translator/testFiles/maps.js @@ -298,7 +298,7 @@ this.values = function () { var values = this._values(); - var i = values.length + var i = values.length; var result = Kotlin.$new(Kotlin.ArrayList)(); while (i--) { result.add(values[i]); @@ -371,7 +371,7 @@ }; this.keySet = function () { - var res = Kotlin.$new(Kotlin.HashSet)(); + var res = Kotlin.$new(Kotlin.ComplexHashSet)(); var keys = this._keys(); var i = keys.length; while (i--) { @@ -475,7 +475,7 @@ Kotlin.ComplexHashMap = Kotlin.HashMap; throw Kotlin.$new(Kotlin.UnsupportedOperationException)(); }, keySet: function () { - var result = Kotlin.$new(Kotlin.HashSet)(); + var result = Kotlin.$new(Kotlin.PrimitiveHashSet)(); var map = this.map; for (var key in map) { if (map.hasOwnProperty(key)) { @@ -494,6 +494,46 @@ Kotlin.ComplexHashMap = Kotlin.HashMap; }); }()); +Kotlin.Set = Kotlin.$createClass(Kotlin.Collection); + +Kotlin.PrimitiveHashSet = Kotlin.$createClass(Kotlin.AbstractCollection, { + initialize: function () { + this.$size = 0; + this.map = {}; + }, + contains: function (key) { + return this.map[key] === true; + }, + add: function (element) { + var prevElement = this.map[element]; + this.map[element] = true; + if (prevElement === true) { + return false; + } + else { + this.$size++; + return true; + } + }, + remove: function (element) { + if (this.map[element] === true) { + delete this.map[element]; + this.$size--; + return true; + } + else { + return false; + } + }, + clear: function () { + this.$size = 0; + this.map = {}; + }, + toArray: function () { + return Kotlin.keys(this.map); + } +}); + (function () { function HashSet(hashingFunction, equalityFunction) { var hashTable = new Kotlin.HashTable(hashingFunction, equalityFunction); @@ -614,7 +654,9 @@ Kotlin.ComplexHashMap = Kotlin.HashMap; }; } - Kotlin.HashSet = Kotlin.$createClass({initialize: function () { + Kotlin.HashSet = Kotlin.$createClass(Kotlin.Set, {initialize: function () { HashSet.call(this); }}); + + Kotlin.ComplexHashSet = Kotlin.HashSet; }());