nc-gcode-interpreter 0.1.4__tar.gz → 0.1.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/Cargo.lock +1 -1
  2. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/Cargo.toml +1 -1
  3. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/PKG-INFO +2 -2
  4. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/README.md +1 -1
  5. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/ggroups/generate_pest.py +13 -1
  6. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/ggroups/ggroups.pest +4 -1
  7. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/pyproject.toml +1 -1
  8. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/src/grammar.pest +6 -64
  9. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/src/interpret_rules.rs +21 -12
  10. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/src/interpreter.rs +39 -54
  11. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/src/lib.rs +10 -4
  12. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/src/main.rs +10 -6
  13. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/src/state.rs +3 -3
  14. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/src/types.rs +1 -3
  15. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/.github/workflows/build-and-release.yml +0 -0
  16. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/.gitignore +0 -0
  17. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/CONTRIBUTING.md +0 -0
  18. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/Development.md +0 -0
  19. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/Example.MPF +0 -0
  20. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/LICENSE +0 -0
  21. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/TODO.md +0 -0
  22. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/examples/arrays.csv +0 -0
  23. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/examples/arrays.mpf +0 -0
  24. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/examples/basic_math.csv +0 -0
  25. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/examples/basic_math.mpf +0 -0
  26. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/examples/custom_vars.csv +0 -0
  27. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/examples/custom_vars.mpf +0 -0
  28. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/examples/defaults.csv +0 -0
  29. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/examples/defaults.mpf +0 -0
  30. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/examples/for_loop.csv +0 -0
  31. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/examples/for_loop.mpf +0 -0
  32. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/examples/if_statement.csv +0 -0
  33. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/examples/if_statement.mpf +0 -0
  34. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/examples/increment.csv +0 -0
  35. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/examples/increment.mpf +0 -0
  36. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/examples/loop.csv +0 -0
  37. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/examples/loop.mpf +0 -0
  38. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/examples/multiple_m_codes.csv +0 -0
  39. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/examples/multiple_m_codes.mpf +0 -0
  40. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/examples/simple.csv +0 -0
  41. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/examples/simple.mpf +0 -0
  42. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/examples/trans.csv +0 -0
  43. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/examples/trans.mpf +0 -0
  44. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/examples/variables.csv +0 -0
  45. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/examples/variables.mpf +0 -0
  46. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/ggroups/generate_modal_ggroups.py +0 -0
  47. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/ggroups/ggroups.json +0 -0
  48. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/ggroups/modal_groups.rs +0 -0
  49. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/python/example/minimal.py +0 -0
  50. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/python/nc_gcode_interpreter/__init__.py +0 -0
  51. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/python/tests/test_expected_output.py +0 -0
  52. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/rustfmt.toml +0 -0
  53. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/src/errors.rs +0 -0
  54. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/src/modal_groups.rs +0 -0
  55. {nc_gcode_interpreter-0.1.4 → nc_gcode_interpreter-0.1.5}/uv.lock +0 -0
