mirror of
https://github.com/yhirose/cpp-peglib.git
synced 2024-12-22 20:05:31 +00:00
Added semantic predicate support.
This commit is contained in:
parent
00e8290b62
commit
9765e095ab
22
README.md
22
README.md
@ -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
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
39
peglib.h
39
peglib.h
@ -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();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
45
test/test.cc
45
test/test.cc
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user