OLD | NEW |
(Empty) | |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are |
| 4 // met: |
| 5 // |
| 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided |
| 11 // with the distribution. |
| 12 // * Neither the name of Google Inc. nor the names of its |
| 13 // contributors may be used to endorse or promote products derived |
| 14 // from this software without specific prior written permission. |
| 15 // |
| 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 |
| 28 #include "../include/v8stdint.h" |
| 29 #include "unicode.h" |
| 30 #include "globals.h" |
| 31 #include "checks.h" |
| 32 #include "allocation.h" |
| 33 #include "utils.h" |
| 34 #include "list.h" |
| 35 #include "scanner-base.h" |
| 36 #include "preparse-data.h" |
| 37 #include "preparser.h" |
| 38 |
| 39 namespace v8 { |
| 40 namespace preparser { |
| 41 |
| 42 // Preparsing checks a JavaScript program and emits preparse-data that helps |
| 43 // a later parsing to be faster. |
| 44 // See preparser-data.h for the data. |
| 45 |
| 46 // The PreParser checks that the syntax follows the grammar for JavaScript, |
| 47 // and collects some information about the program along the way. |
| 48 // The grammar check is only performed in order to understand the program |
| 49 // sufficiently to deduce some information about it, that can be used |
| 50 // to speed up later parsing. Finding errors is not the goal of pre-parsing, |
| 51 // rather it is to speed up properly written and correct programs. |
| 52 // That means that contextual checks (like a label being declared where |
| 53 // it is used) are generally omitted. |
| 54 |
| 55 namespace i = ::v8::internal; |
| 56 |
| 57 #define CHECK_OK ok); \ |
| 58 if (!*ok) return -1; \ |
| 59 ((void)0 |
| 60 #define DUMMY ) // to make indentation work |
| 61 #undef DUMMY |
| 62 |
| 63 |
| 64 void PreParser::ReportUnexpectedToken(i::Token::Value token) { |
| 65 // We don't report stack overflows here, to avoid increasing the |
| 66 // stack depth even further. Instead we report it after parsing is |
| 67 // over, in ParseProgram. |
| 68 if (token == i::Token::ILLEGAL && scanner_->stack_overflow()) { |
| 69 return; |
| 70 } |
| 71 i::JavaScriptScanner::Location source_location = scanner_->location(); |
| 72 |
| 73 // Four of the tokens are treated specially |
| 74 switch (token) { |
| 75 case i::Token::EOS: |
| 76 return ReportMessageAt(source_location.beg_pos, source_location.end_pos, |
| 77 "unexpected_eos", NULL); |
| 78 case i::Token::NUMBER: |
| 79 return ReportMessageAt(source_location.beg_pos, source_location.end_pos, |
| 80 "unexpected_token_number", NULL); |
| 81 case i::Token::STRING: |
| 82 return ReportMessageAt(source_location.beg_pos, source_location.end_pos, |
| 83 "unexpected_token_string", NULL); |
| 84 case i::Token::IDENTIFIER: |
| 85 return ReportMessageAt(source_location.beg_pos, source_location.end_pos, |
| 86 "unexpected_token_identifier", NULL); |
| 87 default: |
| 88 const char* name = i::Token::String(token); |
| 89 ReportMessageAt(source_location.beg_pos, source_location.end_pos, |
| 90 "unexpected_token", name); |
| 91 } |
| 92 } |
| 93 |
| 94 |
| 95 SourceElements PreParser::ParseSourceElements(int end_token, |
| 96 bool* ok) { |
| 97 // SourceElements :: |
| 98 // (Statement)* <end_token> |
| 99 |
| 100 while (peek() != end_token) { |
| 101 ParseStatement(CHECK_OK); |
| 102 } |
| 103 return kUnknownSourceElements; |
| 104 } |
| 105 |
| 106 |
| 107 Statement PreParser::ParseStatement(bool* ok) { |
| 108 // Statement :: |
| 109 // Block |
| 110 // VariableStatement |
| 111 // EmptyStatement |
| 112 // ExpressionStatement |
| 113 // IfStatement |
| 114 // IterationStatement |
| 115 // ContinueStatement |
| 116 // BreakStatement |
| 117 // ReturnStatement |
| 118 // WithStatement |
| 119 // LabelledStatement |
| 120 // SwitchStatement |
| 121 // ThrowStatement |
| 122 // TryStatement |
| 123 // DebuggerStatement |
| 124 |
| 125 // Note: Since labels can only be used by 'break' and 'continue' |
| 126 // statements, which themselves are only valid within blocks, |
| 127 // iterations or 'switch' statements (i.e., BreakableStatements), |
| 128 // labels can be simply ignored in all other cases; except for |
| 129 // trivial labeled break statements 'label: break label' which is |
| 130 // parsed into an empty statement. |
| 131 |
| 132 // Keep the source position of the statement |
| 133 switch (peek()) { |
| 134 case i::Token::LBRACE: |
| 135 return ParseBlock(ok); |
| 136 |
| 137 case i::Token::CONST: |
| 138 case i::Token::VAR: |
| 139 return ParseVariableStatement(ok); |
| 140 |
| 141 case i::Token::SEMICOLON: |
| 142 Next(); |
| 143 return kUnknownStatement; |
| 144 |
| 145 case i::Token::IF: |
| 146 return ParseIfStatement(ok); |
| 147 |
| 148 case i::Token::DO: |
| 149 return ParseDoWhileStatement(ok); |
| 150 |
| 151 case i::Token::WHILE: |
| 152 return ParseWhileStatement(ok); |
| 153 |
| 154 case i::Token::FOR: |
| 155 return ParseForStatement(ok); |
| 156 |
| 157 case i::Token::CONTINUE: |
| 158 return ParseContinueStatement(ok); |
| 159 |
| 160 case i::Token::BREAK: |
| 161 return ParseBreakStatement(ok); |
| 162 |
| 163 case i::Token::RETURN: |
| 164 return ParseReturnStatement(ok); |
| 165 |
| 166 case i::Token::WITH: |
| 167 return ParseWithStatement(ok); |
| 168 |
| 169 case i::Token::SWITCH: |
| 170 return ParseSwitchStatement(ok); |
| 171 |
| 172 case i::Token::THROW: |
| 173 return ParseThrowStatement(ok); |
| 174 |
| 175 case i::Token::TRY: |
| 176 return ParseTryStatement(ok); |
| 177 |
| 178 case i::Token::FUNCTION: |
| 179 return ParseFunctionDeclaration(ok); |
| 180 |
| 181 case i::Token::NATIVE: |
| 182 return ParseNativeDeclaration(ok); |
| 183 |
| 184 case i::Token::DEBUGGER: |
| 185 return ParseDebuggerStatement(ok); |
| 186 |
| 187 default: |
| 188 return ParseExpressionOrLabelledStatement(ok); |
| 189 } |
| 190 } |
| 191 |
| 192 |
| 193 Statement PreParser::ParseFunctionDeclaration(bool* ok) { |
| 194 // FunctionDeclaration :: |
| 195 // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}' |
| 196 Expect(i::Token::FUNCTION, CHECK_OK); |
| 197 ParseIdentifier(CHECK_OK); |
| 198 ParseFunctionLiteral(CHECK_OK); |
| 199 return kUnknownStatement; |
| 200 } |
| 201 |
| 202 |
| 203 // Language extension which is only enabled for source files loaded |
| 204 // through the API's extension mechanism. A native function |
| 205 // declaration is resolved by looking up the function through a |
| 206 // callback provided by the extension. |
| 207 Statement PreParser::ParseNativeDeclaration(bool* ok) { |
| 208 Expect(i::Token::NATIVE, CHECK_OK); |
| 209 Expect(i::Token::FUNCTION, CHECK_OK); |
| 210 ParseIdentifier(CHECK_OK); |
| 211 Expect(i::Token::LPAREN, CHECK_OK); |
| 212 bool done = (peek() == i::Token::RPAREN); |
| 213 while (!done) { |
| 214 ParseIdentifier(CHECK_OK); |
| 215 done = (peek() == i::Token::RPAREN); |
| 216 if (!done) { |
| 217 Expect(i::Token::COMMA, CHECK_OK); |
| 218 } |
| 219 } |
| 220 Expect(i::Token::RPAREN, CHECK_OK); |
| 221 Expect(i::Token::SEMICOLON, CHECK_OK); |
| 222 return kUnknownStatement; |
| 223 } |
| 224 |
| 225 |
| 226 Statement PreParser::ParseBlock(bool* ok) { |
| 227 // Block :: |
| 228 // '{' Statement* '}' |
| 229 |
| 230 // Note that a Block does not introduce a new execution scope! |
| 231 // (ECMA-262, 3rd, 12.2) |
| 232 // |
| 233 Expect(i::Token::LBRACE, CHECK_OK); |
| 234 while (peek() != i::Token::RBRACE) { |
| 235 ParseStatement(CHECK_OK); |
| 236 } |
| 237 Expect(i::Token::RBRACE, CHECK_OK); |
| 238 return kUnknownStatement; |
| 239 } |
| 240 |
| 241 |
| 242 Statement PreParser::ParseVariableStatement(bool* ok) { |
| 243 // VariableStatement :: |
| 244 // VariableDeclarations ';' |
| 245 |
| 246 Statement result = ParseVariableDeclarations(true, NULL, CHECK_OK); |
| 247 ExpectSemicolon(CHECK_OK); |
| 248 return result; |
| 249 } |
| 250 |
| 251 |
| 252 // If the variable declaration declares exactly one non-const |
| 253 // variable, then *var is set to that variable. In all other cases, |
| 254 // *var is untouched; in particular, it is the caller's responsibility |
| 255 // to initialize it properly. This mechanism is also used for the parsing |
| 256 // of 'for-in' loops. |
| 257 Statement PreParser::ParseVariableDeclarations(bool accept_IN, |
| 258 int* num_decl, |
| 259 bool* ok) { |
| 260 // VariableDeclarations :: |
| 261 // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[','] |
| 262 |
| 263 if (peek() == i::Token::VAR) { |
| 264 Consume(i::Token::VAR); |
| 265 } else if (peek() == i::Token::CONST) { |
| 266 Consume(i::Token::CONST); |
| 267 } else { |
| 268 *ok = false; |
| 269 return 0; |
| 270 } |
| 271 |
| 272 // The scope of a variable/const declared anywhere inside a function |
| 273 // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). . |
| 274 int nvars = 0; // the number of variables declared |
| 275 do { |
| 276 // Parse variable name. |
| 277 if (nvars > 0) Consume(i::Token::COMMA); |
| 278 ParseIdentifier(CHECK_OK); |
| 279 nvars++; |
| 280 if (peek() == i::Token::ASSIGN) { |
| 281 Expect(i::Token::ASSIGN, CHECK_OK); |
| 282 ParseAssignmentExpression(accept_IN, CHECK_OK); |
| 283 } |
| 284 } while (peek() == i::Token::COMMA); |
| 285 |
| 286 if (num_decl != NULL) *num_decl = nvars; |
| 287 return kUnknownStatement; |
| 288 } |
| 289 |
| 290 |
| 291 Statement PreParser::ParseExpressionOrLabelledStatement( |
| 292 bool* ok) { |
| 293 // ExpressionStatement | LabelledStatement :: |
| 294 // Expression ';' |
| 295 // Identifier ':' Statement |
| 296 |
| 297 Expression expr = ParseExpression(true, CHECK_OK); |
| 298 if (peek() == i::Token::COLON && expr == kIdentifierExpression) { |
| 299 Consume(i::Token::COLON); |
| 300 return ParseStatement(ok); |
| 301 } |
| 302 // Parsed expression statement. |
| 303 ExpectSemicolon(CHECK_OK); |
| 304 return kUnknownStatement; |
| 305 } |
| 306 |
| 307 |
| 308 Statement PreParser::ParseIfStatement(bool* ok) { |
| 309 // IfStatement :: |
| 310 // 'if' '(' Expression ')' Statement ('else' Statement)? |
| 311 |
| 312 Expect(i::Token::IF, CHECK_OK); |
| 313 Expect(i::Token::LPAREN, CHECK_OK); |
| 314 ParseExpression(true, CHECK_OK); |
| 315 Expect(i::Token::RPAREN, CHECK_OK); |
| 316 ParseStatement(CHECK_OK); |
| 317 if (peek() == i::Token::ELSE) { |
| 318 Next(); |
| 319 ParseStatement(CHECK_OK); |
| 320 } |
| 321 return kUnknownStatement; |
| 322 } |
| 323 |
| 324 |
| 325 Statement PreParser::ParseContinueStatement(bool* ok) { |
| 326 // ContinueStatement :: |
| 327 // 'continue' [no line terminator] Identifier? ';' |
| 328 |
| 329 Expect(i::Token::CONTINUE, CHECK_OK); |
| 330 i::Token::Value tok = peek(); |
| 331 if (!scanner_->has_line_terminator_before_next() && |
| 332 tok != i::Token::SEMICOLON && |
| 333 tok != i::Token::RBRACE && |
| 334 tok != i::Token::EOS) { |
| 335 ParseIdentifier(CHECK_OK); |
| 336 } |
| 337 ExpectSemicolon(CHECK_OK); |
| 338 return kUnknownStatement; |
| 339 } |
| 340 |
| 341 |
| 342 Statement PreParser::ParseBreakStatement(bool* ok) { |
| 343 // BreakStatement :: |
| 344 // 'break' [no line terminator] Identifier? ';' |
| 345 |
| 346 Expect(i::Token::BREAK, CHECK_OK); |
| 347 i::Token::Value tok = peek(); |
| 348 if (!scanner_->has_line_terminator_before_next() && |
| 349 tok != i::Token::SEMICOLON && |
| 350 tok != i::Token::RBRACE && |
| 351 tok != i::Token::EOS) { |
| 352 ParseIdentifier(CHECK_OK); |
| 353 } |
| 354 ExpectSemicolon(CHECK_OK); |
| 355 return kUnknownStatement; |
| 356 } |
| 357 |
| 358 |
| 359 Statement PreParser::ParseReturnStatement(bool* ok) { |
| 360 // ReturnStatement :: |
| 361 // 'return' [no line terminator] Expression? ';' |
| 362 |
| 363 // Consume the return token. It is necessary to do the before |
| 364 // reporting any errors on it, because of the way errors are |
| 365 // reported (underlining). |
| 366 Expect(i::Token::RETURN, CHECK_OK); |
| 367 |
| 368 // An ECMAScript program is considered syntactically incorrect if it |
| 369 // contains a return statement that is not within the body of a |
| 370 // function. See ECMA-262, section 12.9, page 67. |
| 371 // This is not handled during preparsing. |
| 372 |
| 373 i::Token::Value tok = peek(); |
| 374 if (!scanner_->has_line_terminator_before_next() && |
| 375 tok != i::Token::SEMICOLON && |
| 376 tok != i::Token::RBRACE && |
| 377 tok != i::Token::EOS) { |
| 378 ParseExpression(true, CHECK_OK); |
| 379 } |
| 380 ExpectSemicolon(CHECK_OK); |
| 381 return kUnknownStatement; |
| 382 } |
| 383 |
| 384 |
| 385 Statement PreParser::ParseWithStatement(bool* ok) { |
| 386 // WithStatement :: |
| 387 // 'with' '(' Expression ')' Statement |
| 388 Expect(i::Token::WITH, CHECK_OK); |
| 389 Expect(i::Token::LPAREN, CHECK_OK); |
| 390 ParseExpression(true, CHECK_OK); |
| 391 Expect(i::Token::RPAREN, CHECK_OK); |
| 392 |
| 393 scope_->EnterWith(); |
| 394 ParseStatement(CHECK_OK); |
| 395 scope_->LeaveWith(); |
| 396 return kUnknownStatement; |
| 397 } |
| 398 |
| 399 |
| 400 Statement PreParser::ParseSwitchStatement(bool* ok) { |
| 401 // SwitchStatement :: |
| 402 // 'switch' '(' Expression ')' '{' CaseClause* '}' |
| 403 |
| 404 Expect(i::Token::SWITCH, CHECK_OK); |
| 405 Expect(i::Token::LPAREN, CHECK_OK); |
| 406 ParseExpression(true, CHECK_OK); |
| 407 Expect(i::Token::RPAREN, CHECK_OK); |
| 408 |
| 409 Expect(i::Token::LBRACE, CHECK_OK); |
| 410 i::Token::Value token = peek(); |
| 411 while (token != i::Token::RBRACE) { |
| 412 if (token == i::Token::CASE) { |
| 413 Expect(i::Token::CASE, CHECK_OK); |
| 414 ParseExpression(true, CHECK_OK); |
| 415 Expect(i::Token::COLON, CHECK_OK); |
| 416 } else if (token == i::Token::DEFAULT) { |
| 417 Expect(i::Token::DEFAULT, CHECK_OK); |
| 418 Expect(i::Token::COLON, CHECK_OK); |
| 419 } else { |
| 420 ParseStatement(CHECK_OK); |
| 421 } |
| 422 token = peek(); |
| 423 } |
| 424 Expect(i::Token::RBRACE, CHECK_OK); |
| 425 |
| 426 return kUnknownStatement; |
| 427 } |
| 428 |
| 429 |
| 430 Statement PreParser::ParseDoWhileStatement(bool* ok) { |
| 431 // DoStatement :: |
| 432 // 'do' Statement 'while' '(' Expression ')' ';' |
| 433 |
| 434 Expect(i::Token::DO, CHECK_OK); |
| 435 ParseStatement(CHECK_OK); |
| 436 Expect(i::Token::WHILE, CHECK_OK); |
| 437 Expect(i::Token::LPAREN, CHECK_OK); |
| 438 ParseExpression(true, CHECK_OK); |
| 439 Expect(i::Token::RPAREN, CHECK_OK); |
| 440 return kUnknownStatement; |
| 441 } |
| 442 |
| 443 |
| 444 Statement PreParser::ParseWhileStatement(bool* ok) { |
| 445 // WhileStatement :: |
| 446 // 'while' '(' Expression ')' Statement |
| 447 |
| 448 Expect(i::Token::WHILE, CHECK_OK); |
| 449 Expect(i::Token::LPAREN, CHECK_OK); |
| 450 ParseExpression(true, CHECK_OK); |
| 451 Expect(i::Token::RPAREN, CHECK_OK); |
| 452 ParseStatement(CHECK_OK); |
| 453 return kUnknownStatement; |
| 454 } |
| 455 |
| 456 |
| 457 Statement PreParser::ParseForStatement(bool* ok) { |
| 458 // ForStatement :: |
| 459 // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement |
| 460 |
| 461 Expect(i::Token::FOR, CHECK_OK); |
| 462 Expect(i::Token::LPAREN, CHECK_OK); |
| 463 if (peek() != i::Token::SEMICOLON) { |
| 464 if (peek() == i::Token::VAR || peek() == i::Token::CONST) { |
| 465 int decl_count; |
| 466 ParseVariableDeclarations(false, &decl_count, CHECK_OK); |
| 467 if (peek() == i::Token::IN && decl_count == 1) { |
| 468 Expect(i::Token::IN, CHECK_OK); |
| 469 ParseExpression(true, CHECK_OK); |
| 470 Expect(i::Token::RPAREN, CHECK_OK); |
| 471 |
| 472 ParseStatement(CHECK_OK); |
| 473 return kUnknownStatement; |
| 474 } |
| 475 } else { |
| 476 ParseExpression(false, CHECK_OK); |
| 477 if (peek() == i::Token::IN) { |
| 478 Expect(i::Token::IN, CHECK_OK); |
| 479 ParseExpression(true, CHECK_OK); |
| 480 Expect(i::Token::RPAREN, CHECK_OK); |
| 481 |
| 482 ParseStatement(CHECK_OK); |
| 483 return kUnknownStatement; |
| 484 } |
| 485 } |
| 486 } |
| 487 |
| 488 // Parsed initializer at this point. |
| 489 Expect(i::Token::SEMICOLON, CHECK_OK); |
| 490 |
| 491 if (peek() != i::Token::SEMICOLON) { |
| 492 ParseExpression(true, CHECK_OK); |
| 493 } |
| 494 Expect(i::Token::SEMICOLON, CHECK_OK); |
| 495 |
| 496 if (peek() != i::Token::RPAREN) { |
| 497 ParseExpression(true, CHECK_OK); |
| 498 } |
| 499 Expect(i::Token::RPAREN, CHECK_OK); |
| 500 |
| 501 ParseStatement(CHECK_OK); |
| 502 return kUnknownStatement; |
| 503 } |
| 504 |
| 505 |
| 506 Statement PreParser::ParseThrowStatement(bool* ok) { |
| 507 // ThrowStatement :: |
| 508 // 'throw' [no line terminator] Expression ';' |
| 509 |
| 510 Expect(i::Token::THROW, CHECK_OK); |
| 511 if (scanner_->has_line_terminator_before_next()) { |
| 512 i::JavaScriptScanner::Location pos = scanner_->location(); |
| 513 ReportMessageAt(pos.beg_pos, pos.end_pos, |
| 514 "newline_after_throw", NULL); |
| 515 *ok = false; |
| 516 return kUnknownStatement; |
| 517 } |
| 518 ParseExpression(true, CHECK_OK); |
| 519 ExpectSemicolon(CHECK_OK); |
| 520 |
| 521 return kUnknownStatement; |
| 522 } |
| 523 |
| 524 |
| 525 Statement PreParser::ParseTryStatement(bool* ok) { |
| 526 // TryStatement :: |
| 527 // 'try' Block Catch |
| 528 // 'try' Block Finally |
| 529 // 'try' Block Catch Finally |
| 530 // |
| 531 // Catch :: |
| 532 // 'catch' '(' Identifier ')' Block |
| 533 // |
| 534 // Finally :: |
| 535 // 'finally' Block |
| 536 |
| 537 // In preparsing, allow any number of catch/finally blocks, including zero |
| 538 // of both. |
| 539 |
| 540 Expect(i::Token::TRY, CHECK_OK); |
| 541 |
| 542 ParseBlock(CHECK_OK); |
| 543 |
| 544 bool catch_or_finally_seen = false; |
| 545 if (peek() == i::Token::CATCH) { |
| 546 Consume(i::Token::CATCH); |
| 547 Expect(i::Token::LPAREN, CHECK_OK); |
| 548 ParseIdentifier(CHECK_OK); |
| 549 Expect(i::Token::RPAREN, CHECK_OK); |
| 550 scope_->EnterWith(); |
| 551 ParseBlock(ok); |
| 552 scope_->LeaveWith(); |
| 553 if (!*ok) return kUnknownStatement; |
| 554 catch_or_finally_seen = true; |
| 555 } |
| 556 if (peek() == i::Token::FINALLY) { |
| 557 Consume(i::Token::FINALLY); |
| 558 ParseBlock(CHECK_OK); |
| 559 catch_or_finally_seen = true; |
| 560 } |
| 561 if (!catch_or_finally_seen) { |
| 562 *ok = false; |
| 563 } |
| 564 return kUnknownStatement; |
| 565 } |
| 566 |
| 567 |
| 568 Statement PreParser::ParseDebuggerStatement(bool* ok) { |
| 569 // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser |
| 570 // contexts this is used as a statement which invokes the debugger as if a |
| 571 // break point is present. |
| 572 // DebuggerStatement :: |
| 573 // 'debugger' ';' |
| 574 |
| 575 Expect(i::Token::DEBUGGER, CHECK_OK); |
| 576 ExpectSemicolon(CHECK_OK); |
| 577 return kUnknownStatement; |
| 578 } |
| 579 |
| 580 |
| 581 // Precedence = 1 |
| 582 Expression PreParser::ParseExpression(bool accept_IN, bool* ok) { |
| 583 // Expression :: |
| 584 // AssignmentExpression |
| 585 // Expression ',' AssignmentExpression |
| 586 |
| 587 Expression result = ParseAssignmentExpression(accept_IN, CHECK_OK); |
| 588 while (peek() == i::Token::COMMA) { |
| 589 Expect(i::Token::COMMA, CHECK_OK); |
| 590 ParseAssignmentExpression(accept_IN, CHECK_OK); |
| 591 result = kUnknownExpression; |
| 592 } |
| 593 return result; |
| 594 } |
| 595 |
| 596 |
| 597 // Precedence = 2 |
| 598 Expression PreParser::ParseAssignmentExpression(bool accept_IN, |
| 599 bool* ok) { |
| 600 // AssignmentExpression :: |
| 601 // ConditionalExpression |
| 602 // LeftHandSideExpression AssignmentOperator AssignmentExpression |
| 603 |
| 604 Expression expression = ParseConditionalExpression(accept_IN, CHECK_OK); |
| 605 |
| 606 if (!i::Token::IsAssignmentOp(peek())) { |
| 607 // Parsed conditional expression only (no assignment). |
| 608 return expression; |
| 609 } |
| 610 |
| 611 i::Token::Value op = Next(); // Get assignment operator. |
| 612 ParseAssignmentExpression(accept_IN, CHECK_OK); |
| 613 |
| 614 if ((op == i::Token::ASSIGN) && (expression == kThisPropertyExpression)) { |
| 615 scope_->AddProperty(); |
| 616 } |
| 617 |
| 618 return kUnknownExpression; |
| 619 } |
| 620 |
| 621 |
| 622 // Precedence = 3 |
| 623 Expression PreParser::ParseConditionalExpression(bool accept_IN, |
| 624 bool* ok) { |
| 625 // ConditionalExpression :: |
| 626 // LogicalOrExpression |
| 627 // LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression |
| 628 |
| 629 // We start using the binary expression parser for prec >= 4 only! |
| 630 Expression expression = ParseBinaryExpression(4, accept_IN, CHECK_OK); |
| 631 if (peek() != i::Token::CONDITIONAL) return expression; |
| 632 Consume(i::Token::CONDITIONAL); |
| 633 // In parsing the first assignment expression in conditional |
| 634 // expressions we always accept the 'in' keyword; see ECMA-262, |
| 635 // section 11.12, page 58. |
| 636 ParseAssignmentExpression(true, CHECK_OK); |
| 637 Expect(i::Token::COLON, CHECK_OK); |
| 638 ParseAssignmentExpression(accept_IN, CHECK_OK); |
| 639 return kUnknownExpression; |
| 640 } |
| 641 |
| 642 |
| 643 int PreParser::Precedence(i::Token::Value tok, bool accept_IN) { |
| 644 if (tok == i::Token::IN && !accept_IN) |
| 645 return 0; // 0 precedence will terminate binary expression parsing |
| 646 |
| 647 return i::Token::Precedence(tok); |
| 648 } |
| 649 |
| 650 |
| 651 // Precedence >= 4 |
| 652 Expression PreParser::ParseBinaryExpression(int prec, |
| 653 bool accept_IN, |
| 654 bool* ok) { |
| 655 Expression result = ParseUnaryExpression(CHECK_OK); |
| 656 for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) { |
| 657 // prec1 >= 4 |
| 658 while (Precedence(peek(), accept_IN) == prec1) { |
| 659 Next(); |
| 660 ParseBinaryExpression(prec1 + 1, accept_IN, CHECK_OK); |
| 661 result = kUnknownExpression; |
| 662 } |
| 663 } |
| 664 return result; |
| 665 } |
| 666 |
| 667 |
| 668 Expression PreParser::ParseUnaryExpression(bool* ok) { |
| 669 // UnaryExpression :: |
| 670 // PostfixExpression |
| 671 // 'delete' UnaryExpression |
| 672 // 'void' UnaryExpression |
| 673 // 'typeof' UnaryExpression |
| 674 // '++' UnaryExpression |
| 675 // '--' UnaryExpression |
| 676 // '+' UnaryExpression |
| 677 // '-' UnaryExpression |
| 678 // '~' UnaryExpression |
| 679 // '!' UnaryExpression |
| 680 |
| 681 i::Token::Value op = peek(); |
| 682 if (i::Token::IsUnaryOp(op) || i::Token::IsCountOp(op)) { |
| 683 op = Next(); |
| 684 ParseUnaryExpression(ok); |
| 685 return kUnknownExpression; |
| 686 } else { |
| 687 return ParsePostfixExpression(ok); |
| 688 } |
| 689 } |
| 690 |
| 691 |
| 692 Expression PreParser::ParsePostfixExpression(bool* ok) { |
| 693 // PostfixExpression :: |
| 694 // LeftHandSideExpression ('++' | '--')? |
| 695 |
| 696 Expression expression = ParseLeftHandSideExpression(CHECK_OK); |
| 697 if (!scanner_->has_line_terminator_before_next() && |
| 698 i::Token::IsCountOp(peek())) { |
| 699 Next(); |
| 700 return kUnknownExpression; |
| 701 } |
| 702 return expression; |
| 703 } |
| 704 |
| 705 |
| 706 Expression PreParser::ParseLeftHandSideExpression(bool* ok) { |
| 707 // LeftHandSideExpression :: |
| 708 // (NewExpression | MemberExpression) ... |
| 709 |
| 710 Expression result; |
| 711 if (peek() == i::Token::NEW) { |
| 712 result = ParseNewExpression(CHECK_OK); |
| 713 } else { |
| 714 result = ParseMemberExpression(CHECK_OK); |
| 715 } |
| 716 |
| 717 while (true) { |
| 718 switch (peek()) { |
| 719 case i::Token::LBRACK: { |
| 720 Consume(i::Token::LBRACK); |
| 721 ParseExpression(true, CHECK_OK); |
| 722 Expect(i::Token::RBRACK, CHECK_OK); |
| 723 if (result == kThisExpression) { |
| 724 result = kThisPropertyExpression; |
| 725 } else { |
| 726 result = kUnknownExpression; |
| 727 } |
| 728 break; |
| 729 } |
| 730 |
| 731 case i::Token::LPAREN: { |
| 732 ParseArguments(CHECK_OK); |
| 733 result = kUnknownExpression; |
| 734 break; |
| 735 } |
| 736 |
| 737 case i::Token::PERIOD: { |
| 738 Consume(i::Token::PERIOD); |
| 739 ParseIdentifierName(CHECK_OK); |
| 740 if (result == kThisExpression) { |
| 741 result = kThisPropertyExpression; |
| 742 } else { |
| 743 result = kUnknownExpression; |
| 744 } |
| 745 break; |
| 746 } |
| 747 |
| 748 default: |
| 749 return result; |
| 750 } |
| 751 } |
| 752 } |
| 753 |
| 754 |
| 755 Expression PreParser::ParseNewExpression(bool* ok) { |
| 756 // NewExpression :: |
| 757 // ('new')+ MemberExpression |
| 758 |
| 759 // The grammar for new expressions is pretty warped. The keyword |
| 760 // 'new' can either be a part of the new expression (where it isn't |
| 761 // followed by an argument list) or a part of the member expression, |
| 762 // where it must be followed by an argument list. To accommodate |
| 763 // this, we parse the 'new' keywords greedily and keep track of how |
| 764 // many we have parsed. This information is then passed on to the |
| 765 // member expression parser, which is only allowed to match argument |
| 766 // lists as long as it has 'new' prefixes left |
| 767 unsigned new_count = 0; |
| 768 do { |
| 769 Consume(i::Token::NEW); |
| 770 new_count++; |
| 771 } while (peek() == i::Token::NEW); |
| 772 |
| 773 return ParseMemberWithNewPrefixesExpression(new_count, ok); |
| 774 } |
| 775 |
| 776 |
| 777 Expression PreParser::ParseMemberExpression(bool* ok) { |
| 778 return ParseMemberWithNewPrefixesExpression(0, ok); |
| 779 } |
| 780 |
| 781 |
| 782 Expression PreParser::ParseMemberWithNewPrefixesExpression( |
| 783 unsigned new_count, bool* ok) { |
| 784 // MemberExpression :: |
| 785 // (PrimaryExpression | FunctionLiteral) |
| 786 // ('[' Expression ']' | '.' Identifier | Arguments)* |
| 787 |
| 788 // Parse the initial primary or function expression. |
| 789 Expression result = kUnknownExpression; |
| 790 if (peek() == i::Token::FUNCTION) { |
| 791 Consume(i::Token::FUNCTION); |
| 792 if (peek() == i::Token::IDENTIFIER) { |
| 793 ParseIdentifier(CHECK_OK); |
| 794 } |
| 795 result = ParseFunctionLiteral(CHECK_OK); |
| 796 } else { |
| 797 result = ParsePrimaryExpression(CHECK_OK); |
| 798 } |
| 799 |
| 800 while (true) { |
| 801 switch (peek()) { |
| 802 case i::Token::LBRACK: { |
| 803 Consume(i::Token::LBRACK); |
| 804 ParseExpression(true, CHECK_OK); |
| 805 Expect(i::Token::RBRACK, CHECK_OK); |
| 806 if (result == kThisExpression) { |
| 807 result = kThisPropertyExpression; |
| 808 } else { |
| 809 result = kUnknownExpression; |
| 810 } |
| 811 break; |
| 812 } |
| 813 case i::Token::PERIOD: { |
| 814 Consume(i::Token::PERIOD); |
| 815 ParseIdentifierName(CHECK_OK); |
| 816 if (result == kThisExpression) { |
| 817 result = kThisPropertyExpression; |
| 818 } else { |
| 819 result = kUnknownExpression; |
| 820 } |
| 821 break; |
| 822 } |
| 823 case i::Token::LPAREN: { |
| 824 if (new_count == 0) return result; |
| 825 // Consume one of the new prefixes (already parsed). |
| 826 ParseArguments(CHECK_OK); |
| 827 new_count--; |
| 828 result = kUnknownExpression; |
| 829 break; |
| 830 } |
| 831 default: |
| 832 return result; |
| 833 } |
| 834 } |
| 835 } |
| 836 |
| 837 |
| 838 Expression PreParser::ParsePrimaryExpression(bool* ok) { |
| 839 // PrimaryExpression :: |
| 840 // 'this' |
| 841 // 'null' |
| 842 // 'true' |
| 843 // 'false' |
| 844 // Identifier |
| 845 // Number |
| 846 // String |
| 847 // ArrayLiteral |
| 848 // ObjectLiteral |
| 849 // RegExpLiteral |
| 850 // '(' Expression ')' |
| 851 |
| 852 Expression result = kUnknownExpression; |
| 853 switch (peek()) { |
| 854 case i::Token::THIS: { |
| 855 Next(); |
| 856 result = kThisExpression; |
| 857 break; |
| 858 } |
| 859 |
| 860 case i::Token::IDENTIFIER: { |
| 861 ParseIdentifier(CHECK_OK); |
| 862 result = kIdentifierExpression; |
| 863 break; |
| 864 } |
| 865 |
| 866 case i::Token::NULL_LITERAL: |
| 867 case i::Token::TRUE_LITERAL: |
| 868 case i::Token::FALSE_LITERAL: |
| 869 case i::Token::NUMBER: { |
| 870 Next(); |
| 871 break; |
| 872 } |
| 873 case i::Token::STRING: { |
| 874 Next(); |
| 875 result = GetStringSymbol(); |
| 876 break; |
| 877 } |
| 878 |
| 879 case i::Token::ASSIGN_DIV: |
| 880 result = ParseRegExpLiteral(true, CHECK_OK); |
| 881 break; |
| 882 |
| 883 case i::Token::DIV: |
| 884 result = ParseRegExpLiteral(false, CHECK_OK); |
| 885 break; |
| 886 |
| 887 case i::Token::LBRACK: |
| 888 result = ParseArrayLiteral(CHECK_OK); |
| 889 break; |
| 890 |
| 891 case i::Token::LBRACE: |
| 892 result = ParseObjectLiteral(CHECK_OK); |
| 893 break; |
| 894 |
| 895 case i::Token::LPAREN: |
| 896 Consume(i::Token::LPAREN); |
| 897 result = ParseExpression(true, CHECK_OK); |
| 898 Expect(i::Token::RPAREN, CHECK_OK); |
| 899 if (result == kIdentifierExpression) result = kUnknownExpression; |
| 900 break; |
| 901 |
| 902 case i::Token::MOD: |
| 903 result = ParseV8Intrinsic(CHECK_OK); |
| 904 break; |
| 905 |
| 906 default: { |
| 907 Next(); |
| 908 *ok = false; |
| 909 return kUnknownExpression; |
| 910 } |
| 911 } |
| 912 |
| 913 return result; |
| 914 } |
| 915 |
| 916 |
| 917 Expression PreParser::ParseArrayLiteral(bool* ok) { |
| 918 // ArrayLiteral :: |
| 919 // '[' Expression? (',' Expression?)* ']' |
| 920 Expect(i::Token::LBRACK, CHECK_OK); |
| 921 while (peek() != i::Token::RBRACK) { |
| 922 if (peek() != i::Token::COMMA) { |
| 923 ParseAssignmentExpression(true, CHECK_OK); |
| 924 } |
| 925 if (peek() != i::Token::RBRACK) { |
| 926 Expect(i::Token::COMMA, CHECK_OK); |
| 927 } |
| 928 } |
| 929 Expect(i::Token::RBRACK, CHECK_OK); |
| 930 |
| 931 scope_->NextMaterializedLiteralIndex(); |
| 932 return kUnknownExpression; |
| 933 } |
| 934 |
| 935 |
| 936 Expression PreParser::ParseObjectLiteral(bool* ok) { |
| 937 // ObjectLiteral :: |
| 938 // '{' ( |
| 939 // ((IdentifierName | String | Number) ':' AssignmentExpression) |
| 940 // | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral) |
| 941 // )*[','] '}' |
| 942 |
| 943 Expect(i::Token::LBRACE, CHECK_OK); |
| 944 while (peek() != i::Token::RBRACE) { |
| 945 i::Token::Value next = peek(); |
| 946 switch (next) { |
| 947 case i::Token::IDENTIFIER: { |
| 948 bool is_getter = false; |
| 949 bool is_setter = false; |
| 950 ParseIdentifierOrGetOrSet(&is_getter, &is_setter, CHECK_OK); |
| 951 if ((is_getter || is_setter) && peek() != i::Token::COLON) { |
| 952 i::Token::Value name = Next(); |
| 953 if (name != i::Token::IDENTIFIER && |
| 954 name != i::Token::NUMBER && |
| 955 name != i::Token::STRING && |
| 956 !i::Token::IsKeyword(name)) { |
| 957 *ok = false; |
| 958 return kUnknownExpression; |
| 959 } |
| 960 ParseFunctionLiteral(CHECK_OK); |
| 961 if (peek() != i::Token::RBRACE) { |
| 962 Expect(i::Token::COMMA, CHECK_OK); |
| 963 } |
| 964 continue; // restart the while |
| 965 } |
| 966 break; |
| 967 } |
| 968 case i::Token::STRING: |
| 969 Consume(next); |
| 970 GetStringSymbol(); |
| 971 break; |
| 972 case i::Token::NUMBER: |
| 973 Consume(next); |
| 974 break; |
| 975 default: |
| 976 if (i::Token::IsKeyword(next)) { |
| 977 Consume(next); |
| 978 } else { |
| 979 // Unexpected token. |
| 980 *ok = false; |
| 981 return kUnknownExpression; |
| 982 } |
| 983 } |
| 984 |
| 985 Expect(i::Token::COLON, CHECK_OK); |
| 986 ParseAssignmentExpression(true, CHECK_OK); |
| 987 |
| 988 // TODO(1240767): Consider allowing trailing comma. |
| 989 if (peek() != i::Token::RBRACE) Expect(i::Token::COMMA, CHECK_OK); |
| 990 } |
| 991 Expect(i::Token::RBRACE, CHECK_OK); |
| 992 |
| 993 scope_->NextMaterializedLiteralIndex(); |
| 994 return kUnknownExpression; |
| 995 } |
| 996 |
| 997 |
| 998 Expression PreParser::ParseRegExpLiteral(bool seen_equal, |
| 999 bool* ok) { |
| 1000 if (!scanner_->ScanRegExpPattern(seen_equal)) { |
| 1001 Next(); |
| 1002 i::JavaScriptScanner::Location location = scanner_->location(); |
| 1003 ReportMessageAt(location.beg_pos, location.end_pos, |
| 1004 "unterminated_regexp", NULL); |
| 1005 *ok = false; |
| 1006 return kUnknownExpression; |
| 1007 } |
| 1008 |
| 1009 scope_->NextMaterializedLiteralIndex(); |
| 1010 |
| 1011 if (!scanner_->ScanRegExpFlags()) { |
| 1012 Next(); |
| 1013 i::JavaScriptScanner::Location location = scanner_->location(); |
| 1014 ReportMessageAt(location.beg_pos, location.end_pos, |
| 1015 "invalid_regexp_flags", NULL); |
| 1016 *ok = false; |
| 1017 return kUnknownExpression; |
| 1018 } |
| 1019 Next(); |
| 1020 return kUnknownExpression; |
| 1021 } |
| 1022 |
| 1023 |
| 1024 Arguments PreParser::ParseArguments(bool* ok) { |
| 1025 // Arguments :: |
| 1026 // '(' (AssignmentExpression)*[','] ')' |
| 1027 |
| 1028 Expect(i::Token::LPAREN, CHECK_OK); |
| 1029 bool done = (peek() == i::Token::RPAREN); |
| 1030 int argc = 0; |
| 1031 while (!done) { |
| 1032 ParseAssignmentExpression(true, CHECK_OK); |
| 1033 argc++; |
| 1034 done = (peek() == i::Token::RPAREN); |
| 1035 if (!done) Expect(i::Token::COMMA, CHECK_OK); |
| 1036 } |
| 1037 Expect(i::Token::RPAREN, CHECK_OK); |
| 1038 return argc; |
| 1039 } |
| 1040 |
| 1041 |
| 1042 Expression PreParser::ParseFunctionLiteral(bool* ok) { |
| 1043 // Function :: |
| 1044 // '(' FormalParameterList? ')' '{' FunctionBody '}' |
| 1045 |
| 1046 // Parse function body. |
| 1047 ScopeType outer_scope_type = scope_->type(); |
| 1048 bool inside_with = scope_->IsInsideWith(); |
| 1049 Scope function_scope(&scope_, kFunctionScope); |
| 1050 |
| 1051 // FormalParameterList :: |
| 1052 // '(' (Identifier)*[','] ')' |
| 1053 Expect(i::Token::LPAREN, CHECK_OK); |
| 1054 bool done = (peek() == i::Token::RPAREN); |
| 1055 while (!done) { |
| 1056 ParseIdentifier(CHECK_OK); |
| 1057 done = (peek() == i::Token::RPAREN); |
| 1058 if (!done) { |
| 1059 Expect(i::Token::COMMA, CHECK_OK); |
| 1060 } |
| 1061 } |
| 1062 Expect(i::Token::RPAREN, CHECK_OK); |
| 1063 |
| 1064 Expect(i::Token::LBRACE, CHECK_OK); |
| 1065 int function_block_pos = scanner_->location().beg_pos; |
| 1066 |
| 1067 // Determine if the function will be lazily compiled. |
| 1068 // Currently only happens to top-level functions. |
| 1069 // Optimistically assume that all top-level functions are lazily compiled. |
| 1070 bool is_lazily_compiled = |
| 1071 (outer_scope_type == kTopLevelScope && !inside_with && allow_lazy_); |
| 1072 |
| 1073 if (is_lazily_compiled) { |
| 1074 log_->PauseRecording(); |
| 1075 ParseSourceElements(i::Token::RBRACE, ok); |
| 1076 log_->ResumeRecording(); |
| 1077 if (!*ok) return kUnknownExpression; |
| 1078 |
| 1079 Expect(i::Token::RBRACE, CHECK_OK); |
| 1080 |
| 1081 int end_pos = scanner_->location().end_pos; |
| 1082 log_->LogFunction(function_block_pos, end_pos, |
| 1083 function_scope.materialized_literal_count(), |
| 1084 function_scope.expected_properties()); |
| 1085 } else { |
| 1086 ParseSourceElements(i::Token::RBRACE, CHECK_OK); |
| 1087 Expect(i::Token::RBRACE, CHECK_OK); |
| 1088 } |
| 1089 return kUnknownExpression; |
| 1090 } |
| 1091 |
| 1092 |
| 1093 Expression PreParser::ParseV8Intrinsic(bool* ok) { |
| 1094 // CallRuntime :: |
| 1095 // '%' Identifier Arguments |
| 1096 |
| 1097 Expect(i::Token::MOD, CHECK_OK); |
| 1098 ParseIdentifier(CHECK_OK); |
| 1099 ParseArguments(CHECK_OK); |
| 1100 |
| 1101 return kUnknownExpression; |
| 1102 } |
| 1103 |
| 1104 |
| 1105 void PreParser::ExpectSemicolon(bool* ok) { |
| 1106 // Check for automatic semicolon insertion according to |
| 1107 // the rules given in ECMA-262, section 7.9, page 21. |
| 1108 i::Token::Value tok = peek(); |
| 1109 if (tok == i::Token::SEMICOLON) { |
| 1110 Next(); |
| 1111 return; |
| 1112 } |
| 1113 if (scanner_->has_line_terminator_before_next() || |
| 1114 tok == i::Token::RBRACE || |
| 1115 tok == i::Token::EOS) { |
| 1116 return; |
| 1117 } |
| 1118 Expect(i::Token::SEMICOLON, ok); |
| 1119 } |
| 1120 |
| 1121 |
| 1122 Identifier PreParser::GetIdentifierSymbol() { |
| 1123 const char* literal_chars = scanner_->literal_string(); |
| 1124 int literal_length = scanner_->literal_length(); |
| 1125 int identifier_pos = scanner_->location().beg_pos; |
| 1126 |
| 1127 log_->LogSymbol(identifier_pos, literal_chars, literal_length); |
| 1128 |
| 1129 return kUnknownExpression; |
| 1130 } |
| 1131 |
| 1132 |
| 1133 Expression PreParser::GetStringSymbol() { |
| 1134 const char* literal_chars = scanner_->literal_string(); |
| 1135 int literal_length = scanner_->literal_length(); |
| 1136 |
| 1137 int literal_position = scanner_->location().beg_pos; |
| 1138 log_->LogSymbol(literal_position, literal_chars, literal_length); |
| 1139 |
| 1140 return kUnknownExpression; |
| 1141 } |
| 1142 |
| 1143 |
| 1144 Identifier PreParser::ParseIdentifier(bool* ok) { |
| 1145 Expect(i::Token::IDENTIFIER, ok); |
| 1146 if (!*ok) return kUnknownIdentifier; |
| 1147 return GetIdentifierSymbol(); |
| 1148 } |
| 1149 |
| 1150 |
| 1151 Identifier PreParser::ParseIdentifierName(bool* ok) { |
| 1152 i::Token::Value next = Next(); |
| 1153 if (i::Token::IsKeyword(next)) { |
| 1154 int pos = scanner_->location().beg_pos; |
| 1155 const char* keyword = i::Token::String(next); |
| 1156 log_->LogSymbol(pos, keyword, i::StrLength(keyword)); |
| 1157 return kUnknownExpression; |
| 1158 } |
| 1159 if (next == i::Token::IDENTIFIER) { |
| 1160 return GetIdentifierSymbol(); |
| 1161 } |
| 1162 *ok = false; |
| 1163 return kUnknownIdentifier; |
| 1164 } |
| 1165 |
| 1166 |
| 1167 // This function reads an identifier and determines whether or not it |
| 1168 // is 'get' or 'set'. The reason for not using ParseIdentifier and |
| 1169 // checking on the output is that this involves heap allocation which |
| 1170 // we can't do during preparsing. |
| 1171 Identifier PreParser::ParseIdentifierOrGetOrSet(bool* is_get, |
| 1172 bool* is_set, |
| 1173 bool* ok) { |
| 1174 Expect(i::Token::IDENTIFIER, CHECK_OK); |
| 1175 if (scanner_->literal_length() == 3) { |
| 1176 const char* token = scanner_->literal_string(); |
| 1177 *is_get = strncmp(token, "get", 3) == 0; |
| 1178 *is_set = !*is_get && strncmp(token, "set", 3) == 0; |
| 1179 } |
| 1180 return GetIdentifierSymbol(); |
| 1181 } |
| 1182 |
| 1183 #undef CHECK_OK |
| 1184 } } // v8::preparser |
OLD | NEW |