• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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