@@ -1654,7 +1654,7 @@ class Parser {
16541654
16551655 Token skipBlock (Token token) {
16561656 // The scanner ensures that `{` always has a closing `}`.
1657- return ensureBlock (token, null ).endGroup;
1657+ return ensureBlock (token, null , null ).endGroup;
16581658 }
16591659
16601660 /// ```
@@ -1713,7 +1713,8 @@ class Parser {
17131713 }
17141714 }
17151715 } else {
1716- leftBrace = ensureBlock (token, fasta.templateExpectedEnumBody);
1716+ // TODO(danrubel): merge this error message with missing class/mixin body
1717+ leftBrace = ensureBlock (token, fasta.templateExpectedEnumBody, null );
17171718 token = leftBrace.endGroup;
17181719 }
17191720 assert (optional ('}' , token));
@@ -1772,7 +1773,7 @@ class Parser {
17721773 if (! optional ('{' , token.next)) {
17731774 // Recovery
17741775 token = parseClassHeaderRecovery (start, begin, classKeyword);
1775- ensureBlock (token, fasta.templateExpectedClassOrMixinBody );
1776+ ensureBlock (token, null , 'class declaration' );
17761777 }
17771778 token = parseClassOrMixinBody (token);
17781779 listener.endClassDeclaration (begin, token);
@@ -1938,7 +1939,7 @@ class Parser {
19381939 if (! optional ('{' , token.next)) {
19391940 // Recovery
19401941 token = parseMixinHeaderRecovery (token, mixinKeyword, headerStart);
1941- ensureBlock (token, fasta.templateExpectedClassOrMixinBody );
1942+ ensureBlock (token, null , 'mixin declaration' );
19421943 }
19431944 token = parseClassOrMixinBody (token);
19441945 listener.endMixinDeclaration (mixinKeyword, token);
@@ -2078,8 +2079,7 @@ class Parser {
20782079 TypeInfo typeInfo = computeType (onKeyword, true );
20792080 token = typeInfo.ensureTypeNotVoid (onKeyword, this );
20802081 if (! optional ('{' , token.next)) {
2081- // TODO(danrubel): replace this with a better error message.
2082- ensureBlock (token, fasta.templateExpectedClassOrMixinBody);
2082+ ensureBlock (token, null , 'extension declaration' );
20832083 }
20842084 // TODO(danrubel): Do not allow fields or constructors
20852085 token = parseClassOrMixinBody (token);
@@ -2701,17 +2701,28 @@ class Parser {
27012701 }
27022702
27032703 /// If the next token is an opening curly brace, return it. Otherwise, use the
2704- /// given [template] to report an error, insert an opening and a closing curly
2705- /// brace, and return the newly inserted opening curly brace. If the
2706- /// [template] is `null` , use a default error message instead.
2707- Token ensureBlock (
2708- Token token, Template <Message Function (Token token)> template) {
2704+ /// given [template] or [blockKind] to report an error, insert an opening and
2705+ /// a closing curly brace, and return the newly inserted opening curly brace.
2706+ /// If [template] and [blockKind] are `null` , then use
2707+ /// a default error message instead.
2708+ Token ensureBlock (Token token,
2709+ Template <Message Function (Token token)> template, String blockKind) {
27092710 Token next = token.next;
27102711 if (optional ('{' , next)) return next;
2711- Message message = template == null
2712- ? fasta.templateExpectedButGot.withArguments ('{' )
2713- : template.withArguments (next);
2714- reportRecoverableError (next, message);
2712+ if (template == null ) {
2713+ if (blockKind == null ) {
2714+ // TODO(danrubel): rename ExpectedButGot to ExpectedBefore
2715+ reportRecoverableError (
2716+ next, fasta.templateExpectedButGot.withArguments ('{' ));
2717+ } else {
2718+ // TODO(danrubel): rename ExpectedClassOrMixinBody
2719+ // to ExpectedDeclarationOrClauseBody
2720+ reportRecoverableError (token,
2721+ fasta.templateExpectedClassOrMixinBody.withArguments (blockKind));
2722+ }
2723+ } else {
2724+ reportRecoverableError (next, template.withArguments (next));
2725+ }
27152726 return insertBlock (token);
27162727 }
27172728
@@ -2842,7 +2853,7 @@ class Parser {
28422853
28432854 Token skipClassOrMixinBody (Token token) {
28442855 // The scanner ensures that `{` always has a closing `}`.
2845- return ensureBlock (token, fasta.templateExpectedClassOrMixinBody );
2856+ return ensureBlock (token, null , null );
28462857 }
28472858
28482859 /// ```
@@ -3556,7 +3567,7 @@ class Parser {
35563567 begin = next = token.next;
35573568 // Fall through to parse the block.
35583569 } else {
3559- token = ensureBlock (token, fasta.templateExpectedFunctionBody);
3570+ token = ensureBlock (token, fasta.templateExpectedFunctionBody, null );
35603571 listener.handleInvalidFunctionBody (token);
35613572 return token.endGroup;
35623573 }
@@ -3678,7 +3689,8 @@ class Parser {
36783689 }
36793690 final value = token.next.stringValue;
36803691 if (identical (value, '{' )) {
3681- return parseBlock (token);
3692+ // The scanner ensures that `{` always has a closing `}`.
3693+ return parseBlock (token, null );
36823694 } else if (identical (value, 'return' )) {
36833695 return parseReturnStatement (token);
36843696 } else if (identical (value, 'var' ) || identical (value, 'final' )) {
@@ -5631,8 +5643,8 @@ class Parser {
56315643 /// '{' statement* '}'
56325644 /// ;
56335645 /// ```
5634- Token parseBlock (Token token) {
5635- Token begin = token = ensureBlock (token, null );
5646+ Token parseBlock (Token token, String blockKind ) {
5647+ Token begin = token = ensureBlock (token, null , blockKind );
56365648 listener.beginBlock (begin);
56375649 int statementCount = 0 ;
56385650 Token startToken = token.next;
@@ -5661,7 +5673,8 @@ class Parser {
56615673 // because an error has already been reported by the caller.
56625674 Listener originalListener = listener;
56635675 listener = new ForwardingListener (listener)..forwardErrors = false ;
5664- token = parseBlock (token);
5676+ // The scanner ensures that `{` always has a closing `}`.
5677+ token = parseBlock (token, null );
56655678 listener = originalListener;
56665679 listener.handleInvalidTopLevelBlock (begin);
56675680 return token;
@@ -5776,7 +5789,8 @@ class Parser {
57765789 Token tryKeyword = token.next;
57775790 assert (optional ('try' , tryKeyword));
57785791 listener.beginTryStatement (tryKeyword);
5779- Token lastConsumed = parseBlock (tryKeyword);
5792+ // TODO(danrubel): pass 'try statement' for blockKind and update tests
5793+ Token lastConsumed = parseBlock (tryKeyword, null );
57805794 token = lastConsumed.next;
57815795 int catchCount = 0 ;
57825796
@@ -5871,7 +5885,8 @@ class Parser {
58715885 token = lastConsumed.next;
58725886 }
58735887 listener.endCatchClause (token);
5874- lastConsumed = parseBlock (lastConsumed);
5888+ // TODO(danrubel): pass 'catch clause' for blockKind and update tests
5889+ lastConsumed = parseBlock (lastConsumed, null );
58755890 token = lastConsumed.next;
58765891 ++ catchCount;
58775892 listener.handleCatchBlock (onKeyword, catchKeyword, comma);
@@ -5881,7 +5896,8 @@ class Parser {
58815896 Token finallyKeyword = null ;
58825897 if (optional ('finally' , token)) {
58835898 finallyKeyword = token;
5884- lastConsumed = parseBlock (token);
5899+ // TODO(danrubel): pass 'finally clause' for blockKind and update tests
5900+ lastConsumed = parseBlock (token, null );
58855901 token = lastConsumed.next;
58865902 listener.handleFinallyBlock (finallyKeyword);
58875903 } else {
@@ -5919,7 +5935,8 @@ class Parser {
59195935 /// ;
59205936 /// ```
59215937 Token parseSwitchBlock (Token token) {
5922- Token beginSwitch = token = ensureBlock (token, null );
5938+ // TODO(danrubel): pass 'switch statement' for blockKind and update tests
5939+ Token beginSwitch = token = ensureBlock (token, null , null );
59235940 listener.beginSwitchBlock (beginSwitch);
59245941 int caseCount = 0 ;
59255942 Token defaultKeyword = null ;
0 commit comments