diff --git a/README.md b/README.md index b779b73..3c24156 100644 --- a/README.md +++ b/README.md @@ -115,9 +115,9 @@ auto grammar = R"( 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"; -}; +}); auto ok = parser.load_grammar(grammar); 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 -------------------- diff --git a/docs/native.cpp b/docs/native.cpp index b36fbd1..4777274 100644 --- a/docs/native.cpp +++ b/docs/native.cpp @@ -18,11 +18,10 @@ std::string escape_json(const std::string &s) { return o.str(); } -std::function +std::function makeJSONFormatter(std::string &json, bool &init) { init = true; - return [&](size_t ln, size_t col, const std::string &msg, - const std::string &) mutable { + return [&](size_t ln, size_t col, const std::string &msg) mutable { if (!init) { json += ","; } json += "{"; 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, std::string &json) { bool init; - peg.log = makeJSONFormatter(json, init); + peg.set_logger(makeJSONFormatter(json, init)); json += "["; auto ret = peg.load_grammar(text.data(), text.size()); json += "]"; @@ -48,7 +47,7 @@ bool parse_code(const std::string &text, peg::parser &peg, std::string &json, std::shared_ptr &ast) { peg.enable_ast(); bool init; - peg.log = makeJSONFormatter(json, init); + peg.set_logger(makeJSONFormatter(json, init)); json += "["; auto ret = peg.parse_n(text.data(), text.size(), ast); json += "]"; diff --git a/docs/native.wasm b/docs/native.wasm index 026a48a..c11f203 100755 Binary files a/docs/native.wasm and b/docs/native.wasm differ diff --git a/lint/peglint.cc b/lint/peglint.cc index bea46b5..0479883 100644 --- a/lint/peglint.cc +++ b/lint/peglint.cc @@ -105,10 +105,9 @@ int main(int argc, const char **argv) { peg::parser parser; - parser.log = [&](size_t ln, size_t col, const string &msg, - const string & /*rule*/) { + parser.set_logger([&](size_t ln, size_t col, const string &msg) { cerr << syntax_path << ":" << ln << ":" << col << ": " << msg << endl; - }; + }); 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]; } - parser.log = [&](size_t ln, size_t col, const string &msg, - const string & /*rule*/) { + parser.set_logger([&](size_t ln, size_t col, const string &msg) { cerr << source_path << ":" << ln << ":" << col << ": " << msg << endl; - }; + }); if (opt_packrat) { parser.enable_packrat_parsing(); } diff --git a/peglib.h b/peglib.h index 84bf481..0591b1f 100644 --- a/peglib.h +++ b/peglib.h @@ -2504,8 +2504,7 @@ inline std::pair SemanticValues::line_info() const { return c_->line_info(sv_.data()); } -inline void ErrorInfo::output_log(const Log &log, const char *s, - size_t n) { +inline void ErrorInfo::output_log(const Log &log, const char *s, size_t n) { if (message_pos) { if (message_pos > last_output_pos) { last_output_pos = message_pos; @@ -4443,8 +4442,8 @@ public: operator bool() { return grammar_ != nullptr; } bool load_grammar(const char *s, size_t n, const Rules &rules) { - grammar_ = - ParserGenerator::parse(s, n, rules, start_, enablePackratParsing_, log); + grammar_ = ParserGenerator::parse(s, n, rules, start_, + enablePackratParsing_, log_); return grammar_ != nullptr; } @@ -4463,7 +4462,7 @@ public: bool parse_n(const char *s, size_t n, const char *path = nullptr) const { if (grammar_ != nullptr) { 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 false; @@ -4473,7 +4472,7 @@ public: const char *path = nullptr) const { if (grammar_ != nullptr) { 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 false; @@ -4484,7 +4483,7 @@ public: const char *path = nullptr) const { if (grammar_ != nullptr) { 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 false; @@ -4496,7 +4495,7 @@ public: if (grammar_ != nullptr) { const auto &rule = (*grammar_)[start_]; 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; } @@ -4612,12 +4611,18 @@ public: 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 + log) { + log_ = [&](size_t line, size_t col, const std::string &msg, + const std::string & /*rule*/) { log(line, col, msg); }; + } private: - bool post_process(const char *s, size_t n, - Definition::Result &r) const { - if (log && !r.ret) { r.error_info.output_log(log, s, n); } + bool post_process(const char *s, size_t n, Definition::Result &r) const { + if (log_ && !r.ret) { r.error_info.output_log(log_, s, n); } return r.ret && !r.recovered; } @@ -4632,6 +4637,7 @@ private: std::shared_ptr grammar_; std::string start_; bool enablePackratParsing_ = false; + Log log_; }; /*----------------------------------------------------------------------------- diff --git a/test/test1.cc b/test/test1.cc index a3e4303..3139dda 100644 --- a/test/test1.cc +++ b/test/test1.cc @@ -247,12 +247,11 @@ TEST(GeneralTest, enter_leave_handlers_test) { 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, - const std::string & /*rule*/) { + parser.set_logger([&](size_t ln, size_t col, const std::string &msg) { EXPECT_EQ(1, ln); EXPECT_EQ(7, col); EXPECT_EQ(message, msg); - }; + }); 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'"} )"); - 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(6, col); EXPECT_EQ("invalid/missing enum type, expected one of 'sequence' or " "'bitmask', got 'sequencer'", msg); - }; + }); auto ret = parser.parse("enum sequencer"); EXPECT_FALSE(ret); diff --git a/test/test2.cc b/test/test2.cc index c0fc84e..57bd7cd 100644 --- a/test/test2.cc +++ b/test/test2.cc @@ -853,12 +853,11 @@ TEST(PredicateTest, Semantic_predicate_test) { EXPECT_TRUE(parser.parse("100", val)); EXPECT_EQ(100, val); - parser.log = [](size_t line, size_t col, const std::string &msg, - const std::string & /*rule*/) { + parser.set_logger([](size_t line, size_t col, const std::string &msg) { EXPECT_EQ(1, line); EXPECT_EQ(1, col); EXPECT_EQ("value error!!", msg); - }; + }); EXPECT_FALSE(parser.parse("200", val)); } @@ -879,12 +878,11 @@ is_symbol <- Name { check_symbol var_table } ref aaa ref bbb )"; - parser.log = [](size_t line, size_t col, const std::string &msg, - const std::string & /*rule*/) { + parser.set_logger([](size_t line, size_t col, const std::string &msg) { EXPECT_EQ(3, line); EXPECT_EQ(5, col); EXPECT_EQ("'bbb' doesn't exist.", msg); - }; + }); EXPECT_FALSE(parser.parse(source)); } @@ -893,12 +891,11 @@ ref bbb ref aaa decl aaa )"; - parser.log = [](size_t line, size_t col, const std::string &msg, - const std::string & /*rule*/) { + parser.set_logger([](size_t line, size_t col, const std::string &msg) { EXPECT_EQ(3, line); EXPECT_EQ(6, col); EXPECT_EQ("'aaa' already exists.", msg); - }; + }); EXPECT_FALSE(parser.parse(source)); } } @@ -966,12 +963,11 @@ typedef __off64_t __loff_t; typedef long __off64_t; typedef __off64_T __loff_t; )"; - parser.log = [](size_t line, size_t col, const std::string &msg, - const std::string & /*rule*/) { + parser.set_logger([](size_t line, size_t col, const std::string &msg) { EXPECT_EQ(3, line); EXPECT_EQ(9, col); EXPECT_EQ("'__off64_T' doesn't exist.", msg); - }; + }); EXPECT_FALSE(parser.parse(source)); } @@ -981,12 +977,11 @@ 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, - const std::string & /*rule*/) { + parser.set_logger([](size_t line, size_t col, const std::string &msg) { EXPECT_EQ(4, line); EXPECT_EQ(19, col); EXPECT_EQ("'__loff_t' already exists.", msg); - }; + }); EXPECT_FALSE(parser.parse(source)); } } @@ -1034,12 +1029,11 @@ is_symbol <- < Name > ref aaa ref bbb )"; - parser.log = [](size_t line, size_t col, const std::string &msg, - const std::string & /*rule*/) { + parser.set_logger([](size_t line, size_t col, const std::string &msg) { EXPECT_EQ(3, line); EXPECT_EQ(5, col); EXPECT_EQ("'bbb' doesn't exist.", msg); - }; + }); std::shared_ptr ast; dic.clear(); EXPECT_FALSE(parser.parse(source, ast)); @@ -1050,13 +1044,12 @@ ref bbb ref aaa decl aaa )"; - parser.log = [](size_t line, size_t col, const std::string &msg, - const std::string & /*rule*/) { + parser.set_logger([](size_t line, size_t col, const std::string &msg) { std::cerr << line << ":" << col << ": " << msg << "\n"; EXPECT_EQ(3, line); EXPECT_EQ(6, col); EXPECT_EQ("'aaa' already exists.", msg); - }; + }); std::shared_ptr ast; dic.clear(); EXPECT_FALSE(parser.parse(source, ast)); @@ -1452,12 +1445,11 @@ TEST(ErrorTest, Default_error_handling_1) { }; size_t i = 0; - pg.log = [&](size_t ln, size_t col, const std::string &msg, - const std::string & /*rule*/) { + pg.set_logger([&](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(" @ aaa typo ")); EXPECT_EQ(i, errors.size()); @@ -1479,12 +1471,11 @@ TEST(ErrorTest, Default_error_handling_2) { }; size_t i = 0; - pg.log = [&](size_t ln, size_t col, const std::string &msg, - const std::string & /*rule*/) { + pg.set_logger([&](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(" @ aaa typo ")); EXPECT_EQ(i, errors.size()); @@ -1524,12 +1515,11 @@ TEST(ErrorTest, Default_error_handling_fiblang) { }; size_t i = 0; - pg.log = [&](size_t ln, size_t col, const std::string &msg, - const std::string & /*rule*/) { + pg.set_logger([&](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) @@ -1582,12 +1572,11 @@ entry <- (!(__ / HEADER) .)+ { error_message "invalid entry." } }; size_t i = 0; - pg.log = [&](size_t ln, size_t col, const std::string &msg, - const std::string & /*rule*/) { + pg.set_logger([&](size_t ln, size_t col, const std::string &msg) { std::stringstream ss; ss << ln << ":" << col << ": " << msg; EXPECT_EQ(errors[i++], ss.str()); - }; + }); pg.enable_ast(); @@ -1647,12 +1636,11 @@ TEST(ErrorTest, Error_recovery_2) { }; size_t i = 0; - pg.log = [&](size_t ln, size_t col, const std::string &msg, - const std::string & /*rule*/) { + pg.set_logger([&](size_t ln, size_t col, const std::string &msg) { std::stringstream ss; ss << ln << ":" << col << ": " << msg; EXPECT_EQ(errors[i++], ss.str()); - }; + }); pg.enable_ast(); @@ -1735,12 +1723,11 @@ skip_puncs <- [|=]* _ }; size_t i = 0; - pg.log = [&](size_t ln, size_t col, const std::string &msg, - const std::string & /*rule*/) { + pg.set_logger([&](size_t ln, size_t col, const std::string &msg) { std::stringstream ss; ss << ln << ":" << col << ": " << msg; EXPECT_EQ(errors[i++], ss.str()); - }; + }); pg.enable_ast(); @@ -1849,12 +1836,11 @@ SkipToRCUR ← (!RCUR (LCUR SkipToRCUR / .))* RCUR }; size_t i = 0; - pg.log = [&](size_t ln, size_t col, const std::string &msg, - const std::string & /*rule*/) { + pg.set_logger([&](size_t ln, size_t col, const std::string &msg) { std::stringstream ss; ss << ln << ":" << col << ": " << msg; EXPECT_EQ(errors[i++], ss.str()); - }; + }); pg.enable_ast(); @@ -1899,12 +1885,11 @@ STR <- < [a-z0-9]+ > }; size_t i = 0; - pg.log = [&](size_t ln, size_t col, const std::string &msg, - const std::string & /*rule*/) { + pg.set_logger([&](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"(1 = ah 2 = b @@ -2019,12 +2004,12 @@ expr <- 'hello' }; size_t i = 0; - pg.log = [&](size_t ln, size_t col, const std::string &msg, - const std::string & /*rule*/) { + pg.set_logger([&](size_t ln, size_t col, const std::string &msg, const std::string &rule) { std::stringstream ss; ss << ln << ":" << col << ": " << msg; EXPECT_EQ(errors[i++], ss.str()); + EXPECT_EQ("unterminated_comment", rule); EXPECT_EQ(4, locations.size()); EXPECT_EQ(1, locations[0].first); EXPECT_EQ(1, locations[0].second); @@ -2034,7 +2019,7 @@ expr <- 'hello' EXPECT_EQ(3, locations[2].second); EXPECT_EQ(4, locations[3].first); EXPECT_EQ(4, locations[3].second); - }; + }); EXPECT_FALSE(pg.parse(R"(/* line 1:1 is the first comment open /* line 2:2 is the second