--- /dev/null
+#ifndef FORTRAN_PARSE_STATE_H_
+#define FORTRAN_PARSE_STATE_H_
+
+// Defines the ParseState type used as the argument for every parser's
+// Parse member or static function. Tracks position, context, accumulated
+// messages, and an arbitrary UserState instance for parsing attempts.
+// Must be efficient to duplicate and assign for backtracking and recovery
+// during parsing!
+
+#include "idioms.h"
+#include "message.h"
+#include "position.h"
+#include <cstring>
+#include <list>
+#include <memory>
+#include <optional>
+#include <utility>
+
+namespace Fortran {
+
+class UserState;
+
+class ParseState {
+ public:
+ ParseState() {}
+ ParseState(const char *str) : p_{str}, remaining_{std::strlen(str)} {}
+ ParseState(const char *str, size_t bytes) : p_{str}, remaining_{bytes} {}
+ ParseState(const ParseState &that)
+ : p_{that.p_}, remaining_{that.remaining_}, position_{that.position_},
+ userState_{that.userState_},
+ inCharLiteral_{that.inCharLiteral_}, inFortran_{that.inFortran_},
+ inFixedForm_{that.inFixedForm_},
+ enableOldDebugLines_{that.enableOldDebugLines_}, columns_{that.columns_},
+ enableBackslashEscapesInCharLiterals_
+ {that.enableBackslashEscapesInCharLiterals_},
+ strictConformance_{that.strictConformance_},
+ warnOnNonstandardUsage_{that.warnOnNonstandardUsage_},
+ warnOnDeprecatedUsage_{that.warnOnDeprecatedUsage_},
+ skippedNewLines_{that.skippedNewLines_},
+ tabInCurrentLine_{that.tabInCurrentLine_},
+ anyErrorRecovery_{that.anyErrorRecovery_},
+ prescanned_{that.prescanned_} {}
+ ParseState(ParseState &&that)
+ : p_{that.p_}, remaining_{that.remaining_}, position_{that.position_},
+ messages_{std::move(that.messages_)}, context_{std::move(that.context_)},
+ userState_{that.userState_},
+ inCharLiteral_{that.inCharLiteral_}, inFortran_{that.inFortran_},
+ inFixedForm_{that.inFixedForm_},
+ enableOldDebugLines_{that.enableOldDebugLines_}, columns_{that.columns_},
+ enableBackslashEscapesInCharLiterals_
+ {that.enableBackslashEscapesInCharLiterals_},
+ strictConformance_{that.strictConformance_},
+ warnOnNonstandardUsage_{that.warnOnNonstandardUsage_},
+ warnOnDeprecatedUsage_{that.warnOnDeprecatedUsage_},
+ skippedNewLines_{that.skippedNewLines_},
+ tabInCurrentLine_{that.tabInCurrentLine_},
+ anyErrorRecovery_{that.anyErrorRecovery_},
+ prescanned_{that.prescanned_} {}
+ ParseState &operator=(ParseState &&that) {
+ swap(that);
+ return *this;
+ }
+
+ void swap(ParseState &that) {
+ constexpr size_t bytes{sizeof *this};
+ char buffer[bytes];
+ std::memcpy(buffer, this, bytes);
+ std::memcpy(this, &that, bytes);
+ std::memcpy(&that, buffer, bytes);
+ }
+
+ Position position() const { return position_; }
+
+ bool anyErrorRecovery() const { return anyErrorRecovery_; }
+ void set_anyErrorRecovery() { anyErrorRecovery_ = true; }
+
+ UserState *userState() const { return userState_; }
+ void set_userState(UserState *u) { userState_ = u; }
+
+ Messages *messages() { return &messages_; }
+
+ MessageContext context() const { return context_; }
+ MessageContext set_context(MessageContext c) {
+ MessageContext was{context_};
+ context_ = c;
+ return was;
+ }
+
+ void PushContext(const std::string &str) {
+ context_ = std::make_shared<Message>(position_, str, context_);
+ }
+ void PushContext(std::string &&str) {
+ context_ = std::make_shared<Message>(position_, std::move(str), context_);
+ }
+ void PushContext(const char *str) {
+ context_ = std::make_shared<Message>(position_, str, context_);
+ }
+
+ void PopContext() {
+ if (context_) {
+ context_ = context_->context();
+ }
+ }
+
+ bool inCharLiteral() const { return inCharLiteral_; }
+ bool set_inCharLiteral(bool yes) {
+ bool was{inCharLiteral_};
+ inCharLiteral_ = yes;
+ return was;
+ }
+
+ bool inFortran() const { return inFortran_; }
+ bool set_inFortran(bool yes) {
+ bool was{inFortran_};
+ inFortran_ = yes;
+ return was;
+ }
+
+ bool inFixedForm() const { return inFixedForm_; }
+ bool set_inFixedForm(bool yes) {
+ bool was{inFixedForm_};
+ inFixedForm_ = yes;
+ return was;
+ }
+
+ bool enableOldDebugLines() const { return enableOldDebugLines_; }
+ bool set_enableOldDebugLines(bool yes) {
+ bool was{enableOldDebugLines_};
+ enableOldDebugLines_ = yes;
+ return was;
+ }
+
+ int columns() const { return columns_; }
+ int set_columns(int cols) {
+ int was{columns_};
+ columns_ = cols;
+ return was;
+ }
+
+ bool enableBackslashEscapesInCharLiterals() const {
+ return enableBackslashEscapesInCharLiterals_;
+ }
+ bool set_enableBackslashEscapesInCharLiterals(bool yes) {
+ bool was{enableBackslashEscapesInCharLiterals_};
+ enableBackslashEscapesInCharLiterals_ = yes;
+ return was;
+ }
+
+ bool strictConformance() const { return strictConformance_; }
+ bool set_strictConformance(bool yes) {
+ bool was{strictConformance_};
+ strictConformance_ = yes;
+ return was;
+ }
+
+ bool warnOnNonstandardUsage() const { return warnOnNonstandardUsage_; }
+ bool set_warnOnNonstandardUsage(bool yes) {
+ bool was{warnOnNonstandardUsage_};
+ warnOnNonstandardUsage_ = yes;
+ return was;
+ }
+
+ bool warnOnDeprecatedUsage() const { return warnOnDeprecatedUsage_; }
+ bool set_warnOnDeprecatedUsage(bool yes) {
+ bool was{warnOnDeprecatedUsage_};
+ warnOnDeprecatedUsage_ = yes;
+ return was;
+ }
+
+ int skippedNewLines() const { return skippedNewLines_; }
+ void set_skippedNewLines(int n) { skippedNewLines_ = n; }
+
+ bool prescanned() const { return prescanned_; }
+ void set_prescanned(bool yes) { prescanned_ = yes; }
+
+ bool tabInCurrentLine() const { return tabInCurrentLine_; }
+
+ bool IsAtEnd() const { return remaining_ == 0; }
+
+ std::optional<char> GetNextRawChar() const {
+ if (remaining_ > 0) {
+ return {*p_};
+ }
+ return {};
+ }
+
+ void Advance() {
+ CHECK(remaining_ > 0);
+ --remaining_;
+ if (*p_ == '\n') {
+ position_.AdvanceLine();
+ tabInCurrentLine_ = false;
+ } else if (*p_ == '\t') {
+ position_.TabAdvanceColumn();
+ tabInCurrentLine_ = true;
+ } else {
+ position_.AdvanceColumn();
+ }
+ ++p_;
+ }
+
+ void AdvancePositionForPadding() {
+ position_.AdvanceColumn();
+ }
+
+ private:
+ // Text remaining to be parsed
+ const char *p_{nullptr};
+ size_t remaining_{0};
+ Position position_;
+
+ // Accumulated messages and current nested context.
+ Messages messages_;
+ MessageContext context_;
+
+ UserState *userState_{nullptr};
+
+ bool inCharLiteral_{false};
+ bool inFortran_{true};
+ bool inFixedForm_{false};
+ bool enableOldDebugLines_{false};
+ int columns_{72};
+ bool enableBackslashEscapesInCharLiterals_{true};
+ bool strictConformance_{false};
+ bool warnOnNonstandardUsage_{false};
+ bool warnOnDeprecatedUsage_{false};
+ int skippedNewLines_{0};
+ bool tabInCurrentLine_{false};
+ bool anyErrorRecovery_{false};
+ bool prescanned_{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!
+};
+} // namespace Fortran
+#endif // FORTRAN_PARSE_STATE_H_