OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |