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

Unified Diff: pkg/analyzer/lib/src/generated/incremental_resolver.dart

Issue 753803002: Use a poor man's incremental parser to perform incremental resolution. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month 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 side-by-side diff with in-line comments
Download patch
Index: pkg/analyzer/lib/src/generated/incremental_resolver.dart
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolver.dart b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
index 97a36a994f8003e96d1efad13b31890109e0d65f..009e01e77302776c8560ee801e81e484ac7e1d6c 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
@@ -5,6 +5,7 @@
library engine.incremental_resolver;
import 'dart:collection';
+import 'dart:math' as math;
import 'ast.dart';
import 'element.dart';
@@ -13,6 +14,151 @@ import 'java_engine.dart';
import 'resolver.dart';
import 'scanner.dart';
import 'source.dart';
+import 'parser.dart';
+
+
+/**
+ * Attempts to update [oldUnit] to the state that would correspond to [newCode].
+ * Returns `true` if success, or `false` otherwise.
+ * The [oldUnit] might be damaged.
+ */
+bool poorMansIncrementalResolution(TypeProvider typeProvider,
+ CompilationUnit oldUnit, String newCode) {
+ try {
+ CompilationUnit newUnit = _parseUnit(newCode);
+ _TokenPair firstPair =
+ _findFirstDifferentToken(oldUnit.beginToken, newUnit.beginToken);
+ _TokenPair lastPair =
+ _findLastDifferentToken(oldUnit.endToken, newUnit.endToken);
+ if (firstPair != null && lastPair != null) {
+ AstNode oldNode = _findNodeWithTokens(oldUnit, firstPair.a, lastPair.a);
+ AstNode newNode = _findNodeWithTokens(newUnit, firstPair.b, lastPair.b);
+ // Try to find the smallest common node, a FunctionBody currently.
+ {
+ List<AstNode> oldParents = _getParents(oldNode);
Brian Wilkerson 2014/11/24 15:09:14 Why compute a list? Why not just walk up both pare
+ List<AstNode> newParents = _getParents(newNode);
+ int length = math.min(oldParents.length, newParents.length);
+ bool found = false;
+ for (int i = 0; i < length; i++) {
+ AstNode oldParent = oldParents[i];
+ AstNode newParent = newParents[i];
+ if (oldParent is FunctionBody &&
+ newParent is FunctionBody) {
+ oldNode = oldParent;
+ newNode = newParent;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ return false;
+ }
+ }
+ // replace node
+ NodeReplacer.replace(oldNode, newNode);
+ // update token references
+ firstPair.a.previous.setNext(firstPair.b);
+ lastPair.b.setNext(firstPair.a.next);
Paul Berry 2014/11/24 15:02:25 I think this should be: lastPair.b.setNext(last
scheglov 2014/11/24 18:59:06 Done.
+ // perform incremental resolution
+ // TODO(scheglov) update errors
+ AnalysisErrorListener errorListener = new BooleanErrorListener();
+ CompilationUnitElement oldUnitElement = oldUnit.element;
+ IncrementalResolver incrementalResolver = new IncrementalResolver(
+ errorListener,
+ typeProvider,
+ oldUnitElement.library,
+ oldUnitElement,
+ oldUnitElement.source,
+ oldNode.offset,
+ oldNode.length,
+ newNode.length);
+ incrementalResolver.resolve(newNode);
+ return true;
+ }
+ } catch (e) {
+ }
Paul Berry 2014/11/24 15:02:25 Can we report the exception using the "server.erro
scheglov 2014/11/24 18:59:05 We're in a wrong project to do this. I'll add TODO
+ return false;
+}
+
+
+List<AstNode> _getParents(AstNode node) {
+ List<AstNode> parents = <AstNode>[];
+ while (node != null) {
+ parents.insert(0, node);
+ node = node.parent;
+ }
+ return parents;
+}
+
+AstNode _findNodeWithTokens(AstNode root, Token first, Token last) {
+ int offset = first.offset;
+ int end = last.end;
+ NodeLocator nodeLocator = new NodeLocator.con2(offset, end);
+ return nodeLocator.searchWithin(root);
+}
+
+
+class _TokenPair {
+ final Token a;
Paul Berry 2014/11/24 15:02:25 It looks like all uses of _TokenPair use "a" to re
scheglov 2014/11/24 18:59:05 Done.
+ final Token b;
+ _TokenPair(this.a, this.b);
+}
+
+
+_TokenPair _findFirstDifferentToken(Token a, Token b) {
Paul Berry 2014/11/24 15:02:25 The same rename would be nice here too (and also i
scheglov 2014/11/24 18:59:05 Done.
+// print('first ------------');
Paul Berry 2014/11/24 15:02:25 Commented out debug code should be removed (and al
scheglov 2014/11/24 18:59:05 I'd prefer to keep it in for some time and remove
+ while (true) {
+// print('a: $a @ ${a.offset}');
+// print('b: $b @ ${b.offset}');
+ if (!_equalToken(a, b, 0)) {
+ return new _TokenPair(a, b);
+ }
+ if (a.type == TokenType.EOF) {
Brian Wilkerson 2014/11/24 15:09:13 Why not make this part of the while loop's conditi
scheglov 2014/11/24 18:59:06 Done.
+ return null;
+ }
+ a = a.next;
+ b = b.next;
+ }
+ return null;
+}
+
+
+_TokenPair _findLastDifferentToken(Token a, Token b) {
+// print('last ------------');
+ int delta = b.offset - a.offset;
+ while (a.previous != a && b.previous != b) {
+// print('a: $a @ ${a.offset}');
+// print('b: $b @ ${b.offset}');
+ if (!_equalToken(a, b, delta)) {
+ return new _TokenPair(a.next, b.next);
+ }
+ a.offset += delta;
+ a = a.previous;
+ b = b.previous;
+ }
Brian Wilkerson 2014/11/24 15:09:14 For what it's worth, I would find the code easier
scheglov 2014/11/24 18:59:06 Done.
+}
+
+
+bool _equalToken(Token a, Token b, int delta) {
+ if (a.type != b.type) {
+ return false;
+ }
+ if (b.offset - a.offset != delta) {
+ return false;
+ }
+ return a.lexeme == b.lexeme;
+}
+
+
+CompilationUnit _parseUnit(String code) {
+ // TODO(scheglov) remember and update errors
+ var errorListener = new BooleanErrorListener();
+ var reader = new CharSequenceReader(code);
+ var scanner = new Scanner(null, reader, errorListener);
+ var token = scanner.tokenize();
+ var parser = new Parser(null, errorListener);
+ return parser.parseCompilationUnit(token);
+}
/**
@@ -454,8 +600,12 @@ class DeclarationMatcher extends RecursiveAstVisitor {
} else if (type is TypeParameterType) {
_assertEquals(nodeName, type.name);
// TODO(scheglov) it should be possible to rename type parameters
+ } else if (type is VoidType) {
+ _assertEquals(nodeName, 'void');
+ // TODO(scheglov) add test for "void"
} else {
// TODO(scheglov) support other types
+// print('node: $node type: $type type.type: ${type.runtimeType}');
_assertTrue(false);
}
}
@@ -548,8 +698,8 @@ class DeclarationMatcher extends RecursiveAstVisitor {
void _gatherElements(Element element) {
_ElementsGatherer gatherer = new _ElementsGatherer(this);
element.accept(gatherer);
- // TODO(scheglov) push into CompilationUnitElement
- if (identical(_enclosingUnit, _enclosingLibrary.definingCompilationUnit)) {
+ // TODO(scheglov) what if a change in a directive?
+ if (identical(element, _enclosingLibrary.definingCompilationUnit)) {
gatherer.addElements(_enclosingLibrary.imports);
gatherer.addElements(_enclosingLibrary.exports);
gatherer.addElements(_enclosingLibrary.parts);

Powered by Google App Engine
This is Rietveld 408576698