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