| 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 |