Skip to content

Commit 82ff687

Browse files
authored
Fix parsing flags and add test (#519)
1 parent 566181c commit 82ff687

File tree

2 files changed

+51
-30
lines changed

2 files changed

+51
-30
lines changed

source/citnames/source/semantic/Parsers.cc

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -200,19 +200,21 @@ namespace cs::semantic {
200200
if (auto result = check_equal(key, *candidate); result) {
201201
return result;
202202
}
203-
// check if the argument is allowed to stick to the flag
204-
if (auto result = check_partial(key, *candidate); result) {
205-
return result;
206-
}
207203
}
208-
// partial match is less likely to be a few steps away from the lower bound,
209-
// therefore search the whole flag list again.
210-
for (const auto &candidate : flags_) {
211-
if (auto result = check_partial(key, candidate); result) {
212-
return result;
204+
205+
std::optional<std::string> candidate_longest = std::nullopt;
206+
for (const auto &[candidate, info] : flags_) {
207+
if (const auto& extra = split_extra(candidate, key); extra) {
208+
const size_t prefix_length = key.size() - extra.value().size();
209+
if (!candidate_longest || (prefix_length > candidate_longest.value().size())) {
210+
candidate_longest = std::make_optional(std::string(candidate));
211+
}
213212
}
214213
}
215-
return std::nullopt;
214+
215+
return (candidate_longest.has_value())
216+
? check_partial(key, *(flags_.find(candidate_longest.value())))
217+
: std::nullopt;
216218
}
217219

218220
std::optional<FlagParser::Match>
@@ -228,26 +230,24 @@ namespace cs::semantic {
228230
std::optional<FlagParser::Match>
229231
FlagParser::check_partial(const std::string_view &key, const FlagsByName::value_type &candidate) {
230232
const auto &flag_definition = candidate.second;
231-
if (const auto &extra = split_extra(candidate.first, key); extra) {
232-
const auto flag_matching = classify_flag_matching(extra.value());
233-
switch (flag_matching) {
234-
case FlagMatch::GLUED:
235-
if (is_glue_allowed(flag_definition.match)) {
236-
const size_t decrease = is_prefix_match(flag_definition.match) ? 0 : 1;
237-
const size_t count = count_of_arguments(flag_definition.match) - decrease;
238-
return std::make_optional(std::make_tuple(count, flag_definition.type));
239-
}
240-
break;
241-
case FlagMatch::GLUED_WITH_EQ:
242-
if (is_glue_with_equal_allowed(flag_definition.match)) {
243-
const size_t count = count_of_arguments(flag_definition.match) - 1;
244-
return std::make_optional(std::make_tuple(count, flag_definition.type));
245-
}
246-
break;
247-
default:
248-
// This should not happen here. Exact match is already filtered out.
249-
return std::nullopt;
250-
}
233+
const auto flag_matching = classify_flag_matching(key.substr(candidate.first.size()));
234+
switch (flag_matching) {
235+
case FlagMatch::GLUED:
236+
if (is_glue_allowed(flag_definition.match)) {
237+
const size_t decrease = is_prefix_match(flag_definition.match) ? 0 : 1;
238+
const size_t count = count_of_arguments(flag_definition.match) - decrease;
239+
return std::make_optional(std::make_tuple(count, flag_definition.type));
240+
}
241+
break;
242+
case FlagMatch::GLUED_WITH_EQ:
243+
if (is_glue_with_equal_allowed(flag_definition.match)) {
244+
const size_t count = count_of_arguments(flag_definition.match) - 1;
245+
return std::make_optional(std::make_tuple(count, flag_definition.type));
246+
}
247+
break;
248+
default:
249+
// This should not happen here. Exact match is already filtered out.
250+
__builtin_unreachable();
251251
}
252252
return std::nullopt;
253253
}

source/citnames/test/ParserTest.cc

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,4 +320,25 @@ namespace {
320320
EXPECT_TRUE(flags.is_err());
321321
}
322322
}
323+
324+
TEST(Parser, parse_flags_with_several_suitable_prefixes) {
325+
const FlagsByName flags_by_name = {
326+
{"-l", {MatchInstruction::PREFIX, CompilerFlagType::LINKER}},
327+
{"-language", {MatchInstruction::EXACTLY_WITH_1_OPT_SEP, CompilerFlagType::OTHER}},
328+
{"-linker", {MatchInstruction::PREFIX_WITH_2_OPTS, CompilerFlagType::OTHER}},
329+
};
330+
const auto sut = Repeat(FlagParser(flags_by_name));
331+
332+
{
333+
const Arguments input = {"compiler", "-lin", "-language", "s", "-linkeriasds", "opt1", "opt2"};
334+
const auto flags = parse(sut, input);
335+
EXPECT_TRUE(flags.is_ok());
336+
const CompilerFlags expected = {
337+
CompilerFlag{slice(input, 1), CompilerFlagType::LINKER},
338+
CompilerFlag{slice(input, 2, 4), CompilerFlagType::OTHER},
339+
CompilerFlag{slice(input, 4, 7), CompilerFlagType::OTHER},
340+
};
341+
EXPECT_EQ(expected, flags.unwrap());
342+
}
343+
}
323344
}

0 commit comments

Comments
 (0)