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

Side by Side Diff: pkg/analyzer/lib/src/generated/incremental_scanner.dart

Issue 745873002: Stop copying tokens in incremental scanner (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Clean-up 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
« no previous file with comments | « no previous file | pkg/analyzer/lib/src/generated/scanner.dart » ('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) 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_scanner; 5 library engine.incremental_scanner;
6 6
7 import "dart:math" as math; 7 import "dart:math" as math;
8 8
9 import 'error.dart'; 9 import 'error.dart';
10 import 'scanner.dart'; 10 import 'scanner.dart';
11 import 'source.dart'; 11 import 'source.dart';
12 import 'utilities_collection.dart' show TokenMap; 12 import 'utilities_collection.dart' show TokenMap;
13 13
14 /** 14 /**
15 * Instances of the class `IncrementalScanner` implement a scanner that scans a subset of a 15 * An `IncrementalScanner` is a scanner that scans a subset of a string and
16 * string and inserts the resulting tokens into the middle of an existing token stream. 16 * inserts the resulting tokens into the middle of an existing token stream.
17 */ 17 */
18 class IncrementalScanner extends Scanner { 18 class IncrementalScanner {
19 /**
20 * The source being scanned.
21 */
22 final Source source;
23
19 /** 24 /**
20 * The reader used to access the characters in the source. 25 * The reader used to access the characters in the source.
21 */ 26 */
22 CharacterReader _reader; 27 final CharacterReader reader;
28
29 /**
30 * The error listener that will be informed of any errors that are found
31 * during the scan.
32 *
33 * TODO(brianwilkerson) Replace this with a list of errors so that we can
34 * update the errors.
35 */
36 final AnalysisErrorListener errorListener;
23 37
24 /** 38 /**
25 * A map from tokens that were copied to the copies of the tokens. 39 * A map from tokens that were copied to the copies of the tokens.
26 */ 40 */
27 TokenMap _tokenMap = new TokenMap(); 41 TokenMap _tokenMap = new TokenMap();
28 42
29 /** 43 /**
30 * The token in the new token stream immediately to the left of the range of t okens that were 44 * The token in the new token stream immediately to the left of the range of t okens that were
31 * inserted, or the token immediately to the left of the modified region if th ere were no new 45 * inserted, or the token immediately to the left of the modified region if th ere were no new
32 * tokens. 46 * tokens.
33 */ 47 */
34 Token _leftToken; 48 Token _leftToken;
35 49
36 /** 50 /**
37 * The token in the new token stream immediately to the right of the range of tokens that were 51 * The token in the new token stream immediately to the right of the range of tokens that were
38 * inserted, or the token immediately to the right of the modified region if t here were no new 52 * inserted, or the token immediately to the right of the modified region if t here were no new
39 * tokens. 53 * tokens.
40 */ 54 */
41 Token _rightToken; 55 Token _rightToken;
42 56
43 /** 57 /**
44 * A flag indicating whether there were any tokens changed as a result of the modification. 58 * A flag indicating whether there were any tokens changed as a result of the modification.
45 */ 59 */
46 bool _hasNonWhitespaceChange = false; 60 bool _hasNonWhitespaceChange = false;
47 61
48 /** 62 /**
49 * Initialize a newly created scanner. 63 * Initialize a newly created scanner to scan characters within the given
50 * 64 * [source]. The content of the source can be read using the given [reader].
51 * @param source the source being scanned 65 * Any errors that are found will be reported to the given [errorListener].
52 * @param reader the character reader used to read the characters in the sourc e
53 * @param errorListener the error listener that will be informed of any errors that are found
54 */ 66 */
55 IncrementalScanner(Source source, CharacterReader reader, 67 IncrementalScanner(this.source, this.reader, this.errorListener);
56 AnalysisErrorListener errorListener)
57 : super(source, reader, errorListener) {
58 this._reader = reader;
59 }
60 68
61 /** 69 /**
62 * Return `true` if there were any tokens either added or removed (or both) as a result of 70 * Return `true` if there were any tokens either added or removed (or both) as a result of
63 * the modification. 71 * the modification.
64 * 72 *
65 * @return `true` if there were any tokens changed as a result of the modifica tion 73 * @return `true` if there were any tokens changed as a result of the modifica tion
66 */ 74 */
67 bool get hasNonWhitespaceChange => _hasNonWhitespaceChange; 75 bool get hasNonWhitespaceChange => _hasNonWhitespaceChange;
68 76
69 /** 77 /**
(...skipping 15 matching lines...) Expand all
85 Token get rightToken => _rightToken; 93 Token get rightToken => _rightToken;
86 94
87 /** 95 /**
88 * Return a map from tokens that were copied to the copies of the tokens. 96 * Return a map from tokens that were copied to the copies of the tokens.
89 * 97 *
90 * @return a map from tokens that were copied to the copies of the tokens 98 * @return a map from tokens that were copied to the copies of the tokens
91 */ 99 */
92 TokenMap get tokenMap => _tokenMap; 100 TokenMap get tokenMap => _tokenMap;
93 101
94 /** 102 /**
95 * Given the stream of tokens scanned from the original source, the modified s ource (the result of 103 * Given the [stream] of tokens scanned from the original source, the modified
96 * replacing one contiguous range of characters with another string of charact ers), and a 104 * source (the result of replacing one contiguous range of characters with
97 * specification of the modification that was made, return a stream of tokens scanned from the 105 * another string of characters), and a specification of the modification that
98 * modified source. The original stream of tokens will not be modified. 106 * was made, update the token stream to reflect the modified source. Return
107 * the first token in the updated token stream.
99 * 108 *
100 * @param originalStream the stream of tokens scanned from the original source 109 * The [stream] is expected to be the first non-EOF token in the token stream.
101 * @param index the index of the first character in both the original and modi fied source that was 110 *
102 * affected by the modification 111 * The modification is specified by the [index] of the first character in both
103 * @param removedLength the number of characters removed from the original sou rce 112 * the original and modified source that was affected by the modification, the
104 * @param insertedLength the number of characters added to the modified source 113 * number of characters removed from the original source (the [removedLength])
114 * and the number of characters added to the modified source (the
115 * [insertedLength]).
105 */ 116 */
106 Token rescan(Token originalStream, int index, int removedLength, 117 Token rescan(Token stream, int index, int removedLength, int insertedLength) {
107 int insertedLength) { 118 Token leftEof = stream.previous;
108 //
109 // Copy all of the tokens in the originalStream whose end is less than the
110 // replacement start. (If the replacement start is equal to the end of an
111 // existing token, then it means that the existing token might have been
112 // modified, so we need to rescan it.)
113 //
114 while (originalStream.type != TokenType.EOF && originalStream.end < index) {
115 originalStream = _copyAndAdvance(originalStream, 0);
116 }
117 Token oldFirst = originalStream;
118 Token oldLeftToken = originalStream.previous;
119 _leftToken = tail;
120 //
121 // Skip tokens in the original stream until we find a token whose offset is
122 // greater than the end of the removed region. (If the end of the removed
123 // region is equal to the beginning of an existing token, then it means that
124 // the existing token might have been modified, so we need to rescan it.)
125 //
126 int removedEnd = index + (removedLength == 0 ? 0 : removedLength - 1);
127 while (originalStream.type != TokenType.EOF &&
128 originalStream.offset <= removedEnd) {
129 originalStream = originalStream.next;
130 }
131 Token oldLast;
132 Token oldRightToken;
133 if (originalStream.type != TokenType.EOF &&
134 removedEnd + 1 == originalStream.offset) {
135 oldLast = originalStream;
136 originalStream = originalStream.next;
137 oldRightToken = originalStream;
138 } else {
139 oldLast = originalStream.previous;
140 oldRightToken = originalStream;
141 }
142 // 119 //
143 // Compute the delta between the character index of characters after the 120 // Compute the delta between the character index of characters after the
144 // modified region in the original source and the index of the corresponding 121 // modified region in the original source and the index of the corresponding
145 // character in the modified source. 122 // character in the modified source.
146 // 123 //
147 int delta = insertedLength - removedLength; 124 int delta = insertedLength - removedLength;
148 // 125 //
126 // Skip past the tokens whose end is less than the replacement start. (If
127 // the replacement start is equal to the end of an existing token, then it
128 // means that the existing token might have been modified, so we need to
129 // rescan it.)
130 //
131 while (stream.type != TokenType.EOF && stream.end < index) {
132 _tokenMap.put(stream, stream);
133 stream = stream.next;
134 }
135 Token oldFirst = stream;
136 Token oldLeftToken = stream.previous;
137 _leftToken = oldLeftToken;
138 //
139 // Skip past tokens until we find a token whose offset is greater than the
140 // end of the removed region. (If the end of the removed region is equal to
141 // the beginning of an existing token, then it means that the existing token
142 // might have been modified, so we need to rescan it.)
143 //
144 int removedEnd = index + (removedLength == 0 ? 0 : removedLength - 1);
145 while (stream.type != TokenType.EOF && stream.offset <= removedEnd) {
146 stream = stream.next;
147 }
148 //
149 // Figure out which region of characters actually needs to be re-scanned.
150 //
151 Token oldLast;
152 Token oldRightToken;
153 if (stream.type != TokenType.EOF && removedEnd + 1 == stream.offset) {
154 oldLast = stream;
155 stream = stream.next;
156 oldRightToken = stream;
157 } else {
158 oldLast = stream.previous;
159 oldRightToken = stream;
160 }
161 //
149 // Compute the range of characters that are known to need to be rescanned. 162 // Compute the range of characters that are known to need to be rescanned.
150 // If the index is within an existing token, then we need to start at the 163 // If the index is within an existing token, then we need to start at the
151 // beginning of the token. 164 // beginning of the token.
152 // 165 //
153 int scanStart = math.min(oldFirst.offset, index); 166 int scanStart = math.max(oldFirst.previous.end, 0);
154 int oldEnd = oldLast.end + delta - 1; 167 int scanEnd = oldLast.end + delta;
155 int newEnd = index + insertedLength - 1;
156 int scanEnd = math.max(newEnd, oldEnd);
157 // 168 //
158 // Starting at the start of the scan region, scan tokens from the 169 // Starting at the start of the scan region, scan tokens from the modified
159 // modifiedSource until the end of the just scanned token is greater than or 170 // source until the end of the just scanned token is greater than or equal
160 // equal to end of the scan region in the modified source. Include trailing 171 // to end of the scan region in the modified source. Include trailing
161 // characters of any token that was split as a result of inserted text, 172 // characters of any token that was split as a result of inserted text, as
162 // as in "ab" --> "a.b". 173 // in "ab" --> "a.b".
163 // 174 //
164 _reader.offset = scanStart - 1; 175 Token replacementStart = _scanRange(scanStart, scanEnd);
165 int next = _reader.advance(); 176 oldLeftToken.setNext(replacementStart);
166 while (next != -1 && _reader.offset <= scanEnd) { 177 Token replacementEnd = _findEof(replacementStart).previous;
167 next = bigSwitch(next); 178 replacementEnd.setNext(stream);
168 }
169 // 179 //
170 // Copy the remaining tokens in the original stream, but apply the delta to 180 // Apply the delta to the tokens after the last new token.
171 // the token's offset.
172 // 181 //
173 if (originalStream.type == TokenType.EOF) { 182 _updateOffsets(stream, delta);
174 _copyAndAdvance(originalStream, delta); 183 _rightToken = stream;
175 _rightToken = tail;
176 _rightToken.setNextWithoutSettingPrevious(_rightToken);
177 } else {
178 originalStream = _copyAndAdvance(originalStream, delta);
179 _rightToken = tail;
180 while (originalStream.type != TokenType.EOF) {
181 originalStream = _copyAndAdvance(originalStream, delta);
182 }
183 Token eof = _copyAndAdvance(originalStream, delta);
184 eof.setNextWithoutSettingPrevious(eof);
185 }
186 // 184 //
187 // If the index is immediately after an existing token and the inserted 185 // If the index is immediately after an existing token and the inserted
188 // characters did not change that original token, then adjust the leftToken 186 // characters did not change that original token, then adjust the leftToken
189 // to be the next token. For example, in "a; c;" --> "a;b c;", the leftToken 187 // to be the next token. For example, in "a; c;" --> "a;b c;", the leftToken
190 // was ";", but this code advances it to "b" since "b" is the first new 188 // was ";", but this code advances it to "b" since "b" is the first new
191 // token. 189 // token.
192 // 190 //
193 Token newFirst = _leftToken.next; 191 Token newFirst = _leftToken.next;
194 while (!identical(newFirst, _rightToken) && 192 while (!identical(newFirst, _rightToken) &&
195 !identical(oldFirst, oldRightToken) && 193 !identical(oldFirst, oldRightToken) &&
196 newFirst.type != TokenType.EOF && 194 newFirst.type != TokenType.EOF &&
197 _equalTokens(oldFirst, newFirst)) { 195 _equalTokens(oldFirst, newFirst)) {
198 _tokenMap.put(oldFirst, newFirst); 196 _tokenMap.put(oldFirst, newFirst);
199 oldLeftToken = oldFirst; 197 oldLeftToken = oldFirst;
Paul Berry 2014/11/20 22:41:59 Instead of these four statements, I think we need
Brian Wilkerson 2014/11/20 22:55:02 I think we want even bigger changes. My plan is to
200 oldFirst = oldFirst.next; 198 oldFirst = oldFirst.next;
201 _leftToken = newFirst; 199 _leftToken = newFirst;
202 newFirst = newFirst.next; 200 newFirst = newFirst.next;
203 } 201 }
204 Token newLast = _rightToken.previous; 202 Token newLast = _rightToken.previous;
205 while (!identical(newLast, _leftToken) && 203 while (!identical(newLast, _leftToken) &&
206 !identical(oldLast, oldLeftToken) && 204 !identical(oldLast, oldLeftToken) &&
207 newLast.type != TokenType.EOF && 205 newLast.type != TokenType.EOF &&
208 _equalTokens(oldLast, newLast)) { 206 _equalTokens(oldLast, newLast)) {
209 _tokenMap.put(oldLast, newLast); 207 _tokenMap.put(oldLast, newLast);
210 oldRightToken = oldLast; 208 oldRightToken = oldLast;
Paul Berry 2014/11/20 22:41:59 Similar comment here, mutatis mutandis.
211 oldLast = oldLast.previous; 209 oldLast = oldLast.previous;
212 _rightToken = newLast; 210 _rightToken = newLast;
213 newLast = newLast.previous; 211 newLast = newLast.previous;
214 } 212 }
215 _hasNonWhitespaceChange = !identical(_leftToken.next, _rightToken) || 213 _hasNonWhitespaceChange = !identical(_leftToken.next, _rightToken) ||
216 !identical(oldLeftToken.next, oldRightToken); 214 !identical(oldLeftToken.next, oldRightToken);
217 // 215 //
218 // TODO(brianwilkerson) Begin tokens are not getting associated with the 216 // TODO(brianwilkerson) Begin tokens are not getting associated with the
219 // corresponding end tokens (because the end tokens have not been copied 217 // corresponding end tokens (because the end tokens have not been copied
220 // when we're copying the begin tokens). This could have implications for 218 // when we're copying the begin tokens). This could have implications for
221 // parsing. 219 // parsing.
222 // TODO(brianwilkerson) Update the lineInfo. 220 // TODO(brianwilkerson) Update the lineInfo.
223 // 221 //
224 return firstToken; 222 return leftEof.next;
225 }
226
227 Token _copyAndAdvance(Token originalToken, int delta) {
228 Token copiedToken = originalToken.copy();
229 _tokenMap.put(originalToken, copiedToken);
230 copiedToken.offset += delta;
231 appendToken(copiedToken);
232 Token originalComment = originalToken.precedingComments;
233 Token copiedComment = originalToken.precedingComments;
234 while (originalComment != null) {
235 _tokenMap.put(originalComment, copiedComment);
236 originalComment = originalComment.next;
237 copiedComment = copiedComment.next;
238 }
239 return originalToken.next;
240 } 223 }
241 224
242 /** 225 /**
243 * Return `true` if the two tokens are equal to each other. For the purposes o f the 226 * Return `true` if the two tokens are equal to each other. For the purposes o f the
244 * incremental scanner, two tokens are equal if they have the same type and le xeme. 227 * incremental scanner, two tokens are equal if they have the same type and le xeme.
245 * 228 *
246 * @param oldToken the token from the old stream that is being compared 229 * @param oldToken the token from the old stream that is being compared
247 * @param newToken the token from the new stream that is being compared 230 * @param newToken the token from the new stream that is being compared
248 * @return `true` if the two tokens are equal to each other 231 * @return `true` if the two tokens are equal to each other
249 */ 232 */
250 bool _equalTokens(Token oldToken, Token newToken) => 233 bool _equalTokens(Token oldToken, Token newToken) =>
251 oldToken.type == newToken.type && 234 oldToken.type == newToken.type &&
252 oldToken.length == newToken.length && 235 oldToken.length == newToken.length &&
253 oldToken.lexeme == newToken.lexeme; 236 oldToken.lexeme == newToken.lexeme;
237
238 /**
239 * Given a [token], return the EOF token that follows the token.
240 */
241 Token _findEof(Token token) {
242 while (token.type != TokenType.EOF) {
243 token = token.next;
244 }
245 return token;
246 }
247
248 /**
249 * Scan the token between the [start] (inclusive) and [end] (exclusive)
250 * offsets.
251 */
252 Token _scanRange(int start, int end) {
253 Scanner scanner = new Scanner(
254 source,
255 new CharacterRangeReader(reader, start, end),
256 errorListener);
257 return scanner.tokenize();
258 }
259
260 /**
261 * Update the offsets of every token from the given [token] to the end of the
262 * stream by adding the given [delta].
263 */
264 void _updateOffsets(Token token, int delta) {
265 while (token.type != TokenType.EOF) {
266 _tokenMap.put(token, token);
267 token.offset += delta;
268 Token comment = token.precedingComments;
269 while (comment != null) {
270 comment.offset += delta;
271 comment = comment.next;
272 }
273 token = token.next;
274 }
275 _tokenMap.put(token, token);
276 token.offset += delta;
Paul Berry 2014/11/20 22:41:59 Does the EOF token ever have precedingComments? (
Brian Wilkerson 2014/11/20 22:55:02 Yes, when there are comments at the end of the fil
277 }
254 } 278 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer/lib/src/generated/scanner.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698