Fixed #202 again

This commit is contained in:
yhirose 2022-05-27 21:48:12 -04:00
parent 0ada38acec
commit 959128ec0f
2 changed files with 54 additions and 4 deletions

View File

@ -662,6 +662,7 @@ struct ErrorInfo {
const char *message_pos = nullptr;
std::string message;
mutable const char *last_output_pos = nullptr;
bool keep_previous_token = false;
void clear() {
error_pos = nullptr;
@ -1047,9 +1048,11 @@ public:
auto &chldsv = c.push();
c.push_capture_scope();
c.error_info.keep_previous_token = id > 0;
auto se = scope_exit([&]() {
c.pop();
c.pop_capture_scope();
c.error_info.keep_previous_token = false;
});
len = ope->parse(s, n, chldsv, c, dt);
@ -1123,7 +1126,7 @@ public:
auto se = scope_exit([&]() { c.pop_capture_scope(); });
auto save_sv_size = vs.size();
auto save_tok_size = vs.tokens.size();
auto save_error_info = c.error_info;
const auto &rule = *ope_;
auto len = rule.parse(s + i, n - i, vs, c, dt);
if (success(len)) {
@ -1138,7 +1141,6 @@ public:
vs.tokens.erase(vs.tokens.begin() +
static_cast<std::ptrdiff_t>(save_tok_size));
}
c.error_info = save_error_info;
break;
}
i += len;
@ -2539,7 +2541,7 @@ inline const std::vector<size_t> &SemanticValues::source_line_index() const {
inline void Context::set_error_pos(const char *a_s, const char *literal) {
if (log) {
if (error_info.error_pos <= a_s) {
if (error_info.error_pos < a_s) {
if (error_info.error_pos < a_s || !error_info.keep_previous_token) {
error_info.error_pos = a_s;
error_info.expected_tokens.clear();
}

View File

@ -1248,6 +1248,54 @@ TEST(ErrorTest, Default_error_handling_2) {
EXPECT_FALSE(pg.parse(" @ aaa typo "));
}
TEST(ErrorTest, Default_error_handling_fiblang) {
parser pg(R"(
# Syntax
START STATEMENTS
STATEMENTS (DEFINITION / EXPRESSION)*
DEFINITION 'def' Identifier '(' Identifier ')' EXPRESSION
EXPRESSION TERNARY
TERNARY CONDITION ('?' EXPRESSION (':' / %recover(col)) EXPRESSION)?
CONDITION INFIX (ConditionOperator INFIX)?
INFIX CALL (InfixOperator CALL)*
CALL PRIMARY ('(' EXPRESSION ')')?
PRIMARY FOR / Identifier / '(' EXPRESSION ')' / Number
FOR 'for' Identifier 'from' Number 'to' Number EXPRESSION
# Token
ConditionOperator '<'
InfixOperator '+' / '-'
Identifier !Keyword < [a-zA-Z][a-zA-Z0-9_]* >
Number < [0-9]+ >
Keyword 'def' / 'for' / 'from' / 'to'
%whitespace [ \t\r\n]*
%word [a-zA-Z]
col '' { message "missing colon." }
)");
EXPECT_TRUE(!!pg);
std::vector<std::string> errors{
R"(4:7: syntax error, unexpected 'frm', expecting 'from'.)",
};
size_t i = 0;
pg.log = [&](size_t ln, size_t col, const std::string &msg) {
std::stringstream ss;
ss << ln << ":" << col << ": " << msg;
EXPECT_EQ(errors[i++], ss.str());
};
EXPECT_FALSE(pg.parse(R"(def fib(x)
x < 2 ? 1 : fib(x - 2) + fib(x - 1)
for n frm 1 to 30
puts(fib(n))
)"));
}
TEST(ErrorTest, Error_recovery_1) {
parser pg(R"(
START <- __? SECTION*
@ -1395,7 +1443,7 @@ TEST(ErrorTest, Error_recovery_2) {
R"(1:38: syntax error, unexpected 'ddd', expecting '"', <NUM>.)",
R"(1:55: syntax error, unexpected ']', expecting '"'.)",
R"(1:58: syntax error, unexpected '\n', expecting '"', <NUM>.)",
R"(2:3: syntax error.)",
R"(2:3: syntax error, expecting ']'.)",
};
size_t i = 0;