mirror of
https://github.com/yhirose/cpp-peglib.git
synced 2024-12-22 20:05:31 +00:00
Added the predicate control feature.
This commit is contained in:
parent
faa70f1f37
commit
8bac879ff9
27
README.md
27
README.md
@ -90,7 +90,7 @@ struct SemanticValue {
|
|||||||
const char* s; // Token start for the semantic value
|
const char* s; // Token start for the semantic value
|
||||||
size_t n; // Token length for the semantic value
|
size_t n; // Token length for the semantic value
|
||||||
|
|
||||||
// Utility method
|
// Utility method
|
||||||
template <typename T> T& get();
|
template <typename T> T& get();
|
||||||
template <typename T> const T& get() const;
|
template <typename T> const T& get() const;
|
||||||
std::string str() const;
|
std::string str() const;
|
||||||
@ -108,7 +108,7 @@ struct SemanticValues : protected std::vector<SemanticValue>
|
|||||||
using std::vector<T>::end;
|
using std::vector<T>::end;
|
||||||
// NOTE: There are more std::vector methods available...
|
// NOTE: There are more std::vector methods available...
|
||||||
|
|
||||||
// Transform the semantice values vector to another vector
|
// Transform the semantice values vector to another vector
|
||||||
template <typename F> auto map(size_t beg, size_t end, F f) const -> vector<typename std::remove_const<decltype(f(SemanticValue()))>::type>;
|
template <typename F> auto map(size_t beg, size_t end, F f) const -> vector<typename std::remove_const<decltype(f(SemanticValue()))>::type>;
|
||||||
template <typename F> auto map(F f) const -> vector<typename std::remove_const<decltype(f(SemanticValue()))>::type>;
|
template <typename F> auto map(F f) const -> vector<typename std::remove_const<decltype(f(SemanticValue()))>::type>;
|
||||||
template <typename T> auto map(size_t beg = 0, size_t end = -1) const -> vector<T>;
|
template <typename T> auto map(size_t beg = 0, size_t end = -1) const -> vector<T>;
|
||||||
@ -258,6 +258,29 @@ The following are available operators:
|
|||||||
| cap | Capture character |
|
| cap | Capture character |
|
||||||
| usr | User defiend parser |
|
| 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
|
Adjust definitions
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
38
peglib.h
38
peglib.h
@ -284,6 +284,11 @@ any call(F fn, Args&&... args) {
|
|||||||
return any(fn(std::forward<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
|
class Action
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -1159,14 +1164,14 @@ public:
|
|||||||
return parse_and_get_value(s, n, dt, val);
|
return parse_and_get_value(s, n, dt, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
Definition& operator=(Action ac) {
|
Definition& operator=(Action action) {
|
||||||
assert(!actions.empty());
|
assert(!actions.empty());
|
||||||
actions[0] = ac;
|
actions[0] = action;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Definition& operator=(std::initializer_list<Action> acs) {
|
Definition& operator=(std::initializer_list<Action> ini) {
|
||||||
actions = acs;
|
actions = ini;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1187,6 +1192,7 @@ public:
|
|||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
size_t id;
|
size_t id;
|
||||||
|
Predicate predicate;
|
||||||
std::vector<Action> actions;
|
std::vector<Action> actions;
|
||||||
std::function<std::string ()> error_message;
|
std::function<std::string ()> error_message;
|
||||||
bool ignoreSemanticValue;
|
bool ignoreSemanticValue;
|
||||||
@ -1221,17 +1227,20 @@ inline int Holder::parse(const char* s, size_t n, SemanticValues& sv, Context& c
|
|||||||
throw std::logic_error("Uninitialized definition ope was used...");
|
throw std::logic_error("Uninitialized definition ope was used...");
|
||||||
}
|
}
|
||||||
|
|
||||||
int len;
|
int len;
|
||||||
any val;
|
any val;
|
||||||
const char* ancs = s;
|
const char* anchors = s;
|
||||||
size_t ancn = n;
|
size_t anchorn = n;
|
||||||
|
|
||||||
c.packrat(s, outer_->id, len, val, [&](any& val) {
|
c.packrat(s, outer_->id, len, val, [&](any& val) {
|
||||||
auto& chldsv = c.push();
|
auto& chldsv = c.push();
|
||||||
|
|
||||||
const auto& rule = *ope_;
|
const auto& rule = *ope_;
|
||||||
len = rule.parse(s, n, chldsv, c, dt);
|
len = rule.parse(s, n, chldsv, c, dt);
|
||||||
ancn = len;
|
|
||||||
|
anchorn = len;
|
||||||
|
|
||||||
|
// Invoke action
|
||||||
if (success(len) && !outer_->ignoreSemanticValue) {
|
if (success(len) && !outer_->ignoreSemanticValue) {
|
||||||
assert(!outer_->actions.empty());
|
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];
|
: outer_->actions[0];
|
||||||
|
|
||||||
if (chldsv.s) {
|
if (chldsv.s) {
|
||||||
ancs = chldsv.s;
|
anchors = chldsv.s;
|
||||||
ancn = chldsv.n;
|
anchorn = chldsv.n;
|
||||||
} else {
|
} else {
|
||||||
chldsv.s = s;
|
chldsv.s = s;
|
||||||
chldsv.n = len;
|
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);
|
val = reduce(chldsv, dt, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Predicate check
|
||||||
|
if (success(len) && outer_->predicate && !outer_->predicate(anchors, anchorn, val, dt)) {
|
||||||
|
len = -1;
|
||||||
|
}
|
||||||
|
|
||||||
c.pop();
|
c.pop();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (success(len) && !outer_->ignoreSemanticValue) {
|
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) {
|
if (fail(len) && outer_->error_message && !c.message_pos) {
|
||||||
|
21
test/test.cc
21
test/test.cc
@ -422,6 +422,27 @@ TEST_CASE("Calculator test3", "[general]")
|
|||||||
REQUIRE(val == -3);
|
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) {
|
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