mirror of
https://github.com/yhirose/cpp-peglib.git
synced 2024-12-22 20:05:31 +00:00
Changed interface of parse in Definition.
This commit is contained in:
parent
09ce72b25e
commit
6e8ea2b471
@ -55,7 +55,7 @@ int main(int argc, const char** argv)
|
|||||||
" NUMBER <- [0-9]+ "
|
" NUMBER <- [0-9]+ "
|
||||||
;
|
;
|
||||||
|
|
||||||
Parser parser = make_parser(syntax);
|
Parser parser(syntax);
|
||||||
|
|
||||||
parser["EXPRESSION"] = reduce;
|
parser["EXPRESSION"] = reduce;
|
||||||
parser["TERM"] = reduce;
|
parser["TERM"] = reduce;
|
||||||
|
@ -56,7 +56,7 @@ int main(int argc, const char** argv)
|
|||||||
NUMBER <= oom(cls("0-9")), [](const char* s, size_t l) { return atol(s); };
|
NUMBER <= oom(cls("0-9")), [](const char* s, size_t l) { return atol(s); };
|
||||||
|
|
||||||
long val = 0;
|
long val = 0;
|
||||||
if (EXPRESSION.parse(s, val)) {
|
if (EXPRESSION.parse(s, val).ret) {
|
||||||
cout << s << " = " << val << endl;
|
cout << s << " = " << val << endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
320
peglib.h
320
peglib.h
@ -359,15 +359,15 @@ struct Result
|
|||||||
size_t len;
|
size_t len;
|
||||||
size_t choice;
|
size_t choice;
|
||||||
const char* ptr;
|
const char* ptr;
|
||||||
const std::string msg;
|
const std::string err; // TODO: should be `int`.
|
||||||
};
|
};
|
||||||
|
|
||||||
Result success(size_t len, size_t choice = 0) {
|
Result success(size_t len, size_t choice = 0) {
|
||||||
return Result{ true, len, choice, nullptr, std::string() };
|
return Result{ true, len, choice, nullptr, std::string() };
|
||||||
}
|
}
|
||||||
|
|
||||||
Result fail(const char* ptr, std::string msg = std::string(), std::string name = std::string()) {
|
Result fail(const char* ptr, std::string err = std::string(), std::string name = std::string()) {
|
||||||
return Result{ false, 0, (size_t)-1, ptr, msg };
|
return Result{ false, 0, (size_t)-1, ptr, err };
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -408,15 +408,15 @@ public:
|
|||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
for (const auto& ope : opes_) {
|
for (const auto& ope : opes_) {
|
||||||
const auto& rule = *ope;
|
const auto& rule = *ope;
|
||||||
auto m = rule.parse(s + i, l - i, v);
|
auto r = rule.parse(s + i, l - i, v);
|
||||||
if (!m.ret) {
|
if (!r.ret) {
|
||||||
auto msg = m.msg;
|
auto err = r.err;
|
||||||
if (msg.empty()) {
|
if (err.empty()) {
|
||||||
msg = "missing an element in the 'sequence'";
|
err = "missing an element in the 'sequence'";
|
||||||
}
|
}
|
||||||
return fail(m.ptr, msg);
|
return fail(r.ptr, err);
|
||||||
}
|
}
|
||||||
i += m.len;
|
i += r.len;
|
||||||
}
|
}
|
||||||
return success(i);
|
return success(i);
|
||||||
}
|
}
|
||||||
@ -452,8 +452,8 @@ public:
|
|||||||
for (const auto& ope : opes_) {
|
for (const auto& ope : opes_) {
|
||||||
const auto& rule = *ope;
|
const auto& rule = *ope;
|
||||||
Values chldsv;
|
Values chldsv;
|
||||||
auto m = rule.parse(s, l, chldsv);
|
auto r = rule.parse(s, l, chldsv);
|
||||||
if (m.ret) {
|
if (r.ret) {
|
||||||
if (!chldsv.values.empty()) {
|
if (!chldsv.values.empty()) {
|
||||||
for (const auto& x: chldsv.values) {
|
for (const auto& x: chldsv.values) {
|
||||||
v.values.push_back(x);
|
v.values.push_back(x);
|
||||||
@ -462,7 +462,7 @@ public:
|
|||||||
v.names.push_back(x);
|
v.names.push_back(x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return success(m.len, id);
|
return success(r.len, id);
|
||||||
}
|
}
|
||||||
id++;
|
id++;
|
||||||
}
|
}
|
||||||
@ -484,11 +484,11 @@ public:
|
|||||||
auto i = 0;
|
auto i = 0;
|
||||||
while (l - i > 0) {
|
while (l - i > 0) {
|
||||||
const auto& rule = *ope_;
|
const auto& rule = *ope_;
|
||||||
auto m = rule.parse(s + i, l - i, v);
|
auto r = rule.parse(s + i, l - i, v);
|
||||||
if (!m.ret) {
|
if (!r.ret) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
i += m.len;
|
i += r.len;
|
||||||
}
|
}
|
||||||
return success(i);
|
return success(i);
|
||||||
}
|
}
|
||||||
@ -503,22 +503,23 @@ public:
|
|||||||
OneOrMore(const std::shared_ptr<Ope>& ope) : ope_(ope) {}
|
OneOrMore(const std::shared_ptr<Ope>& ope) : ope_(ope) {}
|
||||||
|
|
||||||
Result parse(const char* s, size_t l, Values& v) const {
|
Result parse(const char* s, size_t l, Values& v) const {
|
||||||
auto m = ope_->parse(s, l, v);
|
const auto& rule = *ope_;
|
||||||
if (!m.ret) {
|
auto r = rule.parse(s, l, v);
|
||||||
auto msg = m.msg;
|
if (!r.ret) {
|
||||||
if (msg.empty()) {
|
auto err = r.err;
|
||||||
msg = "nothing occurred in the 'one-or-more'";
|
if (err.empty()) {
|
||||||
|
err = "nothing occurred in the 'one-or-more'";
|
||||||
}
|
}
|
||||||
return fail(m.ptr, m.msg);
|
return fail(r.ptr, r.err);
|
||||||
}
|
}
|
||||||
auto i = m.len;
|
auto i = r.len;
|
||||||
while (l - i > 0) {
|
while (l - i > 0) {
|
||||||
const auto& rule = *ope_;
|
const auto& rule = *ope_;
|
||||||
auto m = rule.parse(s + i, l - i, v);
|
auto r = rule.parse(s + i, l - i, v);
|
||||||
if (!m.ret) {
|
if (!r.ret) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
i += m.len;
|
i += r.len;
|
||||||
}
|
}
|
||||||
return success(i);
|
return success(i);
|
||||||
}
|
}
|
||||||
@ -534,8 +535,8 @@ public:
|
|||||||
|
|
||||||
Result parse(const char* s, size_t l, Values& v) const {
|
Result parse(const char* s, size_t l, Values& v) const {
|
||||||
const auto& rule = *ope_;
|
const auto& rule = *ope_;
|
||||||
auto m = rule.parse(s, l, v);
|
auto r = rule.parse(s, l, v);
|
||||||
return success(m.ret ? m.len : 0);
|
return success(r.ret ? r.len : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -549,11 +550,11 @@ public:
|
|||||||
|
|
||||||
Result parse(const char* s, size_t l, Values& v) const {
|
Result parse(const char* s, size_t l, Values& v) const {
|
||||||
const auto& rule = *ope_;
|
const auto& rule = *ope_;
|
||||||
auto m = rule.parse(s, l, v);
|
auto r = rule.parse(s, l, v);
|
||||||
if (m.ret) {
|
if (r.ret) {
|
||||||
return success(0);
|
return success(0);
|
||||||
} else {
|
} else {
|
||||||
return fail(m.ptr, m.msg);
|
return fail(r.ptr, r.err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -568,8 +569,8 @@ public:
|
|||||||
|
|
||||||
Result parse(const char* s, size_t l, Values& v) const {
|
Result parse(const char* s, size_t l, Values& v) const {
|
||||||
const auto& rule = *ope_;
|
const auto& rule = *ope_;
|
||||||
auto m = rule.parse(s, l, v);
|
auto r = rule.parse(s, l, v);
|
||||||
if (m.ret) {
|
if (r.ret) {
|
||||||
return fail(s);
|
return fail(s);
|
||||||
} else {
|
} else {
|
||||||
return success(0);
|
return success(0);
|
||||||
@ -670,11 +671,11 @@ public:
|
|||||||
Result parse(const char* s, size_t l, Values& v) const {
|
Result parse(const char* s, size_t l, Values& v) const {
|
||||||
assert(ope_);
|
assert(ope_);
|
||||||
const auto& rule = *ope_;
|
const auto& rule = *ope_;
|
||||||
auto m = rule.parse(s, l, v);
|
auto r = rule.parse(s, l, v);
|
||||||
if (m.ret && match_) {
|
if (r.ret && match_) {
|
||||||
match_(s, m.len);
|
match_(s, r.len);
|
||||||
}
|
}
|
||||||
return m;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -740,42 +741,26 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Definition& ope(const std::shared_ptr<Ope>& ope) {
|
|
||||||
holder_->ope_ = ope;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result parse_with_match(const char* s, size_t l) const {
|
|
||||||
Values v;
|
|
||||||
return holder_->parse(s, l, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool parse(const char* s, size_t l, T& val, bool exact = true) const {
|
Result parse(const char* s, size_t l, T& val) const {
|
||||||
Values v;
|
Values v;
|
||||||
auto m = holder_->parse(s, l, v);
|
auto r = holder_->parse(s, l, v);
|
||||||
auto ret = m.ret && (!exact || m.len == l);
|
if (r.ret && !v.values.empty() && !v.values.front().is_undefined()) {
|
||||||
if (ret && !v.values.empty() && !v.values.front().is_undefined()) {
|
|
||||||
val = v.values[0].get<T>();
|
val = v.values[0].get<T>();
|
||||||
}
|
}
|
||||||
return ret;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool parse(const char* s, T& val, bool exact = true) const {
|
Result parse(const char* s, T& val) const {
|
||||||
auto l = strlen(s);
|
auto l = strlen(s);
|
||||||
return parse(s, l, val, exact);
|
return parse(s, l, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse(const char* s, size_t l, bool exact = true) const {
|
Result parse(const char* s) const {
|
||||||
|
auto l = strlen(s);
|
||||||
Values v;
|
Values v;
|
||||||
auto m = holder_->parse(s, l, v);
|
return holder_->parse(s, l, v);
|
||||||
return m.ret && (!exact || m.len == l);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool parse(const char* s, bool exact = true) const {
|
|
||||||
auto l = strlen(s);
|
|
||||||
return parse(s, l, exact);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Definition& operator=(Action ac) {
|
Definition& operator=(Action ac) {
|
||||||
@ -814,20 +799,20 @@ private:
|
|||||||
|
|
||||||
const auto& rule = *ope_;
|
const auto& rule = *ope_;
|
||||||
Values chldsv;
|
Values chldsv;
|
||||||
auto m = rule.parse(s, l, chldsv);
|
auto r = rule.parse(s, l, chldsv);
|
||||||
if (m.ret) {
|
if (r.ret) {
|
||||||
v.names.push_back(outer_->name);
|
v.names.push_back(outer_->name);
|
||||||
|
|
||||||
assert(!outer_->actions.empty());
|
assert(!outer_->actions.empty());
|
||||||
|
|
||||||
auto id = m.choice + 1;
|
auto id = r.choice + 1;
|
||||||
const auto& ac = (id < outer_->actions.size() && outer_->actions[id])
|
const auto& ac = (id < outer_->actions.size() && outer_->actions[id])
|
||||||
? outer_->actions[id]
|
? outer_->actions[id]
|
||||||
: outer_->actions[0];
|
: outer_->actions[0];
|
||||||
|
|
||||||
v.values.push_back(reduce(s, m.len, chldsv, ac));
|
v.values.push_back(reduce(s, r.len, chldsv, ac));
|
||||||
}
|
}
|
||||||
return m;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -1018,69 +1003,14 @@ inline std::pair<size_t, size_t> line_info(const char* s, const char* ptr) {
|
|||||||
return std::make_pair(no, col);
|
return std::make_pair(no, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef std::function<void (size_t, size_t, const std::string&)> Log;
|
||||||
|
|
||||||
class GrammarGenerator
|
class GrammarGenerator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static GrammarGenerator& instance() {
|
static std::shared_ptr<Grammar> perform(const char* s, size_t l, std::string& start, Log log) {
|
||||||
static GrammarGenerator instance;
|
static GrammarGenerator instance;
|
||||||
return instance;
|
return instance.perform_core(s, l, start, log);
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<Grammar> perform(
|
|
||||||
const char* syntax,
|
|
||||||
size_t syntax_len,
|
|
||||||
std::string& start,
|
|
||||||
std::function<void (size_t, size_t, const std::string&)> log = nullptr) {
|
|
||||||
|
|
||||||
auto grammar = std::make_shared<Grammar>();
|
|
||||||
start.clear();
|
|
||||||
std::map<std::string, const char*> refs;
|
|
||||||
|
|
||||||
peg["Definition"] = [&](const std::vector<Any>& v) {
|
|
||||||
const auto& name = v[0].get<std::string>();
|
|
||||||
(*grammar)[name] <= v[2].get<std::shared_ptr<Ope>>();
|
|
||||||
(*grammar)[name].name = name;
|
|
||||||
|
|
||||||
if (start.empty()) {
|
|
||||||
start = name;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
peg["Primary"].actions = {
|
|
||||||
[&](const std::vector<Any>& v) {
|
|
||||||
return v[0];
|
|
||||||
},
|
|
||||||
[&](const char* s, size_t l, const std::vector<Any>& v) {
|
|
||||||
refs[v[0]] = s;
|
|
||||||
return ref(*grammar, v[0]);
|
|
||||||
},
|
|
||||||
[&](const std::vector<Any>& v) {
|
|
||||||
return v[1];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
auto m = peg["Grammar"].parse_with_match(syntax, syntax_len);
|
|
||||||
if (!m.ret) {
|
|
||||||
if (log) {
|
|
||||||
auto line = line_info(syntax, m.ptr);
|
|
||||||
log(line.first, line.second, m.msg.empty() ? "syntax error" : m.msg);
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& x : refs) {
|
|
||||||
const auto& name = x.first;
|
|
||||||
auto ptr = x.second;
|
|
||||||
if (grammar->find(name) == grammar->end()) {
|
|
||||||
if (log) {
|
|
||||||
auto line = line_info(syntax, ptr);
|
|
||||||
log(line.first, line.second, "'" + name + "' is not defined.");
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return grammar;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -1176,9 +1106,62 @@ private:
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Grammar> perform_core(const char* s, size_t l, std::string& start, Log log) {
|
||||||
|
auto grammar = std::make_shared<Grammar>();
|
||||||
|
start.clear();
|
||||||
|
std::map<std::string, const char*> refs;
|
||||||
|
|
||||||
|
peg["Definition"] = [&](const std::vector<Any>& v) {
|
||||||
|
const auto& name = v[0].get<std::string>();
|
||||||
|
(*grammar)[name] <= v[2].get<std::shared_ptr<Ope>>();
|
||||||
|
(*grammar)[name].name = name;
|
||||||
|
|
||||||
|
if (start.empty()) {
|
||||||
|
start = name;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
peg["Primary"].actions = {
|
||||||
|
[&](const std::vector<Any>& v) {
|
||||||
|
return v[0];
|
||||||
|
},
|
||||||
|
[&](const char* s, size_t l, const std::vector<Any>& v) {
|
||||||
|
refs[v[0]] = s;
|
||||||
|
return ref(*grammar, v[0]);
|
||||||
|
},
|
||||||
|
[&](const std::vector<Any>& v) {
|
||||||
|
return v[1];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto r = peg["Grammar"].parse(s, l);
|
||||||
|
if (!r.ret) {
|
||||||
|
if (log) {
|
||||||
|
auto line = line_info(s, r.ptr);
|
||||||
|
log(line.first, line.second, r.err.empty() ? "syntax error" : r.err);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& x : refs) {
|
||||||
|
const auto& name = x.first;
|
||||||
|
auto ptr = x.second;
|
||||||
|
if (grammar->find(name) == grammar->end()) {
|
||||||
|
if (log) {
|
||||||
|
auto line = line_info(s, ptr);
|
||||||
|
log(line.first, line.second, "'" + name + "' is not defined.");
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return grammar;
|
||||||
|
}
|
||||||
|
|
||||||
std::string resolve_escape_sequence(const char*s, size_t l) {
|
std::string resolve_escape_sequence(const char*s, size_t l) {
|
||||||
std::string r;
|
std::string r;
|
||||||
r.reserve(l);
|
r.reserve(l);
|
||||||
|
|
||||||
for (auto i = 0u; i < l; i++) {
|
for (auto i = 0u; i < l; i++) {
|
||||||
auto ch = s[i];
|
auto ch = s[i];
|
||||||
if (ch == '\\') {
|
if (ch == '\\') {
|
||||||
@ -1208,20 +1191,6 @@ private:
|
|||||||
Grammar peg;
|
Grammar peg;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::shared_ptr<Grammar> make_grammar(
|
|
||||||
const char* syntax, size_t syntax_len, std::string& start,
|
|
||||||
std::function<void (size_t, size_t, const std::string&)> log = nullptr)
|
|
||||||
{
|
|
||||||
return GrammarGenerator::instance().perform(syntax, syntax_len, start, log);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::shared_ptr<Grammar> make_grammar(
|
|
||||||
const char* syntax, std::string& start,
|
|
||||||
std::function<void (size_t, size_t, const std::string&)> log = nullptr)
|
|
||||||
{
|
|
||||||
return make_grammar(syntax, strlen(syntax), start, log);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------
|
/*-----------------------------------------------------------------------------
|
||||||
* Parser
|
* Parser
|
||||||
*---------------------------------------------------------------------------*/
|
*---------------------------------------------------------------------------*/
|
||||||
@ -1229,68 +1198,64 @@ inline std::shared_ptr<Grammar> make_grammar(
|
|||||||
class Parser
|
class Parser
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
Parser(const char* s, size_t l, Log log = nullptr) {
|
||||||
|
grammar_ = GrammarGenerator::perform(s, l, start_, log);
|
||||||
|
}
|
||||||
|
|
||||||
|
Parser(const char* s, Log log = nullptr) {
|
||||||
|
auto l = strlen(s);
|
||||||
|
grammar_ = GrammarGenerator::perform(s, l, start_, log);
|
||||||
|
}
|
||||||
|
|
||||||
operator bool() {
|
operator bool() {
|
||||||
return grammar_ != nullptr;
|
return grammar_ != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool load_syntax(
|
|
||||||
const char* s, size_t l,
|
|
||||||
std::function<void (size_t, size_t, const std::string&)> log = nullptr) {
|
|
||||||
|
|
||||||
grammar_ = make_grammar(s, l, start_, log);
|
|
||||||
return grammar_ != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool parse(const char* s, size_t l, T& out) const {
|
bool parse(const char* s, size_t l, T& out, bool exact = true) const {
|
||||||
if (grammar_ != nullptr) {
|
if (grammar_ != nullptr) {
|
||||||
const auto& rule = (*grammar_)[start_];
|
const auto& rule = (*grammar_)[start_];
|
||||||
Any val;
|
auto r = rule.parse(s, l, out);
|
||||||
auto ret = rule.parse(s, l, val);
|
return r.ret && (!exact || r.len == l);
|
||||||
if (ret) {
|
|
||||||
out = val.get<T>();
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse(const char* s, size_t l) const {
|
bool parse(const char* s, size_t l, bool exact = true) const {
|
||||||
if (grammar_ != nullptr) {
|
if (grammar_ != nullptr) {
|
||||||
const auto& rule = (*grammar_)[start_];
|
const auto& rule = (*grammar_)[start_];
|
||||||
return rule.parse(s, l);
|
auto r = rule.parse(s, l);
|
||||||
|
return r.ret && (!exact || r.len == l);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool parse(const char* s, T& out) const {
|
bool parse(const char* s, T& out, bool exact = true) const {
|
||||||
auto l = strlen(s);
|
auto l = strlen(s);
|
||||||
return parse(s, l, out);
|
return parse(s, l, out, exact);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse(const char* s) const {
|
bool parse(const char* s, bool exact = true) const {
|
||||||
auto l = strlen(s);
|
auto l = strlen(s);
|
||||||
return parse(s, l);
|
return parse(s, l, exact);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lint(const char* s, size_t l, bool exact,
|
bool lint(const char* s, size_t l, bool exact, Log log = nullptr) {
|
||||||
std::function<void (size_t, size_t, const std::string&)> log = nullptr) {
|
|
||||||
|
|
||||||
assert(grammar_);
|
assert(grammar_);
|
||||||
if (grammar_ != nullptr) {
|
if (grammar_ != nullptr) {
|
||||||
const auto& rule = (*grammar_)[start_];
|
const auto& rule = (*grammar_)[start_];
|
||||||
auto m = rule.parse_with_match(s, l);
|
auto r = rule.parse(s, l);
|
||||||
if (!m.ret) {
|
if (!r.ret) {
|
||||||
if (log) {
|
if (log) {
|
||||||
auto line = line_info(s, m.ptr);
|
auto line = line_info(s, r.ptr);
|
||||||
log(line.first, line.second, m.msg.empty() ? "syntax error" : m.msg);
|
log(line.first, line.second, r.err.empty() ? "syntax error" : r.err);
|
||||||
}
|
}
|
||||||
} else if (exact && m.len != l) {
|
} else if (exact && r.len != l) {
|
||||||
auto line = line_info(s, s + m.len);
|
auto line = line_info(s, s + r.len);
|
||||||
log(line.first, line.second, "garbage string at the end");
|
log(line.first, line.second, "garbage string at the end");
|
||||||
}
|
}
|
||||||
return m.ret && (!exact || m.len == l);
|
return r.ret && (!exact || r.len == l);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1304,19 +1269,6 @@ private:
|
|||||||
std::string start_;
|
std::string start_;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline Parser make_parser(const char* s, size_t l, std::function<void (size_t, size_t, const std::string&)> log = nullptr) {
|
|
||||||
Parser parser;
|
|
||||||
parser.load_syntax(s, l, log);
|
|
||||||
return parser;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Parser make_parser(const char* s, std::function<void (size_t, size_t, const std::string&)> log = nullptr) {
|
|
||||||
Parser parser;
|
|
||||||
auto l = strlen(s);
|
|
||||||
parser.load_syntax(s, l, log);
|
|
||||||
return parser;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace peglib
|
} // namespace peglib
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
344
test/test.cc
344
test/test.cc
@ -7,14 +7,14 @@
|
|||||||
|
|
||||||
TEST_CASE("Empty syntax test", "[general]")
|
TEST_CASE("Empty syntax test", "[general]")
|
||||||
{
|
{
|
||||||
auto parser = peglib::make_parser("");
|
peglib::Parser parser("");
|
||||||
bool ret = parser;
|
bool ret = parser;
|
||||||
REQUIRE(ret == false);
|
REQUIRE(ret == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("String capture test", "[general]")
|
TEST_CASE("String capture test", "[general]")
|
||||||
{
|
{
|
||||||
auto parser = peglib::make_parser(
|
peglib::Parser parser(
|
||||||
" ROOT <- _ ('[' TAG_NAME ']' _)* "
|
" ROOT <- _ ('[' TAG_NAME ']' _)* "
|
||||||
" TAG_NAME <- (!']' .)+ "
|
" TAG_NAME <- (!']' .)+ "
|
||||||
" _ <- [ \t]* "
|
" _ <- [ \t]* "
|
||||||
@ -48,9 +48,9 @@ TEST_CASE("String capture test2", "[general]")
|
|||||||
TAG_NAME <= oom(seq(npd(chr(']')), any())), [&](const char* s, size_t l) { tags.push_back(string(s, l)); };
|
TAG_NAME <= oom(seq(npd(chr(']')), any())), [&](const char* s, size_t l) { tags.push_back(string(s, l)); };
|
||||||
WS <= zom(cls(" \t"));
|
WS <= zom(cls(" \t"));
|
||||||
|
|
||||||
auto ret = ROOT.parse(" [tag1] [tag:2] [tag-3] ");
|
auto m = ROOT.parse(" [tag1] [tag:2] [tag-3] ");
|
||||||
|
|
||||||
REQUIRE(ret == true);
|
REQUIRE(m.ret == true);
|
||||||
REQUIRE(tags.size() == 3);
|
REQUIRE(tags.size() == 3);
|
||||||
REQUIRE(tags[0] == "tag1");
|
REQUIRE(tags[0] == "tag1");
|
||||||
REQUIRE(tags[1] == "tag:2");
|
REQUIRE(tags[1] == "tag:2");
|
||||||
@ -68,9 +68,9 @@ TEST_CASE("String capture test with embedded match action", "[general]")
|
|||||||
TAG_NAME <= oom(seq(npd(chr(']')), any()));
|
TAG_NAME <= oom(seq(npd(chr(']')), any()));
|
||||||
WS <= zom(cls(" \t"));
|
WS <= zom(cls(" \t"));
|
||||||
|
|
||||||
auto ret = ROOT.parse(" [tag1] [tag:2] [tag-3] ");
|
auto m = ROOT.parse(" [tag1] [tag:2] [tag-3] ");
|
||||||
|
|
||||||
REQUIRE(ret == true);
|
REQUIRE(m.ret == true);
|
||||||
REQUIRE(tags.size() == 3);
|
REQUIRE(tags.size() == 3);
|
||||||
REQUIRE(tags[0] == "tag1");
|
REQUIRE(tags[0] == "tag1");
|
||||||
REQUIRE(tags[1] == "tag:2");
|
REQUIRE(tags[1] == "tag:2");
|
||||||
@ -88,7 +88,7 @@ TEST_CASE("Cyclic grammer test", "[general]")
|
|||||||
|
|
||||||
TEST_CASE("Lambda action test", "[general]")
|
TEST_CASE("Lambda action test", "[general]")
|
||||||
{
|
{
|
||||||
auto parser = make_parser(
|
Parser parser(
|
||||||
" START <- (CHAR)* "
|
" START <- (CHAR)* "
|
||||||
" CHAR <- . ");
|
" CHAR <- . ");
|
||||||
|
|
||||||
@ -104,7 +104,7 @@ TEST_CASE("Lambda action test", "[general]")
|
|||||||
|
|
||||||
TEST_CASE("Backtracking test", "[general]")
|
TEST_CASE("Backtracking test", "[general]")
|
||||||
{
|
{
|
||||||
auto parser = make_parser(
|
Parser parser(
|
||||||
" START <- PAT1 / PAT2 "
|
" START <- PAT1 / PAT2 "
|
||||||
" PAT1 <- HELLO ' One' "
|
" PAT1 <- HELLO ' One' "
|
||||||
" PAT2 <- HELLO ' Two' "
|
" PAT2 <- HELLO ' Two' "
|
||||||
@ -129,7 +129,7 @@ TEST_CASE("Simple calculator test", "[general]")
|
|||||||
" Primary <- '(' Additive ')' / Number "
|
" Primary <- '(' Additive ')' / Number "
|
||||||
" Number <- [0-9]+ ";
|
" Number <- [0-9]+ ";
|
||||||
|
|
||||||
auto parser = make_parser(syntax);
|
Parser parser(syntax);
|
||||||
|
|
||||||
parser["Additive"] = {
|
parser["Additive"] = {
|
||||||
// Default action
|
// Default action
|
||||||
@ -192,11 +192,11 @@ TEST_CASE("Calculator test", "[general]")
|
|||||||
NUMBER = [&](const char* s, size_t l) { return stol(string(s, l), nullptr, 10); };
|
NUMBER = [&](const char* s, size_t l) { return stol(string(s, l), nullptr, 10); };
|
||||||
|
|
||||||
// Parse
|
// Parse
|
||||||
Any val;
|
long val;
|
||||||
auto ret = EXPRESSION.parse("1+2*3*(4-5+6)/7-8", val);
|
auto m = EXPRESSION.parse("1+2*3*(4-5+6)/7-8", val);
|
||||||
|
|
||||||
REQUIRE(ret == true);
|
REQUIRE(m.ret == true);
|
||||||
REQUIRE(val.get<long>() == -3);
|
REQUIRE(val == -3);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Calculator test2", "[general]")
|
TEST_CASE("Calculator test2", "[general]")
|
||||||
@ -213,7 +213,7 @@ TEST_CASE("Calculator test2", "[general]")
|
|||||||
;
|
;
|
||||||
|
|
||||||
string start;
|
string start;
|
||||||
auto grammar = make_grammar(syntax, start);
|
auto grammar = GrammarGenerator::perform(syntax, strlen(syntax), start, nullptr);
|
||||||
auto& g = *grammar;
|
auto& g = *grammar;
|
||||||
|
|
||||||
// Setup actions
|
// Setup actions
|
||||||
@ -238,17 +238,17 @@ TEST_CASE("Calculator test2", "[general]")
|
|||||||
g["NUMBER"] = [](const char* s, size_t l) { return stol(string(s, l), nullptr, 10); };
|
g["NUMBER"] = [](const char* s, size_t l) { return stol(string(s, l), nullptr, 10); };
|
||||||
|
|
||||||
// Parse
|
// Parse
|
||||||
Any val;
|
long val;
|
||||||
auto ret = g[start].parse("1+2*3*(4-5+6)/7-8", val);
|
auto m = g[start].parse("1+2*3*(4-5+6)/7-8", val);
|
||||||
|
|
||||||
REQUIRE(ret == true);
|
REQUIRE(m.ret == true);
|
||||||
REQUIRE(val.get<long>() == -3);
|
REQUIRE(val == -3);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Calculator test3", "[general]")
|
TEST_CASE("Calculator test3", "[general]")
|
||||||
{
|
{
|
||||||
// Parse syntax
|
// Parse syntax
|
||||||
auto parser = make_parser(
|
Parser parser(
|
||||||
" # Grammar for Calculator...\n "
|
" # Grammar for Calculator...\n "
|
||||||
" EXPRESSION <- TERM (TERM_OPERATOR TERM)* "
|
" EXPRESSION <- TERM (TERM_OPERATOR TERM)* "
|
||||||
" TERM <- FACTOR (FACTOR_OPERATOR FACTOR)* "
|
" TERM <- FACTOR (FACTOR_OPERATOR FACTOR)* "
|
||||||
@ -287,249 +287,255 @@ TEST_CASE("Calculator test3", "[general]")
|
|||||||
REQUIRE(val == -3);
|
REQUIRE(val == -3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool exact(Grammar& g, const char* d, const char* s) {
|
||||||
|
auto l = strlen(s);
|
||||||
|
auto r = g[d].parse(s, l);
|
||||||
|
return r.ret && r.len == l;
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("PEG Grammar", "[peg]")
|
TEST_CASE("PEG Grammar", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
Grammar g = make_peg_grammar();
|
||||||
REQUIRE(g["Grammar"].parse(" Definition <- a / ( b c ) / d \n rule2 <- [a-zA-Z][a-z0-9-]+ ") == true);
|
REQUIRE(exact(g, "Grammar", " Definition <- a / ( b c ) / d \n rule2 <- [a-zA-Z][a-z0-9-]+ ") == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("PEG Definition", "[peg]")
|
TEST_CASE("PEG Definition", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
Grammar g = make_peg_grammar();
|
||||||
REQUIRE(g["Definition"].parse("Definition <- a / (b c) / d ") == true);
|
REQUIRE(exact(g, "Definition", "Definition <- a / (b c) / d ") == true);
|
||||||
REQUIRE(g["Definition"].parse("Definition <- a / b c / d ") == true);
|
REQUIRE(exact(g, "Definition", "Definition <- a / b c / d ") == true);
|
||||||
REQUIRE(g["Definition"].parse("Definition ") == false);
|
REQUIRE(exact(g, "Definition", "Definition ") == false);
|
||||||
REQUIRE(g["Definition"].parse(" ") == false);
|
REQUIRE(exact(g, "Definition", " ") == false);
|
||||||
REQUIRE(g["Definition"].parse("") == false);
|
REQUIRE(exact(g, "Definition", "") == false);
|
||||||
REQUIRE(g["Definition"].parse("Definition = a / (b c) / d ") == false);
|
REQUIRE(exact(g, "Definition", "Definition = a / (b c) / d ") == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("PEG Expression", "[peg]")
|
TEST_CASE("PEG Expression", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
Grammar g = make_peg_grammar();
|
||||||
REQUIRE(g["Expression"].parse("a / (b c) / d ") == true);
|
REQUIRE(exact(g, "Expression", "a / (b c) / d ") == true);
|
||||||
REQUIRE(g["Expression"].parse("a / b c / d ") == true);
|
REQUIRE(exact(g, "Expression", "a / b c / d ") == true);
|
||||||
REQUIRE(g["Expression"].parse("a b ") == true);
|
REQUIRE(exact(g, "Expression", "a b ") == true);
|
||||||
REQUIRE(g["Expression"].parse("") == true);
|
REQUIRE(exact(g, "Expression", "") == true);
|
||||||
REQUIRE(g["Expression"].parse(" ") == false);
|
REQUIRE(exact(g, "Expression", " ") == false);
|
||||||
REQUIRE(g["Expression"].parse(" a b ") == false);
|
REQUIRE(exact(g, "Expression", " a b ") == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("PEG Sequence", "[peg]")
|
TEST_CASE("PEG Sequence", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
Grammar g = make_peg_grammar();
|
||||||
REQUIRE(g["Sequence"].parse("a b c d ") == true);
|
REQUIRE(exact(g, "Sequence", "a b c d ") == true);
|
||||||
REQUIRE(g["Sequence"].parse("") == true);
|
REQUIRE(exact(g, "Sequence", "") == true);
|
||||||
REQUIRE(g["Sequence"].parse("!") == false);
|
REQUIRE(exact(g, "Sequence", "!") == false);
|
||||||
REQUIRE(g["Sequence"].parse("<-") == false);
|
REQUIRE(exact(g, "Sequence", "<-") == false);
|
||||||
REQUIRE(g["Sequence"].parse(" a") == false);
|
REQUIRE(exact(g, "Sequence", " a") == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("PEG Prefix", "[peg]")
|
TEST_CASE("PEG Prefix", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
Grammar g = make_peg_grammar();
|
||||||
REQUIRE(g["Prefix"].parse("&[a]") == true);
|
REQUIRE(exact(g, "Prefix", "&[a]") == true);
|
||||||
REQUIRE(g["Prefix"].parse("![']") == true);
|
REQUIRE(exact(g, "Prefix", "![']") == true);
|
||||||
REQUIRE(g["Prefix"].parse("-[']") == false);
|
REQUIRE(exact(g, "Prefix", "-[']") == false);
|
||||||
REQUIRE(g["Prefix"].parse("") == false);
|
REQUIRE(exact(g, "Prefix", "") == false);
|
||||||
REQUIRE(g["Sequence"].parse(" a") == false);
|
REQUIRE(exact(g, "Sequence", " a") == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("PEG Suffix", "[peg]")
|
TEST_CASE("PEG Suffix", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
Grammar g = make_peg_grammar();
|
||||||
REQUIRE(g["Suffix"].parse("aaa ") == true);
|
REQUIRE(exact(g, "Suffix", "aaa ") == true);
|
||||||
REQUIRE(g["Suffix"].parse("aaa? ") == true);
|
REQUIRE(exact(g, "Suffix", "aaa? ") == true);
|
||||||
REQUIRE(g["Suffix"].parse("aaa* ") == true);
|
REQUIRE(exact(g, "Suffix", "aaa* ") == true);
|
||||||
REQUIRE(g["Suffix"].parse("aaa+ ") == true);
|
REQUIRE(exact(g, "Suffix", "aaa+ ") == true);
|
||||||
REQUIRE(g["Suffix"].parse(". + ") == true);
|
REQUIRE(exact(g, "Suffix", ". + ") == true);
|
||||||
REQUIRE(g["Suffix"].parse("?") == false);
|
REQUIRE(exact(g, "Suffix", "?") == false);
|
||||||
REQUIRE(g["Suffix"].parse("") == false);
|
REQUIRE(exact(g, "Suffix", "") == false);
|
||||||
REQUIRE(g["Sequence"].parse(" a") == false);
|
REQUIRE(exact(g, "Sequence", " a") == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("PEG Primary", "[peg]")
|
TEST_CASE("PEG Primary", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
Grammar g = make_peg_grammar();
|
||||||
REQUIRE(g["Primary"].parse("_Identifier0_ ") == true);
|
REQUIRE(exact(g, "Primary", "_Identifier0_ ") == true);
|
||||||
REQUIRE(g["Primary"].parse("_Identifier0_<-") == false);
|
REQUIRE(exact(g, "Primary", "_Identifier0_<-") == false);
|
||||||
REQUIRE(g["Primary"].parse("( _Identifier0_ _Identifier1_ )") == true);
|
REQUIRE(exact(g, "Primary", "( _Identifier0_ _Identifier1_ )") == true);
|
||||||
REQUIRE(g["Primary"].parse("'Literal String'") == true);
|
REQUIRE(exact(g, "Primary", "'Literal String'") == true);
|
||||||
REQUIRE(g["Primary"].parse("\"Literal String\"") == true);
|
REQUIRE(exact(g, "Primary", "\"Literal String\"") == true);
|
||||||
REQUIRE(g["Primary"].parse("[a-zA-Z]") == true);
|
REQUIRE(exact(g, "Primary", "[a-zA-Z]") == true);
|
||||||
REQUIRE(g["Primary"].parse(".") == true);
|
REQUIRE(exact(g, "Primary", ".") == true);
|
||||||
REQUIRE(g["Primary"].parse("") == false);
|
REQUIRE(exact(g, "Primary", "") == false);
|
||||||
REQUIRE(g["Primary"].parse(" ") == false);
|
REQUIRE(exact(g, "Primary", " ") == false);
|
||||||
REQUIRE(g["Primary"].parse(" a") == false);
|
REQUIRE(exact(g, "Primary", " a") == false);
|
||||||
REQUIRE(g["Primary"].parse("") == false);
|
REQUIRE(exact(g, "Primary", "") == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("PEG Identifier", "[peg]")
|
TEST_CASE("PEG Identifier", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
Grammar g = make_peg_grammar();
|
||||||
REQUIRE(g["Identifier"].parse("_Identifier0_ ") == true);
|
REQUIRE(exact(g, "Identifier", "_Identifier0_ ") == true);
|
||||||
REQUIRE(g["Identifier"].parse("0Identifier_ ") == false);
|
REQUIRE(exact(g, "Identifier", "0Identifier_ ") == false);
|
||||||
REQUIRE(g["Identifier"].parse("Iden|t ") == false);
|
REQUIRE(exact(g, "Identifier", "Iden|t ") == false);
|
||||||
REQUIRE(g["Identifier"].parse(" ") == false);
|
REQUIRE(exact(g, "Identifier", " ") == false);
|
||||||
REQUIRE(g["Identifier"].parse(" a") == false);
|
REQUIRE(exact(g, "Identifier", " a") == false);
|
||||||
REQUIRE(g["Identifier"].parse("") == false);
|
REQUIRE(exact(g, "Identifier", "") == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("PEG IdentStart", "[peg]")
|
TEST_CASE("PEG IdentStart", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
Grammar g = make_peg_grammar();
|
||||||
REQUIRE(g["IdentStart"].parse("_") == true);
|
REQUIRE(exact(g, "IdentStart", "_") == true);
|
||||||
REQUIRE(g["IdentStart"].parse("a") == true);
|
REQUIRE(exact(g, "IdentStart", "a") == true);
|
||||||
REQUIRE(g["IdentStart"].parse("Z") == true);
|
REQUIRE(exact(g, "IdentStart", "Z") == true);
|
||||||
REQUIRE(g["IdentStart"].parse("") == false);
|
REQUIRE(exact(g, "IdentStart", "") == false);
|
||||||
REQUIRE(g["IdentStart"].parse(" ") == false);
|
REQUIRE(exact(g, "IdentStart", " ") == false);
|
||||||
REQUIRE(g["IdentStart"].parse("0") == false);
|
REQUIRE(exact(g, "IdentStart", "0") == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("PEG IdentRest", "[peg]")
|
TEST_CASE("PEG IdentRest", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
Grammar g = make_peg_grammar();
|
||||||
REQUIRE(g["IdentRest"].parse("_") == true);
|
REQUIRE(exact(g, "IdentRest", "_") == true);
|
||||||
REQUIRE(g["IdentRest"].parse("a") == true);
|
REQUIRE(exact(g, "IdentRest", "a") == true);
|
||||||
REQUIRE(g["IdentRest"].parse("Z") == true);
|
REQUIRE(exact(g, "IdentRest", "Z") == true);
|
||||||
REQUIRE(g["IdentRest"].parse("") == false);
|
REQUIRE(exact(g, "IdentRest", "") == false);
|
||||||
REQUIRE(g["IdentRest"].parse(" ") == false);
|
REQUIRE(exact(g, "IdentRest", " ") == false);
|
||||||
REQUIRE(g["IdentRest"].parse("0") == true);
|
REQUIRE(exact(g, "IdentRest", "0") == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("PEG Literal", "[peg]")
|
TEST_CASE("PEG Literal", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
Grammar g = make_peg_grammar();
|
||||||
REQUIRE(g["Literal"].parse("'abc' ") == true);
|
REQUIRE(exact(g, "Literal", "'abc' ") == true);
|
||||||
REQUIRE(g["Literal"].parse("'a\\nb\\tc' ") == true);
|
REQUIRE(exact(g, "Literal", "'a\\nb\\tc' ") == true);
|
||||||
REQUIRE(g["Literal"].parse("'a\\277\tc' ") == true);
|
REQUIRE(exact(g, "Literal", "'a\\277\tc' ") == true);
|
||||||
REQUIRE(g["Literal"].parse("'a\\77\tc' ") == true);
|
REQUIRE(exact(g, "Literal", "'a\\77\tc' ") == true);
|
||||||
REQUIRE(g["Literal"].parse("'a\\80\tc' ") == false);
|
REQUIRE(exact(g, "Literal", "'a\\80\tc' ") == false);
|
||||||
REQUIRE(g["Literal"].parse("'\n' ") == true);
|
REQUIRE(exact(g, "Literal", "'\n' ") == true);
|
||||||
REQUIRE(g["Literal"].parse("'a\\'b' ") == true);
|
REQUIRE(exact(g, "Literal", "'a\\'b' ") == true);
|
||||||
REQUIRE(g["Literal"].parse("'a'b' ") == false);
|
REQUIRE(exact(g, "Literal", "'a'b' ") == false);
|
||||||
REQUIRE(g["Literal"].parse("'a\"'b' ") == false);
|
REQUIRE(exact(g, "Literal", "'a\"'b' ") == false);
|
||||||
REQUIRE(g["Literal"].parse("\"'\\\"abc\\\"'\" ") == true);
|
REQUIRE(exact(g, "Literal", "\"'\\\"abc\\\"'\" ") == true);
|
||||||
REQUIRE(g["Literal"].parse("\"'\"abc\"'\" ") == false);
|
REQUIRE(exact(g, "Literal", "\"'\"abc\"'\" ") == false);
|
||||||
REQUIRE(g["Literal"].parse("abc") == false);
|
REQUIRE(exact(g, "Literal", "abc") == false);
|
||||||
REQUIRE(g["Literal"].parse("") == false);
|
REQUIRE(exact(g, "Literal", "") == false);
|
||||||
REQUIRE(g["Literal"].parse("日本語") == false);
|
REQUIRE(exact(g, "Literal", "日本語") == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("PEG Class", "[peg]")
|
TEST_CASE("PEG Class", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
Grammar g = make_peg_grammar();
|
||||||
REQUIRE(g["Class"].parse("[]") == true);
|
REQUIRE(exact(g, "Class", "[]") == true);
|
||||||
REQUIRE(g["Class"].parse("[a]") == true);
|
REQUIRE(exact(g, "Class", "[a]") == true);
|
||||||
REQUIRE(g["Class"].parse("[a-z]") == true);
|
REQUIRE(exact(g, "Class", "[a-z]") == true);
|
||||||
REQUIRE(g["Class"].parse("[az]") == true);
|
REQUIRE(exact(g, "Class", "[az]") == true);
|
||||||
REQUIRE(g["Class"].parse("[a-zA-Z-]") == true);
|
REQUIRE(exact(g, "Class", "[a-zA-Z-]") == true);
|
||||||
REQUIRE(g["Class"].parse("[a-zA-Z-0-9]") == true);
|
REQUIRE(exact(g, "Class", "[a-zA-Z-0-9]") == true);
|
||||||
REQUIRE(g["Class"].parse("[a-]") == false);
|
REQUIRE(exact(g, "Class", "[a-]") == false);
|
||||||
REQUIRE(g["Class"].parse("[-a]") == true);
|
REQUIRE(exact(g, "Class", "[-a]") == true);
|
||||||
REQUIRE(g["Class"].parse("[") == false);
|
REQUIRE(exact(g, "Class", "[") == false);
|
||||||
REQUIRE(g["Class"].parse("[a") == false);
|
REQUIRE(exact(g, "Class", "[a") == false);
|
||||||
REQUIRE(g["Class"].parse("]") == false);
|
REQUIRE(exact(g, "Class", "]") == false);
|
||||||
REQUIRE(g["Class"].parse("a]") == false);
|
REQUIRE(exact(g, "Class", "a]") == false);
|
||||||
REQUIRE(g["Class"].parse("あ-ん") == false);
|
REQUIRE(exact(g, "Class", "あ-ん") == false);
|
||||||
REQUIRE(g["Class"].parse("[-+]") == true);
|
REQUIRE(exact(g, "Class", "[-+]") == true);
|
||||||
REQUIRE(g["Class"].parse("[+-]") == false);
|
REQUIRE(exact(g, "Class", "[+-]") == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("PEG Range", "[peg]")
|
TEST_CASE("PEG Range", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
Grammar g = make_peg_grammar();
|
||||||
REQUIRE(g["Range"].parse("a") == true);
|
REQUIRE(exact(g, "Range", "a") == true);
|
||||||
REQUIRE(g["Range"].parse("a-z") == true);
|
REQUIRE(exact(g, "Range", "a-z") == true);
|
||||||
REQUIRE(g["Range"].parse("az") == false);
|
REQUIRE(exact(g, "Range", "az") == false);
|
||||||
REQUIRE(g["Range"].parse("") == false);
|
REQUIRE(exact(g, "Range", "") == false);
|
||||||
REQUIRE(g["Range"].parse("a-") == false);
|
REQUIRE(exact(g, "Range", "a-") == false);
|
||||||
REQUIRE(g["Range"].parse("-a") == false);
|
REQUIRE(exact(g, "Range", "-a") == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("PEG Char", "[peg]")
|
TEST_CASE("PEG Char", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
Grammar g = make_peg_grammar();
|
||||||
REQUIRE(g["Char"].parse("\\n") == true);
|
REQUIRE(exact(g, "Char", "\\n") == true);
|
||||||
REQUIRE(g["Char"].parse("\\r") == true);
|
REQUIRE(exact(g, "Char", "\\r") == true);
|
||||||
REQUIRE(g["Char"].parse("\\t") == true);
|
REQUIRE(exact(g, "Char", "\\t") == true);
|
||||||
REQUIRE(g["Char"].parse("\\'") == true);
|
REQUIRE(exact(g, "Char", "\\'") == true);
|
||||||
REQUIRE(g["Char"].parse("\\\"") == true);
|
REQUIRE(exact(g, "Char", "\\\"") == true);
|
||||||
REQUIRE(g["Char"].parse("\\[") == true);
|
REQUIRE(exact(g, "Char", "\\[") == true);
|
||||||
REQUIRE(g["Char"].parse("\\]") == true);
|
REQUIRE(exact(g, "Char", "\\]") == true);
|
||||||
REQUIRE(g["Char"].parse("\\\\") == true);
|
REQUIRE(exact(g, "Char", "\\\\") == true);
|
||||||
REQUIRE(g["Char"].parse("\\000") == true);
|
REQUIRE(exact(g, "Char", "\\000") == true);
|
||||||
REQUIRE(g["Char"].parse("\\277") == true);
|
REQUIRE(exact(g, "Char", "\\277") == true);
|
||||||
REQUIRE(g["Char"].parse("\\377") == false);
|
REQUIRE(exact(g, "Char", "\\377") == false);
|
||||||
REQUIRE(g["Char"].parse("\\087") == false);
|
REQUIRE(exact(g, "Char", "\\087") == false);
|
||||||
REQUIRE(g["Char"].parse("\\079") == false);
|
REQUIRE(exact(g, "Char", "\\079") == false);
|
||||||
REQUIRE(g["Char"].parse("\\00") == true);
|
REQUIRE(exact(g, "Char", "\\00") == true);
|
||||||
REQUIRE(g["Char"].parse("\\77") == true);
|
REQUIRE(exact(g, "Char", "\\77") == true);
|
||||||
REQUIRE(g["Char"].parse("\\80") == false);
|
REQUIRE(exact(g, "Char", "\\80") == false);
|
||||||
REQUIRE(g["Char"].parse("\\08") == false);
|
REQUIRE(exact(g, "Char", "\\08") == false);
|
||||||
REQUIRE(g["Char"].parse("\\0") == true);
|
REQUIRE(exact(g, "Char", "\\0") == true);
|
||||||
REQUIRE(g["Char"].parse("\\7") == true);
|
REQUIRE(exact(g, "Char", "\\7") == true);
|
||||||
REQUIRE(g["Char"].parse("\\8") == false);
|
REQUIRE(exact(g, "Char", "\\8") == false);
|
||||||
REQUIRE(g["Char"].parse("a") == true);
|
REQUIRE(exact(g, "Char", "a") == true);
|
||||||
REQUIRE(g["Char"].parse(".") == true);
|
REQUIRE(exact(g, "Char", ".") == true);
|
||||||
REQUIRE(g["Char"].parse("0") == true);
|
REQUIRE(exact(g, "Char", "0") == true);
|
||||||
REQUIRE(g["Char"].parse("\\") == false);
|
REQUIRE(exact(g, "Char", "\\") == false);
|
||||||
REQUIRE(g["Char"].parse(" ") == true);
|
REQUIRE(exact(g, "Char", " ") == true);
|
||||||
REQUIRE(g["Char"].parse(" ") == false);
|
REQUIRE(exact(g, "Char", " ") == false);
|
||||||
REQUIRE(g["Char"].parse("") == false);
|
REQUIRE(exact(g, "Char", "") == false);
|
||||||
REQUIRE(g["Char"].parse("あ") == false);
|
REQUIRE(exact(g, "Char", "あ") == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("PEG Operators", "[peg]")
|
TEST_CASE("PEG Operators", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
Grammar g = make_peg_grammar();
|
||||||
REQUIRE(g["LEFTARROW"].parse("<-") == true);
|
REQUIRE(exact(g, "LEFTARROW", "<-") == true);
|
||||||
REQUIRE(g["SLASH"].parse("/ ") == true);
|
REQUIRE(exact(g, "SLASH", "/ ") == true);
|
||||||
REQUIRE(g["AND"].parse("& ") == true);
|
REQUIRE(exact(g, "AND", "& ") == true);
|
||||||
REQUIRE(g["NOT"].parse("! ") == true);
|
REQUIRE(exact(g, "NOT", "! ") == true);
|
||||||
REQUIRE(g["QUESTION"].parse("? ") == true);
|
REQUIRE(exact(g, "QUESTION", "? ") == true);
|
||||||
REQUIRE(g["STAR"].parse("* ") == true);
|
REQUIRE(exact(g, "STAR", "* ") == true);
|
||||||
REQUIRE(g["PLUS"].parse("+ ") == true);
|
REQUIRE(exact(g, "PLUS", "+ ") == true);
|
||||||
REQUIRE(g["OPEN"].parse("( ") == true);
|
REQUIRE(exact(g, "OPEN", "( ") == true);
|
||||||
REQUIRE(g["CLOSE"].parse(") ") == true);
|
REQUIRE(exact(g, "CLOSE", ") ") == true);
|
||||||
REQUIRE(g["DOT"].parse(". ") == true);
|
REQUIRE(exact(g, "DOT", ". ") == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("PEG Comment", "[peg]")
|
TEST_CASE("PEG Comment", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
Grammar g = make_peg_grammar();
|
||||||
REQUIRE(g["Comment"].parse("# Comment.\n") == true);
|
REQUIRE(exact(g, "Comment", "# Comment.\n") == true);
|
||||||
REQUIRE(g["Comment"].parse("# Comment.") == false);
|
REQUIRE(exact(g, "Comment", "# Comment.") == false);
|
||||||
REQUIRE(g["Comment"].parse(" ") == false);
|
REQUIRE(exact(g, "Comment", " ") == false);
|
||||||
REQUIRE(g["Comment"].parse("a") == false);
|
REQUIRE(exact(g, "Comment", "a") == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("PEG Space", "[peg]")
|
TEST_CASE("PEG Space", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
Grammar g = make_peg_grammar();
|
||||||
REQUIRE(g["Space"].parse(" ") == true);
|
REQUIRE(exact(g, "Space", " ") == true);
|
||||||
REQUIRE(g["Space"].parse("\t") == true);
|
REQUIRE(exact(g, "Space", "\t") == true);
|
||||||
REQUIRE(g["Space"].parse("\n") == true);
|
REQUIRE(exact(g, "Space", "\n") == true);
|
||||||
REQUIRE(g["Space"].parse("") == false);
|
REQUIRE(exact(g, "Space", "") == false);
|
||||||
REQUIRE(g["Space"].parse("a") == false);
|
REQUIRE(exact(g, "Space", "a") == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("PEG EndOfLine", "[peg]")
|
TEST_CASE("PEG EndOfLine", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
Grammar g = make_peg_grammar();
|
||||||
REQUIRE(g["EndOfLine"].parse("\r\n") == true);
|
REQUIRE(exact(g, "EndOfLine", "\r\n") == true);
|
||||||
REQUIRE(g["EndOfLine"].parse("\n") == true);
|
REQUIRE(exact(g, "EndOfLine", "\n") == true);
|
||||||
REQUIRE(g["EndOfLine"].parse("\r") == true);
|
REQUIRE(exact(g, "EndOfLine", "\r") == true);
|
||||||
REQUIRE(g["EndOfLine"].parse(" ") == false);
|
REQUIRE(exact(g, "EndOfLine", " ") == false);
|
||||||
REQUIRE(g["EndOfLine"].parse("") == false);
|
REQUIRE(exact(g, "EndOfLine", "") == false);
|
||||||
REQUIRE(g["EndOfLine"].parse("a") == false);
|
REQUIRE(exact(g, "EndOfLine", "a") == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("PEG EndOfFile", "[peg]")
|
TEST_CASE("PEG EndOfFile", "[peg]")
|
||||||
{
|
{
|
||||||
Grammar g = make_peg_grammar();
|
Grammar g = make_peg_grammar();
|
||||||
REQUIRE(g["EndOfFile"].parse("") == true);
|
REQUIRE(exact(g, "EndOfFile", "") == true);
|
||||||
REQUIRE(g["EndOfFile"].parse(" ") == false);
|
REQUIRE(exact(g, "EndOfFile", " ") == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: et ts=4 sw=4 cin cino={1s ff=unix
|
// vim: et ts=4 sw=4 cin cino={1s ff=unix
|
||||||
|
Loading…
Reference in New Issue
Block a user