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

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

Issue 1413773003: Improve recovery for local variable declarations. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 2 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 | « no previous file | pkg/analyzer/test/generated/parser_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) 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.parser; 5 library engine.parser;
6 6
7 import 'dart:collection'; 7 import 'dart:collection';
8 import "dart:math" as math; 8 import "dart:math" as math;
9 9
10 import 'ast.dart'; 10 import 'ast.dart';
(...skipping 4020 matching lines...) Expand 10 before | Expand all | Expand 10 after
4031 if (_matchesKeyword(Keyword.CONST)) { 4031 if (_matchesKeyword(Keyword.CONST)) {
4032 // Look to see whether we might be at the start of a list or map literal, 4032 // Look to see whether we might be at the start of a list or map literal,
4033 // otherwise this should be the start of a variable declaration. 4033 // otherwise this should be the start of a variable declaration.
4034 return !_peek().matchesAny([ 4034 return !_peek().matchesAny([
4035 TokenType.LT, 4035 TokenType.LT,
4036 TokenType.OPEN_CURLY_BRACKET, 4036 TokenType.OPEN_CURLY_BRACKET,
4037 TokenType.OPEN_SQUARE_BRACKET, 4037 TokenType.OPEN_SQUARE_BRACKET,
4038 TokenType.INDEX 4038 TokenType.INDEX
4039 ]); 4039 ]);
4040 } 4040 }
4041 bool allowAdditionalTokens = true;
4041 // We know that we have an identifier, and need to see whether it might be 4042 // We know that we have an identifier, and need to see whether it might be
4042 // a type name. 4043 // a type name.
4044 if (_currentToken.type != TokenType.IDENTIFIER) {
4045 allowAdditionalTokens = false;
4046 }
4043 Token token = _skipTypeName(_currentToken); 4047 Token token = _skipTypeName(_currentToken);
4044 if (token == null) { 4048 if (token == null) {
4045 // There was no type name, so this can't be a declaration. 4049 // There was no type name, so this can't be a declaration.
4046 return false; 4050 return false;
4047 } 4051 }
4052 if (token.type != TokenType.IDENTIFIER) {
4053 allowAdditionalTokens = false;
4054 }
4048 token = _skipSimpleIdentifier(token); 4055 token = _skipSimpleIdentifier(token);
4049 if (token == null) { 4056 if (token == null) {
4050 return false; 4057 return false;
4051 } 4058 }
4052 TokenType type = token.type; 4059 TokenType type = token.type;
4053 return type == TokenType.EQ || 4060 // Usual cases in valid code:
4061 // String v = '';
4062 // String v, v2;
4063 // String v;
4064 // for (String item in items) {}
4065 if (type == TokenType.EQ ||
4054 type == TokenType.COMMA || 4066 type == TokenType.COMMA ||
4055 type == TokenType.SEMICOLON || 4067 type == TokenType.SEMICOLON ||
4056 _tokenMatchesKeyword(token, Keyword.IN); 4068 _tokenMatchesKeyword(token, Keyword.IN)) {
4069 return true;
4070 }
4071 // It is OK to parse as a variable declaration in these cases:
4072 // String v }
4073 // String v if (true) print('OK');
4074 // String v { print(42); }
4075 // ...but not in these cases:
4076 // get getterName {
4077 // String get getterName
4078 if (allowAdditionalTokens) {
4079 if (type == TokenType.CLOSE_CURLY_BRACKET ||
4080 type == TokenType.KEYWORD ||
4081 type == TokenType.IDENTIFIER ||
4082 type == TokenType.OPEN_CURLY_BRACKET) {
4083 return true;
4084 }
4085 }
4086 return false;
4057 } 4087 }
4058 4088
4059 bool _isLikelyParameterList() { 4089 bool _isLikelyParameterList() {
4060 if (_matches(TokenType.OPEN_PAREN)) { 4090 if (_matches(TokenType.OPEN_PAREN)) {
4061 return true; 4091 return true;
4062 } 4092 }
4063 if (!parseGenericMethods) { 4093 if (!parseGenericMethods) {
4064 return false; 4094 return false;
4065 } 4095 }
4066 Token token = _skipTypeArgumentList(_currentToken); 4096 Token token = _skipTypeArgumentList(_currentToken);
(...skipping 4207 matching lines...) Expand 10 before | Expand all | Expand 10 after
8274 * token following the simple identifier that was parsed, or `null` if the 8304 * token following the simple identifier that was parsed, or `null` if the
8275 * given token is not the first token in a valid simple identifier. 8305 * given token is not the first token in a valid simple identifier.
8276 * 8306 *
8277 * This method must be kept in sync with [parseSimpleIdentifier]. 8307 * This method must be kept in sync with [parseSimpleIdentifier].
8278 * 8308 *
8279 * identifier ::= 8309 * identifier ::=
8280 * IDENTIFIER 8310 * IDENTIFIER
8281 */ 8311 */
8282 Token _skipSimpleIdentifier(Token startToken) { 8312 Token _skipSimpleIdentifier(Token startToken) {
8283 if (_tokenMatches(startToken, TokenType.IDENTIFIER) || 8313 if (_tokenMatches(startToken, TokenType.IDENTIFIER) ||
8284 (_tokenMatches(startToken, TokenType.KEYWORD) && 8314 _tokenMatchesPseudoKeyword(startToken)) {
8285 (startToken as KeywordToken).keyword.isPseudoKeyword)) {
8286 return startToken.next; 8315 return startToken.next;
8287 } 8316 }
8288 return null; 8317 return null;
8289 } 8318 }
8290 8319
8291 /** 8320 /**
8292 * Parse a string literal that contains interpolations, starting at the 8321 * Parse a string literal that contains interpolations, starting at the
8293 * [startToken], without actually creating a string literal or changing the 8322 * [startToken], without actually creating a string literal or changing the
8294 * current token. Return the token following the string literal that was 8323 * current token. Return the token following the string literal that was
8295 * parsed, or `null` if the given token is not the first token in a valid 8324 * parsed, or `null` if the given token is not the first token in a valid
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after
8499 * Return `true` if the given [token] has the given [type]. 8528 * Return `true` if the given [token] has the given [type].
8500 */ 8529 */
8501 bool _tokenMatches(Token token, TokenType type) => token.type == type; 8530 bool _tokenMatches(Token token, TokenType type) => token.type == type;
8502 8531
8503 /** 8532 /**
8504 * Return `true` if the given [token] is a valid identifier. Valid identifiers 8533 * Return `true` if the given [token] is a valid identifier. Valid identifiers
8505 * include built-in identifiers (pseudo-keywords). 8534 * include built-in identifiers (pseudo-keywords).
8506 */ 8535 */
8507 bool _tokenMatchesIdentifier(Token token) => 8536 bool _tokenMatchesIdentifier(Token token) =>
8508 _tokenMatches(token, TokenType.IDENTIFIER) || 8537 _tokenMatches(token, TokenType.IDENTIFIER) ||
8509 (_tokenMatches(token, TokenType.KEYWORD) && 8538 _tokenMatchesPseudoKeyword(token);
8510 (token as KeywordToken).keyword.isPseudoKeyword);
8511 8539
8512 /** 8540 /**
8513 * Return `true` if the given [token] matches the given [keyword]. 8541 * Return `true` if the given [token] matches the given [keyword].
8514 */ 8542 */
8515 bool _tokenMatchesKeyword(Token token, Keyword keyword) => 8543 bool _tokenMatchesKeyword(Token token, Keyword keyword) =>
8516 token.type == TokenType.KEYWORD && 8544 token.type == TokenType.KEYWORD &&
8517 (token as KeywordToken).keyword == keyword; 8545 (token as KeywordToken).keyword == keyword;
8518 8546
8519 /** 8547 /**
8548 * Return `true` if the given [token] matches a pseudo keyword.
8549 */
8550 bool _tokenMatchesPseudoKeyword(Token token) =>
8551 _tokenMatches(token, TokenType.KEYWORD) &&
8552 (token as KeywordToken).keyword.isPseudoKeyword;
8553
8554 /**
8520 * Return `true` if the given [token] matches the given [identifier]. 8555 * Return `true` if the given [token] matches the given [identifier].
8521 */ 8556 */
8522 bool _tokenMatchesString(Token token, String identifier) => 8557 bool _tokenMatchesString(Token token, String identifier) =>
8523 token.type == TokenType.IDENTIFIER && token.lexeme == identifier; 8558 token.type == TokenType.IDENTIFIER && token.lexeme == identifier;
8524 8559
8525 /** 8560 /**
8526 * Translate the characters at the given [index] in the given [lexeme], 8561 * Translate the characters at the given [index] in the given [lexeme],
8527 * appending the translated character to the given [buffer]. The index is 8562 * appending the translated character to the given [buffer]. The index is
8528 * assumed to be valid. 8563 * assumed to be valid.
8529 */ 8564 */
(...skipping 2488 matching lines...) Expand 10 before | Expand all | Expand 10 after
11018 } 11053 }
11019 11054
11020 /** 11055 /**
11021 * Copy resolution data from the [fromNode] to the [toNode]. 11056 * Copy resolution data from the [fromNode] to the [toNode].
11022 */ 11057 */
11023 static void copyResolutionData(AstNode fromNode, AstNode toNode) { 11058 static void copyResolutionData(AstNode fromNode, AstNode toNode) {
11024 ResolutionCopier copier = new ResolutionCopier(); 11059 ResolutionCopier copier = new ResolutionCopier();
11025 copier._isEqualNodes(fromNode, toNode); 11060 copier._isEqualNodes(fromNode, toNode);
11026 } 11061 }
11027 } 11062 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer/test/generated/parser_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698