Fixed problem with %recover

This commit is contained in:
yhirose 2021-01-15 16:51:36 -05:00
parent 0d005fb3da
commit 8ad71c4adc
5 changed files with 68 additions and 46 deletions

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -144,7 +144,7 @@ int main(int argc, const char **argv) {
name = peg::TraceOpeName::get(const_cast<peg::Ope &>(ope)); name = peg::TraceOpeName::get(const_cast<peg::Ope &>(ope));
auto lit = dynamic_cast<const peg::LiteralString *>(&ope); auto lit = dynamic_cast<const peg::LiteralString *>(&ope);
if (lit) { name += " '" + lit->lit_ + "'"; } if (lit) { name += " '" + peg::escape_characters(lit->lit_) + "'"; }
} }
std::cout << "E " << pos << backtrack << "\t" << indent << "" << name std::cout << "E " << pos << backtrack << "\t" << indent << "" << name
<< " #" << c.trace_ids.back() << std::endl; << " #" << c.trace_ids.back() << std::endl;

View File

@ -201,6 +201,10 @@ inline std::string escape_characters(const char *s, size_t n) {
return str; return str;
} }
inline std::string escape_characters(std::string_view sv) {
return escape_characters(sv.data(), sv.size());
}
/*----------------------------------------------------------------------------- /*-----------------------------------------------------------------------------
* resolve_escape_sequence * resolve_escape_sequence
*---------------------------------------------------------------------------*/ *---------------------------------------------------------------------------*/
@ -685,11 +689,7 @@ private:
if (len) { if (len) {
size_t i = 0; size_t i = 0;
int c = error_pos[i++]; int c = error_pos[i++];
if (std::ispunct(c)) { if (!std::ispunct(c) && !std::isspace(c)) {
while (i < len && std::ispunct(error_pos[i])) {
i++;
}
} else {
while (i < len && !std::ispunct(error_pos[i]) && while (i < len && !std::ispunct(error_pos[i]) &&
!std::isspace(error_pos[i])) { !std::isspace(error_pos[i])) {
i++; i++;
@ -2121,7 +2121,6 @@ private:
static const char *WHITESPACE_DEFINITION_NAME = "%whitespace"; static const char *WHITESPACE_DEFINITION_NAME = "%whitespace";
static const char *WORD_DEFINITION_NAME = "%word"; static const char *WORD_DEFINITION_NAME = "%word";
static const char *RECOVER_DEFINITION_NAME = "%recover"; static const char *RECOVER_DEFINITION_NAME = "%recover";
static const char *RECOVER_TO_DEFINITION_NAME = "%recover_to";
/* /*
* Definition * Definition
@ -3213,8 +3212,6 @@ private:
auto ope = ref(*data.grammar, ident, vs.sv().data(), is_macro, args); auto ope = ref(*data.grammar, ident, vs.sv().data(), is_macro, args);
if (ident == RECOVER_DEFINITION_NAME) { if (ident == RECOVER_DEFINITION_NAME) {
ope = rec(ope); ope = rec(ope);
} else if (ident == RECOVER_TO_DEFINITION_NAME) {
ope = rec(ope);
} }
if (ignore) { if (ignore) {
@ -3401,17 +3398,6 @@ private:
rule.is_macro = true; rule.is_macro = true;
rule.params = {"x"}; rule.params = {"x"};
} }
// `%recover_to`
{
auto &rule = grammar[RECOVER_TO_DEFINITION_NAME];
rule <= oom(seq(npd(ref(grammar, "x", "", false, {})), dot()));
rule.name = RECOVER_TO_DEFINITION_NAME;
rule.s_ = "[native]";
rule.ignoreSemanticValue = true;
rule.is_macro = true;
rule.params = {"x"};
}
} }
std::any dt = &data; std::any dt = &data;

View File

@ -1083,19 +1083,19 @@ TEST_CASE("Error recovery 1", "[error]") {
HEADER <- '[' _ CATEGORY (':' _ ATTRIBUTES)? ']' HEADER <- '[' _ CATEGORY (':' _ ATTRIBUTES)? ']'
CATEGORY <- < [-_a-zA-Z0-9 ]+ > _ CATEGORY <- < [-_a-zA-Z0-9\u0080-\uFFFF ]+ > _
ATTRIBUTES <- ATTRIBUTE (',' _ ATTRIBUTE)* ATTRIBUTES <- ATTRIBUTE (',' _ ATTRIBUTE)*
ATTRIBUTE <- < [-_a-zA-Z0-9]+ > _ ATTRIBUTE <- < [-_a-zA-Z0-9\u0080-\uFFFF]+ > _
ENTRIES <- (ENTRY (__ ENTRY)*)? ENTRIES <- (ENTRY (__ ENTRY)*)?
ENTRY <- ONE_WAY PHRASE ('|' _ PHRASE)* ENTRY <- ONE_WAY PHRASE ('|' _ PHRASE)* !'='
/ PHRASE ('|' _ PHRASE) / PHRASE ('|' _ PHRASE)+ !'='
/ %recover_to(__ / HEADER) / %recover((!(__ / HEADER) .)+)
ONE_WAY <- PHRASE '=' _ ONE_WAY <- PHRASE '=' _
PHRASE <- WORD (' ' WORD)* _ PHRASE <- WORD (' ' WORD)* _
WORD <- < (![ \t\r\n=|[#] .)+ > WORD <- < (![ \t\r\n=|[\]#] .)+ >
~__ <- _ (comment? nl _)+ ~__ <- _ (comment? nl _)+
~_ <- [ \t]* ~_ <- [ \t]*
@ -1107,9 +1107,10 @@ TEST_CASE("Error recovery 1", "[error]") {
REQUIRE(!!pg); // OK REQUIRE(!!pg); // OK
std::vector<std::string> errors{ std::vector<std::string> errors{
R"(2:6: syntax error, unexpected '|', expecting <WORD>.)", R"(3:6: syntax error, unexpected '|', expecting <WORD>.)",
R"(4:4: syntax error, unexpected '\n', expecting <WORD>.)", R"(7:4: syntax error, unexpected '\n', expecting <WORD>.)",
R"(8:4: syntax error, unexpected '\n', expecting <WORD>.)" R"(10:1: syntax error, unexpected '[', expecting <WORD>.)",
R"(18:17: syntax error, unexpected '=', expecting <ENTRY>, <WORD>.)",
}; };
size_t i = 0; size_t i = 0;
@ -1122,16 +1123,27 @@ TEST_CASE("Error recovery 1", "[error]") {
pg.enable_ast(); pg.enable_ast();
std::shared_ptr<Ast> ast; std::shared_ptr<Ast> ast;
REQUIRE_FALSE(pg.parse(R"([Section1] REQUIRE_FALSE(pg.parse(R"([Section 1]
111 = 222 | 333
aaa || bbb aaa || bbb
ccc = ddd ccc = ddd
[Section 2]
eee eee
fff | ggg
[Section2] [Section 3
hhh | iii
fff [Section ]
ppp | qqq
ggg hhh | iii [Section 4]
jjj | kkk
lll = mmm | nnn = ooo
[Section 5]
rrr | sss
)", ast)); )", ast));
@ -1140,30 +1152,54 @@ ggg hhh | iii
REQUIRE(ast_to_s(ast) == REQUIRE(ast_to_s(ast) ==
R"(+ START R"(+ START
+ SECTION + SECTION
- HEADER/0[CATEGORY] (Section1) - HEADER/0[CATEGORY] (Section 1)
+ ENTRIES + ENTRIES
+ ENTRY/0
- ONE_WAY/0[WORD] (111)
- PHRASE/0[WORD] (222)
- PHRASE/0[WORD] (333)
+ ENTRY/2 + ENTRY/2
+ ENTRY/0 + ENTRY/0
- ONE_WAY/0[WORD] (ccc) - ONE_WAY/0[WORD] (ccc)
- PHRASE/0[WORD] (ddd) - PHRASE/0[WORD] (ddd)
+ ENTRY/2
+ SECTION + SECTION
- HEADER/0[CATEGORY] (Section2) - HEADER/0[CATEGORY] (Section 2)
+ ENTRIES + ENTRIES
+ ENTRY/2 + ENTRY/2
+ ENTRY/1 + ENTRY/1
+ PHRASE - PHRASE/0[WORD] (fff)
- WORD (ggg) - PHRASE/0[WORD] (ggg)
- WORD (hhh) + ENTRY/2
+ ENTRY/1
- PHRASE/0[WORD] (hhh)
- PHRASE/0[WORD] (iii) - PHRASE/0[WORD] (iii)
+ SECTION
- HEADER/0[CATEGORY] (Section )
+ ENTRIES
+ ENTRY/1
- PHRASE/0[WORD] (ppp)
- PHRASE/0[WORD] (qqq)
+ SECTION
- HEADER/0[CATEGORY] (Section 4)
+ ENTRIES
+ ENTRY/1
- PHRASE/0[WORD] (jjj)
- PHRASE/0[WORD] (kkk)
+ ENTRY/2
+ SECTION
- HEADER/0[CATEGORY] (Section 5)
+ ENTRIES
+ ENTRY/1
- PHRASE/0[WORD] (rrr)
- PHRASE/0[WORD] (sss)
)"); )");
} }
TEST_CASE("Error recovery 2", "[error]") { TEST_CASE("Error recovery 2", "[error]") {
parser pg(R"( parser pg(R"(
START <- ENTRY ((',' ENTRY) / %recover_to(',' / Space))* (_ / %recover_to('!.')) START <- ENTRY ((',' ENTRY) / %recover((!(',' / Space) .)+))* (_ / %recover((!'!.' .)+))
ENTRY <- '[' ITEM (',' ITEM)* ']' ENTRY <- '[' ITEM (',' ITEM)* ']'
ITEM <- WORD / NUM / %recover_to(',' / ']') ITEM <- WORD / NUM / %recover((!(',' / ']') .)+)
NUM <- [0-9]+ ![a-z] NUM <- [0-9]+ ![a-z]
WORD <- '"' [a-z]+ '"' WORD <- '"' [a-z]+ '"'
@ -1174,14 +1210,14 @@ TEST_CASE("Error recovery 2", "[error]") {
REQUIRE(!!pg); // OK REQUIRE(!!pg); // OK
std::vector<std::string> errors{ std::vector<std::string> errors{
R"(1:6: syntax error, unexpected '],['.)", R"(1:6: syntax error, unexpected ']'.)",
R"(1:18: syntax error, unexpected 'z', expecting <NUM>.)", R"(1:18: syntax error, unexpected 'z', expecting <NUM>.)",
R"(1:24: syntax error, unexpected ',"', expecting <WORD>.)", R"(1:24: syntax error, unexpected ',', expecting <WORD>.)",
R"(1:31: syntax error, unexpected 'ccc', expecting <NUM>.)", R"(1:31: syntax error, unexpected 'ccc', expecting <NUM>.)",
R"(1:38: syntax error, unexpected 'ddd', expecting <NUM>.)", R"(1:38: syntax error, unexpected 'ddd', expecting <NUM>.)",
R"(1:55: syntax error, unexpected '],[', expecting <WORD>.)", R"(1:55: syntax error, unexpected ']', expecting <WORD>.)",
R"(1:58: syntax error, unexpected '\n', expecting <NUM>.)", R"(1:58: syntax error, unexpected '\n', expecting <NUM>.)",
R"(1:56: syntax error, unexpected ',[', expecting <Space>.)", R"(1:56: syntax error, unexpected ',', expecting <Space>.)",
}; };
size_t i = 0; size_t i = 0;