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

Side by Side Diff: pkg/front_end/lib/src/fasta/parser/parser.dart

Issue 2795063002: Add support for parsing comments with generic parameters /*<K, V>*/ with Fasta. (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « pkg/analyzer/test/generated/parser_fasta_test.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 fasta.parser.parser; 5 library fasta.parser.parser;
6 6
7 import '../fasta_codes.dart' 7 import '../fasta_codes.dart'
8 show 8 show
9 FastaCode, 9 FastaCode,
10 FastaMessage, 10 FastaMessage,
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
58 58
59 import '../scanner/recover.dart' show closeBraceFor, skipToEof; 59 import '../scanner/recover.dart' show closeBraceFor, skipToEof;
60 60
61 import '../scanner/keyword.dart' show Keyword; 61 import '../scanner/keyword.dart' show Keyword;
62 62
63 import '../scanner/precedence.dart' 63 import '../scanner/precedence.dart'
64 show 64 show
65 ASSIGNMENT_PRECEDENCE, 65 ASSIGNMENT_PRECEDENCE,
66 AS_INFO, 66 AS_INFO,
67 CASCADE_PRECEDENCE, 67 CASCADE_PRECEDENCE,
68 EOF_INFO,
68 EQUALITY_PRECEDENCE, 69 EQUALITY_PRECEDENCE,
70 GENERIC_METHOD_TYPE_ASSIGN,
71 GENERIC_METHOD_TYPE_LIST,
69 GT_INFO, 72 GT_INFO,
70 IS_INFO, 73 IS_INFO,
71 MINUS_MINUS_INFO, 74 MINUS_MINUS_INFO,
72 OPEN_PAREN_INFO, 75 OPEN_PAREN_INFO,
73 OPEN_SQUARE_BRACKET_INFO, 76 OPEN_SQUARE_BRACKET_INFO,
74 PERIOD_INFO, 77 PERIOD_INFO,
75 PLUS_PLUS_INFO, 78 PLUS_PLUS_INFO,
76 POSTFIX_PRECEDENCE, 79 POSTFIX_PRECEDENCE,
77 PrecedenceInfo, 80 PrecedenceInfo,
78 QUESTION_INFO, 81 QUESTION_INFO,
79 QUESTION_PERIOD_INFO, 82 QUESTION_PERIOD_INFO,
80 RELATIONAL_PRECEDENCE, 83 RELATIONAL_PRECEDENCE,
81 SCRIPT_INFO; 84 SCRIPT_INFO;
82 85
83 import '../scanner/token.dart' 86 import '../scanner/token.dart'
84 show 87 show
85 BeginGroupToken, 88 BeginGroupToken,
89 CommentToken,
86 KeywordToken, 90 KeywordToken,
87 SymbolToken, 91 SymbolToken,
88 Token, 92 Token,
89 isUserDefinableOperator; 93 isUserDefinableOperator;
90 94
91 import '../scanner/token_constants.dart' 95 import '../scanner/token_constants.dart'
92 show 96 show
93 COMMA_TOKEN, 97 COMMA_TOKEN,
94 DOUBLE_TOKEN, 98 DOUBLE_TOKEN,
95 EOF_TOKEN, 99 EOF_TOKEN,
(...skipping 10 matching lines...) Expand all
106 OPEN_CURLY_BRACKET_TOKEN, 110 OPEN_CURLY_BRACKET_TOKEN,
107 OPEN_PAREN_TOKEN, 111 OPEN_PAREN_TOKEN,
108 OPEN_SQUARE_BRACKET_TOKEN, 112 OPEN_SQUARE_BRACKET_TOKEN,
109 PERIOD_TOKEN, 113 PERIOD_TOKEN,
110 SEMICOLON_TOKEN, 114 SEMICOLON_TOKEN,
111 STRING_INTERPOLATION_IDENTIFIER_TOKEN, 115 STRING_INTERPOLATION_IDENTIFIER_TOKEN,
112 STRING_INTERPOLATION_TOKEN, 116 STRING_INTERPOLATION_TOKEN,
113 STRING_TOKEN; 117 STRING_TOKEN;
114 118
115 import '../scanner/characters.dart' show $CLOSE_CURLY_BRACKET; 119 import '../scanner/characters.dart' show $CLOSE_CURLY_BRACKET;
120 import '../scanner/string_scanner.dart';
ahe 2017/04/04 08:10:45 The parser shouldn't be importing as specific scan
scheglov 2017/04/04 15:33:47 Why? The parser knows what it wants to parse and h
116 121
117 import '../util/link.dart' show Link; 122 import '../util/link.dart' show Link;
118 123
119 import 'async_modifier.dart' show AsyncModifier; 124 import 'async_modifier.dart' show AsyncModifier;
120 125
121 import 'listener.dart' show Listener; 126 import 'listener.dart' show Listener;
122 127
123 import 'identifier_context.dart' show IdentifierContext; 128 import 'identifier_context.dart' show IdentifierContext;
124 129
125 /// Returns true if [token] is the symbol or keyword [value]. 130 /// Returns true if [token] is the symbol or keyword [value].
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
177 /// 182 ///
178 /// Historically, we over-used identical, and when identical is used on other 183 /// Historically, we over-used identical, and when identical is used on other
179 /// objects than strings, it can often be replaced by `==`. 184 /// objects than strings, it can often be replaced by `==`.
180 class Parser { 185 class Parser {
181 final Listener listener; 186 final Listener listener;
182 187
183 Uri get uri => listener.uri; 188 Uri get uri => listener.uri;
184 189
185 bool mayParseFunctionExpressions = true; 190 bool mayParseFunctionExpressions = true;
186 191
192 bool parseGenericMethodComments = false;
193
187 /// Represents parser state: what asynchronous syntax is allowed in the 194 /// Represents parser state: what asynchronous syntax is allowed in the
188 /// function being currently parsed. In rare situations, this can be set by 195 /// function being currently parsed. In rare situations, this can be set by
189 /// external clients, for example, to parse an expression outside a function. 196 /// external clients, for example, to parse an expression outside a function.
190 AsyncModifier asyncState = AsyncModifier.Sync; 197 AsyncModifier asyncState = AsyncModifier.Sync;
191 198
192 Parser(this.listener); 199 Parser(this.listener);
193 200
194 bool get inGenerator { 201 bool get inGenerator {
195 return asyncState == AsyncModifier.AsyncStar || 202 return asyncState == AsyncModifier.AsyncStar ||
196 asyncState == AsyncModifier.SyncStar; 203 asyncState == AsyncModifier.SyncStar;
(...skipping 429 matching lines...) Expand 10 before | Expand all | Expand 10 after
626 token = expect('.', token.next); 633 token = expect('.', token.next);
627 nameToken = token; 634 nameToken = token;
628 token = parseIdentifier(token, IdentifierContext.fieldInitializer); 635 token = parseIdentifier(token, IdentifierContext.fieldInitializer);
629 } else { 636 } else {
630 nameToken = token; 637 nameToken = token;
631 token = parseIdentifier( 638 token = parseIdentifier(
632 token, IdentifierContext.formalParameterDeclaration); 639 token, IdentifierContext.formalParameterDeclaration);
633 } 640 }
634 } 641 }
635 642
643 token = _injectGenericCommentTypeList(token);
ahe 2017/04/04 08:10:45 This method should be public and overridden in a s
scheglov 2017/04/04 15:33:47 In which subclass?
636 if (optional('(', token)) { 644 if (optional('(', token)) {
637 Token inlineFunctionTypeStart = token; 645 Token inlineFunctionTypeStart = token;
638 listener.beginFunctionTypedFormalParameter(token); 646 listener.beginFunctionTypedFormalParameter(token);
639 listener.handleNoTypeVariables(token); 647 listener.handleNoTypeVariables(token);
640 token = parseFormalParameters(token); 648 token = parseFormalParameters(token);
641 listener.endFunctionTypedFormalParameter( 649 listener.endFunctionTypedFormalParameter(
642 covariantKeyword, thisKeyword, kind); 650 covariantKeyword, thisKeyword, kind);
643 // Generalized function types don't allow inline function types. 651 // Generalized function types don't allow inline function types.
644 // The following isn't allowed: 652 // The following isn't allowed:
645 // int Function(int bar(String x)). 653 // int Function(int bar(String x)).
(...skipping 454 matching lines...) Expand 10 before | Expand all | Expand 10 after
1100 1108
1101 Token parseTypeVariablesOpt(Token token) { 1109 Token parseTypeVariablesOpt(Token token) {
1102 return parseStuff( 1110 return parseStuff(
1103 token, 1111 token,
1104 (t) => listener.beginTypeVariables(t), 1112 (t) => listener.beginTypeVariables(t),
1105 (t) => parseTypeVariable(t), 1113 (t) => parseTypeVariable(t),
1106 (c, bt, et) => listener.endTypeVariables(c, bt, et), 1114 (c, bt, et) => listener.endTypeVariables(c, bt, et),
1107 (t) => listener.handleNoTypeVariables(t)); 1115 (t) => listener.handleNoTypeVariables(t));
1108 } 1116 }
1109 1117
1110 // TODO(ahe): Clean this up. 1118 /// TODO(ahe): Clean this up.
ahe 2017/04/04 08:10:45 This isn't a documentation comment.
scheglov 2017/04/04 15:33:47 Well, I think any comment before a method, and whi
1111 Token parseStuff(Token token, Function beginStuff, Function stuffParser, 1119 Token parseStuff(Token token, Function beginStuff, Function stuffParser,
1112 Function endStuff, Function handleNoStuff) { 1120 Function endStuff, Function handleNoStuff) {
1121 token = _injectGenericCommentTypeList(token);
1113 if (optional('<', token)) { 1122 if (optional('<', token)) {
1114 Token begin = token; 1123 Token begin = token;
1115 beginStuff(begin); 1124 beginStuff(begin);
1116 int count = 0; 1125 int count = 0;
1117 do { 1126 do {
1118 token = stuffParser(token.next); 1127 token = stuffParser(token.next);
1119 ++count; 1128 ++count;
1120 } while (optional(',', token)); 1129 } while (optional(',', token));
1121 Token next = token.next; 1130 Token next = token.next;
1122 if (identical(token.stringValue, '>>')) { 1131 if (identical(token.stringValue, '>>')) {
(...skipping 1658 matching lines...) Expand 10 before | Expand all | Expand 10 after
2781 token = parseArguments(token); 2790 token = parseArguments(token);
2782 listener.endSend(beginToken, token); 2791 listener.endSend(beginToken, token);
2783 } else { 2792 } else {
2784 break; 2793 break;
2785 } 2794 }
2786 } 2795 }
2787 return token; 2796 return token;
2788 } 2797 }
2789 2798
2790 Token parsePrimary(Token token, IdentifierContext context) { 2799 Token parsePrimary(Token token, IdentifierContext context) {
2800 token = _injectGenericCommentTypeList(token);
2791 final kind = token.kind; 2801 final kind = token.kind;
2792 if (kind == IDENTIFIER_TOKEN) { 2802 if (kind == IDENTIFIER_TOKEN) {
2793 return parseSendOrFunctionLiteral(token, context); 2803 return parseSendOrFunctionLiteral(token, context);
2794 } else if (kind == INT_TOKEN || kind == HEXADECIMAL_TOKEN) { 2804 } else if (kind == INT_TOKEN || kind == HEXADECIMAL_TOKEN) {
2795 return parseLiteralInt(token); 2805 return parseLiteralInt(token);
2796 } else if (kind == DOUBLE_TOKEN) { 2806 } else if (kind == DOUBLE_TOKEN) {
2797 return parseLiteralDouble(token); 2807 return parseLiteralDouble(token);
2798 } else if (kind == STRING_TOKEN) { 2808 } else if (kind == STRING_TOKEN) {
2799 return parseLiteralString(token); 2809 return parseLiteralString(token);
2800 } else if (kind == HASH_TOKEN) { 2810 } else if (kind == HASH_TOKEN) {
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after
3073 listener.beginNewExpression(newKeyword); 3083 listener.beginNewExpression(newKeyword);
3074 token = parseConstructorReference(token); 3084 token = parseConstructorReference(token);
3075 token = parseRequiredArguments(token); 3085 token = parseRequiredArguments(token);
3076 listener.endNewExpression(newKeyword); 3086 listener.endNewExpression(newKeyword);
3077 return token; 3087 return token;
3078 } 3088 }
3079 3089
3080 Token parseConstExpression(Token token) { 3090 Token parseConstExpression(Token token) {
3081 Token constKeyword = token; 3091 Token constKeyword = token;
3082 token = expect('const', token); 3092 token = expect('const', token);
3093 token = _injectGenericCommentTypeList(token);
3083 final String value = token.stringValue; 3094 final String value = token.stringValue;
3084 if ((identical(value, '[')) || (identical(value, '[]'))) { 3095 if ((identical(value, '[')) || (identical(value, '[]'))) {
3085 listener.handleNoTypeArguments(token); 3096 listener.handleNoTypeArguments(token);
3086 return parseLiteralListSuffix(token, constKeyword); 3097 return parseLiteralListSuffix(token, constKeyword);
3087 } 3098 }
3088 if (identical(value, '{')) { 3099 if (identical(value, '{')) {
3089 listener.handleNoTypeArguments(token); 3100 listener.handleNoTypeArguments(token);
3090 return parseLiteralMapSuffix(token, constKeyword); 3101 return parseLiteralMapSuffix(token, constKeyword);
3091 } 3102 }
3092 if (identical(value, '<')) { 3103 if (identical(value, '<')) {
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
3186 3197
3187 Token parseLiteralNull(Token token) { 3198 Token parseLiteralNull(Token token) {
3188 listener.handleLiteralNull(token); 3199 listener.handleLiteralNull(token);
3189 return token.next; 3200 return token.next;
3190 } 3201 }
3191 3202
3192 Token parseSend(Token token, IdentifierContext context) { 3203 Token parseSend(Token token, IdentifierContext context) {
3193 Token beginToken = token; 3204 Token beginToken = token;
3194 listener.beginSend(token); 3205 listener.beginSend(token);
3195 token = parseIdentifier(token, context); 3206 token = parseIdentifier(token, context);
3207 token = _injectGenericCommentTypeList(token);
3196 if (isValidMethodTypeArguments(token)) { 3208 if (isValidMethodTypeArguments(token)) {
3197 token = parseTypeArgumentsOpt(token); 3209 token = parseTypeArgumentsOpt(token);
3198 } else { 3210 } else {
3199 listener.handleNoTypeArguments(token); 3211 listener.handleNoTypeArguments(token);
3200 } 3212 }
3201 token = parseArgumentsOpt(token); 3213 token = parseArgumentsOpt(token);
3202 listener.endSend(beginToken, token); 3214 listener.endSend(beginToken, token);
3203 return token; 3215 return token;
3204 } 3216 }
3205 3217
(...skipping 576 matching lines...) Expand 10 before | Expand all | Expand 10 after
3782 Token token, FastaCode<TokenArgument> code) { 3794 Token token, FastaCode<TokenArgument> code) {
3783 return reportUnrecoverableError( 3795 return reportUnrecoverableError(
3784 token, () => code.format(uri, token.charOffset, token)); 3796 token, () => code.format(uri, token.charOffset, token));
3785 } 3797 }
3786 3798
3787 Token reportUnrecoverableErrorCodeWithString( 3799 Token reportUnrecoverableErrorCodeWithString(
3788 Token token, FastaCode<StringArgument> code, String string) { 3800 Token token, FastaCode<StringArgument> code, String string) {
3789 return reportUnrecoverableError( 3801 return reportUnrecoverableError(
3790 token, () => code.format(uri, token.charOffset, string)); 3802 token, () => code.format(uri, token.charOffset, string));
3791 } 3803 }
3804
3805 /// Matches a generic comment type parameters or type arguments and injects
3806 /// them into the token stream before the given [token].
3807 Token _injectGenericCommentTypeList(Token token) {
3808 return _injectGenericComment(token, GENERIC_METHOD_TYPE_LIST, 2);
3809 }
3810
3811 /// Check if the given [token] has a comment token with the given [info],
3812 /// which should be either [GENERIC_METHOD_TYPE_ASSIGN] or
3813 /// [GENERIC_METHOD_TYPE_LIST]. If found, parse the comment into tokens and
3814 /// inject into the token stream before the [token].
3815 Token _injectGenericComment(Token token, PrecedenceInfo info, int prefixLen) {
3816 if (parseGenericMethodComments) {
3817 CommentToken t = token.precedingCommentTokens;
3818 for (; t != null; t = t.next) {
3819 if (t.info == info) {
3820 String code = t.lexeme.substring(prefixLen, t.lexeme.length - 2);
3821 Token tokens = _scanGenericMethodComment(code, t.offset + prefixLen);
3822 if (tokens != null) {
3823 // Remove the token from the comment stream.
3824 t.remove();
3825 // Insert the tokens into the stream.
3826 _injectTokenList(token, tokens);
3827 return tokens;
3828 }
3829 }
3830 }
3831 }
3832 return token;
3833 }
3834
3835 /// Scans the given [code], and returns the tokens, otherwise returns `null`.
3836 Token _scanGenericMethodComment(String code, int offset) {
3837 // TODO(scheglov) Let StringScanner to specify the string offset.
3838 var scanner = new StringScanner(' ' * offset + code);
ahe 2017/04/04 08:10:45 The listener should be asked how to create a scann
scheglov 2017/04/04 15:33:47 What do we want to extend? These comments are part
3839 Token firstToken = scanner.tokenize();
3840 if (scanner.hasErrors) {
3841 return null;
3842 }
3843 return firstToken;
3844 }
3845
3846 void _injectTokenList(Token beforeToken, Token firstToken) {
3847 // Scanner creates a cyclic EOF token.
3848 Token lastToken = firstToken;
3849 while (lastToken.next.info != EOF_INFO) {
3850 lastToken = lastToken.next;
3851 }
3852 // Inject these new tokens into the stream.
3853 Token previous = beforeToken.previous;
3854 lastToken.setNext(beforeToken);
3855 previous.setNext(firstToken);
3856 beforeToken = firstToken;
3857 }
3792 } 3858 }
3793 3859
3794 typedef FastaMessage NoArgument(Uri uri, int charOffset); 3860 typedef FastaMessage NoArgument(Uri uri, int charOffset);
3795 3861
3796 typedef FastaMessage TokenArgument(Uri uri, int charOffset, Token token); 3862 typedef FastaMessage TokenArgument(Uri uri, int charOffset, Token token);
3797 3863
3798 typedef FastaMessage StringArgument(Uri uri, int charOffset, String string); 3864 typedef FastaMessage StringArgument(Uri uri, int charOffset, String string);
OLDNEW
« no previous file with comments | « pkg/analyzer/test/generated/parser_fasta_test.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698