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/parse_tree.h" | 5 #include "tools/gn/parse_tree.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include <string> | 9 #include <string> |
10 #include <tuple> | 10 #include <tuple> |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
165 out << IndentFor(indent) << "ACCESSOR\n"; | 165 out << IndentFor(indent) << "ACCESSOR\n"; |
166 PrintComments(out, indent); | 166 PrintComments(out, indent); |
167 out << IndentFor(indent + 1) << base_.value() << "\n"; | 167 out << IndentFor(indent + 1) << base_.value() << "\n"; |
168 if (index_) | 168 if (index_) |
169 index_->Print(out, indent + 1); | 169 index_->Print(out, indent + 1); |
170 else if (member_) | 170 else if (member_) |
171 member_->Print(out, indent + 1); | 171 member_->Print(out, indent + 1); |
172 } | 172 } |
173 | 173 |
174 Value AccessorNode::ExecuteArrayAccess(Scope* scope, Err* err) const { | 174 Value AccessorNode::ExecuteArrayAccess(Scope* scope, Err* err) const { |
175 Value index_value = index_->Execute(scope, err); | |
176 if (err->has_error()) | |
177 return Value(); | |
178 if (!index_value.VerifyTypeIs(Value::INTEGER, err)) | |
179 return Value(); | |
180 | |
181 const Value* base_value = scope->GetValue(base_.value(), true); | 175 const Value* base_value = scope->GetValue(base_.value(), true); |
182 if (!base_value) { | 176 if (!base_value) { |
183 *err = MakeErrorDescribing("Undefined identifier."); | 177 *err = MakeErrorDescribing("Undefined identifier."); |
184 return Value(); | 178 return Value(); |
185 } | 179 } |
186 if (!base_value->VerifyTypeIs(Value::LIST, err)) | 180 if (!base_value->VerifyTypeIs(Value::LIST, err)) |
187 return Value(); | 181 return Value(); |
188 | 182 |
189 int64_t index_int = index_value.int_value(); | 183 size_t index = 0; |
190 if (index_int < 0) { | 184 if (!ComputeAndValidateListIndex(scope, base_value->list_value().size(), |
191 *err = Err(index_->GetRange(), "Negative array subscript.", | 185 &index, err)) |
192 "You gave me " + base::Int64ToString(index_int) + "."); | |
193 return Value(); | 186 return Value(); |
194 } | 187 return base_value->list_value()[index]; |
195 size_t index_sizet = static_cast<size_t>(index_int); | |
196 if (index_sizet >= base_value->list_value().size()) { | |
197 *err = | |
198 Err(index_->GetRange(), "Array subscript out of range.", | |
199 "You gave me " + base::Int64ToString(index_int) + | |
200 " but I was expecting something from 0 to " + | |
201 base::Int64ToString( | |
202 static_cast<int64_t>(base_value->list_value().size()) - 1) + | |
203 ", inclusive."); | |
204 return Value(); | |
205 } | |
206 | |
207 // Doing this assumes that there's no way in the language to do anything | |
208 // between the time the reference is created and the time that the reference | |
209 // is used. If there is, this will crash! Currently, this is just used for | |
210 // array accesses where this "shouldn't" happen. | |
211 return base_value->list_value()[index_sizet]; | |
212 } | 188 } |
213 | 189 |
214 Value AccessorNode::ExecuteScopeAccess(Scope* scope, Err* err) const { | 190 Value AccessorNode::ExecuteScopeAccess(Scope* scope, Err* err) const { |
215 // We jump through some hoops here since ideally a.b will count "b" as | 191 // We jump through some hoops here since ideally a.b will count "b" as |
216 // accessed in the given scope. The value "a" might be in some normal nested | 192 // accessed in the given scope. The value "a" might be in some normal nested |
217 // scope and we can modify it, but it might also be inherited from the | 193 // scope and we can modify it, but it might also be inherited from the |
218 // readonly root scope and we can't do used variable tracking on it. (It's | 194 // readonly root scope and we can't do used variable tracking on it. (It's |
219 // not legal to const cast it away since the root scope will be in readonly | 195 // not legal to const cast it away since the root scope will be in readonly |
220 // mode and being accessed from multiple threads without locking.) So this | 196 // mode and being accessed from multiple threads without locking.) So this |
221 // code handles both cases. | 197 // code handles both cases. |
222 const Value* result = nullptr; | 198 const Value* result = nullptr; |
223 | 199 |
224 // Look up the value in the scope named by "base_". | 200 // Look up the value in the scope named by "base_". |
225 Value* mutable_base_value = scope->GetMutableValue(base_.value(), true); | 201 Value* mutable_base_value = scope->GetMutableValue( |
| 202 base_.value(), Scope::SEARCH_NESTED, true); |
226 if (mutable_base_value) { | 203 if (mutable_base_value) { |
227 // Common case: base value is mutable so we can track variable accesses | 204 // Common case: base value is mutable so we can track variable accesses |
228 // for unused value warnings. | 205 // for unused value warnings. |
229 if (!mutable_base_value->VerifyTypeIs(Value::SCOPE, err)) | 206 if (!mutable_base_value->VerifyTypeIs(Value::SCOPE, err)) |
230 return Value(); | 207 return Value(); |
231 result = mutable_base_value->scope_value()->GetValue( | 208 result = mutable_base_value->scope_value()->GetValue( |
232 member_->value().value(), true); | 209 member_->value().value(), true); |
233 } else { | 210 } else { |
234 // Fall back to see if the value is on a read-only scope. | 211 // Fall back to see if the value is on a read-only scope. |
235 const Value* const_base_value = scope->GetValue(base_.value(), true); | 212 const Value* const_base_value = scope->GetValue(base_.value(), true); |
(...skipping 16 matching lines...) Expand all Loading... |
252 } | 229 } |
253 return *result; | 230 return *result; |
254 } | 231 } |
255 | 232 |
256 void AccessorNode::SetNewLocation(int line_number) { | 233 void AccessorNode::SetNewLocation(int line_number) { |
257 Location old = base_.location(); | 234 Location old = base_.location(); |
258 base_.set_location( | 235 base_.set_location( |
259 Location(old.file(), line_number, old.column_number(), old.byte())); | 236 Location(old.file(), line_number, old.column_number(), old.byte())); |
260 } | 237 } |
261 | 238 |
| 239 bool AccessorNode::ComputeAndValidateListIndex(Scope* scope, |
| 240 size_t max_len, |
| 241 size_t* computed_index, |
| 242 Err* err) const { |
| 243 Value index_value = index_->Execute(scope, err); |
| 244 if (err->has_error()) |
| 245 return false; |
| 246 if (!index_value.VerifyTypeIs(Value::INTEGER, err)) |
| 247 return false; |
| 248 |
| 249 int64_t index_int = index_value.int_value(); |
| 250 if (index_int < 0) { |
| 251 *err = Err(index_->GetRange(), "Negative array subscript.", |
| 252 "You gave me " + base::Int64ToString(index_int) + "."); |
| 253 return false; |
| 254 } |
| 255 size_t index_sizet = static_cast<size_t>(index_int); |
| 256 if (index_sizet >= max_len) { |
| 257 *err = Err(index_->GetRange(), "Array subscript out of range.", |
| 258 "You gave me " + base::Int64ToString(index_int) + |
| 259 " but I was expecting something from 0 to " + |
| 260 base::SizeTToString(max_len) + ", inclusive."); |
| 261 return false; |
| 262 } |
| 263 |
| 264 *computed_index = index_sizet; |
| 265 return true; |
| 266 } |
| 267 |
262 // BinaryOpNode --------------------------------------------------------------- | 268 // BinaryOpNode --------------------------------------------------------------- |
263 | 269 |
264 BinaryOpNode::BinaryOpNode() { | 270 BinaryOpNode::BinaryOpNode() { |
265 } | 271 } |
266 | 272 |
267 BinaryOpNode::~BinaryOpNode() { | 273 BinaryOpNode::~BinaryOpNode() { |
268 } | 274 } |
269 | 275 |
270 const BinaryOpNode* BinaryOpNode::AsBinaryOp() const { | 276 const BinaryOpNode* BinaryOpNode::AsBinaryOp() const { |
271 return this; | 277 return this; |
(...skipping 14 matching lines...) Expand all Loading... |
286 | 292 |
287 void BinaryOpNode::Print(std::ostream& out, int indent) const { | 293 void BinaryOpNode::Print(std::ostream& out, int indent) const { |
288 out << IndentFor(indent) << "BINARY(" << op_.value() << ")\n"; | 294 out << IndentFor(indent) << "BINARY(" << op_.value() << ")\n"; |
289 PrintComments(out, indent); | 295 PrintComments(out, indent); |
290 left_->Print(out, indent + 1); | 296 left_->Print(out, indent + 1); |
291 right_->Print(out, indent + 1); | 297 right_->Print(out, indent + 1); |
292 } | 298 } |
293 | 299 |
294 // BlockNode ------------------------------------------------------------------ | 300 // BlockNode ------------------------------------------------------------------ |
295 | 301 |
296 BlockNode::BlockNode() { | 302 BlockNode::BlockNode(ResultMode result_mode) : result_mode_(result_mode) { |
297 } | 303 } |
298 | 304 |
299 BlockNode::~BlockNode() { | 305 BlockNode::~BlockNode() { |
300 } | 306 } |
301 | 307 |
302 const BlockNode* BlockNode::AsBlock() const { | 308 const BlockNode* BlockNode::AsBlock() const { |
303 return this; | 309 return this; |
304 } | 310 } |
305 | 311 |
306 Value BlockNode::Execute(Scope* scope, Err* err) const { | 312 Value BlockNode::Execute(Scope* enclosing_scope, Err* err) const { |
| 313 std::unique_ptr<Scope> nested_scope; // May be null. |
| 314 |
| 315 Scope* execution_scope; // Either the enclosing_scope or nested_scope. |
| 316 if (result_mode_ == RETURNS_SCOPE) { |
| 317 // Create a nested scope to save the values for returning. |
| 318 nested_scope.reset(new Scope(enclosing_scope)); |
| 319 execution_scope = nested_scope.get(); |
| 320 } else { |
| 321 // Use the enclosing scope. Modifications will go into this also (for |
| 322 // example, if conditions and loops). |
| 323 execution_scope = enclosing_scope; |
| 324 } |
| 325 |
307 for (size_t i = 0; i < statements_.size() && !err->has_error(); i++) { | 326 for (size_t i = 0; i < statements_.size() && !err->has_error(); i++) { |
308 // Check for trying to execute things with no side effects in a block. | 327 // Check for trying to execute things with no side effects in a block. |
| 328 // |
| 329 // A BlockNode here means that somebody has a free-floating { }. |
| 330 // Technically this can have side effects since it could generated targets, |
| 331 // but we don't want to allow this since it creates ambiguity when |
| 332 // immediately following a function call that takes no block. By not |
| 333 // allowing free-floating blocks that aren't passed anywhere or assigned to |
| 334 // anything, this ambiguity is resolved. |
309 const ParseNode* cur = statements_[i].get(); | 335 const ParseNode* cur = statements_[i].get(); |
310 if (cur->AsList() || cur->AsLiteral() || cur->AsUnaryOp() || | 336 if (cur->AsList() || cur->AsLiteral() || cur->AsUnaryOp() || |
311 cur->AsIdentifier()) { | 337 cur->AsIdentifier() || cur->AsBlock()) { |
312 *err = cur->MakeErrorDescribing( | 338 *err = cur->MakeErrorDescribing( |
313 "This statement has no effect.", | 339 "This statement has no effect.", |
314 "Either delete it or do something with the result."); | 340 "Either delete it or do something with the result."); |
315 return Value(); | 341 return Value(); |
316 } | 342 } |
317 cur->Execute(scope, err); | 343 cur->Execute(execution_scope, err); |
| 344 } |
| 345 |
| 346 if (result_mode_ == RETURNS_SCOPE) { |
| 347 // Clear the reference to the containing scope. This will be passed in |
| 348 // a value whose lifetime will not be related to the enclosing_scope passed |
| 349 // to this function. |
| 350 nested_scope->DetachFromContaining(); |
| 351 return Value(this, std::move(nested_scope)); |
318 } | 352 } |
319 return Value(); | 353 return Value(); |
320 } | 354 } |
321 | 355 |
322 LocationRange BlockNode::GetRange() const { | 356 LocationRange BlockNode::GetRange() const { |
323 if (begin_token_.type() != Token::INVALID && | 357 if (begin_token_.type() != Token::INVALID && |
324 end_->value().type() != Token::INVALID) { | 358 end_->value().type() != Token::INVALID) { |
325 return begin_token_.range().Union(end_->value().range()); | 359 return begin_token_.range().Union(end_->value().range()); |
326 } else if (!statements_.empty()) { | 360 } else if (!statements_.empty()) { |
327 return statements_[0]->GetRange().Union( | 361 return statements_[0]->GetRange().Union( |
(...skipping 505 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
833 | 867 |
834 Err EndNode::MakeErrorDescribing(const std::string& msg, | 868 Err EndNode::MakeErrorDescribing(const std::string& msg, |
835 const std::string& help) const { | 869 const std::string& help) const { |
836 return Err(value_, msg, help); | 870 return Err(value_, msg, help); |
837 } | 871 } |
838 | 872 |
839 void EndNode::Print(std::ostream& out, int indent) const { | 873 void EndNode::Print(std::ostream& out, int indent) const { |
840 out << IndentFor(indent) << "END(" << value_.value() << ")\n"; | 874 out << IndentFor(indent) << "END(" << value_.value() << ")\n"; |
841 PrintComments(out, indent); | 875 PrintComments(out, indent); |
842 } | 876 } |
OLD | NEW |