Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2017, 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 import 'package:front_end/src/fasta/errors.dart'; | |
| 6 import 'package:front_end/src/fasta/scanner/precedence.dart'; | |
| 7 import 'package:front_end/src/fasta/scanner/token.dart'; | |
| 8 | |
| 9 /// Provides the capability of inserting tokens into a token stream by rewriting | |
| 10 /// the previous token to point to the inserted token. | |
| 11 /// | |
| 12 /// This class has been designed to take advantage of "previousToken" pointers | |
| 13 /// when they are present, but not to depend on them. When they are not | |
| 14 /// present, it uses heuristics to try to find the find the previous token as | |
| 15 /// quickly as possible by walking through tokens starting at the start of the | |
| 16 /// file. | |
| 17 class TokenStreamRewriter { | |
| 18 /// Synthetic token whose "next" pointer points to the first token in the | |
| 19 /// stream. | |
| 20 final Token _head; | |
| 21 | |
| 22 /// The token whose "next" pointer was updated in the last call to | |
| 23 /// [insertTokenBefore]. This can often be used as a starting point to find | |
| 24 /// the a future insertion point quickly. | |
| 25 Token _lastPreviousToken; | |
| 26 | |
| 27 /// Creates a [TokenStreamRewriter] which is prepared to rewrite the token | |
| 28 /// stream whose first token is [firstToken]. | |
| 29 TokenStreamRewriter(Token firstToken) | |
| 30 : _head = firstToken.previousToken ?? | |
| 31 (new SymbolToken(EOF_INFO, -1)..next = firstToken); | |
| 32 | |
| 33 /// Gets the first token in the stream (which may not be the same token that | |
| 34 /// was passed to the constructor, if something was inserted before it). | |
| 35 Token get firstToken => _head.next; | |
| 36 | |
| 37 /// Inserts [newToken] into the token stream just before [insertionPoint], and | |
| 38 /// fixes up all "next" and "previous" pointers. | |
| 39 /// | |
| 40 /// Caller is required to ensure that [insertionPoint] is actually present in | |
| 41 /// the token stream. | |
| 42 void insertTokenBefore(Token newToken, Token insertionPoint) { | |
| 43 Token previous = _findPreviousToken(insertionPoint); | |
| 44 _lastPreviousToken = previous; | |
| 45 newToken.next = insertionPoint; | |
| 46 previous.next = newToken; | |
| 47 // Note: even though previousToken is deprecated, we need to hook it up in | |
|
ahe
2017/03/09 13:47:07
A trick I've used in the past:
{
// Note: even
Paul Berry
2017/03/09 16:44:39
Good idea--that's much clearer. I'll fix in a fol
| |
| 48 // case any uses of it remain. Once previousToken is removed it should be | |
| 49 // safe to remove the code below. | |
| 50 insertionPoint.previousToken = newToken; | |
| 51 newToken.previousToken = previous; | |
| 52 } | |
| 53 | |
| 54 /// Finds the token that immediately precedes [target]. | |
| 55 Token _findPreviousToken(Token target) { | |
| 56 // First see if the target has a previous token pointer. If it does, then | |
| 57 // we can find the previous token with no extra effort. Note: it's ok that | |
| 58 // we're accessing the deprecated member previousToken here, because we have | |
| 59 // a fallback if it is not available. Once previousToken is removed, we can | |
| 60 // remove the "if" test below, and always use the fallback code. | |
| 61 if (target.previousToken != null) { | |
| 62 return target.previousToken; | |
| 63 } | |
| 64 | |
| 65 // Look for the previous token by scanning forward from [lastPreviousToken], | |
| 66 // if it makes sense to do so. | |
| 67 if (_lastPreviousToken != null && | |
| 68 target.charOffset >= _lastPreviousToken.charOffset) { | |
| 69 Token previous = _scanForPreviousToken(target, _lastPreviousToken); | |
| 70 if (previous != null) return previous; | |
| 71 } | |
| 72 | |
| 73 // Otherwise scan forward from the start of the token stream. | |
| 74 Token previous = _scanForPreviousToken(target, _head); | |
| 75 if (previous == null) { | |
| 76 internalError('Could not find previous token'); | |
| 77 } | |
| 78 return previous; | |
| 79 } | |
| 80 | |
| 81 /// Searches for the token that immediately precedes [target], using [pos] as | |
| 82 /// a starting point. | |
| 83 /// | |
| 84 /// Uses heuristics to skip matching {}, [], (), and <> if possible. | |
|
ahe
2017/03/09 13:47:08
Wrap syntax in back ticks?
Paul Berry
2017/03/09 16:44:39
Will address in a follow-up CL.
| |
| 85 /// | |
| 86 /// If no such token is found, returns `null`. | |
| 87 Token _scanForPreviousToken(Token target, Token pos) { | |
| 88 while (!identical(pos.next, target)) { | |
| 89 Token nextPos; | |
| 90 if (pos is BeginGroupToken && | |
| 91 pos.endGroup != null && | |
| 92 pos.endGroup.charOffset < target.charOffset) { | |
| 93 nextPos = pos.endGroup; | |
| 94 } else { | |
| 95 nextPos = pos.next; | |
| 96 if (nextPos == null || nextPos.charOffset > target.charOffset) { | |
| 97 return null; | |
| 98 } | |
| 99 } | |
| 100 pos = nextPos; | |
| 101 } | |
| 102 return pos; | |
| 103 } | |
| 104 } | |
| OLD | NEW |