| OLD | NEW |
| (Empty) |
| 1 // This code was auto-generated, is not intended to be edited, and is subject to | |
| 2 // significant change. Please see the README file for more information. | |
| 3 | |
| 4 library engine.parser; | |
| 5 | |
| 6 import 'dart:collection'; | |
| 7 import 'java_core.dart'; | |
| 8 import 'java_engine.dart'; | |
| 9 import 'error.dart'; | |
| 10 import 'source.dart'; | |
| 11 import 'scanner.dart'; | |
| 12 import 'ast.dart'; | |
| 13 import 'package:analyzer-experimental/src/generated/utilities_dart.dart'; | |
| 14 | |
| 15 /** | |
| 16 * Instances of the class {@code CommentAndMetadata} implement a simple data-hol
der for a method | |
| 17 * that needs to return multiple values. | |
| 18 * @coverage dart.engine.parser | |
| 19 */ | |
| 20 class CommentAndMetadata { | |
| 21 /** | |
| 22 * The documentation comment that was parsed, or {@code null} if none was give
n. | |
| 23 */ | |
| 24 Comment _comment; | |
| 25 /** | |
| 26 * The metadata that was parsed. | |
| 27 */ | |
| 28 List<Annotation> _metadata; | |
| 29 /** | |
| 30 * Initialize a newly created holder with the given data. | |
| 31 * @param comment the documentation comment that was parsed | |
| 32 * @param metadata the metadata that was parsed | |
| 33 */ | |
| 34 CommentAndMetadata(Comment comment, List<Annotation> metadata) { | |
| 35 this._comment = comment; | |
| 36 this._metadata = metadata; | |
| 37 } | |
| 38 /** | |
| 39 * Return the documentation comment that was parsed, or {@code null} if none w
as given. | |
| 40 * @return the documentation comment that was parsed | |
| 41 */ | |
| 42 Comment get comment => _comment; | |
| 43 /** | |
| 44 * Return the metadata that was parsed. If there was no metadata, then the lis
t will be empty. | |
| 45 * @return the metadata that was parsed | |
| 46 */ | |
| 47 List<Annotation> get metadata => _metadata; | |
| 48 } | |
| 49 /** | |
| 50 * Instances of the class {@code FinalConstVarOrType} implement a simple data-ho
lder for a method | |
| 51 * that needs to return multiple values. | |
| 52 * @coverage dart.engine.parser | |
| 53 */ | |
| 54 class FinalConstVarOrType { | |
| 55 /** | |
| 56 * The 'final', 'const' or 'var' keyword, or {@code null} if none was given. | |
| 57 */ | |
| 58 Token _keyword; | |
| 59 /** | |
| 60 * The type, of {@code null} if no type was specified. | |
| 61 */ | |
| 62 TypeName _type; | |
| 63 /** | |
| 64 * Initialize a newly created holder with the given data. | |
| 65 * @param keyword the 'final', 'const' or 'var' keyword | |
| 66 * @param type the type | |
| 67 */ | |
| 68 FinalConstVarOrType(Token keyword, TypeName type) { | |
| 69 this._keyword = keyword; | |
| 70 this._type = type; | |
| 71 } | |
| 72 /** | |
| 73 * Return the 'final', 'const' or 'var' keyword, or {@code null} if none was g
iven. | |
| 74 * @return the 'final', 'const' or 'var' keyword | |
| 75 */ | |
| 76 Token get keyword => _keyword; | |
| 77 /** | |
| 78 * Return the type, of {@code null} if no type was specified. | |
| 79 * @return the type | |
| 80 */ | |
| 81 TypeName get type => _type; | |
| 82 } | |
| 83 /** | |
| 84 * Instances of the class {@code Modifiers} implement a simple data-holder for a
method that needs | |
| 85 * to return multiple values. | |
| 86 * @coverage dart.engine.parser | |
| 87 */ | |
| 88 class Modifiers { | |
| 89 /** | |
| 90 * The token representing the keyword 'abstract', or {@code null} if the keywo
rd was not found. | |
| 91 */ | |
| 92 Token _abstractKeyword; | |
| 93 /** | |
| 94 * The token representing the keyword 'const', or {@code null} if the keyword
was not found. | |
| 95 */ | |
| 96 Token _constKeyword; | |
| 97 /** | |
| 98 * The token representing the keyword 'external', or {@code null} if the keywo
rd was not found. | |
| 99 */ | |
| 100 Token _externalKeyword; | |
| 101 /** | |
| 102 * The token representing the keyword 'factory', or {@code null} if the keywor
d was not found. | |
| 103 */ | |
| 104 Token _factoryKeyword; | |
| 105 /** | |
| 106 * The token representing the keyword 'final', or {@code null} if the keyword
was not found. | |
| 107 */ | |
| 108 Token _finalKeyword; | |
| 109 /** | |
| 110 * The token representing the keyword 'static', or {@code null} if the keyword
was not found. | |
| 111 */ | |
| 112 Token _staticKeyword; | |
| 113 /** | |
| 114 * The token representing the keyword 'var', or {@code null} if the keyword wa
s not found. | |
| 115 */ | |
| 116 Token _varKeyword; | |
| 117 /** | |
| 118 * Initialize a newly created and empty set of modifiers. | |
| 119 */ | |
| 120 Modifiers() : super() { | |
| 121 } | |
| 122 /** | |
| 123 * Return the token representing the keyword 'abstract', or {@code null} if th
e keyword was not | |
| 124 * found. | |
| 125 * @return the token representing the keyword 'abstract' | |
| 126 */ | |
| 127 Token get abstractKeyword => _abstractKeyword; | |
| 128 /** | |
| 129 * Return the token representing the keyword 'const', or {@code null} if the k
eyword was not | |
| 130 * found. | |
| 131 * @return the token representing the keyword 'const' | |
| 132 */ | |
| 133 Token get constKeyword => _constKeyword; | |
| 134 /** | |
| 135 * Return the token representing the keyword 'external', or {@code null} if th
e keyword was not | |
| 136 * found. | |
| 137 * @return the token representing the keyword 'external' | |
| 138 */ | |
| 139 Token get externalKeyword => _externalKeyword; | |
| 140 /** | |
| 141 * Return the token representing the keyword 'factory', or {@code null} if the
keyword was not | |
| 142 * found. | |
| 143 * @return the token representing the keyword 'factory' | |
| 144 */ | |
| 145 Token get factoryKeyword => _factoryKeyword; | |
| 146 /** | |
| 147 * Return the token representing the keyword 'final', or {@code null} if the k
eyword was not | |
| 148 * found. | |
| 149 * @return the token representing the keyword 'final' | |
| 150 */ | |
| 151 Token get finalKeyword => _finalKeyword; | |
| 152 /** | |
| 153 * Return the token representing the keyword 'static', or {@code null} if the
keyword was not | |
| 154 * found. | |
| 155 * @return the token representing the keyword 'static' | |
| 156 */ | |
| 157 Token get staticKeyword => _staticKeyword; | |
| 158 /** | |
| 159 * Return the token representing the keyword 'var', or {@code null} if the key
word was not found. | |
| 160 * @return the token representing the keyword 'var' | |
| 161 */ | |
| 162 Token get varKeyword => _varKeyword; | |
| 163 /** | |
| 164 * Set the token representing the keyword 'abstract' to the given token. | |
| 165 * @param abstractKeyword the token representing the keyword 'abstract' | |
| 166 */ | |
| 167 void set abstractKeyword(Token abstractKeyword4) { | |
| 168 this._abstractKeyword = abstractKeyword4; | |
| 169 } | |
| 170 /** | |
| 171 * Set the token representing the keyword 'const' to the given token. | |
| 172 * @param constKeyword the token representing the keyword 'const' | |
| 173 */ | |
| 174 void set constKeyword(Token constKeyword3) { | |
| 175 this._constKeyword = constKeyword3; | |
| 176 } | |
| 177 /** | |
| 178 * Set the token representing the keyword 'external' to the given token. | |
| 179 * @param externalKeyword the token representing the keyword 'external' | |
| 180 */ | |
| 181 void set externalKeyword(Token externalKeyword5) { | |
| 182 this._externalKeyword = externalKeyword5; | |
| 183 } | |
| 184 /** | |
| 185 * Set the token representing the keyword 'factory' to the given token. | |
| 186 * @param factoryKeyword the token representing the keyword 'factory' | |
| 187 */ | |
| 188 void set factoryKeyword(Token factoryKeyword3) { | |
| 189 this._factoryKeyword = factoryKeyword3; | |
| 190 } | |
| 191 /** | |
| 192 * Set the token representing the keyword 'final' to the given token. | |
| 193 * @param finalKeyword the token representing the keyword 'final' | |
| 194 */ | |
| 195 void set finalKeyword(Token finalKeyword2) { | |
| 196 this._finalKeyword = finalKeyword2; | |
| 197 } | |
| 198 /** | |
| 199 * Set the token representing the keyword 'static' to the given token. | |
| 200 * @param staticKeyword the token representing the keyword 'static' | |
| 201 */ | |
| 202 void set staticKeyword(Token staticKeyword2) { | |
| 203 this._staticKeyword = staticKeyword2; | |
| 204 } | |
| 205 /** | |
| 206 * Set the token representing the keyword 'var' to the given token. | |
| 207 * @param varKeyword the token representing the keyword 'var' | |
| 208 */ | |
| 209 void set varKeyword(Token varKeyword2) { | |
| 210 this._varKeyword = varKeyword2; | |
| 211 } | |
| 212 String toString() { | |
| 213 JavaStringBuilder builder = new JavaStringBuilder(); | |
| 214 bool needsSpace = appendKeyword(builder, false, _abstractKeyword); | |
| 215 needsSpace = appendKeyword(builder, needsSpace, _constKeyword); | |
| 216 needsSpace = appendKeyword(builder, needsSpace, _externalKeyword); | |
| 217 needsSpace = appendKeyword(builder, needsSpace, _factoryKeyword); | |
| 218 needsSpace = appendKeyword(builder, needsSpace, _finalKeyword); | |
| 219 needsSpace = appendKeyword(builder, needsSpace, _staticKeyword); | |
| 220 appendKeyword(builder, needsSpace, _varKeyword); | |
| 221 return builder.toString(); | |
| 222 } | |
| 223 /** | |
| 224 * If the given keyword is not {@code null}, append it to the given builder, p
refixing it with a | |
| 225 * space if needed. | |
| 226 * @param builder the builder to which the keyword will be appended | |
| 227 * @param needsSpace {@code true} if the keyword needs to be prefixed with a s
pace | |
| 228 * @param keyword the keyword to be appended | |
| 229 * @return {@code true} if subsequent keywords need to be prefixed with a spac
e | |
| 230 */ | |
| 231 bool appendKeyword(JavaStringBuilder builder, bool needsSpace, Token keyword)
{ | |
| 232 if (keyword != null) { | |
| 233 if (needsSpace) { | |
| 234 builder.appendChar(0x20); | |
| 235 } | |
| 236 builder.append(keyword.lexeme); | |
| 237 return true; | |
| 238 } | |
| 239 return needsSpace; | |
| 240 } | |
| 241 } | |
| 242 /** | |
| 243 * Instances of the class {@code Parser} are used to parse tokens into an AST st
ructure. | |
| 244 * @coverage dart.engine.parser | |
| 245 */ | |
| 246 class Parser { | |
| 247 /** | |
| 248 * The source being parsed. | |
| 249 */ | |
| 250 Source _source; | |
| 251 /** | |
| 252 * The error listener that will be informed of any errors that are found durin
g the parse. | |
| 253 */ | |
| 254 AnalysisErrorListener _errorListener; | |
| 255 /** | |
| 256 * The next token to be parsed. | |
| 257 */ | |
| 258 Token _currentToken; | |
| 259 /** | |
| 260 * A flag indicating whether the parser is currently in the body of a loop. | |
| 261 */ | |
| 262 bool _inLoop = false; | |
| 263 /** | |
| 264 * A flag indicating whether the parser is currently in a switch statement. | |
| 265 */ | |
| 266 bool _inSwitch = false; | |
| 267 static String _HIDE = "hide"; | |
| 268 static String _OF = "of"; | |
| 269 static String _ON = "on"; | |
| 270 static String _SHOW = "show"; | |
| 271 /** | |
| 272 * Initialize a newly created parser. | |
| 273 * @param source the source being parsed | |
| 274 * @param errorListener the error listener that will be informed of any errors
that are found | |
| 275 * during the parse | |
| 276 */ | |
| 277 Parser(Source source, AnalysisErrorListener errorListener) { | |
| 278 this._source = source; | |
| 279 this._errorListener = errorListener; | |
| 280 } | |
| 281 /** | |
| 282 * Parse a compilation unit, starting with the given token. | |
| 283 * @param token the first token of the compilation unit | |
| 284 * @return the compilation unit that was parsed | |
| 285 */ | |
| 286 CompilationUnit parseCompilationUnit(Token token) { | |
| 287 _currentToken = token; | |
| 288 return parseCompilationUnit2(); | |
| 289 } | |
| 290 /** | |
| 291 * Parse an expression, starting with the given token. | |
| 292 * @param token the first token of the expression | |
| 293 * @return the expression that was parsed, or {@code null} if the tokens do no
t represent a | |
| 294 * recognizable expression | |
| 295 */ | |
| 296 Expression parseExpression(Token token) { | |
| 297 _currentToken = token; | |
| 298 return parseExpression2(); | |
| 299 } | |
| 300 /** | |
| 301 * Parse a statement, starting with the given token. | |
| 302 * @param token the first token of the statement | |
| 303 * @return the statement that was parsed, or {@code null} if the tokens do not
represent a | |
| 304 * recognizable statement | |
| 305 */ | |
| 306 Statement parseStatement(Token token) { | |
| 307 _currentToken = token; | |
| 308 return parseStatement2(); | |
| 309 } | |
| 310 /** | |
| 311 * Parse a sequence of statements, starting with the given token. | |
| 312 * @param token the first token of the sequence of statement | |
| 313 * @return the statements that were parsed, or {@code null} if the tokens do n
ot represent a | |
| 314 * recognizable sequence of statements | |
| 315 */ | |
| 316 List<Statement> parseStatements(Token token) { | |
| 317 _currentToken = token; | |
| 318 return parseStatements2(); | |
| 319 } | |
| 320 void set currentToken(Token currentToken2) { | |
| 321 this._currentToken = currentToken2; | |
| 322 } | |
| 323 /** | |
| 324 * Advance to the next token in the token stream. | |
| 325 */ | |
| 326 void advance() { | |
| 327 _currentToken = _currentToken.next; | |
| 328 } | |
| 329 /** | |
| 330 * Append the character equivalent of the given scalar value to the given buil
der. Use the start | |
| 331 * and end indices to report an error, and don't append anything to the builde
r, if the scalar | |
| 332 * value is invalid. | |
| 333 * @param builder the builder to which the scalar value is to be appended | |
| 334 * @param escapeSequence the escape sequence that was parsed to produce the sc
alar value | |
| 335 * @param scalarValue the value to be appended | |
| 336 * @param startIndex the index of the first character representing the scalar
value | |
| 337 * @param endIndex the index of the last character representing the scalar val
ue | |
| 338 */ | |
| 339 void appendScalarValue(JavaStringBuilder builder, String escapeSequence, int s
calarValue, int startIndex, int endIndex) { | |
| 340 if (scalarValue < 0 || scalarValue > Character.MAX_CODE_POINT || (scalarValu
e >= 0xD800 && scalarValue <= 0xDFFF)) { | |
| 341 reportError4(ParserErrorCode.INVALID_CODE_POINT, [escapeSequence]); | |
| 342 return; | |
| 343 } | |
| 344 if (scalarValue < Character.MAX_VALUE) { | |
| 345 builder.appendChar((scalarValue as int)); | |
| 346 } else { | |
| 347 builder.append(Character.toChars(scalarValue)); | |
| 348 } | |
| 349 } | |
| 350 /** | |
| 351 * Compute the content of a string with the given literal representation. | |
| 352 * @param lexeme the literal representation of the string | |
| 353 * @return the actual value of the string | |
| 354 */ | |
| 355 String computeStringValue(String lexeme) { | |
| 356 if (lexeme.startsWith("r\"\"\"") || lexeme.startsWith("r'''")) { | |
| 357 if (lexeme.length > 4) { | |
| 358 return lexeme.substring(4, lexeme.length - 3); | |
| 359 } | |
| 360 } else if (lexeme.startsWith("r\"") || lexeme.startsWith("r'")) { | |
| 361 if (lexeme.length > 2) { | |
| 362 return lexeme.substring(2, lexeme.length - 1); | |
| 363 } | |
| 364 } | |
| 365 int start = 0; | |
| 366 if (lexeme.startsWith("\"\"\"") || lexeme.startsWith("'''")) { | |
| 367 start += 3; | |
| 368 } else if (lexeme.startsWith("\"") || lexeme.startsWith("'")) { | |
| 369 start += 1; | |
| 370 } | |
| 371 int end = lexeme.length; | |
| 372 if (end > 3 && (lexeme.endsWith("\"\"\"") || lexeme.endsWith("'''"))) { | |
| 373 end -= 3; | |
| 374 } else if (end > 1 && (lexeme.endsWith("\"") || lexeme.endsWith("'"))) { | |
| 375 end -= 1; | |
| 376 } | |
| 377 JavaStringBuilder builder = new JavaStringBuilder(); | |
| 378 int index = start; | |
| 379 while (index < end) { | |
| 380 index = translateCharacter(builder, lexeme, index); | |
| 381 } | |
| 382 return builder.toString(); | |
| 383 } | |
| 384 /** | |
| 385 * Create a synthetic identifier. | |
| 386 * @return the synthetic identifier that was created | |
| 387 */ | |
| 388 SimpleIdentifier createSyntheticIdentifier() => new SimpleIdentifier.full(crea
teSyntheticToken(TokenType.IDENTIFIER)); | |
| 389 /** | |
| 390 * Create a synthetic string literal. | |
| 391 * @return the synthetic string literal that was created | |
| 392 */ | |
| 393 SimpleStringLiteral createSyntheticStringLiteral() => new SimpleStringLiteral.
full(createSyntheticToken(TokenType.STRING), ""); | |
| 394 /** | |
| 395 * Create a synthetic token with the given type. | |
| 396 * @return the synthetic token that was created | |
| 397 */ | |
| 398 Token createSyntheticToken(TokenType type) => new StringToken(type, "", _curre
ntToken.offset); | |
| 399 /** | |
| 400 * Check that the given expression is assignable and report an error if it isn
't. | |
| 401 * <pre> | |
| 402 * assignableExpression ::= | |
| 403 * primary (arguments* assignableSelector)+ | |
| 404 * | 'super' assignableSelector | |
| 405 * | identifier | |
| 406 * assignableSelector ::= | |
| 407 * '[' expression ']' | |
| 408 * | '.' identifier | |
| 409 * </pre> | |
| 410 * @param expression the expression being checked | |
| 411 */ | |
| 412 void ensureAssignable(Expression expression) { | |
| 413 if (expression != null && !expression.isAssignable()) { | |
| 414 reportError4(ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE, []); | |
| 415 } | |
| 416 } | |
| 417 /** | |
| 418 * If the current token is a keyword matching the given string, return it afte
r advancing to the | |
| 419 * next token. Otherwise report an error and return the current token without
advancing. | |
| 420 * @param keyword the keyword that is expected | |
| 421 * @return the token that matched the given type | |
| 422 */ | |
| 423 Token expect(Keyword keyword) { | |
| 424 if (matches(keyword)) { | |
| 425 return andAdvance; | |
| 426 } | |
| 427 reportError4(ParserErrorCode.EXPECTED_TOKEN, [keyword.syntax]); | |
| 428 return _currentToken; | |
| 429 } | |
| 430 /** | |
| 431 * If the current token has the expected type, return it after advancing to th
e next token. | |
| 432 * Otherwise report an error and return the current token without advancing. | |
| 433 * @param type the type of token that is expected | |
| 434 * @return the token that matched the given type | |
| 435 */ | |
| 436 Token expect2(TokenType type) { | |
| 437 if (matches5(type)) { | |
| 438 return andAdvance; | |
| 439 } | |
| 440 if (identical(type, TokenType.SEMICOLON)) { | |
| 441 reportError5(ParserErrorCode.EXPECTED_TOKEN, _currentToken.previous, [type
.lexeme]); | |
| 442 } else { | |
| 443 reportError4(ParserErrorCode.EXPECTED_TOKEN, [type.lexeme]); | |
| 444 } | |
| 445 return _currentToken; | |
| 446 } | |
| 447 /** | |
| 448 * Advance to the next token in the token stream, making it the new current to
ken. | |
| 449 * @return the token that was current before this method was invoked | |
| 450 */ | |
| 451 Token get andAdvance { | |
| 452 Token token = _currentToken; | |
| 453 advance(); | |
| 454 return token; | |
| 455 } | |
| 456 /** | |
| 457 * Return {@code true} if the current token is the first token of a return typ
e that is followed | |
| 458 * by an identifier, possibly followed by a list of type parameters, followed
by a | |
| 459 * left-parenthesis. This is used by parseTypeAlias to determine whether or no
t to parse a return | |
| 460 * type. | |
| 461 * @return {@code true} if we can successfully parse the rest of a type alias
if we first parse a | |
| 462 * return type. | |
| 463 */ | |
| 464 bool hasReturnTypeInTypeAlias() { | |
| 465 Token next = skipReturnType(_currentToken); | |
| 466 if (next == null) { | |
| 467 return false; | |
| 468 } | |
| 469 return matchesIdentifier2(next); | |
| 470 } | |
| 471 /** | |
| 472 * Return {@code true} if the current token appears to be the beginning of a f
unction declaration. | |
| 473 * @return {@code true} if the current token appears to be the beginning of a
function declaration | |
| 474 */ | |
| 475 bool isFunctionDeclaration() { | |
| 476 if (matches(Keyword.VOID)) { | |
| 477 return true; | |
| 478 } | |
| 479 Token afterReturnType = skipTypeName(_currentToken); | |
| 480 if (afterReturnType == null) { | |
| 481 afterReturnType = _currentToken; | |
| 482 } | |
| 483 Token afterIdentifier = skipSimpleIdentifier(afterReturnType); | |
| 484 if (afterIdentifier == null) { | |
| 485 afterIdentifier = skipSimpleIdentifier(_currentToken); | |
| 486 } | |
| 487 if (afterIdentifier == null) { | |
| 488 return false; | |
| 489 } | |
| 490 return isFunctionExpression(afterIdentifier); | |
| 491 } | |
| 492 /** | |
| 493 * Return {@code true} if the given token appears to be the beginning of a fun
ction expression. | |
| 494 * @param startToken the token that might be the start of a function expressio
n | |
| 495 * @return {@code true} if the given token appears to be the beginning of a fu
nction expression | |
| 496 */ | |
| 497 bool isFunctionExpression(Token startToken) { | |
| 498 Token afterParameters = skipFormalParameterList(startToken); | |
| 499 if (afterParameters == null) { | |
| 500 return false; | |
| 501 } | |
| 502 return matchesAny(afterParameters, [TokenType.OPEN_CURLY_BRACKET, TokenType.
FUNCTION]); | |
| 503 } | |
| 504 /** | |
| 505 * Return {@code true} if the given character is a valid hexadecimal digit. | |
| 506 * @param character the character being tested | |
| 507 * @return {@code true} if the character is a valid hexadecimal digit | |
| 508 */ | |
| 509 bool isHexDigit(int character) => (0x30 <= character && character <= 0x39) ||
(0x41 <= character && character <= 0x46) || (0x61 <= character && character <= 0
x66); | |
| 510 /** | |
| 511 * Return {@code true} if the current token is the first token in an initializ
ed variable | |
| 512 * declaration rather than an expression. This method assumes that we have alr
eady skipped past | |
| 513 * any metadata that might be associated with the declaration. | |
| 514 * <pre> | |
| 515 * initializedVariableDeclaration ::= | |
| 516 * declaredIdentifier ('=' expression)? (',' initializedIdentifier) | |
| 517 * declaredIdentifier ::= | |
| 518 * metadata finalConstVarOrType identifier | |
| 519 * finalConstVarOrType ::= | |
| 520 * 'final' type? | |
| 521 * | 'const' type? | |
| 522 * | 'var' | |
| 523 * | type | |
| 524 * type ::= | |
| 525 * qualified typeArguments? | |
| 526 * initializedIdentifier ::= | |
| 527 * identifier ('=' expression)? | |
| 528 * </pre> | |
| 529 * @return {@code true} if the current token is the first token in an initiali
zed variable | |
| 530 * declaration | |
| 531 */ | |
| 532 bool isInitializedVariableDeclaration() { | |
| 533 if (matches(Keyword.FINAL) || matches(Keyword.CONST) || matches(Keyword.VAR)
) { | |
| 534 return true; | |
| 535 } | |
| 536 Token token = skipTypeName(_currentToken); | |
| 537 if (token == null) { | |
| 538 return false; | |
| 539 } | |
| 540 token = skipSimpleIdentifier(token); | |
| 541 if (token == null) { | |
| 542 return false; | |
| 543 } | |
| 544 TokenType type21 = token.type; | |
| 545 return identical(type21, TokenType.EQ) || identical(type21, TokenType.COMMA)
|| identical(type21, TokenType.SEMICOLON) || matches3(token, Keyword.IN); | |
| 546 } | |
| 547 /** | |
| 548 * Return {@code true} if the current token appears to be the beginning of a s
witch member. | |
| 549 * @return {@code true} if the current token appears to be the beginning of a
switch member | |
| 550 */ | |
| 551 bool isSwitchMember() { | |
| 552 Token token = _currentToken; | |
| 553 while (matches4(token, TokenType.IDENTIFIER) && matches4(token.next, TokenTy
pe.COLON)) { | |
| 554 token = token.next.next; | |
| 555 } | |
| 556 if (identical(token.type, TokenType.KEYWORD)) { | |
| 557 Keyword keyword29 = ((token as KeywordToken)).keyword; | |
| 558 return identical(keyword29, Keyword.CASE) || identical(keyword29, Keyword.
DEFAULT); | |
| 559 } | |
| 560 return false; | |
| 561 } | |
| 562 /** | |
| 563 * Compare the given tokens to find the token that appears first in the source
being parsed. That | |
| 564 * is, return the left-most of all of the tokens. The arguments are allowed to
be {@code null}. | |
| 565 * Return the token with the smallest offset, or {@code null} if there are no
arguments or if all | |
| 566 * of the arguments are {@code null}. | |
| 567 * @param tokens the tokens being compared | |
| 568 * @return the token with the smallest offset | |
| 569 */ | |
| 570 Token lexicallyFirst(List<Token> tokens) { | |
| 571 Token first = null; | |
| 572 int firstOffset = 2147483647; | |
| 573 for (Token token in tokens) { | |
| 574 if (token != null) { | |
| 575 int offset5 = token.offset; | |
| 576 if (offset5 < firstOffset) { | |
| 577 first = token; | |
| 578 } | |
| 579 } | |
| 580 } | |
| 581 return first; | |
| 582 } | |
| 583 /** | |
| 584 * Return {@code true} if the current token matches the given keyword. | |
| 585 * @param keyword the keyword that can optionally appear in the current locati
on | |
| 586 * @return {@code true} if the current token matches the given keyword | |
| 587 */ | |
| 588 bool matches(Keyword keyword) => matches3(_currentToken, keyword); | |
| 589 /** | |
| 590 * Return {@code true} if the current token matches the given identifier. | |
| 591 * @param identifier the identifier that can optionally appear in the current
location | |
| 592 * @return {@code true} if the current token matches the given identifier | |
| 593 */ | |
| 594 bool matches2(String identifier) => identical(_currentToken.type, TokenType.ID
ENTIFIER) && _currentToken.lexeme == identifier; | |
| 595 /** | |
| 596 * Return {@code true} if the given token matches the given keyword. | |
| 597 * @param token the token being tested | |
| 598 * @param keyword the keyword that is being tested for | |
| 599 * @return {@code true} if the given token matches the given keyword | |
| 600 */ | |
| 601 bool matches3(Token token, Keyword keyword37) => identical(token.type, TokenTy
pe.KEYWORD) && identical(((token as KeywordToken)).keyword, keyword37); | |
| 602 /** | |
| 603 * Return {@code true} if the given token has the given type. | |
| 604 * @param token the token being tested | |
| 605 * @param type the type of token that is being tested for | |
| 606 * @return {@code true} if the given token has the given type | |
| 607 */ | |
| 608 bool matches4(Token token, TokenType type30) => identical(token.type, type30); | |
| 609 /** | |
| 610 * Return {@code true} if the current token has the given type. Note that this
method, unlike | |
| 611 * other variants, will modify the token stream if possible to match a wider r
ange of tokens. In | |
| 612 * particular, if we are attempting to match a '>' and the next token is eithe
r a '>>' or '>>>', | |
| 613 * the token stream will be re-written and {@code true} will be returned. | |
| 614 * @param type the type of token that can optionally appear in the current loc
ation | |
| 615 * @return {@code true} if the current token has the given type | |
| 616 */ | |
| 617 bool matches5(TokenType type31) { | |
| 618 TokenType currentType = _currentToken.type; | |
| 619 if (currentType != type31) { | |
| 620 if (identical(type31, TokenType.GT)) { | |
| 621 if (identical(currentType, TokenType.GT_GT)) { | |
| 622 int offset6 = _currentToken.offset; | |
| 623 Token first = new Token(TokenType.GT, offset6); | |
| 624 Token second = new Token(TokenType.GT, offset6 + 1); | |
| 625 second.setNext(_currentToken.next); | |
| 626 first.setNext(second); | |
| 627 _currentToken.previous.setNext(first); | |
| 628 _currentToken = first; | |
| 629 return true; | |
| 630 } else if (identical(currentType, TokenType.GT_EQ)) { | |
| 631 int offset7 = _currentToken.offset; | |
| 632 Token first = new Token(TokenType.GT, offset7); | |
| 633 Token second = new Token(TokenType.EQ, offset7 + 1); | |
| 634 second.setNext(_currentToken.next); | |
| 635 first.setNext(second); | |
| 636 _currentToken.previous.setNext(first); | |
| 637 _currentToken = first; | |
| 638 return true; | |
| 639 } else if (identical(currentType, TokenType.GT_GT_EQ)) { | |
| 640 int offset8 = _currentToken.offset; | |
| 641 Token first = new Token(TokenType.GT, offset8); | |
| 642 Token second = new Token(TokenType.GT, offset8 + 1); | |
| 643 Token third = new Token(TokenType.EQ, offset8 + 2); | |
| 644 third.setNext(_currentToken.next); | |
| 645 second.setNext(third); | |
| 646 first.setNext(second); | |
| 647 _currentToken.previous.setNext(first); | |
| 648 _currentToken = first; | |
| 649 return true; | |
| 650 } | |
| 651 } | |
| 652 return false; | |
| 653 } | |
| 654 return true; | |
| 655 } | |
| 656 /** | |
| 657 * Return {@code true} if the given token has any one of the given types. | |
| 658 * @param token the token being tested | |
| 659 * @param types the types of token that are being tested for | |
| 660 * @return {@code true} if the given token has any of the given types | |
| 661 */ | |
| 662 bool matchesAny(Token token, List<TokenType> types) { | |
| 663 TokenType actualType = token.type; | |
| 664 for (TokenType type in types) { | |
| 665 if (identical(actualType, type)) { | |
| 666 return true; | |
| 667 } | |
| 668 } | |
| 669 return false; | |
| 670 } | |
| 671 /** | |
| 672 * Return {@code true} if the current token is a valid identifier. Valid ident
ifiers include | |
| 673 * built-in identifiers (pseudo-keywords). | |
| 674 * @return {@code true} if the current token is a valid identifier | |
| 675 */ | |
| 676 bool matchesIdentifier() => matchesIdentifier2(_currentToken); | |
| 677 /** | |
| 678 * Return {@code true} if the given token is a valid identifier. Valid identif
iers include | |
| 679 * built-in identifiers (pseudo-keywords). | |
| 680 * @return {@code true} if the given token is a valid identifier | |
| 681 */ | |
| 682 bool matchesIdentifier2(Token token) => matches4(token, TokenType.IDENTIFIER)
|| (matches4(token, TokenType.KEYWORD) && ((token as KeywordToken)).keyword.isPs
eudoKeyword()); | |
| 683 /** | |
| 684 * If the current token has the given type, then advance to the next token and
return {@code true}. Otherwise, return {@code false} without advancing. | |
| 685 * @param type the type of token that can optionally appear in the current loc
ation | |
| 686 * @return {@code true} if the current token has the given type | |
| 687 */ | |
| 688 bool optional(TokenType type) { | |
| 689 if (matches5(type)) { | |
| 690 advance(); | |
| 691 return true; | |
| 692 } | |
| 693 return false; | |
| 694 } | |
| 695 /** | |
| 696 * Parse an additive expression. | |
| 697 * <pre> | |
| 698 * additiveExpression ::= | |
| 699 * multiplicativeExpression (additiveOperator multiplicativeExpression) | |
| 700 * | 'super' (additiveOperator multiplicativeExpression)+ | |
| 701 * </pre> | |
| 702 * @return the additive expression that was parsed | |
| 703 */ | |
| 704 Expression parseAdditiveExpression() { | |
| 705 Expression expression; | |
| 706 if (matches(Keyword.SUPER) && _currentToken.next.type.isAdditiveOperator())
{ | |
| 707 expression = new SuperExpression.full(andAdvance); | |
| 708 } else { | |
| 709 expression = parseMultiplicativeExpression(); | |
| 710 } | |
| 711 while (_currentToken.type.isAdditiveOperator()) { | |
| 712 Token operator = andAdvance; | |
| 713 expression = new BinaryExpression.full(expression, operator, parseMultipli
cativeExpression()); | |
| 714 } | |
| 715 return expression; | |
| 716 } | |
| 717 /** | |
| 718 * Parse an annotation. | |
| 719 * <pre> | |
| 720 * annotation ::= | |
| 721 * '@' qualified (‘.’ identifier)? arguments? | |
| 722 * </pre> | |
| 723 * @return the annotation that was parsed | |
| 724 */ | |
| 725 Annotation parseAnnotation() { | |
| 726 Token atSign = expect2(TokenType.AT); | |
| 727 Identifier name = parsePrefixedIdentifier(); | |
| 728 Token period = null; | |
| 729 SimpleIdentifier constructorName = null; | |
| 730 if (matches5(TokenType.PERIOD)) { | |
| 731 period = andAdvance; | |
| 732 constructorName = parseSimpleIdentifier(); | |
| 733 } | |
| 734 ArgumentList arguments = null; | |
| 735 if (matches5(TokenType.OPEN_PAREN)) { | |
| 736 arguments = parseArgumentList(); | |
| 737 } | |
| 738 return new Annotation.full(atSign, name, period, constructorName, arguments)
; | |
| 739 } | |
| 740 /** | |
| 741 * Parse an argument. | |
| 742 * <pre> | |
| 743 * argument ::= | |
| 744 * namedArgument | |
| 745 * | expression | |
| 746 * namedArgument ::= | |
| 747 * label expression | |
| 748 * </pre> | |
| 749 * @return the argument that was parsed | |
| 750 */ | |
| 751 Expression parseArgument() { | |
| 752 if (matchesIdentifier() && matches4(peek(), TokenType.COLON)) { | |
| 753 SimpleIdentifier label = new SimpleIdentifier.full(andAdvance); | |
| 754 Label name = new Label.full(label, andAdvance); | |
| 755 return new NamedExpression.full(name, parseExpression2()); | |
| 756 } else { | |
| 757 return parseExpression2(); | |
| 758 } | |
| 759 } | |
| 760 /** | |
| 761 * Parse an argument definition test. | |
| 762 * <pre> | |
| 763 * argumentDefinitionTest ::= | |
| 764 * '?' identifier | |
| 765 * </pre> | |
| 766 * @return the argument definition test that was parsed | |
| 767 */ | |
| 768 ArgumentDefinitionTest parseArgumentDefinitionTest() { | |
| 769 Token question = expect2(TokenType.QUESTION); | |
| 770 SimpleIdentifier identifier = parseSimpleIdentifier(); | |
| 771 return new ArgumentDefinitionTest.full(question, identifier); | |
| 772 } | |
| 773 /** | |
| 774 * Parse a list of arguments. | |
| 775 * <pre> | |
| 776 * arguments ::= | |
| 777 * '(' argumentList? ')' | |
| 778 * argumentList ::= | |
| 779 * namedArgument (',' namedArgument) | |
| 780 * | expressionList (',' namedArgument) | |
| 781 * </pre> | |
| 782 * @return the argument list that was parsed | |
| 783 */ | |
| 784 ArgumentList parseArgumentList() { | |
| 785 Token leftParenthesis = expect2(TokenType.OPEN_PAREN); | |
| 786 List<Expression> arguments = new List<Expression>(); | |
| 787 if (matches5(TokenType.CLOSE_PAREN)) { | |
| 788 return new ArgumentList.full(leftParenthesis, arguments, andAdvance); | |
| 789 } | |
| 790 Expression argument = parseArgument(); | |
| 791 arguments.add(argument); | |
| 792 bool foundNamedArgument = argument is NamedExpression; | |
| 793 bool generatedError = false; | |
| 794 while (optional(TokenType.COMMA)) { | |
| 795 argument = parseArgument(); | |
| 796 arguments.add(argument); | |
| 797 if (foundNamedArgument) { | |
| 798 if (!generatedError && argument is! NamedExpression) { | |
| 799 reportError4(ParserErrorCode.POSITIONAL_AFTER_NAMED_ARGUMENT, []); | |
| 800 generatedError = true; | |
| 801 } | |
| 802 } else if (argument is NamedExpression) { | |
| 803 foundNamedArgument = true; | |
| 804 } | |
| 805 } | |
| 806 Token rightParenthesis = expect2(TokenType.CLOSE_PAREN); | |
| 807 return new ArgumentList.full(leftParenthesis, arguments, rightParenthesis); | |
| 808 } | |
| 809 /** | |
| 810 * Parse an assert statement. | |
| 811 * <pre> | |
| 812 * assertStatement ::= | |
| 813 * 'assert' '(' conditionalExpression ')' ';' | |
| 814 * </pre> | |
| 815 * @return the assert statement | |
| 816 */ | |
| 817 AssertStatement parseAssertStatement() { | |
| 818 Token keyword = expect(Keyword.ASSERT); | |
| 819 Token leftParen = expect2(TokenType.OPEN_PAREN); | |
| 820 Expression expression = parseConditionalExpression(); | |
| 821 Token rightParen = expect2(TokenType.CLOSE_PAREN); | |
| 822 Token semicolon = expect2(TokenType.SEMICOLON); | |
| 823 return new AssertStatement.full(keyword, leftParen, expression, rightParen,
semicolon); | |
| 824 } | |
| 825 /** | |
| 826 * Parse an assignable expression. | |
| 827 * <pre> | |
| 828 * assignableExpression ::= | |
| 829 * primary (arguments* assignableSelector)+ | |
| 830 * | 'super' assignableSelector | |
| 831 * | identifier | |
| 832 * </pre> | |
| 833 * @param primaryAllowed {@code true} if the expression is allowed to be a pri
mary without any | |
| 834 * assignable selector | |
| 835 * @return the assignable expression that was parsed | |
| 836 */ | |
| 837 Expression parseAssignableExpression(bool primaryAllowed) { | |
| 838 if (matches(Keyword.SUPER)) { | |
| 839 return parseAssignableSelector(new SuperExpression.full(andAdvance), false
); | |
| 840 } | |
| 841 Expression expression = parsePrimaryExpression(); | |
| 842 bool isOptional = primaryAllowed || expression is SimpleIdentifier; | |
| 843 while (true) { | |
| 844 while (matches5(TokenType.OPEN_PAREN)) { | |
| 845 ArgumentList argumentList = parseArgumentList(); | |
| 846 if (expression is SimpleIdentifier) { | |
| 847 expression = new MethodInvocation.full(null, null, (expression as Simp
leIdentifier), argumentList); | |
| 848 } else if (expression is PrefixedIdentifier) { | |
| 849 PrefixedIdentifier identifier = expression as PrefixedIdentifier; | |
| 850 expression = new MethodInvocation.full(identifier.prefix, identifier.p
eriod, identifier.identifier, argumentList); | |
| 851 } else if (expression is PropertyAccess) { | |
| 852 PropertyAccess access = expression as PropertyAccess; | |
| 853 expression = new MethodInvocation.full(access.target, access.operator,
access.propertyName, argumentList); | |
| 854 } else { | |
| 855 expression = new FunctionExpressionInvocation.full(expression, argumen
tList); | |
| 856 } | |
| 857 if (!primaryAllowed) { | |
| 858 isOptional = false; | |
| 859 } | |
| 860 } | |
| 861 Expression selectorExpression = parseAssignableSelector(expression, isOpti
onal || (expression is PrefixedIdentifier)); | |
| 862 if (identical(selectorExpression, expression)) { | |
| 863 if (!isOptional && (expression is PrefixedIdentifier)) { | |
| 864 PrefixedIdentifier identifier = expression as PrefixedIdentifier; | |
| 865 expression = new PropertyAccess.full(identifier.prefix, identifier.per
iod, identifier.identifier); | |
| 866 } | |
| 867 return expression; | |
| 868 } | |
| 869 expression = selectorExpression; | |
| 870 isOptional = true; | |
| 871 } | |
| 872 } | |
| 873 /** | |
| 874 * Parse an assignable selector. | |
| 875 * <pre> | |
| 876 * assignableSelector ::= | |
| 877 * '[' expression ']' | |
| 878 * | '.' identifier | |
| 879 * </pre> | |
| 880 * @param prefix the expression preceding the selector | |
| 881 * @param optional {@code true} if the selector is optional | |
| 882 * @return the assignable selector that was parsed | |
| 883 */ | |
| 884 Expression parseAssignableSelector(Expression prefix, bool optional) { | |
| 885 if (matches5(TokenType.OPEN_SQUARE_BRACKET)) { | |
| 886 Token leftBracket = andAdvance; | |
| 887 Expression index = parseExpression2(); | |
| 888 Token rightBracket = expect2(TokenType.CLOSE_SQUARE_BRACKET); | |
| 889 return new IndexExpression.forTarget_full(prefix, leftBracket, index, righ
tBracket); | |
| 890 } else if (matches5(TokenType.PERIOD)) { | |
| 891 Token period = andAdvance; | |
| 892 return new PropertyAccess.full(prefix, period, parseSimpleIdentifier()); | |
| 893 } else { | |
| 894 if (!optional) { | |
| 895 reportError4(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, []); | |
| 896 } | |
| 897 return prefix; | |
| 898 } | |
| 899 } | |
| 900 /** | |
| 901 * Parse a bitwise and expression. | |
| 902 * <pre> | |
| 903 * bitwiseAndExpression ::= | |
| 904 * equalityExpression ('&' equalityExpression) | |
| 905 * | 'super' ('&' equalityExpression)+ | |
| 906 * </pre> | |
| 907 * @return the bitwise and expression that was parsed | |
| 908 */ | |
| 909 Expression parseBitwiseAndExpression() { | |
| 910 Expression expression; | |
| 911 if (matches(Keyword.SUPER) && matches4(peek(), TokenType.AMPERSAND)) { | |
| 912 expression = new SuperExpression.full(andAdvance); | |
| 913 } else { | |
| 914 expression = parseEqualityExpression(); | |
| 915 } | |
| 916 while (matches5(TokenType.AMPERSAND)) { | |
| 917 Token operator = andAdvance; | |
| 918 expression = new BinaryExpression.full(expression, operator, parseEquality
Expression()); | |
| 919 } | |
| 920 return expression; | |
| 921 } | |
| 922 /** | |
| 923 * Parse a bitwise or expression. | |
| 924 * <pre> | |
| 925 * bitwiseOrExpression ::= | |
| 926 * bitwiseXorExpression ('|' bitwiseXorExpression) | |
| 927 * | 'super' ('|' bitwiseXorExpression)+ | |
| 928 * </pre> | |
| 929 * @return the bitwise or expression that was parsed | |
| 930 */ | |
| 931 Expression parseBitwiseOrExpression() { | |
| 932 Expression expression; | |
| 933 if (matches(Keyword.SUPER) && matches4(peek(), TokenType.BAR)) { | |
| 934 expression = new SuperExpression.full(andAdvance); | |
| 935 } else { | |
| 936 expression = parseBitwiseXorExpression(); | |
| 937 } | |
| 938 while (matches5(TokenType.BAR)) { | |
| 939 Token operator = andAdvance; | |
| 940 expression = new BinaryExpression.full(expression, operator, parseBitwiseX
orExpression()); | |
| 941 } | |
| 942 return expression; | |
| 943 } | |
| 944 /** | |
| 945 * Parse a bitwise exclusive-or expression. | |
| 946 * <pre> | |
| 947 * bitwiseXorExpression ::= | |
| 948 * bitwiseAndExpression ('^' bitwiseAndExpression) | |
| 949 * | 'super' ('^' bitwiseAndExpression)+ | |
| 950 * </pre> | |
| 951 * @return the bitwise exclusive-or expression that was parsed | |
| 952 */ | |
| 953 Expression parseBitwiseXorExpression() { | |
| 954 Expression expression; | |
| 955 if (matches(Keyword.SUPER) && matches4(peek(), TokenType.CARET)) { | |
| 956 expression = new SuperExpression.full(andAdvance); | |
| 957 } else { | |
| 958 expression = parseBitwiseAndExpression(); | |
| 959 } | |
| 960 while (matches5(TokenType.CARET)) { | |
| 961 Token operator = andAdvance; | |
| 962 expression = new BinaryExpression.full(expression, operator, parseBitwiseA
ndExpression()); | |
| 963 } | |
| 964 return expression; | |
| 965 } | |
| 966 /** | |
| 967 * Parse a block. | |
| 968 * <pre> | |
| 969 * block ::= | |
| 970 * '{' statements '}' | |
| 971 * </pre> | |
| 972 * @return the block that was parsed | |
| 973 */ | |
| 974 Block parseBlock() { | |
| 975 Token leftBracket = expect2(TokenType.OPEN_CURLY_BRACKET); | |
| 976 List<Statement> statements = new List<Statement>(); | |
| 977 Token statementStart = _currentToken; | |
| 978 while (!matches5(TokenType.EOF) && !matches5(TokenType.CLOSE_CURLY_BRACKET))
{ | |
| 979 Statement statement = parseStatement2(); | |
| 980 if (statement != null) { | |
| 981 statements.add(statement); | |
| 982 } | |
| 983 if (identical(_currentToken, statementStart)) { | |
| 984 reportError5(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentT
oken.lexeme]); | |
| 985 advance(); | |
| 986 } | |
| 987 statementStart = _currentToken; | |
| 988 } | |
| 989 Token rightBracket = expect2(TokenType.CLOSE_CURLY_BRACKET); | |
| 990 return new Block.full(leftBracket, statements, rightBracket); | |
| 991 } | |
| 992 /** | |
| 993 * Parse a break statement. | |
| 994 * <pre> | |
| 995 * breakStatement ::= | |
| 996 * 'break' identifier? ';' | |
| 997 * </pre> | |
| 998 * @return the break statement that was parsed | |
| 999 */ | |
| 1000 Statement parseBreakStatement() { | |
| 1001 Token breakKeyword = expect(Keyword.BREAK); | |
| 1002 SimpleIdentifier label = null; | |
| 1003 if (matchesIdentifier()) { | |
| 1004 label = parseSimpleIdentifier(); | |
| 1005 } | |
| 1006 if (!_inLoop && !_inSwitch && label == null) { | |
| 1007 reportError5(ParserErrorCode.BREAK_OUTSIDE_OF_LOOP, breakKeyword, []); | |
| 1008 } | |
| 1009 Token semicolon = expect2(TokenType.SEMICOLON); | |
| 1010 return new BreakStatement.full(breakKeyword, label, semicolon); | |
| 1011 } | |
| 1012 /** | |
| 1013 * Parse a cascade section. | |
| 1014 * <pre> | |
| 1015 * cascadeSection ::= | |
| 1016 * '..' (cascadeSelector arguments*) (assignableSelector arguments*)* cascadeA
ssignment? | |
| 1017 * cascadeSelector ::= | |
| 1018 * '[' expression ']' | |
| 1019 * | identifier | |
| 1020 * cascadeAssignment ::= | |
| 1021 * assignmentOperator expressionWithoutCascade | |
| 1022 * </pre> | |
| 1023 * @return the expression representing the cascaded method invocation | |
| 1024 */ | |
| 1025 Expression parseCascadeSection() { | |
| 1026 Token period = expect2(TokenType.PERIOD_PERIOD); | |
| 1027 Expression expression = null; | |
| 1028 SimpleIdentifier functionName = null; | |
| 1029 if (matchesIdentifier()) { | |
| 1030 functionName = parseSimpleIdentifier(); | |
| 1031 } else if (identical(_currentToken.type, TokenType.OPEN_SQUARE_BRACKET)) { | |
| 1032 Token leftBracket = andAdvance; | |
| 1033 Expression index = parseExpression2(); | |
| 1034 Token rightBracket = expect2(TokenType.CLOSE_SQUARE_BRACKET); | |
| 1035 expression = new IndexExpression.forCascade_full(period, leftBracket, inde
x, rightBracket); | |
| 1036 period = null; | |
| 1037 } else { | |
| 1038 reportError5(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentTok
en.lexeme]); | |
| 1039 return expression; | |
| 1040 } | |
| 1041 if (identical(_currentToken.type, TokenType.OPEN_PAREN)) { | |
| 1042 while (identical(_currentToken.type, TokenType.OPEN_PAREN)) { | |
| 1043 if (functionName != null) { | |
| 1044 expression = new MethodInvocation.full(expression, period, functionNam
e, parseArgumentList()); | |
| 1045 period = null; | |
| 1046 functionName = null; | |
| 1047 } else if (expression == null) { | |
| 1048 return null; | |
| 1049 } else { | |
| 1050 expression = new FunctionExpressionInvocation.full(expression, parseAr
gumentList()); | |
| 1051 } | |
| 1052 } | |
| 1053 } else if (functionName != null) { | |
| 1054 expression = new PropertyAccess.full(expression, period, functionName); | |
| 1055 period = null; | |
| 1056 } | |
| 1057 bool progress = true; | |
| 1058 while (progress) { | |
| 1059 progress = false; | |
| 1060 Expression selector = parseAssignableSelector(expression, true); | |
| 1061 if (selector != expression) { | |
| 1062 expression = selector; | |
| 1063 progress = true; | |
| 1064 while (identical(_currentToken.type, TokenType.OPEN_PAREN)) { | |
| 1065 expression = new FunctionExpressionInvocation.full(expression, parseAr
gumentList()); | |
| 1066 } | |
| 1067 } | |
| 1068 } | |
| 1069 if (_currentToken.type.isAssignmentOperator()) { | |
| 1070 Token operator = andAdvance; | |
| 1071 ensureAssignable(expression); | |
| 1072 expression = new AssignmentExpression.full(expression, operator, parseExpr
essionWithoutCascade()); | |
| 1073 } | |
| 1074 return expression; | |
| 1075 } | |
| 1076 /** | |
| 1077 * Parse a class declaration. | |
| 1078 * <pre> | |
| 1079 * classDeclaration ::= | |
| 1080 * metadata 'abstract'? 'class' name typeParameterList? (extendsClause withCla
use?)? implementsClause? '{' classMembers '}' | |
| 1081 * </pre> | |
| 1082 * @param commentAndMetadata the metadata to be associated with the member | |
| 1083 * @param abstractKeyword the token for the keyword 'abstract', or {@code null
} if the keyword was | |
| 1084 * not given | |
| 1085 * @return the class declaration that was parsed | |
| 1086 */ | |
| 1087 ClassDeclaration parseClassDeclaration(CommentAndMetadata commentAndMetadata,
Token abstractKeyword) { | |
| 1088 Token keyword = expect(Keyword.CLASS); | |
| 1089 SimpleIdentifier name = parseSimpleIdentifier(); | |
| 1090 String className = name.name; | |
| 1091 TypeParameterList typeParameters = null; | |
| 1092 if (matches5(TokenType.LT)) { | |
| 1093 typeParameters = parseTypeParameterList(); | |
| 1094 } | |
| 1095 ExtendsClause extendsClause = null; | |
| 1096 WithClause withClause = null; | |
| 1097 ImplementsClause implementsClause = null; | |
| 1098 bool foundClause = true; | |
| 1099 while (foundClause) { | |
| 1100 if (matches(Keyword.EXTENDS)) { | |
| 1101 if (extendsClause == null) { | |
| 1102 extendsClause = parseExtendsClause(); | |
| 1103 if (withClause != null) { | |
| 1104 reportError5(ParserErrorCode.WITH_BEFORE_EXTENDS, withClause.withKey
word, []); | |
| 1105 } else if (implementsClause != null) { | |
| 1106 reportError5(ParserErrorCode.IMPLEMENTS_BEFORE_EXTENDS, implementsCl
ause.keyword, []); | |
| 1107 } | |
| 1108 } else { | |
| 1109 reportError5(ParserErrorCode.MULTIPLE_EXTENDS_CLAUSES, extendsClause.k
eyword, []); | |
| 1110 parseExtendsClause(); | |
| 1111 } | |
| 1112 } else if (matches(Keyword.WITH)) { | |
| 1113 if (withClause == null) { | |
| 1114 withClause = parseWithClause(); | |
| 1115 if (implementsClause != null) { | |
| 1116 reportError5(ParserErrorCode.IMPLEMENTS_BEFORE_WITH, implementsClaus
e.keyword, []); | |
| 1117 } | |
| 1118 } else { | |
| 1119 reportError5(ParserErrorCode.MULTIPLE_WITH_CLAUSES, withClause.withKey
word, []); | |
| 1120 parseWithClause(); | |
| 1121 } | |
| 1122 } else if (matches(Keyword.IMPLEMENTS)) { | |
| 1123 if (implementsClause == null) { | |
| 1124 implementsClause = parseImplementsClause(); | |
| 1125 } else { | |
| 1126 reportError5(ParserErrorCode.MULTIPLE_IMPLEMENTS_CLAUSES, implementsCl
ause.keyword, []); | |
| 1127 parseImplementsClause(); | |
| 1128 } | |
| 1129 } else { | |
| 1130 foundClause = false; | |
| 1131 } | |
| 1132 } | |
| 1133 if (withClause != null && extendsClause == null) { | |
| 1134 reportError5(ParserErrorCode.WITH_WITHOUT_EXTENDS, withClause.withKeyword,
[]); | |
| 1135 } | |
| 1136 Token leftBracket = null; | |
| 1137 List<ClassMember> members = null; | |
| 1138 Token rightBracket = null; | |
| 1139 if (matches5(TokenType.OPEN_CURLY_BRACKET)) { | |
| 1140 leftBracket = expect2(TokenType.OPEN_CURLY_BRACKET); | |
| 1141 members = parseClassMembers(className, ((leftBracket as BeginToken)).endTo
ken != null); | |
| 1142 rightBracket = expect2(TokenType.CLOSE_CURLY_BRACKET); | |
| 1143 } else { | |
| 1144 leftBracket = createSyntheticToken(TokenType.OPEN_CURLY_BRACKET); | |
| 1145 rightBracket = createSyntheticToken(TokenType.CLOSE_CURLY_BRACKET); | |
| 1146 reportError4(ParserErrorCode.MISSING_CLASS_BODY, []); | |
| 1147 } | |
| 1148 return new ClassDeclaration.full(commentAndMetadata.comment, commentAndMetad
ata.metadata, abstractKeyword, keyword, name, typeParameters, extendsClause, wit
hClause, implementsClause, leftBracket, members, rightBracket); | |
| 1149 } | |
| 1150 /** | |
| 1151 * Parse a class member. | |
| 1152 * <pre> | |
| 1153 * classMemberDefinition ::= | |
| 1154 * declaration ';' | |
| 1155 * | methodSignature functionBody | |
| 1156 * </pre> | |
| 1157 * @param className the name of the class containing the member being parsed | |
| 1158 * @return the class member that was parsed | |
| 1159 */ | |
| 1160 ClassMember parseClassMember(String className) { | |
| 1161 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata(); | |
| 1162 Modifiers modifiers = parseModifiers(); | |
| 1163 if (matches(Keyword.VOID)) { | |
| 1164 TypeName returnType = parseReturnType(); | |
| 1165 if (matches(Keyword.GET) && matchesIdentifier2(peek())) { | |
| 1166 validateModifiersForGetterOrSetterOrMethod(modifiers); | |
| 1167 return parseGetter(commentAndMetadata, modifiers.externalKeyword, modifi
ers.staticKeyword, returnType); | |
| 1168 } else if (matches(Keyword.SET) && matchesIdentifier2(peek())) { | |
| 1169 validateModifiersForGetterOrSetterOrMethod(modifiers); | |
| 1170 return parseSetter(commentAndMetadata, modifiers.externalKeyword, modifi
ers.staticKeyword, returnType); | |
| 1171 } else if (matches(Keyword.OPERATOR) && peek().isOperator()) { | |
| 1172 validateModifiersForOperator(modifiers); | |
| 1173 return parseOperator(commentAndMetadata, modifiers.externalKeyword, retu
rnType); | |
| 1174 } else if (matchesIdentifier() && matchesAny(peek(), [TokenType.OPEN_PAREN
, TokenType.OPEN_CURLY_BRACKET, TokenType.FUNCTION])) { | |
| 1175 validateModifiersForGetterOrSetterOrMethod(modifiers); | |
| 1176 return parseMethodDeclaration(commentAndMetadata, modifiers.externalKeyw
ord, modifiers.staticKeyword, returnType); | |
| 1177 } else { | |
| 1178 if (matchesIdentifier()) { | |
| 1179 if (matchesAny(peek(), [TokenType.EQ, TokenType.COMMA, TokenType.SEMIC
OLON])) { | |
| 1180 reportError(ParserErrorCode.VOID_VARIABLE, returnType, []); | |
| 1181 return parseInitializedIdentifierList(commentAndMetadata, modifiers.
staticKeyword, validateModifiersForField(modifiers), returnType); | |
| 1182 } | |
| 1183 } | |
| 1184 return null; | |
| 1185 } | |
| 1186 } else if (matches(Keyword.GET) && matchesIdentifier2(peek())) { | |
| 1187 validateModifiersForGetterOrSetterOrMethod(modifiers); | |
| 1188 return parseGetter(commentAndMetadata, modifiers.externalKeyword, modifier
s.staticKeyword, null); | |
| 1189 } else if (matches(Keyword.SET) && matchesIdentifier2(peek())) { | |
| 1190 validateModifiersForGetterOrSetterOrMethod(modifiers); | |
| 1191 return parseSetter(commentAndMetadata, modifiers.externalKeyword, modifier
s.staticKeyword, null); | |
| 1192 } else if (matches(Keyword.OPERATOR) && peek().isOperator() && matches4(peek
2(2), TokenType.OPEN_PAREN)) { | |
| 1193 validateModifiersForOperator(modifiers); | |
| 1194 return parseOperator(commentAndMetadata, modifiers.externalKeyword, null); | |
| 1195 } else if (!matchesIdentifier()) { | |
| 1196 return null; | |
| 1197 } else if (matches4(peek(), TokenType.PERIOD) && matchesIdentifier2(peek2(2)
) && matches4(peek2(3), TokenType.OPEN_PAREN)) { | |
| 1198 return parseConstructor(commentAndMetadata, modifiers.externalKeyword, val
idateModifiersForConstructor(modifiers), modifiers.factoryKeyword, parseSimpleId
entifier(), andAdvance, parseSimpleIdentifier(), parseFormalParameterList()); | |
| 1199 } else if (matches4(peek(), TokenType.OPEN_PAREN)) { | |
| 1200 SimpleIdentifier methodName = parseSimpleIdentifier(); | |
| 1201 FormalParameterList parameters = parseFormalParameterList(); | |
| 1202 if (matches5(TokenType.COLON) || modifiers.factoryKeyword != null || metho
dName.name == className) { | |
| 1203 return parseConstructor(commentAndMetadata, modifiers.externalKeyword, v
alidateModifiersForConstructor(modifiers), modifiers.factoryKeyword, methodName,
null, null, parameters); | |
| 1204 } | |
| 1205 validateModifiersForGetterOrSetterOrMethod(modifiers); | |
| 1206 validateFormalParameterList(parameters); | |
| 1207 return parseMethodDeclaration2(commentAndMetadata, modifiers.externalKeywo
rd, modifiers.staticKeyword, null, methodName, parameters); | |
| 1208 } else if (matchesAny(peek(), [TokenType.EQ, TokenType.COMMA, TokenType.SEMI
COLON])) { | |
| 1209 return parseInitializedIdentifierList(commentAndMetadata, modifiers.static
Keyword, validateModifiersForField(modifiers), null); | |
| 1210 } | |
| 1211 TypeName type = parseTypeName(); | |
| 1212 if (matches(Keyword.GET) && matchesIdentifier2(peek())) { | |
| 1213 validateModifiersForGetterOrSetterOrMethod(modifiers); | |
| 1214 return parseGetter(commentAndMetadata, modifiers.externalKeyword, modifier
s.staticKeyword, type); | |
| 1215 } else if (matches(Keyword.SET) && matchesIdentifier2(peek())) { | |
| 1216 validateModifiersForGetterOrSetterOrMethod(modifiers); | |
| 1217 return parseSetter(commentAndMetadata, modifiers.externalKeyword, modifier
s.staticKeyword, type); | |
| 1218 } else if (matches(Keyword.OPERATOR) && peek().isOperator() && matches4(peek
2(2), TokenType.OPEN_PAREN)) { | |
| 1219 validateModifiersForOperator(modifiers); | |
| 1220 return parseOperator(commentAndMetadata, modifiers.externalKeyword, type); | |
| 1221 } else if (!matchesIdentifier()) { | |
| 1222 } else if (matches4(peek(), TokenType.OPEN_PAREN)) { | |
| 1223 validateModifiersForGetterOrSetterOrMethod(modifiers); | |
| 1224 return parseMethodDeclaration(commentAndMetadata, modifiers.externalKeywor
d, modifiers.staticKeyword, type); | |
| 1225 } | |
| 1226 return parseInitializedIdentifierList(commentAndMetadata, modifiers.staticKe
yword, validateModifiersForField(modifiers), type); | |
| 1227 } | |
| 1228 /** | |
| 1229 * Parse a list of class members. | |
| 1230 * <pre> | |
| 1231 * classMembers ::= | |
| 1232 * (metadata memberDefinition) | |
| 1233 * </pre> | |
| 1234 * @param className the name of the class whose members are being parsed | |
| 1235 * @param balancedBrackets {@code true} if the opening and closing brackets fo
r the class are | |
| 1236 * balanced | |
| 1237 * @return the list of class members that were parsed | |
| 1238 */ | |
| 1239 List<ClassMember> parseClassMembers(String className, bool balancedBrackets) { | |
| 1240 List<ClassMember> members = new List<ClassMember>(); | |
| 1241 Token memberStart = _currentToken; | |
| 1242 while (!matches5(TokenType.EOF) && !matches5(TokenType.CLOSE_CURLY_BRACKET)
&& (balancedBrackets || (!matches(Keyword.CLASS) && !matches(Keyword.TYPEDEF))))
{ | |
| 1243 if (matches5(TokenType.SEMICOLON)) { | |
| 1244 reportError5(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentT
oken.lexeme]); | |
| 1245 advance(); | |
| 1246 } else { | |
| 1247 ClassMember member = parseClassMember(className); | |
| 1248 if (member != null) { | |
| 1249 members.add(member); | |
| 1250 } | |
| 1251 } | |
| 1252 if (identical(_currentToken, memberStart)) { | |
| 1253 reportError5(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentT
oken.lexeme]); | |
| 1254 advance(); | |
| 1255 } | |
| 1256 memberStart = _currentToken; | |
| 1257 } | |
| 1258 return members; | |
| 1259 } | |
| 1260 /** | |
| 1261 * Parse a class type alias. | |
| 1262 * <pre> | |
| 1263 * classTypeAlias ::= | |
| 1264 * identifier typeParameters? '=' 'abstract'? mixinApplication | |
| 1265 * mixinApplication ::= | |
| 1266 * type withClause implementsClause? ';' | |
| 1267 * </pre> | |
| 1268 * @param commentAndMetadata the metadata to be associated with the member | |
| 1269 * @param keyword the token representing the 'typedef' keyword | |
| 1270 * @return the class type alias that was parsed | |
| 1271 */ | |
| 1272 ClassTypeAlias parseClassTypeAlias(CommentAndMetadata commentAndMetadata, Toke
n keyword) { | |
| 1273 SimpleIdentifier name = parseSimpleIdentifier(); | |
| 1274 TypeParameterList typeParameters = null; | |
| 1275 if (matches5(TokenType.LT)) { | |
| 1276 typeParameters = parseTypeParameterList(); | |
| 1277 } | |
| 1278 Token equals = expect2(TokenType.EQ); | |
| 1279 Token abstractKeyword = null; | |
| 1280 if (matches(Keyword.ABSTRACT)) { | |
| 1281 abstractKeyword = andAdvance; | |
| 1282 } | |
| 1283 TypeName superclass = parseTypeName(); | |
| 1284 WithClause withClause = parseWithClause(); | |
| 1285 ImplementsClause implementsClause = null; | |
| 1286 if (matches(Keyword.IMPLEMENTS)) { | |
| 1287 implementsClause = parseImplementsClause(); | |
| 1288 } | |
| 1289 Token semicolon = expect2(TokenType.SEMICOLON); | |
| 1290 return new ClassTypeAlias.full(commentAndMetadata.comment, commentAndMetadat
a.metadata, keyword, name, typeParameters, equals, abstractKeyword, superclass,
withClause, implementsClause, semicolon); | |
| 1291 } | |
| 1292 /** | |
| 1293 * Parse a list of combinators in a directive. | |
| 1294 * <pre> | |
| 1295 * combinator ::= | |
| 1296 * 'show' identifier (',' identifier) | |
| 1297 * | 'hide' identifier (',' identifier) | |
| 1298 * </pre> | |
| 1299 * @return the combinators that were parsed | |
| 1300 */ | |
| 1301 List<Combinator> parseCombinators() { | |
| 1302 List<Combinator> combinators = new List<Combinator>(); | |
| 1303 while (matches2(_SHOW) || matches2(_HIDE)) { | |
| 1304 Token keyword = expect2(TokenType.IDENTIFIER); | |
| 1305 if (keyword.lexeme == _SHOW) { | |
| 1306 List<SimpleIdentifier> shownNames = parseIdentifierList(); | |
| 1307 combinators.add(new ShowCombinator.full(keyword, shownNames)); | |
| 1308 } else { | |
| 1309 List<SimpleIdentifier> hiddenNames = parseIdentifierList(); | |
| 1310 combinators.add(new HideCombinator.full(keyword, hiddenNames)); | |
| 1311 } | |
| 1312 } | |
| 1313 return combinators; | |
| 1314 } | |
| 1315 /** | |
| 1316 * Parse the documentation comment and metadata preceeding a declaration. This
method allows any | |
| 1317 * number of documentation comments to occur before, after or between the meta
data, but only | |
| 1318 * returns the last (right-most) documentation comment that is found. | |
| 1319 * <pre> | |
| 1320 * metadata ::= | |
| 1321 * annotation | |
| 1322 * </pre> | |
| 1323 * @return the documentation comment and metadata that were parsed | |
| 1324 */ | |
| 1325 CommentAndMetadata parseCommentAndMetadata() { | |
| 1326 Comment comment = parseDocumentationComment(); | |
| 1327 List<Annotation> metadata = new List<Annotation>(); | |
| 1328 while (matches5(TokenType.AT)) { | |
| 1329 metadata.add(parseAnnotation()); | |
| 1330 Comment optionalComment = parseDocumentationComment(); | |
| 1331 if (optionalComment != null) { | |
| 1332 comment = optionalComment; | |
| 1333 } | |
| 1334 } | |
| 1335 return new CommentAndMetadata(comment, metadata); | |
| 1336 } | |
| 1337 /** | |
| 1338 * Parse a comment reference from the source between square brackets. | |
| 1339 * <pre> | |
| 1340 * commentReference ::= | |
| 1341 * 'new'? prefixedIdentifier | |
| 1342 * </pre> | |
| 1343 * @param referenceSource the source occurring between the square brackets wit
hin a documentation | |
| 1344 * comment | |
| 1345 * @param sourceOffset the offset of the first character of the reference sour
ce | |
| 1346 * @return the comment reference that was parsed | |
| 1347 */ | |
| 1348 CommentReference parseCommentReference(String referenceSource, int sourceOffse
t) { | |
| 1349 if (referenceSource.length == 0) { | |
| 1350 return null; | |
| 1351 } | |
| 1352 try { | |
| 1353 List<bool> errorFound = [false]; | |
| 1354 AnalysisErrorListener listener = new AnalysisErrorListener_7(errorFound); | |
| 1355 StringScanner scanner = new StringScanner(null, referenceSource, listener)
; | |
| 1356 scanner.setSourceStart(1, 1, sourceOffset); | |
| 1357 Token firstToken = scanner.tokenize(); | |
| 1358 if (!errorFound[0]) { | |
| 1359 Token newKeyword = null; | |
| 1360 if (matches3(firstToken, Keyword.NEW)) { | |
| 1361 newKeyword = firstToken; | |
| 1362 firstToken = firstToken.next; | |
| 1363 } | |
| 1364 if (matchesIdentifier2(firstToken)) { | |
| 1365 Token secondToken = firstToken.next; | |
| 1366 Token thirdToken = secondToken.next; | |
| 1367 Token nextToken; | |
| 1368 Identifier identifier; | |
| 1369 if (matches4(secondToken, TokenType.PERIOD) && matchesIdentifier2(thir
dToken)) { | |
| 1370 identifier = new PrefixedIdentifier.full(new SimpleIdentifier.full(f
irstToken), secondToken, new SimpleIdentifier.full(thirdToken)); | |
| 1371 nextToken = thirdToken.next; | |
| 1372 } else { | |
| 1373 identifier = new SimpleIdentifier.full(firstToken); | |
| 1374 nextToken = firstToken.next; | |
| 1375 } | |
| 1376 if (nextToken.type != TokenType.EOF) { | |
| 1377 } | |
| 1378 return new CommentReference.full(newKeyword, identifier); | |
| 1379 } else if (matches3(firstToken, Keyword.THIS) || matches3(firstToken, Ke
yword.NULL) || matches3(firstToken, Keyword.TRUE) || matches3(firstToken, Keywor
d.FALSE)) { | |
| 1380 return null; | |
| 1381 } else if (matches4(firstToken, TokenType.STRING)) { | |
| 1382 } else { | |
| 1383 } | |
| 1384 } | |
| 1385 } on JavaException catch (exception) { | |
| 1386 } | |
| 1387 return null; | |
| 1388 } | |
| 1389 /** | |
| 1390 * Parse all of the comment references occurring in the given array of documen
tation comments. | |
| 1391 * <pre> | |
| 1392 * commentReference ::= | |
| 1393 * '[' 'new'? qualified ']' libraryReference? | |
| 1394 * libraryReference ::= | |
| 1395 * '(' stringLiteral ')' | |
| 1396 * </pre> | |
| 1397 * @param tokens the comment tokens representing the documentation comments to
be parsed | |
| 1398 * @return the comment references that were parsed | |
| 1399 */ | |
| 1400 List<CommentReference> parseCommentReferences(List<Token> tokens) { | |
| 1401 List<CommentReference> references = new List<CommentReference>(); | |
| 1402 for (Token token in tokens) { | |
| 1403 String comment = token.lexeme; | |
| 1404 int leftIndex = comment.indexOf('['); | |
| 1405 while (leftIndex >= 0) { | |
| 1406 int rightIndex = comment.indexOf(']', leftIndex); | |
| 1407 if (rightIndex >= 0) { | |
| 1408 int firstChar = comment.codeUnitAt(leftIndex + 1); | |
| 1409 if (firstChar != 0x27 && firstChar != 0x22 && firstChar != 0x3A) { | |
| 1410 CommentReference reference = parseCommentReference(comment.substring
(leftIndex + 1, rightIndex), token.offset + leftIndex + 1); | |
| 1411 if (reference != null) { | |
| 1412 references.add(reference); | |
| 1413 } | |
| 1414 } | |
| 1415 } else { | |
| 1416 rightIndex = leftIndex + 1; | |
| 1417 } | |
| 1418 leftIndex = comment.indexOf('[', rightIndex); | |
| 1419 } | |
| 1420 } | |
| 1421 return references; | |
| 1422 } | |
| 1423 /** | |
| 1424 * Parse a compilation unit. | |
| 1425 * <p> | |
| 1426 * Specified: | |
| 1427 * <pre> | |
| 1428 * compilationUnit ::= | |
| 1429 * scriptTag? directive* topLevelDeclaration | |
| 1430 * </pre> | |
| 1431 * Actual: | |
| 1432 * <pre> | |
| 1433 * compilationUnit ::= | |
| 1434 * scriptTag? topLevelElement | |
| 1435 * topLevelElement ::= | |
| 1436 * directive | |
| 1437 * | topLevelDeclaration | |
| 1438 * </pre> | |
| 1439 * @return the compilation unit that was parsed | |
| 1440 */ | |
| 1441 CompilationUnit parseCompilationUnit2() { | |
| 1442 Token firstToken = _currentToken; | |
| 1443 ScriptTag scriptTag = null; | |
| 1444 if (matches5(TokenType.SCRIPT_TAG)) { | |
| 1445 scriptTag = new ScriptTag.full(andAdvance); | |
| 1446 } | |
| 1447 bool libraryDirectiveFound = false; | |
| 1448 bool partOfDirectiveFound = false; | |
| 1449 bool partDirectiveFound = false; | |
| 1450 bool directiveFoundAfterDeclaration = false; | |
| 1451 List<Directive> directives = new List<Directive>(); | |
| 1452 List<CompilationUnitMember> declarations = new List<CompilationUnitMember>()
; | |
| 1453 Token memberStart = _currentToken; | |
| 1454 while (!matches5(TokenType.EOF)) { | |
| 1455 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata(); | |
| 1456 if ((matches(Keyword.IMPORT) || matches(Keyword.EXPORT) || matches(Keyword
.LIBRARY) || matches(Keyword.PART)) && !matches4(peek(), TokenType.PERIOD) && !m
atches4(peek(), TokenType.LT)) { | |
| 1457 Directive directive = parseDirective(commentAndMetadata); | |
| 1458 if (declarations.length > 0 && !directiveFoundAfterDeclaration) { | |
| 1459 reportError4(ParserErrorCode.DIRECTIVE_AFTER_DECLARATION, []); | |
| 1460 directiveFoundAfterDeclaration = true; | |
| 1461 } | |
| 1462 if (directive is LibraryDirective) { | |
| 1463 if (libraryDirectiveFound) { | |
| 1464 reportError4(ParserErrorCode.MULTIPLE_LIBRARY_DIRECTIVES, []); | |
| 1465 } else { | |
| 1466 if (directives.length > 0) { | |
| 1467 reportError4(ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST, []); | |
| 1468 } | |
| 1469 libraryDirectiveFound = true; | |
| 1470 } | |
| 1471 } else if (directive is PartDirective) { | |
| 1472 partDirectiveFound = true; | |
| 1473 } else if (partDirectiveFound) { | |
| 1474 if (directive is ExportDirective) { | |
| 1475 reportError4(ParserErrorCode.EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE,
[]); | |
| 1476 } else if (directive is ImportDirective) { | |
| 1477 reportError4(ParserErrorCode.IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE,
[]); | |
| 1478 } | |
| 1479 } | |
| 1480 if (directive is PartOfDirective) { | |
| 1481 if (partOfDirectiveFound) { | |
| 1482 reportError4(ParserErrorCode.MULTIPLE_PART_OF_DIRECTIVES, []); | |
| 1483 } else { | |
| 1484 for (Directive preceedingDirective in directives) { | |
| 1485 reportError5(ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART, precee
dingDirective.keyword, []); | |
| 1486 } | |
| 1487 partOfDirectiveFound = true; | |
| 1488 } | |
| 1489 } else { | |
| 1490 if (partOfDirectiveFound) { | |
| 1491 reportError5(ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART, directiv
e.keyword, []); | |
| 1492 } | |
| 1493 } | |
| 1494 directives.add(directive); | |
| 1495 } else if (matches5(TokenType.SEMICOLON)) { | |
| 1496 reportError5(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentT
oken.lexeme]); | |
| 1497 advance(); | |
| 1498 } else { | |
| 1499 CompilationUnitMember member = parseCompilationUnitMember(commentAndMeta
data); | |
| 1500 if (member != null) { | |
| 1501 declarations.add(member); | |
| 1502 } | |
| 1503 } | |
| 1504 if (identical(_currentToken, memberStart)) { | |
| 1505 reportError5(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentT
oken.lexeme]); | |
| 1506 advance(); | |
| 1507 } | |
| 1508 memberStart = _currentToken; | |
| 1509 } | |
| 1510 return new CompilationUnit.full(firstToken, scriptTag, directives, declarati
ons, _currentToken); | |
| 1511 } | |
| 1512 /** | |
| 1513 * Parse a compilation unit member. | |
| 1514 * <pre> | |
| 1515 * compilationUnitMember ::= | |
| 1516 * classDefinition | |
| 1517 * | functionTypeAlias | |
| 1518 * | external functionSignature | |
| 1519 * | external getterSignature | |
| 1520 * | external setterSignature | |
| 1521 * | functionSignature functionBody | |
| 1522 * | returnType? getOrSet identifier formalParameterList functionBody | |
| 1523 * | (final | const) type? staticFinalDeclarationList ';' | |
| 1524 * | variableDeclaration ';' | |
| 1525 * </pre> | |
| 1526 * @param commentAndMetadata the metadata to be associated with the member | |
| 1527 * @return the compilation unit member that was parsed | |
| 1528 */ | |
| 1529 CompilationUnitMember parseCompilationUnitMember(CommentAndMetadata commentAnd
Metadata) { | |
| 1530 Modifiers modifiers = parseModifiers(); | |
| 1531 if (matches(Keyword.CLASS)) { | |
| 1532 return parseClassDeclaration(commentAndMetadata, validateModifiersForClass
(modifiers)); | |
| 1533 } else if (matches(Keyword.TYPEDEF) && !matches4(peek(), TokenType.PERIOD) &
& !matches4(peek(), TokenType.LT)) { | |
| 1534 validateModifiersForTypedef(modifiers); | |
| 1535 return parseTypeAlias(commentAndMetadata); | |
| 1536 } | |
| 1537 if (matches(Keyword.VOID)) { | |
| 1538 TypeName returnType = parseReturnType(); | |
| 1539 if ((matches(Keyword.GET) || matches(Keyword.SET)) && matchesIdentifier2(p
eek())) { | |
| 1540 validateModifiersForTopLevelFunction(modifiers); | |
| 1541 return parseFunctionDeclaration(commentAndMetadata, modifiers.externalKe
yword, null); | |
| 1542 } else if (matches(Keyword.OPERATOR) && peek().isOperator()) { | |
| 1543 return null; | |
| 1544 } else if (matchesIdentifier() && matchesAny(peek(), [TokenType.OPEN_PAREN
, TokenType.OPEN_CURLY_BRACKET, TokenType.FUNCTION])) { | |
| 1545 validateModifiersForTopLevelFunction(modifiers); | |
| 1546 return parseFunctionDeclaration(commentAndMetadata, modifiers.externalKe
yword, null); | |
| 1547 } else { | |
| 1548 if (matchesIdentifier()) { | |
| 1549 if (matchesAny(peek(), [TokenType.EQ, TokenType.COMMA, TokenType.SEMIC
OLON])) { | |
| 1550 reportError(ParserErrorCode.VOID_VARIABLE, returnType, []); | |
| 1551 return new TopLevelVariableDeclaration.full(commentAndMetadata.comme
nt, commentAndMetadata.metadata, parseVariableDeclarationList2(validateModifiers
ForTopLevelVariable(modifiers), null), expect2(TokenType.SEMICOLON)); | |
| 1552 } | |
| 1553 } | |
| 1554 return null; | |
| 1555 } | |
| 1556 } else if ((matches(Keyword.GET) || matches(Keyword.SET)) && matchesIdentifi
er2(peek())) { | |
| 1557 validateModifiersForTopLevelFunction(modifiers); | |
| 1558 return parseFunctionDeclaration(commentAndMetadata, modifiers.externalKeyw
ord, null); | |
| 1559 } else if (matches(Keyword.OPERATOR) && peek().isOperator() && matches4(peek
2(2), TokenType.OPEN_PAREN)) { | |
| 1560 return null; | |
| 1561 } else if (!matchesIdentifier()) { | |
| 1562 return null; | |
| 1563 } else if (matches4(peek(), TokenType.OPEN_PAREN)) { | |
| 1564 validateModifiersForTopLevelFunction(modifiers); | |
| 1565 return parseFunctionDeclaration(commentAndMetadata, modifiers.externalKeyw
ord, null); | |
| 1566 } else if (matchesAny(peek(), [TokenType.EQ, TokenType.COMMA, TokenType.SEMI
COLON])) { | |
| 1567 return new TopLevelVariableDeclaration.full(commentAndMetadata.comment, co
mmentAndMetadata.metadata, parseVariableDeclarationList2(validateModifiersForTop
LevelVariable(modifiers), null), expect2(TokenType.SEMICOLON)); | |
| 1568 } | |
| 1569 TypeName returnType = parseReturnType(); | |
| 1570 if (matches(Keyword.GET) || matches(Keyword.SET)) { | |
| 1571 validateModifiersForTopLevelFunction(modifiers); | |
| 1572 return parseFunctionDeclaration(commentAndMetadata, modifiers.externalKeyw
ord, returnType); | |
| 1573 } else if (!matchesIdentifier()) { | |
| 1574 return null; | |
| 1575 } | |
| 1576 if (matchesAny(peek(), [TokenType.OPEN_PAREN, TokenType.FUNCTION, TokenType.
OPEN_CURLY_BRACKET])) { | |
| 1577 validateModifiersForTopLevelFunction(modifiers); | |
| 1578 return parseFunctionDeclaration(commentAndMetadata, modifiers.externalKeyw
ord, returnType); | |
| 1579 } | |
| 1580 return new TopLevelVariableDeclaration.full(commentAndMetadata.comment, comm
entAndMetadata.metadata, parseVariableDeclarationList2(validateModifiersForTopLe
velVariable(modifiers), returnType), expect2(TokenType.SEMICOLON)); | |
| 1581 } | |
| 1582 /** | |
| 1583 * Parse a conditional expression. | |
| 1584 * <pre> | |
| 1585 * conditionalExpression ::= | |
| 1586 * logicalOrExpression ('?' expressionWithoutCascade ':' expressionWithoutCasc
ade)? | |
| 1587 * </pre> | |
| 1588 * @return the conditional expression that was parsed | |
| 1589 */ | |
| 1590 Expression parseConditionalExpression() { | |
| 1591 Expression condition = parseLogicalOrExpression(); | |
| 1592 if (!matches5(TokenType.QUESTION)) { | |
| 1593 return condition; | |
| 1594 } | |
| 1595 Token question = andAdvance; | |
| 1596 Expression thenExpression = parseExpressionWithoutCascade(); | |
| 1597 Token colon = expect2(TokenType.COLON); | |
| 1598 Expression elseExpression = parseExpressionWithoutCascade(); | |
| 1599 return new ConditionalExpression.full(condition, question, thenExpression, c
olon, elseExpression); | |
| 1600 } | |
| 1601 /** | |
| 1602 * Parse a const expression. | |
| 1603 * <pre> | |
| 1604 * constExpression ::= | |
| 1605 * instanceCreationExpression | |
| 1606 * | listLiteral | |
| 1607 * | mapLiteral | |
| 1608 * </pre> | |
| 1609 * @return the const expression that was parsed | |
| 1610 */ | |
| 1611 Expression parseConstExpression() { | |
| 1612 Token keyword = expect(Keyword.CONST); | |
| 1613 if (matches5(TokenType.OPEN_SQUARE_BRACKET) || matches5(TokenType.INDEX)) { | |
| 1614 return parseListLiteral(keyword, null); | |
| 1615 } else if (matches5(TokenType.OPEN_CURLY_BRACKET)) { | |
| 1616 return parseMapLiteral(keyword, null); | |
| 1617 } else if (matches5(TokenType.LT)) { | |
| 1618 return parseListOrMapLiteral(keyword); | |
| 1619 } | |
| 1620 return parseInstanceCreationExpression(keyword); | |
| 1621 } | |
| 1622 ConstructorDeclaration parseConstructor(CommentAndMetadata commentAndMetadata,
Token externalKeyword, Token constKeyword, Token factoryKeyword, SimpleIdentifi
er returnType, Token period, SimpleIdentifier name, FormalParameterList paramete
rs) { | |
| 1623 bool bodyAllowed = externalKeyword == null; | |
| 1624 Token separator = null; | |
| 1625 List<ConstructorInitializer> initializers = null; | |
| 1626 if (matches5(TokenType.COLON)) { | |
| 1627 separator = andAdvance; | |
| 1628 initializers = new List<ConstructorInitializer>(); | |
| 1629 do { | |
| 1630 if (matches(Keyword.THIS)) { | |
| 1631 if (matches4(peek(), TokenType.OPEN_PAREN)) { | |
| 1632 bodyAllowed = false; | |
| 1633 initializers.add(parseRedirectingConstructorInvocation()); | |
| 1634 } else if (matches4(peek(), TokenType.PERIOD) && matches4(peek2(3), To
kenType.OPEN_PAREN)) { | |
| 1635 bodyAllowed = false; | |
| 1636 initializers.add(parseRedirectingConstructorInvocation()); | |
| 1637 } else { | |
| 1638 initializers.add(parseConstructorFieldInitializer()); | |
| 1639 } | |
| 1640 } else if (matches(Keyword.SUPER)) { | |
| 1641 initializers.add(parseSuperConstructorInvocation()); | |
| 1642 } else { | |
| 1643 initializers.add(parseConstructorFieldInitializer()); | |
| 1644 } | |
| 1645 } while (optional(TokenType.COMMA)); | |
| 1646 } | |
| 1647 ConstructorName redirectedConstructor = null; | |
| 1648 FunctionBody body; | |
| 1649 if (matches5(TokenType.EQ)) { | |
| 1650 separator = andAdvance; | |
| 1651 redirectedConstructor = parseConstructorName(); | |
| 1652 body = new EmptyFunctionBody.full(expect2(TokenType.SEMICOLON)); | |
| 1653 } else { | |
| 1654 body = parseFunctionBody(true, false); | |
| 1655 if (!bodyAllowed && body is! EmptyFunctionBody) { | |
| 1656 reportError4(ParserErrorCode.EXTERNAL_CONSTRUCTOR_WITH_BODY, []); | |
| 1657 } | |
| 1658 } | |
| 1659 return new ConstructorDeclaration.full(commentAndMetadata.comment, commentAn
dMetadata.metadata, externalKeyword, constKeyword, factoryKeyword, returnType, p
eriod, name, parameters, separator, initializers, redirectedConstructor, body); | |
| 1660 } | |
| 1661 /** | |
| 1662 * Parse a field initializer within a constructor. | |
| 1663 * <pre> | |
| 1664 * fieldInitializer: | |
| 1665 * ('this' '.')? identifier '=' conditionalExpression cascadeSection | |
| 1666 * </pre> | |
| 1667 * @return the field initializer that was parsed | |
| 1668 */ | |
| 1669 ConstructorFieldInitializer parseConstructorFieldInitializer() { | |
| 1670 Token keyword = null; | |
| 1671 Token period = null; | |
| 1672 if (matches(Keyword.THIS)) { | |
| 1673 keyword = andAdvance; | |
| 1674 period = expect2(TokenType.PERIOD); | |
| 1675 } | |
| 1676 SimpleIdentifier fieldName = parseSimpleIdentifier(); | |
| 1677 Token equals = expect2(TokenType.EQ); | |
| 1678 Expression expression = parseConditionalExpression(); | |
| 1679 TokenType tokenType = _currentToken.type; | |
| 1680 if (identical(tokenType, TokenType.PERIOD_PERIOD)) { | |
| 1681 List<Expression> cascadeSections = new List<Expression>(); | |
| 1682 while (identical(tokenType, TokenType.PERIOD_PERIOD)) { | |
| 1683 Expression section = parseCascadeSection(); | |
| 1684 if (section != null) { | |
| 1685 cascadeSections.add(section); | |
| 1686 } | |
| 1687 tokenType = _currentToken.type; | |
| 1688 } | |
| 1689 expression = new CascadeExpression.full(expression, cascadeSections); | |
| 1690 } | |
| 1691 return new ConstructorFieldInitializer.full(keyword, period, fieldName, equa
ls, expression); | |
| 1692 } | |
| 1693 /** | |
| 1694 * Parse the name of a constructor. | |
| 1695 * <pre> | |
| 1696 * constructorName: | |
| 1697 * type ('.' identifier)? | |
| 1698 * </pre> | |
| 1699 * @return the constructor name that was parsed | |
| 1700 */ | |
| 1701 ConstructorName parseConstructorName() { | |
| 1702 TypeName type = parseTypeName(); | |
| 1703 Token period = null; | |
| 1704 SimpleIdentifier name = null; | |
| 1705 if (matches5(TokenType.PERIOD)) { | |
| 1706 period = andAdvance; | |
| 1707 name = parseSimpleIdentifier(); | |
| 1708 } | |
| 1709 return new ConstructorName.full(type, period, name); | |
| 1710 } | |
| 1711 /** | |
| 1712 * Parse a continue statement. | |
| 1713 * <pre> | |
| 1714 * continueStatement ::= | |
| 1715 * 'continue' identifier? ';' | |
| 1716 * </pre> | |
| 1717 * @return the continue statement that was parsed | |
| 1718 */ | |
| 1719 Statement parseContinueStatement() { | |
| 1720 Token continueKeyword = expect(Keyword.CONTINUE); | |
| 1721 if (!_inLoop && !_inSwitch) { | |
| 1722 reportError5(ParserErrorCode.CONTINUE_OUTSIDE_OF_LOOP, continueKeyword, []
); | |
| 1723 } | |
| 1724 SimpleIdentifier label = null; | |
| 1725 if (matchesIdentifier()) { | |
| 1726 label = parseSimpleIdentifier(); | |
| 1727 } | |
| 1728 if (_inSwitch && !_inLoop && label == null) { | |
| 1729 reportError5(ParserErrorCode.CONTINUE_WITHOUT_LABEL_IN_CASE, continueKeywo
rd, []); | |
| 1730 } | |
| 1731 Token semicolon = expect2(TokenType.SEMICOLON); | |
| 1732 return new ContinueStatement.full(continueKeyword, label, semicolon); | |
| 1733 } | |
| 1734 /** | |
| 1735 * Parse a directive. | |
| 1736 * <pre> | |
| 1737 * directive ::= | |
| 1738 * exportDirective | |
| 1739 * | libraryDirective | |
| 1740 * | importDirective | |
| 1741 * | partDirective | |
| 1742 * </pre> | |
| 1743 * @param commentAndMetadata the metadata to be associated with the directive | |
| 1744 * @return the directive that was parsed | |
| 1745 */ | |
| 1746 Directive parseDirective(CommentAndMetadata commentAndMetadata) { | |
| 1747 if (matches(Keyword.IMPORT)) { | |
| 1748 return parseImportDirective(commentAndMetadata); | |
| 1749 } else if (matches(Keyword.EXPORT)) { | |
| 1750 return parseExportDirective(commentAndMetadata); | |
| 1751 } else if (matches(Keyword.LIBRARY)) { | |
| 1752 return parseLibraryDirective(commentAndMetadata); | |
| 1753 } else if (matches(Keyword.PART)) { | |
| 1754 return parsePartDirective(commentAndMetadata); | |
| 1755 } else { | |
| 1756 return null; | |
| 1757 } | |
| 1758 } | |
| 1759 /** | |
| 1760 * Parse a documentation comment. | |
| 1761 * <pre> | |
| 1762 * documentationComment ::= | |
| 1763 * multiLineComment? | |
| 1764 * | singleLineComment | |
| 1765 * </pre> | |
| 1766 * @return the documentation comment that was parsed, or {@code null} if there
was no comment | |
| 1767 */ | |
| 1768 Comment parseDocumentationComment() { | |
| 1769 List<Token> commentTokens = new List<Token>(); | |
| 1770 Token commentToken = _currentToken.precedingComments; | |
| 1771 while (commentToken != null) { | |
| 1772 if (identical(commentToken.type, TokenType.SINGLE_LINE_COMMENT)) { | |
| 1773 if (commentToken.lexeme.startsWith("///")) { | |
| 1774 if (commentTokens.length == 1 && commentTokens[0].lexeme.startsWith("/
**")) { | |
| 1775 commentTokens.clear(); | |
| 1776 } | |
| 1777 commentTokens.add(commentToken); | |
| 1778 } | |
| 1779 } else { | |
| 1780 if (commentToken.lexeme.startsWith("/**")) { | |
| 1781 commentTokens.clear(); | |
| 1782 commentTokens.add(commentToken); | |
| 1783 } | |
| 1784 } | |
| 1785 commentToken = commentToken.next; | |
| 1786 } | |
| 1787 if (commentTokens.isEmpty) { | |
| 1788 return null; | |
| 1789 } | |
| 1790 List<Token> tokens = new List.from(commentTokens); | |
| 1791 List<CommentReference> references = parseCommentReferences(tokens); | |
| 1792 return Comment.createDocumentationComment2(tokens, references); | |
| 1793 } | |
| 1794 /** | |
| 1795 * Parse a do statement. | |
| 1796 * <pre> | |
| 1797 * doStatement ::= | |
| 1798 * 'do' statement 'while' '(' expression ')' ';' | |
| 1799 * </pre> | |
| 1800 * @return the do statement that was parsed | |
| 1801 */ | |
| 1802 Statement parseDoStatement() { | |
| 1803 bool wasInLoop = _inLoop; | |
| 1804 _inLoop = true; | |
| 1805 try { | |
| 1806 Token doKeyword = expect(Keyword.DO); | |
| 1807 Statement body = parseStatement2(); | |
| 1808 Token whileKeyword = expect(Keyword.WHILE); | |
| 1809 Token leftParenthesis = expect2(TokenType.OPEN_PAREN); | |
| 1810 Expression condition = parseExpression2(); | |
| 1811 Token rightParenthesis = expect2(TokenType.CLOSE_PAREN); | |
| 1812 Token semicolon = expect2(TokenType.SEMICOLON); | |
| 1813 return new DoStatement.full(doKeyword, body, whileKeyword, leftParenthesis
, condition, rightParenthesis, semicolon); | |
| 1814 } finally { | |
| 1815 _inLoop = wasInLoop; | |
| 1816 } | |
| 1817 } | |
| 1818 /** | |
| 1819 * Parse an empty statement. | |
| 1820 * <pre> | |
| 1821 * emptyStatement ::= | |
| 1822 * ';' | |
| 1823 * </pre> | |
| 1824 * @return the empty statement that was parsed | |
| 1825 */ | |
| 1826 Statement parseEmptyStatement() => new EmptyStatement.full(andAdvance); | |
| 1827 /** | |
| 1828 * Parse an equality expression. | |
| 1829 * <pre> | |
| 1830 * equalityExpression ::= | |
| 1831 * relationalExpression (equalityOperator relationalExpression)? | |
| 1832 * | 'super' equalityOperator relationalExpression | |
| 1833 * </pre> | |
| 1834 * @return the equality expression that was parsed | |
| 1835 */ | |
| 1836 Expression parseEqualityExpression() { | |
| 1837 Expression expression; | |
| 1838 if (matches(Keyword.SUPER) && _currentToken.next.type.isEqualityOperator())
{ | |
| 1839 expression = new SuperExpression.full(andAdvance); | |
| 1840 } else { | |
| 1841 expression = parseRelationalExpression(); | |
| 1842 } | |
| 1843 while (_currentToken.type.isEqualityOperator()) { | |
| 1844 Token operator = andAdvance; | |
| 1845 expression = new BinaryExpression.full(expression, operator, parseRelation
alExpression()); | |
| 1846 } | |
| 1847 return expression; | |
| 1848 } | |
| 1849 /** | |
| 1850 * Parse an export directive. | |
| 1851 * <pre> | |
| 1852 * exportDirective ::= | |
| 1853 * metadata 'export' stringLiteral combinator*';' | |
| 1854 * </pre> | |
| 1855 * @param commentAndMetadata the metadata to be associated with the directive | |
| 1856 * @return the export directive that was parsed | |
| 1857 */ | |
| 1858 ExportDirective parseExportDirective(CommentAndMetadata commentAndMetadata) { | |
| 1859 Token exportKeyword = expect(Keyword.EXPORT); | |
| 1860 StringLiteral libraryUri = parseStringLiteral(); | |
| 1861 List<Combinator> combinators = parseCombinators(); | |
| 1862 Token semicolon = expect2(TokenType.SEMICOLON); | |
| 1863 return new ExportDirective.full(commentAndMetadata.comment, commentAndMetada
ta.metadata, exportKeyword, libraryUri, combinators, semicolon); | |
| 1864 } | |
| 1865 /** | |
| 1866 * Parse an expression that does not contain any cascades. | |
| 1867 * <pre> | |
| 1868 * expression ::= | |
| 1869 * assignableExpression assignmentOperator expression | |
| 1870 * | conditionalExpression cascadeSection | |
| 1871 * | throwExpression | |
| 1872 * </pre> | |
| 1873 * @return the expression that was parsed | |
| 1874 */ | |
| 1875 Expression parseExpression2() { | |
| 1876 if (matches(Keyword.THROW)) { | |
| 1877 return parseThrowExpression(); | |
| 1878 } | |
| 1879 Expression expression = parseConditionalExpression(); | |
| 1880 TokenType tokenType = _currentToken.type; | |
| 1881 if (identical(tokenType, TokenType.PERIOD_PERIOD)) { | |
| 1882 List<Expression> cascadeSections = new List<Expression>(); | |
| 1883 while (identical(tokenType, TokenType.PERIOD_PERIOD)) { | |
| 1884 Expression section = parseCascadeSection(); | |
| 1885 if (section != null) { | |
| 1886 cascadeSections.add(section); | |
| 1887 } | |
| 1888 tokenType = _currentToken.type; | |
| 1889 } | |
| 1890 return new CascadeExpression.full(expression, cascadeSections); | |
| 1891 } else if (tokenType.isAssignmentOperator()) { | |
| 1892 Token operator = andAdvance; | |
| 1893 ensureAssignable(expression); | |
| 1894 return new AssignmentExpression.full(expression, operator, parseExpression
2()); | |
| 1895 } | |
| 1896 return expression; | |
| 1897 } | |
| 1898 /** | |
| 1899 * Parse a list of expressions. | |
| 1900 * <pre> | |
| 1901 * expressionList ::= | |
| 1902 * expression (',' expression) | |
| 1903 * </pre> | |
| 1904 * @return the expression that was parsed | |
| 1905 */ | |
| 1906 List<Expression> parseExpressionList() { | |
| 1907 List<Expression> expressions = new List<Expression>(); | |
| 1908 expressions.add(parseExpression2()); | |
| 1909 while (optional(TokenType.COMMA)) { | |
| 1910 expressions.add(parseExpression2()); | |
| 1911 } | |
| 1912 return expressions; | |
| 1913 } | |
| 1914 /** | |
| 1915 * Parse an expression that does not contain any cascades. | |
| 1916 * <pre> | |
| 1917 * expressionWithoutCascade ::= | |
| 1918 * assignableExpression assignmentOperator expressionWithoutCascade | |
| 1919 * | conditionalExpression | |
| 1920 * | throwExpressionWithoutCascade | |
| 1921 * </pre> | |
| 1922 * @return the expression that was parsed | |
| 1923 */ | |
| 1924 Expression parseExpressionWithoutCascade() { | |
| 1925 if (matches(Keyword.THROW)) { | |
| 1926 return parseThrowExpressionWithoutCascade(); | |
| 1927 } | |
| 1928 Expression expression = parseConditionalExpression(); | |
| 1929 if (_currentToken.type.isAssignmentOperator()) { | |
| 1930 Token operator = andAdvance; | |
| 1931 ensureAssignable(expression); | |
| 1932 expression = new AssignmentExpression.full(expression, operator, parseExpr
essionWithoutCascade()); | |
| 1933 } | |
| 1934 return expression; | |
| 1935 } | |
| 1936 /** | |
| 1937 * Parse a class extends clause. | |
| 1938 * <pre> | |
| 1939 * classExtendsClause ::= | |
| 1940 * 'extends' type | |
| 1941 * </pre> | |
| 1942 * @return the class extends clause that was parsed | |
| 1943 */ | |
| 1944 ExtendsClause parseExtendsClause() { | |
| 1945 Token keyword = expect(Keyword.EXTENDS); | |
| 1946 TypeName superclass = parseTypeName(); | |
| 1947 return new ExtendsClause.full(keyword, superclass); | |
| 1948 } | |
| 1949 /** | |
| 1950 * Parse the 'final', 'const', 'var' or type preceding a variable declaration. | |
| 1951 * <pre> | |
| 1952 * finalConstVarOrType ::= | |
| 1953 * | 'final' type? | |
| 1954 * | 'const' type? | |
| 1955 * | 'var' | |
| 1956 * | type | |
| 1957 * </pre> | |
| 1958 * @param optional {@code true} if the keyword and type are optional | |
| 1959 * @return the 'final', 'const', 'var' or type that was parsed | |
| 1960 */ | |
| 1961 FinalConstVarOrType parseFinalConstVarOrType(bool optional) { | |
| 1962 Token keyword = null; | |
| 1963 TypeName type = null; | |
| 1964 if (matches(Keyword.FINAL) || matches(Keyword.CONST)) { | |
| 1965 keyword = andAdvance; | |
| 1966 if (matchesIdentifier2(peek()) || matches4(peek(), TokenType.LT) || matche
s3(peek(), Keyword.THIS)) { | |
| 1967 type = parseTypeName(); | |
| 1968 } | |
| 1969 } else if (matches(Keyword.VAR)) { | |
| 1970 keyword = andAdvance; | |
| 1971 } else { | |
| 1972 if (matchesIdentifier2(peek()) || matches4(peek(), TokenType.LT) || matche
s3(peek(), Keyword.THIS) || (matches4(peek(), TokenType.PERIOD) && matchesIdenti
fier2(peek2(2)) && (matchesIdentifier2(peek2(3)) || matches4(peek2(3), TokenType
.LT) || matches3(peek2(3), Keyword.THIS)))) { | |
| 1973 type = parseReturnType(); | |
| 1974 } else if (!optional) { | |
| 1975 reportError4(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, []); | |
| 1976 } | |
| 1977 } | |
| 1978 return new FinalConstVarOrType(keyword, type); | |
| 1979 } | |
| 1980 /** | |
| 1981 * Parse a formal parameter. At most one of {@code isOptional} and {@code isNa
med} can be{@code true}. | |
| 1982 * <pre> | |
| 1983 * defaultFormalParameter ::= | |
| 1984 * normalFormalParameter ('=' expression)? | |
| 1985 * defaultNamedParameter ::= | |
| 1986 * normalFormalParameter (':' expression)? | |
| 1987 * </pre> | |
| 1988 * @param kind the kind of parameter being expected based on the presence or a
bsence of group | |
| 1989 * delimiters | |
| 1990 * @return the formal parameter that was parsed | |
| 1991 */ | |
| 1992 FormalParameter parseFormalParameter(ParameterKind kind) { | |
| 1993 NormalFormalParameter parameter = parseNormalFormalParameter(); | |
| 1994 if (matches5(TokenType.EQ)) { | |
| 1995 Token seperator = andAdvance; | |
| 1996 Expression defaultValue = parseExpression2(); | |
| 1997 if (identical(kind, ParameterKind.NAMED)) { | |
| 1998 reportError5(ParserErrorCode.WRONG_SEPARATOR_FOR_NAMED_PARAMETER, sepera
tor, []); | |
| 1999 } else if (identical(kind, ParameterKind.REQUIRED)) { | |
| 2000 reportError(ParserErrorCode.POSITIONAL_PARAMETER_OUTSIDE_GROUP, paramete
r, []); | |
| 2001 } | |
| 2002 return new DefaultFormalParameter.full(parameter, kind, seperator, default
Value); | |
| 2003 } else if (matches5(TokenType.COLON)) { | |
| 2004 Token seperator = andAdvance; | |
| 2005 Expression defaultValue = parseExpression2(); | |
| 2006 if (identical(kind, ParameterKind.POSITIONAL)) { | |
| 2007 reportError5(ParserErrorCode.WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER, s
eperator, []); | |
| 2008 } else if (identical(kind, ParameterKind.REQUIRED)) { | |
| 2009 reportError(ParserErrorCode.NAMED_PARAMETER_OUTSIDE_GROUP, parameter, []
); | |
| 2010 } | |
| 2011 return new DefaultFormalParameter.full(parameter, kind, seperator, default
Value); | |
| 2012 } else if (kind != ParameterKind.REQUIRED) { | |
| 2013 return new DefaultFormalParameter.full(parameter, kind, null, null); | |
| 2014 } | |
| 2015 return parameter; | |
| 2016 } | |
| 2017 /** | |
| 2018 * Parse a list of formal parameters. | |
| 2019 * <pre> | |
| 2020 * formalParameterList ::= | |
| 2021 * '(' ')' | |
| 2022 * | '(' normalFormalParameters (',' optionalFormalParameters)? ')' | |
| 2023 * | '(' optionalFormalParameters ')' | |
| 2024 * normalFormalParameters ::= | |
| 2025 * normalFormalParameter (',' normalFormalParameter) | |
| 2026 * optionalFormalParameters ::= | |
| 2027 * optionalPositionalFormalParameters | |
| 2028 * | namedFormalParameters | |
| 2029 * optionalPositionalFormalParameters ::= | |
| 2030 * '[' defaultFormalParameter (',' defaultFormalParameter)* ']' | |
| 2031 * namedFormalParameters ::= | |
| 2032 * '{' defaultNamedParameter (',' defaultNamedParameter)* '}' | |
| 2033 * </pre> | |
| 2034 * @return the formal parameters that were parsed | |
| 2035 */ | |
| 2036 FormalParameterList parseFormalParameterList() { | |
| 2037 if (matches5(TokenType.EQ) && matches4(peek(), TokenType.OPEN_PAREN)) { | |
| 2038 Token previous4 = _currentToken.previous; | |
| 2039 if ((matches4(previous4, TokenType.EQ_EQ) || matches4(previous4, TokenType
.BANG_EQ)) && _currentToken.offset == previous4.offset + 2) { | |
| 2040 advance(); | |
| 2041 } | |
| 2042 } | |
| 2043 Token leftParenthesis = expect2(TokenType.OPEN_PAREN); | |
| 2044 if (matches5(TokenType.CLOSE_PAREN)) { | |
| 2045 return new FormalParameterList.full(leftParenthesis, null, null, null, and
Advance); | |
| 2046 } | |
| 2047 List<FormalParameter> parameters = new List<FormalParameter>(); | |
| 2048 List<FormalParameter> normalParameters = new List<FormalParameter>(); | |
| 2049 List<FormalParameter> positionalParameters = new List<FormalParameter>(); | |
| 2050 List<FormalParameter> namedParameters = new List<FormalParameter>(); | |
| 2051 List<FormalParameter> currentParameters = normalParameters; | |
| 2052 Token leftSquareBracket = null; | |
| 2053 Token rightSquareBracket = null; | |
| 2054 Token leftCurlyBracket = null; | |
| 2055 Token rightCurlyBracket = null; | |
| 2056 ParameterKind kind = ParameterKind.REQUIRED; | |
| 2057 bool firstParameter = true; | |
| 2058 bool reportedMuliplePositionalGroups = false; | |
| 2059 bool reportedMulipleNamedGroups = false; | |
| 2060 bool reportedMixedGroups = false; | |
| 2061 Token initialToken = null; | |
| 2062 do { | |
| 2063 if (firstParameter) { | |
| 2064 firstParameter = false; | |
| 2065 } else if (!optional(TokenType.COMMA)) { | |
| 2066 if (((leftParenthesis as BeginToken)).endToken != null) { | |
| 2067 reportError4(ParserErrorCode.EXPECTED_TOKEN, [TokenType.COMMA.lexeme])
; | |
| 2068 } else { | |
| 2069 break; | |
| 2070 } | |
| 2071 } | |
| 2072 initialToken = _currentToken; | |
| 2073 if (matches5(TokenType.OPEN_SQUARE_BRACKET)) { | |
| 2074 if (leftSquareBracket != null && !reportedMuliplePositionalGroups) { | |
| 2075 reportError4(ParserErrorCode.MULTIPLE_POSITIONAL_PARAMETER_GROUPS, [])
; | |
| 2076 reportedMuliplePositionalGroups = true; | |
| 2077 } | |
| 2078 if (leftCurlyBracket != null && !reportedMixedGroups) { | |
| 2079 reportError4(ParserErrorCode.MIXED_PARAMETER_GROUPS, []); | |
| 2080 reportedMixedGroups = true; | |
| 2081 } | |
| 2082 leftSquareBracket = andAdvance; | |
| 2083 currentParameters = positionalParameters; | |
| 2084 kind = ParameterKind.POSITIONAL; | |
| 2085 } else if (matches5(TokenType.OPEN_CURLY_BRACKET)) { | |
| 2086 if (leftCurlyBracket != null && !reportedMulipleNamedGroups) { | |
| 2087 reportError4(ParserErrorCode.MULTIPLE_NAMED_PARAMETER_GROUPS, []); | |
| 2088 reportedMulipleNamedGroups = true; | |
| 2089 } | |
| 2090 if (leftSquareBracket != null && !reportedMixedGroups) { | |
| 2091 reportError4(ParserErrorCode.MIXED_PARAMETER_GROUPS, []); | |
| 2092 reportedMixedGroups = true; | |
| 2093 } | |
| 2094 leftCurlyBracket = andAdvance; | |
| 2095 currentParameters = namedParameters; | |
| 2096 kind = ParameterKind.NAMED; | |
| 2097 } | |
| 2098 FormalParameter parameter = parseFormalParameter(kind); | |
| 2099 parameters.add(parameter); | |
| 2100 currentParameters.add(parameter); | |
| 2101 if (matches5(TokenType.CLOSE_SQUARE_BRACKET)) { | |
| 2102 rightSquareBracket = andAdvance; | |
| 2103 currentParameters = normalParameters; | |
| 2104 if (leftSquareBracket == null) { | |
| 2105 if (leftCurlyBracket != null) { | |
| 2106 reportError4(ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, [
"}"]); | |
| 2107 rightCurlyBracket = rightSquareBracket; | |
| 2108 rightSquareBracket = null; | |
| 2109 } else { | |
| 2110 reportError4(ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GRO
UP, ["["]); | |
| 2111 } | |
| 2112 } | |
| 2113 kind = ParameterKind.REQUIRED; | |
| 2114 } else if (matches5(TokenType.CLOSE_CURLY_BRACKET)) { | |
| 2115 rightCurlyBracket = andAdvance; | |
| 2116 currentParameters = normalParameters; | |
| 2117 if (leftCurlyBracket == null) { | |
| 2118 if (leftSquareBracket != null) { | |
| 2119 reportError4(ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, [
"]"]); | |
| 2120 rightSquareBracket = rightCurlyBracket; | |
| 2121 rightCurlyBracket = null; | |
| 2122 } else { | |
| 2123 reportError4(ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GRO
UP, ["{"]); | |
| 2124 } | |
| 2125 } | |
| 2126 kind = ParameterKind.REQUIRED; | |
| 2127 } | |
| 2128 } while (!matches5(TokenType.CLOSE_PAREN) && initialToken != _currentToken); | |
| 2129 Token rightParenthesis = expect2(TokenType.CLOSE_PAREN); | |
| 2130 if (leftSquareBracket != null && rightSquareBracket == null) { | |
| 2131 reportError4(ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]
); | |
| 2132 } | |
| 2133 if (leftCurlyBracket != null && rightCurlyBracket == null) { | |
| 2134 reportError4(ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]
); | |
| 2135 } | |
| 2136 if (leftSquareBracket == null) { | |
| 2137 leftSquareBracket = leftCurlyBracket; | |
| 2138 } | |
| 2139 if (rightSquareBracket == null) { | |
| 2140 rightSquareBracket = rightCurlyBracket; | |
| 2141 } | |
| 2142 return new FormalParameterList.full(leftParenthesis, parameters, leftSquareB
racket, rightSquareBracket, rightParenthesis); | |
| 2143 } | |
| 2144 /** | |
| 2145 * Parse a for statement. | |
| 2146 * <pre> | |
| 2147 * forStatement ::= | |
| 2148 * 'for' '(' forLoopParts ')' statement | |
| 2149 * forLoopParts ::= | |
| 2150 * forInitializerStatement expression? ';' expressionList? | |
| 2151 * | declaredIdentifier 'in' expression | |
| 2152 * | identifier 'in' expression | |
| 2153 * forInitializerStatement ::= | |
| 2154 * variableDeclarationList ';' | |
| 2155 * | expression? ';' | |
| 2156 * </pre> | |
| 2157 * @return the for statement that was parsed | |
| 2158 */ | |
| 2159 Statement parseForStatement() { | |
| 2160 bool wasInLoop = _inLoop; | |
| 2161 _inLoop = true; | |
| 2162 try { | |
| 2163 Token forKeyword = expect(Keyword.FOR); | |
| 2164 Token leftParenthesis = expect2(TokenType.OPEN_PAREN); | |
| 2165 VariableDeclarationList variableList = null; | |
| 2166 Expression initialization = null; | |
| 2167 if (!matches5(TokenType.SEMICOLON)) { | |
| 2168 if (matchesIdentifier() && matches3(peek(), Keyword.IN)) { | |
| 2169 List<VariableDeclaration> variables = new List<VariableDeclaration>(); | |
| 2170 SimpleIdentifier variableName = parseSimpleIdentifier(); | |
| 2171 variables.add(new VariableDeclaration.full(null, null, variableName, n
ull, null)); | |
| 2172 variableList = new VariableDeclarationList.full(null, null, variables)
; | |
| 2173 } else if (isInitializedVariableDeclaration()) { | |
| 2174 variableList = parseVariableDeclarationList(); | |
| 2175 } else { | |
| 2176 initialization = parseExpression2(); | |
| 2177 } | |
| 2178 if (matches(Keyword.IN)) { | |
| 2179 DeclaredIdentifier loopVariable = null; | |
| 2180 if (variableList == null) { | |
| 2181 reportError4(ParserErrorCode.MISSING_VARIABLE_IN_FOR_EACH, []); | |
| 2182 } else { | |
| 2183 NodeList<VariableDeclaration> variables3 = variableList.variables; | |
| 2184 if (variables3.length > 1) { | |
| 2185 reportError4(ParserErrorCode.MULTIPLE_VARIABLES_IN_FOR_EACH, [vari
ables3.length.toString()]); | |
| 2186 } | |
| 2187 VariableDeclaration variable = variables3[0]; | |
| 2188 if (variable.initializer != null) { | |
| 2189 reportError4(ParserErrorCode.INITIALIZED_VARIABLE_IN_FOR_EACH, [])
; | |
| 2190 } | |
| 2191 loopVariable = new DeclaredIdentifier.full(null, null, variableList.
keyword, variableList.type, variable.name); | |
| 2192 } | |
| 2193 Token inKeyword = expect(Keyword.IN); | |
| 2194 Expression iterator = parseExpression2(); | |
| 2195 Token rightParenthesis = expect2(TokenType.CLOSE_PAREN); | |
| 2196 Statement body = parseStatement2(); | |
| 2197 return new ForEachStatement.full(forKeyword, leftParenthesis, loopVari
able, inKeyword, iterator, rightParenthesis, body); | |
| 2198 } | |
| 2199 } | |
| 2200 Token leftSeparator = expect2(TokenType.SEMICOLON); | |
| 2201 Expression condition = null; | |
| 2202 if (!matches5(TokenType.SEMICOLON)) { | |
| 2203 condition = parseExpression2(); | |
| 2204 } | |
| 2205 Token rightSeparator = expect2(TokenType.SEMICOLON); | |
| 2206 List<Expression> updaters = null; | |
| 2207 if (!matches5(TokenType.CLOSE_PAREN)) { | |
| 2208 updaters = parseExpressionList(); | |
| 2209 } | |
| 2210 Token rightParenthesis = expect2(TokenType.CLOSE_PAREN); | |
| 2211 Statement body = parseStatement2(); | |
| 2212 return new ForStatement.full(forKeyword, leftParenthesis, variableList, in
itialization, leftSeparator, condition, rightSeparator, updaters, rightParenthes
is, body); | |
| 2213 } finally { | |
| 2214 _inLoop = wasInLoop; | |
| 2215 } | |
| 2216 } | |
| 2217 /** | |
| 2218 * Parse a function body. | |
| 2219 * <pre> | |
| 2220 * functionBody ::= | |
| 2221 * '=>' expression ';' | |
| 2222 * | block | |
| 2223 * functionExpressionBody ::= | |
| 2224 * '=>' expression | |
| 2225 * | block | |
| 2226 * </pre> | |
| 2227 * @param mayBeEmpty {@code true} if the function body is allowed to be empty | |
| 2228 * @param inExpression {@code true} if the function body is being parsed as pa
rt of an expression | |
| 2229 * and therefore does not have a terminating semicolon | |
| 2230 * @return the function body that was parsed | |
| 2231 */ | |
| 2232 FunctionBody parseFunctionBody(bool mayBeEmpty, bool inExpression) { | |
| 2233 bool wasInLoop = _inLoop; | |
| 2234 bool wasInSwitch = _inSwitch; | |
| 2235 _inLoop = false; | |
| 2236 _inSwitch = false; | |
| 2237 try { | |
| 2238 if (matches5(TokenType.SEMICOLON)) { | |
| 2239 if (!mayBeEmpty) { | |
| 2240 reportError4(ParserErrorCode.MISSING_FUNCTION_BODY, []); | |
| 2241 } | |
| 2242 return new EmptyFunctionBody.full(andAdvance); | |
| 2243 } else if (matches5(TokenType.FUNCTION)) { | |
| 2244 Token functionDefinition = andAdvance; | |
| 2245 Expression expression = parseExpression2(); | |
| 2246 Token semicolon = null; | |
| 2247 if (!inExpression) { | |
| 2248 semicolon = expect2(TokenType.SEMICOLON); | |
| 2249 } | |
| 2250 return new ExpressionFunctionBody.full(functionDefinition, expression, s
emicolon); | |
| 2251 } else if (matches5(TokenType.OPEN_CURLY_BRACKET)) { | |
| 2252 return new BlockFunctionBody.full(parseBlock()); | |
| 2253 } else if (matches2("native")) { | |
| 2254 advance(); | |
| 2255 parseStringLiteral(); | |
| 2256 return new EmptyFunctionBody.full(andAdvance); | |
| 2257 } else { | |
| 2258 reportError4(ParserErrorCode.MISSING_FUNCTION_BODY, []); | |
| 2259 return new EmptyFunctionBody.full(createSyntheticToken(TokenType.SEMICOL
ON)); | |
| 2260 } | |
| 2261 } finally { | |
| 2262 _inLoop = wasInLoop; | |
| 2263 _inSwitch = wasInSwitch; | |
| 2264 } | |
| 2265 } | |
| 2266 /** | |
| 2267 * Parse a function declaration. | |
| 2268 * <pre> | |
| 2269 * functionDeclaration ::= | |
| 2270 * functionSignature functionBody | |
| 2271 * | returnType? getOrSet identifier formalParameterList functionBody | |
| 2272 * </pre> | |
| 2273 * @param commentAndMetadata the documentation comment and metadata to be asso
ciated with the | |
| 2274 * declaration | |
| 2275 * @param externalKeyword the 'external' keyword, or {@code null} if the funct
ion is not external | |
| 2276 * @param returnType the return type, or {@code null} if there is no return ty
pe | |
| 2277 * @param isStatement {@code true} if the function declaration is being parsed
as a statement | |
| 2278 * @return the function declaration that was parsed | |
| 2279 */ | |
| 2280 FunctionDeclaration parseFunctionDeclaration(CommentAndMetadata commentAndMeta
data, Token externalKeyword, TypeName returnType) { | |
| 2281 Token keyword = null; | |
| 2282 bool isGetter = false; | |
| 2283 if (matches(Keyword.GET) && !matches4(peek(), TokenType.OPEN_PAREN)) { | |
| 2284 keyword = andAdvance; | |
| 2285 isGetter = true; | |
| 2286 } else if (matches(Keyword.SET) && !matches4(peek(), TokenType.OPEN_PAREN))
{ | |
| 2287 keyword = andAdvance; | |
| 2288 } | |
| 2289 SimpleIdentifier name = parseSimpleIdentifier(); | |
| 2290 FormalParameterList parameters = null; | |
| 2291 if (!isGetter) { | |
| 2292 if (matches5(TokenType.OPEN_PAREN)) { | |
| 2293 parameters = parseFormalParameterList(); | |
| 2294 validateFormalParameterList(parameters); | |
| 2295 } else { | |
| 2296 reportError4(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, []); | |
| 2297 } | |
| 2298 } else if (matches5(TokenType.OPEN_PAREN)) { | |
| 2299 reportError4(ParserErrorCode.GETTER_WITH_PARAMETERS, []); | |
| 2300 parseFormalParameterList(); | |
| 2301 } | |
| 2302 FunctionBody body; | |
| 2303 if (externalKeyword == null) { | |
| 2304 body = parseFunctionBody(false, false); | |
| 2305 } else { | |
| 2306 body = new EmptyFunctionBody.full(expect2(TokenType.SEMICOLON)); | |
| 2307 } | |
| 2308 return new FunctionDeclaration.full(commentAndMetadata.comment, commentAndMe
tadata.metadata, externalKeyword, returnType, keyword, name, new FunctionExpress
ion.full(parameters, body)); | |
| 2309 } | |
| 2310 /** | |
| 2311 * Parse a function declaration statement. | |
| 2312 * <pre> | |
| 2313 * functionDeclarationStatement ::= | |
| 2314 * functionSignature functionBody | |
| 2315 * </pre> | |
| 2316 * @return the function declaration statement that was parsed | |
| 2317 */ | |
| 2318 Statement parseFunctionDeclarationStatement() => parseFunctionDeclarationState
ment2(parseCommentAndMetadata(), parseOptionalReturnType()); | |
| 2319 /** | |
| 2320 * Parse a function declaration statement. | |
| 2321 * <pre> | |
| 2322 * functionDeclarationStatement ::= | |
| 2323 * functionSignature functionBody | |
| 2324 * </pre> | |
| 2325 * @param commentAndMetadata the documentation comment and metadata to be asso
ciated with the | |
| 2326 * declaration | |
| 2327 * @param returnType the return type, or {@code null} if there is no return ty
pe | |
| 2328 * @return the function declaration statement that was parsed | |
| 2329 */ | |
| 2330 Statement parseFunctionDeclarationStatement2(CommentAndMetadata commentAndMeta
data, TypeName returnType) => new FunctionDeclarationStatement.full(parseFunctio
nDeclaration(commentAndMetadata, null, returnType)); | |
| 2331 /** | |
| 2332 * Parse a function expression. | |
| 2333 * <pre> | |
| 2334 * functionExpression ::= | |
| 2335 * (returnType? identifier)? formalParameterList functionExpressionBody | |
| 2336 * </pre> | |
| 2337 * @return the function expression that was parsed | |
| 2338 */ | |
| 2339 FunctionExpression parseFunctionExpression() { | |
| 2340 FormalParameterList parameters = parseFormalParameterList(); | |
| 2341 validateFormalParameterList(parameters); | |
| 2342 FunctionBody body = parseFunctionBody(false, true); | |
| 2343 return new FunctionExpression.full(parameters, body); | |
| 2344 } | |
| 2345 /** | |
| 2346 * Parse a function type alias. | |
| 2347 * <pre> | |
| 2348 * functionTypeAlias ::= | |
| 2349 * functionPrefix typeParameterList? formalParameterList ';' | |
| 2350 * functionPrefix ::= | |
| 2351 * returnType? name | |
| 2352 * </pre> | |
| 2353 * @param commentAndMetadata the metadata to be associated with the member | |
| 2354 * @param keyword the token representing the 'typedef' keyword | |
| 2355 * @return the function type alias that was parsed | |
| 2356 */ | |
| 2357 FunctionTypeAlias parseFunctionTypeAlias(CommentAndMetadata commentAndMetadata
, Token keyword) { | |
| 2358 TypeName returnType = null; | |
| 2359 if (hasReturnTypeInTypeAlias()) { | |
| 2360 returnType = parseReturnType(); | |
| 2361 } | |
| 2362 SimpleIdentifier name = parseSimpleIdentifier(); | |
| 2363 TypeParameterList typeParameters = null; | |
| 2364 if (matches5(TokenType.LT)) { | |
| 2365 typeParameters = parseTypeParameterList(); | |
| 2366 } | |
| 2367 if (matches5(TokenType.SEMICOLON) || matches5(TokenType.EOF)) { | |
| 2368 reportError4(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS, []); | |
| 2369 FormalParameterList parameters = new FormalParameterList.full(createSynthe
ticToken(TokenType.OPEN_PAREN), null, null, null, createSyntheticToken(TokenType
.CLOSE_PAREN)); | |
| 2370 Token semicolon = expect2(TokenType.SEMICOLON); | |
| 2371 return new FunctionTypeAlias.full(commentAndMetadata.comment, commentAndMe
tadata.metadata, keyword, returnType, name, typeParameters, parameters, semicolo
n); | |
| 2372 } else if (!matches5(TokenType.OPEN_PAREN)) { | |
| 2373 return null; | |
| 2374 } | |
| 2375 FormalParameterList parameters = parseFormalParameterList(); | |
| 2376 validateFormalParameterList(parameters); | |
| 2377 Token semicolon = expect2(TokenType.SEMICOLON); | |
| 2378 return new FunctionTypeAlias.full(commentAndMetadata.comment, commentAndMeta
data.metadata, keyword, returnType, name, typeParameters, parameters, semicolon)
; | |
| 2379 } | |
| 2380 /** | |
| 2381 * Parse a getter. | |
| 2382 * <pre> | |
| 2383 * getter ::= | |
| 2384 * getterSignature functionBody? | |
| 2385 * getterSignature ::= | |
| 2386 * 'external'? 'static'? returnType? 'get' identifier | |
| 2387 * </pre> | |
| 2388 * @param commentAndMetadata the documentation comment and metadata to be asso
ciated with the | |
| 2389 * declaration | |
| 2390 * @param externalKeyword the 'external' token | |
| 2391 * @param staticKeyword the static keyword, or {@code null} if the getter is n
ot static | |
| 2392 * @param the return type that has already been parsed, or {@code null} if the
re was no return | |
| 2393 * type | |
| 2394 * @return the getter that was parsed | |
| 2395 */ | |
| 2396 MethodDeclaration parseGetter(CommentAndMetadata commentAndMetadata, Token ext
ernalKeyword, Token staticKeyword, TypeName returnType) { | |
| 2397 Token propertyKeyword = expect(Keyword.GET); | |
| 2398 SimpleIdentifier name = parseSimpleIdentifier(); | |
| 2399 if (matches5(TokenType.OPEN_PAREN) && matches4(peek(), TokenType.CLOSE_PAREN
)) { | |
| 2400 reportError4(ParserErrorCode.GETTER_WITH_PARAMETERS, []); | |
| 2401 advance(); | |
| 2402 advance(); | |
| 2403 } | |
| 2404 FunctionBody body = parseFunctionBody(true, false); | |
| 2405 if (externalKeyword != null && body is! EmptyFunctionBody) { | |
| 2406 reportError4(ParserErrorCode.EXTERNAL_GETTER_WITH_BODY, []); | |
| 2407 } | |
| 2408 return new MethodDeclaration.full(commentAndMetadata.comment, commentAndMeta
data.metadata, externalKeyword, staticKeyword, returnType, propertyKeyword, null
, name, null, body); | |
| 2409 } | |
| 2410 /** | |
| 2411 * Parse a list of identifiers. | |
| 2412 * <pre> | |
| 2413 * identifierList ::= | |
| 2414 * identifier (',' identifier) | |
| 2415 * </pre> | |
| 2416 * @return the list of identifiers that were parsed | |
| 2417 */ | |
| 2418 List<SimpleIdentifier> parseIdentifierList() { | |
| 2419 List<SimpleIdentifier> identifiers = new List<SimpleIdentifier>(); | |
| 2420 identifiers.add(parseSimpleIdentifier()); | |
| 2421 while (matches5(TokenType.COMMA)) { | |
| 2422 advance(); | |
| 2423 identifiers.add(parseSimpleIdentifier()); | |
| 2424 } | |
| 2425 return identifiers; | |
| 2426 } | |
| 2427 /** | |
| 2428 * Parse an if statement. | |
| 2429 * <pre> | |
| 2430 * ifStatement ::= | |
| 2431 * 'if' '(' expression ')' statement ('else' statement)? | |
| 2432 * </pre> | |
| 2433 * @return the if statement that was parsed | |
| 2434 */ | |
| 2435 Statement parseIfStatement() { | |
| 2436 Token ifKeyword = expect(Keyword.IF); | |
| 2437 Token leftParenthesis = expect2(TokenType.OPEN_PAREN); | |
| 2438 Expression condition = parseExpression2(); | |
| 2439 Token rightParenthesis = expect2(TokenType.CLOSE_PAREN); | |
| 2440 Statement thenStatement = parseStatement2(); | |
| 2441 Token elseKeyword = null; | |
| 2442 Statement elseStatement = null; | |
| 2443 if (matches(Keyword.ELSE)) { | |
| 2444 elseKeyword = andAdvance; | |
| 2445 elseStatement = parseStatement2(); | |
| 2446 } | |
| 2447 return new IfStatement.full(ifKeyword, leftParenthesis, condition, rightPare
nthesis, thenStatement, elseKeyword, elseStatement); | |
| 2448 } | |
| 2449 /** | |
| 2450 * Parse an implements clause. | |
| 2451 * <pre> | |
| 2452 * implementsClause ::= | |
| 2453 * 'implements' type (',' type) | |
| 2454 * </pre> | |
| 2455 * @return the implements clause that was parsed | |
| 2456 */ | |
| 2457 ImplementsClause parseImplementsClause() { | |
| 2458 Token keyword = expect(Keyword.IMPLEMENTS); | |
| 2459 List<TypeName> interfaces = new List<TypeName>(); | |
| 2460 interfaces.add(parseTypeName()); | |
| 2461 while (optional(TokenType.COMMA)) { | |
| 2462 interfaces.add(parseTypeName()); | |
| 2463 } | |
| 2464 return new ImplementsClause.full(keyword, interfaces); | |
| 2465 } | |
| 2466 /** | |
| 2467 * Parse an import directive. | |
| 2468 * <pre> | |
| 2469 * importDirective ::= | |
| 2470 * metadata 'import' stringLiteral ('as' identifier)? combinator*';' | |
| 2471 * </pre> | |
| 2472 * @param commentAndMetadata the metadata to be associated with the directive | |
| 2473 * @return the import directive that was parsed | |
| 2474 */ | |
| 2475 ImportDirective parseImportDirective(CommentAndMetadata commentAndMetadata) { | |
| 2476 Token importKeyword = expect(Keyword.IMPORT); | |
| 2477 StringLiteral libraryUri = parseStringLiteral(); | |
| 2478 Token asToken = null; | |
| 2479 SimpleIdentifier prefix = null; | |
| 2480 if (matches(Keyword.AS)) { | |
| 2481 asToken = andAdvance; | |
| 2482 prefix = parseSimpleIdentifier(); | |
| 2483 } | |
| 2484 List<Combinator> combinators = parseCombinators(); | |
| 2485 Token semicolon = expect2(TokenType.SEMICOLON); | |
| 2486 return new ImportDirective.full(commentAndMetadata.comment, commentAndMetada
ta.metadata, importKeyword, libraryUri, asToken, prefix, combinators, semicolon)
; | |
| 2487 } | |
| 2488 /** | |
| 2489 * Parse a list of initialized identifiers. | |
| 2490 * <pre> | |
| 2491 * ?? ::= | |
| 2492 * 'static'? ('var' | type) initializedIdentifierList ';' | |
| 2493 * | 'final' type? initializedIdentifierList ';' | |
| 2494 * initializedIdentifierList ::= | |
| 2495 * initializedIdentifier (',' initializedIdentifier) | |
| 2496 * initializedIdentifier ::= | |
| 2497 * identifier ('=' expression)? | |
| 2498 * </pre> | |
| 2499 * @param commentAndMetadata the documentation comment and metadata to be asso
ciated with the | |
| 2500 * declaration | |
| 2501 * @param staticKeyword the static keyword, or {@code null} if the getter is n
ot static | |
| 2502 * @param keyword the token representing the 'final', 'const' or 'var' keyword
, or {@code null} if | |
| 2503 * there is no keyword | |
| 2504 * @param type the type that has already been parsed, or {@code null} if 'var'
was provided | |
| 2505 * @return the getter that was parsed | |
| 2506 */ | |
| 2507 FieldDeclaration parseInitializedIdentifierList(CommentAndMetadata commentAndM
etadata, Token staticKeyword, Token keyword, TypeName type) { | |
| 2508 VariableDeclarationList fieldList = parseVariableDeclarationList2(keyword, t
ype); | |
| 2509 return new FieldDeclaration.full(commentAndMetadata.comment, commentAndMetad
ata.metadata, staticKeyword, fieldList, expect2(TokenType.SEMICOLON)); | |
| 2510 } | |
| 2511 /** | |
| 2512 * Parse an instance creation expression. | |
| 2513 * <pre> | |
| 2514 * instanceCreationExpression ::= | |
| 2515 * ('new' | 'const') type ('.' identifier)? argumentList | |
| 2516 * </pre> | |
| 2517 * @param keyword the 'new' or 'const' keyword that introduces the expression | |
| 2518 * @return the instance creation expression that was parsed | |
| 2519 */ | |
| 2520 InstanceCreationExpression parseInstanceCreationExpression(Token keyword) { | |
| 2521 ConstructorName constructorName = parseConstructorName(); | |
| 2522 ArgumentList argumentList = parseArgumentList(); | |
| 2523 return new InstanceCreationExpression.full(keyword, constructorName, argumen
tList); | |
| 2524 } | |
| 2525 /** | |
| 2526 * Parse a library directive. | |
| 2527 * <pre> | |
| 2528 * libraryDirective ::= | |
| 2529 * metadata 'library' identifier ';' | |
| 2530 * </pre> | |
| 2531 * @param commentAndMetadata the metadata to be associated with the directive | |
| 2532 * @return the library directive that was parsed | |
| 2533 */ | |
| 2534 LibraryDirective parseLibraryDirective(CommentAndMetadata commentAndMetadata)
{ | |
| 2535 Token keyword = expect(Keyword.LIBRARY); | |
| 2536 LibraryIdentifier libraryName = parseLibraryName(ParserErrorCode.MISSING_NAM
E_IN_LIBRARY_DIRECTIVE, keyword); | |
| 2537 Token semicolon = expect2(TokenType.SEMICOLON); | |
| 2538 return new LibraryDirective.full(commentAndMetadata.comment, commentAndMetad
ata.metadata, keyword, libraryName, semicolon); | |
| 2539 } | |
| 2540 /** | |
| 2541 * Parse a library identifier. | |
| 2542 * <pre> | |
| 2543 * libraryIdentifier ::= | |
| 2544 * identifier ('.' identifier) | |
| 2545 * </pre> | |
| 2546 * @return the library identifier that was parsed | |
| 2547 */ | |
| 2548 LibraryIdentifier parseLibraryIdentifier() { | |
| 2549 List<SimpleIdentifier> components = new List<SimpleIdentifier>(); | |
| 2550 components.add(parseSimpleIdentifier()); | |
| 2551 while (matches5(TokenType.PERIOD)) { | |
| 2552 advance(); | |
| 2553 components.add(parseSimpleIdentifier()); | |
| 2554 } | |
| 2555 return new LibraryIdentifier.full(components); | |
| 2556 } | |
| 2557 /** | |
| 2558 * Parse a library name. | |
| 2559 * <pre> | |
| 2560 * libraryName ::= | |
| 2561 * libraryIdentifier | |
| 2562 * </pre> | |
| 2563 * @param missingNameError the error code to be used if the library name is mi
ssing | |
| 2564 * @param missingNameToken the token associated with the error produced if the
library name is | |
| 2565 * missing | |
| 2566 * @return the library name that was parsed | |
| 2567 */ | |
| 2568 LibraryIdentifier parseLibraryName(ParserErrorCode missingNameError, Token mis
singNameToken) { | |
| 2569 if (matchesIdentifier()) { | |
| 2570 return parseLibraryIdentifier(); | |
| 2571 } else if (matches5(TokenType.STRING)) { | |
| 2572 StringLiteral string = parseStringLiteral(); | |
| 2573 reportError(ParserErrorCode.NON_IDENTIFIER_LIBRARY_NAME, string, []); | |
| 2574 } else { | |
| 2575 reportError5(missingNameError, missingNameToken, []); | |
| 2576 } | |
| 2577 List<SimpleIdentifier> components = new List<SimpleIdentifier>(); | |
| 2578 components.add(createSyntheticIdentifier()); | |
| 2579 return new LibraryIdentifier.full(components); | |
| 2580 } | |
| 2581 /** | |
| 2582 * Parse a list literal. | |
| 2583 * <pre> | |
| 2584 * listLiteral ::= | |
| 2585 * 'const'? typeArguments? '[' (expressionList ','?)? ']' | |
| 2586 * </pre> | |
| 2587 * @param modifier the 'const' modifier appearing before the literal, or {@cod
e null} if there is | |
| 2588 * no modifier | |
| 2589 * @param typeArguments the type arguments appearing before the literal, or {@
code null} if there | |
| 2590 * are no type arguments | |
| 2591 * @return the list literal that was parsed | |
| 2592 */ | |
| 2593 ListLiteral parseListLiteral(Token modifier, TypeArgumentList typeArguments) { | |
| 2594 if (matches5(TokenType.INDEX)) { | |
| 2595 BeginToken leftBracket = new BeginToken(TokenType.OPEN_SQUARE_BRACKET, _cu
rrentToken.offset); | |
| 2596 Token rightBracket = new Token(TokenType.CLOSE_SQUARE_BRACKET, _currentTok
en.offset + 1); | |
| 2597 leftBracket.endToken = rightBracket; | |
| 2598 rightBracket.setNext(_currentToken.next); | |
| 2599 leftBracket.setNext(rightBracket); | |
| 2600 _currentToken.previous.setNext(leftBracket); | |
| 2601 _currentToken = _currentToken.next; | |
| 2602 return new ListLiteral.full(modifier, typeArguments, leftBracket, null, ri
ghtBracket); | |
| 2603 } | |
| 2604 Token leftBracket = expect2(TokenType.OPEN_SQUARE_BRACKET); | |
| 2605 if (matches5(TokenType.CLOSE_SQUARE_BRACKET)) { | |
| 2606 return new ListLiteral.full(modifier, typeArguments, leftBracket, null, an
dAdvance); | |
| 2607 } | |
| 2608 List<Expression> elements = new List<Expression>(); | |
| 2609 elements.add(parseExpression2()); | |
| 2610 while (optional(TokenType.COMMA)) { | |
| 2611 if (matches5(TokenType.CLOSE_SQUARE_BRACKET)) { | |
| 2612 return new ListLiteral.full(modifier, typeArguments, leftBracket, elemen
ts, andAdvance); | |
| 2613 } | |
| 2614 elements.add(parseExpression2()); | |
| 2615 } | |
| 2616 Token rightBracket = expect2(TokenType.CLOSE_SQUARE_BRACKET); | |
| 2617 return new ListLiteral.full(modifier, typeArguments, leftBracket, elements,
rightBracket); | |
| 2618 } | |
| 2619 /** | |
| 2620 * Parse a list or map literal. | |
| 2621 * <pre> | |
| 2622 * listOrMapLiteral ::= | |
| 2623 * listLiteral | |
| 2624 * | mapLiteral | |
| 2625 * </pre> | |
| 2626 * @param modifier the 'const' modifier appearing before the literal, or {@cod
e null} if there is | |
| 2627 * no modifier | |
| 2628 * @return the list or map literal that was parsed | |
| 2629 */ | |
| 2630 TypedLiteral parseListOrMapLiteral(Token modifier) { | |
| 2631 TypeArgumentList typeArguments = null; | |
| 2632 if (matches5(TokenType.LT)) { | |
| 2633 typeArguments = parseTypeArgumentList(); | |
| 2634 } | |
| 2635 if (matches5(TokenType.OPEN_CURLY_BRACKET)) { | |
| 2636 return parseMapLiteral(modifier, typeArguments); | |
| 2637 } else if (matches5(TokenType.OPEN_SQUARE_BRACKET) || matches5(TokenType.IND
EX)) { | |
| 2638 return parseListLiteral(modifier, typeArguments); | |
| 2639 } | |
| 2640 reportError4(ParserErrorCode.EXPECTED_LIST_OR_MAP_LITERAL, []); | |
| 2641 return new ListLiteral.full(modifier, typeArguments, createSyntheticToken(To
kenType.OPEN_SQUARE_BRACKET), null, createSyntheticToken(TokenType.CLOSE_SQUARE_
BRACKET)); | |
| 2642 } | |
| 2643 /** | |
| 2644 * Parse a logical and expression. | |
| 2645 * <pre> | |
| 2646 * logicalAndExpression ::= | |
| 2647 * bitwiseOrExpression ('&&' bitwiseOrExpression) | |
| 2648 * </pre> | |
| 2649 * @return the logical and expression that was parsed | |
| 2650 */ | |
| 2651 Expression parseLogicalAndExpression() { | |
| 2652 Expression expression = parseBitwiseOrExpression(); | |
| 2653 while (matches5(TokenType.AMPERSAND_AMPERSAND)) { | |
| 2654 Token operator = andAdvance; | |
| 2655 expression = new BinaryExpression.full(expression, operator, parseBitwiseO
rExpression()); | |
| 2656 } | |
| 2657 return expression; | |
| 2658 } | |
| 2659 /** | |
| 2660 * Parse a logical or expression. | |
| 2661 * <pre> | |
| 2662 * logicalOrExpression ::= | |
| 2663 * logicalAndExpression ('||' logicalAndExpression) | |
| 2664 * </pre> | |
| 2665 * @return the logical or expression that was parsed | |
| 2666 */ | |
| 2667 Expression parseLogicalOrExpression() { | |
| 2668 Expression expression = parseLogicalAndExpression(); | |
| 2669 while (matches5(TokenType.BAR_BAR)) { | |
| 2670 Token operator = andAdvance; | |
| 2671 expression = new BinaryExpression.full(expression, operator, parseLogicalA
ndExpression()); | |
| 2672 } | |
| 2673 return expression; | |
| 2674 } | |
| 2675 /** | |
| 2676 * Parse a map literal. | |
| 2677 * <pre> | |
| 2678 * mapLiteral ::= | |
| 2679 * 'const'? typeArguments? '{' (mapLiteralEntry (',' mapLiteralEntry)* ','?)?
'}' | |
| 2680 * </pre> | |
| 2681 * @param modifier the 'const' modifier appearing before the literal, or {@cod
e null} if there is | |
| 2682 * no modifier | |
| 2683 * @param typeArguments the type arguments that were declared, or {@code null}
if there are no | |
| 2684 * type arguments | |
| 2685 * @return the map literal that was parsed | |
| 2686 */ | |
| 2687 MapLiteral parseMapLiteral(Token modifier, TypeArgumentList typeArguments) { | |
| 2688 Token leftBracket = expect2(TokenType.OPEN_CURLY_BRACKET); | |
| 2689 List<MapLiteralEntry> entries = new List<MapLiteralEntry>(); | |
| 2690 if (matches5(TokenType.CLOSE_CURLY_BRACKET)) { | |
| 2691 return new MapLiteral.full(modifier, typeArguments, leftBracket, entries,
andAdvance); | |
| 2692 } | |
| 2693 entries.add(parseMapLiteralEntry()); | |
| 2694 while (optional(TokenType.COMMA)) { | |
| 2695 if (matches5(TokenType.CLOSE_CURLY_BRACKET)) { | |
| 2696 return new MapLiteral.full(modifier, typeArguments, leftBracket, entries
, andAdvance); | |
| 2697 } | |
| 2698 entries.add(parseMapLiteralEntry()); | |
| 2699 } | |
| 2700 Token rightBracket = expect2(TokenType.CLOSE_CURLY_BRACKET); | |
| 2701 return new MapLiteral.full(modifier, typeArguments, leftBracket, entries, ri
ghtBracket); | |
| 2702 } | |
| 2703 /** | |
| 2704 * Parse a map literal entry. | |
| 2705 * <pre> | |
| 2706 * mapLiteralEntry ::= | |
| 2707 * stringLiteral ':' expression | |
| 2708 * </pre> | |
| 2709 * @return the map literal entry that was parsed | |
| 2710 */ | |
| 2711 MapLiteralEntry parseMapLiteralEntry() { | |
| 2712 StringLiteral key = parseStringLiteral(); | |
| 2713 Token separator = expect2(TokenType.COLON); | |
| 2714 Expression value = parseExpression2(); | |
| 2715 return new MapLiteralEntry.full(key, separator, value); | |
| 2716 } | |
| 2717 /** | |
| 2718 * Parse a method declaration. | |
| 2719 * <pre> | |
| 2720 * functionDeclaration ::= | |
| 2721 * 'external'? 'static'? functionSignature functionBody | |
| 2722 * | 'external'? functionSignature ';' | |
| 2723 * </pre> | |
| 2724 * @param commentAndMetadata the documentation comment and metadata to be asso
ciated with the | |
| 2725 * declaration | |
| 2726 * @param externalKeyword the 'external' token | |
| 2727 * @param staticKeyword the static keyword, or {@code null} if the getter is n
ot static | |
| 2728 * @param returnType the return type of the method | |
| 2729 * @return the method declaration that was parsed | |
| 2730 */ | |
| 2731 MethodDeclaration parseMethodDeclaration(CommentAndMetadata commentAndMetadata
, Token externalKeyword, Token staticKeyword, TypeName returnType) { | |
| 2732 SimpleIdentifier methodName = parseSimpleIdentifier(); | |
| 2733 FormalParameterList parameters = parseFormalParameterList(); | |
| 2734 validateFormalParameterList(parameters); | |
| 2735 return parseMethodDeclaration2(commentAndMetadata, externalKeyword, staticKe
yword, returnType, methodName, parameters); | |
| 2736 } | |
| 2737 /** | |
| 2738 * Parse a method declaration. | |
| 2739 * <pre> | |
| 2740 * functionDeclaration ::= | |
| 2741 * ('external' 'static'?)? functionSignature functionBody | |
| 2742 * | 'external'? functionSignature ';' | |
| 2743 * </pre> | |
| 2744 * @param commentAndMetadata the documentation comment and metadata to be asso
ciated with the | |
| 2745 * declaration | |
| 2746 * @param externalKeyword the 'external' token | |
| 2747 * @param staticKeyword the static keyword, or {@code null} if the getter is n
ot static | |
| 2748 * @param returnType the return type of the method | |
| 2749 * @param name the name of the method | |
| 2750 * @param parameters the parameters to the method | |
| 2751 * @return the method declaration that was parsed | |
| 2752 */ | |
| 2753 MethodDeclaration parseMethodDeclaration2(CommentAndMetadata commentAndMetadat
a, Token externalKeyword, Token staticKeyword, TypeName returnType, SimpleIdenti
fier name, FormalParameterList parameters) { | |
| 2754 FunctionBody body = parseFunctionBody(externalKeyword != null || staticKeywo
rd == null, false); | |
| 2755 if (externalKeyword != null) { | |
| 2756 if (body is! EmptyFunctionBody) { | |
| 2757 reportError(ParserErrorCode.EXTERNAL_METHOD_WITH_BODY, body, []); | |
| 2758 } | |
| 2759 } else if (staticKeyword != null) { | |
| 2760 if (body is EmptyFunctionBody) { | |
| 2761 reportError(ParserErrorCode.ABSTRACT_STATIC_METHOD, body, []); | |
| 2762 } | |
| 2763 } | |
| 2764 return new MethodDeclaration.full(commentAndMetadata.comment, commentAndMeta
data.metadata, externalKeyword, staticKeyword, returnType, null, null, name, par
ameters, body); | |
| 2765 } | |
| 2766 /** | |
| 2767 * Parse the modifiers preceding a declaration. This method allows the modifie
rs to appear in any | |
| 2768 * order but does generate errors for duplicated modifiers. Checks for other p
roblems, such as | |
| 2769 * having the modifiers appear in the wrong order or specifying both 'const' a
nd 'final', are | |
| 2770 * reported in one of the methods whose name is prefixed with {@code validateM
odifiersFor}. | |
| 2771 * <pre> | |
| 2772 * modifiers ::= | |
| 2773 * ('abstract' | 'const' | 'external' | 'factory' | 'final' | 'static' | 'var'
) | |
| 2774 * </pre> | |
| 2775 * @return the modifiers that were parsed | |
| 2776 */ | |
| 2777 Modifiers parseModifiers() { | |
| 2778 Modifiers modifiers = new Modifiers(); | |
| 2779 bool progress = true; | |
| 2780 while (progress) { | |
| 2781 if (matches(Keyword.ABSTRACT) && !matches4(peek(), TokenType.PERIOD) && !m
atches4(peek(), TokenType.LT)) { | |
| 2782 if (modifiers.abstractKeyword != null) { | |
| 2783 reportError4(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexem
e]); | |
| 2784 advance(); | |
| 2785 } else { | |
| 2786 modifiers.abstractKeyword = andAdvance; | |
| 2787 } | |
| 2788 } else if (matches(Keyword.CONST)) { | |
| 2789 if (modifiers.constKeyword != null) { | |
| 2790 reportError4(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexem
e]); | |
| 2791 advance(); | |
| 2792 } else { | |
| 2793 modifiers.constKeyword = andAdvance; | |
| 2794 } | |
| 2795 } else if (matches(Keyword.EXTERNAL) && !matches4(peek(), TokenType.PERIOD
) && !matches4(peek(), TokenType.LT)) { | |
| 2796 if (modifiers.externalKeyword != null) { | |
| 2797 reportError4(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexem
e]); | |
| 2798 advance(); | |
| 2799 } else { | |
| 2800 modifiers.externalKeyword = andAdvance; | |
| 2801 } | |
| 2802 } else if (matches(Keyword.FACTORY) && !matches4(peek(), TokenType.PERIOD)
&& !matches4(peek(), TokenType.LT)) { | |
| 2803 if (modifiers.factoryKeyword != null) { | |
| 2804 reportError4(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexem
e]); | |
| 2805 advance(); | |
| 2806 } else { | |
| 2807 modifiers.factoryKeyword = andAdvance; | |
| 2808 } | |
| 2809 } else if (matches(Keyword.FINAL)) { | |
| 2810 if (modifiers.finalKeyword != null) { | |
| 2811 reportError4(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexem
e]); | |
| 2812 advance(); | |
| 2813 } else { | |
| 2814 modifiers.finalKeyword = andAdvance; | |
| 2815 } | |
| 2816 } else if (matches(Keyword.STATIC) && !matches4(peek(), TokenType.PERIOD)
&& !matches4(peek(), TokenType.LT)) { | |
| 2817 if (modifiers.staticKeyword != null) { | |
| 2818 reportError4(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexem
e]); | |
| 2819 advance(); | |
| 2820 } else { | |
| 2821 modifiers.staticKeyword = andAdvance; | |
| 2822 } | |
| 2823 } else if (matches(Keyword.VAR)) { | |
| 2824 if (modifiers.varKeyword != null) { | |
| 2825 reportError4(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexem
e]); | |
| 2826 advance(); | |
| 2827 } else { | |
| 2828 modifiers.varKeyword = andAdvance; | |
| 2829 } | |
| 2830 } else { | |
| 2831 progress = false; | |
| 2832 } | |
| 2833 } | |
| 2834 return modifiers; | |
| 2835 } | |
| 2836 /** | |
| 2837 * Parse a multiplicative expression. | |
| 2838 * <pre> | |
| 2839 * multiplicativeExpression ::= | |
| 2840 * unaryExpression (multiplicativeOperator unaryExpression) | |
| 2841 * | 'super' (multiplicativeOperator unaryExpression)+ | |
| 2842 * </pre> | |
| 2843 * @return the multiplicative expression that was parsed | |
| 2844 */ | |
| 2845 Expression parseMultiplicativeExpression() { | |
| 2846 Expression expression; | |
| 2847 if (matches(Keyword.SUPER) && _currentToken.next.type.isMultiplicativeOperat
or()) { | |
| 2848 expression = new SuperExpression.full(andAdvance); | |
| 2849 } else { | |
| 2850 expression = parseUnaryExpression(); | |
| 2851 } | |
| 2852 while (_currentToken.type.isMultiplicativeOperator()) { | |
| 2853 Token operator = andAdvance; | |
| 2854 expression = new BinaryExpression.full(expression, operator, parseUnaryExp
ression()); | |
| 2855 } | |
| 2856 return expression; | |
| 2857 } | |
| 2858 /** | |
| 2859 * Parse a new expression. | |
| 2860 * <pre> | |
| 2861 * newExpression ::= | |
| 2862 * instanceCreationExpression | |
| 2863 * </pre> | |
| 2864 * @return the new expression that was parsed | |
| 2865 */ | |
| 2866 InstanceCreationExpression parseNewExpression() => parseInstanceCreationExpres
sion(expect(Keyword.NEW)); | |
| 2867 /** | |
| 2868 * Parse a non-labeled statement. | |
| 2869 * <pre> | |
| 2870 * nonLabeledStatement ::= | |
| 2871 * block | |
| 2872 * | assertStatement | |
| 2873 * | breakStatement | |
| 2874 * | continueStatement | |
| 2875 * | doStatement | |
| 2876 * | forStatement | |
| 2877 * | ifStatement | |
| 2878 * | returnStatement | |
| 2879 * | switchStatement | |
| 2880 * | tryStatement | |
| 2881 * | whileStatement | |
| 2882 * | variableDeclarationList ';' | |
| 2883 * | expressionStatement | |
| 2884 * | functionSignature functionBody | |
| 2885 * </pre> | |
| 2886 * @return the non-labeled statement that was parsed | |
| 2887 */ | |
| 2888 Statement parseNonLabeledStatement() { | |
| 2889 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata(); | |
| 2890 if (matches5(TokenType.OPEN_CURLY_BRACKET)) { | |
| 2891 if (matches4(peek(), TokenType.STRING)) { | |
| 2892 Token afterString = skipStringLiteral(_currentToken.next); | |
| 2893 if (afterString != null && identical(afterString.type, TokenType.COLON))
{ | |
| 2894 return new ExpressionStatement.full(parseExpression2(), expect2(TokenT
ype.SEMICOLON)); | |
| 2895 } | |
| 2896 } | |
| 2897 return parseBlock(); | |
| 2898 } else if (matches5(TokenType.KEYWORD) && !((_currentToken as KeywordToken))
.keyword.isPseudoKeyword()) { | |
| 2899 Keyword keyword30 = ((_currentToken as KeywordToken)).keyword; | |
| 2900 if (identical(keyword30, Keyword.ASSERT)) { | |
| 2901 return parseAssertStatement(); | |
| 2902 } else if (identical(keyword30, Keyword.BREAK)) { | |
| 2903 return parseBreakStatement(); | |
| 2904 } else if (identical(keyword30, Keyword.CONTINUE)) { | |
| 2905 return parseContinueStatement(); | |
| 2906 } else if (identical(keyword30, Keyword.DO)) { | |
| 2907 return parseDoStatement(); | |
| 2908 } else if (identical(keyword30, Keyword.FOR)) { | |
| 2909 return parseForStatement(); | |
| 2910 } else if (identical(keyword30, Keyword.IF)) { | |
| 2911 return parseIfStatement(); | |
| 2912 } else if (identical(keyword30, Keyword.RETURN)) { | |
| 2913 return parseReturnStatement(); | |
| 2914 } else if (identical(keyword30, Keyword.SWITCH)) { | |
| 2915 return parseSwitchStatement(); | |
| 2916 } else if (identical(keyword30, Keyword.THROW)) { | |
| 2917 return new ExpressionStatement.full(parseThrowExpression(), expect2(Toke
nType.SEMICOLON)); | |
| 2918 } else if (identical(keyword30, Keyword.TRY)) { | |
| 2919 return parseTryStatement(); | |
| 2920 } else if (identical(keyword30, Keyword.WHILE)) { | |
| 2921 return parseWhileStatement(); | |
| 2922 } else if (identical(keyword30, Keyword.VAR) || identical(keyword30, Keywo
rd.FINAL)) { | |
| 2923 return parseVariableDeclarationStatement(); | |
| 2924 } else if (identical(keyword30, Keyword.VOID)) { | |
| 2925 TypeName returnType = parseReturnType(); | |
| 2926 if (matchesIdentifier() && matchesAny(peek(), [TokenType.OPEN_PAREN, Tok
enType.OPEN_CURLY_BRACKET, TokenType.FUNCTION])) { | |
| 2927 return parseFunctionDeclarationStatement2(commentAndMetadata, returnTy
pe); | |
| 2928 } else { | |
| 2929 if (matchesIdentifier()) { | |
| 2930 if (matchesAny(peek(), [TokenType.EQ, TokenType.COMMA, TokenType.SEM
ICOLON])) { | |
| 2931 reportError(ParserErrorCode.VOID_VARIABLE, returnType, []); | |
| 2932 return parseVariableDeclarationStatement(); | |
| 2933 } | |
| 2934 } | |
| 2935 return null; | |
| 2936 } | |
| 2937 } else if (identical(keyword30, Keyword.CONST)) { | |
| 2938 if (matchesAny(peek(), [TokenType.LT, TokenType.OPEN_CURLY_BRACKET, Toke
nType.OPEN_SQUARE_BRACKET, TokenType.INDEX])) { | |
| 2939 return new ExpressionStatement.full(parseExpression2(), expect2(TokenT
ype.SEMICOLON)); | |
| 2940 } else if (matches4(peek(), TokenType.IDENTIFIER)) { | |
| 2941 Token afterType = skipTypeName(peek()); | |
| 2942 if (afterType != null) { | |
| 2943 if (matches4(afterType, TokenType.OPEN_PAREN) || (matches4(afterType
, TokenType.PERIOD) && matches4(afterType.next, TokenType.IDENTIFIER) && matches
4(afterType.next.next, TokenType.OPEN_PAREN))) { | |
| 2944 return new ExpressionStatement.full(parseExpression2(), expect2(To
kenType.SEMICOLON)); | |
| 2945 } | |
| 2946 } | |
| 2947 } | |
| 2948 return parseVariableDeclarationStatement(); | |
| 2949 } else if (identical(keyword30, Keyword.NEW) || identical(keyword30, Keywo
rd.TRUE) || identical(keyword30, Keyword.FALSE) || identical(keyword30, Keyword.
NULL) || identical(keyword30, Keyword.SUPER) || identical(keyword30, Keyword.THI
S)) { | |
| 2950 return new ExpressionStatement.full(parseExpression2(), expect2(TokenTyp
e.SEMICOLON)); | |
| 2951 } else { | |
| 2952 return null; | |
| 2953 } | |
| 2954 } else if (matches5(TokenType.SEMICOLON)) { | |
| 2955 return parseEmptyStatement(); | |
| 2956 } else if (isInitializedVariableDeclaration()) { | |
| 2957 return parseVariableDeclarationStatement(); | |
| 2958 } else if (isFunctionDeclaration()) { | |
| 2959 return parseFunctionDeclarationStatement(); | |
| 2960 } else { | |
| 2961 return new ExpressionStatement.full(parseExpression2(), expect2(TokenType.
SEMICOLON)); | |
| 2962 } | |
| 2963 } | |
| 2964 /** | |
| 2965 * Parse a normal formal parameter. | |
| 2966 * <pre> | |
| 2967 * normalFormalParameter ::= | |
| 2968 * functionSignature | |
| 2969 * | fieldFormalParameter | |
| 2970 * | simpleFormalParameter | |
| 2971 * functionSignature: | |
| 2972 * metadata returnType? identifier formalParameterList | |
| 2973 * fieldFormalParameter ::= | |
| 2974 * metadata finalConstVarOrType? 'this' '.' identifier | |
| 2975 * simpleFormalParameter ::= | |
| 2976 * declaredIdentifier | |
| 2977 * | metadata identifier | |
| 2978 * </pre> | |
| 2979 * @return the normal formal parameter that was parsed | |
| 2980 */ | |
| 2981 NormalFormalParameter parseNormalFormalParameter() { | |
| 2982 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata(); | |
| 2983 FinalConstVarOrType holder = parseFinalConstVarOrType(true); | |
| 2984 Token thisKeyword = null; | |
| 2985 Token period = null; | |
| 2986 if (matches(Keyword.THIS)) { | |
| 2987 thisKeyword = andAdvance; | |
| 2988 period = expect2(TokenType.PERIOD); | |
| 2989 } | |
| 2990 SimpleIdentifier identifier = parseSimpleIdentifier(); | |
| 2991 if (matches5(TokenType.OPEN_PAREN)) { | |
| 2992 if (thisKeyword != null) { | |
| 2993 } | |
| 2994 FormalParameterList parameters = parseFormalParameterList(); | |
| 2995 return new FunctionTypedFormalParameter.full(commentAndMetadata.comment, c
ommentAndMetadata.metadata, holder.type, identifier, parameters); | |
| 2996 } | |
| 2997 TypeName type22 = holder.type; | |
| 2998 if (type22 != null && matches3(type22.name.beginToken, Keyword.VOID)) { | |
| 2999 reportError5(ParserErrorCode.VOID_PARAMETER, type22.name.beginToken, []); | |
| 3000 } | |
| 3001 if (thisKeyword != null) { | |
| 3002 return new FieldFormalParameter.full(commentAndMetadata.comment, commentAn
dMetadata.metadata, holder.keyword, holder.type, thisKeyword, period, identifier
); | |
| 3003 } | |
| 3004 return new SimpleFormalParameter.full(commentAndMetadata.comment, commentAnd
Metadata.metadata, holder.keyword, holder.type, identifier); | |
| 3005 } | |
| 3006 /** | |
| 3007 * Parse an operator declaration. | |
| 3008 * <pre> | |
| 3009 * operatorDeclaration ::= | |
| 3010 * operatorSignature (';' | functionBody) | |
| 3011 * operatorSignature ::= | |
| 3012 * 'external'? returnType? 'operator' operator formalParameterList | |
| 3013 * </pre> | |
| 3014 * @param commentAndMetadata the documentation comment and metadata to be asso
ciated with the | |
| 3015 * declaration | |
| 3016 * @param externalKeyword the 'external' token | |
| 3017 * @param the return type that has already been parsed, or {@code null} if the
re was no return | |
| 3018 * type | |
| 3019 * @return the operator declaration that was parsed | |
| 3020 */ | |
| 3021 MethodDeclaration parseOperator(CommentAndMetadata commentAndMetadata, Token e
xternalKeyword, TypeName returnType) { | |
| 3022 Token operatorKeyword = expect(Keyword.OPERATOR); | |
| 3023 if (!_currentToken.isUserDefinableOperator()) { | |
| 3024 reportError4(ParserErrorCode.NON_USER_DEFINABLE_OPERATOR, [_currentToken.l
exeme]); | |
| 3025 } | |
| 3026 SimpleIdentifier name = new SimpleIdentifier.full(andAdvance); | |
| 3027 FormalParameterList parameters = parseFormalParameterList(); | |
| 3028 validateFormalParameterList(parameters); | |
| 3029 FunctionBody body = parseFunctionBody(true, false); | |
| 3030 if (externalKeyword != null && body is! EmptyFunctionBody) { | |
| 3031 reportError4(ParserErrorCode.EXTERNAL_OPERATOR_WITH_BODY, []); | |
| 3032 } | |
| 3033 return new MethodDeclaration.full(commentAndMetadata.comment, commentAndMeta
data.metadata, externalKeyword, null, returnType, null, operatorKeyword, name, p
arameters, body); | |
| 3034 } | |
| 3035 /** | |
| 3036 * Parse a return type if one is given, otherwise return {@code null} without
advancing. | |
| 3037 * @return the return type that was parsed | |
| 3038 */ | |
| 3039 TypeName parseOptionalReturnType() { | |
| 3040 if (matches(Keyword.VOID)) { | |
| 3041 return parseReturnType(); | |
| 3042 } else if (matchesIdentifier() && !matches(Keyword.GET) && !matches(Keyword.
SET) && !matches(Keyword.OPERATOR) && (matchesIdentifier2(peek()) || matches4(pe
ek(), TokenType.LT))) { | |
| 3043 return parseReturnType(); | |
| 3044 } else if (matchesIdentifier() && matches4(peek(), TokenType.PERIOD) && matc
hesIdentifier2(peek2(2)) && (matchesIdentifier2(peek2(3)) || matches4(peek2(3),
TokenType.LT))) { | |
| 3045 return parseReturnType(); | |
| 3046 } | |
| 3047 return null; | |
| 3048 } | |
| 3049 /** | |
| 3050 * Parse a part or part-of directive. | |
| 3051 * <pre> | |
| 3052 * partDirective ::= | |
| 3053 * metadata 'part' stringLiteral ';' | |
| 3054 * partOfDirective ::= | |
| 3055 * metadata 'part' 'of' identifier ';' | |
| 3056 * </pre> | |
| 3057 * @param commentAndMetadata the metadata to be associated with the directive | |
| 3058 * @return the part or part-of directive that was parsed | |
| 3059 */ | |
| 3060 Directive parsePartDirective(CommentAndMetadata commentAndMetadata) { | |
| 3061 Token partKeyword = expect(Keyword.PART); | |
| 3062 if (matches2(_OF)) { | |
| 3063 Token ofKeyword = andAdvance; | |
| 3064 LibraryIdentifier libraryName = parseLibraryName(ParserErrorCode.MISSING_N
AME_IN_PART_OF_DIRECTIVE, ofKeyword); | |
| 3065 Token semicolon = expect2(TokenType.SEMICOLON); | |
| 3066 return new PartOfDirective.full(commentAndMetadata.comment, commentAndMeta
data.metadata, partKeyword, ofKeyword, libraryName, semicolon); | |
| 3067 } | |
| 3068 StringLiteral partUri = parseStringLiteral(); | |
| 3069 Token semicolon = expect2(TokenType.SEMICOLON); | |
| 3070 return new PartDirective.full(commentAndMetadata.comment, commentAndMetadata
.metadata, partKeyword, partUri, semicolon); | |
| 3071 } | |
| 3072 /** | |
| 3073 * Parse a postfix expression. | |
| 3074 * <pre> | |
| 3075 * postfixExpression ::= | |
| 3076 * assignableExpression postfixOperator | |
| 3077 * | primary selector | |
| 3078 * selector ::= | |
| 3079 * assignableSelector | |
| 3080 * | argumentList | |
| 3081 * </pre> | |
| 3082 * @return the postfix expression that was parsed | |
| 3083 */ | |
| 3084 Expression parsePostfixExpression() { | |
| 3085 Expression operand = parseAssignableExpression(true); | |
| 3086 if (matches5(TokenType.OPEN_SQUARE_BRACKET) || matches5(TokenType.PERIOD) ||
matches5(TokenType.OPEN_PAREN)) { | |
| 3087 do { | |
| 3088 if (matches5(TokenType.OPEN_PAREN)) { | |
| 3089 ArgumentList argumentList = parseArgumentList(); | |
| 3090 if (operand is PropertyAccess) { | |
| 3091 PropertyAccess access = operand as PropertyAccess; | |
| 3092 operand = new MethodInvocation.full(access.target, access.operator,
access.propertyName, argumentList); | |
| 3093 } else { | |
| 3094 operand = new FunctionExpressionInvocation.full(operand, argumentLis
t); | |
| 3095 } | |
| 3096 } else { | |
| 3097 operand = parseAssignableSelector(operand, true); | |
| 3098 } | |
| 3099 } while (matches5(TokenType.OPEN_SQUARE_BRACKET) || matches5(TokenType.PER
IOD) || matches5(TokenType.OPEN_PAREN)); | |
| 3100 return operand; | |
| 3101 } | |
| 3102 if (!_currentToken.type.isIncrementOperator()) { | |
| 3103 return operand; | |
| 3104 } | |
| 3105 if (operand is FunctionExpressionInvocation) { | |
| 3106 reportError4(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, []); | |
| 3107 } | |
| 3108 Token operator = andAdvance; | |
| 3109 return new PostfixExpression.full(operand, operator); | |
| 3110 } | |
| 3111 /** | |
| 3112 * Parse a prefixed identifier. | |
| 3113 * <pre> | |
| 3114 * prefixedIdentifier ::= | |
| 3115 * identifier ('.' identifier)? | |
| 3116 * </pre> | |
| 3117 * @return the prefixed identifier that was parsed | |
| 3118 */ | |
| 3119 Identifier parsePrefixedIdentifier() { | |
| 3120 SimpleIdentifier qualifier = parseSimpleIdentifier(); | |
| 3121 if (!matches5(TokenType.PERIOD)) { | |
| 3122 return qualifier; | |
| 3123 } | |
| 3124 Token period = andAdvance; | |
| 3125 SimpleIdentifier qualified = parseSimpleIdentifier(); | |
| 3126 return new PrefixedIdentifier.full(qualifier, period, qualified); | |
| 3127 } | |
| 3128 /** | |
| 3129 * Parse a primary expression. | |
| 3130 * <pre> | |
| 3131 * primary ::= | |
| 3132 * thisExpression | |
| 3133 * | 'super' assignableSelector | |
| 3134 * | functionExpression | |
| 3135 * | literal | |
| 3136 * | identifier | |
| 3137 * | newExpression | |
| 3138 * | constObjectExpression | |
| 3139 * | '(' expression ')' | |
| 3140 * | argumentDefinitionTest | |
| 3141 * literal ::= | |
| 3142 * nullLiteral | |
| 3143 * | booleanLiteral | |
| 3144 * | numericLiteral | |
| 3145 * | stringLiteral | |
| 3146 * | mapLiteral | |
| 3147 * | listLiteral | |
| 3148 * </pre> | |
| 3149 * @return the primary expression that was parsed | |
| 3150 */ | |
| 3151 Expression parsePrimaryExpression() { | |
| 3152 if (matches(Keyword.THIS)) { | |
| 3153 return new ThisExpression.full(andAdvance); | |
| 3154 } else if (matches(Keyword.SUPER)) { | |
| 3155 return parseAssignableSelector(new SuperExpression.full(andAdvance), false
); | |
| 3156 } else if (matches(Keyword.NULL)) { | |
| 3157 return new NullLiteral.full(andAdvance); | |
| 3158 } else if (matches(Keyword.FALSE)) { | |
| 3159 return new BooleanLiteral.full(andAdvance, false); | |
| 3160 } else if (matches(Keyword.TRUE)) { | |
| 3161 return new BooleanLiteral.full(andAdvance, true); | |
| 3162 } else if (matches5(TokenType.DOUBLE)) { | |
| 3163 Token token = andAdvance; | |
| 3164 double value = 0.0; | |
| 3165 try { | |
| 3166 value = double.parse(token.lexeme); | |
| 3167 } on NumberFormatException catch (exception) { | |
| 3168 } | |
| 3169 return new DoubleLiteral.full(token, value); | |
| 3170 } else if (matches5(TokenType.HEXADECIMAL)) { | |
| 3171 Token token = andAdvance; | |
| 3172 int value = null; | |
| 3173 try { | |
| 3174 value = int.parse(token.lexeme.substring(2), radix: 16); | |
| 3175 } on NumberFormatException catch (exception) { | |
| 3176 } | |
| 3177 return new IntegerLiteral.full(token, value); | |
| 3178 } else if (matches5(TokenType.INT)) { | |
| 3179 Token token = andAdvance; | |
| 3180 int value = null; | |
| 3181 try { | |
| 3182 value = int.parse(token.lexeme); | |
| 3183 } on NumberFormatException catch (exception) { | |
| 3184 } | |
| 3185 return new IntegerLiteral.full(token, value); | |
| 3186 } else if (matches5(TokenType.STRING)) { | |
| 3187 return parseStringLiteral(); | |
| 3188 } else if (matches5(TokenType.OPEN_CURLY_BRACKET)) { | |
| 3189 return parseMapLiteral(null, null); | |
| 3190 } else if (matches5(TokenType.OPEN_SQUARE_BRACKET) || matches5(TokenType.IND
EX)) { | |
| 3191 return parseListLiteral(null, null); | |
| 3192 } else if (matchesIdentifier()) { | |
| 3193 return parsePrefixedIdentifier(); | |
| 3194 } else if (matches(Keyword.NEW)) { | |
| 3195 return parseNewExpression(); | |
| 3196 } else if (matches(Keyword.CONST)) { | |
| 3197 return parseConstExpression(); | |
| 3198 } else if (matches5(TokenType.OPEN_PAREN)) { | |
| 3199 if (isFunctionExpression(_currentToken)) { | |
| 3200 return parseFunctionExpression(); | |
| 3201 } | |
| 3202 Token leftParenthesis = andAdvance; | |
| 3203 Expression expression = parseExpression2(); | |
| 3204 Token rightParenthesis = expect2(TokenType.CLOSE_PAREN); | |
| 3205 return new ParenthesizedExpression.full(leftParenthesis, expression, right
Parenthesis); | |
| 3206 } else if (matches5(TokenType.LT)) { | |
| 3207 return parseListOrMapLiteral(null); | |
| 3208 } else if (matches5(TokenType.QUESTION)) { | |
| 3209 return parseArgumentDefinitionTest(); | |
| 3210 } else if (matches(Keyword.VOID)) { | |
| 3211 reportError4(ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]); | |
| 3212 advance(); | |
| 3213 return parsePrimaryExpression(); | |
| 3214 } else { | |
| 3215 return createSyntheticIdentifier(); | |
| 3216 } | |
| 3217 } | |
| 3218 /** | |
| 3219 * Parse a redirecting constructor invocation. | |
| 3220 * <pre> | |
| 3221 * redirectingConstructorInvocation ::= | |
| 3222 * 'this' ('.' identifier)? arguments | |
| 3223 * </pre> | |
| 3224 * @return the redirecting constructor invocation that was parsed | |
| 3225 */ | |
| 3226 RedirectingConstructorInvocation parseRedirectingConstructorInvocation() { | |
| 3227 Token keyword = expect(Keyword.THIS); | |
| 3228 Token period = null; | |
| 3229 SimpleIdentifier constructorName = null; | |
| 3230 if (matches5(TokenType.PERIOD)) { | |
| 3231 period = andAdvance; | |
| 3232 constructorName = parseSimpleIdentifier(); | |
| 3233 } | |
| 3234 ArgumentList argumentList = parseArgumentList(); | |
| 3235 return new RedirectingConstructorInvocation.full(keyword, period, constructo
rName, argumentList); | |
| 3236 } | |
| 3237 /** | |
| 3238 * Parse a relational expression. | |
| 3239 * <pre> | |
| 3240 * relationalExpression ::= | |
| 3241 * shiftExpression ('is' type | 'as' type | relationalOperator shiftExpression
)? | |
| 3242 * | 'super' relationalOperator shiftExpression | |
| 3243 * </pre> | |
| 3244 * @return the relational expression that was parsed | |
| 3245 */ | |
| 3246 Expression parseRelationalExpression() { | |
| 3247 if (matches(Keyword.SUPER) && _currentToken.next.type.isRelationalOperator()
) { | |
| 3248 Expression expression = new SuperExpression.full(andAdvance); | |
| 3249 Token operator = andAdvance; | |
| 3250 expression = new BinaryExpression.full(expression, operator, parseShiftExp
ression()); | |
| 3251 return expression; | |
| 3252 } | |
| 3253 Expression expression = parseShiftExpression(); | |
| 3254 if (matches(Keyword.AS)) { | |
| 3255 Token asOperator = andAdvance; | |
| 3256 expression = new AsExpression.full(expression, asOperator, parseTypeName()
); | |
| 3257 } else if (matches(Keyword.IS)) { | |
| 3258 Token isOperator = andAdvance; | |
| 3259 Token notOperator = null; | |
| 3260 if (matches5(TokenType.BANG)) { | |
| 3261 notOperator = andAdvance; | |
| 3262 } | |
| 3263 expression = new IsExpression.full(expression, isOperator, notOperator, pa
rseTypeName()); | |
| 3264 } else if (_currentToken.type.isRelationalOperator()) { | |
| 3265 Token operator = andAdvance; | |
| 3266 expression = new BinaryExpression.full(expression, operator, parseShiftExp
ression()); | |
| 3267 } | |
| 3268 return expression; | |
| 3269 } | |
| 3270 /** | |
| 3271 * Parse a return statement. | |
| 3272 * <pre> | |
| 3273 * returnStatement ::= | |
| 3274 * 'return' expression? ';' | |
| 3275 * </pre> | |
| 3276 * @return the return statement that was parsed | |
| 3277 */ | |
| 3278 Statement parseReturnStatement() { | |
| 3279 Token returnKeyword = expect(Keyword.RETURN); | |
| 3280 if (matches5(TokenType.SEMICOLON)) { | |
| 3281 return new ReturnStatement.full(returnKeyword, null, andAdvance); | |
| 3282 } | |
| 3283 Expression expression = parseExpression2(); | |
| 3284 Token semicolon = expect2(TokenType.SEMICOLON); | |
| 3285 return new ReturnStatement.full(returnKeyword, expression, semicolon); | |
| 3286 } | |
| 3287 /** | |
| 3288 * Parse a return type. | |
| 3289 * <pre> | |
| 3290 * returnType ::= | |
| 3291 * 'void' | |
| 3292 * | type | |
| 3293 * </pre> | |
| 3294 * @return the return type that was parsed | |
| 3295 */ | |
| 3296 TypeName parseReturnType() { | |
| 3297 if (matches(Keyword.VOID)) { | |
| 3298 return new TypeName.full(new SimpleIdentifier.full(andAdvance), null); | |
| 3299 } else { | |
| 3300 return parseTypeName(); | |
| 3301 } | |
| 3302 } | |
| 3303 /** | |
| 3304 * Parse a setter. | |
| 3305 * <pre> | |
| 3306 * setter ::= | |
| 3307 * setterSignature functionBody? | |
| 3308 * setterSignature ::= | |
| 3309 * 'external'? 'static'? returnType? 'set' identifier formalParameterList | |
| 3310 * </pre> | |
| 3311 * @param commentAndMetadata the documentation comment and metadata to be asso
ciated with the | |
| 3312 * declaration | |
| 3313 * @param externalKeyword the 'external' token | |
| 3314 * @param staticKeyword the static keyword, or {@code null} if the setter is n
ot static | |
| 3315 * @param the return type that has already been parsed, or {@code null} if the
re was no return | |
| 3316 * type | |
| 3317 * @return the setter that was parsed | |
| 3318 */ | |
| 3319 MethodDeclaration parseSetter(CommentAndMetadata commentAndMetadata, Token ext
ernalKeyword, Token staticKeyword, TypeName returnType) { | |
| 3320 Token propertyKeyword = expect(Keyword.SET); | |
| 3321 SimpleIdentifier name = parseSimpleIdentifier(); | |
| 3322 FormalParameterList parameters = parseFormalParameterList(); | |
| 3323 validateFormalParameterList(parameters); | |
| 3324 FunctionBody body = parseFunctionBody(true, false); | |
| 3325 if (externalKeyword != null && body is! EmptyFunctionBody) { | |
| 3326 reportError4(ParserErrorCode.EXTERNAL_SETTER_WITH_BODY, []); | |
| 3327 } | |
| 3328 return new MethodDeclaration.full(commentAndMetadata.comment, commentAndMeta
data.metadata, externalKeyword, staticKeyword, returnType, propertyKeyword, null
, name, parameters, body); | |
| 3329 } | |
| 3330 /** | |
| 3331 * Parse a shift expression. | |
| 3332 * <pre> | |
| 3333 * shiftExpression ::= | |
| 3334 * additiveExpression (shiftOperator additiveExpression) | |
| 3335 * | 'super' (shiftOperator additiveExpression)+ | |
| 3336 * </pre> | |
| 3337 * @return the shift expression that was parsed | |
| 3338 */ | |
| 3339 Expression parseShiftExpression() { | |
| 3340 Expression expression; | |
| 3341 if (matches(Keyword.SUPER) && _currentToken.next.type.isShiftOperator()) { | |
| 3342 expression = new SuperExpression.full(andAdvance); | |
| 3343 } else { | |
| 3344 expression = parseAdditiveExpression(); | |
| 3345 } | |
| 3346 while (_currentToken.type.isShiftOperator()) { | |
| 3347 Token operator = andAdvance; | |
| 3348 expression = new BinaryExpression.full(expression, operator, parseAdditive
Expression()); | |
| 3349 } | |
| 3350 return expression; | |
| 3351 } | |
| 3352 /** | |
| 3353 * Parse a simple identifier. | |
| 3354 * <pre> | |
| 3355 * identifier ::= | |
| 3356 * IDENTIFIER | |
| 3357 * </pre> | |
| 3358 * @return the simple identifier that was parsed | |
| 3359 */ | |
| 3360 SimpleIdentifier parseSimpleIdentifier() { | |
| 3361 if (matchesIdentifier()) { | |
| 3362 return new SimpleIdentifier.full(andAdvance); | |
| 3363 } | |
| 3364 reportError4(ParserErrorCode.MISSING_IDENTIFIER, []); | |
| 3365 return createSyntheticIdentifier(); | |
| 3366 } | |
| 3367 /** | |
| 3368 * Parse a statement. | |
| 3369 * <pre> | |
| 3370 * statement ::= | |
| 3371 * label* nonLabeledStatement | |
| 3372 * </pre> | |
| 3373 * @return the statement that was parsed | |
| 3374 */ | |
| 3375 Statement parseStatement2() { | |
| 3376 List<Label> labels = new List<Label>(); | |
| 3377 while (matchesIdentifier() && matches4(peek(), TokenType.COLON)) { | |
| 3378 SimpleIdentifier label = parseSimpleIdentifier(); | |
| 3379 Token colon = expect2(TokenType.COLON); | |
| 3380 labels.add(new Label.full(label, colon)); | |
| 3381 } | |
| 3382 Statement statement = parseNonLabeledStatement(); | |
| 3383 if (labels.isEmpty) { | |
| 3384 return statement; | |
| 3385 } | |
| 3386 return new LabeledStatement.full(labels, statement); | |
| 3387 } | |
| 3388 /** | |
| 3389 * Parse a list of statements within a switch statement. | |
| 3390 * <pre> | |
| 3391 * statements ::= | |
| 3392 * statement | |
| 3393 * </pre> | |
| 3394 * @return the statements that were parsed | |
| 3395 */ | |
| 3396 List<Statement> parseStatements2() { | |
| 3397 List<Statement> statements = new List<Statement>(); | |
| 3398 Token statementStart = _currentToken; | |
| 3399 while (!matches5(TokenType.EOF) && !matches5(TokenType.CLOSE_CURLY_BRACKET)
&& !isSwitchMember()) { | |
| 3400 statements.add(parseStatement2()); | |
| 3401 if (identical(_currentToken, statementStart)) { | |
| 3402 reportError5(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentT
oken.lexeme]); | |
| 3403 advance(); | |
| 3404 } | |
| 3405 statementStart = _currentToken; | |
| 3406 } | |
| 3407 return statements; | |
| 3408 } | |
| 3409 /** | |
| 3410 * Parse a string literal that contains interpolations. | |
| 3411 * @return the string literal that was parsed | |
| 3412 */ | |
| 3413 StringInterpolation parseStringInterpolation(Token string) { | |
| 3414 List<InterpolationElement> elements = new List<InterpolationElement>(); | |
| 3415 elements.add(new InterpolationString.full(string, computeStringValue(string.
lexeme))); | |
| 3416 while (matches5(TokenType.STRING_INTERPOLATION_EXPRESSION) || matches5(Token
Type.STRING_INTERPOLATION_IDENTIFIER)) { | |
| 3417 if (matches5(TokenType.STRING_INTERPOLATION_EXPRESSION)) { | |
| 3418 Token openToken = andAdvance; | |
| 3419 Expression expression = parseExpression2(); | |
| 3420 Token rightBracket = expect2(TokenType.CLOSE_CURLY_BRACKET); | |
| 3421 elements.add(new InterpolationExpression.full(openToken, expression, rig
htBracket)); | |
| 3422 } else { | |
| 3423 Token openToken = andAdvance; | |
| 3424 Expression expression = null; | |
| 3425 if (matches(Keyword.THIS)) { | |
| 3426 expression = new ThisExpression.full(andAdvance); | |
| 3427 } else { | |
| 3428 expression = parseSimpleIdentifier(); | |
| 3429 } | |
| 3430 elements.add(new InterpolationExpression.full(openToken, expression, nul
l)); | |
| 3431 } | |
| 3432 if (matches5(TokenType.STRING)) { | |
| 3433 string = andAdvance; | |
| 3434 elements.add(new InterpolationString.full(string, computeStringValue(str
ing.lexeme))); | |
| 3435 } | |
| 3436 } | |
| 3437 return new StringInterpolation.full(elements); | |
| 3438 } | |
| 3439 /** | |
| 3440 * Parse a string literal. | |
| 3441 * <pre> | |
| 3442 * stringLiteral ::= | |
| 3443 * MULTI_LINE_STRING+ | |
| 3444 * | SINGLE_LINE_STRING+ | |
| 3445 * </pre> | |
| 3446 * @return the string literal that was parsed | |
| 3447 */ | |
| 3448 StringLiteral parseStringLiteral() { | |
| 3449 List<StringLiteral> strings = new List<StringLiteral>(); | |
| 3450 while (matches5(TokenType.STRING)) { | |
| 3451 Token string = andAdvance; | |
| 3452 if (matches5(TokenType.STRING_INTERPOLATION_EXPRESSION) || matches5(TokenT
ype.STRING_INTERPOLATION_IDENTIFIER)) { | |
| 3453 strings.add(parseStringInterpolation(string)); | |
| 3454 } else { | |
| 3455 strings.add(new SimpleStringLiteral.full(string, computeStringValue(stri
ng.lexeme))); | |
| 3456 } | |
| 3457 } | |
| 3458 if (strings.length < 1) { | |
| 3459 reportError4(ParserErrorCode.EXPECTED_STRING_LITERAL, []); | |
| 3460 return createSyntheticStringLiteral(); | |
| 3461 } else if (strings.length == 1) { | |
| 3462 return strings[0]; | |
| 3463 } else { | |
| 3464 return new AdjacentStrings.full(strings); | |
| 3465 } | |
| 3466 } | |
| 3467 /** | |
| 3468 * Parse a super constructor invocation. | |
| 3469 * <pre> | |
| 3470 * superConstructorInvocation ::= | |
| 3471 * 'super' ('.' identifier)? arguments | |
| 3472 * </pre> | |
| 3473 * @return the super constructor invocation that was parsed | |
| 3474 */ | |
| 3475 SuperConstructorInvocation parseSuperConstructorInvocation() { | |
| 3476 Token keyword = expect(Keyword.SUPER); | |
| 3477 Token period = null; | |
| 3478 SimpleIdentifier constructorName = null; | |
| 3479 if (matches5(TokenType.PERIOD)) { | |
| 3480 period = andAdvance; | |
| 3481 constructorName = parseSimpleIdentifier(); | |
| 3482 } | |
| 3483 ArgumentList argumentList = parseArgumentList(); | |
| 3484 return new SuperConstructorInvocation.full(keyword, period, constructorName,
argumentList); | |
| 3485 } | |
| 3486 /** | |
| 3487 * Parse a switch statement. | |
| 3488 * <pre> | |
| 3489 * switchStatement ::= | |
| 3490 * 'switch' '(' expression ')' '{' switchCase* defaultCase? '}' | |
| 3491 * switchCase ::= | |
| 3492 * label* ('case' expression ':') statements | |
| 3493 * defaultCase ::= | |
| 3494 * label* 'default' ':' statements | |
| 3495 * </pre> | |
| 3496 * @return the switch statement that was parsed | |
| 3497 */ | |
| 3498 SwitchStatement parseSwitchStatement() { | |
| 3499 bool wasInSwitch = _inSwitch; | |
| 3500 _inSwitch = true; | |
| 3501 try { | |
| 3502 Set<String> definedLabels = new Set<String>(); | |
| 3503 Token keyword = expect(Keyword.SWITCH); | |
| 3504 Token leftParenthesis = expect2(TokenType.OPEN_PAREN); | |
| 3505 Expression expression = parseExpression2(); | |
| 3506 Token rightParenthesis = expect2(TokenType.CLOSE_PAREN); | |
| 3507 Token leftBracket = expect2(TokenType.OPEN_CURLY_BRACKET); | |
| 3508 List<SwitchMember> members = new List<SwitchMember>(); | |
| 3509 while (!matches5(TokenType.EOF) && !matches5(TokenType.CLOSE_CURLY_BRACKET
)) { | |
| 3510 List<Label> labels = new List<Label>(); | |
| 3511 while (matchesIdentifier() && matches4(peek(), TokenType.COLON)) { | |
| 3512 SimpleIdentifier identifier = parseSimpleIdentifier(); | |
| 3513 String label = identifier.token.lexeme; | |
| 3514 if (definedLabels.contains(label)) { | |
| 3515 reportError5(ParserErrorCode.DUPLICATE_LABEL_IN_SWITCH_STATEMENT, id
entifier.token, [label]); | |
| 3516 } else { | |
| 3517 javaSetAdd(definedLabels, label); | |
| 3518 } | |
| 3519 Token colon = expect2(TokenType.COLON); | |
| 3520 labels.add(new Label.full(identifier, colon)); | |
| 3521 } | |
| 3522 if (matches(Keyword.CASE)) { | |
| 3523 Token caseKeyword = andAdvance; | |
| 3524 Expression caseExpression = parseExpression2(); | |
| 3525 Token colon = expect2(TokenType.COLON); | |
| 3526 members.add(new SwitchCase.full(labels, caseKeyword, caseExpression, c
olon, parseStatements2())); | |
| 3527 } else if (matches(Keyword.DEFAULT)) { | |
| 3528 Token defaultKeyword = andAdvance; | |
| 3529 Token colon = expect2(TokenType.COLON); | |
| 3530 members.add(new SwitchDefault.full(labels, defaultKeyword, colon, pars
eStatements2())); | |
| 3531 } else { | |
| 3532 reportError4(ParserErrorCode.EXPECTED_CASE_OR_DEFAULT, []); | |
| 3533 while (!matches5(TokenType.EOF) && !matches5(TokenType.CLOSE_CURLY_BRA
CKET) && !matches(Keyword.CASE) && !matches(Keyword.DEFAULT)) { | |
| 3534 advance(); | |
| 3535 } | |
| 3536 } | |
| 3537 } | |
| 3538 Token rightBracket = expect2(TokenType.CLOSE_CURLY_BRACKET); | |
| 3539 return new SwitchStatement.full(keyword, leftParenthesis, expression, righ
tParenthesis, leftBracket, members, rightBracket); | |
| 3540 } finally { | |
| 3541 _inSwitch = wasInSwitch; | |
| 3542 } | |
| 3543 } | |
| 3544 /** | |
| 3545 * Parse a throw expression. | |
| 3546 * <pre> | |
| 3547 * throwExpression ::= | |
| 3548 * 'throw' expression? ';' | |
| 3549 * </pre> | |
| 3550 * @return the throw expression that was parsed | |
| 3551 */ | |
| 3552 Expression parseThrowExpression() { | |
| 3553 Token keyword = expect(Keyword.THROW); | |
| 3554 if (matches5(TokenType.SEMICOLON) || matches5(TokenType.CLOSE_PAREN)) { | |
| 3555 return new ThrowExpression.full(keyword, null); | |
| 3556 } | |
| 3557 Expression expression = parseExpression2(); | |
| 3558 return new ThrowExpression.full(keyword, expression); | |
| 3559 } | |
| 3560 /** | |
| 3561 * Parse a throw expression. | |
| 3562 * <pre> | |
| 3563 * throwExpressionWithoutCascade ::= | |
| 3564 * 'throw' expressionWithoutCascade? ';' | |
| 3565 * </pre> | |
| 3566 * @return the throw expression that was parsed | |
| 3567 */ | |
| 3568 Expression parseThrowExpressionWithoutCascade() { | |
| 3569 Token keyword = expect(Keyword.THROW); | |
| 3570 if (matches5(TokenType.SEMICOLON) || matches5(TokenType.CLOSE_PAREN)) { | |
| 3571 return new ThrowExpression.full(keyword, null); | |
| 3572 } | |
| 3573 Expression expression = parseExpressionWithoutCascade(); | |
| 3574 return new ThrowExpression.full(keyword, expression); | |
| 3575 } | |
| 3576 /** | |
| 3577 * Parse a try statement. | |
| 3578 * <pre> | |
| 3579 * tryStatement ::= | |
| 3580 * 'try' block (onPart+ finallyPart? | finallyPart) | |
| 3581 * onPart ::= | |
| 3582 * catchPart block | |
| 3583 * | 'on' qualified catchPart? block | |
| 3584 * catchPart ::= | |
| 3585 * 'catch' '(' identifier (',' identifier)? ')' | |
| 3586 * finallyPart ::= | |
| 3587 * 'finally' block | |
| 3588 * </pre> | |
| 3589 * @return the try statement that was parsed | |
| 3590 */ | |
| 3591 Statement parseTryStatement() { | |
| 3592 Token tryKeyword = expect(Keyword.TRY); | |
| 3593 Block body = parseBlock(); | |
| 3594 List<CatchClause> catchClauses = new List<CatchClause>(); | |
| 3595 Block finallyClause = null; | |
| 3596 while (matches2(_ON) || matches(Keyword.CATCH)) { | |
| 3597 Token onKeyword = null; | |
| 3598 TypeName exceptionType = null; | |
| 3599 if (matches2(_ON)) { | |
| 3600 onKeyword = andAdvance; | |
| 3601 exceptionType = new TypeName.full(parsePrefixedIdentifier(), null); | |
| 3602 } | |
| 3603 Token catchKeyword = null; | |
| 3604 Token leftParenthesis = null; | |
| 3605 SimpleIdentifier exceptionParameter = null; | |
| 3606 Token comma = null; | |
| 3607 SimpleIdentifier stackTraceParameter = null; | |
| 3608 Token rightParenthesis = null; | |
| 3609 if (matches(Keyword.CATCH)) { | |
| 3610 catchKeyword = andAdvance; | |
| 3611 leftParenthesis = expect2(TokenType.OPEN_PAREN); | |
| 3612 exceptionParameter = parseSimpleIdentifier(); | |
| 3613 if (matches5(TokenType.COMMA)) { | |
| 3614 comma = andAdvance; | |
| 3615 stackTraceParameter = parseSimpleIdentifier(); | |
| 3616 } | |
| 3617 rightParenthesis = expect2(TokenType.CLOSE_PAREN); | |
| 3618 } | |
| 3619 Block catchBody = parseBlock(); | |
| 3620 catchClauses.add(new CatchClause.full(onKeyword, exceptionType, catchKeywo
rd, leftParenthesis, exceptionParameter, comma, stackTraceParameter, rightParent
hesis, catchBody)); | |
| 3621 } | |
| 3622 Token finallyKeyword = null; | |
| 3623 if (matches(Keyword.FINALLY)) { | |
| 3624 finallyKeyword = andAdvance; | |
| 3625 finallyClause = parseBlock(); | |
| 3626 } else { | |
| 3627 if (catchClauses.isEmpty) { | |
| 3628 reportError4(ParserErrorCode.MISSING_CATCH_OR_FINALLY, []); | |
| 3629 } | |
| 3630 } | |
| 3631 return new TryStatement.full(tryKeyword, body, catchClauses, finallyKeyword,
finallyClause); | |
| 3632 } | |
| 3633 /** | |
| 3634 * Parse a type alias. | |
| 3635 * <pre> | |
| 3636 * typeAlias ::= | |
| 3637 * 'typedef' typeAliasBody | |
| 3638 * typeAliasBody ::= | |
| 3639 * classTypeAlias | |
| 3640 * | functionTypeAlias | |
| 3641 * classTypeAlias ::= | |
| 3642 * identifier typeParameters? '=' 'abstract'? mixinApplication | |
| 3643 * mixinApplication ::= | |
| 3644 * qualified withClause implementsClause? ';' | |
| 3645 * functionTypeAlias ::= | |
| 3646 * functionPrefix typeParameterList? formalParameterList ';' | |
| 3647 * functionPrefix ::= | |
| 3648 * returnType? name | |
| 3649 * </pre> | |
| 3650 * @param commentAndMetadata the metadata to be associated with the member | |
| 3651 * @return the type alias that was parsed | |
| 3652 */ | |
| 3653 TypeAlias parseTypeAlias(CommentAndMetadata commentAndMetadata) { | |
| 3654 Token keyword = expect(Keyword.TYPEDEF); | |
| 3655 if (matchesIdentifier()) { | |
| 3656 Token next = peek(); | |
| 3657 if (matches4(next, TokenType.LT)) { | |
| 3658 next = skipTypeParameterList(next); | |
| 3659 if (next != null && matches4(next, TokenType.EQ)) { | |
| 3660 return parseClassTypeAlias(commentAndMetadata, keyword); | |
| 3661 } | |
| 3662 } else if (matches4(next, TokenType.EQ)) { | |
| 3663 return parseClassTypeAlias(commentAndMetadata, keyword); | |
| 3664 } | |
| 3665 } | |
| 3666 return parseFunctionTypeAlias(commentAndMetadata, keyword); | |
| 3667 } | |
| 3668 /** | |
| 3669 * Parse a list of type arguments. | |
| 3670 * <pre> | |
| 3671 * typeArguments ::= | |
| 3672 * '<' typeList '>' | |
| 3673 * typeList ::= | |
| 3674 * type (',' type) | |
| 3675 * </pre> | |
| 3676 * @return the type argument list that was parsed | |
| 3677 */ | |
| 3678 TypeArgumentList parseTypeArgumentList() { | |
| 3679 Token leftBracket = expect2(TokenType.LT); | |
| 3680 List<TypeName> arguments = new List<TypeName>(); | |
| 3681 arguments.add(parseTypeName()); | |
| 3682 while (optional(TokenType.COMMA)) { | |
| 3683 arguments.add(parseTypeName()); | |
| 3684 } | |
| 3685 Token rightBracket = expect2(TokenType.GT); | |
| 3686 return new TypeArgumentList.full(leftBracket, arguments, rightBracket); | |
| 3687 } | |
| 3688 /** | |
| 3689 * Parse a type name. | |
| 3690 * <pre> | |
| 3691 * type ::= | |
| 3692 * qualified typeArguments? | |
| 3693 * </pre> | |
| 3694 * @return the type name that was parsed | |
| 3695 */ | |
| 3696 TypeName parseTypeName() { | |
| 3697 Identifier typeName = parsePrefixedIdentifier(); | |
| 3698 TypeArgumentList typeArguments = null; | |
| 3699 if (matches5(TokenType.LT)) { | |
| 3700 typeArguments = parseTypeArgumentList(); | |
| 3701 } | |
| 3702 return new TypeName.full(typeName, typeArguments); | |
| 3703 } | |
| 3704 /** | |
| 3705 * Parse a type parameter. | |
| 3706 * <pre> | |
| 3707 * typeParameter ::= | |
| 3708 * metadata name ('extends' bound)? | |
| 3709 * </pre> | |
| 3710 * @return the type parameter that was parsed | |
| 3711 */ | |
| 3712 TypeParameter parseTypeParameter() { | |
| 3713 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata(); | |
| 3714 SimpleIdentifier name = parseSimpleIdentifier(); | |
| 3715 if (matches(Keyword.EXTENDS)) { | |
| 3716 Token keyword = andAdvance; | |
| 3717 TypeName bound = parseTypeName(); | |
| 3718 return new TypeParameter.full(commentAndMetadata.comment, commentAndMetada
ta.metadata, name, keyword, bound); | |
| 3719 } | |
| 3720 return new TypeParameter.full(commentAndMetadata.comment, commentAndMetadata
.metadata, name, null, null); | |
| 3721 } | |
| 3722 /** | |
| 3723 * Parse a list of type parameters. | |
| 3724 * <pre> | |
| 3725 * typeParameterList ::= | |
| 3726 * '<' typeParameter (',' typeParameter)* '>' | |
| 3727 * </pre> | |
| 3728 * @return the list of type parameters that were parsed | |
| 3729 */ | |
| 3730 TypeParameterList parseTypeParameterList() { | |
| 3731 Token leftBracket = expect2(TokenType.LT); | |
| 3732 List<TypeParameter> typeParameters = new List<TypeParameter>(); | |
| 3733 typeParameters.add(parseTypeParameter()); | |
| 3734 while (optional(TokenType.COMMA)) { | |
| 3735 typeParameters.add(parseTypeParameter()); | |
| 3736 } | |
| 3737 Token rightBracket = expect2(TokenType.GT); | |
| 3738 return new TypeParameterList.full(leftBracket, typeParameters, rightBracket)
; | |
| 3739 } | |
| 3740 /** | |
| 3741 * Parse a unary expression. | |
| 3742 * <pre> | |
| 3743 * unaryExpression ::= | |
| 3744 * prefixOperator unaryExpression | |
| 3745 * | postfixExpression | |
| 3746 * | unaryOperator 'super' | |
| 3747 * | '-' 'super' | |
| 3748 * | incrementOperator assignableExpression | |
| 3749 * </pre> | |
| 3750 * @return the unary expression that was parsed | |
| 3751 */ | |
| 3752 Expression parseUnaryExpression() { | |
| 3753 if (matches5(TokenType.MINUS) || matches5(TokenType.BANG) || matches5(TokenT
ype.TILDE)) { | |
| 3754 Token operator = andAdvance; | |
| 3755 if (matches(Keyword.SUPER)) { | |
| 3756 if (matches4(peek(), TokenType.OPEN_SQUARE_BRACKET) || matches4(peek(),
TokenType.PERIOD)) { | |
| 3757 return new PrefixExpression.full(operator, parseUnaryExpression()); | |
| 3758 } | |
| 3759 return new PrefixExpression.full(operator, new SuperExpression.full(andA
dvance)); | |
| 3760 } | |
| 3761 return new PrefixExpression.full(operator, parseUnaryExpression()); | |
| 3762 } else if (_currentToken.type.isIncrementOperator()) { | |
| 3763 Token operator = andAdvance; | |
| 3764 if (matches(Keyword.SUPER)) { | |
| 3765 if (identical(operator.type, TokenType.MINUS_MINUS)) { | |
| 3766 int offset9 = operator.offset; | |
| 3767 Token firstOperator = new Token(TokenType.MINUS, offset9); | |
| 3768 Token secondOperator = new Token(TokenType.MINUS, offset9 + 1); | |
| 3769 secondOperator.setNext(_currentToken); | |
| 3770 firstOperator.setNext(secondOperator); | |
| 3771 operator.previous.setNext(firstOperator); | |
| 3772 return new PrefixExpression.full(firstOperator, new PrefixExpression.f
ull(secondOperator, new SuperExpression.full(andAdvance))); | |
| 3773 } else { | |
| 3774 reportError4(ParserErrorCode.INVALID_OPERATOR_FOR_SUPER, [operator.lex
eme]); | |
| 3775 return new PrefixExpression.full(operator, new SuperExpression.full(an
dAdvance)); | |
| 3776 } | |
| 3777 } | |
| 3778 return new PrefixExpression.full(operator, parseAssignableExpression(false
)); | |
| 3779 } else if (matches5(TokenType.PLUS)) { | |
| 3780 reportError4(ParserErrorCode.USE_OF_UNARY_PLUS_OPERATOR, []); | |
| 3781 } | |
| 3782 return parsePostfixExpression(); | |
| 3783 } | |
| 3784 /** | |
| 3785 * Parse a variable declaration. | |
| 3786 * <pre> | |
| 3787 * variableDeclaration ::= | |
| 3788 * identifier ('=' expression)? | |
| 3789 * </pre> | |
| 3790 * @return the variable declaration that was parsed | |
| 3791 */ | |
| 3792 VariableDeclaration parseVariableDeclaration() { | |
| 3793 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata(); | |
| 3794 SimpleIdentifier name = parseSimpleIdentifier(); | |
| 3795 Token equals = null; | |
| 3796 Expression initializer = null; | |
| 3797 if (matches5(TokenType.EQ)) { | |
| 3798 equals = andAdvance; | |
| 3799 initializer = parseExpression2(); | |
| 3800 } | |
| 3801 return new VariableDeclaration.full(commentAndMetadata.comment, commentAndMe
tadata.metadata, name, equals, initializer); | |
| 3802 } | |
| 3803 /** | |
| 3804 * Parse a variable declaration list. | |
| 3805 * <pre> | |
| 3806 * variableDeclarationList ::= | |
| 3807 * finalConstVarOrType variableDeclaration (',' variableDeclaration) | |
| 3808 * </pre> | |
| 3809 * @return the variable declaration list that was parsed | |
| 3810 */ | |
| 3811 VariableDeclarationList parseVariableDeclarationList() { | |
| 3812 FinalConstVarOrType holder = parseFinalConstVarOrType(false); | |
| 3813 return parseVariableDeclarationList2(holder.keyword, holder.type); | |
| 3814 } | |
| 3815 /** | |
| 3816 * Parse a variable declaration list. | |
| 3817 * <pre> | |
| 3818 * variableDeclarationList ::= | |
| 3819 * finalConstVarOrType variableDeclaration (',' variableDeclaration) | |
| 3820 * </pre> | |
| 3821 * @param keyword the token representing the 'final', 'const' or 'var' keyword
, or {@code null} if | |
| 3822 * there is no keyword | |
| 3823 * @param type the type of the variables in the list | |
| 3824 * @return the variable declaration list that was parsed | |
| 3825 */ | |
| 3826 VariableDeclarationList parseVariableDeclarationList2(Token keyword, TypeName
type) { | |
| 3827 List<VariableDeclaration> variables = new List<VariableDeclaration>(); | |
| 3828 variables.add(parseVariableDeclaration()); | |
| 3829 while (matches5(TokenType.COMMA)) { | |
| 3830 advance(); | |
| 3831 variables.add(parseVariableDeclaration()); | |
| 3832 } | |
| 3833 return new VariableDeclarationList.full(keyword, type, variables); | |
| 3834 } | |
| 3835 /** | |
| 3836 * Parse a variable declaration statement. | |
| 3837 * <pre> | |
| 3838 * variableDeclarationStatement ::= | |
| 3839 * variableDeclarationList ';' | |
| 3840 * </pre> | |
| 3841 * @return the variable declaration statement that was parsed | |
| 3842 */ | |
| 3843 VariableDeclarationStatement parseVariableDeclarationStatement() { | |
| 3844 VariableDeclarationList variableList = parseVariableDeclarationList(); | |
| 3845 Token semicolon = expect2(TokenType.SEMICOLON); | |
| 3846 return new VariableDeclarationStatement.full(variableList, semicolon); | |
| 3847 } | |
| 3848 /** | |
| 3849 * Parse a while statement. | |
| 3850 * <pre> | |
| 3851 * whileStatement ::= | |
| 3852 * 'while' '(' expression ')' statement | |
| 3853 * </pre> | |
| 3854 * @return the while statement that was parsed | |
| 3855 */ | |
| 3856 Statement parseWhileStatement() { | |
| 3857 bool wasInLoop = _inLoop; | |
| 3858 _inLoop = true; | |
| 3859 try { | |
| 3860 Token keyword = expect(Keyword.WHILE); | |
| 3861 Token leftParenthesis = expect2(TokenType.OPEN_PAREN); | |
| 3862 Expression condition = parseExpression2(); | |
| 3863 Token rightParenthesis = expect2(TokenType.CLOSE_PAREN); | |
| 3864 Statement body = parseStatement2(); | |
| 3865 return new WhileStatement.full(keyword, leftParenthesis, condition, rightP
arenthesis, body); | |
| 3866 } finally { | |
| 3867 _inLoop = wasInLoop; | |
| 3868 } | |
| 3869 } | |
| 3870 /** | |
| 3871 * Parse a with clause. | |
| 3872 * <pre> | |
| 3873 * withClause ::= | |
| 3874 * 'with' typeName (',' typeName) | |
| 3875 * </pre> | |
| 3876 * @return the with clause that was parsed | |
| 3877 */ | |
| 3878 WithClause parseWithClause() { | |
| 3879 Token with2 = expect(Keyword.WITH); | |
| 3880 List<TypeName> types = new List<TypeName>(); | |
| 3881 types.add(parseTypeName()); | |
| 3882 while (optional(TokenType.COMMA)) { | |
| 3883 types.add(parseTypeName()); | |
| 3884 } | |
| 3885 return new WithClause.full(with2, types); | |
| 3886 } | |
| 3887 /** | |
| 3888 * Return the token that is immediately after the current token. This is equiv
alent to{@link #peek(int) peek(1)}. | |
| 3889 * @return the token that is immediately after the current token | |
| 3890 */ | |
| 3891 Token peek() => _currentToken.next; | |
| 3892 /** | |
| 3893 * Return the token that is the given distance after the current token. | |
| 3894 * @param distance the number of tokens to look ahead, where {@code 0} is the
current token,{@code 1} is the next token, etc. | |
| 3895 * @return the token that is the given distance after the current token | |
| 3896 */ | |
| 3897 Token peek2(int distance) { | |
| 3898 Token token = _currentToken; | |
| 3899 for (int i = 0; i < distance; i++) { | |
| 3900 token = token.next; | |
| 3901 } | |
| 3902 return token; | |
| 3903 } | |
| 3904 /** | |
| 3905 * Report an error with the given error code and arguments. | |
| 3906 * @param errorCode the error code of the error to be reported | |
| 3907 * @param node the node specifying the location of the error | |
| 3908 * @param arguments the arguments to the error, used to compose the error mess
age | |
| 3909 */ | |
| 3910 void reportError(ParserErrorCode errorCode, ASTNode node, List<Object> argumen
ts) { | |
| 3911 _errorListener.onError(new AnalysisError.con2(_source, node.offset, node.len
gth, errorCode, [arguments])); | |
| 3912 } | |
| 3913 /** | |
| 3914 * Report an error with the given error code and arguments. | |
| 3915 * @param errorCode the error code of the error to be reported | |
| 3916 * @param arguments the arguments to the error, used to compose the error mess
age | |
| 3917 */ | |
| 3918 void reportError4(ParserErrorCode errorCode, List<Object> arguments) { | |
| 3919 reportError5(errorCode, _currentToken, arguments); | |
| 3920 } | |
| 3921 /** | |
| 3922 * Report an error with the given error code and arguments. | |
| 3923 * @param errorCode the error code of the error to be reported | |
| 3924 * @param token the token specifying the location of the error | |
| 3925 * @param arguments the arguments to the error, used to compose the error mess
age | |
| 3926 */ | |
| 3927 void reportError5(ParserErrorCode errorCode, Token token, List<Object> argumen
ts) { | |
| 3928 _errorListener.onError(new AnalysisError.con2(_source, token.offset, token.l
ength, errorCode, [arguments])); | |
| 3929 } | |
| 3930 /** | |
| 3931 * Parse the 'final', 'const', 'var' or type preceding a variable declaration,
starting at the | |
| 3932 * given token, without actually creating a type or changing the current token
. Return the token | |
| 3933 * following the type that was parsed, or {@code null} if the given token is n
ot the first token | |
| 3934 * in a valid type. | |
| 3935 * <pre> | |
| 3936 * finalConstVarOrType ::= | |
| 3937 * | 'final' type? | |
| 3938 * | 'const' type? | |
| 3939 * | 'var' | |
| 3940 * | type | |
| 3941 * </pre> | |
| 3942 * @param startToken the token at which parsing is to begin | |
| 3943 * @return the token following the type that was parsed | |
| 3944 */ | |
| 3945 Token skipFinalConstVarOrType(Token startToken) { | |
| 3946 if (matches3(startToken, Keyword.FINAL) || matches3(startToken, Keyword.CONS
T)) { | |
| 3947 Token next3 = startToken.next; | |
| 3948 if (matchesIdentifier2(next3.next) || matches4(next3.next, TokenType.LT) |
| matches3(next3.next, Keyword.THIS)) { | |
| 3949 return skipTypeName(next3); | |
| 3950 } | |
| 3951 } else if (matches3(startToken, Keyword.VAR)) { | |
| 3952 return startToken.next; | |
| 3953 } else if (matchesIdentifier2(startToken)) { | |
| 3954 Token next4 = startToken.next; | |
| 3955 if (matchesIdentifier2(next4) || matches4(next4, TokenType.LT) || matches3
(next4, Keyword.THIS) || (matches4(next4, TokenType.PERIOD) && matchesIdentifier
2(next4.next) && (matchesIdentifier2(next4.next.next) || matches4(next4.next.nex
t, TokenType.LT) || matches3(next4.next.next, Keyword.THIS)))) { | |
| 3956 return skipReturnType(startToken); | |
| 3957 } | |
| 3958 } | |
| 3959 return null; | |
| 3960 } | |
| 3961 /** | |
| 3962 * Parse a list of formal parameters, starting at the given token, without act
ually creating a | |
| 3963 * formal parameter list or changing the current token. Return the token follo
wing the formal | |
| 3964 * parameter list that was parsed, or {@code null} if the given token is not t
he first token in a | |
| 3965 * valid list of formal parameter. | |
| 3966 * <p> | |
| 3967 * Note that unlike other skip methods, this method uses a heuristic. In the w
orst case, the | |
| 3968 * parameters could be prefixed by metadata, which would require us to be able
to skip arbitrary | |
| 3969 * expressions. Rather than duplicate the logic of most of the parse methods w
e simply look for | |
| 3970 * something that is likely to be a list of parameters and then skip to return
ing the token after | |
| 3971 * the closing parenthesis. | |
| 3972 * <p> | |
| 3973 * This method must be kept in sync with {@link #parseFormalParameterList()}. | |
| 3974 * <pre> | |
| 3975 * formalParameterList ::= | |
| 3976 * '(' ')' | |
| 3977 * | '(' normalFormalParameters (',' optionalFormalParameters)? ')' | |
| 3978 * | '(' optionalFormalParameters ')' | |
| 3979 * normalFormalParameters ::= | |
| 3980 * normalFormalParameter (',' normalFormalParameter) | |
| 3981 * optionalFormalParameters ::= | |
| 3982 * optionalPositionalFormalParameters | |
| 3983 * | namedFormalParameters | |
| 3984 * optionalPositionalFormalParameters ::= | |
| 3985 * '[' defaultFormalParameter (',' defaultFormalParameter)* ']' | |
| 3986 * namedFormalParameters ::= | |
| 3987 * '{' defaultNamedParameter (',' defaultNamedParameter)* '}' | |
| 3988 * </pre> | |
| 3989 * @param startToken the token at which parsing is to begin | |
| 3990 * @return the token following the formal parameter list that was parsed | |
| 3991 */ | |
| 3992 Token skipFormalParameterList(Token startToken) { | |
| 3993 if (!matches4(startToken, TokenType.OPEN_PAREN)) { | |
| 3994 return null; | |
| 3995 } | |
| 3996 Token next5 = startToken.next; | |
| 3997 if (matches4(next5, TokenType.CLOSE_PAREN)) { | |
| 3998 return next5.next; | |
| 3999 } | |
| 4000 if (matchesAny(next5, [TokenType.AT, TokenType.OPEN_SQUARE_BRACKET, TokenTyp
e.OPEN_CURLY_BRACKET]) || matches3(next5, Keyword.VOID) || (matchesIdentifier2(n
ext5) && (matchesAny(next5.next, [TokenType.COMMA, TokenType.CLOSE_PAREN])))) { | |
| 4001 return skipPastMatchingToken(startToken); | |
| 4002 } | |
| 4003 if (matchesIdentifier2(next5) && matches4(next5.next, TokenType.OPEN_PAREN))
{ | |
| 4004 Token afterParameters = skipFormalParameterList(next5.next); | |
| 4005 if (afterParameters != null && (matchesAny(afterParameters, [TokenType.COM
MA, TokenType.CLOSE_PAREN]))) { | |
| 4006 return skipPastMatchingToken(startToken); | |
| 4007 } | |
| 4008 } | |
| 4009 Token afterType = skipFinalConstVarOrType(next5); | |
| 4010 if (afterType == null) { | |
| 4011 return null; | |
| 4012 } | |
| 4013 if (skipSimpleIdentifier(afterType) == null) { | |
| 4014 return null; | |
| 4015 } | |
| 4016 return skipPastMatchingToken(startToken); | |
| 4017 } | |
| 4018 /** | |
| 4019 * If the given token is a begin token with an associated end token, then retu
rn the token | |
| 4020 * following the end token. Otherwise, return {@code null}. | |
| 4021 * @param startToken the token that is assumed to be a being token | |
| 4022 * @return the token following the matching end token | |
| 4023 */ | |
| 4024 Token skipPastMatchingToken(Token startToken) { | |
| 4025 if (startToken is! BeginToken) { | |
| 4026 return null; | |
| 4027 } | |
| 4028 Token closeParen = ((startToken as BeginToken)).endToken; | |
| 4029 if (closeParen == null) { | |
| 4030 return null; | |
| 4031 } | |
| 4032 return closeParen.next; | |
| 4033 } | |
| 4034 /** | |
| 4035 * Parse a prefixed identifier, starting at the given token, without actually
creating a prefixed | |
| 4036 * identifier or changing the current token. Return the token following the pr
efixed identifier | |
| 4037 * that was parsed, or {@code null} if the given token is not the first token
in a valid prefixed | |
| 4038 * identifier. | |
| 4039 * <p> | |
| 4040 * This method must be kept in sync with {@link #parsePrefixedIdentifier()}. | |
| 4041 * <pre> | |
| 4042 * prefixedIdentifier ::= | |
| 4043 * identifier ('.' identifier)? | |
| 4044 * </pre> | |
| 4045 * @param startToken the token at which parsing is to begin | |
| 4046 * @return the token following the prefixed identifier that was parsed | |
| 4047 */ | |
| 4048 Token skipPrefixedIdentifier(Token startToken) { | |
| 4049 Token token = skipSimpleIdentifier(startToken); | |
| 4050 if (token == null) { | |
| 4051 return null; | |
| 4052 } else if (!matches4(token, TokenType.PERIOD)) { | |
| 4053 return token; | |
| 4054 } | |
| 4055 return skipSimpleIdentifier(token.next); | |
| 4056 } | |
| 4057 /** | |
| 4058 * Parse a return type, starting at the given token, without actually creating
a return type or | |
| 4059 * changing the current token. Return the token following the return type that
was parsed, or{@code null} if the given token is not the first token in a valid
return type. | |
| 4060 * <p> | |
| 4061 * This method must be kept in sync with {@link #parseReturnType()}. | |
| 4062 * <pre> | |
| 4063 * returnType ::= | |
| 4064 * 'void' | |
| 4065 * | type | |
| 4066 * </pre> | |
| 4067 * @param startToken the token at which parsing is to begin | |
| 4068 * @return the token following the return type that was parsed | |
| 4069 */ | |
| 4070 Token skipReturnType(Token startToken) { | |
| 4071 if (matches3(startToken, Keyword.VOID)) { | |
| 4072 return startToken.next; | |
| 4073 } else { | |
| 4074 return skipTypeName(startToken); | |
| 4075 } | |
| 4076 } | |
| 4077 /** | |
| 4078 * Parse a simple identifier, starting at the given token, without actually cr
eating a simple | |
| 4079 * identifier or changing the current token. Return the token following the si
mple identifier that | |
| 4080 * was parsed, or {@code null} if the given token is not the first token in a
valid simple | |
| 4081 * identifier. | |
| 4082 * <p> | |
| 4083 * This method must be kept in sync with {@link #parseSimpleIdentifier()}. | |
| 4084 * <pre> | |
| 4085 * identifier ::= | |
| 4086 * IDENTIFIER | |
| 4087 * </pre> | |
| 4088 * @param startToken the token at which parsing is to begin | |
| 4089 * @return the token following the simple identifier that was parsed | |
| 4090 */ | |
| 4091 Token skipSimpleIdentifier(Token startToken) { | |
| 4092 if (matches4(startToken, TokenType.IDENTIFIER) || (matches4(startToken, Toke
nType.KEYWORD) && ((startToken as KeywordToken)).keyword.isPseudoKeyword())) { | |
| 4093 return startToken.next; | |
| 4094 } | |
| 4095 return null; | |
| 4096 } | |
| 4097 /** | |
| 4098 * Parse a string literal that contains interpolations, starting at the given
token, without | |
| 4099 * actually creating a string literal or changing the current token. Return th
e token following | |
| 4100 * the string literal that was parsed, or {@code null} if the given token is n
ot the first token | |
| 4101 * in a valid string literal. | |
| 4102 * <p> | |
| 4103 * This method must be kept in sync with {@link #parseStringInterpolation(Toke
n)}. | |
| 4104 * @param startToken the token at which parsing is to begin | |
| 4105 * @return the string literal that was parsed | |
| 4106 */ | |
| 4107 Token skipStringInterpolation(Token startToken) { | |
| 4108 Token token = startToken; | |
| 4109 TokenType type23 = token.type; | |
| 4110 while (identical(type23, TokenType.STRING_INTERPOLATION_EXPRESSION) || ident
ical(type23, TokenType.STRING_INTERPOLATION_IDENTIFIER)) { | |
| 4111 if (identical(type23, TokenType.STRING_INTERPOLATION_EXPRESSION)) { | |
| 4112 token = token.next; | |
| 4113 type23 = token.type; | |
| 4114 int bracketNestingLevel = 1; | |
| 4115 while (bracketNestingLevel > 0) { | |
| 4116 if (identical(type23, TokenType.EOF)) { | |
| 4117 return null; | |
| 4118 } else if (identical(type23, TokenType.OPEN_CURLY_BRACKET)) { | |
| 4119 bracketNestingLevel++; | |
| 4120 } else if (identical(type23, TokenType.CLOSE_CURLY_BRACKET)) { | |
| 4121 bracketNestingLevel--; | |
| 4122 } else if (identical(type23, TokenType.STRING)) { | |
| 4123 token = skipStringLiteral(token); | |
| 4124 if (token == null) { | |
| 4125 return null; | |
| 4126 } | |
| 4127 } else { | |
| 4128 token = token.next; | |
| 4129 } | |
| 4130 type23 = token.type; | |
| 4131 } | |
| 4132 token = token.next; | |
| 4133 type23 = token.type; | |
| 4134 } else { | |
| 4135 token = token.next; | |
| 4136 if (token.type != TokenType.IDENTIFIER) { | |
| 4137 return null; | |
| 4138 } | |
| 4139 token = token.next; | |
| 4140 } | |
| 4141 type23 = token.type; | |
| 4142 if (identical(type23, TokenType.STRING)) { | |
| 4143 token = token.next; | |
| 4144 type23 = token.type; | |
| 4145 } | |
| 4146 } | |
| 4147 return token; | |
| 4148 } | |
| 4149 /** | |
| 4150 * Parse a string literal, starting at the given token, without actually creat
ing a string literal | |
| 4151 * or changing the current token. Return the token following the string litera
l that was parsed, | |
| 4152 * or {@code null} if the given token is not the first token in a valid string
literal. | |
| 4153 * <p> | |
| 4154 * This method must be kept in sync with {@link #parseStringLiteral()}. | |
| 4155 * <pre> | |
| 4156 * stringLiteral ::= | |
| 4157 * MULTI_LINE_STRING+ | |
| 4158 * | SINGLE_LINE_STRING+ | |
| 4159 * </pre> | |
| 4160 * @param startToken the token at which parsing is to begin | |
| 4161 * @return the token following the string literal that was parsed | |
| 4162 */ | |
| 4163 Token skipStringLiteral(Token startToken) { | |
| 4164 Token token = startToken; | |
| 4165 while (token != null && matches4(token, TokenType.STRING)) { | |
| 4166 token = token.next; | |
| 4167 TokenType type24 = token.type; | |
| 4168 if (identical(type24, TokenType.STRING_INTERPOLATION_EXPRESSION) || identi
cal(type24, TokenType.STRING_INTERPOLATION_IDENTIFIER)) { | |
| 4169 token = skipStringInterpolation(token); | |
| 4170 } | |
| 4171 } | |
| 4172 if (identical(token, startToken)) { | |
| 4173 return null; | |
| 4174 } | |
| 4175 return token; | |
| 4176 } | |
| 4177 /** | |
| 4178 * Parse a list of type arguments, starting at the given token, without actual
ly creating a type argument list | |
| 4179 * or changing the current token. Return the token following the type argument
list that was parsed, | |
| 4180 * or {@code null} if the given token is not the first token in a valid type a
rgument list. | |
| 4181 * <p> | |
| 4182 * This method must be kept in sync with {@link #parseTypeArgumentList()}. | |
| 4183 * <pre> | |
| 4184 * typeArguments ::= | |
| 4185 * '<' typeList '>' | |
| 4186 * typeList ::= | |
| 4187 * type (',' type) | |
| 4188 * </pre> | |
| 4189 * @param startToken the token at which parsing is to begin | |
| 4190 * @return the token following the type argument list that was parsed | |
| 4191 */ | |
| 4192 Token skipTypeArgumentList(Token startToken) { | |
| 4193 Token token = startToken; | |
| 4194 if (!matches4(token, TokenType.LT)) { | |
| 4195 return null; | |
| 4196 } | |
| 4197 token = skipTypeName(token.next); | |
| 4198 if (token == null) { | |
| 4199 return null; | |
| 4200 } | |
| 4201 while (matches4(token, TokenType.COMMA)) { | |
| 4202 token = skipTypeName(token.next); | |
| 4203 if (token == null) { | |
| 4204 return null; | |
| 4205 } | |
| 4206 } | |
| 4207 if (identical(token.type, TokenType.GT)) { | |
| 4208 return token.next; | |
| 4209 } else if (identical(token.type, TokenType.GT_GT)) { | |
| 4210 Token second = new Token(TokenType.GT, token.offset + 1); | |
| 4211 second.setNextWithoutSettingPrevious(token.next); | |
| 4212 return second; | |
| 4213 } | |
| 4214 return null; | |
| 4215 } | |
| 4216 /** | |
| 4217 * Parse a type name, starting at the given token, without actually creating a
type name or | |
| 4218 * changing the current token. Return the token following the type name that w
as parsed, or{@code null} if the given token is not the first token in a valid t
ype name. | |
| 4219 * <p> | |
| 4220 * This method must be kept in sync with {@link #parseTypeName()}. | |
| 4221 * <pre> | |
| 4222 * type ::= | |
| 4223 * qualified typeArguments? | |
| 4224 * </pre> | |
| 4225 * @param startToken the token at which parsing is to begin | |
| 4226 * @return the token following the type name that was parsed | |
| 4227 */ | |
| 4228 Token skipTypeName(Token startToken) { | |
| 4229 Token token = skipPrefixedIdentifier(startToken); | |
| 4230 if (token == null) { | |
| 4231 return null; | |
| 4232 } | |
| 4233 if (matches4(token, TokenType.LT)) { | |
| 4234 token = skipTypeArgumentList(token); | |
| 4235 } | |
| 4236 return token; | |
| 4237 } | |
| 4238 /** | |
| 4239 * Parse a list of type parameters, starting at the given token, without actua
lly creating a type | |
| 4240 * parameter list or changing the current token. Return the token following th
e type parameter | |
| 4241 * list that was parsed, or {@code null} if the given token is not the first t
oken in a valid type | |
| 4242 * parameter list. | |
| 4243 * <p> | |
| 4244 * This method must be kept in sync with {@link #parseTypeParameterList()}. | |
| 4245 * <pre> | |
| 4246 * typeParameterList ::= | |
| 4247 * '<' typeParameter (',' typeParameter)* '>' | |
| 4248 * </pre> | |
| 4249 * @param startToken the token at which parsing is to begin | |
| 4250 * @return the token following the type parameter list that was parsed | |
| 4251 */ | |
| 4252 Token skipTypeParameterList(Token startToken) { | |
| 4253 if (!matches4(startToken, TokenType.LT)) { | |
| 4254 return null; | |
| 4255 } | |
| 4256 int depth = 1; | |
| 4257 Token next6 = startToken.next; | |
| 4258 while (depth > 0) { | |
| 4259 if (matches4(next6, TokenType.EOF)) { | |
| 4260 return null; | |
| 4261 } else if (matches4(next6, TokenType.LT)) { | |
| 4262 depth++; | |
| 4263 } else if (matches4(next6, TokenType.GT)) { | |
| 4264 depth--; | |
| 4265 } else if (matches4(next6, TokenType.GT_EQ)) { | |
| 4266 if (depth == 1) { | |
| 4267 Token fakeEquals = new Token(TokenType.EQ, next6.offset + 2); | |
| 4268 fakeEquals.setNextWithoutSettingPrevious(next6.next); | |
| 4269 return fakeEquals; | |
| 4270 } | |
| 4271 depth--; | |
| 4272 } else if (matches4(next6, TokenType.GT_GT)) { | |
| 4273 depth -= 2; | |
| 4274 } else if (matches4(next6, TokenType.GT_GT_EQ)) { | |
| 4275 if (depth < 2) { | |
| 4276 return null; | |
| 4277 } else if (depth == 2) { | |
| 4278 Token fakeEquals = new Token(TokenType.EQ, next6.offset + 2); | |
| 4279 fakeEquals.setNextWithoutSettingPrevious(next6.next); | |
| 4280 return fakeEquals; | |
| 4281 } | |
| 4282 depth -= 2; | |
| 4283 } | |
| 4284 next6 = next6.next; | |
| 4285 } | |
| 4286 return next6; | |
| 4287 } | |
| 4288 /** | |
| 4289 * Translate the characters at the given index in the given string, appending
the translated | |
| 4290 * character to the given builder. The index is assumed to be valid. | |
| 4291 * @param builder the builder to which the translated character is to be appen
ded | |
| 4292 * @param lexeme the string containing the character(s) to be translated | |
| 4293 * @param index the index of the character to be translated | |
| 4294 * @return the index of the next character to be translated | |
| 4295 */ | |
| 4296 int translateCharacter(JavaStringBuilder builder, String lexeme, int index) { | |
| 4297 int currentChar = lexeme.codeUnitAt(index); | |
| 4298 if (currentChar != 0x5C) { | |
| 4299 builder.appendChar(currentChar); | |
| 4300 return index + 1; | |
| 4301 } | |
| 4302 int length8 = lexeme.length; | |
| 4303 int currentIndex = index + 1; | |
| 4304 if (currentIndex >= length8) { | |
| 4305 return length8; | |
| 4306 } | |
| 4307 currentChar = lexeme.codeUnitAt(currentIndex); | |
| 4308 if (currentChar == 0x6E) { | |
| 4309 builder.appendChar(0xA); | |
| 4310 } else if (currentChar == 0x72) { | |
| 4311 builder.appendChar(0xD); | |
| 4312 } else if (currentChar == 0x66) { | |
| 4313 builder.appendChar(0xC); | |
| 4314 } else if (currentChar == 0x62) { | |
| 4315 builder.appendChar(0x8); | |
| 4316 } else if (currentChar == 0x74) { | |
| 4317 builder.appendChar(0x9); | |
| 4318 } else if (currentChar == 0x76) { | |
| 4319 builder.appendChar(0xB); | |
| 4320 } else if (currentChar == 0x78) { | |
| 4321 if (currentIndex + 2 >= length8) { | |
| 4322 reportError4(ParserErrorCode.INVALID_HEX_ESCAPE, []); | |
| 4323 return length8; | |
| 4324 } | |
| 4325 int firstDigit = lexeme.codeUnitAt(currentIndex + 1); | |
| 4326 int secondDigit = lexeme.codeUnitAt(currentIndex + 2); | |
| 4327 if (!isHexDigit(firstDigit) || !isHexDigit(secondDigit)) { | |
| 4328 reportError4(ParserErrorCode.INVALID_HEX_ESCAPE, []); | |
| 4329 } else { | |
| 4330 builder.appendChar((((Character.digit(firstDigit, 16) << 4) + Character.
digit(secondDigit, 16)) as int)); | |
| 4331 } | |
| 4332 return currentIndex + 3; | |
| 4333 } else if (currentChar == 0x75) { | |
| 4334 currentIndex++; | |
| 4335 if (currentIndex >= length8) { | |
| 4336 reportError4(ParserErrorCode.INVALID_UNICODE_ESCAPE, []); | |
| 4337 return length8; | |
| 4338 } | |
| 4339 currentChar = lexeme.codeUnitAt(currentIndex); | |
| 4340 if (currentChar == 0x7B) { | |
| 4341 currentIndex++; | |
| 4342 if (currentIndex >= length8) { | |
| 4343 reportError4(ParserErrorCode.INVALID_UNICODE_ESCAPE, []); | |
| 4344 return length8; | |
| 4345 } | |
| 4346 currentChar = lexeme.codeUnitAt(currentIndex); | |
| 4347 int digitCount = 0; | |
| 4348 int value = 0; | |
| 4349 while (currentChar != 0x7D) { | |
| 4350 if (!isHexDigit(currentChar)) { | |
| 4351 reportError4(ParserErrorCode.INVALID_UNICODE_ESCAPE, []); | |
| 4352 currentIndex++; | |
| 4353 while (currentIndex < length8 && lexeme.codeUnitAt(currentIndex) !=
0x7D) { | |
| 4354 currentIndex++; | |
| 4355 } | |
| 4356 return currentIndex + 1; | |
| 4357 } | |
| 4358 digitCount++; | |
| 4359 value = (value << 4) + Character.digit(currentChar, 16); | |
| 4360 currentIndex++; | |
| 4361 if (currentIndex >= length8) { | |
| 4362 reportError4(ParserErrorCode.INVALID_UNICODE_ESCAPE, []); | |
| 4363 return length8; | |
| 4364 } | |
| 4365 currentChar = lexeme.codeUnitAt(currentIndex); | |
| 4366 } | |
| 4367 if (digitCount < 1 || digitCount > 6) { | |
| 4368 reportError4(ParserErrorCode.INVALID_UNICODE_ESCAPE, []); | |
| 4369 } | |
| 4370 appendScalarValue(builder, lexeme.substring(index, currentIndex + 1), va
lue, index, currentIndex); | |
| 4371 return currentIndex + 1; | |
| 4372 } else { | |
| 4373 if (currentIndex + 3 >= length8) { | |
| 4374 reportError4(ParserErrorCode.INVALID_UNICODE_ESCAPE, []); | |
| 4375 return length8; | |
| 4376 } | |
| 4377 int firstDigit = currentChar; | |
| 4378 int secondDigit = lexeme.codeUnitAt(currentIndex + 1); | |
| 4379 int thirdDigit = lexeme.codeUnitAt(currentIndex + 2); | |
| 4380 int fourthDigit = lexeme.codeUnitAt(currentIndex + 3); | |
| 4381 if (!isHexDigit(firstDigit) || !isHexDigit(secondDigit) || !isHexDigit(t
hirdDigit) || !isHexDigit(fourthDigit)) { | |
| 4382 reportError4(ParserErrorCode.INVALID_UNICODE_ESCAPE, []); | |
| 4383 } else { | |
| 4384 appendScalarValue(builder, lexeme.substring(index, currentIndex + 1),
((((((Character.digit(firstDigit, 16) << 4) + Character.digit(secondDigit, 16))
<< 4) + Character.digit(thirdDigit, 16)) << 4) + Character.digit(fourthDigit, 16
)), index, currentIndex + 3); | |
| 4385 } | |
| 4386 return currentIndex + 4; | |
| 4387 } | |
| 4388 } else { | |
| 4389 builder.appendChar(currentChar); | |
| 4390 } | |
| 4391 return currentIndex + 1; | |
| 4392 } | |
| 4393 /** | |
| 4394 * Validate that the given parameter list does not contain any field initializ
ers. | |
| 4395 * @param parameterList the parameter list to be validated | |
| 4396 */ | |
| 4397 void validateFormalParameterList(FormalParameterList parameterList) { | |
| 4398 for (FormalParameter parameter in parameterList.parameters) { | |
| 4399 if (parameter is FieldFormalParameter) { | |
| 4400 reportError(ParserErrorCode.FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR, ((par
ameter as FieldFormalParameter)).identifier, []); | |
| 4401 } | |
| 4402 } | |
| 4403 } | |
| 4404 /** | |
| 4405 * Validate that the given set of modifiers is appropriate for a class and ret
urn the 'abstract' | |
| 4406 * keyword if there is one. | |
| 4407 * @param modifiers the modifiers being validated | |
| 4408 */ | |
| 4409 Token validateModifiersForClass(Modifiers modifiers) { | |
| 4410 validateModifiersForTopLevelDeclaration(modifiers); | |
| 4411 if (modifiers.constKeyword != null) { | |
| 4412 reportError5(ParserErrorCode.CONST_CLASS, modifiers.constKeyword, []); | |
| 4413 } | |
| 4414 if (modifiers.externalKeyword != null) { | |
| 4415 reportError5(ParserErrorCode.EXTERNAL_CLASS, modifiers.externalKeyword, []
); | |
| 4416 } | |
| 4417 if (modifiers.finalKeyword != null) { | |
| 4418 reportError5(ParserErrorCode.FINAL_CLASS, modifiers.finalKeyword, []); | |
| 4419 } | |
| 4420 if (modifiers.varKeyword != null) { | |
| 4421 reportError5(ParserErrorCode.VAR_CLASS, modifiers.varKeyword, []); | |
| 4422 } | |
| 4423 return modifiers.abstractKeyword; | |
| 4424 } | |
| 4425 /** | |
| 4426 * Validate that the given set of modifiers is appropriate for a constructor a
nd return the | |
| 4427 * 'const' keyword if there is one. | |
| 4428 * @param modifiers the modifiers being validated | |
| 4429 * @return the 'const' or 'final' keyword associated with the constructor | |
| 4430 */ | |
| 4431 Token validateModifiersForConstructor(Modifiers modifiers) { | |
| 4432 if (modifiers.abstractKeyword != null) { | |
| 4433 reportError4(ParserErrorCode.ABSTRACT_CLASS_MEMBER, []); | |
| 4434 } | |
| 4435 if (modifiers.finalKeyword != null) { | |
| 4436 reportError5(ParserErrorCode.FINAL_CONSTRUCTOR, modifiers.finalKeyword, []
); | |
| 4437 } | |
| 4438 if (modifiers.staticKeyword != null) { | |
| 4439 reportError5(ParserErrorCode.STATIC_CONSTRUCTOR, modifiers.staticKeyword,
[]); | |
| 4440 } | |
| 4441 if (modifiers.varKeyword != null) { | |
| 4442 reportError5(ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, modifiers.varKe
yword, []); | |
| 4443 } | |
| 4444 Token externalKeyword6 = modifiers.externalKeyword; | |
| 4445 Token constKeyword4 = modifiers.constKeyword; | |
| 4446 Token factoryKeyword4 = modifiers.factoryKeyword; | |
| 4447 if (externalKeyword6 != null && constKeyword4 != null && constKeyword4.offse
t < externalKeyword6.offset) { | |
| 4448 reportError5(ParserErrorCode.EXTERNAL_AFTER_CONST, externalKeyword6, []); | |
| 4449 } | |
| 4450 if (externalKeyword6 != null && factoryKeyword4 != null && factoryKeyword4.o
ffset < externalKeyword6.offset) { | |
| 4451 reportError5(ParserErrorCode.EXTERNAL_AFTER_FACTORY, externalKeyword6, [])
; | |
| 4452 } | |
| 4453 return constKeyword4; | |
| 4454 } | |
| 4455 /** | |
| 4456 * Validate that the given set of modifiers is appropriate for a field and ret
urn the 'final', | |
| 4457 * 'const' or 'var' keyword if there is one. | |
| 4458 * @param modifiers the modifiers being validated | |
| 4459 * @return the 'final', 'const' or 'var' keyword associated with the field | |
| 4460 */ | |
| 4461 Token validateModifiersForField(Modifiers modifiers) { | |
| 4462 if (modifiers.abstractKeyword != null) { | |
| 4463 reportError4(ParserErrorCode.ABSTRACT_CLASS_MEMBER, []); | |
| 4464 } | |
| 4465 if (modifiers.externalKeyword != null) { | |
| 4466 reportError5(ParserErrorCode.EXTERNAL_FIELD, modifiers.externalKeyword, []
); | |
| 4467 } | |
| 4468 if (modifiers.factoryKeyword != null) { | |
| 4469 reportError5(ParserErrorCode.NON_CONSTRUCTOR_FACTORY, modifiers.factoryKey
word, []); | |
| 4470 } | |
| 4471 Token staticKeyword3 = modifiers.staticKeyword; | |
| 4472 Token constKeyword5 = modifiers.constKeyword; | |
| 4473 Token finalKeyword3 = modifiers.finalKeyword; | |
| 4474 Token varKeyword3 = modifiers.varKeyword; | |
| 4475 if (constKeyword5 != null) { | |
| 4476 if (finalKeyword3 != null) { | |
| 4477 reportError5(ParserErrorCode.CONST_AND_FINAL, finalKeyword3, []); | |
| 4478 } | |
| 4479 if (varKeyword3 != null) { | |
| 4480 reportError5(ParserErrorCode.CONST_AND_VAR, varKeyword3, []); | |
| 4481 } | |
| 4482 if (staticKeyword3 != null && constKeyword5.offset < staticKeyword3.offset
) { | |
| 4483 reportError5(ParserErrorCode.STATIC_AFTER_CONST, staticKeyword3, []); | |
| 4484 } | |
| 4485 } else if (finalKeyword3 != null) { | |
| 4486 if (varKeyword3 != null) { | |
| 4487 reportError5(ParserErrorCode.FINAL_AND_VAR, varKeyword3, []); | |
| 4488 } | |
| 4489 if (staticKeyword3 != null && finalKeyword3.offset < staticKeyword3.offset
) { | |
| 4490 reportError5(ParserErrorCode.STATIC_AFTER_FINAL, staticKeyword3, []); | |
| 4491 } | |
| 4492 } else if (varKeyword3 != null && staticKeyword3 != null && varKeyword3.offs
et < staticKeyword3.offset) { | |
| 4493 reportError5(ParserErrorCode.STATIC_AFTER_VAR, staticKeyword3, []); | |
| 4494 } | |
| 4495 return lexicallyFirst([constKeyword5, finalKeyword3, varKeyword3]); | |
| 4496 } | |
| 4497 /** | |
| 4498 * Validate that the given set of modifiers is appropriate for a getter, sette
r, or method. | |
| 4499 * @param modifiers the modifiers being validated | |
| 4500 */ | |
| 4501 void validateModifiersForGetterOrSetterOrMethod(Modifiers modifiers) { | |
| 4502 if (modifiers.abstractKeyword != null) { | |
| 4503 reportError4(ParserErrorCode.ABSTRACT_CLASS_MEMBER, []); | |
| 4504 } | |
| 4505 if (modifiers.constKeyword != null) { | |
| 4506 reportError5(ParserErrorCode.CONST_METHOD, modifiers.constKeyword, []); | |
| 4507 } | |
| 4508 if (modifiers.factoryKeyword != null) { | |
| 4509 reportError5(ParserErrorCode.NON_CONSTRUCTOR_FACTORY, modifiers.factoryKey
word, []); | |
| 4510 } | |
| 4511 if (modifiers.finalKeyword != null) { | |
| 4512 reportError5(ParserErrorCode.FINAL_METHOD, modifiers.finalKeyword, []); | |
| 4513 } | |
| 4514 if (modifiers.varKeyword != null) { | |
| 4515 reportError5(ParserErrorCode.VAR_RETURN_TYPE, modifiers.varKeyword, []); | |
| 4516 } | |
| 4517 Token externalKeyword7 = modifiers.externalKeyword; | |
| 4518 Token staticKeyword4 = modifiers.staticKeyword; | |
| 4519 if (externalKeyword7 != null && staticKeyword4 != null && staticKeyword4.off
set < externalKeyword7.offset) { | |
| 4520 reportError5(ParserErrorCode.EXTERNAL_AFTER_STATIC, externalKeyword7, []); | |
| 4521 } | |
| 4522 } | |
| 4523 /** | |
| 4524 * Validate that the given set of modifiers is appropriate for a getter, sette
r, or method. | |
| 4525 * @param modifiers the modifiers being validated | |
| 4526 */ | |
| 4527 void validateModifiersForOperator(Modifiers modifiers) { | |
| 4528 if (modifiers.abstractKeyword != null) { | |
| 4529 reportError4(ParserErrorCode.ABSTRACT_CLASS_MEMBER, []); | |
| 4530 } | |
| 4531 if (modifiers.constKeyword != null) { | |
| 4532 reportError5(ParserErrorCode.CONST_METHOD, modifiers.constKeyword, []); | |
| 4533 } | |
| 4534 if (modifiers.factoryKeyword != null) { | |
| 4535 reportError5(ParserErrorCode.NON_CONSTRUCTOR_FACTORY, modifiers.factoryKey
word, []); | |
| 4536 } | |
| 4537 if (modifiers.finalKeyword != null) { | |
| 4538 reportError5(ParserErrorCode.FINAL_METHOD, modifiers.finalKeyword, []); | |
| 4539 } | |
| 4540 if (modifiers.staticKeyword != null) { | |
| 4541 reportError5(ParserErrorCode.STATIC_OPERATOR, modifiers.staticKeyword, [])
; | |
| 4542 } | |
| 4543 if (modifiers.varKeyword != null) { | |
| 4544 reportError5(ParserErrorCode.VAR_RETURN_TYPE, modifiers.varKeyword, []); | |
| 4545 } | |
| 4546 } | |
| 4547 /** | |
| 4548 * Validate that the given set of modifiers is appropriate for a top-level dec
laration. | |
| 4549 * @param modifiers the modifiers being validated | |
| 4550 */ | |
| 4551 void validateModifiersForTopLevelDeclaration(Modifiers modifiers) { | |
| 4552 if (modifiers.factoryKeyword != null) { | |
| 4553 reportError5(ParserErrorCode.FACTORY_TOP_LEVEL_DECLARATION, modifiers.fact
oryKeyword, []); | |
| 4554 } | |
| 4555 if (modifiers.staticKeyword != null) { | |
| 4556 reportError5(ParserErrorCode.STATIC_TOP_LEVEL_DECLARATION, modifiers.stati
cKeyword, []); | |
| 4557 } | |
| 4558 } | |
| 4559 /** | |
| 4560 * Validate that the given set of modifiers is appropriate for a top-level fun
ction. | |
| 4561 * @param modifiers the modifiers being validated | |
| 4562 */ | |
| 4563 void validateModifiersForTopLevelFunction(Modifiers modifiers) { | |
| 4564 validateModifiersForTopLevelDeclaration(modifiers); | |
| 4565 if (modifiers.abstractKeyword != null) { | |
| 4566 reportError4(ParserErrorCode.ABSTRACT_TOP_LEVEL_FUNCTION, []); | |
| 4567 } | |
| 4568 if (modifiers.constKeyword != null) { | |
| 4569 reportError5(ParserErrorCode.CONST_CLASS, modifiers.constKeyword, []); | |
| 4570 } | |
| 4571 if (modifiers.finalKeyword != null) { | |
| 4572 reportError5(ParserErrorCode.FINAL_CLASS, modifiers.finalKeyword, []); | |
| 4573 } | |
| 4574 if (modifiers.varKeyword != null) { | |
| 4575 reportError5(ParserErrorCode.VAR_RETURN_TYPE, modifiers.varKeyword, []); | |
| 4576 } | |
| 4577 } | |
| 4578 /** | |
| 4579 * Validate that the given set of modifiers is appropriate for a field and ret
urn the 'final', | |
| 4580 * 'const' or 'var' keyword if there is one. | |
| 4581 * @param modifiers the modifiers being validated | |
| 4582 * @return the 'final', 'const' or 'var' keyword associated with the field | |
| 4583 */ | |
| 4584 Token validateModifiersForTopLevelVariable(Modifiers modifiers) { | |
| 4585 validateModifiersForTopLevelDeclaration(modifiers); | |
| 4586 if (modifiers.abstractKeyword != null) { | |
| 4587 reportError4(ParserErrorCode.ABSTRACT_TOP_LEVEL_VARIABLE, []); | |
| 4588 } | |
| 4589 if (modifiers.externalKeyword != null) { | |
| 4590 reportError5(ParserErrorCode.EXTERNAL_FIELD, modifiers.externalKeyword, []
); | |
| 4591 } | |
| 4592 Token constKeyword6 = modifiers.constKeyword; | |
| 4593 Token finalKeyword4 = modifiers.finalKeyword; | |
| 4594 Token varKeyword4 = modifiers.varKeyword; | |
| 4595 if (constKeyword6 != null) { | |
| 4596 if (finalKeyword4 != null) { | |
| 4597 reportError5(ParserErrorCode.CONST_AND_FINAL, finalKeyword4, []); | |
| 4598 } | |
| 4599 if (varKeyword4 != null) { | |
| 4600 reportError5(ParserErrorCode.CONST_AND_VAR, varKeyword4, []); | |
| 4601 } | |
| 4602 } else if (finalKeyword4 != null) { | |
| 4603 if (varKeyword4 != null) { | |
| 4604 reportError5(ParserErrorCode.FINAL_AND_VAR, varKeyword4, []); | |
| 4605 } | |
| 4606 } | |
| 4607 return lexicallyFirst([constKeyword6, finalKeyword4, varKeyword4]); | |
| 4608 } | |
| 4609 /** | |
| 4610 * Validate that the given set of modifiers is appropriate for a class and ret
urn the 'abstract' | |
| 4611 * keyword if there is one. | |
| 4612 * @param modifiers the modifiers being validated | |
| 4613 */ | |
| 4614 void validateModifiersForTypedef(Modifiers modifiers) { | |
| 4615 validateModifiersForTopLevelDeclaration(modifiers); | |
| 4616 if (modifiers.abstractKeyword != null) { | |
| 4617 reportError5(ParserErrorCode.ABSTRACT_TYPEDEF, modifiers.abstractKeyword,
[]); | |
| 4618 } | |
| 4619 if (modifiers.constKeyword != null) { | |
| 4620 reportError5(ParserErrorCode.CONST_TYPEDEF, modifiers.constKeyword, []); | |
| 4621 } | |
| 4622 if (modifiers.externalKeyword != null) { | |
| 4623 reportError5(ParserErrorCode.EXTERNAL_TYPEDEF, modifiers.externalKeyword,
[]); | |
| 4624 } | |
| 4625 if (modifiers.finalKeyword != null) { | |
| 4626 reportError5(ParserErrorCode.FINAL_TYPEDEF, modifiers.finalKeyword, []); | |
| 4627 } | |
| 4628 if (modifiers.varKeyword != null) { | |
| 4629 reportError5(ParserErrorCode.VAR_TYPEDEF, modifiers.varKeyword, []); | |
| 4630 } | |
| 4631 } | |
| 4632 } | |
| 4633 class AnalysisErrorListener_7 implements AnalysisErrorListener { | |
| 4634 List<bool> errorFound; | |
| 4635 AnalysisErrorListener_7(this.errorFound); | |
| 4636 void onError(AnalysisError error) { | |
| 4637 errorFound[0] = true; | |
| 4638 } | |
| 4639 } | |
| 4640 /** | |
| 4641 * The enumeration {@code ParserErrorCode} defines the error codes used for erro
rs detected by the | |
| 4642 * parser. The convention for this class is for the name of the error code to in
dicate the problem | |
| 4643 * that caused the error to be generated and for the error message to explain wh
at is wrong and, | |
| 4644 * when appropriate, how the problem can be corrected. | |
| 4645 * @coverage dart.engine.parser | |
| 4646 */ | |
| 4647 class ParserErrorCode implements ErrorCode { | |
| 4648 static final ParserErrorCode ABSTRACT_CLASS_MEMBER = new ParserErrorCode.con2(
'ABSTRACT_CLASS_MEMBER', 0, "Members of classes cannot be declared to be 'abstra
ct'"); | |
| 4649 static final ParserErrorCode ABSTRACT_STATIC_METHOD = new ParserErrorCode.con2
('ABSTRACT_STATIC_METHOD', 1, "Static methods cannot be declared to be 'abstract
'"); | |
| 4650 static final ParserErrorCode ABSTRACT_TOP_LEVEL_FUNCTION = new ParserErrorCode
.con2('ABSTRACT_TOP_LEVEL_FUNCTION', 2, "Top-level functions cannot be declared
to be 'abstract'"); | |
| 4651 static final ParserErrorCode ABSTRACT_TOP_LEVEL_VARIABLE = new ParserErrorCode
.con2('ABSTRACT_TOP_LEVEL_VARIABLE', 3, "Top-level variables cannot be declared
to be 'abstract'"); | |
| 4652 static final ParserErrorCode ABSTRACT_TYPEDEF = new ParserErrorCode.con2('ABST
RACT_TYPEDEF', 4, "Type aliases cannot be declared to be 'abstract'"); | |
| 4653 static final ParserErrorCode BREAK_OUTSIDE_OF_LOOP = new ParserErrorCode.con2(
'BREAK_OUTSIDE_OF_LOOP', 5, "A break statement cannot be used outside of a loop
or switch statement"); | |
| 4654 static final ParserErrorCode CONST_AND_FINAL = new ParserErrorCode.con2('CONST
_AND_FINAL', 6, "Members cannot be declared to be both 'const' and 'final'"); | |
| 4655 static final ParserErrorCode CONST_AND_VAR = new ParserErrorCode.con2('CONST_A
ND_VAR', 7, "Members cannot be declared to be both 'const' and 'var'"); | |
| 4656 static final ParserErrorCode CONST_CLASS = new ParserErrorCode.con2('CONST_CLA
SS', 8, "Classes cannot be declared to be 'const'"); | |
| 4657 static final ParserErrorCode CONST_METHOD = new ParserErrorCode.con2('CONST_ME
THOD', 9, "Getters, setters and methods cannot be declared to be 'const'"); | |
| 4658 static final ParserErrorCode CONST_TYPEDEF = new ParserErrorCode.con2('CONST_T
YPEDEF', 10, "Type aliases cannot be declared to be 'const'"); | |
| 4659 static final ParserErrorCode CONSTRUCTOR_WITH_RETURN_TYPE = new ParserErrorCod
e.con2('CONSTRUCTOR_WITH_RETURN_TYPE', 11, "Constructors cannot have a return ty
pe"); | |
| 4660 static final ParserErrorCode CONTINUE_OUTSIDE_OF_LOOP = new ParserErrorCode.co
n2('CONTINUE_OUTSIDE_OF_LOOP', 12, "A continue statement cannot be used outside
of a loop or switch statement"); | |
| 4661 static final ParserErrorCode CONTINUE_WITHOUT_LABEL_IN_CASE = new ParserErrorC
ode.con2('CONTINUE_WITHOUT_LABEL_IN_CASE', 13, "A continue statement in a switch
statement must have a label as a target"); | |
| 4662 static final ParserErrorCode DIRECTIVE_AFTER_DECLARATION = new ParserErrorCode
.con2('DIRECTIVE_AFTER_DECLARATION', 14, "Directives must appear before any decl
arations"); | |
| 4663 static final ParserErrorCode DUPLICATE_LABEL_IN_SWITCH_STATEMENT = new ParserE
rrorCode.con2('DUPLICATE_LABEL_IN_SWITCH_STATEMENT', 15, "The label %s was alrea
dy used in this switch statement"); | |
| 4664 static final ParserErrorCode DUPLICATED_MODIFIER = new ParserErrorCode.con2('D
UPLICATED_MODIFIER', 16, "The modifier '%s' was already specified."); | |
| 4665 static final ParserErrorCode EXPECTED_CASE_OR_DEFAULT = new ParserErrorCode.co
n2('EXPECTED_CASE_OR_DEFAULT', 17, "Expected 'case' or 'default'"); | |
| 4666 static final ParserErrorCode EXPECTED_LIST_OR_MAP_LITERAL = new ParserErrorCod
e.con2('EXPECTED_LIST_OR_MAP_LITERAL', 18, "Expected a list or map literal"); | |
| 4667 static final ParserErrorCode EXPECTED_STRING_LITERAL = new ParserErrorCode.con
2('EXPECTED_STRING_LITERAL', 19, "Expected a string literal"); | |
| 4668 static final ParserErrorCode EXPECTED_TOKEN = new ParserErrorCode.con2('EXPECT
ED_TOKEN', 20, "Expected to find: %s"); | |
| 4669 static final ParserErrorCode EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE = new Parse
rErrorCode.con2('EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE', 21, "Export directives
must preceed part directives"); | |
| 4670 static final ParserErrorCode EXTERNAL_AFTER_CONST = new ParserErrorCode.con2('
EXTERNAL_AFTER_CONST', 22, "The modifier 'external' should be before the modifie
r 'const'"); | |
| 4671 static final ParserErrorCode EXTERNAL_AFTER_FACTORY = new ParserErrorCode.con2
('EXTERNAL_AFTER_FACTORY', 23, "The modifier 'external' should be before the mod
ifier 'factory'"); | |
| 4672 static final ParserErrorCode EXTERNAL_AFTER_STATIC = new ParserErrorCode.con2(
'EXTERNAL_AFTER_STATIC', 24, "The modifier 'external' should be before the modif
ier 'static'"); | |
| 4673 static final ParserErrorCode EXTERNAL_CLASS = new ParserErrorCode.con2('EXTERN
AL_CLASS', 25, "Classes cannot be declared to be 'external'"); | |
| 4674 static final ParserErrorCode EXTERNAL_CONSTRUCTOR_WITH_BODY = new ParserErrorC
ode.con2('EXTERNAL_CONSTRUCTOR_WITH_BODY', 26, "External constructors cannot hav
e a body"); | |
| 4675 static final ParserErrorCode EXTERNAL_FIELD = new ParserErrorCode.con2('EXTERN
AL_FIELD', 27, "Fields cannot be declared to be 'external'"); | |
| 4676 static final ParserErrorCode EXTERNAL_GETTER_WITH_BODY = new ParserErrorCode.c
on2('EXTERNAL_GETTER_WITH_BODY', 28, "External getters cannot have a body"); | |
| 4677 static final ParserErrorCode EXTERNAL_METHOD_WITH_BODY = new ParserErrorCode.c
on2('EXTERNAL_METHOD_WITH_BODY', 29, "External methods cannot have a body"); | |
| 4678 static final ParserErrorCode EXTERNAL_OPERATOR_WITH_BODY = new ParserErrorCode
.con2('EXTERNAL_OPERATOR_WITH_BODY', 30, "External operators cannot have a body"
); | |
| 4679 static final ParserErrorCode EXTERNAL_SETTER_WITH_BODY = new ParserErrorCode.c
on2('EXTERNAL_SETTER_WITH_BODY', 31, "External setters cannot have a body"); | |
| 4680 static final ParserErrorCode EXTERNAL_TYPEDEF = new ParserErrorCode.con2('EXTE
RNAL_TYPEDEF', 32, "Type aliases cannot be declared to be 'external'"); | |
| 4681 static final ParserErrorCode FACTORY_TOP_LEVEL_DECLARATION = new ParserErrorCo
de.con2('FACTORY_TOP_LEVEL_DECLARATION', 33, "Top-level declarations cannot be d
eclared to be 'factory'"); | |
| 4682 static final ParserErrorCode FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR = new Parse
rErrorCode.con2('FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR', 34, "Field initializers
can only be used in a constructor"); | |
| 4683 static final ParserErrorCode FINAL_AND_VAR = new ParserErrorCode.con2('FINAL_A
ND_VAR', 35, "Members cannot be declared to be both 'final' and 'var'"); | |
| 4684 static final ParserErrorCode FINAL_CLASS = new ParserErrorCode.con2('FINAL_CLA
SS', 36, "Classes cannot be declared to be 'final'"); | |
| 4685 static final ParserErrorCode FINAL_CONSTRUCTOR = new ParserErrorCode.con2('FIN
AL_CONSTRUCTOR', 37, "A constructor cannot be declared to be 'final'"); | |
| 4686 static final ParserErrorCode FINAL_METHOD = new ParserErrorCode.con2('FINAL_ME
THOD', 38, "Getters, setters and methods cannot be declared to be 'final'"); | |
| 4687 static final ParserErrorCode FINAL_TYPEDEF = new ParserErrorCode.con2('FINAL_T
YPEDEF', 39, "Type aliases cannot be declared to be 'final'"); | |
| 4688 static final ParserErrorCode GETTER_WITH_PARAMETERS = new ParserErrorCode.con2
('GETTER_WITH_PARAMETERS', 40, "Getter should be declared without a parameter li
st"); | |
| 4689 static final ParserErrorCode ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE = new Parser
ErrorCode.con2('ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE', 41, "Illegal assignment t
o non-assignable expression"); | |
| 4690 static final ParserErrorCode IMPLEMENTS_BEFORE_EXTENDS = new ParserErrorCode.c
on2('IMPLEMENTS_BEFORE_EXTENDS', 42, "The extends clause must be before the impl
ements clause"); | |
| 4691 static final ParserErrorCode IMPLEMENTS_BEFORE_WITH = new ParserErrorCode.con2
('IMPLEMENTS_BEFORE_WITH', 43, "The with clause must be before the implements cl
ause"); | |
| 4692 static final ParserErrorCode IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE = new Parse
rErrorCode.con2('IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE', 44, "Import directives
must preceed part directives"); | |
| 4693 static final ParserErrorCode INITIALIZED_VARIABLE_IN_FOR_EACH = new ParserErro
rCode.con2('INITIALIZED_VARIABLE_IN_FOR_EACH', 45, "The loop variable in a for-e
ach loop cannot be initialized"); | |
| 4694 static final ParserErrorCode INVALID_CODE_POINT = new ParserErrorCode.con2('IN
VALID_CODE_POINT', 46, "The escape sequence '%s' is not a valid code point"); | |
| 4695 static final ParserErrorCode INVALID_COMMENT_REFERENCE = new ParserErrorCode.c
on2('INVALID_COMMENT_REFERENCE', 47, "Comment references should contain a possib
ly prefixed identifier and can start with 'new', but should not contain anything
else"); | |
| 4696 static final ParserErrorCode INVALID_HEX_ESCAPE = new ParserErrorCode.con2('IN
VALID_HEX_ESCAPE', 48, "An escape sequence starting with '\\x' must be followed
by 2 hexidecimal digits"); | |
| 4697 static final ParserErrorCode INVALID_OPERATOR_FOR_SUPER = new ParserErrorCode.
con2('INVALID_OPERATOR_FOR_SUPER', 49, "The operator '%s' cannot be used with 's
uper'"); | |
| 4698 static final ParserErrorCode INVALID_UNICODE_ESCAPE = new ParserErrorCode.con2
('INVALID_UNICODE_ESCAPE', 50, "An escape sequence starting with '\\u' must be f
ollowed by 4 hexidecimal digits or from 1 to 6 digits between '{' and '}'"); | |
| 4699 static final ParserErrorCode LIBRARY_DIRECTIVE_NOT_FIRST = new ParserErrorCode
.con2('LIBRARY_DIRECTIVE_NOT_FIRST', 51, "The library directive must appear befo
re all other directives"); | |
| 4700 static final ParserErrorCode MISSING_ASSIGNABLE_SELECTOR = new ParserErrorCode
.con2('MISSING_ASSIGNABLE_SELECTOR', 52, "Missing selector such as \".<identifie
r>\" or \"[0]\""); | |
| 4701 static final ParserErrorCode MISSING_CATCH_OR_FINALLY = new ParserErrorCode.co
n2('MISSING_CATCH_OR_FINALLY', 53, "A try statement must have either a catch or
finally clause"); | |
| 4702 static final ParserErrorCode MISSING_CLASS_BODY = new ParserErrorCode.con2('MI
SSING_CLASS_BODY', 54, "A class definition must have a body, even if it is empty
"); | |
| 4703 static final ParserErrorCode MISSING_CONST_FINAL_VAR_OR_TYPE = new ParserError
Code.con2('MISSING_CONST_FINAL_VAR_OR_TYPE', 55, "Variables must be declared usi
ng the keywords 'const', 'final', 'var' or a type name"); | |
| 4704 static final ParserErrorCode MISSING_FUNCTION_BODY = new ParserErrorCode.con2(
'MISSING_FUNCTION_BODY', 56, "A function body must be provided"); | |
| 4705 static final ParserErrorCode MISSING_FUNCTION_PARAMETERS = new ParserErrorCode
.con2('MISSING_FUNCTION_PARAMETERS', 57, "Functions must have an explicit list o
f parameters"); | |
| 4706 static final ParserErrorCode MISSING_IDENTIFIER = new ParserErrorCode.con2('MI
SSING_IDENTIFIER', 58, "Expected an identifier"); | |
| 4707 static final ParserErrorCode MISSING_NAME_IN_LIBRARY_DIRECTIVE = new ParserErr
orCode.con2('MISSING_NAME_IN_LIBRARY_DIRECTIVE', 59, "Library directives must in
clude a library name"); | |
| 4708 static final ParserErrorCode MISSING_NAME_IN_PART_OF_DIRECTIVE = new ParserErr
orCode.con2('MISSING_NAME_IN_PART_OF_DIRECTIVE', 60, "Library directives must in
clude a library name"); | |
| 4709 static final ParserErrorCode MISSING_TERMINATOR_FOR_PARAMETER_GROUP = new Pars
erErrorCode.con2('MISSING_TERMINATOR_FOR_PARAMETER_GROUP', 61, "There is no '%s'
to close the parameter group"); | |
| 4710 static final ParserErrorCode MISSING_TYPEDEF_PARAMETERS = new ParserErrorCode.
con2('MISSING_TYPEDEF_PARAMETERS', 62, "Type aliases for functions must have an
explicit list of parameters"); | |
| 4711 static final ParserErrorCode MISSING_VARIABLE_IN_FOR_EACH = new ParserErrorCod
e.con2('MISSING_VARIABLE_IN_FOR_EACH', 63, "A loop variable must be declared in
a for-each loop before the 'in', but none were found"); | |
| 4712 static final ParserErrorCode MIXED_PARAMETER_GROUPS = new ParserErrorCode.con2
('MIXED_PARAMETER_GROUPS', 64, "Cannot have both positional and named parameters
in a single parameter list"); | |
| 4713 static final ParserErrorCode MULTIPLE_EXTENDS_CLAUSES = new ParserErrorCode.co
n2('MULTIPLE_EXTENDS_CLAUSES', 65, "Each class definition can have at most one e
xtends clause"); | |
| 4714 static final ParserErrorCode MULTIPLE_IMPLEMENTS_CLAUSES = new ParserErrorCode
.con2('MULTIPLE_IMPLEMENTS_CLAUSES', 66, "Each class definition can have at most
one implements clause"); | |
| 4715 static final ParserErrorCode MULTIPLE_LIBRARY_DIRECTIVES = new ParserErrorCode
.con2('MULTIPLE_LIBRARY_DIRECTIVES', 67, "Only one library directive may be decl
ared in a file"); | |
| 4716 static final ParserErrorCode MULTIPLE_NAMED_PARAMETER_GROUPS = new ParserError
Code.con2('MULTIPLE_NAMED_PARAMETER_GROUPS', 68, "Cannot have multiple groups of
named parameters in a single parameter list"); | |
| 4717 static final ParserErrorCode MULTIPLE_PART_OF_DIRECTIVES = new ParserErrorCode
.con2('MULTIPLE_PART_OF_DIRECTIVES', 69, "Only one part-of directive may be decl
ared in a file"); | |
| 4718 static final ParserErrorCode MULTIPLE_POSITIONAL_PARAMETER_GROUPS = new Parser
ErrorCode.con2('MULTIPLE_POSITIONAL_PARAMETER_GROUPS', 70, "Cannot have multiple
groups of positional parameters in a single parameter list"); | |
| 4719 static final ParserErrorCode MULTIPLE_VARIABLES_IN_FOR_EACH = new ParserErrorC
ode.con2('MULTIPLE_VARIABLES_IN_FOR_EACH', 71, "A single loop variable must be d
eclared in a for-each loop before the 'in', but %s were found"); | |
| 4720 static final ParserErrorCode MULTIPLE_WITH_CLAUSES = new ParserErrorCode.con2(
'MULTIPLE_WITH_CLAUSES', 72, "Each class definition can have at most one with cl
ause"); | |
| 4721 static final ParserErrorCode NAMED_PARAMETER_OUTSIDE_GROUP = new ParserErrorCo
de.con2('NAMED_PARAMETER_OUTSIDE_GROUP', 73, "Named parameters must be enclosed
in curly braces ('{' and '}')"); | |
| 4722 static final ParserErrorCode NON_CONSTRUCTOR_FACTORY = new ParserErrorCode.con
2('NON_CONSTRUCTOR_FACTORY', 74, "Only constructors can be declared to be a 'fac
tory'"); | |
| 4723 static final ParserErrorCode NON_IDENTIFIER_LIBRARY_NAME = new ParserErrorCode
.con2('NON_IDENTIFIER_LIBRARY_NAME', 75, "The name of a library must be an ident
ifier"); | |
| 4724 static final ParserErrorCode NON_PART_OF_DIRECTIVE_IN_PART = new ParserErrorCo
de.con2('NON_PART_OF_DIRECTIVE_IN_PART', 76, "The part-of directive must be the
only directive in a part"); | |
| 4725 static final ParserErrorCode NON_USER_DEFINABLE_OPERATOR = new ParserErrorCode
.con2('NON_USER_DEFINABLE_OPERATOR', 77, "The operator '%s' is not user definabl
e"); | |
| 4726 static final ParserErrorCode POSITIONAL_AFTER_NAMED_ARGUMENT = new ParserError
Code.con2('POSITIONAL_AFTER_NAMED_ARGUMENT', 78, "Positional arguments must occu
r before named arguments"); | |
| 4727 static final ParserErrorCode POSITIONAL_PARAMETER_OUTSIDE_GROUP = new ParserEr
rorCode.con2('POSITIONAL_PARAMETER_OUTSIDE_GROUP', 79, "Positional parameters mu
st be enclosed in square brackets ('[' and ']')"); | |
| 4728 static final ParserErrorCode STATIC_AFTER_CONST = new ParserErrorCode.con2('ST
ATIC_AFTER_CONST', 80, "The modifier 'static' should be before the modifier 'con
st'"); | |
| 4729 static final ParserErrorCode STATIC_AFTER_FINAL = new ParserErrorCode.con2('ST
ATIC_AFTER_FINAL', 81, "The modifier 'static' should be before the modifier 'fin
al'"); | |
| 4730 static final ParserErrorCode STATIC_AFTER_VAR = new ParserErrorCode.con2('STAT
IC_AFTER_VAR', 82, "The modifier 'static' should be before the modifier 'var'"); | |
| 4731 static final ParserErrorCode STATIC_CONSTRUCTOR = new ParserErrorCode.con2('ST
ATIC_CONSTRUCTOR', 83, "Constructors cannot be static"); | |
| 4732 static final ParserErrorCode STATIC_OPERATOR = new ParserErrorCode.con2('STATI
C_OPERATOR', 84, "Operators cannot be static"); | |
| 4733 static final ParserErrorCode STATIC_TOP_LEVEL_DECLARATION = new ParserErrorCod
e.con2('STATIC_TOP_LEVEL_DECLARATION', 85, "Top-level declarations cannot be dec
lared to be 'static'"); | |
| 4734 static final ParserErrorCode UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP = new P
arserErrorCode.con2('UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP', 86, "There is n
o '%s' to open a parameter group"); | |
| 4735 static final ParserErrorCode UNEXPECTED_TOKEN = new ParserErrorCode.con2('UNEX
PECTED_TOKEN', 87, "Unexpected token '%s'"); | |
| 4736 static final ParserErrorCode USE_OF_UNARY_PLUS_OPERATOR = new ParserErrorCode.
con2('USE_OF_UNARY_PLUS_OPERATOR', 88, "There is no unary plus operator in Dart"
); | |
| 4737 static final ParserErrorCode WITH_BEFORE_EXTENDS = new ParserErrorCode.con2('W
ITH_BEFORE_EXTENDS', 89, "The extends clause must be before the with clause"); | |
| 4738 static final ParserErrorCode WITH_WITHOUT_EXTENDS = new ParserErrorCode.con2('
WITH_WITHOUT_EXTENDS', 90, "The with clause cannot be used without an extends cl
ause"); | |
| 4739 static final ParserErrorCode WRONG_SEPARATOR_FOR_NAMED_PARAMETER = new ParserE
rrorCode.con2('WRONG_SEPARATOR_FOR_NAMED_PARAMETER', 91, "The default value of a
named parameter should be preceeded by ':'"); | |
| 4740 static final ParserErrorCode WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER = new Pa
rserErrorCode.con2('WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER', 92, "The default
value of a positional parameter should be preceeded by '='"); | |
| 4741 static final ParserErrorCode WRONG_TERMINATOR_FOR_PARAMETER_GROUP = new Parser
ErrorCode.con2('WRONG_TERMINATOR_FOR_PARAMETER_GROUP', 93, "Expected '%s' to clo
se parameter group"); | |
| 4742 static final ParserErrorCode VAR_CLASS = new ParserErrorCode.con2('VAR_CLASS',
94, "Classes cannot be declared to be 'var'"); | |
| 4743 static final ParserErrorCode VAR_RETURN_TYPE = new ParserErrorCode.con2('VAR_R
ETURN_TYPE', 95, "The return type cannot be 'var'"); | |
| 4744 static final ParserErrorCode VAR_TYPEDEF = new ParserErrorCode.con2('VAR_TYPED
EF', 96, "Type aliases cannot be declared to be 'var'"); | |
| 4745 static final ParserErrorCode VOID_PARAMETER = new ParserErrorCode.con2('VOID_P
ARAMETER', 97, "Parameters cannot have a type of 'void'"); | |
| 4746 static final ParserErrorCode VOID_VARIABLE = new ParserErrorCode.con2('VOID_VA
RIABLE', 98, "Variables cannot have a type of 'void'"); | |
| 4747 static final List<ParserErrorCode> values = [ABSTRACT_CLASS_MEMBER, ABSTRACT_S
TATIC_METHOD, ABSTRACT_TOP_LEVEL_FUNCTION, ABSTRACT_TOP_LEVEL_VARIABLE, ABSTRACT
_TYPEDEF, BREAK_OUTSIDE_OF_LOOP, CONST_AND_FINAL, CONST_AND_VAR, CONST_CLASS, CO
NST_METHOD, CONST_TYPEDEF, CONSTRUCTOR_WITH_RETURN_TYPE, CONTINUE_OUTSIDE_OF_LOO
P, CONTINUE_WITHOUT_LABEL_IN_CASE, DIRECTIVE_AFTER_DECLARATION, DUPLICATE_LABEL_
IN_SWITCH_STATEMENT, DUPLICATED_MODIFIER, EXPECTED_CASE_OR_DEFAULT, EXPECTED_LIS
T_OR_MAP_LITERAL, EXPECTED_STRING_LITERAL, EXPECTED_TOKEN, EXPORT_DIRECTIVE_AFTE
R_PART_DIRECTIVE, EXTERNAL_AFTER_CONST, EXTERNAL_AFTER_FACTORY, EXTERNAL_AFTER_S
TATIC, EXTERNAL_CLASS, EXTERNAL_CONSTRUCTOR_WITH_BODY, EXTERNAL_FIELD, EXTERNAL_
GETTER_WITH_BODY, EXTERNAL_METHOD_WITH_BODY, EXTERNAL_OPERATOR_WITH_BODY, EXTERN
AL_SETTER_WITH_BODY, EXTERNAL_TYPEDEF, FACTORY_TOP_LEVEL_DECLARATION, FIELD_INIT
IALIZER_OUTSIDE_CONSTRUCTOR, FINAL_AND_VAR, FINAL_CLASS, FINAL_CONSTRUCTOR, FINA
L_METHOD, FINAL_TYPEDEF, GETTER_WITH_PARAMETERS, ILLEGAL_ASSIGNMENT_TO_NON_ASSIG
NABLE, IMPLEMENTS_BEFORE_EXTENDS, IMPLEMENTS_BEFORE_WITH, IMPORT_DIRECTIVE_AFTER
_PART_DIRECTIVE, INITIALIZED_VARIABLE_IN_FOR_EACH, INVALID_CODE_POINT, INVALID_C
OMMENT_REFERENCE, INVALID_HEX_ESCAPE, INVALID_OPERATOR_FOR_SUPER, INVALID_UNICOD
E_ESCAPE, LIBRARY_DIRECTIVE_NOT_FIRST, MISSING_ASSIGNABLE_SELECTOR, MISSING_CATC
H_OR_FINALLY, MISSING_CLASS_BODY, MISSING_CONST_FINAL_VAR_OR_TYPE, MISSING_FUNCT
ION_BODY, MISSING_FUNCTION_PARAMETERS, MISSING_IDENTIFIER, MISSING_NAME_IN_LIBRA
RY_DIRECTIVE, MISSING_NAME_IN_PART_OF_DIRECTIVE, MISSING_TERMINATOR_FOR_PARAMETE
R_GROUP, MISSING_TYPEDEF_PARAMETERS, MISSING_VARIABLE_IN_FOR_EACH, MIXED_PARAMET
ER_GROUPS, MULTIPLE_EXTENDS_CLAUSES, MULTIPLE_IMPLEMENTS_CLAUSES, MULTIPLE_LIBRA
RY_DIRECTIVES, MULTIPLE_NAMED_PARAMETER_GROUPS, MULTIPLE_PART_OF_DIRECTIVES, MUL
TIPLE_POSITIONAL_PARAMETER_GROUPS, MULTIPLE_VARIABLES_IN_FOR_EACH, MULTIPLE_WITH
_CLAUSES, NAMED_PARAMETER_OUTSIDE_GROUP, NON_CONSTRUCTOR_FACTORY, NON_IDENTIFIER
_LIBRARY_NAME, NON_PART_OF_DIRECTIVE_IN_PART, NON_USER_DEFINABLE_OPERATOR, POSIT
IONAL_AFTER_NAMED_ARGUMENT, POSITIONAL_PARAMETER_OUTSIDE_GROUP, STATIC_AFTER_CON
ST, STATIC_AFTER_FINAL, STATIC_AFTER_VAR, STATIC_CONSTRUCTOR, STATIC_OPERATOR, S
TATIC_TOP_LEVEL_DECLARATION, UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP, UNEXPECT
ED_TOKEN, USE_OF_UNARY_PLUS_OPERATOR, WITH_BEFORE_EXTENDS, WITH_WITHOUT_EXTENDS,
WRONG_SEPARATOR_FOR_NAMED_PARAMETER, WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER,
WRONG_TERMINATOR_FOR_PARAMETER_GROUP, VAR_CLASS, VAR_RETURN_TYPE, VAR_TYPEDEF, V
OID_PARAMETER, VOID_VARIABLE]; | |
| 4748 String __name; | |
| 4749 int __ordinal = 0; | |
| 4750 int get ordinal => __ordinal; | |
| 4751 /** | |
| 4752 * The severity of this error. | |
| 4753 */ | |
| 4754 ErrorSeverity _severity; | |
| 4755 /** | |
| 4756 * The message template used to create the message to be displayed for this er
ror. | |
| 4757 */ | |
| 4758 String _message; | |
| 4759 /** | |
| 4760 * Initialize a newly created error code to have the given severity and messag
e. | |
| 4761 * @param severity the severity of the error | |
| 4762 * @param message the message template used to create the message to be displa
yed for the error | |
| 4763 */ | |
| 4764 ParserErrorCode.con1(String ___name, int ___ordinal, ErrorSeverity severity2,
String message2) { | |
| 4765 _jtd_constructor_258_impl(___name, ___ordinal, severity2, message2); | |
| 4766 } | |
| 4767 _jtd_constructor_258_impl(String ___name, int ___ordinal, ErrorSeverity severi
ty2, String message2) { | |
| 4768 __name = ___name; | |
| 4769 __ordinal = ___ordinal; | |
| 4770 this._severity = severity2; | |
| 4771 this._message = message2; | |
| 4772 } | |
| 4773 /** | |
| 4774 * Initialize a newly created error code to have the given message and a sever
ity of ERROR. | |
| 4775 * @param message the message template used to create the message to be displa
yed for the error | |
| 4776 */ | |
| 4777 ParserErrorCode.con2(String ___name, int ___ordinal, String message) { | |
| 4778 _jtd_constructor_259_impl(___name, ___ordinal, message); | |
| 4779 } | |
| 4780 _jtd_constructor_259_impl(String ___name, int ___ordinal, String message) { | |
| 4781 _jtd_constructor_258_impl(___name, ___ordinal, ErrorSeverity.ERROR, message)
; | |
| 4782 } | |
| 4783 ErrorSeverity get errorSeverity => _severity; | |
| 4784 String get message => _message; | |
| 4785 ErrorType get type => ErrorType.SYNTACTIC_ERROR; | |
| 4786 bool needsRecompilation() => true; | |
| 4787 String toString() => __name; | |
| 4788 } | |
| 4789 /** | |
| 4790 * Instances of the class {link ToFormattedSourceVisitor} write a source represe
ntation of a visited | |
| 4791 * AST node (and all of it's children) to a writer. | |
| 4792 */ | |
| 4793 class ToFormattedSourceVisitor implements ASTVisitor<Object> { | |
| 4794 /** | |
| 4795 * The writer to which the source is to be written. | |
| 4796 */ | |
| 4797 PrintWriter _writer; | |
| 4798 int _indentLevel = 0; | |
| 4799 String _indentString = ""; | |
| 4800 /** | |
| 4801 * Initialize a newly created visitor to write source code representing the vi
sited nodes to the | |
| 4802 * given writer. | |
| 4803 * @param writer the writer to which the source is to be written | |
| 4804 */ | |
| 4805 ToFormattedSourceVisitor(PrintWriter writer) { | |
| 4806 this._writer = writer; | |
| 4807 } | |
| 4808 Object visitAdjacentStrings(AdjacentStrings node) { | |
| 4809 visitList5(node.strings, " "); | |
| 4810 return null; | |
| 4811 } | |
| 4812 Object visitAnnotation(Annotation node) { | |
| 4813 _writer.print('@'); | |
| 4814 visit(node.name); | |
| 4815 visit7(".", node.constructorName); | |
| 4816 visit(node.arguments); | |
| 4817 return null; | |
| 4818 } | |
| 4819 Object visitArgumentDefinitionTest(ArgumentDefinitionTest node) { | |
| 4820 _writer.print('?'); | |
| 4821 visit(node.identifier); | |
| 4822 return null; | |
| 4823 } | |
| 4824 Object visitArgumentList(ArgumentList node) { | |
| 4825 _writer.print('('); | |
| 4826 visitList5(node.arguments, ", "); | |
| 4827 _writer.print(')'); | |
| 4828 return null; | |
| 4829 } | |
| 4830 Object visitAsExpression(AsExpression node) { | |
| 4831 visit(node.expression); | |
| 4832 _writer.print(" as "); | |
| 4833 visit(node.type); | |
| 4834 return null; | |
| 4835 } | |
| 4836 Object visitAssertStatement(AssertStatement node) { | |
| 4837 _writer.print("assert("); | |
| 4838 visit(node.condition); | |
| 4839 _writer.print(");"); | |
| 4840 return null; | |
| 4841 } | |
| 4842 Object visitAssignmentExpression(AssignmentExpression node) { | |
| 4843 visit(node.leftHandSide); | |
| 4844 _writer.print(' '); | |
| 4845 _writer.print(node.operator.lexeme); | |
| 4846 _writer.print(' '); | |
| 4847 visit(node.rightHandSide); | |
| 4848 return null; | |
| 4849 } | |
| 4850 Object visitBinaryExpression(BinaryExpression node) { | |
| 4851 visit(node.leftOperand); | |
| 4852 _writer.print(' '); | |
| 4853 _writer.print(node.operator.lexeme); | |
| 4854 _writer.print(' '); | |
| 4855 visit(node.rightOperand); | |
| 4856 return null; | |
| 4857 } | |
| 4858 Object visitBlock(Block node) { | |
| 4859 _writer.print('{'); | |
| 4860 { | |
| 4861 indentInc(); | |
| 4862 visitList5(node.statements, "\n"); | |
| 4863 indentDec(); | |
| 4864 } | |
| 4865 nl2(); | |
| 4866 _writer.print('}'); | |
| 4867 return null; | |
| 4868 } | |
| 4869 Object visitBlockFunctionBody(BlockFunctionBody node) { | |
| 4870 visit(node.block); | |
| 4871 return null; | |
| 4872 } | |
| 4873 Object visitBooleanLiteral(BooleanLiteral node) { | |
| 4874 _writer.print(node.literal.lexeme); | |
| 4875 return null; | |
| 4876 } | |
| 4877 Object visitBreakStatement(BreakStatement node) { | |
| 4878 _writer.print("break"); | |
| 4879 visit7(" ", node.label); | |
| 4880 _writer.print(";"); | |
| 4881 return null; | |
| 4882 } | |
| 4883 Object visitCascadeExpression(CascadeExpression node) { | |
| 4884 visit(node.target); | |
| 4885 visitList(node.cascadeSections); | |
| 4886 return null; | |
| 4887 } | |
| 4888 Object visitCatchClause(CatchClause node) { | |
| 4889 visit7("on ", node.exceptionType); | |
| 4890 if (node.catchKeyword != null) { | |
| 4891 if (node.exceptionType != null) { | |
| 4892 _writer.print(' '); | |
| 4893 } | |
| 4894 _writer.print("catch ("); | |
| 4895 visit(node.exceptionParameter); | |
| 4896 visit7(", ", node.stackTraceParameter); | |
| 4897 _writer.print(") "); | |
| 4898 } else { | |
| 4899 _writer.print(" "); | |
| 4900 } | |
| 4901 visit(node.body); | |
| 4902 return null; | |
| 4903 } | |
| 4904 Object visitClassDeclaration(ClassDeclaration node) { | |
| 4905 visit(node.documentationComment); | |
| 4906 visit8(node.abstractKeyword, " "); | |
| 4907 _writer.print("class "); | |
| 4908 visit(node.name); | |
| 4909 visit(node.typeParameters); | |
| 4910 visit7(" ", node.extendsClause); | |
| 4911 visit7(" ", node.withClause); | |
| 4912 visit7(" ", node.implementsClause); | |
| 4913 _writer.print(" {"); | |
| 4914 { | |
| 4915 indentInc(); | |
| 4916 visitList5(node.members, "\n"); | |
| 4917 indentDec(); | |
| 4918 } | |
| 4919 nl2(); | |
| 4920 _writer.print("}"); | |
| 4921 return null; | |
| 4922 } | |
| 4923 Object visitClassTypeAlias(ClassTypeAlias node) { | |
| 4924 _writer.print("typedef "); | |
| 4925 visit(node.name); | |
| 4926 visit(node.typeParameters); | |
| 4927 _writer.print(" = "); | |
| 4928 if (node.abstractKeyword != null) { | |
| 4929 _writer.print("abstract "); | |
| 4930 } | |
| 4931 visit(node.superclass); | |
| 4932 visit7(" ", node.withClause); | |
| 4933 visit7(" ", node.implementsClause); | |
| 4934 _writer.print(";"); | |
| 4935 return null; | |
| 4936 } | |
| 4937 Object visitComment(Comment node) { | |
| 4938 Token token = node.beginToken; | |
| 4939 while (token != null) { | |
| 4940 bool firstLine = true; | |
| 4941 for (String line in StringUtils.split(token.lexeme, "\n")) { | |
| 4942 if (firstLine) { | |
| 4943 firstLine = false; | |
| 4944 } else { | |
| 4945 line = " ${line.trim()}"; | |
| 4946 line = StringUtils.replace(line, "/*", "/ *"); | |
| 4947 } | |
| 4948 _writer.print(line); | |
| 4949 nl2(); | |
| 4950 } | |
| 4951 if (identical(token, node.endToken)) { | |
| 4952 break; | |
| 4953 } | |
| 4954 } | |
| 4955 return null; | |
| 4956 } | |
| 4957 Object visitCommentReference(CommentReference node) => null; | |
| 4958 Object visitCompilationUnit(CompilationUnit node) { | |
| 4959 ScriptTag scriptTag7 = node.scriptTag; | |
| 4960 NodeList<Directive> directives4 = node.directives; | |
| 4961 visit(scriptTag7); | |
| 4962 String prefix = scriptTag7 == null ? "" : " "; | |
| 4963 visitList7(prefix, directives4, "\n"); | |
| 4964 prefix = scriptTag7 == null && directives4.isEmpty ? "" : "\n\n"; | |
| 4965 visitList7(prefix, node.declarations, "\n"); | |
| 4966 return null; | |
| 4967 } | |
| 4968 Object visitConditionalExpression(ConditionalExpression node) { | |
| 4969 visit(node.condition); | |
| 4970 _writer.print(" ? "); | |
| 4971 visit(node.thenExpression); | |
| 4972 _writer.print(" : "); | |
| 4973 visit(node.elseExpression); | |
| 4974 return null; | |
| 4975 } | |
| 4976 Object visitConstructorDeclaration(ConstructorDeclaration node) { | |
| 4977 visit(node.documentationComment); | |
| 4978 visit8(node.externalKeyword, " "); | |
| 4979 visit8(node.constKeyword, " "); | |
| 4980 visit8(node.factoryKeyword, " "); | |
| 4981 visit(node.returnType); | |
| 4982 visit7(".", node.name); | |
| 4983 visit(node.parameters); | |
| 4984 visitList7(" : ", node.initializers, ", "); | |
| 4985 visit7(" = ", node.redirectedConstructor); | |
| 4986 if (node.body is! EmptyFunctionBody) { | |
| 4987 _writer.print(' '); | |
| 4988 } | |
| 4989 visit(node.body); | |
| 4990 return null; | |
| 4991 } | |
| 4992 Object visitConstructorFieldInitializer(ConstructorFieldInitializer node) { | |
| 4993 visit8(node.keyword, "."); | |
| 4994 visit(node.fieldName); | |
| 4995 _writer.print(" = "); | |
| 4996 visit(node.expression); | |
| 4997 return null; | |
| 4998 } | |
| 4999 Object visitConstructorName(ConstructorName node) { | |
| 5000 visit(node.type); | |
| 5001 visit7(".", node.name); | |
| 5002 return null; | |
| 5003 } | |
| 5004 Object visitContinueStatement(ContinueStatement node) { | |
| 5005 _writer.print("continue"); | |
| 5006 visit7(" ", node.label); | |
| 5007 _writer.print(";"); | |
| 5008 return null; | |
| 5009 } | |
| 5010 Object visitDeclaredIdentifier(DeclaredIdentifier node) { | |
| 5011 visit8(node.keyword, " "); | |
| 5012 visit6(node.type, " "); | |
| 5013 visit(node.identifier); | |
| 5014 return null; | |
| 5015 } | |
| 5016 Object visitDefaultFormalParameter(DefaultFormalParameter node) { | |
| 5017 visit(node.parameter); | |
| 5018 if (node.separator != null) { | |
| 5019 _writer.print(" "); | |
| 5020 _writer.print(node.separator.lexeme); | |
| 5021 visit7(" ", node.defaultValue); | |
| 5022 } | |
| 5023 return null; | |
| 5024 } | |
| 5025 Object visitDoStatement(DoStatement node) { | |
| 5026 _writer.print("do "); | |
| 5027 visit(node.body); | |
| 5028 _writer.print(" while ("); | |
| 5029 visit(node.condition); | |
| 5030 _writer.print(");"); | |
| 5031 return null; | |
| 5032 } | |
| 5033 Object visitDoubleLiteral(DoubleLiteral node) { | |
| 5034 _writer.print(node.literal.lexeme); | |
| 5035 return null; | |
| 5036 } | |
| 5037 Object visitEmptyFunctionBody(EmptyFunctionBody node) { | |
| 5038 _writer.print(';'); | |
| 5039 return null; | |
| 5040 } | |
| 5041 Object visitEmptyStatement(EmptyStatement node) { | |
| 5042 _writer.print(';'); | |
| 5043 return null; | |
| 5044 } | |
| 5045 Object visitExportDirective(ExportDirective node) { | |
| 5046 _writer.print("export "); | |
| 5047 visit(node.uri); | |
| 5048 visitList7(" ", node.combinators, " "); | |
| 5049 _writer.print(';'); | |
| 5050 return null; | |
| 5051 } | |
| 5052 Object visitExpressionFunctionBody(ExpressionFunctionBody node) { | |
| 5053 _writer.print("=> "); | |
| 5054 visit(node.expression); | |
| 5055 if (node.semicolon != null) { | |
| 5056 _writer.print(';'); | |
| 5057 } | |
| 5058 return null; | |
| 5059 } | |
| 5060 Object visitExpressionStatement(ExpressionStatement node) { | |
| 5061 visit(node.expression); | |
| 5062 _writer.print(';'); | |
| 5063 return null; | |
| 5064 } | |
| 5065 Object visitExtendsClause(ExtendsClause node) { | |
| 5066 _writer.print("extends "); | |
| 5067 visit(node.superclass); | |
| 5068 return null; | |
| 5069 } | |
| 5070 Object visitFieldDeclaration(FieldDeclaration node) { | |
| 5071 visit(node.documentationComment); | |
| 5072 visit8(node.keyword, " "); | |
| 5073 visit(node.fields); | |
| 5074 _writer.print(";"); | |
| 5075 return null; | |
| 5076 } | |
| 5077 Object visitFieldFormalParameter(FieldFormalParameter node) { | |
| 5078 visit8(node.keyword, " "); | |
| 5079 visit6(node.type, " "); | |
| 5080 _writer.print("this."); | |
| 5081 visit(node.identifier); | |
| 5082 return null; | |
| 5083 } | |
| 5084 Object visitForEachStatement(ForEachStatement node) { | |
| 5085 _writer.print("for ("); | |
| 5086 visit(node.loopVariable); | |
| 5087 _writer.print(" in "); | |
| 5088 visit(node.iterator); | |
| 5089 _writer.print(") "); | |
| 5090 visit(node.body); | |
| 5091 return null; | |
| 5092 } | |
| 5093 Object visitFormalParameterList(FormalParameterList node) { | |
| 5094 String groupEnd = null; | |
| 5095 _writer.print('('); | |
| 5096 NodeList<FormalParameter> parameters13 = node.parameters; | |
| 5097 int size7 = parameters13.length; | |
| 5098 for (int i = 0; i < size7; i++) { | |
| 5099 FormalParameter parameter = parameters13[i]; | |
| 5100 if (i > 0) { | |
| 5101 _writer.print(", "); | |
| 5102 } | |
| 5103 if (groupEnd == null && parameter is DefaultFormalParameter) { | |
| 5104 if (identical(parameter.kind, ParameterKind.NAMED)) { | |
| 5105 groupEnd = "}"; | |
| 5106 _writer.print('{'); | |
| 5107 } else { | |
| 5108 groupEnd = "]"; | |
| 5109 _writer.print('['); | |
| 5110 } | |
| 5111 } | |
| 5112 parameter.accept(this); | |
| 5113 } | |
| 5114 if (groupEnd != null) { | |
| 5115 _writer.print(groupEnd); | |
| 5116 } | |
| 5117 _writer.print(')'); | |
| 5118 return null; | |
| 5119 } | |
| 5120 Object visitForStatement(ForStatement node) { | |
| 5121 Expression initialization4 = node.initialization; | |
| 5122 _writer.print("for ("); | |
| 5123 if (initialization4 != null) { | |
| 5124 visit(initialization4); | |
| 5125 } else { | |
| 5126 visit(node.variables); | |
| 5127 } | |
| 5128 _writer.print(";"); | |
| 5129 visit7(" ", node.condition); | |
| 5130 _writer.print(";"); | |
| 5131 visitList7(" ", node.updaters, ", "); | |
| 5132 _writer.print(") "); | |
| 5133 visit(node.body); | |
| 5134 return null; | |
| 5135 } | |
| 5136 Object visitFunctionDeclaration(FunctionDeclaration node) { | |
| 5137 visit6(node.returnType, " "); | |
| 5138 visit8(node.propertyKeyword, " "); | |
| 5139 visit(node.name); | |
| 5140 visit(node.functionExpression); | |
| 5141 return null; | |
| 5142 } | |
| 5143 Object visitFunctionDeclarationStatement(FunctionDeclarationStatement node) { | |
| 5144 visit(node.functionDeclaration); | |
| 5145 _writer.print(';'); | |
| 5146 return null; | |
| 5147 } | |
| 5148 Object visitFunctionExpression(FunctionExpression node) { | |
| 5149 visit(node.parameters); | |
| 5150 _writer.print(' '); | |
| 5151 visit(node.body); | |
| 5152 return null; | |
| 5153 } | |
| 5154 Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { | |
| 5155 visit(node.function); | |
| 5156 visit(node.argumentList); | |
| 5157 return null; | |
| 5158 } | |
| 5159 Object visitFunctionTypeAlias(FunctionTypeAlias node) { | |
| 5160 _writer.print("typedef "); | |
| 5161 visit6(node.returnType, " "); | |
| 5162 visit(node.name); | |
| 5163 visit(node.typeParameters); | |
| 5164 visit(node.parameters); | |
| 5165 _writer.print(";"); | |
| 5166 return null; | |
| 5167 } | |
| 5168 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { | |
| 5169 visit6(node.returnType, " "); | |
| 5170 visit(node.identifier); | |
| 5171 visit(node.parameters); | |
| 5172 return null; | |
| 5173 } | |
| 5174 Object visitHideCombinator(HideCombinator node) { | |
| 5175 _writer.print("hide "); | |
| 5176 visitList5(node.hiddenNames, ", "); | |
| 5177 return null; | |
| 5178 } | |
| 5179 Object visitIfStatement(IfStatement node) { | |
| 5180 _writer.print("if ("); | |
| 5181 visit(node.condition); | |
| 5182 _writer.print(") "); | |
| 5183 visit(node.thenStatement); | |
| 5184 visit7(" else ", node.elseStatement); | |
| 5185 return null; | |
| 5186 } | |
| 5187 Object visitImplementsClause(ImplementsClause node) { | |
| 5188 _writer.print("implements "); | |
| 5189 visitList5(node.interfaces, ", "); | |
| 5190 return null; | |
| 5191 } | |
| 5192 Object visitImportDirective(ImportDirective node) { | |
| 5193 _writer.print("import "); | |
| 5194 visit(node.uri); | |
| 5195 visit7(" as ", node.prefix); | |
| 5196 visitList7(" ", node.combinators, " "); | |
| 5197 _writer.print(';'); | |
| 5198 return null; | |
| 5199 } | |
| 5200 Object visitIndexExpression(IndexExpression node) { | |
| 5201 if (node.isCascaded()) { | |
| 5202 _writer.print(".."); | |
| 5203 } else { | |
| 5204 visit(node.array); | |
| 5205 } | |
| 5206 _writer.print('['); | |
| 5207 visit(node.index); | |
| 5208 _writer.print(']'); | |
| 5209 return null; | |
| 5210 } | |
| 5211 Object visitInstanceCreationExpression(InstanceCreationExpression node) { | |
| 5212 visit8(node.keyword, " "); | |
| 5213 visit(node.constructorName); | |
| 5214 visit(node.argumentList); | |
| 5215 return null; | |
| 5216 } | |
| 5217 Object visitIntegerLiteral(IntegerLiteral node) { | |
| 5218 _writer.print(node.literal.lexeme); | |
| 5219 return null; | |
| 5220 } | |
| 5221 Object visitInterpolationExpression(InterpolationExpression node) { | |
| 5222 if (node.rightBracket != null) { | |
| 5223 _writer.print("\${"); | |
| 5224 visit(node.expression); | |
| 5225 _writer.print("}"); | |
| 5226 } else { | |
| 5227 _writer.print("\$"); | |
| 5228 visit(node.expression); | |
| 5229 } | |
| 5230 return null; | |
| 5231 } | |
| 5232 Object visitInterpolationString(InterpolationString node) { | |
| 5233 _writer.print(node.contents.lexeme); | |
| 5234 return null; | |
| 5235 } | |
| 5236 Object visitIsExpression(IsExpression node) { | |
| 5237 visit(node.expression); | |
| 5238 if (node.notOperator == null) { | |
| 5239 _writer.print(" is "); | |
| 5240 } else { | |
| 5241 _writer.print(" is! "); | |
| 5242 } | |
| 5243 visit(node.type); | |
| 5244 return null; | |
| 5245 } | |
| 5246 Object visitLabel(Label node) { | |
| 5247 visit(node.label); | |
| 5248 _writer.print(":"); | |
| 5249 return null; | |
| 5250 } | |
| 5251 Object visitLabeledStatement(LabeledStatement node) { | |
| 5252 visitList6(node.labels, " ", " "); | |
| 5253 visit(node.statement); | |
| 5254 return null; | |
| 5255 } | |
| 5256 Object visitLibraryDirective(LibraryDirective node) { | |
| 5257 _writer.print("library "); | |
| 5258 visit(node.name); | |
| 5259 _writer.print(';'); | |
| 5260 nl(); | |
| 5261 return null; | |
| 5262 } | |
| 5263 Object visitLibraryIdentifier(LibraryIdentifier node) { | |
| 5264 _writer.print(node.name); | |
| 5265 return null; | |
| 5266 } | |
| 5267 Object visitListLiteral(ListLiteral node) { | |
| 5268 if (node.modifier != null) { | |
| 5269 _writer.print(node.modifier.lexeme); | |
| 5270 _writer.print(' '); | |
| 5271 } | |
| 5272 visit6(node.typeArguments, " "); | |
| 5273 _writer.print("["); | |
| 5274 visitList5(node.elements, ", "); | |
| 5275 _writer.print("]"); | |
| 5276 return null; | |
| 5277 } | |
| 5278 Object visitMapLiteral(MapLiteral node) { | |
| 5279 if (node.modifier != null) { | |
| 5280 _writer.print(node.modifier.lexeme); | |
| 5281 _writer.print(' '); | |
| 5282 } | |
| 5283 visit6(node.typeArguments, " "); | |
| 5284 _writer.print("{"); | |
| 5285 visitList5(node.entries, ", "); | |
| 5286 _writer.print("}"); | |
| 5287 return null; | |
| 5288 } | |
| 5289 Object visitMapLiteralEntry(MapLiteralEntry node) { | |
| 5290 visit(node.key); | |
| 5291 _writer.print(" : "); | |
| 5292 visit(node.value); | |
| 5293 return null; | |
| 5294 } | |
| 5295 Object visitMethodDeclaration(MethodDeclaration node) { | |
| 5296 visit(node.documentationComment); | |
| 5297 visit8(node.externalKeyword, " "); | |
| 5298 visit8(node.modifierKeyword, " "); | |
| 5299 visit6(node.returnType, " "); | |
| 5300 visit8(node.propertyKeyword, " "); | |
| 5301 visit8(node.operatorKeyword, " "); | |
| 5302 visit(node.name); | |
| 5303 if (!node.isGetter()) { | |
| 5304 visit(node.parameters); | |
| 5305 } | |
| 5306 if (node.body is! EmptyFunctionBody) { | |
| 5307 _writer.print(' '); | |
| 5308 } | |
| 5309 visit(node.body); | |
| 5310 return null; | |
| 5311 } | |
| 5312 Object visitMethodInvocation(MethodInvocation node) { | |
| 5313 if (node.isCascaded()) { | |
| 5314 _writer.print(".."); | |
| 5315 } else { | |
| 5316 visit6(node.target, "."); | |
| 5317 } | |
| 5318 visit(node.methodName); | |
| 5319 visit(node.argumentList); | |
| 5320 return null; | |
| 5321 } | |
| 5322 Object visitNamedExpression(NamedExpression node) { | |
| 5323 visit(node.name); | |
| 5324 visit7(" ", node.expression); | |
| 5325 return null; | |
| 5326 } | |
| 5327 Object visitNullLiteral(NullLiteral node) { | |
| 5328 _writer.print("null"); | |
| 5329 return null; | |
| 5330 } | |
| 5331 Object visitParenthesizedExpression(ParenthesizedExpression node) { | |
| 5332 _writer.print('('); | |
| 5333 visit(node.expression); | |
| 5334 _writer.print(')'); | |
| 5335 return null; | |
| 5336 } | |
| 5337 Object visitPartDirective(PartDirective node) { | |
| 5338 _writer.print("part "); | |
| 5339 visit(node.uri); | |
| 5340 _writer.print(';'); | |
| 5341 return null; | |
| 5342 } | |
| 5343 Object visitPartOfDirective(PartOfDirective node) { | |
| 5344 _writer.print("part of "); | |
| 5345 visit(node.libraryName); | |
| 5346 _writer.print(';'); | |
| 5347 return null; | |
| 5348 } | |
| 5349 Object visitPostfixExpression(PostfixExpression node) { | |
| 5350 visit(node.operand); | |
| 5351 _writer.print(node.operator.lexeme); | |
| 5352 return null; | |
| 5353 } | |
| 5354 Object visitPrefixedIdentifier(PrefixedIdentifier node) { | |
| 5355 visit(node.prefix); | |
| 5356 _writer.print('.'); | |
| 5357 visit(node.identifier); | |
| 5358 return null; | |
| 5359 } | |
| 5360 Object visitPrefixExpression(PrefixExpression node) { | |
| 5361 _writer.print(node.operator.lexeme); | |
| 5362 visit(node.operand); | |
| 5363 return null; | |
| 5364 } | |
| 5365 Object visitPropertyAccess(PropertyAccess node) { | |
| 5366 if (node.isCascaded()) { | |
| 5367 _writer.print(".."); | |
| 5368 } else { | |
| 5369 visit6(node.target, "."); | |
| 5370 } | |
| 5371 visit(node.propertyName); | |
| 5372 return null; | |
| 5373 } | |
| 5374 Object visitRedirectingConstructorInvocation(RedirectingConstructorInvocation
node) { | |
| 5375 _writer.print("this"); | |
| 5376 visit7(".", node.constructorName); | |
| 5377 visit(node.argumentList); | |
| 5378 return null; | |
| 5379 } | |
| 5380 Object visitReturnStatement(ReturnStatement node) { | |
| 5381 Expression expression17 = node.expression; | |
| 5382 if (expression17 == null) { | |
| 5383 _writer.print("return;"); | |
| 5384 } else { | |
| 5385 _writer.print("return "); | |
| 5386 expression17.accept(this); | |
| 5387 _writer.print(";"); | |
| 5388 } | |
| 5389 return null; | |
| 5390 } | |
| 5391 Object visitScriptTag(ScriptTag node) { | |
| 5392 _writer.print(node.scriptTag.lexeme); | |
| 5393 return null; | |
| 5394 } | |
| 5395 Object visitShowCombinator(ShowCombinator node) { | |
| 5396 _writer.print("show "); | |
| 5397 visitList5(node.shownNames, ", "); | |
| 5398 return null; | |
| 5399 } | |
| 5400 Object visitSimpleFormalParameter(SimpleFormalParameter node) { | |
| 5401 visit8(node.keyword, " "); | |
| 5402 visit6(node.type, " "); | |
| 5403 visit(node.identifier); | |
| 5404 return null; | |
| 5405 } | |
| 5406 Object visitSimpleIdentifier(SimpleIdentifier node) { | |
| 5407 _writer.print(node.token.lexeme); | |
| 5408 return null; | |
| 5409 } | |
| 5410 Object visitSimpleStringLiteral(SimpleStringLiteral node) { | |
| 5411 _writer.print(node.literal.lexeme); | |
| 5412 return null; | |
| 5413 } | |
| 5414 Object visitStringInterpolation(StringInterpolation node) { | |
| 5415 visitList(node.elements); | |
| 5416 return null; | |
| 5417 } | |
| 5418 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) { | |
| 5419 _writer.print("super"); | |
| 5420 visit7(".", node.constructorName); | |
| 5421 visit(node.argumentList); | |
| 5422 return null; | |
| 5423 } | |
| 5424 Object visitSuperExpression(SuperExpression node) { | |
| 5425 _writer.print("super"); | |
| 5426 return null; | |
| 5427 } | |
| 5428 Object visitSwitchCase(SwitchCase node) { | |
| 5429 visitList6(node.labels, " ", " "); | |
| 5430 _writer.print("case "); | |
| 5431 visit(node.expression); | |
| 5432 _writer.print(": "); | |
| 5433 { | |
| 5434 indentInc(); | |
| 5435 visitList5(node.statements, "\n"); | |
| 5436 indentDec(); | |
| 5437 } | |
| 5438 return null; | |
| 5439 } | |
| 5440 Object visitSwitchDefault(SwitchDefault node) { | |
| 5441 visitList6(node.labels, " ", " "); | |
| 5442 _writer.print("default: "); | |
| 5443 { | |
| 5444 indentInc(); | |
| 5445 visitList5(node.statements, "\n"); | |
| 5446 indentDec(); | |
| 5447 } | |
| 5448 return null; | |
| 5449 } | |
| 5450 Object visitSwitchStatement(SwitchStatement node) { | |
| 5451 _writer.print("switch ("); | |
| 5452 visit(node.expression); | |
| 5453 _writer.print(") {"); | |
| 5454 { | |
| 5455 indentInc(); | |
| 5456 visitList5(node.members, "\n"); | |
| 5457 indentDec(); | |
| 5458 } | |
| 5459 nl2(); | |
| 5460 _writer.print('}'); | |
| 5461 return null; | |
| 5462 } | |
| 5463 Object visitThisExpression(ThisExpression node) { | |
| 5464 _writer.print("this"); | |
| 5465 return null; | |
| 5466 } | |
| 5467 Object visitThrowExpression(ThrowExpression node) { | |
| 5468 _writer.print("throw "); | |
| 5469 visit(node.expression); | |
| 5470 return null; | |
| 5471 } | |
| 5472 Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { | |
| 5473 visit6(node.variables, ";"); | |
| 5474 return null; | |
| 5475 } | |
| 5476 Object visitTryStatement(TryStatement node) { | |
| 5477 _writer.print("try "); | |
| 5478 visit(node.body); | |
| 5479 visitList7(" ", node.catchClauses, " "); | |
| 5480 visit7(" finally ", node.finallyClause); | |
| 5481 return null; | |
| 5482 } | |
| 5483 Object visitTypeArgumentList(TypeArgumentList node) { | |
| 5484 _writer.print('<'); | |
| 5485 visitList5(node.arguments, ", "); | |
| 5486 _writer.print('>'); | |
| 5487 return null; | |
| 5488 } | |
| 5489 Object visitTypeName(TypeName node) { | |
| 5490 visit(node.name); | |
| 5491 visit(node.typeArguments); | |
| 5492 return null; | |
| 5493 } | |
| 5494 Object visitTypeParameter(TypeParameter node) { | |
| 5495 visit(node.name); | |
| 5496 visit7(" extends ", node.bound); | |
| 5497 return null; | |
| 5498 } | |
| 5499 Object visitTypeParameterList(TypeParameterList node) { | |
| 5500 _writer.print('<'); | |
| 5501 visitList5(node.typeParameters, ", "); | |
| 5502 _writer.print('>'); | |
| 5503 return null; | |
| 5504 } | |
| 5505 Object visitVariableDeclaration(VariableDeclaration node) { | |
| 5506 visit(node.name); | |
| 5507 visit7(" = ", node.initializer); | |
| 5508 return null; | |
| 5509 } | |
| 5510 Object visitVariableDeclarationList(VariableDeclarationList node) { | |
| 5511 visit8(node.keyword, " "); | |
| 5512 visit6(node.type, " "); | |
| 5513 visitList5(node.variables, ", "); | |
| 5514 return null; | |
| 5515 } | |
| 5516 Object visitVariableDeclarationStatement(VariableDeclarationStatement node) { | |
| 5517 visit(node.variables); | |
| 5518 _writer.print(";"); | |
| 5519 return null; | |
| 5520 } | |
| 5521 Object visitWhileStatement(WhileStatement node) { | |
| 5522 _writer.print("while ("); | |
| 5523 visit(node.condition); | |
| 5524 _writer.print(") "); | |
| 5525 visit(node.body); | |
| 5526 return null; | |
| 5527 } | |
| 5528 Object visitWithClause(WithClause node) { | |
| 5529 _writer.print("with "); | |
| 5530 visitList5(node.mixinTypes, ", "); | |
| 5531 return null; | |
| 5532 } | |
| 5533 void indent() { | |
| 5534 _writer.print(_indentString); | |
| 5535 } | |
| 5536 void indentDec() { | |
| 5537 _indentLevel -= 2; | |
| 5538 _indentString = StringUtils.repeat(" ", _indentLevel); | |
| 5539 } | |
| 5540 void indentInc() { | |
| 5541 _indentLevel += 2; | |
| 5542 _indentString = StringUtils.repeat(" ", _indentLevel); | |
| 5543 } | |
| 5544 void nl() { | |
| 5545 _writer.print("\n"); | |
| 5546 } | |
| 5547 void nl2() { | |
| 5548 nl(); | |
| 5549 indent(); | |
| 5550 } | |
| 5551 /** | |
| 5552 * Safely visit the given node. | |
| 5553 * @param node the node to be visited | |
| 5554 */ | |
| 5555 void visit(ASTNode node) { | |
| 5556 if (node != null) { | |
| 5557 node.accept(this); | |
| 5558 } | |
| 5559 } | |
| 5560 /** | |
| 5561 * Safely visit the given node, printing the suffix after the node if it is no
n-<code>null</code>. | |
| 5562 * @param suffix the suffix to be printed if there is a node to visit | |
| 5563 * @param node the node to be visited | |
| 5564 */ | |
| 5565 void visit6(ASTNode node, String suffix) { | |
| 5566 if (node != null) { | |
| 5567 node.accept(this); | |
| 5568 _writer.print(suffix); | |
| 5569 } | |
| 5570 } | |
| 5571 /** | |
| 5572 * Safely visit the given node, printing the prefix before the node if it is n
on-<code>null</code> | |
| 5573 * . | |
| 5574 * @param prefix the prefix to be printed if there is a node to visit | |
| 5575 * @param node the node to be visited | |
| 5576 */ | |
| 5577 void visit7(String prefix, ASTNode node) { | |
| 5578 if (node != null) { | |
| 5579 _writer.print(prefix); | |
| 5580 node.accept(this); | |
| 5581 } | |
| 5582 } | |
| 5583 /** | |
| 5584 * Safely visit the given node, printing the suffix after the node if it is no
n-<code>null</code>. | |
| 5585 * @param suffix the suffix to be printed if there is a node to visit | |
| 5586 * @param node the node to be visited | |
| 5587 */ | |
| 5588 void visit8(Token token, String suffix) { | |
| 5589 if (token != null) { | |
| 5590 _writer.print(token.lexeme); | |
| 5591 _writer.print(suffix); | |
| 5592 } | |
| 5593 } | |
| 5594 /** | |
| 5595 * Print a list of nodes without any separation. | |
| 5596 * @param nodes the nodes to be printed | |
| 5597 * @param separator the separator to be printed between adjacent nodes | |
| 5598 */ | |
| 5599 void visitList(NodeList<ASTNode> nodes) { | |
| 5600 visitList5(nodes, ""); | |
| 5601 } | |
| 5602 /** | |
| 5603 * Print a list of nodes, separated by the given separator. | |
| 5604 * @param nodes the nodes to be printed | |
| 5605 * @param separator the separator to be printed between adjacent nodes | |
| 5606 */ | |
| 5607 void visitList5(NodeList<ASTNode> nodes, String separator) { | |
| 5608 if (nodes != null) { | |
| 5609 int size8 = nodes.length; | |
| 5610 for (int i = 0; i < size8; i++) { | |
| 5611 if ("\n" == separator) { | |
| 5612 _writer.print("\n"); | |
| 5613 indent(); | |
| 5614 } else if (i > 0) { | |
| 5615 _writer.print(separator); | |
| 5616 } | |
| 5617 nodes[i].accept(this); | |
| 5618 } | |
| 5619 } | |
| 5620 } | |
| 5621 /** | |
| 5622 * Print a list of nodes, separated by the given separator. | |
| 5623 * @param nodes the nodes to be printed | |
| 5624 * @param separator the separator to be printed between adjacent nodes | |
| 5625 * @param suffix the suffix to be printed if the list is not empty | |
| 5626 */ | |
| 5627 void visitList6(NodeList<ASTNode> nodes, String separator, String suffix) { | |
| 5628 if (nodes != null) { | |
| 5629 int size9 = nodes.length; | |
| 5630 if (size9 > 0) { | |
| 5631 for (int i = 0; i < size9; i++) { | |
| 5632 if (i > 0) { | |
| 5633 _writer.print(separator); | |
| 5634 } | |
| 5635 nodes[i].accept(this); | |
| 5636 } | |
| 5637 _writer.print(suffix); | |
| 5638 } | |
| 5639 } | |
| 5640 } | |
| 5641 /** | |
| 5642 * Print a list of nodes, separated by the given separator. | |
| 5643 * @param prefix the prefix to be printed if the list is not empty | |
| 5644 * @param nodes the nodes to be printed | |
| 5645 * @param separator the separator to be printed between adjacent nodes | |
| 5646 */ | |
| 5647 void visitList7(String prefix, NodeList<ASTNode> nodes, String separator) { | |
| 5648 if (nodes != null) { | |
| 5649 int size10 = nodes.length; | |
| 5650 if (size10 > 0) { | |
| 5651 _writer.print(prefix); | |
| 5652 for (int i = 0; i < size10; i++) { | |
| 5653 if (i > 0) { | |
| 5654 _writer.print(separator); | |
| 5655 } | |
| 5656 nodes[i].accept(this); | |
| 5657 } | |
| 5658 } | |
| 5659 } | |
| 5660 } | |
| 5661 } | |
| OLD | NEW |