| 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 |