| Index: pkg/dart_parser/lib/src/listener.dart
|
| diff --git a/pkg/dart_parser/lib/src/listener.dart b/pkg/dart_parser/lib/src/listener.dart
|
| index 9d656bbcf94dd29adb6d08d793bf9ed2e8dfaf18..63d0188d6f021a7f083afb978300b04a372429f8 100644
|
| --- a/pkg/dart_parser/lib/src/listener.dart
|
| +++ b/pkg/dart_parser/lib/src/listener.dart
|
| @@ -4,18 +4,9 @@
|
|
|
| library dart_parser.listener;
|
|
|
| -import 'package:dart_scanner/src/precedence.dart' show
|
| - EOF_INFO,
|
| - IDENTIFIER_INFO;
|
| -
|
| import 'package:dart_scanner/src/token.dart' show
|
| - BadInputToken,
|
| BeginGroupToken,
|
| - ErrorToken,
|
| - StringToken,
|
| - Token,
|
| - UnmatchedToken,
|
| - UnterminatedToken;
|
| + Token;
|
|
|
| import 'error_kind.dart' show
|
| ErrorKind;
|
| @@ -760,216 +751,28 @@ class Listener {
|
| logEvent("YieldStatement");
|
| }
|
|
|
| - // TODO(ahe): Rename to `handleUnexpected`.
|
| - Token expected(String string, Token token) {
|
| - if (token is ErrorToken) {
|
| - reportErrorToken(token);
|
| - } else {
|
| - error("expected '$string', but got '${token.value}'", token);
|
| - }
|
| - return skipToEof(token);
|
| - }
|
| -
|
| - // TODO(ahe): Move away from this class.
|
| - Token synthesizeIdentifier(Token token) {
|
| - Token synthesizedToken = new StringToken.fromString(
|
| - IDENTIFIER_INFO, '?', token.charOffset);
|
| - synthesizedToken.next = token.next;
|
| - return synthesizedToken;
|
| - }
|
| -
|
| - // TODO(ahe): Rename to `handleIdentifierExpected`.
|
| - Token expectedIdentifier(Token token) {
|
| - if (token is ErrorToken) {
|
| - reportErrorToken(token);
|
| - } else {
|
| - error("expected identifier, but got '${token.value}'", token);
|
| - }
|
| - return skipToEof(token);
|
| - }
|
| -
|
| - // TODO(ahe): Rename to `handleTypeExpected`.
|
| - Token expectedType(Token token) {
|
| - if (token is ErrorToken) {
|
| - reportErrorToken(token);
|
| - } else {
|
| - error("expected a type, but got '${token.value}'", token);
|
| - }
|
| - return skipToEof(token);
|
| - }
|
| -
|
| - // TODO(ahe): Rename to `handleExpressionExpected`.
|
| - Token expectedExpression(Token token) {
|
| - if (token is ErrorToken) {
|
| - reportErrorToken(token);
|
| - } else {
|
| - error("expected an expression, but got '${token.value}'", token);
|
| - }
|
| - return skipToEof(token);
|
| - }
|
| -
|
| - // TODO(ahe): Merge with `handleUnexpected` (nee `expected`).
|
| - Token unexpected(Token token) {
|
| - if (token is ErrorToken) {
|
| - reportErrorToken(token);
|
| - } else {
|
| - error("unexpected token '${token.value}'", token);
|
| - }
|
| - return skipToEof(token);
|
| - }
|
| -
|
| - // TODO(ahe): Rename to `handleBlockToSkipExpected`.
|
| - Token expectedBlockToSkip(Token token) {
|
| - if (token is ErrorToken) {
|
| - reportErrorToken(token);
|
| - } else {
|
| - error("expected a block, but got '${token.value}'", token);
|
| - }
|
| - return skipToEof(token);
|
| - }
|
| -
|
| - // TODO(ahe): Rename to `handleFunctionBodyExpected`.
|
| - Token expectedFunctionBody(Token token) {
|
| - if (token is ErrorToken) {
|
| - reportErrorToken(token);
|
| - } else {
|
| - error("expected a function body, but got '${token.value}'", token);
|
| - }
|
| - return skipToEof(token);
|
| - }
|
| -
|
| - // TODO(ahe): Rename to `handleClassBodyExpected`.
|
| - Token expectedClassBody(Token token) {
|
| - if (token is ErrorToken) {
|
| - reportErrorToken(token);
|
| - } else {
|
| - error("expected a class body, but got '${token.value}'", token);
|
| - }
|
| - return skipToEof(token);
|
| - }
|
| -
|
| - // TODO(ahe): Rename to `handleClassBodyToSkipExpected`.
|
| - Token expectedClassBodyToSkip(Token token) {
|
| - if (token is ErrorToken) {
|
| - reportErrorToken(token);
|
| - } else {
|
| - error("expected a class body, but got '${token.value}'", token);
|
| - }
|
| - return skipToEof(token);
|
| - }
|
| -
|
| - // TODO(ahe): Rename to `handleDeclarationExpected`.
|
| - Token expectedDeclaration(Token token) {
|
| - if (token is ErrorToken) {
|
| - reportErrorToken(token);
|
| - } else {
|
| - error("expected a declaration, but got '${token.value}'", token);
|
| - }
|
| - return skipToEof(token);
|
| - }
|
| -
|
| - // TODO(ahe): Rename to `handleUnmatched`.
|
| - Token unmatched(Token token) {
|
| - if (token is ErrorToken) {
|
| - reportErrorToken(token);
|
| - } else {
|
| - error("unmatched '${token.value}'", token);
|
| - }
|
| - return skipToEof(token);
|
| - }
|
| -
|
| - // TODO(ahe): Move away from this class.
|
| - Token skipToEof(Token token) {
|
| - while (!identical(token.info, EOF_INFO)) {
|
| - token = token.next;
|
| - }
|
| - return token;
|
| - }
|
| -
|
| - // TODO(ahe): Merge with `handleError` (nee `reportError`).
|
| - void error(String message, Token token) {
|
| - throw new ParserError.fromTokens(
|
| - token, token, ErrorKind.Unspecified, {'text': message});
|
| - }
|
| -
|
| - // TODO(ahe): Rename to `handleError`.
|
| - void reportError(Token token, ErrorKind kind, [Map arguments = const {}]) {
|
| - if (token is ErrorToken) {
|
| - reportErrorToken(token);
|
| - } else {
|
| - reportErrorHelper(token, kind, arguments);
|
| - }
|
| - }
|
| -
|
| - // TODO(ahe): Move away from this class.
|
| - void reportErrorHelper(Token token, ErrorKind kind, Map arguments) {
|
| - recoverableErrors.add(
|
| - new ParserError.fromTokens(token, token, kind, arguments));
|
| + /// An unrecoverable error is an error that the parser can't recover from
|
| + /// itself, and recovery is left to the listener. If the listener can
|
| + /// recover, it should return a non-null continuation token. Error recovery
|
| + /// is tightly coupled to the parser implementation, so to recover from an
|
| + /// error, one must carefully examine the code in the parser that generates
|
| + /// the error.
|
| + ///
|
| + /// If the listener can't recover, it can throw an exception or return
|
| + /// `null`. In the latter case, the parser simply skips to EOF which will
|
| + /// often result in additional parser errors as the parser returns from its
|
| + /// recursive state.
|
| + Token handleUnrecoverableError(Token token, ErrorKind kind, Map arguments) {
|
| + throw new ParserError.fromTokens(token, token, kind, arguments);
|
| }
|
|
|
| - // TODO(ahe): Move away from this class.
|
| - void reportErrorToken(ErrorToken token) {
|
| - if (token is BadInputToken) {
|
| - String hex = token.character.toRadixString(16);
|
| - if (hex.length < 4) {
|
| - String padding = "0000".substring(hex.length);
|
| - hex = "$padding$hex";
|
| - }
|
| - reportErrorHelper(
|
| - token, ErrorKind.InvalidInputCharacter, {'characterHex': hex});
|
| - } else if (token is UnterminatedToken) {
|
| - ErrorKind kind;
|
| - var arguments = const {};
|
| - switch (token.start) {
|
| - case '1e':
|
| - kind = ErrorKind.MissingExponent;
|
| - break;
|
| - case '"':
|
| - case "'":
|
| - case '"""':
|
| - case "'''":
|
| - case 'r"':
|
| - case "r'":
|
| - case 'r"""':
|
| - case "r'''":
|
| - kind = ErrorKind.UnterminatedString;
|
| - arguments = {'quote': token.start};
|
| - break;
|
| - case '0x':
|
| - kind = ErrorKind.ExpectedHexDigit;
|
| - break;
|
| - case r'$':
|
| - kind = ErrorKind.MalformedStringLiteral;
|
| - break;
|
| - case '/*':
|
| - kind = ErrorKind.UnterminatedComment;
|
| - break;
|
| - default:
|
| - kind = ErrorKind.UnterminatedToken;
|
| - break;
|
| - }
|
| - reportErrorHelper(token, kind, arguments);
|
| - } else if (token is UnmatchedToken) {
|
| - String begin = token.begin.value;
|
| - String end = closeBraceFor(begin);
|
| - reportErrorHelper(
|
| - token, ErrorKind.UnmatchedToken, {'begin': begin, 'end': end});
|
| - } else {
|
| - error(token.assertionMessage, token);
|
| - }
|
| + /// The parser noticed a syntax error, but was able to recover from it.
|
| + void handleRecoverableError(Token token, ErrorKind kind, Map arguments) {
|
| + recoverableErrors.add(
|
| + new ParserError.fromTokens(token, token, kind, arguments));
|
| }
|
| }
|
|
|
| -String closeBraceFor(String openBrace) {
|
| - return const {
|
| - '(': ')',
|
| - '[': ']',
|
| - '{': '}',
|
| - '<': '>',
|
| - r'${': '}',
|
| - }[openBrace];
|
| -}
|
| -
|
| class ParserError {
|
| /// Character offset from the beginning of file where this error starts.
|
| final int beginOffset;
|
|
|