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

Unified Diff: pkg/compiler/lib/src/parser/element_listener.dart

Issue 2650813002: Restructure parser error handling and recovery. (Closed)
Patch Set: Address comments. Created 3 years, 11 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/compiler/lib/src/native/scanner.dart ('k') | pkg/compiler/lib/src/parser/node_listener.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/parser/element_listener.dart
diff --git a/pkg/compiler/lib/src/parser/element_listener.dart b/pkg/compiler/lib/src/parser/element_listener.dart
index 8111f2333d902435cbdcf7b6629ed3dac90b6bd2..c7300abe4b9514f675697be7fd1940639f10b6c1 100644
--- a/pkg/compiler/lib/src/parser/element_listener.dart
+++ b/pkg/compiler/lib/src/parser/element_listener.dart
@@ -23,14 +23,14 @@ import '../id_generator.dart';
import '../native/native.dart' as native;
import '../string_validator.dart' show StringValidator;
import 'package:dart_scanner/dart_scanner.dart'
- show Keyword, BeginGroupToken, ErrorToken, KeywordToken, Token;
+ show Keyword, BeginGroupToken, ErrorToken, KeywordToken, StringToken, Token;
import 'package:dart_scanner/dart_scanner.dart' as Tokens show EOF_TOKEN;
import 'package:dart_scanner/src/precedence.dart' as Precedence show
- BAD_INPUT_INFO;
+ BAD_INPUT_INFO, IDENTIFIER_INFO;
import '../tree/tree.dart';
import '../util/util.dart' show Link, LinkBuilder;
import 'package:dart_parser/dart_parser.dart'
- show ErrorKind, Listener, ParserError, closeBraceFor;
+ show ErrorKind, Listener, ParserError, closeBraceFor, optional;
import 'partial_elements.dart'
show
PartialClassElement,
@@ -452,29 +452,225 @@ class ElementListener extends Listener {
}
@override
- Token expected(String string, Token token) {
- if (token is ErrorToken) {
- reportErrorToken(token);
- } else if (identical(';', string)) {
- // When a semicolon is missing, it often leads to an error on the
- // following line. So we try to find the token preceding the semicolon
- // and report that something is missing *after* it.
- Token preceding = findPrecedingToken(token);
- if (preceding == token) {
- reportErrorMessageToken(
- token, MessageKind.MISSING_TOKEN_BEFORE_THIS, {'token': string});
- } else {
- reportErrorMessageToken(
- preceding, MessageKind.MISSING_TOKEN_AFTER_THIS, {'token': string});
- }
- return token;
+ Token handleUnrecoverableError(Token token, ErrorKind kind, Map arguments) {
+ Token next = handleError(token, kind, arguments);
+ if (next == null) {
+ throw new ParserError.fromTokens(token, token, kind, arguments);
} else {
- reportFatalError(
- reporter.spanFromToken(token),
- MessageTemplate.TEMPLATES[MessageKind.MISSING_TOKEN_BEFORE_THIS]
- .message({'token': string}, true).toString());
+ return next;
+ }
+ }
+
+ @override
+ void handleRecoverableError(Token token, ErrorKind kind, Map arguments) {
+ handleError(token, kind, arguments);
+ }
+
+ Token handleError(Token token, ErrorKind kind, Map arguments) {
+ MessageKind errorCode;
+
+ switch (kind) {
+ case ErrorKind.ExpectedButGot:
+ String expected = arguments["expected"];
+ if (identical(";", expected)) {
+ // When a semicolon is missing, it often leads to an error on the
+ // following line. So we try to find the token preceding the semicolon
+ // and report that something is missing *after* it.
+ Token preceding = findPrecedingToken(token);
+ if (preceding == token) {
+ reportErrorFromToken(
+ token, MessageKind.MISSING_TOKEN_BEFORE_THIS,
+ {'token': expected});
+ } else {
+ reportErrorFromToken(
+ preceding, MessageKind.MISSING_TOKEN_AFTER_THIS,
+ {'token': expected});
+ }
+ return token;
+ } else {
+ return reportFatalError(
+ reporter.spanFromToken(token),
+ MessageTemplate.TEMPLATES[MessageKind.MISSING_TOKEN_BEFORE_THIS]
+ .message({'token': expected}, true).toString());
+ }
+ break;
+
+ case ErrorKind.ExpectedIdentifier:
+ if (token is KeywordToken) {
+ reportErrorFromToken(token,
+ MessageKind.EXPECTED_IDENTIFIER_NOT_RESERVED_WORD,
+ {'keyword': token.value});
+ } else if (token is ErrorToken) {
+ // TODO(ahe): This is dead code.
+ return synthesizeIdentifier(token);
+ } else {
+ reportFatalError(reporter.spanFromToken(token),
+ "Expected identifier, but got '${token.value}'.");
+ }
+ return token;
+
+ case ErrorKind.ExpectedType:
+ pushNode(null);
+ if (token is ErrorToken) {
+ // TODO(ahe): This is dead code.
+ return synthesizeIdentifier(token);
+ } else {
+ reportFatalError(reporter.spanFromToken(token),
+ "Expected a type, but got '${token.value}'.");
+ }
+ return null;
+
+ case ErrorKind.ExpectedExpression:
+ if (token is ErrorToken) {
+ // TODO(ahe): This dead code.
+ pushNode(new ErrorExpression(token));
+ return token.next;
+ } else {
+ pushNode(null);
+ reportFatalError(
+ reporter.spanFromToken(token),
+ "Expected an expression, but got '${token.value}'.");
+ }
+ return null;
+
+ case ErrorKind.UnexpectedToken:
+ String message = "Unexpected token '${token.value}'.";
+ if (token.info == Precedence.BAD_INPUT_INFO) {
+ message = token.value;
+ }
+ return reportFatalError(reporter.spanFromToken(token), message);
+
+ case ErrorKind.ExpectedBlockToSkip:
+ if (optional("native", token)) {
+ return native.handleNativeBlockToSkip(this, token);
+ } else {
+ errorCode = MessageKind.BODY_EXPECTED;
+ }
+ break;
+
+ case ErrorKind.ExpectedFunctionBody:
+ if (optional("native", token)) {
+ return native.handleNativeFunctionBody(this, token);
+ } else {
+ reportFatalError(
+ reporter.spanFromToken(token),
+ "Expected a function body, but got '${token.value}'.");
+ }
+ return null;
+
+ case ErrorKind.ExpectedClassBodyToSkip:
+ case ErrorKind.ExpectedClassBody:
+ return reportFatalError(
+ reporter.spanFromToken(token),
+ "Expected a class body, but got '${token.value}'.");
+
+ case ErrorKind.ExpectedDeclaration:
+ return reportFatalError(
+ reporter.spanFromToken(token),
+ "Expected a declaration, but got '${token.value}'.");
+
+ case ErrorKind.UnmatchedToken:
+ String begin = token.value;
+ String end = closeBraceFor(begin);
+ reportErrorFromToken(
+ token, MessageKind.UNMATCHED_TOKEN, {'begin': begin, 'end': end});
+ Token next = token.next;
+ while (next is ErrorToken) {
+ next = next.next;
+ }
+ return next;
+
+ case ErrorKind.EmptyNamedParameterList:
+ errorCode = MessageKind.EMPTY_NAMED_PARAMETER_LIST;
+ break;
+
+ case ErrorKind.EmptyOptionalParameterList:
+ errorCode = MessageKind.EMPTY_OPTIONAL_PARAMETER_LIST;
+ break;
+
+ case ErrorKind.ExpectedBody:
+ errorCode = MessageKind.BODY_EXPECTED;
+ break;
+
+ case ErrorKind.ExpectedHexDigit:
+ errorCode = MessageKind.HEX_DIGIT_EXPECTED;
+ break;
+
+ case ErrorKind.ExpectedOpenParens:
+ errorCode = MessageKind.GENERIC;
+ arguments = {"text": "Expected '('."};
+ break;
+
+ case ErrorKind.ExpectedString:
+ errorCode = MessageKind.STRING_EXPECTED;
+ break;
+
+ case ErrorKind.ExtraneousModifier:
+ errorCode = MessageKind.EXTRANEOUS_MODIFIER;
+ break;
+
+ case ErrorKind.ExtraneousModifierReplace:
+ errorCode = MessageKind.EXTRANEOUS_MODIFIER_REPLACE;
+ break;
+
+ case ErrorKind.InvalidAwaitFor:
+ errorCode = MessageKind.INVALID_AWAIT_FOR;
+ break;
+
+ case ErrorKind.InvalidInputCharacter:
+ errorCode = MessageKind.BAD_INPUT_CHARACTER;
+ break;
+
+ case ErrorKind.InvalidSyncModifier:
+ errorCode = MessageKind.INVALID_SYNC_MODIFIER;
+ break;
+
+ case ErrorKind.InvalidVoid:
+ errorCode = MessageKind.VOID_NOT_ALLOWED;
+ break;
+
+ case ErrorKind.MalformedStringLiteral:
+ errorCode = MessageKind.MALFORMED_STRING_LITERAL;
+ break;
+
+ case ErrorKind.MissingExponent:
+ errorCode = MessageKind.EXPONENT_MISSING;
+ break;
+
+ case ErrorKind.PositionalParameterWithEquals:
+ errorCode = MessageKind.POSITIONAL_PARAMETER_WITH_EQUALS;
+ break;
+
+ case ErrorKind.RequiredParameterWithDefault:
+ errorCode = MessageKind.REQUIRED_PARAMETER_WITH_DEFAULT;
+ break;
+
+ case ErrorKind.UnmatchedToken:
+ errorCode = MessageKind.UNMATCHED_TOKEN;
+ break;
+
+ case ErrorKind.UnsupportedPrefixPlus:
+ errorCode = MessageKind.UNSUPPORTED_PREFIX_PLUS;
+ break;
+
+ case ErrorKind.UnterminatedComment:
+ errorCode = MessageKind.UNTERMINATED_COMMENT;
+ break;
+
+ case ErrorKind.UnterminatedString:
+ errorCode = MessageKind.UNTERMINATED_STRING;
+ break;
+
+ case ErrorKind.UnterminatedToken:
+ errorCode = MessageKind.UNTERMINATED_TOKEN;
+ break;
+
+ case ErrorKind.Unspecified:
+ errorCode = MessageKind.GENERIC;
+ break;
}
- return skipToEof(token);
+ SourceSpan span = reporter.spanFromToken(token);
+ reportError(span, errorCode, arguments);
}
/// Finds the preceding token via the begin token of the last AST node pushed
@@ -534,130 +730,13 @@ class ElementListener extends Listener {
return null;
}
- @override
- Token expectedIdentifier(Token token) {
- if (token is KeywordToken) {
- reportErrorMessageToken(token,
- MessageKind.EXPECTED_IDENTIFIER_NOT_RESERVED_WORD,
- {'keyword': token.value});
- } else if (token is ErrorToken) {
- reportErrorToken(token);
- return synthesizeIdentifier(token);
- } else {
- reportFatalError(reporter.spanFromToken(token),
- "Expected identifier, but got '${token.value}'.");
- }
- return token;
- }
-
- @override
- Token expectedType(Token token) {
- pushNode(null);
- if (token is ErrorToken) {
- reportErrorToken(token);
- return synthesizeIdentifier(token);
- } else {
- reportFatalError(reporter.spanFromToken(token),
- "Expected a type, but got '${token.value}'.");
- return skipToEof(token);
- }
- }
-
- @override
- Token expectedExpression(Token token) {
- if (token is ErrorToken) {
- reportErrorToken(token);
- pushNode(new ErrorExpression(token));
- return token.next;
- } else {
- reportFatalError(
- reporter.spanFromToken(token),
- "Expected an expression, but got '${token.value}'.");
- pushNode(null);
- return skipToEof(token);
- }
- }
-
- @override
- Token unexpected(Token token) {
- if (token is ErrorToken) {
- reportErrorToken(token);
- } else {
- String message = "Unexpected token '${token.value}'.";
- if (token.info == Precedence.BAD_INPUT_INFO) {
- message = token.value;
- }
- reportFatalError(reporter.spanFromToken(token), message);
- }
- return skipToEof(token);
- }
-
- @override
- Token expectedBlockToSkip(Token token) {
- if (identical(token.stringValue, 'native')) {
- return native.handleNativeBlockToSkip(this, token);
- } else {
- return unexpected(token);
- }
- }
-
- @override
- Token expectedFunctionBody(Token token) {
- if (token is ErrorToken) {
- reportErrorToken(token);
- } else {
- String printString = token.value;
- reportFatalError(
- reporter.spanFromToken(token),
- "Expected a function body, but got '$printString'.");
- }
- return skipToEof(token);
- }
-
- @override
- Token expectedClassBody(Token token) {
- if (token is ErrorToken) {
- reportErrorToken(token);
- } else {
- reportFatalError(
- reporter.spanFromToken(token),
- "Expected a class body, but got '${token.value}'.");
- }
- return skipToEof(token);
- }
-
- @override
- Token expectedClassBodyToSkip(Token token) {
- return unexpected(token);
- }
-
- @override
- Token expectedDeclaration(Token token) {
- if (token is ErrorToken) {
- reportErrorToken(token);
- } else {
- reportFatalError(
- reporter.spanFromToken(token),
- "Expected a declaration, but got '${token.value}'.");
- }
- return skipToEof(token);
- }
-
- @override
- Token unmatched(Token token) {
- if (token is ErrorToken) {
- reportErrorToken(token);
- } else {
- String begin = token.value;
- String end = closeBraceFor(begin);
- reportErrorMessageToken(
- token, MessageKind.UNMATCHED_TOKEN, {'begin': begin, 'end': end});
- }
- Token next = token.next;
- while (next is ErrorToken) {
- next = next.next;
- }
- return next;
+ /// Finds the preceding token via the begin token of the last AST node pushed
+ /// on the [nodes] stack.
+ Token synthesizeIdentifier(Token token) {
+ Token synthesizedToken = new StringToken.fromString(
+ Precedence.IDENTIFIER_INFO, '?', token.charOffset);
+ synthesizedToken.next = token.next;
+ return synthesizedToken;
}
void recoverableError(Spannable node, String message) {
@@ -801,14 +880,14 @@ class ElementListener extends Listener {
/// Don't call this method. Should only be used as a last resort when there
/// is no feasible way to recover from a parser error.
- void reportFatalError(SourceSpan span, String message) {
- reportErrorMessageHelper(span, MessageKind.GENERIC, {'text': message});
+ Token reportFatalError(SourceSpan span, String message) {
+ reportError(span, MessageKind.GENERIC, {'text': message});
// Some parse errors are infeasible to recover from, so we throw an error.
throw new ParserError(
span.begin, span.end, ErrorKind.Unspecified, {'text': message});
}
- void reportErrorMessageHelper(Spannable spannable, MessageKind errorCode,
+ void reportError(Spannable spannable, MessageKind errorCode,
[Map arguments = const {}]) {
if (currentMemberHasParseError) return; // Error already reported.
if (suppressParseErrors) return;
@@ -818,109 +897,8 @@ class ElementListener extends Listener {
reporter.reportErrorMessage(spannable, errorCode, arguments);
}
- void reportErrorMessageToken(Token token, MessageKind errorCode,
+ void reportErrorFromToken(Token token, MessageKind errorCode,
[Map arguments = const {}]) {
- if (token is ErrorToken) {
- reportErrorToken(token);
- } else {
- reportErrorMessageHelper(
- reporter.spanFromToken(token), errorCode, arguments);
- }
- }
-
- void reportErrorHelper(Token token, ErrorKind kind, Map arguments) {
- SourceSpan span = reporter.spanFromToken(token);
- MessageKind errorCode;
- switch (kind) {
- case ErrorKind.EmptyNamedParameterList:
- errorCode = MessageKind.EMPTY_NAMED_PARAMETER_LIST;
- break;
-
- case ErrorKind.EmptyOptionalParameterList:
- errorCode = MessageKind.EMPTY_OPTIONAL_PARAMETER_LIST;
- break;
-
- case ErrorKind.ExpectedBody:
- errorCode = MessageKind.BODY_EXPECTED;
- break;
-
- case ErrorKind.ExpectedHexDigit:
- errorCode = MessageKind.HEX_DIGIT_EXPECTED;
- break;
-
- case ErrorKind.ExpectedOpenParens:
- errorCode = MessageKind.GENERIC;
- arguments = {"text": "Expected '('."};
- break;
-
- case ErrorKind.ExpectedString:
- errorCode = MessageKind.STRING_EXPECTED;
- break;
-
- case ErrorKind.ExtraneousModifier:
- errorCode = MessageKind.EXTRANEOUS_MODIFIER;
- break;
-
- case ErrorKind.ExtraneousModifierReplace:
- errorCode = MessageKind.EXTRANEOUS_MODIFIER_REPLACE;
- break;
-
- case ErrorKind.InvalidAwaitFor:
- errorCode = MessageKind.INVALID_AWAIT_FOR;
- break;
-
- case ErrorKind.InvalidInputCharacter:
- errorCode = MessageKind.BAD_INPUT_CHARACTER;
- break;
-
- case ErrorKind.InvalidSyncModifier:
- errorCode = MessageKind.INVALID_SYNC_MODIFIER;
- break;
-
- case ErrorKind.InvalidVoid:
- errorCode = MessageKind.VOID_NOT_ALLOWED;
- break;
-
- case ErrorKind.MalformedStringLiteral:
- errorCode = MessageKind.MALFORMED_STRING_LITERAL;
- break;
-
- case ErrorKind.MissingExponent:
- errorCode = MessageKind.EXPONENT_MISSING;
- break;
-
- case ErrorKind.PositionalParameterWithEquals:
- errorCode = MessageKind.POSITIONAL_PARAMETER_WITH_EQUALS;
- break;
-
- case ErrorKind.RequiredParameterWithDefault:
- errorCode = MessageKind.REQUIRED_PARAMETER_WITH_DEFAULT;
- break;
-
- case ErrorKind.UnmatchedToken:
- errorCode = MessageKind.UNMATCHED_TOKEN;
- break;
-
- case ErrorKind.UnsupportedPrefixPlus:
- errorCode = MessageKind.UNSUPPORTED_PREFIX_PLUS;
- break;
-
- case ErrorKind.UnterminatedComment:
- errorCode = MessageKind.UNTERMINATED_COMMENT;
- break;
-
- case ErrorKind.UnterminatedString:
- errorCode = MessageKind.UNTERMINATED_STRING;
- break;
-
- case ErrorKind.UnterminatedToken:
- errorCode = MessageKind.UNTERMINATED_TOKEN;
- break;
-
- case ErrorKind.Unspecified:
- errorCode = MessageKind.GENERIC;
- break;
- }
- reportErrorMessageHelper(span, errorCode, arguments);
+ reportError(reporter.spanFromToken(token), errorCode, arguments);
}
}
« no previous file with comments | « pkg/compiler/lib/src/native/scanner.dart ('k') | pkg/compiler/lib/src/parser/node_listener.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698