diff --git a/esm/interpreter/quickjs-emscripten.js b/esm/interpreter/quickjs-emscripten.js new file mode 100644 index 0000000..a50abec --- /dev/null +++ b/esm/interpreter/quickjs-emscripten.js @@ -0,0 +1,74 @@ +import { fetchFiles, fetchPaths, io, stdio, writeFileShim } from './_utils.js'; + +const type = 'quickjs-emscripten'; + +const moduleLoader = (name, interpreter) => { + return modules.get(interpreter).get(name).text; +}; + +const modules = new WeakMap; + +// REQUIRES INTEGRATION TEST +/* c8 ignore start */ +export default { + type, + module: (version = '0.0.2') => + `https://cdn.jsdelivr.net/npm/@webreflection/quickjs-emscripten@${version}/index.js`, + async engine({ getQuickJS }, config) { + const QuickJS = await getQuickJS(); + const { stderr, stdout, get } = stdio(); + const interpreter = await get(QuickJS.newContext()); + + // TODO: this should not be needed if CLI flags are passed along + const console = interpreter.newObject(); + const log = interpreter.newFunction('log', (...args) => { + for (const value of args) + interpreter.module.out(interpreter.dump(value)); + }); + interpreter.setProp(console, 'log', log); + interpreter.setProp(interpreter.global, 'console', console); + + // TODO: these two are actually ignored completely + interpreter.module.stderr = stderr; + interpreter.module.stdout = stdout; + + interpreter.runtime.setModuleLoader(moduleLoader); + modules.set(interpreter, new Map); + if (config.files) await fetchFiles(this, interpreter, config.files); + if (config.fetch) await fetchPaths(this, interpreter, config.fetch); + return interpreter; + }, + registerJSModule(interpreter, name, value) { + // TODO: wrap all module things and create a better export per field + // considering the `default` as special. + // Value also cannot be just passed to setProp as it is. + const m = modules.get(interpreter); + const id = `__${name}`; + interpreter.setProp(interpreter.global, id, value); + m.set(name, { id, value, text: `export default ${id};` }); + }, + run(interpreter, code) { + try { + const result = interpreter.evalCode(code, {strict: true}); + return interpreter.dump(interpreter.unwrapResult(result)); + } + catch (error) { + io.get(interpreter).stderr(error); + } + }, + async runAsync(interpreter, code) { + try { + const result = await interpreter.evalCodeAsync(code, {strict: true}); + return interpreter.dump(interpreter.unwrapResult(result)); + } + catch (error) { + io.get(interpreter).stderr(error); + } + }, + runEvent(interpreter, code, event) { + + }, + transform: (_, value) => value, + writeFile: ({ module: { FS } }, path, buffer) => writeFileShim(FS, path, buffer), +}; +/* c8 ignore stop */ diff --git a/esm/interpreters.js b/esm/interpreters.js index ed858d9..36ed79a 100644 --- a/esm/interpreters.js +++ b/esm/interpreters.js @@ -54,7 +54,8 @@ const register = (interpreter) => { //:RUNTIMES import micropython from './interpreter/micropython.js'; import pyodide from './interpreter/pyodide.js'; +import quickjs_emscripten from './interpreter/quickjs-emscripten.js'; import ruby_wasm_wasi from './interpreter/ruby-wasm-wasi.js'; import wasmoon from './interpreter/wasmoon.js'; -for (const interpreter of [micropython, pyodide, ruby_wasm_wasi, wasmoon]) +for (const interpreter of [micropython, pyodide, quickjs_emscripten, ruby_wasm_wasi, wasmoon]) register(interpreter); diff --git a/test/quickjs-emscripten.html b/test/quickjs-emscripten.html new file mode 100644 index 0000000..c4f3589 --- /dev/null +++ b/test/quickjs-emscripten.html @@ -0,0 +1,22 @@ + + +
+ + +