| Index: pkg/front_end/lib/src/fasta/parser/parser.dart
|
| diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart
|
| index 9e345bc7e4c3df12776c06ae72ea98e5462ddbbf..e6dba6a39dc1d8cd5fc6c8321fba028110f6bda5 100644
|
| --- a/pkg/front_end/lib/src/fasta/parser/parser.dart
|
| +++ b/pkg/front_end/lib/src/fasta/parser/parser.dart
|
| @@ -4,6 +4,56 @@
|
|
|
| library fasta.parser.parser;
|
|
|
| +import '../fasta_codes.dart'
|
| + show
|
| + FastaCode,
|
| + FastaMessage,
|
| + codeAbstractNotSync,
|
| + codeAsciiControlCharacter,
|
| + codeAsyncAsIdentifier,
|
| + codeAwaitAsIdentifier,
|
| + codeAwaitForNotAsync,
|
| + codeAwaitNotAsync,
|
| + codeBuiltInIdentifierAsType,
|
| + codeBuiltInIdentifierInDeclaration,
|
| + codeEmptyNamedParameterList,
|
| + codeEmptyOptionalParameterList,
|
| + codeEncoding,
|
| + codeExpectedBlockToSkip,
|
| + codeExpectedBody,
|
| + codeExpectedButGot,
|
| + codeExpectedClassBody,
|
| + codeExpectedClassBodyToSkip,
|
| + codeExpectedDeclaration,
|
| + codeExpectedExpression,
|
| + codeExpectedFunctionBody,
|
| + codeExpectedIdentifier,
|
| + codeExpectedOpenParens,
|
| + codeExpectedString,
|
| + codeExpectedType,
|
| + codeExtraneousModifier,
|
| + codeExtraneousModifierReplace,
|
| + codeFactoryNotSync,
|
| + codeGeneratorReturnsValue,
|
| + codeInvalidAwaitFor,
|
| + codeInvalidInlineFunctionType,
|
| + codeInvalidSyncModifier,
|
| + codeInvalidVoid,
|
| + codeNonAsciiIdentifier,
|
| + codeNonAsciiWhitespace,
|
| + codeOnlyTry,
|
| + codePositionalParameterWithEquals,
|
| + codeRequiredParameterWithDefault,
|
| + codeSetterNotSync,
|
| + codeStackOverflow,
|
| + codeUnexpectedToken,
|
| + codeUnmatchedToken,
|
| + codeUnspecified,
|
| + codeUnsupportedPrefixPlus,
|
| + codeUnterminatedString,
|
| + codeYieldAsIdentifier,
|
| + codeYieldNotGenerator;
|
| +
|
| import '../scanner.dart' show ErrorToken;
|
|
|
| import '../scanner/recover.dart' show closeBraceFor, skipToEof;
|
| @@ -70,8 +120,6 @@ import 'async_modifier.dart' show AsyncModifier;
|
|
|
| import 'listener.dart' show Listener;
|
|
|
| -import 'error_kind.dart' show ErrorKind;
|
| -
|
| import 'identifier_context.dart' show IdentifierContext;
|
|
|
| /// Returns true if [token] is the symbol or keyword [value].
|
| @@ -132,6 +180,8 @@ class FormalParameterType {
|
| class Parser {
|
| final Listener listener;
|
|
|
| + Uri get uri => listener.uri;
|
| +
|
| bool mayParseFunctionExpressions = true;
|
|
|
| /// Represents parser state: what asynchronous syntax is allowed in the
|
| @@ -487,11 +537,12 @@ class Parser {
|
| listener.beginOptionalFormalParameters(token);
|
| if (!optional('(', token)) {
|
| if (optional(';', token)) {
|
| - reportRecoverableError(token, ErrorKind.ExpectedOpenParens);
|
| + reportRecoverableErrorCode(token, codeExpectedOpenParens);
|
| return token;
|
| }
|
| - return reportUnrecoverableError(
|
| - token, ErrorKind.ExpectedButGot, {"expected": "("})?.next;
|
| + return reportUnrecoverableErrorCodeWithString(
|
| + token, codeExpectedButGot, "(")
|
| + .next;
|
| }
|
| BeginGroupToken beginGroupToken = token;
|
| Token endToken = beginGroupToken.endGroup;
|
| @@ -525,7 +576,7 @@ class Parser {
|
| break;
|
| } else if (identical(value, '[]')) {
|
| --parameterCount;
|
| - reportRecoverableError(token, ErrorKind.EmptyOptionalParameterList);
|
| + reportRecoverableErrorCode(token, codeEmptyOptionalParameterList);
|
| token = token.next;
|
| break;
|
| }
|
| @@ -593,8 +644,8 @@ class Parser {
|
| // The following isn't allowed:
|
| // int Function(int bar(String x)).
|
| if (inFunctionType) {
|
| - reportRecoverableError(
|
| - inlineFunctionTypeStart, ErrorKind.InvalidInlineFunctionType);
|
| + reportRecoverableErrorCode(
|
| + inlineFunctionTypeStart, codeInvalidInlineFunctionType);
|
| }
|
| } else if (optional('<', token)) {
|
| Token inlineFunctionTypeStart = token;
|
| @@ -607,8 +658,8 @@ class Parser {
|
| // The following isn't allowed:
|
| // int Function(int bar(String x)).
|
| if (inFunctionType) {
|
| - reportRecoverableError(
|
| - inlineFunctionTypeStart, ErrorKind.InvalidInlineFunctionType);
|
| + reportRecoverableErrorCode(
|
| + inlineFunctionTypeStart, codeInvalidInlineFunctionType);
|
| }
|
| }
|
| String value = token.stringValue;
|
| @@ -618,9 +669,9 @@ class Parser {
|
| token = parseExpression(token.next);
|
| listener.handleValuedFormalParameter(equal, token);
|
| if (kind.isRequired) {
|
| - reportRecoverableError(equal, ErrorKind.RequiredParameterWithDefault);
|
| + reportRecoverableErrorCode(equal, codeRequiredParameterWithDefault);
|
| } else if (kind.isPositional && identical(':', value)) {
|
| - reportRecoverableError(equal, ErrorKind.PositionalParameterWithEquals);
|
| + reportRecoverableErrorCode(equal, codePositionalParameterWithEquals);
|
| }
|
| } else {
|
| listener.handleFormalParameterWithoutValue(token);
|
| @@ -648,11 +699,11 @@ class Parser {
|
| ++parameterCount;
|
| } while (optional(',', token));
|
| if (parameterCount == 0) {
|
| - reportRecoverableError(
|
| + reportRecoverableErrorCode(
|
| token,
|
| isNamed
|
| - ? ErrorKind.EmptyNamedParameterList
|
| - : ErrorKind.EmptyOptionalParameterList);
|
| + ? codeEmptyNamedParameterList
|
| + : codeEmptyOptionalParameterList);
|
| }
|
| listener.endOptionalFormalParameters(parameterCount, begin, token);
|
| if (isNamed) {
|
| @@ -791,17 +842,12 @@ class Parser {
|
|
|
| Token skipBlock(Token token) {
|
| if (!optional('{', token)) {
|
| - return reportUnrecoverableError(token, ErrorKind.ExpectedBlockToSkip)
|
| - ?.next;
|
| + return reportUnrecoverableErrorCode(token, codeExpectedBlockToSkip).next;
|
| }
|
| BeginGroupToken beginGroupToken = token;
|
| Token endGroup = beginGroupToken.endGroup;
|
| - if (endGroup == null) {
|
| - return reportUnrecoverableError(beginGroupToken, ErrorKind.UnmatchedToken)
|
| - ?.next;
|
| - } else if (!identical(endGroup.kind, $CLOSE_CURLY_BRACKET)) {
|
| - return reportUnrecoverableError(beginGroupToken, ErrorKind.UnmatchedToken)
|
| - ?.next;
|
| + if (endGroup == null || !identical(endGroup.kind, $CLOSE_CURLY_BRACKET)) {
|
| + return reportUnmatchedToken(beginGroupToken).next;
|
| }
|
| return beginGroupToken.endGroup;
|
| }
|
| @@ -910,7 +956,8 @@ class Parser {
|
|
|
| Token parseStringPart(Token token) {
|
| if (token.kind != STRING_TOKEN) {
|
| - token = reportUnrecoverableError(token, ErrorKind.ExpectedString)?.next;
|
| + token =
|
| + reportUnrecoverableErrorCodeWithToken(token, codeExpectedString).next;
|
| }
|
| listener.handleStringPart(token);
|
| return token.next;
|
| @@ -919,21 +966,23 @@ class Parser {
|
| Token parseIdentifier(Token token, IdentifierContext context) {
|
| if (!token.isIdentifier()) {
|
| token =
|
| - reportUnrecoverableError(token, ErrorKind.ExpectedIdentifier)?.next;
|
| + reportUnrecoverableErrorCodeWithToken(token, codeExpectedIdentifier)
|
| + .next;
|
| } else if (token.isBuiltInIdentifier &&
|
| !context.isBuiltInIdentifierAllowed) {
|
| if (context.inDeclaration) {
|
| - reportRecoverableError(token, ErrorKind.BuiltInIdentifierInDeclaration);
|
| + reportRecoverableErrorCodeWithToken(
|
| + token, codeBuiltInIdentifierInDeclaration);
|
| } else if (!optional("dynamic", token)) {
|
| - reportRecoverableError(token, ErrorKind.BuiltInIdentifierAsType);
|
| + reportRecoverableErrorCodeWithToken(token, codeBuiltInIdentifierAsType);
|
| }
|
| } else if (!inPlainSync && token.isPseudo) {
|
| if (optional('await', token)) {
|
| - reportRecoverableError(token, ErrorKind.AwaitAsIdentifier);
|
| + reportRecoverableErrorCode(token, codeAwaitAsIdentifier);
|
| } else if (optional('yield', token)) {
|
| - reportRecoverableError(token, ErrorKind.YieldAsIdentifier);
|
| + reportRecoverableErrorCode(token, codeYieldAsIdentifier);
|
| } else if (optional('async', token)) {
|
| - reportRecoverableError(token, ErrorKind.AsyncAsIdentifier);
|
| + reportRecoverableErrorCode(token, codeAsyncAsIdentifier);
|
| }
|
| }
|
| listener.handleIdentifier(token, context);
|
| @@ -942,8 +991,9 @@ class Parser {
|
|
|
| Token expect(String string, Token token) {
|
| if (!identical(string, token.stringValue)) {
|
| - return reportUnrecoverableError(
|
| - token, ErrorKind.ExpectedButGot, {"expected": string})?.next;
|
| + return reportUnrecoverableErrorCodeWithString(
|
| + token, codeExpectedButGot, string)
|
| + .next;
|
| }
|
| return token.next;
|
| }
|
| @@ -1010,7 +1060,8 @@ class Parser {
|
| token = parseQualifiedRestOpt(
|
| token, IdentifierContext.typeReferenceContinuation);
|
| } else {
|
| - token = reportUnrecoverableError(token, ErrorKind.ExpectedType)?.next;
|
| + token =
|
| + reportUnrecoverableErrorCodeWithToken(token, codeExpectedType).next;
|
| listener.handleInvalidTypeReference(token);
|
| }
|
| token = parseTypeArgumentsOpt(token);
|
| @@ -1086,15 +1137,17 @@ class Parser {
|
|
|
| Link<Token> identifiers = findMemberName(token);
|
| if (identifiers.isEmpty) {
|
| - return reportUnrecoverableError(start, ErrorKind.ExpectedDeclaration)
|
| - ?.next;
|
| + return reportUnrecoverableErrorCodeWithToken(
|
| + start, codeExpectedDeclaration)
|
| + .next;
|
| }
|
| Token afterName = identifiers.head;
|
| identifiers = identifiers.tail;
|
|
|
| if (identifiers.isEmpty) {
|
| - return reportUnrecoverableError(start, ErrorKind.ExpectedDeclaration)
|
| - ?.next;
|
| + return reportUnrecoverableErrorCodeWithToken(
|
| + start, codeExpectedDeclaration)
|
| + .next;
|
| }
|
| Token name = identifiers.head;
|
| identifiers = identifiers.tail;
|
| @@ -1139,8 +1192,7 @@ class Parser {
|
| }
|
| break;
|
| } else {
|
| - token =
|
| - reportUnrecoverableError(token, ErrorKind.UnexpectedToken)?.next;
|
| + token = reportUnexpectedToken(token).next;
|
| if (identical(token.kind, EOF_TOKEN)) return token;
|
| }
|
| }
|
| @@ -1207,11 +1259,12 @@ class Parser {
|
| modifierList.remove(varFinalOrConst);
|
| }
|
| listener.handleModifiers(modifierCount);
|
| - var kind = hasTypeOrModifier
|
| - ? ErrorKind.ExtraneousModifier
|
| - : ErrorKind.ExtraneousModifierReplace;
|
| for (Token modifier in modifierList) {
|
| - reportRecoverableError(modifier, kind, {'modifier': modifier});
|
| + reportRecoverableErrorCodeWithToken(
|
| + modifier,
|
| + hasTypeOrModifier
|
| + ? codeExtraneousModifier
|
| + : codeExtraneousModifierReplace);
|
| }
|
| return null;
|
| }
|
| @@ -1256,10 +1309,11 @@ class Parser {
|
| }
|
|
|
| if (getOrSet != null) {
|
| - var kind = (hasModifier || hasType)
|
| - ? ErrorKind.ExtraneousModifier
|
| - : ErrorKind.ExtraneousModifierReplace;
|
| - reportRecoverableError(getOrSet, kind, {'modifier': getOrSet});
|
| + reportRecoverableErrorCodeWithToken(
|
| + getOrSet,
|
| + hasModifier || hasType
|
| + ? codeExtraneousModifier
|
| + : codeExtraneousModifierReplace);
|
| }
|
|
|
| if (!hasType) {
|
| @@ -1270,12 +1324,12 @@ class Parser {
|
| // TODO(ahe): This error is reported twice, second time is from
|
| // [parseVariablesDeclarationMaybeSemicolon] via
|
| // [PartialFieldListElement.parseNode].
|
| - reportRecoverableError(type, ErrorKind.InvalidVoid);
|
| + reportRecoverableErrorCode(type, codeInvalidVoid);
|
| } else {
|
| parseType(type);
|
| if (isVar) {
|
| - reportRecoverableError(modifiers.head, ErrorKind.ExtraneousModifier,
|
| - {'modifier': modifiers.head});
|
| + reportRecoverableErrorCodeWithToken(
|
| + modifiers.head, codeExtraneousModifier);
|
| }
|
| }
|
|
|
| @@ -1311,8 +1365,7 @@ class Parser {
|
| if (externalModifier == null && optional('external', modifier)) {
|
| externalModifier = modifier;
|
| } else {
|
| - reportRecoverableError(
|
| - modifier, ErrorKind.ExtraneousModifier, {'modifier': modifier});
|
| + reportRecoverableErrorCodeWithToken(modifier, codeExtraneousModifier);
|
| }
|
| }
|
| if (externalModifier != null) {
|
| @@ -1340,7 +1393,7 @@ class Parser {
|
| Token asyncToken = token;
|
| token = parseAsyncModifier(token);
|
| if (getOrSet != null && !inPlainSync && optional("set", getOrSet)) {
|
| - reportRecoverableError(asyncToken, ErrorKind.SetterNotSync);
|
| + reportRecoverableErrorCode(asyncToken, codeSetterNotSync);
|
| }
|
| token = parseFunctionBody(token, false, externalModifier != null);
|
| asyncState = savedAsyncModifier;
|
| @@ -1434,7 +1487,7 @@ class Parser {
|
| if (token.next is BeginGroupToken) {
|
| BeginGroupToken beginGroup = token.next;
|
| if (beginGroup.endGroup == null) {
|
| - reportUnrecoverableError(beginGroup, ErrorKind.UnmatchedToken);
|
| + token = reportUnmatchedToken(beginGroup).next;
|
| } else {
|
| token = beginGroup.endGroup;
|
| }
|
| @@ -1449,7 +1502,7 @@ class Parser {
|
| if (token is BeginGroupToken) {
|
| BeginGroupToken beginGroup = token;
|
| if (beginGroup.endGroup == null) {
|
| - reportUnrecoverableError(beginGroup, ErrorKind.UnmatchedToken);
|
| + token = reportUnmatchedToken(beginGroup).next;
|
| } else {
|
| token = beginGroup.endGroup.next;
|
| }
|
| @@ -1457,14 +1510,14 @@ class Parser {
|
| }
|
| if (!optional('(', token)) {
|
| if (optional(';', token)) {
|
| - reportRecoverableError(token, ErrorKind.ExpectedOpenParens);
|
| + reportRecoverableErrorCode(token, codeExpectedOpenParens);
|
| }
|
| token = expect("(", token);
|
| }
|
| if (token is BeginGroupToken) {
|
| BeginGroupToken beginGroup = token;
|
| if (beginGroup.endGroup == null) {
|
| - reportUnrecoverableError(beginGroup, ErrorKind.UnmatchedToken);
|
| + token = reportUnmatchedToken(beginGroup).next;
|
| } else {
|
| token = beginGroup.endGroup.next;
|
| }
|
| @@ -1530,7 +1583,7 @@ class Parser {
|
| if (identical(token.kind, STRING_TOKEN)) {
|
| return parseLiteralString(token);
|
| } else {
|
| - reportRecoverableError(token, ErrorKind.ExpectedString);
|
| + reportRecoverableErrorCodeWithToken(token, codeExpectedString);
|
| return parseRecoverExpression(token);
|
| }
|
| }
|
| @@ -1562,7 +1615,7 @@ class Parser {
|
| if (isModifier(token)) {
|
| parseModifier(token);
|
| } else {
|
| - reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
|
| + reportUnexpectedToken(token);
|
| // Skip the remaining modifiers.
|
| break;
|
| }
|
| @@ -1576,7 +1629,7 @@ class Parser {
|
| // change. For example, this is parsed as a local variable declaration:
|
| // `abstract foo;`. Ideally, this example should be handled as a local
|
| // variable having the type `abstract` (which should be reported as
|
| - // `ErrorKind.BuiltInIdentifierAsType` by [parseIdentifier]).
|
| + // `codeBuiltInIdentifierAsType` by [parseIdentifier]).
|
| int count = 0;
|
| while (identical(token.kind, KEYWORD_TOKEN)) {
|
| if (!isModifier(token)) break;
|
| @@ -1686,17 +1739,14 @@ class Parser {
|
|
|
| Token skipClassBody(Token token) {
|
| if (!optional('{', token)) {
|
| - return reportUnrecoverableError(token, ErrorKind.ExpectedClassBodyToSkip)
|
| - ?.next;
|
| + return reportUnrecoverableErrorCodeWithToken(
|
| + token, codeExpectedClassBodyToSkip)
|
| + .next;
|
| }
|
| BeginGroupToken beginGroupToken = token;
|
| Token endGroup = beginGroupToken.endGroup;
|
| - if (endGroup == null) {
|
| - return reportUnrecoverableError(beginGroupToken, ErrorKind.UnmatchedToken)
|
| - ?.next;
|
| - } else if (!identical(endGroup.kind, $CLOSE_CURLY_BRACKET)) {
|
| - return reportUnrecoverableError(beginGroupToken, ErrorKind.UnmatchedToken)
|
| - ?.next;
|
| + if (endGroup == null || !identical(endGroup.kind, $CLOSE_CURLY_BRACKET)) {
|
| + return reportUnmatchedToken(beginGroupToken).next;
|
| }
|
| return endGroup;
|
| }
|
| @@ -1706,7 +1756,8 @@ class Parser {
|
| listener.beginClassBody(token);
|
| if (!optional('{', token)) {
|
| token =
|
| - reportUnrecoverableError(token, ErrorKind.ExpectedClassBody)?.next;
|
| + reportUnrecoverableErrorCodeWithToken(token, codeExpectedClassBody)
|
| + .next;
|
| }
|
| token = token.next;
|
| int count = 0;
|
| @@ -1743,15 +1794,17 @@ class Parser {
|
|
|
| Link<Token> identifiers = findMemberName(token);
|
| if (identifiers.isEmpty) {
|
| - return reportUnrecoverableError(start, ErrorKind.ExpectedDeclaration)
|
| - ?.next;
|
| + return reportUnrecoverableErrorCodeWithToken(
|
| + start, codeExpectedDeclaration)
|
| + .next;
|
| }
|
| Token afterName = identifiers.head;
|
| identifiers = identifiers.tail;
|
|
|
| if (identifiers.isEmpty) {
|
| - return reportUnrecoverableError(start, ErrorKind.ExpectedDeclaration)
|
| - ?.next;
|
| + return reportUnrecoverableErrorCodeWithToken(
|
| + start, codeExpectedDeclaration)
|
| + .next;
|
| }
|
| Token name = identifiers.head;
|
| identifiers = identifiers.tail;
|
| @@ -1803,8 +1856,7 @@ class Parser {
|
| isField = true;
|
| break;
|
| } else {
|
| - token =
|
| - reportUnrecoverableError(token, ErrorKind.UnexpectedToken)?.next;
|
| + token = reportUnexpectedToken(token).next;
|
| if (identical(token.kind, EOF_TOKEN)) {
|
| // TODO(ahe): This is a hack, see parseTopLevelMember.
|
| listener.endFields(1, null, start, token);
|
| @@ -1837,32 +1889,28 @@ class Parser {
|
| modifierCount++;
|
| externalModifier = modifier;
|
| if (modifierCount != allowedModifierCount) {
|
| - reportRecoverableError(
|
| - modifier, ErrorKind.ExtraneousModifier, {'modifier': modifier});
|
| + reportRecoverableErrorCodeWithToken(modifier, codeExtraneousModifier);
|
| }
|
| allowedModifierCount++;
|
| } else if (staticModifier == null && optional('static', modifier)) {
|
| modifierCount++;
|
| staticModifier = modifier;
|
| if (modifierCount != allowedModifierCount) {
|
| - reportRecoverableError(
|
| - modifier, ErrorKind.ExtraneousModifier, {'modifier': modifier});
|
| + reportRecoverableErrorCodeWithToken(modifier, codeExtraneousModifier);
|
| }
|
| } else if (constModifier == null && optional('const', modifier)) {
|
| modifierCount++;
|
| constModifier = modifier;
|
| if (modifierCount != allowedModifierCount) {
|
| - reportRecoverableError(
|
| - modifier, ErrorKind.ExtraneousModifier, {'modifier': modifier});
|
| + reportRecoverableErrorCodeWithToken(modifier, codeExtraneousModifier);
|
| }
|
| } else {
|
| - reportRecoverableError(
|
| - modifier, ErrorKind.ExtraneousModifier, {'modifier': modifier});
|
| + reportRecoverableErrorCodeWithToken(modifier, codeExtraneousModifier);
|
| }
|
| }
|
| if (getOrSet != null && constModifier != null) {
|
| - reportRecoverableError(constModifier, ErrorKind.ExtraneousModifier,
|
| - {'modifier': constModifier});
|
| + reportRecoverableErrorCodeWithToken(
|
| + constModifier, codeExtraneousModifier);
|
| }
|
| parseModifierList(modifiers);
|
|
|
| @@ -1875,8 +1923,8 @@ class Parser {
|
| if (optional('operator', name)) {
|
| token = parseOperatorName(name);
|
| if (staticModifier != null) {
|
| - reportRecoverableError(staticModifier, ErrorKind.ExtraneousModifier,
|
| - {'modifier': staticModifier});
|
| + reportRecoverableErrorCodeWithToken(
|
| + staticModifier, codeExtraneousModifier);
|
| }
|
| } else {
|
| token = parseIdentifier(name, IdentifierContext.methodDeclaration);
|
| @@ -1895,7 +1943,7 @@ class Parser {
|
| Token asyncToken = token;
|
| token = parseAsyncModifier(token);
|
| if (getOrSet != null && !inPlainSync && optional("set", getOrSet)) {
|
| - reportRecoverableError(asyncToken, ErrorKind.SetterNotSync);
|
| + reportRecoverableErrorCode(asyncToken, codeSetterNotSync);
|
| }
|
| if (optional('=', token)) {
|
| token = parseRedirectingFactoryBody(token);
|
| @@ -1929,7 +1977,7 @@ class Parser {
|
| Token asyncToken = token;
|
| token = parseAsyncModifier(token);
|
| if (!inPlainSync) {
|
| - reportRecoverableError(asyncToken, ErrorKind.FactoryNotSync);
|
| + reportRecoverableErrorCode(asyncToken, codeFactoryNotSync);
|
| }
|
| if (optional('=', token)) {
|
| token = parseRedirectingFactoryBody(token);
|
| @@ -2081,7 +2129,7 @@ class Parser {
|
| String value = token.stringValue;
|
| if (identical(value, ';')) {
|
| if (!allowAbstract) {
|
| - reportRecoverableError(token, ErrorKind.ExpectedBody);
|
| + reportRecoverableErrorCode(token, codeExpectedBody);
|
| }
|
| listener.handleNoFunctionBody(token);
|
| } else {
|
| @@ -2090,7 +2138,7 @@ class Parser {
|
| expectSemicolon(token);
|
| listener.handleFunctionBodySkipped(token, true);
|
| } else if (identical(value, '=')) {
|
| - reportRecoverableError(token, ErrorKind.ExpectedBody);
|
| + reportRecoverableErrorCode(token, codeExpectedBody);
|
| token = parseExpression(token.next);
|
| expectSemicolon(token);
|
| listener.handleFunctionBodySkipped(token, true);
|
| @@ -2105,7 +2153,7 @@ class Parser {
|
| Token parseFunctionBody(Token token, bool isExpression, bool allowAbstract) {
|
| if (optional(';', token)) {
|
| if (!allowAbstract) {
|
| - reportRecoverableError(token, ErrorKind.ExpectedBody);
|
| + reportRecoverableErrorCode(token, codeExpectedBody);
|
| }
|
| listener.handleEmptyFunctionBody(token);
|
| return token;
|
| @@ -2122,7 +2170,7 @@ class Parser {
|
| } else if (optional('=', token)) {
|
| Token begin = token;
|
| // Recover from a bad factory method.
|
| - reportRecoverableError(token, ErrorKind.ExpectedBody);
|
| + reportRecoverableErrorCode(token, codeExpectedBody);
|
| token = parseExpression(token.next);
|
| if (!isExpression) {
|
| expectSemicolon(token);
|
| @@ -2136,7 +2184,8 @@ class Parser {
|
| int statementCount = 0;
|
| if (!optional('{', token)) {
|
| token =
|
| - reportUnrecoverableError(token, ErrorKind.ExpectedFunctionBody)?.next;
|
| + reportUnrecoverableErrorCodeWithToken(token, codeExpectedFunctionBody)
|
| + .next;
|
| listener.handleInvalidFunctionBody(token);
|
| return token;
|
| }
|
| @@ -2194,14 +2243,14 @@ class Parser {
|
| star = token;
|
| token = token.next;
|
| } else {
|
| - reportRecoverableError(async, ErrorKind.InvalidSyncModifier);
|
| + reportRecoverableErrorCode(async, codeInvalidSyncModifier);
|
| }
|
| }
|
| listener.handleAsyncModifier(async, star);
|
| if (inGenerator && optional('=>', token)) {
|
| - reportRecoverableError(token, ErrorKind.GeneratorReturnsValue);
|
| + reportRecoverableErrorCode(token, codeGeneratorReturnsValue);
|
| } else if (!inPlainSync && optional(';', token)) {
|
| - reportRecoverableError(token, ErrorKind.AbstractNotSync);
|
| + reportRecoverableErrorCode(token, codeAbstractNotSync);
|
| }
|
| return token;
|
| }
|
| @@ -2212,7 +2261,7 @@ class Parser {
|
| // This happens for degenerate programs, for example, a lot of nested
|
| // if-statements. The language test deep_nesting2_negative_test, for
|
| // example, provokes this.
|
| - return reportUnrecoverableError(token, ErrorKind.StackOverflow)?.next;
|
| + return reportUnrecoverableErrorCode(token, codeStackOverflow).next;
|
| }
|
| Token result = parseStatementX(token);
|
| statementDepth--;
|
| @@ -2233,7 +2282,7 @@ class Parser {
|
| return parseIfStatement(token);
|
| } else if (identical(value, 'await') && optional('for', token.next)) {
|
| if (!inAsync) {
|
| - reportRecoverableError(token, ErrorKind.AwaitForNotAsync);
|
| + reportRecoverableErrorCode(token, codeAwaitForNotAsync);
|
| }
|
| return parseForStatement(token, token.next);
|
| } else if (identical(value, 'for')) {
|
| @@ -2271,7 +2320,7 @@ class Parser {
|
| return parseYieldStatement(token);
|
|
|
| case AsyncModifier.Async:
|
| - reportRecoverableError(token, ErrorKind.YieldNotGenerator);
|
| + reportRecoverableErrorCode(token, codeYieldNotGenerator);
|
| return parseYieldStatement(token);
|
| }
|
| throw "Internal error: Unknown asyncState: '$asyncState'.";
|
| @@ -2309,7 +2358,7 @@ class Parser {
|
| } else {
|
| token = parseExpression(token);
|
| if (inGenerator) {
|
| - reportRecoverableError(begin.next, ErrorKind.GeneratorReturnsValue);
|
| + reportRecoverableErrorCode(begin.next, codeGeneratorReturnsValue);
|
| }
|
| listener.endReturnStatement(true, begin, token);
|
| }
|
| @@ -2534,7 +2583,7 @@ class Parser {
|
| BeginGroupToken begin = token;
|
| token = (begin.endGroup != null) ? begin.endGroup : token;
|
| } else if (token is ErrorToken) {
|
| - reportErrorToken(token, false)?.next;
|
| + reportErrorToken(token, false).next;
|
| }
|
| token = token.next;
|
| }
|
| @@ -2549,7 +2598,7 @@ class Parser {
|
| // This happens in degenerate programs, for example, with a lot of nested
|
| // list literals. This is provoked by, for examaple, the language test
|
| // deep_nesting1_negative_test.
|
| - return reportUnrecoverableError(token, ErrorKind.StackOverflow)?.next;
|
| + return reportUnrecoverableErrorCode(token, codeStackOverflow).next;
|
| }
|
| listener.beginExpression(token);
|
| Token result = optional('throw', token)
|
| @@ -2617,8 +2666,7 @@ class Parser {
|
| listener.handleUnaryPostfixAssignmentExpression(token);
|
| token = token.next;
|
| } else {
|
| - token = reportUnrecoverableError(token, ErrorKind.UnexpectedToken)
|
| - ?.next;
|
| + token = reportUnexpectedToken(token).next;
|
| }
|
| } else if (identical(info, IS_INFO)) {
|
| token = parseIsOperatorRest(token);
|
| @@ -2658,7 +2706,7 @@ class Parser {
|
| token = parseSend(token, IdentifierContext.expressionContinuation);
|
| listener.handleBinaryExpression(cascadeOperator);
|
| } else {
|
| - return reportUnrecoverableError(token, ErrorKind.UnexpectedToken)?.next;
|
| + return reportUnexpectedToken(token).next;
|
| }
|
| Token mark;
|
| do {
|
| @@ -2691,7 +2739,7 @@ class Parser {
|
| }
|
| } else if (identical(value, '+')) {
|
| // Dart no longer allows prefix-plus.
|
| - reportRecoverableError(token, ErrorKind.UnsupportedPrefixPlus);
|
| + reportRecoverableErrorCode(token, codeUnsupportedPrefixPlus);
|
| return parseUnaryExpression(token.next, allowCascades);
|
| } else if ((identical(value, '!')) ||
|
| (identical(value, '-')) ||
|
| @@ -2791,7 +2839,8 @@ class Parser {
|
| }
|
|
|
| Token expressionExpected(Token token) {
|
| - token = reportUnrecoverableError(token, ErrorKind.ExpectedExpression)?.next;
|
| + token = reportUnrecoverableErrorCodeWithToken(token, codeExpectedExpression)
|
| + .next;
|
| listener.handleInvalidExpression(token);
|
| return token;
|
| }
|
| @@ -2826,7 +2875,7 @@ class Parser {
|
| // [begin] is now known to have type [BeginGroupToken].
|
| token = parseExpression(token);
|
| if (!identical(begin.endGroup, token)) {
|
| - reportUnrecoverableError(token, ErrorKind.UnexpectedToken)?.next;
|
| + reportUnexpectedToken(token).next;
|
| token = begin.endGroup;
|
| }
|
| listener.handleParenthesizedExpression(begin);
|
| @@ -2930,8 +2979,7 @@ class Parser {
|
| }
|
| // Fall through.
|
| }
|
| - reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
|
| - return null;
|
| + return reportUnexpectedToken(token).next;
|
| }
|
|
|
| /// genericListLiteral | genericMapLiteral | genericFunctionLiteral.
|
| @@ -2958,8 +3006,7 @@ class Parser {
|
| } else if ((optional('[', token)) || (optional('[]', token))) {
|
| return parseLiteralListSuffix(token, constKeyword);
|
| }
|
| - reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
|
| - return null;
|
| + return reportUnexpectedToken(token).next;
|
| }
|
| }
|
|
|
| @@ -3015,7 +3062,7 @@ class Parser {
|
| token = parseArguments(token);
|
| } else {
|
| listener.handleNoArguments(token);
|
| - token = reportUnrecoverableError(token, ErrorKind.UnexpectedToken)?.next;
|
| + token = reportUnexpectedToken(token).next;
|
| }
|
| return token;
|
| }
|
| @@ -3220,7 +3267,7 @@ class Parser {
|
| if (identical(value, 'is') || identical(value, 'as')) {
|
| // The is- and as-operators cannot be chained, but they can take part of
|
| // expressions like: foo is Foo || foo is Bar.
|
| - reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
|
| + reportUnexpectedToken(token);
|
| }
|
| return token;
|
| }
|
| @@ -3233,7 +3280,7 @@ class Parser {
|
| String value = token.stringValue;
|
| if (identical(value, 'is') || identical(value, 'as')) {
|
| // The is- and as-operators cannot be chained.
|
| - reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
|
| + reportUnexpectedToken(token);
|
| }
|
| return token;
|
| }
|
| @@ -3308,7 +3355,7 @@ class Parser {
|
| return parseForInRest(awaitToken, forKeyword, leftParenthesis, token);
|
| } else {
|
| if (awaitToken != null) {
|
| - reportRecoverableError(awaitToken, ErrorKind.InvalidAwaitFor);
|
| + reportRecoverableErrorCode(awaitToken, codeInvalidAwaitFor);
|
| }
|
| return parseForRest(forKeyword, leftParenthesis, token);
|
| }
|
| @@ -3421,7 +3468,7 @@ class Parser {
|
| listener.beginAwaitExpression(awaitToken);
|
| token = expect('await', token);
|
| if (!inAsync) {
|
| - reportRecoverableError(awaitToken, ErrorKind.AwaitNotAsync);
|
| + reportRecoverableErrorCode(awaitToken, codeAwaitNotAsync);
|
| }
|
| token = parsePrecedenceExpression(token, POSTFIX_PRECEDENCE, allowCascades);
|
| listener.endAwaitExpression(awaitToken, token);
|
| @@ -3489,7 +3536,7 @@ class Parser {
|
| listener.handleFinallyBlock(finallyKeyword);
|
| } else {
|
| if (catchCount == 0) {
|
| - reportRecoverableError(tryKeyword, ErrorKind.OnlyTry);
|
| + reportRecoverableErrorCode(tryKeyword, codeOnlyTry);
|
| }
|
| }
|
| listener.endTryStatement(catchCount, tryKeyword, finallyKeyword);
|
| @@ -3568,8 +3615,8 @@ class Parser {
|
| } else {
|
| if (expressionCount == 0) {
|
| // TODO(ahe): This is probably easy to recover from.
|
| - reportUnrecoverableError(
|
| - token, ErrorKind.ExpectedButGot, {"expected": "case"});
|
| + reportUnrecoverableErrorCodeWithString(
|
| + token, codeExpectedButGot, "case");
|
| }
|
| break;
|
| }
|
| @@ -3650,65 +3697,102 @@ class Parser {
|
|
|
| /// 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.
|
| - Token reportUnrecoverableError(Token token, ErrorKind kind, [Map arguments]) {
|
| + Token reportUnrecoverableError(Token token, FastaMessage format()) {
|
| Token next;
|
| if (token is ErrorToken) {
|
| next = reportErrorToken(token, false);
|
| } else {
|
| - arguments ??= {};
|
| - arguments.putIfAbsent("actual", () => token.lexeme);
|
| - next = listener.handleUnrecoverableError(token, kind, arguments);
|
| + next = listener.handleUnrecoverableError(token, format());
|
| }
|
| return next ?? skipToEof(token);
|
| }
|
|
|
| - void reportRecoverableError(Token token, ErrorKind kind, [Map arguments]) {
|
| + void reportRecoverableError(Token token, FastaMessage format()) {
|
| if (token is ErrorToken) {
|
| reportErrorToken(token, true);
|
| } else {
|
| - arguments ??= {};
|
| - listener.handleRecoverableError(token, kind, arguments);
|
| + listener.handleRecoverableError(token, format());
|
| }
|
| }
|
|
|
| Token reportErrorToken(ErrorToken token, bool isRecoverable) {
|
| - ErrorKind kind = token.errorCode;
|
| - Map arguments = const {};
|
| - switch (kind) {
|
| - case ErrorKind.AsciiControlCharacter:
|
| - case ErrorKind.NonAsciiIdentifier:
|
| - case ErrorKind.NonAsciiWhitespace:
|
| - case ErrorKind.Encoding:
|
| - String hex = token.character.toRadixString(16);
|
| - if (hex.length < 4) {
|
| - String padding = "0000".substring(hex.length);
|
| - hex = "$padding$hex";
|
| - }
|
| - arguments = {'characterHex': hex};
|
| - break;
|
| -
|
| - case ErrorKind.UnterminatedString:
|
| - arguments = {'quote': token.start};
|
| - break;
|
| -
|
| - case ErrorKind.UnmatchedToken:
|
| - String begin = token.begin.lexeme;
|
| - String end = closeBraceFor(begin);
|
| - arguments = {'begin': begin, 'end': end};
|
| - break;
|
| -
|
| - case ErrorKind.Unspecified:
|
| - arguments = {"text": token.assertionMessage};
|
| - break;
|
| -
|
| - default:
|
| - break;
|
| + FastaCode code = token.errorCode;
|
| + FastaMessage message;
|
| + if (code == codeAsciiControlCharacter) {
|
| + message = codeAsciiControlCharacter.format(
|
| + uri, token.charOffset, token.character);
|
| + } else if (code == codeNonAsciiWhitespace) {
|
| + message =
|
| + codeNonAsciiWhitespace.format(uri, token.charOffset, token.character);
|
| + } else if (code == codeEncoding) {
|
| + message = codeEncoding.format(uri, token.charOffset);
|
| + } else if (code == codeNonAsciiIdentifier) {
|
| + message = codeNonAsciiIdentifier.format(uri, token.charOffset,
|
| + new String.fromCharCodes([token.character]), token.character);
|
| + } else if (code == codeUnterminatedString) {
|
| + message =
|
| + codeUnterminatedString.format(uri, token.charOffset, token.start);
|
| + } else if (code == codeUnmatchedToken) {
|
| + Token begin = token.begin;
|
| + message = codeUnmatchedToken.format(
|
| + uri, token.charOffset, closeBraceFor(begin.lexeme), begin);
|
| + } else if (code == codeUnspecified) {
|
| + message =
|
| + codeUnspecified.format(uri, token.charOffset, token.assertionMessage);
|
| + } else {
|
| + message = code.format(uri, token.charOffset);
|
| }
|
| if (isRecoverable) {
|
| - listener.handleRecoverableError(token, kind, arguments);
|
| + listener.handleRecoverableError(token, message);
|
| return null;
|
| } else {
|
| - return listener.handleUnrecoverableError(token, kind, arguments);
|
| + Token next = listener.handleUnrecoverableError(token, message);
|
| + return next ?? skipToEof(token);
|
| }
|
| }
|
| +
|
| + Token reportUnmatchedToken(BeginGroupToken token) {
|
| + return reportUnrecoverableError(
|
| + token,
|
| + () => codeUnmatchedToken.format(
|
| + uri, token.charOffset, closeBraceFor(token.lexeme), token));
|
| + }
|
| +
|
| + Token reportUnexpectedToken(Token token) {
|
| + return reportUnrecoverableError(
|
| + token, () => codeUnexpectedToken.format(uri, token.charOffset, token));
|
| + }
|
| +
|
| + void reportRecoverableErrorCode(Token token, FastaCode<NoArgument> code) {
|
| + reportRecoverableError(token, () => code.format(uri, token.charOffset));
|
| + }
|
| +
|
| + Token reportUnrecoverableErrorCode(Token token, FastaCode<NoArgument> code) {
|
| + return reportUnrecoverableError(
|
| + token, () => code.format(uri, token.charOffset));
|
| + }
|
| +
|
| + void reportRecoverableErrorCodeWithToken(
|
| + Token token, FastaCode<TokenArgument> code) {
|
| + reportRecoverableError(
|
| + token, () => code.format(uri, token.charOffset, token));
|
| + }
|
| +
|
| + Token reportUnrecoverableErrorCodeWithToken(
|
| + Token token, FastaCode<TokenArgument> code) {
|
| + return reportUnrecoverableError(
|
| + token, () => code.format(uri, token.charOffset, token));
|
| + }
|
| +
|
| + Token reportUnrecoverableErrorCodeWithString(
|
| + Token token, FastaCode<StringArgument> code, String string) {
|
| + return reportUnrecoverableError(
|
| + token, () => code.format(uri, token.charOffset, string));
|
| + }
|
| }
|
| +
|
| +typedef FastaMessage NoArgument(Uri uri, int charOffset);
|
| +
|
| +typedef FastaMessage TokenArgument(Uri uri, int charOffset, Token token);
|
| +
|
| +typedef FastaMessage StringArgument(Uri uri, int charOffset, String string);
|
|
|