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