constexpr BacktrackingParser(const BacktrackingParser &) = default;
constexpr BacktrackingParser(const A &parser) : parser_{parser} {}
std::optional<resultType> Parse(ParseState *state) const {
- Messages messages{std::move(*state->messages())};
+ Messages messages{std::move(state->messages())};
MessageContext context{state->context()};
ParseState backtrack{*state};
std::optional<resultType> result{parser_.Parse(state)};
if (result.has_value()) {
// preserve any new messages
messages.Annex(state->messages());
- state->messages()->swap(messages);
+ state->messages().swap(messages);
} else {
state->swap(backtrack);
- state->messages()->swap(messages);
+ state->messages().swap(messages);
state->set_context(context);
}
return result;
constexpr NegatedParser(const NegatedParser &) = default;
constexpr NegatedParser(const PA &p) : parser_{p} {}
std::optional<Success> Parse(ParseState *state) const {
- Messages messages{std::move(*state->messages())};
+ Messages messages{std::move(state->messages())};
ParseState forked{*state};
- state->messages()->swap(messages);
+ state->messages().swap(messages);
if (parser_.Parse(&forked)) {
return {};
}
constexpr LookAheadParser(const LookAheadParser &) = default;
constexpr LookAheadParser(const PA &p) : parser_{p} {}
std::optional<Success> Parse(ParseState *state) const {
- Messages messages{std::move(*state->messages())};
+ Messages messages{std::move(state->messages())};
ParseState forked{*state};
- state->messages()->swap(messages);
+ state->messages().swap(messages);
if (parser_.Parse(&forked).has_value()) {
return {Success{}};
}
constexpr AlternativeParser(const AlternativeParser &) = default;
constexpr AlternativeParser(const PA &pa, const PB &pb) : pa_{pa}, pb_{pb} {}
std::optional<resultType> Parse(ParseState *state) const {
- Messages messages{std::move(*state->messages())};
+ Messages messages{std::move(state->messages())};
MessageContext context{state->context()};
ParseState backtrack{*state};
+ int depth{state->alternativeDepth()};
+ bool deferred{state->deferMessages()};
+ if (!deferred) {
+ if (depth == 0 && state->messages().empty()) {
+ CHECK(!state->blockedMessages());
+ state->set_deferMessages(true);
+ }
+ }
+ state->set_alternativeDepth(depth + 1);
if (std::optional<resultType> ax{pa_.Parse(state)}) {
- // preserve any new messages
- messages.Annex(state->messages());
- state->messages()->swap(messages);
+ if (!deferred && state->blockedMessages()) {
+ // We deferred messages but now we need them. Regenerate.
+ state->swap(backtrack);
+ state->messages().swap(messages);
+ state->set_context(context);
+ return pa_.Parse(state);
+ }
+ state->set_alternativeDepth(depth)
+ .set_deferMessages(deferred)
+ .set_context(context)
+ .messages().Annex(messages);
return ax;
}
-#if 0 // needed below if "tied" messages are to be saved
- auto start = backtrack.GetLocation();
-#endif
- ParseState paState{std::move(*state)};
+ ParseState backtrack2{backtrack};
state->swap(backtrack);
- state->set_context(context);
+ if (!deferred) {
+ if (depth == 0 && state->messages().empty()) {
+ CHECK(!state->blockedMessages());
+ state->set_deferMessages(true);
+ }
+ }
+ state->set_alternativeDepth(depth + 1);
if (std::optional<resultType> bx{pb_.Parse(state)}) {
- // preserve any new messages
- messages.Annex(state->messages());
- state->messages()->swap(messages);
+ if (!deferred && state->blockedMessages()) {
+ state->swap(backtrack2);
+ state->messages().swap(messages);
+ state->set_context(context);
+ return pb_.Parse(state);
+ }
+ state->set_alternativeDepth(depth)
+ .set_deferMessages(deferred)
+ .set_context(context)
+ .messages().Annex(messages);
return bx;
}
// Both alternatives failed. Retain the state (and messages) from the
// alternative parse that went the furthest.
- auto paEnd = paState.GetLocation();
- auto pbEnd = state->GetLocation();
- if (paEnd > pbEnd) {
- messages.Annex(paState.messages());
- state->swap(paState);
- } else if (paEnd < pbEnd) {
- messages.Annex(state->messages());
+ if (backtrack.GetLocation() >= state->GetLocation()) {
+ if (!deferred && backtrack.blockedMessages()) {
+ state->swap(backtrack2);
+ state->messages().swap(messages);
+ state->set_context(context);
+ return pa_.Parse(state);
+ }
+ state->swap(backtrack);
} else {
- // It's a tie.
- messages.Annex(paState.messages());
-#if 0
- if (paEnd > start) {
- // Both parsers consumed text; retain messages from both.
- messages.Annex(state->messages());
+ if (!deferred && state->blockedMessages()) {
+ state->swap(backtrack2);
+ state->messages().swap(messages);
+ state->set_context(context);
+ return pb_.Parse(state);
}
-#endif
}
- state->messages()->swap(messages);
+ state->set_alternativeDepth(depth)
+ .set_deferMessages(deferred)
+ .set_context(context)
+ .messages().Annex(messages);
return {};
}
constexpr RecoveryParser(const RecoveryParser &) = default;
constexpr RecoveryParser(const PA &pa, const PB &pb) : pa_{pa}, pb_{pb} {}
std::optional<resultType> Parse(ParseState *state) const {
- Messages messages{std::move(*state->messages())};
+ Messages messages{std::move(state->messages())};
MessageContext context{state->context()};
ParseState backtrack{*state};
std::optional<resultType> ax{pa_.Parse(state)};
messages.Annex(state->messages());
if (ax.has_value()) {
- state->messages()->swap(messages);
+ state->messages().swap(messages);
return ax;
}
state->swap(backtrack);
state->set_context(context);
std::optional<resultType> bx{pb_.Parse(state)};
- state->messages()->swap(messages);
+ state->messages().swap(messages);
if (bx.has_value()) {
state->set_anyErrorRecovery();
}
warnOnNonstandardUsage_{that.warnOnNonstandardUsage_},
warnOnDeprecatedUsage_{that.warnOnDeprecatedUsage_},
anyErrorRecovery_{that.anyErrorRecovery_},
- anyConformanceViolation_{that.anyConformanceViolation_} {}
+ anyConformanceViolation_{that.anyConformanceViolation_},
+ alternativeDepth_{that.alternativeDepth_},
+ deferMessages_{that.deferMessages_}, blockedMessages_{
+ that.blockedMessages_} {}
ParseState(ParseState &&that)
: p_{that.p_}, limit_{that.limit_}, messages_{std::move(that.messages_)},
context_{std::move(that.context_)}, userState_{that.userState_},
warnOnNonstandardUsage_{that.warnOnNonstandardUsage_},
warnOnDeprecatedUsage_{that.warnOnDeprecatedUsage_},
anyErrorRecovery_{that.anyErrorRecovery_},
- anyConformanceViolation_{that.anyConformanceViolation_} {}
+ anyConformanceViolation_{that.anyConformanceViolation_},
+ alternativeDepth_{that.alternativeDepth_},
+ deferMessages_{that.deferMessages_}, blockedMessages_{
+ that.blockedMessages_} {}
ParseState &operator=(ParseState &&that) {
swap(that);
return *this;
std::memcpy(&that, buffer, bytes);
}
- Messages *messages() { return &messages_; }
+ Messages &messages() { return messages_; }
bool anyErrorRecovery() const { return anyErrorRecovery_; }
void set_anyErrorRecovery() { anyErrorRecovery_ = true; }
return *this;
}
+ int alternativeDepth() const { return alternativeDepth_; }
+ ParseState &set_alternativeDepth(int d) {
+ alternativeDepth_ = d;
+ return *this;
+ }
+
+ bool deferMessages() const { return deferMessages_; }
+ ParseState &set_deferMessages(bool yes) {
+ deferMessages_ = yes;
+ return *this;
+ }
+
+ bool blockedMessages() const { return blockedMessages_; }
+
const char *GetLocation() const { return p_; }
MessageContext &PushContext(MessageFixedText text) {
}
}
- Message &Say(MessageFixedText t) { return Say(p_, t); }
- Message &Say(MessageFormattedText &&t) { return Say(p_, std::move(t)); }
- Message &Say(MessageExpectedText &&t) { return Say(p_, std::move(t)); }
+ void Say(MessageFixedText t) { return Say(p_, t); }
+ void Say(MessageFormattedText &&t) { return Say(p_, std::move(t)); }
+ void Say(MessageExpectedText &&t) { return Say(p_, std::move(t)); }
- Message &Say(const char *at, MessageFixedText t) {
- return messages_.Put(Message{at, t, context_});
+ void Say(const char *at, MessageFixedText t) {
+ if (deferMessages_) {
+ blockedMessages_ = true;
+ } else {
+ messages_.Put(Message{at, t, context_});
+ }
}
- Message &Say(const char *at, MessageFormattedText &&t) {
- return messages_.Put(Message{at, std::move(t), context_});
+ void Say(const char *at, MessageFormattedText &&t) {
+ if (deferMessages_) {
+ blockedMessages_ = true;
+ } else {
+ messages_.Put(Message{at, std::move(t), context_});
+ }
}
- Message &Say(const char *at, MessageExpectedText &&t) {
- return messages_.Put(Message{at, std::move(t), context_});
+ void Say(const char *at, MessageExpectedText &&t) {
+ if (deferMessages_) {
+ blockedMessages_ = true;
+ } else {
+ messages_.Put(Message{at, std::move(t), context_});
+ }
}
bool IsAtEnd() const { return p_ >= limit_; }
bool warnOnDeprecatedUsage_{false};
bool anyErrorRecovery_{false};
bool anyConformanceViolation_{false};
+ int alternativeDepth_{0};
+ bool deferMessages_{false};
+ bool blockedMessages_{false};
// NOTE: Any additions or modifications to these data members must also be
// reflected in the copy and move constructors defined at the top of this
// class definition!