This commit is contained in:
yhirose 2019-08-27 20:08:48 -04:00
parent 9ee03a9211
commit 3482a08465
2 changed files with 73 additions and 14 deletions

View File

@ -432,6 +432,23 @@ inline std::pair<size_t, size_t> line_info(const char* start, const char* cur) {
return std::make_pair(no, col); 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<unsigned char>(str[h]);
}
namespace udl {
inline constexpr unsigned int operator "" _(const char* s, size_t) {
return str2tag(s);
}
}
#endif
/* /*
* Semantic values * Semantic values
*/ */
@ -452,6 +469,10 @@ struct SemanticValues : protected std::vector<any>
// Definition name // Definition name
const std::string& name() const { return name_; } const std::string& name() const { return name_; }
#ifndef PEGLIB_NO_CONSTEXPR_SUPPORT
std::vector<unsigned int> tags;
#endif
// Line number and column at which the matched string is // Line number and column at which the matched string is
std::pair<size_t, size_t> line_info() const { std::pair<size_t, size_t> line_info() const {
return peg::line_info(ss, s_); return peg::line_info(ss, s_);
@ -860,6 +881,7 @@ public:
auto& sv = *value_stack[value_stack_size++]; auto& sv = *value_stack[value_stack_size++];
if (!sv.empty()) { if (!sv.empty()) {
sv.clear(); sv.clear();
sv.tags.clear();
} }
sv.reset(); sv.reset();
sv.path = path; sv.path = path;
@ -961,6 +983,7 @@ public:
i += len; i += len;
} }
sv.insert(sv.end(), chldsv.begin(), chldsv.end()); 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.s_ = chldsv.c_str();
sv.n_ = chldsv.length(); sv.n_ = chldsv.length();
sv.tokens.insert(sv.tokens.end(), chldsv.tokens.begin(), chldsv.tokens.end()); 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); auto len = rule.parse(s, n, chldsv, c, dt);
if (success(len)) { if (success(len)) {
sv.insert(sv.end(), chldsv.begin(), chldsv.end()); 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.s_ = chldsv.c_str();
sv.n_ = chldsv.length(); sv.n_ = chldsv.length();
sv.choice_count_ = opes_.size(); sv.choice_count_ = opes_.size();
@ -1056,6 +1080,7 @@ public:
} else { } else {
if (sv.size() != save_sv_size) { if (sv.size() != save_sv_size) {
sv.erase(sv.begin() + static_cast<std::ptrdiff_t>(save_sv_size)); sv.erase(sv.begin() + static_cast<std::ptrdiff_t>(save_sv_size));
sv.tags.erase(sv.tags.begin() + static_cast<std::ptrdiff_t>(save_sv_size));
} }
if (sv.tokens.size() != save_tok_size) { if (sv.tokens.size() != save_tok_size) {
sv.tokens.erase(sv.tokens.begin() + static_cast<std::ptrdiff_t>(save_tok_size)); sv.tokens.erase(sv.tokens.begin() + static_cast<std::ptrdiff_t>(save_tok_size));
@ -1114,6 +1139,7 @@ public:
} else { } else {
if (sv.size() != save_sv_size) { if (sv.size() != save_sv_size) {
sv.erase(sv.begin() + static_cast<std::ptrdiff_t>(save_sv_size)); sv.erase(sv.begin() + static_cast<std::ptrdiff_t>(save_sv_size));
sv.tags.erase(sv.tags.begin() + static_cast<std::ptrdiff_t>(save_sv_size));
} }
if (sv.tokens.size() != save_tok_size) { if (sv.tokens.size() != save_tok_size) {
sv.tokens.erase(sv.tokens.begin() + static_cast<std::ptrdiff_t>(save_tok_size)); sv.tokens.erase(sv.tokens.begin() + static_cast<std::ptrdiff_t>(save_tok_size));
@ -1155,6 +1181,7 @@ public:
} else { } else {
if (sv.size() != save_sv_size) { if (sv.size() != save_sv_size) {
sv.erase(sv.begin() + static_cast<std::ptrdiff_t>(save_sv_size)); sv.erase(sv.begin() + static_cast<std::ptrdiff_t>(save_sv_size));
sv.tags.erase(sv.tags.begin() + static_cast<std::ptrdiff_t>(save_sv_size));
} }
if (sv.tokens.size() != save_tok_size) { if (sv.tokens.size() != save_tok_size) {
sv.tokens.erase(sv.tokens.begin() + static_cast<std::ptrdiff_t>(save_tok_size)); sv.tokens.erase(sv.tokens.begin() + static_cast<std::ptrdiff_t>(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 (success(len)) {
if (!outer_->ignoreSemanticValue) { if (!outer_->ignoreSemanticValue) {
sv.emplace_back(val); sv.emplace_back(val);
sv.tags.emplace_back(str2tag(outer_->name.c_str()));
} }
} else { } else {
if (outer_->error_message) { if (outer_->error_message) {
@ -2957,20 +2985,6 @@ private:
* AST * 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<unsigned char>(str[h]);
}
namespace udl {
inline constexpr unsigned int operator "" _(const char* s, size_t) {
return str2tag(s);
}
}
#endif
template <typename Annotation> template <typename Annotation>
struct AstBase : public Annotation struct AstBase : public Annotation
{ {

View File

@ -842,6 +842,51 @@ TEST_CASE("Ordered choice count 2", "[general]")
parser.parse("b"); 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]") TEST_CASE("Packrat parser test with %whitespace%", "[packrat]")
{ {
peg::parser parser(R"( peg::parser parser(R"(