Added the predicate control feature.

This commit is contained in:
yhirose 2015-04-08 12:02:26 -04:00
parent faa70f1f37
commit 8bac879ff9
3 changed files with 72 additions and 14 deletions

View File

@ -258,6 +258,29 @@ The following are available operators:
| cap | Capture character |
| usr | User defiend parser |
Predicate control
-----------------
```c++
peg parser("NUMBER <- [0-9]+");
parser["NUMBER"] = [](const char* s, size_t n) {
return stol(string(s, n), nullptr, 10);
};
parser["NUMBER"].predicate = [](const char* s, size_t n, const any& val, const any& dt) {
return val.get<long>() == 100;
};
long val;
auto ret = parser.parse("100", val);
assert(ret == true);
assert(val == 100);
ret = parser.parse("200", val);
assert(ret == false);
```
Adjust definitions
------------------

View File

@ -284,6 +284,11 @@ any call(F fn, Args&&... args) {
return any(fn(std::forward<Args>(args)...));
}
/*
* Predicate
*/
typedef std::function<bool(const char* s, size_t n, const any& val, const any& dt)> Predicate;
class Action
{
public:
@ -1159,14 +1164,14 @@ public:
return parse_and_get_value(s, n, dt, val);
}
Definition& operator=(Action ac) {
Definition& operator=(Action action) {
assert(!actions.empty());
actions[0] = ac;
actions[0] = action;
return *this;
}
Definition& operator=(std::initializer_list<Action> acs) {
actions = acs;
Definition& operator=(std::initializer_list<Action> ini) {
actions = ini;
return *this;
}
@ -1187,6 +1192,7 @@ public:
std::string name;
size_t id;
Predicate predicate;
std::vector<Action> actions;
std::function<std::string ()> error_message;
bool ignoreSemanticValue;
@ -1223,15 +1229,18 @@ inline int Holder::parse(const char* s, size_t n, SemanticValues& sv, Context& c
int len;
any val;
const char* ancs = s;
size_t ancn = n;
const char* anchors = s;
size_t anchorn = n;
c.packrat(s, outer_->id, len, val, [&](any& val) {
auto& chldsv = c.push();
const auto& rule = *ope_;
len = rule.parse(s, n, chldsv, c, dt);
ancn = len;
anchorn = len;
// Invoke action
if (success(len) && !outer_->ignoreSemanticValue) {
assert(!outer_->actions.empty());
@ -1241,8 +1250,8 @@ inline int Holder::parse(const char* s, size_t n, SemanticValues& sv, Context& c
: outer_->actions[0];
if (chldsv.s) {
ancs = chldsv.s;
ancn = chldsv.n;
anchors = chldsv.s;
anchorn = chldsv.n;
} else {
chldsv.s = s;
chldsv.n = len;
@ -1251,11 +1260,16 @@ inline int Holder::parse(const char* s, size_t n, SemanticValues& sv, Context& c
val = reduce(chldsv, dt, action);
}
// Predicate check
if (success(len) && outer_->predicate && !outer_->predicate(anchors, anchorn, val, dt)) {
len = -1;
}
c.pop();
});
if (success(len) && !outer_->ignoreSemanticValue) {
sv.emplace_back(val, outer_->name.c_str(), ancs, ancn);
sv.emplace_back(val, outer_->name.c_str(), anchors, anchorn);
}
if (fail(len) && outer_->error_message && !c.message_pos) {

View File

@ -422,6 +422,27 @@ TEST_CASE("Calculator test3", "[general]")
REQUIRE(val == -3);
}
TEST_CASE("Predicate test", "[general]")
{
peg parser("NUMBER <- [0-9]+");
parser["NUMBER"] = [](const char* s, size_t n) {
return stol(string(s, n), nullptr, 10);
};
parser["NUMBER"].predicate = [](const char* s, size_t n, const any& val, const any& dt) {
return val.get<long>() == 100;
};
long val;
auto ret = parser.parse("100", val);
REQUIRE(ret == true);
REQUIRE(val == 100);
ret = parser.parse("200", val);
REQUIRE(ret == false);
}
bool exact(Grammar& g, const char* d, const char* s) {
auto n = strlen(s);
auto r = g[d].parse(s, n);