Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(61)

Side by Side Diff: pkg/analyzer/lib/src/generated/parser.dart

Issue 2041723008: Rework the parser to improve performance (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: clean-up Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | pkg/analyzer/test/generated/parser_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library analyzer.src.generated.parser; 5 library analyzer.src.generated.parser;
6 6
7 import 'dart:collection'; 7 import 'dart:collection';
8 import "dart:math" as math; 8 import "dart:math" as math;
9 9
10 import 'package:analyzer/dart/ast/ast.dart'; 10 import 'package:analyzer/dart/ast/ast.dart';
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after
209 'parseCompilationUnitMember_1': new MethodTrampoline( 209 'parseCompilationUnitMember_1': new MethodTrampoline(
210 1, (Parser target, arg0) => target._parseCompilationUnitMember(arg0)), 210 1, (Parser target, arg0) => target._parseCompilationUnitMember(arg0)),
211 'parseConfiguration_0': 211 'parseConfiguration_0':
212 new MethodTrampoline(0, (Parser target) => target._parseConfiguration()), 212 new MethodTrampoline(0, (Parser target) => target._parseConfiguration()),
213 'parseConstExpression_0': new MethodTrampoline( 213 'parseConstExpression_0': new MethodTrampoline(
214 0, (Parser target) => target._parseConstExpression()), 214 0, (Parser target) => target._parseConstExpression()),
215 'parseConstructor_8': new MethodTrampoline( 215 'parseConstructor_8': new MethodTrampoline(
216 8, 216 8,
217 (Parser target, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) => target 217 (Parser target, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) => target
218 ._parseConstructor(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)), 218 ._parseConstructor(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)),
219 'parseConstructorFieldInitializer_0': new MethodTrampoline( 219 'parseConstructorFieldInitializer_1': new MethodTrampoline(1,
220 0, (Parser target) => target._parseConstructorFieldInitializer()), 220 (Parser target, arg0) => target._parseConstructorFieldInitializer(arg0)),
221 'parseContinueStatement_0': new MethodTrampoline( 221 'parseContinueStatement_0': new MethodTrampoline(
222 0, (Parser target) => target._parseContinueStatement()), 222 0, (Parser target) => target._parseContinueStatement()),
223 'parseDirective_1': new MethodTrampoline( 223 'parseDirective_1': new MethodTrampoline(
224 1, (Parser target, arg0) => target._parseDirective(arg0)), 224 1, (Parser target, arg0) => target._parseDirective(arg0)),
225 'parseDirectives_0': 225 'parseDirectives_0':
226 new MethodTrampoline(0, (Parser target) => target._parseDirectives()), 226 new MethodTrampoline(0, (Parser target) => target._parseDirectives()),
227 'parseDocumentationComment_0': new MethodTrampoline( 227 'parseDocumentationComment_0': new MethodTrampoline(0, (Parser target) {
228 0, (Parser target) => target._parseDocumentationComment()), 228 List<DocumentationCommentToken> tokens =
229 target._parseDocumentationCommentTokens();
230 return target._parseDocumentationComment(tokens);
231 }),
229 'parseDoStatement_0': 232 'parseDoStatement_0':
230 new MethodTrampoline(0, (Parser target) => target._parseDoStatement()), 233 new MethodTrampoline(0, (Parser target) => target._parseDoStatement()),
231 'parseDottedName_0': 234 'parseDottedName_0':
232 new MethodTrampoline(0, (Parser target) => target._parseDottedName()), 235 new MethodTrampoline(0, (Parser target) => target._parseDottedName()),
233 'parseEmptyStatement_0': 236 'parseEmptyStatement_0':
234 new MethodTrampoline(0, (Parser target) => target._parseEmptyStatement()), 237 new MethodTrampoline(0, (Parser target) => target._parseEmptyStatement()),
235 'parseEnumConstantDeclaration_0': new MethodTrampoline( 238 'parseEnumConstantDeclaration_0': new MethodTrampoline(
236 0, (Parser target) => target._parseEnumConstantDeclaration()), 239 0, (Parser target) => target._parseEnumConstantDeclaration()),
237 'parseEnumDeclaration_1': new MethodTrampoline( 240 'parseEnumDeclaration_1': new MethodTrampoline(
238 1, (Parser target, arg0) => target._parseEnumDeclaration(arg0)), 241 1, (Parser target, arg0) => target._parseEnumDeclaration(arg0)),
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
313 new MethodTrampoline(0, (Parser target) => target._parseNewExpression()), 316 new MethodTrampoline(0, (Parser target) => target._parseNewExpression()),
314 'parseNonLabeledStatement_0': new MethodTrampoline( 317 'parseNonLabeledStatement_0': new MethodTrampoline(
315 0, (Parser target) => target._parseNonLabeledStatement()), 318 0, (Parser target) => target._parseNonLabeledStatement()),
316 'parseOperator_3': new MethodTrampoline( 319 'parseOperator_3': new MethodTrampoline(
317 3, 320 3,
318 (Parser target, arg0, arg1, arg2) => 321 (Parser target, arg0, arg1, arg2) =>
319 target._parseOperator(arg0, arg1, arg2)), 322 target._parseOperator(arg0, arg1, arg2)),
320 'parseOptionalReturnType_0': new MethodTrampoline( 323 'parseOptionalReturnType_0': new MethodTrampoline(
321 0, (Parser target) => target._parseOptionalReturnType()), 324 0, (Parser target) => target._parseOptionalReturnType()),
322 'parsePartDirective_1': new MethodTrampoline( 325 'parsePartDirective_1': new MethodTrampoline(
323 1, (Parser target, arg0) => target._parsePartDirective(arg0)), 326 1, (Parser target, arg0) => target._parsePartOrPartOfDirective(arg0)),
324 'parsePostfixExpression_0': new MethodTrampoline( 327 'parsePostfixExpression_0': new MethodTrampoline(
325 0, (Parser target) => target._parsePostfixExpression()), 328 0, (Parser target) => target._parsePostfixExpression()),
326 'parsePrimaryExpression_0': new MethodTrampoline( 329 'parsePrimaryExpression_0': new MethodTrampoline(
327 0, (Parser target) => target._parsePrimaryExpression()), 330 0, (Parser target) => target._parsePrimaryExpression()),
328 'parseRedirectingConstructorInvocation_0': new MethodTrampoline( 331 'parseRedirectingConstructorInvocation_1': new MethodTrampoline(
329 0, (Parser target) => target._parseRedirectingConstructorInvocation()), 332 1,
333 (Parser target, arg0) =>
334 target._parseRedirectingConstructorInvocation(arg0)),
330 'parseRelationalExpression_0': new MethodTrampoline( 335 'parseRelationalExpression_0': new MethodTrampoline(
331 0, (Parser target) => target._parseRelationalExpression()), 336 0, (Parser target) => target._parseRelationalExpression()),
332 'parseRethrowExpression_0': new MethodTrampoline( 337 'parseRethrowExpression_0': new MethodTrampoline(
333 0, (Parser target) => target._parseRethrowExpression()), 338 0, (Parser target) => target._parseRethrowExpression()),
334 'parseReturnStatement_0': new MethodTrampoline( 339 'parseReturnStatement_0': new MethodTrampoline(
335 0, (Parser target) => target._parseReturnStatement()), 340 0, (Parser target) => target._parseReturnStatement()),
336 'parseSetter_4': new MethodTrampoline( 341 'parseSetter_4': new MethodTrampoline(
337 4, 342 4,
338 (Parser target, arg0, arg1, arg2, arg3) => 343 (Parser target, arg0, arg1, arg2, arg3) =>
339 target._parseSetter(arg0, arg1, arg2, arg3)), 344 target._parseSetter(arg0, arg1, arg2, arg3)),
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
486 /** 491 /**
487 * A simple data-holder for a method that needs to return multiple values. 492 * A simple data-holder for a method that needs to return multiple values.
488 */ 493 */
489 class CommentAndMetadata { 494 class CommentAndMetadata {
490 /** 495 /**
491 * The documentation comment that was parsed, or `null` if none was given. 496 * The documentation comment that was parsed, or `null` if none was given.
492 */ 497 */
493 final Comment comment; 498 final Comment comment;
494 499
495 /** 500 /**
496 * The metadata that was parsed. 501 * The metadata that was parsed, or `null` if none was given.
497 */ 502 */
498 final List<Annotation> metadata; 503 final List<Annotation> metadata;
499 504
500 /** 505 /**
501 * Initialize a newly created holder with the given [comment] and [metadata]. 506 * Initialize a newly created holder with the given [comment] and [metadata].
502 */ 507 */
503 CommentAndMetadata(this.comment, this.metadata); 508 CommentAndMetadata(this.comment, this.metadata);
509
510 /**
511 * Return `true` if some metadata was parsed.
512 */
513 bool get hasMetadata => metadata != null && metadata.isNotEmpty;
504 } 514 }
505 515
506 /** 516 /**
507 * A simple data-holder for a method that needs to return multiple values. 517 * A simple data-holder for a method that needs to return multiple values.
508 */ 518 */
509 class FinalConstVarOrType { 519 class FinalConstVarOrType {
510 /** 520 /**
511 * The 'final', 'const' or 'var' keyword, or `null` if none was given. 521 * The 'final', 'const' or 'var' keyword, or `null` if none was given.
512 */ 522 */
513 final Token keyword; 523 final Token keyword;
(...skipping 1626 matching lines...) Expand 10 before | Expand all | Expand 10 after
2140 Token _currentToken; 2150 Token _currentToken;
2141 2151
2142 /** 2152 /**
2143 * A flag indicating whether the parser is currently in a function body marked 2153 * A flag indicating whether the parser is currently in a function body marked
2144 * as being 'async'. 2154 * as being 'async'.
2145 */ 2155 */
2146 bool _inAsync = false; 2156 bool _inAsync = false;
2147 2157
2148 /** 2158 /**
2149 * A flag indicating whether the parser is currently in a function body marked 2159 * A flag indicating whether the parser is currently in a function body marked
2150 * as being 'async'. 2160 * (by a star) as being a generator.
2151 */ 2161 */
2152 bool _inGenerator = false; 2162 bool _inGenerator = false;
2153 2163
2154 /** 2164 /**
2155 * A flag indicating whether the parser is currently in the body of a loop. 2165 * A flag indicating whether the parser is currently in the body of a loop.
2156 */ 2166 */
2157 bool _inLoop = false; 2167 bool _inLoop = false;
2158 2168
2159 /** 2169 /**
2160 * A flag indicating whether the parser is currently in a switch statement. 2170 * A flag indicating whether the parser is currently in a switch statement.
2161 */ 2171 */
2162 bool _inSwitch = false; 2172 bool _inSwitch = false;
2163 2173
2164 /** 2174 /**
2165 * A flag indicating whether the parser is currently in a constructor field 2175 * A flag indicating whether the parser is currently in a constructor field
2166 * initializer, with no intervening parens, braces, or brackets. 2176 * initializer, with no intervening parentheses, braces, or brackets.
2167 */ 2177 */
2168 bool _inInitializer = false; 2178 bool _inInitializer = false;
2169 2179
2170 /** 2180 /**
2171 * A flag indicating whether the parser is to parse generic method syntax. 2181 * A flag indicating whether the parser is to parse generic method syntax.
2172 */ 2182 */
2173 bool parseGenericMethods = false; 2183 bool parseGenericMethods = false;
2174 2184
2175 /** 2185 /**
2176 * A flag indicating whether to parse generic method comments, of the form 2186 * A flag indicating whether to parse generic method comments, of the form
2177 * `/*=T*/` and `/*<T>*/`. 2187 * `/*=T*/` and `/*<T>*/`.
2178 */ 2188 */
2179 bool parseGenericMethodComments = false; 2189 bool parseGenericMethodComments = false;
2180 2190
2181 /** 2191 /**
2182 * Initialize a newly created parser to parse the content of the given 2192 * Initialize a newly created parser to parse tokens in the given [_source]
2183 * [_source] and to report any errors that are found to the given 2193 * and to report any errors that are found to the given [_errorListener].
2184 * [_errorListener].
2185 */ 2194 */
2186 Parser(this._source, this._errorListener); 2195 Parser(this._source, this._errorListener);
2187 2196
2188 void set currentToken(Token currentToken) { 2197 /**
2189 this._currentToken = currentToken; 2198 * Set the token with which the parse is to begin to the given [token].
2199 */
2200 void set currentToken(Token token) {
2201 this._currentToken = token;
2190 } 2202 }
2191 2203
2192 /** 2204 /**
2193 * Return `true` if the current token is the first token of a return type that 2205 * Return `true` if the current token is the first token of a return type that
2194 * is followed by an identifier, possibly followed by a list of type 2206 * is followed by an identifier, possibly followed by a list of type
2195 * parameters, followed by a left-parenthesis. This is used by 2207 * parameters, followed by a left-parenthesis. This is used by
2196 * [_parseTypeAlias] to determine whether or not to parse a return type. 2208 * [_parseTypeAlias] to determine whether or not to parse a return type.
2197 */ 2209 */
2210 @deprecated
2198 bool get hasReturnTypeInTypeAlias { 2211 bool get hasReturnTypeInTypeAlias {
2199 Token next = _skipReturnType(_currentToken); 2212 Token next = _skipReturnType(_currentToken);
2200 if (next == null) { 2213 if (next == null) {
2201 return false; 2214 return false;
2202 } 2215 }
2203 return _tokenMatchesIdentifier(next); 2216 return _tokenMatchesIdentifier(next);
2204 } 2217 }
2205 2218
2206 /** 2219 /**
2207 * Set whether the parser is to parse the async support. 2220 * Set whether the parser is to parse the async support.
(...skipping 14 matching lines...) Expand all
2222 void set parseFunctionBodies(bool parseFunctionBodies) { 2235 void set parseFunctionBodies(bool parseFunctionBodies) {
2223 this._parseFunctionBodies = parseFunctionBodies; 2236 this._parseFunctionBodies = parseFunctionBodies;
2224 } 2237 }
2225 2238
2226 /** 2239 /**
2227 * Advance to the next token in the token stream, making it the new current 2240 * Advance to the next token in the token stream, making it the new current
2228 * token and return the token that was current before this method was invoked. 2241 * token and return the token that was current before this method was invoked.
2229 */ 2242 */
2230 Token getAndAdvance() { 2243 Token getAndAdvance() {
2231 Token token = _currentToken; 2244 Token token = _currentToken;
2232 _advance(); 2245 _currentToken = _currentToken.next;
2233 return token; 2246 return token;
2234 } 2247 }
2235 2248
2236 /** 2249 /**
2237 * Parse an annotation. Return the annotation that was parsed. 2250 * Parse an annotation. Return the annotation that was parsed.
2238 * 2251 *
2252 * This method assumes that the current token matches [TokenType.AT].
2253 *
2239 * annotation ::= 2254 * annotation ::=
2240 * '@' qualified ('.' identifier)? arguments? 2255 * '@' qualified ('.' identifier)? arguments?
2241 *
2242 */ 2256 */
2243 Annotation parseAnnotation() { 2257 Annotation parseAnnotation() {
2244 Token atSign = _expect(TokenType.AT); 2258 Token atSign = getAndAdvance();
2245 Identifier name = parsePrefixedIdentifier(); 2259 Identifier name = parsePrefixedIdentifier();
2246 Token period = null; 2260 Token period = null;
2247 SimpleIdentifier constructorName = null; 2261 SimpleIdentifier constructorName = null;
2248 if (_matches(TokenType.PERIOD)) { 2262 if (_matches(TokenType.PERIOD)) {
2249 period = getAndAdvance(); 2263 period = getAndAdvance();
2250 constructorName = parseSimpleIdentifier(); 2264 constructorName = parseSimpleIdentifier();
2251 } 2265 }
2252 ArgumentList arguments = null; 2266 ArgumentList arguments = null;
2253 if (_matches(TokenType.OPEN_PAREN)) { 2267 if (_matches(TokenType.OPEN_PAREN)) {
2254 arguments = parseArgumentList(); 2268 arguments = parseArgumentList();
2255 } 2269 }
2256 return new Annotation(atSign, name, period, constructorName, arguments); 2270 return new Annotation(atSign, name, period, constructorName, arguments);
2257 } 2271 }
2258 2272
2259 /** 2273 /**
2260 * Parse an argument. Return the argument that was parsed. 2274 * Parse an argument. Return the argument that was parsed.
2261 * 2275 *
2262 * argument ::= 2276 * argument ::=
2263 * namedArgument 2277 * namedArgument
2264 * | expression 2278 * | expression
2265 * 2279 *
2266 * namedArgument ::= 2280 * namedArgument ::=
2267 * label expression 2281 * label expression
2268 */ 2282 */
2269 Expression parseArgument() { 2283 Expression parseArgument() {
2284 // TODO(brianwilkerson) Consider returning a wrapper indicating whether the
2285 // expression is a named expression in order to remove the 'is' check in
2286 // 'parseArgumentList'.
2270 // 2287 //
2271 // Both namedArgument and expression can start with an identifier, but only 2288 // Both namedArgument and expression can start with an identifier, but only
2272 // namedArgument can have an identifier followed by a colon. 2289 // namedArgument can have an identifier followed by a colon.
2273 // 2290 //
2274 if (_matchesIdentifier() && _tokenMatches(_peek(), TokenType.COLON)) { 2291 if (_matchesIdentifier() && _tokenMatches(_peek(), TokenType.COLON)) {
2275 return new NamedExpression(parseLabel(), parseExpression2()); 2292 return new NamedExpression(parseLabel(), parseExpression2());
2276 } else { 2293 } else {
2277 return parseExpression2(); 2294 return parseExpression2();
2278 } 2295 }
2279 } 2296 }
2280 2297
2281 /** 2298 /**
2282 * Parse a list of arguments. Return the argument list that was parsed. 2299 * Parse a list of arguments. Return the argument list that was parsed.
2283 * 2300 *
2301 * This method assumes that the current token matches [TokenType.OPEN_PAREN].
2302 *
2284 * arguments ::= 2303 * arguments ::=
2285 * '(' argumentList? ')' 2304 * '(' argumentList? ')'
2286 * 2305 *
2287 * argumentList ::= 2306 * argumentList ::=
2288 * namedArgument (',' namedArgument)* 2307 * namedArgument (',' namedArgument)*
2289 * | expressionList (',' namedArgument)* 2308 * | expressionList (',' namedArgument)*
2290 */ 2309 */
2291 ArgumentList parseArgumentList() { 2310 ArgumentList parseArgumentList() {
2292 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); 2311 Token leftParenthesis = getAndAdvance();
2293 List<Expression> arguments = new List<Expression>();
2294 if (_matches(TokenType.CLOSE_PAREN)) { 2312 if (_matches(TokenType.CLOSE_PAREN)) {
2295 return new ArgumentList(leftParenthesis, arguments, getAndAdvance()); 2313 return new ArgumentList(leftParenthesis, null, getAndAdvance());
2296 } 2314 }
2297 // 2315 //
2298 // Even though unnamed arguments must all appear before any named arguments, 2316 // Even though unnamed arguments must all appear before any named arguments,
2299 // we allow them to appear in any order so that we can recover faster. 2317 // we allow them to appear in any order so that we can recover faster.
2300 // 2318 //
2301 bool wasInInitializer = _inInitializer; 2319 bool wasInInitializer = _inInitializer;
2302 _inInitializer = false; 2320 _inInitializer = false;
2303 try { 2321 try {
2304 Expression argument = parseArgument(); 2322 Expression argument = parseArgument();
2305 arguments.add(argument); 2323 List<Expression> arguments = <Expression>[argument];
2306 bool foundNamedArgument = argument is NamedExpression; 2324 bool foundNamedArgument = argument is NamedExpression;
2307 bool generatedError = false; 2325 bool generatedError = false;
2308 while (_optional(TokenType.COMMA)) { 2326 while (_optional(TokenType.COMMA)) {
2309 argument = parseArgument(); 2327 argument = parseArgument();
2310 arguments.add(argument); 2328 arguments.add(argument);
2311 if (foundNamedArgument) { 2329 if (argument is NamedExpression) {
2312 bool blankArgument = 2330 foundNamedArgument = true;
2313 argument is SimpleIdentifier && argument.name.isEmpty; 2331 } else if (foundNamedArgument) {
2314 if (!generatedError && 2332 if (!generatedError) {
2315 !(argument is NamedExpression && !blankArgument)) { 2333 if (!argument.isSynthetic) {
2316 // Report the error, once, but allow the arguments to be in any 2334 // Report the error, once, but allow the arguments to be in any
2317 // order in the AST. 2335 // order in the AST.
2318 _reportErrorForCurrentToken( 2336 _reportErrorForCurrentToken(
2319 ParserErrorCode.POSITIONAL_AFTER_NAMED_ARGUMENT); 2337 ParserErrorCode.POSITIONAL_AFTER_NAMED_ARGUMENT);
2320 generatedError = true; 2338 generatedError = true;
2339 }
2321 } 2340 }
2322 } else if (argument is NamedExpression) {
2323 foundNamedArgument = true;
2324 } 2341 }
2325 } 2342 }
2326 // TODO(brianwilkerson) Recovery: Look at the left parenthesis to see 2343 // Recovery: If the next token is not a right parenthesis, look at the
2327 // whether there is a matching right parenthesis. If there is, then we're 2344 // left parenthesis to see whether there is a matching right parenthesis.
2328 // more likely missing a comma and should go back to parsing arguments. 2345 // If there is, then we're more likely missing a comma and should go back
2346 // to parsing arguments.
2329 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); 2347 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
2330 return new ArgumentList(leftParenthesis, arguments, rightParenthesis); 2348 return new ArgumentList(leftParenthesis, arguments, rightParenthesis);
2331 } finally { 2349 } finally {
2332 _inInitializer = wasInInitializer; 2350 _inInitializer = wasInInitializer;
2333 } 2351 }
2334 } 2352 }
2335 2353
2336 /** 2354 /**
2337 * Parse a bitwise or expression. Return the bitwise or expression that was 2355 * Parse a bitwise or expression. Return the bitwise or expression that was
2338 * parsed. 2356 * parsed.
2339 * 2357 *
2340 * bitwiseOrExpression ::= 2358 * bitwiseOrExpression ::=
2341 * bitwiseXorExpression ('|' bitwiseXorExpression)* 2359 * bitwiseXorExpression ('|' bitwiseXorExpression)*
2342 * | 'super' ('|' bitwiseXorExpression)+ 2360 * | 'super' ('|' bitwiseXorExpression)+
2343 */ 2361 */
2344 Expression parseBitwiseOrExpression() { 2362 Expression parseBitwiseOrExpression() {
2345 Expression expression; 2363 Expression expression;
2346 if (_matchesKeyword(Keyword.SUPER) && 2364 if (_currentToken.keyword == Keyword.SUPER &&
2347 _tokenMatches(_peek(), TokenType.BAR)) { 2365 _currentToken.next.type == TokenType.BAR) {
2348 expression = new SuperExpression(getAndAdvance()); 2366 expression = new SuperExpression(getAndAdvance());
2349 } else { 2367 } else {
2350 expression = _parseBitwiseXorExpression(); 2368 expression = _parseBitwiseXorExpression();
2351 } 2369 }
2352 while (_matches(TokenType.BAR)) { 2370 while (_currentToken.type == TokenType.BAR) {
2353 Token operator = getAndAdvance();
2354 expression = new BinaryExpression( 2371 expression = new BinaryExpression(
2355 expression, operator, _parseBitwiseXorExpression()); 2372 expression, getAndAdvance(), _parseBitwiseXorExpression());
2356 } 2373 }
2357 return expression; 2374 return expression;
2358 } 2375 }
2359 2376
2360 /** 2377 /**
2361 * Parse a block. Return the block that was parsed. 2378 * Parse a block. Return the block that was parsed.
2362 * 2379 *
2380 * This method assumes that the current token matches
2381 * [TokenType.OPEN_CURLY_BRACKET].
2382 *
2363 * block ::= 2383 * block ::=
2364 * '{' statements '}' 2384 * '{' statements '}'
2365 */ 2385 */
2366 Block parseBlock() { 2386 Block parseBlock() {
2367 Token leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET); 2387 bool isEndOfBlock() {
2368 List<Statement> statements = new List<Statement>(); 2388 TokenType type = _currentToken.type;
2389 return type == TokenType.EOF || type == TokenType.CLOSE_CURLY_BRACKET;
2390 }
2391
2392 Token leftBracket = getAndAdvance();
2393 List<Statement> statements = <Statement>[];
2369 Token statementStart = _currentToken; 2394 Token statementStart = _currentToken;
2370 while ( 2395 while (!isEndOfBlock()) {
2371 !_matches(TokenType.EOF) && !_matches(TokenType.CLOSE_CURLY_BRACKET)) {
2372 Statement statement = parseStatement2(); 2396 Statement statement = parseStatement2();
2373 if (statement != null) {
2374 statements.add(statement);
2375 }
2376 if (identical(_currentToken, statementStart)) { 2397 if (identical(_currentToken, statementStart)) {
2377 // Ensure that we are making progress and report an error if we're not. 2398 // Ensure that we are making progress and report an error if we're not.
2378 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, 2399 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
2379 [_currentToken.lexeme]); 2400 [_currentToken.lexeme]);
2380 _advance(); 2401 _advance();
2402 } else if (statement != null) {
2403 statements.add(statement);
2381 } 2404 }
2382 statementStart = _currentToken; 2405 statementStart = _currentToken;
2383 } 2406 }
2407 // Recovery: If the next token is not a right curly bracket, look at the
2408 // left curly bracket to see whether there is a matching right bracket. If
2409 // there is, then we're more likely missing a semi-colon and should go back
2410 // to parsing statements.
2384 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET); 2411 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
2385 return new Block(leftBracket, statements, rightBracket); 2412 return new Block(leftBracket, statements, rightBracket);
2386 } 2413 }
2387 2414
2388 /** 2415 /**
2389 * Parse a class member. The [className] is the name of the class containing 2416 * Parse a class member. The [className] is the name of the class containing
2390 * the member being parsed. Return the class member that was parsed, or `null` 2417 * the member being parsed. Return the class member that was parsed, or `null`
2391 * if what was found was not a valid class member. 2418 * if what was found was not a valid class member.
2392 * 2419 *
2393 * classMemberDefinition ::= 2420 * classMemberDefinition ::=
2394 * declaration ';' 2421 * declaration ';'
2395 * | methodSignature functionBody 2422 * | methodSignature functionBody
2396 */ 2423 */
2397 ClassMember parseClassMember(String className) { 2424 ClassMember parseClassMember(String className) {
2398 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); 2425 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata();
2399 Modifiers modifiers = _parseModifiers(); 2426 Modifiers modifiers = _parseModifiers();
2400 if (_matchesKeyword(Keyword.VOID)) { 2427 Keyword keyword = _currentToken.keyword;
2401 TypeName returnType = parseReturnType(); 2428 if (keyword == Keyword.VOID) {
2402 if (_matchesKeyword(Keyword.GET) && _tokenMatchesIdentifier(_peek())) { 2429 TypeName returnType =
2430 new TypeName(new SimpleIdentifier(getAndAdvance()), null);
2431 keyword = _currentToken.keyword;
2432 Token next = _peek();
2433 bool isFollowedByIdentifier = _tokenMatchesIdentifier(next);
2434 if (keyword == Keyword.GET && isFollowedByIdentifier) {
2403 _validateModifiersForGetterOrSetterOrMethod(modifiers); 2435 _validateModifiersForGetterOrSetterOrMethod(modifiers);
2404 return _parseGetter(commentAndMetadata, modifiers.externalKeyword, 2436 return _parseGetter(commentAndMetadata, modifiers.externalKeyword,
2405 modifiers.staticKeyword, returnType); 2437 modifiers.staticKeyword, returnType);
2406 } else if (_matchesKeyword(Keyword.SET) && 2438 } else if (keyword == Keyword.SET && isFollowedByIdentifier) {
2407 _tokenMatchesIdentifier(_peek())) {
2408 _validateModifiersForGetterOrSetterOrMethod(modifiers); 2439 _validateModifiersForGetterOrSetterOrMethod(modifiers);
2409 return _parseSetter(commentAndMetadata, modifiers.externalKeyword, 2440 return _parseSetter(commentAndMetadata, modifiers.externalKeyword,
2410 modifiers.staticKeyword, returnType); 2441 modifiers.staticKeyword, returnType);
2411 } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) { 2442 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
2412 _validateModifiersForOperator(modifiers); 2443 _validateModifiersForOperator(modifiers);
2413 return _parseOperator( 2444 return _parseOperatorAfterKeyword(commentAndMetadata,
2414 commentAndMetadata, modifiers.externalKeyword, returnType); 2445 modifiers.externalKeyword, returnType, getAndAdvance());
2415 } else if (_matchesIdentifier() && 2446 } else if (_matchesIdentifier() &&
2416 _peek().matchesAny(const <TokenType>[ 2447 _peek().matchesAny(const <TokenType>[
2417 TokenType.OPEN_PAREN, 2448 TokenType.OPEN_PAREN,
2418 TokenType.OPEN_CURLY_BRACKET, 2449 TokenType.OPEN_CURLY_BRACKET,
2419 TokenType.FUNCTION, 2450 TokenType.FUNCTION,
2420 TokenType.LT 2451 TokenType.LT
2421 ])) { 2452 ])) {
2422 _validateModifiersForGetterOrSetterOrMethod(modifiers); 2453 _validateModifiersForGetterOrSetterOrMethod(modifiers);
2423 return _parseMethodDeclarationAfterReturnType(commentAndMetadata, 2454 return _parseMethodDeclarationAfterReturnType(commentAndMetadata,
2424 modifiers.externalKeyword, modifiers.staticKeyword, returnType); 2455 modifiers.externalKeyword, modifiers.staticKeyword, returnType);
(...skipping 24 matching lines...) Expand all
2449 // 'operator' keyword. 2480 // 'operator' keyword.
2450 // 2481 //
2451 _validateModifiersForOperator(modifiers); 2482 _validateModifiersForOperator(modifiers);
2452 return _parseOperator( 2483 return _parseOperator(
2453 commentAndMetadata, modifiers.externalKeyword, returnType); 2484 commentAndMetadata, modifiers.externalKeyword, returnType);
2454 } 2485 }
2455 _reportErrorForToken( 2486 _reportErrorForToken(
2456 ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken); 2487 ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken);
2457 return null; 2488 return null;
2458 } 2489 }
2459 } else if (_matchesKeyword(Keyword.GET) && 2490 }
2460 _tokenMatchesIdentifier(_peek())) { 2491 Token next = _peek();
2492 bool isFollowedByIdentifier = _tokenMatchesIdentifier(next);
2493 if (keyword == Keyword.GET && isFollowedByIdentifier) {
2461 _validateModifiersForGetterOrSetterOrMethod(modifiers); 2494 _validateModifiersForGetterOrSetterOrMethod(modifiers);
2462 return _parseGetter(commentAndMetadata, modifiers.externalKeyword, 2495 return _parseGetter(commentAndMetadata, modifiers.externalKeyword,
2463 modifiers.staticKeyword, null); 2496 modifiers.staticKeyword, null);
2464 } else if (_matchesKeyword(Keyword.SET) && 2497 } else if (keyword == Keyword.SET && isFollowedByIdentifier) {
2465 _tokenMatchesIdentifier(_peek())) {
2466 _validateModifiersForGetterOrSetterOrMethod(modifiers); 2498 _validateModifiersForGetterOrSetterOrMethod(modifiers);
2467 return _parseSetter(commentAndMetadata, modifiers.externalKeyword, 2499 return _parseSetter(commentAndMetadata, modifiers.externalKeyword,
2468 modifiers.staticKeyword, null); 2500 modifiers.staticKeyword, null);
2469 } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) { 2501 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
2470 _validateModifiersForOperator(modifiers); 2502 _validateModifiersForOperator(modifiers);
2471 return _parseOperator( 2503 return _parseOperatorAfterKeyword(
2472 commentAndMetadata, modifiers.externalKeyword, null); 2504 commentAndMetadata, modifiers.externalKeyword, null, getAndAdvance());
2473 } else if (!_matchesIdentifier()) { 2505 } else if (!_matchesIdentifier()) {
2474 // 2506 //
2475 // Recover from an error. 2507 // Recover from an error.
2476 // 2508 //
2477 if (_matchesKeyword(Keyword.CLASS)) { 2509 if (_matchesKeyword(Keyword.CLASS)) {
2478 _reportErrorForCurrentToken(ParserErrorCode.CLASS_IN_CLASS); 2510 _reportErrorForCurrentToken(ParserErrorCode.CLASS_IN_CLASS);
2479 // TODO(brianwilkerson) We don't currently have any way to capture the 2511 // TODO(brianwilkerson) We don't currently have any way to capture the
2480 // class that was parsed. 2512 // class that was parsed.
2481 _parseClassDeclaration(commentAndMetadata, null); 2513 _parseClassDeclaration(commentAndMetadata, null);
2482 return null; 2514 return null;
(...skipping 24 matching lines...) Expand all
2507 keyword = modifiers.finalKeyword; 2539 keyword = modifiers.finalKeyword;
2508 } 2540 }
2509 if (keyword == null) { 2541 if (keyword == null) {
2510 keyword = modifiers.constKeyword; 2542 keyword = modifiers.constKeyword;
2511 } 2543 }
2512 if (keyword != null) { 2544 if (keyword != null) {
2513 // 2545 //
2514 // We appear to have found an incomplete field declaration. 2546 // We appear to have found an incomplete field declaration.
2515 // 2547 //
2516 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); 2548 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
2517 List<VariableDeclaration> variables = new List<VariableDeclaration>(); 2549 VariableDeclaration variable =
2518 variables.add( 2550 new VariableDeclaration(_createSyntheticIdentifier(), null, null);
2519 new VariableDeclaration(_createSyntheticIdentifier(), null, null)); 2551 List<VariableDeclaration> variables = <VariableDeclaration>[variable];
2520 return new FieldDeclaration( 2552 return new FieldDeclaration(
2521 commentAndMetadata.comment, 2553 commentAndMetadata.comment,
2522 commentAndMetadata.metadata, 2554 commentAndMetadata.metadata,
2523 null, 2555 null,
2524 new VariableDeclarationList(null, null, keyword, null, variables), 2556 new VariableDeclarationList(null, null, keyword, null, variables),
2525 _expect(TokenType.SEMICOLON)); 2557 _expect(TokenType.SEMICOLON));
2526 } 2558 }
2527 _reportErrorForToken( 2559 _reportErrorForToken(
2528 ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken); 2560 ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken);
2529 if (commentAndMetadata.comment != null || 2561 if (commentAndMetadata.comment != null ||
2530 !commentAndMetadata.metadata.isEmpty) { 2562 commentAndMetadata.hasMetadata) {
2531 // 2563 //
2532 // We appear to have found an incomplete declaration at the end of the 2564 // We appear to have found an incomplete declaration at the end of the
2533 // class. At this point it consists of a metadata, which we don't want 2565 // class. At this point it consists of a metadata, which we don't want
2534 // to loose, so we'll treat it as a method declaration with a missing 2566 // to loose, so we'll treat it as a method declaration with a missing
2535 // name, parameters and empty body. 2567 // name, parameters and empty body.
2536 // 2568 //
2537 return new MethodDeclaration( 2569 return new MethodDeclaration(
2538 commentAndMetadata.comment, 2570 commentAndMetadata.comment,
2539 commentAndMetadata.metadata, 2571 commentAndMetadata.metadata,
2540 null, 2572 null,
2541 null, 2573 null,
2542 null, 2574 null,
2543 null, 2575 null,
2544 null, 2576 null,
2545 _createSyntheticIdentifier(isDeclaration: true), 2577 _createSyntheticIdentifier(isDeclaration: true),
2546 null, 2578 null,
2547 new FormalParameterList( 2579 new FormalParameterList(
2548 null, <FormalParameter>[], null, null, null), 2580 null, <FormalParameter>[], null, null, null),
2549 new EmptyFunctionBody(_createSyntheticToken(TokenType.SEMICOLON))); 2581 new EmptyFunctionBody(_createSyntheticToken(TokenType.SEMICOLON)));
2550 } 2582 }
2551 return null; 2583 return null;
2552 } else if (_tokenMatches(_peek(), TokenType.PERIOD) && 2584 } else if (_tokenMatches(next, TokenType.PERIOD) &&
2553 _tokenMatchesIdentifier(_peekAt(2)) && 2585 _tokenMatchesIdentifier(_peekAt(2)) &&
2554 _tokenMatches(_peekAt(3), TokenType.OPEN_PAREN)) { 2586 _tokenMatches(_peekAt(3), TokenType.OPEN_PAREN)) {
2555 return _parseConstructor( 2587 return _parseConstructor(
2556 commentAndMetadata, 2588 commentAndMetadata,
2557 modifiers.externalKeyword, 2589 modifiers.externalKeyword,
2558 _validateModifiersForConstructor(modifiers), 2590 _validateModifiersForConstructor(modifiers),
2559 modifiers.factoryKeyword, 2591 modifiers.factoryKeyword,
2560 parseSimpleIdentifier(), 2592 parseSimpleIdentifier(),
2561 getAndAdvance(), 2593 getAndAdvance(),
2562 parseSimpleIdentifier(isDeclaration: true), 2594 parseSimpleIdentifier(isDeclaration: true),
2563 parseFormalParameterList()); 2595 parseFormalParameterList());
2564 } else if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { 2596 } else if (_tokenMatches(next, TokenType.OPEN_PAREN)) {
2565 TypeName returnType = _parseOptionalTypeNameComment(); 2597 TypeName returnType = _parseOptionalTypeNameComment();
2566 SimpleIdentifier methodName = parseSimpleIdentifier(isDeclaration: true); 2598 SimpleIdentifier methodName = parseSimpleIdentifier(isDeclaration: true);
2567 TypeParameterList typeParameters = _parseGenericCommentTypeParameters(); 2599 TypeParameterList typeParameters = _parseGenericCommentTypeParameters();
2568 FormalParameterList parameters = parseFormalParameterList(); 2600 FormalParameterList parameters = parseFormalParameterList();
2569 if (_matches(TokenType.COLON) || 2601 if (_matches(TokenType.COLON) ||
2570 modifiers.factoryKeyword != null || 2602 modifiers.factoryKeyword != null ||
2571 methodName.name == className) { 2603 methodName.name == className) {
2572 return _parseConstructor( 2604 return _parseConstructor(
2573 commentAndMetadata, 2605 commentAndMetadata,
2574 modifiers.externalKeyword, 2606 modifiers.externalKeyword,
2575 _validateModifiersForConstructor(modifiers), 2607 _validateModifiersForConstructor(modifiers),
2576 modifiers.factoryKeyword, 2608 modifiers.factoryKeyword,
2577 new SimpleIdentifier(methodName.token, isDeclaration: false), 2609 new SimpleIdentifier(methodName.token, isDeclaration: false),
2578 null, 2610 null,
2579 null, 2611 null,
2580 parameters); 2612 parameters);
2581 } 2613 }
2582 _validateModifiersForGetterOrSetterOrMethod(modifiers); 2614 _validateModifiersForGetterOrSetterOrMethod(modifiers);
2583 _validateFormalParameterList(parameters); 2615 _validateFormalParameterList(parameters);
2584 return _parseMethodDeclarationAfterParameters( 2616 return _parseMethodDeclarationAfterParameters(
2585 commentAndMetadata, 2617 commentAndMetadata,
2586 modifiers.externalKeyword, 2618 modifiers.externalKeyword,
2587 modifiers.staticKeyword, 2619 modifiers.staticKeyword,
2588 returnType, 2620 returnType,
2589 methodName, 2621 methodName,
2590 typeParameters, 2622 typeParameters,
2591 parameters); 2623 parameters);
2592 } else if (_peek().matchesAny(const <TokenType>[ 2624 } else if (next.matchesAny(const <TokenType>[
2593 TokenType.EQ, 2625 TokenType.EQ,
2594 TokenType.COMMA, 2626 TokenType.COMMA,
2595 TokenType.SEMICOLON 2627 TokenType.SEMICOLON
2596 ])) { 2628 ])) {
2597 if (modifiers.constKeyword == null && 2629 if (modifiers.constKeyword == null &&
2598 modifiers.finalKeyword == null && 2630 modifiers.finalKeyword == null &&
2599 modifiers.varKeyword == null) { 2631 modifiers.varKeyword == null) {
2600 _reportErrorForCurrentToken( 2632 _reportErrorForCurrentToken(
2601 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE); 2633 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE);
2602 } 2634 }
2603 return _parseInitializedIdentifierList(commentAndMetadata, 2635 return _parseInitializedIdentifierList(commentAndMetadata,
2604 modifiers.staticKeyword, _validateModifiersForField(modifiers), null); 2636 modifiers.staticKeyword, _validateModifiersForField(modifiers), null);
2605 } else if (_matchesKeyword(Keyword.TYPEDEF)) { 2637 } else if (keyword == Keyword.TYPEDEF) {
2606 _reportErrorForCurrentToken(ParserErrorCode.TYPEDEF_IN_CLASS); 2638 _reportErrorForCurrentToken(ParserErrorCode.TYPEDEF_IN_CLASS);
2607 // TODO(brianwilkerson) We don't currently have any way to capture the 2639 // TODO(brianwilkerson) We don't currently have any way to capture the
2608 // function type alias that was parsed. 2640 // function type alias that was parsed.
2609 _parseFunctionTypeAlias(commentAndMetadata, getAndAdvance()); 2641 _parseFunctionTypeAlias(commentAndMetadata, getAndAdvance());
2610 return null; 2642 return null;
2611 } else if (parseGenericMethods) { 2643 } else if (parseGenericMethods) {
2612 Token token = _skipTypeParameterList(_peek()); 2644 Token token = _skipTypeParameterList(_peek());
2613 if (token != null && _tokenMatches(token, TokenType.OPEN_PAREN)) { 2645 if (token != null && _tokenMatches(token, TokenType.OPEN_PAREN)) {
2614 return _parseMethodDeclarationAfterReturnType(commentAndMetadata, 2646 return _parseMethodDeclarationAfterReturnType(commentAndMetadata,
2615 modifiers.externalKeyword, modifiers.staticKeyword, null); 2647 modifiers.externalKeyword, modifiers.staticKeyword, null);
2616 } 2648 }
2617 } 2649 }
2618 TypeName type = parseTypeName(); 2650 TypeName type = _parseTypeNameAfterIdentifier();
2619 if (_matchesKeyword(Keyword.GET) && _tokenMatchesIdentifier(_peek())) { 2651 keyword = _currentToken.keyword;
2652 next = _peek();
2653 isFollowedByIdentifier = _tokenMatchesIdentifier(next);
2654 if (keyword == Keyword.GET && isFollowedByIdentifier) {
2620 _validateModifiersForGetterOrSetterOrMethod(modifiers); 2655 _validateModifiersForGetterOrSetterOrMethod(modifiers);
2621 return _parseGetter(commentAndMetadata, modifiers.externalKeyword, 2656 return _parseGetter(commentAndMetadata, modifiers.externalKeyword,
2622 modifiers.staticKeyword, type); 2657 modifiers.staticKeyword, type);
2623 } else if (_matchesKeyword(Keyword.SET) && 2658 } else if (keyword == Keyword.SET && isFollowedByIdentifier) {
2624 _tokenMatchesIdentifier(_peek())) {
2625 _validateModifiersForGetterOrSetterOrMethod(modifiers); 2659 _validateModifiersForGetterOrSetterOrMethod(modifiers);
2626 return _parseSetter(commentAndMetadata, modifiers.externalKeyword, 2660 return _parseSetter(commentAndMetadata, modifiers.externalKeyword,
2627 modifiers.staticKeyword, type); 2661 modifiers.staticKeyword, type);
2628 } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) { 2662 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
2629 _validateModifiersForOperator(modifiers); 2663 _validateModifiersForOperator(modifiers);
2630 return _parseOperator( 2664 return _parseOperatorAfterKeyword(
2631 commentAndMetadata, modifiers.externalKeyword, type); 2665 commentAndMetadata, modifiers.externalKeyword, type, getAndAdvance());
2632 } else if (!_matchesIdentifier()) { 2666 } else if (!_matchesIdentifier()) {
2633 if (_matches(TokenType.CLOSE_CURLY_BRACKET)) { 2667 if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
2634 // 2668 //
2635 // We appear to have found an incomplete declaration at the end of the 2669 // We appear to have found an incomplete declaration at the end of the
2636 // class. At this point it consists of a type name, so we'll treat it as 2670 // class. At this point it consists of a type name, so we'll treat it as
2637 // a field declaration with a missing field name and semicolon. 2671 // a field declaration with a missing field name and semicolon.
2638 // 2672 //
2639 return _parseInitializedIdentifierList( 2673 return _parseInitializedIdentifierList(
2640 commentAndMetadata, 2674 commentAndMetadata,
2641 modifiers.staticKeyword, 2675 modifiers.staticKeyword,
(...skipping 19 matching lines...) Expand all
2661 try { 2695 try {
2662 _lockErrorListener(); 2696 _lockErrorListener();
2663 return _parseInitializedIdentifierList( 2697 return _parseInitializedIdentifierList(
2664 commentAndMetadata, 2698 commentAndMetadata,
2665 modifiers.staticKeyword, 2699 modifiers.staticKeyword,
2666 _validateModifiersForField(modifiers), 2700 _validateModifiersForField(modifiers),
2667 type); 2701 type);
2668 } finally { 2702 } finally {
2669 _unlockErrorListener(); 2703 _unlockErrorListener();
2670 } 2704 }
2671 } else if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { 2705 } else if (_tokenMatches(next, TokenType.OPEN_PAREN)) {
2672 SimpleIdentifier methodName = parseSimpleIdentifier(isDeclaration: true); 2706 SimpleIdentifier methodName =
2707 _parseSimpleIdentifierUnchecked(isDeclaration: true);
2673 TypeParameterList typeParameters = _parseGenericCommentTypeParameters(); 2708 TypeParameterList typeParameters = _parseGenericCommentTypeParameters();
2674 FormalParameterList parameters = parseFormalParameterList(); 2709 FormalParameterList parameters = parseFormalParameterList();
2675 if (methodName.name == className) { 2710 if (methodName.name == className) {
2676 _reportErrorForNode(ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, type); 2711 _reportErrorForNode(ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, type);
2677 return _parseConstructor( 2712 return _parseConstructor(
2678 commentAndMetadata, 2713 commentAndMetadata,
2679 modifiers.externalKeyword, 2714 modifiers.externalKeyword,
2680 _validateModifiersForConstructor(modifiers), 2715 _validateModifiersForConstructor(modifiers),
2681 modifiers.factoryKeyword, 2716 modifiers.factoryKeyword,
2682 new SimpleIdentifier(methodName.token, isDeclaration: true), 2717 new SimpleIdentifier(methodName.token, isDeclaration: true),
2683 null, 2718 null,
2684 null, 2719 null,
2685 parameters); 2720 parameters);
2686 } 2721 }
2687 _validateModifiersForGetterOrSetterOrMethod(modifiers); 2722 _validateModifiersForGetterOrSetterOrMethod(modifiers);
2688 _validateFormalParameterList(parameters); 2723 _validateFormalParameterList(parameters);
2689 return _parseMethodDeclarationAfterParameters( 2724 return _parseMethodDeclarationAfterParameters(
2690 commentAndMetadata, 2725 commentAndMetadata,
2691 modifiers.externalKeyword, 2726 modifiers.externalKeyword,
2692 modifiers.staticKeyword, 2727 modifiers.staticKeyword,
2693 type, 2728 type,
2694 methodName, 2729 methodName,
2695 typeParameters, 2730 typeParameters,
2696 parameters); 2731 parameters);
2697 } else if (parseGenericMethods && _tokenMatches(_peek(), TokenType.LT)) { 2732 } else if (parseGenericMethods && _tokenMatches(next, TokenType.LT)) {
2698 return _parseMethodDeclarationAfterReturnType(commentAndMetadata, 2733 return _parseMethodDeclarationAfterReturnType(commentAndMetadata,
2699 modifiers.externalKeyword, modifiers.staticKeyword, type); 2734 modifiers.externalKeyword, modifiers.staticKeyword, type);
2700 } else if (_tokenMatches(_peek(), TokenType.OPEN_CURLY_BRACKET)) { 2735 } else if (_tokenMatches(next, TokenType.OPEN_CURLY_BRACKET)) {
2701 // We have found "TypeName identifier {", and are guessing that this is a 2736 // We have found "TypeName identifier {", and are guessing that this is a
2702 // getter without the keyword 'get'. 2737 // getter without the keyword 'get'.
2703 _validateModifiersForGetterOrSetterOrMethod(modifiers); 2738 _validateModifiersForGetterOrSetterOrMethod(modifiers);
2704 _reportErrorForCurrentToken(ParserErrorCode.MISSING_GET); 2739 _reportErrorForCurrentToken(ParserErrorCode.MISSING_GET);
2705 _currentToken = _injectToken( 2740 _currentToken = _injectToken(
2706 new Parser_SyntheticKeywordToken(Keyword.GET, _currentToken.offset)); 2741 new Parser_SyntheticKeywordToken(Keyword.GET, _currentToken.offset));
2707 return _parseGetter(commentAndMetadata, modifiers.externalKeyword, 2742 return _parseGetter(commentAndMetadata, modifiers.externalKeyword,
2708 modifiers.staticKeyword, type); 2743 modifiers.staticKeyword, type);
2709 } 2744 }
2710 return _parseInitializedIdentifierList(commentAndMetadata, 2745 return _parseInitializedIdentifierList(commentAndMetadata,
2711 modifiers.staticKeyword, _validateModifiersForField(modifiers), type); 2746 modifiers.staticKeyword, _validateModifiersForField(modifiers), type);
2712 } 2747 }
2713 2748
2714 /** 2749 /**
2715 * Parse a single combinator. Return the combinator that was parsed, or `null` 2750 * Parse a single combinator. Return the combinator that was parsed, or `null`
2716 * if no combinator is found. 2751 * if no combinator is found.
2717 * 2752 *
2718 * combinator ::= 2753 * combinator ::=
2719 * 'show' identifier (',' identifier)* 2754 * 'show' identifier (',' identifier)*
2720 * | 'hide' identifier (',' identifier)* 2755 * | 'hide' identifier (',' identifier)*
2721 */ 2756 */
2722 Combinator parseCombinator() { 2757 Combinator parseCombinator() {
2723 if (_matchesString(_SHOW) || _matchesString(_HIDE)) { 2758 if (_matchesString(_SHOW)) {
2724 Token keyword = getAndAdvance(); 2759 return new ShowCombinator(getAndAdvance(), _parseIdentifierList());
2725 List<SimpleIdentifier> names = _parseIdentifierList(); 2760 } else if (_matchesString(_HIDE)) {
2726 if (keyword.lexeme == _SHOW) { 2761 return new HideCombinator(getAndAdvance(), _parseIdentifierList());
2727 return new ShowCombinator(keyword, names);
2728 } else {
2729 return new HideCombinator(keyword, names);
2730 }
2731 } 2762 }
2732 return null; 2763 return null;
2733 } 2764 }
2734 2765
2735 /** 2766 /**
2736 * Parse a compilation unit, starting with the given [token]. Return the 2767 * Parse a compilation unit, starting with the given [token]. Return the
2737 * compilation unit that was parsed. 2768 * compilation unit that was parsed.
2738 */ 2769 */
2739 CompilationUnit parseCompilationUnit(Token token) { 2770 CompilationUnit parseCompilationUnit(Token token) {
2740 _currentToken = token; 2771 _currentToken = token;
(...skipping 25 matching lines...) Expand all
2766 } 2797 }
2767 // 2798 //
2768 // Even though all directives must appear before declarations and must occur 2799 // Even though all directives must appear before declarations and must occur
2769 // in a given order, we allow directives and declarations to occur in any 2800 // in a given order, we allow directives and declarations to occur in any
2770 // order so that we can recover better. 2801 // order so that we can recover better.
2771 // 2802 //
2772 bool libraryDirectiveFound = false; 2803 bool libraryDirectiveFound = false;
2773 bool partOfDirectiveFound = false; 2804 bool partOfDirectiveFound = false;
2774 bool partDirectiveFound = false; 2805 bool partDirectiveFound = false;
2775 bool directiveFoundAfterDeclaration = false; 2806 bool directiveFoundAfterDeclaration = false;
2776 List<Directive> directives = new List<Directive>(); 2807 List<Directive> directives = <Directive>[];
2777 List<CompilationUnitMember> declarations = 2808 List<CompilationUnitMember> declarations = <CompilationUnitMember>[];
2778 new List<CompilationUnitMember>();
2779 Token memberStart = _currentToken; 2809 Token memberStart = _currentToken;
2780 while (!_matches(TokenType.EOF)) { 2810 TokenType type = _currentToken.type;
2811 while (type != TokenType.EOF) {
2781 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); 2812 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata();
2782 if ((_matchesKeyword(Keyword.IMPORT) || 2813 Keyword keyword = _currentToken.keyword;
2783 _matchesKeyword(Keyword.EXPORT) || 2814 TokenType nextType = _currentToken.next.type;
2784 _matchesKeyword(Keyword.LIBRARY) || 2815 if ((keyword == Keyword.IMPORT ||
2785 _matchesKeyword(Keyword.PART)) && 2816 keyword == Keyword.EXPORT ||
2786 !_tokenMatches(_peek(), TokenType.PERIOD) && 2817 keyword == Keyword.LIBRARY ||
2787 !_tokenMatches(_peek(), TokenType.LT) && 2818 keyword == Keyword.PART) &&
2788 !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { 2819 nextType != TokenType.PERIOD &&
2789 Directive directive = _parseDirective(commentAndMetadata); 2820 nextType != TokenType.LT &&
2821 nextType != TokenType.OPEN_PAREN) {
2822 Directive parseDirective() {
2823 if (keyword == Keyword.IMPORT) {
2824 if (partDirectiveFound) {
2825 _reportErrorForCurrentToken(
2826 ParserErrorCode.IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE);
2827 }
2828 return _parseImportDirective(commentAndMetadata);
2829 } else if (keyword == Keyword.EXPORT) {
2830 if (partDirectiveFound) {
2831 _reportErrorForCurrentToken(
2832 ParserErrorCode.EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE);
2833 }
2834 return _parseExportDirective(commentAndMetadata);
2835 } else if (keyword == Keyword.LIBRARY) {
2836 if (libraryDirectiveFound) {
2837 _reportErrorForCurrentToken(
2838 ParserErrorCode.MULTIPLE_LIBRARY_DIRECTIVES);
2839 } else {
2840 if (directives.length > 0) {
2841 _reportErrorForCurrentToken(
2842 ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST);
2843 }
2844 libraryDirectiveFound = true;
2845 }
2846 return _parseLibraryDirective(commentAndMetadata);
2847 } else if (keyword == Keyword.PART) {
2848 if (_tokenMatchesString(_peek(), _OF)) {
2849 partOfDirectiveFound = true;
2850 return _parsePartOfDirective(commentAndMetadata);
2851 } else {
2852 partDirectiveFound = true;
2853 return _parsePartDirective(commentAndMetadata);
2854 }
2855 } else {
2856 // Internal error: this method should not have been invoked if the
2857 // current token was something other than one of the above.
2858 throw new IllegalStateException(
2859 "parseDirective invoked in an invalid state (currentToken = $_cu rrentToken)");
2860 }
2861 }
2862 Directive directive = parseDirective();
2790 if (declarations.length > 0 && !directiveFoundAfterDeclaration) { 2863 if (declarations.length > 0 && !directiveFoundAfterDeclaration) {
2791 _reportErrorForToken(ParserErrorCode.DIRECTIVE_AFTER_DECLARATION, 2864 _reportErrorForToken(ParserErrorCode.DIRECTIVE_AFTER_DECLARATION,
2792 directive.beginToken); 2865 directive.beginToken);
2793 directiveFoundAfterDeclaration = true; 2866 directiveFoundAfterDeclaration = true;
2794 } 2867 }
2795 if (directive is LibraryDirective) {
2796 if (libraryDirectiveFound) {
2797 _reportErrorForCurrentToken(
2798 ParserErrorCode.MULTIPLE_LIBRARY_DIRECTIVES);
2799 } else {
2800 if (directives.length > 0) {
2801 _reportErrorForToken(ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST,
2802 directive.libraryKeyword);
2803 }
2804 libraryDirectiveFound = true;
2805 }
2806 } else if (directive is PartDirective) {
2807 partDirectiveFound = true;
2808 } else if (partDirectiveFound) {
2809 if (directive is ExportDirective) {
2810 _reportErrorForToken(
2811 ParserErrorCode.EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE,
2812 directive.keyword);
2813 } else if (directive is ImportDirective) {
2814 _reportErrorForToken(
2815 ParserErrorCode.IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE,
2816 directive.keyword);
2817 }
2818 }
2819 if (directive is PartOfDirective) {
2820 if (partOfDirectiveFound) {
2821 _reportErrorForCurrentToken(
2822 ParserErrorCode.MULTIPLE_PART_OF_DIRECTIVES);
2823 } else {
2824 int directiveCount = directives.length;
2825 for (int i = 0; i < directiveCount; i++) {
2826 _reportErrorForToken(
2827 ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART,
2828 directives[i].keyword);
2829 }
2830 partOfDirectiveFound = true;
2831 }
2832 } else {
2833 if (partOfDirectiveFound) {
2834 _reportErrorForToken(ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART,
2835 directive.keyword);
2836 }
2837 }
2838 directives.add(directive); 2868 directives.add(directive);
2839 } else if (_matches(TokenType.SEMICOLON)) { 2869 } else if (type == TokenType.SEMICOLON) {
2870 // TODO(brianwilkerson) Consider moving this error detection into
2871 // _parseCompilationUnitMember (in the places where EXPECTED_EXECUTABLE
2872 // is being generated).
2840 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, 2873 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
2841 [_currentToken.lexeme]); 2874 [_currentToken.lexeme]);
2842 _advance(); 2875 _advance();
2843 } else { 2876 } else {
2844 CompilationUnitMember member = 2877 CompilationUnitMember member =
2845 _parseCompilationUnitMember(commentAndMetadata); 2878 _parseCompilationUnitMember(commentAndMetadata);
2846 if (member != null) { 2879 if (member != null) {
2847 declarations.add(member); 2880 declarations.add(member);
2848 } 2881 }
2849 } 2882 }
2850 if (identical(_currentToken, memberStart)) { 2883 if (identical(_currentToken, memberStart)) {
2851 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, 2884 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
2852 [_currentToken.lexeme]); 2885 [_currentToken.lexeme]);
2853 _advance(); 2886 _advance();
2854 while (!_matches(TokenType.EOF) && 2887 while (!_matches(TokenType.EOF) &&
2855 !_couldBeStartOfCompilationUnitMember()) { 2888 !_couldBeStartOfCompilationUnitMember()) {
2856 _advance(); 2889 _advance();
2857 } 2890 }
2858 } 2891 }
2859 memberStart = _currentToken; 2892 memberStart = _currentToken;
2893 type = _currentToken.type;
2894 }
2895 if (partOfDirectiveFound && directives.length > 1) {
2896 // TODO(brianwilkerson) Improve error reporting when both a library and
2897 // part-of directive are found.
2898 // if (libraryDirectiveFound) {
2899 // int directiveCount = directives.length;
2900 // for (int i = 0; i < directiveCount; i++) {
2901 // Directive directive = directives[i];
2902 // if (directive is PartOfDirective) {
2903 // _reportErrorForToken(
2904 // ParserErrorCode.PART_OF_IN_LIBRARY, directive.partKeyword);
2905 // }
2906 // }
2907 // } else {
2908 bool firstPartOf = true;
2909 int directiveCount = directives.length;
2910 for (int i = 0; i < directiveCount; i++) {
2911 Directive directive = directives[i];
2912 if (directive is PartOfDirective) {
2913 if (firstPartOf) {
2914 firstPartOf = false;
2915 } else {
2916 _reportErrorForToken(ParserErrorCode.MULTIPLE_PART_OF_DIRECTIVES,
2917 directive.partKeyword);
2918 }
2919 } else {
2920 _reportErrorForToken(ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART,
2921 directives[i].keyword);
2922 }
2923 // }
2924 }
2860 } 2925 }
2861 return new CompilationUnit( 2926 return new CompilationUnit(
2862 firstToken, scriptTag, directives, declarations, _currentToken); 2927 firstToken, scriptTag, directives, declarations, _currentToken);
2863 } 2928 }
2864 2929
2865 /** 2930 /**
2866 * Parse a conditional expression. Return the conditional expression that was 2931 * Parse a conditional expression. Return the conditional expression that was
2867 * parsed. 2932 * parsed.
2868 * 2933 *
2869 * conditionalExpression ::= 2934 * conditionalExpression ::=
2870 * ifNullExpression ('?' expressionWithoutCascade ':' expressionWithou tCascade)? 2935 * ifNullExpression ('?' expressionWithoutCascade ':' expressionWithou tCascade)?
2871 */ 2936 */
2872 Expression parseConditionalExpression() { 2937 Expression parseConditionalExpression() {
2873 Expression condition = parseIfNullExpression(); 2938 Expression condition = parseIfNullExpression();
2874 if (!_matches(TokenType.QUESTION)) { 2939 if (_currentToken.type != TokenType.QUESTION) {
2875 return condition; 2940 return condition;
2876 } 2941 }
2877 Token question = getAndAdvance(); 2942 Token question = getAndAdvance();
2878 Expression thenExpression = parseExpressionWithoutCascade(); 2943 Expression thenExpression = parseExpressionWithoutCascade();
2879 Token colon = _expect(TokenType.COLON); 2944 Token colon = _expect(TokenType.COLON);
2880 Expression elseExpression = parseExpressionWithoutCascade(); 2945 Expression elseExpression = parseExpressionWithoutCascade();
2881 return new ConditionalExpression( 2946 return new ConditionalExpression(
2882 condition, question, thenExpression, colon, elseExpression); 2947 condition, question, thenExpression, colon, elseExpression);
2883 } 2948 }
2884 2949
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
2925 /** 2990 /**
2926 * Parse an expression that might contain a cascade. Return the expression 2991 * Parse an expression that might contain a cascade. Return the expression
2927 * that was parsed. 2992 * that was parsed.
2928 * 2993 *
2929 * expression ::= 2994 * expression ::=
2930 * assignableExpression assignmentOperator expression 2995 * assignableExpression assignmentOperator expression
2931 * | conditionalExpression cascadeSection* 2996 * | conditionalExpression cascadeSection*
2932 * | throwExpression 2997 * | throwExpression
2933 */ 2998 */
2934 Expression parseExpression2() { 2999 Expression parseExpression2() {
2935 if (_matchesKeyword(Keyword.THROW)) { 3000 Keyword keyword = _currentToken.keyword;
3001 if (keyword == Keyword.THROW) {
2936 return _parseThrowExpression(); 3002 return _parseThrowExpression();
2937 } else if (_matchesKeyword(Keyword.RETHROW)) { 3003 } else if (keyword == Keyword.RETHROW) {
2938 // TODO(brianwilkerson) Rethrow is a statement again. 3004 // TODO(brianwilkerson) Rethrow is a statement again.
2939 return _parseRethrowExpression(); 3005 return _parseRethrowExpression();
2940 } 3006 }
2941 // 3007 //
2942 // assignableExpression is a subset of conditionalExpression, so we can 3008 // assignableExpression is a subset of conditionalExpression, so we can
2943 // parse a conditional expression and then determine whether it is followed 3009 // parse a conditional expression and then determine whether it is followed
2944 // by an assignmentOperator, checking for conformance to the restricted 3010 // by an assignmentOperator, checking for conformance to the restricted
2945 // grammar after making that determination. 3011 // grammar after making that determination.
2946 // 3012 //
2947 Expression expression = parseConditionalExpression(); 3013 Expression expression = parseConditionalExpression();
2948 TokenType tokenType = _currentToken.type; 3014 TokenType type = _currentToken.type;
2949 if (tokenType == TokenType.PERIOD_PERIOD) { 3015 if (type == TokenType.PERIOD_PERIOD) {
2950 List<Expression> cascadeSections = new List<Expression>(); 3016 List<Expression> cascadeSections = <Expression>[];
2951 while (tokenType == TokenType.PERIOD_PERIOD) { 3017 do {
2952 Expression section = _parseCascadeSection(); 3018 Expression section = _parseCascadeSection();
2953 if (section != null) { 3019 if (section != null) {
2954 cascadeSections.add(section); 3020 cascadeSections.add(section);
2955 } 3021 }
2956 tokenType = _currentToken.type; 3022 } while (_currentToken.type == TokenType.PERIOD_PERIOD);
2957 }
2958 return new CascadeExpression(expression, cascadeSections); 3023 return new CascadeExpression(expression, cascadeSections);
2959 } else if (tokenType.isAssignmentOperator) { 3024 } else if (type.isAssignmentOperator) {
2960 Token operator = getAndAdvance(); 3025 Token operator = getAndAdvance();
2961 _ensureAssignable(expression); 3026 _ensureAssignable(expression);
2962 return new AssignmentExpression(expression, operator, parseExpression2()); 3027 return new AssignmentExpression(expression, operator, parseExpression2());
2963 } 3028 }
2964 return expression; 3029 return expression;
2965 } 3030 }
2966 3031
2967 /** 3032 /**
2968 * Parse an expression that does not contain any cascades. Return the 3033 * Parse an expression that does not contain any cascades. Return the
2969 * expression that was parsed. 3034 * expression that was parsed.
(...skipping 22 matching lines...) Expand all
2992 expression = new AssignmentExpression( 3057 expression = new AssignmentExpression(
2993 expression, operator, parseExpressionWithoutCascade()); 3058 expression, operator, parseExpressionWithoutCascade());
2994 } 3059 }
2995 return expression; 3060 return expression;
2996 } 3061 }
2997 3062
2998 /** 3063 /**
2999 * Parse a class extends clause. Return the class extends clause that was 3064 * Parse a class extends clause. Return the class extends clause that was
3000 * parsed. 3065 * parsed.
3001 * 3066 *
3067 * This method assumes that the current token matches `Keyword.EXTENDS`.
3068 *
3002 * classExtendsClause ::= 3069 * classExtendsClause ::=
3003 * 'extends' type 3070 * 'extends' type
3004 */ 3071 */
3005 ExtendsClause parseExtendsClause() { 3072 ExtendsClause parseExtendsClause() {
3006 Token keyword = _expectKeyword(Keyword.EXTENDS); 3073 Token keyword = getAndAdvance();
3007 TypeName superclass = parseTypeName(); 3074 TypeName superclass = parseTypeName();
3008 return new ExtendsClause(keyword, superclass); 3075 return new ExtendsClause(keyword, superclass);
3009 } 3076 }
3010 3077
3011 /** 3078 /**
3012 * Parse a list of formal parameters. Return the formal parameters that were 3079 * Parse a list of formal parameters. Return the formal parameters that were
3013 * parsed. 3080 * parsed.
3014 * 3081 *
3015 * formalParameterList ::= 3082 * formalParameterList ::=
3016 * '(' ')' 3083 * '(' ')'
3017 * | '(' normalFormalParameters (',' optionalFormalParameters)? ')' 3084 * | '(' normalFormalParameters (',' optionalFormalParameters)? ')'
3018 * | '(' optionalFormalParameters ')' 3085 * | '(' optionalFormalParameters ')'
3019 * 3086 *
3020 * normalFormalParameters ::= 3087 * normalFormalParameters ::=
3021 * normalFormalParameter (',' normalFormalParameter)* 3088 * normalFormalParameter (',' normalFormalParameter)*
3022 * 3089 *
3023 * optionalFormalParameters ::= 3090 * optionalFormalParameters ::=
3024 * optionalPositionalFormalParameters 3091 * optionalPositionalFormalParameters
3025 * | namedFormalParameters 3092 * | namedFormalParameters
3026 * 3093 *
3027 * optionalPositionalFormalParameters ::= 3094 * optionalPositionalFormalParameters ::=
3028 * '[' defaultFormalParameter (',' defaultFormalParameter)* ']' 3095 * '[' defaultFormalParameter (',' defaultFormalParameter)* ']'
3029 * 3096 *
3030 * namedFormalParameters ::= 3097 * namedFormalParameters ::=
3031 * '{' defaultNamedParameter (',' defaultNamedParameter)* '}' 3098 * '{' defaultNamedParameter (',' defaultNamedParameter)* '}'
3032 */ 3099 */
3033 FormalParameterList parseFormalParameterList() { 3100 FormalParameterList parseFormalParameterList() {
3034 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); 3101 if (_matches(TokenType.OPEN_PAREN)) {
3035 if (_matches(TokenType.CLOSE_PAREN)) { 3102 return _parseFormalParameterListUnchecked();
3036 return new FormalParameterList(
3037 leftParenthesis, null, null, null, getAndAdvance());
3038 } 3103 }
3039 // 3104 // TODO(brianwilkerson) Improve the error message.
3040 // Even though it is invalid to have default parameters outside of brackets, 3105 _reportErrorForCurrentToken(
3041 // required parameters inside of brackets, or multiple groups of default and 3106 ParserErrorCode.EXPECTED_TOKEN, [TokenType.OPEN_PAREN.lexeme]);
3042 // named parameters, we allow all of these cases so that we can recover 3107 // Recovery: Check for an unmatched closing paren and parse parameters until
3043 // better. 3108 // it is reached.
3044 // 3109 return _parseFormalParameterListAfterParen(
3045 List<FormalParameter> parameters = new List<FormalParameter>(); 3110 _createSyntheticToken(TokenType.OPEN_PAREN));
3046 Token leftSquareBracket = null;
3047 Token rightSquareBracket = null;
3048 Token leftCurlyBracket = null;
3049 Token rightCurlyBracket = null;
3050 ParameterKind kind = ParameterKind.REQUIRED;
3051 bool firstParameter = true;
3052 bool reportedMultiplePositionalGroups = false;
3053 bool reportedMultipleNamedGroups = false;
3054 bool reportedMixedGroups = false;
3055 bool wasOptionalParameter = false;
3056 Token initialToken = null;
3057 do {
3058 if (firstParameter) {
3059 firstParameter = false;
3060 } else if (!_optional(TokenType.COMMA)) {
3061 // TODO(brianwilkerson) The token is wrong, we need to recover from this
3062 // case.
3063 if (_getEndToken(leftParenthesis) != null) {
3064 _reportErrorForCurrentToken(
3065 ParserErrorCode.EXPECTED_TOKEN, [TokenType.COMMA.lexeme]);
3066 } else {
3067 _reportErrorForToken(ParserErrorCode.MISSING_CLOSING_PARENTHESIS,
3068 _currentToken.previous);
3069 break;
3070 }
3071 }
3072 initialToken = _currentToken;
3073 //
3074 // Handle the beginning of parameter groups.
3075 //
3076 if (_matches(TokenType.OPEN_SQUARE_BRACKET)) {
3077 wasOptionalParameter = true;
3078 if (leftSquareBracket != null && !reportedMultiplePositionalGroups) {
3079 _reportErrorForCurrentToken(
3080 ParserErrorCode.MULTIPLE_POSITIONAL_PARAMETER_GROUPS);
3081 reportedMultiplePositionalGroups = true;
3082 }
3083 if (leftCurlyBracket != null && !reportedMixedGroups) {
3084 _reportErrorForCurrentToken(ParserErrorCode.MIXED_PARAMETER_GROUPS);
3085 reportedMixedGroups = true;
3086 }
3087 leftSquareBracket = getAndAdvance();
3088 kind = ParameterKind.POSITIONAL;
3089 } else if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
3090 wasOptionalParameter = true;
3091 if (leftCurlyBracket != null && !reportedMultipleNamedGroups) {
3092 _reportErrorForCurrentToken(
3093 ParserErrorCode.MULTIPLE_NAMED_PARAMETER_GROUPS);
3094 reportedMultipleNamedGroups = true;
3095 }
3096 if (leftSquareBracket != null && !reportedMixedGroups) {
3097 _reportErrorForCurrentToken(ParserErrorCode.MIXED_PARAMETER_GROUPS);
3098 reportedMixedGroups = true;
3099 }
3100 leftCurlyBracket = getAndAdvance();
3101 kind = ParameterKind.NAMED;
3102 }
3103 //
3104 // Parse and record the parameter.
3105 //
3106 FormalParameter parameter = _parseFormalParameter(kind);
3107 parameters.add(parameter);
3108 if (kind == ParameterKind.REQUIRED && wasOptionalParameter) {
3109 _reportErrorForNode(
3110 ParserErrorCode.NORMAL_BEFORE_OPTIONAL_PARAMETERS, parameter);
3111 }
3112 //
3113 // Handle the end of parameter groups.
3114 //
3115 // TODO(brianwilkerson) Improve the detection and reporting of missing and
3116 // mismatched delimiters.
3117 if (_matches(TokenType.CLOSE_SQUARE_BRACKET)) {
3118 rightSquareBracket = getAndAdvance();
3119 if (leftSquareBracket == null) {
3120 if (leftCurlyBracket != null) {
3121 _reportErrorForCurrentToken(
3122 ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]);
3123 rightCurlyBracket = rightSquareBracket;
3124 rightSquareBracket = null;
3125 } else {
3126 _reportErrorForCurrentToken(
3127 ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP,
3128 ["["]);
3129 }
3130 }
3131 kind = ParameterKind.REQUIRED;
3132 } else if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
3133 rightCurlyBracket = getAndAdvance();
3134 if (leftCurlyBracket == null) {
3135 if (leftSquareBracket != null) {
3136 _reportErrorForCurrentToken(
3137 ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]);
3138 rightSquareBracket = rightCurlyBracket;
3139 rightCurlyBracket = null;
3140 } else {
3141 _reportErrorForCurrentToken(
3142 ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP,
3143 ["{"]);
3144 }
3145 }
3146 kind = ParameterKind.REQUIRED;
3147 }
3148 } while (!_matches(TokenType.CLOSE_PAREN) &&
3149 !identical(initialToken, _currentToken));
3150 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
3151 //
3152 // Check that the groups were closed correctly.
3153 //
3154 if (leftSquareBracket != null && rightSquareBracket == null) {
3155 _reportErrorForCurrentToken(
3156 ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]);
3157 }
3158 if (leftCurlyBracket != null && rightCurlyBracket == null) {
3159 _reportErrorForCurrentToken(
3160 ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]);
3161 }
3162 //
3163 // Build the parameter list.
3164 //
3165 if (leftSquareBracket == null) {
3166 leftSquareBracket = leftCurlyBracket;
3167 }
3168 if (rightSquareBracket == null) {
3169 rightSquareBracket = rightCurlyBracket;
3170 }
3171 return new FormalParameterList(leftParenthesis, parameters,
3172 leftSquareBracket, rightSquareBracket, rightParenthesis);
3173 } 3111 }
3174 3112
3175 /** 3113 /**
3176 * Parse a function expression. Return the function expression that was 3114 * Parse a function expression. Return the function expression that was
3177 * parsed. 3115 * parsed.
3178 * 3116 *
3179 * functionExpression ::= 3117 * functionExpression ::=
3180 * typeParameters? formalParameterList functionExpressionBody 3118 * typeParameters? formalParameterList functionExpressionBody
3181 */ 3119 */
3182 FunctionExpression parseFunctionExpression() { 3120 FunctionExpression parseFunctionExpression() {
3183 TypeParameterList typeParameters = _parseGenericMethodTypeParameters(); 3121 TypeParameterList typeParameters = _parseGenericMethodTypeParameters();
3184 FormalParameterList parameters = parseFormalParameterList(); 3122 FormalParameterList parameters = parseFormalParameterList();
3185 _validateFormalParameterList(parameters); 3123 _validateFormalParameterList(parameters);
3186 FunctionBody body = 3124 FunctionBody body =
3187 _parseFunctionBody(false, ParserErrorCode.MISSING_FUNCTION_BODY, true); 3125 _parseFunctionBody(false, ParserErrorCode.MISSING_FUNCTION_BODY, true);
3188 return new FunctionExpression(typeParameters, parameters, body); 3126 return new FunctionExpression(typeParameters, parameters, body);
3189 } 3127 }
3190 3128
3191 /** 3129 /**
3192 * Parse an if-null expression. Return the if-null expression that was 3130 * Parse an if-null expression. Return the if-null expression that was
3193 * parsed. 3131 * parsed.
3194 * 3132 *
3195 * ifNullExpression ::= logicalOrExpression ('??' logicalOrExpression)* 3133 * ifNullExpression ::= logicalOrExpression ('??' logicalOrExpression)*
3196 */ 3134 */
3197 Expression parseIfNullExpression() { 3135 Expression parseIfNullExpression() {
3198 Expression expression = parseLogicalOrExpression(); 3136 Expression expression = parseLogicalOrExpression();
3199 while (_matches(TokenType.QUESTION_QUESTION)) { 3137 while (_currentToken.type == TokenType.QUESTION_QUESTION) {
3200 Token operator = getAndAdvance();
3201 expression = new BinaryExpression( 3138 expression = new BinaryExpression(
3202 expression, operator, parseLogicalOrExpression()); 3139 expression, getAndAdvance(), parseLogicalOrExpression());
3203 } 3140 }
3204 return expression; 3141 return expression;
3205 } 3142 }
3206 3143
3207 /** 3144 /**
3208 * Parse an implements clause. Return the implements clause that was parsed. 3145 * Parse an implements clause. Return the implements clause that was parsed.
3209 * 3146 *
3147 * This method assumes that the current token matches `Keyword.IMPLEMENTS`.
3148 *
3210 * implementsClause ::= 3149 * implementsClause ::=
3211 * 'implements' type (',' type)* 3150 * 'implements' type (',' type)*
3212 */ 3151 */
3213 ImplementsClause parseImplementsClause() { 3152 ImplementsClause parseImplementsClause() {
3214 Token keyword = _expectKeyword(Keyword.IMPLEMENTS); 3153 Token keyword = getAndAdvance();
3215 List<TypeName> interfaces = new List<TypeName>(); 3154 List<TypeName> interfaces = <TypeName>[];
3216 interfaces.add(parseTypeName()); 3155 interfaces.add(parseTypeName());
3217 while (_optional(TokenType.COMMA)) { 3156 while (_optional(TokenType.COMMA)) {
3218 interfaces.add(parseTypeName()); 3157 interfaces.add(parseTypeName());
3219 } 3158 }
3220 return new ImplementsClause(keyword, interfaces); 3159 return new ImplementsClause(keyword, interfaces);
3221 } 3160 }
3222 3161
3223 /** 3162 /**
3224 * Parse a label. Return the label that was parsed. 3163 * Parse a label. Return the label that was parsed.
3225 * 3164 *
3165 * This method assumes that the current token matches an identifier and that
3166 * the following token matches `TokenType.COLON`.
3167 *
3226 * label ::= 3168 * label ::=
3227 * identifier ':' 3169 * identifier ':'
3228 */ 3170 */
3229 Label parseLabel({bool isDeclaration: false}) { 3171 Label parseLabel({bool isDeclaration: false}) {
3230 SimpleIdentifier label = 3172 SimpleIdentifier label =
3231 parseSimpleIdentifier(isDeclaration: isDeclaration); 3173 _parseSimpleIdentifierUnchecked(isDeclaration: isDeclaration);
3232 Token colon = _expect(TokenType.COLON); 3174 Token colon = getAndAdvance();
3233 return new Label(label, colon); 3175 return new Label(label, colon);
3234 } 3176 }
3235 3177
3236 /** 3178 /**
3237 * Parse a library identifier. Return the library identifier that was parsed. 3179 * Parse a library identifier. Return the library identifier that was parsed.
3238 * 3180 *
3239 * libraryIdentifier ::= 3181 * libraryIdentifier ::=
3240 * identifier ('.' identifier)* 3182 * identifier ('.' identifier)*
3241 */ 3183 */
3242 LibraryIdentifier parseLibraryIdentifier() { 3184 LibraryIdentifier parseLibraryIdentifier() {
3243 List<SimpleIdentifier> components = new List<SimpleIdentifier>(); 3185 List<SimpleIdentifier> components = <SimpleIdentifier>[];
3244 components.add(parseSimpleIdentifier()); 3186 components.add(parseSimpleIdentifier());
3245 while (_matches(TokenType.PERIOD)) { 3187 while (_optional(TokenType.PERIOD)) {
3246 _advance();
3247 components.add(parseSimpleIdentifier()); 3188 components.add(parseSimpleIdentifier());
3248 } 3189 }
3249 return new LibraryIdentifier(components); 3190 return new LibraryIdentifier(components);
3250 } 3191 }
3251 3192
3252 /** 3193 /**
3253 * Parse a logical or expression. Return the logical or expression that was 3194 * Parse a logical or expression. Return the logical or expression that was
3254 * parsed. 3195 * parsed.
3255 * 3196 *
3256 * logicalOrExpression ::= 3197 * logicalOrExpression ::=
3257 * logicalAndExpression ('||' logicalAndExpression)* 3198 * logicalAndExpression ('||' logicalAndExpression)*
3258 */ 3199 */
3259 Expression parseLogicalOrExpression() { 3200 Expression parseLogicalOrExpression() {
3260 Expression expression = _parseLogicalAndExpression(); 3201 Expression expression = _parseLogicalAndExpression();
3261 while (_matches(TokenType.BAR_BAR)) { 3202 while (_currentToken.type == TokenType.BAR_BAR) {
3262 Token operator = getAndAdvance();
3263 expression = new BinaryExpression( 3203 expression = new BinaryExpression(
3264 expression, operator, _parseLogicalAndExpression()); 3204 expression, getAndAdvance(), _parseLogicalAndExpression());
3265 } 3205 }
3266 return expression; 3206 return expression;
3267 } 3207 }
3268 3208
3269 /** 3209 /**
3270 * Parse a map literal entry. Return the map literal entry that was parsed. 3210 * Parse a map literal entry. Return the map literal entry that was parsed.
3271 * 3211 *
3272 * mapLiteralEntry ::= 3212 * mapLiteralEntry ::=
3273 * expression ':' expression 3213 * expression ':' expression
3274 */ 3214 */
(...skipping 28 matching lines...) Expand all
3303 FinalConstVarOrType holder = _parseFinalConstVarOrType(true); 3243 FinalConstVarOrType holder = _parseFinalConstVarOrType(true);
3304 Token thisKeyword = null; 3244 Token thisKeyword = null;
3305 Token period = null; 3245 Token period = null;
3306 if (_matchesKeyword(Keyword.THIS)) { 3246 if (_matchesKeyword(Keyword.THIS)) {
3307 thisKeyword = getAndAdvance(); 3247 thisKeyword = getAndAdvance();
3308 period = _expect(TokenType.PERIOD); 3248 period = _expect(TokenType.PERIOD);
3309 } 3249 }
3310 SimpleIdentifier identifier = parseSimpleIdentifier(); 3250 SimpleIdentifier identifier = parseSimpleIdentifier();
3311 TypeParameterList typeParameters = _parseGenericMethodTypeParameters(); 3251 TypeParameterList typeParameters = _parseGenericMethodTypeParameters();
3312 if (_matches(TokenType.OPEN_PAREN)) { 3252 if (_matches(TokenType.OPEN_PAREN)) {
3313 FormalParameterList parameters = parseFormalParameterList(); 3253 FormalParameterList parameters = _parseFormalParameterListUnchecked();
3314 if (thisKeyword == null) { 3254 if (thisKeyword == null) {
3315 if (holder.keyword != null) { 3255 if (holder.keyword != null) {
3316 _reportErrorForToken( 3256 _reportErrorForToken(
3317 ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR, holder.keyword); 3257 ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR, holder.keyword);
3318 } 3258 }
3319 return new FunctionTypedFormalParameter( 3259 return new FunctionTypedFormalParameter(
3320 commentAndMetadata.comment, 3260 commentAndMetadata.comment,
3321 commentAndMetadata.metadata, 3261 commentAndMetadata.metadata,
3322 holder.type, 3262 holder.type,
3323 new SimpleIdentifier(identifier.token, isDeclaration: true), 3263 new SimpleIdentifier(identifier.token, isDeclaration: true),
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
3374 } 3314 }
3375 3315
3376 /** 3316 /**
3377 * Parse a prefixed identifier. Return the prefixed identifier that was 3317 * Parse a prefixed identifier. Return the prefixed identifier that was
3378 * parsed. 3318 * parsed.
3379 * 3319 *
3380 * prefixedIdentifier ::= 3320 * prefixedIdentifier ::=
3381 * identifier ('.' identifier)? 3321 * identifier ('.' identifier)?
3382 */ 3322 */
3383 Identifier parsePrefixedIdentifier() { 3323 Identifier parsePrefixedIdentifier() {
3384 SimpleIdentifier qualifier = parseSimpleIdentifier(); 3324 return _parsePrefixedIdentifierAfterIdentifier(parseSimpleIdentifier());
3385 if (!_matches(TokenType.PERIOD) || _injectGenericCommentTypeList()) {
3386 return qualifier;
3387 }
3388 Token period = getAndAdvance();
3389 SimpleIdentifier qualified = parseSimpleIdentifier();
3390 return new PrefixedIdentifier(qualifier, period, qualified);
3391 } 3325 }
3392 3326
3393 /** 3327 /**
3394 * Parse a return type. Return the return type that was parsed. 3328 * Parse a return type. Return the return type that was parsed.
3395 * 3329 *
3396 * returnType ::= 3330 * returnType ::=
3397 * 'void' 3331 * 'void'
3398 * | type 3332 * | type
3399 */ 3333 */
3400 TypeName parseReturnType() { 3334 TypeName parseReturnType() {
3401 if (_matchesKeyword(Keyword.VOID)) { 3335 if (_currentToken.keyword == Keyword.VOID) {
3402 return new TypeName(new SimpleIdentifier(getAndAdvance()), null); 3336 return new TypeName(new SimpleIdentifier(getAndAdvance()), null);
3403 } else { 3337 } else {
3404 return parseTypeName(); 3338 return parseTypeName();
3405 } 3339 }
3406 } 3340 }
3407 3341
3408 /** 3342 /**
3409 * Parse a simple identifier. Return the simple identifier that was parsed. 3343 * Parse a simple identifier. Return the simple identifier that was parsed.
3410 * 3344 *
3411 * identifier ::= 3345 * identifier ::=
3412 * IDENTIFIER 3346 * IDENTIFIER
3413 */ 3347 */
3414 SimpleIdentifier parseSimpleIdentifier({bool isDeclaration: false}) { 3348 SimpleIdentifier parseSimpleIdentifier({bool isDeclaration: false}) {
3415 if (_matchesIdentifier()) { 3349 if (_matchesIdentifier()) {
3416 String lexeme = _currentToken.lexeme; 3350 return _parseSimpleIdentifierUnchecked(isDeclaration: isDeclaration);
3417 if ((_inAsync || _inGenerator) &&
3418 (lexeme == 'async' || lexeme == 'await' || lexeme == 'yield')) {
3419 _reportErrorForCurrentToken(
3420 ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER);
3421 }
3422 return new SimpleIdentifier(getAndAdvance(),
3423 isDeclaration: isDeclaration);
3424 } 3351 }
3425 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); 3352 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
3426 return _createSyntheticIdentifier(isDeclaration: isDeclaration); 3353 return _createSyntheticIdentifier(isDeclaration: isDeclaration);
3427 } 3354 }
3428 3355
3429 /** 3356 /**
3430 * Parse a statement, starting with the given [token]. Return the statement 3357 * Parse a statement, starting with the given [token]. Return the statement
3431 * that was parsed, or `null` if the tokens do not represent a recognizable 3358 * that was parsed, or `null` if the tokens do not represent a recognizable
3432 * statement. 3359 * statement.
3433 */ 3360 */
3434 Statement parseStatement(Token token) { 3361 Statement parseStatement(Token token) {
3435 _currentToken = token; 3362 _currentToken = token;
3436 return parseStatement2(); 3363 return parseStatement2();
3437 } 3364 }
3438 3365
3439 /** 3366 /**
3440 * Parse a statement. Return the statement that was parsed. 3367 * Parse a statement. Return the statement that was parsed.
3441 * 3368 *
3442 * statement ::= 3369 * statement ::=
3443 * label* nonLabeledStatement 3370 * label* nonLabeledStatement
3444 */ 3371 */
3445 Statement parseStatement2() { 3372 Statement parseStatement2() {
3446 List<Label> labels = null; 3373 List<Label> labels = null;
3447 while (_matchesIdentifier() && _tokenMatches(_peek(), TokenType.COLON)) { 3374 while (_matchesIdentifier() && _currentToken.next.type == TokenType.COLON) {
3448 Label label = parseLabel(isDeclaration: true); 3375 Label label = parseLabel(isDeclaration: true);
3449 if (labels == null) { 3376 if (labels == null) {
3450 labels = <Label>[label]; 3377 labels = <Label>[label];
3451 } else { 3378 } else {
3452 labels.add(label); 3379 labels.add(label);
3453 } 3380 }
3454 } 3381 }
3455 Statement statement = _parseNonLabeledStatement(); 3382 Statement statement = _parseNonLabeledStatement();
3456 if (labels == null) { 3383 if (labels == null) {
3457 return statement; 3384 return statement;
(...skipping 12 matching lines...) Expand all
3470 } 3397 }
3471 3398
3472 /** 3399 /**
3473 * Parse a string literal. Return the string literal that was parsed. 3400 * Parse a string literal. Return the string literal that was parsed.
3474 * 3401 *
3475 * stringLiteral ::= 3402 * stringLiteral ::=
3476 * MULTI_LINE_STRING+ 3403 * MULTI_LINE_STRING+
3477 * | SINGLE_LINE_STRING+ 3404 * | SINGLE_LINE_STRING+
3478 */ 3405 */
3479 StringLiteral parseStringLiteral() { 3406 StringLiteral parseStringLiteral() {
3480 List<StringLiteral> strings = new List<StringLiteral>(); 3407 if (_matches(TokenType.STRING)) {
3481 while (_matches(TokenType.STRING)) { 3408 return _parseStringLiteralUnchecked();
3482 Token string = getAndAdvance();
3483 if (_matches(TokenType.STRING_INTERPOLATION_EXPRESSION) ||
3484 _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER)) {
3485 strings.add(_parseStringInterpolation(string));
3486 } else {
3487 strings.add(new SimpleStringLiteral(
3488 string, _computeStringValue(string.lexeme, true, true)));
3489 }
3490 } 3409 }
3491 if (strings.length < 1) { 3410 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_STRING_LITERAL);
3492 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_STRING_LITERAL); 3411 return _createSyntheticStringLiteral();
3493 return _createSyntheticStringLiteral();
3494 } else if (strings.length == 1) {
3495 return strings[0];
3496 } else {
3497 return new AdjacentStrings(strings);
3498 }
3499 } 3412 }
3500 3413
3501 /** 3414 /**
3502 * Parse a list of type arguments. Return the type argument list that was 3415 * Parse a list of type arguments. Return the type argument list that was
3503 * parsed. 3416 * parsed.
3504 * 3417 *
3418 * This method assumes that the current token matches `TokenType.LT`.
3419 *
3505 * typeArguments ::= 3420 * typeArguments ::=
3506 * '<' typeList '>' 3421 * '<' typeList '>'
3507 * 3422 *
3508 * typeList ::= 3423 * typeList ::=
3509 * type (',' type)* 3424 * type (',' type)*
3510 */ 3425 */
3511 TypeArgumentList parseTypeArgumentList() { 3426 TypeArgumentList parseTypeArgumentList() {
3512 Token leftBracket = _expect(TokenType.LT); 3427 Token leftBracket = getAndAdvance();
3513 List<TypeName> arguments = new List<TypeName>(); 3428 List<TypeName> arguments = <TypeName>[parseTypeName()];
3514 arguments.add(parseTypeName());
3515 while (_optional(TokenType.COMMA)) { 3429 while (_optional(TokenType.COMMA)) {
3516 arguments.add(parseTypeName()); 3430 arguments.add(parseTypeName());
3517 } 3431 }
3518 Token rightBracket = _expectGt(); 3432 Token rightBracket = _expectGt();
3519 return new TypeArgumentList(leftBracket, arguments, rightBracket); 3433 return new TypeArgumentList(leftBracket, arguments, rightBracket);
3520 } 3434 }
3521 3435
3522 /** 3436 /**
3523 * Parse a type name. Return the type name that was parsed. 3437 * Parse a type name. Return the type name that was parsed.
3524 * 3438 *
3525 * type ::= 3439 * type ::=
3526 * qualified typeArguments? 3440 * qualified typeArguments?
3527 */ 3441 */
3528 TypeName parseTypeName() { 3442 TypeName parseTypeName() {
3529 TypeName realType = _parseTypeName(); 3443 TypeName realType = _parseTypeName();
3530 // If this is followed by a generic method type comment, allow the comment 3444 // If this is followed by a generic method type comment, allow the comment
3531 // type to replace the real type name. 3445 // type to replace the real type name.
3532 // TODO(jmesserly): this feels like a big hammer. Can we restrict it to 3446 // TODO(jmesserly): this feels like a big hammer. Can we restrict it to
3533 // only work inside generic methods? 3447 // only work inside generic methods?
3534 TypeName typeComment = _parseOptionalTypeNameComment(); 3448 TypeName typeFromComment = _parseOptionalTypeNameComment();
3535 return typeComment ?? realType; 3449 return typeFromComment ?? realType;
3536 } 3450 }
3537 3451
3538 /** 3452 /**
3539 * Parse a type parameter. Return the type parameter that was parsed. 3453 * Parse a type parameter. Return the type parameter that was parsed.
3540 * 3454 *
3541 * typeParameter ::= 3455 * typeParameter ::=
3542 * metadata name ('extends' bound)? 3456 * metadata name ('extends' bound)?
3543 */ 3457 */
3544 TypeParameter parseTypeParameter() { 3458 TypeParameter parseTypeParameter() {
3545 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); 3459 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata();
3546 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true); 3460 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
3547 if (_matchesKeyword(Keyword.EXTENDS)) { 3461 if (_matchesKeyword(Keyword.EXTENDS)) {
3548 Token keyword = getAndAdvance(); 3462 Token keyword = getAndAdvance();
3549 TypeName bound = parseTypeName(); 3463 TypeName bound = parseTypeName();
3550 return new TypeParameter(commentAndMetadata.comment, 3464 return new TypeParameter(commentAndMetadata.comment,
3551 commentAndMetadata.metadata, name, keyword, bound); 3465 commentAndMetadata.metadata, name, keyword, bound);
3552 } 3466 }
3553 return new TypeParameter(commentAndMetadata.comment, 3467 return new TypeParameter(commentAndMetadata.comment,
3554 commentAndMetadata.metadata, name, null, null); 3468 commentAndMetadata.metadata, name, null, null);
3555 } 3469 }
3556 3470
3557 /** 3471 /**
3558 * Parse a list of type parameters. Return the list of type parameters that 3472 * Parse a list of type parameters. Return the list of type parameters that
3559 * were parsed. 3473 * were parsed.
3560 * 3474 *
3475 * This method assumes that the current token matches `TokenType.LT`.
3476 *
3561 * typeParameterList ::= 3477 * typeParameterList ::=
3562 * '<' typeParameter (',' typeParameter)* '>' 3478 * '<' typeParameter (',' typeParameter)* '>'
3563 */ 3479 */
3564 TypeParameterList parseTypeParameterList() { 3480 TypeParameterList parseTypeParameterList() {
3565 Token leftBracket = _expect(TokenType.LT); 3481 Token leftBracket = getAndAdvance();
3566 List<TypeParameter> typeParameters = new List<TypeParameter>(); 3482 List<TypeParameter> typeParameters = <TypeParameter>[parseTypeParameter()];
3567 typeParameters.add(parseTypeParameter());
3568 while (_optional(TokenType.COMMA)) { 3483 while (_optional(TokenType.COMMA)) {
3569 typeParameters.add(parseTypeParameter()); 3484 typeParameters.add(parseTypeParameter());
3570 } 3485 }
3571 Token rightBracket = _expectGt(); 3486 Token rightBracket = _expectGt();
3572 return new TypeParameterList(leftBracket, typeParameters, rightBracket); 3487 return new TypeParameterList(leftBracket, typeParameters, rightBracket);
3573 } 3488 }
3574 3489
3575 /** 3490 /**
3576 * Parse a with clause. Return the with clause that was parsed. 3491 * Parse a with clause. Return the with clause that was parsed.
3577 * 3492 *
3493 * This method assumes that the current token matches `Keyword.WITH`.
3494 *
3578 * withClause ::= 3495 * withClause ::=
3579 * 'with' typeName (',' typeName)* 3496 * 'with' typeName (',' typeName)*
3580 */ 3497 */
3581 WithClause parseWithClause() { 3498 WithClause parseWithClause() {
3582 Token with2 = _expectKeyword(Keyword.WITH); 3499 Token withKeyword = getAndAdvance();
3583 List<TypeName> types = new List<TypeName>(); 3500 List<TypeName> types = <TypeName>[parseTypeName()];
3584 types.add(parseTypeName());
3585 while (_optional(TokenType.COMMA)) { 3501 while (_optional(TokenType.COMMA)) {
3586 types.add(parseTypeName()); 3502 types.add(parseTypeName());
3587 } 3503 }
3588 return new WithClause(with2, types); 3504 return new WithClause(withKeyword, types);
3589 } 3505 }
3590 3506
3591 /** 3507 /**
3592 * Advance to the next token in the token stream. 3508 * Advance to the next token in the token stream.
3593 */ 3509 */
3594 void _advance() { 3510 void _advance() {
3595 _currentToken = _currentToken.next; 3511 _currentToken = _currentToken.next;
3596 } 3512 }
3597 3513
3598 /** 3514 /**
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
3662 new FunctionExpression( 3578 new FunctionExpression(
3663 method.typeParameters, method.parameters, method.body)); 3579 method.typeParameters, method.parameters, method.body));
3664 3580
3665 /** 3581 /**
3666 * Return `true` if the current token could be the start of a compilation unit 3582 * Return `true` if the current token could be the start of a compilation unit
3667 * member. This method is used for recovery purposes to decide when to stop 3583 * member. This method is used for recovery purposes to decide when to stop
3668 * skipping tokens after finding an error while parsing a compilation unit 3584 * skipping tokens after finding an error while parsing a compilation unit
3669 * member. 3585 * member.
3670 */ 3586 */
3671 bool _couldBeStartOfCompilationUnitMember() { 3587 bool _couldBeStartOfCompilationUnitMember() {
3672 if ((_matchesKeyword(Keyword.IMPORT) || 3588 Keyword keyword = _currentToken.keyword;
3673 _matchesKeyword(Keyword.EXPORT) || 3589 Token next = _currentToken.next;
3674 _matchesKeyword(Keyword.LIBRARY) || 3590 TokenType nextType = next.type;
3675 _matchesKeyword(Keyword.PART)) && 3591 if ((keyword == Keyword.IMPORT ||
3676 !_tokenMatches(_peek(), TokenType.PERIOD) && 3592 keyword == Keyword.EXPORT ||
3677 !_tokenMatches(_peek(), TokenType.LT)) { 3593 keyword == Keyword.LIBRARY ||
3594 keyword == Keyword.PART) &&
3595 nextType != TokenType.PERIOD &&
3596 nextType != TokenType.LT) {
3678 // This looks like the start of a directive 3597 // This looks like the start of a directive
3679 return true; 3598 return true;
3680 } else if (_matchesKeyword(Keyword.CLASS)) { 3599 } else if (keyword == Keyword.CLASS) {
3681 // This looks like the start of a class definition 3600 // This looks like the start of a class definition
3682 return true; 3601 return true;
3683 } else if (_matchesKeyword(Keyword.TYPEDEF) && 3602 } else if (keyword == Keyword.TYPEDEF &&
3684 !_tokenMatches(_peek(), TokenType.PERIOD) && 3603 nextType != TokenType.PERIOD &&
3685 !_tokenMatches(_peek(), TokenType.LT)) { 3604 nextType != TokenType.LT) {
3686 // This looks like the start of a typedef 3605 // This looks like the start of a typedef
3687 return true; 3606 return true;
3688 } else if (_matchesKeyword(Keyword.VOID) || 3607 } else if (keyword == Keyword.VOID ||
3689 ((_matchesKeyword(Keyword.GET) || _matchesKeyword(Keyword.SET)) && 3608 ((keyword == Keyword.GET || keyword == Keyword.SET) &&
3690 _tokenMatchesIdentifier(_peek())) || 3609 _tokenMatchesIdentifier(next)) ||
3691 (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek()))) { 3610 (keyword == Keyword.OPERATOR && _isOperator(next))) {
3692 // This looks like the start of a function 3611 // This looks like the start of a function
3693 return true; 3612 return true;
3694 } else if (_matchesIdentifier()) { 3613 } else if (_matchesIdentifier()) {
3695 if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { 3614 if (nextType == TokenType.OPEN_PAREN) {
3696 // This looks like the start of a function 3615 // This looks like the start of a function
3697 return true; 3616 return true;
3698 } 3617 }
3699 Token token = _skipReturnType(_currentToken); 3618 Token token = _skipReturnType(_currentToken);
3700 if (token == null) { 3619 if (token == null) {
3701 return false; 3620 return false;
3702 } 3621 }
3703 if (_matchesKeyword(Keyword.GET) || 3622 // TODO(brianwilkerson) This looks wrong; should we be checking 'token'?
3704 _matchesKeyword(Keyword.SET) || 3623 if (keyword == Keyword.GET ||
3705 (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) || 3624 keyword == Keyword.SET ||
3625 (keyword == Keyword.OPERATOR && _isOperator(next)) ||
3706 _matchesIdentifier()) { 3626 _matchesIdentifier()) {
3707 return true; 3627 return true;
3708 } 3628 }
3709 } 3629 }
3710 return false; 3630 return false;
3711 } 3631 }
3712 3632
3713 /** 3633 /**
3714 * Return a synthetic identifier. 3634 * Return a synthetic identifier.
3715 */ 3635 */
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
3865 } 3785 }
3866 } 3786 }
3867 return null; 3787 return null;
3868 } 3788 }
3869 3789
3870 /** 3790 /**
3871 * Return a list of the ranges of characters in the given [comment] that 3791 * Return a list of the ranges of characters in the given [comment] that
3872 * should be treated as code blocks. 3792 * should be treated as code blocks.
3873 */ 3793 */
3874 List<List<int>> _getCodeBlockRanges(String comment) { 3794 List<List<int>> _getCodeBlockRanges(String comment) {
3875 List<List<int>> ranges = new List<List<int>>(); 3795 List<List<int>> ranges = <List<int>>[];
3876 int length = comment.length; 3796 int length = comment.length;
3877 if (length < 3) { 3797 if (length < 3) {
3878 return ranges; 3798 return ranges;
3879 } 3799 }
3880 int index = 0; 3800 int index = 0;
3881 int firstChar = comment.codeUnitAt(0); 3801 int firstChar = comment.codeUnitAt(0);
3882 if (firstChar == 0x2F) { 3802 if (firstChar == 0x2F) {
3883 int secondChar = comment.codeUnitAt(1); 3803 int secondChar = comment.codeUnitAt(1);
3884 int thirdChar = comment.codeUnitAt(2); 3804 int thirdChar = comment.codeUnitAt(2);
3885 if ((secondChar == 0x2A && thirdChar == 0x2A) || 3805 if ((secondChar == 0x2A && thirdChar == 0x2A) ||
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
4008 lastToken.setNext(_currentToken); 3928 lastToken.setNext(_currentToken);
4009 previous.setNext(firstToken); 3929 previous.setNext(firstToken);
4010 _currentToken = firstToken; 3930 _currentToken = firstToken;
4011 } 3931 }
4012 3932
4013 /** 3933 /**
4014 * Return `true` if the current token appears to be the beginning of a 3934 * Return `true` if the current token appears to be the beginning of a
4015 * function declaration. 3935 * function declaration.
4016 */ 3936 */
4017 bool _isFunctionDeclaration() { 3937 bool _isFunctionDeclaration() {
4018 if (_matchesKeyword(Keyword.VOID)) { 3938 Keyword keyword = _currentToken.keyword;
3939 if (keyword == Keyword.VOID) {
4019 return true; 3940 return true;
4020 } 3941 }
4021 Token afterReturnType = _skipTypeName(_currentToken); 3942 Token afterReturnType = _skipTypeName(_currentToken);
4022 if (afterReturnType == null) { 3943 if (afterReturnType == null) {
4023 // There was no return type, but it is optional, so go back to where we 3944 // There was no return type, but it is optional, so go back to where we
4024 // started. 3945 // started.
4025 afterReturnType = _currentToken; 3946 afterReturnType = _currentToken;
4026 } 3947 }
4027 Token afterIdentifier = _skipSimpleIdentifier(afterReturnType); 3948 Token afterIdentifier = _skipSimpleIdentifier(afterReturnType);
4028 if (afterIdentifier == null) { 3949 if (afterIdentifier == null) {
4029 // It's possible that we parsed the function name as if it were a type 3950 // It's possible that we parsed the function name as if it were a type
4030 // name, so see whether it makes sense if we assume that there is no type. 3951 // name, so see whether it makes sense if we assume that there is no type.
4031 afterIdentifier = _skipSimpleIdentifier(_currentToken); 3952 afterIdentifier = _skipSimpleIdentifier(_currentToken);
4032 } 3953 }
4033 if (afterIdentifier == null) { 3954 if (afterIdentifier == null) {
4034 return false; 3955 return false;
4035 } 3956 }
4036 if (_isFunctionExpression(afterIdentifier)) { 3957 if (_isFunctionExpression(afterIdentifier)) {
4037 return true; 3958 return true;
4038 } 3959 }
4039 // It's possible that we have found a getter. While this isn't valid at this 3960 // It's possible that we have found a getter. While this isn't valid at this
4040 // point we test for it in order to recover better. 3961 // point we test for it in order to recover better.
4041 if (_matchesKeyword(Keyword.GET)) { 3962 if (keyword == Keyword.GET) {
4042 Token afterName = _skipSimpleIdentifier(_currentToken.next); 3963 Token afterName = _skipSimpleIdentifier(_currentToken.next);
4043 if (afterName == null) { 3964 if (afterName == null) {
4044 return false; 3965 return false;
4045 } 3966 }
4046 return _tokenMatches(afterName, TokenType.FUNCTION) || 3967 TokenType type = afterName.type;
4047 _tokenMatches(afterName, TokenType.OPEN_CURLY_BRACKET); 3968 return type == TokenType.FUNCTION || type == TokenType.OPEN_CURLY_BRACKET;
4048 } else if (_tokenMatchesKeyword(afterReturnType, Keyword.GET)) { 3969 } else if (_tokenMatchesKeyword(afterReturnType, Keyword.GET)) {
4049 Token afterName = _skipSimpleIdentifier(afterReturnType.next); 3970 Token afterName = _skipSimpleIdentifier(afterReturnType.next);
4050 if (afterName == null) { 3971 if (afterName == null) {
4051 return false; 3972 return false;
4052 } 3973 }
4053 return _tokenMatches(afterName, TokenType.FUNCTION) || 3974 TokenType type = afterName.type;
4054 _tokenMatches(afterName, TokenType.OPEN_CURLY_BRACKET); 3975 return type == TokenType.FUNCTION || type == TokenType.OPEN_CURLY_BRACKET;
4055 } 3976 }
4056 return false; 3977 return false;
4057 } 3978 }
4058 3979
4059 /** 3980 /**
4060 * Return `true` if the given [token] appears to be the beginning of a 3981 * Return `true` if the given [token] appears to be the beginning of a
4061 * function expression. 3982 * function expression.
4062 */ 3983 */
4063 bool _isFunctionExpression(Token token) { 3984 bool _isFunctionExpression(Token token) {
4064 // Function expressions aren't allowed in initializer lists. 3985 // Function expressions aren't allowed in initializer lists.
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
4107 * | 'var' 4028 * | 'var'
4108 * | type 4029 * | type
4109 * 4030 *
4110 * type ::= 4031 * type ::=
4111 * qualified typeArguments? 4032 * qualified typeArguments?
4112 * 4033 *
4113 * initializedIdentifier ::= 4034 * initializedIdentifier ::=
4114 * identifier ('=' expression)? 4035 * identifier ('=' expression)?
4115 */ 4036 */
4116 bool _isInitializedVariableDeclaration() { 4037 bool _isInitializedVariableDeclaration() {
4117 if (_matchesKeyword(Keyword.FINAL) || _matchesKeyword(Keyword.VAR)) { 4038 Keyword keyword = _currentToken.keyword;
4039 if (keyword == Keyword.FINAL || keyword == Keyword.VAR) {
4118 // An expression cannot start with a keyword other than 'const', 4040 // An expression cannot start with a keyword other than 'const',
4119 // 'rethrow', or 'throw'. 4041 // 'rethrow', or 'throw'.
4120 return true; 4042 return true;
4121 } 4043 }
4122 if (_matchesKeyword(Keyword.CONST)) { 4044 if (keyword == Keyword.CONST) {
4123 // Look to see whether we might be at the start of a list or map literal, 4045 // Look to see whether we might be at the start of a list or map literal,
4124 // otherwise this should be the start of a variable declaration. 4046 // otherwise this should be the start of a variable declaration.
4125 return !_peek().matchesAny(const <TokenType>[ 4047 return !_peek().matchesAny(const <TokenType>[
4126 TokenType.LT, 4048 TokenType.LT,
4127 TokenType.OPEN_CURLY_BRACKET, 4049 TokenType.OPEN_CURLY_BRACKET,
4128 TokenType.OPEN_SQUARE_BRACKET, 4050 TokenType.OPEN_SQUARE_BRACKET,
4129 TokenType.INDEX 4051 TokenType.INDEX
4130 ]); 4052 ]);
4131 } 4053 }
4132 bool allowAdditionalTokens = true; 4054 bool allowAdditionalTokens = true;
(...skipping 16 matching lines...) Expand all
4149 } 4071 }
4150 TokenType type = token.type; 4072 TokenType type = token.type;
4151 // Usual cases in valid code: 4073 // Usual cases in valid code:
4152 // String v = ''; 4074 // String v = '';
4153 // String v, v2; 4075 // String v, v2;
4154 // String v; 4076 // String v;
4155 // for (String item in items) {} 4077 // for (String item in items) {}
4156 if (type == TokenType.EQ || 4078 if (type == TokenType.EQ ||
4157 type == TokenType.COMMA || 4079 type == TokenType.COMMA ||
4158 type == TokenType.SEMICOLON || 4080 type == TokenType.SEMICOLON ||
4159 _tokenMatchesKeyword(token, Keyword.IN)) { 4081 token.keyword == Keyword.IN) {
4160 return true; 4082 return true;
4161 } 4083 }
4162 // It is OK to parse as a variable declaration in these cases: 4084 // It is OK to parse as a variable declaration in these cases:
4163 // String v } 4085 // String v }
4164 // String v if (true) print('OK'); 4086 // String v if (true) print('OK');
4165 // String v { print(42); } 4087 // String v { print(42); }
4166 // ...but not in these cases: 4088 // ...but not in these cases:
4167 // get getterName { 4089 // get getterName {
4168 // String get getterName 4090 // String get getterName
4169 if (allowAdditionalTokens) { 4091 if (allowAdditionalTokens) {
4170 if (type == TokenType.CLOSE_CURLY_BRACKET || 4092 if (type == TokenType.CLOSE_CURLY_BRACKET ||
4171 type == TokenType.KEYWORD || 4093 type == TokenType.KEYWORD ||
4172 type == TokenType.IDENTIFIER || 4094 type == TokenType.IDENTIFIER ||
4173 type == TokenType.OPEN_CURLY_BRACKET) { 4095 type == TokenType.OPEN_CURLY_BRACKET) {
4174 return true; 4096 return true;
4175 } 4097 }
4176 } 4098 }
4177 return false; 4099 return false;
4178 } 4100 }
4179 4101
4180 bool _isLikelyArgumentList() { 4102 bool _isLikelyArgumentList() {
4103 // Try to reduce the amount of lookahead required here before enabling
4104 // generic methods.
4181 if (_matches(TokenType.OPEN_PAREN)) { 4105 if (_matches(TokenType.OPEN_PAREN)) {
4182 return true; 4106 return true;
4183 } 4107 }
4184 if (!parseGenericMethods) { 4108 if (!parseGenericMethods) {
4185 return false; 4109 return false;
4186 } 4110 }
4187 Token token = _skipTypeArgumentList(_currentToken); 4111 Token token = _skipTypeArgumentList(_currentToken);
4188 return token != null && _tokenMatches(token, TokenType.OPEN_PAREN); 4112 return token != null && _tokenMatches(token, TokenType.OPEN_PAREN);
4189 } 4113 }
4190 4114
(...skipping 30 matching lines...) Expand all
4221 4145
4222 /** 4146 /**
4223 * Return `true` if the given [startToken] appears to be the beginning of an 4147 * Return `true` if the given [startToken] appears to be the beginning of an
4224 * operator declaration. 4148 * operator declaration.
4225 */ 4149 */
4226 bool _isOperator(Token startToken) { 4150 bool _isOperator(Token startToken) {
4227 // Accept any operator here, even if it is not user definable. 4151 // Accept any operator here, even if it is not user definable.
4228 if (!startToken.isOperator) { 4152 if (!startToken.isOperator) {
4229 return false; 4153 return false;
4230 } 4154 }
4231 // Token "=" means that it is actually field initializer. 4155 // Token "=" means that it is actually a field initializer.
4232 if (startToken.type == TokenType.EQ) { 4156 if (startToken.type == TokenType.EQ) {
4233 return false; 4157 return false;
4234 } 4158 }
4235 // Consume all operator tokens. 4159 // Consume all operator tokens.
4236 Token token = startToken.next; 4160 Token token = startToken.next;
4237 while (token.isOperator) { 4161 while (token.isOperator) {
4238 token = token.next; 4162 token = token.next;
4239 } 4163 }
4240 // Formal parameter list is expect now. 4164 // Formal parameter list is expect now.
4241 return _tokenMatches(token, TokenType.OPEN_PAREN); 4165 return _tokenMatches(token, TokenType.OPEN_PAREN);
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
4365 bool _matchesString(String identifier) => 4289 bool _matchesString(String identifier) =>
4366 _currentToken.type == TokenType.IDENTIFIER && 4290 _currentToken.type == TokenType.IDENTIFIER &&
4367 _currentToken.lexeme == identifier; 4291 _currentToken.lexeme == identifier;
4368 4292
4369 /** 4293 /**
4370 * If the current token has the given [type], then advance to the next token 4294 * If the current token has the given [type], then advance to the next token
4371 * and return `true`. Otherwise, return `false` without advancing. This method 4295 * and return `true`. Otherwise, return `false` without advancing. This method
4372 * should not be invoked with an argument value of [TokenType.GT]. 4296 * should not be invoked with an argument value of [TokenType.GT].
4373 */ 4297 */
4374 bool _optional(TokenType type) { 4298 bool _optional(TokenType type) {
4375 if (_matches(type)) { 4299 if (_currentToken.type == type) {
4376 _advance(); 4300 _advance();
4377 return true; 4301 return true;
4378 } 4302 }
4379 return false; 4303 return false;
4380 } 4304 }
4381 4305
4382 /** 4306 /**
4383 * Parse an additive expression. Return the additive expression that was 4307 * Parse an additive expression. Return the additive expression that was
4384 * parsed. 4308 * parsed.
4385 * 4309 *
4386 * additiveExpression ::= 4310 * additiveExpression ::=
4387 * multiplicativeExpression (additiveOperator multiplicativeExpression )* 4311 * multiplicativeExpression (additiveOperator multiplicativeExpression )*
4388 * | 'super' (additiveOperator multiplicativeExpression)+ 4312 * | 'super' (additiveOperator multiplicativeExpression)+
4389 */ 4313 */
4390 Expression _parseAdditiveExpression() { 4314 Expression _parseAdditiveExpression() {
4391 Expression expression; 4315 Expression expression;
4392 if (_matchesKeyword(Keyword.SUPER) && 4316 if (_currentToken.keyword == Keyword.SUPER &&
4393 _currentToken.next.type.isAdditiveOperator) { 4317 _currentToken.next.type.isAdditiveOperator) {
4394 expression = new SuperExpression(getAndAdvance()); 4318 expression = new SuperExpression(getAndAdvance());
4395 } else { 4319 } else {
4396 expression = _parseMultiplicativeExpression(); 4320 expression = _parseMultiplicativeExpression();
4397 } 4321 }
4398 while (_currentToken.type.isAdditiveOperator) { 4322 while (_currentToken.type.isAdditiveOperator) {
4399 Token operator = getAndAdvance();
4400 expression = new BinaryExpression( 4323 expression = new BinaryExpression(
4401 expression, operator, _parseMultiplicativeExpression()); 4324 expression, getAndAdvance(), _parseMultiplicativeExpression());
4402 } 4325 }
4403 return expression; 4326 return expression;
4404 } 4327 }
4405 4328
4406 /** 4329 /**
4330 * Parse an argument list when we need to check for an open paren and recover
4331 * when there isn't one. Return the argument list that was parsed.
4332 */
4333 ArgumentList _parseArgumentListChecked() {
4334 if (_matches(TokenType.OPEN_PAREN)) {
4335 return parseArgumentList();
4336 }
4337 _reportErrorForCurrentToken(
4338 ParserErrorCode.EXPECTED_TOKEN, [TokenType.OPEN_PAREN.lexeme]);
4339 // Recovery: Look to see whether there is a close paren that isn't matched
4340 // to an open paren and if so parse the list of arguments as normal.
4341 return new ArgumentList(_createSyntheticToken(TokenType.OPEN_PAREN), null,
4342 _createSyntheticToken(TokenType.CLOSE_PAREN));
4343 }
4344
4345 /**
4407 * Parse an assert statement. Return the assert statement. 4346 * Parse an assert statement. Return the assert statement.
4408 * 4347 *
4348 * This method assumes that the current token matches `Keyword.ASSERT`.
4349 *
4409 * assertStatement ::= 4350 * assertStatement ::=
4410 * 'assert' '(' conditionalExpression ')' ';' 4351 * 'assert' '(' conditionalExpression ')' ';'
4411 */ 4352 */
4412 AssertStatement _parseAssertStatement() { 4353 AssertStatement _parseAssertStatement() {
4413 Token keyword = _expectKeyword(Keyword.ASSERT); 4354 Token keyword = getAndAdvance();
4414 Token leftParen = _expect(TokenType.OPEN_PAREN); 4355 Token leftParen = _expect(TokenType.OPEN_PAREN);
4415 Expression expression = parseExpression2(); 4356 Expression expression = parseExpression2();
4416 if (expression is AssignmentExpression) { 4357 if (expression is AssignmentExpression) {
4417 _reportErrorForNode( 4358 _reportErrorForNode(
4418 ParserErrorCode.ASSERT_DOES_NOT_TAKE_ASSIGNMENT, expression); 4359 ParserErrorCode.ASSERT_DOES_NOT_TAKE_ASSIGNMENT, expression);
4419 } else if (expression is CascadeExpression) { 4360 } else if (expression is CascadeExpression) {
4420 _reportErrorForNode( 4361 _reportErrorForNode(
4421 ParserErrorCode.ASSERT_DOES_NOT_TAKE_CASCADE, expression); 4362 ParserErrorCode.ASSERT_DOES_NOT_TAKE_CASCADE, expression);
4422 } else if (expression is ThrowExpression) { 4363 } else if (expression is ThrowExpression) {
4423 _reportErrorForNode( 4364 _reportErrorForNode(
(...skipping 23 matching lines...) Expand all
4447 * primary (arguments* assignableSelector)+ 4388 * primary (arguments* assignableSelector)+
4448 * | 'super' unconditionalAssignableSelector 4389 * | 'super' unconditionalAssignableSelector
4449 * | identifier 4390 * | identifier
4450 */ 4391 */
4451 Expression _parseAssignableExpression(bool primaryAllowed) { 4392 Expression _parseAssignableExpression(bool primaryAllowed) {
4452 if (_matchesKeyword(Keyword.SUPER)) { 4393 if (_matchesKeyword(Keyword.SUPER)) {
4453 return _parseAssignableSelector( 4394 return _parseAssignableSelector(
4454 new SuperExpression(getAndAdvance()), false, 4395 new SuperExpression(getAndAdvance()), false,
4455 allowConditional: false); 4396 allowConditional: false);
4456 } 4397 }
4398 return _parseAssignableExpressionNotStartingWithSuper(primaryAllowed);
4399 }
4400
4401 /**
4402 * Parse an assignable expression given that the current token is not 'super'.
4403 * The [primaryAllowed] is `true` if the expression is allowed to be a primary
4404 * without any assignable selector. Return the assignable expression that was
4405 * parsed.
4406 */
4407 Expression _parseAssignableExpressionNotStartingWithSuper(
4408 bool primaryAllowed) {
4457 // 4409 //
4458 // A primary expression can start with an identifier. We resolve the 4410 // A primary expression can start with an identifier. We resolve the
4459 // ambiguity by determining whether the primary consists of anything other 4411 // ambiguity by determining whether the primary consists of anything other
4460 // than an identifier and/or is followed by an assignableSelector. 4412 // than an identifier and/or is followed by an assignableSelector.
4461 // 4413 //
4462 Expression expression = _parsePrimaryExpression(); 4414 Expression expression = _parsePrimaryExpression();
4463 bool isOptional = primaryAllowed || expression is SimpleIdentifier; 4415 bool isOptional = primaryAllowed || expression is SimpleIdentifier;
4464 while (true) { 4416 while (true) {
4465 while (_isLikelyArgumentList()) { 4417 while (_isLikelyArgumentList()) {
4466 TypeArgumentList typeArguments = _parseOptionalTypeArguments(); 4418 TypeArgumentList typeArguments = _parseOptionalTypeArguments();
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
4516 * unconditionalAssignableSelector ::= 4468 * unconditionalAssignableSelector ::=
4517 * '[' expression ']' 4469 * '[' expression ']'
4518 * | '.' identifier 4470 * | '.' identifier
4519 * 4471 *
4520 * assignableSelector ::= 4472 * assignableSelector ::=
4521 * unconditionalAssignableSelector 4473 * unconditionalAssignableSelector
4522 * | '?.' identifier 4474 * | '?.' identifier
4523 */ 4475 */
4524 Expression _parseAssignableSelector(Expression prefix, bool optional, 4476 Expression _parseAssignableSelector(Expression prefix, bool optional,
4525 {bool allowConditional: true}) { 4477 {bool allowConditional: true}) {
4526 if (_matches(TokenType.OPEN_SQUARE_BRACKET)) { 4478 TokenType type = _currentToken.type;
4479 if (type == TokenType.OPEN_SQUARE_BRACKET) {
4527 Token leftBracket = getAndAdvance(); 4480 Token leftBracket = getAndAdvance();
4528 bool wasInInitializer = _inInitializer; 4481 bool wasInInitializer = _inInitializer;
4529 _inInitializer = false; 4482 _inInitializer = false;
4530 try { 4483 try {
4531 Expression index = parseExpression2(); 4484 Expression index = parseExpression2();
4532 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET); 4485 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET);
4533 return new IndexExpression.forTarget( 4486 return new IndexExpression.forTarget(
4534 prefix, leftBracket, index, rightBracket); 4487 prefix, leftBracket, index, rightBracket);
4535 } finally { 4488 } finally {
4536 _inInitializer = wasInInitializer; 4489 _inInitializer = wasInInitializer;
4537 } 4490 }
4538 } else if (_matches(TokenType.PERIOD) || 4491 } else {
4539 _matches(TokenType.QUESTION_PERIOD)) { 4492 bool isQuestionPeriod = type == TokenType.QUESTION_PERIOD;
4540 if (_matches(TokenType.QUESTION_PERIOD) && !allowConditional) { 4493 if (type == TokenType.PERIOD || isQuestionPeriod) {
4541 _reportErrorForCurrentToken( 4494 if (isQuestionPeriod && !allowConditional) {
4542 ParserErrorCode.INVALID_OPERATOR_FOR_SUPER, [_currentToken.lexeme]); 4495 _reportErrorForCurrentToken(
4496 ParserErrorCode.INVALID_OPERATOR_FOR_SUPER,
4497 [_currentToken.lexeme]);
4498 }
4499 Token operator = getAndAdvance();
4500 return new PropertyAccess(prefix, operator, parseSimpleIdentifier());
4501 } else {
4502 if (!optional) {
4503 // Report the missing selector.
4504 _reportErrorForCurrentToken(
4505 ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR);
4506 }
4507 return prefix;
4543 } 4508 }
4544 Token operator = getAndAdvance();
4545 return new PropertyAccess(prefix, operator, parseSimpleIdentifier());
4546 } else {
4547 if (!optional) {
4548 // Report the missing selector.
4549 _reportErrorForCurrentToken(
4550 ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR);
4551 }
4552 return prefix;
4553 } 4509 }
4554 } 4510 }
4555 4511
4556 /** 4512 /**
4557 * Parse a await expression. Return the await expression that was parsed. 4513 * Parse a await expression. Return the await expression that was parsed.
4558 * 4514 *
4515 * This method assumes that the current token matches `_AWAIT`.
4516 *
4559 * awaitExpression ::= 4517 * awaitExpression ::=
4560 * 'await' unaryExpression 4518 * 'await' unaryExpression
4561 */ 4519 */
4562 AwaitExpression _parseAwaitExpression() { 4520 AwaitExpression _parseAwaitExpression() {
4563 Token awaitToken = getAndAdvance(); 4521 Token awaitToken = getAndAdvance();
4564 Expression expression = _parseUnaryExpression(); 4522 Expression expression = _parseUnaryExpression();
4565 return new AwaitExpression(awaitToken, expression); 4523 return new AwaitExpression(awaitToken, expression);
4566 } 4524 }
4567 4525
4568 /** 4526 /**
4569 * Parse a bitwise and expression. Return the bitwise and expression that was 4527 * Parse a bitwise and expression. Return the bitwise and expression that was
4570 * parsed. 4528 * parsed.
4571 * 4529 *
4572 * bitwiseAndExpression ::= 4530 * bitwiseAndExpression ::=
4573 * shiftExpression ('&' shiftExpression)* 4531 * shiftExpression ('&' shiftExpression)*
4574 * | 'super' ('&' shiftExpression)+ 4532 * | 'super' ('&' shiftExpression)+
4575 */ 4533 */
4576 Expression _parseBitwiseAndExpression() { 4534 Expression _parseBitwiseAndExpression() {
4577 Expression expression; 4535 Expression expression;
4578 if (_matchesKeyword(Keyword.SUPER) && 4536 if (_currentToken.keyword == Keyword.SUPER &&
4579 _tokenMatches(_peek(), TokenType.AMPERSAND)) { 4537 _currentToken.next.type == TokenType.AMPERSAND) {
4580 expression = new SuperExpression(getAndAdvance()); 4538 expression = new SuperExpression(getAndAdvance());
4581 } else { 4539 } else {
4582 expression = _parseShiftExpression(); 4540 expression = _parseShiftExpression();
4583 } 4541 }
4584 while (_matches(TokenType.AMPERSAND)) { 4542 while (_currentToken.type == TokenType.AMPERSAND) {
4585 Token operator = getAndAdvance(); 4543 expression = new BinaryExpression(
4586 expression = 4544 expression, getAndAdvance(), _parseShiftExpression());
4587 new BinaryExpression(expression, operator, _parseShiftExpression());
4588 } 4545 }
4589 return expression; 4546 return expression;
4590 } 4547 }
4591 4548
4592 /** 4549 /**
4593 * Parse a bitwise exclusive-or expression. Return the bitwise exclusive-or 4550 * Parse a bitwise exclusive-or expression. Return the bitwise exclusive-or
4594 * expression that was parsed. 4551 * expression that was parsed.
4595 * 4552 *
4596 * bitwiseXorExpression ::= 4553 * bitwiseXorExpression ::=
4597 * bitwiseAndExpression ('^' bitwiseAndExpression)* 4554 * bitwiseAndExpression ('^' bitwiseAndExpression)*
4598 * | 'super' ('^' bitwiseAndExpression)+ 4555 * | 'super' ('^' bitwiseAndExpression)+
4599 */ 4556 */
4600 Expression _parseBitwiseXorExpression() { 4557 Expression _parseBitwiseXorExpression() {
4601 Expression expression; 4558 Expression expression;
4602 if (_matchesKeyword(Keyword.SUPER) && 4559 if (_currentToken.keyword == Keyword.SUPER &&
4603 _tokenMatches(_peek(), TokenType.CARET)) { 4560 _currentToken.next.type == TokenType.CARET) {
4604 expression = new SuperExpression(getAndAdvance()); 4561 expression = new SuperExpression(getAndAdvance());
4605 } else { 4562 } else {
4606 expression = _parseBitwiseAndExpression(); 4563 expression = _parseBitwiseAndExpression();
4607 } 4564 }
4608 while (_matches(TokenType.CARET)) { 4565 while (_currentToken.type == TokenType.CARET) {
4609 Token operator = getAndAdvance();
4610 expression = new BinaryExpression( 4566 expression = new BinaryExpression(
4611 expression, operator, _parseBitwiseAndExpression()); 4567 expression, getAndAdvance(), _parseBitwiseAndExpression());
4612 } 4568 }
4613 return expression; 4569 return expression;
4614 } 4570 }
4615 4571
4616 /** 4572 /**
4573 * Parse a block when we need to check for an open curly brace and recover
4574 * when there isn't one. Return the block that was parsed.
4575 *
4576 * block ::=
4577 * '{' statements '}'
4578 */
4579 Block _parseBlockChecked() {
4580 if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
4581 return parseBlock();
4582 }
4583 // TODO(brianwilkerson) Improve the error message.
4584 _reportErrorForCurrentToken(
4585 ParserErrorCode.EXPECTED_TOKEN, [TokenType.OPEN_CURLY_BRACKET.lexeme]);
4586 // Recovery: Check for an unmatched closing curly bracket and parse
4587 // statements until it is reached.
4588 return new Block(_createSyntheticToken(TokenType.OPEN_CURLY_BRACKET), null,
4589 _createSyntheticToken(TokenType.CLOSE_CURLY_BRACKET));
4590 }
4591
4592 /**
4617 * Parse a break statement. Return the break statement that was parsed. 4593 * Parse a break statement. Return the break statement that was parsed.
4618 * 4594 *
4595 * This method assumes that the current token matches `Keyword.BREAK`.
4596 *
4619 * breakStatement ::= 4597 * breakStatement ::=
4620 * 'break' identifier? ';' 4598 * 'break' identifier? ';'
4621 */ 4599 */
4622 Statement _parseBreakStatement() { 4600 Statement _parseBreakStatement() {
4623 Token breakKeyword = _expectKeyword(Keyword.BREAK); 4601 Token breakKeyword = getAndAdvance();
4624 SimpleIdentifier label = null; 4602 SimpleIdentifier label = null;
4625 if (_matchesIdentifier()) { 4603 if (_matchesIdentifier()) {
4626 label = parseSimpleIdentifier(); 4604 label = _parseSimpleIdentifierUnchecked();
4627 } 4605 }
4628 if (!_inLoop && !_inSwitch && label == null) { 4606 if (!_inLoop && !_inSwitch && label == null) {
4629 _reportErrorForToken(ParserErrorCode.BREAK_OUTSIDE_OF_LOOP, breakKeyword); 4607 _reportErrorForToken(ParserErrorCode.BREAK_OUTSIDE_OF_LOOP, breakKeyword);
4630 } 4608 }
4631 Token semicolon = _expect(TokenType.SEMICOLON); 4609 Token semicolon = _expect(TokenType.SEMICOLON);
4632 return new BreakStatement(breakKeyword, label, semicolon); 4610 return new BreakStatement(breakKeyword, label, semicolon);
4633 } 4611 }
4634 4612
4635 /** 4613 /**
4636 * Parse a cascade section. Return the expression representing the cascaded 4614 * Parse a cascade section. Return the expression representing the cascaded
4637 * method invocation. 4615 * method invocation.
4638 * 4616 *
4617 * This method assumes that the current token matches
4618 * `TokenType.PERIOD_PERIOD`.
4619 *
4639 * cascadeSection ::= 4620 * cascadeSection ::=
4640 * '..' (cascadeSelector typeArguments? arguments*) 4621 * '..' (cascadeSelector typeArguments? arguments*)
4641 * (assignableSelector typeArguments? arguments*)* cascadeAssignment? 4622 * (assignableSelector typeArguments? arguments*)* cascadeAssignment?
4642 * 4623 *
4643 * cascadeSelector ::= 4624 * cascadeSelector ::=
4644 * '[' expression ']' 4625 * '[' expression ']'
4645 * | identifier 4626 * | identifier
4646 * 4627 *
4647 * cascadeAssignment ::= 4628 * cascadeAssignment ::=
4648 * assignmentOperator expressionWithoutCascade 4629 * assignmentOperator expressionWithoutCascade
4649 */ 4630 */
4650 Expression _parseCascadeSection() { 4631 Expression _parseCascadeSection() {
4651 Token period = _expect(TokenType.PERIOD_PERIOD); 4632 Token period = getAndAdvance();
4652 Expression expression = null; 4633 Expression expression = null;
4653 SimpleIdentifier functionName = null; 4634 SimpleIdentifier functionName = null;
4654 if (_matchesIdentifier()) { 4635 if (_matchesIdentifier()) {
4655 functionName = parseSimpleIdentifier(); 4636 functionName = _parseSimpleIdentifierUnchecked();
4656 } else if (_currentToken.type == TokenType.OPEN_SQUARE_BRACKET) { 4637 } else if (_currentToken.type == TokenType.OPEN_SQUARE_BRACKET) {
4657 Token leftBracket = getAndAdvance(); 4638 Token leftBracket = getAndAdvance();
4658 bool wasInInitializer = _inInitializer; 4639 bool wasInInitializer = _inInitializer;
4659 _inInitializer = false; 4640 _inInitializer = false;
4660 try { 4641 try {
4661 Expression index = parseExpression2(); 4642 Expression index = parseExpression2();
4662 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET); 4643 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET);
4663 expression = new IndexExpression.forCascade( 4644 expression = new IndexExpression.forCascade(
4664 period, leftBracket, index, rightBracket); 4645 period, leftBracket, index, rightBracket);
4665 period = null; 4646 period = null;
4666 } finally { 4647 } finally {
4667 _inInitializer = wasInInitializer; 4648 _inInitializer = wasInInitializer;
4668 } 4649 }
4669 } else { 4650 } else {
4670 _reportErrorForToken(ParserErrorCode.MISSING_IDENTIFIER, _currentToken, 4651 _reportErrorForToken(ParserErrorCode.MISSING_IDENTIFIER, _currentToken,
4671 [_currentToken.lexeme]); 4652 [_currentToken.lexeme]);
4672 functionName = _createSyntheticIdentifier(); 4653 functionName = _createSyntheticIdentifier();
4673 } 4654 }
4674 assert((expression == null && functionName != null) || 4655 assert((expression == null && functionName != null) ||
4675 (expression != null && functionName == null)); 4656 (expression != null && functionName == null));
4676 if (_isLikelyArgumentList()) { 4657 if (_isLikelyArgumentList()) {
4677 while (_isLikelyArgumentList()) { 4658 do {
4678 TypeArgumentList typeArguments = _parseOptionalTypeArguments(); 4659 TypeArgumentList typeArguments = _parseOptionalTypeArguments();
4679 if (functionName != null) { 4660 if (functionName != null) {
4680 expression = new MethodInvocation(expression, period, functionName, 4661 expression = new MethodInvocation(expression, period, functionName,
4681 typeArguments, parseArgumentList()); 4662 typeArguments, parseArgumentList());
4682 period = null; 4663 period = null;
4683 functionName = null; 4664 functionName = null;
4684 } else if (expression == null) { 4665 } else if (expression == null) {
4685 // It should not be possible to get here. 4666 // It should not be possible to get here.
4686 expression = new MethodInvocation(expression, period, 4667 expression = new MethodInvocation(expression, period,
4687 _createSyntheticIdentifier(), typeArguments, parseArgumentList()); 4668 _createSyntheticIdentifier(), typeArguments, parseArgumentList());
4688 } else { 4669 } else {
4689 expression = new FunctionExpressionInvocation( 4670 expression = new FunctionExpressionInvocation(
4690 expression, typeArguments, parseArgumentList()); 4671 expression, typeArguments, parseArgumentList());
4691 } 4672 }
4692 } 4673 } while (_isLikelyArgumentList());
4693 } else if (functionName != null) { 4674 } else if (functionName != null) {
4694 expression = new PropertyAccess(expression, period, functionName); 4675 expression = new PropertyAccess(expression, period, functionName);
4695 period = null; 4676 period = null;
4696 } 4677 }
4697 assert(expression != null); 4678 assert(expression != null);
4698 bool progress = true; 4679 bool progress = true;
4699 while (progress) { 4680 while (progress) {
4700 progress = false; 4681 progress = false;
4701 Expression selector = _parseAssignableSelector(expression, true); 4682 Expression selector = _parseAssignableSelector(expression, true);
4702 if (!identical(selector, expression)) { 4683 if (!identical(selector, expression)) {
(...skipping 24 matching lines...) Expand all
4727 } 4708 }
4728 return expression; 4709 return expression;
4729 } 4710 }
4730 4711
4731 /** 4712 /**
4732 * Parse a class declaration. The [commentAndMetadata] is the metadata to be 4713 * Parse a class declaration. The [commentAndMetadata] is the metadata to be
4733 * associated with the member. The [abstractKeyword] is the token for the 4714 * associated with the member. The [abstractKeyword] is the token for the
4734 * keyword 'abstract', or `null` if the keyword was not given. Return the 4715 * keyword 'abstract', or `null` if the keyword was not given. Return the
4735 * class declaration that was parsed. 4716 * class declaration that was parsed.
4736 * 4717 *
4718 * This method assumes that the current token matches `Keyword.CLASS`.
4719 *
4737 * classDeclaration ::= 4720 * classDeclaration ::=
4738 * metadata 'abstract'? 'class' name typeParameterList? (extendsClause withClause?)? implementsClause? '{' classMembers '}' | 4721 * metadata 'abstract'? 'class' name typeParameterList? (extendsClause withClause?)? implementsClause? '{' classMembers '}' |
4739 * metadata 'abstract'? 'class' mixinApplicationClass 4722 * metadata 'abstract'? 'class' mixinApplicationClass
4740 */ 4723 */
4741 CompilationUnitMember _parseClassDeclaration( 4724 CompilationUnitMember _parseClassDeclaration(
4742 CommentAndMetadata commentAndMetadata, Token abstractKeyword) { 4725 CommentAndMetadata commentAndMetadata, Token abstractKeyword) {
4743 Token keyword = _expectKeyword(Keyword.CLASS); 4726 //
4744 if (_matchesIdentifier()) { 4727 // Parse the name and type parameters.
4745 Token next = _peek(); 4728 //
4746 if (_tokenMatches(next, TokenType.LT)) { 4729 Token keyword = getAndAdvance();
4747 next = _skipTypeParameterList(next);
4748 if (next != null && _tokenMatches(next, TokenType.EQ)) {
4749 return _parseClassTypeAlias(
4750 commentAndMetadata, abstractKeyword, keyword);
4751 }
4752 } else if (_tokenMatches(next, TokenType.EQ)) {
4753 return _parseClassTypeAlias(
4754 commentAndMetadata, abstractKeyword, keyword);
4755 }
4756 }
4757 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true); 4730 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
4758 String className = name.name; 4731 String className = name.name;
4759 TypeParameterList typeParameters = null; 4732 TypeParameterList typeParameters = null;
4760 if (_matches(TokenType.LT)) { 4733 TokenType type = _currentToken.type;
4734 if (type == TokenType.LT) {
4761 typeParameters = parseTypeParameterList(); 4735 typeParameters = parseTypeParameterList();
4736 type = _currentToken.type;
4737 }
4738 //
4739 // Check to see whether this might be a class type alias rather than a class
4740 // declaration.
4741 //
4742 if (type == TokenType.EQ) {
4743 return _parseClassTypeAliasAfterName(
4744 commentAndMetadata, abstractKeyword, keyword, name, typeParameters);
4762 } 4745 }
4763 // 4746 //
4764 // Parse the clauses. The parser accepts clauses in any order, but will 4747 // Parse the clauses. The parser accepts clauses in any order, but will
4765 // generate errors if they are not in the order required by the 4748 // generate errors if they are not in the order required by the
4766 // specification. 4749 // specification.
4767 // 4750 //
4768 ExtendsClause extendsClause = null; 4751 ExtendsClause extendsClause = null;
4769 WithClause withClause = null; 4752 WithClause withClause = null;
4770 ImplementsClause implementsClause = null; 4753 ImplementsClause implementsClause = null;
4771 bool foundClause = true; 4754 bool foundClause = true;
4772 while (foundClause) { 4755 while (foundClause) {
4773 if (_matchesKeyword(Keyword.EXTENDS)) { 4756 Keyword keyword = _currentToken.keyword;
4757 if (keyword == Keyword.EXTENDS) {
4774 if (extendsClause == null) { 4758 if (extendsClause == null) {
4775 extendsClause = parseExtendsClause(); 4759 extendsClause = parseExtendsClause();
4776 if (withClause != null) { 4760 if (withClause != null) {
4777 _reportErrorForToken( 4761 _reportErrorForToken(
4778 ParserErrorCode.WITH_BEFORE_EXTENDS, withClause.withKeyword); 4762 ParserErrorCode.WITH_BEFORE_EXTENDS, withClause.withKeyword);
4779 } else if (implementsClause != null) { 4763 } else if (implementsClause != null) {
4780 _reportErrorForToken(ParserErrorCode.IMPLEMENTS_BEFORE_EXTENDS, 4764 _reportErrorForToken(ParserErrorCode.IMPLEMENTS_BEFORE_EXTENDS,
4781 implementsClause.implementsKeyword); 4765 implementsClause.implementsKeyword);
4782 } 4766 }
4783 } else { 4767 } else {
4784 _reportErrorForToken(ParserErrorCode.MULTIPLE_EXTENDS_CLAUSES, 4768 _reportErrorForToken(ParserErrorCode.MULTIPLE_EXTENDS_CLAUSES,
4785 extendsClause.extendsKeyword); 4769 extendsClause.extendsKeyword);
4786 parseExtendsClause(); 4770 parseExtendsClause();
4787 } 4771 }
4788 } else if (_matchesKeyword(Keyword.WITH)) { 4772 } else if (keyword == Keyword.WITH) {
4789 if (withClause == null) { 4773 if (withClause == null) {
4790 withClause = parseWithClause(); 4774 withClause = parseWithClause();
4791 if (implementsClause != null) { 4775 if (implementsClause != null) {
4792 _reportErrorForToken(ParserErrorCode.IMPLEMENTS_BEFORE_WITH, 4776 _reportErrorForToken(ParserErrorCode.IMPLEMENTS_BEFORE_WITH,
4793 implementsClause.implementsKeyword); 4777 implementsClause.implementsKeyword);
4794 } 4778 }
4795 } else { 4779 } else {
4796 _reportErrorForToken( 4780 _reportErrorForToken(
4797 ParserErrorCode.MULTIPLE_WITH_CLAUSES, withClause.withKeyword); 4781 ParserErrorCode.MULTIPLE_WITH_CLAUSES, withClause.withKeyword);
4798 parseWithClause(); 4782 parseWithClause();
4799 // TODO(brianwilkerson) Should we merge the list of applied mixins 4783 // TODO(brianwilkerson) Should we merge the list of applied mixins
4800 // into a single list? 4784 // into a single list?
4801 } 4785 }
4802 } else if (_matchesKeyword(Keyword.IMPLEMENTS)) { 4786 } else if (keyword == Keyword.IMPLEMENTS) {
4803 if (implementsClause == null) { 4787 if (implementsClause == null) {
4804 implementsClause = parseImplementsClause(); 4788 implementsClause = parseImplementsClause();
4805 } else { 4789 } else {
4806 _reportErrorForToken(ParserErrorCode.MULTIPLE_IMPLEMENTS_CLAUSES, 4790 _reportErrorForToken(ParserErrorCode.MULTIPLE_IMPLEMENTS_CLAUSES,
4807 implementsClause.implementsKeyword); 4791 implementsClause.implementsKeyword);
4808 parseImplementsClause(); 4792 parseImplementsClause();
4809 // TODO(brianwilkerson) Should we merge the list of implemented 4793 // TODO(brianwilkerson) Should we merge the list of implemented
4810 // classes into a single list? 4794 // classes into a single list?
4811 } 4795 }
4812 } else { 4796 } else {
(...skipping 11 matching lines...) Expand all
4824 if (_matchesString(_NATIVE) && _tokenMatches(_peek(), TokenType.STRING)) { 4808 if (_matchesString(_NATIVE) && _tokenMatches(_peek(), TokenType.STRING)) {
4825 nativeClause = _parseNativeClause(); 4809 nativeClause = _parseNativeClause();
4826 } 4810 }
4827 // 4811 //
4828 // Parse the body of the class. 4812 // Parse the body of the class.
4829 // 4813 //
4830 Token leftBracket = null; 4814 Token leftBracket = null;
4831 List<ClassMember> members = null; 4815 List<ClassMember> members = null;
4832 Token rightBracket = null; 4816 Token rightBracket = null;
4833 if (_matches(TokenType.OPEN_CURLY_BRACKET)) { 4817 if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
4834 leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET); 4818 leftBracket = getAndAdvance();
4835 members = _parseClassMembers(className, _getEndToken(leftBracket)); 4819 members = _parseClassMembers(className, _getEndToken(leftBracket));
4836 rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET); 4820 rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
4837 } else { 4821 } else {
4822 // Recovery: Check for an unmatched closing curly bracket and parse
4823 // members until it is reached.
4838 leftBracket = _createSyntheticToken(TokenType.OPEN_CURLY_BRACKET); 4824 leftBracket = _createSyntheticToken(TokenType.OPEN_CURLY_BRACKET);
4839 rightBracket = _createSyntheticToken(TokenType.CLOSE_CURLY_BRACKET); 4825 rightBracket = _createSyntheticToken(TokenType.CLOSE_CURLY_BRACKET);
4840 _reportErrorForCurrentToken(ParserErrorCode.MISSING_CLASS_BODY); 4826 _reportErrorForCurrentToken(ParserErrorCode.MISSING_CLASS_BODY);
4841 } 4827 }
4842 ClassDeclaration classDeclaration = new ClassDeclaration( 4828 ClassDeclaration classDeclaration = new ClassDeclaration(
4843 commentAndMetadata.comment, 4829 commentAndMetadata.comment,
4844 commentAndMetadata.metadata, 4830 commentAndMetadata.metadata,
4845 abstractKeyword, 4831 abstractKeyword,
4846 keyword, 4832 keyword,
4847 name, 4833 name,
(...skipping 11 matching lines...) Expand all
4859 /** 4845 /**
4860 * Parse a list of class members. The [className] is the name of the class 4846 * Parse a list of class members. The [className] is the name of the class
4861 * whose members are being parsed. The [closingBracket] is the closing bracket 4847 * whose members are being parsed. The [closingBracket] is the closing bracket
4862 * for the class, or `null` if the closing bracket is missing. Return the list 4848 * for the class, or `null` if the closing bracket is missing. Return the list
4863 * of class members that were parsed. 4849 * of class members that were parsed.
4864 * 4850 *
4865 * classMembers ::= 4851 * classMembers ::=
4866 * (metadata memberDefinition)* 4852 * (metadata memberDefinition)*
4867 */ 4853 */
4868 List<ClassMember> _parseClassMembers(String className, Token closingBracket) { 4854 List<ClassMember> _parseClassMembers(String className, Token closingBracket) {
4869 List<ClassMember> members = new List<ClassMember>(); 4855 List<ClassMember> members = <ClassMember>[];
4870 Token memberStart = _currentToken; 4856 Token memberStart = _currentToken;
4871 while (!_matches(TokenType.EOF) && 4857 TokenType type = _currentToken.type;
4872 !_matches(TokenType.CLOSE_CURLY_BRACKET) && 4858 Keyword keyword = _currentToken.keyword;
4859 while (type != TokenType.EOF &&
4860 type != TokenType.CLOSE_CURLY_BRACKET &&
4873 (closingBracket != null || 4861 (closingBracket != null ||
4874 (!_matchesKeyword(Keyword.CLASS) && 4862 (keyword != Keyword.CLASS && keyword != Keyword.TYPEDEF))) {
4875 !_matchesKeyword(Keyword.TYPEDEF)))) { 4863 if (type == TokenType.SEMICOLON) {
4876 if (_matches(TokenType.SEMICOLON)) {
4877 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, 4864 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
4878 [_currentToken.lexeme]); 4865 [_currentToken.lexeme]);
4879 _advance(); 4866 _advance();
4880 } else { 4867 } else {
4881 ClassMember member = parseClassMember(className); 4868 ClassMember member = parseClassMember(className);
4882 if (member != null) { 4869 if (member != null) {
4883 members.add(member); 4870 members.add(member);
4884 } 4871 }
4885 } 4872 }
4886 if (identical(_currentToken, memberStart)) { 4873 if (identical(_currentToken, memberStart)) {
4887 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, 4874 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
4888 [_currentToken.lexeme]); 4875 [_currentToken.lexeme]);
4889 _advance(); 4876 _advance();
4890 } 4877 }
4891 memberStart = _currentToken; 4878 memberStart = _currentToken;
4879 type = _currentToken.type;
4880 keyword = _currentToken.keyword;
4892 } 4881 }
4893 return members; 4882 return members;
4894 } 4883 }
4895 4884
4896 /** 4885 /**
4897 * Parse a class type alias. The [commentAndMetadata] is the metadata to be 4886 * Parse a class type alias. The [commentAndMetadata] is the metadata to be
4898 * associated with the member. The [abstractKeyword] is the token representing 4887 * associated with the member. The [abstractKeyword] is the token representing
4899 * the 'abstract' keyword. The [classKeyword] is the token representing the 4888 * the 'abstract' keyword. The [classKeyword] is the token representing the
4900 * 'class' keyword. Return the class type alias that was parsed. 4889 * 'class' keyword. Return the class type alias that was parsed.
4901 * 4890 *
4891 * This method assumes that the current token matches an identifier.
4892 *
4902 * classTypeAlias ::= 4893 * classTypeAlias ::=
4903 * identifier typeParameters? '=' 'abstract'? mixinApplication 4894 * identifier typeParameters? '=' 'abstract'? mixinApplication
4904 * 4895 *
4905 * mixinApplication ::= 4896 * mixinApplication ::=
4906 * type withClause implementsClause? ';' 4897 * type withClause implementsClause? ';'
4907 */ 4898 */
4908 ClassTypeAlias _parseClassTypeAlias(CommentAndMetadata commentAndMetadata, 4899 ClassTypeAlias _parseClassTypeAlias(CommentAndMetadata commentAndMetadata,
4909 Token abstractKeyword, Token classKeyword) { 4900 Token abstractKeyword, Token classKeyword) {
4910 SimpleIdentifier className = parseSimpleIdentifier(isDeclaration: true); 4901 SimpleIdentifier className =
4902 _parseSimpleIdentifierUnchecked(isDeclaration: true);
4911 TypeParameterList typeParameters = null; 4903 TypeParameterList typeParameters = null;
4912 if (_matches(TokenType.LT)) { 4904 if (_matches(TokenType.LT)) {
4913 typeParameters = parseTypeParameterList(); 4905 typeParameters = parseTypeParameterList();
4914 } 4906 }
4907 return _parseClassTypeAliasAfterName(commentAndMetadata, abstractKeyword,
4908 classKeyword, className, typeParameters);
4909 }
4910
4911 /**
4912 * Parse a class type alias. The [commentAndMetadata] is the metadata to be
4913 * associated with the member. The [abstractKeyword] is the token representing
4914 * the 'abstract' keyword. The [classKeyword] is the token representing the
4915 * 'class' keyword. The [className] is the name of the alias, and the
4916 * [typeParameters] are the type parameters following the name. Return the
4917 * class type alias that was parsed.
4918 *
4919 * classTypeAlias ::=
4920 * identifier typeParameters? '=' 'abstract'? mixinApplication
4921 *
4922 * mixinApplication ::=
4923 * type withClause implementsClause? ';'
4924 */
4925 ClassTypeAlias _parseClassTypeAliasAfterName(
4926 CommentAndMetadata commentAndMetadata,
4927 Token abstractKeyword,
4928 Token classKeyword,
4929 SimpleIdentifier className,
4930 TypeParameterList typeParameters) {
4915 Token equals = _expect(TokenType.EQ); 4931 Token equals = _expect(TokenType.EQ);
4916 TypeName superclass = parseTypeName(); 4932 TypeName superclass = parseTypeName();
4917 WithClause withClause = null; 4933 WithClause withClause = null;
4918 if (_matchesKeyword(Keyword.WITH)) { 4934 if (_matchesKeyword(Keyword.WITH)) {
4919 withClause = parseWithClause(); 4935 withClause = parseWithClause();
4920 } else { 4936 } else {
4921 _reportErrorForCurrentToken( 4937 _reportErrorForCurrentToken(
4922 ParserErrorCode.EXPECTED_TOKEN, [Keyword.WITH.syntax]); 4938 ParserErrorCode.EXPECTED_TOKEN, [Keyword.WITH.syntax]);
4923 } 4939 }
4924 ImplementsClause implementsClause = null; 4940 ImplementsClause implementsClause = null;
(...skipping 25 matching lines...) Expand all
4950 equals, 4966 equals,
4951 abstractKeyword, 4967 abstractKeyword,
4952 superclass, 4968 superclass,
4953 withClause, 4969 withClause,
4954 implementsClause, 4970 implementsClause,
4955 semicolon); 4971 semicolon);
4956 } 4972 }
4957 4973
4958 /** 4974 /**
4959 * Parse a list of combinators in a directive. Return the combinators that 4975 * Parse a list of combinators in a directive. Return the combinators that
4960 * were parsed. 4976 * were parsed, or `null` if there are no combinators.
4961 * 4977 *
4962 * combinator ::= 4978 * combinator ::=
4963 * 'show' identifier (',' identifier)* 4979 * 'show' identifier (',' identifier)*
4964 * | 'hide' identifier (',' identifier)* 4980 * | 'hide' identifier (',' identifier)*
4965 */ 4981 */
4966 List<Combinator> _parseCombinators() { 4982 List<Combinator> _parseCombinators() {
4967 List<Combinator> combinators = new List<Combinator>(); 4983 List<Combinator> combinators = null;
4968 while (true) { 4984 while (true) {
4969 Combinator combinator = parseCombinator(); 4985 Combinator combinator = parseCombinator();
4970 if (combinator == null) { 4986 if (combinator == null) {
4971 break; 4987 break;
4972 } 4988 }
4989 combinators ??= <Combinator>[];
4973 combinators.add(combinator); 4990 combinators.add(combinator);
4974 } 4991 }
4975 return combinators; 4992 return combinators;
4976 } 4993 }
4977 4994
4978 /** 4995 /**
4979 * Parse the documentation comment and metadata preceding a declaration. This 4996 * Parse the documentation comment and metadata preceding a declaration. This
4980 * method allows any number of documentation comments to occur before, after 4997 * method allows any number of documentation comments to occur before, after
4981 * or between the metadata, but only returns the last (right-most) 4998 * or between the metadata, but only returns the last (right-most)
4982 * documentation comment that is found. Return the documentation comment and 4999 * documentation comment that is found. Return the documentation comment and
4983 * metadata that were parsed. 5000 * metadata that were parsed.
4984 * 5001 *
4985 * metadata ::= 5002 * metadata ::=
4986 * annotation* 5003 * annotation*
4987 */ 5004 */
4988 CommentAndMetadata _parseCommentAndMetadata() { 5005 CommentAndMetadata _parseCommentAndMetadata() {
4989 Comment comment = _parseDocumentationComment(); 5006 // TODO(brianwilkerson) Consider making the creation of documentation
5007 // comments be lazy.
5008 List<DocumentationCommentToken> tokens = _parseDocumentationCommentTokens();
4990 List<Annotation> metadata = null; 5009 List<Annotation> metadata = null;
4991 while (_matches(TokenType.AT)) { 5010 while (_matches(TokenType.AT)) {
4992 metadata ??= new List<Annotation>(); 5011 metadata ??= <Annotation>[];
4993 metadata.add(parseAnnotation()); 5012 metadata.add(parseAnnotation());
4994 Comment optionalComment = _parseDocumentationComment(); 5013 List<DocumentationCommentToken> optionalTokens =
4995 if (optionalComment != null) { 5014 _parseDocumentationCommentTokens();
4996 comment = optionalComment; 5015 if (optionalTokens != null) {
5016 tokens = optionalTokens;
4997 } 5017 }
4998 } 5018 }
4999 metadata ??= const <Annotation>[]; 5019 return new CommentAndMetadata(_parseDocumentationComment(tokens), metadata);
5000 return new CommentAndMetadata(comment, metadata);
5001 } 5020 }
5002 5021
5003 /** 5022 /**
5004 * Parse a comment reference from the source between square brackets. The 5023 * Parse a comment reference from the source between square brackets. The
5005 * [referenceSource] is the source occurring between the square brackets 5024 * [referenceSource] is the source occurring between the square brackets
5006 * within a documentation comment. The [sourceOffset] is the offset of the 5025 * within a documentation comment. The [sourceOffset] is the offset of the
5007 * first character of the reference source. Return the comment reference that 5026 * first character of the reference source. Return the comment reference that
5008 * was parsed, or `null` if no reference could be found. 5027 * was parsed, or `null` if no reference could be found.
5009 * 5028 *
5010 * commentReference ::= 5029 * commentReference ::=
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
5044 secondToken, new SimpleIdentifier(thirdToken)); 5063 secondToken, new SimpleIdentifier(thirdToken));
5045 nextToken = thirdToken.next; 5064 nextToken = thirdToken.next;
5046 } else { 5065 } else {
5047 identifier = new SimpleIdentifier(firstToken); 5066 identifier = new SimpleIdentifier(firstToken);
5048 nextToken = firstToken.next; 5067 nextToken = firstToken.next;
5049 } 5068 }
5050 if (nextToken.type != TokenType.EOF) { 5069 if (nextToken.type != TokenType.EOF) {
5051 return null; 5070 return null;
5052 } 5071 }
5053 return new CommentReference(newKeyword, identifier); 5072 return new CommentReference(newKeyword, identifier);
5054 } else if (_tokenMatchesKeyword(firstToken, Keyword.THIS) || 5073 } else {
5055 _tokenMatchesKeyword(firstToken, Keyword.NULL) || 5074 Keyword keyword = firstToken.keyword;
5056 _tokenMatchesKeyword(firstToken, Keyword.TRUE) || 5075 if (keyword == Keyword.THIS ||
5057 _tokenMatchesKeyword(firstToken, Keyword.FALSE)) { 5076 keyword == Keyword.NULL ||
5058 // TODO(brianwilkerson) If we want to support this we will need to 5077 keyword == Keyword.TRUE ||
5059 // extend the definition of CommentReference to take an expression 5078 keyword == Keyword.FALSE) {
5060 // rather than an identifier. For now we just ignore it to reduce the 5079 // TODO(brianwilkerson) If we want to support this we will need to
5061 // number of errors produced, but that's probably not a valid long term 5080 // extend the definition of CommentReference to take an expression
5062 // approach. 5081 // rather than an identifier. For now we just ignore it to reduce the
5063 return null; 5082 // number of errors produced, but that's probably not a valid long ter m
5083 // approach.
5084 return null;
5085 }
5064 } 5086 }
5065 } catch (exception) { 5087 } catch (exception) {
5066 // Ignored because we assume that it wasn't a real comment reference. 5088 // Ignored because we assume that it wasn't a real comment reference.
5067 } 5089 }
5068 return null; 5090 return null;
5069 } 5091 }
5070 5092
5071 /** 5093 /**
5072 * Parse all of the comment references occurring in the given array of 5094 * Parse all of the comment references occurring in the given array of
5073 * documentation comments. The [tokens] are the comment tokens representing 5095 * documentation comments. The [tokens] are the comment tokens representing
5074 * the documentation comments to be parsed. Return the comment references that 5096 * the documentation comments to be parsed. Return the comment references that
5075 * were parsed. 5097 * were parsed.
5076 * 5098 *
5077 * commentReference ::= 5099 * commentReference ::=
5078 * '[' 'new'? qualified ']' libraryReference? 5100 * '[' 'new'? qualified ']' libraryReference?
5079 * 5101 *
5080 * libraryReference ::= 5102 * libraryReference ::=
5081 * '(' stringLiteral ')' 5103 * '(' stringLiteral ')'
5082 */ 5104 */
5083 List<CommentReference> _parseCommentReferences( 5105 List<CommentReference> _parseCommentReferences(
5084 List<DocumentationCommentToken> tokens) { 5106 List<DocumentationCommentToken> tokens) {
5085 List<CommentReference> references = new List<CommentReference>(); 5107 List<CommentReference> references = <CommentReference>[];
5086 for (DocumentationCommentToken token in tokens) { 5108 for (DocumentationCommentToken token in tokens) {
5087 String comment = token.lexeme; 5109 String comment = token.lexeme;
5088 comment = _removeCodeBlocksGitHub(comment); 5110 comment = _removeCodeBlocksGitHub(comment);
5089 int length = comment.length; 5111 int length = comment.length;
5090 List<List<int>> codeBlockRanges = _getCodeBlockRanges(comment); 5112 List<List<int>> codeBlockRanges = _getCodeBlockRanges(comment);
5091 int leftIndex = comment.indexOf('['); 5113 int leftIndex = comment.indexOf('[');
5092 while (leftIndex >= 0 && leftIndex + 1 < length) { 5114 while (leftIndex >= 0 && leftIndex + 1 < length) {
5093 List<int> range = _findRange(codeBlockRanges, leftIndex); 5115 List<int> range = _findRange(codeBlockRanges, leftIndex);
5094 if (range == null) { 5116 if (range == null) {
5095 int nameOffset = token.offset + leftIndex + 1; 5117 int nameOffset = token.offset + leftIndex + 1;
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
5151 * | external getterSignature 5173 * | external getterSignature
5152 * | external setterSignature 5174 * | external setterSignature
5153 * | functionSignature functionBody 5175 * | functionSignature functionBody
5154 * | returnType? getOrSet identifier formalParameterList functionBody 5176 * | returnType? getOrSet identifier formalParameterList functionBody
5155 * | (final | const) type? staticFinalDeclarationList ';' 5177 * | (final | const) type? staticFinalDeclarationList ';'
5156 * | variableDeclaration ';' 5178 * | variableDeclaration ';'
5157 */ 5179 */
5158 CompilationUnitMember _parseCompilationUnitMember( 5180 CompilationUnitMember _parseCompilationUnitMember(
5159 CommentAndMetadata commentAndMetadata) { 5181 CommentAndMetadata commentAndMetadata) {
5160 Modifiers modifiers = _parseModifiers(); 5182 Modifiers modifiers = _parseModifiers();
5161 if (_matchesKeyword(Keyword.CLASS)) { 5183 Keyword keyword = _currentToken.keyword;
5184 if (keyword == Keyword.CLASS) {
5162 return _parseClassDeclaration( 5185 return _parseClassDeclaration(
5163 commentAndMetadata, _validateModifiersForClass(modifiers)); 5186 commentAndMetadata, _validateModifiersForClass(modifiers));
5164 } else if (_matchesKeyword(Keyword.TYPEDEF) && 5187 }
5165 !_tokenMatches(_peek(), TokenType.PERIOD) && 5188 Token next = _peek();
5166 !_tokenMatches(_peek(), TokenType.LT) && 5189 TokenType nextType = next.type;
5167 !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { 5190 if (keyword == Keyword.TYPEDEF &&
5191 nextType != TokenType.PERIOD &&
5192 nextType != TokenType.LT &&
5193 nextType != TokenType.OPEN_PAREN) {
5168 _validateModifiersForTypedef(modifiers); 5194 _validateModifiersForTypedef(modifiers);
5169 return _parseTypeAlias(commentAndMetadata); 5195 return _parseTypeAlias(commentAndMetadata);
5170 } else if (_matchesKeyword(Keyword.ENUM)) { 5196 } else if (keyword == Keyword.ENUM) {
5171 _validateModifiersForEnum(modifiers); 5197 _validateModifiersForEnum(modifiers);
5172 return _parseEnumDeclaration(commentAndMetadata); 5198 return _parseEnumDeclaration(commentAndMetadata);
5173 } 5199 } else if (keyword == Keyword.VOID) {
5174 if (_matchesKeyword(Keyword.VOID)) { 5200 TypeName returnType =
5175 TypeName returnType = parseReturnType(); 5201 new TypeName(new SimpleIdentifier(getAndAdvance()), null);
5176 if ((_matchesKeyword(Keyword.GET) || _matchesKeyword(Keyword.SET)) && 5202 keyword = _currentToken.keyword;
5177 _tokenMatchesIdentifier(_peek())) { 5203 next = _peek();
5204 if ((keyword == Keyword.GET || keyword == Keyword.SET) &&
5205 _tokenMatchesIdentifier(next)) {
5178 _validateModifiersForTopLevelFunction(modifiers); 5206 _validateModifiersForTopLevelFunction(modifiers);
5179 return _parseFunctionDeclaration( 5207 return _parseFunctionDeclaration(
5180 commentAndMetadata, modifiers.externalKeyword, returnType); 5208 commentAndMetadata, modifiers.externalKeyword, returnType);
5181 } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) { 5209 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
5182 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken); 5210 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken);
5183 return _convertToFunctionDeclaration(_parseOperator( 5211 return _convertToFunctionDeclaration(_parseOperatorAfterKeyword(
5184 commentAndMetadata, modifiers.externalKeyword, returnType)); 5212 commentAndMetadata,
5213 modifiers.externalKeyword,
5214 returnType,
5215 getAndAdvance()));
5185 } else if (_matchesIdentifier() && 5216 } else if (_matchesIdentifier() &&
5186 _peek().matchesAny(const <TokenType>[ 5217 next.matchesAny(const <TokenType>[
5187 TokenType.OPEN_PAREN, 5218 TokenType.OPEN_PAREN,
5188 TokenType.OPEN_CURLY_BRACKET, 5219 TokenType.OPEN_CURLY_BRACKET,
5189 TokenType.FUNCTION, 5220 TokenType.FUNCTION,
5190 TokenType.LT 5221 TokenType.LT
5191 ])) { 5222 ])) {
5192 _validateModifiersForTopLevelFunction(modifiers); 5223 _validateModifiersForTopLevelFunction(modifiers);
5193 return _parseFunctionDeclaration( 5224 return _parseFunctionDeclaration(
5194 commentAndMetadata, modifiers.externalKeyword, returnType); 5225 commentAndMetadata, modifiers.externalKeyword, returnType);
5195 } else { 5226 } else {
5196 // 5227 //
5197 // We have found an error of some kind. Try to recover. 5228 // We have found an error of some kind. Try to recover.
5198 // 5229 //
5199 if (_matchesIdentifier()) { 5230 if (_matchesIdentifier()) {
5200 if (_peek().matchesAny(const <TokenType>[ 5231 if (next.matchesAny(const <TokenType>[
5201 TokenType.EQ, 5232 TokenType.EQ,
5202 TokenType.COMMA, 5233 TokenType.COMMA,
5203 TokenType.SEMICOLON 5234 TokenType.SEMICOLON
5204 ])) { 5235 ])) {
5205 // 5236 //
5206 // We appear to have a variable declaration with a type of "void". 5237 // We appear to have a variable declaration with a type of "void".
5207 // 5238 //
5208 _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType); 5239 _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType);
5209 return new TopLevelVariableDeclaration( 5240 return new TopLevelVariableDeclaration(
5210 commentAndMetadata.comment, 5241 commentAndMetadata.comment,
5211 commentAndMetadata.metadata, 5242 commentAndMetadata.metadata,
5212 _parseVariableDeclarationListAfterType(null, 5243 _parseVariableDeclarationListAfterType(null,
5213 _validateModifiersForTopLevelVariable(modifiers), null), 5244 _validateModifiersForTopLevelVariable(modifiers), null),
5214 _expect(TokenType.SEMICOLON)); 5245 _expect(TokenType.SEMICOLON));
5215 } 5246 }
5216 } 5247 }
5217 _reportErrorForToken( 5248 _reportErrorForToken(
5218 ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken); 5249 ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken);
5219 return null; 5250 return null;
5220 } 5251 }
5221 } else if ((_matchesKeyword(Keyword.GET) || _matchesKeyword(Keyword.SET)) && 5252 } else if ((keyword == Keyword.GET || keyword == Keyword.SET) &&
5222 _tokenMatchesIdentifier(_peek())) { 5253 _tokenMatchesIdentifier(next)) {
5223 _validateModifiersForTopLevelFunction(modifiers); 5254 _validateModifiersForTopLevelFunction(modifiers);
5224 return _parseFunctionDeclaration( 5255 return _parseFunctionDeclaration(
5225 commentAndMetadata, modifiers.externalKeyword, null); 5256 commentAndMetadata, modifiers.externalKeyword, null);
5226 } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) { 5257 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
5227 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken); 5258 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken);
5228 return _convertToFunctionDeclaration( 5259 return _convertToFunctionDeclaration(_parseOperatorAfterKeyword(
5229 _parseOperator(commentAndMetadata, modifiers.externalKeyword, null)); 5260 commentAndMetadata,
5261 modifiers.externalKeyword,
5262 null,
5263 getAndAdvance()));
5230 } else if (!_matchesIdentifier()) { 5264 } else if (!_matchesIdentifier()) {
5231 Token keyword = modifiers.varKeyword; 5265 Token keyword = modifiers.varKeyword;
5232 if (keyword == null) { 5266 if (keyword == null) {
5233 keyword = modifiers.finalKeyword; 5267 keyword = modifiers.finalKeyword;
5234 } 5268 }
5235 if (keyword == null) { 5269 if (keyword == null) {
5236 keyword = modifiers.constKeyword; 5270 keyword = modifiers.constKeyword;
5237 } 5271 }
5238 if (keyword != null) { 5272 if (keyword != null) {
5239 // 5273 //
5240 // We appear to have found an incomplete top-level variable declaration. 5274 // We appear to have found an incomplete top-level variable declaration.
5241 // 5275 //
5242 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); 5276 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
5243 List<VariableDeclaration> variables = new List<VariableDeclaration>(); 5277 VariableDeclaration variable =
5244 variables.add( 5278 new VariableDeclaration(_createSyntheticIdentifier(), null, null);
5245 new VariableDeclaration(_createSyntheticIdentifier(), null, null)); 5279 List<VariableDeclaration> variables = <VariableDeclaration>[variable];
5246 return new TopLevelVariableDeclaration( 5280 return new TopLevelVariableDeclaration(
5247 commentAndMetadata.comment, 5281 commentAndMetadata.comment,
5248 commentAndMetadata.metadata, 5282 commentAndMetadata.metadata,
5249 new VariableDeclarationList(null, null, keyword, null, variables), 5283 new VariableDeclarationList(null, null, keyword, null, variables),
5250 _expect(TokenType.SEMICOLON)); 5284 _expect(TokenType.SEMICOLON));
5251 } 5285 }
5252 _reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken); 5286 _reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken);
5253 return null; 5287 return null;
5254 } else if (_isPeekGenericTypeParametersAndOpenParen()) { 5288 } else if (_isPeekGenericTypeParametersAndOpenParen()) {
5255 return _parseFunctionDeclaration( 5289 return _parseFunctionDeclaration(
5256 commentAndMetadata, modifiers.externalKeyword, null); 5290 commentAndMetadata, modifiers.externalKeyword, null);
5257 } else if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { 5291 } else if (_tokenMatches(next, TokenType.OPEN_PAREN)) {
5258 TypeName returnType = _parseOptionalTypeNameComment(); 5292 TypeName returnType = _parseOptionalTypeNameComment();
5259 _validateModifiersForTopLevelFunction(modifiers); 5293 _validateModifiersForTopLevelFunction(modifiers);
5260 return _parseFunctionDeclaration( 5294 return _parseFunctionDeclaration(
5261 commentAndMetadata, modifiers.externalKeyword, returnType); 5295 commentAndMetadata, modifiers.externalKeyword, returnType);
5262 } else if (_peek().matchesAny(const <TokenType>[ 5296 } else if (next.matchesAny(const <TokenType>[
5263 TokenType.EQ, 5297 TokenType.EQ,
5264 TokenType.COMMA, 5298 TokenType.COMMA,
5265 TokenType.SEMICOLON 5299 TokenType.SEMICOLON
5266 ])) { 5300 ])) {
5267 if (modifiers.constKeyword == null && 5301 if (modifiers.constKeyword == null &&
5268 modifiers.finalKeyword == null && 5302 modifiers.finalKeyword == null &&
5269 modifiers.varKeyword == null) { 5303 modifiers.varKeyword == null) {
5270 _reportErrorForCurrentToken( 5304 _reportErrorForCurrentToken(
5271 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE); 5305 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE);
5272 } 5306 }
5273 return new TopLevelVariableDeclaration( 5307 return new TopLevelVariableDeclaration(
5274 commentAndMetadata.comment, 5308 commentAndMetadata.comment,
5275 commentAndMetadata.metadata, 5309 commentAndMetadata.metadata,
5276 _parseVariableDeclarationListAfterType( 5310 _parseVariableDeclarationListAfterType(
5277 null, _validateModifiersForTopLevelVariable(modifiers), null), 5311 null, _validateModifiersForTopLevelVariable(modifiers), null),
5278 _expect(TokenType.SEMICOLON)); 5312 _expect(TokenType.SEMICOLON));
5279 } 5313 }
5280 TypeName returnType = parseReturnType(); 5314 TypeName returnType = parseReturnType();
5281 if ((_matchesKeyword(Keyword.GET) || _matchesKeyword(Keyword.SET)) && 5315 keyword = _currentToken.keyword;
5282 _tokenMatchesIdentifier(_peek())) { 5316 next = _peek();
5317 if ((keyword == Keyword.GET || keyword == Keyword.SET) &&
5318 _tokenMatchesIdentifier(next)) {
5283 _validateModifiersForTopLevelFunction(modifiers); 5319 _validateModifiersForTopLevelFunction(modifiers);
5284 return _parseFunctionDeclaration( 5320 return _parseFunctionDeclaration(
5285 commentAndMetadata, modifiers.externalKeyword, returnType); 5321 commentAndMetadata, modifiers.externalKeyword, returnType);
5286 } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) { 5322 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
5287 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken); 5323 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken);
5288 return _convertToFunctionDeclaration(_parseOperator( 5324 return _convertToFunctionDeclaration(_parseOperatorAfterKeyword(
5289 commentAndMetadata, modifiers.externalKeyword, returnType)); 5325 commentAndMetadata,
5326 modifiers.externalKeyword,
5327 returnType,
5328 getAndAdvance()));
5290 } else if (_matches(TokenType.AT)) { 5329 } else if (_matches(TokenType.AT)) {
5291 return new TopLevelVariableDeclaration( 5330 return new TopLevelVariableDeclaration(
5292 commentAndMetadata.comment, 5331 commentAndMetadata.comment,
5293 commentAndMetadata.metadata, 5332 commentAndMetadata.metadata,
5294 _parseVariableDeclarationListAfterType(null, 5333 _parseVariableDeclarationListAfterType(null,
5295 _validateModifiersForTopLevelVariable(modifiers), returnType), 5334 _validateModifiersForTopLevelVariable(modifiers), returnType),
5296 _expect(TokenType.SEMICOLON)); 5335 _expect(TokenType.SEMICOLON));
5297 } else if (!_matchesIdentifier()) { 5336 } else if (!_matchesIdentifier()) {
5298 // TODO(brianwilkerson) Generalize this error. We could also be parsing a 5337 // TODO(brianwilkerson) Generalize this error. We could also be parsing a
5299 // top-level variable at this point. 5338 // top-level variable at this point.
5300 _reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken); 5339 _reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken);
5301 Token semicolon; 5340 Token semicolon;
5302 if (_matches(TokenType.SEMICOLON)) { 5341 if (_matches(TokenType.SEMICOLON)) {
5303 semicolon = getAndAdvance(); 5342 semicolon = getAndAdvance();
5304 } else { 5343 } else {
5305 semicolon = _createSyntheticToken(TokenType.SEMICOLON); 5344 semicolon = _createSyntheticToken(TokenType.SEMICOLON);
5306 } 5345 }
5307 List<VariableDeclaration> variables = new List<VariableDeclaration>(); 5346 VariableDeclaration variable =
5308 variables.add( 5347 new VariableDeclaration(_createSyntheticIdentifier(), null, null);
5309 new VariableDeclaration(_createSyntheticIdentifier(), null, null)); 5348 List<VariableDeclaration> variables = <VariableDeclaration>[variable];
5310 return new TopLevelVariableDeclaration( 5349 return new TopLevelVariableDeclaration(
5311 commentAndMetadata.comment, 5350 commentAndMetadata.comment,
5312 commentAndMetadata.metadata, 5351 commentAndMetadata.metadata,
5313 new VariableDeclarationList(null, null, null, returnType, variables), 5352 new VariableDeclarationList(null, null, null, returnType, variables),
5314 semicolon); 5353 semicolon);
5315 } 5354 } else if (next.matchesAny(const <TokenType>[
5316 if (_peek().matchesAny(const <TokenType>[
5317 TokenType.OPEN_PAREN, 5355 TokenType.OPEN_PAREN,
5318 TokenType.FUNCTION, 5356 TokenType.FUNCTION,
5319 TokenType.OPEN_CURLY_BRACKET, 5357 TokenType.OPEN_CURLY_BRACKET,
5320 TokenType.LT 5358 TokenType.LT
5321 ])) { 5359 ])) {
5322 _validateModifiersForTopLevelFunction(modifiers); 5360 _validateModifiersForTopLevelFunction(modifiers);
5323 return _parseFunctionDeclaration( 5361 return _parseFunctionDeclaration(
5324 commentAndMetadata, modifiers.externalKeyword, returnType); 5362 commentAndMetadata, modifiers.externalKeyword, returnType);
5325 } 5363 }
5326 return new TopLevelVariableDeclaration( 5364 return new TopLevelVariableDeclaration(
5327 commentAndMetadata.comment, 5365 commentAndMetadata.comment,
5328 commentAndMetadata.metadata, 5366 commentAndMetadata.metadata,
5329 _parseVariableDeclarationListAfterType( 5367 _parseVariableDeclarationListAfterType(
5330 null, _validateModifiersForTopLevelVariable(modifiers), returnType), 5368 null, _validateModifiersForTopLevelVariable(modifiers), returnType),
5331 _expect(TokenType.SEMICOLON)); 5369 _expect(TokenType.SEMICOLON));
5332 } 5370 }
5333 5371
5334 /** 5372 /**
5335 * Parse a configuration in either an import or export directive. 5373 * Parse a configuration in either an import or export directive.
5336 * 5374 *
5375 * This method assumes that the current token matches `Keyword.IF`.
5376 *
5337 * configuration ::= 5377 * configuration ::=
5338 * 'if' '(' test ')' uri 5378 * 'if' '(' test ')' uri
5339 * 5379 *
5340 * test ::= 5380 * test ::=
5341 * dottedName ('==' stringLiteral)? 5381 * dottedName ('==' stringLiteral)?
5342 * 5382 *
5343 * dottedName ::= 5383 * dottedName ::=
5344 * identifier ('.' identifier)* 5384 * identifier ('.' identifier)*
5345 */ 5385 */
5346 Configuration _parseConfiguration() { 5386 Configuration _parseConfiguration() {
5347 Token ifKeyword = _expectKeyword(Keyword.IF); 5387 Token ifKeyword = getAndAdvance();
5348 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); 5388 Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
5349 DottedName name = _parseDottedName(); 5389 DottedName name = _parseDottedName();
5350 Token equalToken = null; 5390 Token equalToken = null;
5351 StringLiteral value = null; 5391 StringLiteral value = null;
5352 if (_matches(TokenType.EQ_EQ)) { 5392 if (_matches(TokenType.EQ_EQ)) {
5353 equalToken = getAndAdvance(); 5393 equalToken = getAndAdvance();
5354 value = parseStringLiteral(); 5394 value = parseStringLiteral();
5355 if (value is StringInterpolation) { 5395 if (value is StringInterpolation) {
5356 _reportErrorForNode( 5396 _reportErrorForNode(
5357 ParserErrorCode.INVALID_LITERAL_IN_CONFIGURATION, value); 5397 ParserErrorCode.INVALID_LITERAL_IN_CONFIGURATION, value);
5358 } 5398 }
5359 } 5399 }
5360 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); 5400 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
5361 StringLiteral libraryUri = _parseUri(); 5401 StringLiteral libraryUri = _parseUri();
5362 return new Configuration(ifKeyword, leftParenthesis, name, equalToken, 5402 return new Configuration(ifKeyword, leftParenthesis, name, equalToken,
5363 value, rightParenthesis, libraryUri); 5403 value, rightParenthesis, libraryUri);
5364 } 5404 }
5365 5405
5366 /** 5406 /**
5367 * Parse a list of configurations. If conditional directives are not 5407 * Parse a list of configurations. Return the configurations that were parsed,
5368 * supported, return an empty list without attempting to parse anything. 5408 * or `null` if there are no configurations.
5369 */ 5409 */
5370 List<Configuration> _parseConfigurations() { 5410 List<Configuration> _parseConfigurations() {
5371 List<Configuration> configurations = <Configuration>[]; 5411 List<Configuration> configurations = null;
5372 while (_matchesKeyword(Keyword.IF)) { 5412 while (_matchesKeyword(Keyword.IF)) {
5413 configurations ??= <Configuration>[];
5373 configurations.add(_parseConfiguration()); 5414 configurations.add(_parseConfiguration());
5374 } 5415 }
5375 return configurations; 5416 return configurations;
5376 } 5417 }
5377 5418
5378 /** 5419 /**
5379 * Parse a const expression. Return the const expression that was parsed. 5420 * Parse a const expression. Return the const expression that was parsed.
5380 * 5421 *
5422 * This method assumes that the current token matches `Keyword.CONST`.
5423 *
5381 * constExpression ::= 5424 * constExpression ::=
5382 * instanceCreationExpression 5425 * instanceCreationExpression
5383 * | listLiteral 5426 * | listLiteral
5384 * | mapLiteral 5427 * | mapLiteral
5385 */ 5428 */
5386 Expression _parseConstExpression() { 5429 Expression _parseConstExpression() {
5387 Token keyword = _expectKeyword(Keyword.CONST); 5430 Token keyword = getAndAdvance();
5388 if (_matches(TokenType.LT) || _injectGenericCommentTypeList()) { 5431 TokenType type = _currentToken.type;
5432 if (type == TokenType.LT || _injectGenericCommentTypeList()) {
5389 return _parseListOrMapLiteral(keyword); 5433 return _parseListOrMapLiteral(keyword);
5390 } else if (_matches(TokenType.OPEN_SQUARE_BRACKET) || 5434 } else if (type == TokenType.OPEN_SQUARE_BRACKET ||
5391 _matches(TokenType.INDEX)) { 5435 type == TokenType.INDEX) {
5392 return _parseListLiteral(keyword, null); 5436 return _parseListLiteral(keyword, null);
5393 } else if (_matches(TokenType.OPEN_CURLY_BRACKET)) { 5437 } else if (type == TokenType.OPEN_CURLY_BRACKET) {
5394 return _parseMapLiteral(keyword, null); 5438 return _parseMapLiteral(keyword, null);
5395 } 5439 }
5396 return _parseInstanceCreationExpression(keyword); 5440 return _parseInstanceCreationExpression(keyword);
5397 } 5441 }
5398 5442
5399 ConstructorDeclaration _parseConstructor( 5443 ConstructorDeclaration _parseConstructor(
5400 CommentAndMetadata commentAndMetadata, 5444 CommentAndMetadata commentAndMetadata,
5401 Token externalKeyword, 5445 Token externalKeyword,
5402 Token constKeyword, 5446 Token constKeyword,
5403 Token factoryKeyword, 5447 Token factoryKeyword,
5404 SimpleIdentifier returnType, 5448 SimpleIdentifier returnType,
5405 Token period, 5449 Token period,
5406 SimpleIdentifier name, 5450 SimpleIdentifier name,
5407 FormalParameterList parameters) { 5451 FormalParameterList parameters) {
5408 bool bodyAllowed = externalKeyword == null; 5452 bool bodyAllowed = externalKeyword == null;
5409 Token separator = null; 5453 Token separator = null;
5410 List<ConstructorInitializer> initializers = null; 5454 List<ConstructorInitializer> initializers = null;
5411 if (_matches(TokenType.COLON)) { 5455 if (_matches(TokenType.COLON)) {
5412 separator = getAndAdvance(); 5456 separator = getAndAdvance();
5413 initializers = new List<ConstructorInitializer>(); 5457 initializers = <ConstructorInitializer>[];
5414 do { 5458 do {
5415 if (_matchesKeyword(Keyword.THIS)) { 5459 Keyword keyword = _currentToken.keyword;
5416 if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { 5460 if (keyword == Keyword.THIS) {
5461 TokenType nextType = _peek().type;
5462 if (nextType == TokenType.OPEN_PAREN) {
5417 bodyAllowed = false; 5463 bodyAllowed = false;
5418 initializers.add(_parseRedirectingConstructorInvocation()); 5464 initializers.add(_parseRedirectingConstructorInvocation(false));
5419 } else if (_tokenMatches(_peek(), TokenType.PERIOD) && 5465 } else if (nextType == TokenType.PERIOD &&
5420 _tokenMatches(_peekAt(3), TokenType.OPEN_PAREN)) { 5466 _tokenMatches(_peekAt(3), TokenType.OPEN_PAREN)) {
5421 bodyAllowed = false; 5467 bodyAllowed = false;
5422 initializers.add(_parseRedirectingConstructorInvocation()); 5468 initializers.add(_parseRedirectingConstructorInvocation(true));
5423 } else { 5469 } else {
5424 initializers.add(_parseConstructorFieldInitializer()); 5470 initializers.add(_parseConstructorFieldInitializer(true));
5425 } 5471 }
5426 } else if (_matchesKeyword(Keyword.SUPER)) { 5472 } else if (keyword == Keyword.SUPER) {
5427 initializers.add(_parseSuperConstructorInvocation()); 5473 initializers.add(_parseSuperConstructorInvocation());
5428 } else if (_matches(TokenType.OPEN_CURLY_BRACKET) || 5474 } else if (_matches(TokenType.OPEN_CURLY_BRACKET) ||
5429 _matches(TokenType.FUNCTION)) { 5475 _matches(TokenType.FUNCTION)) {
5430 _reportErrorForCurrentToken(ParserErrorCode.MISSING_INITIALIZER); 5476 _reportErrorForCurrentToken(ParserErrorCode.MISSING_INITIALIZER);
5431 } else { 5477 } else {
5432 initializers.add(_parseConstructorFieldInitializer()); 5478 initializers.add(_parseConstructorFieldInitializer(false));
5433 } 5479 }
5434 } while (_optional(TokenType.COMMA)); 5480 } while (_optional(TokenType.COMMA));
5435 if (factoryKeyword != null) { 5481 if (factoryKeyword != null) {
5436 _reportErrorForToken( 5482 _reportErrorForToken(
5437 ParserErrorCode.FACTORY_WITH_INITIALIZERS, factoryKeyword); 5483 ParserErrorCode.FACTORY_WITH_INITIALIZERS, factoryKeyword);
5438 } 5484 }
5439 } 5485 }
5440 ConstructorName redirectedConstructor = null; 5486 ConstructorName redirectedConstructor = null;
5441 FunctionBody body; 5487 FunctionBody body;
5442 if (_matches(TokenType.EQ)) { 5488 if (_matches(TokenType.EQ)) {
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
5485 period, 5531 period,
5486 name, 5532 name,
5487 parameters, 5533 parameters,
5488 separator, 5534 separator,
5489 initializers, 5535 initializers,
5490 redirectedConstructor, 5536 redirectedConstructor,
5491 body); 5537 body);
5492 } 5538 }
5493 5539
5494 /** 5540 /**
5495 * Parse a field initializer within a constructor. Return the field 5541 * Parse a field initializer within a constructor. The flag [hasThis] should
5496 * initializer that was parsed. 5542 * be true if the current token is `this`. Return the field initializer that
5543 * was parsed.
5497 * 5544 *
5498 * fieldInitializer: 5545 * fieldInitializer:
5499 * ('this' '.')? identifier '=' conditionalExpression cascadeSection* 5546 * ('this' '.')? identifier '=' conditionalExpression cascadeSection*
5500 */ 5547 */
5501 ConstructorFieldInitializer _parseConstructorFieldInitializer() { 5548 ConstructorFieldInitializer _parseConstructorFieldInitializer(bool hasThis) {
5502 Token keyword = null; 5549 Token keywordToken = null;
5503 Token period = null; 5550 Token period = null;
5504 if (_matchesKeyword(Keyword.THIS)) { 5551 if (hasThis) {
5505 keyword = getAndAdvance(); 5552 keywordToken = getAndAdvance();
5506 period = _expect(TokenType.PERIOD); 5553 period = _expect(TokenType.PERIOD);
5507 } 5554 }
5508 SimpleIdentifier fieldName = parseSimpleIdentifier(); 5555 SimpleIdentifier fieldName = parseSimpleIdentifier();
5509 Token equals = null; 5556 Token equals = null;
5510 if (_matches(TokenType.EQ)) { 5557 TokenType type = _currentToken.type;
5558 if (type == TokenType.EQ) {
5511 equals = getAndAdvance(); 5559 equals = getAndAdvance();
5512 } else if (!_matchesKeyword(Keyword.THIS) &&
5513 !_matchesKeyword(Keyword.SUPER) &&
5514 !_matches(TokenType.OPEN_CURLY_BRACKET) &&
5515 !_matches(TokenType.FUNCTION)) {
5516 _reportErrorForCurrentToken(
5517 ParserErrorCode.MISSING_ASSIGNMENT_IN_INITIALIZER);
5518 equals = _createSyntheticToken(TokenType.EQ);
5519 } else { 5560 } else {
5520 _reportErrorForCurrentToken( 5561 _reportErrorForCurrentToken(
5521 ParserErrorCode.MISSING_ASSIGNMENT_IN_INITIALIZER); 5562 ParserErrorCode.MISSING_ASSIGNMENT_IN_INITIALIZER);
5522 return new ConstructorFieldInitializer(keyword, period, fieldName, 5563 Keyword keyword = _currentToken.keyword;
5523 _createSyntheticToken(TokenType.EQ), _createSyntheticIdentifier()); 5564 if (keyword != Keyword.THIS &&
5565 keyword != Keyword.SUPER &&
5566 type != TokenType.OPEN_CURLY_BRACKET &&
5567 type != TokenType.FUNCTION) {
5568 equals = _createSyntheticToken(TokenType.EQ);
5569 } else {
5570 return new ConstructorFieldInitializer(keywordToken, period, fieldName,
5571 _createSyntheticToken(TokenType.EQ), _createSyntheticIdentifier());
5572 }
5524 } 5573 }
5525 bool wasInInitializer = _inInitializer; 5574 bool wasInInitializer = _inInitializer;
5526 _inInitializer = true; 5575 _inInitializer = true;
5527 try { 5576 try {
5528 Expression expression = parseConditionalExpression(); 5577 Expression expression = parseConditionalExpression();
5529 TokenType tokenType = _currentToken.type; 5578 if (_matches(TokenType.PERIOD_PERIOD)) {
5530 if (tokenType == TokenType.PERIOD_PERIOD) { 5579 List<Expression> cascadeSections = <Expression>[];
5531 List<Expression> cascadeSections = new List<Expression>(); 5580 do {
5532 while (tokenType == TokenType.PERIOD_PERIOD) {
5533 Expression section = _parseCascadeSection(); 5581 Expression section = _parseCascadeSection();
5534 if (section != null) { 5582 if (section != null) {
5535 cascadeSections.add(section); 5583 cascadeSections.add(section);
5536 } 5584 }
5537 tokenType = _currentToken.type; 5585 } while (_matches(TokenType.PERIOD_PERIOD));
5538 }
5539 expression = new CascadeExpression(expression, cascadeSections); 5586 expression = new CascadeExpression(expression, cascadeSections);
5540 } 5587 }
5541 return new ConstructorFieldInitializer( 5588 return new ConstructorFieldInitializer(
5542 keyword, period, fieldName, equals, expression); 5589 keywordToken, period, fieldName, equals, expression);
5543 } finally { 5590 } finally {
5544 _inInitializer = wasInInitializer; 5591 _inInitializer = wasInInitializer;
5545 } 5592 }
5546 } 5593 }
5547 5594
5548 /** 5595 /**
5549 * Parse a continue statement. Return the continue statement that was parsed. 5596 * Parse a continue statement. Return the continue statement that was parsed.
5550 * 5597 *
5598 * This method assumes that the current token matches `Keyword.CONTINUE`.
5599 *
5551 * continueStatement ::= 5600 * continueStatement ::=
5552 * 'continue' identifier? ';' 5601 * 'continue' identifier? ';'
5553 */ 5602 */
5554 Statement _parseContinueStatement() { 5603 Statement _parseContinueStatement() {
5555 Token continueKeyword = _expectKeyword(Keyword.CONTINUE); 5604 Token continueKeyword = getAndAdvance();
5556 if (!_inLoop && !_inSwitch) { 5605 if (!_inLoop && !_inSwitch) {
5557 _reportErrorForToken( 5606 _reportErrorForToken(
5558 ParserErrorCode.CONTINUE_OUTSIDE_OF_LOOP, continueKeyword); 5607 ParserErrorCode.CONTINUE_OUTSIDE_OF_LOOP, continueKeyword);
5559 } 5608 }
5560 SimpleIdentifier label = null; 5609 SimpleIdentifier label = null;
5561 if (_matchesIdentifier()) { 5610 if (_matchesIdentifier()) {
5562 label = parseSimpleIdentifier(); 5611 label = _parseSimpleIdentifierUnchecked();
5563 } 5612 }
5564 if (_inSwitch && !_inLoop && label == null) { 5613 if (_inSwitch && !_inLoop && label == null) {
5565 _reportErrorForToken( 5614 _reportErrorForToken(
5566 ParserErrorCode.CONTINUE_WITHOUT_LABEL_IN_CASE, continueKeyword); 5615 ParserErrorCode.CONTINUE_WITHOUT_LABEL_IN_CASE, continueKeyword);
5567 } 5616 }
5568 Token semicolon = _expect(TokenType.SEMICOLON); 5617 Token semicolon = _expect(TokenType.SEMICOLON);
5569 return new ContinueStatement(continueKeyword, label, semicolon); 5618 return new ContinueStatement(continueKeyword, label, semicolon);
5570 } 5619 }
5571 5620
5572 /** 5621 /**
5573 * Parse a directive. The [commentAndMetadata] is the metadata to be 5622 * Parse a directive. The [commentAndMetadata] is the metadata to be
5574 * associated with the directive. Return the directive that was parsed. 5623 * associated with the directive. Return the directive that was parsed.
5575 * 5624 *
5576 * directive ::= 5625 * directive ::=
5577 * exportDirective 5626 * exportDirective
5578 * | libraryDirective 5627 * | libraryDirective
5579 * | importDirective 5628 * | importDirective
5580 * | partDirective 5629 * | partDirective
5581 */ 5630 */
5582 Directive _parseDirective(CommentAndMetadata commentAndMetadata) { 5631 Directive _parseDirective(CommentAndMetadata commentAndMetadata) {
5583 if (_matchesKeyword(Keyword.IMPORT)) { 5632 if (_matchesKeyword(Keyword.IMPORT)) {
5584 return _parseImportDirective(commentAndMetadata); 5633 return _parseImportDirective(commentAndMetadata);
5585 } else if (_matchesKeyword(Keyword.EXPORT)) { 5634 } else if (_matchesKeyword(Keyword.EXPORT)) {
5586 return _parseExportDirective(commentAndMetadata); 5635 return _parseExportDirective(commentAndMetadata);
5587 } else if (_matchesKeyword(Keyword.LIBRARY)) { 5636 } else if (_matchesKeyword(Keyword.LIBRARY)) {
5588 return _parseLibraryDirective(commentAndMetadata); 5637 return _parseLibraryDirective(commentAndMetadata);
5589 } else if (_matchesKeyword(Keyword.PART)) { 5638 } else if (_matchesKeyword(Keyword.PART)) {
5590 return _parsePartDirective(commentAndMetadata); 5639 return _parsePartOrPartOfDirective(commentAndMetadata);
5591 } else { 5640 } else {
5592 // Internal error: this method should not have been invoked if the current 5641 // Internal error: this method should not have been invoked if the current
5593 // token was something other than one of the above. 5642 // token was something other than one of the above.
5594 throw new IllegalStateException( 5643 throw new IllegalStateException(
5595 "parseDirective invoked in an invalid state; currentToken = $_currentT oken"); 5644 "parseDirective invoked in an invalid state; currentToken = $_currentT oken");
5596 } 5645 }
5597 } 5646 }
5598 5647
5599 /** 5648 /**
5600 * Parse the script tag and directives in a compilation unit until the first 5649 * Parse the script tag and directives in a compilation unit until the first
5601 * non-directive is encountered. Return the compilation unit that was parsed. 5650 * non-directive is encountered. Return the compilation unit that was parsed.
5602 * 5651 *
5603 * compilationUnit ::= 5652 * compilationUnit ::=
5604 * scriptTag? directive* 5653 * scriptTag? directive*
5605 */ 5654 */
5606 CompilationUnit _parseDirectives() { 5655 CompilationUnit _parseDirectives() {
5607 Token firstToken = _currentToken; 5656 Token firstToken = _currentToken;
5608 ScriptTag scriptTag = null; 5657 ScriptTag scriptTag = null;
5609 if (_matches(TokenType.SCRIPT_TAG)) { 5658 if (_matches(TokenType.SCRIPT_TAG)) {
5610 scriptTag = new ScriptTag(getAndAdvance()); 5659 scriptTag = new ScriptTag(getAndAdvance());
5611 } 5660 }
5612 List<Directive> directives = new List<Directive>(); 5661 List<Directive> directives = <Directive>[];
5613 while (!_matches(TokenType.EOF)) { 5662 while (!_matches(TokenType.EOF)) {
5614 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); 5663 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata();
5615 if ((_matchesKeyword(Keyword.IMPORT) || 5664 Keyword keyword = _currentToken.keyword;
5616 _matchesKeyword(Keyword.EXPORT) || 5665 TokenType type = _peek().type;
5617 _matchesKeyword(Keyword.LIBRARY) || 5666 if ((keyword == Keyword.IMPORT ||
5618 _matchesKeyword(Keyword.PART)) && 5667 keyword == Keyword.EXPORT ||
5619 !_tokenMatches(_peek(), TokenType.PERIOD) && 5668 keyword == Keyword.LIBRARY ||
5620 !_tokenMatches(_peek(), TokenType.LT) && 5669 keyword == Keyword.PART) &&
5621 !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { 5670 type != TokenType.PERIOD &&
5671 type != TokenType.LT &&
5672 type != TokenType.OPEN_PAREN) {
5622 directives.add(_parseDirective(commentAndMetadata)); 5673 directives.add(_parseDirective(commentAndMetadata));
5623 } else if (_matches(TokenType.SEMICOLON)) { 5674 } else if (_matches(TokenType.SEMICOLON)) {
5624 _advance(); 5675 _advance();
5625 } else { 5676 } else {
5626 while (!_matches(TokenType.EOF)) { 5677 while (!_matches(TokenType.EOF)) {
5627 _advance(); 5678 _advance();
5628 } 5679 }
5629 return new CompilationUnit(firstToken, scriptTag, directives, 5680 return new CompilationUnit(
5630 new List<CompilationUnitMember>(), _currentToken); 5681 firstToken, scriptTag, directives, null, _currentToken);
5631 } 5682 }
5632 } 5683 }
5633 return new CompilationUnit(firstToken, scriptTag, directives, 5684 return new CompilationUnit(
5634 new List<CompilationUnitMember>(), _currentToken); 5685 firstToken, scriptTag, directives, null, _currentToken);
5635 } 5686 }
5636 5687
5637 /** 5688 /**
5689 * Parse a documentation comment based on the given list of documentation
5690 * comment tokens. Return the documentation comment that was parsed, or `null`
5691 * if there was no comment.
5692 *
5693 * documentationComment ::=
5694 * multiLineComment?
5695 * | singleLineComment*
5696 */
5697 Comment _parseDocumentationComment(List<DocumentationCommentToken> tokens) {
5698 if (tokens == null) {
5699 return null;
5700 }
5701 List<CommentReference> references = _parseCommentReferences(tokens);
5702 return Comment.createDocumentationCommentWithReferences(tokens, references);
5703 }
5704
5705 /**
5638 * Parse a documentation comment. Return the documentation comment that was 5706 * Parse a documentation comment. Return the documentation comment that was
5639 * parsed, or `null` if there was no comment. 5707 * parsed, or `null` if there was no comment.
5640 * 5708 *
5641 * documentationComment ::= 5709 * documentationComment ::=
5642 * multiLineComment? 5710 * multiLineComment?
5643 * | singleLineComment* 5711 * | singleLineComment*
5644 */ 5712 */
5645 Comment _parseDocumentationComment() { 5713 List<DocumentationCommentToken> _parseDocumentationCommentTokens() {
5646 List<DocumentationCommentToken> documentationTokens = 5714 List<DocumentationCommentToken> tokens = <DocumentationCommentToken>[];
5647 <DocumentationCommentToken>[];
5648 CommentToken commentToken = _currentToken.precedingComments; 5715 CommentToken commentToken = _currentToken.precedingComments;
5649 while (commentToken != null) { 5716 while (commentToken != null) {
5650 if (commentToken is DocumentationCommentToken) { 5717 if (commentToken is DocumentationCommentToken) {
5651 if (documentationTokens.isNotEmpty) { 5718 if (tokens.isNotEmpty) {
5652 if (commentToken.type == TokenType.SINGLE_LINE_COMMENT) { 5719 if (commentToken.type == TokenType.SINGLE_LINE_COMMENT) {
5653 if (documentationTokens[0].type != TokenType.SINGLE_LINE_COMMENT) { 5720 if (tokens[0].type != TokenType.SINGLE_LINE_COMMENT) {
5654 documentationTokens.clear(); 5721 tokens.clear();
5655 } 5722 }
5656 } else { 5723 } else {
5657 documentationTokens.clear(); 5724 tokens.clear();
5658 } 5725 }
5659 } 5726 }
5660 documentationTokens.add(commentToken); 5727 tokens.add(commentToken);
5661 } 5728 }
5662 commentToken = commentToken.next; 5729 commentToken = commentToken.next;
5663 } 5730 }
5664 if (documentationTokens.isEmpty) { 5731 return tokens.isEmpty ? null : tokens;
5665 return null;
5666 }
5667 List<CommentReference> references =
5668 _parseCommentReferences(documentationTokens);
5669 return Comment.createDocumentationCommentWithReferences(
5670 documentationTokens, references);
5671 } 5732 }
5672 5733
5673 /** 5734 /**
5674 * Parse a do statement. Return the do statement that was parsed. 5735 * Parse a do statement. Return the do statement that was parsed.
5675 * 5736 *
5737 * This method assumes that the current token matches `Keyword.DO`.
5738 *
5676 * doStatement ::= 5739 * doStatement ::=
5677 * 'do' statement 'while' '(' expression ')' ';' 5740 * 'do' statement 'while' '(' expression ')' ';'
5678 */ 5741 */
5679 Statement _parseDoStatement() { 5742 Statement _parseDoStatement() {
5680 bool wasInLoop = _inLoop; 5743 bool wasInLoop = _inLoop;
5681 _inLoop = true; 5744 _inLoop = true;
5682 try { 5745 try {
5683 Token doKeyword = _expectKeyword(Keyword.DO); 5746 Token doKeyword = getAndAdvance();
5684 Statement body = parseStatement2(); 5747 Statement body = parseStatement2();
5685 Token whileKeyword = _expectKeyword(Keyword.WHILE); 5748 Token whileKeyword = _expectKeyword(Keyword.WHILE);
5686 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); 5749 Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
5687 Expression condition = parseExpression2(); 5750 Expression condition = parseExpression2();
5688 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); 5751 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
5689 Token semicolon = _expect(TokenType.SEMICOLON); 5752 Token semicolon = _expect(TokenType.SEMICOLON);
5690 return new DoStatement(doKeyword, body, whileKeyword, leftParenthesis, 5753 return new DoStatement(doKeyword, body, whileKeyword, leftParenthesis,
5691 condition, rightParenthesis, semicolon); 5754 condition, rightParenthesis, semicolon);
5692 } finally { 5755 } finally {
5693 _inLoop = wasInLoop; 5756 _inLoop = wasInLoop;
5694 } 5757 }
5695 } 5758 }
5696 5759
5697 /** 5760 /**
5698 * Parse a dotted name. Return the dotted name that was parsed. 5761 * Parse a dotted name. Return the dotted name that was parsed.
5699 * 5762 *
5700 * dottedName ::= 5763 * dottedName ::=
5701 * identifier ('.' identifier)* 5764 * identifier ('.' identifier)*
5702 */ 5765 */
5703 DottedName _parseDottedName() { 5766 DottedName _parseDottedName() {
5704 List<SimpleIdentifier> components = new List<SimpleIdentifier>(); 5767 List<SimpleIdentifier> components = <SimpleIdentifier>[
5705 components.add(parseSimpleIdentifier()); 5768 parseSimpleIdentifier()
5706 while (_matches(TokenType.PERIOD)) { 5769 ];
5707 _advance(); 5770 while (_optional(TokenType.PERIOD)) {
5708 components.add(parseSimpleIdentifier()); 5771 components.add(parseSimpleIdentifier());
5709 } 5772 }
5710 return new DottedName(components); 5773 return new DottedName(components);
5711 } 5774 }
5712 5775
5713 /** 5776 /**
5714 * Parse an empty statement. Return the empty statement that was parsed. 5777 * Parse an empty statement. Return the empty statement that was parsed.
5715 * 5778 *
5779 * This method assumes that the current token matches `TokenType.SEMICOLON`.
5780 *
5716 * emptyStatement ::= 5781 * emptyStatement ::=
5717 * ';' 5782 * ';'
5718 */ 5783 */
5719 Statement _parseEmptyStatement() => new EmptyStatement(getAndAdvance()); 5784 Statement _parseEmptyStatement() => new EmptyStatement(getAndAdvance());
5720 5785
5786 /**
5787 * Parse an enum constant declaration. Return the enum constant declaration
5788 * that was parsed.
5789 *
5790 * Specified:
5791 *
5792 * enumConstant ::=
5793 * id
5794 *
5795 * Actual:
5796 *
5797 * enumConstant ::=
5798 * metadata id
5799 */
5721 EnumConstantDeclaration _parseEnumConstantDeclaration() { 5800 EnumConstantDeclaration _parseEnumConstantDeclaration() {
5722 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); 5801 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata();
5723 SimpleIdentifier name; 5802 SimpleIdentifier name;
5724 if (_matchesIdentifier()) { 5803 if (_matchesIdentifier()) {
5725 name = parseSimpleIdentifier(isDeclaration: true); 5804 name = _parseSimpleIdentifierUnchecked(isDeclaration: true);
5726 } else { 5805 } else {
5727 name = _createSyntheticIdentifier(); 5806 name = _createSyntheticIdentifier();
5728 } 5807 }
5729 if (commentAndMetadata.metadata.isNotEmpty) { 5808 if (commentAndMetadata.hasMetadata) {
5730 _reportErrorForNode(ParserErrorCode.ANNOTATION_ON_ENUM_CONSTANT, 5809 _reportErrorForNode(ParserErrorCode.ANNOTATION_ON_ENUM_CONSTANT,
5731 commentAndMetadata.metadata[0]); 5810 commentAndMetadata.metadata[0]);
5732 } 5811 }
5733 return new EnumConstantDeclaration( 5812 return new EnumConstantDeclaration(
5734 commentAndMetadata.comment, commentAndMetadata.metadata, name); 5813 commentAndMetadata.comment, commentAndMetadata.metadata, name);
5735 } 5814 }
5736 5815
5737 /** 5816 /**
5738 * Parse an enum declaration. The [commentAndMetadata] is the metadata to be 5817 * Parse an enum declaration. The [commentAndMetadata] is the metadata to be
5739 * associated with the member. Return the enum declaration that was parsed. 5818 * associated with the member. Return the enum declaration that was parsed.
5740 * 5819 *
5820 * This method assumes that the current token matches `Keyword.ENUM`.
5821 *
5741 * enumType ::= 5822 * enumType ::=
5742 * metadata 'enum' id '{' id (',' id)* (',')? '}' 5823 * metadata 'enum' id '{' id (',' id)* (',')? '}'
5743 */ 5824 */
5744 EnumDeclaration _parseEnumDeclaration(CommentAndMetadata commentAndMetadata) { 5825 EnumDeclaration _parseEnumDeclaration(CommentAndMetadata commentAndMetadata) {
5745 Token keyword = _expectKeyword(Keyword.ENUM); 5826 Token keyword = getAndAdvance();
5746 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true); 5827 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
5747 Token leftBracket = null; 5828 Token leftBracket = null;
5748 List<EnumConstantDeclaration> constants = 5829 List<EnumConstantDeclaration> constants = <EnumConstantDeclaration>[];
5749 new List<EnumConstantDeclaration>();
5750 Token rightBracket = null; 5830 Token rightBracket = null;
5751 if (_matches(TokenType.OPEN_CURLY_BRACKET)) { 5831 if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
5752 leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET); 5832 leftBracket = getAndAdvance();
5753 if (_matchesIdentifier() || _matches(TokenType.AT)) { 5833 if (_matchesIdentifier() || _matches(TokenType.AT)) {
5754 constants.add(_parseEnumConstantDeclaration()); 5834 constants.add(_parseEnumConstantDeclaration());
5755 } else if (_matches(TokenType.COMMA) && 5835 } else if (_matches(TokenType.COMMA) &&
5756 _tokenMatchesIdentifier(_peek())) { 5836 _tokenMatchesIdentifier(_peek())) {
5757 constants.add(_parseEnumConstantDeclaration()); 5837 constants.add(_parseEnumConstantDeclaration());
5758 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); 5838 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
5759 } else { 5839 } else {
5760 constants.add(_parseEnumConstantDeclaration()); 5840 constants.add(_parseEnumConstantDeclaration());
5761 _reportErrorForCurrentToken(ParserErrorCode.EMPTY_ENUM_BODY); 5841 _reportErrorForCurrentToken(ParserErrorCode.EMPTY_ENUM_BODY);
5762 } 5842 }
(...skipping 22 matching lines...) Expand all
5785 /** 5865 /**
5786 * Parse an equality expression. Return the equality expression that was 5866 * Parse an equality expression. Return the equality expression that was
5787 * parsed. 5867 * parsed.
5788 * 5868 *
5789 * equalityExpression ::= 5869 * equalityExpression ::=
5790 * relationalExpression (equalityOperator relationalExpression)? 5870 * relationalExpression (equalityOperator relationalExpression)?
5791 * | 'super' equalityOperator relationalExpression 5871 * | 'super' equalityOperator relationalExpression
5792 */ 5872 */
5793 Expression _parseEqualityExpression() { 5873 Expression _parseEqualityExpression() {
5794 Expression expression; 5874 Expression expression;
5795 if (_matchesKeyword(Keyword.SUPER) && 5875 if (_currentToken.keyword == Keyword.SUPER &&
5796 _currentToken.next.type.isEqualityOperator) { 5876 _currentToken.next.type.isEqualityOperator) {
5797 expression = new SuperExpression(getAndAdvance()); 5877 expression = new SuperExpression(getAndAdvance());
5798 } else { 5878 } else {
5799 expression = _parseRelationalExpression(); 5879 expression = _parseRelationalExpression();
5800 } 5880 }
5801 bool leftEqualityExpression = false; 5881 bool leftEqualityExpression = false;
5802 while (_currentToken.type.isEqualityOperator) { 5882 while (_currentToken.type.isEqualityOperator) {
5803 Token operator = getAndAdvance();
5804 if (leftEqualityExpression) { 5883 if (leftEqualityExpression) {
5805 _reportErrorForNode( 5884 _reportErrorForNode(
5806 ParserErrorCode.EQUALITY_CANNOT_BE_EQUALITY_OPERAND, expression); 5885 ParserErrorCode.EQUALITY_CANNOT_BE_EQUALITY_OPERAND, expression);
5807 } 5886 }
5808 expression = new BinaryExpression( 5887 expression = new BinaryExpression(
5809 expression, operator, _parseRelationalExpression()); 5888 expression, getAndAdvance(), _parseRelationalExpression());
5810 leftEqualityExpression = true; 5889 leftEqualityExpression = true;
5811 } 5890 }
5812 return expression; 5891 return expression;
5813 } 5892 }
5814 5893
5815 /** 5894 /**
5816 * Parse an export directive. The [commentAndMetadata] is the metadata to be 5895 * Parse an export directive. The [commentAndMetadata] is the metadata to be
5817 * associated with the directive. Return the export directive that was parsed. 5896 * associated with the directive. Return the export directive that was parsed.
5818 * 5897 *
5898 * This method assumes that the current token matches `Keyword.EXPORT`.
5899 *
5819 * exportDirective ::= 5900 * exportDirective ::=
5820 * metadata 'export' stringLiteral configuration* combinator*';' 5901 * metadata 'export' stringLiteral configuration* combinator*';'
5821 */ 5902 */
5822 ExportDirective _parseExportDirective(CommentAndMetadata commentAndMetadata) { 5903 ExportDirective _parseExportDirective(CommentAndMetadata commentAndMetadata) {
5823 Token exportKeyword = _expectKeyword(Keyword.EXPORT); 5904 Token exportKeyword = getAndAdvance();
5824 StringLiteral libraryUri = _parseUri(); 5905 StringLiteral libraryUri = _parseUri();
5825 List<Configuration> configurations = _parseConfigurations(); 5906 List<Configuration> configurations = _parseConfigurations();
5826 List<Combinator> combinators = _parseCombinators(); 5907 List<Combinator> combinators = _parseCombinators();
5827 Token semicolon = _expect(TokenType.SEMICOLON); 5908 Token semicolon = _expect(TokenType.SEMICOLON);
5828 return new ExportDirective( 5909 return new ExportDirective(
5829 commentAndMetadata.comment, 5910 commentAndMetadata.comment,
5830 commentAndMetadata.metadata, 5911 commentAndMetadata.metadata,
5831 exportKeyword, 5912 exportKeyword,
5832 libraryUri, 5913 libraryUri,
5833 configurations, 5914 configurations,
5834 combinators, 5915 combinators,
5835 semicolon); 5916 semicolon);
5836 } 5917 }
5837 5918
5838 /** 5919 /**
5839 * Parse a list of expressions. Return the expression that was parsed. 5920 * Parse a list of expressions. Return the expression that was parsed.
5840 * 5921 *
5841 * expressionList ::= 5922 * expressionList ::=
5842 * expression (',' expression)* 5923 * expression (',' expression)*
5843 */ 5924 */
5844 List<Expression> _parseExpressionList() { 5925 List<Expression> _parseExpressionList() {
5845 List<Expression> expressions = new List<Expression>(); 5926 List<Expression> expressions = <Expression>[parseExpression2()];
5846 expressions.add(parseExpression2());
5847 while (_optional(TokenType.COMMA)) { 5927 while (_optional(TokenType.COMMA)) {
5848 expressions.add(parseExpression2()); 5928 expressions.add(parseExpression2());
5849 } 5929 }
5850 return expressions; 5930 return expressions;
5851 } 5931 }
5852 5932
5853 /** 5933 /**
5854 * Parse the 'final', 'const', 'var' or type preceding a variable declaration. 5934 * Parse the 'final', 'const', 'var' or type preceding a variable declaration.
5855 * The [optional] is `true` if the keyword and type are optional. Return the 5935 * The [optional] is `true` if the keyword and type are optional. Return the
5856 * 'final', 'const', 'var' or type that was parsed. 5936 * 'final', 'const', 'var' or type that was parsed.
5857 * 5937 *
5858 * finalConstVarOrType ::= 5938 * finalConstVarOrType ::=
5859 * 'final' type? 5939 * 'final' type?
5860 * | 'const' type? 5940 * | 'const' type?
5861 * | 'var' 5941 * | 'var'
5862 * | type 5942 * | type
5863 */ 5943 */
5864 FinalConstVarOrType _parseFinalConstVarOrType(bool optional) { 5944 FinalConstVarOrType _parseFinalConstVarOrType(bool optional) {
5865 Token keyword = null; 5945 Token keywordToken = null;
5866 TypeName type = null; 5946 TypeName type = null;
5867 if (_matchesKeyword(Keyword.FINAL) || _matchesKeyword(Keyword.CONST)) { 5947 Keyword keyword = _currentToken.keyword;
5868 keyword = getAndAdvance(); 5948 if (keyword == Keyword.FINAL || keyword == Keyword.CONST) {
5949 keywordToken = getAndAdvance();
5869 if (_isTypedIdentifier(_currentToken)) { 5950 if (_isTypedIdentifier(_currentToken)) {
5870 type = parseTypeName(); 5951 type = parseTypeName();
5871 } else { 5952 } else {
5872 // Support `final/*=T*/ x;` 5953 // Support `final/*=T*/ x;`
5873 type = _parseOptionalTypeNameComment(); 5954 type = _parseOptionalTypeNameComment();
5874 } 5955 }
5875 } else if (_matchesKeyword(Keyword.VAR)) { 5956 } else if (keyword == Keyword.VAR) {
5876 keyword = getAndAdvance(); 5957 keywordToken = getAndAdvance();
5877 // Support `var/*=T*/ x;` 5958 // Support `var/*=T*/ x;`
5878 type = _parseOptionalTypeNameComment(); 5959 type = _parseOptionalTypeNameComment();
5879 if (type != null) { 5960 if (type != null) {
5880 // Clear the keyword to prevent an error. 5961 // Clear the keyword to prevent an error.
5881 keyword = null; 5962 keywordToken = null;
5882 } 5963 }
5883 } else if (_isTypedIdentifier(_currentToken)) { 5964 } else if (_isTypedIdentifier(_currentToken)) {
5884 type = parseReturnType(); 5965 type = parseReturnType();
5885 } else if (!optional) { 5966 } else if (!optional) {
5886 _reportErrorForCurrentToken( 5967 _reportErrorForCurrentToken(
5887 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE); 5968 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE);
5888 } else { 5969 } else {
5889 // Support parameters such as `(/*=K*/ key, /*=V*/ value)` 5970 // Support parameters such as `(/*=K*/ key, /*=V*/ value)`
5890 // This is not supported if the type is required. 5971 // This is not supported if the type is required.
5891 type = _parseOptionalTypeNameComment(); 5972 type = _parseOptionalTypeNameComment();
5892 } 5973 }
5893 return new FinalConstVarOrType(keyword, type); 5974 return new FinalConstVarOrType(keywordToken, type);
5894 } 5975 }
5895 5976
5896 /** 5977 /**
5897 * Parse a formal parameter. At most one of `isOptional` and `isNamed` can be 5978 * Parse a formal parameter. At most one of `isOptional` and `isNamed` can be
5898 * `true`. The [kind] is the kind of parameter being expected based on the 5979 * `true`. The [kind] is the kind of parameter being expected based on the
5899 * presence or absence of group delimiters. Return the formal parameter that 5980 * presence or absence of group delimiters. Return the formal parameter that
5900 * was parsed. 5981 * was parsed.
5901 * 5982 *
5902 * defaultFormalParameter ::= 5983 * defaultFormalParameter ::=
5903 * normalFormalParameter ('=' expression)? 5984 * normalFormalParameter ('=' expression)?
5904 * 5985 *
5905 * defaultNamedParameter ::= 5986 * defaultNamedParameter ::=
5906 * normalFormalParameter (':' expression)? 5987 * normalFormalParameter (':' expression)?
5907 */ 5988 */
5908 FormalParameter _parseFormalParameter(ParameterKind kind) { 5989 FormalParameter _parseFormalParameter(ParameterKind kind) {
5909 NormalFormalParameter parameter = parseNormalFormalParameter(); 5990 NormalFormalParameter parameter = parseNormalFormalParameter();
5910 if (_matches(TokenType.EQ)) { 5991 TokenType type = _currentToken.type;
5911 Token seperator = getAndAdvance(); 5992 if (type == TokenType.EQ) {
5993 Token separator = getAndAdvance();
5912 Expression defaultValue = parseExpression2(); 5994 Expression defaultValue = parseExpression2();
5913 if (kind == ParameterKind.NAMED) { 5995 if (kind == ParameterKind.NAMED) {
5914 _reportErrorForToken( 5996 _reportErrorForToken(
5915 ParserErrorCode.WRONG_SEPARATOR_FOR_NAMED_PARAMETER, seperator); 5997 ParserErrorCode.WRONG_SEPARATOR_FOR_NAMED_PARAMETER, separator);
5916 } else if (kind == ParameterKind.REQUIRED) { 5998 } else if (kind == ParameterKind.REQUIRED) {
5917 _reportErrorForNode( 5999 _reportErrorForNode(
5918 ParserErrorCode.POSITIONAL_PARAMETER_OUTSIDE_GROUP, parameter); 6000 ParserErrorCode.POSITIONAL_PARAMETER_OUTSIDE_GROUP, parameter);
5919 } 6001 }
5920 return new DefaultFormalParameter( 6002 return new DefaultFormalParameter(
5921 parameter, kind, seperator, defaultValue); 6003 parameter, kind, separator, defaultValue);
5922 } else if (_matches(TokenType.COLON)) { 6004 } else if (type == TokenType.COLON) {
5923 Token seperator = getAndAdvance(); 6005 Token separator = getAndAdvance();
5924 Expression defaultValue = parseExpression2(); 6006 Expression defaultValue = parseExpression2();
5925 if (kind == ParameterKind.POSITIONAL) { 6007 if (kind == ParameterKind.POSITIONAL) {
5926 _reportErrorForToken( 6008 _reportErrorForToken(
5927 ParserErrorCode.WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER, 6009 ParserErrorCode.WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER,
5928 seperator); 6010 separator);
5929 } else if (kind == ParameterKind.REQUIRED) { 6011 } else if (kind == ParameterKind.REQUIRED) {
5930 _reportErrorForNode( 6012 _reportErrorForNode(
5931 ParserErrorCode.NAMED_PARAMETER_OUTSIDE_GROUP, parameter); 6013 ParserErrorCode.NAMED_PARAMETER_OUTSIDE_GROUP, parameter);
5932 } 6014 }
5933 return new DefaultFormalParameter( 6015 return new DefaultFormalParameter(
5934 parameter, kind, seperator, defaultValue); 6016 parameter, kind, separator, defaultValue);
5935 } else if (kind != ParameterKind.REQUIRED) { 6017 } else if (kind != ParameterKind.REQUIRED) {
5936 return new DefaultFormalParameter(parameter, kind, null, null); 6018 return new DefaultFormalParameter(parameter, kind, null, null);
5937 } 6019 }
5938 return parameter; 6020 return parameter;
5939 } 6021 }
5940 6022
5941 /** 6023 /**
6024 * Parse a list of formal parameters given that the list starts with the given
6025 * [leftParenthesis]. Return the formal parameters that were parsed.
6026 */
6027 FormalParameterList _parseFormalParameterListAfterParen(
6028 Token leftParenthesis) {
6029 if (_matches(TokenType.CLOSE_PAREN)) {
6030 return new FormalParameterList(
6031 leftParenthesis, null, null, null, getAndAdvance());
6032 }
6033 //
6034 // Even though it is invalid to have default parameters outside of brackets,
6035 // required parameters inside of brackets, or multiple groups of default and
6036 // named parameters, we allow all of these cases so that we can recover
6037 // better.
6038 //
6039 List<FormalParameter> parameters = <FormalParameter>[];
6040 Token leftSquareBracket = null;
6041 Token rightSquareBracket = null;
6042 Token leftCurlyBracket = null;
6043 Token rightCurlyBracket = null;
6044 ParameterKind kind = ParameterKind.REQUIRED;
6045 bool firstParameter = true;
6046 bool reportedMultiplePositionalGroups = false;
6047 bool reportedMultipleNamedGroups = false;
6048 bool reportedMixedGroups = false;
6049 bool wasOptionalParameter = false;
6050 Token initialToken = null;
6051 do {
6052 if (firstParameter) {
6053 firstParameter = false;
6054 } else if (!_optional(TokenType.COMMA)) {
6055 // TODO(brianwilkerson) The token is wrong, we need to recover from this
6056 // case.
6057 if (_getEndToken(leftParenthesis) != null) {
6058 _reportErrorForCurrentToken(
6059 ParserErrorCode.EXPECTED_TOKEN, [TokenType.COMMA.lexeme]);
6060 } else {
6061 _reportErrorForToken(ParserErrorCode.MISSING_CLOSING_PARENTHESIS,
6062 _currentToken.previous);
6063 break;
6064 }
6065 }
6066 initialToken = _currentToken;
6067 //
6068 // Handle the beginning of parameter groups.
6069 //
6070 TokenType type = _currentToken.type;
6071 if (type == TokenType.OPEN_SQUARE_BRACKET) {
6072 wasOptionalParameter = true;
6073 if (leftSquareBracket != null && !reportedMultiplePositionalGroups) {
6074 _reportErrorForCurrentToken(
6075 ParserErrorCode.MULTIPLE_POSITIONAL_PARAMETER_GROUPS);
6076 reportedMultiplePositionalGroups = true;
6077 }
6078 if (leftCurlyBracket != null && !reportedMixedGroups) {
6079 _reportErrorForCurrentToken(ParserErrorCode.MIXED_PARAMETER_GROUPS);
6080 reportedMixedGroups = true;
6081 }
6082 leftSquareBracket = getAndAdvance();
6083 kind = ParameterKind.POSITIONAL;
6084 } else if (type == TokenType.OPEN_CURLY_BRACKET) {
6085 wasOptionalParameter = true;
6086 if (leftCurlyBracket != null && !reportedMultipleNamedGroups) {
6087 _reportErrorForCurrentToken(
6088 ParserErrorCode.MULTIPLE_NAMED_PARAMETER_GROUPS);
6089 reportedMultipleNamedGroups = true;
6090 }
6091 if (leftSquareBracket != null && !reportedMixedGroups) {
6092 _reportErrorForCurrentToken(ParserErrorCode.MIXED_PARAMETER_GROUPS);
6093 reportedMixedGroups = true;
6094 }
6095 leftCurlyBracket = getAndAdvance();
6096 kind = ParameterKind.NAMED;
6097 }
6098 //
6099 // Parse and record the parameter.
6100 //
6101 FormalParameter parameter = _parseFormalParameter(kind);
6102 parameters.add(parameter);
6103 if (kind == ParameterKind.REQUIRED && wasOptionalParameter) {
6104 _reportErrorForNode(
6105 ParserErrorCode.NORMAL_BEFORE_OPTIONAL_PARAMETERS, parameter);
6106 }
6107 //
6108 // Handle the end of parameter groups.
6109 //
6110 // TODO(brianwilkerson) Improve the detection and reporting of missing and
6111 // mismatched delimiters.
6112 type = _currentToken.type;
6113 if (type == TokenType.CLOSE_SQUARE_BRACKET) {
6114 rightSquareBracket = getAndAdvance();
6115 if (leftSquareBracket == null) {
6116 if (leftCurlyBracket != null) {
6117 _reportErrorForCurrentToken(
6118 ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]);
6119 rightCurlyBracket = rightSquareBracket;
6120 rightSquareBracket = null;
6121 } else {
6122 _reportErrorForCurrentToken(
6123 ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP,
6124 ["["]);
6125 }
6126 }
6127 kind = ParameterKind.REQUIRED;
6128 } else if (type == TokenType.CLOSE_CURLY_BRACKET) {
6129 rightCurlyBracket = getAndAdvance();
6130 if (leftCurlyBracket == null) {
6131 if (leftSquareBracket != null) {
6132 _reportErrorForCurrentToken(
6133 ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]);
6134 rightSquareBracket = rightCurlyBracket;
6135 rightCurlyBracket = null;
6136 } else {
6137 _reportErrorForCurrentToken(
6138 ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP,
6139 ["{"]);
6140 }
6141 }
6142 kind = ParameterKind.REQUIRED;
6143 }
6144 } while (!_matches(TokenType.CLOSE_PAREN) &&
6145 !identical(initialToken, _currentToken));
6146 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
6147 //
6148 // Check that the groups were closed correctly.
6149 //
6150 if (leftSquareBracket != null && rightSquareBracket == null) {
6151 _reportErrorForCurrentToken(
6152 ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]);
6153 }
6154 if (leftCurlyBracket != null && rightCurlyBracket == null) {
6155 _reportErrorForCurrentToken(
6156 ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]);
6157 }
6158 //
6159 // Build the parameter list.
6160 //
6161 leftSquareBracket ??= leftCurlyBracket;
6162 rightSquareBracket ??= rightCurlyBracket;
6163 return new FormalParameterList(leftParenthesis, parameters,
6164 leftSquareBracket, rightSquareBracket, rightParenthesis);
6165 }
6166
6167 /**
6168 * Parse a list of formal parameters. Return the formal parameters that were
6169 * parsed.
6170 *
6171 * This method assumes that the current token matches `TokenType.OPEN_PAREN`.
6172 */
6173 FormalParameterList _parseFormalParameterListUnchecked() {
6174 return _parseFormalParameterListAfterParen(getAndAdvance());
6175 }
6176
6177 /**
5942 * Parse a for statement. Return the for statement that was parsed. 6178 * Parse a for statement. Return the for statement that was parsed.
5943 * 6179 *
5944 * forStatement ::= 6180 * forStatement ::=
5945 * 'for' '(' forLoopParts ')' statement 6181 * 'for' '(' forLoopParts ')' statement
5946 * 6182 *
5947 * forLoopParts ::= 6183 * forLoopParts ::=
5948 * forInitializerStatement expression? ';' expressionList? 6184 * forInitializerStatement expression? ';' expressionList?
5949 * | declaredIdentifier 'in' expression 6185 * | declaredIdentifier 'in' expression
5950 * | identifier 'in' expression 6186 * | identifier 'in' expression
5951 * 6187 *
(...skipping 11 matching lines...) Expand all
5963 } 6199 }
5964 Token forKeyword = _expectKeyword(Keyword.FOR); 6200 Token forKeyword = _expectKeyword(Keyword.FOR);
5965 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); 6201 Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
5966 VariableDeclarationList variableList = null; 6202 VariableDeclarationList variableList = null;
5967 Expression initialization = null; 6203 Expression initialization = null;
5968 if (!_matches(TokenType.SEMICOLON)) { 6204 if (!_matches(TokenType.SEMICOLON)) {
5969 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); 6205 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata();
5970 if (_matchesIdentifier() && 6206 if (_matchesIdentifier() &&
5971 (_tokenMatchesKeyword(_peek(), Keyword.IN) || 6207 (_tokenMatchesKeyword(_peek(), Keyword.IN) ||
5972 _tokenMatches(_peek(), TokenType.COLON))) { 6208 _tokenMatches(_peek(), TokenType.COLON))) {
5973 List<VariableDeclaration> variables = new List<VariableDeclaration>(); 6209 SimpleIdentifier variableName = _parseSimpleIdentifierUnchecked();
5974 SimpleIdentifier variableName = parseSimpleIdentifier();
5975 variables.add(new VariableDeclaration(variableName, null, null));
5976 variableList = new VariableDeclarationList(commentAndMetadata.comment, 6210 variableList = new VariableDeclarationList(commentAndMetadata.comment,
5977 commentAndMetadata.metadata, null, null, variables); 6211 commentAndMetadata.metadata, null, null, <VariableDeclaration>[
6212 new VariableDeclaration(variableName, null, null)
6213 ]);
5978 } else if (_isInitializedVariableDeclaration()) { 6214 } else if (_isInitializedVariableDeclaration()) {
5979 variableList = 6215 variableList =
5980 _parseVariableDeclarationListAfterMetadata(commentAndMetadata); 6216 _parseVariableDeclarationListAfterMetadata(commentAndMetadata);
5981 } else { 6217 } else {
5982 initialization = parseExpression2(); 6218 initialization = parseExpression2();
5983 } 6219 }
5984 if (_matchesKeyword(Keyword.IN) || _matches(TokenType.COLON)) { 6220 TokenType type = _currentToken.type;
5985 if (_matches(TokenType.COLON)) { 6221 if (_matchesKeyword(Keyword.IN) || type == TokenType.COLON) {
6222 if (type == TokenType.COLON) {
5986 _reportErrorForCurrentToken(ParserErrorCode.COLON_IN_PLACE_OF_IN); 6223 _reportErrorForCurrentToken(ParserErrorCode.COLON_IN_PLACE_OF_IN);
5987 } 6224 }
5988 DeclaredIdentifier loopVariable = null; 6225 DeclaredIdentifier loopVariable = null;
5989 SimpleIdentifier identifier = null; 6226 SimpleIdentifier identifier = null;
5990 if (variableList == null) { 6227 if (variableList == null) {
5991 // We found: <expression> 'in' 6228 // We found: <expression> 'in'
5992 _reportErrorForCurrentToken( 6229 _reportErrorForCurrentToken(
5993 ParserErrorCode.MISSING_VARIABLE_IN_FOR_EACH); 6230 ParserErrorCode.MISSING_VARIABLE_IN_FOR_EACH);
5994 } else { 6231 } else {
5995 NodeList<VariableDeclaration> variables = variableList.variables; 6232 NodeList<VariableDeclaration> variables = variableList.variables;
(...skipping 11 matching lines...) Expand all
6007 TypeName type = variableList.type; 6244 TypeName type = variableList.type;
6008 if (keyword != null || type != null) { 6245 if (keyword != null || type != null) {
6009 loopVariable = new DeclaredIdentifier( 6246 loopVariable = new DeclaredIdentifier(
6010 commentAndMetadata.comment, 6247 commentAndMetadata.comment,
6011 commentAndMetadata.metadata, 6248 commentAndMetadata.metadata,
6012 keyword, 6249 keyword,
6013 type, 6250 type,
6014 new SimpleIdentifier(variable.name.token, 6251 new SimpleIdentifier(variable.name.token,
6015 isDeclaration: true)); 6252 isDeclaration: true));
6016 } else { 6253 } else {
6017 if (!commentAndMetadata.metadata.isEmpty) { 6254 if (commentAndMetadata.hasMetadata) {
6018 // TODO(jwren) metadata isn't allowed before the identifier in 6255 // TODO(jwren) metadata isn't allowed before the identifier in
6019 // "identifier in expression", add warning if commentAndMetadata 6256 // "identifier in expression", add warning if commentAndMetadata
6020 // has content 6257 // has content
6021 } 6258 }
6022 identifier = variable.name; 6259 identifier = variable.name;
6023 } 6260 }
6024 } 6261 }
6025 Token inKeyword = getAndAdvance(); 6262 Token inKeyword = getAndAdvance();
6026 Expression iterator = parseExpression2(); 6263 Expression iterator = parseExpression2();
6027 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); 6264 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
6099 bool mayBeEmpty, ParserErrorCode emptyErrorCode, bool inExpression) { 6336 bool mayBeEmpty, ParserErrorCode emptyErrorCode, bool inExpression) {
6100 bool wasInAsync = _inAsync; 6337 bool wasInAsync = _inAsync;
6101 bool wasInGenerator = _inGenerator; 6338 bool wasInGenerator = _inGenerator;
6102 bool wasInLoop = _inLoop; 6339 bool wasInLoop = _inLoop;
6103 bool wasInSwitch = _inSwitch; 6340 bool wasInSwitch = _inSwitch;
6104 _inAsync = false; 6341 _inAsync = false;
6105 _inGenerator = false; 6342 _inGenerator = false;
6106 _inLoop = false; 6343 _inLoop = false;
6107 _inSwitch = false; 6344 _inSwitch = false;
6108 try { 6345 try {
6109 if (_matches(TokenType.SEMICOLON)) { 6346 TokenType type = _currentToken.type;
6347 if (type == TokenType.SEMICOLON) {
6110 if (!mayBeEmpty) { 6348 if (!mayBeEmpty) {
6111 _reportErrorForCurrentToken(emptyErrorCode); 6349 _reportErrorForCurrentToken(emptyErrorCode);
6112 } 6350 }
6113 return new EmptyFunctionBody(getAndAdvance()); 6351 return new EmptyFunctionBody(getAndAdvance());
6114 } else if (_matchesString(_NATIVE)) {
6115 Token nativeToken = getAndAdvance();
6116 StringLiteral stringLiteral = null;
6117 if (_matches(TokenType.STRING)) {
6118 stringLiteral = parseStringLiteral();
6119 }
6120 return new NativeFunctionBody(
6121 nativeToken, stringLiteral, _expect(TokenType.SEMICOLON));
6122 } 6352 }
6123 Token keyword = null; 6353 Token keyword = null;
6124 Token star = null; 6354 Token star = null;
6125 if (_matchesString(ASYNC)) { 6355 bool foundAsync = false;
6126 keyword = getAndAdvance(); 6356 bool foundSync = false;
6127 if (!_parseAsync) { 6357 if (type == TokenType.IDENTIFIER) {
6128 _reportErrorForToken(ParserErrorCode.ASYNC_NOT_SUPPORTED, keyword); 6358 String lexeme = _currentToken.lexeme;
6129 } 6359 if (lexeme == ASYNC) {
6130 if (_matches(TokenType.STAR)) { 6360 foundAsync = true;
6131 star = getAndAdvance(); 6361 keyword = getAndAdvance();
6132 _inGenerator = true; 6362 if (!_parseAsync) {
6133 } 6363 _reportErrorForToken(ParserErrorCode.ASYNC_NOT_SUPPORTED, keyword);
6134 _inAsync = true; 6364 }
6135 } else if (_matchesString(SYNC)) { 6365 if (_matches(TokenType.STAR)) {
6136 keyword = getAndAdvance(); 6366 star = getAndAdvance();
6137 if (!_parseAsync) { 6367 _inGenerator = true;
6138 _reportErrorForToken(ParserErrorCode.ASYNC_NOT_SUPPORTED, keyword); 6368 }
6139 } 6369 type = _currentToken.type;
6140 if (_matches(TokenType.STAR)) { 6370 _inAsync = true;
6141 star = getAndAdvance(); 6371 } else if (lexeme == SYNC) {
6142 _inGenerator = true; 6372 foundSync = true;
6373 keyword = getAndAdvance();
6374 if (!_parseAsync) {
6375 _reportErrorForToken(ParserErrorCode.ASYNC_NOT_SUPPORTED, keyword);
6376 }
6377 if (_matches(TokenType.STAR)) {
6378 star = getAndAdvance();
6379 _inGenerator = true;
6380 }
6381 type = _currentToken.type;
6143 } 6382 }
6144 } 6383 }
6145 if (_matches(TokenType.FUNCTION)) { 6384 if (type == TokenType.FUNCTION) {
6146 if (keyword != null) { 6385 if (keyword != null) {
6147 if (!_tokenMatchesString(keyword, ASYNC)) { 6386 if (!foundAsync) {
6148 _reportErrorForToken(ParserErrorCode.INVALID_SYNC, keyword); 6387 _reportErrorForToken(ParserErrorCode.INVALID_SYNC, keyword);
6149 keyword = null; 6388 keyword = null;
6150 } else if (star != null) { 6389 } else if (star != null) {
6151 _reportErrorForToken( 6390 _reportErrorForToken(
6152 ParserErrorCode.INVALID_STAR_AFTER_ASYNC, star); 6391 ParserErrorCode.INVALID_STAR_AFTER_ASYNC, star);
6153 } 6392 }
6154 } 6393 }
6155 Token functionDefinition = getAndAdvance(); 6394 Token functionDefinition = getAndAdvance();
6156 if (_matchesKeyword(Keyword.RETURN)) { 6395 if (_matchesKeyword(Keyword.RETURN)) {
6157 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, 6396 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
6158 [_currentToken.lexeme]); 6397 [_currentToken.lexeme]);
6159 _advance(); 6398 _advance();
6160 } 6399 }
6161 Expression expression = parseExpression2(); 6400 Expression expression = parseExpression2();
6162 Token semicolon = null; 6401 Token semicolon = null;
6163 if (!inExpression) { 6402 if (!inExpression) {
6164 semicolon = _expect(TokenType.SEMICOLON); 6403 semicolon = _expect(TokenType.SEMICOLON);
6165 } 6404 }
6166 if (!_parseFunctionBodies) { 6405 if (!_parseFunctionBodies) {
6167 return new EmptyFunctionBody( 6406 return new EmptyFunctionBody(
6168 _createSyntheticToken(TokenType.SEMICOLON)); 6407 _createSyntheticToken(TokenType.SEMICOLON));
6169 } 6408 }
6170 return new ExpressionFunctionBody( 6409 return new ExpressionFunctionBody(
6171 keyword, functionDefinition, expression, semicolon); 6410 keyword, functionDefinition, expression, semicolon);
6172 } else if (_matches(TokenType.OPEN_CURLY_BRACKET)) { 6411 } else if (type == TokenType.OPEN_CURLY_BRACKET) {
6173 if (keyword != null) { 6412 if (keyword != null) {
6174 if (_tokenMatchesString(keyword, SYNC) && star == null) { 6413 if (foundSync && star == null) {
6175 _reportErrorForToken( 6414 _reportErrorForToken(
6176 ParserErrorCode.MISSING_STAR_AFTER_SYNC, keyword); 6415 ParserErrorCode.MISSING_STAR_AFTER_SYNC, keyword);
6177 } 6416 }
6178 } 6417 }
6179 if (!_parseFunctionBodies) { 6418 if (!_parseFunctionBodies) {
6180 _skipBlock(); 6419 _skipBlock();
6181 return new EmptyFunctionBody( 6420 return new EmptyFunctionBody(
6182 _createSyntheticToken(TokenType.SEMICOLON)); 6421 _createSyntheticToken(TokenType.SEMICOLON));
6183 } 6422 }
6184 return new BlockFunctionBody(keyword, star, parseBlock()); 6423 return new BlockFunctionBody(keyword, star, parseBlock());
6424 } else if (_matchesString(_NATIVE)) {
6425 Token nativeToken = getAndAdvance();
6426 StringLiteral stringLiteral = null;
6427 if (_matches(TokenType.STRING)) {
6428 stringLiteral = _parseStringLiteralUnchecked();
6429 }
6430 return new NativeFunctionBody(
6431 nativeToken, stringLiteral, _expect(TokenType.SEMICOLON));
6185 } else { 6432 } else {
6186 // Invalid function body 6433 // Invalid function body
6187 _reportErrorForCurrentToken(emptyErrorCode); 6434 _reportErrorForCurrentToken(emptyErrorCode);
6188 return new EmptyFunctionBody( 6435 return new EmptyFunctionBody(
6189 _createSyntheticToken(TokenType.SEMICOLON)); 6436 _createSyntheticToken(TokenType.SEMICOLON));
6190 } 6437 }
6191 } finally { 6438 } finally {
6192 _inAsync = wasInAsync; 6439 _inAsync = wasInAsync;
6193 _inGenerator = wasInGenerator; 6440 _inGenerator = wasInGenerator;
6194 _inLoop = wasInLoop; 6441 _inLoop = wasInLoop;
(...skipping 11 matching lines...) Expand all
6206 * parsed. 6453 * parsed.
6207 * 6454 *
6208 * functionDeclaration ::= 6455 * functionDeclaration ::=
6209 * functionSignature functionBody 6456 * functionSignature functionBody
6210 * | returnType? getOrSet identifier formalParameterList functionBody 6457 * | returnType? getOrSet identifier formalParameterList functionBody
6211 */ 6458 */
6212 FunctionDeclaration _parseFunctionDeclaration( 6459 FunctionDeclaration _parseFunctionDeclaration(
6213 CommentAndMetadata commentAndMetadata, 6460 CommentAndMetadata commentAndMetadata,
6214 Token externalKeyword, 6461 Token externalKeyword,
6215 TypeName returnType) { 6462 TypeName returnType) {
6216 Token keyword = null; 6463 Token keywordToken = null;
6217 bool isGetter = false; 6464 bool isGetter = false;
6218 if (_matchesKeyword(Keyword.GET) && 6465 Keyword keyword = _currentToken.keyword;
6219 !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { 6466 SimpleIdentifier name = null;
6220 keyword = getAndAdvance(); 6467 if (keyword == Keyword.GET) {
6468 keywordToken = getAndAdvance();
6221 isGetter = true; 6469 isGetter = true;
6222 } else if (_matchesKeyword(Keyword.SET) && 6470 } else if (keyword == Keyword.SET) {
6223 !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { 6471 keywordToken = getAndAdvance();
6224 keyword = getAndAdvance();
6225 } 6472 }
6226 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true); 6473 if (keywordToken != null && _matches(TokenType.OPEN_PAREN)) {
6474 name = new SimpleIdentifier(keywordToken, isDeclaration: true);
6475 keywordToken = null;
6476 isGetter = false;
6477 } else {
6478 name = parseSimpleIdentifier(isDeclaration: true);
6479 }
6227 TypeParameterList typeParameters = _parseGenericMethodTypeParameters(); 6480 TypeParameterList typeParameters = _parseGenericMethodTypeParameters();
6228 FormalParameterList parameters = null; 6481 FormalParameterList parameters = null;
6229 if (!isGetter) { 6482 if (!isGetter) {
6230 if (_matches(TokenType.OPEN_PAREN)) { 6483 if (_matches(TokenType.OPEN_PAREN)) {
6231 parameters = parseFormalParameterList(); 6484 parameters = _parseFormalParameterListUnchecked();
6232 _validateFormalParameterList(parameters); 6485 _validateFormalParameterList(parameters);
6233 } else { 6486 } else {
6234 _reportErrorForCurrentToken( 6487 _reportErrorForCurrentToken(
6235 ParserErrorCode.MISSING_FUNCTION_PARAMETERS); 6488 ParserErrorCode.MISSING_FUNCTION_PARAMETERS);
6236 parameters = new FormalParameterList( 6489 parameters = new FormalParameterList(
6237 _createSyntheticToken(TokenType.OPEN_PAREN), 6490 _createSyntheticToken(TokenType.OPEN_PAREN),
6238 null, 6491 null,
6239 null, 6492 null,
6240 null, 6493 null,
6241 _createSyntheticToken(TokenType.CLOSE_PAREN)); 6494 _createSyntheticToken(TokenType.CLOSE_PAREN));
6242 } 6495 }
6243 } else if (_matches(TokenType.OPEN_PAREN)) { 6496 } else if (_matches(TokenType.OPEN_PAREN)) {
6244 _reportErrorForCurrentToken(ParserErrorCode.GETTER_WITH_PARAMETERS); 6497 _reportErrorForCurrentToken(ParserErrorCode.GETTER_WITH_PARAMETERS);
6245 parseFormalParameterList(); 6498 _parseFormalParameterListUnchecked();
6246 } 6499 }
6247 FunctionBody body; 6500 FunctionBody body;
6248 if (externalKeyword == null) { 6501 if (externalKeyword == null) {
6249 body = _parseFunctionBody( 6502 body = _parseFunctionBody(
6250 false, ParserErrorCode.MISSING_FUNCTION_BODY, false); 6503 false, ParserErrorCode.MISSING_FUNCTION_BODY, false);
6251 } else { 6504 } else {
6252 body = new EmptyFunctionBody(_expect(TokenType.SEMICOLON)); 6505 body = new EmptyFunctionBody(_expect(TokenType.SEMICOLON));
6253 } 6506 }
6254 // if (!isStatement && matches(TokenType.SEMICOLON)) { 6507 // if (!isStatement && matches(TokenType.SEMICOLON)) {
6255 // // TODO(brianwilkerson) Improve this error message. 6508 // // TODO(brianwilkerson) Improve this error message.
6256 // reportError(ParserErrorCode.UNEXPECTED_TOKEN, currentToken.getLexeme ()); 6509 // reportError(ParserErrorCode.UNEXPECTED_TOKEN, currentToken.getLexeme ());
6257 // advance(); 6510 // advance();
6258 // } 6511 // }
6259 return new FunctionDeclaration( 6512 return new FunctionDeclaration(
6260 commentAndMetadata.comment, 6513 commentAndMetadata.comment,
6261 commentAndMetadata.metadata, 6514 commentAndMetadata.metadata,
6262 externalKeyword, 6515 externalKeyword,
6263 returnType, 6516 returnType,
6264 keyword, 6517 keywordToken,
6265 name, 6518 name,
6266 new FunctionExpression(typeParameters, parameters, body)); 6519 new FunctionExpression(typeParameters, parameters, body));
6267 } 6520 }
6268 6521
6269 /** 6522 /**
6270 * Parse a function declaration statement. Return the function declaration 6523 * Parse a function declaration statement. Return the function declaration
6271 * statement that was parsed. 6524 * statement that was parsed.
6272 * 6525 *
6273 * functionDeclarationStatement ::= 6526 * functionDeclarationStatement ::=
6274 * functionSignature functionBody 6527 * functionSignature functionBody
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
6321 CommentAndMetadata commentAndMetadata, Token keyword) { 6574 CommentAndMetadata commentAndMetadata, Token keyword) {
6322 TypeName returnType = null; 6575 TypeName returnType = null;
6323 if (hasReturnTypeInTypeAlias) { 6576 if (hasReturnTypeInTypeAlias) {
6324 returnType = parseReturnType(); 6577 returnType = parseReturnType();
6325 } 6578 }
6326 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true); 6579 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
6327 TypeParameterList typeParameters = null; 6580 TypeParameterList typeParameters = null;
6328 if (_matches(TokenType.LT)) { 6581 if (_matches(TokenType.LT)) {
6329 typeParameters = parseTypeParameterList(); 6582 typeParameters = parseTypeParameterList();
6330 } 6583 }
6331 if (_matches(TokenType.SEMICOLON) || _matches(TokenType.EOF)) { 6584 TokenType type = _currentToken.type;
6585 if (type == TokenType.SEMICOLON || type == TokenType.EOF) {
6332 _reportErrorForCurrentToken(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS); 6586 _reportErrorForCurrentToken(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS);
6333 FormalParameterList parameters = new FormalParameterList( 6587 FormalParameterList parameters = new FormalParameterList(
6334 _createSyntheticToken(TokenType.OPEN_PAREN), 6588 _createSyntheticToken(TokenType.OPEN_PAREN),
6335 null, 6589 null,
6336 null, 6590 null,
6337 null, 6591 null,
6338 _createSyntheticToken(TokenType.CLOSE_PAREN)); 6592 _createSyntheticToken(TokenType.CLOSE_PAREN));
6339 Token semicolon = _expect(TokenType.SEMICOLON); 6593 Token semicolon = _expect(TokenType.SEMICOLON);
6340 return new FunctionTypeAlias( 6594 return new FunctionTypeAlias(
6341 commentAndMetadata.comment, 6595 commentAndMetadata.comment,
6342 commentAndMetadata.metadata, 6596 commentAndMetadata.metadata,
6343 keyword, 6597 keyword,
6344 returnType, 6598 returnType,
6345 name, 6599 name,
6346 typeParameters, 6600 typeParameters,
6347 parameters, 6601 parameters,
6348 semicolon); 6602 semicolon);
6349 } else if (!_matches(TokenType.OPEN_PAREN)) { 6603 } else if (type == TokenType.OPEN_PAREN) {
6350 _reportErrorForCurrentToken(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS); 6604 FormalParameterList parameters = _parseFormalParameterListUnchecked();
6351 // TODO(brianwilkerson) Recover from this error. At the very least we 6605 _validateFormalParameterList(parameters);
6352 // should skip to the start of the next valid compilation unit member, 6606 Token semicolon = _expect(TokenType.SEMICOLON);
6353 // allowing for the possibility of finding the typedef parameters before
6354 // that point.
6355 return new FunctionTypeAlias( 6607 return new FunctionTypeAlias(
6356 commentAndMetadata.comment, 6608 commentAndMetadata.comment,
6357 commentAndMetadata.metadata, 6609 commentAndMetadata.metadata,
6610 keyword,
6611 returnType,
6612 name,
6613 typeParameters,
6614 parameters,
6615 semicolon);
6616 } else {
6617 _reportErrorForCurrentToken(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS);
6618 // Recovery: At the very least we should skip to the start of the next
6619 // valid compilation unit member, allowing for the possibility of finding
6620 // the typedef parameters before that point.
6621 return new FunctionTypeAlias(
6622 commentAndMetadata.comment,
6623 commentAndMetadata.metadata,
6358 keyword, 6624 keyword,
6359 returnType, 6625 returnType,
6360 name, 6626 name,
6361 typeParameters, 6627 typeParameters,
6362 new FormalParameterList(_createSyntheticToken(TokenType.OPEN_PAREN), 6628 new FormalParameterList(_createSyntheticToken(TokenType.OPEN_PAREN),
6363 null, null, null, _createSyntheticToken(TokenType.CLOSE_PAREN)), 6629 null, null, null, _createSyntheticToken(TokenType.CLOSE_PAREN)),
6364 _createSyntheticToken(TokenType.SEMICOLON)); 6630 _createSyntheticToken(TokenType.SEMICOLON));
6365 } 6631 }
6366 FormalParameterList parameters = parseFormalParameterList();
6367 _validateFormalParameterList(parameters);
6368 Token semicolon = _expect(TokenType.SEMICOLON);
6369 return new FunctionTypeAlias(
6370 commentAndMetadata.comment,
6371 commentAndMetadata.metadata,
6372 keyword,
6373 returnType,
6374 name,
6375 typeParameters,
6376 parameters,
6377 semicolon);
6378 } 6632 }
6379 6633
6380 /** 6634 /**
6381 * Parses generic type parameters from a comment. 6635 * Parses generic type parameters from a comment.
6382 * 6636 *
6383 * Normally this is handled by [_parseGenericMethodTypeParameters], but if the 6637 * Normally this is handled by [_parseGenericMethodTypeParameters], but if the
6384 * code already handles the normal generic type parameters, the comment 6638 * code already handles the normal generic type parameters, the comment
6385 * matcher can be called directly. For example, we may have already tried 6639 * matcher can be called directly. For example, we may have already tried
6386 * matching `<` (less than sign) in a method declaration, and be currently 6640 * matching `<` (less than sign) in a method declaration, and be currently
6387 * on the `(` (open paren) because we didn't find it. In that case, this 6641 * on the `(` (open paren) because we didn't find it. In that case, this
(...skipping 21 matching lines...) Expand all
6409 } 6663 }
6410 6664
6411 /** 6665 /**
6412 * Parse a getter. The [commentAndMetadata] is the documentation comment and 6666 * Parse a getter. The [commentAndMetadata] is the documentation comment and
6413 * metadata to be associated with the declaration. The externalKeyword] is the 6667 * metadata to be associated with the declaration. The externalKeyword] is the
6414 * 'external' token. The staticKeyword] is the static keyword, or `null` if 6668 * 'external' token. The staticKeyword] is the static keyword, or `null` if
6415 * the getter is not static. The [returnType] the return type that has already 6669 * the getter is not static. The [returnType] the return type that has already
6416 * been parsed, or `null` if there was no return type. Return the getter that 6670 * been parsed, or `null` if there was no return type. Return the getter that
6417 * was parsed. 6671 * was parsed.
6418 * 6672 *
6673 * This method assumes that the current token matches `Keyword.GET`.
6674 *
6419 * getter ::= 6675 * getter ::=
6420 * getterSignature functionBody? 6676 * getterSignature functionBody?
6421 * 6677 *
6422 * getterSignature ::= 6678 * getterSignature ::=
6423 * 'external'? 'static'? returnType? 'get' identifier 6679 * 'external'? 'static'? returnType? 'get' identifier
6424 */ 6680 */
6425 MethodDeclaration _parseGetter(CommentAndMetadata commentAndMetadata, 6681 MethodDeclaration _parseGetter(CommentAndMetadata commentAndMetadata,
6426 Token externalKeyword, Token staticKeyword, TypeName returnType) { 6682 Token externalKeyword, Token staticKeyword, TypeName returnType) {
6427 Token propertyKeyword = _expectKeyword(Keyword.GET); 6683 Token propertyKeyword = getAndAdvance();
6428 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true); 6684 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
6429 if (_matches(TokenType.OPEN_PAREN) && 6685 if (_matches(TokenType.OPEN_PAREN) &&
6430 _tokenMatches(_peek(), TokenType.CLOSE_PAREN)) { 6686 _tokenMatches(_peek(), TokenType.CLOSE_PAREN)) {
6431 _reportErrorForCurrentToken(ParserErrorCode.GETTER_WITH_PARAMETERS); 6687 _reportErrorForCurrentToken(ParserErrorCode.GETTER_WITH_PARAMETERS);
6432 _advance(); 6688 _advance();
6433 _advance(); 6689 _advance();
6434 } 6690 }
6435 FunctionBody body = _parseFunctionBody( 6691 FunctionBody body = _parseFunctionBody(
6436 externalKeyword != null || staticKeyword == null, 6692 externalKeyword != null || staticKeyword == null,
6437 ParserErrorCode.STATIC_GETTER_WITHOUT_BODY, 6693 ParserErrorCode.STATIC_GETTER_WITHOUT_BODY,
(...skipping 16 matching lines...) Expand all
6454 } 6710 }
6455 6711
6456 /** 6712 /**
6457 * Parse a list of identifiers. Return the list of identifiers that were 6713 * Parse a list of identifiers. Return the list of identifiers that were
6458 * parsed. 6714 * parsed.
6459 * 6715 *
6460 * identifierList ::= 6716 * identifierList ::=
6461 * identifier (',' identifier)* 6717 * identifier (',' identifier)*
6462 */ 6718 */
6463 List<SimpleIdentifier> _parseIdentifierList() { 6719 List<SimpleIdentifier> _parseIdentifierList() {
6464 List<SimpleIdentifier> identifiers = new List<SimpleIdentifier>(); 6720 List<SimpleIdentifier> identifiers = <SimpleIdentifier>[
6465 identifiers.add(parseSimpleIdentifier()); 6721 parseSimpleIdentifier()
6466 while (_matches(TokenType.COMMA)) { 6722 ];
6467 _advance(); 6723 while (_optional(TokenType.COMMA)) {
6468 identifiers.add(parseSimpleIdentifier()); 6724 identifiers.add(parseSimpleIdentifier());
6469 } 6725 }
6470 return identifiers; 6726 return identifiers;
6471 } 6727 }
6472 6728
6473 /** 6729 /**
6474 * Parse an if statement. Return the if statement that was parsed. 6730 * Parse an if statement. Return the if statement that was parsed.
6475 * 6731 *
6732 * This method assumes that the current token matches `Keyword.IF`.
6733 *
6476 * ifStatement ::= 6734 * ifStatement ::=
6477 * 'if' '(' expression ')' statement ('else' statement)? 6735 * 'if' '(' expression ')' statement ('else' statement)?
6478 */ 6736 */
6479 Statement _parseIfStatement() { 6737 Statement _parseIfStatement() {
6480 Token ifKeyword = _expectKeyword(Keyword.IF); 6738 Token ifKeyword = getAndAdvance();
6481 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); 6739 Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
6482 Expression condition = parseExpression2(); 6740 Expression condition = parseExpression2();
6483 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); 6741 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
6484 Statement thenStatement = parseStatement2(); 6742 Statement thenStatement = parseStatement2();
6485 Token elseKeyword = null; 6743 Token elseKeyword = null;
6486 Statement elseStatement = null; 6744 Statement elseStatement = null;
6487 if (_matchesKeyword(Keyword.ELSE)) { 6745 if (_matchesKeyword(Keyword.ELSE)) {
6488 elseKeyword = getAndAdvance(); 6746 elseKeyword = getAndAdvance();
6489 elseStatement = parseStatement2(); 6747 elseStatement = parseStatement2();
6490 } 6748 }
6491 return new IfStatement(ifKeyword, leftParenthesis, condition, 6749 return new IfStatement(ifKeyword, leftParenthesis, condition,
6492 rightParenthesis, thenStatement, elseKeyword, elseStatement); 6750 rightParenthesis, thenStatement, elseKeyword, elseStatement);
6493 } 6751 }
6494 6752
6495 /** 6753 /**
6496 * Parse an import directive. The [commentAndMetadata] is the metadata to be 6754 * Parse an import directive. The [commentAndMetadata] is the metadata to be
6497 * associated with the directive. Return the import directive that was parsed. 6755 * associated with the directive. Return the import directive that was parsed.
6498 * 6756 *
6757 * This method assumes that the current token matches `Keyword.IMPORT`.
6758 *
6499 * importDirective ::= 6759 * importDirective ::=
6500 * metadata 'import' stringLiteral configuration* (deferred)? ('as' id entifier)? combinator*';' 6760 * metadata 'import' stringLiteral configuration* (deferred)? ('as' id entifier)? combinator*';'
6501 */ 6761 */
6502 ImportDirective _parseImportDirective(CommentAndMetadata commentAndMetadata) { 6762 ImportDirective _parseImportDirective(CommentAndMetadata commentAndMetadata) {
6503 Token importKeyword = _expectKeyword(Keyword.IMPORT); 6763 Token importKeyword = getAndAdvance();
6504 StringLiteral libraryUri = _parseUri(); 6764 StringLiteral libraryUri = _parseUri();
6505 List<Configuration> configurations = _parseConfigurations(); 6765 List<Configuration> configurations = _parseConfigurations();
6506 Token deferredToken = null; 6766 Token deferredToken = null;
6507 Token asToken = null; 6767 Token asToken = null;
6508 SimpleIdentifier prefix = null; 6768 SimpleIdentifier prefix = null;
6509 if (_matchesKeyword(Keyword.DEFERRED)) { 6769 if (_matchesKeyword(Keyword.DEFERRED)) {
6510 deferredToken = getAndAdvance(); 6770 deferredToken = getAndAdvance();
6511 } 6771 }
6512 if (_matchesKeyword(Keyword.AS)) { 6772 if (_matchesKeyword(Keyword.AS)) {
6513 asToken = getAndAdvance(); 6773 asToken = getAndAdvance();
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
6583 /** 6843 /**
6584 * Parse an instance creation expression. The [keyword] is the 'new' or 6844 * Parse an instance creation expression. The [keyword] is the 'new' or
6585 * 'const' keyword that introduces the expression. Return the instance 6845 * 'const' keyword that introduces the expression. Return the instance
6586 * creation expression that was parsed. 6846 * creation expression that was parsed.
6587 * 6847 *
6588 * instanceCreationExpression ::= 6848 * instanceCreationExpression ::=
6589 * ('new' | 'const') type ('.' identifier)? argumentList 6849 * ('new' | 'const') type ('.' identifier)? argumentList
6590 */ 6850 */
6591 InstanceCreationExpression _parseInstanceCreationExpression(Token keyword) { 6851 InstanceCreationExpression _parseInstanceCreationExpression(Token keyword) {
6592 ConstructorName constructorName = parseConstructorName(); 6852 ConstructorName constructorName = parseConstructorName();
6593 ArgumentList argumentList = parseArgumentList(); 6853 ArgumentList argumentList = _parseArgumentListChecked();
6594 return new InstanceCreationExpression( 6854 return new InstanceCreationExpression(
6595 keyword, constructorName, argumentList); 6855 keyword, constructorName, argumentList);
6596 } 6856 }
6597 6857
6598 /** 6858 /**
6599 * Parse a library directive. The [commentAndMetadata] is the metadata to be 6859 * Parse a library directive. The [commentAndMetadata] is the metadata to be
6600 * associated with the directive. Return the library directive that was 6860 * associated with the directive. Return the library directive that was
6601 * parsed. 6861 * parsed.
6602 * 6862 *
6863 * This method assumes that the current token matches `Keyword.LIBRARY`.
6864 *
6603 * libraryDirective ::= 6865 * libraryDirective ::=
6604 * metadata 'library' identifier ';' 6866 * metadata 'library' identifier ';'
6605 */ 6867 */
6606 LibraryDirective _parseLibraryDirective( 6868 LibraryDirective _parseLibraryDirective(
6607 CommentAndMetadata commentAndMetadata) { 6869 CommentAndMetadata commentAndMetadata) {
6608 Token keyword = _expectKeyword(Keyword.LIBRARY); 6870 Token keyword = getAndAdvance();
6609 LibraryIdentifier libraryName = _parseLibraryName( 6871 LibraryIdentifier libraryName = _parseLibraryName(
6610 ParserErrorCode.MISSING_NAME_IN_LIBRARY_DIRECTIVE, keyword); 6872 ParserErrorCode.MISSING_NAME_IN_LIBRARY_DIRECTIVE, keyword);
6611 Token semicolon = _expect(TokenType.SEMICOLON); 6873 Token semicolon = _expect(TokenType.SEMICOLON);
6612 return new LibraryDirective(commentAndMetadata.comment, 6874 return new LibraryDirective(commentAndMetadata.comment,
6613 commentAndMetadata.metadata, keyword, libraryName, semicolon); 6875 commentAndMetadata.metadata, keyword, libraryName, semicolon);
6614 } 6876 }
6615 6877
6616 /** 6878 /**
6617 * Parse a library name. The [missingNameError] is the error code to be used 6879 * Parse a library name. The [missingNameError] is the error code to be used
6618 * if the library name is missing. The [missingNameToken] is the token 6880 * if the library name is missing. The [missingNameToken] is the token
6619 * associated with the error produced if the library name is missing. Return 6881 * associated with the error produced if the library name is missing. Return
6620 * the library name that was parsed. 6882 * the library name that was parsed.
6621 * 6883 *
6622 * libraryName ::= 6884 * libraryName ::=
6623 * libraryIdentifier 6885 * libraryIdentifier
6624 */ 6886 */
6625 LibraryIdentifier _parseLibraryName( 6887 LibraryIdentifier _parseLibraryName(
6626 ParserErrorCode missingNameError, Token missingNameToken) { 6888 ParserErrorCode missingNameError, Token missingNameToken) {
6627 if (_matchesIdentifier()) { 6889 if (_matchesIdentifier()) {
6628 return parseLibraryIdentifier(); 6890 return parseLibraryIdentifier();
6629 } else if (_matches(TokenType.STRING)) { 6891 } else if (_matches(TokenType.STRING)) {
6630 // TODO(brianwilkerson) Recovery: This should be extended to handle 6892 // Recovery: This should be extended to handle arbitrary tokens until we
6631 // arbitrary tokens until we can find a token that can start a compilation 6893 // can find a token that can start a compilation unit member.
6632 // unit member.
6633 StringLiteral string = parseStringLiteral(); 6894 StringLiteral string = parseStringLiteral();
6634 _reportErrorForNode(ParserErrorCode.NON_IDENTIFIER_LIBRARY_NAME, string); 6895 _reportErrorForNode(ParserErrorCode.NON_IDENTIFIER_LIBRARY_NAME, string);
6635 } else { 6896 } else {
6636 _reportErrorForToken(missingNameError, missingNameToken); 6897 _reportErrorForToken(missingNameError, missingNameToken);
6637 } 6898 }
6638 List<SimpleIdentifier> components = new List<SimpleIdentifier>(); 6899 return new LibraryIdentifier(
6639 components.add(_createSyntheticIdentifier()); 6900 <SimpleIdentifier>[_createSyntheticIdentifier()]);
6640 return new LibraryIdentifier(components);
6641 } 6901 }
6642 6902
6643 /** 6903 /**
6644 * Parse a list literal. The [modifier] is the 'const' modifier appearing 6904 * Parse a list literal. The [modifier] is the 'const' modifier appearing
6645 * before the literal, or `null` if there is no modifier. The [typeArguments] 6905 * before the literal, or `null` if there is no modifier. The [typeArguments]
6646 * is the type arguments appearing before the literal, or `null` if there are 6906 * is the type arguments appearing before the literal, or `null` if there are
6647 * no type arguments. Return the list literal that was parsed. 6907 * no type arguments. Return the list literal that was parsed.
6648 * 6908 *
6909 * This method assumes that the current token matches either
6910 * `TokenType.OPEN_SQUARE_BRACKET` or `TokenType.INDEX`.
6911 *
6649 * listLiteral ::= 6912 * listLiteral ::=
6650 * 'const'? typeArguments? '[' (expressionList ','?)? ']' 6913 * 'const'? typeArguments? '[' (expressionList ','?)? ']'
6651 */ 6914 */
6652 ListLiteral _parseListLiteral( 6915 ListLiteral _parseListLiteral(
6653 Token modifier, TypeArgumentList typeArguments) { 6916 Token modifier, TypeArgumentList typeArguments) {
6654 // may be empty list literal
6655 if (_matches(TokenType.INDEX)) { 6917 if (_matches(TokenType.INDEX)) {
6918 // Split the token into two separate tokens.
6656 BeginToken leftBracket = _createToken( 6919 BeginToken leftBracket = _createToken(
6657 _currentToken, TokenType.OPEN_SQUARE_BRACKET, 6920 _currentToken, TokenType.OPEN_SQUARE_BRACKET,
6658 isBegin: true); 6921 isBegin: true);
6659 Token rightBracket = 6922 Token rightBracket =
6660 new Token(TokenType.CLOSE_SQUARE_BRACKET, _currentToken.offset + 1); 6923 new Token(TokenType.CLOSE_SQUARE_BRACKET, _currentToken.offset + 1);
6661 leftBracket.endToken = rightBracket; 6924 leftBracket.endToken = rightBracket;
6662 rightBracket.setNext(_currentToken.next); 6925 rightBracket.setNext(_currentToken.next);
6663 leftBracket.setNext(rightBracket); 6926 leftBracket.setNext(rightBracket);
6664 _currentToken.previous.setNext(leftBracket); 6927 _currentToken.previous.setNext(leftBracket);
6665 _currentToken = _currentToken.next; 6928 _currentToken = _currentToken.next;
6666 return new ListLiteral( 6929 return new ListLiteral(
6667 modifier, typeArguments, leftBracket, null, rightBracket); 6930 modifier, typeArguments, leftBracket, null, rightBracket);
6668 } 6931 }
6669 // open 6932 Token leftBracket = getAndAdvance();
6670 Token leftBracket = _expect(TokenType.OPEN_SQUARE_BRACKET);
6671 if (_matches(TokenType.CLOSE_SQUARE_BRACKET)) { 6933 if (_matches(TokenType.CLOSE_SQUARE_BRACKET)) {
6672 return new ListLiteral( 6934 return new ListLiteral(
6673 modifier, typeArguments, leftBracket, null, getAndAdvance()); 6935 modifier, typeArguments, leftBracket, null, getAndAdvance());
6674 } 6936 }
6675 bool wasInInitializer = _inInitializer; 6937 bool wasInInitializer = _inInitializer;
6676 _inInitializer = false; 6938 _inInitializer = false;
6677 try { 6939 try {
6678 List<Expression> elements = new List<Expression>(); 6940 List<Expression> elements = <Expression>[parseExpression2()];
6679 elements.add(parseExpression2());
6680 while (_optional(TokenType.COMMA)) { 6941 while (_optional(TokenType.COMMA)) {
6681 if (_matches(TokenType.CLOSE_SQUARE_BRACKET)) { 6942 if (_matches(TokenType.CLOSE_SQUARE_BRACKET)) {
6682 return new ListLiteral( 6943 return new ListLiteral(
6683 modifier, typeArguments, leftBracket, elements, getAndAdvance()); 6944 modifier, typeArguments, leftBracket, elements, getAndAdvance());
6684 } 6945 }
6685 elements.add(parseExpression2()); 6946 elements.add(parseExpression2());
6686 } 6947 }
6687 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET); 6948 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET);
6688 return new ListLiteral( 6949 return new ListLiteral(
6689 modifier, typeArguments, leftBracket, elements, rightBracket); 6950 modifier, typeArguments, leftBracket, elements, rightBracket);
(...skipping 30 matching lines...) Expand all
6720 6981
6721 /** 6982 /**
6722 * Parse a logical and expression. Return the logical and expression that was 6983 * Parse a logical and expression. Return the logical and expression that was
6723 * parsed. 6984 * parsed.
6724 * 6985 *
6725 * logicalAndExpression ::= 6986 * logicalAndExpression ::=
6726 * equalityExpression ('&&' equalityExpression)* 6987 * equalityExpression ('&&' equalityExpression)*
6727 */ 6988 */
6728 Expression _parseLogicalAndExpression() { 6989 Expression _parseLogicalAndExpression() {
6729 Expression expression = _parseEqualityExpression(); 6990 Expression expression = _parseEqualityExpression();
6730 while (_matches(TokenType.AMPERSAND_AMPERSAND)) { 6991 while (_currentToken.type == TokenType.AMPERSAND_AMPERSAND) {
6731 Token operator = getAndAdvance();
6732 expression = new BinaryExpression( 6992 expression = new BinaryExpression(
6733 expression, operator, _parseEqualityExpression()); 6993 expression, getAndAdvance(), _parseEqualityExpression());
6734 } 6994 }
6735 return expression; 6995 return expression;
6736 } 6996 }
6737 6997
6738 /** 6998 /**
6739 * Parse a map literal. The [modifier] is the 'const' modifier appearing 6999 * Parse a map literal. The [modifier] is the 'const' modifier appearing
6740 * before the literal, or `null` if there is no modifier. The [typeArguments] 7000 * before the literal, or `null` if there is no modifier. The [typeArguments]
6741 * is the type arguments that were declared, or `null` if there are no type 7001 * is the type arguments that were declared, or `null` if there are no type
6742 * arguments. Return the map literal that was parsed. 7002 * arguments. Return the map literal that was parsed.
6743 * 7003 *
7004 * This method assumes that the current token matches
7005 * `TokenType.OPEN_CURLY_BRACKET`.
7006 *
6744 * mapLiteral ::= 7007 * mapLiteral ::=
6745 * 'const'? typeArguments? '{' (mapLiteralEntry (',' mapLiteralEntry)* ','?)? '}' 7008 * 'const'? typeArguments? '{' (mapLiteralEntry (',' mapLiteralEntry)* ','?)? '}'
6746 */ 7009 */
6747 MapLiteral _parseMapLiteral(Token modifier, TypeArgumentList typeArguments) { 7010 MapLiteral _parseMapLiteral(Token modifier, TypeArgumentList typeArguments) {
6748 Token leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET); 7011 Token leftBracket = getAndAdvance();
6749 List<MapLiteralEntry> entries = new List<MapLiteralEntry>();
6750 if (_matches(TokenType.CLOSE_CURLY_BRACKET)) { 7012 if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
6751 return new MapLiteral( 7013 return new MapLiteral(
6752 modifier, typeArguments, leftBracket, entries, getAndAdvance()); 7014 modifier, typeArguments, leftBracket, null, getAndAdvance());
6753 } 7015 }
6754 bool wasInInitializer = _inInitializer; 7016 bool wasInInitializer = _inInitializer;
6755 _inInitializer = false; 7017 _inInitializer = false;
6756 try { 7018 try {
6757 entries.add(parseMapLiteralEntry()); 7019 List<MapLiteralEntry> entries = <MapLiteralEntry>[parseMapLiteralEntry()];
6758 while (_optional(TokenType.COMMA)) { 7020 while (_optional(TokenType.COMMA)) {
6759 if (_matches(TokenType.CLOSE_CURLY_BRACKET)) { 7021 if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
6760 return new MapLiteral( 7022 return new MapLiteral(
6761 modifier, typeArguments, leftBracket, entries, getAndAdvance()); 7023 modifier, typeArguments, leftBracket, entries, getAndAdvance());
6762 } 7024 }
6763 entries.add(parseMapLiteralEntry()); 7025 entries.add(parseMapLiteralEntry());
6764 } 7026 }
6765 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET); 7027 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
6766 return new MapLiteral( 7028 return new MapLiteral(
6767 modifier, typeArguments, leftBracket, entries, rightBracket); 7029 modifier, typeArguments, leftBracket, entries, rightBracket);
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
6831 * | 'external'? functionSignature ';' 7093 * | 'external'? functionSignature ';'
6832 */ 7094 */
6833 MethodDeclaration _parseMethodDeclarationAfterReturnType( 7095 MethodDeclaration _parseMethodDeclarationAfterReturnType(
6834 CommentAndMetadata commentAndMetadata, 7096 CommentAndMetadata commentAndMetadata,
6835 Token externalKeyword, 7097 Token externalKeyword,
6836 Token staticKeyword, 7098 Token staticKeyword,
6837 TypeName returnType) { 7099 TypeName returnType) {
6838 SimpleIdentifier methodName = parseSimpleIdentifier(isDeclaration: true); 7100 SimpleIdentifier methodName = parseSimpleIdentifier(isDeclaration: true);
6839 TypeParameterList typeParameters = _parseGenericMethodTypeParameters(); 7101 TypeParameterList typeParameters = _parseGenericMethodTypeParameters();
6840 FormalParameterList parameters; 7102 FormalParameterList parameters;
6841 if (!_matches(TokenType.OPEN_PAREN) && 7103 TokenType type = _currentToken.type;
6842 (_matches(TokenType.OPEN_CURLY_BRACKET) || 7104 // TODO(brianwilkerson) Figure out why we care what the current token is if
6843 _matches(TokenType.FUNCTION))) { 7105 // it isn't a paren.
7106 if (type != TokenType.OPEN_PAREN &&
7107 (type == TokenType.OPEN_CURLY_BRACKET || type == TokenType.FUNCTION)) {
6844 _reportErrorForToken( 7108 _reportErrorForToken(
6845 ParserErrorCode.MISSING_METHOD_PARAMETERS, _currentToken.previous); 7109 ParserErrorCode.MISSING_METHOD_PARAMETERS, _currentToken.previous);
6846 parameters = new FormalParameterList( 7110 parameters = new FormalParameterList(
6847 _createSyntheticToken(TokenType.OPEN_PAREN), 7111 _createSyntheticToken(TokenType.OPEN_PAREN),
6848 null, 7112 null,
6849 null, 7113 null,
6850 null, 7114 null,
6851 _createSyntheticToken(TokenType.CLOSE_PAREN)); 7115 _createSyntheticToken(TokenType.CLOSE_PAREN));
6852 } else { 7116 } else {
6853 parameters = parseFormalParameterList(); 7117 parameters = parseFormalParameterList();
(...skipping 17 matching lines...) Expand all
6871 * one of the methods whose name is prefixed with `validateModifiersFor`. 7135 * one of the methods whose name is prefixed with `validateModifiersFor`.
6872 * Return the modifiers that were parsed. 7136 * Return the modifiers that were parsed.
6873 * 7137 *
6874 * modifiers ::= 7138 * modifiers ::=
6875 * ('abstract' | 'const' | 'external' | 'factory' | 'final' | 'static' | 'var')* 7139 * ('abstract' | 'const' | 'external' | 'factory' | 'final' | 'static' | 'var')*
6876 */ 7140 */
6877 Modifiers _parseModifiers() { 7141 Modifiers _parseModifiers() {
6878 Modifiers modifiers = new Modifiers(); 7142 Modifiers modifiers = new Modifiers();
6879 bool progress = true; 7143 bool progress = true;
6880 while (progress) { 7144 while (progress) {
6881 if (_tokenMatches(_peek(), TokenType.PERIOD) || 7145 TokenType nextType = _peek().type;
6882 _tokenMatches(_peek(), TokenType.LT) || 7146 if (nextType == TokenType.PERIOD ||
6883 _tokenMatches(_peek(), TokenType.OPEN_PAREN)) { 7147 nextType == TokenType.LT ||
7148 nextType == TokenType.OPEN_PAREN) {
6884 return modifiers; 7149 return modifiers;
6885 } 7150 }
6886 if (_matchesKeyword(Keyword.ABSTRACT)) { 7151 Keyword keyword = _currentToken.keyword;
7152 if (keyword == Keyword.ABSTRACT) {
6887 if (modifiers.abstractKeyword != null) { 7153 if (modifiers.abstractKeyword != null) {
6888 _reportErrorForCurrentToken( 7154 _reportErrorForCurrentToken(
6889 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); 7155 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
6890 _advance(); 7156 _advance();
6891 } else { 7157 } else {
6892 modifiers.abstractKeyword = getAndAdvance(); 7158 modifiers.abstractKeyword = getAndAdvance();
6893 } 7159 }
6894 } else if (_matchesKeyword(Keyword.CONST)) { 7160 } else if (keyword == Keyword.CONST) {
6895 if (modifiers.constKeyword != null) { 7161 if (modifiers.constKeyword != null) {
6896 _reportErrorForCurrentToken( 7162 _reportErrorForCurrentToken(
6897 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); 7163 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
6898 _advance(); 7164 _advance();
6899 } else { 7165 } else {
6900 modifiers.constKeyword = getAndAdvance(); 7166 modifiers.constKeyword = getAndAdvance();
6901 } 7167 }
6902 } else if (_matchesKeyword(Keyword.EXTERNAL) && 7168 } else if (keyword == Keyword.EXTERNAL) {
6903 !_tokenMatches(_peek(), TokenType.PERIOD) &&
6904 !_tokenMatches(_peek(), TokenType.LT)) {
6905 if (modifiers.externalKeyword != null) { 7169 if (modifiers.externalKeyword != null) {
6906 _reportErrorForCurrentToken( 7170 _reportErrorForCurrentToken(
6907 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); 7171 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
6908 _advance(); 7172 _advance();
6909 } else { 7173 } else {
6910 modifiers.externalKeyword = getAndAdvance(); 7174 modifiers.externalKeyword = getAndAdvance();
6911 } 7175 }
6912 } else if (_matchesKeyword(Keyword.FACTORY) && 7176 } else if (keyword == Keyword.FACTORY) {
6913 !_tokenMatches(_peek(), TokenType.PERIOD) &&
6914 !_tokenMatches(_peek(), TokenType.LT)) {
6915 if (modifiers.factoryKeyword != null) { 7177 if (modifiers.factoryKeyword != null) {
6916 _reportErrorForCurrentToken( 7178 _reportErrorForCurrentToken(
6917 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); 7179 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
6918 _advance(); 7180 _advance();
6919 } else { 7181 } else {
6920 modifiers.factoryKeyword = getAndAdvance(); 7182 modifiers.factoryKeyword = getAndAdvance();
6921 } 7183 }
6922 } else if (_matchesKeyword(Keyword.FINAL)) { 7184 } else if (keyword == Keyword.FINAL) {
6923 if (modifiers.finalKeyword != null) { 7185 if (modifiers.finalKeyword != null) {
6924 _reportErrorForCurrentToken( 7186 _reportErrorForCurrentToken(
6925 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); 7187 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
6926 _advance(); 7188 _advance();
6927 } else { 7189 } else {
6928 modifiers.finalKeyword = getAndAdvance(); 7190 modifiers.finalKeyword = getAndAdvance();
6929 } 7191 }
6930 } else if (_matchesKeyword(Keyword.STATIC) && 7192 } else if (keyword == Keyword.STATIC) {
6931 !_tokenMatches(_peek(), TokenType.PERIOD) &&
6932 !_tokenMatches(_peek(), TokenType.LT)) {
6933 if (modifiers.staticKeyword != null) { 7193 if (modifiers.staticKeyword != null) {
6934 _reportErrorForCurrentToken( 7194 _reportErrorForCurrentToken(
6935 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); 7195 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
6936 _advance(); 7196 _advance();
6937 } else { 7197 } else {
6938 modifiers.staticKeyword = getAndAdvance(); 7198 modifiers.staticKeyword = getAndAdvance();
6939 } 7199 }
6940 } else if (_matchesKeyword(Keyword.VAR)) { 7200 } else if (keyword == Keyword.VAR) {
6941 if (modifiers.varKeyword != null) { 7201 if (modifiers.varKeyword != null) {
6942 _reportErrorForCurrentToken( 7202 _reportErrorForCurrentToken(
6943 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); 7203 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
6944 _advance(); 7204 _advance();
6945 } else { 7205 } else {
6946 modifiers.varKeyword = getAndAdvance(); 7206 modifiers.varKeyword = getAndAdvance();
6947 } 7207 }
6948 } else { 7208 } else {
6949 progress = false; 7209 progress = false;
6950 } 7210 }
6951 } 7211 }
6952 return modifiers; 7212 return modifiers;
6953 } 7213 }
6954 7214
6955 /** 7215 /**
6956 * Parse a multiplicative expression. Return the multiplicative expression 7216 * Parse a multiplicative expression. Return the multiplicative expression
6957 * that was parsed. 7217 * that was parsed.
6958 * 7218 *
6959 * multiplicativeExpression ::= 7219 * multiplicativeExpression ::=
6960 * unaryExpression (multiplicativeOperator unaryExpression)* 7220 * unaryExpression (multiplicativeOperator unaryExpression)*
6961 * | 'super' (multiplicativeOperator unaryExpression)+ 7221 * | 'super' (multiplicativeOperator unaryExpression)+
6962 */ 7222 */
6963 Expression _parseMultiplicativeExpression() { 7223 Expression _parseMultiplicativeExpression() {
6964 Expression expression; 7224 Expression expression;
6965 if (_matchesKeyword(Keyword.SUPER) && 7225 if (_currentToken.keyword == Keyword.SUPER &&
6966 _currentToken.next.type.isMultiplicativeOperator) { 7226 _currentToken.next.type.isMultiplicativeOperator) {
6967 expression = new SuperExpression(getAndAdvance()); 7227 expression = new SuperExpression(getAndAdvance());
6968 } else { 7228 } else {
6969 expression = _parseUnaryExpression(); 7229 expression = _parseUnaryExpression();
6970 } 7230 }
6971 while (_currentToken.type.isMultiplicativeOperator) { 7231 while (_currentToken.type.isMultiplicativeOperator) {
6972 Token operator = getAndAdvance(); 7232 expression = new BinaryExpression(
6973 expression = 7233 expression, getAndAdvance(), _parseUnaryExpression());
6974 new BinaryExpression(expression, operator, _parseUnaryExpression());
6975 } 7234 }
6976 return expression; 7235 return expression;
6977 } 7236 }
6978 7237
6979 /** 7238 /**
6980 * Parse a class native clause. Return the native clause that was parsed. 7239 * Parse a class native clause. Return the native clause that was parsed.
6981 * 7240 *
7241 * This method assumes that the current token matches `_NATIVE`.
7242 *
6982 * classNativeClause ::= 7243 * classNativeClause ::=
6983 * 'native' name 7244 * 'native' name
6984 */ 7245 */
6985 NativeClause _parseNativeClause() { 7246 NativeClause _parseNativeClause() {
6986 Token keyword = getAndAdvance(); 7247 Token keyword = getAndAdvance();
6987 StringLiteral name = parseStringLiteral(); 7248 StringLiteral name = parseStringLiteral();
6988 return new NativeClause(keyword, name); 7249 return new NativeClause(keyword, name);
6989 } 7250 }
6990 7251
6991 /** 7252 /**
6992 * Parse a new expression. Return the new expression that was parsed. 7253 * Parse a new expression. Return the new expression that was parsed.
6993 * 7254 *
7255 * This method assumes that the current token matches `Keyword.NEW`.
7256 *
6994 * newExpression ::= 7257 * newExpression ::=
6995 * instanceCreationExpression 7258 * instanceCreationExpression
6996 */ 7259 */
6997 InstanceCreationExpression _parseNewExpression() => 7260 InstanceCreationExpression _parseNewExpression() =>
6998 _parseInstanceCreationExpression(_expectKeyword(Keyword.NEW)); 7261 _parseInstanceCreationExpression(getAndAdvance());
6999 7262
7000 /** 7263 /**
7001 * Parse a non-labeled statement. Return the non-labeled statement that was 7264 * Parse a non-labeled statement. Return the non-labeled statement that was
7002 * parsed. 7265 * parsed.
7003 * 7266 *
7004 * nonLabeledStatement ::= 7267 * nonLabeledStatement ::=
7005 * block 7268 * block
7006 * | assertStatement 7269 * | assertStatement
7007 * | breakStatement 7270 * | breakStatement
7008 * | continueStatement 7271 * | continueStatement
7009 * | doStatement 7272 * | doStatement
7010 * | forStatement 7273 * | forStatement
7011 * | ifStatement 7274 * | ifStatement
7012 * | returnStatement 7275 * | returnStatement
7013 * | switchStatement 7276 * | switchStatement
7014 * | tryStatement 7277 * | tryStatement
7015 * | whileStatement 7278 * | whileStatement
7016 * | variableDeclarationList ';' 7279 * | variableDeclarationList ';'
7017 * | expressionStatement 7280 * | expressionStatement
7018 * | functionSignature functionBody 7281 * | functionSignature functionBody
7019 */ 7282 */
7020 Statement _parseNonLabeledStatement() { 7283 Statement _parseNonLabeledStatement() {
7021 // TODO(brianwilkerson) Pass the comment and metadata on where appropriate. 7284 // TODO(brianwilkerson) Pass the comment and metadata on where appropriate.
7022 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); 7285 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata();
7023 if (_matches(TokenType.OPEN_CURLY_BRACKET)) { 7286 TokenType type = _currentToken.type;
7287 if (type == TokenType.OPEN_CURLY_BRACKET) {
7024 if (_tokenMatches(_peek(), TokenType.STRING)) { 7288 if (_tokenMatches(_peek(), TokenType.STRING)) {
7025 Token afterString = _skipStringLiteral(_currentToken.next); 7289 Token afterString = _skipStringLiteral(_currentToken.next);
7026 if (afterString != null && afterString.type == TokenType.COLON) { 7290 if (afterString != null && afterString.type == TokenType.COLON) {
7027 return new ExpressionStatement( 7291 return new ExpressionStatement(
7028 parseExpression2(), _expect(TokenType.SEMICOLON)); 7292 parseExpression2(), _expect(TokenType.SEMICOLON));
7029 } 7293 }
7030 } 7294 }
7031 return parseBlock(); 7295 return parseBlock();
7032 } else if (_matches(TokenType.KEYWORD) && 7296 } else if (type == TokenType.KEYWORD &&
7033 !_currentToken.keyword.isPseudoKeyword) { 7297 !_currentToken.keyword.isPseudoKeyword) {
7034 Keyword keyword = _currentToken.keyword; 7298 Keyword keyword = _currentToken.keyword;
7035 // TODO(jwren) compute some metrics to figure out a better order for this 7299 // TODO(jwren) compute some metrics to figure out a better order for this
7036 // if-then sequence to optimize performance 7300 // if-then sequence to optimize performance
7037 if (keyword == Keyword.ASSERT) { 7301 if (keyword == Keyword.ASSERT) {
7038 return _parseAssertStatement(); 7302 return _parseAssertStatement();
7039 } else if (keyword == Keyword.BREAK) { 7303 } else if (keyword == Keyword.BREAK) {
7040 return _parseBreakStatement(); 7304 return _parseBreakStatement();
7041 } else if (keyword == Keyword.CONTINUE) { 7305 } else if (keyword == Keyword.CONTINUE) {
7042 return _parseContinueStatement(); 7306 return _parseContinueStatement();
(...skipping 14 matching lines...) Expand all
7057 return new ExpressionStatement( 7321 return new ExpressionStatement(
7058 _parseThrowExpression(), _expect(TokenType.SEMICOLON)); 7322 _parseThrowExpression(), _expect(TokenType.SEMICOLON));
7059 } else if (keyword == Keyword.TRY) { 7323 } else if (keyword == Keyword.TRY) {
7060 return _parseTryStatement(); 7324 return _parseTryStatement();
7061 } else if (keyword == Keyword.WHILE) { 7325 } else if (keyword == Keyword.WHILE) {
7062 return _parseWhileStatement(); 7326 return _parseWhileStatement();
7063 } else if (keyword == Keyword.VAR || keyword == Keyword.FINAL) { 7327 } else if (keyword == Keyword.VAR || keyword == Keyword.FINAL) {
7064 return _parseVariableDeclarationStatementAfterMetadata( 7328 return _parseVariableDeclarationStatementAfterMetadata(
7065 commentAndMetadata); 7329 commentAndMetadata);
7066 } else if (keyword == Keyword.VOID) { 7330 } else if (keyword == Keyword.VOID) {
7067 TypeName returnType = parseReturnType(); 7331 TypeName returnType =
7332 new TypeName(new SimpleIdentifier(getAndAdvance()), null);
7333 Token next = _currentToken.next;
7068 if (_matchesIdentifier() && 7334 if (_matchesIdentifier() &&
7069 _peek().matchesAny(const <TokenType>[ 7335 next.matchesAny(const <TokenType>[
7070 TokenType.OPEN_PAREN, 7336 TokenType.OPEN_PAREN,
7071 TokenType.OPEN_CURLY_BRACKET, 7337 TokenType.OPEN_CURLY_BRACKET,
7072 TokenType.FUNCTION, 7338 TokenType.FUNCTION,
7073 TokenType.LT 7339 TokenType.LT
7074 ])) { 7340 ])) {
7075 return _parseFunctionDeclarationStatementAfterReturnType( 7341 return _parseFunctionDeclarationStatementAfterReturnType(
7076 commentAndMetadata, returnType); 7342 commentAndMetadata, returnType);
7077 } else { 7343 } else {
7078 // 7344 //
7079 // We have found an error of some kind. Try to recover. 7345 // We have found an error of some kind. Try to recover.
7080 // 7346 //
7081 if (_matchesIdentifier()) { 7347 if (_matchesIdentifier()) {
7082 if (_peek().matchesAny(const <TokenType>[ 7348 if (next.matchesAny(const <TokenType>[
7083 TokenType.EQ, 7349 TokenType.EQ,
7084 TokenType.COMMA, 7350 TokenType.COMMA,
7085 TokenType.SEMICOLON 7351 TokenType.SEMICOLON
7086 ])) { 7352 ])) {
7087 // 7353 //
7088 // We appear to have a variable declaration with a type of "void". 7354 // We appear to have a variable declaration with a type of "void".
7089 // 7355 //
7090 _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType); 7356 _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType);
7091 return _parseVariableDeclarationStatementAfterMetadata( 7357 return _parseVariableDeclarationStatementAfterMetadata(
7092 commentAndMetadata); 7358 commentAndMetadata);
7093 } 7359 }
7094 } else if (_matches(TokenType.CLOSE_CURLY_BRACKET)) { 7360 } else if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
7095 // 7361 //
7096 // We appear to have found an incomplete statement at the end of a 7362 // We appear to have found an incomplete statement at the end of a
7097 // block. Parse it as a variable declaration. 7363 // block. Parse it as a variable declaration.
7098 // 7364 //
7099 return _parseVariableDeclarationStatementAfterType( 7365 return _parseVariableDeclarationStatementAfterType(
7100 commentAndMetadata, null, returnType); 7366 commentAndMetadata, null, returnType);
7101 } 7367 }
7102 _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT); 7368 _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT);
7103 // TODO(brianwilkerson) Recover from this error. 7369 // TODO(brianwilkerson) Recover from this error.
7104 return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON)); 7370 return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON));
7105 } 7371 }
7106 } else if (keyword == Keyword.CONST) { 7372 } else if (keyword == Keyword.CONST) {
7107 if (_peek().matchesAny(const <TokenType>[ 7373 Token next = _currentToken.next;
7374 if (next.matchesAny(const <TokenType>[
7108 TokenType.LT, 7375 TokenType.LT,
7109 TokenType.OPEN_CURLY_BRACKET, 7376 TokenType.OPEN_CURLY_BRACKET,
7110 TokenType.OPEN_SQUARE_BRACKET, 7377 TokenType.OPEN_SQUARE_BRACKET,
7111 TokenType.INDEX 7378 TokenType.INDEX
7112 ])) { 7379 ])) {
7113 return new ExpressionStatement( 7380 return new ExpressionStatement(
7114 parseExpression2(), _expect(TokenType.SEMICOLON)); 7381 parseExpression2(), _expect(TokenType.SEMICOLON));
7115 } else if (_tokenMatches(_peek(), TokenType.IDENTIFIER)) { 7382 } else if (_tokenMatches(next, TokenType.IDENTIFIER)) {
7116 Token afterType = _skipTypeName(_peek()); 7383 Token afterType = _skipTypeName(next);
7117 if (afterType != null) { 7384 if (afterType != null) {
7118 if (_tokenMatches(afterType, TokenType.OPEN_PAREN) || 7385 if (_tokenMatches(afterType, TokenType.OPEN_PAREN) ||
7119 (_tokenMatches(afterType, TokenType.PERIOD) && 7386 (_tokenMatches(afterType, TokenType.PERIOD) &&
7120 _tokenMatches(afterType.next, TokenType.IDENTIFIER) && 7387 _tokenMatches(afterType.next, TokenType.IDENTIFIER) &&
7121 _tokenMatches(afterType.next.next, TokenType.OPEN_PAREN))) { 7388 _tokenMatches(afterType.next.next, TokenType.OPEN_PAREN))) {
7122 return new ExpressionStatement( 7389 return new ExpressionStatement(
7123 parseExpression2(), _expect(TokenType.SEMICOLON)); 7390 parseExpression2(), _expect(TokenType.SEMICOLON));
7124 } 7391 }
7125 } 7392 }
7126 } 7393 }
(...skipping 24 matching lines...) Expand all
7151 parseExpression2(), _expect(TokenType.SEMICOLON)); 7418 parseExpression2(), _expect(TokenType.SEMICOLON));
7152 } else if (_matchesString(_AWAIT) && 7419 } else if (_matchesString(_AWAIT) &&
7153 _tokenMatchesKeyword(_peek(), Keyword.FOR)) { 7420 _tokenMatchesKeyword(_peek(), Keyword.FOR)) {
7154 Token awaitToken = _currentToken; 7421 Token awaitToken = _currentToken;
7155 Statement statement = _parseForStatement(); 7422 Statement statement = _parseForStatement();
7156 if (statement is! ForStatement) { 7423 if (statement is! ForStatement) {
7157 _reportErrorForToken( 7424 _reportErrorForToken(
7158 CompileTimeErrorCode.ASYNC_FOR_IN_WRONG_CONTEXT, awaitToken); 7425 CompileTimeErrorCode.ASYNC_FOR_IN_WRONG_CONTEXT, awaitToken);
7159 } 7426 }
7160 return statement; 7427 return statement;
7161 } else if (_matches(TokenType.SEMICOLON)) { 7428 } else if (type == TokenType.SEMICOLON) {
7162 return _parseEmptyStatement(); 7429 return _parseEmptyStatement();
7163 } else if (_isInitializedVariableDeclaration()) { 7430 } else if (_isInitializedVariableDeclaration()) {
7164 return _parseVariableDeclarationStatementAfterMetadata( 7431 return _parseVariableDeclarationStatementAfterMetadata(
7165 commentAndMetadata); 7432 commentAndMetadata);
7166 } else if (_isFunctionDeclaration()) { 7433 } else if (_isFunctionDeclaration()) {
7167 return _parseFunctionDeclarationStatement(); 7434 return _parseFunctionDeclarationStatement();
7168 } else if (_matches(TokenType.CLOSE_CURLY_BRACKET)) { 7435 } else if (type == TokenType.CLOSE_CURLY_BRACKET) {
7169 _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT); 7436 _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT);
7170 return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON)); 7437 return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON));
7171 } else { 7438 } else {
7172 return new ExpressionStatement( 7439 return new ExpressionStatement(
7173 parseExpression2(), _expect(TokenType.SEMICOLON)); 7440 parseExpression2(), _expect(TokenType.SEMICOLON));
7174 } 7441 }
7175 } 7442 }
7176 7443
7177 /** 7444 /**
7178 * Parse an operator declaration. The [commentAndMetadata] is the 7445 * Parse an operator declaration. The [commentAndMetadata] is the
(...skipping 11 matching lines...) Expand all
7190 MethodDeclaration _parseOperator(CommentAndMetadata commentAndMetadata, 7457 MethodDeclaration _parseOperator(CommentAndMetadata commentAndMetadata,
7191 Token externalKeyword, TypeName returnType) { 7458 Token externalKeyword, TypeName returnType) {
7192 Token operatorKeyword; 7459 Token operatorKeyword;
7193 if (_matchesKeyword(Keyword.OPERATOR)) { 7460 if (_matchesKeyword(Keyword.OPERATOR)) {
7194 operatorKeyword = getAndAdvance(); 7461 operatorKeyword = getAndAdvance();
7195 } else { 7462 } else {
7196 _reportErrorForToken( 7463 _reportErrorForToken(
7197 ParserErrorCode.MISSING_KEYWORD_OPERATOR, _currentToken); 7464 ParserErrorCode.MISSING_KEYWORD_OPERATOR, _currentToken);
7198 operatorKeyword = _createSyntheticKeyword(Keyword.OPERATOR); 7465 operatorKeyword = _createSyntheticKeyword(Keyword.OPERATOR);
7199 } 7466 }
7467 return _parseOperatorAfterKeyword(
7468 commentAndMetadata, externalKeyword, returnType, operatorKeyword);
7469 }
7470
7471 /**
7472 * Parse an operator declaration starting after the 'operator' keyword. The
7473 * [commentAndMetadata] is the documentation comment and metadata to be
7474 * associated with the declaration. The [externalKeyword] is the 'external'
7475 * token. The [returnType] is the return type that has already been parsed, or
7476 * `null` if there was no return type. The [operatorKeyword] is the 'operator'
7477 * keyword. Return the operator declaration that was parsed.
7478 *
7479 * operatorDeclaration ::=
7480 * operatorSignature (';' | functionBody)
7481 *
7482 * operatorSignature ::=
7483 * 'external'? returnType? 'operator' operator formalParameterList
7484 */
7485 MethodDeclaration _parseOperatorAfterKeyword(
7486 CommentAndMetadata commentAndMetadata,
7487 Token externalKeyword,
7488 TypeName returnType,
7489 Token operatorKeyword) {
7200 if (!_currentToken.isUserDefinableOperator) { 7490 if (!_currentToken.isUserDefinableOperator) {
7201 _reportErrorForCurrentToken( 7491 _reportErrorForCurrentToken(
7202 ParserErrorCode.NON_USER_DEFINABLE_OPERATOR, [_currentToken.lexeme]); 7492 ParserErrorCode.NON_USER_DEFINABLE_OPERATOR, [_currentToken.lexeme]);
7203 } 7493 }
7204 SimpleIdentifier name = 7494 SimpleIdentifier name =
7205 new SimpleIdentifier(getAndAdvance(), isDeclaration: true); 7495 new SimpleIdentifier(getAndAdvance(), isDeclaration: true);
7206 if (_matches(TokenType.EQ)) { 7496 if (_matches(TokenType.EQ)) {
7207 Token previous = _currentToken.previous; 7497 Token previous = _currentToken.previous;
7208 if ((_tokenMatches(previous, TokenType.EQ_EQ) || 7498 if ((_tokenMatches(previous, TokenType.EQ_EQ) ||
7209 _tokenMatches(previous, TokenType.BANG_EQ)) && 7499 _tokenMatches(previous, TokenType.BANG_EQ)) &&
(...skipping 25 matching lines...) Expand all
7235 } 7525 }
7236 7526
7237 /** 7527 /**
7238 * Parse a return type if one is given, otherwise return `null` without 7528 * Parse a return type if one is given, otherwise return `null` without
7239 * advancing. Return the return type that was parsed. 7529 * advancing. Return the return type that was parsed.
7240 */ 7530 */
7241 TypeName _parseOptionalReturnType() { 7531 TypeName _parseOptionalReturnType() {
7242 TypeName typeComment = _parseOptionalTypeNameComment(); 7532 TypeName typeComment = _parseOptionalTypeNameComment();
7243 if (typeComment != null) { 7533 if (typeComment != null) {
7244 return typeComment; 7534 return typeComment;
7245 } else if (_matchesKeyword(Keyword.VOID)) { 7535 }
7246 return parseReturnType(); 7536 Keyword keyword = _currentToken.keyword;
7247 } else if (_matchesIdentifier() && 7537 if (keyword == Keyword.VOID) {
7248 !_matchesKeyword(Keyword.GET) && 7538 return new TypeName(new SimpleIdentifier(getAndAdvance()), null);
7249 !_matchesKeyword(Keyword.SET) && 7539 } else if (_matchesIdentifier()) {
7250 !_matchesKeyword(Keyword.OPERATOR) && 7540 Token next = _peek();
7251 (_tokenMatchesIdentifier(_peek()) || 7541 if (keyword != Keyword.GET &&
7252 _tokenMatches(_peek(), TokenType.LT))) { 7542 keyword != Keyword.SET &&
7253 return parseReturnType(); 7543 keyword != Keyword.OPERATOR &&
7254 } else if (_matchesIdentifier() && 7544 (_tokenMatchesIdentifier(next) ||
7255 _tokenMatches(_peek(), TokenType.PERIOD) && 7545 _tokenMatches(next, TokenType.LT))) {
7256 _tokenMatchesIdentifier(_peekAt(2)) && 7546 return parseReturnType();
7257 (_tokenMatchesIdentifier(_peekAt(3)) || 7547 }
7258 _tokenMatches(_peekAt(3), TokenType.LT))) { 7548 Token next2 = next.next;
7259 return parseReturnType(); 7549 Token next3 = next2.next;
7550 if (_tokenMatches(next, TokenType.PERIOD) &&
7551 _tokenMatchesIdentifier(next2) &&
7552 (_tokenMatchesIdentifier(next3) ||
7553 _tokenMatches(next3, TokenType.LT))) {
7554 return parseReturnType();
7555 }
7260 } 7556 }
7261 return null; 7557 return null;
7262 } 7558 }
7263 7559
7264 /** 7560 /**
7265 * Parse a [TypeArgumentList] if present, otherwise return null. 7561 * Parse a [TypeArgumentList] if present, otherwise return null.
7266 * This also supports the comment form, if enabled: `/*<T>*/` 7562 * This also supports the comment form, if enabled: `/*<T>*/`
7267 */ 7563 */
7268 TypeArgumentList _parseOptionalTypeArguments() { 7564 TypeArgumentList _parseOptionalTypeArguments() {
7269 if (_matches(TokenType.LT) || _injectGenericCommentTypeList()) { 7565 if (_matches(TokenType.LT) || _injectGenericCommentTypeList()) {
7270 return parseTypeArgumentList(); 7566 return parseTypeArgumentList();
7271 } 7567 }
7272 return null; 7568 return null;
7273 } 7569 }
7274 7570
7275 TypeName _parseOptionalTypeNameComment() { 7571 TypeName _parseOptionalTypeNameComment() {
7276 if (_injectGenericCommentTypeAssign()) { 7572 if (_injectGenericCommentTypeAssign()) {
7277 return _parseTypeName(); 7573 return _parseTypeName();
7278 } 7574 }
7279 return null; 7575 return null;
7280 } 7576 }
7281 7577
7282 /** 7578 /**
7579 * Parse a part directive. The [commentAndMetadata] is the metadata to be
7580 * associated with the directive. Return the part or part-of directive that
7581 * was parsed.
7582 *
7583 * This method assumes that the current token matches `Keyword.PART`.
7584 *
7585 * partDirective ::=
7586 * metadata 'part' stringLiteral ';'
7587 */
7588 Directive _parsePartDirective(CommentAndMetadata commentAndMetadata) {
7589 Token partKeyword = getAndAdvance();
7590 StringLiteral partUri = _parseUri();
7591 Token semicolon = _expect(TokenType.SEMICOLON);
7592 return new PartDirective(commentAndMetadata.comment,
7593 commentAndMetadata.metadata, partKeyword, partUri, semicolon);
7594 }
7595
7596 /**
7597 * Parse a part-of directive. The [commentAndMetadata] is the metadata to be
7598 * associated with the directive. Return the part or part-of directive that
7599 * was parsed.
7600 *
7601 * This method assumes that the current token matches [Keyword.PART] and that
7602 * the following token matches the identifier 'of'.
7603 *
7604 * partOfDirective ::=
7605 * metadata 'part' 'of' identifier ';'
7606 */
7607 Directive _parsePartOfDirective(CommentAndMetadata commentAndMetadata) {
7608 Token partKeyword = getAndAdvance();
7609 Token ofKeyword = getAndAdvance();
7610 LibraryIdentifier libraryName = _parseLibraryName(
7611 ParserErrorCode.MISSING_NAME_IN_PART_OF_DIRECTIVE, ofKeyword);
7612 Token semicolon = _expect(TokenType.SEMICOLON);
7613 return new PartOfDirective(
7614 commentAndMetadata.comment,
7615 commentAndMetadata.metadata,
7616 partKeyword,
7617 ofKeyword,
7618 libraryName,
7619 semicolon);
7620 }
7621
7622 /**
7283 * Parse a part or part-of directive. The [commentAndMetadata] is the metadata 7623 * Parse a part or part-of directive. The [commentAndMetadata] is the metadata
7284 * to be associated with the directive. Return the part or part-of directive 7624 * to be associated with the directive. Return the part or part-of directive
7285 * that was parsed. 7625 * that was parsed.
7286 * 7626 *
7627 * This method assumes that the current token matches `Keyword.PART`.
7628 *
7287 * partDirective ::= 7629 * partDirective ::=
7288 * metadata 'part' stringLiteral ';' 7630 * metadata 'part' stringLiteral ';'
7289 * 7631 *
7290 * partOfDirective ::= 7632 * partOfDirective ::=
7291 * metadata 'part' 'of' identifier ';' 7633 * metadata 'part' 'of' identifier ';'
7292 */ 7634 */
7293 Directive _parsePartDirective(CommentAndMetadata commentAndMetadata) { 7635 Directive _parsePartOrPartOfDirective(CommentAndMetadata commentAndMetadata) {
7294 Token partKeyword = _expectKeyword(Keyword.PART); 7636 if (_tokenMatchesString(_peek(), _OF)) {
7295 if (_matchesString(_OF)) { 7637 return _parsePartOfDirective(commentAndMetadata);
7296 Token ofKeyword = getAndAdvance();
7297 LibraryIdentifier libraryName = _parseLibraryName(
7298 ParserErrorCode.MISSING_NAME_IN_PART_OF_DIRECTIVE, ofKeyword);
7299 Token semicolon = _expect(TokenType.SEMICOLON);
7300 return new PartOfDirective(
7301 commentAndMetadata.comment,
7302 commentAndMetadata.metadata,
7303 partKeyword,
7304 ofKeyword,
7305 libraryName,
7306 semicolon);
7307 } 7638 }
7308 StringLiteral partUri = _parseUri(); 7639 return _parsePartDirective(commentAndMetadata);
7309 Token semicolon = _expect(TokenType.SEMICOLON);
7310 return new PartDirective(commentAndMetadata.comment,
7311 commentAndMetadata.metadata, partKeyword, partUri, semicolon);
7312 } 7640 }
7313 7641
7314 /** 7642 /**
7315 * Parse a postfix expression. Return the postfix expression that was parsed. 7643 * Parse a postfix expression. Return the postfix expression that was parsed.
7316 * 7644 *
7317 * postfixExpression ::= 7645 * postfixExpression ::=
7318 * assignableExpression postfixOperator 7646 * assignableExpression postfixOperator
7319 * | primary selector* 7647 * | primary selector*
7320 * 7648 *
7321 * selector ::= 7649 * selector ::=
7322 * assignableSelector 7650 * assignableSelector
7323 * | argumentList 7651 * | argumentList
7324 */ 7652 */
7325 Expression _parsePostfixExpression() { 7653 Expression _parsePostfixExpression() {
7326 Expression operand = _parseAssignableExpression(true); 7654 Expression operand = _parseAssignableExpression(true);
7327 if (_matches(TokenType.OPEN_SQUARE_BRACKET) || 7655 TokenType type = _currentToken.type;
7328 _matches(TokenType.PERIOD) || 7656 if (type == TokenType.OPEN_SQUARE_BRACKET ||
7329 _matches(TokenType.QUESTION_PERIOD) || 7657 type == TokenType.PERIOD ||
7330 _matches(TokenType.OPEN_PAREN) || 7658 type == TokenType.QUESTION_PERIOD ||
7331 (parseGenericMethods && _matches(TokenType.LT))) { 7659 type == TokenType.OPEN_PAREN ||
7660 (parseGenericMethods && type == TokenType.LT)) {
7332 do { 7661 do {
7333 if (_isLikelyArgumentList()) { 7662 if (_isLikelyArgumentList()) {
7334 TypeArgumentList typeArguments = _parseOptionalTypeArguments(); 7663 TypeArgumentList typeArguments = _parseOptionalTypeArguments();
7335 ArgumentList argumentList = parseArgumentList(); 7664 ArgumentList argumentList = parseArgumentList();
7336 Expression currentOperand = operand; 7665 Expression currentOperand = operand;
7337 if (currentOperand is PropertyAccess) { 7666 if (currentOperand is PropertyAccess) {
7338 operand = new MethodInvocation( 7667 operand = new MethodInvocation(
7339 currentOperand.target, 7668 currentOperand.target,
7340 currentOperand.operator, 7669 currentOperand.operator,
7341 currentOperand.propertyName, 7670 currentOperand.propertyName,
7342 typeArguments, 7671 typeArguments,
7343 argumentList); 7672 argumentList);
7344 } else { 7673 } else {
7345 operand = new FunctionExpressionInvocation( 7674 operand = new FunctionExpressionInvocation(
7346 operand, typeArguments, argumentList); 7675 operand, typeArguments, argumentList);
7347 } 7676 }
7348 } else { 7677 } else {
7349 operand = _parseAssignableSelector(operand, true); 7678 operand = _parseAssignableSelector(operand, true);
7350 } 7679 }
7351 } while (_matches(TokenType.OPEN_SQUARE_BRACKET) || 7680 type = _currentToken.type;
7352 _matches(TokenType.PERIOD) || 7681 } while (type == TokenType.OPEN_SQUARE_BRACKET ||
7353 _matches(TokenType.QUESTION_PERIOD) || 7682 type == TokenType.PERIOD ||
7354 _matches(TokenType.OPEN_PAREN)); 7683 type == TokenType.QUESTION_PERIOD ||
7684 type == TokenType.OPEN_PAREN);
7355 return operand; 7685 return operand;
7356 } 7686 }
7357 if (!_currentToken.type.isIncrementOperator) { 7687 if (!_currentToken.type.isIncrementOperator) {
7358 return operand; 7688 return operand;
7359 } 7689 }
7360 _ensureAssignable(operand); 7690 _ensureAssignable(operand);
7361 Token operator = getAndAdvance(); 7691 Token operator = getAndAdvance();
7362 return new PostfixExpression(operand, operator); 7692 return new PostfixExpression(operand, operator);
7363 } 7693 }
7364 7694
7365 /** 7695 /**
7696 * Parse a prefixed identifier given that the given [qualifier] was already
7697 * parsed. Return the prefixed identifier that was parsed.
7698 *
7699 * prefixedIdentifier ::=
7700 * identifier ('.' identifier)?
7701 */
7702 Identifier _parsePrefixedIdentifierAfterIdentifier(
7703 SimpleIdentifier qualifier) {
7704 if (!_matches(TokenType.PERIOD) || _injectGenericCommentTypeList()) {
7705 return qualifier;
7706 }
7707 Token period = getAndAdvance();
7708 SimpleIdentifier qualified = parseSimpleIdentifier();
7709 return new PrefixedIdentifier(qualifier, period, qualified);
7710 }
7711
7712 /**
7713 * Parse a prefixed identifier. Return the prefixed identifier that was
7714 * parsed.
7715 *
7716 * This method assumes that the current token matches an identifier.
7717 *
7718 * prefixedIdentifier ::=
7719 * identifier ('.' identifier)?
7720 */
7721 Identifier _parsePrefixedIdentifierUnchecked() {
7722 return _parsePrefixedIdentifierAfterIdentifier(
7723 _parseSimpleIdentifierUnchecked());
7724 }
7725
7726 /**
7366 * Parse a primary expression. Return the primary expression that was parsed. 7727 * Parse a primary expression. Return the primary expression that was parsed.
7367 * 7728 *
7368 * primary ::= 7729 * primary ::=
7369 * thisExpression 7730 * thisExpression
7370 * | 'super' unconditionalAssignableSelector 7731 * | 'super' unconditionalAssignableSelector
7371 * | functionExpression 7732 * | functionExpression
7372 * | literal 7733 * | literal
7373 * | identifier 7734 * | identifier
7374 * | newExpression 7735 * | newExpression
7375 * | constObjectExpression 7736 * | constObjectExpression
7376 * | '(' expression ')' 7737 * | '(' expression ')'
7377 * | argumentDefinitionTest 7738 * | argumentDefinitionTest
7378 * 7739 *
7379 * literal ::= 7740 * literal ::=
7380 * nullLiteral 7741 * nullLiteral
7381 * | booleanLiteral 7742 * | booleanLiteral
7382 * | numericLiteral 7743 * | numericLiteral
7383 * | stringLiteral 7744 * | stringLiteral
7384 * | symbolLiteral 7745 * | symbolLiteral
7385 * | mapLiteral 7746 * | mapLiteral
7386 * | listLiteral 7747 * | listLiteral
7387 */ 7748 */
7388 Expression _parsePrimaryExpression() { 7749 Expression _parsePrimaryExpression() {
7389 if (_matchesKeyword(Keyword.THIS)) { 7750 if (_matchesIdentifier()) {
7751 // TODO(brianwilkerson) The code below was an attempt to recover from an
7752 // error case, but it needs to be applied as a recovery only after we
7753 // know that parsing it as an identifier doesn't work. Leaving the code as
7754 // a reminder of how to recover.
7755 // if (isFunctionExpression(_peek())) {
7756 // //
7757 // // Function expressions were allowed to have names at one point, but t his is now illegal.
7758 // //
7759 // reportError(ParserErrorCode.NAMED_FUNCTION_EXPRESSION, getAndAdvance() );
7760 // return parseFunctionExpression();
7761 // }
7762 return _parsePrefixedIdentifierUnchecked();
7763 }
7764 TokenType type = _currentToken.type;
7765 if (type == TokenType.STRING) {
7766 return parseStringLiteral();
7767 } else if (type == TokenType.INT) {
7768 Token token = getAndAdvance();
7769 int value = null;
7770 try {
7771 value = int.parse(token.lexeme);
7772 } on FormatException {
7773 // The invalid format should have been reported by the scanner.
7774 }
7775 return new IntegerLiteral(token, value);
7776 }
7777 Keyword keyword = _currentToken.keyword;
7778 if (keyword == Keyword.NULL) {
7779 return new NullLiteral(getAndAdvance());
7780 } else if (keyword == Keyword.NEW) {
7781 return _parseNewExpression();
7782 } else if (keyword == Keyword.THIS) {
7390 return new ThisExpression(getAndAdvance()); 7783 return new ThisExpression(getAndAdvance());
7391 } else if (_matchesKeyword(Keyword.SUPER)) { 7784 } else if (keyword == Keyword.SUPER) {
7392 // TODO(paulberry): verify with Gilad that "super" must be followed by 7785 // TODO(paulberry): verify with Gilad that "super" must be followed by
7393 // unconditionalAssignableSelector in this case. 7786 // unconditionalAssignableSelector in this case.
7394 return _parseAssignableSelector( 7787 return _parseAssignableSelector(
7395 new SuperExpression(getAndAdvance()), false, 7788 new SuperExpression(getAndAdvance()), false,
7396 allowConditional: false); 7789 allowConditional: false);
7397 } else if (_matchesKeyword(Keyword.NULL)) { 7790 } else if (keyword == Keyword.FALSE) {
7398 return new NullLiteral(getAndAdvance());
7399 } else if (_matchesKeyword(Keyword.FALSE)) {
7400 return new BooleanLiteral(getAndAdvance(), false); 7791 return new BooleanLiteral(getAndAdvance(), false);
7401 } else if (_matchesKeyword(Keyword.TRUE)) { 7792 } else if (keyword == Keyword.TRUE) {
7402 return new BooleanLiteral(getAndAdvance(), true); 7793 return new BooleanLiteral(getAndAdvance(), true);
7403 } else if (_matches(TokenType.DOUBLE)) { 7794 }
7795 if (type == TokenType.DOUBLE) {
7404 Token token = getAndAdvance(); 7796 Token token = getAndAdvance();
7405 double value = 0.0; 7797 double value = 0.0;
7406 try { 7798 try {
7407 value = double.parse(token.lexeme); 7799 value = double.parse(token.lexeme);
7408 } on FormatException { 7800 } on FormatException {
7409 // The invalid format should have been reported by the scanner. 7801 // The invalid format should have been reported by the scanner.
7410 } 7802 }
7411 return new DoubleLiteral(token, value); 7803 return new DoubleLiteral(token, value);
7412 } else if (_matches(TokenType.HEXADECIMAL)) { 7804 } else if (type == TokenType.HEXADECIMAL) {
7413 Token token = getAndAdvance(); 7805 Token token = getAndAdvance();
7414 int value = null; 7806 int value = null;
7415 try { 7807 try {
7416 value = int.parse(token.lexeme.substring(2), radix: 16); 7808 value = int.parse(token.lexeme.substring(2), radix: 16);
7417 } on FormatException { 7809 } on FormatException {
7418 // The invalid format should have been reported by the scanner. 7810 // The invalid format should have been reported by the scanner.
7419 } 7811 }
7420 return new IntegerLiteral(token, value); 7812 return new IntegerLiteral(token, value);
7421 } else if (_matches(TokenType.INT)) { 7813 } else if (keyword == Keyword.CONST) {
7422 Token token = getAndAdvance();
7423 int value = null;
7424 try {
7425 value = int.parse(token.lexeme);
7426 } on FormatException {
7427 // The invalid format should have been reported by the scanner.
7428 }
7429 return new IntegerLiteral(token, value);
7430 } else if (_matches(TokenType.STRING)) {
7431 return parseStringLiteral();
7432 } else if (_matchesIdentifier()) {
7433 // TODO(brianwilkerson) The code below was an attempt to recover from an
7434 // error case, but it needs to be applied as a recovery only after we
7435 // know that parsing it as an identifier doesn't work. Leaving the code as
7436 // a reminder of how to recover.
7437 // if (isFunctionExpression(peek())) {
7438 // //
7439 // // Function expressions were allowed to have names at one point, but this is now illegal.
7440 // //
7441 // reportError(ParserErrorCode.NAMED_FUNCTION_EXPRESSION, getAndAdv ance());
7442 // return parseFunctionExpression();
7443 // }
7444 return parsePrefixedIdentifier();
7445 } else if (_matchesKeyword(Keyword.NEW)) {
7446 return _parseNewExpression();
7447 } else if (_matchesKeyword(Keyword.CONST)) {
7448 return _parseConstExpression(); 7814 return _parseConstExpression();
7449 } else if (_matches(TokenType.OPEN_PAREN)) { 7815 } else if (type == TokenType.OPEN_PAREN) {
7450 if (_isFunctionExpression(_currentToken)) { 7816 if (_isFunctionExpression(_currentToken)) {
7451 return parseFunctionExpression(); 7817 return parseFunctionExpression();
7452 } 7818 }
7453 Token leftParenthesis = getAndAdvance(); 7819 Token leftParenthesis = getAndAdvance();
7454 bool wasInInitializer = _inInitializer; 7820 bool wasInInitializer = _inInitializer;
7455 _inInitializer = false; 7821 _inInitializer = false;
7456 try { 7822 try {
7457 Expression expression = parseExpression2(); 7823 Expression expression = parseExpression2();
7458 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); 7824 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
7459 return new ParenthesizedExpression( 7825 return new ParenthesizedExpression(
7460 leftParenthesis, expression, rightParenthesis); 7826 leftParenthesis, expression, rightParenthesis);
7461 } finally { 7827 } finally {
7462 _inInitializer = wasInInitializer; 7828 _inInitializer = wasInInitializer;
7463 } 7829 }
7464 } else if (_matches(TokenType.LT) || _injectGenericCommentTypeList()) { 7830 } else if (type == TokenType.LT || _injectGenericCommentTypeList()) {
7465 return _parseListOrMapLiteral(null); 7831 return _parseListOrMapLiteral(null);
7466 } else if (_matches(TokenType.OPEN_CURLY_BRACKET)) { 7832 } else if (type == TokenType.OPEN_CURLY_BRACKET) {
7467 return _parseMapLiteral(null, null); 7833 return _parseMapLiteral(null, null);
7468 } else if (_matches(TokenType.OPEN_SQUARE_BRACKET) || 7834 } else if (type == TokenType.OPEN_SQUARE_BRACKET ||
7469 _matches(TokenType.INDEX)) { 7835 type == TokenType.INDEX) {
7470 return _parseListLiteral(null, null); 7836 return _parseListLiteral(null, null);
7471 } else if (_matches(TokenType.QUESTION) && 7837 } else if (type == TokenType.QUESTION &&
7472 _tokenMatches(_peek(), TokenType.IDENTIFIER)) { 7838 _tokenMatches(_peek(), TokenType.IDENTIFIER)) {
7473 _reportErrorForCurrentToken( 7839 _reportErrorForCurrentToken(
7474 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]); 7840 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]);
7475 _advance(); 7841 _advance();
7476 return _parsePrimaryExpression(); 7842 return _parsePrimaryExpression();
7477 } else if (_matchesKeyword(Keyword.VOID)) { 7843 } else if (keyword == Keyword.VOID) {
7478 // 7844 //
7479 // Recover from having a return type of "void" where a return type is not 7845 // Recover from having a return type of "void" where a return type is not
7480 // expected. 7846 // expected.
7481 // 7847 //
7482 // TODO(brianwilkerson) Improve this error message. 7848 // TODO(brianwilkerson) Improve this error message.
7483 _reportErrorForCurrentToken( 7849 _reportErrorForCurrentToken(
7484 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]); 7850 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]);
7485 _advance(); 7851 _advance();
7486 return _parsePrimaryExpression(); 7852 return _parsePrimaryExpression();
7487 } else if (_matches(TokenType.HASH)) { 7853 } else if (type == TokenType.HASH) {
7488 return _parseSymbolLiteral(); 7854 return _parseSymbolLiteral();
7489 } else { 7855 } else {
7490 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); 7856 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
7491 return _createSyntheticIdentifier(); 7857 return _createSyntheticIdentifier();
7492 } 7858 }
7493 } 7859 }
7494 7860
7495 /** 7861 /**
7496 * Parse a redirecting constructor invocation. Return the redirecting 7862 * Parse a redirecting constructor invocation. The flag [hasPeriod] should be
7863 * `true` if the `this` is followed by a period. Return the redirecting
7497 * constructor invocation that was parsed. 7864 * constructor invocation that was parsed.
7498 * 7865 *
7866 * This method assumes that the current token matches `Keyword.THIS`.
7867 *
7499 * redirectingConstructorInvocation ::= 7868 * redirectingConstructorInvocation ::=
7500 * 'this' ('.' identifier)? arguments 7869 * 'this' ('.' identifier)? arguments
7501 */ 7870 */
7502 RedirectingConstructorInvocation _parseRedirectingConstructorInvocation() { 7871 RedirectingConstructorInvocation _parseRedirectingConstructorInvocation(
7503 Token keyword = _expectKeyword(Keyword.THIS); 7872 bool hasPeriod) {
7873 Token keyword = getAndAdvance();
7504 Token period = null; 7874 Token period = null;
7505 SimpleIdentifier constructorName = null; 7875 SimpleIdentifier constructorName = null;
7506 if (_matches(TokenType.PERIOD)) { 7876 if (hasPeriod) {
7507 period = getAndAdvance(); 7877 period = getAndAdvance();
7508 constructorName = parseSimpleIdentifier(); 7878 if (_matchesIdentifier()) {
7879 constructorName = _parseSimpleIdentifierUnchecked(isDeclaration: false);
7880 } else {
7881 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
7882 constructorName = _createSyntheticIdentifier(isDeclaration: false);
7883 _advance();
7884 }
7509 } 7885 }
7510 ArgumentList argumentList = parseArgumentList(); 7886 ArgumentList argumentList = _parseArgumentListChecked();
7511 return new RedirectingConstructorInvocation( 7887 return new RedirectingConstructorInvocation(
7512 keyword, period, constructorName, argumentList); 7888 keyword, period, constructorName, argumentList);
7513 } 7889 }
7514 7890
7515 /** 7891 /**
7516 * Parse a relational expression. Return the relational expression that was 7892 * Parse a relational expression. Return the relational expression that was
7517 * parsed. 7893 * parsed.
7518 * 7894 *
7519 * relationalExpression ::= 7895 * relationalExpression ::=
7520 * bitwiseOrExpression ('is' '!'? type | 'as' type | relationalOperato r bitwiseOrExpression)? 7896 * bitwiseOrExpression ('is' '!'? type | 'as' type | relationalOperato r bitwiseOrExpression)?
7521 * | 'super' relationalOperator bitwiseOrExpression 7897 * | 'super' relationalOperator bitwiseOrExpression
7522 */ 7898 */
7523 Expression _parseRelationalExpression() { 7899 Expression _parseRelationalExpression() {
7524 if (_matchesKeyword(Keyword.SUPER) && 7900 if (_currentToken.keyword == Keyword.SUPER &&
7525 _currentToken.next.type.isRelationalOperator) { 7901 _currentToken.next.type.isRelationalOperator) {
7526 Expression expression = new SuperExpression(getAndAdvance()); 7902 Expression expression = new SuperExpression(getAndAdvance());
7527 Token operator = getAndAdvance(); 7903 Token operator = getAndAdvance();
7528 expression = new BinaryExpression( 7904 return new BinaryExpression(
7529 expression, operator, parseBitwiseOrExpression()); 7905 expression, operator, parseBitwiseOrExpression());
7530 return expression;
7531 } 7906 }
7532 Expression expression = parseBitwiseOrExpression(); 7907 Expression expression = parseBitwiseOrExpression();
7533 if (_matchesKeyword(Keyword.AS)) { 7908 Keyword keyword = _currentToken.keyword;
7909 if (keyword == Keyword.AS) {
7534 Token asOperator = getAndAdvance(); 7910 Token asOperator = getAndAdvance();
7535 expression = new AsExpression(expression, asOperator, parseTypeName()); 7911 return new AsExpression(expression, asOperator, parseTypeName());
7536 } else if (_matchesKeyword(Keyword.IS)) { 7912 } else if (keyword == Keyword.IS) {
7537 Token isOperator = getAndAdvance(); 7913 Token isOperator = getAndAdvance();
7538 Token notOperator = null; 7914 Token notOperator = null;
7539 if (_matches(TokenType.BANG)) { 7915 if (_matches(TokenType.BANG)) {
7540 notOperator = getAndAdvance(); 7916 notOperator = getAndAdvance();
7541 } 7917 }
7542 expression = new IsExpression( 7918 return new IsExpression(
7543 expression, isOperator, notOperator, parseTypeName()); 7919 expression, isOperator, notOperator, parseTypeName());
7544 } else if (_currentToken.type.isRelationalOperator) { 7920 } else if (_currentToken.type.isRelationalOperator) {
7545 Token operator = getAndAdvance(); 7921 Token operator = getAndAdvance();
7546 expression = new BinaryExpression( 7922 return new BinaryExpression(
7547 expression, operator, parseBitwiseOrExpression()); 7923 expression, operator, parseBitwiseOrExpression());
7548 } 7924 }
7549 return expression; 7925 return expression;
7550 } 7926 }
7551 7927
7552 /** 7928 /**
7553 * Parse a rethrow expression. Return the rethrow expression that was parsed. 7929 * Parse a rethrow expression. Return the rethrow expression that was parsed.
7554 * 7930 *
7931 * This method assumes that the current token matches `Keyword.RETHROW`.
7932 *
7555 * rethrowExpression ::= 7933 * rethrowExpression ::=
7556 * 'rethrow' 7934 * 'rethrow'
7557 */ 7935 */
7558 Expression _parseRethrowExpression() => 7936 Expression _parseRethrowExpression() =>
7559 new RethrowExpression(_expectKeyword(Keyword.RETHROW)); 7937 new RethrowExpression(getAndAdvance());
7560 7938
7561 /** 7939 /**
7562 * Parse a return statement. Return the return statement that was parsed. 7940 * Parse a return statement. Return the return statement that was parsed.
7563 * 7941 *
7942 * This method assumes that the current token matches `Keyword.RETURN`.
7943 *
7564 * returnStatement ::= 7944 * returnStatement ::=
7565 * 'return' expression? ';' 7945 * 'return' expression? ';'
7566 */ 7946 */
7567 Statement _parseReturnStatement() { 7947 Statement _parseReturnStatement() {
7568 Token returnKeyword = _expectKeyword(Keyword.RETURN); 7948 Token returnKeyword = getAndAdvance();
7569 if (_matches(TokenType.SEMICOLON)) { 7949 if (_matches(TokenType.SEMICOLON)) {
7570 return new ReturnStatement(returnKeyword, null, getAndAdvance()); 7950 return new ReturnStatement(returnKeyword, null, getAndAdvance());
7571 } 7951 }
7572 Expression expression = parseExpression2(); 7952 Expression expression = parseExpression2();
7573 Token semicolon = _expect(TokenType.SEMICOLON); 7953 Token semicolon = _expect(TokenType.SEMICOLON);
7574 return new ReturnStatement(returnKeyword, expression, semicolon); 7954 return new ReturnStatement(returnKeyword, expression, semicolon);
7575 } 7955 }
7576 7956
7577 /** 7957 /**
7578 * Parse a setter. The [commentAndMetadata] is the documentation comment and 7958 * Parse a setter. The [commentAndMetadata] is the documentation comment and
7579 * metadata to be associated with the declaration. The [externalKeyword] is 7959 * metadata to be associated with the declaration. The [externalKeyword] is
7580 * the 'external' token. The [staticKeyword] is the static keyword, or `null` 7960 * the 'external' token. The [staticKeyword] is the static keyword, or `null`
7581 * if the setter is not static. The [returnType] is the return type that has 7961 * if the setter is not static. The [returnType] is the return type that has
7582 * already been parsed, or `null` if there was no return type. Return the 7962 * already been parsed, or `null` if there was no return type. Return the
7583 * setter that was parsed. 7963 * setter that was parsed.
7584 * 7964 *
7965 * This method assumes that the current token matches `Keyword.SET`.
7966 *
7585 * setter ::= 7967 * setter ::=
7586 * setterSignature functionBody? 7968 * setterSignature functionBody?
7587 * 7969 *
7588 * setterSignature ::= 7970 * setterSignature ::=
7589 * 'external'? 'static'? returnType? 'set' identifier formalParameterL ist 7971 * 'external'? 'static'? returnType? 'set' identifier formalParameterL ist
7590 */ 7972 */
7591 MethodDeclaration _parseSetter(CommentAndMetadata commentAndMetadata, 7973 MethodDeclaration _parseSetter(CommentAndMetadata commentAndMetadata,
7592 Token externalKeyword, Token staticKeyword, TypeName returnType) { 7974 Token externalKeyword, Token staticKeyword, TypeName returnType) {
7593 Token propertyKeyword = _expectKeyword(Keyword.SET); 7975 Token propertyKeyword = getAndAdvance();
7594 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true); 7976 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
7595 FormalParameterList parameters = parseFormalParameterList(); 7977 FormalParameterList parameters = parseFormalParameterList();
7596 _validateFormalParameterList(parameters); 7978 _validateFormalParameterList(parameters);
7597 FunctionBody body = _parseFunctionBody( 7979 FunctionBody body = _parseFunctionBody(
7598 externalKeyword != null || staticKeyword == null, 7980 externalKeyword != null || staticKeyword == null,
7599 ParserErrorCode.STATIC_SETTER_WITHOUT_BODY, 7981 ParserErrorCode.STATIC_SETTER_WITHOUT_BODY,
7600 false); 7982 false);
7601 if (externalKeyword != null && body is! EmptyFunctionBody) { 7983 if (externalKeyword != null && body is! EmptyFunctionBody) {
7602 _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_SETTER_WITH_BODY); 7984 _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_SETTER_WITH_BODY);
7603 } 7985 }
(...skipping 13 matching lines...) Expand all
7617 7999
7618 /** 8000 /**
7619 * Parse a shift expression. Return the shift expression that was parsed. 8001 * Parse a shift expression. Return the shift expression that was parsed.
7620 * 8002 *
7621 * shiftExpression ::= 8003 * shiftExpression ::=
7622 * additiveExpression (shiftOperator additiveExpression)* 8004 * additiveExpression (shiftOperator additiveExpression)*
7623 * | 'super' (shiftOperator additiveExpression)+ 8005 * | 'super' (shiftOperator additiveExpression)+
7624 */ 8006 */
7625 Expression _parseShiftExpression() { 8007 Expression _parseShiftExpression() {
7626 Expression expression; 8008 Expression expression;
7627 if (_matchesKeyword(Keyword.SUPER) && 8009 if (_currentToken.keyword == Keyword.SUPER &&
7628 _currentToken.next.type.isShiftOperator) { 8010 _currentToken.next.type.isShiftOperator) {
7629 expression = new SuperExpression(getAndAdvance()); 8011 expression = new SuperExpression(getAndAdvance());
7630 } else { 8012 } else {
7631 expression = _parseAdditiveExpression(); 8013 expression = _parseAdditiveExpression();
7632 } 8014 }
7633 while (_currentToken.type.isShiftOperator) { 8015 while (_currentToken.type.isShiftOperator) {
7634 Token operator = getAndAdvance();
7635 expression = new BinaryExpression( 8016 expression = new BinaryExpression(
7636 expression, operator, _parseAdditiveExpression()); 8017 expression, getAndAdvance(), _parseAdditiveExpression());
7637 } 8018 }
7638 return expression; 8019 return expression;
7639 } 8020 }
7640 8021
7641 /** 8022 /**
8023 * Parse a simple identifier. Return the simple identifier that was parsed.
8024 *
8025 * This method assumes that the current token matches an identifier.
8026 *
8027 * identifier ::=
8028 * IDENTIFIER
8029 */
8030 SimpleIdentifier _parseSimpleIdentifierUnchecked(
8031 {bool isDeclaration: false}) {
8032 String lexeme = _currentToken.lexeme;
8033 if ((_inAsync || _inGenerator) &&
8034 (lexeme == ASYNC || lexeme == _AWAIT || lexeme == _YIELD)) {
8035 _reportErrorForCurrentToken(
8036 ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER);
8037 }
8038 return new SimpleIdentifier(getAndAdvance(), isDeclaration: isDeclaration);
8039 }
8040
8041 /**
7642 * Parse a list of statements within a switch statement. Return the statements 8042 * Parse a list of statements within a switch statement. Return the statements
7643 * that were parsed. 8043 * that were parsed.
7644 * 8044 *
7645 * statements ::= 8045 * statements ::=
7646 * statement* 8046 * statement*
7647 */ 8047 */
7648 List<Statement> _parseStatementList() { 8048 List<Statement> _parseStatementList() {
7649 List<Statement> statements = new List<Statement>(); 8049 List<Statement> statements = <Statement>[];
7650 Token statementStart = _currentToken; 8050 Token statementStart = _currentToken;
7651 while (!_matches(TokenType.EOF) && 8051 TokenType type = _currentToken.type;
7652 !_matches(TokenType.CLOSE_CURLY_BRACKET) && 8052 while (type != TokenType.EOF &&
8053 type != TokenType.CLOSE_CURLY_BRACKET &&
7653 !_isSwitchMember()) { 8054 !_isSwitchMember()) {
7654 statements.add(parseStatement2()); 8055 statements.add(parseStatement2());
7655 if (identical(_currentToken, statementStart)) { 8056 if (identical(_currentToken, statementStart)) {
7656 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, 8057 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
7657 [_currentToken.lexeme]); 8058 [_currentToken.lexeme]);
7658 _advance(); 8059 _advance();
7659 } 8060 }
7660 statementStart = _currentToken; 8061 statementStart = _currentToken;
8062 type = _currentToken.type;
7661 } 8063 }
7662 return statements; 8064 return statements;
7663 } 8065 }
7664 8066
7665 /** 8067 /**
7666 * Parse a string literal that contains interpolations. Return the string 8068 * Parse a string literal that contains interpolations. Return the string
7667 * literal that was parsed. 8069 * literal that was parsed.
8070 *
8071 * This method assumes that the current token matches either
8072 * [TokenType.STRING_INTERPOLATION_EXPRESSION] or
8073 * [TokenType.STRING_INTERPOLATION_IDENTIFIER].
7668 */ 8074 */
7669 StringInterpolation _parseStringInterpolation(Token string) { 8075 StringInterpolation _parseStringInterpolation(Token string) {
7670 List<InterpolationElement> elements = new List<InterpolationElement>(); 8076 List<InterpolationElement> elements = <InterpolationElement>[
7671 bool hasMore = _matches(TokenType.STRING_INTERPOLATION_EXPRESSION) || 8077 new InterpolationString(
7672 _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER); 8078 string, _computeStringValue(string.lexeme, true, false))
7673 elements.add(new InterpolationString( 8079 ];
7674 string, _computeStringValue(string.lexeme, true, !hasMore))); 8080 bool hasMore = true;
8081 bool isExpression = _matches(TokenType.STRING_INTERPOLATION_EXPRESSION);
7675 while (hasMore) { 8082 while (hasMore) {
7676 if (_matches(TokenType.STRING_INTERPOLATION_EXPRESSION)) { 8083 if (isExpression) {
7677 Token openToken = getAndAdvance(); 8084 Token openToken = getAndAdvance();
7678 bool wasInInitializer = _inInitializer; 8085 bool wasInInitializer = _inInitializer;
7679 _inInitializer = false; 8086 _inInitializer = false;
7680 try { 8087 try {
7681 Expression expression = parseExpression2(); 8088 Expression expression = parseExpression2();
7682 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET); 8089 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
7683 elements.add( 8090 elements.add(
7684 new InterpolationExpression(openToken, expression, rightBracket)); 8091 new InterpolationExpression(openToken, expression, rightBracket));
7685 } finally { 8092 } finally {
7686 _inInitializer = wasInInitializer; 8093 _inInitializer = wasInInitializer;
7687 } 8094 }
7688 } else { 8095 } else {
7689 Token openToken = getAndAdvance(); 8096 Token openToken = getAndAdvance();
7690 Expression expression = null; 8097 Expression expression = null;
7691 if (_matchesKeyword(Keyword.THIS)) { 8098 if (_matchesKeyword(Keyword.THIS)) {
7692 expression = new ThisExpression(getAndAdvance()); 8099 expression = new ThisExpression(getAndAdvance());
7693 } else { 8100 } else {
7694 expression = parseSimpleIdentifier(); 8101 expression = parseSimpleIdentifier();
7695 } 8102 }
7696 elements.add(new InterpolationExpression(openToken, expression, null)); 8103 elements.add(new InterpolationExpression(openToken, expression, null));
7697 } 8104 }
7698 if (_matches(TokenType.STRING)) { 8105 if (_matches(TokenType.STRING)) {
7699 string = getAndAdvance(); 8106 string = getAndAdvance();
7700 hasMore = _matches(TokenType.STRING_INTERPOLATION_EXPRESSION) || 8107 isExpression = _matches(TokenType.STRING_INTERPOLATION_EXPRESSION);
7701 _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER); 8108 hasMore =
8109 isExpression || _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER);
7702 elements.add(new InterpolationString( 8110 elements.add(new InterpolationString(
7703 string, _computeStringValue(string.lexeme, false, !hasMore))); 8111 string, _computeStringValue(string.lexeme, false, !hasMore)));
7704 } else { 8112 } else {
7705 hasMore = false; 8113 hasMore = false;
7706 } 8114 }
7707 } 8115 }
7708 return new StringInterpolation(elements); 8116 return new StringInterpolation(elements);
7709 } 8117 }
7710 8118
7711 /** 8119 /**
8120 * Parse a string literal. Return the string literal that was parsed.
8121 *
8122 * This method assumes that the current token matches `TokenType.STRING`.
8123 *
8124 * stringLiteral ::=
8125 * MULTI_LINE_STRING+
8126 * | SINGLE_LINE_STRING+
8127 */
8128 StringLiteral _parseStringLiteralUnchecked() {
8129 List<StringLiteral> strings = <StringLiteral>[];
8130 do {
8131 Token string = getAndAdvance();
8132 if (_matches(TokenType.STRING_INTERPOLATION_EXPRESSION) ||
8133 _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER)) {
8134 strings.add(_parseStringInterpolation(string));
8135 } else {
8136 strings.add(new SimpleStringLiteral(
8137 string, _computeStringValue(string.lexeme, true, true)));
8138 }
8139 } while (_matches(TokenType.STRING));
8140 return strings.length == 1 ? strings[0] : new AdjacentStrings(strings);
8141 }
8142
8143 /**
7712 * Parse a super constructor invocation. Return the super constructor 8144 * Parse a super constructor invocation. Return the super constructor
7713 * invocation that was parsed. 8145 * invocation that was parsed.
7714 * 8146 *
8147 * This method assumes that the current token matches [Keyword.SUPER].
8148 *
7715 * superConstructorInvocation ::= 8149 * superConstructorInvocation ::=
7716 * 'super' ('.' identifier)? arguments 8150 * 'super' ('.' identifier)? arguments
7717 */ 8151 */
7718 SuperConstructorInvocation _parseSuperConstructorInvocation() { 8152 SuperConstructorInvocation _parseSuperConstructorInvocation() {
7719 Token keyword = _expectKeyword(Keyword.SUPER); 8153 Token keyword = getAndAdvance();
7720 Token period = null; 8154 Token period = null;
7721 SimpleIdentifier constructorName = null; 8155 SimpleIdentifier constructorName = null;
7722 if (_matches(TokenType.PERIOD)) { 8156 if (_matches(TokenType.PERIOD)) {
7723 period = getAndAdvance(); 8157 period = getAndAdvance();
7724 constructorName = parseSimpleIdentifier(); 8158 constructorName = parseSimpleIdentifier();
7725 } 8159 }
7726 ArgumentList argumentList = parseArgumentList(); 8160 ArgumentList argumentList = _parseArgumentListChecked();
7727 return new SuperConstructorInvocation( 8161 return new SuperConstructorInvocation(
7728 keyword, period, constructorName, argumentList); 8162 keyword, period, constructorName, argumentList);
7729 } 8163 }
7730 8164
7731 /** 8165 /**
7732 * Parse a switch statement. Return the switch statement that was parsed. 8166 * Parse a switch statement. Return the switch statement that was parsed.
7733 * 8167 *
7734 * switchStatement ::= 8168 * switchStatement ::=
7735 * 'switch' '(' expression ')' '{' switchCase* defaultCase? '}' 8169 * 'switch' '(' expression ')' '{' switchCase* defaultCase? '}'
7736 * 8170 *
7737 * switchCase ::= 8171 * switchCase ::=
7738 * label* ('case' expression ':') statements 8172 * label* ('case' expression ':') statements
7739 * 8173 *
7740 * defaultCase ::= 8174 * defaultCase ::=
7741 * label* 'default' ':' statements 8175 * label* 'default' ':' statements
7742 */ 8176 */
7743 SwitchStatement _parseSwitchStatement() { 8177 SwitchStatement _parseSwitchStatement() {
7744 bool wasInSwitch = _inSwitch; 8178 bool wasInSwitch = _inSwitch;
7745 _inSwitch = true; 8179 _inSwitch = true;
7746 try { 8180 try {
7747 HashSet<String> definedLabels = new HashSet<String>(); 8181 HashSet<String> definedLabels = new HashSet<String>();
7748 Token keyword = _expectKeyword(Keyword.SWITCH); 8182 Token keyword = _expectKeyword(Keyword.SWITCH);
7749 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); 8183 Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
7750 Expression expression = parseExpression2(); 8184 Expression expression = parseExpression2();
7751 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); 8185 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
7752 Token leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET); 8186 Token leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET);
7753 Token defaultKeyword = null; 8187 Token defaultKeyword = null;
7754 List<SwitchMember> members = new List<SwitchMember>(); 8188 List<SwitchMember> members = <SwitchMember>[];
7755 while (!_matches(TokenType.EOF) && 8189 TokenType type = _currentToken.type;
7756 !_matches(TokenType.CLOSE_CURLY_BRACKET)) { 8190 while (type != TokenType.EOF && type != TokenType.CLOSE_CURLY_BRACKET) {
7757 List<Label> labels = new List<Label>(); 8191 List<Label> labels = <Label>[];
7758 while ( 8192 while (
7759 _matchesIdentifier() && _tokenMatches(_peek(), TokenType.COLON)) { 8193 _matchesIdentifier() && _tokenMatches(_peek(), TokenType.COLON)) {
7760 SimpleIdentifier identifier = 8194 SimpleIdentifier identifier =
7761 parseSimpleIdentifier(isDeclaration: true); 8195 _parseSimpleIdentifierUnchecked(isDeclaration: true);
7762 String label = identifier.token.lexeme; 8196 String label = identifier.token.lexeme;
7763 if (definedLabels.contains(label)) { 8197 if (definedLabels.contains(label)) {
7764 _reportErrorForToken( 8198 _reportErrorForToken(
7765 ParserErrorCode.DUPLICATE_LABEL_IN_SWITCH_STATEMENT, 8199 ParserErrorCode.DUPLICATE_LABEL_IN_SWITCH_STATEMENT,
7766 identifier.token, 8200 identifier.token,
7767 [label]); 8201 [label]);
7768 } else { 8202 } else {
7769 definedLabels.add(label); 8203 definedLabels.add(label);
7770 } 8204 }
7771 Token colon = _expect(TokenType.COLON); 8205 Token colon = getAndAdvance();
7772 labels.add(new Label(identifier, colon)); 8206 labels.add(new Label(identifier, colon));
7773 } 8207 }
7774 if (_matchesKeyword(Keyword.CASE)) { 8208 Keyword keyword = _currentToken.keyword;
8209 if (keyword == Keyword.CASE) {
7775 Token caseKeyword = getAndAdvance(); 8210 Token caseKeyword = getAndAdvance();
7776 Expression caseExpression = parseExpression2(); 8211 Expression caseExpression = parseExpression2();
7777 Token colon = _expect(TokenType.COLON); 8212 Token colon = _expect(TokenType.COLON);
7778 members.add(new SwitchCase(labels, caseKeyword, caseExpression, colon, 8213 members.add(new SwitchCase(labels, caseKeyword, caseExpression, colon,
7779 _parseStatementList())); 8214 _parseStatementList()));
7780 if (defaultKeyword != null) { 8215 if (defaultKeyword != null) {
7781 _reportErrorForToken( 8216 _reportErrorForToken(
7782 ParserErrorCode.SWITCH_HAS_CASE_AFTER_DEFAULT_CASE, 8217 ParserErrorCode.SWITCH_HAS_CASE_AFTER_DEFAULT_CASE,
7783 caseKeyword); 8218 caseKeyword);
7784 } 8219 }
7785 } else if (_matchesKeyword(Keyword.DEFAULT)) { 8220 } else if (keyword == Keyword.DEFAULT) {
7786 if (defaultKeyword != null) { 8221 if (defaultKeyword != null) {
7787 _reportErrorForToken( 8222 _reportErrorForToken(
7788 ParserErrorCode.SWITCH_HAS_MULTIPLE_DEFAULT_CASES, _peek()); 8223 ParserErrorCode.SWITCH_HAS_MULTIPLE_DEFAULT_CASES, _peek());
7789 } 8224 }
7790 defaultKeyword = getAndAdvance(); 8225 defaultKeyword = getAndAdvance();
7791 Token colon = _expect(TokenType.COLON); 8226 Token colon = _expect(TokenType.COLON);
7792 members.add(new SwitchDefault( 8227 members.add(new SwitchDefault(
7793 labels, defaultKeyword, colon, _parseStatementList())); 8228 labels, defaultKeyword, colon, _parseStatementList()));
7794 } else { 8229 } else {
7795 // We need to advance, otherwise we could end up in an infinite loop, 8230 // We need to advance, otherwise we could end up in an infinite loop,
7796 // but this could be a lot smarter about recovering from the error. 8231 // but this could be a lot smarter about recovering from the error.
7797 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_CASE_OR_DEFAULT); 8232 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_CASE_OR_DEFAULT);
7798 while (!_matches(TokenType.EOF) && 8233 bool atEndOrNextMember() {
7799 !_matches(TokenType.CLOSE_CURLY_BRACKET) && 8234 TokenType type = _currentToken.type;
7800 !_matchesKeyword(Keyword.CASE) && 8235 if (type == TokenType.EOF ||
7801 !_matchesKeyword(Keyword.DEFAULT)) { 8236 type == TokenType.CLOSE_CURLY_BRACKET) {
8237 return true;
8238 }
8239 Keyword keyword = _currentToken.keyword;
8240 return keyword == Keyword.CASE || keyword == Keyword.DEFAULT;
8241 }
8242 while (!atEndOrNextMember()) {
7802 _advance(); 8243 _advance();
7803 } 8244 }
7804 } 8245 }
8246 type = _currentToken.type;
7805 } 8247 }
7806 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET); 8248 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
7807 return new SwitchStatement(keyword, leftParenthesis, expression, 8249 return new SwitchStatement(keyword, leftParenthesis, expression,
7808 rightParenthesis, leftBracket, members, rightBracket); 8250 rightParenthesis, leftBracket, members, rightBracket);
7809 } finally { 8251 } finally {
7810 _inSwitch = wasInSwitch; 8252 _inSwitch = wasInSwitch;
7811 } 8253 }
7812 } 8254 }
7813 8255
7814 /** 8256 /**
7815 * Parse a symbol literal. Return the symbol literal that was parsed. 8257 * Parse a symbol literal. Return the symbol literal that was parsed.
7816 * 8258 *
8259 * This method assumes that the current token matches [TokenType.HASH].
8260 *
7817 * symbolLiteral ::= 8261 * symbolLiteral ::=
7818 * '#' identifier ('.' identifier)* 8262 * '#' identifier ('.' identifier)*
7819 */ 8263 */
7820 SymbolLiteral _parseSymbolLiteral() { 8264 SymbolLiteral _parseSymbolLiteral() {
7821 Token poundSign = getAndAdvance(); 8265 Token poundSign = getAndAdvance();
7822 List<Token> components = new List<Token>(); 8266 List<Token> components = <Token>[];
7823 if (_matchesIdentifier()) { 8267 if (_matchesIdentifier()) {
7824 components.add(getAndAdvance()); 8268 components.add(getAndAdvance());
7825 while (_matches(TokenType.PERIOD)) { 8269 while (_optional(TokenType.PERIOD)) {
7826 _advance();
7827 if (_matchesIdentifier()) { 8270 if (_matchesIdentifier()) {
7828 components.add(getAndAdvance()); 8271 components.add(getAndAdvance());
7829 } else { 8272 } else {
7830 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); 8273 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
7831 components.add(_createSyntheticToken(TokenType.IDENTIFIER)); 8274 components.add(_createSyntheticToken(TokenType.IDENTIFIER));
7832 break; 8275 break;
7833 } 8276 }
7834 } 8277 }
7835 } else if (_currentToken.isOperator) { 8278 } else if (_currentToken.isOperator) {
7836 components.add(getAndAdvance()); 8279 components.add(getAndAdvance());
7837 } else if (_tokenMatchesKeyword(_currentToken, Keyword.VOID)) { 8280 } else if (_matchesKeyword(Keyword.VOID)) {
7838 components.add(getAndAdvance()); 8281 components.add(getAndAdvance());
7839 } else { 8282 } else {
7840 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); 8283 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
7841 components.add(_createSyntheticToken(TokenType.IDENTIFIER)); 8284 components.add(_createSyntheticToken(TokenType.IDENTIFIER));
7842 } 8285 }
7843 return new SymbolLiteral(poundSign, components); 8286 return new SymbolLiteral(poundSign, components);
7844 } 8287 }
7845 8288
7846 /** 8289 /**
7847 * Parse a throw expression. Return the throw expression that was parsed. 8290 * Parse a throw expression. Return the throw expression that was parsed.
7848 * 8291 *
8292 * This method assumes that the current token matches [Keyword.THROW].
8293 *
7849 * throwExpression ::= 8294 * throwExpression ::=
7850 * 'throw' expression 8295 * 'throw' expression
7851 */ 8296 */
7852 Expression _parseThrowExpression() { 8297 Expression _parseThrowExpression() {
7853 Token keyword = _expectKeyword(Keyword.THROW); 8298 Token keyword = getAndAdvance();
7854 if (_matches(TokenType.SEMICOLON) || _matches(TokenType.CLOSE_PAREN)) { 8299 TokenType type = _currentToken.type;
8300 if (type == TokenType.SEMICOLON || type == TokenType.CLOSE_PAREN) {
7855 _reportErrorForToken( 8301 _reportErrorForToken(
7856 ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken); 8302 ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken);
7857 return new ThrowExpression(keyword, _createSyntheticIdentifier()); 8303 return new ThrowExpression(keyword, _createSyntheticIdentifier());
7858 } 8304 }
7859 Expression expression = parseExpression2(); 8305 Expression expression = parseExpression2();
7860 return new ThrowExpression(keyword, expression); 8306 return new ThrowExpression(keyword, expression);
7861 } 8307 }
7862 8308
7863 /** 8309 /**
7864 * Parse a throw expression. Return the throw expression that was parsed. 8310 * Parse a throw expression. Return the throw expression that was parsed.
7865 * 8311 *
8312 * This method assumes that the current token matches [Keyword.THROW].
8313 *
7866 * throwExpressionWithoutCascade ::= 8314 * throwExpressionWithoutCascade ::=
7867 * 'throw' expressionWithoutCascade 8315 * 'throw' expressionWithoutCascade
7868 */ 8316 */
7869 Expression _parseThrowExpressionWithoutCascade() { 8317 Expression _parseThrowExpressionWithoutCascade() {
7870 Token keyword = _expectKeyword(Keyword.THROW); 8318 Token keyword = getAndAdvance();
7871 if (_matches(TokenType.SEMICOLON) || _matches(TokenType.CLOSE_PAREN)) { 8319 TokenType type = _currentToken.type;
8320 if (type == TokenType.SEMICOLON || type == TokenType.CLOSE_PAREN) {
7872 _reportErrorForToken( 8321 _reportErrorForToken(
7873 ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken); 8322 ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken);
7874 return new ThrowExpression(keyword, _createSyntheticIdentifier()); 8323 return new ThrowExpression(keyword, _createSyntheticIdentifier());
7875 } 8324 }
7876 Expression expression = parseExpressionWithoutCascade(); 8325 Expression expression = parseExpressionWithoutCascade();
7877 return new ThrowExpression(keyword, expression); 8326 return new ThrowExpression(keyword, expression);
7878 } 8327 }
7879 8328
7880 /** 8329 /**
7881 * Parse a try statement. Return the try statement that was parsed. 8330 * Parse a try statement. Return the try statement that was parsed.
7882 * 8331 *
8332 * This method assumes that the current token matches [Keyword.TRY].
8333 *
7883 * tryStatement ::= 8334 * tryStatement ::=
7884 * 'try' block (onPart+ finallyPart? | finallyPart) 8335 * 'try' block (onPart+ finallyPart? | finallyPart)
7885 * 8336 *
7886 * onPart ::= 8337 * onPart ::=
7887 * catchPart block 8338 * catchPart block
7888 * | 'on' type catchPart? block 8339 * | 'on' type catchPart? block
7889 * 8340 *
7890 * catchPart ::= 8341 * catchPart ::=
7891 * 'catch' '(' identifier (',' identifier)? ')' 8342 * 'catch' '(' identifier (',' identifier)? ')'
7892 * 8343 *
7893 * finallyPart ::= 8344 * finallyPart ::=
7894 * 'finally' block 8345 * 'finally' block
7895 */ 8346 */
7896 Statement _parseTryStatement() { 8347 Statement _parseTryStatement() {
7897 Token tryKeyword = _expectKeyword(Keyword.TRY); 8348 Token tryKeyword = getAndAdvance();
7898 Block body = parseBlock(); 8349 Block body = _parseBlockChecked();
7899 List<CatchClause> catchClauses = new List<CatchClause>(); 8350 List<CatchClause> catchClauses = <CatchClause>[];
7900 Block finallyClause = null; 8351 Block finallyClause = null;
7901 while (_matchesString(_ON) || _matchesKeyword(Keyword.CATCH)) { 8352 while (_matchesString(_ON) || _matchesKeyword(Keyword.CATCH)) {
7902 Token onKeyword = null; 8353 Token onKeyword = null;
7903 TypeName exceptionType = null; 8354 TypeName exceptionType = null;
7904 if (_matchesString(_ON)) { 8355 if (_matchesString(_ON)) {
7905 onKeyword = getAndAdvance(); 8356 onKeyword = getAndAdvance();
7906 exceptionType = parseTypeName(); 8357 exceptionType = parseTypeName();
7907 } 8358 }
7908 Token catchKeyword = null; 8359 Token catchKeyword = null;
7909 Token leftParenthesis = null; 8360 Token leftParenthesis = null;
7910 SimpleIdentifier exceptionParameter = null; 8361 SimpleIdentifier exceptionParameter = null;
7911 Token comma = null; 8362 Token comma = null;
7912 SimpleIdentifier stackTraceParameter = null; 8363 SimpleIdentifier stackTraceParameter = null;
7913 Token rightParenthesis = null; 8364 Token rightParenthesis = null;
7914 if (_matchesKeyword(Keyword.CATCH)) { 8365 if (_matchesKeyword(Keyword.CATCH)) {
7915 catchKeyword = getAndAdvance(); 8366 catchKeyword = getAndAdvance();
7916 leftParenthesis = _expect(TokenType.OPEN_PAREN); 8367 leftParenthesis = _expect(TokenType.OPEN_PAREN);
7917 exceptionParameter = parseSimpleIdentifier(isDeclaration: true); 8368 exceptionParameter = parseSimpleIdentifier(isDeclaration: true);
7918 if (_matches(TokenType.COMMA)) { 8369 if (_matches(TokenType.COMMA)) {
7919 comma = getAndAdvance(); 8370 comma = getAndAdvance();
7920 stackTraceParameter = parseSimpleIdentifier(isDeclaration: true); 8371 stackTraceParameter = parseSimpleIdentifier(isDeclaration: true);
7921 } 8372 }
7922 rightParenthesis = _expect(TokenType.CLOSE_PAREN); 8373 rightParenthesis = _expect(TokenType.CLOSE_PAREN);
7923 } 8374 }
7924 Block catchBody = parseBlock(); 8375 Block catchBody = _parseBlockChecked();
7925 catchClauses.add(new CatchClause( 8376 catchClauses.add(new CatchClause(
7926 onKeyword, 8377 onKeyword,
7927 exceptionType, 8378 exceptionType,
7928 catchKeyword, 8379 catchKeyword,
7929 leftParenthesis, 8380 leftParenthesis,
7930 exceptionParameter, 8381 exceptionParameter,
7931 comma, 8382 comma,
7932 stackTraceParameter, 8383 stackTraceParameter,
7933 rightParenthesis, 8384 rightParenthesis,
7934 catchBody)); 8385 catchBody));
7935 } 8386 }
7936 Token finallyKeyword = null; 8387 Token finallyKeyword = null;
7937 if (_matchesKeyword(Keyword.FINALLY)) { 8388 if (_matchesKeyword(Keyword.FINALLY)) {
7938 finallyKeyword = getAndAdvance(); 8389 finallyKeyword = getAndAdvance();
7939 finallyClause = parseBlock(); 8390 finallyClause = _parseBlockChecked();
7940 } else { 8391 } else if (catchClauses.isEmpty) {
7941 if (catchClauses.isEmpty) { 8392 _reportErrorForCurrentToken(ParserErrorCode.MISSING_CATCH_OR_FINALLY);
7942 _reportErrorForCurrentToken(ParserErrorCode.MISSING_CATCH_OR_FINALLY);
7943 }
7944 } 8393 }
7945 return new TryStatement( 8394 return new TryStatement(
7946 tryKeyword, body, catchClauses, finallyKeyword, finallyClause); 8395 tryKeyword, body, catchClauses, finallyKeyword, finallyClause);
7947 } 8396 }
7948 8397
7949 /** 8398 /**
7950 * Parse a type alias. The [commentAndMetadata] is the metadata to be 8399 * Parse a type alias. The [commentAndMetadata] is the metadata to be
7951 * associated with the member. Return the type alias that was parsed. 8400 * associated with the member. Return the type alias that was parsed.
7952 * 8401 *
8402 * This method assumes that the current token matches [Keyword.TYPEDEF].
8403 *
7953 * typeAlias ::= 8404 * typeAlias ::=
7954 * 'typedef' typeAliasBody 8405 * 'typedef' typeAliasBody
7955 * 8406 *
7956 * typeAliasBody ::= 8407 * typeAliasBody ::=
7957 * classTypeAlias 8408 * classTypeAlias
7958 * | functionTypeAlias 8409 * | functionTypeAlias
7959 * 8410 *
7960 * classTypeAlias ::= 8411 * classTypeAlias ::=
7961 * identifier typeParameters? '=' 'abstract'? mixinApplication 8412 * identifier typeParameters? '=' 'abstract'? mixinApplication
7962 * 8413 *
7963 * mixinApplication ::= 8414 * mixinApplication ::=
7964 * qualified withClause implementsClause? ';' 8415 * qualified withClause implementsClause? ';'
7965 * 8416 *
7966 * functionTypeAlias ::= 8417 * functionTypeAlias ::=
7967 * functionPrefix typeParameterList? formalParameterList ';' 8418 * functionPrefix typeParameterList? formalParameterList ';'
7968 * 8419 *
7969 * functionPrefix ::= 8420 * functionPrefix ::=
7970 * returnType? name 8421 * returnType? name
7971 */ 8422 */
7972 TypeAlias _parseTypeAlias(CommentAndMetadata commentAndMetadata) { 8423 TypeAlias _parseTypeAlias(CommentAndMetadata commentAndMetadata) {
7973 Token keyword = _expectKeyword(Keyword.TYPEDEF); 8424 Token keyword = getAndAdvance();
7974 if (_matchesIdentifier()) { 8425 if (_matchesIdentifier()) {
7975 Token next = _peek(); 8426 Token next = _peek();
7976 if (_tokenMatches(next, TokenType.LT)) { 8427 if (_tokenMatches(next, TokenType.LT)) {
7977 next = _skipTypeParameterList(next); 8428 next = _skipTypeParameterList(next);
7978 if (next != null && _tokenMatches(next, TokenType.EQ)) { 8429 if (next != null && _tokenMatches(next, TokenType.EQ)) {
7979 TypeAlias typeAlias = 8430 TypeAlias typeAlias =
7980 _parseClassTypeAlias(commentAndMetadata, null, keyword); 8431 _parseClassTypeAlias(commentAndMetadata, null, keyword);
7981 _reportErrorForToken( 8432 _reportErrorForToken(
7982 ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword); 8433 ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword);
7983 return typeAlias; 8434 return typeAlias;
7984 } 8435 }
7985 } else if (_tokenMatches(next, TokenType.EQ)) { 8436 } else if (_tokenMatches(next, TokenType.EQ)) {
7986 TypeAlias typeAlias = 8437 TypeAlias typeAlias =
7987 _parseClassTypeAlias(commentAndMetadata, null, keyword); 8438 _parseClassTypeAlias(commentAndMetadata, null, keyword);
7988 _reportErrorForToken( 8439 _reportErrorForToken(
7989 ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword); 8440 ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword);
7990 return typeAlias; 8441 return typeAlias;
7991 } 8442 }
7992 } 8443 }
7993 return _parseFunctionTypeAlias(commentAndMetadata, keyword); 8444 return _parseFunctionTypeAlias(commentAndMetadata, keyword);
7994 } 8445 }
7995 8446
7996 TypeName _parseTypeName() { 8447 TypeName _parseTypeName() {
7997 Identifier typeName; 8448 Identifier typeName;
7998 if (_matchesKeyword(Keyword.VAR)) { 8449 if (_matchesIdentifier()) {
8450 typeName = _parsePrefixedIdentifierUnchecked();
8451 } else if (_matchesKeyword(Keyword.VAR)) {
7999 _reportErrorForCurrentToken(ParserErrorCode.VAR_AS_TYPE_NAME); 8452 _reportErrorForCurrentToken(ParserErrorCode.VAR_AS_TYPE_NAME);
8000 typeName = new SimpleIdentifier(getAndAdvance()); 8453 typeName = new SimpleIdentifier(getAndAdvance());
8001 } else if (_matchesIdentifier()) {
8002 typeName = parsePrefixedIdentifier();
8003 } else { 8454 } else {
8004 typeName = _createSyntheticIdentifier(); 8455 typeName = _createSyntheticIdentifier();
8005 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TYPE_NAME); 8456 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TYPE_NAME);
8006 } 8457 }
8007 TypeArgumentList typeArguments = _parseOptionalTypeArguments(); 8458 TypeArgumentList typeArguments = _parseOptionalTypeArguments();
8008 return new TypeName(typeName, typeArguments); 8459 return new TypeName(typeName, typeArguments);
8009 } 8460 }
8010 8461
8011 /** 8462 /**
8463 * Parse a type name. Return the type name that was parsed.
8464 *
8465 * This method assumes that the current token is an identifier.
8466 *
8467 * type ::=
8468 * qualified typeArguments?
8469 */
8470 TypeName _parseTypeNameAfterIdentifier() {
8471 Identifier typeName = _parsePrefixedIdentifierUnchecked();
8472 TypeArgumentList typeArguments = _parseOptionalTypeArguments();
8473 // If this is followed by a generic method type comment, allow the comment
8474 // type to replace the real type name.
8475 // TODO(jmesserly): this feels like a big hammer. Can we restrict it to
8476 // only work inside generic methods?
8477 TypeName typeFromComment = _parseOptionalTypeNameComment();
8478 return typeFromComment ?? new TypeName(typeName, typeArguments);
8479 }
8480
8481 /**
8012 * Parse a unary expression. Return the unary expression that was parsed. 8482 * Parse a unary expression. Return the unary expression that was parsed.
8013 * 8483 *
8014 * unaryExpression ::= 8484 * unaryExpression ::=
8015 * prefixOperator unaryExpression 8485 * prefixOperator unaryExpression
8016 * | awaitExpression 8486 * | awaitExpression
8017 * | postfixExpression 8487 * | postfixExpression
8018 * | unaryOperator 'super' 8488 * | unaryOperator 'super'
8019 * | '-' 'super' 8489 * | '-' 'super'
8020 * | incrementOperator assignableExpression 8490 * | incrementOperator assignableExpression
8021 */ 8491 */
8022 Expression _parseUnaryExpression() { 8492 Expression _parseUnaryExpression() {
8023 if (_matches(TokenType.MINUS) || 8493 TokenType type = _currentToken.type;
8024 _matches(TokenType.BANG) || 8494 if (type == TokenType.MINUS ||
8025 _matches(TokenType.TILDE)) { 8495 type == TokenType.BANG ||
8496 type == TokenType.TILDE) {
8026 Token operator = getAndAdvance(); 8497 Token operator = getAndAdvance();
8027 if (_matchesKeyword(Keyword.SUPER)) { 8498 if (_matchesKeyword(Keyword.SUPER)) {
8028 if (_tokenMatches(_peek(), TokenType.OPEN_SQUARE_BRACKET) || 8499 TokenType nextType = _peek().type;
8029 _tokenMatches(_peek(), TokenType.PERIOD)) { 8500 if (nextType == TokenType.OPEN_SQUARE_BRACKET ||
8501 nextType == TokenType.PERIOD) {
8030 // "prefixOperator unaryExpression" 8502 // "prefixOperator unaryExpression"
8031 // --> "prefixOperator postfixExpression" 8503 // --> "prefixOperator postfixExpression"
8032 // --> "prefixOperator primary selector*" 8504 // --> "prefixOperator primary selector*"
8033 // --> "prefixOperator 'super' assignableSelector selector*" 8505 // --> "prefixOperator 'super' assignableSelector selector*"
8034 return new PrefixExpression(operator, _parseUnaryExpression()); 8506 return new PrefixExpression(operator, _parseUnaryExpression());
8035 } 8507 }
8036 return new PrefixExpression( 8508 return new PrefixExpression(
8037 operator, new SuperExpression(getAndAdvance())); 8509 operator, new SuperExpression(getAndAdvance()));
8038 } 8510 }
8039 return new PrefixExpression(operator, _parseUnaryExpression()); 8511 return new PrefixExpression(operator, _parseUnaryExpression());
8040 } else if (_currentToken.type.isIncrementOperator) { 8512 } else if (_currentToken.type.isIncrementOperator) {
8041 Token operator = getAndAdvance(); 8513 Token operator = getAndAdvance();
8042 if (_matchesKeyword(Keyword.SUPER)) { 8514 if (_matchesKeyword(Keyword.SUPER)) {
8043 if (_tokenMatches(_peek(), TokenType.OPEN_SQUARE_BRACKET) || 8515 TokenType nextType = _peek().type;
8044 _tokenMatches(_peek(), TokenType.PERIOD)) { 8516 if (nextType == TokenType.OPEN_SQUARE_BRACKET ||
8517 nextType == TokenType.PERIOD) {
8045 // --> "prefixOperator 'super' assignableSelector selector*" 8518 // --> "prefixOperator 'super' assignableSelector selector*"
8046 return new PrefixExpression(operator, _parseUnaryExpression()); 8519 return new PrefixExpression(operator, _parseUnaryExpression());
8047 } 8520 }
8048 // 8521 //
8049 // Even though it is not valid to use an incrementing operator 8522 // Even though it is not valid to use an incrementing operator
8050 // ('++' or '--') before 'super', we can (and therefore must) interpret 8523 // ('++' or '--') before 'super', we can (and therefore must) interpret
8051 // "--super" as semantically equivalent to "-(-super)". Unfortunately, 8524 // "--super" as semantically equivalent to "-(-super)". Unfortunately,
8052 // we cannot do the same for "++super" because "+super" is also not 8525 // we cannot do the same for "++super" because "+super" is also not
8053 // valid. 8526 // valid.
8054 // 8527 //
8055 if (operator.type == TokenType.MINUS_MINUS) { 8528 if (type == TokenType.MINUS_MINUS) {
8056 Token firstOperator = _createToken(operator, TokenType.MINUS); 8529 Token firstOperator = _createToken(operator, TokenType.MINUS);
8057 Token secondOperator = 8530 Token secondOperator =
8058 new Token(TokenType.MINUS, operator.offset + 1); 8531 new Token(TokenType.MINUS, operator.offset + 1);
8059 secondOperator.setNext(_currentToken); 8532 secondOperator.setNext(_currentToken);
8060 firstOperator.setNext(secondOperator); 8533 firstOperator.setNext(secondOperator);
8061 operator.previous.setNext(firstOperator); 8534 operator.previous.setNext(firstOperator);
8062 return new PrefixExpression( 8535 return new PrefixExpression(
8063 firstOperator, 8536 firstOperator,
8064 new PrefixExpression( 8537 new PrefixExpression(
8065 secondOperator, new SuperExpression(getAndAdvance()))); 8538 secondOperator, new SuperExpression(getAndAdvance())));
8066 } else {
8067 // Invalid operator before 'super'
8068 _reportErrorForCurrentToken(
8069 ParserErrorCode.INVALID_OPERATOR_FOR_SUPER, [operator.lexeme]);
8070 return new PrefixExpression(
8071 operator, new SuperExpression(getAndAdvance()));
8072 } 8539 }
8540 // Invalid operator before 'super'
8541 _reportErrorForCurrentToken(
8542 ParserErrorCode.INVALID_OPERATOR_FOR_SUPER, [operator.lexeme]);
8543 return new PrefixExpression(
8544 operator, new SuperExpression(getAndAdvance()));
8073 } 8545 }
8074 return new PrefixExpression(operator, _parseAssignableExpression(false)); 8546 return new PrefixExpression(
8075 } else if (_matches(TokenType.PLUS)) { 8547 operator, _parseAssignableExpressionNotStartingWithSuper(false));
8548 } else if (type == TokenType.PLUS) {
8076 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); 8549 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
8077 return _createSyntheticIdentifier(); 8550 return _createSyntheticIdentifier();
8078 } else if (_inAsync && _matchesString(_AWAIT)) { 8551 } else if (_inAsync && _matchesString(_AWAIT)) {
8079 return _parseAwaitExpression(); 8552 return _parseAwaitExpression();
8080 } 8553 }
8081 return _parsePostfixExpression(); 8554 return _parsePostfixExpression();
8082 } 8555 }
8083 8556
8084 /** 8557 /**
8085 * Parse a string literal representing a URI. Return the string literal that 8558 * Parse a string literal representing a URI. Return the string literal that
8086 * was parsed. 8559 * was parsed.
8087 */ 8560 */
8088 StringLiteral _parseUri() { 8561 StringLiteral _parseUri() {
8089 bool iskeywordAfterUri(Token token) => 8562 // TODO(brianwilkerson) Should this function also return true for valid
8563 // top-level keywords?
8564 bool isKeywordAfterUri(Token token) =>
8090 token.lexeme == Keyword.AS.syntax || 8565 token.lexeme == Keyword.AS.syntax ||
8091 token.lexeme == _HIDE || 8566 token.lexeme == _HIDE ||
8092 token.lexeme == _SHOW; 8567 token.lexeme == _SHOW;
8093 if (!_matches(TokenType.STRING) && 8568 TokenType type = _currentToken.type;
8094 !_matches(TokenType.SEMICOLON) && 8569 if (type != TokenType.STRING &&
8095 !iskeywordAfterUri(_currentToken)) { 8570 type != TokenType.SEMICOLON &&
8571 !isKeywordAfterUri(_currentToken)) {
8096 // Attempt to recover in the case where the URI was not enclosed in 8572 // Attempt to recover in the case where the URI was not enclosed in
8097 // quotes. 8573 // quotes.
8098 Token token = _currentToken; 8574 Token token = _currentToken;
8099 while ((_tokenMatchesIdentifier(token) && !iskeywordAfterUri(token)) || 8575 bool isValidInUri(Token token) {
8100 _tokenMatches(token, TokenType.COLON) || 8576 TokenType type = token.type;
8101 _tokenMatches(token, TokenType.SLASH) || 8577 return type == TokenType.COLON ||
8102 _tokenMatches(token, TokenType.PERIOD) || 8578 type == TokenType.SLASH ||
8103 _tokenMatches(token, TokenType.PERIOD_PERIOD) || 8579 type == TokenType.PERIOD ||
8104 _tokenMatches(token, TokenType.PERIOD_PERIOD_PERIOD) || 8580 type == TokenType.PERIOD_PERIOD ||
8105 _tokenMatches(token, TokenType.INT) || 8581 type == TokenType.PERIOD_PERIOD_PERIOD ||
8106 _tokenMatches(token, TokenType.DOUBLE)) { 8582 type == TokenType.INT ||
8583 type == TokenType.DOUBLE;
8584 }
8585 while ((_tokenMatchesIdentifier(token) && !isKeywordAfterUri(token)) ||
8586 isValidInUri(token)) {
8107 token = token.next; 8587 token = token.next;
8108 } 8588 }
8109 if (_tokenMatches(token, TokenType.SEMICOLON) || 8589 if (_tokenMatches(token, TokenType.SEMICOLON) ||
8110 iskeywordAfterUri(token)) { 8590 isKeywordAfterUri(token)) {
8111 Token endToken = token.previous; 8591 Token endToken = token.previous;
8112 token = _currentToken; 8592 token = _currentToken;
8113 int endOffset = token.end; 8593 int endOffset = token.end;
8114 StringBuffer buffer = new StringBuffer(); 8594 StringBuffer buffer = new StringBuffer();
8115 buffer.write(token.lexeme); 8595 buffer.write(token.lexeme);
8116 while (token != endToken) { 8596 while (token != endToken) {
8117 token = token.next; 8597 token = token.next;
8118 if (token.offset != endOffset || token.precedingComments != null) { 8598 if (token.offset != endOffset || token.precedingComments != null) {
8119 return parseStringLiteral(); 8599 return parseStringLiteral();
8120 } 8600 }
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
8186 * variableDeclarationList ::= 8666 * variableDeclarationList ::=
8187 * finalConstVarOrType variableDeclaration (',' variableDeclaration)* 8667 * finalConstVarOrType variableDeclaration (',' variableDeclaration)*
8188 */ 8668 */
8189 VariableDeclarationList _parseVariableDeclarationListAfterType( 8669 VariableDeclarationList _parseVariableDeclarationListAfterType(
8190 CommentAndMetadata commentAndMetadata, Token keyword, TypeName type) { 8670 CommentAndMetadata commentAndMetadata, Token keyword, TypeName type) {
8191 if (type != null && 8671 if (type != null &&
8192 keyword != null && 8672 keyword != null &&
8193 _tokenMatchesKeyword(keyword, Keyword.VAR)) { 8673 _tokenMatchesKeyword(keyword, Keyword.VAR)) {
8194 _reportErrorForToken(ParserErrorCode.VAR_AND_TYPE, keyword); 8674 _reportErrorForToken(ParserErrorCode.VAR_AND_TYPE, keyword);
8195 } 8675 }
8196 List<VariableDeclaration> variables = new List<VariableDeclaration>(); 8676 List<VariableDeclaration> variables = <VariableDeclaration>[
8197 variables.add(_parseVariableDeclaration()); 8677 _parseVariableDeclaration()
8198 while (_matches(TokenType.COMMA)) { 8678 ];
8199 _advance(); 8679 while (_optional(TokenType.COMMA)) {
8200 variables.add(_parseVariableDeclaration()); 8680 variables.add(_parseVariableDeclaration());
8201 } 8681 }
8202 return new VariableDeclarationList(commentAndMetadata?.comment, 8682 return new VariableDeclarationList(commentAndMetadata?.comment,
8203 commentAndMetadata?.metadata, keyword, type, variables); 8683 commentAndMetadata?.metadata, keyword, type, variables);
8204 } 8684 }
8205 8685
8206 /** 8686 /**
8207 * Parse a variable declaration statement. The [commentAndMetadata] is the 8687 * Parse a variable declaration statement. The [commentAndMetadata] is the
8208 * metadata to be associated with the variable declaration statement, or 8688 * metadata to be associated with the variable declaration statement, or
8209 * `null` if there is no attempt at parsing the comment and metadata. Return 8689 * `null` if there is no attempt at parsing the comment and metadata. Return
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
8243 VariableDeclarationList variableList = 8723 VariableDeclarationList variableList =
8244 _parseVariableDeclarationListAfterType( 8724 _parseVariableDeclarationListAfterType(
8245 commentAndMetadata, keyword, type); 8725 commentAndMetadata, keyword, type);
8246 Token semicolon = _expect(TokenType.SEMICOLON); 8726 Token semicolon = _expect(TokenType.SEMICOLON);
8247 return new VariableDeclarationStatement(variableList, semicolon); 8727 return new VariableDeclarationStatement(variableList, semicolon);
8248 } 8728 }
8249 8729
8250 /** 8730 /**
8251 * Parse a while statement. Return the while statement that was parsed. 8731 * Parse a while statement. Return the while statement that was parsed.
8252 * 8732 *
8733 * This method assumes that the current token matches [Keyword.WHILE].
8734 *
8253 * whileStatement ::= 8735 * whileStatement ::=
8254 * 'while' '(' expression ')' statement 8736 * 'while' '(' expression ')' statement
8255 */ 8737 */
8256 Statement _parseWhileStatement() { 8738 Statement _parseWhileStatement() {
8257 bool wasInLoop = _inLoop; 8739 bool wasInLoop = _inLoop;
8258 _inLoop = true; 8740 _inLoop = true;
8259 try { 8741 try {
8260 Token keyword = _expectKeyword(Keyword.WHILE); 8742 Token keyword = getAndAdvance();
8261 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); 8743 Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
8262 Expression condition = parseExpression2(); 8744 Expression condition = parseExpression2();
8263 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); 8745 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
8264 Statement body = parseStatement2(); 8746 Statement body = parseStatement2();
8265 return new WhileStatement( 8747 return new WhileStatement(
8266 keyword, leftParenthesis, condition, rightParenthesis, body); 8748 keyword, leftParenthesis, condition, rightParenthesis, body);
8267 } finally { 8749 } finally {
8268 _inLoop = wasInLoop; 8750 _inLoop = wasInLoop;
8269 } 8751 }
8270 } 8752 }
8271 8753
8272 /** 8754 /**
8273 * Parse a yield statement. Return the yield statement that was parsed. 8755 * Parse a yield statement. Return the yield statement that was parsed.
8274 * 8756 *
8757 * This method assumes that the current token matches [Keyword.YIELD].
8758 *
8275 * yieldStatement ::= 8759 * yieldStatement ::=
8276 * 'yield' '*'? expression ';' 8760 * 'yield' '*'? expression ';'
8277 */ 8761 */
8278 YieldStatement _parseYieldStatement() { 8762 YieldStatement _parseYieldStatement() {
8279 Token yieldToken = getAndAdvance(); 8763 Token yieldToken = getAndAdvance();
8280 Token star = null; 8764 Token star = null;
8281 if (_matches(TokenType.STAR)) { 8765 if (_matches(TokenType.STAR)) {
8282 star = getAndAdvance(); 8766 star = getAndAdvance();
8283 } 8767 }
8284 Expression expression = parseExpression2(); 8768 Expression expression = parseExpression2();
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
8408 * [startToken] is the token at which parsing is to begin. Return the token 8892 * [startToken] is the token at which parsing is to begin. Return the token
8409 * following the type that was parsed. 8893 * following the type that was parsed.
8410 * 8894 *
8411 * finalConstVarOrType ::= 8895 * finalConstVarOrType ::=
8412 * | 'final' type? 8896 * | 'final' type?
8413 * | 'const' type? 8897 * | 'const' type?
8414 * | 'var' 8898 * | 'var'
8415 * | type 8899 * | type
8416 */ 8900 */
8417 Token _skipFinalConstVarOrType(Token startToken) { 8901 Token _skipFinalConstVarOrType(Token startToken) {
8418 if (_tokenMatchesKeyword(startToken, Keyword.FINAL) || 8902 Keyword keyword = startToken.keyword;
8419 _tokenMatchesKeyword(startToken, Keyword.CONST)) { 8903 if (keyword == Keyword.FINAL || keyword == Keyword.CONST) {
8420 Token next = startToken.next; 8904 Token next = startToken.next;
8421 if (_tokenMatchesIdentifier(next)) { 8905 if (_tokenMatchesIdentifier(next)) {
8422 Token next2 = next.next; 8906 Token next2 = next.next;
8423 // "Type parameter" or "Type<" or "prefix.Type" 8907 // "Type parameter" or "Type<" or "prefix.Type"
8424 if (_tokenMatchesIdentifier(next2) || 8908 if (_tokenMatchesIdentifier(next2) ||
8425 _tokenMatches(next2, TokenType.LT) || 8909 _tokenMatches(next2, TokenType.LT) ||
8426 _tokenMatches(next2, TokenType.PERIOD)) { 8910 _tokenMatches(next2, TokenType.PERIOD)) {
8427 return _skipTypeName(next); 8911 return _skipTypeName(next);
8428 } 8912 }
8429 // "parameter" 8913 // "parameter"
8430 return next; 8914 return next;
8431 } 8915 }
8432 } else if (_tokenMatchesKeyword(startToken, Keyword.VAR)) { 8916 } else if (keyword == Keyword.VAR) {
8433 return startToken.next; 8917 return startToken.next;
8434 } else if (_tokenMatchesIdentifier(startToken)) { 8918 } else if (_tokenMatchesIdentifier(startToken)) {
8435 Token next = startToken.next; 8919 Token next = startToken.next;
8436 if (_tokenMatchesIdentifier(next) || 8920 if (_tokenMatchesIdentifier(next) ||
8437 _tokenMatches(next, TokenType.LT) || 8921 _tokenMatches(next, TokenType.LT) ||
8438 _tokenMatchesKeyword(next, Keyword.THIS) || 8922 _tokenMatchesKeyword(next, Keyword.THIS) ||
8439 (_tokenMatches(next, TokenType.PERIOD) && 8923 (_tokenMatches(next, TokenType.PERIOD) &&
8440 _tokenMatchesIdentifier(next.next) && 8924 _tokenMatchesIdentifier(next.next) &&
8441 (_tokenMatchesIdentifier(next.next.next) || 8925 (_tokenMatchesIdentifier(next.next.next) ||
8442 _tokenMatches(next.next.next, TokenType.LT) || 8926 _tokenMatches(next.next.next, TokenType.LT) ||
(...skipping 1525 matching lines...) Expand 10 before | Expand all | Expand 10 after
9968 */ 10452 */
9969 const ParserErrorCode(String name, String message, [String correction]) 10453 const ParserErrorCode(String name, String message, [String correction])
9970 : super(name, message, correction); 10454 : super(name, message, correction);
9971 10455
9972 @override 10456 @override
9973 ErrorSeverity get errorSeverity => ErrorSeverity.ERROR; 10457 ErrorSeverity get errorSeverity => ErrorSeverity.ERROR;
9974 10458
9975 @override 10459 @override
9976 ErrorType get type => ErrorType.SYNTACTIC_ERROR; 10460 ErrorType get type => ErrorType.SYNTACTIC_ERROR;
9977 } 10461 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer/test/generated/parser_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698