From 85a382d9348e5673bae1791ceacf9853ef19f6aa Mon Sep 17 00:00:00 2001 From: Nico Lube Date: Fri, 17 Apr 2026 11:07:57 +0200 Subject: [PATCH] Support deprecated G54 aperture-select prefix. Accepts standalone `G54*` and the combined `G54Dnn*` form still emitted by gerbv on save. See gerber spec 8.1.1. Fixes: #16 --- src/parser.rs | 24 ++++++++++++++++ tests/component_tests.rs | 59 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/src/parser.rs b/src/parser.rs index cb4e9bb..d894407 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -263,6 +263,30 @@ fn parse_line( _ => Err(ContentError::UnknownCommand {}), }, ]), + '5' => { + // G54 is the deprecated aperture-select prefix (gerber spec 8.1.1). + // The combined `G54Dnn*` form is still emitted by gerbv on save. + match linechars.next().ok_or(ContentError::UnknownCommand {})? { + '4' => { + let select = Ok(FunctionCode::GCode(GCode::SelectAperture).into()); + match linechars.next() { + None | Some('*') => Ok(vec![select]), + Some('D') => { + linechars.next_back(); + Ok(vec![ + select, + parse_aperture_selection_or_command( + line, + linechars.clone(), + ), + ]) + } + Some(_) => Ok(vec![Err(ContentError::UnknownCommand {})]), + } + } + _ => Ok(vec![Err(ContentError::UnknownCommand {})]), + } + } _ => Ok(vec![Err(ContentError::UnknownCommand {})]), } } diff --git a/tests/component_tests.rs b/tests/component_tests.rs index 78de3c4..94475d8 100644 --- a/tests/component_tests.rs +++ b/tests/component_tests.rs @@ -319,6 +319,65 @@ fn aperture_selection() { ) } +/// Test deprecated `G54` aperture selection (gerber spec 8.1.1). +/// Accepts both `G54*` (standalone) and the combined `G54Dnn*` form (emitted by gerbv on save). +#[test] +fn deprecated_g54_aperture_selection() { + // given + logging_init(); + + let reader = gerber_to_reader( + " + %FSLAX23Y23*% + %MOMM*% + + %ADD10C, 0.01*% + %ADD11R, 0.01X0.15*% + + G04 Deprecated combined G54Dnn form* + G54D10* + G04 Deprecated standalone G54 form* + G54* + G04 Deprecated combined G54Dnn form again* + G54D11* + + M02* + ", + ); + + // when + parse_and_filter!(reader, commands, filtered_commands, |cmd| matches!( + cmd, + Ok(Command::FunctionCode(FunctionCode::DCode( + DCode::SelectAperture(_) + ))) | Ok(Command::FunctionCode(FunctionCode::GCode( + GCode::SelectAperture + ))) + )); + + // then + assert_eq!( + filtered_commands, + vec![ + Ok(Command::FunctionCode(FunctionCode::GCode( + GCode::SelectAperture + ))), + Ok(Command::FunctionCode(FunctionCode::DCode( + DCode::SelectAperture(10) + ))), + Ok(Command::FunctionCode(FunctionCode::GCode( + GCode::SelectAperture + ))), + Ok(Command::FunctionCode(FunctionCode::GCode( + GCode::SelectAperture + ))), + Ok(Command::FunctionCode(FunctionCode::DCode( + DCode::SelectAperture(11) + ))), + ] + ) +} + /// Test the D01* statements (linear) #[test] #[allow(non_snake_case)]