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