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 |