From 9c611b8a01e844cf825f9f221fec5ac325a0e81d Mon Sep 17 00:00:00 2001 From: wangdequan Date: Mon, 8 Jun 2026 05:25:45 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=A7=A3=E9=87=8A=E5=99=A8WA?= =?UTF-8?q?SM=E5=91=BD=E5=90=8D=E5=8F=82=E6=95=B0=E5=A4=B9=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 结论:解释器核心WASM新增带INI文件边界的运行入口,并覆盖namedparam_semantics夹具,INI/HAL解析继续直接来自LinuxCNC解释器源码。 --- wasm-port/docs/compatibility-validation.md | 11 +++--- .../linuxcnc_wrap/linuxcnc_interp_wasm.cpp | 16 +++++++- .../tests/wasm/node/verify_interp_wasm.mjs | 39 ++++++++++++++++++- wasm-port/tools/build_wasm_core.sh | 2 +- 4 files changed, 60 insertions(+), 8 deletions(-) diff --git a/wasm-port/docs/compatibility-validation.md b/wasm-port/docs/compatibility-validation.md index b8f38ca..22246d2 100644 --- a/wasm-port/docs/compatibility-validation.md +++ b/wasm-port/docs/compatibility-validation.md @@ -198,11 +198,12 @@ INI parser smoke harness and an initial interpreter-core canonical event smoke for `minimal_linear`, `arc_semantics`, `length_units`, `modal_incremental`, `plane_selection`, `coordinate_offsets`, `g53_machine_coordinates`, `feed_control_modes`, `position_params`, `probe_semantics`, `spindle_orient`, -`comment_logging`, and `numbered_params`, plus the `g1_zero_feed`, -`arc_radius_mismatch`, `arc_zero_radius`, and `g53_incremental` negative -fixtures. The WASM interpreter file path additionally covers -`file_open_reset`, `percent_file_finish`, and `oword_subroutine`. OPFS -validation is limited to the JavaScript host-boundary adapter plus the INI +`comment_logging`, `numbered_params`, and `namedparam_semantics`, plus the +`g1_zero_feed`, `arc_radius_mismatch`, `arc_zero_radius`, and +`g53_incremental` negative fixtures. The WASM interpreter file path +additionally covers `file_open_reset`, `percent_file_finish`, and +`oword_subroutine`. OPFS validation is limited to the JavaScript host-boundary +adapter plus the INI browser smoke harness. Full browser coverage, full SDK coverage, and full machine-session validation remain future work. diff --git a/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_interp_wasm.cpp b/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_interp_wasm.cpp index 827f188..6b5dac8 100644 --- a/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_interp_wasm.cpp +++ b/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_interp_wasm.cpp @@ -131,8 +131,14 @@ void append_events_and_state(std::ostringstream &output, const Interp &interp) extern "C" { EMSCRIPTEN_KEEPALIVE -char *lcinterp_run_program(const char *program_text) +char *lcinterp_run_program_with_ini(const char *program_text, const char *ini_path) { + if (ini_path && ini_path[0] != '\0') { + setenv("INI_FILE_NAME", ini_path, 1); + } else { + unsetenv("INI_FILE_NAME"); + } + Interp interp; standalone::reset_canon_events(); initialize_minimal_interp(interp); @@ -160,9 +166,17 @@ char *lcinterp_run_program(const char *program_text) return copy_result(output.str()); } +EMSCRIPTEN_KEEPALIVE +char *lcinterp_run_program(const char *program_text) +{ + return lcinterp_run_program_with_ini(program_text, nullptr); +} + EMSCRIPTEN_KEEPALIVE char *lcinterp_run_file(const char *path) { + unsetenv("INI_FILE_NAME"); + Interp interp; standalone::reset_canon_events(); initialize_minimal_interp(interp); diff --git a/wasm-port/tests/wasm/node/verify_interp_wasm.mjs b/wasm-port/tests/wasm/node/verify_interp_wasm.mjs index c5e2763..7c56c92 100644 --- a/wasm-port/tests/wasm/node/verify_interp_wasm.mjs +++ b/wasm-port/tests/wasm/node/verify_interp_wasm.mjs @@ -27,6 +27,23 @@ function runProgram(mod, programText) { } } +function runProgramWithIni(mod, programText, iniPath) { + const programPtr = allocCString(mod, programText); + const iniPathPtr = allocCString(mod, iniPath); + let resultPtr = 0; + try { + resultPtr = mod._lcinterp_run_program_with_ini(programPtr, iniPathPtr); + assert.notEqual(resultPtr, 0); + return mod.UTF8ToString(resultPtr); + } finally { + if (resultPtr) { + mod._lcinterp_free_string(resultPtr); + } + mod._free(programPtr); + mod._free(iniPathPtr); + } +} + function ensureDir(mod, path) { try { mod.FS.mkdir(path); @@ -114,6 +131,27 @@ for (const fixtureName of fixtureNames) { verifyExpectedOutput(fixtureName, runProgram(interp, programText), expectedEvents); } +ensureDir(interp, "/work"); +const namedParamIniPath = "/work/namedparams.ini"; +interp.FS.writeFile( + namedParamIniPath, + readFileSync(resolve(rootDir, "tests/fixtures/ini/namedparams.ini"), "utf8"), + { encoding: "utf8" }, +); +const namedParamProgramText = readFileSync( + resolve(rootDir, "tests/fixtures/gcode/namedparam_semantics.ngc"), + "utf8", +); +const namedParamExpected = readFileSync( + resolve(rootDir, "tests/fixtures/canon/namedparam_semantics.events"), + "utf8", +).trimEnd(); +verifyExpectedOutput( + "namedparam_semantics", + runProgramWithIni(interp, namedParamProgramText, namedParamIniPath), + namedParamExpected, +); + const errorFixtureNames = [ "g1_zero_feed", "arc_radius_mismatch", @@ -140,7 +178,6 @@ const fileFixtureNames = [ "oword_subroutine", ]; -ensureDir(interp, "/work"); for (const fixtureName of fileFixtureNames) { const programPath = `/work/${fixtureName}.ngc`; const programText = readFileSync( diff --git a/wasm-port/tools/build_wasm_core.sh b/wasm-port/tools/build_wasm_core.sh index 3198db0..b85ae33 100755 --- a/wasm-port/tools/build_wasm_core.sh +++ b/wasm-port/tools/build_wasm_core.sh @@ -95,5 +95,5 @@ link_wasm_module \ -s STACK_SIZE=2MB \ -s NO_EXIT_RUNTIME=1 \ -s FORCE_FILESYSTEM=1 \ - -s EXPORTED_FUNCTIONS='["_malloc","_free","_lcinterp_run_program","_lcinterp_run_file","_lcinterp_free_string"]' \ + -s EXPORTED_FUNCTIONS='["_malloc","_free","_lcinterp_run_program","_lcinterp_run_program_with_ini","_lcinterp_run_file","_lcinterp_free_string"]' \ -s EXPORTED_RUNTIME_METHODS='["FS","UTF8ToString","stringToUTF8","lengthBytesUTF8"]'