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

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

Issue 258073004: Require commas between items in a GN list. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 7 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 | Annotate | Revision Log
« no previous file with comments | « skia/BUILD.gn ('k') | tools/gn/parser.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/input_file_manager.h" 5 #include "tools/gn/input_file_manager.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/stl_util.h" 8 #include "base/stl_util.h"
9 #include "tools/gn/filesystem_utils.h" 9 #include "tools/gn/filesystem_utils.h"
10 #include "tools/gn/parser.h" 10 #include "tools/gn/parser.h"
11 #include "tools/gn/scheduler.h" 11 #include "tools/gn/scheduler.h"
12 #include "tools/gn/scope_per_file_provider.h" 12 #include "tools/gn/scope_per_file_provider.h"
13 #include "tools/gn/tokenizer.h" 13 #include "tools/gn/tokenizer.h"
14 #include "tools/gn/trace.h" 14 #include "tools/gn/trace.h"
15 15
16 namespace { 16 namespace {
17 17
18 void InvokeFileLoadCallback(const InputFileManager::FileLoadCallback& cb, 18 void InvokeFileLoadCallback(const InputFileManager::FileLoadCallback& cb,
19 const ParseNode* node) { 19 const ParseNode* node) {
20 cb.Run(node); 20 cb.Run(node);
21 } 21 }
22 22
23 bool DoLoadFile(const LocationRange& origin,
24 const BuildSettings* build_settings,
25 const SourceFile& name,
26 InputFile* file,
27 std::vector<Token>* tokens,
28 scoped_ptr<ParseNode>* root,
29 Err* err) {
30 // Do all of this stuff outside the lock. We should not give out file
31 // pointers until the read is complete.
32 if (g_scheduler->verbose_logging()) {
33 std::string logmsg = name.value();
34 if (origin.begin().file())
35 logmsg += " (referenced from " + origin.begin().Describe(false) + ")";
36 g_scheduler->Log("Loading", logmsg);
37 }
38
39 // Read.
40 base::FilePath primary_path = build_settings->GetFullPath(name);
41 ScopedTrace load_trace(TraceItem::TRACE_FILE_LOAD, name.value());
42 if (!file->Load(primary_path)) {
43 if (!build_settings->secondary_source_path().empty()) {
44 // Fall back to secondary source tree.
45 base::FilePath secondary_path =
46 build_settings->GetFullPathSecondary(name);
47 if (!file->Load(secondary_path)) {
48 *err = Err(origin, "Can't load input file.",
49 "Unable to load either \n" +
50 FilePathToUTF8(primary_path) + " or \n" +
51 FilePathToUTF8(secondary_path));
52 return false;
53 }
54 } else {
55 *err = Err(origin,
56 "Unable to load \"" + FilePathToUTF8(primary_path) + "\".");
57 return false;
58 }
59 }
60 load_trace.Done();
61
62 ScopedTrace exec_trace(TraceItem::TRACE_FILE_PARSE, name.value());
63
64 // Tokenize.
65 *tokens = Tokenizer::Tokenize(file, err);
66 if (err->has_error())
67 return false;
68
69 // Parse.
70 *root = Parser::Parse(*tokens, err);
71 if (err->has_error())
72 return false;
73
74 exec_trace.Done();
75 return true;
76 }
77
23 } // namespace 78 } // namespace
24 79
25 InputFileManager::InputFileData::InputFileData(const SourceFile& file_name) 80 InputFileManager::InputFileData::InputFileData(const SourceFile& file_name)
26 : file(file_name), 81 : file(file_name),
27 loaded(false), 82 loaded(false),
28 sync_invocation(false) { 83 sync_invocation(false) {
29 } 84 }
30 85
31 InputFileManager::InputFileData::~InputFileData() { 86 InputFileManager::InputFileData::~InputFileData() {
32 } 87 }
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
204 Err err; 259 Err err;
205 if (!LoadFile(origin, build_settings, name, file, &err)) 260 if (!LoadFile(origin, build_settings, name, file, &err))
206 g_scheduler->FailWithError(err); 261 g_scheduler->FailWithError(err);
207 } 262 }
208 263
209 bool InputFileManager::LoadFile(const LocationRange& origin, 264 bool InputFileManager::LoadFile(const LocationRange& origin,
210 const BuildSettings* build_settings, 265 const BuildSettings* build_settings,
211 const SourceFile& name, 266 const SourceFile& name,
212 InputFile* file, 267 InputFile* file,
213 Err* err) { 268 Err* err) {
214 // Do all of this stuff outside the lock. We should not give out file 269 std::vector<Token> tokens;
215 // pointers until the read is complete. 270 scoped_ptr<ParseNode> root;
216 if (g_scheduler->verbose_logging()) { 271 bool success = DoLoadFile(origin, build_settings, name, file,
217 std::string logmsg = name.value(); 272 &tokens, &root, err);
218 if (origin.begin().file()) 273 // Can't return early. We have to ensure that the completion event is
219 logmsg += " (referenced from " + origin.begin().Describe(false) + ")"; 274 // signaled in all cases bacause another thread could be blocked on this one.
220 g_scheduler->Log("Loading", logmsg);
221 }
222 275
223 // Read. 276 // Save this pointer for running the callbacks below, which happens after the
224 base::FilePath primary_path = build_settings->GetFullPath(name); 277 // scoped ptr ownership is taken away inside the lock.
225 ScopedTrace load_trace(TraceItem::TRACE_FILE_LOAD, name.value());
226 if (!file->Load(primary_path)) {
227 if (!build_settings->secondary_source_path().empty()) {
228 // Fall back to secondary source tree.
229 base::FilePath secondary_path =
230 build_settings->GetFullPathSecondary(name);
231 if (!file->Load(secondary_path)) {
232 *err = Err(origin, "Can't load input file.",
233 "Unable to load either \n" +
234 FilePathToUTF8(primary_path) + " or \n" +
235 FilePathToUTF8(secondary_path));
236 return false;
237 }
238 } else {
239 *err = Err(origin,
240 "Unable to load \"" + FilePathToUTF8(primary_path) + "\".");
241 return false;
242 }
243 }
244 load_trace.Done();
245
246 ScopedTrace exec_trace(TraceItem::TRACE_FILE_PARSE, name.value());
247
248 // Tokenize.
249 std::vector<Token> tokens = Tokenizer::Tokenize(file, err);
250 if (err->has_error())
251 return false;
252
253 // Parse.
254 scoped_ptr<ParseNode> root = Parser::Parse(tokens, err);
255 if (err->has_error())
256 return false;
257 ParseNode* unowned_root = root.get(); 278 ParseNode* unowned_root = root.get();
258 279
259 exec_trace.Done();
260
261 std::vector<FileLoadCallback> callbacks; 280 std::vector<FileLoadCallback> callbacks;
262 { 281 {
263 base::AutoLock lock(lock_); 282 base::AutoLock lock(lock_);
264 DCHECK(input_files_.find(name) != input_files_.end()); 283 DCHECK(input_files_.find(name) != input_files_.end());
265 284
266 InputFileData* data = input_files_[name]; 285 InputFileData* data = input_files_[name];
267 data->loaded = true; 286 data->loaded = true;
268 data->tokens.swap(tokens); 287 if (success) {
269 data->parsed_root = root.Pass(); 288 data->tokens.swap(tokens);
289 data->parsed_root = root.Pass();
290 }
270 291
271 // Unblock waiters on this event. 292 // Unblock waiters on this event.
272 // 293 //
273 // It's somewhat bad to signal this inside the lock. When it's used, it's 294 // It's somewhat bad to signal this inside the lock. When it's used, it's
274 // lazily created inside the lock. So we need to do the check and signal 295 // lazily created inside the lock. So we need to do the check and signal
275 // inside the lock to avoid race conditions on the lazy creation of the 296 // inside the lock to avoid race conditions on the lazy creation of the
276 // lock. 297 // lock.
277 // 298 //
278 // We could avoid this by creating the lock every time, but the lock is 299 // We could avoid this by creating the lock every time, but the lock is
279 // very seldom used and will generally be NULL, so my current theory is that 300 // very seldom used and will generally be NULL, so my current theory is that
280 // several signals of a completion event inside a lock is better than 301 // several signals of a completion event inside a lock is better than
281 // creating about 1000 extra locks (one for each file). 302 // creating about 1000 extra locks (one for each file).
282 if (data->completion_event) 303 if (data->completion_event)
283 data->completion_event->Signal(); 304 data->completion_event->Signal();
284 305
285 callbacks.swap(data->scheduled_callbacks); 306 callbacks.swap(data->scheduled_callbacks);
286 } 307 }
287 308
288 // Run pending invocations. Theoretically we could schedule each of these 309 // Run pending invocations. Theoretically we could schedule each of these
289 // separately to get some parallelism. But normally there will only be one 310 // separately to get some parallelism. But normally there will only be one
290 // item in the list, so that's extra overhead and complexity for no gain. 311 // item in the list, so that's extra overhead and complexity for no gain.
291 for (size_t i = 0; i < callbacks.size(); i++) 312 if (success) {
292 callbacks[i].Run(unowned_root); 313 for (size_t i = 0; i < callbacks.size(); i++)
293 return true; 314 callbacks[i].Run(unowned_root);
315 }
316 return success;
294 } 317 }
OLDNEW
« no previous file with comments | « skia/BUILD.gn ('k') | tools/gn/parser.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698