Added set_logger

This commit is contained in:
yhirose 2022-09-03 08:12:12 -04:00
parent e5be920106
commit 66e5412b14
7 changed files with 77 additions and 78 deletions

View File

@ -115,9 +115,9 @@ auto grammar = R"(
parser parser; parser parser;
parser.log = [](size_t line, size_t col, const string& msg, const string &rule) { parser.set_logger([](size_t line, size_t col, const string& msg, const string &rule) {
cerr << line << ":" << col << ": " << msg << "\n"; cerr << line << ":" << col << ": " << msg << "\n";
}; });
auto ok = parser.load_grammar(grammar); auto ok = parser.load_grammar(grammar);
assert(ok); assert(ok);
@ -260,6 +260,18 @@ parser["RULE"].leave = [](const char* s, size_t n, size_t matchlen, any& value,
}; };
``` ```
You can receive error information via a logger:
```cpp
parser.set_logger([](size_t line, size_t col, const string& msg) {
...
});
parser.set_logger([](size_t line, size_t col, const string& msg, const string &rule) {
...
});
```
Ignoring Whitespaces Ignoring Whitespaces
-------------------- --------------------

View File

@ -18,11 +18,10 @@ std::string escape_json(const std::string &s) {
return o.str(); return o.str();
} }
std::function<void(size_t, size_t, const std::string &, const std::string &)> std::function<void(size_t, size_t, const std::string &)>
makeJSONFormatter(std::string &json, bool &init) { makeJSONFormatter(std::string &json, bool &init) {
init = true; init = true;
return [&](size_t ln, size_t col, const std::string &msg, return [&](size_t ln, size_t col, const std::string &msg) mutable {
const std::string &) mutable {
if (!init) { json += ","; } if (!init) { json += ","; }
json += "{"; json += "{";
json += R"("ln":)" + std::to_string(ln) + ","; json += R"("ln":)" + std::to_string(ln) + ",";
@ -37,7 +36,7 @@ makeJSONFormatter(std::string &json, bool &init) {
bool parse_grammar(const std::string &text, peg::parser &peg, bool parse_grammar(const std::string &text, peg::parser &peg,
std::string &json) { std::string &json) {
bool init; bool init;
peg.log = makeJSONFormatter(json, init); peg.set_logger(makeJSONFormatter(json, init));
json += "["; json += "[";
auto ret = peg.load_grammar(text.data(), text.size()); auto ret = peg.load_grammar(text.data(), text.size());
json += "]"; json += "]";
@ -48,7 +47,7 @@ bool parse_code(const std::string &text, peg::parser &peg, std::string &json,
std::shared_ptr<peg::Ast> &ast) { std::shared_ptr<peg::Ast> &ast) {
peg.enable_ast(); peg.enable_ast();
bool init; bool init;
peg.log = makeJSONFormatter(json, init); peg.set_logger(makeJSONFormatter(json, init));
json += "["; json += "[";
auto ret = peg.parse_n(text.data(), text.size(), ast); auto ret = peg.parse_n(text.data(), text.size(), ast);
json += "]"; json += "]";

Binary file not shown.

View File

@ -105,10 +105,9 @@ int main(int argc, const char **argv) {
peg::parser parser; peg::parser parser;
parser.log = [&](size_t ln, size_t col, const string &msg, parser.set_logger([&](size_t ln, size_t col, const string &msg) {
const string & /*rule*/) {
cerr << syntax_path << ":" << ln << ":" << col << ": " << msg << endl; cerr << syntax_path << ":" << ln << ":" << col << ": " << msg << endl;
}; });
if (!parser.load_grammar(syntax.data(), syntax.size())) { return -1; } if (!parser.load_grammar(syntax.data(), syntax.size())) { return -1; }
@ -124,10 +123,9 @@ int main(int argc, const char **argv) {
source_path = path_list[1]; source_path = path_list[1];
} }
parser.log = [&](size_t ln, size_t col, const string &msg, parser.set_logger([&](size_t ln, size_t col, const string &msg) {
const string & /*rule*/) {
cerr << source_path << ":" << ln << ":" << col << ": " << msg << endl; cerr << source_path << ":" << ln << ":" << col << ": " << msg << endl;
}; });
if (opt_packrat) { parser.enable_packrat_parsing(); } if (opt_packrat) { parser.enable_packrat_parsing(); }

View File

@ -2504,8 +2504,7 @@ inline std::pair<size_t, size_t> SemanticValues::line_info() const {
return c_->line_info(sv_.data()); return c_->line_info(sv_.data());
} }
inline void ErrorInfo::output_log(const Log &log, const char *s, inline void ErrorInfo::output_log(const Log &log, const char *s, size_t n) {
size_t n) {
if (message_pos) { if (message_pos) {
if (message_pos > last_output_pos) { if (message_pos > last_output_pos) {
last_output_pos = message_pos; last_output_pos = message_pos;
@ -4443,8 +4442,8 @@ public:
operator bool() { return grammar_ != nullptr; } operator bool() { return grammar_ != nullptr; }
bool load_grammar(const char *s, size_t n, const Rules &rules) { bool load_grammar(const char *s, size_t n, const Rules &rules) {
grammar_ = grammar_ = ParserGenerator::parse(s, n, rules, start_,
ParserGenerator::parse(s, n, rules, start_, enablePackratParsing_, log); enablePackratParsing_, log_);
return grammar_ != nullptr; return grammar_ != nullptr;
} }
@ -4463,7 +4462,7 @@ public:
bool parse_n(const char *s, size_t n, const char *path = nullptr) const { bool parse_n(const char *s, size_t n, const char *path = nullptr) const {
if (grammar_ != nullptr) { if (grammar_ != nullptr) {
const auto &rule = (*grammar_)[start_]; const auto &rule = (*grammar_)[start_];
auto result = rule.parse(s, n, path, log); auto result = rule.parse(s, n, path, log_);
return post_process(s, n, result); return post_process(s, n, result);
} }
return false; return false;
@ -4473,7 +4472,7 @@ public:
const char *path = nullptr) const { const char *path = nullptr) const {
if (grammar_ != nullptr) { if (grammar_ != nullptr) {
const auto &rule = (*grammar_)[start_]; const auto &rule = (*grammar_)[start_];
auto result = rule.parse(s, n, dt, path, log); auto result = rule.parse(s, n, dt, path, log_);
return post_process(s, n, result); return post_process(s, n, result);
} }
return false; return false;
@ -4484,7 +4483,7 @@ public:
const char *path = nullptr) const { const char *path = nullptr) const {
if (grammar_ != nullptr) { if (grammar_ != nullptr) {
const auto &rule = (*grammar_)[start_]; const auto &rule = (*grammar_)[start_];
auto result = rule.parse_and_get_value(s, n, val, path, log); auto result = rule.parse_and_get_value(s, n, val, path, log_);
return post_process(s, n, result); return post_process(s, n, result);
} }
return false; return false;
@ -4496,7 +4495,7 @@ public:
if (grammar_ != nullptr) { if (grammar_ != nullptr) {
const auto &rule = (*grammar_)[start_]; const auto &rule = (*grammar_)[start_];
return post_process(s, n, return post_process(s, n,
rule.parse_and_get_value(s, n, dt, val, path, log)); rule.parse_and_get_value(s, n, dt, val, path, log_));
} }
return false; return false;
} }
@ -4612,12 +4611,18 @@ public:
return AstOptimizer(opt_mode, get_no_ast_opt_rules()).optimize(ast); return AstOptimizer(opt_mode, get_no_ast_opt_rules()).optimize(ast);
} }
Log log; void set_logger(Log log) { log_ = log; }
void set_logger(
std::function<void(size_t line, size_t col, const std::string &msg)>
log) {
log_ = [&](size_t line, size_t col, const std::string &msg,
const std::string & /*rule*/) { log(line, col, msg); };
}
private: private:
bool post_process(const char *s, size_t n, bool post_process(const char *s, size_t n, Definition::Result &r) const {
Definition::Result &r) const { if (log_ && !r.ret) { r.error_info.output_log(log_, s, n); }
if (log && !r.ret) { r.error_info.output_log(log, s, n); }
return r.ret && !r.recovered; return r.ret && !r.recovered;
} }
@ -4632,6 +4637,7 @@ private:
std::shared_ptr<Grammar> grammar_; std::shared_ptr<Grammar> grammar_;
std::string start_; std::string start_;
bool enablePackratParsing_ = false; bool enablePackratParsing_ = false;
Log log_;
}; };
/*----------------------------------------------------------------------------- /*-----------------------------------------------------------------------------

View File

@ -247,12 +247,11 @@ TEST(GeneralTest, enter_leave_handlers_test) {
EXPECT_TRUE(parser.parse("hello=WORLD", dt)); EXPECT_TRUE(parser.parse("hello=WORLD", dt));
EXPECT_TRUE(parser.parse("HELLO=WORLD", dt)); EXPECT_TRUE(parser.parse("HELLO=WORLD", dt));
parser.log = [&](size_t ln, size_t col, const std::string &msg, parser.set_logger([&](size_t ln, size_t col, const std::string &msg) {
const std::string & /*rule*/) {
EXPECT_EQ(1, ln); EXPECT_EQ(1, ln);
EXPECT_EQ(7, col); EXPECT_EQ(7, col);
EXPECT_EQ(message, msg); EXPECT_EQ(message, msg);
}; });
parser.parse("hello=world", dt); parser.parse("hello=world", dt);
} }
@ -1091,13 +1090,13 @@ TEST(GeneralTest, HeuristicErrorTokenTest) {
untyped_enum <- '' { message "invalid/missing enum type, expected one of 'sequence' or 'bitmask', got '%t'"} untyped_enum <- '' { message "invalid/missing enum type, expected one of 'sequence' or 'bitmask', got '%t'"}
)"); )");
parser.log = [&](size_t ln, size_t col, const std::string &msg, const std::string & /*rule*/) { parser.set_logger([&](size_t ln, size_t col, const std::string &msg) {
EXPECT_EQ(1, ln); EXPECT_EQ(1, ln);
EXPECT_EQ(6, col); EXPECT_EQ(6, col);
EXPECT_EQ("invalid/missing enum type, expected one of 'sequence' or " EXPECT_EQ("invalid/missing enum type, expected one of 'sequence' or "
"'bitmask', got 'sequencer'", "'bitmask', got 'sequencer'",
msg); msg);
}; });
auto ret = parser.parse("enum sequencer"); auto ret = parser.parse("enum sequencer");
EXPECT_FALSE(ret); EXPECT_FALSE(ret);

View File

@ -853,12 +853,11 @@ TEST(PredicateTest, Semantic_predicate_test) {
EXPECT_TRUE(parser.parse("100", val)); EXPECT_TRUE(parser.parse("100", val));
EXPECT_EQ(100, val); EXPECT_EQ(100, val);
parser.log = [](size_t line, size_t col, const std::string &msg, parser.set_logger([](size_t line, size_t col, const std::string &msg) {
const std::string & /*rule*/) {
EXPECT_EQ(1, line); EXPECT_EQ(1, line);
EXPECT_EQ(1, col); EXPECT_EQ(1, col);
EXPECT_EQ("value error!!", msg); EXPECT_EQ("value error!!", msg);
}; });
EXPECT_FALSE(parser.parse("200", val)); EXPECT_FALSE(parser.parse("200", val));
} }
@ -879,12 +878,11 @@ is_symbol <- Name { check_symbol var_table }
ref aaa ref aaa
ref bbb ref bbb
)"; )";
parser.log = [](size_t line, size_t col, const std::string &msg, parser.set_logger([](size_t line, size_t col, const std::string &msg) {
const std::string & /*rule*/) {
EXPECT_EQ(3, line); EXPECT_EQ(3, line);
EXPECT_EQ(5, col); EXPECT_EQ(5, col);
EXPECT_EQ("'bbb' doesn't exist.", msg); EXPECT_EQ("'bbb' doesn't exist.", msg);
}; });
EXPECT_FALSE(parser.parse(source)); EXPECT_FALSE(parser.parse(source));
} }
@ -893,12 +891,11 @@ ref bbb
ref aaa ref aaa
decl aaa decl aaa
)"; )";
parser.log = [](size_t line, size_t col, const std::string &msg, parser.set_logger([](size_t line, size_t col, const std::string &msg) {
const std::string & /*rule*/) {
EXPECT_EQ(3, line); EXPECT_EQ(3, line);
EXPECT_EQ(6, col); EXPECT_EQ(6, col);
EXPECT_EQ("'aaa' already exists.", msg); EXPECT_EQ("'aaa' already exists.", msg);
}; });
EXPECT_FALSE(parser.parse(source)); EXPECT_FALSE(parser.parse(source));
} }
} }
@ -966,12 +963,11 @@ typedef __off64_t __loff_t;
typedef long __off64_t; typedef long __off64_t;
typedef __off64_T __loff_t; typedef __off64_T __loff_t;
)"; )";
parser.log = [](size_t line, size_t col, const std::string &msg, parser.set_logger([](size_t line, size_t col, const std::string &msg) {
const std::string & /*rule*/) {
EXPECT_EQ(3, line); EXPECT_EQ(3, line);
EXPECT_EQ(9, col); EXPECT_EQ(9, col);
EXPECT_EQ("'__off64_T' doesn't exist.", msg); EXPECT_EQ("'__off64_T' doesn't exist.", msg);
}; });
EXPECT_FALSE(parser.parse(source)); EXPECT_FALSE(parser.parse(source));
} }
@ -981,12 +977,11 @@ typedef long __off64_t;
typedef __off64_t __loff_t; typedef __off64_t __loff_t;
typedef __off64_t __loff_t; typedef __off64_t __loff_t;
)"; )";
parser.log = [](size_t line, size_t col, const std::string &msg, parser.set_logger([](size_t line, size_t col, const std::string &msg) {
const std::string & /*rule*/) {
EXPECT_EQ(4, line); EXPECT_EQ(4, line);
EXPECT_EQ(19, col); EXPECT_EQ(19, col);
EXPECT_EQ("'__loff_t' already exists.", msg); EXPECT_EQ("'__loff_t' already exists.", msg);
}; });
EXPECT_FALSE(parser.parse(source)); EXPECT_FALSE(parser.parse(source));
} }
} }
@ -1034,12 +1029,11 @@ is_symbol <- < Name >
ref aaa ref aaa
ref bbb ref bbb
)"; )";
parser.log = [](size_t line, size_t col, const std::string &msg, parser.set_logger([](size_t line, size_t col, const std::string &msg) {
const std::string & /*rule*/) {
EXPECT_EQ(3, line); EXPECT_EQ(3, line);
EXPECT_EQ(5, col); EXPECT_EQ(5, col);
EXPECT_EQ("'bbb' doesn't exist.", msg); EXPECT_EQ("'bbb' doesn't exist.", msg);
}; });
std::shared_ptr<Ast> ast; std::shared_ptr<Ast> ast;
dic.clear(); dic.clear();
EXPECT_FALSE(parser.parse(source, ast)); EXPECT_FALSE(parser.parse(source, ast));
@ -1050,13 +1044,12 @@ ref bbb
ref aaa ref aaa
decl aaa decl aaa
)"; )";
parser.log = [](size_t line, size_t col, const std::string &msg, parser.set_logger([](size_t line, size_t col, const std::string &msg) {
const std::string & /*rule*/) {
std::cerr << line << ":" << col << ": " << msg << "\n"; std::cerr << line << ":" << col << ": " << msg << "\n";
EXPECT_EQ(3, line); EXPECT_EQ(3, line);
EXPECT_EQ(6, col); EXPECT_EQ(6, col);
EXPECT_EQ("'aaa' already exists.", msg); EXPECT_EQ("'aaa' already exists.", msg);
}; });
std::shared_ptr<Ast> ast; std::shared_ptr<Ast> ast;
dic.clear(); dic.clear();
EXPECT_FALSE(parser.parse(source, ast)); EXPECT_FALSE(parser.parse(source, ast));
@ -1452,12 +1445,11 @@ TEST(ErrorTest, Default_error_handling_1) {
}; };
size_t i = 0; size_t i = 0;
pg.log = [&](size_t ln, size_t col, const std::string &msg, pg.set_logger([&](size_t ln, size_t col, const std::string &msg) {
const std::string & /*rule*/) {
std::stringstream ss; std::stringstream ss;
ss << ln << ":" << col << ": " << msg; ss << ln << ":" << col << ": " << msg;
EXPECT_EQ(errors[i++], ss.str()); EXPECT_EQ(errors[i++], ss.str());
}; });
EXPECT_FALSE(pg.parse(" @ aaa typo ")); EXPECT_FALSE(pg.parse(" @ aaa typo "));
EXPECT_EQ(i, errors.size()); EXPECT_EQ(i, errors.size());
@ -1479,12 +1471,11 @@ TEST(ErrorTest, Default_error_handling_2) {
}; };
size_t i = 0; size_t i = 0;
pg.log = [&](size_t ln, size_t col, const std::string &msg, pg.set_logger([&](size_t ln, size_t col, const std::string &msg) {
const std::string & /*rule*/) {
std::stringstream ss; std::stringstream ss;
ss << ln << ":" << col << ": " << msg; ss << ln << ":" << col << ": " << msg;
EXPECT_EQ(errors[i++], ss.str()); EXPECT_EQ(errors[i++], ss.str());
}; });
EXPECT_FALSE(pg.parse(" @ aaa typo ")); EXPECT_FALSE(pg.parse(" @ aaa typo "));
EXPECT_EQ(i, errors.size()); EXPECT_EQ(i, errors.size());
@ -1524,12 +1515,11 @@ TEST(ErrorTest, Default_error_handling_fiblang) {
}; };
size_t i = 0; size_t i = 0;
pg.log = [&](size_t ln, size_t col, const std::string &msg, pg.set_logger([&](size_t ln, size_t col, const std::string &msg) {
const std::string & /*rule*/) {
std::stringstream ss; std::stringstream ss;
ss << ln << ":" << col << ": " << msg; ss << ln << ":" << col << ": " << msg;
EXPECT_EQ(errors[i++], ss.str()); EXPECT_EQ(errors[i++], ss.str());
}; });
EXPECT_FALSE(pg.parse(R"(def fib(x) EXPECT_FALSE(pg.parse(R"(def fib(x)
x < 2 ? 1 : fib(x - 2) + fib(x - 1) x < 2 ? 1 : fib(x - 2) + fib(x - 1)
@ -1582,12 +1572,11 @@ entry <- (!(__ / HEADER) .)+ { error_message "invalid entry." }
}; };
size_t i = 0; size_t i = 0;
pg.log = [&](size_t ln, size_t col, const std::string &msg, pg.set_logger([&](size_t ln, size_t col, const std::string &msg) {
const std::string & /*rule*/) {
std::stringstream ss; std::stringstream ss;
ss << ln << ":" << col << ": " << msg; ss << ln << ":" << col << ": " << msg;
EXPECT_EQ(errors[i++], ss.str()); EXPECT_EQ(errors[i++], ss.str());
}; });
pg.enable_ast(); pg.enable_ast();
@ -1647,12 +1636,11 @@ TEST(ErrorTest, Error_recovery_2) {
}; };
size_t i = 0; size_t i = 0;
pg.log = [&](size_t ln, size_t col, const std::string &msg, pg.set_logger([&](size_t ln, size_t col, const std::string &msg) {
const std::string & /*rule*/) {
std::stringstream ss; std::stringstream ss;
ss << ln << ":" << col << ": " << msg; ss << ln << ":" << col << ": " << msg;
EXPECT_EQ(errors[i++], ss.str()); EXPECT_EQ(errors[i++], ss.str());
}; });
pg.enable_ast(); pg.enable_ast();
@ -1735,12 +1723,11 @@ skip_puncs <- [|=]* _
}; };
size_t i = 0; size_t i = 0;
pg.log = [&](size_t ln, size_t col, const std::string &msg, pg.set_logger([&](size_t ln, size_t col, const std::string &msg) {
const std::string & /*rule*/) {
std::stringstream ss; std::stringstream ss;
ss << ln << ":" << col << ": " << msg; ss << ln << ":" << col << ": " << msg;
EXPECT_EQ(errors[i++], ss.str()); EXPECT_EQ(errors[i++], ss.str());
}; });
pg.enable_ast(); pg.enable_ast();
@ -1849,12 +1836,11 @@ SkipToRCUR ← (!RCUR (LCUR SkipToRCUR / .))* RCUR
}; };
size_t i = 0; size_t i = 0;
pg.log = [&](size_t ln, size_t col, const std::string &msg, pg.set_logger([&](size_t ln, size_t col, const std::string &msg) {
const std::string & /*rule*/) {
std::stringstream ss; std::stringstream ss;
ss << ln << ":" << col << ": " << msg; ss << ln << ":" << col << ": " << msg;
EXPECT_EQ(errors[i++], ss.str()); EXPECT_EQ(errors[i++], ss.str());
}; });
pg.enable_ast(); pg.enable_ast();
@ -1899,12 +1885,11 @@ STR <- < [a-z0-9]+ >
}; };
size_t i = 0; size_t i = 0;
pg.log = [&](size_t ln, size_t col, const std::string &msg, pg.set_logger([&](size_t ln, size_t col, const std::string &msg) {
const std::string & /*rule*/) {
std::stringstream ss; std::stringstream ss;
ss << ln << ":" << col << ": " << msg; ss << ln << ":" << col << ": " << msg;
EXPECT_EQ(errors[i++], ss.str()); EXPECT_EQ(errors[i++], ss.str());
}; });
EXPECT_FALSE(pg.parse(R"(1 = ah EXPECT_FALSE(pg.parse(R"(1 = ah
2 = b 2 = b
@ -2019,12 +2004,12 @@ expr <- 'hello'
}; };
size_t i = 0; size_t i = 0;
pg.log = [&](size_t ln, size_t col, const std::string &msg, pg.set_logger([&](size_t ln, size_t col, const std::string &msg, const std::string &rule) {
const std::string & /*rule*/) {
std::stringstream ss; std::stringstream ss;
ss << ln << ":" << col << ": " << msg; ss << ln << ":" << col << ": " << msg;
EXPECT_EQ(errors[i++], ss.str()); EXPECT_EQ(errors[i++], ss.str());
EXPECT_EQ("unterminated_comment", rule);
EXPECT_EQ(4, locations.size()); EXPECT_EQ(4, locations.size());
EXPECT_EQ(1, locations[0].first); EXPECT_EQ(1, locations[0].first);
EXPECT_EQ(1, locations[0].second); EXPECT_EQ(1, locations[0].second);
@ -2034,7 +2019,7 @@ expr <- 'hello'
EXPECT_EQ(3, locations[2].second); EXPECT_EQ(3, locations[2].second);
EXPECT_EQ(4, locations[3].first); EXPECT_EQ(4, locations[3].first);
EXPECT_EQ(4, locations[3].second); EXPECT_EQ(4, locations[3].second);
}; });
EXPECT_FALSE(pg.parse(R"(/* line 1:1 is the first comment open EXPECT_FALSE(pg.parse(R"(/* line 1:1 is the first comment open
/* line 2:2 is the second /* line 2:2 is the second