OLD | NEW |
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' show Code, Message, Template; | 7 import '../fasta_codes.dart' show Code, Message, Template; |
8 | 8 |
9 import '../fasta_codes.dart' as fasta; | 9 import '../fasta_codes.dart' as fasta; |
10 | 10 |
11 import '../scanner.dart' show ErrorToken, Token; | 11 import '../scanner.dart' show ErrorToken, Token; |
12 | 12 |
13 import '../scanner/recover.dart' show closeBraceFor, skipToEof; | 13 import '../scanner/recover.dart' show closeBraceFor, skipToEof; |
14 | 14 |
15 import '../../scanner/token.dart' | 15 import '../../scanner/token.dart' |
16 show | 16 show |
17 ASSIGNMENT_PRECEDENCE, | 17 ASSIGNMENT_PRECEDENCE, |
18 BeginToken, | 18 BeginToken, |
19 CASCADE_PRECEDENCE, | 19 CASCADE_PRECEDENCE, |
20 EQUALITY_PRECEDENCE, | 20 EQUALITY_PRECEDENCE, |
21 POSTFIX_PRECEDENCE, | 21 POSTFIX_PRECEDENCE, |
22 RELATIONAL_PRECEDENCE, | 22 RELATIONAL_PRECEDENCE, |
| 23 SyntheticStringToken, |
| 24 SyntheticToken, |
23 TokenType; | 25 TokenType; |
24 | 26 |
25 import '../scanner/token.dart' show isUserDefinableOperator; | 27 import '../scanner/token.dart' show isUserDefinableOperator; |
26 | 28 |
27 import '../scanner/token_constants.dart' | 29 import '../scanner/token_constants.dart' |
28 show | 30 show |
29 COMMA_TOKEN, | 31 COMMA_TOKEN, |
30 DOUBLE_TOKEN, | 32 DOUBLE_TOKEN, |
31 EOF_TOKEN, | 33 EOF_TOKEN, |
32 EQ_TOKEN, | 34 EQ_TOKEN, |
(...skipping 28 matching lines...) Expand all Loading... |
61 FormalParameterKind, | 63 FormalParameterKind, |
62 isMandatoryFormalParameterKind, | 64 isMandatoryFormalParameterKind, |
63 isOptionalPositionalFormalParameterKind; | 65 isOptionalPositionalFormalParameterKind; |
64 | 66 |
65 import 'identifier_context.dart' show IdentifierContext; | 67 import 'identifier_context.dart' show IdentifierContext; |
66 | 68 |
67 import 'listener.dart' show Listener; | 69 import 'listener.dart' show Listener; |
68 | 70 |
69 import 'member_kind.dart' show MemberKind; | 71 import 'member_kind.dart' show MemberKind; |
70 | 72 |
| 73 import 'token_stream_rewriter.dart'; |
| 74 |
71 import 'type_continuation.dart' | 75 import 'type_continuation.dart' |
72 show TypeContinuation, typeContiunationFromFormalParameterKind; | 76 show TypeContinuation, typeContiunationFromFormalParameterKind; |
73 | 77 |
74 import 'util.dart' show closeBraceTokenFor, optional; | 78 import 'util.dart' show closeBraceTokenFor, optional; |
75 | 79 |
76 /// An event generating parser of Dart programs. This parser expects all tokens | 80 /// An event generating parser of Dart programs. This parser expects all tokens |
77 /// in a linked list (aka a token stream). | 81 /// in a linked list (aka a token stream). |
78 /// | 82 /// |
79 /// The class [Scanner] is used to generate a token stream. See the file | 83 /// The class [Scanner] is used to generate a token stream. See the file |
80 /// [scanner.dart](../scanner.dart). | 84 /// [scanner.dart](../scanner.dart). |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
201 | 205 |
202 Uri get uri => listener.uri; | 206 Uri get uri => listener.uri; |
203 | 207 |
204 bool mayParseFunctionExpressions = true; | 208 bool mayParseFunctionExpressions = true; |
205 | 209 |
206 /// Represents parser state: what asynchronous syntax is allowed in the | 210 /// Represents parser state: what asynchronous syntax is allowed in the |
207 /// function being currently parsed. In rare situations, this can be set by | 211 /// function being currently parsed. In rare situations, this can be set by |
208 /// external clients, for example, to parse an expression outside a function. | 212 /// external clients, for example, to parse an expression outside a function. |
209 AsyncModifier asyncState = AsyncModifier.Sync; | 213 AsyncModifier asyncState = AsyncModifier.Sync; |
210 | 214 |
| 215 /// The first token in the parse stream and used during parser recovery. |
| 216 /// This is automatically set by the [parseUnit] method, |
| 217 /// but must be manually set when any other parse method is called. |
| 218 /// If not set, then the parser will call [handleUnrecoverableError] |
| 219 /// rather than rewriting the token stream |
| 220 /// and calling [handleRecoverableError]. |
| 221 Token firstToken; |
| 222 |
| 223 /// A rewriter for inserting synthetic tokens. |
| 224 /// Access using [rewriter] for lazy initialization. |
| 225 TokenStreamRewriter cachedRewriter; |
| 226 |
| 227 TokenStreamRewriter get rewriter { |
| 228 assert(firstToken != null, 'firstToken must be set for parser recovery'); |
| 229 cachedRewriter ??= new TokenStreamRewriter(firstToken); |
| 230 return cachedRewriter; |
| 231 } |
| 232 |
211 Parser(this.listener); | 233 Parser(this.listener); |
212 | 234 |
213 bool get inGenerator { | 235 bool get inGenerator { |
214 return asyncState == AsyncModifier.AsyncStar || | 236 return asyncState == AsyncModifier.AsyncStar || |
215 asyncState == AsyncModifier.SyncStar; | 237 asyncState == AsyncModifier.SyncStar; |
216 } | 238 } |
217 | 239 |
218 bool get inAsync { | 240 bool get inAsync { |
219 return asyncState == AsyncModifier.Async || | 241 return asyncState == AsyncModifier.Async || |
220 asyncState == AsyncModifier.AsyncStar; | 242 asyncState == AsyncModifier.AsyncStar; |
221 } | 243 } |
222 | 244 |
223 bool get inPlainSync => asyncState == AsyncModifier.Sync; | 245 bool get inPlainSync => asyncState == AsyncModifier.Sync; |
224 | 246 |
225 Token parseUnit(Token token) { | 247 Token parseUnit(Token token) { |
| 248 firstToken = token; |
226 listener.beginCompilationUnit(token); | 249 listener.beginCompilationUnit(token); |
227 int count = 0; | 250 int count = 0; |
228 while (!identical(token.kind, EOF_TOKEN)) { | 251 while (!identical(token.kind, EOF_TOKEN)) { |
229 token = parseTopLevelDeclaration(token); | 252 token = parseTopLevelDeclaration(token); |
230 count++; | 253 count++; |
231 } | 254 } |
232 listener.endCompilationUnit(count, token); | 255 listener.endCompilationUnit(count, token); |
| 256 // Clear fields that could lead to memory leak. |
| 257 firstToken = null; |
| 258 cachedRewriter = null; |
233 return token; | 259 return token; |
234 } | 260 } |
235 | 261 |
236 Token parseTopLevelDeclaration(Token token) { | 262 Token parseTopLevelDeclaration(Token token) { |
237 token = _parseTopLevelDeclaration(token); | 263 token = _parseTopLevelDeclaration(token); |
238 listener.endTopLevelDeclaration(token); | 264 listener.endTopLevelDeclaration(token); |
239 return token; | 265 return token; |
240 } | 266 } |
241 | 267 |
242 Token _parseTopLevelDeclaration(Token token) { | 268 Token _parseTopLevelDeclaration(Token token) { |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
349 } | 375 } |
350 listener.endDottedName(count, firstIdentifier); | 376 listener.endDottedName(count, firstIdentifier); |
351 return token; | 377 return token; |
352 } | 378 } |
353 | 379 |
354 /// export uri conditional-uris* combinator* ';' | 380 /// export uri conditional-uris* combinator* ';' |
355 Token parseExport(Token token) { | 381 Token parseExport(Token token) { |
356 Token exportKeyword = token; | 382 Token exportKeyword = token; |
357 listener.beginExport(exportKeyword); | 383 listener.beginExport(exportKeyword); |
358 assert(optional('export', token)); | 384 assert(optional('export', token)); |
359 token = parseLiteralStringOrRecoverExpression(token.next); | 385 token = ensureParseLiteralString(token.next); |
360 token = parseConditionalUris(token); | 386 token = parseConditionalUris(token); |
361 token = parseCombinators(token); | 387 token = parseCombinators(token); |
362 Token semicolon = token; | 388 Token semicolon = ensureSemicolon(token); |
363 token = expect(';', token); | |
364 listener.endExport(exportKeyword, semicolon); | 389 listener.endExport(exportKeyword, semicolon); |
365 return token; | 390 return semicolon.next; |
366 } | 391 } |
367 | 392 |
368 Token parseCombinators(Token token) { | 393 Token parseCombinators(Token token) { |
369 listener.beginCombinators(token); | 394 listener.beginCombinators(token); |
370 int count = 0; | 395 int count = 0; |
371 while (true) { | 396 while (true) { |
372 String value = token.stringValue; | 397 String value = token.stringValue; |
373 if (identical('hide', value)) { | 398 if (identical('hide', value)) { |
374 token = parseHide(token); | 399 token = parseHide(token); |
375 } else if (identical('show', value)) { | 400 } else if (identical('show', value)) { |
(...skipping 526 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
902 reportRecoverableError(token, fasta.messageYieldAsIdentifier); | 927 reportRecoverableError(token, fasta.messageYieldAsIdentifier); |
903 } else if (optional('async', token)) { | 928 } else if (optional('async', token)) { |
904 reportRecoverableError(token, fasta.messageAsyncAsIdentifier); | 929 reportRecoverableError(token, fasta.messageAsyncAsIdentifier); |
905 } | 930 } |
906 } | 931 } |
907 listener.handleIdentifier(token, context); | 932 listener.handleIdentifier(token, context); |
908 return token.next; | 933 return token.next; |
909 } | 934 } |
910 | 935 |
911 Token expect(String string, Token token) { | 936 Token expect(String string, Token token) { |
| 937 // TODO(danrubel) update all uses of expect(';'...) to ensureSemicolon |
| 938 // then add assert(!identical(';', string)); |
912 if (!identical(string, token.stringValue)) { | 939 if (!identical(string, token.stringValue)) { |
913 return reportUnrecoverableError( | 940 return reportUnrecoverableError( |
914 token, fasta.templateExpectedButGot.withArguments(string)) | 941 token, fasta.templateExpectedButGot.withArguments(string)) |
915 .next; | 942 .next; |
916 } | 943 } |
917 return token.next; | 944 return token.next; |
918 } | 945 } |
919 | 946 |
920 Token parseTypeVariable(Token token) { | 947 Token parseTypeVariable(Token token) { |
921 listener.beginTypeVariable(token); | 948 listener.beginTypeVariable(token); |
(...skipping 998 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1920 listener.beginInitializer(token); | 1947 listener.beginInitializer(token); |
1921 if (optional('assert', token)) { | 1948 if (optional('assert', token)) { |
1922 token = parseAssert(token, Assert.Initializer); | 1949 token = parseAssert(token, Assert.Initializer); |
1923 } else { | 1950 } else { |
1924 token = parseExpression(token); | 1951 token = parseExpression(token); |
1925 } | 1952 } |
1926 listener.endInitializer(token); | 1953 listener.endInitializer(token); |
1927 return token; | 1954 return token; |
1928 } | 1955 } |
1929 | 1956 |
| 1957 Token ensureParseLiteralString(Token token) { |
| 1958 if (!identical(token.kind, STRING_TOKEN)) { |
| 1959 Message message = fasta.templateExpectedString.withArguments(token); |
| 1960 Token newToken = |
| 1961 new SyntheticStringToken(TokenType.STRING, '""', token.charOffset, 0); |
| 1962 token = rewriteAndRecover(token, message, newToken); |
| 1963 } |
| 1964 return parseLiteralString(token); |
| 1965 } |
| 1966 |
| 1967 Token ensureSemicolon(Token token) { |
| 1968 // TODO(danrubel): Once all expect(';'...) call sites have been converted |
| 1969 // to use this method, remove similar semicolon recovery code |
| 1970 // from the handleError method in element_listener.dart. |
| 1971 if (optional(';', token)) return token; |
| 1972 Message message = fasta.templateExpectedButGot.withArguments(';'); |
| 1973 Token newToken = new SyntheticToken(TokenType.SEMICOLON, token.charOffset); |
| 1974 return rewriteAndRecover(token, message, newToken); |
| 1975 } |
| 1976 |
| 1977 Token rewriteAndRecover(Token token, Message message, Token newToken) { |
| 1978 if (firstToken == null) return reportUnrecoverableError(token, message); |
| 1979 reportRecoverableError(token, message); |
| 1980 token = rewriter.insertTokenBefore(newToken, token); |
| 1981 return token; |
| 1982 } |
| 1983 |
1930 Token parseLiteralStringOrRecoverExpression(Token token) { | 1984 Token parseLiteralStringOrRecoverExpression(Token token) { |
1931 if (identical(token.kind, STRING_TOKEN)) { | 1985 if (identical(token.kind, STRING_TOKEN)) { |
1932 return parseLiteralString(token); | 1986 return parseLiteralString(token); |
1933 } else if (token is ErrorToken) { | 1987 } else if (token is ErrorToken) { |
1934 return reportErrorToken(token, false); | 1988 return reportErrorToken(token, false); |
1935 } else { | 1989 } else { |
1936 reportRecoverableErrorWithToken(token, fasta.templateExpectedString); | 1990 reportRecoverableErrorWithToken(token, fasta.templateExpectedString); |
1937 return parseRecoverExpression( | 1991 return parseRecoverExpression( |
1938 token, fasta.templateExpectedString.withArguments(token)); | 1992 token, fasta.templateExpectedString.withArguments(token)); |
1939 } | 1993 } |
(...skipping 2143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4083 } | 4137 } |
4084 | 4138 |
4085 Token reportUnexpectedToken(Token token) { | 4139 Token reportUnexpectedToken(Token token) { |
4086 return reportUnrecoverableErrorWithToken( | 4140 return reportUnrecoverableErrorWithToken( |
4087 token, fasta.templateUnexpectedToken); | 4141 token, fasta.templateUnexpectedToken); |
4088 } | 4142 } |
4089 } | 4143 } |
4090 | 4144 |
4091 // TODO(ahe): Remove when analyzer supports generalized function syntax. | 4145 // TODO(ahe): Remove when analyzer supports generalized function syntax. |
4092 typedef _MessageWithArgument<T> = Message Function(T); | 4146 typedef _MessageWithArgument<T> = Message Function(T); |
OLD | NEW |