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

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

Issue 1434863003: initial generic method comment parsing (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library engine.parser; 5 library engine.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 'ast.dart'; 10 import 'ast.dart';
(...skipping 2105 matching lines...) Expand 10 before | Expand all | Expand 10 after
2116 * initializer, with no intervening parens, braces, or brackets. 2116 * initializer, with no intervening parens, braces, or brackets.
2117 */ 2117 */
2118 bool _inInitializer = false; 2118 bool _inInitializer = false;
2119 2119
2120 /** 2120 /**
2121 * A flag indicating whether the parser is to parse generic method syntax. 2121 * A flag indicating whether the parser is to parse generic method syntax.
2122 */ 2122 */
2123 bool parseGenericMethods = false; 2123 bool parseGenericMethods = false;
2124 2124
2125 /** 2125 /**
2126 * A flag indicating whether to parse generic method comments, of the form
2127 * `/*=T*/` and `/*<T>*/`.
2128 */
2129 bool parseGenericMethodComments = false;
Jennifer Messerly 2015/11/11 18:28:06 aside, we don't actually need this flag in the par
Paul Berry 2015/11/11 19:26:53 My two cents: I'd actually lean slightly toward le
Jennifer Messerly 2015/11/11 19:30:25 good point.
Brian Wilkerson 2015/11/11 21:53:42 I agree, I'd leave the flag in. You'll probably ev
2130
2131 /**
2126 * Initialize a newly created parser to parse the content of the given 2132 * Initialize a newly created parser to parse the content of the given
2127 * [_source] and to report any errors that are found to the given 2133 * [_source] and to report any errors that are found to the given
2128 * [_errorListener]. 2134 * [_errorListener].
2129 */ 2135 */
2130 Parser(this._source, this._errorListener); 2136 Parser(this._source, this._errorListener);
2131 2137
2132 void set currentToken(Token currentToken) { 2138 void set currentToken(Token currentToken) {
2133 this._currentToken = currentToken; 2139 this._currentToken = currentToken;
2134 } 2140 }
2135 2141
(...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after
2508 commentAndMetadata, 2514 commentAndMetadata,
2509 modifiers.externalKeyword, 2515 modifiers.externalKeyword,
2510 _validateModifiersForConstructor(modifiers), 2516 _validateModifiersForConstructor(modifiers),
2511 modifiers.factoryKeyword, 2517 modifiers.factoryKeyword,
2512 parseSimpleIdentifier(), 2518 parseSimpleIdentifier(),
2513 getAndAdvance(), 2519 getAndAdvance(),
2514 parseSimpleIdentifier(), 2520 parseSimpleIdentifier(),
2515 parseFormalParameterList()); 2521 parseFormalParameterList());
2516 } else if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { 2522 } else if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) {
2517 SimpleIdentifier methodName = parseSimpleIdentifier(); 2523 SimpleIdentifier methodName = parseSimpleIdentifier();
2524 TypeParameterList typeParameters = _parseGenericCommentTypeParameters();
2518 FormalParameterList parameters = parseFormalParameterList(); 2525 FormalParameterList parameters = parseFormalParameterList();
2519 if (_matches(TokenType.COLON) || 2526 if (_matches(TokenType.COLON) ||
2520 modifiers.factoryKeyword != null || 2527 modifiers.factoryKeyword != null ||
2521 methodName.name == className) { 2528 methodName.name == className) {
2522 return _parseConstructor( 2529 return _parseConstructor(
2523 commentAndMetadata, 2530 commentAndMetadata,
2524 modifiers.externalKeyword, 2531 modifiers.externalKeyword,
2525 _validateModifiersForConstructor(modifiers), 2532 _validateModifiersForConstructor(modifiers),
2526 modifiers.factoryKeyword, 2533 modifiers.factoryKeyword,
2527 methodName, 2534 methodName,
2528 null, 2535 null,
2529 null, 2536 null,
2530 parameters); 2537 parameters);
2531 } 2538 }
2532 _validateModifiersForGetterOrSetterOrMethod(modifiers); 2539 _validateModifiersForGetterOrSetterOrMethod(modifiers);
2533 _validateFormalParameterList(parameters); 2540 _validateFormalParameterList(parameters);
2534 return _parseMethodDeclarationAfterParameters( 2541 return _parseMethodDeclarationAfterParameters(
2535 commentAndMetadata, 2542 commentAndMetadata,
2536 modifiers.externalKeyword, 2543 modifiers.externalKeyword,
2537 modifiers.staticKeyword, 2544 modifiers.staticKeyword,
2538 null, 2545 null,
2539 methodName, 2546 methodName,
2540 null, 2547 typeParameters,
2541 parameters); 2548 parameters);
2542 } else if (_peek() 2549 } else if (_peek()
2543 .matchesAny([TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) { 2550 .matchesAny([TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) {
2544 if (modifiers.constKeyword == null && 2551 if (modifiers.constKeyword == null &&
2545 modifiers.finalKeyword == null && 2552 modifiers.finalKeyword == null &&
2546 modifiers.varKeyword == null) { 2553 modifiers.varKeyword == null) {
2547 _reportErrorForCurrentToken( 2554 _reportErrorForCurrentToken(
2548 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE); 2555 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE);
2549 } 2556 }
2550 return _parseInitializedIdentifierList(commentAndMetadata, 2557 return _parseInitializedIdentifierList(commentAndMetadata,
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
2610 return _parseInitializedIdentifierList( 2617 return _parseInitializedIdentifierList(
2611 commentAndMetadata, 2618 commentAndMetadata,
2612 modifiers.staticKeyword, 2619 modifiers.staticKeyword,
2613 _validateModifiersForField(modifiers), 2620 _validateModifiersForField(modifiers),
2614 type); 2621 type);
2615 } finally { 2622 } finally {
2616 _unlockErrorListener(); 2623 _unlockErrorListener();
2617 } 2624 }
2618 } else if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { 2625 } else if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) {
2619 SimpleIdentifier methodName = parseSimpleIdentifier(); 2626 SimpleIdentifier methodName = parseSimpleIdentifier();
2627 TypeParameterList typeParameters = _parseGenericCommentTypeParameters();
2620 FormalParameterList parameters = parseFormalParameterList(); 2628 FormalParameterList parameters = parseFormalParameterList();
2621 if (methodName.name == className) { 2629 if (methodName.name == className) {
2622 _reportErrorForNode(ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, type); 2630 _reportErrorForNode(ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, type);
2623 return _parseConstructor( 2631 return _parseConstructor(
2624 commentAndMetadata, 2632 commentAndMetadata,
2625 modifiers.externalKeyword, 2633 modifiers.externalKeyword,
2626 _validateModifiersForConstructor(modifiers), 2634 _validateModifiersForConstructor(modifiers),
2627 modifiers.factoryKeyword, 2635 modifiers.factoryKeyword,
2628 methodName, 2636 methodName,
2629 null, 2637 null,
2630 null, 2638 null,
2631 parameters); 2639 parameters);
2632 } 2640 }
2633 _validateModifiersForGetterOrSetterOrMethod(modifiers); 2641 _validateModifiersForGetterOrSetterOrMethod(modifiers);
2634 _validateFormalParameterList(parameters); 2642 _validateFormalParameterList(parameters);
2635 return _parseMethodDeclarationAfterParameters( 2643 return _parseMethodDeclarationAfterParameters(
2636 commentAndMetadata, 2644 commentAndMetadata,
2637 modifiers.externalKeyword, 2645 modifiers.externalKeyword,
2638 modifiers.staticKeyword, 2646 modifiers.staticKeyword,
2639 type, 2647 type,
2640 methodName, 2648 methodName,
2641 null, 2649 typeParameters,
2642 parameters); 2650 parameters);
2643 } else if (parseGenericMethods && _tokenMatches(_peek(), TokenType.LT)) { 2651 } else if (parseGenericMethods && _tokenMatches(_peek(), TokenType.LT)) {
2644 return _parseMethodDeclarationAfterReturnType(commentAndMetadata, 2652 return _parseMethodDeclarationAfterReturnType(commentAndMetadata,
2645 modifiers.externalKeyword, modifiers.staticKeyword, type); 2653 modifiers.externalKeyword, modifiers.staticKeyword, type);
2646 } else if (_tokenMatches(_peek(), TokenType.OPEN_CURLY_BRACKET)) { 2654 } else if (_tokenMatches(_peek(), TokenType.OPEN_CURLY_BRACKET)) {
2647 // We have found "TypeName identifier {", and are guessing that this is a 2655 // We have found "TypeName identifier {", and are guessing that this is a
2648 // getter without the keyword 'get'. 2656 // getter without the keyword 'get'.
2649 _validateModifiersForGetterOrSetterOrMethod(modifiers); 2657 _validateModifiersForGetterOrSetterOrMethod(modifiers);
2650 _reportErrorForCurrentToken(ParserErrorCode.MISSING_GET); 2658 _reportErrorForCurrentToken(ParserErrorCode.MISSING_GET);
2651 _currentToken = _injectToken( 2659 _currentToken = _injectToken(
(...skipping 476 matching lines...) Expand 10 before | Expand all | Expand 10 after
3128 } 3136 }
3129 3137
3130 /** 3138 /**
3131 * Parse a function expression. Return the function expression that was 3139 * Parse a function expression. Return the function expression that was
3132 * parsed. 3140 * parsed.
3133 * 3141 *
3134 * functionExpression ::= 3142 * functionExpression ::=
3135 * typeParameters? formalParameterList functionExpressionBody 3143 * typeParameters? formalParameterList functionExpressionBody
3136 */ 3144 */
3137 FunctionExpression parseFunctionExpression() { 3145 FunctionExpression parseFunctionExpression() {
3138 TypeParameterList typeParameters = null; 3146 TypeParameterList typeParameters = _parseGenericMethodTypeParameters();
3139 if (parseGenericMethods && _matches(TokenType.LT)) {
3140 typeParameters = parseTypeParameterList();
3141 }
3142 FormalParameterList parameters = parseFormalParameterList(); 3147 FormalParameterList parameters = parseFormalParameterList();
3143 _validateFormalParameterList(parameters); 3148 _validateFormalParameterList(parameters);
3144 FunctionBody body = 3149 FunctionBody body =
3145 _parseFunctionBody(false, ParserErrorCode.MISSING_FUNCTION_BODY, true); 3150 _parseFunctionBody(false, ParserErrorCode.MISSING_FUNCTION_BODY, true);
3146 return new FunctionExpression(typeParameters, parameters, body); 3151 return new FunctionExpression(typeParameters, parameters, body);
3147 } 3152 }
3148 3153
3149 /** 3154 /**
3150 * Parse an if-null expression. Return the if-null expression that was 3155 * Parse an if-null expression. Return the if-null expression that was
3151 * parsed. 3156 * parsed.
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
3258 NormalFormalParameter parseNormalFormalParameter() { 3263 NormalFormalParameter parseNormalFormalParameter() {
3259 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); 3264 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata();
3260 FinalConstVarOrType holder = _parseFinalConstVarOrType(true); 3265 FinalConstVarOrType holder = _parseFinalConstVarOrType(true);
3261 Token thisKeyword = null; 3266 Token thisKeyword = null;
3262 Token period = null; 3267 Token period = null;
3263 if (_matchesKeyword(Keyword.THIS)) { 3268 if (_matchesKeyword(Keyword.THIS)) {
3264 thisKeyword = getAndAdvance(); 3269 thisKeyword = getAndAdvance();
3265 period = _expect(TokenType.PERIOD); 3270 period = _expect(TokenType.PERIOD);
3266 } 3271 }
3267 SimpleIdentifier identifier = parseSimpleIdentifier(); 3272 SimpleIdentifier identifier = parseSimpleIdentifier();
3268 TypeParameterList typeParameters = null; 3273 TypeParameterList typeParameters = _parseGenericMethodTypeParameters();
3269 if (parseGenericMethods && _matches(TokenType.LT)) {
3270 typeParameters = parseTypeParameterList();
3271 }
3272 if (_matches(TokenType.OPEN_PAREN)) { 3274 if (_matches(TokenType.OPEN_PAREN)) {
3273 FormalParameterList parameters = parseFormalParameterList(); 3275 FormalParameterList parameters = parseFormalParameterList();
3274 if (thisKeyword == null) { 3276 if (thisKeyword == null) {
3275 if (holder.keyword != null) { 3277 if (holder.keyword != null) {
3276 _reportErrorForToken( 3278 _reportErrorForToken(
3277 ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR, holder.keyword); 3279 ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR, holder.keyword);
3278 } 3280 }
3279 return new FunctionTypedFormalParameter( 3281 return new FunctionTypedFormalParameter(
3280 commentAndMetadata.comment, 3282 commentAndMetadata.comment,
3281 commentAndMetadata.metadata, 3283 commentAndMetadata.metadata,
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after
3469 return new TypeArgumentList(leftBracket, arguments, rightBracket); 3471 return new TypeArgumentList(leftBracket, arguments, rightBracket);
3470 } 3472 }
3471 3473
3472 /** 3474 /**
3473 * Parse a type name. Return the type name that was parsed. 3475 * Parse a type name. Return the type name that was parsed.
3474 * 3476 *
3475 * type ::= 3477 * type ::=
3476 * qualified typeArguments? 3478 * qualified typeArguments?
3477 */ 3479 */
3478 TypeName parseTypeName() { 3480 TypeName parseTypeName() {
3481 TypeName result = _parseTypeName();
3482 // If this is followed by a generic method type comment, allow the comment
3483 // type to replace the real type name.
3484 // TODO(jmesserly): this feels like a big hammer. Can we restrict it to
3485 // only work inside generic methods?
Jennifer Messerly 2015/11/11 18:28:06 This feature weirds me out. I kind of wonder if it
Brian Wilkerson 2015/11/11 21:53:42 Given that this only applies to return types and p
Paul Berry 2015/11/11 22:01:58 I would think it could potentially apply to other
Jennifer Messerly 2015/11/11 22:04:12 EDIT: Paul beat me to it. But here was my comment.
3486 if (_injectGenericCommentTypeAssign()) {
3487 return _parseTypeName();
3488 }
3489 return result;
3490 }
3491
3492 TypeName _parseTypeName() {
3479 Identifier typeName; 3493 Identifier typeName;
3480 if (_matchesKeyword(Keyword.VAR)) { 3494 if (_matchesKeyword(Keyword.VAR)) {
3481 _reportErrorForCurrentToken(ParserErrorCode.VAR_AS_TYPE_NAME); 3495 _reportErrorForCurrentToken(ParserErrorCode.VAR_AS_TYPE_NAME);
3482 typeName = new SimpleIdentifier(getAndAdvance()); 3496 typeName = new SimpleIdentifier(getAndAdvance());
3483 } else if (_matchesIdentifier()) { 3497 } else if (_matchesIdentifier()) {
3484 typeName = parsePrefixedIdentifier(); 3498 typeName = parsePrefixedIdentifier();
3485 } else { 3499 } else {
3486 typeName = _createSyntheticIdentifier(); 3500 typeName = _createSyntheticIdentifier();
3487 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TYPE_NAME); 3501 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TYPE_NAME);
3488 } 3502 }
3489 TypeArgumentList typeArguments = null; 3503 TypeArgumentList typeArguments = _maybeParseTypeArguments();
3490 if (_matches(TokenType.LT)) {
3491 typeArguments = parseTypeArgumentList();
3492 }
3493 return new TypeName(typeName, typeArguments); 3504 return new TypeName(typeName, typeArguments);
3494 } 3505 }
3495 3506
3496 /** 3507 /**
3497 * Parse a type parameter. Return the type parameter that was parsed. 3508 * Parse a type parameter. Return the type parameter that was parsed.
3498 * 3509 *
3499 * typeParameter ::= 3510 * typeParameter ::=
3500 * metadata name ('extends' bound)? 3511 * metadata name ('extends' bound)?
3501 */ 3512 */
3502 TypeParameter parseTypeParameter() { 3513 TypeParameter parseTypeParameter() {
(...skipping 399 matching lines...) Expand 10 before | Expand all | Expand 10 after
3902 * either the given token is not a begin token or it does not have an end 3913 * either the given token is not a begin token or it does not have an end
3903 * token associated with it. 3914 * token associated with it.
3904 */ 3915 */
3905 Token _getEndToken(Token beginToken) { 3916 Token _getEndToken(Token beginToken) {
3906 if (beginToken is BeginToken) { 3917 if (beginToken is BeginToken) {
3907 return beginToken.endToken; 3918 return beginToken.endToken;
3908 } 3919 }
3909 return null; 3920 return null;
3910 } 3921 }
3911 3922
3923 bool _injectGenericComment(TokenType type, int prefixLen) {
3924 if (parseGenericMethodComments) {
Jennifer Messerly 2015/11/11 18:28:06 as noted above, this guard shouldn't really be nec
3925 CommentToken t = _currentToken.precedingComments;
3926 for (; t != null; t = t.next) {
3927 if (t.type == TokenType.GENERIC_METHOD_TYPE_LIST) {
Jennifer Messerly 2015/11/11 20:52:27 Bug here. the /*=T*/ comments weren't working beca
3928 String comment = t.lexeme.substring(prefixLen, t.lexeme.length - 2);
3929 Token list = _scanGenericMethodComment(comment, t.offset + prefixLen);
Paul Berry 2015/11/11 19:26:53 What will happen if the comment is matched by Scan
Jennifer Messerly 2015/11/11 19:30:25 Should be exactly as if you wrote that without the
3930 if (list != null) {
3931 // TODO(jmesserly): detach the old comment token?
Brian Wilkerson 2015/11/11 21:53:42 It shouldn't actually hurt anything if you leave i
Jennifer Messerly 2015/11/12 00:20:00 Sounds good. Removed the TODO.
3932 // Insert the tokens into the stream.
3933 _injectTokenList(list);
3934 return true;
3935 }
3936 }
3937 }
3938 }
3939 return false;
3940 }
3941
3942 /**
3943 * Matches a generic comment type substitution and injects it into the token
Jennifer Messerly 2015/11/11 18:28:06 oops, fixed this locally. Not sure how it happened
3944 * stream. Returns true if a match was injected, otherwise false.
3945 *
3946 * These comments are of the form `/*=T*/`, in other words, a [TypeName]
3947 * inside a slash-star comment, preceded by equals sign.
3948 */
3949 bool _injectGenericCommentTypeAssign() {
3950 return _injectGenericComment(TokenType.GENERIC_METHOD_TYPE_ASSIGN, 3);
3951 }
3952
3953 /**
3954 * Matches a generic comment type parameters and injects them into the token
3955 * stream. Returns true if a match was injected, otherwise false.
3956 *
3957 * These comments are of the form `/*<K, V>*/`, in other words, a
3958 * [TypeParameterList] or [TypeArgumentList] inside a slash-star comment.
3959 */
3960 bool _injectGenericCommentTypeList() {
3961 return _injectGenericComment(TokenType.GENERIC_METHOD_TYPE_LIST, 2);
3962 }
3963
3912 /** 3964 /**
3913 * Inject the given [token] into the token stream immediately before the 3965 * Inject the given [token] into the token stream immediately before the
3914 * current token. 3966 * current token.
3915 */ 3967 */
3916 Token _injectToken(Token token) { 3968 Token _injectToken(Token token) {
3917 Token previous = _currentToken.previous; 3969 Token previous = _currentToken.previous;
3918 token.setNext(_currentToken); 3970 token.setNext(_currentToken);
3919 previous.setNext(token); 3971 previous.setNext(token);
3920 return token; 3972 return token;
3921 } 3973 }
3922 3974
3975 void _injectTokenList(Token firstToken) {
Jennifer Messerly 2015/11/11 18:28:06 I used the same pattern as the existing _injectTok
3976 // Scanner creates a cyclic EOF token.
3977 Token lastToken = firstToken;
3978 while (lastToken.next.type != TokenType.EOF) {
3979 lastToken = lastToken.next;
3980 }
3981 // Inject these new tokens into the stream.
3982 Token previous = _currentToken.previous;
3983 lastToken.setNext(_currentToken);
3984 previous.setNext(firstToken);
3985 _currentToken = firstToken;
3986 }
3987
3923 /** 3988 /**
3924 * Return `true` if the current token appears to be the beginning of a 3989 * Return `true` if the current token appears to be the beginning of a
3925 * function declaration. 3990 * function declaration.
3926 */ 3991 */
3927 bool _isFunctionDeclaration() { 3992 bool _isFunctionDeclaration() {
3928 if (_matchesKeyword(Keyword.VOID)) { 3993 if (_matchesKeyword(Keyword.VOID)) {
3929 return true; 3994 return true;
3930 } 3995 }
3931 Token afterReturnType = _skipTypeName(_currentToken); 3996 Token afterReturnType = _skipTypeName(_currentToken);
3932 if (afterReturnType == null) { 3997 if (afterReturnType == null) {
(...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after
4264 _tokenMatchesKeyword(_currentToken, keyword); 4329 _tokenMatchesKeyword(_currentToken, keyword);
4265 4330
4266 /** 4331 /**
4267 * Return `true` if the current token matches the given [identifier]. 4332 * Return `true` if the current token matches the given [identifier].
4268 */ 4333 */
4269 bool _matchesString(String identifier) => 4334 bool _matchesString(String identifier) =>
4270 _currentToken.type == TokenType.IDENTIFIER && 4335 _currentToken.type == TokenType.IDENTIFIER &&
4271 _currentToken.lexeme == identifier; 4336 _currentToken.lexeme == identifier;
4272 4337
4273 /** 4338 /**
4339 * Parse a [TypeArgumentList] if present, otherwise return null.
4340 * This also supports the comment form, if enabled: `/*<T>*/`
4341 */
4342 TypeArgumentList _maybeParseTypeArguments() {
Brian Wilkerson 2015/11/11 21:53:42 For consistency with "_parseOptionalReturnType", p
Jennifer Messerly 2015/11/12 00:20:00 Done.
4343 if (_matches(TokenType.LT) || _injectGenericCommentTypeList()) {
4344 return parseTypeArgumentList();
4345 }
4346 return null;
4347 }
4348
4349 /**
4274 * If the current token has the given [type], then advance to the next token 4350 * If the current token has the given [type], then advance to the next token
4275 * and return `true`. Otherwise, return `false` without advancing. This method 4351 * and return `true`. Otherwise, return `false` without advancing. This method
4276 * should not be invoked with an argument value of [TokenType.GT]. 4352 * should not be invoked with an argument value of [TokenType.GT].
4277 */ 4353 */
4278 bool _optional(TokenType type) { 4354 bool _optional(TokenType type) {
4279 if (_matches(type)) { 4355 if (_matches(type)) {
4280 _advance(); 4356 _advance();
4281 return true; 4357 return true;
4282 } 4358 }
4283 return false; 4359 return false;
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
4354 } 4430 }
4355 // 4431 //
4356 // A primary expression can start with an identifier. We resolve the 4432 // A primary expression can start with an identifier. We resolve the
4357 // ambiguity by determining whether the primary consists of anything other 4433 // ambiguity by determining whether the primary consists of anything other
4358 // than an identifier and/or is followed by an assignableSelector. 4434 // than an identifier and/or is followed by an assignableSelector.
4359 // 4435 //
4360 Expression expression = _parsePrimaryExpression(); 4436 Expression expression = _parsePrimaryExpression();
4361 bool isOptional = primaryAllowed || expression is SimpleIdentifier; 4437 bool isOptional = primaryAllowed || expression is SimpleIdentifier;
4362 while (true) { 4438 while (true) {
4363 while (_isLikelyParameterList()) { 4439 while (_isLikelyParameterList()) {
4364 TypeArgumentList typeArguments = null; 4440 TypeArgumentList typeArguments = _maybeParseTypeArguments();
4365 if (_matches(TokenType.LT)) {
4366 typeArguments = parseTypeArgumentList();
4367 }
4368 ArgumentList argumentList = parseArgumentList(); 4441 ArgumentList argumentList = parseArgumentList();
4369 if (expression is SimpleIdentifier) { 4442 if (expression is SimpleIdentifier) {
4370 expression = new MethodInvocation(null, null, 4443 expression = new MethodInvocation(null, null,
4371 expression as SimpleIdentifier, typeArguments, argumentList); 4444 expression as SimpleIdentifier, typeArguments, argumentList);
4372 } else if (expression is PrefixedIdentifier) { 4445 } else if (expression is PrefixedIdentifier) {
4373 PrefixedIdentifier identifier = expression as PrefixedIdentifier; 4446 PrefixedIdentifier identifier = expression as PrefixedIdentifier;
4374 expression = new MethodInvocation( 4447 expression = new MethodInvocation(
4375 identifier.prefix, 4448 identifier.prefix,
4376 identifier.period, 4449 identifier.period,
4377 identifier.identifier, 4450 identifier.identifier,
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after
4566 } 4639 }
4567 } else { 4640 } else {
4568 _reportErrorForToken(ParserErrorCode.MISSING_IDENTIFIER, _currentToken, 4641 _reportErrorForToken(ParserErrorCode.MISSING_IDENTIFIER, _currentToken,
4569 [_currentToken.lexeme]); 4642 [_currentToken.lexeme]);
4570 functionName = _createSyntheticIdentifier(); 4643 functionName = _createSyntheticIdentifier();
4571 } 4644 }
4572 assert((expression == null && functionName != null) || 4645 assert((expression == null && functionName != null) ||
4573 (expression != null && functionName == null)); 4646 (expression != null && functionName == null));
4574 if (_isLikelyParameterList()) { 4647 if (_isLikelyParameterList()) {
4575 while (_isLikelyParameterList()) { 4648 while (_isLikelyParameterList()) {
4576 TypeArgumentList typeArguments = null; 4649 TypeArgumentList typeArguments = _maybeParseTypeArguments();
4577 if (_matches(TokenType.LT)) {
4578 typeArguments = parseTypeArgumentList();
4579 }
4580 if (functionName != null) { 4650 if (functionName != null) {
4581 expression = new MethodInvocation(expression, period, functionName, 4651 expression = new MethodInvocation(expression, period, functionName,
4582 typeArguments, parseArgumentList()); 4652 typeArguments, parseArgumentList());
4583 period = null; 4653 period = null;
4584 functionName = null; 4654 functionName = null;
4585 } else if (expression == null) { 4655 } else if (expression == null) {
4586 // It should not be possible to get here. 4656 // It should not be possible to get here.
4587 expression = new MethodInvocation(expression, period, 4657 expression = new MethodInvocation(expression, period,
4588 _createSyntheticIdentifier(), typeArguments, parseArgumentList()); 4658 _createSyntheticIdentifier(), typeArguments, parseArgumentList());
4589 } else { 4659 } else {
4590 expression = new FunctionExpressionInvocation( 4660 expression = new FunctionExpressionInvocation(
4591 expression, typeArguments, parseArgumentList()); 4661 expression, typeArguments, parseArgumentList());
4592 } 4662 }
4593 } 4663 }
4594 } else if (functionName != null) { 4664 } else if (functionName != null) {
4595 expression = new PropertyAccess(expression, period, functionName); 4665 expression = new PropertyAccess(expression, period, functionName);
4596 period = null; 4666 period = null;
4597 } 4667 }
4598 assert(expression != null); 4668 assert(expression != null);
4599 bool progress = true; 4669 bool progress = true;
4600 while (progress) { 4670 while (progress) {
4601 progress = false; 4671 progress = false;
4602 Expression selector = _parseAssignableSelector(expression, true); 4672 Expression selector = _parseAssignableSelector(expression, true);
4603 if (!identical(selector, expression)) { 4673 if (!identical(selector, expression)) {
4604 expression = selector; 4674 expression = selector;
4605 progress = true; 4675 progress = true;
4606 while (_isLikelyParameterList()) { 4676 while (_isLikelyParameterList()) {
4607 TypeArgumentList typeArguments = null; 4677 TypeArgumentList typeArguments = _maybeParseTypeArguments();
4608 if (_matches(TokenType.LT)) {
4609 typeArguments = parseTypeArgumentList();
4610 }
4611 if (expression is PropertyAccess) { 4678 if (expression is PropertyAccess) {
4612 PropertyAccess propertyAccess = expression as PropertyAccess; 4679 PropertyAccess propertyAccess = expression as PropertyAccess;
4613 expression = new MethodInvocation( 4680 expression = new MethodInvocation(
4614 propertyAccess.target, 4681 propertyAccess.target,
4615 propertyAccess.operator, 4682 propertyAccess.operator,
4616 propertyAccess.propertyName, 4683 propertyAccess.propertyName,
4617 typeArguments, 4684 typeArguments,
4618 parseArgumentList()); 4685 parseArgumentList());
4619 } else { 4686 } else {
4620 expression = new FunctionExpressionInvocation( 4687 expression = new FunctionExpressionInvocation(
(...skipping 1397 matching lines...) Expand 10 before | Expand all | Expand 10 after
6018 bool isGetter = false; 6085 bool isGetter = false;
6019 if (_matchesKeyword(Keyword.GET) && 6086 if (_matchesKeyword(Keyword.GET) &&
6020 !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { 6087 !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) {
6021 keyword = getAndAdvance(); 6088 keyword = getAndAdvance();
6022 isGetter = true; 6089 isGetter = true;
6023 } else if (_matchesKeyword(Keyword.SET) && 6090 } else if (_matchesKeyword(Keyword.SET) &&
6024 !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { 6091 !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) {
6025 keyword = getAndAdvance(); 6092 keyword = getAndAdvance();
6026 } 6093 }
6027 SimpleIdentifier name = parseSimpleIdentifier(); 6094 SimpleIdentifier name = parseSimpleIdentifier();
6028 TypeParameterList typeParameters = null; 6095 TypeParameterList typeParameters = _parseGenericMethodTypeParameters();
6029 if (parseGenericMethods && _matches(TokenType.LT)) {
6030 typeParameters = parseTypeParameterList();
6031 }
6032 FormalParameterList parameters = null; 6096 FormalParameterList parameters = null;
6033 if (!isGetter) { 6097 if (!isGetter) {
6034 if (_matches(TokenType.OPEN_PAREN)) { 6098 if (_matches(TokenType.OPEN_PAREN)) {
6035 parameters = parseFormalParameterList(); 6099 parameters = parseFormalParameterList();
6036 _validateFormalParameterList(parameters); 6100 _validateFormalParameterList(parameters);
6037 } else { 6101 } else {
6038 _reportErrorForCurrentToken( 6102 _reportErrorForCurrentToken(
6039 ParserErrorCode.MISSING_FUNCTION_PARAMETERS); 6103 ParserErrorCode.MISSING_FUNCTION_PARAMETERS);
6040 parameters = new FormalParameterList( 6104 parameters = new FormalParameterList(
6041 _createSyntheticToken(TokenType.OPEN_PAREN), 6105 _createSyntheticToken(TokenType.OPEN_PAREN),
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
6175 commentAndMetadata.metadata, 6239 commentAndMetadata.metadata,
6176 keyword, 6240 keyword,
6177 returnType, 6241 returnType,
6178 name, 6242 name,
6179 typeParameters, 6243 typeParameters,
6180 parameters, 6244 parameters,
6181 semicolon); 6245 semicolon);
6182 } 6246 }
6183 6247
6184 /** 6248 /**
6249 * Parses generic type parameters from a comment.
6250 *
6251 * Normally this is handled by [_parseGenericMethodTypeParameters], but if t he
Jennifer Messerly 2015/11/11 18:28:06 fixed this locally, will be in next upload
6252 * code already handles the normal generic type parameters, the comment
6253 * matcher can be called directly. For example, we may have already tried
6254 * matching `<` (less than sign) in a method declaration, and be currently
6255 * on the `(` (open paren) because we didn't find it. In that case, this
6256 * function will parse the preceding comment such as `/*<T, R>*/`.
6257 */
6258 TypeParameterList _parseGenericCommentTypeParameters() {
6259 if (_injectGenericCommentTypeList()) {
6260 return parseTypeParameterList();
6261 }
6262 return null;
6263 }
6264
6265 /**
6266 * Parse the generic method or function's type parameters.
6267 *
6268 * For backwards compatibility this can optionally use comments.
6269 * See [parseGenericMethodComments].
6270 */
6271 TypeParameterList _parseGenericMethodTypeParameters() {
6272 if (parseGenericMethods && _matches(TokenType.LT) ||
6273 _injectGenericCommentTypeList()) {
6274 return parseTypeParameterList();
6275 }
6276 }
6277
6278 /**
6185 * Parse a getter. The [commentAndMetadata] is the documentation comment and 6279 * Parse a getter. The [commentAndMetadata] is the documentation comment and
6186 * metadata to be associated with the declaration. The externalKeyword] is the 6280 * metadata to be associated with the declaration. The externalKeyword] is the
6187 * 'external' token. The staticKeyword] is the static keyword, or `null` if 6281 * 'external' token. The staticKeyword] is the static keyword, or `null` if
6188 * the getter is not static. The [returnType] the return type that has already 6282 * the getter is not static. The [returnType] the return type that has already
6189 * been parsed, or `null` if there was no return type. Return the getter that 6283 * been parsed, or `null` if there was no return type. Return the getter that
6190 * was parsed. 6284 * was parsed.
6191 * 6285 *
6192 * getter ::= 6286 * getter ::=
6193 * getterSignature functionBody? 6287 * getterSignature functionBody?
6194 * 6288 *
(...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after
6466 /** 6560 /**
6467 * Parse a list or map literal. The [modifier] is the 'const' modifier 6561 * Parse a list or map literal. The [modifier] is the 'const' modifier
6468 * appearing before the literal, or `null` if there is no modifier. Return the 6562 * appearing before the literal, or `null` if there is no modifier. Return the
6469 * list or map literal that was parsed. 6563 * list or map literal that was parsed.
6470 * 6564 *
6471 * listOrMapLiteral ::= 6565 * listOrMapLiteral ::=
6472 * listLiteral 6566 * listLiteral
6473 * | mapLiteral 6567 * | mapLiteral
6474 */ 6568 */
6475 TypedLiteral _parseListOrMapLiteral(Token modifier) { 6569 TypedLiteral _parseListOrMapLiteral(Token modifier) {
6476 TypeArgumentList typeArguments = null; 6570 TypeArgumentList typeArguments = _maybeParseTypeArguments();
6477 if (_matches(TokenType.LT)) {
6478 typeArguments = parseTypeArgumentList();
6479 }
6480 if (_matches(TokenType.OPEN_CURLY_BRACKET)) { 6571 if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
6481 return _parseMapLiteral(modifier, typeArguments); 6572 return _parseMapLiteral(modifier, typeArguments);
6482 } else if (_matches(TokenType.OPEN_SQUARE_BRACKET) || 6573 } else if (_matches(TokenType.OPEN_SQUARE_BRACKET) ||
6483 _matches(TokenType.INDEX)) { 6574 _matches(TokenType.INDEX)) {
6484 return _parseListLiteral(modifier, typeArguments); 6575 return _parseListLiteral(modifier, typeArguments);
6485 } 6576 }
6486 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_LIST_OR_MAP_LITERAL); 6577 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_LIST_OR_MAP_LITERAL);
6487 return new ListLiteral( 6578 return new ListLiteral(
6488 modifier, 6579 modifier,
6489 typeArguments, 6580 typeArguments,
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
6603 * functionDeclaration ::= 6694 * functionDeclaration ::=
6604 * 'external'? 'static'? functionSignature functionBody 6695 * 'external'? 'static'? functionSignature functionBody
6605 * | 'external'? functionSignature ';' 6696 * | 'external'? functionSignature ';'
6606 */ 6697 */
6607 MethodDeclaration _parseMethodDeclarationAfterReturnType( 6698 MethodDeclaration _parseMethodDeclarationAfterReturnType(
6608 CommentAndMetadata commentAndMetadata, 6699 CommentAndMetadata commentAndMetadata,
6609 Token externalKeyword, 6700 Token externalKeyword,
6610 Token staticKeyword, 6701 Token staticKeyword,
6611 TypeName returnType) { 6702 TypeName returnType) {
6612 SimpleIdentifier methodName = parseSimpleIdentifier(); 6703 SimpleIdentifier methodName = parseSimpleIdentifier();
6613 TypeParameterList typeParameters = null; 6704 TypeParameterList typeParameters = _parseGenericMethodTypeParameters();
6614 if (parseGenericMethods && _matches(TokenType.LT)) {
6615 typeParameters = parseTypeParameterList();
6616 }
6617 FormalParameterList parameters; 6705 FormalParameterList parameters;
6618 if (!_matches(TokenType.OPEN_PAREN) && 6706 if (!_matches(TokenType.OPEN_PAREN) &&
6619 (_matches(TokenType.OPEN_CURLY_BRACKET) || 6707 (_matches(TokenType.OPEN_CURLY_BRACKET) ||
6620 _matches(TokenType.FUNCTION))) { 6708 _matches(TokenType.FUNCTION))) {
6621 _reportErrorForToken( 6709 _reportErrorForToken(
6622 ParserErrorCode.MISSING_METHOD_PARAMETERS, _currentToken.previous); 6710 ParserErrorCode.MISSING_METHOD_PARAMETERS, _currentToken.previous);
6623 parameters = new FormalParameterList( 6711 parameters = new FormalParameterList(
6624 _createSyntheticToken(TokenType.OPEN_PAREN), 6712 _createSyntheticToken(TokenType.OPEN_PAREN),
6625 null, 6713 null,
6626 null, 6714 null,
(...skipping 447 matching lines...) Expand 10 before | Expand all | Expand 10 after
7074 */ 7162 */
7075 Expression _parsePostfixExpression() { 7163 Expression _parsePostfixExpression() {
7076 Expression operand = _parseAssignableExpression(true); 7164 Expression operand = _parseAssignableExpression(true);
7077 if (_matches(TokenType.OPEN_SQUARE_BRACKET) || 7165 if (_matches(TokenType.OPEN_SQUARE_BRACKET) ||
7078 _matches(TokenType.PERIOD) || 7166 _matches(TokenType.PERIOD) ||
7079 _matches(TokenType.QUESTION_PERIOD) || 7167 _matches(TokenType.QUESTION_PERIOD) ||
7080 _matches(TokenType.OPEN_PAREN) || 7168 _matches(TokenType.OPEN_PAREN) ||
7081 (parseGenericMethods && _matches(TokenType.LT))) { 7169 (parseGenericMethods && _matches(TokenType.LT))) {
7082 do { 7170 do {
7083 if (_isLikelyParameterList()) { 7171 if (_isLikelyParameterList()) {
7084 TypeArgumentList typeArguments = null; 7172 TypeArgumentList typeArguments = _maybeParseTypeArguments();
7085 if (_matches(TokenType.LT)) {
7086 typeArguments = parseTypeArgumentList();
7087 }
7088 ArgumentList argumentList = parseArgumentList(); 7173 ArgumentList argumentList = parseArgumentList();
7089 if (operand is PropertyAccess) { 7174 if (operand is PropertyAccess) {
7090 PropertyAccess access = operand as PropertyAccess; 7175 PropertyAccess access = operand as PropertyAccess;
7091 operand = new MethodInvocation(access.target, access.operator, 7176 operand = new MethodInvocation(access.target, access.operator,
7092 access.propertyName, typeArguments, argumentList); 7177 access.propertyName, typeArguments, argumentList);
7093 } else { 7178 } else {
7094 operand = new FunctionExpressionInvocation( 7179 operand = new FunctionExpressionInvocation(
7095 operand, typeArguments, argumentList); 7180 operand, typeArguments, argumentList);
7096 } 7181 }
7097 } else { 7182 } else {
(...skipping 979 matching lines...) Expand 10 before | Expand all | Expand 10 after
8077 void _reportErrorForToken(ErrorCode errorCode, Token token, 8162 void _reportErrorForToken(ErrorCode errorCode, Token token,
8078 [List<Object> arguments]) { 8163 [List<Object> arguments]) {
8079 if (token.type == TokenType.EOF) { 8164 if (token.type == TokenType.EOF) {
8080 token = token.previous; 8165 token = token.previous;
8081 } 8166 }
8082 _reportError(new AnalysisError(_source, token.offset, 8167 _reportError(new AnalysisError(_source, token.offset,
8083 math.max(token.length, 1), errorCode, arguments)); 8168 math.max(token.length, 1), errorCode, arguments));
8084 } 8169 }
8085 8170
8086 /** 8171 /**
8172 * Scans the generic method comment, and returns the tokens, otherwise
8173 * returns null.
8174 */
8175 Token _scanGenericMethodComment(String code, int offset) {
8176 BooleanErrorListener listener = new BooleanErrorListener();
8177 Scanner scanner =
8178 new Scanner(null, new SubSequenceReader(code, offset), listener);
8179 scanner.setSourceStart(1, 1);
8180 Token firstToken = scanner.tokenize();
8181 if (listener.errorReported) {
8182 // TODO(jmesserly): should we report these messages?
Brian Wilkerson 2015/11/11 21:53:42 It would help you find bugs while using this featu
Jennifer Messerly 2015/11/12 00:20:00 Good point. Removed the TODO.
8183 return null;
8184 }
8185 return firstToken;
8186 }
8187
8188 /**
8087 * Skips a block with all containing blocks. 8189 * Skips a block with all containing blocks.
8088 */ 8190 */
8089 void _skipBlock() { 8191 void _skipBlock() {
8090 Token endToken = (_currentToken as BeginToken).endToken; 8192 Token endToken = (_currentToken as BeginToken).endToken;
8091 if (endToken == null) { 8193 if (endToken == null) {
8092 endToken = _currentToken.next; 8194 endToken = _currentToken.next;
8093 while (!identical(endToken, _currentToken)) { 8195 while (!identical(endToken, _currentToken)) {
8094 _currentToken = endToken; 8196 _currentToken = endToken;
8095 endToken = _currentToken.next; 8197 endToken = _currentToken.next;
8096 } 8198 }
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after
8413 * This method must be kept in sync with [parseTypeArgumentList]. 8515 * This method must be kept in sync with [parseTypeArgumentList].
8414 * 8516 *
8415 * typeArguments ::= 8517 * typeArguments ::=
8416 * '<' typeList '>' 8518 * '<' typeList '>'
8417 * 8519 *
8418 * typeList ::= 8520 * typeList ::=
8419 * type (',' type)* 8521 * type (',' type)*
8420 */ 8522 */
8421 Token _skipTypeArgumentList(Token startToken) { 8523 Token _skipTypeArgumentList(Token startToken) {
8422 Token token = startToken; 8524 Token token = startToken;
8423 if (!_tokenMatches(token, TokenType.LT)) { 8525 if (!_tokenMatches(token, TokenType.LT) &&
8526 !_injectGenericCommentTypeList()) {
8424 return null; 8527 return null;
8425 } 8528 }
8426 token = _skipTypeName(token.next); 8529 token = _skipTypeName(token.next);
8427 if (token == null) { 8530 if (token == null) {
8428 // If the start token '<' is followed by '>' 8531 // If the start token '<' is followed by '>'
8429 // then assume this should be type argument list but is missing a type 8532 // then assume this should be type argument list but is missing a type
8430 token = startToken.next; 8533 token = startToken.next;
8431 if (_tokenMatches(token, TokenType.GT)) { 8534 if (_tokenMatches(token, TokenType.GT)) {
8432 return token.next; 8535 return token.next;
8433 } 8536 }
(...skipping 2619 matching lines...) Expand 10 before | Expand all | Expand 10 after
11053 } 11156 }
11054 11157
11055 /** 11158 /**
11056 * Copy resolution data from the [fromNode] to the [toNode]. 11159 * Copy resolution data from the [fromNode] to the [toNode].
11057 */ 11160 */
11058 static void copyResolutionData(AstNode fromNode, AstNode toNode) { 11161 static void copyResolutionData(AstNode fromNode, AstNode toNode) {
11059 ResolutionCopier copier = new ResolutionCopier(); 11162 ResolutionCopier copier = new ResolutionCopier();
11060 copier._isEqualNodes(fromNode, toNode); 11163 copier._isEqualNodes(fromNode, toNode);
11061 } 11164 }
11062 } 11165 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer/lib/src/generated/scanner.dart » ('j') | pkg/analyzer/lib/src/generated/scanner.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698