Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "tools/gn/string_utils.h" | 5 #include "tools/gn/string_utils.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <cctype> | |
| 8 | 9 |
| 10 #include "base/strings/string_number_conversions.h" | |
| 9 #include "tools/gn/err.h" | 11 #include "tools/gn/err.h" |
| 10 #include "tools/gn/input_file.h" | 12 #include "tools/gn/input_file.h" |
| 11 #include "tools/gn/parser.h" | 13 #include "tools/gn/parser.h" |
| 12 #include "tools/gn/scope.h" | 14 #include "tools/gn/scope.h" |
| 13 #include "tools/gn/token.h" | 15 #include "tools/gn/token.h" |
| 14 #include "tools/gn/tokenizer.h" | 16 #include "tools/gn/tokenizer.h" |
| 15 #include "tools/gn/value.h" | 17 #include "tools/gn/value.h" |
| 16 | 18 |
| 17 namespace { | 19 namespace { |
| 18 | 20 |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 124 std::string("\"") + identifier + "\" is not currently in scope."); | 126 std::string("\"") + identifier + "\" is not currently in scope."); |
| 125 return false; | 127 return false; |
| 126 } | 128 } |
| 127 | 129 |
| 128 output->append(value->ToString(false)); | 130 output->append(value->ToString(false)); |
| 129 return true; | 131 return true; |
| 130 } | 132 } |
| 131 | 133 |
| 132 // Handles string interpolations: $identifier and ${expression} | 134 // Handles string interpolations: $identifier and ${expression} |
| 133 // | 135 // |
| 134 // |*i| is the index into |input| of the $. This will be updated to point to | 136 // |*i| is the index into |input| after the $. This will be updated to point to |
| 135 // the last character consumed on success. The token is the original string | 137 // the last character consumed on success. The token is the original string |
| 136 // to blame on failure. | 138 // to blame on failure. |
| 137 // | 139 // |
| 138 // On failure, returns false and sets the error. On success, appends the | 140 // On failure, returns false and sets the error. On success, appends the |
| 139 // result of the interpolation to |*output|. | 141 // result of the interpolation to |*output|. |
| 140 bool AppendStringInterpolation(Scope* scope, | 142 bool AppendStringInterpolation(Scope* scope, |
| 141 const Token& token, | 143 const Token& token, |
| 142 const char* input, size_t size, | 144 const char* input, size_t size, |
| 143 size_t* i, | 145 size_t* i, |
| 144 std::string* output, | 146 std::string* output, |
| 145 Err* err) { | 147 Err* err) { |
| 146 size_t dollars_index = *i; | 148 size_t dollars_index = *i - 1; |
| 147 (*i)++; | |
| 148 if (*i == size) { | |
| 149 *err = ErrInsideStringToken(token, dollars_index, 1, "$ at end of string.", | |
| 150 "I was expecting an identifier or {...} after the $."); | |
| 151 return false; | |
| 152 } | |
| 153 | 149 |
| 154 if (input[*i] == '{') { | 150 if (input[*i] == '{') { |
| 155 // Bracketed expression. | 151 // Bracketed expression. |
| 156 (*i)++; | 152 (*i)++; |
| 157 size_t begin_offset = *i; | 153 size_t begin_offset = *i; |
| 158 | 154 |
| 159 // Find the closing } and check for non-identifier chars. Don't need to | 155 // Find the closing } and check for non-identifier chars. Don't need to |
| 160 // bother checking for the more-restricted first character of an identifier | 156 // bother checking for the more-restricted first character of an identifier |
| 161 // since the {} unambiguously denotes the range, and identifiers with | 157 // since the {} unambiguously denotes the range, and identifiers with |
| 162 // invalid names just won't be found later. | 158 // invalid names just won't be found later. |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 196 | 192 |
| 197 // Find the first non-identifier char following the string. | 193 // Find the first non-identifier char following the string. |
| 198 while (*i < size && Tokenizer::IsIdentifierContinuingChar(input[*i])) | 194 while (*i < size && Tokenizer::IsIdentifierContinuingChar(input[*i])) |
| 199 (*i)++; | 195 (*i)++; |
| 200 size_t end_offset = *i; | 196 size_t end_offset = *i; |
| 201 (*i)--; // Back up to mark the last character consumed. | 197 (*i)--; // Back up to mark the last character consumed. |
| 202 return AppendInterpolatedIdentifier(scope, token, input, begin_offset, | 198 return AppendInterpolatedIdentifier(scope, token, input, begin_offset, |
| 203 end_offset, output, err); | 199 end_offset, output, err); |
| 204 } | 200 } |
| 205 | 201 |
| 202 // Handles a hex literal: $0xFF | |
| 203 // | |
| 204 // |*i| is the index into |input| after the $. This will be updated to point to | |
| 205 // the last character consumed on success. The token is the original string | |
| 206 // to blame on failure. | |
| 207 // | |
| 208 // On failure, returns false and sets the error. On success, appends the | |
| 209 // char with the given hex value to |*output|. | |
| 210 bool AppendHexByte(Scope* scope, | |
| 211 const Token& token, | |
| 212 const char* input, size_t size, | |
| 213 size_t* i, | |
| 214 std::string* output, | |
| 215 Err* err) { | |
| 216 size_t dollars_index = *i - 1; | |
| 217 // "$0" is already known to exist. | |
| 218 if (*i + 3 >= size || input[*i + 1] != 'x' || !std::isxdigit(input[*i + 2]) || | |
| 219 !std::isxdigit(input[*i + 3])) { | |
| 220 *err = ErrInsideStringToken( | |
| 221 token, dollars_index, *i - dollars_index + 1, | |
| 222 "Invalid hex character. Hex values must look like 0xFF."); | |
| 223 return false; | |
| 224 } | |
| 225 int value = 0; | |
| 226 if (!base::HexStringToInt(base::StringPiece(&input[*i + 2], 2), &value)) { | |
| 227 *err = ErrInsideStringToken(token, dollars_index, *i - dollars_index + 1, | |
| 228 "Could not convert hex value."); | |
| 229 return false; | |
| 230 } | |
| 231 *i += 3; | |
| 232 output->push_back(value); | |
|
brettw
2016/01/05 18:11:04
I'm surprised you can push_back an into on a strin
agrieve
2016/01/05 19:43:19
Yeah, just tried both GCC and clang again but no w
| |
| 233 return true; | |
| 234 } | |
| 235 | |
| 206 } // namespace | 236 } // namespace |
| 207 | 237 |
| 208 bool ExpandStringLiteral(Scope* scope, | 238 bool ExpandStringLiteral(Scope* scope, |
| 209 const Token& literal, | 239 const Token& literal, |
| 210 Value* result, | 240 Value* result, |
| 211 Err* err) { | 241 Err* err) { |
| 212 DCHECK(literal.type() == Token::STRING); | 242 DCHECK(literal.type() == Token::STRING); |
| 213 DCHECK(literal.value().size() > 1); // Should include quotes. | 243 DCHECK(literal.value().size() > 1); // Should include quotes. |
| 214 DCHECK(result->type() == Value::STRING); // Should be already set. | 244 DCHECK(result->type() == Value::STRING); // Should be already set. |
| 215 | 245 |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 228 case '$': | 258 case '$': |
| 229 output.push_back(input[i + 1]); | 259 output.push_back(input[i + 1]); |
| 230 i++; | 260 i++; |
| 231 continue; | 261 continue; |
| 232 default: // Everything else has no meaning: pass the literal. | 262 default: // Everything else has no meaning: pass the literal. |
| 233 break; | 263 break; |
| 234 } | 264 } |
| 235 } | 265 } |
| 236 output.push_back(input[i]); | 266 output.push_back(input[i]); |
| 237 } else if (input[i] == '$') { | 267 } else if (input[i] == '$') { |
| 238 if (!AppendStringInterpolation(scope, literal, input, size, &i, | 268 i++; |
| 269 if (i == size) { | |
| 270 *err = ErrInsideStringToken(literal, i - 1, 1, "$ at end of string.", | |
| 271 "I was expecting an identifier, 0xFF, or {...} after the $."); | |
| 272 return false; | |
| 273 } | |
| 274 if (input[i] == '0') { | |
| 275 if (!AppendHexByte(scope, literal, input, size, &i, &output, err)) | |
| 276 return false; | |
| 277 } else if (!AppendStringInterpolation(scope, literal, input, size, &i, | |
| 239 &output, err)) | 278 &output, err)) |
| 240 return false; | 279 return false; |
| 241 } else { | 280 } else { |
| 242 output.push_back(input[i]); | 281 output.push_back(input[i]); |
| 243 } | 282 } |
| 244 } | 283 } |
| 245 return true; | 284 return true; |
| 246 } | 285 } |
| OLD | NEW |