FLANG

parse-state.h
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.
38 ParseState(const CookedSource &cooked)
39 : p_{&cooked.data().front()}, limit_{&cooked.data().back() + 1} {}
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_} {}
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
79 const Messages &messages() const { return messages_; }
80 Messages &messages() { return messages_; }
81
82 const Message::Reference &context() const { return context_; }
83 Message::Reference &context() { return context_; }
84
85 bool anyErrorRecovery() const { return anyErrorRecovery_; }
86 void set_anyErrorRecovery() { anyErrorRecovery_ = true; }
87
88 bool anyConformanceViolation() const { return anyConformanceViolation_; }
89 void set_anyConformanceViolation() { anyConformanceViolation_ = true; }
90
91 UserState *userState() const { return userState_; }
92 ParseState &set_userState(UserState *u) {
93 userState_ = u;
94 return *this;
95 }
96
97 bool inFixedForm() const { return inFixedForm_; }
98 ParseState &set_inFixedForm(bool yes = true) {
99 inFixedForm_ = yes;
100 return *this;
101 }
102
103 bool deferMessages() const { return deferMessages_; }
104 ParseState &set_deferMessages(bool yes = true) {
105 deferMessages_ = yes;
106 return *this;
107 }
108
109 bool anyDeferredMessages() const { return anyDeferredMessages_; }
110 ParseState &set_anyDeferredMessages(bool yes = true) {
111 anyDeferredMessages_ = yes;
112 return *this;
113 }
114
115 bool anyTokenMatched() const { return anyTokenMatched_; }
116 ParseState &set_anyTokenMatched(bool yes = true) {
117 anyTokenMatched_ = yes;
118 return *this;
119 }
120
121 const char *GetLocation() const { return p_; }
122
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
129 void PopContext() {
130 CHECK(context_);
131 context_ = context_->attachment();
132 }
133
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 }
141 template <typename... A>
142 void Say(const MessageFixedText &text, A &&... args) {
143 Say(p_, text, std::forward<A>(args)...);
144 }
145 template <typename... A>
146 void Say(const MessageExpectedText &text, A &&... args) {
147 Say(p_, text, std::forward<A>(args)...);
148 }
149
150 void Nonstandard(LanguageFeature lf, const MessageFixedText &msg) {
151 Nonstandard(p_, lf, msg);
152 }
153 void Nonstandard(
154 CharBlock range, LanguageFeature lf, const MessageFixedText &msg) {
155 anyConformanceViolation_ = true;
156 if (userState_ && userState_->features().ShouldWarn(lf)) {
157 Say(range, msg);
158 }
159 }
160 bool IsNonstandardOk(LanguageFeature lf, const MessageFixedText &msg) {
161 if (userState_ && !userState_->features().IsEnabled(lf)) {
162 return false;
163 }
164 Nonstandard(lf, msg);
165 return true;
166 }
167
168 bool IsAtEnd() const { return p_ >= limit_; }
169
170 const char *UncheckedAdvance(std::size_t n = 1) {
171 const char *result{p_};
172 p_ += n;
173 return result;
174 }
175
176 std::optional<const char *> GetNextChar() {
177 if (p_ < limit_) {
178 return UncheckedAdvance();
179 } else {
180 return std::nullopt;
181 }
182 }
183
184 std::optional<const char *> PeekAtNextChar() const {
185 if (p_ < limit_) {
186 return p_;
187 } else {
188 return std::nullopt;
189 }
190 }
191
192 std::size_t BytesRemaining() const {
193 std::size_t remain = limit_ - p_;
194 return remain;
195 }
196
197 void CombineFailedParses(ParseState &&prev) {
198 if (prev.anyTokenMatched_) {
199 if (!anyTokenMatched_ || prev.p_ > p_) {
200 anyTokenMatched_ = true;
201 p_ = prev.p_;
202 messages_ = std::move(prev.messages_);
203 } else if (prev.p_ == p_) {
204 messages_.Merge(std::move(prev.messages_));
205 }
206 }
207 anyDeferredMessages_ |= prev.anyDeferredMessages_;
208 anyConformanceViolation_ |= prev.anyConformanceViolation_;
209 anyErrorRecovery_ |= prev.anyErrorRecovery_;
210 }
211
212 private:
213 // Text remaining to be parsed
214 const char *p_{nullptr}, *limit_{nullptr};
215
216 // Accumulated messages and current nested context.
217 Messages messages_;
218 Message::Reference context_;
219
220 UserState *userState_{nullptr};
221
222 bool inFixedForm_{false};
223 bool anyErrorRecovery_{false};
224 bool anyConformanceViolation_{false};
225 bool deferMessages_{false};
226 bool anyDeferredMessages_{false};
227 bool anyTokenMatched_{false};
228 // NOTE: Any additions or modifications to these data members must also be
229 // reflected in the copy and move constructors defined at the top of this
230 // class definition!
231 };
232 } // namespace Fortran::parser
233 #endif // FORTRAN_PARSER_PARSE_STATE_H_
Fortran::common::CountedReference< Message >
Fortran::parser::MessageExpectedText
Definition: message.h:113
Fortran::parser::CookedSource
Definition: provenance.h:216
Fortran::parser::Messages
Definition: message.h:213
Fortran::parser::Message
Definition: message.h:141
Fortran::parser::MessageFixedText
Definition: message.h:33
Fortran::parser::CharBlock
Definition: char-block.h:28
Fortran::parser::ParseState
Definition: parse-state.h:35
Fortran::parser
Definition: check-expression.h:19
Fortran::parser::UserState
Definition: user-state.h:35