From 3482a0846577ffdfdefcd2e9431a455ca5cd7a40 Mon Sep 17 00:00:00 2001 From: yhirose Date: Tue, 27 Aug 2019 20:08:48 -0400 Subject: [PATCH] Fix #67 --- peglib.h | 42 ++++++++++++++++++++++++++++-------------- test/test.cc | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 14 deletions(-) diff --git a/peglib.h b/peglib.h index 7192834..1ee75d2 100644 --- a/peglib.h +++ b/peglib.h @@ -432,6 +432,23 @@ inline std::pair line_info(const char* start, const char* cur) { return std::make_pair(no, col); } +/* +* String tag +*/ +#ifndef PEGLIB_NO_CONSTEXPR_SUPPORT +inline constexpr unsigned int str2tag(const char* str, int h = 0) { + return !str[h] ? 5381 : (str2tag(str, h + 1) * 33) ^ static_cast(str[h]); +} + +namespace udl { + +inline constexpr unsigned int operator "" _(const char* s, size_t) { + return str2tag(s); +} + +} +#endif + /* * Semantic values */ @@ -452,6 +469,10 @@ struct SemanticValues : protected std::vector // Definition name const std::string& name() const { return name_; } +#ifndef PEGLIB_NO_CONSTEXPR_SUPPORT + std::vector tags; +#endif + // Line number and column at which the matched string is std::pair line_info() const { return peg::line_info(ss, s_); @@ -860,6 +881,7 @@ public: auto& sv = *value_stack[value_stack_size++]; if (!sv.empty()) { sv.clear(); + sv.tags.clear(); } sv.reset(); sv.path = path; @@ -961,6 +983,7 @@ public: i += len; } sv.insert(sv.end(), chldsv.begin(), chldsv.end()); + sv.tags.insert(sv.tags.end(), chldsv.tags.begin(), chldsv.tags.end()); sv.s_ = chldsv.c_str(); sv.n_ = chldsv.length(); sv.tokens.insert(sv.tokens.end(), chldsv.tokens.begin(), chldsv.tokens.end()); @@ -1010,6 +1033,7 @@ public: auto len = rule.parse(s, n, chldsv, c, dt); if (success(len)) { sv.insert(sv.end(), chldsv.begin(), chldsv.end()); + sv.tags.insert(sv.tags.end(), chldsv.tags.begin(), chldsv.tags.end()); sv.s_ = chldsv.c_str(); sv.n_ = chldsv.length(); sv.choice_count_ = opes_.size(); @@ -1056,6 +1080,7 @@ public: } else { if (sv.size() != save_sv_size) { sv.erase(sv.begin() + static_cast(save_sv_size)); + sv.tags.erase(sv.tags.begin() + static_cast(save_sv_size)); } if (sv.tokens.size() != save_tok_size) { sv.tokens.erase(sv.tokens.begin() + static_cast(save_tok_size)); @@ -1114,6 +1139,7 @@ public: } else { if (sv.size() != save_sv_size) { sv.erase(sv.begin() + static_cast(save_sv_size)); + sv.tags.erase(sv.tags.begin() + static_cast(save_sv_size)); } if (sv.tokens.size() != save_tok_size) { sv.tokens.erase(sv.tokens.begin() + static_cast(save_tok_size)); @@ -1155,6 +1181,7 @@ public: } else { if (sv.size() != save_sv_size) { sv.erase(sv.begin() + static_cast(save_sv_size)); + sv.tags.erase(sv.tags.begin() + static_cast(save_sv_size)); } if (sv.tokens.size() != save_tok_size) { sv.tokens.erase(sv.tokens.begin() + static_cast(save_tok_size)); @@ -2278,6 +2305,7 @@ inline size_t Holder::parse(const char* s, size_t n, SemanticValues& sv, Context if (success(len)) { if (!outer_->ignoreSemanticValue) { sv.emplace_back(val); + sv.tags.emplace_back(str2tag(outer_->name.c_str())); } } else { if (outer_->error_message) { @@ -2957,20 +2985,6 @@ private: * AST *---------------------------------------------------------------------------*/ -const int AstDefaultTag = -1; - -#ifndef PEGLIB_NO_CONSTEXPR_SUPPORT -inline constexpr unsigned int str2tag(const char* str, int h = 0) { - return !str[h] ? 5381 : (str2tag(str, h + 1) * 33) ^ static_cast(str[h]); -} - -namespace udl { -inline constexpr unsigned int operator "" _(const char* s, size_t) { - return str2tag(s); -} -} -#endif - template struct AstBase : public Annotation { diff --git a/test/test.cc b/test/test.cc index f30323e..2ceb4a1 100644 --- a/test/test.cc +++ b/test/test.cc @@ -842,6 +842,51 @@ TEST_CASE("Ordered choice count 2", "[general]") parser.parse("b"); } +TEST_CASE("Semantic value tag", "[general]") +{ + parser parser(R"( + S <- A? B* C? + A <- 'a' + B <- 'b' + C <- 'c' + )"); + + { + using namespace udl; + parser["S"] = [](const SemanticValues& sv) { + REQUIRE(sv.size() == 1); + REQUIRE(sv.tags.size() == 1); + REQUIRE(sv.tags[0] == "C"_); + }; + auto ret = parser.parse("c"); + REQUIRE(ret == true); + } + + { + using namespace udl; + parser["S"] = [](const SemanticValues& sv) { + REQUIRE(sv.size() == 2); + REQUIRE(sv.tags.size() == 2); + REQUIRE(sv.tags[0] == "B"_); + REQUIRE(sv.tags[1] == "B"_); + }; + auto ret = parser.parse("bb"); + REQUIRE(ret == true); + } + + { + using namespace udl; + parser["S"] = [](const SemanticValues& sv) { + REQUIRE(sv.size() == 2); + REQUIRE(sv.tags.size() == 2); + REQUIRE(sv.tags[0] == "A"_); + REQUIRE(sv.tags[1] == "C"_); + }; + auto ret = parser.parse("ac"); + REQUIRE(ret == true); + } +} + TEST_CASE("Packrat parser test with %whitespace%", "[packrat]") { peg::parser parser(R"(