diff --git a/wasm-port/docs/porting-steps-standalone.md b/wasm-port/docs/porting-steps-standalone.md index 033f945..eff1b42 100644 --- a/wasm-port/docs/porting-steps-standalone.md +++ b/wasm-port/docs/porting-steps-standalone.md @@ -351,6 +351,9 @@ Current verified progress: `STRAIGHT_TRAVERSE` canonical event for `G0 X1.0 Y2.0`, plus `SET_FEED_RATE` and `STRAIGHT_FEED` canonical events for `G1 X3.0 Y4.0 F120.0`. +- The same validation is now fixture-driven through + `tests/fixtures/gcode/minimal_linear.ngc` and + `tests/fixtures/canon/minimal_linear.events`. - This proves the current extracted interpreter slice can parse and execute a simple traverse and feed move through a standalone canonical event sink. @@ -651,7 +654,7 @@ Keep these documents under `wasm-port/docs/`: Continue expanding the standalone interpreter core from the verified minimal traverse path: -1. introduce a fixture-driven G-code validation script under `tests/fixtures/`, +1. add another fixture for incremental mode and modal carry-forward, 2. replace the temporary minimal `convert_g()` implementation with thin wrappers around more vendored interpreter conversion code, 3. keep all source changes inside `wasm-port/` and leave `../linuxcnc/` diff --git a/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_harness.cpp b/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_harness.cpp index 57f9e54..91aed3a 100644 --- a/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_harness.cpp +++ b/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_interp_minimal_harness.cpp @@ -3,14 +3,17 @@ #undef private #include +#include #include +#include +#include #include "canon_event_sink.hh" -int main() +namespace { + +void initialize_minimal_interp(Interp &interp) { - Interp interp; - standalone::reset_canon_events(); interp._setup.length_units = CANON_UNITS_MM; interp._setup.distance_mode = DISTANCE_MODE::ABSOLUTE; interp._setup.ijk_distance_mode = DISTANCE_MODE::ABSOLUTE; @@ -21,17 +24,63 @@ int main() interp._setup.sequence_number = 0; interp._setup.parameter_occurrence = 0; std::memcpy(interp._readers, Interp::default_readers, sizeof(Interp::default_readers)); +} - char line[] = "G0 X1.0 Y2.0 (Comment)\n"; +std::vector load_program(int argc, char **argv) +{ + if (argc <= 1) { + return { + "G0 X1.0 Y2.0 (Comment)\n", + "G1 X3.0 Y4.0 F120.0\n", + }; + } + + std::ifstream input(argv[1]); + if (!input) { + std::cerr << "failed to open fixture: " << argv[1] << "\n"; + std::exit(2); + } + + std::vector lines; + std::string line; + while (std::getline(input, line)) { + if (!line.empty()) { + lines.push_back(line + "\n"); + } + } + return lines; +} + +} // namespace + +int main(int argc, char **argv) +{ + Interp interp; + standalone::reset_canon_events(); + initialize_minimal_interp(interp); + + const std::vector program = load_program(argc, argv); + if (program.empty()) { + std::cerr << "empty fixture\n"; + return 2; + } + + char line[LINELEN] = {0}; + std::strncpy(line, program.front().c_str(), sizeof(line) - 1); char raw_line[LINELEN] = {0}; char cooked_line[LINELEN] = {0}; int length = -1; const int read_text_rc = interp.read_text(line, nullptr, raw_line, cooked_line, &length); const int downcase_rc = interp.close_and_downcase(line); - const int read_rc = interp.read("G0 X1.0 Y2.0 (Comment)\n"); - const int execute_rc = interp.execute("G0 X1.0 Y2.0 (Comment)\n"); - const int execute_feed_rc = interp.execute("G1 X3.0 Y4.0 F120.0\n"); + const int read_rc = interp.read(program.front().c_str()); + + initialize_minimal_interp(interp); + for (std::size_t idx = 0; idx < program.size(); ++idx) { + interp._setup.sequence_number = static_cast(idx + 1); + const int execute_rc = interp.execute(program[idx].c_str()); + std::cout << "execute_line_" << (idx + 1) << "=" << execute_rc << "\n"; + } block block{}; const int init_block_rc = interp.init_block(&block); @@ -45,8 +94,6 @@ int main() std::cout << "cooked_line=" << cooked_line << "\n"; std::cout << "line_length=" << length << "\n"; std::cout << "read=" << read_rc << "\n"; - std::cout << "execute=" << execute_rc << "\n"; - std::cout << "execute_feed=" << execute_feed_rc << "\n"; std::cout << "setup.linetext=" << interp._setup.linetext << "\n"; std::cout << "setup.blocktext=" << interp._setup.blocktext << "\n"; std::cout << "setup.line_length=" << interp._setup.line_length << "\n"; diff --git a/wasm-port/tests/fixtures/canon/minimal_linear.events b/wasm-port/tests/fixtures/canon/minimal_linear.events new file mode 100644 index 0000000..ed3ec63 --- /dev/null +++ b/wasm-port/tests/fixtures/canon/minimal_linear.events @@ -0,0 +1,4 @@ +canon_event=COMMENT: Comment +canon_event=STRAIGHT_TRAVERSE line=1 x=1 y=2 z=0 a=0 b=0 c=0 u=0 v=0 w=0 +canon_event=SET_FEED_RATE rate=120 +canon_event=STRAIGHT_FEED line=2 x=3 y=4 z=0 a=0 b=0 c=0 u=0 v=0 w=0 diff --git a/wasm-port/tests/fixtures/gcode/minimal_linear.ngc b/wasm-port/tests/fixtures/gcode/minimal_linear.ngc new file mode 100644 index 0000000..8a1d627 --- /dev/null +++ b/wasm-port/tests/fixtures/gcode/minimal_linear.ngc @@ -0,0 +1,2 @@ +G0 X1.0 Y2.0 (Comment) +G1 X3.0 Y4.0 F120.0 diff --git a/wasm-port/tests/native/verify_native_probes.sh b/wasm-port/tests/native/verify_native_probes.sh index c37176f..248147f 100755 --- a/wasm-port/tests/native/verify_native_probes.sh +++ b/wasm-port/tests/native/verify_native_probes.sh @@ -3,6 +3,7 @@ set -euo pipefail ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)" BUILD_DIR="$ROOT_DIR/build/native" +EXPECTED_EVENTS="$ROOT_DIR/tests/fixtures/canon/minimal_linear.events" "$ROOT_DIR/tools/build_native_probes.sh" @@ -35,11 +36,13 @@ check_exitcode linuxcnc_rs274_compile_probe RUN_STDOUT="$BUILD_DIR/linuxcnc_interp_minimal_harness.run.stdout.log" grep -Fq "read=0" "$RUN_STDOUT" -grep -Fq "execute=0" "$RUN_STDOUT" -grep -Fq "execute_feed=0" "$RUN_STDOUT" +grep -Fq "execute_line_1=0" "$RUN_STDOUT" +grep -Fq "execute_line_2=0" "$RUN_STDOUT" grep -Fq "parse_line=0" "$RUN_STDOUT" -grep -Fq "canon_event=STRAIGHT_TRAVERSE line=0 x=1 y=2 z=0" "$RUN_STDOUT" -grep -Fq "canon_event=SET_FEED_RATE rate=120" "$RUN_STDOUT" -grep -Fq "canon_event=STRAIGHT_FEED line=0 x=3 y=4 z=0" "$RUN_STDOUT" + +while IFS= read -r expected_event; do + [[ -z "$expected_event" ]] && continue + grep -Fq "$expected_event" "$RUN_STDOUT" +done < "$EXPECTED_EVENTS" echo "native probe validation complete" diff --git a/wasm-port/tools/build_native_probes.sh b/wasm-port/tools/build_native_probes.sh index 68e54a2..4916915 100755 --- a/wasm-port/tools/build_native_probes.sh +++ b/wasm-port/tools/build_native_probes.sh @@ -7,6 +7,7 @@ BUILD_DIR="$ROOT_DIR/build/native" WRAP_DIR="$ROOT_DIR/runtime/core/linuxcnc_wrap" SHIM_DIR="$ROOT_DIR/runtime/core/shims" INCLUDE_DIR="$ROOT_DIR/runtime/core/include" +MINIMAL_GCODE_FIXTURE="$ROOT_DIR/tests/fixtures/gcode/minimal_linear.ngc" mkdir -p "$BUILD_DIR" @@ -130,7 +131,7 @@ echo "$INTERP_MIN_RC" > "$BUILD_DIR/linuxcnc_interp_minimal_harness.exitcode" if [[ "$INTERP_MIN_RC" -eq 0 ]]; then set +e - "$BUILD_DIR/linuxcnc_interp_minimal_harness" \ + "$BUILD_DIR/linuxcnc_interp_minimal_harness" "$MINIMAL_GCODE_FIXTURE" \ >"$BUILD_DIR/linuxcnc_interp_minimal_harness.run.stdout.log" \ 2>"$BUILD_DIR/linuxcnc_interp_minimal_harness.run.stderr.log" INTERP_MIN_RUN_RC=$?