Skip to content

Commit 97b3ae6

Browse files
committed
Add parsing of MO command
1 parent 8c5faee commit 97b3ae6

File tree

2 files changed

+105
-11
lines changed

2 files changed

+105
-11
lines changed

cpp/src/GerberParserCppModule.cxx

Lines changed: 84 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ export namespace gerber {
189189
Zeros(Enum value) :
190190
value(value) {}
191191

192-
static Enum from_string(const std::string_view& str) {
192+
static Enum fromString(const std::string_view& str) {
193193
if (str == "L") {
194194
return Enum::SKIP_LEADING;
195195
} else if (str == "T") {
@@ -223,7 +223,7 @@ export namespace gerber {
223223
CoordinateNotation(Enum value) :
224224
value(value) {}
225225

226-
static CoordinateNotation from_string(const std::string_view& str) {
226+
static CoordinateNotation fromString(const std::string_view& str) {
227227
if (str == "A") {
228228
return Enum::ABSOLUTE;
229229
} else if (str == "I") {
@@ -259,8 +259,8 @@ export namespace gerber {
259259
int x_decimal,
260260
int y_integral,
261261
int y_decimal) :
262-
zeros(Zeros::from_string(zeros)),
263-
coordinate_mode(CoordinateNotation::from_string(coordinate_mode)),
262+
zeros(Zeros::fromString(zeros)),
263+
coordinate_mode(CoordinateNotation::fromString(coordinate_mode)),
264264
x_integral(x_integral),
265265
x_decimal(x_decimal),
266266
y_integral(y_integral),
@@ -271,6 +271,57 @@ export namespace gerber {
271271
}
272272
};
273273

274+
class UnitMode {
275+
public:
276+
enum Enum : uint8_t {
277+
INCHES,
278+
MILLIMETERS
279+
};
280+
281+
Enum value;
282+
283+
private:
284+
UnitMode() = delete;
285+
286+
public:
287+
UnitMode(Enum value) :
288+
value(value) {}
289+
290+
static UnitMode fromString(const std::string_view& str) {
291+
if (str == "IN") {
292+
return Enum::INCHES;
293+
} else if (str == "MM") {
294+
return Enum::MILLIMETERS;
295+
}
296+
throw std::invalid_argument("Invalid unit mode");
297+
}
298+
299+
std::string toString() const {
300+
return value == Enum::INCHES ? "IN" : "MM";
301+
}
302+
303+
bool operator==(const UnitMode& other) const {
304+
return value == other.value;
305+
}
306+
307+
bool operator==(const Enum& other) const {
308+
return value == other;
309+
}
310+
};
311+
312+
class MO : public ExtendedCommand {
313+
public:
314+
UnitMode unit_mode;
315+
316+
public:
317+
MO(const std::string_view& unit_mode) :
318+
unit_mode(UnitMode::fromString(unit_mode)) {}
319+
320+
std::string getNodeName() const override {
321+
return "MO";
322+
}
323+
};
324+
274325
class SyntaxError : public std::runtime_error {
275326
public:
276327
explicit SyntaxError(const std::string& message) :
@@ -284,18 +335,16 @@ export namespace gerber {
284335
location_t global_index;
285336
// Regular expressions cache
286337
// G-codes
287-
std::regex g_code_regex;
288-
std::regex g04_regex;
338+
std::regex g_code_regex{"^[Gg]0*([1-9][0-9]*)\\*"};
339+
std::regex g04_regex{"^[Gg]0*4([^%*]+)\\*"};
289340
// Properties
290-
std::regex fs_regex;
341+
std::regex fs_regex{"^%FS([TL])([IA])X([0-9])([0-9])Y([0-9])([0-9])\\*%"};
342+
std::regex mo_regex{"^%MO(IN|MM)\\*%"};
291343

292344
Parser() :
293345
commands(0),
294346
full_source(""),
295-
global_index(0),
296-
g_code_regex("^[Gg]0*([1-9][0-9]*)\\*"),
297-
g04_regex("^[Gg]0*4([^%*]+)\\*"),
298-
fs_regex("^%FS([TL])([IA])X([0-9])([0-9])Y([0-9])([0-9])\\*%") {}
347+
global_index(0) {}
299348

300349
~Parser() {}
301350

@@ -449,6 +498,10 @@ export namespace gerber {
449498
return parse_fs_command(source, index);
450499
break;
451500

501+
case 'M':
502+
return parse_mo_command(source, index);
503+
break;
504+
452505
default:
453506
break;
454507
}
@@ -482,5 +535,25 @@ export namespace gerber {
482535
}
483536
throw_syntax_error();
484537
}
538+
539+
offset_t parse_mo_command(const std::string_view& source, const location_t& index) {
540+
if (source.length() < 6) {
541+
throw_syntax_error();
542+
}
543+
std::cmatch match;
544+
545+
const auto result = std::regex_search(
546+
source.data(),
547+
source.data() + source.size(),
548+
match,
549+
mo_regex,
550+
std::regex_constants::match_continuous
551+
);
552+
if (result && match.size() == 2) {
553+
commands.push_back(std::make_shared<MO>(match[1].str()));
554+
return match.length();
555+
}
556+
throw_syntax_error();
557+
}
485558
};
486559
} // namespace gerber

cpp/test/main.test.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,25 @@ TEST_CASE("Parse FS", "[properties]") {
8282

8383
REQUIRE(fs->y_integral == 2);
8484
REQUIRE(fs->y_decimal == 6);
85+
}
86+
87+
TEMPLATE_TEST_CASE_SIG(
88+
"Parse MO",
89+
"[properties]",
90+
((gerber::UnitMode::Enum enumValue), enumValue),
91+
(gerber::UnitMode::INCHES),
92+
(gerber::UnitMode::MILLIMETERS)
93+
) {
94+
std::string unitModeString = gerber::UnitMode(enumValue).toString();
95+
gerber::Parser parser;
96+
auto gerber_source = std::format("%MO{}*%", unitModeString);
97+
auto result = parser.parse(gerber_source);
98+
const auto& nodes = result.getNodes();
99+
100+
REQUIRE(nodes.size() == 1);
101+
auto mo = std::dynamic_pointer_cast<gerber::MO>(nodes[0]);
102+
103+
REQUIRE(mo->getNodeName() == "MO");
104+
105+
REQUIRE(mo->unit_mode == enumValue);
85106
}

0 commit comments

Comments
 (0)