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

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

Issue 3007943002: gracefully recover from extraneous top level modifiers (Closed)
Patch Set: revise parseTopLevelDeclaration and address comments Created 3 years, 3 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
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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.parser.parser; 5 library fasta.parser.parser;
6 6
7 import '../fasta_codes.dart' show Code, Message, Template; 7 import '../fasta_codes.dart' show Code, Message, Template;
8 8
9 import '../fasta_codes.dart' as fasta; 9 import '../fasta_codes.dart' as fasta;
10 10
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after
253 count++; 253 count++;
254 } 254 }
255 listener.endCompilationUnit(count, token); 255 listener.endCompilationUnit(count, token);
256 // Clear fields that could lead to memory leak. 256 // Clear fields that could lead to memory leak.
257 firstToken = null; 257 firstToken = null;
258 cachedRewriter = null; 258 cachedRewriter = null;
259 return token; 259 return token;
260 } 260 }
261 261
262 Token parseTopLevelDeclaration(Token token) { 262 Token parseTopLevelDeclaration(Token token) {
263 token = _parseTopLevelDeclaration(token); 263 token = parseTopLevelDeclarationImpl(token);
264 listener.endTopLevelDeclaration(token); 264 listener.endTopLevelDeclaration(token);
265 return token; 265 return token;
266 } 266 }
267 267
268 Token _parseTopLevelDeclaration(Token token) { 268 Token parseTopLevelDeclarationImpl(Token token) {
269 if (identical(token.type, TokenType.SCRIPT_TAG)) { 269 if (identical(token.type, TokenType.SCRIPT_TAG)) {
270 return parseScript(token); 270 return parseScript(token);
271 } 271 }
272 token = parseMetadataStar(token); 272 token = parseMetadataStar(token);
273 String value = token.stringValue; 273 if (token.isTopLevelKeyword) {
274 if (identical(value, 'abstract')) { 274 return parseTopLevelKeywordDeclaration(null, token);
275 if (optional('class', token.next)) { 275 }
276 return parseClassOrNamedMixinApplication(token); 276 Token start = token;
277 // Skip modifiers to find a top level keyword or identifier
278 while (token.isModifier) {
279 token = token.next;
280 }
281 if (token.isTopLevelKeyword) {
282 Token abstractToken;
283 Token modifierToken = start;
284 while (modifierToken != token) {
285 if (optional('abstract', modifierToken) &&
286 optional('class', token) &&
287 abstractToken == null) {
288 abstractToken = modifierToken;
289 } else {
290 // TODO(danrubel): Report more specific recoverable error message
291 // for `const class` to better help the user.
292 // See ParserErrorCode CONST_CLASS
293
294 // Report an error for each extraneous modifier
295 reportRecoverableErrorWithToken(
296 modifierToken, fasta.templateExtraneousModifier);
297 }
298 modifierToken = modifierToken.next;
277 } 299 }
278 reportRecoverableErrorWithToken(token, fasta.templateExtraneousModifier); 300 return parseTopLevelKeywordDeclaration(abstractToken, token);
279 token = token.next; 301 } else if (token.isIdentifier || token.keyword != null) {
280 value = token.stringValue; 302 // TODO(danrubel): improve parseTopLevelMember
303 // so that we don't parse modifiers twice.
304 return parseTopLevelMember(start);
305 } else if (start != token) {
306 // Handle the edge case where a modifier is being used as an identifier
307 return parseTopLevelMember(start);
281 } 308 }
309 // Ignore any preceding modifiers and just report the unexpected token
310 reportRecoverableErrorWithToken(token, fasta.templateExpectedDeclaration);
311 listener.handleInvalidTopLevelDeclaration(token);
312 return token.next;
313 }
314
315 Token parseTopLevelKeywordDeclaration(Token abstractToken, Token token) {
316 final String value = token.stringValue;
282 if (identical(value, 'class')) { 317 if (identical(value, 'class')) {
283 return parseClassOrNamedMixinApplication(token); 318 return parseClassOrNamedMixinApplication(abstractToken, token);
284 } else if (identical(value, 'enum')) { 319 } else if (identical(value, 'enum')) {
285 return parseEnum(token); 320 return parseEnum(token);
286 } else if (identical(value, 'typedef') && 321 } else if (identical(value, 'typedef')) {
287 (token.next.isIdentifier || optional("void", token.next))) { 322 Token next = token.next;
288 return parseTypedef(token); 323 if (next.isIdentifier || optional("void", next)) {
324 return parseTypedef(token);
325 } else {
326 return parseTopLevelMember(token);
327 }
289 } else if (identical(value, 'library')) { 328 } else if (identical(value, 'library')) {
290 return parseLibraryName(token); 329 return parseLibraryName(token);
291 } else if (identical(value, 'import')) { 330 } else if (identical(value, 'import')) {
292 return parseImport(token); 331 return parseImport(token);
293 } else if (identical(value, 'export')) { 332 } else if (identical(value, 'export')) {
294 return parseExport(token); 333 return parseExport(token);
295 } else if (identical(value, 'part')) { 334 } else if (identical(value, 'part')) {
296 return parsePartOrPartOf(token); 335 return parsePartOrPartOf(token);
297 } else if (token.type == TokenType.IDENTIFIER || token.keyword != null) {
298 return parseTopLevelMember(token);
299 } else {
300 reportRecoverableErrorWithToken(token, fasta.templateExpectedDeclaration);
301 listener.handleInvalidTopLevelDeclaration(token);
302 return token.next;
303 } 336 }
337
338 throw "Internal error: Unhandled top level keyword '$value'.";
304 } 339 }
305 340
306 /// library qualified ';' 341 /// library qualified ';'
307 Token parseLibraryName(Token token) { 342 Token parseLibraryName(Token token) {
308 Token libraryKeyword = token; 343 Token libraryKeyword = token;
309 listener.beginLibraryName(libraryKeyword); 344 listener.beginLibraryName(libraryKeyword);
310 assert(optional('library', token)); 345 assert(optional('library', token));
311 token = parseQualified(token.next, IdentifierContext.libraryName, 346 token = parseQualified(token.next, IdentifierContext.libraryName,
312 IdentifierContext.libraryNameContinuation); 347 IdentifierContext.libraryNameContinuation);
313 Token semicolon = token; 348 Token semicolon = token;
(...skipping 506 matching lines...) Expand 10 before | Expand all | Expand 10 after
820 token = parseIdentifier(token, IdentifierContext.enumValueDeclaration); 855 token = parseIdentifier(token, IdentifierContext.enumValueDeclaration);
821 count++; 856 count++;
822 } 857 }
823 } 858 }
824 Token endBrace = token; 859 Token endBrace = token;
825 token = expect('}', token); 860 token = expect('}', token);
826 listener.endEnum(enumKeyword, endBrace, count); 861 listener.endEnum(enumKeyword, endBrace, count);
827 return token; 862 return token;
828 } 863 }
829 864
830 Token parseClassOrNamedMixinApplication(Token token) { 865 Token parseClassOrNamedMixinApplication(Token abstractToken, Token token) {
831 listener.beginClassOrNamedMixinApplication(token); 866 listener.beginClassOrNamedMixinApplication(token);
832 Token begin = token; 867 Token begin = abstractToken ?? token;
833 if (optional('abstract', token)) { 868 if (abstractToken != null) {
834 token = parseModifier(token); 869 token = parseModifier(abstractToken);
835 listener.handleModifiers(1); 870 listener.handleModifiers(1);
836 } else { 871 } else {
837 listener.handleModifiers(0); 872 listener.handleModifiers(0);
838 } 873 }
839 Token classKeyword = token; 874 Token classKeyword = token;
840 token = expect("class", token); 875 token = expect("class", token);
841 Token name = token; 876 Token name = token;
842 token = 877 token =
843 parseIdentifier(name, IdentifierContext.classOrNamedMixinDeclaration); 878 parseIdentifier(name, IdentifierContext.classOrNamedMixinDeclaration);
844 token = parseTypeVariablesOpt(token); 879 token = parseTypeVariablesOpt(token);
(...skipping 3303 matching lines...) Expand 10 before | Expand all | Expand 10 after
4148 } 4183 }
4149 4184
4150 Token reportUnexpectedToken(Token token) { 4185 Token reportUnexpectedToken(Token token) {
4151 return reportUnrecoverableErrorWithToken( 4186 return reportUnrecoverableErrorWithToken(
4152 token, fasta.templateUnexpectedToken); 4187 token, fasta.templateUnexpectedToken);
4153 } 4188 }
4154 } 4189 }
4155 4190
4156 // TODO(ahe): Remove when analyzer supports generalized function syntax. 4191 // TODO(ahe): Remove when analyzer supports generalized function syntax.
4157 typedef _MessageWithArgument<T> = Message Function(T); 4192 typedef _MessageWithArgument<T> = Message Function(T);
OLDNEW
« no previous file with comments | « pkg/front_end/lib/src/fasta/parser/listener.dart ('k') | pkg/front_end/lib/src/scanner/token.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698