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