diff --git a/peglib.h b/peglib.h index 2993d86..90a0760 100644 --- a/peglib.h +++ b/peglib.h @@ -737,11 +737,8 @@ public: size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const override { const auto& rule = *ope_; auto error_pos = c.error_pos; - auto& chldsv = c.push(); auto len = rule.parse(s, n, sv, c, dt); - c.pop(); - if (success(len)) - { + if (success(len)) { c.set_error_pos(s); return -1; } else { @@ -856,7 +853,6 @@ public: : ope_(ope), match_action_(ma), id(n), name(s) {} size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const override { - assert(ope_); const auto& rule = *ope_; auto len = rule.parse(s, n, sv, c, dt); if (success(len) && match_action_) { @@ -880,7 +876,6 @@ public: Anchor(const std::shared_ptr& ope) : ope_(ope) {} size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const override { - assert(ope_); const auto& rule = *ope_; auto len = rule.parse(s, n, sv, c, dt); if (success(len)) { @@ -896,6 +891,25 @@ public: std::shared_ptr ope_; }; +class Ignore : public Ope +{ +public: + Ignore(const std::shared_ptr& ope) : ope_(ope) {} + + size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const override { + const auto& rule = *ope_; + auto& chldsv = c.push(); + auto len = rule.parse(s, n, chldsv, c, dt); + c.pop(); + return len; + } + + void accept(Visitor& v) override; + +//private: + std::shared_ptr ope_; +}; + typedef std::function Parser; class User : public Ope @@ -992,6 +1006,7 @@ struct Ope::Visitor virtual void visit(AnyCharacter& ope) = 0; virtual void visit(Capture& ope) = 0; virtual void visit(Anchor& ope) = 0; + virtual void visit(Ignore& ope) = 0; virtual void visit(User& ope) = 0; virtual void visit(WeakHolder& ope) = 0; virtual void visit(Holder& ope) = 0; @@ -1021,6 +1036,7 @@ struct AssignIDToDefinition : public Ope::Visitor void visit(AnyCharacter& ope) override {} void visit(Capture& ope) override { ope.ope_->accept(*this); } void visit(Anchor& ope) override { ope.ope_->accept(*this); } + void visit(Ignore& ope) override { ope.ope_->accept(*this); } void visit(User& ope) override {} void visit(WeakHolder& ope) override { ope.weak_.lock()->accept(*this); } void visit(Holder& ope) override; @@ -1046,14 +1062,15 @@ struct IsToken : public Ope::Visitor void visit(ZeroOrMore& ope) override { ope.ope_->accept(*this); } void visit(OneOrMore& ope) override { ope.ope_->accept(*this); } void visit(Option& ope) override { ope.ope_->accept(*this); } - void visit(AndPredicate& ope) override { ope.ope_->accept(*this); } - void visit(NotPredicate& ope) override { ope.ope_->accept(*this); } + void visit(AndPredicate& ope) override {} + void visit(NotPredicate& ope) override {} void visit(LiteralString& ope) override {} void visit(CharacterClass& ope) override {} void visit(Character& ope) override {} void visit(AnyCharacter& ope) override {} void visit(Capture& ope) override { ope.ope_->accept(*this); } void visit(Anchor& ope) override { has_anchor = true; } + void visit(Ignore& ope) override { ope.ope_->accept(*this); } void visit(User& ope) override {} void visit(WeakHolder& ope) override { ope.weak_.lock()->accept(*this); } void visit(Holder& ope) override {} @@ -1342,6 +1359,7 @@ inline void Character::accept(Visitor& v) { v.visit(*this); } inline void AnyCharacter::accept(Visitor& v) { v.visit(*this); } inline void Capture::accept(Visitor& v) { v.visit(*this); } inline void Anchor::accept(Visitor& v) { v.visit(*this); } +inline void Ignore::accept(Visitor& v) { v.visit(*this); } inline void User::accept(Visitor& v) { v.visit(*this); } inline void WeakHolder::accept(Visitor& v) { v.visit(*this); } inline void Holder::accept(Visitor& v) { v.visit(*this); } @@ -1419,6 +1437,10 @@ inline std::shared_ptr anc(const std::shared_ptr& ope) { return std::make_shared(ope); } +inline std::shared_ptr ign(const std::shared_ptr& ope) { + return std::make_shared(ope); +} + inline std::shared_ptr usr(std::function fn) { return std::make_shared(fn); } @@ -1518,7 +1540,7 @@ private: g["Sequence"] <= zom(g["Prefix"]); g["Prefix"] <= seq(opt(cho(g["AND"], g["NOT"])), g["Suffix"]); g["Suffix"] <= seq(g["Primary"], opt(cho(g["QUESTION"], g["STAR"], g["PLUS"]))); - g["Primary"] <= cho(seq(g["Identifier"], npd(g["LEFTARROW"])), + g["Primary"] <= cho(seq(opt(g["IGNORE"]), g["Identifier"], npd(g["LEFTARROW"])), seq(g["OPEN"], g["Expression"], g["CLOSE"]), seq(g["Begin"], g["Expression"], g["End"]), seq(g["BeginCap"], g["Expression"], g["EndCap"]), @@ -1660,9 +1682,18 @@ private: // Reference [&](const SemanticValues& sv, any& dt) { Data& data = *dt.get(); - const auto& ident = sv[0].val.get(); + + auto ignore = (sv.size() == 2); + auto baseId = ignore ? 1 : 0; + + const auto& ident = sv[baseId].val.get(); data.references[ident] = sv.s; // for error handling - return ref(*data.grammar, ident); + + if (ignore) { + return ign(ref(*data.grammar, ident)); + } else { + return ref(*data.grammar, ident); + } }, // (Expression) [&](const SemanticValues& sv) { diff --git a/test/test.cc b/test/test.cc index 6637bea..0442f43 100644 --- a/test/test.cc +++ b/test/test.cc @@ -505,6 +505,45 @@ TEST_CASE("Predicate test", "[general]") REQUIRE(ret == false); } +TEST_CASE("Ignore semantic value test", "[general]") +{ + peg parser( + " START <- ~HELLO WORLD " + " HELLO <- 'Hello' _ " + " WORLD <- 'World' _ " + " _ <- [ \t\r\n]* " + ); + + parser.enable_ast(false); + + shared_ptr ast; + auto ret = parser.parse("Hello World", ast); + + REQUIRE(ret == true); + REQUIRE(ast->nodes.size() == 1); + REQUIRE(ast->nodes[0]->name == "WORLD"); +} + +TEST_CASE("Ignore semantic value of 'or' predicate test", "[general]") +{ + peg parser( + " START <- _ !DUMMY HELLO_WORLD '.' " + " HELLO_WORLD <- HELLO 'World' _ " + " HELLO <- 'Hello' _ " + " DUMMY <- 'dummy' _ " + " ~_ <- [ \t\r\n]* " + ); + + parser.enable_ast(false); + + shared_ptr ast; + auto ret = parser.parse("Hello World.", ast); + + REQUIRE(ret == true); + REQUIRE(ast->nodes.size() == 1); + REQUIRE(ast->nodes[0]->name == "HELLO_WORLD"); +} + TEST_CASE("Ignore semantic value of 'and' predicate test", "[general]") { peg parser(