From 5b9daaf0906f2ac45cb0639f11e71805034dc4fb Mon Sep 17 00:00:00 2001 From: yhirose Date: Tue, 17 Nov 2015 06:10:32 -0500 Subject: [PATCH] Restored before/after handlers. --- peglib.h | 42 +++++++++++++++++++++++++++++++----------- test/test.cc | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 11 deletions(-) diff --git a/peglib.h b/peglib.h index ca891fc..e3502ee 100644 --- a/peglib.h +++ b/peglib.h @@ -1182,13 +1182,15 @@ public: holder_->accept(v); } - std::string name; - size_t id; - Action action; - std::function error_message; - bool ignoreSemanticValue; - bool enablePackratParsing; - bool is_token; + std::string name; + size_t id; + Action action; + std::function before; + std::function after; + std::function error_message; + bool ignoreSemanticValue; + bool enablePackratParsing; + bool is_token; private: friend class DefinitionReference; @@ -1225,6 +1227,10 @@ inline size_t Holder::parse(const char* s, size_t n, SemanticValues& sv, Context c.packrat(s, outer_->id, len, val, [&](any& val) { auto& chldsv = c.push(); + if (outer_->before) { + outer_->before(dt); + } + const auto& rule = *ope_; len = rule.parse(s, n, chldsv, c, dt); @@ -1251,6 +1257,10 @@ inline size_t Holder::parse(const char* s, size_t n, SemanticValues& sv, Context } } + if (outer_->after) { + outer_->after(dt); + } + c.pop(); }); @@ -1793,8 +1803,13 @@ private: if (!r.ret) { if (log) { - auto line = line_info(s, r.error_pos); - log(line.first, line.second, r.message.empty() ? "syntax error" : r.message); + if (r.message_pos) { + auto line = line_info(s, r.message_pos); + log(line.first, line.second, r.message); + } else { + auto line = line_info(s, r.error_pos); + log(line.first, line.second, "syntax error"); + } } return nullptr; } @@ -2279,8 +2294,13 @@ private: void output_log(const char* s, size_t n, Log log, const Definition::Result& r) const { if (log) { if (!r.ret) { - auto line = line_info(s, r.error_pos); - log(line.first, line.second, r.message.empty() ? "syntax error" : r.message); + if (r.message_pos) { + auto line = line_info(s, r.message_pos); + log(line.first, line.second, r.message); + } else { + auto line = line_info(s, r.error_pos); + log(line.first, line.second, "syntax error"); + } } else if (r.len != n) { auto line = line_info(s, s + r.len); log(line.first, line.second, "syntax error"); diff --git a/test/test.cc b/test/test.cc index 46e3842..3b321d8 100644 --- a/test/test.cc +++ b/test/test.cc @@ -213,6 +213,48 @@ TEST_CASE("Lambda action test", "[general]") REQUIRE(ss == "hello"); } +TEST_CASE("before/after handlers test", "[general]") +{ + parser parser(R"( + START <- LTOKEN '=' RTOKEN + LTOKEN <- TOKEN + RTOKEN <- TOKEN + TOKEN <- [A-Za-z]+ + )"); + + parser["LTOKEN"].before = [&](any& dt) { + auto& require_upper_case = *dt.get(); + require_upper_case = false; + }; + parser["LTOKEN"].after = [&](any& dt) { + auto& require_upper_case = *dt.get(); + require_upper_case = true; + }; + + parser["TOKEN"] = [&](const SemanticValues& sv, any& dt) { + auto& require_upper_case = *dt.get(); + if (require_upper_case) { + const auto& s = sv.str(); + if (!std::all_of(s.begin(), s.end(), ::isupper)) { + throw parse_error("should be upper case string..."); + } + } + }; + + bool require_upper_case = false; + any dt = &require_upper_case; + REQUIRE(parser.parse("hello=world", dt) == false); + REQUIRE(parser.parse("HELLO=world", dt) == false); + REQUIRE(parser.parse("hello=WORLD", dt) == true); + REQUIRE(parser.parse("HELLO=WORLD", dt) == true); + + parser.log = [&](size_t ln, size_t col, const string& msg) { + REQUIRE(ln == 1); + REQUIRE(col == 7); + }; + parser.parse("hello=world", dt); +} + TEST_CASE("Skip token test", "[general]") { peg::parser parser(