1 //===-- include/flang/Parser/parse-state.h ----------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef FORTRAN_PARSER_PARSE_STATE_H_ 10 #define FORTRAN_PARSER_PARSE_STATE_H_ 11 12 // Defines the ParseState type used as the argument for every parser's 13 // Parse member or static function. Tracks source provenance, context, 14 // accumulated messages, and an arbitrary UserState instance for parsing 15 // attempts. Must be efficient to duplicate and assign for backtracking 16 // and recovery during parsing! 17 18 #include "user-state.h" 19 #include "flang/Common/Fortran-features.h" 20 #include "flang/Common/idioms.h" 21 #include "flang/Parser/characters.h" 22 #include "flang/Parser/message.h" 23 #include "flang/Parser/provenance.h" 24 #include <cstddef> 25 #include <cstring> 26 #include <list> 27 #include <memory> 28 #include <optional> 29 #include <utility> 30 31 namespace Fortran::parser { 32 33 using common::LanguageFeature; 34 35 class ParseState { 36 public: ParseState(const CookedSource & cooked)37 ParseState(const CookedSource &cooked) 38 : p_{cooked.AsCharBlock().begin()}, limit_{cooked.AsCharBlock().end()} {} ParseState(const ParseState & that)39 ParseState(const ParseState &that) 40 : p_{that.p_}, limit_{that.limit_}, context_{that.context_}, 41 userState_{that.userState_}, inFixedForm_{that.inFixedForm_}, 42 anyErrorRecovery_{that.anyErrorRecovery_}, 43 anyConformanceViolation_{that.anyConformanceViolation_}, 44 deferMessages_{that.deferMessages_}, 45 anyDeferredMessages_{that.anyDeferredMessages_}, 46 anyTokenMatched_{that.anyTokenMatched_} {} ParseState(ParseState && that)47 ParseState(ParseState &&that) 48 : p_{that.p_}, limit_{that.limit_}, messages_{std::move(that.messages_)}, 49 context_{std::move(that.context_)}, userState_{that.userState_}, 50 inFixedForm_{that.inFixedForm_}, 51 anyErrorRecovery_{that.anyErrorRecovery_}, 52 anyConformanceViolation_{that.anyConformanceViolation_}, 53 deferMessages_{that.deferMessages_}, 54 anyDeferredMessages_{that.anyDeferredMessages_}, 55 anyTokenMatched_{that.anyTokenMatched_} {} 56 ParseState &operator=(const ParseState &that) { 57 p_ = that.p_, limit_ = that.limit_, context_ = that.context_; 58 userState_ = that.userState_, inFixedForm_ = that.inFixedForm_; 59 anyErrorRecovery_ = that.anyErrorRecovery_; 60 anyConformanceViolation_ = that.anyConformanceViolation_; 61 deferMessages_ = that.deferMessages_; 62 anyDeferredMessages_ = that.anyDeferredMessages_; 63 anyTokenMatched_ = that.anyTokenMatched_; 64 return *this; 65 } 66 ParseState &operator=(ParseState &&that) { 67 p_ = that.p_, limit_ = that.limit_, messages_ = std::move(that.messages_); 68 context_ = std::move(that.context_); 69 userState_ = that.userState_, inFixedForm_ = that.inFixedForm_; 70 anyErrorRecovery_ = that.anyErrorRecovery_; 71 anyConformanceViolation_ = that.anyConformanceViolation_; 72 deferMessages_ = that.deferMessages_; 73 anyDeferredMessages_ = that.anyDeferredMessages_; 74 anyTokenMatched_ = that.anyTokenMatched_; 75 return *this; 76 } 77 messages()78 const Messages &messages() const { return messages_; } messages()79 Messages &messages() { return messages_; } 80 context()81 const Message::Reference &context() const { return context_; } context()82 Message::Reference &context() { return context_; } 83 anyErrorRecovery()84 bool anyErrorRecovery() const { return anyErrorRecovery_; } set_anyErrorRecovery()85 void set_anyErrorRecovery() { anyErrorRecovery_ = true; } 86 anyConformanceViolation()87 bool anyConformanceViolation() const { return anyConformanceViolation_; } set_anyConformanceViolation()88 void set_anyConformanceViolation() { anyConformanceViolation_ = true; } 89 userState()90 UserState *userState() const { return userState_; } set_userState(UserState * u)91 ParseState &set_userState(UserState *u) { 92 userState_ = u; 93 return *this; 94 } 95 inFixedForm()96 bool inFixedForm() const { return inFixedForm_; } 97 ParseState &set_inFixedForm(bool yes = true) { 98 inFixedForm_ = yes; 99 return *this; 100 } 101 deferMessages()102 bool deferMessages() const { return deferMessages_; } 103 ParseState &set_deferMessages(bool yes = true) { 104 deferMessages_ = yes; 105 return *this; 106 } 107 anyDeferredMessages()108 bool anyDeferredMessages() const { return anyDeferredMessages_; } 109 ParseState &set_anyDeferredMessages(bool yes = true) { 110 anyDeferredMessages_ = yes; 111 return *this; 112 } 113 anyTokenMatched()114 bool anyTokenMatched() const { return anyTokenMatched_; } 115 ParseState &set_anyTokenMatched(bool yes = true) { 116 anyTokenMatched_ = yes; 117 return *this; 118 } 119 GetLocation()120 const char *GetLocation() const { return p_; } 121 PushContext(MessageFixedText text)122 void PushContext(MessageFixedText text) { 123 auto m{new Message{p_, text}}; // reference-counted 124 m->SetContext(context_.get()); 125 context_ = Message::Reference{m}; 126 } 127 PopContext()128 void PopContext() { 129 CHECK(context_); 130 context_ = context_->attachment(); 131 } 132 Say(CharBlock range,A &&...args)133 template <typename... A> void Say(CharBlock range, A &&...args) { 134 if (deferMessages_) { 135 anyDeferredMessages_ = true; 136 } else { 137 messages_.Say(range, std::forward<A>(args)...).SetContext(context_.get()); 138 } 139 } Say(const MessageFixedText & text,A &&...args)140 template <typename... A> void Say(const MessageFixedText &text, A &&...args) { 141 Say(p_, text, std::forward<A>(args)...); 142 } 143 template <typename... A> Say(const MessageExpectedText & text,A &&...args)144 void Say(const MessageExpectedText &text, A &&...args) { 145 Say(p_, text, std::forward<A>(args)...); 146 } 147 Nonstandard(LanguageFeature lf,const MessageFixedText & msg)148 void Nonstandard(LanguageFeature lf, const MessageFixedText &msg) { 149 Nonstandard(p_, lf, msg); 150 } Nonstandard(CharBlock range,LanguageFeature lf,const MessageFixedText & msg)151 void Nonstandard( 152 CharBlock range, LanguageFeature lf, const MessageFixedText &msg) { 153 anyConformanceViolation_ = true; 154 if (userState_ && userState_->features().ShouldWarn(lf)) { 155 Say(range, msg); 156 } 157 } IsNonstandardOk(LanguageFeature lf,const MessageFixedText & msg)158 bool IsNonstandardOk(LanguageFeature lf, const MessageFixedText &msg) { 159 if (userState_ && !userState_->features().IsEnabled(lf)) { 160 return false; 161 } 162 Nonstandard(lf, msg); 163 return true; 164 } 165 IsAtEnd()166 bool IsAtEnd() const { return p_ >= limit_; } 167 168 const char *UncheckedAdvance(std::size_t n = 1) { 169 const char *result{p_}; 170 p_ += n; 171 return result; 172 } 173 GetNextChar()174 std::optional<const char *> GetNextChar() { 175 if (p_ < limit_) { 176 return UncheckedAdvance(); 177 } else { 178 return std::nullopt; 179 } 180 } 181 PeekAtNextChar()182 std::optional<const char *> PeekAtNextChar() const { 183 if (p_ < limit_) { 184 return p_; 185 } else { 186 return std::nullopt; 187 } 188 } 189 BytesRemaining()190 std::size_t BytesRemaining() const { 191 std::size_t remain = limit_ - p_; 192 return remain; 193 } 194 CombineFailedParses(ParseState && prev)195 void CombineFailedParses(ParseState &&prev) { 196 if (prev.anyTokenMatched_) { 197 if (!anyTokenMatched_ || prev.p_ > p_) { 198 anyTokenMatched_ = true; 199 p_ = prev.p_; 200 messages_ = std::move(prev.messages_); 201 } else if (prev.p_ == p_) { 202 messages_.Merge(std::move(prev.messages_)); 203 } 204 } 205 anyDeferredMessages_ |= prev.anyDeferredMessages_; 206 anyConformanceViolation_ |= prev.anyConformanceViolation_; 207 anyErrorRecovery_ |= prev.anyErrorRecovery_; 208 } 209 210 private: 211 // Text remaining to be parsed 212 const char *p_{nullptr}, *limit_{nullptr}; 213 214 // Accumulated messages and current nested context. 215 Messages messages_; 216 Message::Reference context_; 217 218 UserState *userState_{nullptr}; 219 220 bool inFixedForm_{false}; 221 bool anyErrorRecovery_{false}; 222 bool anyConformanceViolation_{false}; 223 bool deferMessages_{false}; 224 bool anyDeferredMessages_{false}; 225 bool anyTokenMatched_{false}; 226 // NOTE: Any additions or modifications to these data members must also be 227 // reflected in the copy and move constructors defined at the top of this 228 // class definition! 229 }; 230 } // namespace Fortran::parser 231 #endif // FORTRAN_PARSER_PARSE_STATE_H_ 232