Skip to content

Commit 939ccb2

Browse files
committed
Fix #291
1 parent 6201458 commit 939ccb2

File tree

3 files changed

+42
-5
lines changed

3 files changed

+42
-5
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,14 @@ START <- 'This month is ' MONTH '.'
347347
MONTH <- 'Jan' | 'January' | 'Feb' | 'February' | '...'
348348
```
349349

350+
We are able to find which item is matched with `choice()`.
351+
352+
```cpp
353+
parser["MONTH"] = [](const SemanticValues &vs) {
354+
auto id = vs.choice();
355+
};
356+
```
357+
350358
It supports the case insensitive mode.
351359

352360
```peg

peglib.h

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -379,24 +379,26 @@ class Trie {
379379
public:
380380
Trie(const std::vector<std::string> &items, bool ignore_case)
381381
: ignore_case_(ignore_case) {
382+
size_t id = 0;
382383
for (const auto &item : items) {
383384
for (size_t len = 1; len <= item.size(); len++) {
384385
auto last = len == item.size();
385386
const auto &s = ignore_case ? to_lower(item) : item;
386387
std::string_view sv(s.data(), len);
387388
auto it = dic_.find(sv);
388389
if (it == dic_.end()) {
389-
dic_.emplace(sv, Info{last, last});
390+
dic_.emplace(sv, Info{last, last, id});
390391
} else if (last) {
391392
it->second.match = true;
392393
} else {
393394
it->second.done = false;
394395
}
395396
}
397+
id++;
396398
}
397399
}
398400

399-
size_t match(const char *text, size_t text_len) const {
401+
size_t match(const char *text, size_t text_len, size_t &id) const {
400402
size_t match_len = 0;
401403
auto done = false;
402404
size_t len = 1;
@@ -407,14 +409,19 @@ class Trie {
407409
if (it == dic_.end()) {
408410
done = true;
409411
} else {
410-
if (it->second.match) { match_len = len; }
412+
if (it->second.match) {
413+
match_len = len;
414+
id = it->second.id;
415+
}
411416
if (it->second.done) { done = true; }
412417
}
413418
len += 1;
414419
}
415420
return match_len;
416421
}
417422

423+
size_t size() const { return dic_.size(); }
424+
418425
private:
419426
std::string to_lower(std::string s) const {
420427
for (char &c : s) {
@@ -426,6 +433,7 @@ class Trie {
426433
struct Info {
427434
bool done;
428435
bool match;
436+
size_t id;
429437
};
430438

431439
// TODO: Use unordered_map when heterogeneous lookup is supported in C++20
@@ -580,6 +588,7 @@ struct SemanticValues : protected std::vector<std::any> {
580588

581589
private:
582590
friend class Context;
591+
friend class Dictionary;
583592
friend class Sequence;
584593
friend class PrioritizedChoice;
585594
friend class Repetition;
@@ -2673,12 +2682,17 @@ inline size_t Ope::parse(const char *s, size_t n, SemanticValues &vs,
26732682
inline size_t Dictionary::parse_core(const char *s, size_t n,
26742683
SemanticValues &vs, Context &c,
26752684
std::any &dt) const {
2676-
auto i = trie_.match(s, n);
2685+
size_t id;
2686+
auto i = trie_.match(s, n, id);
2687+
26772688
if (i == 0) {
26782689
c.set_error_pos(s);
26792690
return static_cast<size_t>(-1);
26802691
}
26812692

2693+
vs.choice_count_ = trie_.size();
2694+
vs.choice_ = id;
2695+
26822696
// Word check
26832697
if (c.wordOpe) {
26842698
auto save_ignore_trace_state = c.ignore_trace_state;
@@ -2792,7 +2806,8 @@ inline size_t Holder::parse_core(const char *s, size_t n, SemanticValues &vs,
27922806
auto tok_ptr = dynamic_cast<const peg::TokenBoundary *>(ope_ptr);
27932807
if (tok_ptr) { ope_ptr = tok_ptr->ope_.get(); }
27942808
}
2795-
if (!dynamic_cast<const peg::PrioritizedChoice *>(ope_ptr)) {
2809+
if (!dynamic_cast<const peg::PrioritizedChoice *>(ope_ptr) &&
2810+
!dynamic_cast<const peg::Dictionary *>(ope_ptr)) {
27962811
chvs.choice_count_ = 0;
27972812
chvs.choice_ = 0;
27982813
}

test/test2.cc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1429,6 +1429,20 @@ TEST(DicTest, Dictionary_invalid) {
14291429
EXPECT_FALSE(ret);
14301430
}
14311431

1432+
TEST(DicTest, Dictionary_index) {
1433+
parser parser(R"(
1434+
START <- 'This month is ' MONTH '.'
1435+
MONTH <- 'Jan' | 'January' | 'Feb' | 'February'
1436+
)");
1437+
1438+
parser["MONTH"] = [](const SemanticValues &vs) {
1439+
EXPECT_EQ("Feb", vs.token());
1440+
EXPECT_EQ(2, vs.choice());
1441+
};
1442+
1443+
EXPECT_TRUE(parser.parse("This month is Feb."));
1444+
}
1445+
14321446
TEST(ErrorTest, Default_error_handling_1) {
14331447
parser pg(R"(
14341448
S <- '@' A B

0 commit comments

Comments
 (0)