Warning: This file is not a C or C++ file. It does not have highlighting.
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 | ParseState(const CookedSource &cooked) |
38 | : p_{cooked.AsCharBlock().begin()}, limit_{cooked.AsCharBlock().end()} {} |
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_} {} |
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 | |
78 | const Messages &messages() const { return messages_; } |
79 | Messages &messages() { return messages_; } |
80 | |
81 | const Message::Reference &context() const { return context_; } |
82 | Message::Reference &context() { return context_; } |
83 | |
84 | bool anyErrorRecovery() const { return anyErrorRecovery_; } |
85 | void set_anyErrorRecovery() { anyErrorRecovery_ = true; } |
86 | |
87 | bool anyConformanceViolation() const { return anyConformanceViolation_; } |
88 | void set_anyConformanceViolation() { anyConformanceViolation_ = true; } |
89 | |
90 | UserState *userState() const { return userState_; } |
91 | ParseState &set_userState(UserState *u) { |
92 | userState_ = u; |
93 | return *this; |
94 | } |
95 | |
96 | bool inFixedForm() const { return inFixedForm_; } |
97 | ParseState &set_inFixedForm(bool yes = true) { |
98 | inFixedForm_ = yes; |
99 | return *this; |
100 | } |
101 | |
102 | bool deferMessages() const { return deferMessages_; } |
103 | ParseState &set_deferMessages(bool yes = true) { |
104 | deferMessages_ = yes; |
105 | return *this; |
106 | } |
107 | |
108 | bool anyDeferredMessages() const { return anyDeferredMessages_; } |
109 | ParseState &set_anyDeferredMessages(bool yes = true) { |
110 | anyDeferredMessages_ = yes; |
111 | return *this; |
112 | } |
113 | |
114 | bool anyTokenMatched() const { return anyTokenMatched_; } |
115 | ParseState &set_anyTokenMatched(bool yes = true) { |
116 | anyTokenMatched_ = yes; |
117 | return *this; |
118 | } |
119 | |
120 | const char *GetLocation() const { return p_; } |
121 | |
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 | |
128 | void PopContext() { |
129 | CHECK(context_); |
130 | context_ = context_->attachment(); |
131 | } |
132 | |
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 | } |
140 | template <typename... A> void Say(const MessageFixedText &text, A &&...args) { |
141 | Say(p_, text, std::forward<A>(args)...); |
142 | } |
143 | template <typename... A> |
144 | void Say(const MessageExpectedText &text, A &&...args) { |
145 | Say(p_, text, std::forward<A>(args)...); |
146 | } |
147 | |
148 | void Nonstandard(LanguageFeature lf, const MessageFixedText &msg) { |
149 | Nonstandard(p_, lf, msg); |
150 | } |
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 | } |
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 | |
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 | |
174 | std::optional<const char *> GetNextChar() { |
175 | if (p_ < limit_) { |
176 | return UncheckedAdvance(); |
177 | } else { |
178 | return std::nullopt; |
179 | } |
180 | } |
181 | |
182 | std::optional<const char *> PeekAtNextChar() const { |
183 | if (p_ < limit_) { |
184 | return p_; |
185 | } else { |
186 | return std::nullopt; |
187 | } |
188 | } |
189 | |
190 | std::size_t BytesRemaining() const { |
191 | std::size_t remain = limit_ - p_; |
192 | return remain; |
193 | } |
194 | |
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 |
Warning: This file is not a C or C++ file. It does not have highlighting.