2018-02-16 20:42:17 +01:00
|
|
|
#ifndef FORTRAN_PARSER_PARSE_STATE_H_
|
|
|
|
#define FORTRAN_PARSER_PARSE_STATE_H_
|
2018-01-30 20:51:59 +01:00
|
|
|
|
|
|
|
// Defines the ParseState type used as the argument for every parser's
|
2018-02-09 23:04:11 +01:00
|
|
|
// Parse member or static function. Tracks source provenance, context,
|
|
|
|
// accumulated messages, and an arbitrary UserState instance for parsing
|
|
|
|
// attempts. Must be efficient to duplicate and assign for backtracking
|
|
|
|
// and recovery during parsing!
|
2018-01-30 20:51:59 +01:00
|
|
|
|
|
|
|
#include "idioms.h"
|
|
|
|
#include "message.h"
|
2018-02-09 23:04:11 +01:00
|
|
|
#include "provenance.h"
|
2018-01-30 20:51:59 +01:00
|
|
|
#include <cstring>
|
|
|
|
#include <list>
|
|
|
|
#include <memory>
|
|
|
|
#include <optional>
|
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
namespace Fortran {
|
2018-02-07 21:04:42 +01:00
|
|
|
namespace parser {
|
2018-01-30 20:51:59 +01:00
|
|
|
|
|
|
|
class UserState;
|
|
|
|
|
|
|
|
class ParseState {
|
2018-02-05 21:54:36 +01:00
|
|
|
public:
|
2018-02-15 19:42:36 +01:00
|
|
|
// TODO: Add a constructor for parsing a normalized module file.
|
2018-02-09 23:04:11 +01:00
|
|
|
ParseState(const CookedSource &cooked)
|
2018-02-15 19:42:36 +01:00
|
|
|
: cooked_{cooked}, p_{&cooked[0]}, limit_{p_ + cooked.size()},
|
|
|
|
messages_{*cooked.allSources()} {}
|
2018-01-30 20:51:59 +01:00
|
|
|
ParseState(const ParseState &that)
|
2018-02-15 19:42:36 +01:00
|
|
|
: cooked_{that.cooked_}, p_{that.p_}, limit_{that.limit_},
|
2018-02-12 21:48:13 +01:00
|
|
|
column_{that.column_}, messages_{*that.cooked_.allSources()},
|
2018-02-16 19:41:16 +01:00
|
|
|
userState_{that.userState_}, inFixedForm_{that.inFixedForm_},
|
2018-02-05 23:29:26 +01:00
|
|
|
enableBackslashEscapesInCharLiterals_{
|
|
|
|
that.enableBackslashEscapesInCharLiterals_},
|
2018-01-30 20:51:59 +01:00
|
|
|
strictConformance_{that.strictConformance_},
|
|
|
|
warnOnNonstandardUsage_{that.warnOnNonstandardUsage_},
|
|
|
|
warnOnDeprecatedUsage_{that.warnOnDeprecatedUsage_},
|
2018-02-16 19:58:17 +01:00
|
|
|
anyErrorRecovery_{that.anyErrorRecovery_} {}
|
2018-01-30 20:51:59 +01:00
|
|
|
ParseState(ParseState &&that)
|
2018-02-15 19:42:36 +01:00
|
|
|
: cooked_{that.cooked_}, p_{that.p_}, limit_{that.limit_},
|
|
|
|
column_{that.column_}, messages_{std::move(that.messages_)},
|
|
|
|
context_{std::move(that.context_)}, userState_{that.userState_},
|
|
|
|
inFixedForm_{that.inFixedForm_},
|
2018-02-05 23:29:26 +01:00
|
|
|
enableBackslashEscapesInCharLiterals_{
|
|
|
|
that.enableBackslashEscapesInCharLiterals_},
|
2018-01-30 20:51:59 +01:00
|
|
|
strictConformance_{that.strictConformance_},
|
|
|
|
warnOnNonstandardUsage_{that.warnOnNonstandardUsage_},
|
|
|
|
warnOnDeprecatedUsage_{that.warnOnDeprecatedUsage_},
|
2018-02-16 19:58:17 +01:00
|
|
|
anyErrorRecovery_{that.anyErrorRecovery_} {}
|
2018-01-30 20:51:59 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2018-02-12 21:48:13 +01:00
|
|
|
const CookedSource &cooked() const { return cooked_; }
|
|
|
|
int column() const { return column_; }
|
|
|
|
Messages *messages() { return &messages_; }
|
|
|
|
|
2018-01-30 20:51:59 +01:00
|
|
|
bool anyErrorRecovery() const { return anyErrorRecovery_; }
|
|
|
|
void set_anyErrorRecovery() { anyErrorRecovery_ = true; }
|
|
|
|
|
|
|
|
UserState *userState() const { return userState_; }
|
|
|
|
void set_userState(UserState *u) { userState_ = u; }
|
|
|
|
|
|
|
|
MessageContext context() const { return context_; }
|
2018-02-15 19:42:36 +01:00
|
|
|
ParseState &set_context(MessageContext c) {
|
2018-01-30 20:51:59 +01:00
|
|
|
context_ = c;
|
2018-02-15 19:42:36 +01:00
|
|
|
return *this;
|
2018-01-30 20:51:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool inFixedForm() const { return inFixedForm_; }
|
2018-02-15 19:42:36 +01:00
|
|
|
ParseState &set_inFixedForm(bool yes) {
|
2018-01-30 20:51:59 +01:00
|
|
|
inFixedForm_ = yes;
|
2018-02-15 19:42:36 +01:00
|
|
|
return *this;
|
2018-01-30 20:51:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool enableBackslashEscapesInCharLiterals() const {
|
|
|
|
return enableBackslashEscapesInCharLiterals_;
|
|
|
|
}
|
2018-02-15 19:42:36 +01:00
|
|
|
ParseState &set_enableBackslashEscapesInCharLiterals(bool yes) {
|
2018-01-30 20:51:59 +01:00
|
|
|
enableBackslashEscapesInCharLiterals_ = yes;
|
2018-02-15 19:42:36 +01:00
|
|
|
return *this;
|
2018-01-30 20:51:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool strictConformance() const { return strictConformance_; }
|
2018-02-15 19:42:36 +01:00
|
|
|
ParseState &set_strictConformance(bool yes) {
|
2018-01-30 20:51:59 +01:00
|
|
|
strictConformance_ = yes;
|
2018-02-15 19:42:36 +01:00
|
|
|
return *this;
|
2018-01-30 20:51:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool warnOnNonstandardUsage() const { return warnOnNonstandardUsage_; }
|
2018-02-15 19:42:36 +01:00
|
|
|
ParseState &set_warnOnNonstandardUsage(bool yes) {
|
2018-01-30 20:51:59 +01:00
|
|
|
warnOnNonstandardUsage_ = yes;
|
2018-02-15 19:42:36 +01:00
|
|
|
return *this;
|
2018-01-30 20:51:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool warnOnDeprecatedUsage() const { return warnOnDeprecatedUsage_; }
|
2018-02-15 19:42:36 +01:00
|
|
|
ParseState &set_warnOnDeprecatedUsage(bool yes) {
|
2018-01-30 20:51:59 +01:00
|
|
|
warnOnDeprecatedUsage_ = yes;
|
2018-02-15 19:42:36 +01:00
|
|
|
return *this;
|
2018-01-30 20:51:59 +01:00
|
|
|
}
|
|
|
|
|
2018-02-09 23:04:11 +01:00
|
|
|
const char *GetLocation() const { return p_; }
|
|
|
|
Provenance GetProvenance(const char *at) const {
|
2018-02-15 19:42:36 +01:00
|
|
|
return cooked_.GetProvenance(at).LocalOffsetToProvenance(0);
|
2018-02-09 23:04:11 +01:00
|
|
|
}
|
|
|
|
Provenance GetProvenance() const { return GetProvenance(p_); }
|
|
|
|
|
|
|
|
void PushContext(const std::string &str) {
|
|
|
|
context_ = std::make_shared<Message>(GetProvenance(), str, context_);
|
|
|
|
}
|
|
|
|
void PushContext(std::string &&str) {
|
|
|
|
context_ =
|
|
|
|
std::make_shared<Message>(GetProvenance(), std::move(str), context_);
|
|
|
|
}
|
|
|
|
void PushContext(const char *str) {
|
|
|
|
context_ = std::make_shared<Message>(GetProvenance(), str, context_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PopContext() {
|
|
|
|
if (context_) {
|
|
|
|
context_ = context_->context();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PutMessage(Provenance at, const std::string &msg) {
|
|
|
|
messages_.Put(Message{at, msg, context_});
|
|
|
|
}
|
|
|
|
void PutMessage(const char *at, const std::string &msg) {
|
|
|
|
PutMessage(GetProvenance(at), msg);
|
|
|
|
}
|
|
|
|
void PutMessage(const std::string &msg) { PutMessage(p_, msg); }
|
|
|
|
void PutMessage(Provenance at, std::string &&msg) {
|
|
|
|
messages_.Put(Message{at, std::move(msg), context_});
|
|
|
|
}
|
|
|
|
void PutMessage(const char *at, std::string &&msg) {
|
|
|
|
PutMessage(GetProvenance(at), std::move(msg));
|
|
|
|
}
|
|
|
|
void PutMessage(std::string &&msg) { PutMessage(p_, std::move(msg)); }
|
|
|
|
void PutMessage(Provenance at, const char *msg) {
|
|
|
|
PutMessage(at, std::string{msg});
|
|
|
|
}
|
|
|
|
void PutMessage(const char *at, const char *msg) {
|
|
|
|
PutMessage(GetProvenance(at), msg);
|
|
|
|
}
|
|
|
|
void PutMessage(const char *msg) { PutMessage(p_, msg); }
|
|
|
|
|
2018-02-15 19:42:36 +01:00
|
|
|
bool IsAtEnd() const { return p_ >= limit_; }
|
2018-01-30 20:51:59 +01:00
|
|
|
|
2018-02-16 19:41:16 +01:00
|
|
|
std::optional<char> GetNextChar() {
|
|
|
|
if (p_ >= limit_) {
|
|
|
|
return {};
|
2018-01-30 20:51:59 +01:00
|
|
|
}
|
2018-02-16 19:41:16 +01:00
|
|
|
char ch{*p_++};
|
|
|
|
++column_;
|
|
|
|
if (ch == '\n') {
|
2018-02-09 23:04:11 +01:00
|
|
|
column_ = 1;
|
2018-01-30 20:51:59 +01:00
|
|
|
}
|
2018-02-16 19:41:16 +01:00
|
|
|
return {ch};
|
2018-01-30 20:51:59 +01:00
|
|
|
}
|
|
|
|
|
2018-02-05 21:54:36 +01:00
|
|
|
private:
|
2018-01-30 20:51:59 +01:00
|
|
|
// Text remaining to be parsed
|
2018-02-09 23:04:11 +01:00
|
|
|
const CookedSource &cooked_;
|
2018-02-15 19:42:36 +01:00
|
|
|
const char *p_{nullptr}, *limit_{nullptr};
|
2018-02-09 23:04:11 +01:00
|
|
|
int column_{1};
|
2018-01-30 20:51:59 +01:00
|
|
|
|
|
|
|
// Accumulated messages and current nested context.
|
|
|
|
Messages messages_;
|
|
|
|
MessageContext context_;
|
|
|
|
|
|
|
|
UserState *userState_{nullptr};
|
|
|
|
|
|
|
|
bool inFixedForm_{false};
|
|
|
|
bool enableBackslashEscapesInCharLiterals_{true};
|
|
|
|
bool strictConformance_{false};
|
|
|
|
bool warnOnNonstandardUsage_{false};
|
|
|
|
bool warnOnDeprecatedUsage_{false};
|
|
|
|
bool anyErrorRecovery_{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!
|
|
|
|
};
|
2018-02-07 21:04:42 +01:00
|
|
|
} // namespace parser
|
2018-01-30 20:51:59 +01:00
|
|
|
} // namespace Fortran
|
2018-02-16 20:42:17 +01:00
|
|
|
#endif // FORTRAN_PARSER_PARSE_STATE_H_
|