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

Side by Side 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: Fixes for review comments. Created 6 years 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
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library engine.incremental_resolver; 5 library engine.incremental_resolver;
6 6
7 import 'dart:collection'; 7 import 'dart:collection';
8 import 'dart:math' as math;
8 9
9 import 'ast.dart'; 10 import 'ast.dart';
10 import 'element.dart'; 11 import 'element.dart';
11 import 'error.dart'; 12 import 'error.dart';
12 import 'java_engine.dart'; 13 import 'java_engine.dart';
13 import 'resolver.dart'; 14 import 'resolver.dart';
14 import 'scanner.dart'; 15 import 'scanner.dart';
15 import 'source.dart'; 16 import 'source.dart';
17 import 'parser.dart';
16 18
17 19
18 /** 20 /**
21 * Attempts to update [oldUnit] to the state that would correspond to [newCode].
22 * Returns `true` if success, or `false` otherwise.
23 * The [oldUnit] might be damaged.
24 */
25 bool poorMansIncrementalResolution(TypeProvider typeProvider,
26 CompilationUnit oldUnit, String newCode) {
27 try {
28 CompilationUnit newUnit = _parseUnit(newCode);
29 _TokenPair firstPair =
30 _findFirstDifferentToken(oldUnit.beginToken, newUnit.beginToken);
31 _TokenPair lastPair =
32 _findLastDifferentToken(oldUnit.endToken, newUnit.endToken);
33 if (firstPair != null && lastPair != null) {
34 // Prepare the "old" token range.
35 Token oldBeginToken;
36 Token oldEndToken;
37 if (firstPair.oldToken.offset < lastPair.oldToken.offset) {
38 oldBeginToken = firstPair.oldToken;
39 oldEndToken = lastPair.oldToken;
40 } else {
41 oldBeginToken = lastPair.oldToken;
42 oldEndToken = firstPair.oldToken;
43 }
44 // Prepare the "old" token tange.
45 Token newBeginToken;
46 Token newEndToken;
47 if (firstPair.newToken.offset < lastPair.newToken.offset) {
48 newBeginToken = firstPair.newToken;
49 newEndToken = lastPair.newToken;
50 } else {
51 newBeginToken = lastPair.newToken;
52 newEndToken = firstPair.newToken;
53 }
54 // Find nodes covering the "old" and "new" token ranges.
55 AstNode oldNode =
56 _findNodeWithTokens(oldUnit, oldBeginToken, oldEndToken);
57 AstNode newNode =
58 _findNodeWithTokens(newUnit, newBeginToken, newEndToken);
59 // Try to find the smallest common node, a FunctionBody currently.
60 {
61 List<AstNode> oldParents = _getParents(oldNode);
62 List<AstNode> newParents = _getParents(newNode);
63 int length = math.min(oldParents.length, newParents.length);
64 bool found = false;
65 for (int i = 0; i < length; i++) {
66 AstNode oldParent = oldParents[i];
67 AstNode newParent = newParents[i];
68 if (oldParent is FunctionBody && newParent is FunctionBody) {
69 oldNode = oldParent;
70 newNode = newParent;
71 found = true;
72 break;
73 }
74 }
75 if (!found) {
76 return false;
77 }
78 }
79 // replace node
80 NodeReplacer.replace(oldNode, newNode);
81 // update token references
82 oldNode.beginToken.previous.setNext(newNode.beginToken);
83 oldNode.endToken.setNext(oldNode.endToken.next);
84 // perform incremental resolution
85 // TODO(scheglov) update errors
86 AnalysisErrorListener errorListener = new BooleanErrorListener();
87 CompilationUnitElement oldUnitElement = oldUnit.element;
88 IncrementalResolver incrementalResolver = new IncrementalResolver(
89 errorListener,
90 typeProvider,
91 oldUnitElement.library,
92 oldUnitElement,
93 oldUnitElement.source,
94 oldNode.offset,
95 oldNode.length,
96 newNode.length);
97 incrementalResolver.resolve(newNode);
98 return true;
99 }
100 } catch (e) {
101 // TODO(scheglov) find a way to log these exceptions
102 }
103 return false;
104 }
105
106
107 List<AstNode> _getParents(AstNode node) {
108 List<AstNode> parents = <AstNode>[];
109 while (node != null) {
110 parents.insert(0, node);
111 node = node.parent;
112 }
113 return parents;
114 }
115
116 AstNode _findNodeWithTokens(AstNode root, Token first, Token last) {
117 int offset = first.offset;
118 int end = last.end;
119 NodeLocator nodeLocator = new NodeLocator.con2(offset, end);
120 return nodeLocator.searchWithin(root);
121 }
122
123
124 class _TokenPair {
125 final Token oldToken;
126 final Token newToken;
127 _TokenPair(this.oldToken, this.newToken);
128 }
129
130
131 _TokenPair _findFirstDifferentToken(Token oldToken, Token newToken) {
132 // print('first ------------');
133 while (oldToken.type != TokenType.EOF && newToken.type != TokenType.EOF) {
134 // print('old: $oldToken @ ${oldToken.offset}');
135 // print('new: $newToken @ ${newToken.offset}');
136 if (!_equalToken(oldToken, newToken, 0)) {
137 return new _TokenPair(oldToken, newToken);
138 }
139 oldToken = oldToken.next;
140 newToken = newToken.next;
141 }
142 return null;
143 }
144
145
146 _TokenPair _findLastDifferentToken(Token oldToken, Token newToken) {
147 // print('last ------------');
148 int delta = newToken.offset - oldToken.offset;
149 while (oldToken.previous != oldToken && newToken.previous != newToken) {
150 // print('old: $oldToken @ ${oldToken.offset}');
151 // print('new: $newToken @ ${newToken.offset}');
152 if (!_equalToken(oldToken, newToken, delta)) {
153 return new _TokenPair(oldToken.next, newToken.next);
154 }
155 oldToken.offset += delta;
156 oldToken = oldToken.previous;
157 newToken = newToken.previous;
158 }
159 return null;
160 }
161
162
163 bool _equalToken(Token a, Token b, int delta) {
164 if (a.type != b.type) {
165 return false;
166 }
167 if (b.offset - a.offset != delta) {
168 return false;
169 }
170 return a.lexeme == b.lexeme;
171 }
172
173
174 CompilationUnit _parseUnit(String code) {
175 // TODO(scheglov) remember and update errors
176 var errorListener = new BooleanErrorListener();
177 var reader = new CharSequenceReader(code);
178 var scanner = new Scanner(null, reader, errorListener);
179 var token = scanner.tokenize();
180 var parser = new Parser(null, errorListener);
181 return parser.parseCompilationUnit(token);
182 }
183
184
185 /**
19 * Instances of the class [DeclarationMatcher] determine whether the element 186 * Instances of the class [DeclarationMatcher] determine whether the element
20 * model defined by a given AST structure matches an existing element model. 187 * model defined by a given AST structure matches an existing element model.
21 */ 188 */
22 class DeclarationMatcher extends RecursiveAstVisitor { 189 class DeclarationMatcher extends RecursiveAstVisitor {
23 /** 190 /**
24 * The libary containing the AST nodes being visited. 191 * The libary containing the AST nodes being visited.
25 */ 192 */
26 LibraryElement _enclosingLibrary; 193 LibraryElement _enclosingLibrary;
27 194
28 /** 195 /**
(...skipping 354 matching lines...) Expand 10 before | Expand all | Expand 10 after
383 } 550 }
384 _assertTrue(showNames.isEmpty); 551 _assertTrue(showNames.isEmpty);
385 _assertTrue(hideNames.isEmpty); 552 _assertTrue(hideNames.isEmpty);
386 } 553 }
387 554
388 void _assertCompatibleParameter(FormalParameter node, 555 void _assertCompatibleParameter(FormalParameter node,
389 ParameterElement element) { 556 ParameterElement element) {
390 if (node is SimpleFormalParameter) { 557 if (node is SimpleFormalParameter) {
391 _assertSameType(node.type, element.type); 558 _assertSameType(node.type, element.type);
392 node.identifier.staticElement = element; 559 node.identifier.staticElement = element;
393 element.nameOffset = node.identifier.offset; 560 (element as ElementImpl).nameOffset = node.identifier.offset;
394 (element as ElementImpl).name = node.identifier.name; 561 (element as ElementImpl).name = node.identifier.name;
395 } else { 562 } else {
396 // TODO(scheglov) support other parameter types 563 // TODO(scheglov) support other parameter types
397 _assertTrue(false); 564 _assertTrue(false);
398 } 565 }
399 // TODO(scheglov) check names of named parameters 566 // TODO(scheglov) check names of named parameters
400 } 567 }
401 568
402 void _assertCompatibleParameters(FormalParameterList nodes, 569 void _assertCompatibleParameters(FormalParameterList nodes,
403 List<ParameterElement> elements) { 570 List<ParameterElement> elements) {
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
450 List<DartType> typeArguments = type.typeArguments; 617 List<DartType> typeArguments = type.typeArguments;
451 if (nodeArgumentList == null) { 618 if (nodeArgumentList == null) {
452 _assertTrue(typeArguments.isEmpty); 619 _assertTrue(typeArguments.isEmpty);
453 } else { 620 } else {
454 List<TypeName> nodeArguments = nodeArgumentList.arguments; 621 List<TypeName> nodeArguments = nodeArgumentList.arguments;
455 _assertSameTypes(nodeArguments, typeArguments); 622 _assertSameTypes(nodeArguments, typeArguments);
456 } 623 }
457 } else if (type is TypeParameterType) { 624 } else if (type is TypeParameterType) {
458 _assertEquals(nodeName, type.name); 625 _assertEquals(nodeName, type.name);
459 // TODO(scheglov) it should be possible to rename type parameters 626 // TODO(scheglov) it should be possible to rename type parameters
627 } else if (type is VoidType) {
628 _assertEquals(nodeName, 'void');
629 // TODO(scheglov) add test for "void"
460 } else { 630 } else {
461 // TODO(scheglov) support other types 631 // TODO(scheglov) support other types
632 // print('node: $node type: $type type.type: ${type.runtimeType}');
462 _assertTrue(false); 633 _assertTrue(false);
463 } 634 }
464 } 635 }
465 636
466 void _assertSameTypes(List<TypeName> nodes, List<DartType> types) { 637 void _assertSameTypes(List<TypeName> nodes, List<DartType> types) {
467 int length = nodes.length; 638 int length = nodes.length;
468 _assertEquals(length, types.length); 639 _assertEquals(length, types.length);
469 for (int i = 0; i < length; i++) { 640 for (int i = 0; i < length; i++) {
470 _assertSameType(nodes[i], types[i]); 641 _assertSameType(nodes[i], types[i]);
471 } 642 }
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
544 if (element.displayName == name && element.nameOffset == offset) { 715 if (element.displayName == name && element.nameOffset == offset) {
545 return element; 716 return element;
546 } 717 }
547 } 718 }
548 return null; 719 return null;
549 } 720 }
550 721
551 void _gatherElements(Element element) { 722 void _gatherElements(Element element) {
552 _ElementsGatherer gatherer = new _ElementsGatherer(this); 723 _ElementsGatherer gatherer = new _ElementsGatherer(this);
553 element.accept(gatherer); 724 element.accept(gatherer);
554 // TODO(scheglov) push into CompilationUnitElement 725 // TODO(scheglov) what if a change in a directive?
555 if (identical(_enclosingUnit, _enclosingLibrary.definingCompilationUnit)) { 726 if (identical(element, _enclosingLibrary.definingCompilationUnit)) {
556 gatherer.addElements(_enclosingLibrary.imports); 727 gatherer.addElements(_enclosingLibrary.imports);
557 gatherer.addElements(_enclosingLibrary.exports); 728 gatherer.addElements(_enclosingLibrary.exports);
558 gatherer.addElements(_enclosingLibrary.parts); 729 gatherer.addElements(_enclosingLibrary.parts);
559 } 730 }
560 } 731 }
561 732
562 /** 733 /**
563 * Return the value of the given string literal, or `null` if the string is no t a constant 734 * Return the value of the given string literal, or `null` if the string is no t a constant
564 * string without any string interpolation. 735 * string without any string interpolation.
565 * 736 *
(...skipping 516 matching lines...) Expand 10 before | Expand all | Expand 10 after
1082 visitFunctionExpression(FunctionExpression node) { 1253 visitFunctionExpression(FunctionExpression node) {
1083 _elements[node] = node.element; 1254 _elements[node] = node.element;
1084 super.visitFunctionExpression(node); 1255 super.visitFunctionExpression(node);
1085 } 1256 }
1086 1257
1087 @override 1258 @override
1088 visitSimpleIdentifier(SimpleIdentifier node) { 1259 visitSimpleIdentifier(SimpleIdentifier node) {
1089 _elements[node] = node.staticElement; 1260 _elements[node] = node.staticElement;
1090 } 1261 }
1091 } 1262 }
OLDNEW
« no previous file with comments | « pkg/analyzer/lib/src/generated/engine.dart ('k') | pkg/analyzer/test/generated/incremental_resolver_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698