31 KiB
LinuxCNC to WASM porting steps
This file defines the incremental path for replacing the temporary smoke parser with the LinuxCNC interpreter.
Step 0: Stable simulator ABI
Status: done.
The browser calls only cnc_sim_* functions from core/include/cnc_sim_api.h. This ABI remains stable while the backend changes.
Test:
g++ -std=c++17 -I core/include core/src/cnc_sim_api.cpp core/tests/cnc_sim_api_smoke.cpp -o ./cnc_sim_api_smoke
./cnc_sim_api_smoke
Step 1: Temporary event parser
Status: in progress.
This parser only exists to test the ABI and UI before Emscripten and LinuxCNC are wired in. It is not a production feature implementation. Do not extend it with independently designed G-code behavior; when a behavior needs to change, first locate the LinuxCNC source implementation and either route to that source-backed backend or port the corresponding source logic. It currently handles:
- multiple G/M words on one line
G0,G1,G2,G3G17,G18,G19G90.1,G91.1arc IJK distance modeG20,G21,G70,G71G7,G8lathe diameter/radius mode for X-axis inputG90,G91G4 P...G38.2,G38.3,G38.4,G38.5F,S,T,M3,M4,M5,M6,M2,M30- spindle modes
G96,G97 - IJK and R arcs
- numbered and named parameter assignment/reference such as
#1 = ...,#<name> = ...,X#1, and nested expressions likeX[[#<name> + 2] * 3] - expression functions
ABS[],SQRT[],EXP[],LN[], degree-basedSIN[]/COS[]/TAN[]/ASIN[]/ACOS[], LinuxCNC-styleATAN[]/[],FIX[]/FUP[]/ROUND[], and source-linkedmod/**/logical/relational operator precedence - numeric and named O-word subprograms such as
O100 callandO<name> call - canned cycles
G73,G74,G81,G82,G83,G84,G85,G86,G87,G88,G89withG80,G98,G99,L - coordinate offset events for
G10 L2,G10 L20,G54-G59.3,G52,G92,G92.1,G92.2, andG92.3
It is not the production interpreter. Any remaining smoke-only behavior is technical debt to replace with LinuxCNC source-backed code.
Step 2: Canon event sink
Status: started.
Create a C++ file that implements the Canon functions declared by LinuxCNC src/emc/nml_intf/canon.hh.
High-priority callbacks:
INIT_CANONUSE_LENGTH_UNITSSELECT_PLANESET_FEED_RATESET_SPINDLE_SPEEDSELECT_TOOLCHANGE_TOOLSTRAIGHT_TRAVERSESTRAIGHT_FEEDARC_FEEDDWELLPROGRAM_ENDFINISH
The sink will translate these callbacks to CncSimEvent.
Current bridge files:
core/src/canon_event_sink.hcore/src/canon_event_sink.cppcore/src/linuxcnc_canon_bridge.hcore/src/linuxcnc_canon_bridge.cpp
The LinuxCNC bridge is optional and not built by default:
cmake -S core -B build/native-linuxcnc \
-DCNC_SIM_ENABLE_LINUXCNC_BRIDGE=ON \
-DCNC_SIM_LINUXCNC_ROOT=/path/to/linuxcnc
This bridge is intentionally thin. The production parser still needs the rs274ngc interpreter linked on top of it.
Bridge smoke test:
./test-linuxcnc-bridge-native.sh
Set LINUXCNC_ROOT=/path/to/linuxcnc if the LinuxCNC source tree is not next to wasm-simulator.
Step 3a: Native librs274 runner
Status: started.
Before porting rs274ngc sources to wasm, use the already-built native LinuxCNC librs274 to validate the bridge and event schema:
./test-linuxcnc-rs274-native.sh
This builds core/tools/linuxcnc_rs274_dump.cpp, links LinuxCNC librs274, and writes:
- run-local output files under a per-run temporary
build_dir/outputs/ - example files:
cnc_sim_linuxcnc_basic_motion.json,cnc_sim_linuxcnc_basic_mill.json
This is a native-only stepping stone. Once stable, the same event sink is used by the wasm build.
T... M6 now works in the native runner after initializing LinuxCNC mmap tooldata with a minimal tool table.
Step 3b: API-level native librs274 backend
Status: started.
The public cnc_sim_api defaults to the LinuxCNC RS274 backend and can still select backends through config JSON:
{"backend":"linuxcnc-rs274"}
API-level native smoke:
./test-linuxcnc-api-native.sh
Step 4a: Source compilation map
Status: started.
Before replacing librs274 with source-level compilation, keep the source manifest and syntax probe green:
./test-linuxcnc-source-syntax.sh
./test-linuxcnc-source-objects.sh
The manifest is:
linuxcnc-rs274-source-files.txtdocs/linuxcnc-rs274-source-map.md
The first compile condition discovered is that LinuxCNC user-space source probes need -DULAPI.
Step 3: Native LinuxCNC interpreter comparison
Build a native adapter that links:
src/emc/rs274ngcsrc/emc/nml_intf- the Canon event sink
Then run the same G-code corpus through both the temporary parser and LinuxCNC-backed parser. Numeric differences are expected around arc canonicalization; they must be recorded and bounded.
Step 4: Remove browser-hostile dependencies
LinuxCNC interpreter sources currently involve Python/Boost.Python remap paths. For the first WASM target:
- disable Python remap
- disable dynamic module loading
- route LinuxCNC parameter-file reads and writes through an OPFS-backed wasm
workspace, preserving
rs274ngc.varand.bakpersistence in browser runs as defined bysrc/emc/rs274ngc/interp_internal.hhand exercised byInterp::restore_parameters/Interp::save_parametersinsrc/emc/rs274ngc/rs274ngc_pre.cc - provide browser-safe tool table and INI/config loading through JSON or OPFS-backed files
Step 5: Emscripten build
Generate:
web/public/cnc_sim.jsweb/public/cnc_sim.wasm
Command:
./build-wasm.sh
Step 6: Controller dialects
Fanuc and Siemens support should remain outside the LinuxCNC core as preprocessors/adapters. They normalize controller-specific constructs into the internal event/interpreter input layer.
Functional parity matrix
This matrix tracks LinuxCNC feature coverage for the web/WASM simulator. A feature is not considered covered until it has a native regression in at least the librs274 runner and the source-link runner.
| Area | Status | Regression |
|---|---|---|
Basic modal motion G0/G1/G2/G3 |
covered, including G91 incremental linear motion, R-format arcs, G18/G19 arc plane mapping, G90.1/G91.1 IJK modes, and native/source center-format arc tolerance acceptance/rejection |
tests/gcode/linuxcnc_basic_motion.ngc, tests/gcode/basic_mill.ngc, tests/gcode/incremental_and_r_arc.ngc, tests/gcode/linuxcnc_arc_planes.ngc, tests/gcode/linuxcnc_arc_distance_modes.ngc, tests/gcode/linuxcnc_arc_center_tolerance_good_imperial.ngc, tests/gcode/linuxcnc_arc_center_tolerance_bad_metric.ngc |
| Polar coordinates and extended-plane motion restrictions | covered through LinuxCNC native/source @/^ polar parsing, G17-only polar motion validation, absolute/incremental polar endpoint mapping, G53/origin rejection, and extended-plane arc/NURBS rejection |
tests/gcode/linuxcnc_polar_coordinates.ngc, tests/gcode/linuxcnc_polar_coordinate_variants.ngc, tests/gcode/linuxcnc_polar_g18_error.ngc, tests/gcode/linuxcnc_polar_with_x_error.ngc, tests/gcode/linuxcnc_polar_with_y_error.ngc, tests/gcode/linuxcnc_polar_g92_error.ngc, tests/gcode/linuxcnc_polar_g53_error.ngc, tests/gcode/linuxcnc_polar_radius_origin_error.ngc, tests/gcode/linuxcnc_polar_incremental_radius_origin_error.ngc, tests/gcode/linuxcnc_polar_incremental_theta_origin_error.ngc, tests/gcode/linuxcnc_extended_plane_arc_error.ngc, tests/gcode/linuxcnc_g62_extended_plane_error.ngc |
| Block-level axis/motion validation | covered through LinuxCNC native/source enhance_block() checks for invalid G80 axes, missing G52/G92 or motion axes, bare axes without active motion, and modal-0 axis consumers on motion blocks |
tests/gcode/linuxcnc_g80_axis_error.ngc, tests/gcode/linuxcnc_g52_missing_axis_error.ngc, tests/gcode/linuxcnc_g92_missing_axis_error.ngc, tests/gcode/linuxcnc_motion_missing_axis_error.ngc, tests/gcode/linuxcnc_axis_without_motion_error.ngc, tests/gcode/linuxcnc_motion_with_g92_axis_error.ngc |
Predefined position moves G28/G28.1, G30/G30.1 |
covered for stored position, waypoint, selected-axis return, and all-axis return | tests/gcode/linuxcnc_predefined_positions.ngc |
Machine-coordinate move G53 |
covered for explicit/modal G0, G1, arc rejection, and incremental-mode rejection through LinuxCNC native/source backends |
tests/gcode/linuxcnc_machine_coordinates.ngc, tests/gcode/linuxcnc_g53_arc_error.ngc, tests/gcode/linuxcnc_g53_incremental_error.ngc |
Tool select/change T... M6 |
covered with minimal native tooldata, including native/source find_tool_index() rejection of missing T... and M61 Q... tools |
tests/gcode/basic_mill.ngc, tests/gcode/linuxcnc_t_missing_tool_error.ngc, tests/gcode/linuxcnc_m61_missing_tool_error.ngc |
Tool length offset G43/G43.1/G43.2/G49 |
covered with nonzero tool-table offset, dynamic replacement, additive axis offsets, G43.2 H..., clear, native/source missing-tool rejection, and native/source G43.2 H/axis validation |
tests/gcode/linuxcnc_tool_length.ngc, tests/gcode/linuxcnc_dynamic_tool_length.ngc, tests/gcode/linuxcnc_g43_missing_tool_error.ngc, tests/gcode/linuxcnc_g43_2_missing_tool_error.ngc, tests/gcode/linuxcnc_g43_2_h_axis_error.ngc, tests/gcode/linuxcnc_g43_2_missing_h_axis_error.ngc |
RTCP controls G43.4/G43.5/G49 |
covered as simulator-owned control lines | tests/gcode/linuxcnc_rtcp_controls.ngc |
Kinematics switch M428/M429/M430 |
covered as simulator-owned control lines | tests/gcode/linuxcnc_rtcp_controls.ngc |
Spindle, coolant, program stops, and current tool number M3/M4/M5, M7/M8/M9, M0/M1/M60/M30, M61 Q... |
covered through LinuxCNC native/source backends, including native/source convert_m() rejection of out-of-range M3/M4/M5 $ spindle selectors and negative M61 Q |
tests/gcode/linuxcnc_spindle_direction.ngc, tests/gcode/linuxcnc_coolant.ngc, tests/gcode/linuxcnc_program_stops.ngc, tests/gcode/linuxcnc_tool_number.ngc, tests/gcode/linuxcnc_m3_spindle_dollar_out_of_range_error.ngc, tests/gcode/linuxcnc_m4_spindle_dollar_out_of_range_error.ngc, tests/gcode/linuxcnc_m5_spindle_dollar_out_of_range_error.ngc, tests/gcode/linuxcnc_m61_negative_q_error.ngc |
Spindle speed mode G96/G97 |
covered with Canon SET_SPINDLE_MODE preserved as mode state events, including G96 D... max-RPM value and native/source check_other_codes() rejection of missing S with G96 |
tests/gcode/linuxcnc_spindle_modes.ngc, tests/gcode/linuxcnc_g96_missing_s_word_error.ngc |
Spindle orientation M19 R... P... Q... |
covered with Canon ORIENT_SPINDLE and WAIT_SPINDLE_ORIENT_COMPLETE preserved as temporary mode state events, including native/source check_other_codes() validation for P/R words and convert_m() rejection of out-of-range $ selectors and nonpositive Q waits |
tests/gcode/linuxcnc_spindle_orient.ngc, tests/gcode/linuxcnc_m19_spindle_dollar_out_of_range_error.ngc, tests/gcode/linuxcnc_m19_p_not_integer_error.ngc, tests/gcode/linuxcnc_m19_p_out_of_range_error.ngc, tests/gcode/linuxcnc_m19_r_out_of_range_error.ngc, tests/gcode/linuxcnc_m19_zero_q_error.ngc |
Spindle-synchronized feed and threading G33/G33.1/G76 |
covered through smoke, LinuxCNC native, and source-linked paths with Canon START_SPEED_FEED_SYNCH/STOP_SPEED_FEED_SYNCH preserved, rigid-tap line numbers normalized, G76 multi-pass threading smoke-covered, native/source check_other_codes() validation for required/disallowed K/F/P/I/J words, and source-linked convert_straight()/convert_threading_cycle() rejection of invalid spindle state, spindle selector, rotary-axis motion, and G76 I/J/K geometry |
tests/gcode/linuxcnc_threading_sync.ngc, tests/gcode/linuxcnc_threading_cycle.ngc, tests/gcode/linuxcnc_g33_missing_k_word_error.ngc, tests/gcode/linuxcnc_g33_f_word_error.ngc, tests/gcode/linuxcnc_g33_1_missing_k_word_error.ngc, tests/gcode/linuxcnc_g33_1_f_word_error.ngc, tests/gcode/linuxcnc_g76_missing_p_word_error.ngc, tests/gcode/linuxcnc_g76_missing_i_word_error.ngc, tests/gcode/linuxcnc_g76_missing_j_word_error.ngc, tests/gcode/linuxcnc_g76_missing_k_word_error.ngc, tests/gcode/linuxcnc_g33_stopped_spindle_error.ngc, tests/gcode/linuxcnc_g33_1_stopped_spindle_error.ngc, tests/gcode/linuxcnc_g33_spindle_dollar_out_of_range_error.ngc, tests/gcode/linuxcnc_g33_1_spindle_dollar_out_of_range_error.ngc, tests/gcode/linuxcnc_g76_spindle_dollar_out_of_range_error.ngc, tests/gcode/linuxcnc_g76_stopped_spindle_error.ngc, tests/gcode/linuxcnc_g76_rotary_axis_error.ngc, tests/gcode/linuxcnc_g76_i_zero_error.ngc, tests/gcode/linuxcnc_g76_j_zero_error.ngc, tests/gcode/linuxcnc_g76_k_less_equal_j_error.ngc, smoke API regression |
Lathe diameter/radius mode G7/G8 |
covered through LinuxCNC native/source backends for same-block X scaling, G76 I/J/K threading geometry interaction, and #<_lathe_diameter_mode>/#<_lathe_radius_mode> readonly named-parameter state |
tests/gcode/linuxcnc_lathe_diameter_mode.ngc, tests/gcode/linuxcnc_lathe_diameter_g76.ngc |
Digital/analog I/O M62-M68 |
covered with Canon digital output, analog output, and input wait callbacks preserved as temporary state events, including native/source convert_m() validation for required P/E, M66 input selection, M66 wait timeout, and analog wait restrictions |
tests/gcode/linuxcnc_io_controls.ngc, tests/gcode/linuxcnc_m62_missing_p_word_error.ngc, tests/gcode/linuxcnc_m63_missing_p_word_error.ngc, tests/gcode/linuxcnc_m64_missing_p_word_error.ngc, tests/gcode/linuxcnc_m65_missing_p_word_error.ngc, tests/gcode/linuxcnc_m66_missing_input_error.ngc, tests/gcode/linuxcnc_m66_both_inputs_error.ngc, tests/gcode/linuxcnc_m66_zero_timeout_error.ngc, tests/gcode/linuxcnc_m66_analog_wait_error.ngc, tests/gcode/linuxcnc_m67_missing_e_word_error.ngc, tests/gcode/linuxcnc_m68_missing_e_word_error.ngc |
Override controls M48-M53 |
covered with Canon feed override, spindle speed override, adaptive feed, and feed hold callbacks preserved as temporary state events | tests/gcode/linuxcnc_override_controls.ngc |
Modal state save/restore M70-M73 |
covered for main-program save/invalidate/restore plus O-word subroutine autorestore in smoke parser, with native/source regressions checking restored distance mode, units, and XY plane motion | tests/gcode/linuxcnc_modal_state.ngc, tests/gcode/linuxcnc_modal_autorestore.ngc |
| LinuxCNC read-only named parameters | common modal/unit/feed/spindle reads are covered through LinuxCNC native/source backends, with additional ccomp/spindle-mode readonly reads source-linked | tests/gcode/linuxcnc_readonly_named_parameters.ngc, tests/gcode/linuxcnc_readonly_named_parameters_extra.ngc, tests/gcode/linuxcnc_lathe_diameter_mode.ngc |
| LinuxCNC numbered parameters | native/source coverage checks readonly numbered-parameter rejection plus probe, tool, G28/G30, G52/G92, G5X/G59.3, debug/M66 result, tool-offset, and current-position numbered parameters from LinuxCNC source state | tests/gcode/linuxcnc_numbered_parameters.ngc, tests/gcode/linuxcnc_rotary_probe_numbered_parameters.ngc, tests/gcode/linuxcnc_multi_rotary_probe_numbered_parameters.ngc, tests/gcode/linuxcnc_tool_info_zero_parameter.ngc, tests/gcode/linuxcnc_spindle_tool_info_parameter.ngc, tests/gcode/linuxcnc_readonly_numbered_parameter_assign_error.ngc, tests/gcode/linuxcnc_g28_g30_numbered_parameters.ngc, tests/gcode/linuxcnc_rotary_g28_g30_numbered_parameters.ngc, tests/gcode/linuxcnc_g92_numbered_parameters.ngc, tests/gcode/linuxcnc_rotary_g92_numbered_parameters.ngc, tests/gcode/linuxcnc_g52_g92_numbered_interaction.ngc, tests/gcode/linuxcnc_g5x_numbered_parameters.ngc, tests/gcode/linuxcnc_g59_3_numbered_parameters.ngc, tests/gcode/linuxcnc_g59_3_rotary_numbered_parameters.ngc, tests/gcode/linuxcnc_g5x_rotary_numbered_parameters.ngc, tests/gcode/linuxcnc_g54_rotary_numbered_parameters.ngc, tests/gcode/linuxcnc_debug_level_parameter.ngc, tests/gcode/linuxcnc_m66_result_parameter.ngc, tests/gcode/linuxcnc_tool_offset_numbered_parameters.ngc, tests/gcode/linuxcnc_rotary_tool_offset_numbered_parameters.ngc, tests/gcode/linuxcnc_current_position_numbered_parameters.ngc |
Feed and motion control modes G93/G94/G95, G61/G61.1/G64 |
covered through LinuxCNC native/source backends | tests/gcode/linuxcnc_feed_modes.ngc, tests/gcode/linuxcnc_motion_modes.ngc |
Canned cycle G73-G89/G80 |
covered for drilling expand-to-canon path, G18/G19 plane-specific depth-axis mapping for representative drilling/boring cycles, and native/source LinuxCNC interp_cycles.cc validation of repeat counts, required R/depth words, invalid rotary axes, Q/P words, and spindle state |
tests/gcode/linuxcnc_canned_cycle.ngc, tests/gcode/linuxcnc_canned_cycles_extended.ngc, tests/gcode/linuxcnc_canned_cycle_planes.ngc, tests/gcode/linuxcnc_canned_cycle_l0_error.ngc, tests/gcode/linuxcnc_canned_cycle_missing_r_error.ngc, tests/gcode/linuxcnc_canned_cycle_missing_z_error.ngc, tests/gcode/linuxcnc_canned_cycle_g18_missing_y_error.ngc, tests/gcode/linuxcnc_canned_cycle_g19_missing_x_error.ngc, tests/gcode/linuxcnc_canned_cycle_r_less_z_error.ngc, tests/gcode/linuxcnc_canned_cycle_g18_r_less_y_error.ngc, tests/gcode/linuxcnc_canned_cycle_g19_r_less_x_error.ngc, tests/gcode/linuxcnc_canned_cycle_u_in_xy_error.ngc, tests/gcode/linuxcnc_canned_cycle_a_error.ngc, tests/gcode/linuxcnc_canned_cycle_b_error.ngc, tests/gcode/linuxcnc_canned_cycle_c_error.ngc, tests/gcode/linuxcnc_canned_cycle_g73_missing_q_error.ngc, tests/gcode/linuxcnc_canned_cycle_g83_missing_q_error.ngc, tests/gcode/linuxcnc_canned_cycle_g73_q0_error.ngc, tests/gcode/linuxcnc_canned_cycle_g83_q0_error.ngc, tests/gcode/linuxcnc_canned_cycle_g82_missing_p_error.ngc, tests/gcode/linuxcnc_canned_cycle_g86_missing_p_error.ngc, tests/gcode/linuxcnc_canned_cycle_g88_missing_p_error.ngc, tests/gcode/linuxcnc_canned_cycle_g89_missing_p_error.ngc, tests/gcode/linuxcnc_canned_cycle_g74_clockwise_error.ngc, tests/gcode/linuxcnc_canned_cycle_g84_counterclockwise_error.ngc, tests/gcode/linuxcnc_canned_cycle_g74_stopped_spindle_error.ngc, tests/gcode/linuxcnc_canned_cycle_g84_stopped_spindle_error.ngc, tests/gcode/linuxcnc_canned_cycle_g86_stopped_spindle_error.ngc, tests/gcode/linuxcnc_canned_cycle_g88_stopped_spindle_error.ngc, tests/gcode/linuxcnc_canned_cycle_g87_stopped_spindle_error.ngc, tests/gcode/linuxcnc_canned_cycle_g87_missing_k_error.ngc, tests/gcode/linuxcnc_canned_cycle_g87_missing_i_error.ngc, tests/gcode/linuxcnc_canned_cycle_g87_missing_j_error.ngc |
Coordinate offset Canon events G10 L2, G10 L20, G10 P0 active-system targeting, G54-G59.3 selection, G52, G92/G92.1/G92.2/G92.3 |
covered through LinuxCNC native/source backends, including all nine G5X indices | tests/gcode/linuxcnc_coordinate_offsets.ngc, tests/gcode/linuxcnc_coordinate_l20.ngc, tests/gcode/linuxcnc_coordinate_p0.ngc, tests/gcode/linuxcnc_coordinate_select_all.ngc, tests/gcode/linuxcnc_g92_restore.ngc, tests/gcode/linuxcnc_g52_offset.ngc |
| Cutter compensation | covered for tool-table G41/G42 D... and explicit-radius G41.1/G42.1/G40 through LinuxCNC native/source backends |
tests/gcode/linuxcnc_cutter_comp.ngc |
Probe moves G38.2/G38.3/G38.4/G38.5 |
covered as distinct probe events with LinuxCNC probe_type preserved through smoke, native, and source-linked paths |
tests/gcode/linuxcnc_probe_no_error.ngc |
| O-word and Fanuc subroutines, calls, and control flow | covered for numeric and named O... sub/call/return/endsub, Fanuc-style M98 P... L.../M99, plus if/elseif/else, while, repeat, do/while, break, and continue through LinuxCNC file mode; native/source read errors cover malformed O-word commands, missing control-expression brackets, too many or empty call parameters, Fanuc-style M98 missing P, and midline/comment-prefixed M98 falling through to normal M-code handling; native/source execution errors cover duplicate/undefined/unmatched labels, out-of-context return/endsub, wrong subroutine close style, too many nested call levels, lowercase numeric labels, O-word state parameters, EXISTS[] word-value checks, and M98/O-word local-parameter style differences; smoke parser also covers named O<name> sub/call/return/endsub and loop-control forms |
tests/gcode/smoke_oword_subprogram.ngc, tests/gcode/linuxcnc_named_oword_subprogram.ngc, tests/gcode/smoke_subprogram_m98.ngc, tests/gcode/linuxcnc_oword_control_flow.ngc, tests/gcode/linuxcnc_value_returned.ngc, tests/gcode/linuxcnc_call_level.ngc, tests/gcode/linuxcnc_exists_word_value.ngc, tests/gcode/linuxcnc_lowercase_numeric_oword.ngc, tests/gcode/linuxcnc_m98_mixed_styles_variables.ngc, tests/gcode/linuxcnc_oword_unknown_command_error.ngc, tests/gcode/linuxcnc_oword_unexpected_trailing_item_error.ngc, tests/gcode/linuxcnc_oword_if_missing_bracket_error.ngc, tests/gcode/linuxcnc_oword_elseif_missing_bracket_error.ngc, tests/gcode/linuxcnc_oword_while_missing_bracket_error.ngc, tests/gcode/linuxcnc_oword_repeat_missing_bracket_error.ngc, tests/gcode/linuxcnc_oword_too_many_call_parameters_error.ngc, tests/gcode/linuxcnc_oword_empty_call_parameter_error.ngc, tests/gcode/linuxcnc_oword_too_many_call_levels_error.ngc, tests/gcode/linuxcnc_oword_endsub_without_sub_error.ngc, tests/gcode/linuxcnc_oword_return_without_sub_error.ngc, tests/gcode/linuxcnc_oword_duplicate_if_label_error.ngc, tests/gcode/linuxcnc_oword_elseif_undefined_label_error.ngc, tests/gcode/linuxcnc_oword_else_undefined_label_error.ngc, tests/gcode/linuxcnc_oword_endif_undefined_label_error.ngc, tests/gcode/linuxcnc_oword_break_undefined_label_error.ngc, tests/gcode/linuxcnc_oword_continue_undefined_label_error.ngc, tests/gcode/linuxcnc_oword_endwhile_undefined_label_error.ngc, tests/gcode/linuxcnc_oword_elseif_no_matching_if_error.ngc, tests/gcode/linuxcnc_oword_break_no_matching_loop_error.ngc, tests/gcode/linuxcnc_oword_continue_no_matching_loop_error.ngc, tests/gcode/linuxcnc_oword_endrepeat_no_matching_repeat_error.ngc, tests/gcode/linuxcnc_oword_endif_no_matching_if_error.ngc, tests/gcode/linuxcnc_oword_endwhile_no_matching_while_error.ngc, tests/gcode/linuxcnc_oword_fanuc_requires_m99_error.ngc, tests/gcode/linuxcnc_oword_sub_requires_endsub_error.ngc, tests/gcode/linuxcnc_m98_missing_p_word_error.ngc, tests/gcode/linuxcnc_midline_m98_error.ngc, tests/gcode/linuxcnc_comment_prefixed_m98_error.ngc |
| Parameter expressions and operators | covered for parameter references, native/source bracketed word-value whitespace, mod, **, logical, and relational operator precedence, plus LinuxCNC parameter-setting syntax, parameter index validation, named-parameter termination, real-number parsing, divide-by-zero, negative sqrt/power, infinity rejection, malformed and bare ATAN[]/[], unary operation syntax including bare unary items, read_operation_unary() unknown-word branches, read_operation() binary-operation prefix, unknown operation, and unclosed-expression error paths from interp_read.cc/interp_execute.cc |
tests/gcode/linuxcnc_parameter_expression_assignment.ngc, tests/gcode/linuxcnc_word_bracket_whitespace.ngc, tests/gcode/linuxcnc_parameter_missing_equal_error.ngc, tests/gcode/linuxcnc_midline_parameter_missing_equal_error.ngc, tests/gcode/linuxcnc_parameter_missing_value_error.ngc, tests/gcode/linuxcnc_parameter_number_out_of_range_error.ngc, tests/gcode/linuxcnc_parameter_reference_out_of_range_error.ngc, tests/gcode/linuxcnc_non_integer_parameter_index_error.ngc, tests/gcode/linuxcnc_named_parameter_not_terminated_error.ngc, tests/gcode/linuxcnc_no_real_value_error.ngc, tests/gcode/linuxcnc_bad_number_format_error.ngc, tests/gcode/linuxcnc_expression_operators.ngc, tests/gcode/linuxcnc_negative_sqrt_error.ngc, tests/gcode/linuxcnc_divide_by_zero_error.ngc, tests/gcode/linuxcnc_negative_power_error.ngc, tests/gcode/linuxcnc_infinite_expression_error.ngc, tests/gcode/linuxcnc_atan_missing_slash_error.ngc, tests/gcode/linuxcnc_atan_missing_bracket_error.ngc, tests/gcode/linuxcnc_top_level_bare_atan_error.ngc, tests/gcode/linuxcnc_midline_bare_atan_error.ngc, tests/gcode/linuxcnc_unary_missing_bracket_error.ngc, tests/gcode/linuxcnc_unary_unknown_word_error.ngc, tests/gcode/linuxcnc_unary_unknown_c_word_error.ngc, tests/gcode/linuxcnc_unary_unknown_e_word_error.ngc, tests/gcode/linuxcnc_unary_unknown_f_word_error.ngc, tests/gcode/linuxcnc_unary_unknown_l_word_error.ngc, tests/gcode/linuxcnc_unary_unknown_r_word_error.ngc, tests/gcode/linuxcnc_unary_unknown_s_word_error.ngc, tests/gcode/linuxcnc_unary_unknown_t_word_error.ngc, tests/gcode/linuxcnc_unary_unknown_default_word_error.ngc, tests/gcode/linuxcnc_top_level_bare_unary_error.ngc, tests/gcode/linuxcnc_midline_bare_unary_error.ngc, tests/gcode/linuxcnc_binary_unknown_a_operation_error.ngc, tests/gcode/linuxcnc_binary_unknown_e_operation_error.ngc, tests/gcode/linuxcnc_binary_unknown_g_operation_error.ngc, tests/gcode/linuxcnc_binary_unknown_l_operation_error.ngc, tests/gcode/linuxcnc_binary_unknown_m_operation_error.ngc, tests/gcode/linuxcnc_binary_unknown_n_operation_error.ngc, tests/gcode/linuxcnc_binary_unknown_o_operation_error.ngc, tests/gcode/linuxcnc_binary_unknown_x_operation_error.ngc, tests/gcode/linuxcnc_binary_unknown_operation_error.ngc, tests/gcode/linuxcnc_unclosed_expression_error.ngc |
| Word reader validation | LinuxCNC native/source reader errors covered for negative F/G/H/L/M/S/T values and repeated A/B/C/D/E/F/H/I/J/K/L/P/Q/R/S/T/U/V/W/X/Y/Z words from interp_read.cc |
tests/gcode/linuxcnc_negative_f_word_error.ngc, tests/gcode/linuxcnc_negative_g_code_error.ngc, tests/gcode/linuxcnc_negative_h_word_error.ngc, tests/gcode/linuxcnc_negative_l_word_error.ngc, tests/gcode/linuxcnc_negative_m_code_error.ngc, tests/gcode/linuxcnc_negative_s_word_error.ngc, tests/gcode/linuxcnc_negative_t_word_error.ngc, tests/gcode/linuxcnc_multiple_a_words_error.ngc, tests/gcode/linuxcnc_multiple_b_words_error.ngc, tests/gcode/linuxcnc_multiple_c_words_error.ngc, tests/gcode/linuxcnc_multiple_d_words_error.ngc, tests/gcode/linuxcnc_multiple_e_words_error.ngc, tests/gcode/linuxcnc_multiple_f_words_error.ngc, tests/gcode/linuxcnc_multiple_h_words_error.ngc, tests/gcode/linuxcnc_multiple_i_words_error.ngc, tests/gcode/linuxcnc_multiple_j_words_error.ngc, tests/gcode/linuxcnc_multiple_k_words_error.ngc, tests/gcode/linuxcnc_multiple_l_words_error.ngc, tests/gcode/linuxcnc_multiple_p_words_error.ngc, tests/gcode/linuxcnc_multiple_q_words_error.ngc, tests/gcode/linuxcnc_multiple_r_words_error.ngc, tests/gcode/linuxcnc_multiple_s_words_error.ngc, tests/gcode/linuxcnc_multiple_t_words_error.ngc, tests/gcode/linuxcnc_multiple_u_words_error.ngc, tests/gcode/linuxcnc_multiple_v_words_error.ngc, tests/gcode/linuxcnc_multiple_w_words_error.ngc, tests/gcode/linuxcnc_multiple_x_words_error.ngc, tests/gcode/linuxcnc_multiple_y_words_error.ngc, tests/gcode/linuxcnc_multiple_z_words_error.ngc |
| G/M reader validation | LinuxCNC native/source read_g()/read_m() errors covered for range checks, unknown code tables, and same-modal-group conflicts from interp_read.cc and interp_array.cc |
tests/gcode/linuxcnc_g_code_out_of_range_error.ngc, tests/gcode/linuxcnc_unknown_g_code_error.ngc, tests/gcode/linuxcnc_two_g_codes_same_modal_group_error.ngc, tests/gcode/linuxcnc_m_code_greater_199_error.ngc, tests/gcode/linuxcnc_unknown_m_code_error.ngc, tests/gcode/linuxcnc_two_m_codes_same_modal_group_error.ngc |
| Block/item reader validation | LinuxCNC native/source errors covered for repeated $, block-delete execution skipping, unused D/$/E/H/I/J/K/L/P/Q/R words, bad item-start characters, middle-of-line or comment-prefixed N words, comment-prefixed or midline O words, top-level or midline bracket items, naked top-level numbers, non-leading ATAN argument slashes, malformed leading N numbers, EOF/program-end file checks, overlong file lines, and too many M-codes from interp_read.cc, interp_array.cc, and interp_check.cc |
tests/gcode/linuxcnc_block_delete.ngc, tests/gcode/linuxcnc_multiple_spindle_choice_words_error.ngc, tests/gcode/linuxcnc_d_word_no_use_error.ngc, tests/gcode/linuxcnc_spindle_dollar_no_use_error.ngc, tests/gcode/linuxcnc_e_word_no_use_error.ngc, tests/gcode/linuxcnc_h_word_no_use_error.ngc, tests/gcode/linuxcnc_i_word_no_use_error.ngc, tests/gcode/linuxcnc_j_word_no_use_error.ngc, tests/gcode/linuxcnc_k_word_no_use_error.ngc, tests/gcode/linuxcnc_l_word_no_use_error.ngc, tests/gcode/linuxcnc_p_word_no_use_error.ngc, tests/gcode/linuxcnc_q_word_no_use_error.ngc, tests/gcode/linuxcnc_r_word_no_use_error.ngc, tests/gcode/linuxcnc_bad_character_bang_error.ngc, tests/gcode/linuxcnc_bad_character_middle_n_word_error.ngc, tests/gcode/linuxcnc_comment_prefixed_n_word_error.ngc, tests/gcode/linuxcnc_comment_prefixed_spaced_n_word_error.ngc, tests/gcode/linuxcnc_comment_prefixed_oword_error.ngc, tests/gcode/linuxcnc_midline_numeric_oword_error.ngc, tests/gcode/linuxcnc_midline_named_oword_error.ngc, tests/gcode/linuxcnc_bad_character_top_left_bracket_error.ngc, tests/gcode/linuxcnc_bad_character_top_right_bracket_error.ngc, tests/gcode/linuxcnc_bad_character_midline_left_bracket_error.ngc, tests/gcode/linuxcnc_bad_character_midline_right_bracket_error.ngc, tests/gcode/linuxcnc_bad_character_top_number_error.ngc, tests/gcode/linuxcnc_top_level_bare_atan_error.ngc, tests/gcode/linuxcnc_midline_bare_atan_error.ngc, tests/gcode/linuxcnc_bad_n_number_format_error.ngc, tests/gcode/linuxcnc_file_ended_no_program_end_error.ngc, tests/gcode/linuxcnc_file_ended_no_percent_error.ngc, generated linuxcnc_command_too_long_error.ngc, tests/gcode/linuxcnc_too_many_m_codes_error.ngc |
Broader canned cycles G73, G74, G82-G89 |
partially covered: G73, G74, G82, G83, G84, G85, G86, G87, G88, G89; smoke parser maps supported cycles across G17/G18/G19, including LinuxCNC's special non-XY G74/G84 tapping argument order and G87 plane-specific I/J/K mapping; native/source regressions now check non-XY G74/G84/G86/G87/G88 sequences |
tests/gcode/linuxcnc_canned_cycles_extended.ngc, tests/gcode/linuxcnc_canned_cycle_planes.ngc, smoke API regression |
| Full source-level wasm build | covered for the current wasm-safe RS274 source set, with remaining work focused on broadening browser-hostile dependency replacement and feature coverage | ./build-wasm.sh, test-linuxcnc-wasm-runtime-link.sh, test-web-wasm-node-smoke.sh, test-web-wasm-browser-smoke.sh |