From cc02b1cc691b0ae3a896710fdaa995c721839fff Mon Sep 17 00:00:00 2001 From: DerThorsten Date: Mon, 22 Jan 2024 20:34:27 +0100 Subject: [PATCH] first sane version --- .gitignore | 3 + CMakeLists.txt | 1 + notebooks/xeus-javascript.ipynb | 65 ++++++++++++++++++- src/post.js | 2 + src/pre.js | 107 ++++++++++++++++++++++++-------- src/xinterpreter.cpp | 9 ++- 6 files changed, 155 insertions(+), 32 deletions(-) create mode 100644 src/post.js diff --git a/.gitignore b/.gitignore index 0d0ad7c..6a4912e 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,6 @@ build/ build_wasm/ bld + +# macOS +.DS_Store diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c9238b..e00196e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -284,6 +284,7 @@ if(EMSCRIPTEN) PUBLIC "SHELL: -s ASYNCIFY" PUBLIC "SHELL: -s FORCE_FILESYSTEM=1" PUBLIC "SHELL: --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/src/pre.js" + PUBLIC "SHELL: --post-js ${CMAKE_CURRENT_SOURCE_DIR}/src/post.js" ) endif() diff --git a/notebooks/xeus-javascript.ipynb b/notebooks/xeus-javascript.ipynb index ce4708f..2a6d180 100644 --- a/notebooks/xeus-javascript.ipynb +++ b/notebooks/xeus-javascript.ipynb @@ -14,6 +14,17 @@ "# Simple code execution" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "plaintext" + } + }, + "outputs": [], + "source": [] + }, { "cell_type": "code", "execution_count": null, @@ -108,8 +119,7 @@ "metadata": {}, "source": [ "# Scope\n", - "all variables declared via `const` or `let` are scoped to the cell they are declared in and are not accessible from other cells.\n", - "All variables declared via `var` are scoped to the notebook and are accessible from other cells." + "all toplevel variables (const/let/var) are accessible from other cells." ] }, { @@ -126,6 +136,17 @@ "let fubar_local=43;" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "plaintext" + } + }, + "outputs": [], + "source": [] + }, { "cell_type": "code", "execution_count": null, @@ -150,9 +171,47 @@ }, "outputs": [], "source": [ - "// this does not\n", + "// this also works\n", + "\n", "console.log(fubar_local)" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Const reassignment\n", + "within a cell, const cannot be reassigned, but it can be reassigned in another cell, or\n", + "when the cell is re-executed." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "plaintext" + } + }, + "outputs": [], + "source": [ + "const some_const_var = 42;\n", + "pp(some_const_var)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "plaintext" + } + }, + "outputs": [], + "source": [ + "const some_const_var = 43;\n", + "pp(some_const_var)" + ] } ], "metadata": { diff --git a/src/post.js b/src/post.js new file mode 100644 index 0000000..20a6fee --- /dev/null +++ b/src/post.js @@ -0,0 +1,2 @@ + +Module["FS"] = FS; diff --git a/src/pre.js b/src/pre.js index 71155bd..ac929e3 100644 --- a/src/pre.js +++ b/src/pre.js @@ -1,40 +1,67 @@ Module["_make_async_from_code"] = function (code) { - let async_function = Function(` - const afunc = async function(){ + const code_ast = Module["_ast_parse"](code); + let extra_code = []; + for(const node of code_ast.body){ + if(node.type == "FunctionDeclaration") + { + const name = node.id.name; + extra_code.push(`globalThis[\'${name}\'] = eval(${name})`); + } + else if(node.type == "VariableDeclaration") + { + const name = node.declarations[0].id.name; + extra_code.push(`globalThis[\'${name}\'] = eval(${name})`); + } + } + const ec = extra_code.join('\n'); + const total_code = code.concat('\n', ec); - function __storeVars(target) { - return new Proxy(target, { - has(target, prop) { return true; }, - get(target, prop) { - if(prop in target){ - return target[prop]; - } - else{ - if (typeof globalThis[prop] === 'function') { - return globalThis[prop].bind(globalThis); - } - return globalThis[prop]; - } - } - }); - } - let __stored_vars = {}; - with(__storeVars(__stored_vars)) { - ${code} - } - for (const [key, value] of Object.entries(__stored_vars)) { - globalThis[key] = value - } + let async_function = Function(` + const afunc = async function(){ + ${total_code} } return afunc; `)(); return async_function; } +Module["_ast_parse_options"] = { + ranges: true +}; + +Module["_ast_parse"] = function (code) { + return globalThis["meriyah"].parseScript(code, Module["_ast_parse_options"]); +} + Module["_configure"] = function () { - _clog = console.log; + + console.log("import meriyah"); + const url="https://cdn.jsdelivr.net/npm/meriyah@4.3.9/dist/meriyah.umd.min.js" + importScripts(url); + + + + globalThis.ijs + globalThis.pprint = function(...args){ + // stringify all with 2 spaces + // and join with space + // and add newline at the end + + let msg = "" + for (let i = 0; i < args.length; i++) { + msg += `${JSON.stringify(args[i], null, 2)}`; + if (i < args.length - 1) { + msg += " "; + } + } + Module["_publish_stdout_stream"](`${msg}\n`); + } + // alias + globalThis.pp = globalThis.pprint; + + console.log = function (... args) { let msg = "" for (let i = 0; i < args.length; i++) { @@ -45,7 +72,6 @@ Module["_configure"] = function () { } Module["_publish_stdout_stream"](`${msg}\n`); } - _cerr = console.error; console.error = function (... args) { let msg = "" for (let i = 0; i < args.length; i++) { @@ -62,6 +88,7 @@ Module["_configure"] = function () { } Module["_call_user_code"] = async function (code) { + try{ const async_function = Module["_make_async_from_code"](code); await async_function(); @@ -70,6 +97,31 @@ Module["_call_user_code"] = async function (code) { } } catch(err){ + + // if the error is an integer, then + // its a c++ exception ptr + // so we need to get the error message + + if(typeof err === "number"){ + console.log("catched c++ exception", err); + let msg = Module["get_exception_message"](err); + + // if promise + if(msg instanceof Promise){ + console.log("awaiting promise"); + msg = await msg; + } + + + console.log("msg", msg); + return{ + error_type: "C++ Exception", + error_message: `${msg}`, + error_stack: "", + has_error: true + } + } + return{ error_type: `${err.name || "UnkwownError"}`, error_message: `${err.message || ""}`, @@ -77,6 +129,7 @@ Module["_call_user_code"] = async function (code) { has_error: true } } + } diff --git a/src/xinterpreter.cpp b/src/xinterpreter.cpp index eb3b40a..48e692b 100644 --- a/src/xinterpreter.cpp +++ b/src/xinterpreter.cpp @@ -19,6 +19,7 @@ // embind #include +#include #include @@ -51,6 +52,7 @@ namespace xeus_javascript // std::cout<<"display_data"<()) { @@ -100,7 +104,8 @@ namespace xeus_javascript } - return xeus::create_successful_reply(nl::json::array(), nl::json::object()); + + return xeus::create_successful_reply(nl::json::array(), nl::json::object()); } void interpreter::configure_impl()