Index: site/try/poi/poi.dart |
diff --git a/site/try/poi/poi.dart b/site/try/poi/poi.dart |
deleted file mode 100644 |
index cb04b8dcfca9b3495fae4f1209fc16b2ddfc31f2..0000000000000000000000000000000000000000 |
--- a/site/try/poi/poi.dart |
+++ /dev/null |
@@ -1,572 +0,0 @@ |
-// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE file. |
- |
-library trydart.poi; |
- |
-import 'dart:async' show |
- Completer, |
- Future; |
- |
-import 'dart:io' as io; |
- |
-import 'dart:convert' show |
- UTF8; |
- |
-import 'package:dart2js_incremental/dart2js_incremental.dart' show |
- INCREMENTAL_OPTIONS, |
- reuseCompiler; |
- |
-import 'package:dart2js_incremental/library_updater.dart' show |
- IncrementalCompilerContext, |
- LibraryUpdater; |
- |
-import 'package:compiler/src/source_file_provider.dart' show |
- FormattingDiagnosticHandler; |
- |
-import 'package:compiler/compiler.dart' as api; |
- |
-import 'package:compiler/src/compiler.dart' show |
- Compiler; |
- |
-import 'package:compiler/src/common/tasks.dart' show |
- CompilerTask; |
- |
-import 'package:compiler/src/common/work.dart' show |
- WorkItem; |
- |
-import 'package:compiler/src/elements/visitor.dart' show |
- BaseElementVisitor; |
- |
-import 'package:compiler/src/elements/elements.dart' show |
- AbstractFieldElement, |
- ClassElement, |
- CompilationUnitElement, |
- Element, |
- ElementCategory, |
- FunctionElement, |
- LibraryElement, |
- ScopeContainerElement; |
- |
-import 'package:compiler/src/elements/modelx.dart' as modelx; |
- |
-import 'package:compiler/src/elements/modelx.dart' show |
- DeclarationSite; |
- |
-import 'package:compiler/src/enqueue.dart' show |
- Enqueuer, |
- QueueFilter; |
- |
-import 'package:compiler/src/dart_types.dart' show |
- DartType; |
- |
-import 'package:compiler/src/parser/partial_elements.dart' show |
- PartialClassElement, |
- PartialElement; |
- |
-import 'package:compiler/src/tokens/token.dart' show |
- Token; |
- |
-import 'package:compiler/src/tokens/token_constants.dart' show |
- EOF_TOKEN, |
- IDENTIFIER_TOKEN, |
- KEYWORD_TOKEN; |
- |
-import 'package:compiler/src/js/js.dart' show |
- js; |
- |
-import 'scope_information_visitor.dart' show |
- ScopeInformationVisitor; |
- |
-/// Enabled by the option --enable-dart-mind. Controls if this program should |
-/// be querying Dart Mind. |
-bool isDartMindEnabled = false; |
- |
-/// Iterator over lines from standard input (or the argument array). |
-Iterator<String> stdin; |
- |
-/// Enabled by the option --simulate-mutation. When true, this program will |
-/// only prompt for one file name, and subsequent runs will read |
-/// FILENAME.N.dart, where N starts at 1, and is increased on each iteration. |
-/// For example, if the program is invoked as: |
-/// |
-/// dart poi.dart --simulate-mutation test.dart 11 22 33 44 |
-/// |
-/// The program will first read the file 'test.dart' and compute scope |
-/// information about position 11, then position 22 in test.dart.1.dart, then |
-/// position 33 in test.dart.2.dart, and finally position 44 in |
-/// test.dart.3.dart. |
-bool isSimulateMutationEnabled = false; |
- |
-/// Counts the number of times [runPoi] has been invoked. |
-int poiCount; |
- |
-int globalCounter = 0; |
- |
-/// Enabled by the option --verbose (or -v). Prints more information than you |
-/// really need. |
-bool isVerbose = false; |
- |
-/// Enabled by the option --compile. Also compiles the program after analyzing |
-/// the POI. |
-bool isCompiler = false; |
- |
-/// Enabled by the option --minify. Passes the same option to the compiler to |
-/// generate minified output. |
-bool enableMinification = false; |
- |
-/// When true (the default value) print serialized scope information at the |
-/// provided position. |
-const bool PRINT_SCOPE_INFO = |
- const bool.fromEnvironment('PRINT_SCOPE_INFO', defaultValue: true); |
- |
-Stopwatch wallClock = new Stopwatch(); |
- |
-PoiTask poiTask; |
- |
-Compiler cachedCompiler; |
- |
-/// Iterator for reading lines from [io.stdin]. |
-class StdinIterator implements Iterator<String> { |
- String current; |
- |
- bool moveNext() { |
- current = io.stdin.readLineSync(); |
- return true; |
- } |
-} |
- |
-printFormattedTime(message, int us) { |
- String m = '$message${" " * 65}'.substring(0, 60); |
- String i = '${" " * 10}${(us/1000).toStringAsFixed(3)}'; |
- i = i.substring(i.length - 10); |
- print('$m ${i}ms'); |
-} |
- |
-printWallClock(message) { |
- if (!isVerbose) return; |
- if (wallClock.isRunning) { |
- print('$message'); |
- printFormattedTime('--->>>', wallClock.elapsedMicroseconds); |
- wallClock.reset(); |
- } else { |
- print(message); |
- } |
-} |
- |
-printVerbose(message) { |
- if (!isVerbose) return; |
- print(message); |
-} |
- |
-main(List<String> arguments) { |
- poiCount = 0; |
- wallClock.start(); |
- List<String> nonOptionArguments = []; |
- for (String argument in arguments) { |
- if (argument.startsWith('-')) { |
- switch (argument) { |
- case '--simulate-mutation': |
- isSimulateMutationEnabled = true; |
- break; |
- case '--enable-dart-mind': |
- isDartMindEnabled = true; |
- break; |
- case '-v': |
- case '--verbose': |
- isVerbose = true; |
- break; |
- case '--compile': |
- isCompiler = true; |
- break; |
- case '--minify': |
- enableMinification = true; |
- break; |
- default: |
- throw 'Unknown option: $argument.'; |
- } |
- } else { |
- nonOptionArguments.add(argument); |
- } |
- } |
- if (nonOptionArguments.isEmpty) { |
- stdin = new StdinIterator(); |
- } else { |
- stdin = nonOptionArguments.iterator; |
- } |
- |
- FormattingDiagnosticHandler handler = new FormattingDiagnosticHandler(); |
- handler |
- ..verbose = false |
- ..enableColors = true; |
- api.CompilerInputProvider inputProvider = handler.provider; |
- |
- return prompt('Dart file: ').then((String fileName) { |
- if (isSimulateMutationEnabled) { |
- inputProvider = simulateMutation(fileName, inputProvider); |
- } |
- return prompt('Position: ').then((String position) { |
- return parseUserInput(fileName, position, inputProvider, handler); |
- }); |
- }); |
-} |
- |
-/// Create an input provider that implements the behavior documented at |
-/// [simulateMutation]. |
-api.CompilerInputProvider simulateMutation( |
- String fileName, |
- api.CompilerInputProvider inputProvider) { |
- Uri script = Uri.base.resolveUri(new Uri.file(fileName)); |
- int count = poiCount; |
- Future cache; |
- String cachedFileName = script.toFilePath(); |
- int counter = ++globalCounter; |
- return (Uri uri) { |
- if (counter != globalCounter) throw 'Using old provider'; |
- printVerbose('fake inputProvider#$counter($uri): $poiCount $count'); |
- if (uri == script) { |
- if (poiCount == count) { |
- cachedFileName = uri.toFilePath(); |
- if (count != 0) { |
- cachedFileName = '$cachedFileName.$count.dart'; |
- } |
- printVerbose('Not using cached version of $cachedFileName'); |
- cache = new io.File(cachedFileName).readAsBytes().then((data) { |
- printVerbose( |
- 'Read file $cachedFileName: ' |
- '${UTF8.decode(data.take(100).toList(), allowMalformed: true)}...'); |
- return data; |
- }); |
- count++; |
- } else { |
- printVerbose('Using cached version of $cachedFileName'); |
- } |
- return cache; |
- } else { |
- printVerbose('Using original provider for $uri'); |
- return inputProvider(uri); |
- } |
- }; |
-} |
- |
-Future<String> prompt(message) { |
- if (stdin is StdinIterator) { |
- io.stdout.write(message); |
- } |
- return io.stdout.flush().then((_) { |
- stdin.moveNext(); |
- return stdin.current; |
- }); |
-} |
- |
-Future queryDartMind(String prefix, String info) { |
- // TODO(lukechurch): Use [info] for something. |
- String encodedArg0 = Uri.encodeComponent('"$prefix"'); |
- String mindQuery = |
- 'http://dart-mind.appspot.com/rpc' |
- '?action=GetExportingPubCompletions' |
- '&arg0=$encodedArg0'; |
- Uri uri = Uri.parse(mindQuery); |
- |
- io.HttpClient client = new io.HttpClient(); |
- return client.getUrl(uri).then((io.HttpClientRequest request) { |
- return request.close(); |
- }).then((io.HttpClientResponse response) { |
- Completer<String> completer = new Completer<String>(); |
- response.transform(UTF8.decoder).listen((contents) { |
- completer.complete(contents); |
- }); |
- return completer.future; |
- }); |
-} |
- |
-Future parseUserInput( |
- String fileName, |
- String positionString, |
- api.CompilerInputProvider inputProvider, |
- api.DiagnosticHandler handler) { |
- Future repeat() { |
- printFormattedTime('--->>>', wallClock.elapsedMicroseconds); |
- wallClock.reset(); |
- |
- return prompt('Position: ').then((String positionString) { |
- wallClock.reset(); |
- return parseUserInput(fileName, positionString, inputProvider, handler); |
- }); |
- } |
- |
- printWallClock("\n\n\nparseUserInput('$fileName', '$positionString')"); |
- |
- Uri script = Uri.base.resolveUri(new Uri.file(fileName)); |
- if (positionString == null) return null; |
- int position = int.parse( |
- positionString, onError: (_) { print('Please enter an integer.'); }); |
- if (position == null) return repeat(); |
- |
- inputProvider(script); |
- if (isVerbose) { |
- handler( |
- script, position, position + 1, |
- 'Point of interest. ' |
- 'Cursor is immediately before highlighted character.', |
- api.Diagnostic.HINT); |
- } |
- |
- Stopwatch sw = new Stopwatch()..start(); |
- |
- Future future = runPoi(script, position, inputProvider, handler); |
- return future.then((Element element) { |
- if (isVerbose) { |
- printFormattedTime('Resolving took', sw.elapsedMicroseconds); |
- } |
- sw.reset(); |
- String info = scopeInformation(element, position); |
- sw.stop(); |
- if (PRINT_SCOPE_INFO) { |
- print(info); |
- } |
- printVerbose('Scope information took ${sw.elapsedMicroseconds}us.'); |
- sw..reset()..start(); |
- Token token = findToken(element, position); |
- String prefix; |
- if (token != null) { |
- if (token.charOffset + token.charCount <= position) { |
- // After the token; in whitespace, or in the beginning of another token. |
- prefix = ""; |
- } else if (token.kind == IDENTIFIER_TOKEN || |
- token.kind == KEYWORD_TOKEN) { |
- prefix = token.value.substring(0, position - token.charOffset); |
- } |
- } |
- sw.stop(); |
- printVerbose('Find token took ${sw.elapsedMicroseconds}us.'); |
- if (isDartMindEnabled && prefix != null) { |
- sw..reset()..start(); |
- return queryDartMind(prefix, info).then((String dartMindSuggestion) { |
- sw.stop(); |
- print('Dart Mind ($prefix): $dartMindSuggestion.'); |
- printVerbose('Dart Mind took ${sw.elapsedMicroseconds}us.'); |
- return repeat(); |
- }); |
- } else { |
- if (isDartMindEnabled) { |
- print("Didn't talk to Dart Mind, no identifier at POI ($token)."); |
- } |
- return repeat(); |
- } |
- }); |
-} |
- |
-/// Find the token corresponding to [position] in [element]. The method only |
-/// works for instances of [PartialElement] or [LibraryElement]. Support for |
-/// [LibraryElement] is currently limited, and works only for named libraries. |
-Token findToken(modelx.ElementX element, int position) { |
- Token beginToken; |
- DeclarationSite site = element.declarationSite; |
- if (site is PartialElement) { |
- beginToken = site.beginToken; |
- } else if (element.isLibrary) { |
- // TODO(ahe): Generalize support for library elements (and update above |
- // documentation). |
- modelx.LibraryElementX lib = element; |
- var tag = lib.libraryTag; |
- if (tag != null) { |
- beginToken = tag.libraryKeyword; |
- } |
- } else { |
- beginToken = element.position; |
- } |
- if (beginToken == null) return null; |
- for (Token token = beginToken; token.kind != EOF_TOKEN; token = token.next) { |
- if (token.charOffset < position && position <= token.next.charOffset) { |
- return token; |
- } |
- } |
- return null; |
-} |
- |
-Future<Element> runPoi( |
- Uri script, |
- int position, |
- api.CompilerInputProvider inputProvider, |
- api.DiagnosticHandler handler) { |
- Stopwatch sw = new Stopwatch()..start(); |
- Uri libraryRoot = Uri.base.resolve('sdk/'); |
- Uri packageRoot = Uri.base.resolve(io.Platform.packageRoot); |
- |
- var options = [ |
- '--analyze-main', |
- '--verbose', |
- '--categories=Client,Server', |
- ]; |
- options.addAll(INCREMENTAL_OPTIONS); |
- |
- if (!isCompiler) { |
- options.add('--analyze-only'); |
- } |
- |
- if (enableMinification) { |
- options.add('--minify'); |
- } |
- |
- LibraryUpdater updater; |
- |
- Future<bool> reuseLibrary(LibraryElement library) { |
- return poiTask.measure(() => updater.reuseLibrary(library)); |
- } |
- |
- Future<Compiler> invokeReuseCompiler() { |
- var context = new IncrementalCompilerContext(); |
- updater = new LibraryUpdater( |
- cachedCompiler, inputProvider, printWallClock, printVerbose, context); |
- context.registerUriWithUpdates([script]); |
- return reuseCompiler( |
- diagnosticHandler: handler, |
- inputProvider: inputProvider, |
- options: options, |
- cachedCompiler: cachedCompiler, |
- libraryRoot: libraryRoot, |
- packageRoot: packageRoot, |
- packagesAreImmutable: true, |
- reuseLibrary: reuseLibrary); |
- } |
- |
- return invokeReuseCompiler().then((Compiler newCompiler) { |
- // TODO(ahe): Move this "then" block to [reuseCompiler]. |
- if (updater.failed) { |
- cachedCompiler = null; |
- return invokeReuseCompiler(); |
- } else { |
- return newCompiler; |
- } |
- }).then((Compiler newCompiler) { |
- if (!isCompiler) { |
- newCompiler.enqueuerFilter = new ScriptOnlyFilter(script); |
- } |
- return runPoiInternal(newCompiler, sw, updater, script, position); |
- }); |
-} |
- |
-Future<Element> runPoiInternal( |
- Compiler newCompiler, |
- Stopwatch sw, |
- LibraryUpdater updater, |
- Uri uri, |
- int position) { |
- bool isFullCompile = cachedCompiler != newCompiler; |
- cachedCompiler = newCompiler; |
- if (poiTask == null || poiTask.compiler != cachedCompiler) { |
- poiTask = new PoiTask(cachedCompiler); |
- cachedCompiler.tasks.add(poiTask); |
- } |
- |
- if (!isFullCompile) { |
- printFormattedTime( |
- 'Analyzing changes and updating elements took', sw.elapsedMicroseconds); |
- } |
- sw.reset(); |
- |
- Future<bool> compilation; |
- |
- if (updater.hasPendingUpdates) { |
- compilation = new Future(() { |
- var node = js.statement( |
- r'var $dart_patch = #', js.escapedString(updater.computeUpdateJs())); |
- print(updater.prettyPrintJs(node)); |
- |
- return !cachedCompiler.compilationFailed; |
- }); |
- } else { |
- compilation = cachedCompiler.run(uri); |
- } |
- |
- return compilation.then((success) { |
- printVerbose('Compiler queue processed in ${sw.elapsedMicroseconds}us'); |
- if (isVerbose) { |
- for (final task in cachedCompiler.tasks) { |
- int time = task.timingMicroseconds; |
- if (time != 0) { |
- printFormattedTime('${task.name} took', time); |
- } |
- } |
- } |
- |
- if (poiCount != null) poiCount++; |
- if (success != true) { |
- throw 'Compilation failed'; |
- } |
- return findPosition(position, cachedCompiler.mainApp); |
- }); |
-} |
- |
-Element findPosition(int position, Element element) { |
- FindPositionVisitor visitor = new FindPositionVisitor(position, element); |
- element.accept(visitor, null); |
- return visitor.element; |
-} |
- |
-String scopeInformation(Element element, int position) { |
- ScopeInformationVisitor visitor = |
- new ScopeInformationVisitor(cachedCompiler, element, position); |
- element.accept(visitor, null); |
- return '${visitor.buffer}'; |
-} |
- |
-class FindPositionVisitor extends BaseElementVisitor { |
- final int position; |
- Element element; |
- |
- FindPositionVisitor(this.position, this.element); |
- |
- visitElement(modelx.ElementX e, _) { |
- DeclarationSite site = e.declarationSite; |
- if (site is PartialElement) { |
- if (site.beginToken.charOffset <= position && |
- position < site.endToken.next.charOffset) { |
- element = e; |
- } |
- } |
- } |
- |
- visitClassElement(ClassElement e, _) { |
- if (e is PartialClassElement) { |
- if (e.beginToken.charOffset <= position && |
- position < e.endToken.next.charOffset) { |
- element = e; |
- visitScopeContainerElement(e, _); |
- } |
- } |
- } |
- |
- visitScopeContainerElement(ScopeContainerElement e, _) { |
- e.forEachLocalMember((Element element) => element.accept(this, _)); |
- } |
-} |
- |
-class ScriptOnlyFilter implements QueueFilter { |
- final Uri script; |
- |
- ScriptOnlyFilter(this.script); |
- |
- bool checkNoEnqueuedInvokedInstanceMethods(Enqueuer enqueuer) => true; |
- |
- void processWorkItem(void f(WorkItem work), WorkItem work) { |
- if (work.element.library.canonicalUri != script) { |
- // TODO(ahe): Rather nasty hack to work around another nasty hack in |
- // backend.dart. Find better solution. |
- if (work.element.name != 'closureFromTearOff') { |
- printWallClock('Skipped ${work.element}.'); |
- return; |
- } |
- } |
- f(work); |
- printWallClock('Processed ${work.element}.'); |
- } |
-} |
- |
-class PoiTask extends CompilerTask { |
- final Compiler compiler; |
- PoiTask(Compiler compiler) : compiler = compiler, super(compiler.measurer); |
- |
- String get name => 'POI'; |
-} |