| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #ifndef V8_PREPARSER_H | 28 #ifndef V8_PREPARSER_H |
| 29 #define V8_PREPARSER_H | 29 #define V8_PREPARSER_H |
| 30 | 30 |
| 31 #include "unicode.h" | |
| 32 #include "utils.h" | |
| 33 | |
| 34 namespace v8 { | 31 namespace v8 { |
| 35 namespace preparser { | 32 namespace preparser { |
| 36 | 33 |
| 37 // Preparsing checks a JavaScript program and emits preparse-data that helps | 34 // Preparsing checks a JavaScript program and emits preparse-data that helps |
| 38 // a later parsing to be faster. | 35 // a later parsing to be faster. |
| 39 // See preparser-data.h for the data. | 36 // See preparse-data.h for the data. |
| 40 | 37 |
| 41 // The PreParser checks that the syntax follows the grammar for JavaScript, | 38 // The PreParser checks that the syntax follows the grammar for JavaScript, |
| 42 // and collects some information about the program along the way. | 39 // and collects some information about the program along the way. |
| 43 // The grammar check is only performed in order to understand the program | 40 // The grammar check is only performed in order to understand the program |
| 44 // sufficiently to deduce some information about it, that can be used | 41 // sufficiently to deduce some information about it, that can be used |
| 45 // to speed up later parsing. Finding errors is not the goal of pre-parsing, | 42 // to speed up later parsing. Finding errors is not the goal of pre-parsing, |
| 46 // rather it is to speed up properly written and correct programs. | 43 // rather it is to speed up properly written and correct programs. |
| 47 // That means that contextual checks (like a label being declared where | 44 // That means that contextual checks (like a label being declared where |
| 48 // it is used) are generally omitted. | 45 // it is used) are generally omitted. |
| 49 | 46 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 69 }; | 66 }; |
| 70 | 67 |
| 71 | 68 |
| 72 typedef int SourceElements; | 69 typedef int SourceElements; |
| 73 typedef int Expression; | 70 typedef int Expression; |
| 74 typedef int Statement; | 71 typedef int Statement; |
| 75 typedef int Identifier; | 72 typedef int Identifier; |
| 76 typedef int Arguments; | 73 typedef int Arguments; |
| 77 | 74 |
| 78 | 75 |
| 79 template <typename Scanner, typename PreParserLog> | |
| 80 class PreParser { | 76 class PreParser { |
| 81 public: | 77 public: |
| 82 PreParser() : scope_(NULL), allow_lazy_(true) { } | 78 PreParser() : scope_(NULL), allow_lazy_(true) { } |
| 83 ~PreParser() { } | 79 ~PreParser() { } |
| 84 | 80 |
| 85 // Pre-parse the program from the character stream; returns true on | 81 // Pre-parse the program from the character stream; returns true on |
| 86 // success (even if parsing failed, the pre-parse data successfully | 82 // success (even if parsing failed, the pre-parse data successfully |
| 87 // captured the syntax error), and false if a stack-overflow happened | 83 // captured the syntax error), and false if a stack-overflow happened |
| 88 // during parsing. | 84 // during parsing. |
| 89 bool PreParseProgram(Scanner* scanner, | 85 bool PreParseProgram(i::JavaScriptScanner* scanner, |
| 90 PreParserLog* log, | 86 i::ParserRecorder* log, |
| 91 bool allow_lazy) { | 87 bool allow_lazy) { |
| 92 allow_lazy_ = allow_lazy; | 88 allow_lazy_ = allow_lazy; |
| 93 scanner_ = scanner; | 89 scanner_ = scanner; |
| 94 log_ = log; | 90 log_ = log; |
| 95 Scope top_scope(&scope_, kTopLevelScope); | 91 Scope top_scope(&scope_, kTopLevelScope); |
| 96 bool ok = true; | 92 bool ok = true; |
| 97 ParseSourceElements(i::Token::EOS, &ok); | 93 ParseSourceElements(i::Token::EOS, &ok); |
| 98 bool stack_overflow = scanner_->stack_overflow(); | 94 bool stack_overflow = scanner_->stack_overflow(); |
| 99 if (!ok && !stack_overflow) { | 95 if (!ok && !stack_overflow) { |
| 100 ReportUnexpectedToken(scanner_->current_token()); | 96 ReportUnexpectedToken(scanner_->current_token()); |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 228 if (next == token) { | 224 if (next == token) { |
| 229 Consume(next); | 225 Consume(next); |
| 230 return true; | 226 return true; |
| 231 } | 227 } |
| 232 return false; | 228 return false; |
| 233 } | 229 } |
| 234 void ExpectSemicolon(bool* ok); | 230 void ExpectSemicolon(bool* ok); |
| 235 | 231 |
| 236 static int Precedence(i::Token::Value tok, bool accept_IN); | 232 static int Precedence(i::Token::Value tok, bool accept_IN); |
| 237 | 233 |
| 238 Scanner* scanner_; | 234 i::JavaScriptScanner* scanner_; |
| 239 PreParserLog* log_; | 235 i::ParserRecorder* log_; |
| 240 Scope* scope_; | 236 Scope* scope_; |
| 241 bool allow_lazy_; | 237 bool allow_lazy_; |
| 242 }; | 238 }; |
| 243 | |
| 244 | |
| 245 #define CHECK_OK ok); \ | |
| 246 if (!*ok) return -1; \ | |
| 247 ((void)0 | |
| 248 #define DUMMY ) // to make indentation work | |
| 249 #undef DUMMY | |
| 250 | |
| 251 | |
| 252 template <typename Scanner, typename Log> | |
| 253 void PreParser<Scanner, Log>::ReportUnexpectedToken(i::Token::Value token) { | |
| 254 // We don't report stack overflows here, to avoid increasing the | |
| 255 // stack depth even further. Instead we report it after parsing is | |
| 256 // over, in ParseProgram. | |
| 257 if (token == i::Token::ILLEGAL && scanner_->stack_overflow()) { | |
| 258 return; | |
| 259 } | |
| 260 typename Scanner::Location source_location = scanner_->location(); | |
| 261 | |
| 262 // Four of the tokens are treated specially | |
| 263 switch (token) { | |
| 264 case i::Token::EOS: | |
| 265 return ReportMessageAt(source_location.beg_pos, source_location.end_pos, | |
| 266 "unexpected_eos", NULL); | |
| 267 case i::Token::NUMBER: | |
| 268 return ReportMessageAt(source_location.beg_pos, source_location.end_pos, | |
| 269 "unexpected_token_number", NULL); | |
| 270 case i::Token::STRING: | |
| 271 return ReportMessageAt(source_location.beg_pos, source_location.end_pos, | |
| 272 "unexpected_token_string", NULL); | |
| 273 case i::Token::IDENTIFIER: | |
| 274 return ReportMessageAt(source_location.beg_pos, source_location.end_pos, | |
| 275 "unexpected_token_identifier", NULL); | |
| 276 default: | |
| 277 const char* name = i::Token::String(token); | |
| 278 ReportMessageAt(source_location.beg_pos, source_location.end_pos, | |
| 279 "unexpected_token", name); | |
| 280 } | |
| 281 } | |
| 282 | |
| 283 | |
| 284 template <typename Scanner, typename Log> | |
| 285 SourceElements PreParser<Scanner, Log>::ParseSourceElements(int end_token, | |
| 286 bool* ok) { | |
| 287 // SourceElements :: | |
| 288 // (Statement)* <end_token> | |
| 289 | |
| 290 while (peek() != end_token) { | |
| 291 ParseStatement(CHECK_OK); | |
| 292 } | |
| 293 return kUnknownSourceElements; | |
| 294 } | |
| 295 | |
| 296 | |
| 297 template <typename Scanner, typename Log> | |
| 298 Statement PreParser<Scanner, Log>::ParseStatement(bool* ok) { | |
| 299 // Statement :: | |
| 300 // Block | |
| 301 // VariableStatement | |
| 302 // EmptyStatement | |
| 303 // ExpressionStatement | |
| 304 // IfStatement | |
| 305 // IterationStatement | |
| 306 // ContinueStatement | |
| 307 // BreakStatement | |
| 308 // ReturnStatement | |
| 309 // WithStatement | |
| 310 // LabelledStatement | |
| 311 // SwitchStatement | |
| 312 // ThrowStatement | |
| 313 // TryStatement | |
| 314 // DebuggerStatement | |
| 315 | |
| 316 // Note: Since labels can only be used by 'break' and 'continue' | |
| 317 // statements, which themselves are only valid within blocks, | |
| 318 // iterations or 'switch' statements (i.e., BreakableStatements), | |
| 319 // labels can be simply ignored in all other cases; except for | |
| 320 // trivial labeled break statements 'label: break label' which is | |
| 321 // parsed into an empty statement. | |
| 322 | |
| 323 // Keep the source position of the statement | |
| 324 switch (peek()) { | |
| 325 case i::Token::LBRACE: | |
| 326 return ParseBlock(ok); | |
| 327 | |
| 328 case i::Token::CONST: | |
| 329 case i::Token::VAR: | |
| 330 return ParseVariableStatement(ok); | |
| 331 | |
| 332 case i::Token::SEMICOLON: | |
| 333 Next(); | |
| 334 return kUnknownStatement; | |
| 335 | |
| 336 case i::Token::IF: | |
| 337 return ParseIfStatement(ok); | |
| 338 | |
| 339 case i::Token::DO: | |
| 340 return ParseDoWhileStatement(ok); | |
| 341 | |
| 342 case i::Token::WHILE: | |
| 343 return ParseWhileStatement(ok); | |
| 344 | |
| 345 case i::Token::FOR: | |
| 346 return ParseForStatement(ok); | |
| 347 | |
| 348 case i::Token::CONTINUE: | |
| 349 return ParseContinueStatement(ok); | |
| 350 | |
| 351 case i::Token::BREAK: | |
| 352 return ParseBreakStatement(ok); | |
| 353 | |
| 354 case i::Token::RETURN: | |
| 355 return ParseReturnStatement(ok); | |
| 356 | |
| 357 case i::Token::WITH: | |
| 358 return ParseWithStatement(ok); | |
| 359 | |
| 360 case i::Token::SWITCH: | |
| 361 return ParseSwitchStatement(ok); | |
| 362 | |
| 363 case i::Token::THROW: | |
| 364 return ParseThrowStatement(ok); | |
| 365 | |
| 366 case i::Token::TRY: | |
| 367 return ParseTryStatement(ok); | |
| 368 | |
| 369 case i::Token::FUNCTION: | |
| 370 return ParseFunctionDeclaration(ok); | |
| 371 | |
| 372 case i::Token::NATIVE: | |
| 373 return ParseNativeDeclaration(ok); | |
| 374 | |
| 375 case i::Token::DEBUGGER: | |
| 376 return ParseDebuggerStatement(ok); | |
| 377 | |
| 378 default: | |
| 379 return ParseExpressionOrLabelledStatement(ok); | |
| 380 } | |
| 381 } | |
| 382 | |
| 383 | |
| 384 template <typename Scanner, typename Log> | |
| 385 Statement PreParser<Scanner, Log>::ParseFunctionDeclaration(bool* ok) { | |
| 386 // FunctionDeclaration :: | |
| 387 // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}' | |
| 388 Expect(i::Token::FUNCTION, CHECK_OK); | |
| 389 ParseIdentifier(CHECK_OK); | |
| 390 ParseFunctionLiteral(CHECK_OK); | |
| 391 return kUnknownStatement; | |
| 392 } | |
| 393 | |
| 394 | |
| 395 // Language extension which is only enabled for source files loaded | |
| 396 // through the API's extension mechanism. A native function | |
| 397 // declaration is resolved by looking up the function through a | |
| 398 // callback provided by the extension. | |
| 399 template <typename Scanner, typename Log> | |
| 400 Statement PreParser<Scanner, Log>::ParseNativeDeclaration(bool* ok) { | |
| 401 Expect(i::Token::NATIVE, CHECK_OK); | |
| 402 Expect(i::Token::FUNCTION, CHECK_OK); | |
| 403 ParseIdentifier(CHECK_OK); | |
| 404 Expect(i::Token::LPAREN, CHECK_OK); | |
| 405 bool done = (peek() == i::Token::RPAREN); | |
| 406 while (!done) { | |
| 407 ParseIdentifier(CHECK_OK); | |
| 408 done = (peek() == i::Token::RPAREN); | |
| 409 if (!done) { | |
| 410 Expect(i::Token::COMMA, CHECK_OK); | |
| 411 } | |
| 412 } | |
| 413 Expect(i::Token::RPAREN, CHECK_OK); | |
| 414 Expect(i::Token::SEMICOLON, CHECK_OK); | |
| 415 return kUnknownStatement; | |
| 416 } | |
| 417 | |
| 418 | |
| 419 template <typename Scanner, typename Log> | |
| 420 Statement PreParser<Scanner, Log>::ParseBlock(bool* ok) { | |
| 421 // Block :: | |
| 422 // '{' Statement* '}' | |
| 423 | |
| 424 // Note that a Block does not introduce a new execution scope! | |
| 425 // (ECMA-262, 3rd, 12.2) | |
| 426 // | |
| 427 Expect(i::Token::LBRACE, CHECK_OK); | |
| 428 while (peek() != i::Token::RBRACE) { | |
| 429 ParseStatement(CHECK_OK); | |
| 430 } | |
| 431 Expect(i::Token::RBRACE, CHECK_OK); | |
| 432 return kUnknownStatement; | |
| 433 } | |
| 434 | |
| 435 | |
| 436 template <typename Scanner, typename Log> | |
| 437 Statement PreParser<Scanner, Log>::ParseVariableStatement(bool* ok) { | |
| 438 // VariableStatement :: | |
| 439 // VariableDeclarations ';' | |
| 440 | |
| 441 Statement result = ParseVariableDeclarations(true, NULL, CHECK_OK); | |
| 442 ExpectSemicolon(CHECK_OK); | |
| 443 return result; | |
| 444 } | |
| 445 | |
| 446 | |
| 447 // If the variable declaration declares exactly one non-const | |
| 448 // variable, then *var is set to that variable. In all other cases, | |
| 449 // *var is untouched; in particular, it is the caller's responsibility | |
| 450 // to initialize it properly. This mechanism is also used for the parsing | |
| 451 // of 'for-in' loops. | |
| 452 template <typename Scanner, typename Log> | |
| 453 Statement PreParser<Scanner, Log>::ParseVariableDeclarations(bool accept_IN, | |
| 454 int* num_decl, | |
| 455 bool* ok) { | |
| 456 // VariableDeclarations :: | |
| 457 // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[','] | |
| 458 | |
| 459 if (peek() == i::Token::VAR) { | |
| 460 Consume(i::Token::VAR); | |
| 461 } else if (peek() == i::Token::CONST) { | |
| 462 Consume(i::Token::CONST); | |
| 463 } else { | |
| 464 *ok = false; | |
| 465 return 0; | |
| 466 } | |
| 467 | |
| 468 // The scope of a variable/const declared anywhere inside a function | |
| 469 // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). . | |
| 470 int nvars = 0; // the number of variables declared | |
| 471 do { | |
| 472 // Parse variable name. | |
| 473 if (nvars > 0) Consume(i::Token::COMMA); | |
| 474 ParseIdentifier(CHECK_OK); | |
| 475 nvars++; | |
| 476 if (peek() == i::Token::ASSIGN) { | |
| 477 Expect(i::Token::ASSIGN, CHECK_OK); | |
| 478 ParseAssignmentExpression(accept_IN, CHECK_OK); | |
| 479 } | |
| 480 } while (peek() == i::Token::COMMA); | |
| 481 | |
| 482 if (num_decl != NULL) *num_decl = nvars; | |
| 483 return kUnknownStatement; | |
| 484 } | |
| 485 | |
| 486 | |
| 487 template <typename Scanner, typename Log> | |
| 488 Statement PreParser<Scanner, Log>::ParseExpressionOrLabelledStatement( | |
| 489 bool* ok) { | |
| 490 // ExpressionStatement | LabelledStatement :: | |
| 491 // Expression ';' | |
| 492 // Identifier ':' Statement | |
| 493 | |
| 494 Expression expr = ParseExpression(true, CHECK_OK); | |
| 495 if (peek() == i::Token::COLON && expr == kIdentifierExpression) { | |
| 496 Consume(i::Token::COLON); | |
| 497 return ParseStatement(ok); | |
| 498 } | |
| 499 // Parsed expression statement. | |
| 500 ExpectSemicolon(CHECK_OK); | |
| 501 return kUnknownStatement; | |
| 502 } | |
| 503 | |
| 504 | |
| 505 template <typename Scanner, typename Log> | |
| 506 Statement PreParser<Scanner, Log>::ParseIfStatement(bool* ok) { | |
| 507 // IfStatement :: | |
| 508 // 'if' '(' Expression ')' Statement ('else' Statement)? | |
| 509 | |
| 510 Expect(i::Token::IF, CHECK_OK); | |
| 511 Expect(i::Token::LPAREN, CHECK_OK); | |
| 512 ParseExpression(true, CHECK_OK); | |
| 513 Expect(i::Token::RPAREN, CHECK_OK); | |
| 514 ParseStatement(CHECK_OK); | |
| 515 if (peek() == i::Token::ELSE) { | |
| 516 Next(); | |
| 517 ParseStatement(CHECK_OK); | |
| 518 } | |
| 519 return kUnknownStatement; | |
| 520 } | |
| 521 | |
| 522 | |
| 523 template <typename Scanner, typename Log> | |
| 524 Statement PreParser<Scanner, Log>::ParseContinueStatement(bool* ok) { | |
| 525 // ContinueStatement :: | |
| 526 // 'continue' [no line terminator] Identifier? ';' | |
| 527 | |
| 528 Expect(i::Token::CONTINUE, CHECK_OK); | |
| 529 i::Token::Value tok = peek(); | |
| 530 if (!scanner_->has_line_terminator_before_next() && | |
| 531 tok != i::Token::SEMICOLON && | |
| 532 tok != i::Token::RBRACE && | |
| 533 tok != i::Token::EOS) { | |
| 534 ParseIdentifier(CHECK_OK); | |
| 535 } | |
| 536 ExpectSemicolon(CHECK_OK); | |
| 537 return kUnknownStatement; | |
| 538 } | |
| 539 | |
| 540 | |
| 541 template <typename Scanner, typename Log> | |
| 542 Statement PreParser<Scanner, Log>::ParseBreakStatement(bool* ok) { | |
| 543 // BreakStatement :: | |
| 544 // 'break' [no line terminator] Identifier? ';' | |
| 545 | |
| 546 Expect(i::Token::BREAK, CHECK_OK); | |
| 547 i::Token::Value tok = peek(); | |
| 548 if (!scanner_->has_line_terminator_before_next() && | |
| 549 tok != i::Token::SEMICOLON && | |
| 550 tok != i::Token::RBRACE && | |
| 551 tok != i::Token::EOS) { | |
| 552 ParseIdentifier(CHECK_OK); | |
| 553 } | |
| 554 ExpectSemicolon(CHECK_OK); | |
| 555 return kUnknownStatement; | |
| 556 } | |
| 557 | |
| 558 | |
| 559 template <typename Scanner, typename Log> | |
| 560 Statement PreParser<Scanner, Log>::ParseReturnStatement(bool* ok) { | |
| 561 // ReturnStatement :: | |
| 562 // 'return' [no line terminator] Expression? ';' | |
| 563 | |
| 564 // Consume the return token. It is necessary to do the before | |
| 565 // reporting any errors on it, because of the way errors are | |
| 566 // reported (underlining). | |
| 567 Expect(i::Token::RETURN, CHECK_OK); | |
| 568 | |
| 569 // An ECMAScript program is considered syntactically incorrect if it | |
| 570 // contains a return statement that is not within the body of a | |
| 571 // function. See ECMA-262, section 12.9, page 67. | |
| 572 // This is not handled during preparsing. | |
| 573 | |
| 574 i::Token::Value tok = peek(); | |
| 575 if (!scanner_->has_line_terminator_before_next() && | |
| 576 tok != i::Token::SEMICOLON && | |
| 577 tok != i::Token::RBRACE && | |
| 578 tok != i::Token::EOS) { | |
| 579 ParseExpression(true, CHECK_OK); | |
| 580 } | |
| 581 ExpectSemicolon(CHECK_OK); | |
| 582 return kUnknownStatement; | |
| 583 } | |
| 584 | |
| 585 | |
| 586 template <typename Scanner, typename Log> | |
| 587 Statement PreParser<Scanner, Log>::ParseWithStatement(bool* ok) { | |
| 588 // WithStatement :: | |
| 589 // 'with' '(' Expression ')' Statement | |
| 590 Expect(i::Token::WITH, CHECK_OK); | |
| 591 Expect(i::Token::LPAREN, CHECK_OK); | |
| 592 ParseExpression(true, CHECK_OK); | |
| 593 Expect(i::Token::RPAREN, CHECK_OK); | |
| 594 | |
| 595 scope_->EnterWith(); | |
| 596 ParseStatement(CHECK_OK); | |
| 597 scope_->LeaveWith(); | |
| 598 return kUnknownStatement; | |
| 599 } | |
| 600 | |
| 601 | |
| 602 template <typename Scanner, typename Log> | |
| 603 Statement PreParser<Scanner, Log>::ParseSwitchStatement(bool* ok) { | |
| 604 // SwitchStatement :: | |
| 605 // 'switch' '(' Expression ')' '{' CaseClause* '}' | |
| 606 | |
| 607 Expect(i::Token::SWITCH, CHECK_OK); | |
| 608 Expect(i::Token::LPAREN, CHECK_OK); | |
| 609 ParseExpression(true, CHECK_OK); | |
| 610 Expect(i::Token::RPAREN, CHECK_OK); | |
| 611 | |
| 612 Expect(i::Token::LBRACE, CHECK_OK); | |
| 613 i::Token::Value token = peek(); | |
| 614 while (token != i::Token::RBRACE) { | |
| 615 if (token == i::Token::CASE) { | |
| 616 Expect(i::Token::CASE, CHECK_OK); | |
| 617 ParseExpression(true, CHECK_OK); | |
| 618 Expect(i::Token::COLON, CHECK_OK); | |
| 619 } else if (token == i::Token::DEFAULT) { | |
| 620 Expect(i::Token::DEFAULT, CHECK_OK); | |
| 621 Expect(i::Token::COLON, CHECK_OK); | |
| 622 } else { | |
| 623 ParseStatement(CHECK_OK); | |
| 624 } | |
| 625 token = peek(); | |
| 626 } | |
| 627 Expect(i::Token::RBRACE, CHECK_OK); | |
| 628 | |
| 629 return kUnknownStatement; | |
| 630 } | |
| 631 | |
| 632 | |
| 633 template <typename Scanner, typename Log> | |
| 634 Statement PreParser<Scanner, Log>::ParseDoWhileStatement(bool* ok) { | |
| 635 // DoStatement :: | |
| 636 // 'do' Statement 'while' '(' Expression ')' ';' | |
| 637 | |
| 638 Expect(i::Token::DO, CHECK_OK); | |
| 639 ParseStatement(CHECK_OK); | |
| 640 Expect(i::Token::WHILE, CHECK_OK); | |
| 641 Expect(i::Token::LPAREN, CHECK_OK); | |
| 642 ParseExpression(true, CHECK_OK); | |
| 643 Expect(i::Token::RPAREN, CHECK_OK); | |
| 644 return kUnknownStatement; | |
| 645 } | |
| 646 | |
| 647 | |
| 648 template <typename Scanner, typename Log> | |
| 649 Statement PreParser<Scanner, Log>::ParseWhileStatement(bool* ok) { | |
| 650 // WhileStatement :: | |
| 651 // 'while' '(' Expression ')' Statement | |
| 652 | |
| 653 Expect(i::Token::WHILE, CHECK_OK); | |
| 654 Expect(i::Token::LPAREN, CHECK_OK); | |
| 655 ParseExpression(true, CHECK_OK); | |
| 656 Expect(i::Token::RPAREN, CHECK_OK); | |
| 657 ParseStatement(CHECK_OK); | |
| 658 return kUnknownStatement; | |
| 659 } | |
| 660 | |
| 661 | |
| 662 template <typename Scanner, typename Log> | |
| 663 Statement PreParser<Scanner, Log>::ParseForStatement(bool* ok) { | |
| 664 // ForStatement :: | |
| 665 // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement | |
| 666 | |
| 667 Expect(i::Token::FOR, CHECK_OK); | |
| 668 Expect(i::Token::LPAREN, CHECK_OK); | |
| 669 if (peek() != i::Token::SEMICOLON) { | |
| 670 if (peek() == i::Token::VAR || peek() == i::Token::CONST) { | |
| 671 int decl_count; | |
| 672 ParseVariableDeclarations(false, &decl_count, CHECK_OK); | |
| 673 if (peek() == i::Token::IN && decl_count == 1) { | |
| 674 Expect(i::Token::IN, CHECK_OK); | |
| 675 ParseExpression(true, CHECK_OK); | |
| 676 Expect(i::Token::RPAREN, CHECK_OK); | |
| 677 | |
| 678 ParseStatement(CHECK_OK); | |
| 679 return kUnknownStatement; | |
| 680 } | |
| 681 } else { | |
| 682 ParseExpression(false, CHECK_OK); | |
| 683 if (peek() == i::Token::IN) { | |
| 684 Expect(i::Token::IN, CHECK_OK); | |
| 685 ParseExpression(true, CHECK_OK); | |
| 686 Expect(i::Token::RPAREN, CHECK_OK); | |
| 687 | |
| 688 ParseStatement(CHECK_OK); | |
| 689 return kUnknownStatement; | |
| 690 } | |
| 691 } | |
| 692 } | |
| 693 | |
| 694 // Parsed initializer at this point. | |
| 695 Expect(i::Token::SEMICOLON, CHECK_OK); | |
| 696 | |
| 697 if (peek() != i::Token::SEMICOLON) { | |
| 698 ParseExpression(true, CHECK_OK); | |
| 699 } | |
| 700 Expect(i::Token::SEMICOLON, CHECK_OK); | |
| 701 | |
| 702 if (peek() != i::Token::RPAREN) { | |
| 703 ParseExpression(true, CHECK_OK); | |
| 704 } | |
| 705 Expect(i::Token::RPAREN, CHECK_OK); | |
| 706 | |
| 707 ParseStatement(CHECK_OK); | |
| 708 return kUnknownStatement; | |
| 709 } | |
| 710 | |
| 711 | |
| 712 template <typename Scanner, typename Log> | |
| 713 Statement PreParser<Scanner, Log>::ParseThrowStatement(bool* ok) { | |
| 714 // ThrowStatement :: | |
| 715 // 'throw' [no line terminator] Expression ';' | |
| 716 | |
| 717 Expect(i::Token::THROW, CHECK_OK); | |
| 718 if (scanner_->has_line_terminator_before_next()) { | |
| 719 typename Scanner::Location pos = scanner_->location(); | |
| 720 ReportMessageAt(pos.beg_pos, pos.end_pos, | |
| 721 "newline_after_throw", NULL); | |
| 722 *ok = false; | |
| 723 return kUnknownStatement; | |
| 724 } | |
| 725 ParseExpression(true, CHECK_OK); | |
| 726 ExpectSemicolon(CHECK_OK); | |
| 727 | |
| 728 return kUnknownStatement; | |
| 729 } | |
| 730 | |
| 731 | |
| 732 template <typename Scanner, typename Log> | |
| 733 Statement PreParser<Scanner, Log>::ParseTryStatement(bool* ok) { | |
| 734 // TryStatement :: | |
| 735 // 'try' Block Catch | |
| 736 // 'try' Block Finally | |
| 737 // 'try' Block Catch Finally | |
| 738 // | |
| 739 // Catch :: | |
| 740 // 'catch' '(' Identifier ')' Block | |
| 741 // | |
| 742 // Finally :: | |
| 743 // 'finally' Block | |
| 744 | |
| 745 // In preparsing, allow any number of catch/finally blocks, including zero | |
| 746 // of both. | |
| 747 | |
| 748 Expect(i::Token::TRY, CHECK_OK); | |
| 749 | |
| 750 ParseBlock(CHECK_OK); | |
| 751 | |
| 752 bool catch_or_finally_seen = false; | |
| 753 if (peek() == i::Token::CATCH) { | |
| 754 Consume(i::Token::CATCH); | |
| 755 Expect(i::Token::LPAREN, CHECK_OK); | |
| 756 ParseIdentifier(CHECK_OK); | |
| 757 Expect(i::Token::RPAREN, CHECK_OK); | |
| 758 scope_->EnterWith(); | |
| 759 ParseBlock(ok); | |
| 760 scope_->LeaveWith(); | |
| 761 if (!*ok) return kUnknownStatement; | |
| 762 catch_or_finally_seen = true; | |
| 763 } | |
| 764 if (peek() == i::Token::FINALLY) { | |
| 765 Consume(i::Token::FINALLY); | |
| 766 ParseBlock(CHECK_OK); | |
| 767 catch_or_finally_seen = true; | |
| 768 } | |
| 769 if (!catch_or_finally_seen) { | |
| 770 *ok = false; | |
| 771 } | |
| 772 return kUnknownStatement; | |
| 773 } | |
| 774 | |
| 775 | |
| 776 template <typename Scanner, typename Log> | |
| 777 Statement PreParser<Scanner, Log>::ParseDebuggerStatement(bool* ok) { | |
| 778 // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser | |
| 779 // contexts this is used as a statement which invokes the debugger as if a | |
| 780 // break point is present. | |
| 781 // DebuggerStatement :: | |
| 782 // 'debugger' ';' | |
| 783 | |
| 784 Expect(i::Token::DEBUGGER, CHECK_OK); | |
| 785 ExpectSemicolon(CHECK_OK); | |
| 786 return kUnknownStatement; | |
| 787 } | |
| 788 | |
| 789 | |
| 790 // Precedence = 1 | |
| 791 template <typename Scanner, typename Log> | |
| 792 Expression PreParser<Scanner, Log>::ParseExpression(bool accept_IN, bool* ok) { | |
| 793 // Expression :: | |
| 794 // AssignmentExpression | |
| 795 // Expression ',' AssignmentExpression | |
| 796 | |
| 797 Expression result = ParseAssignmentExpression(accept_IN, CHECK_OK); | |
| 798 while (peek() == i::Token::COMMA) { | |
| 799 Expect(i::Token::COMMA, CHECK_OK); | |
| 800 ParseAssignmentExpression(accept_IN, CHECK_OK); | |
| 801 result = kUnknownExpression; | |
| 802 } | |
| 803 return result; | |
| 804 } | |
| 805 | |
| 806 | |
| 807 // Precedence = 2 | |
| 808 template <typename Scanner, typename Log> | |
| 809 Expression PreParser<Scanner, Log>::ParseAssignmentExpression(bool accept_IN, | |
| 810 bool* ok) { | |
| 811 // AssignmentExpression :: | |
| 812 // ConditionalExpression | |
| 813 // LeftHandSideExpression AssignmentOperator AssignmentExpression | |
| 814 | |
| 815 Expression expression = ParseConditionalExpression(accept_IN, CHECK_OK); | |
| 816 | |
| 817 if (!i::Token::IsAssignmentOp(peek())) { | |
| 818 // Parsed conditional expression only (no assignment). | |
| 819 return expression; | |
| 820 } | |
| 821 | |
| 822 i::Token::Value op = Next(); // Get assignment operator. | |
| 823 ParseAssignmentExpression(accept_IN, CHECK_OK); | |
| 824 | |
| 825 if ((op == i::Token::ASSIGN) && (expression == kThisPropertyExpression)) { | |
| 826 scope_->AddProperty(); | |
| 827 } | |
| 828 | |
| 829 return kUnknownExpression; | |
| 830 } | |
| 831 | |
| 832 | |
| 833 // Precedence = 3 | |
| 834 template <typename Scanner, typename Log> | |
| 835 Expression PreParser<Scanner, Log>::ParseConditionalExpression(bool accept_IN, | |
| 836 bool* ok) { | |
| 837 // ConditionalExpression :: | |
| 838 // LogicalOrExpression | |
| 839 // LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression | |
| 840 | |
| 841 // We start using the binary expression parser for prec >= 4 only! | |
| 842 Expression expression = ParseBinaryExpression(4, accept_IN, CHECK_OK); | |
| 843 if (peek() != i::Token::CONDITIONAL) return expression; | |
| 844 Consume(i::Token::CONDITIONAL); | |
| 845 // In parsing the first assignment expression in conditional | |
| 846 // expressions we always accept the 'in' keyword; see ECMA-262, | |
| 847 // section 11.12, page 58. | |
| 848 ParseAssignmentExpression(true, CHECK_OK); | |
| 849 Expect(i::Token::COLON, CHECK_OK); | |
| 850 ParseAssignmentExpression(accept_IN, CHECK_OK); | |
| 851 return kUnknownExpression; | |
| 852 } | |
| 853 | |
| 854 | |
| 855 template <typename Scanner, typename Log> | |
| 856 int PreParser<Scanner, Log>::Precedence(i::Token::Value tok, bool accept_IN) { | |
| 857 if (tok == i::Token::IN && !accept_IN) | |
| 858 return 0; // 0 precedence will terminate binary expression parsing | |
| 859 | |
| 860 return i::Token::Precedence(tok); | |
| 861 } | |
| 862 | |
| 863 | |
| 864 // Precedence >= 4 | |
| 865 template <typename Scanner, typename Log> | |
| 866 Expression PreParser<Scanner, Log>::ParseBinaryExpression(int prec, | |
| 867 bool accept_IN, | |
| 868 bool* ok) { | |
| 869 Expression result = ParseUnaryExpression(CHECK_OK); | |
| 870 for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) { | |
| 871 // prec1 >= 4 | |
| 872 while (Precedence(peek(), accept_IN) == prec1) { | |
| 873 Next(); | |
| 874 ParseBinaryExpression(prec1 + 1, accept_IN, CHECK_OK); | |
| 875 result = kUnknownExpression; | |
| 876 } | |
| 877 } | |
| 878 return result; | |
| 879 } | |
| 880 | |
| 881 | |
| 882 template <typename Scanner, typename Log> | |
| 883 Expression PreParser<Scanner, Log>::ParseUnaryExpression(bool* ok) { | |
| 884 // UnaryExpression :: | |
| 885 // PostfixExpression | |
| 886 // 'delete' UnaryExpression | |
| 887 // 'void' UnaryExpression | |
| 888 // 'typeof' UnaryExpression | |
| 889 // '++' UnaryExpression | |
| 890 // '--' UnaryExpression | |
| 891 // '+' UnaryExpression | |
| 892 // '-' UnaryExpression | |
| 893 // '~' UnaryExpression | |
| 894 // '!' UnaryExpression | |
| 895 | |
| 896 i::Token::Value op = peek(); | |
| 897 if (i::Token::IsUnaryOp(op) || i::Token::IsCountOp(op)) { | |
| 898 op = Next(); | |
| 899 ParseUnaryExpression(ok); | |
| 900 return kUnknownExpression; | |
| 901 } else { | |
| 902 return ParsePostfixExpression(ok); | |
| 903 } | |
| 904 } | |
| 905 | |
| 906 | |
| 907 template <typename Scanner, typename Log> | |
| 908 Expression PreParser<Scanner, Log>::ParsePostfixExpression(bool* ok) { | |
| 909 // PostfixExpression :: | |
| 910 // LeftHandSideExpression ('++' | '--')? | |
| 911 | |
| 912 Expression expression = ParseLeftHandSideExpression(CHECK_OK); | |
| 913 if (!scanner_->has_line_terminator_before_next() && | |
| 914 i::Token::IsCountOp(peek())) { | |
| 915 Next(); | |
| 916 return kUnknownExpression; | |
| 917 } | |
| 918 return expression; | |
| 919 } | |
| 920 | |
| 921 | |
| 922 template <typename Scanner, typename Log> | |
| 923 Expression PreParser<Scanner, Log>::ParseLeftHandSideExpression(bool* ok) { | |
| 924 // LeftHandSideExpression :: | |
| 925 // (NewExpression | MemberExpression) ... | |
| 926 | |
| 927 Expression result; | |
| 928 if (peek() == i::Token::NEW) { | |
| 929 result = ParseNewExpression(CHECK_OK); | |
| 930 } else { | |
| 931 result = ParseMemberExpression(CHECK_OK); | |
| 932 } | |
| 933 | |
| 934 while (true) { | |
| 935 switch (peek()) { | |
| 936 case i::Token::LBRACK: { | |
| 937 Consume(i::Token::LBRACK); | |
| 938 ParseExpression(true, CHECK_OK); | |
| 939 Expect(i::Token::RBRACK, CHECK_OK); | |
| 940 if (result == kThisExpression) { | |
| 941 result = kThisPropertyExpression; | |
| 942 } else { | |
| 943 result = kUnknownExpression; | |
| 944 } | |
| 945 break; | |
| 946 } | |
| 947 | |
| 948 case i::Token::LPAREN: { | |
| 949 ParseArguments(CHECK_OK); | |
| 950 result = kUnknownExpression; | |
| 951 break; | |
| 952 } | |
| 953 | |
| 954 case i::Token::PERIOD: { | |
| 955 Consume(i::Token::PERIOD); | |
| 956 ParseIdentifierName(CHECK_OK); | |
| 957 if (result == kThisExpression) { | |
| 958 result = kThisPropertyExpression; | |
| 959 } else { | |
| 960 result = kUnknownExpression; | |
| 961 } | |
| 962 break; | |
| 963 } | |
| 964 | |
| 965 default: | |
| 966 return result; | |
| 967 } | |
| 968 } | |
| 969 } | |
| 970 | |
| 971 | |
| 972 template <typename Scanner, typename Log> | |
| 973 Expression PreParser<Scanner, Log>::ParseNewExpression(bool* ok) { | |
| 974 // NewExpression :: | |
| 975 // ('new')+ MemberExpression | |
| 976 | |
| 977 // The grammar for new expressions is pretty warped. The keyword | |
| 978 // 'new' can either be a part of the new expression (where it isn't | |
| 979 // followed by an argument list) or a part of the member expression, | |
| 980 // where it must be followed by an argument list. To accommodate | |
| 981 // this, we parse the 'new' keywords greedily and keep track of how | |
| 982 // many we have parsed. This information is then passed on to the | |
| 983 // member expression parser, which is only allowed to match argument | |
| 984 // lists as long as it has 'new' prefixes left | |
| 985 unsigned new_count = 0; | |
| 986 do { | |
| 987 Consume(i::Token::NEW); | |
| 988 new_count++; | |
| 989 } while (peek() == i::Token::NEW); | |
| 990 | |
| 991 return ParseMemberWithNewPrefixesExpression(new_count, ok); | |
| 992 } | |
| 993 | |
| 994 | |
| 995 template <typename Scanner, typename Log> | |
| 996 Expression PreParser<Scanner, Log>::ParseMemberExpression(bool* ok) { | |
| 997 return ParseMemberWithNewPrefixesExpression(0, ok); | |
| 998 } | |
| 999 | |
| 1000 | |
| 1001 template <typename Scanner, typename Log> | |
| 1002 Expression PreParser<Scanner, Log>::ParseMemberWithNewPrefixesExpression( | |
| 1003 unsigned new_count, bool* ok) { | |
| 1004 // MemberExpression :: | |
| 1005 // (PrimaryExpression | FunctionLiteral) | |
| 1006 // ('[' Expression ']' | '.' Identifier | Arguments)* | |
| 1007 | |
| 1008 // Parse the initial primary or function expression. | |
| 1009 Expression result = kUnknownExpression; | |
| 1010 if (peek() == i::Token::FUNCTION) { | |
| 1011 Consume(i::Token::FUNCTION); | |
| 1012 if (peek() == i::Token::IDENTIFIER) { | |
| 1013 ParseIdentifier(CHECK_OK); | |
| 1014 } | |
| 1015 result = ParseFunctionLiteral(CHECK_OK); | |
| 1016 } else { | |
| 1017 result = ParsePrimaryExpression(CHECK_OK); | |
| 1018 } | |
| 1019 | |
| 1020 while (true) { | |
| 1021 switch (peek()) { | |
| 1022 case i::Token::LBRACK: { | |
| 1023 Consume(i::Token::LBRACK); | |
| 1024 ParseExpression(true, CHECK_OK); | |
| 1025 Expect(i::Token::RBRACK, CHECK_OK); | |
| 1026 if (result == kThisExpression) { | |
| 1027 result = kThisPropertyExpression; | |
| 1028 } else { | |
| 1029 result = kUnknownExpression; | |
| 1030 } | |
| 1031 break; | |
| 1032 } | |
| 1033 case i::Token::PERIOD: { | |
| 1034 Consume(i::Token::PERIOD); | |
| 1035 ParseIdentifierName(CHECK_OK); | |
| 1036 if (result == kThisExpression) { | |
| 1037 result = kThisPropertyExpression; | |
| 1038 } else { | |
| 1039 result = kUnknownExpression; | |
| 1040 } | |
| 1041 break; | |
| 1042 } | |
| 1043 case i::Token::LPAREN: { | |
| 1044 if (new_count == 0) return result; | |
| 1045 // Consume one of the new prefixes (already parsed). | |
| 1046 ParseArguments(CHECK_OK); | |
| 1047 new_count--; | |
| 1048 result = kUnknownExpression; | |
| 1049 break; | |
| 1050 } | |
| 1051 default: | |
| 1052 return result; | |
| 1053 } | |
| 1054 } | |
| 1055 } | |
| 1056 | |
| 1057 | |
| 1058 template <typename Scanner, typename Log> | |
| 1059 Expression PreParser<Scanner, Log>::ParsePrimaryExpression(bool* ok) { | |
| 1060 // PrimaryExpression :: | |
| 1061 // 'this' | |
| 1062 // 'null' | |
| 1063 // 'true' | |
| 1064 // 'false' | |
| 1065 // Identifier | |
| 1066 // Number | |
| 1067 // String | |
| 1068 // ArrayLiteral | |
| 1069 // ObjectLiteral | |
| 1070 // RegExpLiteral | |
| 1071 // '(' Expression ')' | |
| 1072 | |
| 1073 Expression result = kUnknownExpression; | |
| 1074 switch (peek()) { | |
| 1075 case i::Token::THIS: { | |
| 1076 Next(); | |
| 1077 result = kThisExpression; | |
| 1078 break; | |
| 1079 } | |
| 1080 | |
| 1081 case i::Token::IDENTIFIER: { | |
| 1082 ParseIdentifier(CHECK_OK); | |
| 1083 result = kIdentifierExpression; | |
| 1084 break; | |
| 1085 } | |
| 1086 | |
| 1087 case i::Token::NULL_LITERAL: | |
| 1088 case i::Token::TRUE_LITERAL: | |
| 1089 case i::Token::FALSE_LITERAL: | |
| 1090 case i::Token::NUMBER: { | |
| 1091 Next(); | |
| 1092 break; | |
| 1093 } | |
| 1094 case i::Token::STRING: { | |
| 1095 Next(); | |
| 1096 result = GetStringSymbol(); | |
| 1097 break; | |
| 1098 } | |
| 1099 | |
| 1100 case i::Token::ASSIGN_DIV: | |
| 1101 result = ParseRegExpLiteral(true, CHECK_OK); | |
| 1102 break; | |
| 1103 | |
| 1104 case i::Token::DIV: | |
| 1105 result = ParseRegExpLiteral(false, CHECK_OK); | |
| 1106 break; | |
| 1107 | |
| 1108 case i::Token::LBRACK: | |
| 1109 result = ParseArrayLiteral(CHECK_OK); | |
| 1110 break; | |
| 1111 | |
| 1112 case i::Token::LBRACE: | |
| 1113 result = ParseObjectLiteral(CHECK_OK); | |
| 1114 break; | |
| 1115 | |
| 1116 case i::Token::LPAREN: | |
| 1117 Consume(i::Token::LPAREN); | |
| 1118 result = ParseExpression(true, CHECK_OK); | |
| 1119 Expect(i::Token::RPAREN, CHECK_OK); | |
| 1120 if (result == kIdentifierExpression) result = kUnknownExpression; | |
| 1121 break; | |
| 1122 | |
| 1123 case i::Token::MOD: | |
| 1124 result = ParseV8Intrinsic(CHECK_OK); | |
| 1125 break; | |
| 1126 | |
| 1127 default: { | |
| 1128 Next(); | |
| 1129 *ok = false; | |
| 1130 return kUnknownExpression; | |
| 1131 } | |
| 1132 } | |
| 1133 | |
| 1134 return result; | |
| 1135 } | |
| 1136 | |
| 1137 | |
| 1138 template <typename Scanner, typename Log> | |
| 1139 Expression PreParser<Scanner, Log>::ParseArrayLiteral(bool* ok) { | |
| 1140 // ArrayLiteral :: | |
| 1141 // '[' Expression? (',' Expression?)* ']' | |
| 1142 Expect(i::Token::LBRACK, CHECK_OK); | |
| 1143 while (peek() != i::Token::RBRACK) { | |
| 1144 if (peek() != i::Token::COMMA) { | |
| 1145 ParseAssignmentExpression(true, CHECK_OK); | |
| 1146 } | |
| 1147 if (peek() != i::Token::RBRACK) { | |
| 1148 Expect(i::Token::COMMA, CHECK_OK); | |
| 1149 } | |
| 1150 } | |
| 1151 Expect(i::Token::RBRACK, CHECK_OK); | |
| 1152 | |
| 1153 scope_->NextMaterializedLiteralIndex(); | |
| 1154 return kUnknownExpression; | |
| 1155 } | |
| 1156 | |
| 1157 | |
| 1158 template <typename Scanner, typename Log> | |
| 1159 Expression PreParser<Scanner, Log>::ParseObjectLiteral(bool* ok) { | |
| 1160 // ObjectLiteral :: | |
| 1161 // '{' ( | |
| 1162 // ((IdentifierName | String | Number) ':' AssignmentExpression) | |
| 1163 // | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral) | |
| 1164 // )*[','] '}' | |
| 1165 | |
| 1166 Expect(i::Token::LBRACE, CHECK_OK); | |
| 1167 while (peek() != i::Token::RBRACE) { | |
| 1168 i::Token::Value next = peek(); | |
| 1169 switch (next) { | |
| 1170 case i::Token::IDENTIFIER: { | |
| 1171 bool is_getter = false; | |
| 1172 bool is_setter = false; | |
| 1173 ParseIdentifierOrGetOrSet(&is_getter, &is_setter, CHECK_OK); | |
| 1174 if ((is_getter || is_setter) && peek() != i::Token::COLON) { | |
| 1175 i::Token::Value name = Next(); | |
| 1176 if (name != i::Token::IDENTIFIER && | |
| 1177 name != i::Token::NUMBER && | |
| 1178 name != i::Token::STRING && | |
| 1179 !i::Token::IsKeyword(name)) { | |
| 1180 *ok = false; | |
| 1181 return kUnknownExpression; | |
| 1182 } | |
| 1183 ParseFunctionLiteral(CHECK_OK); | |
| 1184 if (peek() != i::Token::RBRACE) { | |
| 1185 Expect(i::Token::COMMA, CHECK_OK); | |
| 1186 } | |
| 1187 continue; // restart the while | |
| 1188 } | |
| 1189 break; | |
| 1190 } | |
| 1191 case i::Token::STRING: | |
| 1192 Consume(next); | |
| 1193 GetStringSymbol(); | |
| 1194 break; | |
| 1195 case i::Token::NUMBER: | |
| 1196 Consume(next); | |
| 1197 break; | |
| 1198 default: | |
| 1199 if (i::Token::IsKeyword(next)) { | |
| 1200 Consume(next); | |
| 1201 } else { | |
| 1202 // Unexpected token. | |
| 1203 *ok = false; | |
| 1204 return kUnknownExpression; | |
| 1205 } | |
| 1206 } | |
| 1207 | |
| 1208 Expect(i::Token::COLON, CHECK_OK); | |
| 1209 ParseAssignmentExpression(true, CHECK_OK); | |
| 1210 | |
| 1211 // TODO(1240767): Consider allowing trailing comma. | |
| 1212 if (peek() != i::Token::RBRACE) Expect(i::Token::COMMA, CHECK_OK); | |
| 1213 } | |
| 1214 Expect(i::Token::RBRACE, CHECK_OK); | |
| 1215 | |
| 1216 scope_->NextMaterializedLiteralIndex(); | |
| 1217 return kUnknownExpression; | |
| 1218 } | |
| 1219 | |
| 1220 | |
| 1221 template <typename Scanner, typename Log> | |
| 1222 Expression PreParser<Scanner, Log>::ParseRegExpLiteral(bool seen_equal, | |
| 1223 bool* ok) { | |
| 1224 if (!scanner_->ScanRegExpPattern(seen_equal)) { | |
| 1225 Next(); | |
| 1226 typename Scanner::Location location = scanner_->location(); | |
| 1227 ReportMessageAt(location.beg_pos, location.end_pos, | |
| 1228 "unterminated_regexp", NULL); | |
| 1229 *ok = false; | |
| 1230 return kUnknownExpression; | |
| 1231 } | |
| 1232 | |
| 1233 scope_->NextMaterializedLiteralIndex(); | |
| 1234 | |
| 1235 if (!scanner_->ScanRegExpFlags()) { | |
| 1236 Next(); | |
| 1237 typename Scanner::Location location = scanner_->location(); | |
| 1238 ReportMessageAt(location.beg_pos, location.end_pos, | |
| 1239 "invalid_regexp_flags", NULL); | |
| 1240 *ok = false; | |
| 1241 return kUnknownExpression; | |
| 1242 } | |
| 1243 Next(); | |
| 1244 return kUnknownExpression; | |
| 1245 } | |
| 1246 | |
| 1247 | |
| 1248 template <typename Scanner, typename Log> | |
| 1249 Arguments PreParser<Scanner, Log>::ParseArguments(bool* ok) { | |
| 1250 // Arguments :: | |
| 1251 // '(' (AssignmentExpression)*[','] ')' | |
| 1252 | |
| 1253 Expect(i::Token::LPAREN, CHECK_OK); | |
| 1254 bool done = (peek() == i::Token::RPAREN); | |
| 1255 int argc = 0; | |
| 1256 while (!done) { | |
| 1257 ParseAssignmentExpression(true, CHECK_OK); | |
| 1258 argc++; | |
| 1259 done = (peek() == i::Token::RPAREN); | |
| 1260 if (!done) Expect(i::Token::COMMA, CHECK_OK); | |
| 1261 } | |
| 1262 Expect(i::Token::RPAREN, CHECK_OK); | |
| 1263 return argc; | |
| 1264 } | |
| 1265 | |
| 1266 | |
| 1267 template <typename Scanner, typename Log> | |
| 1268 Expression PreParser<Scanner, Log>::ParseFunctionLiteral(bool* ok) { | |
| 1269 // Function :: | |
| 1270 // '(' FormalParameterList? ')' '{' FunctionBody '}' | |
| 1271 | |
| 1272 // Parse function body. | |
| 1273 ScopeType outer_scope_type = scope_->type(); | |
| 1274 bool inside_with = scope_->IsInsideWith(); | |
| 1275 Scope function_scope(&scope_, kFunctionScope); | |
| 1276 | |
| 1277 // FormalParameterList :: | |
| 1278 // '(' (Identifier)*[','] ')' | |
| 1279 Expect(i::Token::LPAREN, CHECK_OK); | |
| 1280 bool done = (peek() == i::Token::RPAREN); | |
| 1281 while (!done) { | |
| 1282 ParseIdentifier(CHECK_OK); | |
| 1283 done = (peek() == i::Token::RPAREN); | |
| 1284 if (!done) { | |
| 1285 Expect(i::Token::COMMA, CHECK_OK); | |
| 1286 } | |
| 1287 } | |
| 1288 Expect(i::Token::RPAREN, CHECK_OK); | |
| 1289 | |
| 1290 Expect(i::Token::LBRACE, CHECK_OK); | |
| 1291 int function_block_pos = scanner_->location().beg_pos; | |
| 1292 | |
| 1293 // Determine if the function will be lazily compiled. | |
| 1294 // Currently only happens to top-level functions. | |
| 1295 // Optimistically assume that all top-level functions are lazily compiled. | |
| 1296 bool is_lazily_compiled = | |
| 1297 (outer_scope_type == kTopLevelScope && !inside_with && allow_lazy_); | |
| 1298 | |
| 1299 if (is_lazily_compiled) { | |
| 1300 log_->PauseRecording(); | |
| 1301 ParseSourceElements(i::Token::RBRACE, ok); | |
| 1302 log_->ResumeRecording(); | |
| 1303 if (!*ok) return kUnknownExpression; | |
| 1304 | |
| 1305 Expect(i::Token::RBRACE, CHECK_OK); | |
| 1306 | |
| 1307 int end_pos = scanner_->location().end_pos; | |
| 1308 log_->LogFunction(function_block_pos, end_pos, | |
| 1309 function_scope.materialized_literal_count(), | |
| 1310 function_scope.expected_properties()); | |
| 1311 } else { | |
| 1312 ParseSourceElements(i::Token::RBRACE, CHECK_OK); | |
| 1313 Expect(i::Token::RBRACE, CHECK_OK); | |
| 1314 } | |
| 1315 return kUnknownExpression; | |
| 1316 } | |
| 1317 | |
| 1318 | |
| 1319 template <typename Scanner, typename Log> | |
| 1320 Expression PreParser<Scanner, Log>::ParseV8Intrinsic(bool* ok) { | |
| 1321 // CallRuntime :: | |
| 1322 // '%' Identifier Arguments | |
| 1323 | |
| 1324 Expect(i::Token::MOD, CHECK_OK); | |
| 1325 ParseIdentifier(CHECK_OK); | |
| 1326 ParseArguments(CHECK_OK); | |
| 1327 | |
| 1328 return kUnknownExpression; | |
| 1329 } | |
| 1330 | |
| 1331 | |
| 1332 template <typename Scanner, typename Log> | |
| 1333 void PreParser<Scanner, Log>::ExpectSemicolon(bool* ok) { | |
| 1334 // Check for automatic semicolon insertion according to | |
| 1335 // the rules given in ECMA-262, section 7.9, page 21. | |
| 1336 i::Token::Value tok = peek(); | |
| 1337 if (tok == i::Token::SEMICOLON) { | |
| 1338 Next(); | |
| 1339 return; | |
| 1340 } | |
| 1341 if (scanner_->has_line_terminator_before_next() || | |
| 1342 tok == i::Token::RBRACE || | |
| 1343 tok == i::Token::EOS) { | |
| 1344 return; | |
| 1345 } | |
| 1346 Expect(i::Token::SEMICOLON, ok); | |
| 1347 } | |
| 1348 | |
| 1349 | |
| 1350 template <typename Scanner, typename Log> | |
| 1351 Identifier PreParser<Scanner, Log>::GetIdentifierSymbol() { | |
| 1352 const char* literal_chars = scanner_->literal_string(); | |
| 1353 int literal_length = scanner_->literal_length(); | |
| 1354 int identifier_pos = scanner_->location().beg_pos; | |
| 1355 | |
| 1356 log_->LogSymbol(identifier_pos, literal_chars, literal_length); | |
| 1357 | |
| 1358 return kUnknownExpression; | |
| 1359 } | |
| 1360 | |
| 1361 | |
| 1362 template <typename Scanner, typename Log> | |
| 1363 Expression PreParser<Scanner, Log>::GetStringSymbol() { | |
| 1364 const char* literal_chars = scanner_->literal_string(); | |
| 1365 int literal_length = scanner_->literal_length(); | |
| 1366 | |
| 1367 int literal_position = scanner_->location().beg_pos; | |
| 1368 log_->LogSymbol(literal_position, literal_chars, literal_length); | |
| 1369 | |
| 1370 return kUnknownExpression; | |
| 1371 } | |
| 1372 | |
| 1373 | |
| 1374 template <typename Scanner, typename Log> | |
| 1375 Identifier PreParser<Scanner, Log>::ParseIdentifier(bool* ok) { | |
| 1376 Expect(i::Token::IDENTIFIER, ok); | |
| 1377 if (!*ok) return kUnknownIdentifier; | |
| 1378 return GetIdentifierSymbol(); | |
| 1379 } | |
| 1380 | |
| 1381 | |
| 1382 template <typename Scanner, typename Log> | |
| 1383 Identifier PreParser<Scanner, Log>::ParseIdentifierName(bool* ok) { | |
| 1384 i::Token::Value next = Next(); | |
| 1385 if (i::Token::IsKeyword(next)) { | |
| 1386 int pos = scanner_->location().beg_pos; | |
| 1387 const char* keyword = i::Token::String(next); | |
| 1388 log_->LogSymbol(pos, keyword, i::StrLength(keyword)); | |
| 1389 return kUnknownExpression; | |
| 1390 } | |
| 1391 if (next == i::Token::IDENTIFIER) { | |
| 1392 return GetIdentifierSymbol(); | |
| 1393 } | |
| 1394 *ok = false; | |
| 1395 return kUnknownIdentifier; | |
| 1396 } | |
| 1397 | |
| 1398 | |
| 1399 // This function reads an identifier and determines whether or not it | |
| 1400 // is 'get' or 'set'. The reason for not using ParseIdentifier and | |
| 1401 // checking on the output is that this involves heap allocation which | |
| 1402 // we can't do during preparsing. | |
| 1403 template <typename Scanner, typename Log> | |
| 1404 Identifier PreParser<Scanner, Log>::ParseIdentifierOrGetOrSet(bool* is_get, | |
| 1405 bool* is_set, | |
| 1406 bool* ok) { | |
| 1407 Expect(i::Token::IDENTIFIER, CHECK_OK); | |
| 1408 if (scanner_->literal_length() == 3) { | |
| 1409 const char* token = scanner_->literal_string(); | |
| 1410 *is_get = strncmp(token, "get", 3) == 0; | |
| 1411 *is_set = !*is_get && strncmp(token, "set", 3) == 0; | |
| 1412 } | |
| 1413 return GetIdentifierSymbol(); | |
| 1414 } | |
| 1415 | |
| 1416 #undef CHECK_OK | |
| 1417 } } // v8::preparser | 239 } } // v8::preparser |
| 1418 | 240 |
| 1419 #endif // V8_PREPARSER_H | 241 #endif // V8_PREPARSER_H |
| OLD | NEW |