diff --git a/example/calc.cc b/example/calc.cc index 7d5ce9e..e329448 100644 --- a/example/calc.cc +++ b/example/calc.cc @@ -55,7 +55,7 @@ int main(int argc, const char** argv) " NUMBER <- [0-9]+ " ; - Parser parser = make_parser(syntax); + Parser parser(syntax); parser["EXPRESSION"] = reduce; parser["TERM"] = reduce; diff --git a/example/calc2.cc b/example/calc2.cc index 0f8485c..eb6d59c 100644 --- a/example/calc2.cc +++ b/example/calc2.cc @@ -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); }; long val = 0; - if (EXPRESSION.parse(s, val)) { + if (EXPRESSION.parse(s, val).ret) { cout << s << " = " << val << endl; return 0; } diff --git a/peglib.h b/peglib.h index b28b509..5299b06 100644 --- a/peglib.h +++ b/peglib.h @@ -359,15 +359,15 @@ struct Result size_t len; size_t choice; const char* ptr; - const std::string msg; + const std::string err; // TODO: should be `int`. }; Result success(size_t len, size_t choice = 0) { return Result{ true, len, choice, nullptr, std::string() }; } -Result fail(const char* ptr, std::string msg = std::string(), std::string name = std::string()) { - return Result{ false, 0, (size_t)-1, ptr, msg }; +Result fail(const char* ptr, std::string err = std::string(), std::string name = std::string()) { + return Result{ false, 0, (size_t)-1, ptr, err }; } /* @@ -408,15 +408,15 @@ public: size_t i = 0; for (const auto& ope : opes_) { const auto& rule = *ope; - auto m = rule.parse(s + i, l - i, v); - if (!m.ret) { - auto msg = m.msg; - if (msg.empty()) { - msg = "missing an element in the 'sequence'"; + auto r = rule.parse(s + i, l - i, v); + if (!r.ret) { + auto err = r.err; + if (err.empty()) { + 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); } @@ -452,8 +452,8 @@ public: for (const auto& ope : opes_) { const auto& rule = *ope; Values chldsv; - auto m = rule.parse(s, l, chldsv); - if (m.ret) { + auto r = rule.parse(s, l, chldsv); + if (r.ret) { if (!chldsv.values.empty()) { for (const auto& x: chldsv.values) { v.values.push_back(x); @@ -462,7 +462,7 @@ public: v.names.push_back(x); } } - return success(m.len, id); + return success(r.len, id); } id++; } @@ -484,11 +484,11 @@ public: auto i = 0; while (l - i > 0) { const auto& rule = *ope_; - auto m = rule.parse(s + i, l - i, v); - if (!m.ret) { + auto r = rule.parse(s + i, l - i, v); + if (!r.ret) { break; } - i += m.len; + i += r.len; } return success(i); } @@ -503,22 +503,23 @@ public: OneOrMore(const std::shared_ptr& ope) : ope_(ope) {} Result parse(const char* s, size_t l, Values& v) const { - auto m = ope_->parse(s, l, v); - if (!m.ret) { - auto msg = m.msg; - if (msg.empty()) { - msg = "nothing occurred in the 'one-or-more'"; + const auto& rule = *ope_; + auto r = rule.parse(s, l, v); + if (!r.ret) { + auto err = r.err; + 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) { const auto& rule = *ope_; - auto m = rule.parse(s + i, l - i, v); - if (!m.ret) { + auto r = rule.parse(s + i, l - i, v); + if (!r.ret) { break; } - i += m.len; + i += r.len; } return success(i); } @@ -534,8 +535,8 @@ public: Result parse(const char* s, size_t l, Values& v) const { const auto& rule = *ope_; - auto m = rule.parse(s, l, v); - return success(m.ret ? m.len : 0); + auto r = rule.parse(s, l, v); + return success(r.ret ? r.len : 0); } private: @@ -549,11 +550,11 @@ public: Result parse(const char* s, size_t l, Values& v) const { const auto& rule = *ope_; - auto m = rule.parse(s, l, v); - if (m.ret) { + auto r = rule.parse(s, l, v); + if (r.ret) { return success(0); } 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 { const auto& rule = *ope_; - auto m = rule.parse(s, l, v); - if (m.ret) { + auto r = rule.parse(s, l, v); + if (r.ret) { return fail(s); } else { return success(0); @@ -670,11 +671,11 @@ public: Result parse(const char* s, size_t l, Values& v) const { assert(ope_); const auto& rule = *ope_; - auto m = rule.parse(s, l, v); - if (m.ret && match_) { - match_(s, m.len); + auto r = rule.parse(s, l, v); + if (r.ret && match_) { + match_(s, r.len); } - return m; + return r; } private: @@ -740,42 +741,26 @@ public: return *this; } - Definition& ope(const std::shared_ptr& 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 - 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; - auto m = holder_->parse(s, l, v); - auto ret = m.ret && (!exact || m.len == l); - if (ret && !v.values.empty() && !v.values.front().is_undefined()) { + auto r = holder_->parse(s, l, v); + if (r.ret && !v.values.empty() && !v.values.front().is_undefined()) { val = v.values[0].get(); } - return ret; + return r; } template - bool parse(const char* s, T& val, bool exact = true) const { + Result parse(const char* s, T& val) const { 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; - auto m = 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); + return holder_->parse(s, l, v); } Definition& operator=(Action ac) { @@ -814,20 +799,20 @@ private: const auto& rule = *ope_; Values chldsv; - auto m = rule.parse(s, l, chldsv); - if (m.ret) { + auto r = rule.parse(s, l, chldsv); + if (r.ret) { v.names.push_back(outer_->name); assert(!outer_->actions.empty()); - auto id = m.choice + 1; + auto id = r.choice + 1; const auto& ac = (id < outer_->actions.size() && outer_->actions[id]) ? outer_->actions[id] : 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: @@ -1018,69 +1003,14 @@ inline std::pair line_info(const char* s, const char* ptr) { return std::make_pair(no, col); } +typedef std::function Log; + class GrammarGenerator { public: - static GrammarGenerator& instance() { + static std::shared_ptr perform(const char* s, size_t l, std::string& start, Log log) { static GrammarGenerator instance; - return instance; - } - - std::shared_ptr perform( - const char* syntax, - size_t syntax_len, - std::string& start, - std::function log = nullptr) { - - auto grammar = std::make_shared(); - start.clear(); - std::map refs; - - peg["Definition"] = [&](const std::vector& v) { - const auto& name = v[0].get(); - (*grammar)[name] <= v[2].get>(); - (*grammar)[name].name = name; - - if (start.empty()) { - start = name; - } - }; - - peg["Primary"].actions = { - [&](const std::vector& v) { - return v[0]; - }, - [&](const char* s, size_t l, const std::vector& v) { - refs[v[0]] = s; - return ref(*grammar, v[0]); - }, - [&](const std::vector& 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; + return instance.perform_core(s, l, start, log); } private: @@ -1176,9 +1106,62 @@ private: }; } + std::shared_ptr perform_core(const char* s, size_t l, std::string& start, Log log) { + auto grammar = std::make_shared(); + start.clear(); + std::map refs; + + peg["Definition"] = [&](const std::vector& v) { + const auto& name = v[0].get(); + (*grammar)[name] <= v[2].get>(); + (*grammar)[name].name = name; + + if (start.empty()) { + start = name; + } + }; + + peg["Primary"].actions = { + [&](const std::vector& v) { + return v[0]; + }, + [&](const char* s, size_t l, const std::vector& v) { + refs[v[0]] = s; + return ref(*grammar, v[0]); + }, + [&](const std::vector& 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 r; r.reserve(l); + for (auto i = 0u; i < l; i++) { auto ch = s[i]; if (ch == '\\') { @@ -1208,20 +1191,6 @@ private: Grammar peg; }; -inline std::shared_ptr make_grammar( - const char* syntax, size_t syntax_len, std::string& start, - std::function log = nullptr) -{ - return GrammarGenerator::instance().perform(syntax, syntax_len, start, log); -} - -inline std::shared_ptr make_grammar( - const char* syntax, std::string& start, - std::function log = nullptr) -{ - return make_grammar(syntax, strlen(syntax), start, log); -} - /*----------------------------------------------------------------------------- * Parser *---------------------------------------------------------------------------*/ @@ -1229,68 +1198,64 @@ inline std::shared_ptr make_grammar( class Parser { 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() { return grammar_ != nullptr; } - bool load_syntax( - const char* s, size_t l, - std::function log = nullptr) { - - grammar_ = make_grammar(s, l, start_, log); - return grammar_ != nullptr; - } - template - 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) { const auto& rule = (*grammar_)[start_]; - Any val; - auto ret = rule.parse(s, l, val); - if (ret) { - out = val.get(); - } - return ret; + auto r = rule.parse(s, l, out); + return r.ret && (!exact || r.len == l); } 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) { 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; } template - bool parse(const char* s, T& out) const { + bool parse(const char* s, T& out, bool exact = true) const { 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); - return parse(s, l); + return parse(s, l, exact); } - bool lint(const char* s, size_t l, bool exact, - std::function log = nullptr) { - + bool lint(const char* s, size_t l, bool exact, Log log = nullptr) { assert(grammar_); if (grammar_ != nullptr) { const auto& rule = (*grammar_)[start_]; - auto m = rule.parse_with_match(s, l); - if (!m.ret) { + auto r = rule.parse(s, l); + if (!r.ret) { if (log) { - auto line = line_info(s, m.ptr); - log(line.first, line.second, m.msg.empty() ? "syntax error" : m.msg); + auto line = line_info(s, r.ptr); + log(line.first, line.second, r.err.empty() ? "syntax error" : r.err); } - } else if (exact && m.len != l) { - auto line = line_info(s, s + m.len); + } else if (exact && r.len != l) { + auto line = line_info(s, s + r.len); 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; } @@ -1304,19 +1269,6 @@ private: std::string start_; }; -inline Parser make_parser(const char* s, size_t l, std::function log = nullptr) { - Parser parser; - parser.load_syntax(s, l, log); - return parser; -} - -inline Parser make_parser(const char* s, std::function log = nullptr) { - Parser parser; - auto l = strlen(s); - parser.load_syntax(s, l, log); - return parser; -} - } // namespace peglib #endif diff --git a/test/test.cc b/test/test.cc index 47135a7..8696553 100644 --- a/test/test.cc +++ b/test/test.cc @@ -7,14 +7,14 @@ TEST_CASE("Empty syntax test", "[general]") { - auto parser = peglib::make_parser(""); + peglib::Parser parser(""); bool ret = parser; REQUIRE(ret == false); } TEST_CASE("String capture test", "[general]") { - auto parser = peglib::make_parser( + peglib::Parser parser( " ROOT <- _ ('[' TAG_NAME ']' _)* " " TAG_NAME <- (!']' .)+ " " _ <- [ \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)); }; 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[0] == "tag1"); 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())); 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[0] == "tag1"); REQUIRE(tags[1] == "tag:2"); @@ -88,7 +88,7 @@ TEST_CASE("Cyclic grammer test", "[general]") TEST_CASE("Lambda action test", "[general]") { - auto parser = make_parser( + Parser parser( " START <- (CHAR)* " " CHAR <- . "); @@ -104,7 +104,7 @@ TEST_CASE("Lambda action test", "[general]") TEST_CASE("Backtracking test", "[general]") { - auto parser = make_parser( + Parser parser( " START <- PAT1 / PAT2 " " PAT1 <- HELLO ' One' " " PAT2 <- HELLO ' Two' " @@ -129,7 +129,7 @@ TEST_CASE("Simple calculator test", "[general]") " Primary <- '(' Additive ')' / Number " " Number <- [0-9]+ "; - auto parser = make_parser(syntax); + Parser parser(syntax); parser["Additive"] = { // 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); }; // Parse - Any val; - auto ret = EXPRESSION.parse("1+2*3*(4-5+6)/7-8", val); + long val; + auto m = EXPRESSION.parse("1+2*3*(4-5+6)/7-8", val); - REQUIRE(ret == true); - REQUIRE(val.get() == -3); + REQUIRE(m.ret == true); + REQUIRE(val == -3); } TEST_CASE("Calculator test2", "[general]") @@ -213,7 +213,7 @@ TEST_CASE("Calculator test2", "[general]") ; string start; - auto grammar = make_grammar(syntax, start); + auto grammar = GrammarGenerator::perform(syntax, strlen(syntax), start, nullptr); auto& g = *grammar; // 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); }; // Parse - Any val; - auto ret = g[start].parse("1+2*3*(4-5+6)/7-8", val); + long val; + auto m = g[start].parse("1+2*3*(4-5+6)/7-8", val); - REQUIRE(ret == true); - REQUIRE(val.get() == -3); + REQUIRE(m.ret == true); + REQUIRE(val == -3); } TEST_CASE("Calculator test3", "[general]") { // Parse syntax - auto parser = make_parser( + Parser parser( " # Grammar for Calculator...\n " " EXPRESSION <- TERM (TERM_OPERATOR TERM)* " " TERM <- FACTOR (FACTOR_OPERATOR FACTOR)* " @@ -287,249 +287,255 @@ TEST_CASE("Calculator test3", "[general]") 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]") { 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]") { Grammar g = make_peg_grammar(); - REQUIRE(g["Definition"].parse("Definition <- a / (b c) / d ") == true); - REQUIRE(g["Definition"].parse("Definition <- a / b c / d ") == true); - REQUIRE(g["Definition"].parse("Definition ") == false); - REQUIRE(g["Definition"].parse(" ") == false); - REQUIRE(g["Definition"].parse("") == false); - REQUIRE(g["Definition"].parse("Definition = a / (b c) / d ") == false); + REQUIRE(exact(g, "Definition", "Definition <- a / (b c) / d ") == true); + REQUIRE(exact(g, "Definition", "Definition <- a / b c / d ") == true); + REQUIRE(exact(g, "Definition", "Definition ") == false); + REQUIRE(exact(g, "Definition", " ") == false); + REQUIRE(exact(g, "Definition", "") == false); + REQUIRE(exact(g, "Definition", "Definition = a / (b c) / d ") == false); } TEST_CASE("PEG Expression", "[peg]") { Grammar g = make_peg_grammar(); - REQUIRE(g["Expression"].parse("a / (b c) / d ") == true); - REQUIRE(g["Expression"].parse("a / b c / d ") == true); - REQUIRE(g["Expression"].parse("a b ") == true); - REQUIRE(g["Expression"].parse("") == true); - REQUIRE(g["Expression"].parse(" ") == false); - REQUIRE(g["Expression"].parse(" a b ") == false); + REQUIRE(exact(g, "Expression", "a / (b c) / d ") == true); + REQUIRE(exact(g, "Expression", "a / b c / d ") == true); + REQUIRE(exact(g, "Expression", "a b ") == true); + REQUIRE(exact(g, "Expression", "") == true); + REQUIRE(exact(g, "Expression", " ") == false); + REQUIRE(exact(g, "Expression", " a b ") == false); } TEST_CASE("PEG Sequence", "[peg]") { Grammar g = make_peg_grammar(); - REQUIRE(g["Sequence"].parse("a b c d ") == true); - REQUIRE(g["Sequence"].parse("") == true); - REQUIRE(g["Sequence"].parse("!") == false); - REQUIRE(g["Sequence"].parse("<-") == false); - REQUIRE(g["Sequence"].parse(" a") == false); + REQUIRE(exact(g, "Sequence", "a b c d ") == true); + REQUIRE(exact(g, "Sequence", "") == true); + REQUIRE(exact(g, "Sequence", "!") == false); + REQUIRE(exact(g, "Sequence", "<-") == false); + REQUIRE(exact(g, "Sequence", " a") == false); } TEST_CASE("PEG Prefix", "[peg]") { Grammar g = make_peg_grammar(); - REQUIRE(g["Prefix"].parse("&[a]") == true); - REQUIRE(g["Prefix"].parse("![']") == true); - REQUIRE(g["Prefix"].parse("-[']") == false); - REQUIRE(g["Prefix"].parse("") == false); - REQUIRE(g["Sequence"].parse(" a") == false); + REQUIRE(exact(g, "Prefix", "&[a]") == true); + REQUIRE(exact(g, "Prefix", "![']") == true); + REQUIRE(exact(g, "Prefix", "-[']") == false); + REQUIRE(exact(g, "Prefix", "") == false); + REQUIRE(exact(g, "Sequence", " a") == false); } TEST_CASE("PEG Suffix", "[peg]") { Grammar g = make_peg_grammar(); - REQUIRE(g["Suffix"].parse("aaa ") == true); - REQUIRE(g["Suffix"].parse("aaa? ") == true); - REQUIRE(g["Suffix"].parse("aaa* ") == true); - REQUIRE(g["Suffix"].parse("aaa+ ") == true); - REQUIRE(g["Suffix"].parse(". + ") == true); - REQUIRE(g["Suffix"].parse("?") == false); - REQUIRE(g["Suffix"].parse("") == false); - REQUIRE(g["Sequence"].parse(" a") == false); + REQUIRE(exact(g, "Suffix", "aaa ") == true); + REQUIRE(exact(g, "Suffix", "aaa? ") == true); + REQUIRE(exact(g, "Suffix", "aaa* ") == true); + REQUIRE(exact(g, "Suffix", "aaa+ ") == true); + REQUIRE(exact(g, "Suffix", ". + ") == true); + REQUIRE(exact(g, "Suffix", "?") == false); + REQUIRE(exact(g, "Suffix", "") == false); + REQUIRE(exact(g, "Sequence", " a") == false); } TEST_CASE("PEG Primary", "[peg]") { Grammar g = make_peg_grammar(); - REQUIRE(g["Primary"].parse("_Identifier0_ ") == true); - REQUIRE(g["Primary"].parse("_Identifier0_<-") == false); - REQUIRE(g["Primary"].parse("( _Identifier0_ _Identifier1_ )") == true); - REQUIRE(g["Primary"].parse("'Literal String'") == true); - REQUIRE(g["Primary"].parse("\"Literal String\"") == true); - REQUIRE(g["Primary"].parse("[a-zA-Z]") == true); - REQUIRE(g["Primary"].parse(".") == true); - REQUIRE(g["Primary"].parse("") == false); - REQUIRE(g["Primary"].parse(" ") == false); - REQUIRE(g["Primary"].parse(" a") == false); - REQUIRE(g["Primary"].parse("") == false); + REQUIRE(exact(g, "Primary", "_Identifier0_ ") == true); + REQUIRE(exact(g, "Primary", "_Identifier0_<-") == false); + REQUIRE(exact(g, "Primary", "( _Identifier0_ _Identifier1_ )") == true); + REQUIRE(exact(g, "Primary", "'Literal String'") == true); + REQUIRE(exact(g, "Primary", "\"Literal String\"") == true); + REQUIRE(exact(g, "Primary", "[a-zA-Z]") == true); + REQUIRE(exact(g, "Primary", ".") == true); + REQUIRE(exact(g, "Primary", "") == false); + REQUIRE(exact(g, "Primary", " ") == false); + REQUIRE(exact(g, "Primary", " a") == false); + REQUIRE(exact(g, "Primary", "") == false); } TEST_CASE("PEG Identifier", "[peg]") { Grammar g = make_peg_grammar(); - REQUIRE(g["Identifier"].parse("_Identifier0_ ") == true); - REQUIRE(g["Identifier"].parse("0Identifier_ ") == false); - REQUIRE(g["Identifier"].parse("Iden|t ") == false); - REQUIRE(g["Identifier"].parse(" ") == false); - REQUIRE(g["Identifier"].parse(" a") == false); - REQUIRE(g["Identifier"].parse("") == false); + REQUIRE(exact(g, "Identifier", "_Identifier0_ ") == true); + REQUIRE(exact(g, "Identifier", "0Identifier_ ") == false); + REQUIRE(exact(g, "Identifier", "Iden|t ") == false); + REQUIRE(exact(g, "Identifier", " ") == false); + REQUIRE(exact(g, "Identifier", " a") == false); + REQUIRE(exact(g, "Identifier", "") == false); } TEST_CASE("PEG IdentStart", "[peg]") { Grammar g = make_peg_grammar(); - REQUIRE(g["IdentStart"].parse("_") == true); - REQUIRE(g["IdentStart"].parse("a") == true); - REQUIRE(g["IdentStart"].parse("Z") == true); - REQUIRE(g["IdentStart"].parse("") == false); - REQUIRE(g["IdentStart"].parse(" ") == false); - REQUIRE(g["IdentStart"].parse("0") == false); + REQUIRE(exact(g, "IdentStart", "_") == true); + REQUIRE(exact(g, "IdentStart", "a") == true); + REQUIRE(exact(g, "IdentStart", "Z") == true); + REQUIRE(exact(g, "IdentStart", "") == false); + REQUIRE(exact(g, "IdentStart", " ") == false); + REQUIRE(exact(g, "IdentStart", "0") == false); } TEST_CASE("PEG IdentRest", "[peg]") { Grammar g = make_peg_grammar(); - REQUIRE(g["IdentRest"].parse("_") == true); - REQUIRE(g["IdentRest"].parse("a") == true); - REQUIRE(g["IdentRest"].parse("Z") == true); - REQUIRE(g["IdentRest"].parse("") == false); - REQUIRE(g["IdentRest"].parse(" ") == false); - REQUIRE(g["IdentRest"].parse("0") == true); + REQUIRE(exact(g, "IdentRest", "_") == true); + REQUIRE(exact(g, "IdentRest", "a") == true); + REQUIRE(exact(g, "IdentRest", "Z") == true); + REQUIRE(exact(g, "IdentRest", "") == false); + REQUIRE(exact(g, "IdentRest", " ") == false); + REQUIRE(exact(g, "IdentRest", "0") == true); } TEST_CASE("PEG Literal", "[peg]") { Grammar g = make_peg_grammar(); - REQUIRE(g["Literal"].parse("'abc' ") == true); - REQUIRE(g["Literal"].parse("'a\\nb\\tc' ") == true); - REQUIRE(g["Literal"].parse("'a\\277\tc' ") == true); - REQUIRE(g["Literal"].parse("'a\\77\tc' ") == true); - REQUIRE(g["Literal"].parse("'a\\80\tc' ") == false); - REQUIRE(g["Literal"].parse("'\n' ") == true); - REQUIRE(g["Literal"].parse("'a\\'b' ") == true); - REQUIRE(g["Literal"].parse("'a'b' ") == false); - REQUIRE(g["Literal"].parse("'a\"'b' ") == false); - REQUIRE(g["Literal"].parse("\"'\\\"abc\\\"'\" ") == true); - REQUIRE(g["Literal"].parse("\"'\"abc\"'\" ") == false); - REQUIRE(g["Literal"].parse("abc") == false); - REQUIRE(g["Literal"].parse("") == false); - REQUIRE(g["Literal"].parse("日本語") == false); + REQUIRE(exact(g, "Literal", "'abc' ") == true); + REQUIRE(exact(g, "Literal", "'a\\nb\\tc' ") == true); + REQUIRE(exact(g, "Literal", "'a\\277\tc' ") == true); + REQUIRE(exact(g, "Literal", "'a\\77\tc' ") == true); + REQUIRE(exact(g, "Literal", "'a\\80\tc' ") == false); + REQUIRE(exact(g, "Literal", "'\n' ") == true); + REQUIRE(exact(g, "Literal", "'a\\'b' ") == true); + REQUIRE(exact(g, "Literal", "'a'b' ") == false); + REQUIRE(exact(g, "Literal", "'a\"'b' ") == false); + REQUIRE(exact(g, "Literal", "\"'\\\"abc\\\"'\" ") == true); + REQUIRE(exact(g, "Literal", "\"'\"abc\"'\" ") == false); + REQUIRE(exact(g, "Literal", "abc") == false); + REQUIRE(exact(g, "Literal", "") == false); + REQUIRE(exact(g, "Literal", "日本語") == false); } TEST_CASE("PEG Class", "[peg]") { Grammar g = make_peg_grammar(); - REQUIRE(g["Class"].parse("[]") == true); - REQUIRE(g["Class"].parse("[a]") == true); - REQUIRE(g["Class"].parse("[a-z]") == true); - REQUIRE(g["Class"].parse("[az]") == true); - REQUIRE(g["Class"].parse("[a-zA-Z-]") == true); - REQUIRE(g["Class"].parse("[a-zA-Z-0-9]") == true); - REQUIRE(g["Class"].parse("[a-]") == false); - REQUIRE(g["Class"].parse("[-a]") == true); - REQUIRE(g["Class"].parse("[") == false); - REQUIRE(g["Class"].parse("[a") == false); - REQUIRE(g["Class"].parse("]") == false); - REQUIRE(g["Class"].parse("a]") == false); - REQUIRE(g["Class"].parse("あ-ん") == false); - REQUIRE(g["Class"].parse("[-+]") == true); - REQUIRE(g["Class"].parse("[+-]") == false); + REQUIRE(exact(g, "Class", "[]") == true); + REQUIRE(exact(g, "Class", "[a]") == true); + REQUIRE(exact(g, "Class", "[a-z]") == true); + REQUIRE(exact(g, "Class", "[az]") == true); + REQUIRE(exact(g, "Class", "[a-zA-Z-]") == true); + REQUIRE(exact(g, "Class", "[a-zA-Z-0-9]") == true); + REQUIRE(exact(g, "Class", "[a-]") == false); + REQUIRE(exact(g, "Class", "[-a]") == true); + REQUIRE(exact(g, "Class", "[") == false); + REQUIRE(exact(g, "Class", "[a") == false); + REQUIRE(exact(g, "Class", "]") == false); + REQUIRE(exact(g, "Class", "a]") == false); + REQUIRE(exact(g, "Class", "あ-ん") == false); + REQUIRE(exact(g, "Class", "[-+]") == true); + REQUIRE(exact(g, "Class", "[+-]") == false); } TEST_CASE("PEG Range", "[peg]") { Grammar g = make_peg_grammar(); - REQUIRE(g["Range"].parse("a") == true); - REQUIRE(g["Range"].parse("a-z") == true); - REQUIRE(g["Range"].parse("az") == false); - REQUIRE(g["Range"].parse("") == false); - REQUIRE(g["Range"].parse("a-") == false); - REQUIRE(g["Range"].parse("-a") == false); + REQUIRE(exact(g, "Range", "a") == true); + REQUIRE(exact(g, "Range", "a-z") == true); + REQUIRE(exact(g, "Range", "az") == false); + REQUIRE(exact(g, "Range", "") == false); + REQUIRE(exact(g, "Range", "a-") == false); + REQUIRE(exact(g, "Range", "-a") == false); } TEST_CASE("PEG Char", "[peg]") { Grammar g = make_peg_grammar(); - REQUIRE(g["Char"].parse("\\n") == true); - REQUIRE(g["Char"].parse("\\r") == true); - REQUIRE(g["Char"].parse("\\t") == true); - REQUIRE(g["Char"].parse("\\'") == true); - REQUIRE(g["Char"].parse("\\\"") == true); - REQUIRE(g["Char"].parse("\\[") == true); - REQUIRE(g["Char"].parse("\\]") == true); - REQUIRE(g["Char"].parse("\\\\") == true); - REQUIRE(g["Char"].parse("\\000") == true); - REQUIRE(g["Char"].parse("\\277") == true); - REQUIRE(g["Char"].parse("\\377") == false); - REQUIRE(g["Char"].parse("\\087") == false); - REQUIRE(g["Char"].parse("\\079") == false); - REQUIRE(g["Char"].parse("\\00") == true); - REQUIRE(g["Char"].parse("\\77") == true); - REQUIRE(g["Char"].parse("\\80") == false); - REQUIRE(g["Char"].parse("\\08") == false); - REQUIRE(g["Char"].parse("\\0") == true); - REQUIRE(g["Char"].parse("\\7") == true); - REQUIRE(g["Char"].parse("\\8") == false); - REQUIRE(g["Char"].parse("a") == true); - REQUIRE(g["Char"].parse(".") == true); - REQUIRE(g["Char"].parse("0") == true); - REQUIRE(g["Char"].parse("\\") == false); - REQUIRE(g["Char"].parse(" ") == true); - REQUIRE(g["Char"].parse(" ") == false); - REQUIRE(g["Char"].parse("") == false); - REQUIRE(g["Char"].parse("あ") == false); + REQUIRE(exact(g, "Char", "\\n") == true); + REQUIRE(exact(g, "Char", "\\r") == true); + REQUIRE(exact(g, "Char", "\\t") == true); + REQUIRE(exact(g, "Char", "\\'") == true); + REQUIRE(exact(g, "Char", "\\\"") == true); + REQUIRE(exact(g, "Char", "\\[") == true); + REQUIRE(exact(g, "Char", "\\]") == true); + REQUIRE(exact(g, "Char", "\\\\") == true); + REQUIRE(exact(g, "Char", "\\000") == true); + REQUIRE(exact(g, "Char", "\\277") == true); + REQUIRE(exact(g, "Char", "\\377") == false); + REQUIRE(exact(g, "Char", "\\087") == false); + REQUIRE(exact(g, "Char", "\\079") == false); + REQUIRE(exact(g, "Char", "\\00") == true); + REQUIRE(exact(g, "Char", "\\77") == true); + REQUIRE(exact(g, "Char", "\\80") == false); + REQUIRE(exact(g, "Char", "\\08") == false); + REQUIRE(exact(g, "Char", "\\0") == true); + REQUIRE(exact(g, "Char", "\\7") == true); + REQUIRE(exact(g, "Char", "\\8") == false); + REQUIRE(exact(g, "Char", "a") == true); + REQUIRE(exact(g, "Char", ".") == true); + REQUIRE(exact(g, "Char", "0") == true); + REQUIRE(exact(g, "Char", "\\") == false); + REQUIRE(exact(g, "Char", " ") == true); + REQUIRE(exact(g, "Char", " ") == false); + REQUIRE(exact(g, "Char", "") == false); + REQUIRE(exact(g, "Char", "あ") == false); } TEST_CASE("PEG Operators", "[peg]") { Grammar g = make_peg_grammar(); - REQUIRE(g["LEFTARROW"].parse("<-") == true); - REQUIRE(g["SLASH"].parse("/ ") == true); - REQUIRE(g["AND"].parse("& ") == true); - REQUIRE(g["NOT"].parse("! ") == true); - REQUIRE(g["QUESTION"].parse("? ") == true); - REQUIRE(g["STAR"].parse("* ") == true); - REQUIRE(g["PLUS"].parse("+ ") == true); - REQUIRE(g["OPEN"].parse("( ") == true); - REQUIRE(g["CLOSE"].parse(") ") == true); - REQUIRE(g["DOT"].parse(". ") == true); + REQUIRE(exact(g, "LEFTARROW", "<-") == true); + REQUIRE(exact(g, "SLASH", "/ ") == true); + REQUIRE(exact(g, "AND", "& ") == true); + REQUIRE(exact(g, "NOT", "! ") == true); + REQUIRE(exact(g, "QUESTION", "? ") == true); + REQUIRE(exact(g, "STAR", "* ") == true); + REQUIRE(exact(g, "PLUS", "+ ") == true); + REQUIRE(exact(g, "OPEN", "( ") == true); + REQUIRE(exact(g, "CLOSE", ") ") == true); + REQUIRE(exact(g, "DOT", ". ") == true); } TEST_CASE("PEG Comment", "[peg]") { Grammar g = make_peg_grammar(); - REQUIRE(g["Comment"].parse("# Comment.\n") == true); - REQUIRE(g["Comment"].parse("# Comment.") == false); - REQUIRE(g["Comment"].parse(" ") == false); - REQUIRE(g["Comment"].parse("a") == false); + REQUIRE(exact(g, "Comment", "# Comment.\n") == true); + REQUIRE(exact(g, "Comment", "# Comment.") == false); + REQUIRE(exact(g, "Comment", " ") == false); + REQUIRE(exact(g, "Comment", "a") == false); } TEST_CASE("PEG Space", "[peg]") { Grammar g = make_peg_grammar(); - REQUIRE(g["Space"].parse(" ") == true); - REQUIRE(g["Space"].parse("\t") == true); - REQUIRE(g["Space"].parse("\n") == true); - REQUIRE(g["Space"].parse("") == false); - REQUIRE(g["Space"].parse("a") == false); + REQUIRE(exact(g, "Space", " ") == true); + REQUIRE(exact(g, "Space", "\t") == true); + REQUIRE(exact(g, "Space", "\n") == true); + REQUIRE(exact(g, "Space", "") == false); + REQUIRE(exact(g, "Space", "a") == false); } TEST_CASE("PEG EndOfLine", "[peg]") { Grammar g = make_peg_grammar(); - REQUIRE(g["EndOfLine"].parse("\r\n") == true); - REQUIRE(g["EndOfLine"].parse("\n") == true); - REQUIRE(g["EndOfLine"].parse("\r") == true); - REQUIRE(g["EndOfLine"].parse(" ") == false); - REQUIRE(g["EndOfLine"].parse("") == false); - REQUIRE(g["EndOfLine"].parse("a") == false); + REQUIRE(exact(g, "EndOfLine", "\r\n") == true); + REQUIRE(exact(g, "EndOfLine", "\n") == true); + REQUIRE(exact(g, "EndOfLine", "\r") == true); + REQUIRE(exact(g, "EndOfLine", " ") == false); + REQUIRE(exact(g, "EndOfLine", "") == false); + REQUIRE(exact(g, "EndOfLine", "a") == false); } TEST_CASE("PEG EndOfFile", "[peg]") { Grammar g = make_peg_grammar(); - REQUIRE(g["EndOfFile"].parse("") == true); - REQUIRE(g["EndOfFile"].parse(" ") == false); + REQUIRE(exact(g, "EndOfFile", "") == true); + REQUIRE(exact(g, "EndOfFile", " ") == false); } // vim: et ts=4 sw=4 cin cino={1s ff=unix