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