From 1859ddf9415d064ec968d602c4b54a2208f97d9e Mon Sep 17 00:00:00 2001 From: Pavel Talanov Date: Sun, 5 Feb 2012 15:16:09 +0400 Subject: [PATCH] a couple of hacks to make life example work (still not working) --- .../compiler/backend/js/ast/JsProgram.java | 296 +++++++++--------- jslib/src/core/core.kt | 7 +- jslib/src/core/javalang.kt | 7 +- jslib/src/core/javautil.kt | 19 +- jslib/src/core/javautilcollections.kt | 8 - .../src/org/jetbrains/k2js/config/Config.java | 3 +- .../translate/context/StandardClasses.java | 6 + .../expression/ExpressionVisitor.java | 6 + .../expression/FunctionTranslator.java | 16 +- translator/testFiles/kotlin_lib.js | 15 + .../testFiles/webDemoExamples2/cases/life.kt | 41 ++- 11 files changed, 231 insertions(+), 193 deletions(-) delete mode 100644 jslib/src/core/javautilcollections.kt diff --git a/js/src/com/google/dart/compiler/backend/js/ast/JsProgram.java b/js/src/com/google/dart/compiler/backend/js/ast/JsProgram.java index 1d2c902d27a..c8e4310ba9b 100644 --- a/js/src/com/google/dart/compiler/backend/js/ast/JsProgram.java +++ b/js/src/com/google/dart/compiler/backend/js/ast/JsProgram.java @@ -12,161 +12,163 @@ import java.util.Map; */ public final class JsProgram extends JsNode { - private final JsStatement debuggerStmt; - private final JsEmpty emptyStmt; - private final JsBooleanLiteral falseLiteral; - private JsProgramFragment[] fragments; - private final Map indexedFunctions = new HashMap(); - private final JsNullLiteral nullLiteral; - private final Map numberLiteralMap = - new HashMap(); - private final JsScope objectScope; - private final JsRootScope rootScope; - private final Map stringLiteralMap = - new HashMap(); - private final JsScope topScope; - private final JsBooleanLiteral trueLiteral; + private final JsStatement debuggerStmt; + private final JsEmpty emptyStmt; + private final JsBooleanLiteral falseLiteral; + private JsProgramFragment[] fragments; + private final Map indexedFunctions = new HashMap(); + private final JsNullLiteral nullLiteral; + private final Map numberLiteralMap = + new HashMap(); + private final JsScope objectScope; + private final JsRootScope rootScope; + private final Map stringLiteralMap = + new HashMap(); + private final JsScope topScope; + private final JsBooleanLiteral trueLiteral; - /** - * Constructs a JavaScript program object. - */ - public JsProgram(String unitId) { - rootScope = new JsRootScope(this); - topScope = new JsScope(rootScope, "Global", unitId); - objectScope = new JsScope(rootScope, "Object"); - setFragmentCount(1); + /** + * Constructs a JavaScript program object. + */ + public JsProgram(String unitId) { + rootScope = new JsRootScope(this); + topScope = new JsScope(rootScope, "Global", unitId); + objectScope = new JsScope(rootScope, "Object"); + setFragmentCount(1); - debuggerStmt = new JsDebugger(); - emptyStmt = new JsEmpty(); - falseLiteral = new JsBooleanLiteral(false); - nullLiteral = new JsNullLiteral(); - trueLiteral = new JsBooleanLiteral(true); - } - - public JsBooleanLiteral getBooleanLiteral(boolean truth) { - if (truth) { - return getTrueLiteral(); - } - return getFalseLiteral(); - } - - /** - * Gets the {@link JsStatement} to use whenever parsed source include a - * debugger statement. - */ - public JsStatement getDebuggerStmt() { - return debuggerStmt; - } - - public JsEmpty getEmptyStmt() { - return emptyStmt; - } - - public JsBooleanLiteral getFalseLiteral() { - return falseLiteral; - } - - public JsBlock getFragmentBlock(int fragment) { - if (fragment < 0 || fragment >= fragments.length) { - throw new IllegalArgumentException("Invalid fragment: " + fragment); - } - return fragments[fragment].getGlobalBlock(); - } - - public int getFragmentCount() { - return this.fragments.length; - } - - /** - * Gets the one and only global block. - */ - public JsBlock getGlobalBlock() { - return getFragmentBlock(0); - } - - public JsFunction getIndexedFunction(String name) { - return indexedFunctions.get(name); - } - - public JsNullLiteral getNullLiteral() { - return nullLiteral; - } - - public JsNumberLiteral getNumberLiteral(double value) { - JsNumberLiteral lit = numberLiteralMap.get(value); - if (lit == null) { - lit = new JsNumberLiteral(value); - numberLiteralMap.put(value, lit); + debuggerStmt = new JsDebugger(); + emptyStmt = new JsEmpty(); + falseLiteral = new JsBooleanLiteral(false); + nullLiteral = new JsNullLiteral(); + trueLiteral = new JsBooleanLiteral(true); } - return lit; - } - - public JsScope getObjectScope() { - return objectScope; - } - - /** - * Gets the quasi-mythical root scope. This is not the same as the top scope; - * all unresolvable identifiers wind up here, because they are considered - * external to the program. - */ - public JsRootScope getRootScope() { - return rootScope; - } - - /** - * Gets the top level scope. This is the scope of all the statements in the - * main program. - */ - public JsScope getScope() { - return topScope; - } - - /** - * Creates or retrieves a JsStringLiteral from an interned object pool. - */ - public JsStringLiteral getStringLiteral(String value) { - JsStringLiteral lit = stringLiteralMap.get(value); - if (lit == null) { - lit = new JsStringLiteral(value); - stringLiteralMap.put(value, lit); + public JsBooleanLiteral getBooleanLiteral(boolean truth) { + if (truth) { + return getTrueLiteral(); + } + return getFalseLiteral(); } - return lit; - } - public JsBooleanLiteral getTrueLiteral() { - return trueLiteral; - } - - public JsNameRef getUndefinedLiteral() { - return new JsNameRef("$Dart$Null"); - } - - public void setFragmentCount(int fragments) { - this.fragments = new JsProgramFragment[fragments]; - for (int i = 0; i < fragments; i++) { - this.fragments[i] = new JsProgramFragment(); + /** + * Gets the {@link JsStatement} to use whenever parsed source include a + * debugger statement. + */ + public JsStatement getDebuggerStmt() { + return debuggerStmt; } - } - public void setIndexedFunctions(Map indexedFunctions) { - this.indexedFunctions.clear(); - this.indexedFunctions.putAll(indexedFunctions); - } - - @Override - public void traverse(JsVisitor v, JsContext ctx) { - if (v.visit(this, ctx)) { - for (JsProgramFragment fragment : fragments) { - v.accept(fragment); - } + public JsEmpty getEmptyStmt() { + return emptyStmt; } - v.endVisit(this, ctx); - } - @Override - public NodeKind getKind() { - return NodeKind.PROGRAM; - } + public JsBooleanLiteral getFalseLiteral() { + return falseLiteral; + } + + public JsBlock getFragmentBlock(int fragment) { + if (fragment < 0 || fragment >= fragments.length) { + throw new IllegalArgumentException("Invalid fragment: " + fragment); + } + return fragments[fragment].getGlobalBlock(); + } + + public int getFragmentCount() { + return this.fragments.length; + } + + /** + * Gets the one and only global block. + */ + public JsBlock getGlobalBlock() { + return getFragmentBlock(0); + } + + public JsFunction getIndexedFunction(String name) { + return indexedFunctions.get(name); + } + + public JsNullLiteral getNullLiteral() { + return nullLiteral; + } + + public JsNumberLiteral getNumberLiteral(double value) { + JsNumberLiteral lit = numberLiteralMap.get(value); + if (lit == null) { + lit = new JsNumberLiteral(value); + numberLiteralMap.put(value, lit); + } + + return lit; + } + + public JsScope getObjectScope() { + return objectScope; + } + + /** + * Gets the quasi-mythical root scope. This is not the same as the top scope; + * all unresolvable identifiers wind up here, because they are considered + * external to the program. + */ + public JsRootScope getRootScope() { + return rootScope; + } + + /** + * Gets the top level scope. This is the scope of all the statements in the + * main program. + */ + public JsScope getScope() { + return topScope; + } + + /** + * Creates or retrieves a JsStringLiteral from an interned object pool. + */ + public JsStringLiteral getStringLiteral(String value) { + JsStringLiteral lit = stringLiteralMap.get(value); + if (lit == null) { + lit = new JsStringLiteral(value); + stringLiteralMap.put(value, lit); + } + return lit; + } + + public JsBooleanLiteral getTrueLiteral() { + return trueLiteral; + } + + public JsNameRef getUndefinedLiteral() { + return new JsNameRef("$Dart$Null"); + } + + public void setFragmentCount(int fragments) { + this.fragments = new JsProgramFragment[fragments]; + for (int i = 0; i < fragments; i++) { + this.fragments[i] = new JsProgramFragment(); + } + } + + public void setIndexedFunctions(Map indexedFunctions) { + this.indexedFunctions.clear(); + this.indexedFunctions.putAll(indexedFunctions); + } + + @Override + public void traverse(JsVisitor v, JsContext ctx) { + if (v.visit(this, ctx)) { + for (JsProgramFragment fragment : fragments) { + v.accept(fragment); + } + } + v.endVisit(this, ctx); + } + + @Override + public NodeKind getKind() { + return NodeKind.PROGRAM; + } + + } diff --git a/jslib/src/core/core.kt b/jslib/src/core/core.kt index 9a690868dbb..c70f0bddcc7 100644 --- a/jslib/src/core/core.kt +++ b/jslib/src/core/core.kt @@ -3,6 +3,7 @@ package js; import js.annotations.library import js.annotations.library import js.annotations.native +import java.util.*; library("println") fun println() {} @@ -23,4 +24,8 @@ fun setTimeout(callback : ()-> Unit) {} native fun setInterval(callback : ()-> Unit, ms : Int) {} native -fun setInterval(callback : ()-> Unit) {} \ No newline at end of file +fun setInterval(callback : ()-> Unit) {} + + +library("collectionsMax") +public fun max(col : Collection, comp : Comparator) : T = f diff --git a/jslib/src/core/javalang.kt b/jslib/src/core/javalang.kt index aa25a0fef92..43939cddd3f 100644 --- a/jslib/src/core/javalang.kt +++ b/jslib/src/core/javalang.kt @@ -6,4 +6,9 @@ import js.annotations.library library trait Iterable { fun iterator() : java.util.Iterator {} -} \ No newline at end of file +} + +library("splitString") +public fun String.split(regex : String) : Array { +} + diff --git a/jslib/src/core/javautil.kt b/jslib/src/core/javautil.kt index 9bc5b5cab55..098cd198ff2 100644 --- a/jslib/src/core/javautil.kt +++ b/jslib/src/core/javautil.kt @@ -17,6 +17,14 @@ public open class Iterator() { open fun hasNext() : Boolean {} } +library +val Collections = object { + library("max") + public fun max(col : Collection, comp : Comparator) : T = f +} + +private val f : Nothing + library public open class ArrayList() : java.util.List { override public fun size() : Int {} @@ -56,7 +64,7 @@ public trait Collection : java.lang.Iterable { } library -public trait List : java.util.Collection { +public trait List : Collection { override fun size() : Int override fun isEmpty() : Boolean override fun contains(o : Any?) : Boolean @@ -81,7 +89,7 @@ public trait List : java.util.Collection { } library -public trait Set : java.util.Collection { +public trait Set : Collection { override fun size() : Int override fun isEmpty() : Boolean override fun contains(o : Any?) : Boolean @@ -143,9 +151,4 @@ library public class StringBuilder() { public fun append(obj : Any) : StringBuilder public fun toString() : String -} - -library("splitString") -public fun String.split(regex : String) : Array { -} - +} \ No newline at end of file diff --git a/jslib/src/core/javautilcollections.kt b/jslib/src/core/javautilcollections.kt deleted file mode 100644 index 557017ffb36..00000000000 --- a/jslib/src/core/javautilcollections.kt +++ /dev/null @@ -1,8 +0,0 @@ -package java.util.Collections; - -import js.annotations.library -import java.util.Collection -import java.util.Comparator - -library("collectionsMax") -public fun max(col : Collection, comp : Comparator) {} \ No newline at end of file diff --git a/translator/src/org/jetbrains/k2js/config/Config.java b/translator/src/org/jetbrains/k2js/config/Config.java index aa482d61202..bbb983b933e 100644 --- a/translator/src/org/jetbrains/k2js/config/Config.java +++ b/translator/src/org/jetbrains/k2js/config/Config.java @@ -31,8 +31,7 @@ public abstract class Config { PATH_TO_JS_LIB_SRC + "\\core\\core.kt", PATH_TO_JS_LIB_SRC + "\\raphael\\raphael.kt", PATH_TO_JS_LIB_SRC + "\\core\\json.kt", - PATH_TO_JS_LIB_SRC + "\\html5\\core.kt", - PATH_TO_JS_LIB_SRC + "\\core\\javautilcollections.kt" + PATH_TO_JS_LIB_SRC + "\\html5\\core.kt" ); diff --git a/translator/src/org/jetbrains/k2js/translate/context/StandardClasses.java b/translator/src/org/jetbrains/k2js/translate/context/StandardClasses.java index 48397232fba..66892d72c01 100644 --- a/translator/src/org/jetbrains/k2js/translate/context/StandardClasses.java +++ b/translator/src/org/jetbrains/k2js/translate/context/StandardClasses.java @@ -86,7 +86,13 @@ public final class StandardClasses { standardClasses.declare().forFQ("jet.IntRange").kotlinClass("NumberRange") .methods("iterator", "contains").properties("start", "size", "end", "reversed"); + standardClasses.declare().forFQ("jet.sure").kotlinFunction("sure"); + standardClasses.declare().forFQ("jet.Any.toString").kotlinFunction("toString"); + + standardClasses.declare().forFQ("java.util.Collections..max").kotlinFunction("collectionsMax"); + + standardClasses.declare().forFQ("jet.CharSequence.get").kotlinFunction("getChar"); } diff --git a/translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java b/translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java index 97e2490288f..91f26f0d1b1 100644 --- a/translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java +++ b/translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java @@ -64,6 +64,12 @@ public final class ExpressionVisitor extends TranslatorVisitor { if (value instanceof Double) { return context.program().getNumberLiteral((Double) value); } + if (value instanceof String) { + return context.program().getStringLiteral((String) value); + } + if (value instanceof Character) { + return context.program().getStringLiteral(value.toString()); + } //TODO: all values throw new AssertionError("Unsupported constant expression" + expression.toString()); } diff --git a/translator/src/org/jetbrains/k2js/translate/expression/FunctionTranslator.java b/translator/src/org/jetbrains/k2js/translate/expression/FunctionTranslator.java index 56c501218a4..2bd5e8145f8 100644 --- a/translator/src/org/jetbrains/k2js/translate/expression/FunctionTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/expression/FunctionTranslator.java @@ -130,6 +130,7 @@ public final class FunctionTranslator extends AbstractTranslator { return (!functionDeclaration.hasBlockBody()) && (!JetStandardClasses.isUnit(functionReturnType)); } + //TODO: refactor @NotNull private JsBlock wrapWithReturnIfNeeded(@NotNull JsNode body, boolean needsReturn) { if (!needsReturn) { @@ -147,11 +148,16 @@ public final class FunctionTranslator extends AbstractTranslator { } private void addReturnToBlockStatement(@NotNull JsBlock bodyBlock) { - List statements = bodyBlock.getStatements(); - int lastIndex = statements.size() - 1; - JsStatement lastStatement = statements.get(lastIndex); - JsReturn returnStatement = new JsReturn(AstUtil.extractExpressionFromStatement(lastStatement)); - statements.set(lastIndex, returnStatement); + AstUtil.mutateLastExpression(bodyBlock, new AstUtil.Mutator() { + @Override + @NotNull + public JsNode mutate(@NotNull JsNode node) { + if (!(node instanceof JsExpression)) { + return node; + } + return new JsReturn((JsExpression) node); + } + }); } @NotNull diff --git a/translator/testFiles/kotlin_lib.js b/translator/testFiles/kotlin_lib.js index c937205ad0f..c99a4052134 100644 --- a/translator/testFiles/kotlin_lib.js +++ b/translator/testFiles/kotlin_lib.js @@ -470,6 +470,17 @@ } ); + Kotlin.comparator = function(f) { + var result = new Kotlin.Comparator; + result.compare = function(el1, el2) { + return f(el1, el2); + }; + }; + + Kotlin.getChar = function(str, index) { + return str.charAt(index); + }; + Kotlin.collectionsMax = function (col, comp) { var it = col.iterator(); if (col.isEmpty()) { @@ -573,6 +584,10 @@ }; + Kotlin.sure = function(obj) { + return obj; + }; + /** * Copyright 2010 Tim Down. * diff --git a/translator/testFiles/webDemoExamples2/cases/life.kt b/translator/testFiles/webDemoExamples2/cases/life.kt index 831b1e6c707..ac398d54a55 100644 --- a/translator/testFiles/webDemoExamples2/cases/life.kt +++ b/translator/testFiles/webDemoExamples2/cases/life.kt @@ -2,9 +2,10 @@ * This is a straightforward implementation of The Game of Life * See http://en.wikipedia.org/wiki/Conway's_Game_of_Life */ -package life import java.util.* +import java.lang.split; +import js.*; /* * A field where cells live. Effectively immutable @@ -119,11 +120,24 @@ fun printField(s : String, steps : Int) { } } + +fun Array.toList() : List = this.to(ArrayList()) + +val String?.size : Int +get() = if (this != null) this.length else 0; + +fun > Array.to(result: C) : C { + for (elem in this) + result.add(elem) + return result +} + fun makeField(s : String) : Field { - val lines = s.split("\n").sure() - val w = max(lines.toList(), comparator {o1, o2 -> - val l1 : Int = o1?.size ?: 0 - val l2 = o2?.size ?: 0 + val lines : Array = s.split("\n") + + val w = max(lines.toList(), comparator {o1, o2 -> + val l1 : Int = o1.size + val l2 = o2.size l1 - l2 }).sure() val data = Array(lines.size) {Array(w.size) {false}} @@ -137,7 +151,7 @@ fun makeField(s : String) : Field { for (line in lines.indices) { for (x in lines[line].indices) { - val c = lines[line].sure()[x] + val c = lines[line][x] data[line][x] = c == '*' } } @@ -150,19 +164,4 @@ val String?.indices : IntRange get() = IntRange(0, this.sure().size) fun Map.set(k : K, v : V) { put(k, v) } -fun comparator (f : (T, T) -> Int) : Comparator = object : Comparator { - override fun compare(o1 : T, o2 : T) : Int = f(o1, o2) -} - val Array.isEmpty : Boolean get() = size == 0 - -val String.size : Int - get() = length - -fun > Array.to(result: C) : C { - for (elem in this) - result.add(elem) - return result -} - -fun Array.toList() : List = this.to(ArrayList())