Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(164)

Side by Side Diff: tools/gn/parse_tree.cc

Issue 2187523003: Allow creation and modification of scopes in GN. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Review comments Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/gn/parse_tree.h ('k') | tools/gn/parse_tree_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « tools/gn/parse_tree.h ('k') | tools/gn/parse_tree_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698