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

Side by Side Diff: pkg/front_end/lib/src/fasta/scanner/array_based_scanner.dart

Issue 2981343002: improve fasta closing brace recovery (Closed)
Patch Set: rebase Created 3 years, 5 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
« no previous file with comments | « pkg/analyzer/test/generated/parser_test.dart ('k') | pkg/front_end/test/scanner_test.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) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, 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 fasta.scanner.array_based_scanner; 5 library fasta.scanner.array_based_scanner;
6 6
7 import 'error_token.dart' show ErrorToken, UnmatchedToken; 7 import 'error_token.dart' show ErrorToken, UnmatchedToken;
8 8
9 import '../../scanner/token.dart' 9 import '../../scanner/token.dart'
10 show 10 show
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
132 if (!identical(type.kind, LT_TOKEN) && 132 if (!identical(type.kind, LT_TOKEN) &&
133 !identical(type.kind, OPEN_PAREN_TOKEN)) { 133 !identical(type.kind, OPEN_PAREN_TOKEN)) {
134 discardOpenLt(); 134 discardOpenLt();
135 } 135 }
136 groupingStack = groupingStack.prepend(token); 136 groupingStack = groupingStack.prepend(token);
137 } 137 }
138 138
139 /** 139 /**
140 * Appends a token that begins an end group, represented by [type]. 140 * Appends a token that begins an end group, represented by [type].
141 * It handles the group end tokens '}', ')' and ']'. The tokens '>' and 141 * It handles the group end tokens '}', ')' and ']'. The tokens '>' and
142 * '>>' are handled separately bo [appendGt] and [appendGtGt]. 142 * '>>' are handled separately by [appendGt] and [appendGtGt].
143 */ 143 */
144 int appendEndGroup(TokenType type, int openKind) { 144 int appendEndGroup(TokenType type, int openKind) {
145 assert(!identical(openKind, LT_TOKEN)); // openKind is < for > and >> 145 assert(!identical(openKind, LT_TOKEN)); // openKind is < for > and >>
146 discardBeginGroupUntil(openKind); 146 if (!discardBeginGroupUntil(openKind)) {
147 // No begin group found. Just continue.
148 appendPrecedenceToken(type);
149 return advance();
150 }
147 appendPrecedenceToken(type); 151 appendPrecedenceToken(type);
148 Token close = tail; 152 Token close = tail;
149 if (groupingStack.isEmpty) {
150 return advance();
151 }
152 BeginToken begin = groupingStack.head; 153 BeginToken begin = groupingStack.head;
153 if (!identical(begin.kind, openKind)) { 154 if (!identical(begin.kind, openKind)) {
154 assert(begin.kind == STRING_INTERPOLATION_TOKEN && 155 assert(begin.kind == STRING_INTERPOLATION_TOKEN &&
155 openKind == OPEN_CURLY_BRACKET_TOKEN); 156 openKind == OPEN_CURLY_BRACKET_TOKEN);
156 // We're ending an interpolated expression. 157 // We're ending an interpolated expression.
157 begin.endGroup = close; 158 begin.endGroup = close;
158 groupingStack = groupingStack.tail; 159 groupingStack = groupingStack.tail;
159 // Using "start-of-text" to signal that we're back in string 160 // Using "start-of-text" to signal that we're back in string
160 // scanning mode. 161 // scanning mode.
161 return $STX; 162 return $STX;
162 } 163 }
163 begin.endGroup = close; 164 begin.endGroup = close;
164 groupingStack = groupingStack.tail; 165 groupingStack = groupingStack.tail;
165 return advance(); 166 return advance();
166 } 167 }
167 168
168 /** 169 /**
169 * Discards begin group tokens until a match with [openKind] is found. 170 * If a begin group token matches [openKind],
170 * This recovers nicely from from a situation like "{[}". 171 * then discard begin group tokens up to that match and return `true`,
172 * otherwise return `false`.
173 * This recovers nicely from from situations like "{[}" and "{foo());}",
174 * but not "foo(() {bar());});
171 */ 175 */
172 void discardBeginGroupUntil(int openKind) { 176 bool discardBeginGroupUntil(int openKind) {
173 while (!groupingStack.isEmpty) { 177 Link<BeginToken> originalStack = groupingStack;
178
179 bool first = true;
180 do {
174 // Don't report unmatched errors for <; it is also the less-than operator. 181 // Don't report unmatched errors for <; it is also the less-than operator.
175 discardOpenLt(); 182 discardOpenLt();
176 if (groupingStack.isEmpty) return; 183 if (groupingStack.isEmpty) break; // recover
177 BeginToken begin = groupingStack.head; 184 BeginToken begin = groupingStack.head;
178 if (openKind == begin.kind) return; 185 if (openKind == begin.kind ||
179 if (openKind == OPEN_CURLY_BRACKET_TOKEN && 186 (openKind == OPEN_CURLY_BRACKET_TOKEN &&
180 begin.kind == STRING_INTERPOLATION_TOKEN) return; 187 begin.kind == STRING_INTERPOLATION_TOKEN)) {
181 unmatchedBeginGroup(begin); 188 if (first) {
189 // If the expected opener has been found on the first pass
190 // then no recovery necessary.
191 return true;
192 }
193 break; // recover
194 }
195 first = false;
182 groupingStack = groupingStack.tail; 196 groupingStack = groupingStack.tail;
197 } while (!groupingStack.isEmpty);
198
199 // If the stack does not have any opener of the given type,
200 // then return without discarding anything.
201 // This recovers nicely from from situations like "{foo());}".
202 if (groupingStack.isEmpty) {
203 groupingStack = originalStack;
204 return false;
183 } 205 }
206
207 // Insert synthetic closers and report errors for any unbalanced openers.
208 // This recovers nicely from from situations like "{[}".
209 while (!identical(originalStack, groupingStack)) {
210 // Don't report unmatched errors for <; it is also the less-than operator.
211 if (!identical(groupingStack.head.kind, LT_TOKEN))
212 unmatchedBeginGroup(originalStack.head);
213 originalStack = originalStack.tail;
214 }
215 return true;
184 } 216 }
185 217
186 /** 218 /**
187 * Appends a token for '>'. 219 * Appends a token for '>'.
188 * This method does not issue unmatched errors, because > is also the 220 * This method does not issue unmatched errors, because > is also the
189 * greater-than operator. It does not necessarily have to close a group. 221 * greater-than operator. It does not necessarily have to close a group.
190 */ 222 */
191 void appendGt(TokenType type) { 223 void appendGt(TokenType type) {
192 appendPrecedenceToken(type); 224 appendPrecedenceToken(type);
193 if (groupingStack.isEmpty) return; 225 if (groupingStack.isEmpty) return;
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
335 // | 367 // |
336 // next 368 // next
337 // v 369 // v
338 // EOF 370 // EOF
339 TokenType type = closeBraceInfoFor(begin); 371 TokenType type = closeBraceInfoFor(begin);
340 appendToken(new SyntheticToken(type, tokenStart)); 372 appendToken(new SyntheticToken(type, tokenStart));
341 begin.endGroup = tail; 373 begin.endGroup = tail;
342 appendErrorToken(new UnmatchedToken(begin)); 374 appendErrorToken(new UnmatchedToken(begin));
343 } 375 }
344 } 376 }
OLDNEW
« no previous file with comments | « pkg/analyzer/test/generated/parser_test.dart ('k') | pkg/front_end/test/scanner_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698