| // TARGET_BACKEND: WASM |
| // WITH_STDLIB |
| |
| // FILE: test.kt |
| |
| @JsExport |
| fun concatAndSlice(prefix: String, value: String, suffix: String): String = |
| (prefix + value + suffix).substring(prefix.length, prefix.length + value.length) |
| |
| @JsExport |
| fun codeUnitAt(value: String, index: Int): Int = |
| value[index].code |
| |
| @JsExport |
| fun makeFromChars(): String = |
| charArrayOf('A', '\u0000', '\uD83D', '\uDE80', 'Z').concatToString() |
| |
| @JsExport |
| fun compareAndCopyThroughChars(lhs: String, rhs: String): String { |
| if (lhs != rhs) return "not equal" |
| if (lhs.compareTo(rhs) != 0) return "not zero" |
| |
| val chars = CharArray(lhs.length) |
| lhs.toCharArray(chars, 0, 0, lhs.length) |
| return chars.concatToString() |
| } |
| |
| private fun jsCodeStringRoundTrip(value: String): String = |
| js("value") |
| |
| @JsExport |
| fun roundTripThroughJsCode(value: String): String = |
| jsCodeStringRoundTrip(value) |
| |
| fun box(): String = "OK" |
| |
| // FILE: entry.mjs |
| import { importObject } from "./index.import-object.mjs"; |
| import { box, codeUnitAt, compareAndCopyThroughChars, concatAndSlice, makeFromChars, roundTripThroughJsCode } from "./index.mjs"; |
| |
| function artifactUrl(name) { |
| return import.meta.url.substring(0, import.meta.url.lastIndexOf("/") + 1) + name; |
| } |
| |
| // js-string builtins are existing in single-module/multi-module mode in stdlib module |
| // ownerBase should resolve to either test directory (whole-program mode), |
| // or to stdlib directory (single-module/multi-module) |
| const indexImportObjectSource = read(artifactUrl("index.import-object.mjs")); |
| |
| let ownerBase = "./index"; |
| const stdlibImport = indexImportObjectSource.match(/from\s*['"]([^'"]*kotlin-kotlin-stdlib)\.mjs['"]/); |
| if (stdlibImport != null) { |
| ownerBase = stdlibImport[1]; |
| } |
| |
| const wrapperSource = read(artifactUrl("index.mjs")); |
| const ownerSource = read(artifactUrl(ownerBase + ".mjs")); |
| const ownerImportObjectSource = read(artifactUrl(ownerBase + ".import-object.mjs")); |
| if (!ownerSource.includes("builtins: ['js-string']")) { |
| throw "owner index.mjs does not request js-string builtins"; |
| } |
| if (!wrapperSource.includes("importedStringConstants: \"'\"")) { |
| throw "index.mjs does not request imported string constants"; |
| } |
| if (!ownerImportObjectSource.includes("StringConstantsProxy")) { |
| throw "owner import-object does not define StringConstantsProxy"; |
| } |
| if (!ownerImportObjectSource.includes("'wasm:js-string'")) { |
| throw "owner import-object does not import wasm:js-string"; |
| } |
| |
| const jsStringBuiltins = await import(artifactUrl(ownerBase + ".js-builtins.mjs")); |
| const ownerImportObject = (await import(artifactUrl(ownerBase + ".import-object.mjs"))).importObject; |
| |
| const requiredBuiltins = [ |
| "length", |
| "concat", |
| "charCodeAt", |
| "substring", |
| "compare", |
| "equals", |
| "fromCharCodeArray", |
| "intoCharCodeArray", |
| ]; |
| |
| for (const name of requiredBuiltins) { |
| if (typeof jsStringBuiltins[name] !== "function") { |
| throw `Missing js-string builtin export: ${name}`; |
| } |
| } |
| |
| if (ownerImportObject["wasm:js-string"] !== jsStringBuiltins) { |
| throw "importObject does not wire wasm:js-string to the js-builtins module"; |
| } |
| |
| const stringConstants = importObject["'"]; |
| if (stringConstants == null) { |
| throw "Missing imported string constants proxy"; |
| } |
| |
| const importedConstant = "A'\u0000B🚀"; |
| if (stringConstants[importedConstant] !== importedConstant) { |
| throw "StringConstantsProxy does not return imported string constants"; |
| } |
| |
| if (box() !== "OK") { |
| throw "Kotlin box failed"; |
| } |
| |
| const edge = "A\u0000🚀e\u0301Z"; |
| if (concatAndSlice("<<", edge, ">>") !== edge) { |
| throw "concat/substring builtins path failed"; |
| } |
| |
| if (codeUnitAt(edge, 2) !== edge.charCodeAt(2)) { |
| throw "charCodeAt builtin path failed"; |
| } |
| |
| if (makeFromChars() !== "A\u0000🚀Z") { |
| throw "fromCharCodeArray builtin path failed"; |
| } |
| |
| if (compareAndCopyThroughChars(edge, edge) !== edge) { |
| throw "equals/compare/intoCharCodeArray builtin path failed"; |
| } |
| |
| if (roundTripThroughJsCode(edge) !== edge) { |
| throw "js_code string roundtrip failed"; |
| } |