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

Side by Side Diff: site/try/poi/poi.dart

Issue 2232273004: Delete site/try (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: 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
OLDNEW
(Empty)
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 library trydart.poi;
6
7 import 'dart:async' show
8 Completer,
9 Future;
10
11 import 'dart:io' as io;
12
13 import 'dart:convert' show
14 UTF8;
15
16 import 'package:dart2js_incremental/dart2js_incremental.dart' show
17 INCREMENTAL_OPTIONS,
18 reuseCompiler;
19
20 import 'package:dart2js_incremental/library_updater.dart' show
21 IncrementalCompilerContext,
22 LibraryUpdater;
23
24 import 'package:compiler/src/source_file_provider.dart' show
25 FormattingDiagnosticHandler;
26
27 import 'package:compiler/compiler.dart' as api;
28
29 import 'package:compiler/src/compiler.dart' show
30 Compiler;
31
32 import 'package:compiler/src/common/tasks.dart' show
33 CompilerTask;
34
35 import 'package:compiler/src/common/work.dart' show
36 WorkItem;
37
38 import 'package:compiler/src/elements/visitor.dart' show
39 BaseElementVisitor;
40
41 import 'package:compiler/src/elements/elements.dart' show
42 AbstractFieldElement,
43 ClassElement,
44 CompilationUnitElement,
45 Element,
46 ElementCategory,
47 FunctionElement,
48 LibraryElement,
49 ScopeContainerElement;
50
51 import 'package:compiler/src/elements/modelx.dart' as modelx;
52
53 import 'package:compiler/src/elements/modelx.dart' show
54 DeclarationSite;
55
56 import 'package:compiler/src/enqueue.dart' show
57 Enqueuer,
58 QueueFilter;
59
60 import 'package:compiler/src/dart_types.dart' show
61 DartType;
62
63 import 'package:compiler/src/parser/partial_elements.dart' show
64 PartialClassElement,
65 PartialElement;
66
67 import 'package:compiler/src/tokens/token.dart' show
68 Token;
69
70 import 'package:compiler/src/tokens/token_constants.dart' show
71 EOF_TOKEN,
72 IDENTIFIER_TOKEN,
73 KEYWORD_TOKEN;
74
75 import 'package:compiler/src/js/js.dart' show
76 js;
77
78 import 'scope_information_visitor.dart' show
79 ScopeInformationVisitor;
80
81 /// Enabled by the option --enable-dart-mind. Controls if this program should
82 /// be querying Dart Mind.
83 bool isDartMindEnabled = false;
84
85 /// Iterator over lines from standard input (or the argument array).
86 Iterator<String> stdin;
87
88 /// Enabled by the option --simulate-mutation. When true, this program will
89 /// only prompt for one file name, and subsequent runs will read
90 /// FILENAME.N.dart, where N starts at 1, and is increased on each iteration.
91 /// For example, if the program is invoked as:
92 ///
93 /// dart poi.dart --simulate-mutation test.dart 11 22 33 44
94 ///
95 /// The program will first read the file 'test.dart' and compute scope
96 /// information about position 11, then position 22 in test.dart.1.dart, then
97 /// position 33 in test.dart.2.dart, and finally position 44 in
98 /// test.dart.3.dart.
99 bool isSimulateMutationEnabled = false;
100
101 /// Counts the number of times [runPoi] has been invoked.
102 int poiCount;
103
104 int globalCounter = 0;
105
106 /// Enabled by the option --verbose (or -v). Prints more information than you
107 /// really need.
108 bool isVerbose = false;
109
110 /// Enabled by the option --compile. Also compiles the program after analyzing
111 /// the POI.
112 bool isCompiler = false;
113
114 /// Enabled by the option --minify. Passes the same option to the compiler to
115 /// generate minified output.
116 bool enableMinification = false;
117
118 /// When true (the default value) print serialized scope information at the
119 /// provided position.
120 const bool PRINT_SCOPE_INFO =
121 const bool.fromEnvironment('PRINT_SCOPE_INFO', defaultValue: true);
122
123 Stopwatch wallClock = new Stopwatch();
124
125 PoiTask poiTask;
126
127 Compiler cachedCompiler;
128
129 /// Iterator for reading lines from [io.stdin].
130 class StdinIterator implements Iterator<String> {
131 String current;
132
133 bool moveNext() {
134 current = io.stdin.readLineSync();
135 return true;
136 }
137 }
138
139 printFormattedTime(message, int us) {
140 String m = '$message${" " * 65}'.substring(0, 60);
141 String i = '${" " * 10}${(us/1000).toStringAsFixed(3)}';
142 i = i.substring(i.length - 10);
143 print('$m ${i}ms');
144 }
145
146 printWallClock(message) {
147 if (!isVerbose) return;
148 if (wallClock.isRunning) {
149 print('$message');
150 printFormattedTime('--->>>', wallClock.elapsedMicroseconds);
151 wallClock.reset();
152 } else {
153 print(message);
154 }
155 }
156
157 printVerbose(message) {
158 if (!isVerbose) return;
159 print(message);
160 }
161
162 main(List<String> arguments) {
163 poiCount = 0;
164 wallClock.start();
165 List<String> nonOptionArguments = [];
166 for (String argument in arguments) {
167 if (argument.startsWith('-')) {
168 switch (argument) {
169 case '--simulate-mutation':
170 isSimulateMutationEnabled = true;
171 break;
172 case '--enable-dart-mind':
173 isDartMindEnabled = true;
174 break;
175 case '-v':
176 case '--verbose':
177 isVerbose = true;
178 break;
179 case '--compile':
180 isCompiler = true;
181 break;
182 case '--minify':
183 enableMinification = true;
184 break;
185 default:
186 throw 'Unknown option: $argument.';
187 }
188 } else {
189 nonOptionArguments.add(argument);
190 }
191 }
192 if (nonOptionArguments.isEmpty) {
193 stdin = new StdinIterator();
194 } else {
195 stdin = nonOptionArguments.iterator;
196 }
197
198 FormattingDiagnosticHandler handler = new FormattingDiagnosticHandler();
199 handler
200 ..verbose = false
201 ..enableColors = true;
202 api.CompilerInputProvider inputProvider = handler.provider;
203
204 return prompt('Dart file: ').then((String fileName) {
205 if (isSimulateMutationEnabled) {
206 inputProvider = simulateMutation(fileName, inputProvider);
207 }
208 return prompt('Position: ').then((String position) {
209 return parseUserInput(fileName, position, inputProvider, handler);
210 });
211 });
212 }
213
214 /// Create an input provider that implements the behavior documented at
215 /// [simulateMutation].
216 api.CompilerInputProvider simulateMutation(
217 String fileName,
218 api.CompilerInputProvider inputProvider) {
219 Uri script = Uri.base.resolveUri(new Uri.file(fileName));
220 int count = poiCount;
221 Future cache;
222 String cachedFileName = script.toFilePath();
223 int counter = ++globalCounter;
224 return (Uri uri) {
225 if (counter != globalCounter) throw 'Using old provider';
226 printVerbose('fake inputProvider#$counter($uri): $poiCount $count');
227 if (uri == script) {
228 if (poiCount == count) {
229 cachedFileName = uri.toFilePath();
230 if (count != 0) {
231 cachedFileName = '$cachedFileName.$count.dart';
232 }
233 printVerbose('Not using cached version of $cachedFileName');
234 cache = new io.File(cachedFileName).readAsBytes().then((data) {
235 printVerbose(
236 'Read file $cachedFileName: '
237 '${UTF8.decode(data.take(100).toList(), allowMalformed: true)}...' );
238 return data;
239 });
240 count++;
241 } else {
242 printVerbose('Using cached version of $cachedFileName');
243 }
244 return cache;
245 } else {
246 printVerbose('Using original provider for $uri');
247 return inputProvider(uri);
248 }
249 };
250 }
251
252 Future<String> prompt(message) {
253 if (stdin is StdinIterator) {
254 io.stdout.write(message);
255 }
256 return io.stdout.flush().then((_) {
257 stdin.moveNext();
258 return stdin.current;
259 });
260 }
261
262 Future queryDartMind(String prefix, String info) {
263 // TODO(lukechurch): Use [info] for something.
264 String encodedArg0 = Uri.encodeComponent('"$prefix"');
265 String mindQuery =
266 'http://dart-mind.appspot.com/rpc'
267 '?action=GetExportingPubCompletions'
268 '&arg0=$encodedArg0';
269 Uri uri = Uri.parse(mindQuery);
270
271 io.HttpClient client = new io.HttpClient();
272 return client.getUrl(uri).then((io.HttpClientRequest request) {
273 return request.close();
274 }).then((io.HttpClientResponse response) {
275 Completer<String> completer = new Completer<String>();
276 response.transform(UTF8.decoder).listen((contents) {
277 completer.complete(contents);
278 });
279 return completer.future;
280 });
281 }
282
283 Future parseUserInput(
284 String fileName,
285 String positionString,
286 api.CompilerInputProvider inputProvider,
287 api.DiagnosticHandler handler) {
288 Future repeat() {
289 printFormattedTime('--->>>', wallClock.elapsedMicroseconds);
290 wallClock.reset();
291
292 return prompt('Position: ').then((String positionString) {
293 wallClock.reset();
294 return parseUserInput(fileName, positionString, inputProvider, handler);
295 });
296 }
297
298 printWallClock("\n\n\nparseUserInput('$fileName', '$positionString')");
299
300 Uri script = Uri.base.resolveUri(new Uri.file(fileName));
301 if (positionString == null) return null;
302 int position = int.parse(
303 positionString, onError: (_) { print('Please enter an integer.'); });
304 if (position == null) return repeat();
305
306 inputProvider(script);
307 if (isVerbose) {
308 handler(
309 script, position, position + 1,
310 'Point of interest. '
311 'Cursor is immediately before highlighted character.',
312 api.Diagnostic.HINT);
313 }
314
315 Stopwatch sw = new Stopwatch()..start();
316
317 Future future = runPoi(script, position, inputProvider, handler);
318 return future.then((Element element) {
319 if (isVerbose) {
320 printFormattedTime('Resolving took', sw.elapsedMicroseconds);
321 }
322 sw.reset();
323 String info = scopeInformation(element, position);
324 sw.stop();
325 if (PRINT_SCOPE_INFO) {
326 print(info);
327 }
328 printVerbose('Scope information took ${sw.elapsedMicroseconds}us.');
329 sw..reset()..start();
330 Token token = findToken(element, position);
331 String prefix;
332 if (token != null) {
333 if (token.charOffset + token.charCount <= position) {
334 // After the token; in whitespace, or in the beginning of another token.
335 prefix = "";
336 } else if (token.kind == IDENTIFIER_TOKEN ||
337 token.kind == KEYWORD_TOKEN) {
338 prefix = token.value.substring(0, position - token.charOffset);
339 }
340 }
341 sw.stop();
342 printVerbose('Find token took ${sw.elapsedMicroseconds}us.');
343 if (isDartMindEnabled && prefix != null) {
344 sw..reset()..start();
345 return queryDartMind(prefix, info).then((String dartMindSuggestion) {
346 sw.stop();
347 print('Dart Mind ($prefix): $dartMindSuggestion.');
348 printVerbose('Dart Mind took ${sw.elapsedMicroseconds}us.');
349 return repeat();
350 });
351 } else {
352 if (isDartMindEnabled) {
353 print("Didn't talk to Dart Mind, no identifier at POI ($token).");
354 }
355 return repeat();
356 }
357 });
358 }
359
360 /// Find the token corresponding to [position] in [element]. The method only
361 /// works for instances of [PartialElement] or [LibraryElement]. Support for
362 /// [LibraryElement] is currently limited, and works only for named libraries.
363 Token findToken(modelx.ElementX element, int position) {
364 Token beginToken;
365 DeclarationSite site = element.declarationSite;
366 if (site is PartialElement) {
367 beginToken = site.beginToken;
368 } else if (element.isLibrary) {
369 // TODO(ahe): Generalize support for library elements (and update above
370 // documentation).
371 modelx.LibraryElementX lib = element;
372 var tag = lib.libraryTag;
373 if (tag != null) {
374 beginToken = tag.libraryKeyword;
375 }
376 } else {
377 beginToken = element.position;
378 }
379 if (beginToken == null) return null;
380 for (Token token = beginToken; token.kind != EOF_TOKEN; token = token.next) {
381 if (token.charOffset < position && position <= token.next.charOffset) {
382 return token;
383 }
384 }
385 return null;
386 }
387
388 Future<Element> runPoi(
389 Uri script,
390 int position,
391 api.CompilerInputProvider inputProvider,
392 api.DiagnosticHandler handler) {
393 Stopwatch sw = new Stopwatch()..start();
394 Uri libraryRoot = Uri.base.resolve('sdk/');
395 Uri packageRoot = Uri.base.resolve(io.Platform.packageRoot);
396
397 var options = [
398 '--analyze-main',
399 '--verbose',
400 '--categories=Client,Server',
401 ];
402 options.addAll(INCREMENTAL_OPTIONS);
403
404 if (!isCompiler) {
405 options.add('--analyze-only');
406 }
407
408 if (enableMinification) {
409 options.add('--minify');
410 }
411
412 LibraryUpdater updater;
413
414 Future<bool> reuseLibrary(LibraryElement library) {
415 return poiTask.measure(() => updater.reuseLibrary(library));
416 }
417
418 Future<Compiler> invokeReuseCompiler() {
419 var context = new IncrementalCompilerContext();
420 updater = new LibraryUpdater(
421 cachedCompiler, inputProvider, printWallClock, printVerbose, context);
422 context.registerUriWithUpdates([script]);
423 return reuseCompiler(
424 diagnosticHandler: handler,
425 inputProvider: inputProvider,
426 options: options,
427 cachedCompiler: cachedCompiler,
428 libraryRoot: libraryRoot,
429 packageRoot: packageRoot,
430 packagesAreImmutable: true,
431 reuseLibrary: reuseLibrary);
432 }
433
434 return invokeReuseCompiler().then((Compiler newCompiler) {
435 // TODO(ahe): Move this "then" block to [reuseCompiler].
436 if (updater.failed) {
437 cachedCompiler = null;
438 return invokeReuseCompiler();
439 } else {
440 return newCompiler;
441 }
442 }).then((Compiler newCompiler) {
443 if (!isCompiler) {
444 newCompiler.enqueuerFilter = new ScriptOnlyFilter(script);
445 }
446 return runPoiInternal(newCompiler, sw, updater, script, position);
447 });
448 }
449
450 Future<Element> runPoiInternal(
451 Compiler newCompiler,
452 Stopwatch sw,
453 LibraryUpdater updater,
454 Uri uri,
455 int position) {
456 bool isFullCompile = cachedCompiler != newCompiler;
457 cachedCompiler = newCompiler;
458 if (poiTask == null || poiTask.compiler != cachedCompiler) {
459 poiTask = new PoiTask(cachedCompiler);
460 cachedCompiler.tasks.add(poiTask);
461 }
462
463 if (!isFullCompile) {
464 printFormattedTime(
465 'Analyzing changes and updating elements took', sw.elapsedMicroseconds);
466 }
467 sw.reset();
468
469 Future<bool> compilation;
470
471 if (updater.hasPendingUpdates) {
472 compilation = new Future(() {
473 var node = js.statement(
474 r'var $dart_patch = #', js.escapedString(updater.computeUpdateJs()));
475 print(updater.prettyPrintJs(node));
476
477 return !cachedCompiler.compilationFailed;
478 });
479 } else {
480 compilation = cachedCompiler.run(uri);
481 }
482
483 return compilation.then((success) {
484 printVerbose('Compiler queue processed in ${sw.elapsedMicroseconds}us');
485 if (isVerbose) {
486 for (final task in cachedCompiler.tasks) {
487 int time = task.timingMicroseconds;
488 if (time != 0) {
489 printFormattedTime('${task.name} took', time);
490 }
491 }
492 }
493
494 if (poiCount != null) poiCount++;
495 if (success != true) {
496 throw 'Compilation failed';
497 }
498 return findPosition(position, cachedCompiler.mainApp);
499 });
500 }
501
502 Element findPosition(int position, Element element) {
503 FindPositionVisitor visitor = new FindPositionVisitor(position, element);
504 element.accept(visitor, null);
505 return visitor.element;
506 }
507
508 String scopeInformation(Element element, int position) {
509 ScopeInformationVisitor visitor =
510 new ScopeInformationVisitor(cachedCompiler, element, position);
511 element.accept(visitor, null);
512 return '${visitor.buffer}';
513 }
514
515 class FindPositionVisitor extends BaseElementVisitor {
516 final int position;
517 Element element;
518
519 FindPositionVisitor(this.position, this.element);
520
521 visitElement(modelx.ElementX e, _) {
522 DeclarationSite site = e.declarationSite;
523 if (site is PartialElement) {
524 if (site.beginToken.charOffset <= position &&
525 position < site.endToken.next.charOffset) {
526 element = e;
527 }
528 }
529 }
530
531 visitClassElement(ClassElement e, _) {
532 if (e is PartialClassElement) {
533 if (e.beginToken.charOffset <= position &&
534 position < e.endToken.next.charOffset) {
535 element = e;
536 visitScopeContainerElement(e, _);
537 }
538 }
539 }
540
541 visitScopeContainerElement(ScopeContainerElement e, _) {
542 e.forEachLocalMember((Element element) => element.accept(this, _));
543 }
544 }
545
546 class ScriptOnlyFilter implements QueueFilter {
547 final Uri script;
548
549 ScriptOnlyFilter(this.script);
550
551 bool checkNoEnqueuedInvokedInstanceMethods(Enqueuer enqueuer) => true;
552
553 void processWorkItem(void f(WorkItem work), WorkItem work) {
554 if (work.element.library.canonicalUri != script) {
555 // TODO(ahe): Rather nasty hack to work around another nasty hack in
556 // backend.dart. Find better solution.
557 if (work.element.name != 'closureFromTearOff') {
558 printWallClock('Skipped ${work.element}.');
559 return;
560 }
561 }
562 f(work);
563 printWallClock('Processed ${work.element}.');
564 }
565 }
566
567 class PoiTask extends CompilerTask {
568 final Compiler compiler;
569 PoiTask(Compiler compiler) : compiler = compiler, super(compiler.measurer);
570
571 String get name => 'POI';
572 }
OLDNEW
« dart.gyp ('K') | « site/try/poi/patcher.js ('k') | site/try/poi/repeat_poi.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698