From 8b9852edeca84fe7bf474de8a771d784ee96ec04 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Fri, 18 Nov 2016 19:53:14 +0300 Subject: [PATCH] JS: remove Kotlin.createClass/definePackage/etc functions from stdlib. Reimplement some classes in Kotlin --- js/js.libraries/src/core/builtins.kt | 3 + js/js.libraries/src/core/console.kt | 88 ++++ .../testData/box/native/library.js | 22 +- js/js.translator/testData/box/native/print.kt | 10 +- js/js.translator/testData/kotlin_lib.js | 82 ---- js/js.translator/testData/kotlin_lib_ecma5.js | 378 ------------------ js/js.translator/testData/test.js | 57 ++- 7 files changed, 135 insertions(+), 505 deletions(-) create mode 100644 js/js.libraries/src/core/console.kt diff --git a/js/js.libraries/src/core/builtins.kt b/js/js.libraries/src/core/builtins.kt index 9d1ebc3d2d3..e51b56a1137 100644 --- a/js/js.libraries/src/core/builtins.kt +++ b/js/js.libraries/src/core/builtins.kt @@ -31,3 +31,6 @@ internal fun arrayIterator(array: dynamic): MutableIterator { } } } + +@JsName("PropertyMetadata") +internal class PropertyMetadata(val name: String) \ No newline at end of file diff --git a/js/js.libraries/src/core/console.kt b/js/js.libraries/src/core/console.kt new file mode 100644 index 00000000000..2330773a11e --- /dev/null +++ b/js/js.libraries/src/core/console.kt @@ -0,0 +1,88 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@JsName("BaseOutput") +internal abstract class BaseOutput { + @JsName("println") + open fun println(a: Any?) { + if (js("typeof a") !== "undefined") { + print(a) + } + print("\n") + } + + @JsName("print") + abstract fun print(a: Any?) + + @JsName("flush") + open fun flush() {} +} + +@JsName("NodeJsOutput") +internal class NodeJsOutput(val outputStream: dynamic) : BaseOutput() { + override fun print(a: dynamic) = outputStream.write(a) +} + +@JsName("OutputToConsoleLog") +internal class OutputToConsoleLog : BaseOutput() { + override fun print(a: Any?) { + console.log(a) + } + + override fun println(a: Any?) { + console.log(if (js("typeof a") !== "undefined") a else "") + } +} + +@JsName("BufferedOutput") +internal open class BufferedOutput : BaseOutput() { + var buffer = "" + + override fun print(a: Any?) { + buffer += String(a) + } + + override fun flush() { + buffer = "" + } +} + +@JsName("BufferedOutputToConsoleLog") +internal class BufferedOutputToConsoleLog : BufferedOutput() { + override fun print(a: Any?) { + var s = String(a) + val i = s.lastIndexOf('\n') + if (i >= 0) { + buffer += s.substring(0, i) + flush() + s = s.substring(i + 1) + } + buffer += s + } + + override fun flush() { + console.log(buffer) + buffer = "" + } +} + +@JsName("out") +internal var `out` = { + val isNode: Boolean = js("typeof process !== 'undefined' && process.versions && !!process.versions.node") + if (isNode) NodeJsOutput(js("process.stdout")) else BufferedOutputToConsoleLog() +}() + +private inline fun String(value: Any?): String = js("String(value)") diff --git a/js/js.translator/testData/box/native/library.js b/js/js.translator/testData/box/native/library.js index c3230b0ab61..9723bbf127b 100644 --- a/js/js.translator/testData/box/native/library.js +++ b/js/js.translator/testData/box/native/library.js @@ -1,18 +1,16 @@ (function () { var c = 0; - kotlin.A = kotlin.createClassNow(null, - function () { - this.f = function (i) { - if (i === undefined && c === 0) { - c = 1; - } - if (i === 2 && c === 1) { - c = 2; - } - } - } - ); + kotlin.A = function() { + this.f = function (i) { + if (i === undefined && c === 0) { + c = 1; + } + if (i === 2 && c === 1) { + c = 2; + } + } + }; kotlin.getResult = function () { return c === 2; }; diff --git a/js/js.translator/testData/box/native/print.kt b/js/js.translator/testData/box/native/print.kt index 2e9d81eb6cc..588eb97285c 100644 --- a/js/js.translator/testData/box/native/print.kt +++ b/js/js.translator/testData/box/native/print.kt @@ -2,7 +2,9 @@ package foo val EXPECTED = """Hello, World - +^^ +^^ +^^ *** #### """ @@ -10,7 +12,9 @@ val EXPECTED = """Hello, World val EXPECTED_NEWLINE_FOR_EACH = """Hello , World - +^^ +^^ +^^ *** ## @@ -28,7 +32,7 @@ fun test(expected: String, initCode: String, getResult: () -> String) { print("Hello") print(", World") - print("\n") + print("\n^^\n^^\n^^") println() println("***") print("##") diff --git a/js/js.translator/testData/kotlin_lib.js b/js/js.translator/testData/kotlin_lib.js index 840569fa86f..ae7327f61ca 100644 --- a/js/js.translator/testData/kotlin_lib.js +++ b/js/js.translator/testData/kotlin_lib.js @@ -230,12 +230,6 @@ function getStringHashCode(str) { return hash; } -Kotlin.PropertyMetadata = Kotlin.createClassNow(null, - function (name) { - this.name = name; - } -); - Kotlin.safeParseInt = function (str) { var r = parseInt(str, 10); return isNaN(r) ? null : r; @@ -299,82 +293,6 @@ Kotlin.arrayDeepHashCode = function (arr) { return result; }; -var BaseOutput = Kotlin.createClassNow(null, null, { - println: function (a) { - if (typeof a !== "undefined") this.print(a); - this.print("\n"); - }, - flush: function () { - } - } -); - - -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.out.println(s); }; diff --git a/js/js.translator/testData/kotlin_lib_ecma5.js b/js/js.translator/testData/kotlin_lib_ecma5.js index 1421e02c58d..392de3543d3 100644 --- a/js/js.translator/testData/kotlin_lib_ecma5.js +++ b/js/js.translator/testData/kotlin_lib_ecma5.js @@ -15,44 +15,6 @@ */ (function () { - function toArray(obj) { - var array; - if (obj == null) { - array = []; - } - else if (!Array.isArray(obj)) { - array = [obj]; - } - else { - array = obj; - } - return array; - } - - function copyProperties(to, from) { - if (to == null || from == null) { - return; - } - for (var p in from) { - if (from.hasOwnProperty(p)) { - to[p] = from[p]; - } - } - } - - function getClass(basesArray) { - for (var i = 0; i < basesArray.length; i++) { - if (isNativeClass(basesArray[i]) || basesArray[i].$metadata$.type === Kotlin.TYPE.CLASS) { - return basesArray[i]; - } - } - return null; - } - - var emptyFunction = function () { - return function() {}; - }; - Kotlin.TYPE = { CLASS: "class", TRAIT: "trait", @@ -71,275 +33,6 @@ return !(obj == null) && obj.$metadata$ == null; } - function applyExtension(current, bases, baseGetter) { - for (var i = 0; i < bases.length; i++) { - if (isNativeClass(bases[i])) { - continue; - } - var base = baseGetter(bases[i]); - for (var p in base) { - if (base.hasOwnProperty(p)) { - if (!current.hasOwnProperty(p) || current[p].$classIndex$ < base[p].$classIndex$) { - current[p] = base[p]; - } - } - } - } - } - - function computeMetadata(bases, properties, staticProperties) { - var metadata = {}; - var p, property; - - metadata.baseClasses = toArray(bases); - metadata.baseClass = getClass(metadata.baseClasses); - metadata.classIndex = Kotlin.newClassIndex(); - metadata.functions = {}; - metadata.properties = {}; - metadata.types = {}; - metadata.staticMembers = {}; - - if (!(properties == null)) { - for (p in properties) { - if (properties.hasOwnProperty(p)) { - property = properties[p]; - property.$classIndex$ = metadata.classIndex; - if (typeof property === "function") { - metadata.functions[p] = property; - } - else { - metadata.properties[p] = property; - } - } - } - } - if (typeof staticProperties !== 'undefined') { - for (p in staticProperties) { - //noinspection JSUnfilteredForInLoop - property = staticProperties[p]; - if (typeof property === "function" && property.type === Kotlin.TYPE.INIT_FUN) { - //noinspection JSUnfilteredForInLoop - metadata.types[p] = property; - } - else { - //noinspection JSUnfilteredForInLoop - metadata.staticMembers[p] = property; - } - } - } - applyExtension(metadata.functions, metadata.baseClasses, function (it) { - return it.$metadata$.functions - }); - applyExtension(metadata.properties, metadata.baseClasses, function (it) { - return it.$metadata$.properties - }); - - return metadata; - } - - /** - * @param {(Array|Object|null)=} bases - * @param {(function(new: T, ?, ?, ?, ?, ?, ?, ?): T)|null=} constructor - * @param {Object=} properties - * @param {Object=} staticProperties - * @returns {function(new: T): T} - * @template T - */ - Kotlin.createClassNow = function (bases, constructor, properties, staticProperties) { - if (constructor == null) { - constructor = emptyFunction(); - } - - var metadata = computeMetadata(bases, properties, staticProperties); - metadata.type = Kotlin.TYPE.CLASS; - copyProperties(constructor, metadata.staticMembers); - - var prototypeObj; - if (metadata.baseClass !== null) { - prototypeObj = Object.create(metadata.baseClass.prototype); - } - else { - prototypeObj = {}; - } - Object.defineProperties(prototypeObj, metadata.properties); - copyProperties(prototypeObj, metadata.functions); - prototypeObj.constructor = constructor; - defineNestedTypes(constructor, metadata.types); - - if (metadata.baseClass != null) { - constructor.baseInitializer = metadata.baseClass; - } - - constructor.$metadata$ = metadata; - constructor.prototype = prototypeObj; - return constructor; - }; - - function defineNestedTypes(constructor, types) { - for (var innerTypeName in types) { - // since types object does not inherit from anything, it's just a map - //noinspection JSUnfilteredForInLoop - var innerType = types[innerTypeName]; - innerType.className = innerTypeName; - //noinspection JSUnfilteredForInLoop - Object.defineProperty(constructor, innerTypeName, { - get: innerType, - configurable: true - }); - } - } - - Kotlin.createTraitNow = function (bases, properties, staticProperties) { - var obj = {}; - - obj.$metadata$ = computeMetadata(bases, properties, staticProperties); - obj.$metadata$.type = Kotlin.TYPE.TRAIT; - copyProperties(obj, obj.$metadata$.staticMembers); - - obj.prototype = {}; - Object.defineProperties(obj.prototype, obj.$metadata$.properties); - copyProperties(obj.prototype, obj.$metadata$.functions); - - defineNestedTypes(obj, obj.$metadata$.types); - return obj; - }; - - function getBases(basesFun) { - if (typeof basesFun === "function") { - return basesFun(); - } - else { - return basesFun; - } - } - - /** - * @param {(function():Array.<*>)|null} basesFun - * @param {?=} constructor - * @param {Object=} properties - * @param {Object=} staticProperties - * @returns {*} - */ - Kotlin.createClass = function (basesFun, constructor, properties, staticProperties) { - function $o() { - var klass = Kotlin.createClassNow(getBases(basesFun), constructor, properties, staticProperties); - klass.$metadata$.simpleName = $o.className; - Object.defineProperty(this, $o.className, {value: klass}); - if (staticProperties && staticProperties.object_initializer$) { - staticProperties.object_initializer$(klass); - } - return klass; - } - - $o.type = Kotlin.TYPE.INIT_FUN; - return $o; - }; - - /** - * @param {(function():Array.<*>)|null} basesFun - * @param {?=} constructor - * @param {function():Object} enumEntries - * @param {Object=} properties - * @param {Object=} staticProperties - * @returns {*} - */ - Kotlin.createEnumClass = function (basesFun, constructor, enumEntries, properties, staticProperties) { - staticProperties = staticProperties || {}; - - // TODO use Object.assign - staticProperties.object_initializer$ = function (cls) { - var enumEntryList = enumEntries(); - var i = 0; - var values = []; - for (var entryName in enumEntryList) { - if (enumEntryList.hasOwnProperty(entryName)) { - var entryFactory = enumEntryList[entryName]; - values.push(entryName); - - var entryObject; - if (typeof entryFactory === 'function' && entryFactory.type === Kotlin.TYPE.INIT_FUN) { - entryFactory.className = entryName; - entryObject = entryFactory.apply(cls); - } - else { - entryObject = entryFactory(); - } - - entryObject.ordinal$ = i++; - entryObject.name$ = entryName; - cls[entryName] = entryObject; - } - } - cls.valuesNames$ = values; - cls.values$ = null; - }; - - staticProperties.values = function () { - if (this.values$ == null) { - this.values$ = []; - for (var i = 0; i < this.valuesNames$.length; ++i) { - this.values$.push(this[this.valuesNames$[i]]) - } - } - return this.values$; - }; - - staticProperties.valueOf_61zpoe$ = function (name) { - return this[name]; - }; - - return Kotlin.createClass(basesFun, constructor, properties, staticProperties) - }; - - /** - * @param {(function():Array.<*>)|null} basesFun - * @param {Object=} properties - * @param {Object=} staticProperties - * @returns {*} - */ - Kotlin.createTrait = function (basesFun, properties, staticProperties) { - function $o() { - var klass = Kotlin.createTraitNow(getBases(basesFun), properties, staticProperties); - klass.name = $o.className; - klass.$metadata$.simpleName = $o.className; - Object.defineProperty(this, $o.className, {value: klass}); - return klass; - } - - $o.type = Kotlin.TYPE.INIT_FUN; - return $o; - }; - - /** - * @param {function()|null} basesFun - * @param {(function(new: T): T)|null=} constructor - * @param {Object=} functions - * @param {Object=} staticProperties - * @returns {Object} - * @template T - */ - Kotlin.createObject = function (basesFun, constructor, functions, staticProperties) { - constructor = constructor || function() {}; - function $o() { - var klass = Kotlin.createClassNow(getBases(basesFun), constructor, functions, staticProperties); - var obj = Object.create(klass.prototype); - var metadata = klass.$metadata$; - metadata.type = Kotlin.TYPE.OBJECT; - metadata.simpleName = $o.className; - Object.defineProperty(this, $o.className, {value: obj}); - defineNestedTypes(obj, klass.$metadata$.types); - copyProperties(obj, metadata.staticMembers); - if (metadata.baseClass != null) { - constructor.baseInitializer = metadata.baseClass; - } - constructor.apply(obj); - return obj; - } - - $o.type = Kotlin.TYPE.INIT_FUN; - return $o; - }; - Kotlin.callGetter = function (thisObject, klass, propertyName) { var propertyDescriptor = Object.getOwnPropertyDescriptor(klass, propertyName); if (propertyDescriptor != null) { @@ -536,77 +229,6 @@ Kotlin.modules = {}; - function createPackageGetter(instance, initializer) { - return function () { - if (initializer !== null) { - var tmp = initializer; - initializer = null; - tmp.call(instance); - } - - return instance; - }; - } - - function createDefinition(members, definition) { - if (typeof definition === "undefined") { - definition = {} - } - if (members == null) { - return definition; - } - for (var p in members) { - if (members.hasOwnProperty(p)) { - if ((typeof members[p]) === "function") { - if (members[p].type === Kotlin.TYPE.INIT_FUN) { - members[p].className = p; - Object.defineProperty(definition, p, { - get: members[p], - configurable: true - }); - } - else { - definition[p] = members[p]; - } - } - else { - Object.defineProperty(definition, p, members[p]); - } - } - } - return definition; - } - - Kotlin.createDefinition = createDefinition; - - /** - * @param {function()|null=} initializer - * @param {Object=} members - * @returns {Object} - */ - Kotlin.definePackage = function (initializer, members) { - var definition = createDefinition(members); - if (initializer === null) { - return {value: definition}; - } - else { - var getter = createPackageGetter(definition, initializer); - return {get: getter}; - } - }; - - Kotlin.defineRootPackage = function (initializer, members) { - var definition = createDefinition(members); - - if (initializer === null) { - definition.$initializer$ = emptyFunction(); - } - else { - definition.$initializer$ = initializer; - } - return definition; - }; - /** * @param {string} id * @param {Object} declaration diff --git a/js/js.translator/testData/test.js b/js/js.translator/testData/test.js index 7fabe32a363..f3ff56cc228 100644 --- a/js/js.translator/testData/test.js +++ b/js/js.translator/testData/test.js @@ -68,34 +68,31 @@ function generateModel(path) { } function supplyAsserter(kotlin) { - var asserterContainer = kotlin.defineRootPackage(null, { - asserter : kotlin.createClass( - function () { - return [kotlin.kotlin.test.Asserter]; - }, - function () {}, - { - assertTrue_tup0fe$: function (lazyMessage, actual) { - kotlin.kotlin.test.assertTrue_8kj6y5$(actual, lazyMessage()); - }, - assertTrue_ivxn3r$: function (message, actual) { - if (!actual) { - this.failWithMessage(message); - } - }, - assertEquals_a59ba6$: kotlin.kotlin.test.Asserter.prototype.assertEquals_a59ba6$, - fail_61zpoe$: function (message) { - this.failWithMessage(message); - }, - failWithMessage: function (message) { - if (message == null) { - throw new Kotlin.AssertionError(); - } else { - throw new Kotlin.AssertionError(message); - } - } - } - ) - }); - kotlin.kotlin.test.asserter = new asserterContainer.asserter(); + function AsserterClass() { + } + AsserterClass.prototype.assertTrue_tup0fe$ = function(lazyMessage, actual) { + kotlin.kotlin.test.assertTrue_8kj6y5$(actual, lazyMessage()); + }; + AsserterClass.prototype.assertTrue_ivxn3r$ = function(message, actual) { + if (!actual) { + this.failWithMessage(message); + } + }; + AsserterClass.prototype.assertEquals_a59ba6$ = kotlin.kotlin.test.Asserter.prototype.assertEquals_a59ba6$; + AsserterClass.prototype.fail_61zpoe$ = function(message) { + this.failWithMessage(message); + }; + AsserterClass.prototype.failWithMessage = function(message) { + if (message == null) { + throw new Kotlin.AssertionError(); + } else { + throw new Kotlin.AssertionError(message); + } + }; + AsserterClass.$metadata$ = { + type: kotlin.TYPE.CLASS, + classIndex: kotlin.newClassIndex(), + baseClasses: [kotlin.kotlin.test.Asserter] + }; + kotlin.kotlin.test.asserter = new AsserterClass(); } \ No newline at end of file