From 55c19a632a4a9f8094aa38871884d0429005cc19 Mon Sep 17 00:00:00 2001 From: Zalim Bashorov Date: Mon, 13 Oct 2014 18:04:18 +0400 Subject: [PATCH] JS lib: introduced different output strategies, and chose them depending of environment. #KT-2994 Fixed --- .../jetbrains/k2js/test/rhino/RhinoUtils.java | 3 + .../test/semantics/NativeInteropTest.java | 4 + .../jetbrains/k2js/facade/K2JSTranslator.java | 4 +- js/js.translator/testData/kotlin_lib.js | 103 ++++++++++++------ .../testData/native/cases/print.kt | 63 +++++++++++ .../testData/native/native/print.js | 24 ++++ 6 files changed, 168 insertions(+), 33 deletions(-) create mode 100644 js/js.translator/testData/native/cases/print.kt create mode 100644 js/js.translator/testData/native/native/print.js diff --git a/js/js.tests/test/org/jetbrains/k2js/test/rhino/RhinoUtils.java b/js/js.tests/test/org/jetbrains/k2js/test/rhino/RhinoUtils.java index 215c62113c0..7afb79a79f3 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/rhino/RhinoUtils.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/rhino/RhinoUtils.java @@ -140,6 +140,9 @@ public final class RhinoUtils { try { ScriptableObject scope = getScope(ecmaVersion, context, jsLibraries); putGlobalVariablesIntoScope(scope, variables); + + context.evaluateString(scope, "Kotlin.out = new Kotlin.BufferedOutput();", "setup Kotlin.out", 0, null); + for (String filename : fileNames) { runFileWithRhino(filename, context, scope); //String problems = lintIt(context, filename, scope); diff --git a/js/js.tests/test/org/jetbrains/k2js/test/semantics/NativeInteropTest.java b/js/js.tests/test/org/jetbrains/k2js/test/semantics/NativeInteropTest.java index 8e82512da24..b4392167aa9 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/semantics/NativeInteropTest.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/semantics/NativeInteropTest.java @@ -130,4 +130,8 @@ public final class NativeInteropTest extends SingleFileTranslationTest { public void testNestedElements() throws Exception { checkFooBoxIsOk(); } + + public void testPrint() throws Exception { + checkFooBoxIsOk(); + } } diff --git a/js/js.translator/src/org/jetbrains/k2js/facade/K2JSTranslator.java b/js/js.translator/src/org/jetbrains/k2js/facade/K2JSTranslator.java index 929a0d35a67..e58362d18c1 100644 --- a/js/js.translator/src/org/jetbrains/k2js/facade/K2JSTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/facade/K2JSTranslator.java @@ -60,8 +60,8 @@ import static org.jetbrains.k2js.facade.FacadeUtils.parseString; */ public final class K2JSTranslator { - public static final String FLUSH_SYSTEM_OUT = "Kotlin.System.flush();\n"; - public static final String GET_SYSTEM_OUT = "Kotlin.System.output();\n"; + public static final String FLUSH_SYSTEM_OUT = "Kotlin.out.flush();\n"; + public static final String GET_SYSTEM_OUT = "Kotlin.out.buffer;\n"; public static OutputFileCollection translateWithMainCallParameters( @NotNull MainCallParameters mainCall, diff --git a/js/js.translator/testData/kotlin_lib.js b/js/js.translator/testData/kotlin_lib.js index 034a7c4e695..00ce9f75723 100644 --- a/js/js.translator/testData/kotlin_lib.js +++ b/js/js.translator/testData/kotlin_lib.js @@ -529,46 +529,87 @@ return true; }; - Kotlin.System = function () { - var output = ""; - - var print = function (obj) { - if (obj !== undefined) { - if (obj === null || typeof obj !== "object") { - output += obj; - } - else { - output += obj.toString(); - } - } - }; - var println = function (obj) { - this.print(obj); - output += "\n"; - }; - - return { - out: function () { - return { - print: print, - println: println - }; - }, - output: function () { - return output; + var BaseOutput = Kotlin.createClassNow(null, null, { + println: function (a) { + if (typeof a !== "undefined") this.print(a); + this.print("\n"); }, flush: function () { - output = ""; } - }; + } + ); + + Kotlin.NodeJsOutput = Kotlin.createClassNow(BaseOutput, + function(outputStream) { + this.outputStream = outputStream; + }, { + print: function (a) { + this.outputStream.write(a); + } + } + ); + + Kotlin.OutputToConsoleLog = Kotlin.createClassNow(BaseOutput, null, { + print: function (a) { + console.log(a); + }, + println: function (a) { + this.print(typeof a !== "undefined" ? a : ""); + } + } + ); + + Kotlin.BufferedOutput = Kotlin.createClassNow(BaseOutput, + function() { + this.buffer = "" + }, { + print: function (a) { + this.buffer += String(a); + }, + flush: function () { + this.buffer = ""; + } + } + ); + + Kotlin.BufferedOutputToConsoleLog = Kotlin.createClassNow(Kotlin.BufferedOutput, + function() { + Kotlin.BufferedOutput.call(this); + }, { + print: function (a) { + var s = String(a); + + var i = s.lastIndexOf("\n"); + if (i != -1) { + this.buffer += s.substr(0, i); + + this.flush(); + + s = s.substr(i + 1); + } + + this.buffer += s; + }, + flush: function () { + console.log(this.buffer); + this.buffer = ""; + } + } + ); + Kotlin.out = function() { + var isNode = typeof process !== 'undefined' && process.versions && !!process.versions.node; + + if (isNode) return new Kotlin.NodeJsOutput(process.stdout); + + return new Kotlin.BufferedOutputToConsoleLog(); }(); Kotlin.println = function (s) { - Kotlin.System.out().println(s); + Kotlin.out.println(s); }; Kotlin.print = function (s) { - Kotlin.System.out().print(s); + Kotlin.out.print(s); }; lazyInitClasses.RangeIterator = Kotlin.createClass( diff --git a/js/js.translator/testData/native/cases/print.kt b/js/js.translator/testData/native/cases/print.kt new file mode 100644 index 00000000000..c90c7ddf8a8 --- /dev/null +++ b/js/js.translator/testData/native/cases/print.kt @@ -0,0 +1,63 @@ +package foo + +val EXPECTED = """Hello, World + +*** +#### +""" + +val EXPECTED_NEWLINE_FOR_EACH = """Hello +, World + + + +*** +## +## + +""" + +native +fun eval(code: String): Any? = noImpl + +native +var buffer: String = noImpl + +fun test(expected: String, initCode: String, getResult: () -> String) { + buffer = "" + + eval("Kotlin.out = new $initCode") + + print("Hello") + print(", World") + print("\n") + println() + println("***") + print("##") + print("##") + println() + + val actual = getResult() + + assertEquals(expected, actual, initCode) +} + +fun box(): String { + test(EXPECTED, "Kotlin.NodeJsOutput(outputStream)") { + buffer + } + + test(EXPECTED_NEWLINE_FOR_EACH, "Kotlin.OutputToConsoleLog()") { + buffer + } + + test(EXPECTED, "Kotlin.BufferedOutput()") { + eval("Kotlin.out.buffer") as String + } + + test(EXPECTED, "Kotlin.BufferedOutputToConsoleLog()") { + buffer + } + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/native/native/print.js b/js/js.translator/testData/native/native/print.js new file mode 100644 index 00000000000..f1350986721 --- /dev/null +++ b/js/js.translator/testData/native/native/print.js @@ -0,0 +1,24 @@ +var buffer = ""; + +function writeToBuffer(a) { + var type = typeof a; + if (type !== "string") throw Error("Expected string argument type, but got: " + type); + + buffer += a; +} + +function writelnToBuffer(a) { + writeToBuffer(a); + writeToBuffer("\n"); +} + +var GLOBAL = (0, eval)("this"); + +GLOBAL.console = { + log: writelnToBuffer +}; + +GLOBAL.outputStream = { + write: writeToBuffer +}; +