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 7d7f6513d61e5a2b12ddfb7d97c65cb5d6341256..f95b1edd485c2545dcf0ce01db269d3c473939b8 100644 |
--- a/pkg/front_end/lib/src/fasta/parser/parser.dart |
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart |
@@ -10,6 +10,8 @@ import '../fasta_codes.dart' |
FastaMessage, |
codeAbstractNotSync, |
codeAsciiControlCharacter, |
+ codeAssertAsExpression, |
+ codeAssertExtraneousArgument, |
codeAsyncAsIdentifier, |
codeAwaitAsIdentifier, |
codeAwaitForNotAsync, |
@@ -158,6 +160,17 @@ enum MemberKind { |
TopLevelField, |
} |
+/// Syntactic forms of `assert`. |
+/// |
+/// An assertion can legally occur as a statement. However, assertions are also |
+/// experimentally allowed in initializers. For improved error recovery, we |
+/// also attempt to parse asserts as expressions. |
+enum Assert { |
+ Expression, |
+ Initializer, |
+ Statement, |
+} |
+ |
/// An event generating parser of Dart programs. This parser expects all tokens |
/// in a linked list (aka a token stream). |
/// |
@@ -1561,10 +1574,7 @@ class Parser { |
bool old = mayParseFunctionExpressions; |
mayParseFunctionExpressions = false; |
do { |
- token = token.next; |
- listener.beginInitializer(token); |
- token = parseExpression(token); |
- listener.endInitializer(token); |
+ token = parseInitializer(token.next); |
++count; |
} while (optional(',', token)); |
mayParseFunctionExpressions = old; |
@@ -1572,12 +1582,24 @@ class Parser { |
return token; |
} |
+ Token parseInitializer(Token token) { |
+ listener.beginInitializer(token); |
+ if (optional('assert', token)) { |
+ token = parseAssert(token, Assert.Initializer); |
+ } else { |
+ token = parseExpression(token); |
+ } |
+ listener.endInitializer(token); |
+ return token; |
+ } |
+ |
Token parseLiteralStringOrRecoverExpression(Token token) { |
if (identical(token.kind, STRING_TOKEN)) { |
return parseLiteralString(token); |
} else { |
reportRecoverableErrorCodeWithToken(token, codeExpectedString); |
- return parseRecoverExpression(token); |
+ return parseRecoverExpression( |
+ token, codeExpectedString.format(uri, token.charOffset, token)); |
} |
} |
@@ -2686,7 +2708,8 @@ class Parser { |
return token; |
} |
- Token parseRecoverExpression(Token token) => parseExpression(token); |
+ Token parseRecoverExpression(Token token, FastaMessage message) => |
+ parseExpression(token); |
int expressionDepth = 0; |
Token parseExpression(Token token) { |
@@ -2915,6 +2938,8 @@ class Parser { |
} else if (!inPlainSync && |
(identical(value, "yield") || identical(value, "async"))) { |
return expressionExpected(token); |
+ } else if (identical(value, "assert")) { |
+ return parseAssert(token, Assert.Expression); |
} else if (token.isIdentifier) { |
return parseSendOrFunctionLiteral(token, context); |
} else { |
@@ -3773,7 +3798,8 @@ class Parser { |
return expectSemicolon(token); |
} |
- Token parseAssertStatement(Token token) { |
+ Token parseAssert(Token token, Assert kind) { |
+ listener.beginAssert(token, kind); |
Token assertKeyword = token; |
Token commaToken = null; |
token = expect('assert', token); |
@@ -3787,11 +3813,30 @@ class Parser { |
token = token.next; |
token = parseExpression(token); |
} |
+ if (optional(',', token)) { |
+ Token firstExtra = token.next; |
+ while (optional(',', token)) { |
+ token = token.next; |
+ Token begin = token; |
+ token = parseExpression(token); |
+ listener.handleExtraneousExpression( |
+ begin, codeAssertExtraneousArgument.format(uri, token.charOffset)); |
+ } |
+ reportRecoverableErrorCode(firstExtra, codeAssertExtraneousArgument); |
+ } |
Token rightParenthesis = token; |
token = expect(')', token); |
mayParseFunctionExpressions = old; |
- listener.handleAssertStatement( |
- assertKeyword, leftParenthesis, commaToken, rightParenthesis, token); |
+ listener.endAssert(assertKeyword, kind, leftParenthesis, commaToken, |
+ rightParenthesis, token); |
+ if (kind == Assert.Expression) { |
+ reportRecoverableErrorCode(assertKeyword, codeAssertAsExpression); |
+ } |
+ return token; |
+ } |
+ |
+ Token parseAssertStatement(Token token) { |
+ token = parseAssert(token, Assert.Statement); |
return expectSemicolon(token); |
} |