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

Side by Side Diff: pkg/front_end/lib/src/fasta/parser/token_stream_rewriter.dart

Issue 2732193007: Create a TokenStreamRewriter class. (Closed)
Patch Set: Created 3 years, 9 months 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
OLDNEW
(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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698