Add peg::Error to allow parsing to fail during action.
Predicates are useful, but often determining whether something can be parsed often involves actually doing redundant work.
For example, you may have a rule INT <- < [0-9]+ >, and want to ensure that the number can be supported by int:
parser['INT'].predicate = [](
const peg::SemanticValues& vs,
const std::any& /*dt*/,
std::string& msg
)
{
int value;
auto [ptr, err] = std::from_chars(
vs.token().data(),
vs.token().data() + vs.token().size(),
value
);
return err == std::errc();
}
Once the predicate passes, a second call to std::from_chars will be necessary within the action.
This PR adds peg::Error, which may be returned from an action and is treated as if the parse was invalid. The above check can be included in the action:
parser['INT'] = [](const peg::SemanticValues& vs)
{
int value;
auto [ptr, err] = std::from_chars(
vs.token().data(),
vs.token().data() + vs.token().size(),
value
);
if (err != std::errc()) {
return peg::Error("Number out of range.");
}
return value;
}
@dnwpark thanks for the pull request. Could you add some unit test cases for this change? Then, I'll take a look at it. Thanks!
@yhirose please take another look!
I also ran into an issue where if I have a grammar such as
WORD <- LETTER*
LETTER <- [a-z]
with the action:
parser["LETTER"] = [&](const SemanticValues &vs) -> std::any {
if (vs.token() == "x") {
return Error("Not allowing 'x'");
}
return vs.token();
};
When parsing a word like "extra", the interaction with zero or more causes the message to be "expected end of input". This only occurs if the erroring action is the last rule.
I am not sure how to fix this, or if this should even be considered a defect.