@@ -724,7 +724,7 @@ dependencies = [
724
724
 
725
725
  [[package]]
726
726
  name = "nc-gcode-interpreter"
727
- version = "0.1.4"
727
+ version = "0.1.5"
728
728
  dependencies = [
729
729
  "clap",
730
730
  "csv",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "nc-gcode-interpreter"
3
- version = "0.1.4"
3
+ version = "0.1.5"
4
4
  edition = "2021"
5
5
 
6
6
  [lib]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: nc-gcode-interpreter
3
- Version: 0.1.4
3
+ Version: 0.1.5
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: 3.12
@@ -84,7 +84,7 @@ Options:
84
84
  -a, --axes <AXIS> Override default axis identifiers (comma-separated, e.g., "X,Y,Z")
85
85
  -e, --extra-axes <EXTRA_AXIS> Add extra axis identifiers (comma-separated, e.g., "RA1,RA2")
86
86
  -i, --initial_state <INITIAL_STATE> Optional initial_state file to initialize state
87
- -l, --iteration_limit <LIMIT> Maximum number of iterations for loops [default: 10000]
87
+ -l, --iteration_limit <LIMIT> Maximum number of iterations for loops [default: 10000]
88
88
  -f, --disable-forward-fill Disable forward-filling of null values in axes columns
89
89
  -h, --help Print help
90
90
  -V, --version Print version
@@ -64,7 +64,7 @@ Options:
64
64
  -a, --axes <AXIS> Override default axis identifiers (comma-separated, e.g., "X,Y,Z")
65
65
  -e, --extra-axes <EXTRA_AXIS> Add extra axis identifiers (comma-separated, e.g., "RA1,RA2")
66
66
  -i, --initial_state <INITIAL_STATE> Optional initial_state file to initialize state
67
- -l, --iteration_limit <LIMIT> Maximum number of iterations for loops [default: 10000]
67
+ -l, --iteration_limit <LIMIT> Maximum number of iterations for loops [default: 10000]
68
68
  -f, --disable-forward-fill Disable forward-filling of null values in axes columns
69
69
  -h, --help Print help
70
70
  -V, --version Print version
@@ -18,6 +18,10 @@ def create_pest_grammar(g_groups):
18
18
  grammar_parts.append(
19
19
  "// Due to the way pest works, the sorting of the literals is important."
20
20
  )
21
+ all_words = [
22
+ f'^"{entry["id"]}"' for group in g_groups for entry in group["entries"]
23
+ ]
24
+
21
25
  ggroup_names = []
22
26
  for group in g_groups:
23
27
  group_rules = []
@@ -28,7 +32,15 @@ def create_pest_grammar(g_groups):
28
32
  grammar_parts.append(
29
33
  f"{ggroup_name} = @{{({' | '.join(reversed(sorted(group_rules)))}) ~ !(ASCII_ALPHANUMERIC) }}"
30
34
  )
31
- grammar_parts.append(f"g_command = {{{' | '.join(ggroup_names)}}}")
35
+
36
+ grammar_parts.append(
37
+ f"\ngcommand_list = @{{({' | '.join(reversed(sorted(all_words)))}) ~ !(ASCII_ALPHANUMERIC) }}"
38
+ )
39
+
40
+ grammar_parts.append('g_command_numbered = { &("G" ~ ASCII_DIGIT+) ~ g_command }')
41
+ grammar_parts.append(
42
+ f"g_command = {{ &gcommand_list ~ ({' | '.join(ggroup_names)})}}"
43
+ )
32
44
  return "\n".join(grammar_parts)
33
45
 
34
46
 
@@ -60,4 +60,7 @@ gg59_area_limit = @{(^"WALCS9" | ^"WALCS8" | ^"WALCS7" | ^"WALCS6" | ^"WALCS5" |
60
60
  gg61_tool_orient_smooth = @{(^"ORISON" | ^"ORISOF") ~ !(ASCII_ALPHANUMERIC) }
61
61
  gg62_repos_non_modal = @{(^"RMNBL" | ^"RMIBL" | ^"RMEBL" | ^"RMBBL") ~ !(ASCII_ALPHANUMERIC) }
62
62
  gg64_grinding_frames = @{(^"GFRAME[9]" | ^"GFRAME[99]" | ^"GFRAME[98]" | ^"GFRAME[97]" | ^"GFRAME[96]" | ^"GFRAME[95]" | ^"GFRAME[94]" | ^"GFRAME[93]" | ^"GFRAME[92]" | ^"GFRAME[91]" | ^"GFRAME[90]" | ^"GFRAME[8]" | ^"GFRAME[89]" | ^"GFRAME[88]" | ^"GFRAME[87]" | ^"GFRAME[86]" | ^"GFRAME[85]" | ^"GFRAME[84]" | ^"GFRAME[83]" | ^"GFRAME[82]" | ^"GFRAME[81]" | ^"GFRAME[80]" | ^"GFRAME[7]" | ^"GFRAME[79]" | ^"GFRAME[78]" | ^"GFRAME[77]" | ^"GFRAME[76]" | ^"GFRAME[75]" | ^"GFRAME[74]" | ^"GFRAME[73]" | ^"GFRAME[72]" | ^"GFRAME[71]" | ^"GFRAME[70]" | ^"GFRAME[6]" | ^"GFRAME[69]" | ^"GFRAME[68]" | ^"GFRAME[67]" | ^"GFRAME[66]" | ^"GFRAME[65]" | ^"GFRAME[64]" | ^"GFRAME[63]" | ^"GFRAME[62]" | ^"GFRAME[61]" | ^"GFRAME[60]" | ^"GFRAME[5]" | ^"GFRAME[59]" | ^"GFRAME[58]" | ^"GFRAME[57]" | ^"GFRAME[56]" | ^"GFRAME[55]" | ^"GFRAME[54]" | ^"GFRAME[53]" | ^"GFRAME[52]" | ^"GFRAME[51]" | ^"GFRAME[50]" | ^"GFRAME[4]" | ^"GFRAME[49]" | ^"GFRAME[48]" | ^"GFRAME[47]" | ^"GFRAME[46]" | ^"GFRAME[45]" | ^"GFRAME[44]" | ^"GFRAME[43]" | ^"GFRAME[42]" | ^"GFRAME[41]" | ^"GFRAME[40]" | ^"GFRAME[3]" | ^"GFRAME[39]" | ^"GFRAME[38]" | ^"GFRAME[37]" | ^"GFRAME[36]" | ^"GFRAME[35]" | ^"GFRAME[34]" | ^"GFRAME[33]" | ^"GFRAME[32]" | ^"GFRAME[31]" | ^"GFRAME[30]" | ^"GFRAME[2]" | ^"GFRAME[29]" | ^"GFRAME[28]" | ^"GFRAME[27]" | ^"GFRAME[26]" | ^"GFRAME[25]" | ^"GFRAME[24]" | ^"GFRAME[23]" | ^"GFRAME[22]" | ^"GFRAME[21]" | ^"GFRAME[20]" | ^"GFRAME[1]" | ^"GFRAME[19]" | ^"GFRAME[18]" | ^"GFRAME[17]" | ^"GFRAME[16]" | ^"GFRAME[15]" | ^"GFRAME[14]" | ^"GFRAME[13]" | ^"GFRAME[12]" | ^"GFRAME[11]" | ^"GFRAME[10]" | ^"GFRAME[100]" | ^"GFRAME[0]") ~ !(ASCII_ALPHANUMERIC) }
63
- g_command = {gg01_motion | gg02_wait | gg03_frame_area_limit | gg04_fifo | gg06_plane_select | gg07_tool_radius | gg08_work_offset | gg09_frame_tool_suppress | gg10_exact_stop_mode | gg11_exact_stop_non_modal | gg12_block_change_g60_g9 | gg13_wp_measure | gg14_wp_measure_mode | gg15_feed_type | gg16_feedrate_override | gg17_approach_retract_tool | gg18_corner_behavior | gg19_curve_start_spline | gg20_curve_end_spline | gg21_accel_profile | gg22_tool_offset_type | gg23_collision_monitor | gg24_precontrol | gg25_tool_orient_ref | gg26_repos_mode | gg27_tool_offset_change | gg28_area_limit | gg29_rad_diam_prog | gg30_nc_compress | gg31_oem_g | gg32_oem_g | gg33_fine_tool_offset | gg34_tool_orient_smooth | gg35_punch_nibble | gg36_punch_delay | gg37_feedrate_profile | gg39_contour_acc | gg40_tool_radius_const | gg41_thread_interrupt | gg42_tool_carrier | gg43_sar_approach | gg44_sar_segment | gg45_path_ref_fgroup | gg46_plane_fast_retract | gg47_mode_switchover | gg48_approach_retract_trc | gg49_ptp_motion | gg50_orient_prog | gg51_interp_type_orient | gg52_frame_rot_wp | gg53_tool_wear | gg54_vector_rot_poly | gg55_rapid_traverse | gg56_frame_rot_tool | gg57_corner_decel | gg58_dyn_resp_path | gg59_area_limit | gg61_tool_orient_smooth | gg62_repos_non_modal | gg64_grinding_frames}
63
+
64
+ gcommand_list = @{(^"WALIMON" | ^"WALIMOF" | ^"WALCS9" | ^"WALCS8" | ^"WALCS7" | ^"WALCS6" | ^"WALCS5" | ^"WALCS4" | ^"WALCS3" | ^"WALCS2" | ^"WALCS10" | ^"WALCS1" | ^"WALCS0" | ^"UPATH" | ^"TRANS" | ^"TOWWCS" | ^"TOWTCS" | ^"TOWSTD" | ^"TOWMCS" | ^"TOWKCS" | ^"TOWBCS" | ^"TOROTZ" | ^"TOROTY" | ^"TOROTX" | ^"TOROTOF" | ^"TOROT" | ^"TOFRAMEZ" | ^"TOFRAMEY" | ^"TOFRAMEX" | ^"TOFRAME" | ^"TCOFRZ" | ^"TCOFRY" | ^"TCOFRX" | ^"TCOFR" | ^"TCOABS" | ^"SUPD" | ^"SUPA" | ^"STOPFIFO" | ^"STARTFIFO" | ^"SPOF" | ^"SPATH" | ^"SONS" | ^"SON" | ^"SOFT" | ^"SCALE" | ^"RTLION" | ^"RTLIOF" | ^"ROTS" | ^"ROT" | ^"RMNBL" | ^"RMN" | ^"RMIBL" | ^"RMI" | ^"RMEBL" | ^"RME" | ^"RMBBL" | ^"RMB" | ^"REPOSQA" | ^"REPOSQ" | ^"REPOSL" | ^"REPOSHA" | ^"REPOSH" | ^"REPOSA" | ^"PTPWOC" | ^"PTPG0" | ^"PTP" | ^"PONS" | ^"PON" | ^"POLY" | ^"PDELAYON" | ^"PDELAYOF" | ^"PAROTOF" | ^"PAROT" | ^"OST" | ^"OSSE" | ^"OSS" | ^"OSOF" | ^"OSD" | ^"OSC" | ^"ORIWKS" | ^"ORIVIRT2" | ^"ORIVIRT1" | ^"ORIVECT" | ^"ORISON" | ^"ORISOF" | ^"ORIRPY2" | ^"ORIRPY" | ^"ORIROTT" | ^"ORIROTR" | ^"ORIROTC" | ^"ORIROTA" | ^"ORIPLANE" | ^"ORIPATHS" | ^"ORIPATH" | ^"ORIMKS" | ^"ORIEULER" | ^"ORID" | ^"ORICURVE" | ^"ORICONTO" | ^"ORICONIO" | ^"ORICONCW" | ^"ORICONCCW" | ^"ORIC" | ^"ORIAXPOS" | ^"ORIAXES" | ^"OEMIPO2" | ^"OEMIPO1" | ^"NORM" | ^"MIRROR" | ^"LFWP" | ^"LFTXT" | ^"LFPOS" | ^"LFON" | ^"LFOF" | ^"KONTT" | ^"KONTC" | ^"KONT" | ^"INVCW" | ^"INVCCW" | ^"GFRAME[9]" | ^"GFRAME[99]" | ^"GFRAME[98]" | ^"GFRAME[97]" | ^"GFRAME[96]" | ^"GFRAME[95]" | ^"GFRAME[94]" | ^"GFRAME[93]" | ^"GFRAME[92]" | ^"GFRAME[91]" | ^"GFRAME[90]" | ^"GFRAME[8]" | ^"GFRAME[89]" | ^"GFRAME[88]" | ^"GFRAME[87]" | ^"GFRAME[86]" | ^"GFRAME[85]" | ^"GFRAME[84]" | ^"GFRAME[83]" | ^"GFRAME[82]" | ^"GFRAME[81]" | ^"GFRAME[80]" | ^"GFRAME[7]" | ^"GFRAME[79]" | ^"GFRAME[78]" | ^"GFRAME[77]" | ^"GFRAME[76]" | ^"GFRAME[75]" | ^"GFRAME[74]" | ^"GFRAME[73]" | ^"GFRAME[72]" | ^"GFRAME[71]" | ^"GFRAME[70]" | ^"GFRAME[6]" | ^"GFRAME[69]" | ^"GFRAME[68]" | ^"GFRAME[67]" | ^"GFRAME[66]" | ^"GFRAME[65]" | ^"GFRAME[64]" | ^"GFRAME[63]" | ^"GFRAME[62]" | ^"GFRAME[61]" | ^"GFRAME[60]" | ^"GFRAME[5]" | ^"GFRAME[59]" | ^"GFRAME[58]" | ^"GFRAME[57]" | ^"GFRAME[56]" | ^"GFRAME[55]" | ^"GFRAME[54]" | ^"GFRAME[53]" | ^"GFRAME[52]" | ^"GFRAME[51]" | ^"GFRAME[50]" | ^"GFRAME[4]" | ^"GFRAME[49]" | ^"GFRAME[48]" | ^"GFRAME[47]" | ^"GFRAME[46]" | ^"GFRAME[45]" | ^"GFRAME[44]" | ^"GFRAME[43]" | ^"GFRAME[42]" | ^"GFRAME[41]" | ^"GFRAME[40]" | ^"GFRAME[3]" | ^"GFRAME[39]" | ^"GFRAME[38]" | ^"GFRAME[37]" | ^"GFRAME[36]" | ^"GFRAME[35]" | ^"GFRAME[34]" | ^"GFRAME[33]" | ^"GFRAME[32]" | ^"GFRAME[31]" | ^"GFRAME[30]" | ^"GFRAME[2]" | ^"GFRAME[29]" | ^"GFRAME[28]" | ^"GFRAME[27]" | ^"GFRAME[26]" | ^"GFRAME[25]" | ^"GFRAME[24]" | ^"GFRAME[23]" | ^"GFRAME[22]" | ^"GFRAME[21]" | ^"GFRAME[20]" | ^"GFRAME[1]" | ^"GFRAME[19]" | ^"GFRAME[18]" | ^"GFRAME[17]" | ^"GFRAME[16]" | ^"GFRAME[15]" | ^"GFRAME[14]" | ^"GFRAME[13]" | ^"GFRAME[12]" | ^"GFRAME[11]" | ^"GFRAME[10]" | ^"GFRAME[100]" | ^"GFRAME[0]" | ^"G973" | ^"G972" | ^"G971" | ^"G97" | ^"G962" | ^"G961" | ^"G96" | ^"G952" | ^"G95" | ^"G942" | ^"G94" | ^"G931" | ^"G93" | ^"G91" | ^"G90" | ^"G9" | ^"G829" | ^"G828" | ^"G827" | ^"G826" | ^"G825" | ^"G824" | ^"G823" | ^"G822" | ^"G821" | ^"G820" | ^"G819" | ^"G818" | ^"G817" | ^"G816" | ^"G815" | ^"G814" | ^"G813" | ^"G812" | ^"G811" | ^"G810" | ^"G75" | ^"G74" | ^"G710" | ^"G71" | ^"G700" | ^"G70" | ^"G7" | ^"G645" | ^"G644" | ^"G643" | ^"G642" | ^"G641" | ^"G64" | ^"G63" | ^"G621" | ^"G62" | ^"G603" | ^"G602" | ^"G601" | ^"G60" | ^"G599" | ^"G598" | ^"G597" | ^"G596" | ^"G595" | ^"G594" | ^"G593" | ^"G592" | ^"G591" | ^"G590" | ^"G59" | ^"G589" | ^"G588" | ^"G587" | ^"G586" | ^"G585" | ^"G584" | ^"G583" | ^"G582" | ^"G581" | ^"G580" | ^"G58" | ^"G579" | ^"G578" | ^"G577" | ^"G576" | ^"G575" | ^"G574" | ^"G573" | ^"G572" | ^"G571" | ^"G570" | ^"G57" | ^"G569" | ^"G568" | ^"G567" | ^"G566" | ^"G565" | ^"G564" | ^"G563" | ^"G562" | ^"G561" | ^"G560" | ^"G56" | ^"G559" | ^"G558" | ^"G557" | ^"G556" | ^"G555" | ^"G554" | ^"G553" | ^"G552" | ^"G551" | ^"G550" | ^"G55" | ^"G549" | ^"G548" | ^"G547" | ^"G546" | ^"G545" | ^"G544" | ^"G543" | ^"G542" | ^"G541" | ^"G540" | ^"G54" | ^"G539" | ^"G538" | ^"G537" | ^"G536" | ^"G535" | ^"G534" | ^"G533" | ^"G532" | ^"G531" | ^"G530" | ^"G53" | ^"G529" | ^"G528" | ^"G527" | ^"G526" | ^"G525" | ^"G524" | ^"G523" | ^"G522" | ^"G521" | ^"G520" | ^"G519" | ^"G518" | ^"G517" | ^"G516" | ^"G515" | ^"G514" | ^"G513" | ^"G512" | ^"G511" | ^"G510" | ^"G509" | ^"G508" | ^"G507" | ^"G506" | ^"G505" | ^"G500" | ^"G5" | ^"G462" | ^"G461" | ^"G460" | ^"G451" | ^"G450" | ^"G42" | ^"G41" | ^"G40" | ^"G4" | ^"G35" | ^"G348" | ^"G347" | ^"G341" | ^"G340" | ^"G34" | ^"G336" | ^"G335" | ^"G332" | ^"G331" | ^"G33" | ^"G3" | ^"G291" | ^"G290" | ^"G26" | ^"G25" | ^"G248" | ^"G247" | ^"G2" | ^"G19" | ^"G18" | ^"G17" | ^"G153" | ^"G148" | ^"G147" | ^"G143" | ^"G142" | ^"G141" | ^"G140" | ^"G112" | ^"G111" | ^"G110" | ^"G1" | ^"G0" | ^"FTOCON" | ^"FTOCOF" | ^"FNORM" | ^"FLIN" | ^"FIFOCTRL" | ^"FFWON" | ^"FFWOF" | ^"FENDNORM" | ^"FCUB" | ^"ETAN" | ^"ENAT" | ^"EAUTO" | ^"DYNSEMIFIN" | ^"DYNROUGH" | ^"DYNPREC" | ^"DYNPOS" | ^"DYNNORM" | ^"DYNFINISH" | ^"DRIVE" | ^"DIAMON" | ^"DIAMOF" | ^"DIAMCYCOF" | ^"DIAM90" | ^"CUTCONON" | ^"CUTCONOF" | ^"CUT3DFS" | ^"CUT3DFF" | ^"CUT3DFD" | ^"CUT3DF" | ^"CUT3DCD" | ^"CUT3DCCD" | ^"CUT3DCC" | ^"CUT3DC" | ^"CUT2DFD" | ^"CUT2DF" | ^"CUT2DD" | ^"CUT2D" | ^"CT" | ^"CSPLINE" | ^"CPRECON" | ^"CPRECOF" | ^"CP" | ^"COMPSURF" | ^"COMPON" | ^"COMPOF" | ^"COMPCURV" | ^"COMPCAD" | ^"CIP" | ^"CFTCP" | ^"CFIN" | ^"CFC" | ^"CDON" | ^"CDOF2" | ^"CDOF" | ^"BTAN" | ^"BSPLINE" | ^"BRISK" | ^"BNAT" | ^"BAUTO" | ^"ATRANS" | ^"ASPLINE" | ^"ASCALE" | ^"AROTS" | ^"AROT" | ^"AMIRROR") ~ !(ASCII_ALPHANUMERIC) }
65
+ g_command_numbered = { &("G" ~ ASCII_DIGIT+) ~ g_command }
66
+ g_command = { &gcommand_list ~ (gg01_motion | gg02_wait | gg03_frame_area_limit | gg04_fifo | gg06_plane_select | gg07_tool_radius | gg08_work_offset | gg09_frame_tool_suppress | gg10_exact_stop_mode | gg11_exact_stop_non_modal | gg12_block_change_g60_g9 | gg13_wp_measure | gg14_wp_measure_mode | gg15_feed_type | gg16_feedrate_override | gg17_approach_retract_tool | gg18_corner_behavior | gg19_curve_start_spline | gg20_curve_end_spline | gg21_accel_profile | gg22_tool_offset_type | gg23_collision_monitor | gg24_precontrol | gg25_tool_orient_ref | gg26_repos_mode | gg27_tool_offset_change | gg28_area_limit | gg29_rad_diam_prog | gg30_nc_compress | gg31_oem_g | gg32_oem_g | gg33_fine_tool_offset | gg34_tool_orient_smooth | gg35_punch_nibble | gg36_punch_delay | gg37_feedrate_profile | gg39_contour_acc | gg40_tool_radius_const | gg41_thread_interrupt | gg42_tool_carrier | gg43_sar_approach | gg44_sar_segment | gg45_path_ref_fgroup | gg46_plane_fast_retract | gg47_mode_switchover | gg48_approach_retract_trc | gg49_ptp_motion | gg50_orient_prog | gg51_interp_type_orient | gg52_frame_rot_wp | gg53_tool_wear | gg54_vector_rot_poly | gg55_rapid_traverse | gg56_frame_rot_tool | gg57_corner_decel | gg58_dyn_resp_path | gg59_area_limit | gg61_tool_orient_smooth | gg62_repos_non_modal | gg64_grinding_frames)}
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "nc-gcode-interpreter"
7
- version = "0.1.4"
7
+ version = "0.1.5"
8
8
  description = "A interpreter for NC (Numerical Control) code"
9
9
  authors = [{ name = "CEAD Group", email = "software@ceadgroup.com" }]
10
10
  requires-python = ">=3.12"
@@ -31,10 +31,11 @@ condition = { base_condition | ("(" ~ base_condition ~ ")") }
31
31
  base_condition = _{ (expression ~ relational_operator ~ expression) | expression }
32
32
  relational_operator = { "<=" | ">=" | "<" | ">" | "==" | "<>" }
33
33
  statement = {
34
- g_command
34
+ g_command_numbered
35
35
  | m_command
36
36
  | assignment_multi
37
37
  | assignment
38
+ | g_command
38
39
  | function_call
39
40
  | tool_selection
40
41
  }
@@ -124,7 +125,6 @@ m_command = { "M" ~ ASCII_DIGIT+ }
124
125
  // G-Code ggroups
125
126
  // This Pest grammar file is auto-generated from G-Code definitions.
126
127
  // Due to the way pest works, the sorting of the literals is important.
127
-
128
128
  gg01_motion = @{ (^"POLY" | ^"OEMIPO2" | ^"OEMIPO1" | ^"INVCW" | ^"INVCCW" | ^"G35" | ^"G34" | ^"G336" | ^"G335" | ^"G332" | ^"G331" | ^"G33" | ^"G3" | ^"G2" | ^"G1" | ^"G0" | ^"CT" | ^"CSPLINE" | ^"CIP" | ^"BSPLINE" | ^"ASPLINE") ~ !(ASCII_ALPHANUMERIC) }
129
129
  gg02_wait = @{ (^"REPOSQA" | ^"REPOSQ" | ^"REPOSL" | ^"REPOSHA" | ^"REPOSH" | ^"REPOSA" | ^"G75" | ^"G74" | ^"G7" | ^"G63" | ^"G5" | ^"G4" | ^"G348" | ^"G347" | ^"G248" | ^"G247" | ^"G148" | ^"G147") ~ !(ASCII_ALPHANUMERIC) }
130
130
  gg03_frame_area_limit = @{ (^"TRANS" | ^"SCALE" | ^"ROTS" | ^"ROT" | ^"MIRROR" | ^"G59" | ^"G58" | ^"G26" | ^"G25" | ^"G112" | ^"G111" | ^"G110" | ^"ATRANS" | ^"ASCALE" | ^"AROTS" | ^"AROT" | ^"AMIRROR") ~ !(ASCII_ALPHANUMERIC) }
@@ -185,65 +185,7 @@ gg59_area_limit = @{ (^"WALCS9" | ^"WALCS8" | ^"WALCS7" | ^"WALCS6" |
185
185
  gg61_tool_orient_smooth = @{ (^"ORISON" | ^"ORISOF") ~ !(ASCII_ALPHANUMERIC) }
186
186
  gg62_repos_non_modal = @{ (^"RMNBL" | ^"RMIBL" | ^"RMEBL" | ^"RMBBL") ~ !(ASCII_ALPHANUMERIC) }
187
187
  gg64_grinding_frames = @{ (^"GFRAME[9]" | ^"GFRAME[99]" | ^"GFRAME[98]" | ^"GFRAME[97]" | ^"GFRAME[96]" | ^"GFRAME[95]" | ^"GFRAME[94]" | ^"GFRAME[93]" | ^"GFRAME[92]" | ^"GFRAME[91]" | ^"GFRAME[90]" | ^"GFRAME[8]" | ^"GFRAME[89]" | ^"GFRAME[88]" | ^"GFRAME[87]" | ^"GFRAME[86]" | ^"GFRAME[85]" | ^"GFRAME[84]" | ^"GFRAME[83]" | ^"GFRAME[82]" | ^"GFRAME[81]" | ^"GFRAME[80]" | ^"GFRAME[7]" | ^"GFRAME[79]" | ^"GFRAME[78]" | ^"GFRAME[77]" | ^"GFRAME[76]" | ^"GFRAME[75]" | ^"GFRAME[74]" | ^"GFRAME[73]" | ^"GFRAME[72]" | ^"GFRAME[71]" | ^"GFRAME[70]" | ^"GFRAME[6]" | ^"GFRAME[69]" | ^"GFRAME[68]" | ^"GFRAME[67]" | ^"GFRAME[66]" | ^"GFRAME[65]" | ^"GFRAME[64]" | ^"GFRAME[63]" | ^"GFRAME[62]" | ^"GFRAME[61]" | ^"GFRAME[60]" | ^"GFRAME[5]" | ^"GFRAME[59]" | ^"GFRAME[58]" | ^"GFRAME[57]" | ^"GFRAME[56]" | ^"GFRAME[55]" | ^"GFRAME[54]" | ^"GFRAME[53]" | ^"GFRAME[52]" | ^"GFRAME[51]" | ^"GFRAME[50]" | ^"GFRAME[4]" | ^"GFRAME[49]" | ^"GFRAME[48]" | ^"GFRAME[47]" | ^"GFRAME[46]" | ^"GFRAME[45]" | ^"GFRAME[44]" | ^"GFRAME[43]" | ^"GFRAME[42]" | ^"GFRAME[41]" | ^"GFRAME[40]" | ^"GFRAME[3]" | ^"GFRAME[39]" | ^"GFRAME[38]" | ^"GFRAME[37]" | ^"GFRAME[36]" | ^"GFRAME[35]" | ^"GFRAME[34]" | ^"GFRAME[33]" | ^"GFRAME[32]" | ^"GFRAME[31]" | ^"GFRAME[30]" | ^"GFRAME[2]" | ^"GFRAME[29]" | ^"GFRAME[28]" | ^"GFRAME[27]" | ^"GFRAME[26]" | ^"GFRAME[25]" | ^"GFRAME[24]" | ^"GFRAME[23]" | ^"GFRAME[22]" | ^"GFRAME[21]" | ^"GFRAME[20]" | ^"GFRAME[1]" | ^"GFRAME[19]" | ^"GFRAME[18]" | ^"GFRAME[17]" | ^"GFRAME[16]" | ^"GFRAME[15]" | ^"GFRAME[14]" | ^"GFRAME[13]" | ^"GFRAME[12]" | ^"GFRAME[11]" | ^"GFRAME[10]" | ^"GFRAME[100]" | ^"GFRAME[0]") ~ !(ASCII_ALPHANUMERIC) }
188
- g_command = {
189
- gg01_motion
190
- | gg02_wait
191
- | gg03_frame_area_limit
192
- | gg04_fifo
193
- | gg06_plane_select
194
- | gg07_tool_radius
195
- | gg08_work_offset
196
- | gg09_frame_tool_suppress
197
- | gg10_exact_stop_mode
198
- | gg11_exact_stop_non_modal
199
- | gg12_block_change_g60_g9
200
- | gg13_wp_measure
201
- | gg14_wp_measure_mode
202
- | gg15_feed_type
203
- | gg16_feedrate_override
204
- | gg17_approach_retract_tool
205
- | gg18_corner_behavior
206
- | gg19_curve_start_spline
207
- | gg20_curve_end_spline
208
- | gg21_accel_profile
209
- | gg22_tool_offset_type
210
- | gg23_collision_monitor
211
- | gg24_precontrol
212
- | gg25_tool_orient_ref
213
- | gg26_repos_mode
214
- | gg27_tool_offset_change
215
- | gg28_area_limit
216
- | gg29_rad_diam_prog
217
- | gg30_nc_compress
218
- | gg31_oem_g
219
- | gg32_oem_g
220
- | gg33_fine_tool_offset
221
- | gg34_tool_orient_smooth
222
- | gg35_punch_nibble
223
- | gg36_punch_delay
224
- | gg37_feedrate_profile
225
- | gg39_contour_acc
226
- | gg40_tool_radius_const
227
- | gg41_thread_interrupt
228
- | gg42_tool_carrier
229
- | gg43_sar_approach
230
- | gg44_sar_segment
231
- | gg45_path_ref_fgroup
232
- | gg46_plane_fast_retract
233
- | gg47_mode_switchover
234
- | gg48_approach_retract_trc
235
- | gg49_ptp_motion
236
- | gg50_orient_prog
237
- | gg51_interp_type_orient
238
- | gg52_frame_rot_wp
239
- | gg53_tool_wear
240
- | gg54_vector_rot_poly
241
- | gg55_rapid_traverse
242
- | gg56_frame_rot_tool
243
- | gg57_corner_decel
244
- | gg58_dyn_resp_path
245
- | gg59_area_limit
246
- | gg61_tool_orient_smooth
247
- | gg62_repos_non_modal
248
- | gg64_grinding_frames
249
- }
188
+
189
+ gcommand_list = @{ (^"WALIMON" | ^"WALIMOF" | ^"WALCS9" | ^"WALCS8" | ^"WALCS7" | ^"WALCS6" | ^"WALCS5" | ^"WALCS4" | ^"WALCS3" | ^"WALCS2" | ^"WALCS10" | ^"WALCS1" | ^"WALCS0" | ^"UPATH" | ^"TRANS" | ^"TOWWCS" | ^"TOWTCS" | ^"TOWSTD" | ^"TOWMCS" | ^"TOWKCS" | ^"TOWBCS" | ^"TOROTZ" | ^"TOROTY" | ^"TOROTX" | ^"TOROTOF" | ^"TOROT" | ^"TOFRAMEZ" | ^"TOFRAMEY" | ^"TOFRAMEX" | ^"TOFRAME" | ^"TCOFRZ" | ^"TCOFRY" | ^"TCOFRX" | ^"TCOFR" | ^"TCOABS" | ^"SUPD" | ^"SUPA" | ^"STOPFIFO" | ^"STARTFIFO" | ^"SPOF" | ^"SPATH" | ^"SONS" | ^"SON" | ^"SOFT" | ^"SCALE" | ^"RTLION" | ^"RTLIOF" | ^"ROTS" | ^"ROT" | ^"RMNBL" | ^"RMN" | ^"RMIBL" | ^"RMI" | ^"RMEBL" | ^"RME" | ^"RMBBL" | ^"RMB" | ^"REPOSQA" | ^"REPOSQ" | ^"REPOSL" | ^"REPOSHA" | ^"REPOSH" | ^"REPOSA" | ^"PTPWOC" | ^"PTPG0" | ^"PTP" | ^"PONS" | ^"PON" | ^"POLY" | ^"PDELAYON" | ^"PDELAYOF" | ^"PAROTOF" | ^"PAROT" | ^"OST" | ^"OSSE" | ^"OSS" | ^"OSOF" | ^"OSD" | ^"OSC" | ^"ORIWKS" | ^"ORIVIRT2" | ^"ORIVIRT1" | ^"ORIVECT" | ^"ORISON" | ^"ORISOF" | ^"ORIRPY2" | ^"ORIRPY" | ^"ORIROTT" | ^"ORIROTR" | ^"ORIROTC" | ^"ORIROTA" | ^"ORIPLANE" | ^"ORIPATHS" | ^"ORIPATH" | ^"ORIMKS" | ^"ORIEULER" | ^"ORID" | ^"ORICURVE" | ^"ORICONTO" | ^"ORICONIO" | ^"ORICONCW" | ^"ORICONCCW" | ^"ORIC" | ^"ORIAXPOS" | ^"ORIAXES" | ^"OEMIPO2" | ^"OEMIPO1" | ^"NORM" | ^"MIRROR" | ^"LFWP" | ^"LFTXT" | ^"LFPOS" | ^"LFON" | ^"LFOF" | ^"KONTT" | ^"KONTC" | ^"KONT" | ^"INVCW" | ^"INVCCW" | ^"GFRAME[9]" | ^"GFRAME[99]" | ^"GFRAME[98]" | ^"GFRAME[97]" | ^"GFRAME[96]" | ^"GFRAME[95]" | ^"GFRAME[94]" | ^"GFRAME[93]" | ^"GFRAME[92]" | ^"GFRAME[91]" | ^"GFRAME[90]" | ^"GFRAME[8]" | ^"GFRAME[89]" | ^"GFRAME[88]" | ^"GFRAME[87]" | ^"GFRAME[86]" | ^"GFRAME[85]" | ^"GFRAME[84]" | ^"GFRAME[83]" | ^"GFRAME[82]" | ^"GFRAME[81]" | ^"GFRAME[80]" | ^"GFRAME[7]" | ^"GFRAME[79]" | ^"GFRAME[78]" | ^"GFRAME[77]" | ^"GFRAME[76]" | ^"GFRAME[75]" | ^"GFRAME[74]" | ^"GFRAME[73]" | ^"GFRAME[72]" | ^"GFRAME[71]" | ^"GFRAME[70]" | ^"GFRAME[6]" | ^"GFRAME[69]" | ^"GFRAME[68]" | ^"GFRAME[67]" | ^"GFRAME[66]" | ^"GFRAME[65]" | ^"GFRAME[64]" | ^"GFRAME[63]" | ^"GFRAME[62]" | ^"GFRAME[61]" | ^"GFRAME[60]" | ^"GFRAME[5]" | ^"GFRAME[59]" | ^"GFRAME[58]" | ^"GFRAME[57]" | ^"GFRAME[56]" | ^"GFRAME[55]" | ^"GFRAME[54]" | ^"GFRAME[53]" | ^"GFRAME[52]" | ^"GFRAME[51]" | ^"GFRAME[50]" | ^"GFRAME[4]" | ^"GFRAME[49]" | ^"GFRAME[48]" | ^"GFRAME[47]" | ^"GFRAME[46]" | ^"GFRAME[45]" | ^"GFRAME[44]" | ^"GFRAME[43]" | ^"GFRAME[42]" | ^"GFRAME[41]" | ^"GFRAME[40]" | ^"GFRAME[3]" | ^"GFRAME[39]" | ^"GFRAME[38]" | ^"GFRAME[37]" | ^"GFRAME[36]" | ^"GFRAME[35]" | ^"GFRAME[34]" | ^"GFRAME[33]" | ^"GFRAME[32]" | ^"GFRAME[31]" | ^"GFRAME[30]" | ^"GFRAME[2]" | ^"GFRAME[29]" | ^"GFRAME[28]" | ^"GFRAME[27]" | ^"GFRAME[26]" | ^"GFRAME[25]" | ^"GFRAME[24]" | ^"GFRAME[23]" | ^"GFRAME[22]" | ^"GFRAME[21]" | ^"GFRAME[20]" | ^"GFRAME[1]" | ^"GFRAME[19]" | ^"GFRAME[18]" | ^"GFRAME[17]" | ^"GFRAME[16]" | ^"GFRAME[15]" | ^"GFRAME[14]" | ^"GFRAME[13]" | ^"GFRAME[12]" | ^"GFRAME[11]" | ^"GFRAME[10]" | ^"GFRAME[100]" | ^"GFRAME[0]" | ^"G973" | ^"G972" | ^"G971" | ^"G97" | ^"G962" | ^"G961" | ^"G96" | ^"G952" | ^"G95" | ^"G942" | ^"G94" | ^"G931" | ^"G93" | ^"G91" | ^"G90" | ^"G9" | ^"G829" | ^"G828" | ^"G827" | ^"G826" | ^"G825" | ^"G824" | ^"G823" | ^"G822" | ^"G821" | ^"G820" | ^"G819" | ^"G818" | ^"G817" | ^"G816" | ^"G815" | ^"G814" | ^"G813" | ^"G812" | ^"G811" | ^"G810" | ^"G75" | ^"G74" | ^"G710" | ^"G71" | ^"G700" | ^"G70" | ^"G7" | ^"G645" | ^"G644" | ^"G643" | ^"G642" | ^"G641" | ^"G64" | ^"G63" | ^"G621" | ^"G62" | ^"G603" | ^"G602" | ^"G601" | ^"G60" | ^"G599" | ^"G598" | ^"G597" | ^"G596" | ^"G595" | ^"G594" | ^"G593" | ^"G592" | ^"G591" | ^"G590" | ^"G59" | ^"G589" | ^"G588" | ^"G587" | ^"G586" | ^"G585" | ^"G584" | ^"G583" | ^"G582" | ^"G581" | ^"G580" | ^"G58" | ^"G579" | ^"G578" | ^"G577" | ^"G576" | ^"G575" | ^"G574" | ^"G573" | ^"G572" | ^"G571" | ^"G570" | ^"G57" | ^"G569" | ^"G568" | ^"G567" | ^"G566" | ^"G565" | ^"G564" | ^"G563" | ^"G562" | ^"G561" | ^"G560" | ^"G56" | ^"G559" | ^"G558" | ^"G557" | ^"G556" | ^"G555" | ^"G554" | ^"G553" | ^"G552" | ^"G551" | ^"G550" | ^"G55" | ^"G549" | ^"G548" | ^"G547" | ^"G546" | ^"G545" | ^"G544" | ^"G543" | ^"G542" | ^"G541" | ^"G540" | ^"G54" | ^"G539" | ^"G538" | ^"G537" | ^"G536" | ^"G535" | ^"G534" | ^"G533" | ^"G532" | ^"G531" | ^"G530" | ^"G53" | ^"G529" | ^"G528" | ^"G527" | ^"G526" | ^"G525" | ^"G524" | ^"G523" | ^"G522" | ^"G521" | ^"G520" | ^"G519" | ^"G518" | ^"G517" | ^"G516" | ^"G515" | ^"G514" | ^"G513" | ^"G512" | ^"G511" | ^"G510" | ^"G509" | ^"G508" | ^"G507" | ^"G506" | ^"G505" | ^"G500" | ^"G5" | ^"G462" | ^"G461" | ^"G460" | ^"G451" | ^"G450" | ^"G42" | ^"G41" | ^"G40" | ^"G4" | ^"G35" | ^"G348" | ^"G347" | ^"G341" | ^"G340" | ^"G34" | ^"G336" | ^"G335" | ^"G332" | ^"G331" | ^"G33" | ^"G3" | ^"G291" | ^"G290" | ^"G26" | ^"G25" | ^"G248" | ^"G247" | ^"G2" | ^"G19" | ^"G18" | ^"G17" | ^"G153" | ^"G148" | ^"G147" | ^"G143" | ^"G142" | ^"G141" | ^"G140" | ^"G112" | ^"G111" | ^"G110" | ^"G1" | ^"G0" | ^"FTOCON" | ^"FTOCOF" | ^"FNORM" | ^"FLIN" | ^"FIFOCTRL" | ^"FFWON" | ^"FFWOF" | ^"FENDNORM" | ^"FCUB" | ^"ETAN" | ^"ENAT" | ^"EAUTO" | ^"DYNSEMIFIN" | ^"DYNROUGH" | ^"DYNPREC" | ^"DYNPOS" | ^"DYNNORM" | ^"DYNFINISH" | ^"DRIVE" | ^"DIAMON" | ^"DIAMOF" | ^"DIAMCYCOF" | ^"DIAM90" | ^"CUTCONON" | ^"CUTCONOF" | ^"CUT3DFS" | ^"CUT3DFF" | ^"CUT3DFD" | ^"CUT3DF" | ^"CUT3DCD" | ^"CUT3DCCD" | ^"CUT3DCC" | ^"CUT3DC" | ^"CUT2DFD" | ^"CUT2DF" | ^"CUT2DD" | ^"CUT2D" | ^"CT" | ^"CSPLINE" | ^"CPRECON" | ^"CPRECOF" | ^"CP" | ^"COMPSURF" | ^"COMPON" | ^"COMPOF" | ^"COMPCURV" | ^"COMPCAD" | ^"CIP" | ^"CFTCP" | ^"CFIN" | ^"CFC" | ^"CDON" | ^"CDOF2" | ^"CDOF" | ^"BTAN" | ^"BSPLINE" | ^"BRISK" | ^"BNAT" | ^"BAUTO" | ^"ATRANS" | ^"ASPLINE" | ^"ASCALE" | ^"AROTS" | ^"AROT" | ^"AMIRROR") ~ !(ASCII_ALPHANUMERIC) }
190
+ g_command_numbered = { &("G" ~ ASCII_DIGIT+) ~ g_command }
191
+ g_command = { &gcommand_list ~ (gg01_motion | gg02_wait | gg03_frame_area_limit | gg04_fifo | gg06_plane_select | gg07_tool_radius | gg08_work_offset | gg09_frame_tool_suppress | gg10_exact_stop_mode | gg11_exact_stop_non_modal | gg12_block_change_g60_g9 | gg13_wp_measure | gg14_wp_measure_mode | gg15_feed_type | gg16_feedrate_override | gg17_approach_retract_tool | gg18_corner_behavior | gg19_curve_start_spline | gg20_curve_end_spline | gg21_accel_profile | gg22_tool_offset_type | gg23_collision_monitor | gg24_precontrol | gg25_tool_orient_ref | gg26_repos_mode | gg27_tool_offset_change | gg28_area_limit | gg29_rad_diam_prog | gg30_nc_compress | gg31_oem_g | gg32_oem_g | gg33_fine_tool_offset | gg34_tool_orient_smooth | gg35_punch_nibble | gg36_punch_delay | gg37_feedrate_profile | gg39_contour_acc | gg40_tool_radius_const | gg41_thread_interrupt | gg42_tool_carrier | gg43_sar_approach | gg44_sar_segment | gg45_path_ref_fgroup | gg46_plane_fast_retract | gg47_mode_switchover | gg48_approach_retract_trc | gg49_ptp_motion | gg50_orient_prog | gg51_interp_type_orient | gg52_frame_rot_wp | gg53_tool_wear | gg54_vector_rot_poly | gg55_rapid_traverse | gg56_frame_rot_tool | gg57_corner_decel | gg58_dyn_resp_path | gg59_area_limit | gg61_tool_orient_smooth | gg62_repos_non_modal | gg64_grinding_frames) }
@@ -139,7 +139,10 @@ fn interpret_assignment(element: Pair<Rule>, state: &mut State) -> Result<(Strin
139
139
  let (key, value, translate) = match (variable_pair.as_rule(), expression_pair.as_rule()) {
140
140
  (Rule::variable_single_char, Rule::value) => {
141
141
  let key = variable_pair.as_str().to_string();
142
- let value = expression_pair.as_str().parse::<f32>().expect("Failed to interpret value");
142
+ let value = expression_pair
143
+ .as_str()
144
+ .parse::<f32>()
145
+ .expect("Failed to interpret value");
143
146
  (key, value, true)
144
147
  }
145
148
  (Rule::variable, Rule::axis_increment) => {
@@ -495,28 +498,29 @@ fn insert_m_key(last: &mut HashMap<String, Value>, value: &str) -> Result<(), Pa
495
498
  if let Value::StrList(ref mut vec) = existing_value {
496
499
  if vec.len() < 5 {
497
500
  vec.push(value.to_string());
498
- return Ok(()); // Successfully added to the list
501
+ return Ok(()); // Successfully added to the list
499
502
  }
500
503
  }
501
504
  } else {
502
505
  // If the key doesn't exist, insert a new StrList with the first value
503
506
  last.insert(m_key.to_owned(), Value::StrList(vec![value.to_string()]));
504
- return Ok(()); // Exit early after insertion
507
+ return Ok(()); // Exit early after insertion
505
508
  }
506
509
  }
507
- Err(ParsingError::TooManyMCommands) // Return error if all keys are full
510
+ Err(ParsingError::TooManyMCommands) // Return error if all keys are full
508
511
  }
509
512
 
510
513
  fn interpret_statement(element: Pair<Rule>, output: &mut Output, state: &mut State) -> Result<(), ParsingError> {
511
514
  // Grammar:
512
- // statement = {
513
- // g_command
514
- // | m_command
515
- // | assignment_multi
516
- // | assignment
517
- // | function_call
518
- // | tool_selection
519
- // }
515
+ // statement = {
516
+ // g_command_numbered
517
+ // | m_command
518
+ // | assignment_multi
519
+ // | assignment
520
+ // | g_command
521
+ // | function_call
522
+ // | tool_selection
523
+ // }
520
524
 
521
525
  for statement in element.into_inner() {
522
526
  let last = output.last_mut().expect("Output vector should not be empty");
@@ -529,6 +533,11 @@ fn interpret_statement(element: Pair<Rule>, output: &mut Output, state: &mut Sta
529
533
  let (key, value) = interpret_g_command(statement);
530
534
  last.insert(key, Value::Str(value));
531
535
  }
536
+ Rule::g_command_numbered => {
537
+ let (key, value) =
538
+ interpret_g_command(statement.into_inner().next().expect("Error parsing g_command_numbered"));
539
+ last.insert(key, Value::Str(value));
540
+ }
532
541
  Rule::m_command => {
533
542
  let (_key, value) = interpret_m_command(statement);
534
543
  // there are 5 M codes allowed in a block. Store them in separate columns in the output
@@ -1,16 +1,15 @@
1
1
  //interpreter.rs
2
2
  use pest::Parser;
3
+ use polars::chunked_array::ops::FillNullStrategy;
3
4
  use polars::prelude::*;
4
5
  use std::collections::HashMap;
5
6
  use std::io::{self};
6
- use polars::chunked_array::ops::FillNullStrategy;
7
7
 
8
8
  use crate::errors::ParsingError;
9
9
  use crate::interpret_rules::interpret_blocks;
10
+ use crate::modal_groups::MODAL_GROUPS;
10
11
  use crate::state::{self, State};
11
12
  use crate::types::{NCParser, Rule, Value};
12
- use crate::modal_groups::MODAL_GROUPS;
13
-
14
13
 
15
14
  /// Helper function to convert PolarsError to ParsingError
16
15
  impl From<PolarsError> for ParsingError {
@@ -29,7 +28,6 @@ pub fn nc_to_dataframe(
29
28
  extra_axes: Option<Vec<String>>,
30
29
  iteration_limit: usize,
31
30
  disable_forward_fill: bool,
32
-
33
31
  ) -> Result<(DataFrame, state::State), ParsingError> {
34
32
  // Default axis identifiers
35
33
  const DEFAULT_AXIS_IDENTIFIERS: &[&str] = &[
@@ -37,9 +35,8 @@ pub fn nc_to_dataframe(
37
35
  ];
38
36
 
39
37
  // Use the override if provided, otherwise use the default identifiers
40
- let axis_identifiers: Vec<String> = axis_identifiers.unwrap_or_else(|| {
41
- DEFAULT_AXIS_IDENTIFIERS.iter().map(|&s| s.to_string()).collect()
42
- });
38
+ let axis_identifiers: Vec<String> =
39
+ axis_identifiers.unwrap_or_else(|| DEFAULT_AXIS_IDENTIFIERS.iter().map(|&s| s.to_string()).collect());
43
40
 
44
41
  // Add extra axes to the existing list if provided
45
42
  let mut axis_identifiers = axis_identifiers;
@@ -65,44 +62,35 @@ pub fn nc_to_dataframe(
65
62
  // Get the column names and reorder them
66
63
  let ordered_columns = reorder_columns(
67
64
  axis_identifiers,
68
- df.get_column_names().into_iter().map(|s| s.to_string()).collect()
65
+ df.get_column_names().into_iter().map(|s| s.to_string()).collect(),
69
66
  );
70
67
 
71
68
  // Select the columns in the specified order and return
72
69
  df = df.select(&ordered_columns).map_err(ParsingError::from)?;
73
70
 
74
-
75
-
76
71
  if !disable_forward_fill {
77
-
78
72
  let fill_columns: Vec<String> = df
79
- .get_column_names()
80
- .iter()
81
- .map(|col| col.to_string())
82
- .filter(|col| state.is_axis(col) || MODAL_GROUPS.contains(&col.as_str()))
83
- .collect();
84
-
85
-
86
-
87
- for col_name in fill_columns {
88
- let column = df
89
- .column(&col_name)
90
- .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
91
- let filled_column = column
92
- .fill_null(FillNullStrategy::Forward(None))
93
- .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
94
- df.with_column(filled_column)
95
- .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
96
- }
73
+ .get_column_names()
74
+ .iter()
75
+ .map(|col| col.to_string())
76
+ .filter(|col| state.is_axis(col) || MODAL_GROUPS.contains(&col.as_str()))
77
+ .collect();
78
+
79
+ for col_name in fill_columns {
80
+ let column = df
81
+ .column(&col_name)
82
+ .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
83
+ let filled_column = column
84
+ .fill_null(FillNullStrategy::Forward(None))
85
+ .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
86
+ df.with_column(filled_column)
87
+ .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
88
+ }
97
89
  }
98
90
 
99
-
100
-
101
-
102
91
  Ok((df, state))
103
92
  }
104
93
 
105
-
106
94
  #[allow(dead_code)] // Only used in main.rs, not in lib.rs
107
95
  pub fn dataframe_to_csv(df: &mut DataFrame, path: &str) -> Result<(), PolarsError> {
108
96
  // Get all column names that are of List type
@@ -125,8 +113,7 @@ pub fn dataframe_to_csv(df: &mut DataFrame, path: &str) -> Result<(), PolarsErro
125
113
  *df = exploded_df;
126
114
  }
127
115
 
128
- let mut file = std::fs::File::create(path)
129
- .map_err(|e| PolarsError::ComputeError(format!("{:?}", e).into()))?;
116
+ let mut file = std::fs::File::create(path).map_err(|e| PolarsError::ComputeError(format!("{:?}", e).into()))?;
130
117
 
131
118
  CsvWriter::new(&mut file)
132
119
  .with_float_precision(Some(3))
@@ -135,7 +122,6 @@ pub fn dataframe_to_csv(df: &mut DataFrame, path: &str) -> Result<(), PolarsErro
135
122
  Ok(())
136
123
  }
137
124
 
138
-
139
125
  /// Parse file and return results as a vector of HashMaps
140
126
  fn interpret_file(input: &str, state: &mut State) -> Result<Vec<HashMap<String, Value>>, ParsingError> {
141
127
  let blocks = NCParser::parse(Rule::file, input)
@@ -162,21 +148,21 @@ fn interpret_file(input: &str, state: &mut State) -> Result<Vec<HashMap<String,
162
148
 
163
149
  fn results_to_dataframe(data: Vec<HashMap<String, Value>>) -> PolarsResult<DataFrame> {
164
150
  // Step 1: Collect all unique keys (column names)
165
- let columns: Vec<String> = data.iter()
151
+ let columns: Vec<String> = data
152
+ .iter()
166
153
  .flat_map(|row| row.keys().cloned())
167
- .collect::<std::collections::HashSet<String>>() // Deduplicate keys
154
+ .collect::<std::collections::HashSet<String>>() // Deduplicate keys
168
155
  .into_iter()
169
156
  .collect();
170
157
 
171
158
  // Step 2: Initialize empty columns (vectors) for each key
172
- let mut series_map: HashMap<String, Vec<Option<AnyValue>>> = columns
173
- .iter()
174
- .map(|key| (key.clone(), Vec::new()))
175
- .collect();
159
+ let mut series_map: HashMap<String, Vec<Option<AnyValue>>> =
160
+ columns.iter().map(|key| (key.clone(), Vec::new())).collect();
176
161
 
177
162
  // Step 3: Populate the columns with data, inserting None where keys are missing
178
163
  for row in &data {
179
- if row.is_empty() { // Skip rows with no values
164
+ if row.is_empty() {
165
+ // Skip rows with no values
180
166
  continue;
181
167
  }
182
168
 
@@ -187,12 +173,16 @@ fn results_to_dataframe(data: Vec<HashMap<String, Value>>) -> PolarsResult<DataF
187
173
  }
188
174
 
189
175
  // Step 4: Convert each column to a Polars Series
190
- let polars_series: Vec<Series> = columns.iter()
176
+ let polars_series: Vec<Series> = columns
177
+ .iter()
191
178
  .map(|key| {
192
179
  let column_data = series_map.remove(key).unwrap();
193
180
  Series::new(
194
- key.as_str().into(), // Convert `&String` to `PlSmallStr` using `Into::into`
195
- column_data.into_iter().map(|opt| opt.unwrap_or(AnyValue::Null)).collect::<Vec<AnyValue>>(),
181
+ key.as_str().into(), // Convert `&String` to `PlSmallStr` using `Into::into`
182
+ column_data
183
+ .into_iter()
184
+ .map(|opt| opt.unwrap_or(AnyValue::Null))
185
+ .collect::<Vec<AnyValue>>(),
196
186
  )
197
187
  })
198
188
  .collect();
@@ -202,13 +192,10 @@ fn results_to_dataframe(data: Vec<HashMap<String, Value>>) -> PolarsResult<DataF
202
192
  }
203
193
 
204
194
  /// Helper function to reorder DataFrame columns
205
- fn reorder_columns(
206
- axis_identifiers: Vec<String>,
207
- mut df_columns: Vec<String>
208
- ) -> Vec<String> {
195
+ fn reorder_columns(axis_identifiers: Vec<String>, mut df_columns: Vec<String>) -> Vec<String> {
209
196
  let mut ordered_columns = Vec::new();
210
- df_columns.sort(); // Sort columns alphabetically
211
- // Move axis columns first
197
+ df_columns.sort(); // Sort columns alphabetically
198
+ // Move axis columns first
212
199
  for axis in axis_identifiers {
213
200
  if let Some(index) = df_columns.iter().position(|col| col == &axis) {
214
201
  ordered_columns.push(df_columns.remove(index));
@@ -226,5 +213,3 @@ fn reorder_columns(
226
213
 
227
214
  ordered_columns
228
215
  }
229
-
230
-
@@ -10,8 +10,8 @@ use std::collections::HashMap;
10
10
  mod errors;
11
11
  mod interpret_rules;
12
12
  mod interpreter;
13
- mod state;
14
13
  mod modal_groups;
14
+ mod state;
15
15
 
16
16
  use pyo3::prelude::*;
17
17
  use pyo3::wrap_pyfunction;
@@ -28,13 +28,19 @@ fn nc_to_dataframe(
28
28
  iteration_limit: usize,
29
29
  disable_forward_fill: bool,
30
30
  ) -> PyResult<(PyDataFrame, HashMap<String, HashMap<String, f32>>)> {
31
- let (df,state) = nc_to_dataframe_rust(input, initial_state.as_deref(), axis_identifiers, extra_axes, iteration_limit, disable_forward_fill)
32
- .map_err(|e| PyErr::new::<PyValueError, _>(format!("Error creating DataFrame: {:?}", e)))?;
31
+ let (df, state) = nc_to_dataframe_rust(
32
+ input,
33
+ initial_state.as_deref(),
34
+ axis_identifiers,
35
+ extra_axes,
36
+ iteration_limit,
37
+ disable_forward_fill,
38
+ )
39
+ .map_err(|e| PyErr::new::<PyValueError, _>(format!("Error creating DataFrame: {:?}", e)))?;
33
40
 
34
41
  Ok((PyDataFrame(df), state.to_python_dict()))
35
42
  }
36
43
 
37
-
38
44
  /// Define the Python module
39
45
  #[pymodule]
40
46
  fn nc_gcode_interpreter(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
@@ -8,9 +8,9 @@ use std::io::{self};
8
8
  mod errors;
9
9
  mod interpret_rules;
10
10
  mod interpreter;
11
+ mod modal_groups;
11
12
  mod state;
12
13
  mod types;
13
- mod modal_groups;
14
14
 
15
15
  use interpreter::{dataframe_to_csv, nc_to_dataframe};
16
16
  use std::path::PathBuf;
@@ -91,13 +91,17 @@ fn main() -> io::Result<()> {
91
91
 
92
92
  let input = std::fs::read_to_string(matches.get_one::<String>("input").unwrap())
93
93
  .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Error reading input file: {:?}", e)))?;
94
-
95
94
 
96
- let initial_state = matches.get_one::<String>("initial_state")
95
+ let initial_state = matches
96
+ .get_one::<String>("initial_state")
97
97
  .map(std::fs::read_to_string)
98
98
  .transpose()
99
- .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Error reading initial state file: {:?}", e)))?;
100
-
99
+ .map_err(|e| {
100
+ io::Error::new(
101
+ io::ErrorKind::Other,
102
+ format!("Error reading initial state file: {:?}", e),
103
+ )
104
+ })?;
101
105
 
102
106
  let (mut df, _state) = nc_to_dataframe(
103
107
  &input,
@@ -105,7 +109,7 @@ fn main() -> io::Result<()> {
105
109
  axes_override.clone(),
106
110
  extra_axes,
107
111
  *iteration_limit,
108
- disable_forward_fill
112
+ disable_forward_fill,
109
113
  )?;
110
114
 
111
115
  let mut output_path = PathBuf::from(input_path.clone());
@@ -54,12 +54,12 @@ impl State {
54
54
  *self.translation.get(axis).unwrap_or(&0.0)
55
55
  }
56
56
 
57
- pub fn update_axis(&mut self, key: &str, value: f32, translate:bool) -> Result<f32, ParsingError> {
57
+ pub fn update_axis(&mut self, key: &str, value: f32, translate: bool) -> Result<f32, ParsingError> {
58
58
  let translation_value = self.get_translation(key);
59
59
  let mut updated_value = value;
60
60
  if translate {
61
- updated_value+= translation_value;
62
- }
61
+ updated_value += translation_value;
62
+ }
63
63
  self.axes.insert(key.to_string(), updated_value);
64
64
  Ok(updated_value)
65
65
  }
@@ -19,9 +19,7 @@ impl Value {
19
19
  match self {
20
20
  Value::Str(s) => AnyValue::String(s),
21
21
  Value::Float(f) => AnyValue::Float32(*f),
22
- Value::StrList(vec) => {
23
- AnyValue::List(vec.iter().map(|s| s.as_str()).collect())
24
- }
22
+ Value::StrList(vec) => AnyValue::List(vec.iter().map(|s| s.as_str()).collect()),
25
23
  }
26
24
  }
27
25
  }