1 //===-- lib/Parser/token-sequence.cpp -------------------------------------===//
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 #include "token-sequence.h"
10 #include "flang/Parser/characters.h"
11 
12 namespace Fortran::parser {
13 
14 TokenSequence &TokenSequence::operator=(TokenSequence &&that) {
15   clear();
16   swap(that);
17   return *this;
18 }
19 
20 void TokenSequence::clear() {
21   start_.clear();
22   nextStart_ = 0;
23   char_.clear();
24   provenances_.clear();
25 }
26 
27 void TokenSequence::pop_back() {
28   std::size_t bytes{nextStart_ - start_.back()};
29   nextStart_ = start_.back();
30   start_.pop_back();
31   char_.resize(nextStart_);
32   provenances_.RemoveLastBytes(bytes);
33 }
34 
35 void TokenSequence::shrink_to_fit() {
36   start_.shrink_to_fit();
37   char_.shrink_to_fit();
38   provenances_.shrink_to_fit();
39 }
40 
41 void TokenSequence::swap(TokenSequence &that) {
42   start_.swap(that.start_);
43   std::swap(nextStart_, that.nextStart_);
44   char_.swap(that.char_);
45   provenances_.swap(that.provenances_);
46 }
47 
48 std::size_t TokenSequence::SkipBlanks(std::size_t at) const {
49   std::size_t tokens{start_.size()};
50   for (; at < tokens; ++at) {
51     if (!TokenAt(at).IsBlank()) {
52       return at;
53     }
54   }
55   return tokens;  // even if at > tokens
56 }
57 
58 void TokenSequence::RemoveLastToken() {
59   CHECK(!start_.empty());
60   CHECK(nextStart_ > start_.back());
61   std::size_t bytes{nextStart_ - start_.back()};
62   nextStart_ = start_.back();
63   start_.pop_back();
64   char_.erase(char_.begin() + nextStart_, char_.end());
65   provenances_.RemoveLastBytes(bytes);
66 }
67 
68 void TokenSequence::Put(const TokenSequence &that) {
69   if (nextStart_ < char_.size()) {
70     start_.push_back(nextStart_);
71   }
72   int offset = char_.size();
73   for (int st : that.start_) {
74     start_.push_back(st + offset);
75   }
76   char_.insert(char_.end(), that.char_.begin(), that.char_.end());
77   nextStart_ = char_.size();
78   provenances_.Put(that.provenances_);
79 }
80 
81 void TokenSequence::Put(const TokenSequence &that, ProvenanceRange range) {
82   std::size_t offset{0};
83   std::size_t tokens{that.SizeInTokens()};
84   for (std::size_t j{0}; j < tokens; ++j) {
85     CharBlock tok{that.TokenAt(j)};
86     Put(tok, range.OffsetMember(offset));
87     offset += tok.size();
88   }
89   CHECK(offset == range.size());
90 }
91 
92 void TokenSequence::Put(
93     const TokenSequence &that, std::size_t at, std::size_t tokens) {
94   ProvenanceRange provenance;
95   std::size_t offset{0};
96   for (; tokens-- > 0; ++at) {
97     CharBlock tok{that.TokenAt(at)};
98     std::size_t tokBytes{tok.size()};
99     for (std::size_t j{0}; j < tokBytes; ++j) {
100       if (offset == provenance.size()) {
101         provenance = that.provenances_.Map(that.start_[at] + j);
102         offset = 0;
103       }
104       PutNextTokenChar(tok[j], provenance.OffsetMember(offset++));
105     }
106     CloseToken();
107   }
108 }
109 
110 void TokenSequence::Put(
111     const char *s, std::size_t bytes, Provenance provenance) {
112   for (std::size_t j{0}; j < bytes; ++j) {
113     PutNextTokenChar(s[j], provenance + j);
114   }
115   CloseToken();
116 }
117 
118 void TokenSequence::Put(const CharBlock &t, Provenance provenance) {
119   Put(&t[0], t.size(), provenance);
120 }
121 
122 void TokenSequence::Put(const std::string &s, Provenance provenance) {
123   Put(s.data(), s.size(), provenance);
124 }
125 
126 void TokenSequence::Put(const std::stringstream &ss, Provenance provenance) {
127   Put(ss.str(), provenance);
128 }
129 
130 TokenSequence &TokenSequence::ToLowerCase() {
131   std::size_t tokens{start_.size()};
132   std::size_t chars{char_.size()};
133   std::size_t atToken{0};
134   for (std::size_t j{0}; j < chars;) {
135     std::size_t nextStart{atToken + 1 < tokens ? start_[++atToken] : chars};
136     char *p{&char_[j]}, *limit{&char_[nextStart]};
137     j = nextStart;
138     if (IsDecimalDigit(*p)) {
139       while (p < limit && IsDecimalDigit(*p)) {
140         ++p;
141       }
142       if (p >= limit) {
143       } else if (*p == 'h' || *p == 'H') {
144         // Hollerith
145         *p = 'h';
146       } else if (*p == '_') {
147         // kind-prefixed character literal (e.g., 1_"ABC")
148       } else {
149         // exponent
150         for (; p < limit; ++p) {
151           *p = ToLowerCaseLetter(*p);
152         }
153       }
154     } else if (limit[-1] == '\'' || limit[-1] == '"') {
155       if (*p == limit[-1]) {
156         // Character literal without prefix
157       } else if (p[1] == limit[-1]) {
158         // BOZX-prefixed constant
159         for (; p < limit; ++p) {
160           *p = ToLowerCaseLetter(*p);
161         }
162       } else {
163         // Literal with kind-param prefix name (e.g., K_"ABC").
164         for (; *p != limit[-1]; ++p) {
165           *p = ToLowerCaseLetter(*p);
166         }
167       }
168     } else {
169       for (; p < limit; ++p) {
170         *p = ToLowerCaseLetter(*p);
171       }
172     }
173   }
174   return *this;
175 }
176 
177 bool TokenSequence::HasBlanks(std::size_t firstChar) const {
178   std::size_t tokens{SizeInTokens()};
179   for (std::size_t j{0}; j < tokens; ++j) {
180     if (start_[j] >= firstChar && TokenAt(j).IsBlank()) {
181       return true;
182     }
183   }
184   return false;
185 }
186 
187 bool TokenSequence::HasRedundantBlanks(std::size_t firstChar) const {
188   std::size_t tokens{SizeInTokens()};
189   bool lastWasBlank{false};
190   for (std::size_t j{0}; j < tokens; ++j) {
191     bool isBlank{TokenAt(j).IsBlank()};
192     if (isBlank && lastWasBlank && start_[j] >= firstChar) {
193       return true;
194     }
195     lastWasBlank = isBlank;
196   }
197   return false;
198 }
199 
200 TokenSequence &TokenSequence::RemoveBlanks(std::size_t firstChar) {
201   std::size_t tokens{SizeInTokens()};
202   TokenSequence result;
203   for (std::size_t j{0}; j < tokens; ++j) {
204     if (!TokenAt(j).IsBlank() || start_[j] < firstChar) {
205       result.Put(*this, j);
206     }
207   }
208   swap(result);
209   return *this;
210 }
211 
212 TokenSequence &TokenSequence::RemoveRedundantBlanks(std::size_t firstChar) {
213   std::size_t tokens{SizeInTokens()};
214   TokenSequence result;
215   bool lastWasBlank{false};
216   for (std::size_t j{0}; j < tokens; ++j) {
217     bool isBlank{TokenAt(j).IsBlank()};
218     if (!isBlank || !lastWasBlank || start_[j] < firstChar) {
219       result.Put(*this, j);
220     }
221     lastWasBlank = isBlank;
222   }
223   swap(result);
224   return *this;
225 }
226 
227 TokenSequence &TokenSequence::ClipComment(bool skipFirst) {
228   std::size_t tokens{SizeInTokens()};
229   for (std::size_t j{0}; j < tokens; ++j) {
230     if (TokenAt(j).FirstNonBlank() == '!') {
231       if (skipFirst) {
232         skipFirst = false;
233       } else {
234         TokenSequence result;
235         if (j > 0) {
236           result.Put(*this, 0, j - 1);
237         }
238         swap(result);
239         return *this;
240       }
241     }
242   }
243   return *this;
244 }
245 
246 void TokenSequence::Emit(CookedSource &cooked) const {
247   cooked.Put(&char_[0], char_.size());
248   cooked.PutProvenanceMappings(provenances_);
249 }
250 
251 void TokenSequence::Dump(std::ostream &o) const {
252   o << "TokenSequence has " << char_.size() << " chars; nextStart_ "
253     << nextStart_ << '\n';
254   for (std::size_t j{0}; j < start_.size(); ++j) {
255     o << '[' << j << "] @ " << start_[j] << " '" << TokenAt(j).ToString()
256       << "'\n";
257   }
258 }
259 
260 Provenance TokenSequence::GetTokenProvenance(
261     std::size_t token, std::size_t offset) const {
262   ProvenanceRange range{provenances_.Map(start_[token] + offset)};
263   return range.start();
264 }
265 
266 ProvenanceRange TokenSequence::GetTokenProvenanceRange(
267     std::size_t token, std::size_t offset) const {
268   ProvenanceRange range{provenances_.Map(start_[token] + offset)};
269   return range.Prefix(TokenBytes(token) - offset);
270 }
271 
272 ProvenanceRange TokenSequence::GetIntervalProvenanceRange(
273     std::size_t token, std::size_t tokens) const {
274   if (tokens == 0) {
275     return {};
276   }
277   ProvenanceRange range{provenances_.Map(start_[token])};
278   while (--tokens > 0 &&
279       range.AnnexIfPredecessor(provenances_.Map(start_[++token]))) {
280   }
281   return range;
282 }
283 
284 ProvenanceRange TokenSequence::GetProvenanceRange() const {
285   return GetIntervalProvenanceRange(0, start_.size());
286 }
287 }
288