Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(78)

Side by Side Diff: src/preparser.h

Issue 5166006: Untemplated preparser.h and made it depend on virtual types. (Closed)
Patch Set: Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/preparse-data.cc ('k') | src/preparser.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « src/preparse-data.cc ('k') | src/preparser.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698