• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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