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); |
} |
} |