Added semantic predicate support.

This commit is contained in:
yhirose 2015-06-15 16:07:25 -04:00
parent 00e8290b62
commit 9765e095ab
3 changed files with 67 additions and 39 deletions

View File

@ -166,6 +166,28 @@ peglib::peg parser(
); );
``` ```
*Semantic predicate* support is available. We can do it by throwing a `peglib::parse_error` exception in a semantic action.
```c++
peglib::peg parser("NUMBER <- [0-9]+");
parser["NUMBER"] = [](const char* s, size_t n) {
auto val = stol(string(s, n), nullptr, 10);
if (val != 100) {
throw peglib::parse_error("value error!!");
}
return val;
};
long val;
auto ret = parser.parse("100", val);
assert(ret == true);
assert(val == 100);
ret = parser.parse("200", val);
assert(ret == false);
```
Simple interface Simple interface
---------------- ----------------

View File

@ -280,13 +280,22 @@ any call(F fn, Args&&... args) {
return any(fn(std::forward<Args>(args)...)); return any(fn(std::forward<Args>(args)...));
} }
#if 0
/* /*
* Predicate * Semantic predicate
*/ */
typedef std::function<bool (const char* s, size_t n, const any& val, const any& dt)> Predicate; typedef std::function<bool (const SemanticValues& sv, const any& dt)> SemanticPredicate;
#endif
struct parse_error {
parse_error() = default;
parse_error(const char* s) : s_(s) {}
const char* what() const { return s_.empty() ? nullptr : s_.c_str(); }
private:
std::string s_;
};
/*
* Action
*/
class Action class Action
{ {
public: public:
@ -1212,9 +1221,6 @@ public:
std::string name; std::string name;
size_t id; size_t id;
#if 0
Predicate predicate;
#endif
std::vector<Action> actions; std::vector<Action> actions;
std::function<std::string ()> error_message; std::function<std::string ()> error_message;
bool ignoreSemanticValue; bool ignoreSemanticValue;
@ -1262,7 +1268,7 @@ inline size_t Holder::parse(const char* s, size_t n, SemanticValues& sv, Context
anchorn = len; anchorn = len;
// Invoke action // Invoke action
if (success(len) && !outer_->ignoreSemanticValue) { if (success(len)) {
assert(!outer_->actions.empty()); assert(!outer_->actions.empty());
auto i = chldsv.choice + 1; // Index 0 is for the default action auto i = chldsv.choice + 1; // Index 0 is for the default action
@ -1278,16 +1284,17 @@ inline size_t Holder::parse(const char* s, size_t n, SemanticValues& sv, Context
chldsv.n = len; chldsv.n = len;
} }
val = reduce(chldsv, dt, action); try {
val = reduce(chldsv, dt, action);
} catch (const parse_error& e) {
if (e.what()) {
c.message_pos = s;
c.message = e.what();
}
len = -1;
}
} }
#if 0
// Predicate check
if (success(len) && outer_->predicate && !outer_->predicate(anchors, anchorn, val, dt)) {
len = -1;
}
#endif
c.pop(); c.pop();
}); });

View File

@ -484,29 +484,6 @@ TEST_CASE("Calculator test with AST", "[general]")
REQUIRE(val == -3); REQUIRE(val == -3);
} }
#if 0
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);
}
#endif
TEST_CASE("Ignore semantic value test", "[general]") TEST_CASE("Ignore semantic value test", "[general]")
{ {
peg parser( peg parser(
@ -639,6 +616,28 @@ TEST_CASE("User rule test", "[user rule]")
REQUIRE(g.parse(" Hello BNF! ") == true); REQUIRE(g.parse(" Hello BNF! ") == true);
} }
TEST_CASE("Semantic predicate test", "[predicate]")
{
peg parser("NUMBER <- [0-9]+");
parser["NUMBER"] = [](const char* s, size_t n) {
auto val = stol(string(s, n), nullptr, 10);
if (val != 100) {
throw parse_error("value error!!");
}
return val;
};
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) { bool exact(Grammar& g, const char* d, const char* s) {
auto n = strlen(s); auto n = strlen(s);
auto r = g[d].parse(s, n); auto r = g[d].parse(s, n);