From 4f49b16079b27d7ce633619e4cddfdf2bffbc952 Mon Sep 17 00:00:00 2001 From: cashmere Date: Fri, 4 Sep 2026 09:05:24 +0200 Subject: initial commit --- extsrc/pikchr.js | 757 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 757 insertions(+) create mode 100644 extsrc/pikchr.js (limited to 'extsrc/pikchr.js') diff --git a/extsrc/pikchr.js b/extsrc/pikchr.js new file mode 100644 index 0000000..5efd240 --- /dev/null +++ b/extsrc/pikchr.js @@ -0,0 +1,757 @@ +// This code implements the `-sMODULARIZE` settings by taking the generated +// JS program code (INNER_JS_CODE) and wrapping it in a factory function. + +// Single threaded MINIMAL_RUNTIME programs do not need access to +// document.currentScript, so a simple export declaration is enough. +var initPikchrModule = (() => { + // When MODULARIZE this JS may be executed later, + // after document.currentScript is gone, so we save it. + // In EXPORT_ES6 mode we can just use 'import.meta.url'. + var _scriptName = globalThis.document?.currentScript?.src; + return async function(moduleArg = {}) { + var moduleRtn; + +// include: shell.js +// include: minimum_runtime_check.js +// end include: minimum_runtime_check.js +// The Module object: Our interface to the outside world. We import +// and export values on it. There are various ways Module can be used: +// 1. Not defined. We create it here +// 2. A function parameter, function(moduleArg) => Promise +// 3. pre-run appended it, var Module = {}; ..generated code.. +// 4. External script tag defines var Module. +// We need to check if Module already exists (e.g. case 3 above). +// Substitution will be replaced with actual code on later stage of the build, +// this way Closure Compiler will not mangle it (e.g. case 4. above). +// Note that if you want to run closure, and also to use Module +// after the generated code, you will need to define var Module = {}; +// before the code. Then that object will be used in the code, and you +// can continue to use Module afterwards as well. +var Module = moduleArg; + +// Determine the runtime environment we are in. You can customize this by +// setting the ENVIRONMENT setting at compile time (see settings.js). +var ENVIRONMENT_IS_WEB = true; + +var ENVIRONMENT_IS_WORKER = false; + +// --pre-jses are emitted after the Module integration code, so that they can +// refer to Module (if they choose; they can also define Module) +var arguments_ = []; + +var thisProgram = "./this.program"; + +var quit_ = (status, toThrow) => { + throw toThrow; +}; + +// `/` should be present at the end if `scriptDirectory` is not empty +var scriptDirectory = ""; + +function locateFile(path) { + if (Module["locateFile"]) { + return Module["locateFile"](path, scriptDirectory); + } + return scriptDirectory + path; +} + +// Hooks that are implemented differently in different runtime environments. +var readAsync, readBinary; + +// Note that this includes Node.js workers when relevant (pthreads is enabled). +// Node.js workers are detected as a combination of ENVIRONMENT_IS_WORKER and +// ENVIRONMENT_IS_NODE. +if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { + try { + scriptDirectory = new URL(".", _scriptName).href; + } catch {} + { + // include: web_or_worker_shell_read.js + readAsync = async url => { + var response = await fetch(url, { + credentials: "same-origin" + }); + if (response.ok) { + return response.arrayBuffer(); + } + throw new Error(response.status + " : " + response.url); + }; + } +} else {} + +var out = console.log.bind(console); + +var err = console.error.bind(console); + +// end include: shell.js +// include: preamble.js +// === Preamble library stuff === +// Documentation for the public APIs defined in this file must be updated in: +// site/source/docs/api_reference/preamble.js.rst +// A prebuilt local version of the documentation is available at: +// site/build/text/docs/api_reference/preamble.js.txt +// You can also build docs locally as HTML or other formats in site/ +// An online HTML version (which may be of a different version of Emscripten) +// is up at http://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html +var wasmBinary; + +// Wasm globals +//======================================== +// Runtime essentials +//======================================== +// whether we are quitting the application. no code should run after this. +// set in exit() and abort() +var ABORT = false; + +// set by exit() and abort(). Passed to 'onExit' handler. +// NOTE: This is also used as the process return code in shell environments +// but only when noExitRuntime is false. +var EXITSTATUS; + +// include: runtime_common.js +// include: runtime_stack_check.js +// end include: runtime_stack_check.js +// include: runtime_exceptions.js +// end include: runtime_exceptions.js +// include: runtime_debug.js +// end include: runtime_debug.js +var readyPromiseResolve, readyPromiseReject; + +// Memory management +var /** @type {!Int8Array} */ HEAP8, /** @type {!Uint8Array} */ HEAPU8, /** @type {!Int16Array} */ HEAP16, /** @type {!Uint16Array} */ HEAPU16, /** @type {!Int32Array} */ HEAP32, /** @type {!Uint32Array} */ HEAPU32, /** @type {!Float32Array} */ HEAPF32, /** @type {!Float64Array} */ HEAPF64; + +// BigInt64Array type is not correctly defined in closure +var /** not-@type {!BigInt64Array} */ HEAP64, /* BigUint64Array type is not correctly defined in closure +/** not-@type {!BigUint64Array} */ HEAPU64; + +var runtimeInitialized = false; + +function updateMemoryViews() { + var b = wasmMemory.buffer; + HEAP8 = new Int8Array(b); + HEAP16 = new Int16Array(b); + HEAPU8 = new Uint8Array(b); + HEAPU16 = new Uint16Array(b); + HEAP32 = new Int32Array(b); + HEAPU32 = new Uint32Array(b); + HEAPF32 = new Float32Array(b); + HEAPF64 = new Float64Array(b); + HEAP64 = new BigInt64Array(b); + HEAPU64 = new BigUint64Array(b); +} + +// include: memoryprofiler.js +// end include: memoryprofiler.js +// end include: runtime_common.js +function preRun() { + if (Module["preRun"]) { + if (typeof Module["preRun"] == "function") Module["preRun"] = [ Module["preRun"] ]; + while (Module["preRun"].length) { + addOnPreRun(Module["preRun"].shift()); + } + } + // Begin ATPRERUNS hooks + callRuntimeCallbacks(onPreRuns); +} + +function initRuntime() { + runtimeInitialized = true; + // No ATINITS hooks + wasmExports["e"](); +} + +function postRun() { + // PThreads reuse the runtime from the main thread. + if (Module["postRun"]) { + if (typeof Module["postRun"] == "function") Module["postRun"] = [ Module["postRun"] ]; + while (Module["postRun"].length) { + addOnPostRun(Module["postRun"].shift()); + } + } + // Begin ATPOSTRUNS hooks + callRuntimeCallbacks(onPostRuns); +} + +/** @param {string|number=} what */ function abort(what) { + Module["onAbort"]?.(what); + what = "Aborted(" + what + ")"; + // TODO(sbc): Should we remove printing and leave it up to whoever + // catches the exception? + err(what); + ABORT = true; + what += ". Build with -sASSERTIONS for more info."; + // Use a wasm runtime error, because a JS error might be seen as a foreign + // exception, which means we'd run destructors on it. We need the error to + // simply make the program stop. + // FIXME This approach does not work in Wasm EH because it currently does not assume + // all RuntimeErrors are from traps; it decides whether a RuntimeError is from + // a trap or not based on a hidden field within the object. So at the moment + // we don't have a way of throwing a wasm trap from JS. TODO Make a JS API that + // allows this in the wasm spec. + // Suppress closure compiler warning here. Closure compiler's builtin extern + // definition for WebAssembly.RuntimeError claims it takes no arguments even + // though it can. + // TODO(https://github.com/google/closure-compiler/pull/3913): Remove if/when upstream closure gets fixed. + /** @suppress {checkTypes} */ var e = new WebAssembly.RuntimeError(what); + readyPromiseReject?.(e); + // Throw the error whether or not MODULARIZE is set because abort is used + // in code paths apart from instantiation where an exception is expected + // to be thrown when abort is called. + throw e; +} + +var wasmBinaryFile; + +function findWasmBinary() { + return locateFile("pikchr-v8806526039.wasm"); +} + +function getBinarySync(file) { + if (file == wasmBinaryFile && wasmBinary) { + return new Uint8Array(wasmBinary); + } + if (readBinary) { + return readBinary(file); + } + // Throwing a plain string here, even though it not normally advisable since + // this gets turning into an `abort` in instantiateArrayBuffer. + throw "both async and sync fetching of the wasm failed"; +} + +async function getWasmBinary(binaryFile) { + // If we don't have the binary yet, load it asynchronously using readAsync. + if (!wasmBinary) { + // Fetch the binary using readAsync + try { + var response = await readAsync(binaryFile); + return new Uint8Array(response); + } catch {} + } + // Otherwise, getBinarySync should be able to get it synchronously + return getBinarySync(binaryFile); +} + +async function instantiateArrayBuffer(binaryFile, imports) { + try { + var binary = await getWasmBinary(binaryFile); + var instance = await WebAssembly.instantiate(binary, imports); + return instance; + } catch (reason) { + err(`failed to asynchronously prepare wasm: ${reason}`); + abort(reason); + } +} + +async function instantiateAsync(binary, binaryFile, imports) { + if (!binary) { + try { + var response = fetch(binaryFile, { + credentials: "same-origin" + }); + var instantiationResult = await WebAssembly.instantiateStreaming(response, imports); + return instantiationResult; + } catch (reason) { + // We expect the most common failure cause to be a bad MIME type for the binary, + // in which case falling back to ArrayBuffer instantiation should work. + err(`wasm streaming compile failed: ${reason}`); + err("falling back to ArrayBuffer instantiation"); + } + } + return instantiateArrayBuffer(binaryFile, imports); +} + +function getWasmImports() { + // prepare imports + var imports = { + "a": wasmImports + }; + return imports; +} + +// Create the wasm instance. +// Receives the wasm imports, returns the exports. +async function createWasm() { + // Load the wasm module and create an instance of using native support in the JS engine. + // handle a generated wasm instance, receiving its exports and + // performing other necessary setup + /** @param {WebAssembly.Module=} module*/ function receiveInstance(instance, module) { + wasmExports = instance.exports; + assignWasmExports(wasmExports); + updateMemoryViews(); + return wasmExports; + } + // Prefer streaming instantiation if available. + function receiveInstantiationResult(result) { + // 'result' is a ResultObject object which has both the module and instance. + // receiveInstance() will swap in the exports (to Module.asm) so they can be called + // TODO: Due to Closure regression https://github.com/google/closure-compiler/issues/3193, the above line no longer optimizes out down to the following line. + // When the regression is fixed, can restore the above PTHREADS-enabled path. + return receiveInstance(result["instance"]); + } + var info = getWasmImports(); + // User shell pages can write their own Module.instantiateWasm = function(imports, successCallback) callback + // to manually instantiate the Wasm module themselves. This allows pages to + // run the instantiation parallel to any other async startup actions they are + // performing. + // Also pthreads and wasm workers initialize the wasm instance through this + // path. + if (Module["instantiateWasm"]) { + return new Promise((resolve, reject) => { + Module["instantiateWasm"](info, (inst, mod) => { + resolve(receiveInstance(inst, mod)); + }); + }); + } + wasmBinaryFile ??= findWasmBinary(); + var result = await instantiateAsync(wasmBinary, wasmBinaryFile, info); + var exports = receiveInstantiationResult(result); + return exports; +} + +// end include: preamble.js +// Begin JS library code +class ExitStatus { + name="ExitStatus"; + constructor(status) { + this.message = `Program terminated with exit(${status})`; + this.status = status; + } +} + +var callRuntimeCallbacks = callbacks => { + while (callbacks.length > 0) { + // Pass the module as the first argument. + callbacks.shift()(Module); + } +}; + +var onPostRuns = []; + +var addOnPostRun = cb => onPostRuns.push(cb); + +var onPreRuns = []; + +var addOnPreRun = cb => onPreRuns.push(cb); + +/** + * @param {number} ptr + * @param {string} type + */ function getValue(ptr, type = "i8") { + if (type.endsWith("*")) type = "*"; + switch (type) { + case "i1": + return HEAP8[ptr]; + + case "i8": + return HEAP8[ptr]; + + case "i16": + return HEAP16[((ptr) >> 1)]; + + case "i32": + return HEAP32[((ptr) >> 2)]; + + case "i64": + return HEAP64[((ptr) >> 3)]; + + case "float": + return HEAPF32[((ptr) >> 2)]; + + case "double": + return HEAPF64[((ptr) >> 3)]; + + case "*": + return HEAPU32[((ptr) >> 2)]; + + default: + abort(`invalid type for getValue: ${type}`); + } +} + +var noExitRuntime = true; + +/** + * @param {number} ptr + * @param {number} value + * @param {string} type + */ function setValue(ptr, value, type = "i8") { + if (type.endsWith("*")) type = "*"; + switch (type) { + case "i1": + HEAP8[ptr] = value; + break; + + case "i8": + HEAP8[ptr] = value; + break; + + case "i16": + HEAP16[((ptr) >> 1)] = value; + break; + + case "i32": + HEAP32[((ptr) >> 2)] = value; + break; + + case "i64": + HEAP64[((ptr) >> 3)] = BigInt(value); + break; + + case "float": + HEAPF32[((ptr) >> 2)] = value; + break; + + case "double": + HEAPF64[((ptr) >> 3)] = value; + break; + + case "*": + HEAPU32[((ptr) >> 2)] = value; + break; + + default: + abort(`invalid type for setValue: ${type}`); + } +} + +var stackRestore = val => __emscripten_stack_restore(val); + +var stackSave = () => _emscripten_stack_get_current(); + +var UTF8Decoder = new TextDecoder; + +var findStringEnd = (heapOrArray, idx, maxBytesToRead, ignoreNul) => { + var maxIdx = idx + maxBytesToRead; + if (ignoreNul) return maxIdx; + // TextDecoder needs to know the byte length in advance, it doesn't stop on + // null terminator by itself. + // As a tiny code save trick, compare idx against maxIdx using a negation, + // so that maxBytesToRead=undefined/NaN means Infinity. + while (heapOrArray[idx] && !(idx >= maxIdx)) ++idx; + return idx; +}; + +/** + * Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the + * emscripten HEAP, returns a copy of that string as a Javascript String object. + * + * @param {number} ptr + * @param {number=} maxBytesToRead - An optional length that specifies the + * maximum number of bytes to read. You can omit this parameter to scan the + * string until the first 0 byte. If maxBytesToRead is passed, and the string + * at [ptr, ptr+maxBytesToReadr[ contains a null byte in the middle, then the + * string will cut short at that byte index. + * @param {boolean=} ignoreNul - If true, the function will not stop on a NUL character. + * @return {string} + */ var UTF8ToString = (ptr, maxBytesToRead, ignoreNul) => { + if (!ptr) return ""; + var end = findStringEnd(HEAPU8, ptr, maxBytesToRead, ignoreNul); + return UTF8Decoder.decode(HEAPU8.subarray(ptr, end)); +}; + +var ___assert_fail = (condition, filename, line, func) => abort(`Assertion failed: ${UTF8ToString(condition)}, at: ` + [ filename ? UTF8ToString(filename) : "unknown filename", line, func ? UTF8ToString(func) : "unknown function" ]); + +var abortOnCannotGrowMemory = requestedSize => { + abort("OOM"); +}; + +var _emscripten_resize_heap = requestedSize => { + var oldSize = HEAPU8.length; + // With CAN_ADDRESS_2GB or MEMORY64, pointers are already unsigned. + requestedSize >>>= 0; + abortOnCannotGrowMemory(requestedSize); +}; + +var runtimeKeepaliveCounter = 0; + +var keepRuntimeAlive = () => noExitRuntime || runtimeKeepaliveCounter > 0; + +var _proc_exit = code => { + EXITSTATUS = code; + if (!keepRuntimeAlive()) { + Module["onExit"]?.(code); + ABORT = true; + } + quit_(code, new ExitStatus(code)); +}; + +/** @param {boolean|number=} implicit */ var exitJS = (status, implicit) => { + EXITSTATUS = status; + _proc_exit(status); +}; + +var _exit = exitJS; + +var getCFunc = ident => { + var func = Module["_" + ident]; + // closure exported function + return func; +}; + +var writeArrayToMemory = (array, buffer) => { + HEAP8.set(array, buffer); +}; + +var lengthBytesUTF8 = str => { + var len = 0; + for (var i = 0; i < str.length; ++i) { + // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code + // unit, not a Unicode code point of the character! So decode + // UTF16->UTF32->UTF8. + // See http://unicode.org/faq/utf_bom.html#utf16-3 + var c = str.charCodeAt(i); + // possibly a lead surrogate + if (c <= 127) { + len++; + } else if (c <= 2047) { + len += 2; + } else if (c >= 55296 && c <= 57343) { + len += 4; + ++i; + } else { + len += 3; + } + } + return len; +}; + +var stringToUTF8Array = (str, heap, outIdx, maxBytesToWrite) => { + // Parameter maxBytesToWrite is not optional. Negative values, 0, null, + // undefined and false each don't write out any bytes. + if (!(maxBytesToWrite > 0)) return 0; + var startIdx = outIdx; + var endIdx = outIdx + maxBytesToWrite - 1; + // -1 for string null terminator. + for (var i = 0; i < str.length; ++i) { + // For UTF8 byte structure, see http://en.wikipedia.org/wiki/UTF-8#Description + // and https://www.ietf.org/rfc/rfc2279.txt + // and https://tools.ietf.org/html/rfc3629 + var u = str.codePointAt(i); + if (u <= 127) { + if (outIdx >= endIdx) break; + heap[outIdx++] = u; + } else if (u <= 2047) { + if (outIdx + 1 >= endIdx) break; + heap[outIdx++] = 192 | (u >> 6); + heap[outIdx++] = 128 | (u & 63); + } else if (u <= 65535) { + if (outIdx + 2 >= endIdx) break; + heap[outIdx++] = 224 | (u >> 12); + heap[outIdx++] = 128 | ((u >> 6) & 63); + heap[outIdx++] = 128 | (u & 63); + } else { + if (outIdx + 3 >= endIdx) break; + heap[outIdx++] = 240 | (u >> 18); + heap[outIdx++] = 128 | ((u >> 12) & 63); + heap[outIdx++] = 128 | ((u >> 6) & 63); + heap[outIdx++] = 128 | (u & 63); + // Gotcha: if codePoint is over 0xFFFF, it is represented as a surrogate pair in UTF-16. + // We need to manually skip over the second code unit for correct iteration. + i++; + } + } + // Null-terminate the pointer to the buffer. + heap[outIdx] = 0; + return outIdx - startIdx; +}; + +var stringToUTF8 = (str, outPtr, maxBytesToWrite) => stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite); + +var stackAlloc = sz => __emscripten_stack_alloc(sz); + +var stringToUTF8OnStack = str => { + var size = lengthBytesUTF8(str) + 1; + var ret = stackAlloc(size); + stringToUTF8(str, ret, size); + return ret; +}; + +/** + * @param {string|null=} returnType + * @param {Array=} argTypes + * @param {Array=} args + * @param {Object=} opts + */ var ccall = (ident, returnType, argTypes, args, opts) => { + // For fast lookup of conversion functions + var toC = { + "string": str => { + var ret = 0; + if (str !== null && str !== undefined && str !== 0) { + // null string + ret = stringToUTF8OnStack(str); + } + return ret; + }, + "array": arr => { + var ret = stackAlloc(arr.length); + writeArrayToMemory(arr, ret); + return ret; + } + }; + function convertReturnValue(ret) { + if (returnType === "string") { + return UTF8ToString(ret); + } + if (returnType === "boolean") return Boolean(ret); + return ret; + } + var func = getCFunc(ident); + var cArgs = []; + var stack = 0; + if (args) { + for (var i = 0; i < args.length; i++) { + var converter = toC[argTypes[i]]; + if (converter) { + if (stack === 0) stack = stackSave(); + cArgs[i] = converter(args[i]); + } else { + cArgs[i] = args[i]; + } + } + } + var ret = func(...cArgs); + function onDone(ret) { + if (stack !== 0) stackRestore(stack); + return convertReturnValue(ret); + } + ret = onDone(ret); + return ret; +}; + +/** + * @param {string=} returnType + * @param {Array=} argTypes + * @param {Object=} opts + */ var cwrap = (ident, returnType, argTypes, opts) => { + // When the function takes numbers and returns a number, we can just return + // the original function + var numericArgs = !argTypes || argTypes.every(type => type === "number" || type === "boolean"); + var numericRet = returnType !== "string"; + if (numericRet && numericArgs && !opts) { + return getCFunc(ident); + } + return (...args) => ccall(ident, returnType, argTypes, args, opts); +}; + +// End JS library code +// include: postlibrary.js +// This file is included after the automatically-generated JS library code +// but before the wasm module is created. +{ + // Begin ATMODULES hooks + if (Module["noExitRuntime"]) noExitRuntime = Module["noExitRuntime"]; + if (Module["print"]) out = Module["print"]; + if (Module["printErr"]) err = Module["printErr"]; + if (Module["wasmBinary"]) wasmBinary = Module["wasmBinary"]; + // End ATMODULES hooks + if (Module["arguments"]) arguments_ = Module["arguments"]; + if (Module["thisProgram"]) thisProgram = Module["thisProgram"]; + if (Module["preInit"]) { + if (typeof Module["preInit"] == "function") Module["preInit"] = [ Module["preInit"] ]; + while (Module["preInit"].length > 0) { + Module["preInit"].shift()(); + } + } +} + +// Begin runtime exports +Module["stackSave"] = stackSave; + +Module["stackRestore"] = stackRestore; + +Module["stackAlloc"] = stackAlloc; + +Module["ccall"] = ccall; + +Module["cwrap"] = cwrap; + +Module["setValue"] = setValue; + +Module["getValue"] = getValue; + +// End runtime exports +// Begin JS library exports +// End JS library exports +// end include: postlibrary.js +// Imports from the Wasm binary. +var _pikchr_version, _pikchr, __emscripten_stack_restore, __emscripten_stack_alloc, _emscripten_stack_get_current, memory, __indirect_function_table, wasmMemory; + +function assignWasmExports(wasmExports) { + _pikchr_version = Module["_pikchr_version"] = wasmExports["f"]; + _pikchr = Module["_pikchr"] = wasmExports["g"]; + __emscripten_stack_restore = wasmExports["h"]; + __emscripten_stack_alloc = wasmExports["i"]; + _emscripten_stack_get_current = wasmExports["j"]; + memory = wasmMemory = wasmExports["d"]; + __indirect_function_table = wasmExports["__indirect_function_table"]; +} + +var wasmImports = { + /** @export */ a: ___assert_fail, + /** @export */ b: _emscripten_resize_heap, + /** @export */ c: _exit +}; + +// include: postamble.js +// === Auto-generated postamble setup entry stuff === +function run() { + preRun(); + function doRun() { + // run may have just been called through dependencies being fulfilled just in this very frame, + // or while the async setStatus time below was happening + Module["calledRun"] = true; + if (ABORT) return; + initRuntime(); + readyPromiseResolve?.(Module); + Module["onRuntimeInitialized"]?.(); + postRun(); + } + if (Module["setStatus"]) { + Module["setStatus"]("Running..."); + setTimeout(() => { + setTimeout(() => Module["setStatus"](""), 1); + doRun(); + }, 1); + } else { + doRun(); + } +} + +var wasmExports; + +// In modularize mode the generated code is within a factory function so we +// can use await here (since it's not top-level-await). +wasmExports = await (createWasm()); + +run(); + +// end include: postamble.js +// include: postamble_modularize.js +// In MODULARIZE mode we wrap the generated code in a factory function +// and return either the Module itself, or a promise of the module. +// We assign to the `moduleRtn` global here and configure closure to see +// this as an extern so it won't get minified. +if (runtimeInitialized) { + moduleRtn = Module; +} else { + // Set up the promise that indicates the Module is initialized + moduleRtn = new Promise((resolve, reject) => { + readyPromiseResolve = resolve; + readyPromiseReject = reject; + }); +} + + + return moduleRtn; + }; +})(); + +// Export using a UMD style export, or ES6 exports if selected +if (typeof exports === 'object' && typeof module === 'object') { + module.exports = initPikchrModule; + // This default export looks redundant, but it allows TS to import this + // commonjs style module. + module.exports.default = initPikchrModule; +} else if (typeof define === 'function' && define['amd']) + define([], () => initPikchrModule); + -- cgit v1.3.1