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: 37 // TODO: Add a constructor for parsing a normalized module file. ParseState(const CookedSource & cooked)38 ParseState(const CookedSource &cooked) 39 : p_{cooked.AsCharBlock().begin()}, limit_{cooked.AsCharBlock().end()} {} ParseState(const ParseState & that)40 ParseState(const ParseState &that) 41 : p_{that.p_}, limit_{that.limit_}, context_{that.context_}, 42 userState_{that.userState_}, inFixedForm_{that.inFixedForm_}, 43 anyErrorRecovery_{that.anyErrorRecovery_}, 44 anyConformanceViolation_{that.anyConformanceViolation_}, 45 deferMessages_{that.deferMessages_}, 46 anyDeferredMessages_{that.anyDeferredMessages_}, 47 anyTokenMatched_{that.anyTokenMatched_} {} ParseState(ParseState && that)48 ParseState(ParseState &&that) 49 : p_{that.p_}, limit_{that.limit_}, messages_{std::move(that.messages_)}, 50 context_{std::move(that.context_)}, userState_{that.userState_}, 51 inFixedForm_{that.inFixedForm_}, 52 anyErrorRecovery_{that.anyErrorRecovery_}, 53 anyConformanceViolation_{that.anyConformanceViolation_}, 54 deferMessages_{that.deferMessages_}, 55 anyDeferredMessages_{that.anyDeferredMessages_}, 56 anyTokenMatched_{that.anyTokenMatched_} {} 57 ParseState &operator=(const ParseState &that) { 58 p_ = that.p_, limit_ = that.limit_, context_ = that.context_; 59 userState_ = that.userState_, inFixedForm_ = that.inFixedForm_; 60 anyErrorRecovery_ = that.anyErrorRecovery_; 61 anyConformanceViolation_ = that.anyConformanceViolation_; 62 deferMessages_ = that.deferMessages_; 63 anyDeferredMessages_ = that.anyDeferredMessages_; 64 anyTokenMatched_ = that.anyTokenMatched_; 65 return *this; 66 } 67 ParseState &operator=(ParseState &&that) { 68 p_ = that.p_, limit_ = that.limit_, messages_ = std::move(that.messages_); 69 context_ = std::move(that.context_); 70 userState_ = that.userState_, inFixedForm_ = that.inFixedForm_; 71 anyErrorRecovery_ = that.anyErrorRecovery_; 72 anyConformanceViolation_ = that.anyConformanceViolation_; 73 deferMessages_ = that.deferMessages_; 74 anyDeferredMessages_ = that.anyDeferredMessages_; 75 anyTokenMatched_ = that.anyTokenMatched_; 76 return *this; 77 } 78 messages()79 const Messages &messages() const { return messages_; } messages()80 Messages &messages() { return messages_; } 81 context()82 const Message::Reference &context() const { return context_; } context()83 Message::Reference &context() { return context_; } 84 anyErrorRecovery()85 bool anyErrorRecovery() const { return anyErrorRecovery_; } set_anyErrorRecovery()86 void set_anyErrorRecovery() { anyErrorRecovery_ = true; } 87 anyConformanceViolation()88 bool anyConformanceViolation() const { return anyConformanceViolation_; } set_anyConformanceViolation()89 void set_anyConformanceViolation() { anyConformanceViolation_ = true; } 90 userState()91 UserState *userState() const { return userState_; } set_userState(UserState * u)92 ParseState &set_userState(UserState *u) { 93 userState_ = u; 94 return *this; 95 } 96 inFixedForm()97 bool inFixedForm() const { return inFixedForm_; } 98 ParseState &set_inFixedForm(bool yes = true) { 99 inFixedForm_ = yes; 100 return *this; 101 } 102 deferMessages()103 bool deferMessages() const { return deferMessages_; } 104 ParseState &set_deferMessages(bool yes = true) { 105 deferMessages_ = yes; 106 return *this; 107 } 108 anyDeferredMessages()109 bool anyDeferredMessages() const { return anyDeferredMessages_; } 110 ParseState &set_anyDeferredMessages(bool yes = true) { 111 anyDeferredMessages_ = yes; 112 return *this; 113 } 114 anyTokenMatched()115 bool anyTokenMatched() const { return anyTokenMatched_; } 116 ParseState &set_anyTokenMatched(bool yes = true) { 117 anyTokenMatched_ = yes; 118 return *this; 119 } 120 GetLocation()121 const char *GetLocation() const { return p_; } 122 PushContext(MessageFixedText text)123 void PushContext(MessageFixedText text) { 124 auto m{new Message{p_, text}}; // reference-counted 125 m->SetContext(context_.get()); 126 context_ = Message::Reference{m}; 127 } 128 PopContext()129 void PopContext() { 130 CHECK(context_); 131 context_ = context_->attachment(); 132 } 133 Say(CharBlock range,A &&...args)134 template <typename... A> void Say(CharBlock range, A &&...args) { 135 if (deferMessages_) { 136 anyDeferredMessages_ = true; 137 } else { 138 messages_.Say(range, std::forward<A>(args)...).SetContext(context_.get()); 139 } 140 } Say(const MessageFixedText & text,A &&...args)141 template <typename... A> void Say(const MessageFixedText &text, A &&...args) { 142 Say(p_, text, std::forward<A>(args)...); 143 } 144 template <typename... A> Say(const MessageExpectedText & text,A &&...args)145 void Say(const MessageExpectedText &text, A &&...args) { 146 Say(p_, text, std::forward<A>(args)...); 147 } 148 Nonstandard(LanguageFeature lf,const MessageFixedText & msg)149 void Nonstandard(LanguageFeature lf, const MessageFixedText &msg) { 150 Nonstandard(p_, lf, msg); 151 } Nonstandard(CharBlock range,LanguageFeature lf,const MessageFixedText & msg)152 void Nonstandard( 153 CharBlock range, LanguageFeature lf, const MessageFixedText &msg) { 154 anyConformanceViolation_ = true; 155 if (userState_ && userState_->features().ShouldWarn(lf)) { 156 Say(range, msg); 157 } 158 } IsNonstandardOk(LanguageFeature lf,const MessageFixedText & msg)159 bool IsNonstandardOk(LanguageFeature lf, const MessageFixedText &msg) { 160 if (userState_ && !userState_->features().IsEnabled(lf)) { 161 return false; 162 } 163 Nonstandard(lf, msg); 164 return true; 165 } 166 IsAtEnd()167 bool IsAtEnd() const { return p_ >= limit_; } 168 169 const char *UncheckedAdvance(std::size_t n = 1) { 170 const char *result{p_}; 171 p_ += n; 172 return result; 173 } 174 GetNextChar()175 std::optional<const char *> GetNextChar() { 176 if (p_ < limit_) { 177 return UncheckedAdvance(); 178 } else { 179 return std::nullopt; 180 } 181 } 182 PeekAtNextChar()183 std::optional<const char *> PeekAtNextChar() const { 184 if (p_ < limit_) { 185 return p_; 186 } else { 187 return std::nullopt; 188 } 189 } 190 BytesRemaining()191 std::size_t BytesRemaining() const { 192 std::size_t remain = limit_ - p_; 193 return remain; 194 } 195 CombineFailedParses(ParseState && prev)196 void CombineFailedParses(ParseState &&prev) { 197 if (prev.anyTokenMatched_) { 198 if (!anyTokenMatched_ || prev.p_ > p_) { 199 anyTokenMatched_ = true; 200 p_ = prev.p_; 201 messages_ = std::move(prev.messages_); 202 } else if (prev.p_ == p_) { 203 messages_.Merge(std::move(prev.messages_)); 204 } 205 } 206 anyDeferredMessages_ |= prev.anyDeferredMessages_; 207 anyConformanceViolation_ |= prev.anyConformanceViolation_; 208 anyErrorRecovery_ |= prev.anyErrorRecovery_; 209 } 210 211 private: 212 // Text remaining to be parsed 213 const char *p_{nullptr}, *limit_{nullptr}; 214 215 // Accumulated messages and current nested context. 216 Messages messages_; 217 Message::Reference context_; 218 219 UserState *userState_{nullptr}; 220 221 bool inFixedForm_{false}; 222 bool anyErrorRecovery_{false}; 223 bool anyConformanceViolation_{false}; 224 bool deferMessages_{false}; 225 bool anyDeferredMessages_{false}; 226 bool anyTokenMatched_{false}; 227 // NOTE: Any additions or modifications to these data members must also be 228 // reflected in the copy and move constructors defined at the top of this 229 // class definition! 230 }; 231 } // namespace Fortran::parser 232 #endif // FORTRAN_PARSER_PARSE_STATE_H_ 233