Switched to using native Javascript array for Kotlin's Array<T> instead of library class.

Motivation: better interop with native libraries
Index in bounds check is dropped for now.
This commit is contained in:
Pavel Talanov
2012-01-31 20:23:15 +04:00
parent 49c09ef43e
commit 52344103d6
14 changed files with 564 additions and 578 deletions
+356 -496
View File
File diff suppressed because it is too large Load Diff
@@ -105,7 +105,6 @@ public final class K2JSTranslator {
@NotNull
public String generateCallToMain(@NotNull JetFile file, @NotNull String argumentString) {
String namespaceName = getRootNamespaceName(file);
List<String> arguments = parseString(argumentString);
return GenerationUtils.generateCallToMain(namespaceName, arguments);
}
@@ -86,19 +86,15 @@ public final class StandardClasses {
}
private static void declareJetObjects(@NotNull StandardClasses standardClasses) {
standardClasses.declare().forFQ("jet.Array").kotlinClass("Array")
.properties("size", "indices");
standardClasses.declare().forFQ("jet.Array").kotlinFunction("array");
standardClasses.declare().forFQ("jet.Iterator").kotlinClass("ArrayIterator")
.methods("next", "hasNext");
standardClasses.declare().forFQ("jet.Iterator").kotlinClass("ArrayIteratorIntrinsic")
.methods("next").properties("hasNext");
standardClasses.declare().forFQ("jet.IntRange").kotlinClass("NumberRange")
.methods("iterator", "contains").properties("start", "size", "end", "reversed");
standardClasses.declare().forFQ("jet.String").kotlinClass("String").
properties("length");
// standardClasses.declare().forFQ("jet.String").kotlinClass("String").
// properties("length");
standardClasses.declare().forFQ("jet.Any.toString").kotlinFunction("toString");
}
@@ -162,7 +158,6 @@ public final class StandardClasses {
@NotNull String... propertyNames) {
for (String propertyName : propertyNames) {
declareInner(classFQName, propertyName, propertyName);
}
}
@@ -19,6 +19,7 @@ import org.jetbrains.k2js.translate.operation.UnaryOperationTranslator;
import org.jetbrains.k2js.translate.reference.AccessTranslator;
import org.jetbrains.k2js.translate.reference.CallTranslator;
import org.jetbrains.k2js.translate.reference.ReferenceTranslator;
import org.jetbrains.k2js.translate.utils.BindingUtils;
import org.jetbrains.k2js.translate.utils.TranslationUtils;
import java.util.List;
@@ -122,10 +123,14 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
@Override
@NotNull
public JsNode visitIfExpression(@NotNull JetIfExpression expression, @NotNull TranslationContext context) {
JsIf ifStatement = translateAsIfStatement(expression, context);
if (BindingUtils.isStatement(context.bindingContext(), expression)) {
return ifStatement;
}
TemporaryVariable result = context.declareTemporary(context.program().getNullLiteral());
AstUtil.SaveLastExpressionMutator saveResultToTemporaryMutator =
new AstUtil.SaveLastExpressionMutator(result.nameReference());
JsNode mutatedIfStatement = AstUtil.mutateLastExpression(translateAsIfStatement(expression, context),
JsNode mutatedIfStatement = AstUtil.mutateLastExpression(ifStatement,
saveResultToTemporaryMutator);
JsStatement resultingStatement = AstUtil.convertToStatement(mutatedIfStatement);
context.jsBlock().addStatement(resultingStatement);
@@ -7,9 +7,7 @@ import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.jetbrains.jet.lang.types.JetStandardLibrary;
import org.jetbrains.jet.lexer.JetToken;
import org.jetbrains.k2js.translate.intrinsic.array.ArrayGetIntrinsic;
import org.jetbrains.k2js.translate.intrinsic.array.ArrayNullConstructorIntrinsic;
import org.jetbrains.k2js.translate.intrinsic.array.ArraySetIntrinsic;
import org.jetbrains.k2js.translate.intrinsic.array.*;
import org.jetbrains.k2js.translate.intrinsic.primitive.*;
import org.jetbrains.k2js.translate.intrinsic.string.LengthIntrinsic;
import org.jetbrains.k2js.translate.intrinsic.tuple.TupleAccessIntrinsic;
@@ -55,14 +53,23 @@ public final class Intrinsics {
declareArrayIntrinsics();
}
//TODO: provide generic mechanism or refactor
private void declareArrayIntrinsics() {
JetScope arrayMemberScope = library.getArray().getDefaultType().getMemberScope();
FunctionDescriptor setFunction = getFunctionByName(arrayMemberScope, "set");
functionIntrinsics.put(setFunction, ArraySetIntrinsic.INSTANCE);
FunctionDescriptor getFunction = getFunctionByName(arrayMemberScope, "get");
functionIntrinsics.put(getFunction, ArrayGetIntrinsic.INSTANCE);
PropertyDescriptor sizeProperty = getPropertyByName(arrayMemberScope, "size");
functionIntrinsics.put(sizeProperty.getGetter(), ArraySizeIntrinsic.INSTANCE);
PropertyDescriptor indicesProperty = getPropertyByName(arrayMemberScope, "indices");
functionIntrinsics.put(indicesProperty.getGetter(), ArrayIndicesIntrinsic.INSTANCE);
FunctionDescriptor nullArrayConstructor = getFunctionByName(library.getLibraryScope(), "Array");
functionIntrinsics.put(nullArrayConstructor, ArrayNullConstructorIntrinsic.INSTANCE);
FunctionDescriptor iteratorFunction = getFunctionByName(arrayMemberScope, "iterator");
functionIntrinsics.put(iteratorFunction, ArrayIteratorIntrinsic.INSTANCE);
ConstructorDescriptor arrayConstructor = library.getArray().getConstructors().iterator().next();
functionIntrinsics.put(arrayConstructor, ArrayFunctionConstructorIntrinsic.INSTANCE);
}
private void declareTuplesIntrinsics() {
@@ -0,0 +1,32 @@
package org.jetbrains.k2js.translate.intrinsic.array;
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;
/**
* @author Pavel Talanov
*/
public enum ArrayFunctionConstructorIntrinsic implements FunctionIntrinsic {
INSTANCE;
@NotNull
@Override
public JsExpression apply(@Nullable JsExpression receiver,
@NotNull List<JsExpression> arguments,
@NotNull TranslationContext context) {
assert receiver == null;
assert arguments.size() == 2;
//TODO: provide better mechanism
JsNameRef iteratorFunName = AstUtil.newQualifiedNameRef("Kotlin.arrayFromFun");
return AstUtil.newInvocation(iteratorFunName, arguments);
}
}
@@ -0,0 +1,31 @@
package org.jetbrains.k2js.translate.intrinsic.array;
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;
/**
* @author Pavel Talanov
*/
public enum ArrayIndicesIntrinsic implements FunctionIntrinsic {
INSTANCE;
@NotNull
@Override
public JsExpression apply(@Nullable JsExpression receiver, @NotNull List<JsExpression> arguments,
@NotNull TranslationContext context) {
assert receiver != null;
assert arguments.size() == 0;
//TODO: provide better mechanism
JsNameRef iteratorFunName = AstUtil.newQualifiedNameRef("Kotlin.arrayIndices");
return AstUtil.newInvocation(iteratorFunName, receiver);
}
}
@@ -0,0 +1,30 @@
package org.jetbrains.k2js.translate.intrinsic.array;
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;
/**
* @author Pavel Talanov
*/
public enum ArrayIteratorIntrinsic implements FunctionIntrinsic {
INSTANCE;
@NotNull
@Override
public JsExpression apply(@Nullable JsExpression receiver, @NotNull List<JsExpression> arguments,
@NotNull TranslationContext context) {
assert receiver != null;
assert arguments.size() == 0;
//TODO: provide better mechanism
JsNameRef iteratorFunName = AstUtil.newQualifiedNameRef("Kotlin.arrayIterator");
return AstUtil.newInvocation(iteratorFunName, receiver);
}
}
@@ -1,7 +1,8 @@
package org.jetbrains.k2js.translate.intrinsic.array;
import com.google.dart.compiler.backend.js.ast.JsArrayLiteral;
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;
@@ -21,6 +22,10 @@ public enum ArrayNullConstructorIntrinsic implements FunctionIntrinsic {
@Override
public JsExpression apply(@Nullable JsExpression receiver, @NotNull List<JsExpression> arguments,
@NotNull TranslationContext context) {
return new JsArrayLiteral();
assert receiver == null;
assert arguments.size() == 1;
//TODO: provide better mechanism
JsNameRef nullArrayFunName = AstUtil.newQualifiedNameRef("Kotlin.nullArray");
return AstUtil.newInvocation(nullArrayFunName, arguments);
}
}
@@ -0,0 +1,32 @@
package org.jetbrains.k2js.translate.intrinsic.array;
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;
/**
* @author Pavel Talanov
*/
public enum ArraySizeIntrinsic implements FunctionIntrinsic {
INSTANCE;
@NotNull
@Override
public JsExpression apply(@Nullable JsExpression receiver, @NotNull List<JsExpression> arguments,
@NotNull TranslationContext context) {
assert receiver != null;
assert arguments.isEmpty() : "Length expression must have zero arguments.";
//TODO: provide better way
JsNameRef lengthProperty = AstUtil.newQualifiedNameRef("length");
AstUtil.setQualifier(lengthProperty, receiver);
return lengthProperty;
}
}
@@ -11,10 +11,10 @@ public final class GenerationUtils {
@NotNull
public static String generateCallToMain(@NotNull String namespaceName, @NotNull List<String> arguments) {
String constructArguments = "var args = Kotlin.array(" + arguments.size() + ");\n";
String constructArguments = "var args = [];\n";
int index = 0;
for (String argument : arguments) {
constructArguments = constructArguments + "args.set(" + index + ", \"" + argument + "\");\n";
constructArguments = constructArguments + "args[" + index + "]= \"" + argument + "\";\n";
index++;
}
String callMain = namespaceName + ".main(args);\n";
@@ -1,7 +1,6 @@
package org.jetbrains.k2js.test;
import org.junit.Test;
import org.mozilla.javascript.JavaScriptException;
/**
* @author Pavel Talanov
@@ -39,10 +38,12 @@ public class StandardClassesTest extends TranslationTest {
testFooBoxIsTrue("arraySize.kt");
}
@Test(expected = JavaScriptException.class)
public void arrayThrowsExceptionOnOOBaccess() throws Exception {
testFooBoxIsTrue("arrayThrowsExceptionOnOOBaccess.kt");
}
//TODO: this feature in not supported for some time
//TODO: support it. Probably confugurable.
// @Test(expected = JavaScriptException.class)
// public void arrayThrowsExceptionOnOOBaccess() throws Exception {
// testFooBoxIsTrue("arrayThrowsExceptionOnOOBaccess.kt");
// }
@Test
public void arraysIterator() throws Exception {
@@ -1,8 +1,6 @@
function test() {
var a = new Kotlin.Array(3, function () {
var a = Kotlin.arrayFromFun(3, function () {
return 3
});
a.set(0, "1")
a.set(2, "4")
return (a.get(0) == "1") && (a.get(2) == "4") && (a.get(1) == 3);
return (a[0] == 3) && (a[2] == 3) && (a[1] == 3);
}
+46 -55
View File
@@ -254,46 +254,6 @@
Kotlin.Exceptions = {}
Kotlin.Exception = Kotlin.Class.create();
Kotlin.Exceptions.IndexOutOfBounds = {}
Kotlin.array = function (len) {
return new Kotlin.Array(len, function () {
return null
});
}
Kotlin.Array = Class.create({
initialize:function (len, f) {
this.array = [];
var i = 0;
while (i < len) {
this.array.push(f(i));
++i;
}
},
get:function (index) {
if ((index < 0) || (index >= this.array.length)) {
throw Kotlin.Exceptions.IndexOutOfBounds;
}
return (this.array)[index];
},
set:function (index, value) {
if ((index < 0) || (index >= this.array.length)) {
throw Kotlin.Exceptions.IndexOutOfBounds;
}
(this.array)[index] = value;
},
size:function () {
return this.array.length;
},
//TODO: remove duplicated methods
get_size:function () {
return this.array.length;
},
iterator:function () {
return new Kotlin.ArrayIterator(this);
},
get_indices:function () {
return new Kotlin.NumberRange(0, this.size(), false);
}
});
Kotlin.ArrayList = Class.create({
@@ -352,19 +312,6 @@
});
Kotlin.ArrayIterator = Class.create({
initialize:function (array) {
this.array = array;
this.index = 0;
},
next:function () {
return this.array.get(this.index++);
},
hasNext:function () {
return (this.array.size() > this.index);
}
});
Kotlin.parseInt =
function (str) {
return parseInt(str);
@@ -502,9 +449,9 @@
Kotlin.Comparator = Kotlin.Class.create(
{
initialize:function() {
initialize:function () {
},
compare:function() {
compare:function () {
throw new Kotlin.AbstractFunctionInvokationError();
}
}
@@ -524,6 +471,50 @@
}
);
Kotlin.nullArray = function (size) {
var res = [];
var i = size;
while (i > 0) {
res[--i] = null;
}
return res;
};
Kotlin.arrayFromFun = function (size, initFun) {
var res = [];
var i = size;
while (i > 0) {
res[--i] = initFun(i);
}
return res;
};
Kotlin.arrayIndices = function (arr) {
return new Kotlin.NumberRange(0, arr.length);
};
var intrinsicArrayIterator = Kotlin.Class.create(
Kotlin.Iterator,
{
initialize:function (arr) {
this.arr = arr;
this.len = arr.length;
this.i = 0;
},
hasNext:function () {
return (this.i < this.len);
},
next:function () {
return this.arr[this.i++];
},
get_hasNext:function() { return this.hasNext()}
}
);
Kotlin.arrayIterator = function (arr) {
return new intrinsicArrayIterator(arr);
};
Kotlin.toString = function (obj) {
return obj.toString();
};