V8 Project
preparser.cc
Go to the documentation of this file.
1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <cmath>
6 
7 #include "include/v8stdint.h"
8 
9 #include "src/allocation.h"
10 #include "src/base/logging.h"
11 #include "src/conversions-inl.h"
12 #include "src/conversions.h"
13 #include "src/globals.h"
14 #include "src/hashmap.h"
15 #include "src/list.h"
16 #include "src/preparse-data.h"
18 #include "src/preparser.h"
19 #include "src/unicode.h"
20 #include "src/utils.h"
21 
22 #if V8_LIBC_MSVCRT && (_MSC_VER < 1800)
23 namespace std {
24 
25 // Usually defined in math.h, but not in MSVC until VS2013+.
26 // Abstracted to work
27 int isfinite(double value);
28 
29 } // namespace std
30 #endif
31 
32 namespace v8 {
33 namespace internal {
34 
36  : public ParserBase<PreParserTraits>::CheckpointBase {
37  public:
39  : ParserBase<PreParserTraits>::CheckpointBase(parser) {}
40 };
41 
43  const char* message,
44  const char* arg,
45  bool is_reference_error) {
46  ReportMessageAt(location.beg_pos,
47  location.end_pos,
48  message,
49  arg,
50  is_reference_error);
51 }
52 
53 
55  int end_pos,
56  const char* message,
57  const char* arg,
58  bool is_reference_error) {
59  pre_parser_->log_->LogMessage(start_pos, end_pos, message, arg,
60  is_reference_error);
61 }
62 
63 
65  if (scanner->current_token() == Token::FUTURE_RESERVED_WORD) {
67  } else if (scanner->current_token() ==
68  Token::FUTURE_STRICT_RESERVED_WORD) {
70  } else if (scanner->current_token() == Token::LET) {
71  return PreParserIdentifier::Let();
72  } else if (scanner->current_token() == Token::YIELD) {
74  }
75  if (scanner->UnescapedLiteralMatches("eval", 4)) {
77  }
78  if (scanner->UnescapedLiteralMatches("arguments", 9)) {
80  }
81  if (scanner->UnescapedLiteralMatches("prototype", 9)) {
83  }
84  if (scanner->UnescapedLiteralMatches("constructor", 11)) {
86  }
88 }
89 
90 
93 }
94 
95 
97  int pos, Scanner* scanner, PreParserFactory* factory) {
98  if (scanner->UnescapedLiteralMatches("use strict", 10)) {
100  }
102 }
103 
104 
106  return pre_parser_->ParseV8Intrinsic(ok);
107 }
108 
109 
111  PreParserIdentifier name, Scanner::Location function_name_location,
112  bool name_is_strict_reserved, FunctionKind kind,
113  int function_token_position, FunctionLiteral::FunctionType type,
114  FunctionLiteral::ArityRestriction arity_restriction, bool* ok) {
116  name, function_name_location, name_is_strict_reserved, kind,
117  function_token_position, type, arity_restriction, ok);
118 }
119 
120 
122  StrictMode strict_mode, bool is_generator, ParserRecorder* log) {
123  log_ = log;
124  // Lazy functions always have trivial outer scopes (no with/catch scopes).
125  PreParserScope top_scope(scope_, GLOBAL_SCOPE);
126  FunctionState top_state(&function_state_, &scope_, &top_scope, NULL,
127  this->ast_value_factory());
128  scope_->SetStrictMode(strict_mode);
129  PreParserScope function_scope(scope_, FUNCTION_SCOPE);
130  FunctionState function_state(&function_state_, &scope_, &function_scope, NULL,
131  this->ast_value_factory());
132  function_state.set_is_generator(is_generator);
133  DCHECK_EQ(Token::LBRACE, scanner()->current_token());
134  bool ok = true;
135  int start_position = peek_position();
138  if (!ok) {
139  ReportUnexpectedToken(scanner()->current_token());
140  } else {
141  DCHECK_EQ(Token::RBRACE, scanner()->peek());
142  if (scope_->strict_mode() == STRICT) {
143  int end_pos = scanner()->location().end_pos;
144  CheckOctalLiteral(start_position, end_pos, &ok);
145  }
146  }
147  return kPreParseSuccess;
148 }
149 
150 
151 // Preparsing checks a JavaScript program and emits preparse-data that helps
152 // a later parsing to be faster.
153 // See preparser-data.h for the data.
154 
155 // The PreParser checks that the syntax follows the grammar for JavaScript,
156 // and collects some information about the program along the way.
157 // The grammar check is only performed in order to understand the program
158 // sufficiently to deduce some information about it, that can be used
159 // to speed up later parsing. Finding errors is not the goal of pre-parsing,
160 // rather it is to speed up properly written and correct programs.
161 // That means that contextual checks (like a label being declared where
162 // it is used) are generally omitted.
163 
164 
165 #define CHECK_OK ok); \
166  if (!*ok) return kUnknownSourceElements; \
167  ((void)0
168 #define DUMMY ) // to make indentation work
169 #undef DUMMY
170 
171 
173  // (Ecma 262 5th Edition, clause 14):
174  // SourceElement:
175  // Statement
176  // FunctionDeclaration
177  //
178  // In harmony mode we allow additionally the following productions
179  // SourceElement:
180  // LetDeclaration
181  // ConstDeclaration
182  // GeneratorDeclaration
183 
184  switch (peek()) {
185  case Token::FUNCTION:
186  return ParseFunctionDeclaration(ok);
187  case Token::CLASS:
188  return ParseClassDeclaration(ok);
189  case Token::CONST:
191  case Token::LET:
193  if (strict_mode() == STRICT) {
195  }
196  // Fall through.
197  default:
198  return ParseStatement(ok);
199  }
200 }
201 
202 
204  bool* ok) {
205  // SourceElements ::
206  // (Statement)* <end_token>
207 
208  bool directive_prologue = true;
209  while (peek() != end_token) {
210  if (directive_prologue && peek() != Token::STRING) {
211  directive_prologue = false;
212  }
214  if (directive_prologue) {
215  if (statement.IsUseStrictLiteral()) {
216  scope_->SetStrictMode(STRICT);
217  } else if (!statement.IsStringLiteral()) {
218  directive_prologue = false;
219  }
220  }
221  }
222  return kUnknownSourceElements;
223 }
224 
225 
226 #undef CHECK_OK
227 #define CHECK_OK ok); \
228  if (!*ok) return Statement::Default(); \
229  ((void)0
230 #define DUMMY ) // to make indentation work
231 #undef DUMMY
232 
233 
235  // Statement ::
236  // Block
237  // VariableStatement
238  // EmptyStatement
239  // ExpressionStatement
240  // IfStatement
241  // IterationStatement
242  // ContinueStatement
243  // BreakStatement
244  // ReturnStatement
245  // WithStatement
246  // LabelledStatement
247  // SwitchStatement
248  // ThrowStatement
249  // TryStatement
250  // DebuggerStatement
251 
252  // Note: Since labels can only be used by 'break' and 'continue'
253  // statements, which themselves are only valid within blocks,
254  // iterations or 'switch' statements (i.e., BreakableStatements),
255  // labels can be simply ignored in all other cases; except for
256  // trivial labeled break statements 'label: break label' which is
257  // parsed into an empty statement.
258 
259  // Keep the source position of the statement
260  switch (peek()) {
261  case Token::LBRACE:
262  return ParseBlock(ok);
263 
264  case Token::SEMICOLON:
265  Next();
266  return Statement::Default();
267 
268  case Token::IF:
269  return ParseIfStatement(ok);
270 
271  case Token::DO:
272  return ParseDoWhileStatement(ok);
273 
274  case Token::WHILE:
275  return ParseWhileStatement(ok);
276 
277  case Token::FOR:
278  return ParseForStatement(ok);
279 
280  case Token::CONTINUE:
281  return ParseContinueStatement(ok);
282 
283  case Token::BREAK:
284  return ParseBreakStatement(ok);
285 
286  case Token::RETURN:
287  return ParseReturnStatement(ok);
288 
289  case Token::WITH:
290  return ParseWithStatement(ok);
291 
292  case Token::SWITCH:
293  return ParseSwitchStatement(ok);
294 
295  case Token::THROW:
296  return ParseThrowStatement(ok);
297 
298  case Token::TRY:
299  return ParseTryStatement(ok);
300 
301  case Token::FUNCTION: {
302  Scanner::Location start_location = scanner()->peek_location();
304  Scanner::Location end_location = scanner()->location();
305  if (strict_mode() == STRICT) {
307  end_location.end_pos,
308  "strict_function");
309  *ok = false;
310  return Statement::Default();
311  } else {
312  return statement;
313  }
314  }
315 
316  case Token::CLASS:
318 
319  case Token::DEBUGGER:
320  return ParseDebuggerStatement(ok);
321 
322  case Token::VAR:
323  case Token::CONST:
325 
326  case Token::LET:
328  if (strict_mode() == STRICT) {
330  }
331  // Fall through.
332  default:
334  }
335 }
336 
337 
339  // FunctionDeclaration ::
340  // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
341  // GeneratorDeclaration ::
342  // 'function' '*' Identifier '(' FormalParameterListopt ')'
343  // '{' FunctionBody '}'
344  Expect(Token::FUNCTION, CHECK_OK);
345  int pos = position();
346  bool is_generator = Check(Token::MUL);
347  bool is_strict_reserved = false;
349  &is_strict_reserved, CHECK_OK);
350  ParseFunctionLiteral(name, scanner()->location(), is_strict_reserved,
353  pos, FunctionLiteral::DECLARATION,
354  FunctionLiteral::NORMAL_ARITY, CHECK_OK);
356 }
357 
358 
360  Expect(Token::CLASS, CHECK_OK);
361  int pos = position();
362  bool is_strict_reserved = false;
363  Identifier name =
364  ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
365  ParseClassLiteral(name, scanner()->location(), is_strict_reserved, pos,
366  CHECK_OK);
367  return Statement::Default();
368 }
369 
370 
372  // Block ::
373  // '{' Statement* '}'
374 
375  // Note that a Block does not introduce a new execution scope!
376  // (ECMA-262, 3rd, 12.2)
377  //
378  Expect(Token::LBRACE, CHECK_OK);
379  while (peek() != Token::RBRACE) {
380  if (allow_harmony_scoping() && strict_mode() == STRICT) {
382  } else {
384  }
385  }
386  Expect(Token::RBRACE, ok);
387  return Statement::Default();
388 }
389 
390 
392  VariableDeclarationContext var_context,
393  bool* ok) {
394  // VariableStatement ::
395  // VariableDeclarations ';'
396 
397  Statement result = ParseVariableDeclarations(var_context,
398  NULL,
399  NULL,
400  CHECK_OK);
402  return result;
403 }
404 
405 
406 // If the variable declaration declares exactly one non-const
407 // variable, then *var is set to that variable. In all other cases,
408 // *var is untouched; in particular, it is the caller's responsibility
409 // to initialize it properly. This mechanism is also used for the parsing
410 // of 'for-in' loops.
412  VariableDeclarationContext var_context,
413  VariableDeclarationProperties* decl_props,
414  int* num_decl,
415  bool* ok) {
416  // VariableDeclarations ::
417  // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[',']
418  //
419  // The ES6 Draft Rev3 specifies the following grammar for const declarations
420  //
421  // ConstDeclaration ::
422  // const ConstBinding (',' ConstBinding)* ';'
423  // ConstBinding ::
424  // Identifier '=' AssignmentExpression
425  //
426  // TODO(ES6):
427  // ConstBinding ::
428  // BindingPattern '=' AssignmentExpression
429  bool require_initializer = false;
430  if (peek() == Token::VAR) {
432  } else if (peek() == Token::CONST) {
433  // TODO(ES6): The ES6 Draft Rev4 section 12.2.2 reads:
434  //
435  // ConstDeclaration : const ConstBinding (',' ConstBinding)* ';'
436  //
437  // * It is a Syntax Error if the code that matches this production is not
438  // contained in extended code.
439  //
440  // However disallowing const in sloppy mode will break compatibility with
441  // existing pages. Therefore we keep allowing const with the old
442  // non-harmony semantics in sloppy mode.
444  if (strict_mode() == STRICT) {
445  if (allow_harmony_scoping()) {
446  if (var_context != kSourceElement && var_context != kForStatement) {
447  ReportMessageAt(scanner()->peek_location(), "unprotected_const");
448  *ok = false;
449  return Statement::Default();
450  }
451  require_initializer = true;
452  } else {
453  Scanner::Location location = scanner()->peek_location();
454  ReportMessageAt(location, "strict_const");
455  *ok = false;
456  return Statement::Default();
457  }
458  }
459  } else if (peek() == Token::LET && strict_mode() == STRICT) {
461  if (var_context != kSourceElement && var_context != kForStatement) {
462  ReportMessageAt(scanner()->peek_location(), "unprotected_let");
463  *ok = false;
464  return Statement::Default();
465  }
466  } else {
467  *ok = false;
468  return Statement::Default();
469  }
470 
471  // The scope of a var/const declared variable anywhere inside a function
472  // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). The scope
473  // of a let declared variable is the scope of the immediately enclosing
474  // block.
475  int nvars = 0; // the number of variables declared
476  do {
477  // Parse variable name.
478  if (nvars > 0) Consume(Token::COMMA);
480  nvars++;
481  if (peek() == Token::ASSIGN || require_initializer) {
482  Expect(Token::ASSIGN, CHECK_OK);
484  if (decl_props != NULL) *decl_props = kHasInitializers;
485  }
486  } while (peek() == Token::COMMA);
487 
488  if (num_decl != NULL) *num_decl = nvars;
489  return Statement::Default();
490 }
491 
492 
494  // ExpressionStatement | LabelledStatement ::
495  // Expression ';'
496  // Identifier ':' Statement
497 
498  bool starts_with_identifier = peek_any_identifier();
499  Expression expr = ParseExpression(true, CHECK_OK);
500  // Even if the expression starts with an identifier, it is not necessarily an
501  // identifier. For example, "foo + bar" starts with an identifier but is not
502  // an identifier.
503  if (starts_with_identifier && expr.IsIdentifier() && peek() == Token::COLON) {
504  // Expression is a single identifier, and not, e.g., a parenthesized
505  // identifier.
507  DCHECK(strict_mode() == SLOPPY ||
509  !expr.AsIdentifier().IsYield()));
510  Consume(Token::COLON);
511  return ParseStatement(ok);
512  // Preparsing is disabled for extensions (because the extension details
513  // aren't passed to lazily compiled functions), so we don't
514  // accept "native function" in the preparser.
515  }
516  // Parsed expression statement.
518  return Statement::ExpressionStatement(expr);
519 }
520 
521 
523  // IfStatement ::
524  // 'if' '(' Expression ')' Statement ('else' Statement)?
525 
526  Expect(Token::IF, CHECK_OK);
527  Expect(Token::LPAREN, CHECK_OK);
528  ParseExpression(true, CHECK_OK);
529  Expect(Token::RPAREN, CHECK_OK);
531  if (peek() == Token::ELSE) {
532  Next();
534  }
535  return Statement::Default();
536 }
537 
538 
540  // ContinueStatement ::
541  // 'continue' [no line terminator] Identifier? ';'
542 
543  Expect(Token::CONTINUE, CHECK_OK);
544  Token::Value tok = peek();
545  if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
546  tok != Token::SEMICOLON &&
547  tok != Token::RBRACE &&
548  tok != Token::EOS) {
549  // ECMA allows "eval" or "arguments" as labels even in strict mode.
551  }
553  return Statement::Default();
554 }
555 
556 
558  // BreakStatement ::
559  // 'break' [no line terminator] Identifier? ';'
560 
562  Token::Value tok = peek();
563  if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
564  tok != Token::SEMICOLON &&
565  tok != Token::RBRACE &&
566  tok != Token::EOS) {
567  // ECMA allows "eval" or "arguments" as labels even in strict mode.
569  }
571  return Statement::Default();
572 }
573 
574 
576  // ReturnStatement ::
577  // 'return' [no line terminator] Expression? ';'
578 
579  // Consume the return token. It is necessary to do before
580  // reporting any errors on it, because of the way errors are
581  // reported (underlining).
582  Expect(Token::RETURN, CHECK_OK);
583 
584  // An ECMAScript program is considered syntactically incorrect if it
585  // contains a return statement that is not within the body of a
586  // function. See ECMA-262, section 12.9, page 67.
587  // This is not handled during preparsing.
588 
589  Token::Value tok = peek();
590  if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
591  tok != Token::SEMICOLON &&
592  tok != Token::RBRACE &&
593  tok != Token::EOS) {
594  ParseExpression(true, CHECK_OK);
595  }
597  return Statement::Default();
598 }
599 
600 
602  // WithStatement ::
603  // 'with' '(' Expression ')' Statement
604  Expect(Token::WITH, CHECK_OK);
605  if (strict_mode() == STRICT) {
606  ReportMessageAt(scanner()->location(), "strict_mode_with");
607  *ok = false;
608  return Statement::Default();
609  }
610  Expect(Token::LPAREN, CHECK_OK);
611  ParseExpression(true, CHECK_OK);
612  Expect(Token::RPAREN, CHECK_OK);
613 
614  PreParserScope with_scope(scope_, WITH_SCOPE);
615  BlockState block_state(&scope_, &with_scope);
617  return Statement::Default();
618 }
619 
620 
622  // SwitchStatement ::
623  // 'switch' '(' Expression ')' '{' CaseClause* '}'
624 
625  Expect(Token::SWITCH, CHECK_OK);
626  Expect(Token::LPAREN, CHECK_OK);
627  ParseExpression(true, CHECK_OK);
628  Expect(Token::RPAREN, CHECK_OK);
629 
630  Expect(Token::LBRACE, CHECK_OK);
631  Token::Value token = peek();
632  while (token != Token::RBRACE) {
633  if (token == Token::CASE) {
635  ParseExpression(true, CHECK_OK);
636  } else {
638  }
639  Expect(Token::COLON, CHECK_OK);
640  token = peek();
641  while (token != Token::CASE &&
642  token != Token::DEFAULT &&
643  token != Token::RBRACE) {
645  token = peek();
646  }
647  }
648  Expect(Token::RBRACE, ok);
649  return Statement::Default();
650 }
651 
652 
654  // DoStatement ::
655  // 'do' Statement 'while' '(' Expression ')' ';'
656 
657  Expect(Token::DO, CHECK_OK);
659  Expect(Token::WHILE, CHECK_OK);
660  Expect(Token::LPAREN, CHECK_OK);
661  ParseExpression(true, CHECK_OK);
662  Expect(Token::RPAREN, ok);
663  if (peek() == Token::SEMICOLON) Consume(Token::SEMICOLON);
664  return Statement::Default();
665 }
666 
667 
669  // WhileStatement ::
670  // 'while' '(' Expression ')' Statement
671 
672  Expect(Token::WHILE, CHECK_OK);
673  Expect(Token::LPAREN, CHECK_OK);
674  ParseExpression(true, CHECK_OK);
675  Expect(Token::RPAREN, CHECK_OK);
676  ParseStatement(ok);
677  return Statement::Default();
678 }
679 
680 
681 bool PreParser::CheckInOrOf(bool accept_OF) {
682  if (Check(Token::IN) ||
683  (accept_OF && CheckContextualKeyword(CStrVector("of")))) {
684  return true;
685  }
686  return false;
687 }
688 
689 
691  // ForStatement ::
692  // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
693 
694  Expect(Token::FOR, CHECK_OK);
695  Expect(Token::LPAREN, CHECK_OK);
696  if (peek() != Token::SEMICOLON) {
697  if (peek() == Token::VAR || peek() == Token::CONST ||
698  (peek() == Token::LET && strict_mode() == STRICT)) {
699  bool is_let = peek() == Token::LET;
700  int decl_count;
703  kForStatement, &decl_props, &decl_count, CHECK_OK);
704  bool has_initializers = decl_props == kHasInitializers;
705  bool accept_IN = decl_count == 1 && !(is_let && has_initializers);
706  bool accept_OF = !has_initializers;
707  if (accept_IN && CheckInOrOf(accept_OF)) {
708  ParseExpression(true, CHECK_OK);
709  Expect(Token::RPAREN, CHECK_OK);
710 
712  return Statement::Default();
713  }
714  } else {
715  Expression lhs = ParseExpression(false, CHECK_OK);
716  if (CheckInOrOf(lhs.IsIdentifier())) {
717  ParseExpression(true, CHECK_OK);
718  Expect(Token::RPAREN, CHECK_OK);
719 
721  return Statement::Default();
722  }
723  }
724  }
725 
726  // Parsed initializer at this point.
727  Expect(Token::SEMICOLON, CHECK_OK);
728 
729  if (peek() != Token::SEMICOLON) {
730  ParseExpression(true, CHECK_OK);
731  }
732  Expect(Token::SEMICOLON, CHECK_OK);
733 
734  if (peek() != Token::RPAREN) {
735  ParseExpression(true, CHECK_OK);
736  }
737  Expect(Token::RPAREN, CHECK_OK);
738 
739  ParseStatement(ok);
740  return Statement::Default();
741 }
742 
743 
745  // ThrowStatement ::
746  // 'throw' [no line terminator] Expression ';'
747 
748  Expect(Token::THROW, CHECK_OK);
749  if (scanner()->HasAnyLineTerminatorBeforeNext()) {
750  ReportMessageAt(scanner()->location(), "newline_after_throw");
751  *ok = false;
752  return Statement::Default();
753  }
754  ParseExpression(true, CHECK_OK);
755  ExpectSemicolon(ok);
756  return Statement::Default();
757 }
758 
759 
761  // TryStatement ::
762  // 'try' Block Catch
763  // 'try' Block Finally
764  // 'try' Block Catch Finally
765  //
766  // Catch ::
767  // 'catch' '(' Identifier ')' Block
768  //
769  // Finally ::
770  // 'finally' Block
771 
772  Expect(Token::TRY, CHECK_OK);
773 
775 
776  Token::Value tok = peek();
777  if (tok != Token::CATCH && tok != Token::FINALLY) {
778  ReportMessageAt(scanner()->location(), "no_catch_or_finally");
779  *ok = false;
780  return Statement::Default();
781  }
782  if (tok == Token::CATCH) {
783  Consume(Token::CATCH);
784  Expect(Token::LPAREN, CHECK_OK);
786  Expect(Token::RPAREN, CHECK_OK);
787  {
788  PreParserScope with_scope(scope_, WITH_SCOPE);
789  BlockState block_state(&scope_, &with_scope);
791  }
792  tok = peek();
793  }
794  if (tok == Token::FINALLY) {
795  Consume(Token::FINALLY);
797  }
798  return Statement::Default();
799 }
800 
801 
803  // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser
804  // contexts this is used as a statement which invokes the debugger as if a
805  // break point is present.
806  // DebuggerStatement ::
807  // 'debugger' ';'
808 
809  Expect(Token::DEBUGGER, CHECK_OK);
810  ExpectSemicolon(ok);
811  return Statement::Default();
812 }
813 
814 
815 #undef CHECK_OK
816 #define CHECK_OK ok); \
817  if (!*ok) return Expression::Default(); \
818  ((void)0
819 #define DUMMY ) // to make indentation work
820 #undef DUMMY
821 
822 
824  Identifier function_name, Scanner::Location function_name_location,
825  bool name_is_strict_reserved, FunctionKind kind, int function_token_pos,
826  FunctionLiteral::FunctionType function_type,
827  FunctionLiteral::ArityRestriction arity_restriction, bool* ok) {
828  // Function ::
829  // '(' FormalParameterList? ')' '{' FunctionBody '}'
830 
831  // Parse function body.
832  ScopeType outer_scope_type = scope_->type();
833  PreParserScope function_scope(scope_, FUNCTION_SCOPE);
834  FunctionState function_state(&function_state_, &scope_, &function_scope, NULL,
835  this->ast_value_factory());
836  function_state.set_is_generator(IsGeneratorFunction(kind));
837  // FormalParameterList ::
838  // '(' (Identifier)*[','] ')'
839  Expect(Token::LPAREN, CHECK_OK);
840  int start_position = position();
841  DuplicateFinder duplicate_finder(scanner()->unicode_cache());
842  // We don't yet know if the function will be strict, so we cannot yet produce
843  // errors for parameter names or duplicates. However, we remember the
844  // locations of these errors if they occur and produce the errors later.
845  Scanner::Location eval_args_error_loc = Scanner::Location::invalid();
847  Scanner::Location reserved_error_loc = Scanner::Location::invalid();
848 
849  bool done = arity_restriction == FunctionLiteral::GETTER_ARITY ||
850  (peek() == Token::RPAREN &&
851  arity_restriction != FunctionLiteral::SETTER_ARITY);
852  while (!done) {
853  bool is_strict_reserved = false;
854  Identifier param_name =
855  ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
856  if (!eval_args_error_loc.IsValid() && param_name.IsEvalOrArguments()) {
857  eval_args_error_loc = scanner()->location();
858  }
859  if (!reserved_error_loc.IsValid() && is_strict_reserved) {
860  reserved_error_loc = scanner()->location();
861  }
862 
863  int prev_value = scanner()->FindSymbol(&duplicate_finder, 1);
864 
865  if (!dupe_error_loc.IsValid() && prev_value != 0) {
866  dupe_error_loc = scanner()->location();
867  }
868 
869  if (arity_restriction == FunctionLiteral::SETTER_ARITY) break;
870  done = (peek() == Token::RPAREN);
871  if (!done) Expect(Token::COMMA, CHECK_OK);
872  }
873  Expect(Token::RPAREN, CHECK_OK);
874 
875  // See Parser::ParseFunctionLiteral for more information about lazy parsing
876  // and lazy compilation.
877  bool is_lazily_parsed = (outer_scope_type == GLOBAL_SCOPE && allow_lazy() &&
879  parenthesized_function_ = false;
880 
881  Expect(Token::LBRACE, CHECK_OK);
882  if (is_lazily_parsed) {
884  } else {
885  ParseSourceElements(Token::RBRACE, ok);
886  }
887  Expect(Token::RBRACE, CHECK_OK);
888 
889  // Validate strict mode. We can do this only after parsing the function,
890  // since the function can declare itself strict.
891  // Concise methods use StrictFormalParameters.
892  if (strict_mode() == STRICT || IsConciseMethod(kind)) {
893  if (function_name.IsEvalOrArguments()) {
894  ReportMessageAt(function_name_location, "strict_eval_arguments");
895  *ok = false;
896  return Expression::Default();
897  }
898  if (name_is_strict_reserved) {
899  ReportMessageAt(function_name_location, "unexpected_strict_reserved");
900  *ok = false;
901  return Expression::Default();
902  }
903  if (eval_args_error_loc.IsValid()) {
904  ReportMessageAt(eval_args_error_loc, "strict_eval_arguments");
905  *ok = false;
906  return Expression::Default();
907  }
908  if (dupe_error_loc.IsValid()) {
909  ReportMessageAt(dupe_error_loc, "strict_param_dupe");
910  *ok = false;
911  return Expression::Default();
912  }
913  if (reserved_error_loc.IsValid()) {
914  ReportMessageAt(reserved_error_loc, "unexpected_strict_reserved");
915  *ok = false;
916  return Expression::Default();
917  }
918 
919  int end_position = scanner()->location().end_pos;
920  CheckOctalLiteral(start_position, end_position, CHECK_OK);
921  }
922 
923  return Expression::Default();
924 }
925 
926 
928  int body_start = position();
929  ParseSourceElements(Token::RBRACE, ok);
930  if (!*ok) return;
931 
932  // Position right after terminal '}'.
933  DCHECK_EQ(Token::RBRACE, scanner()->peek());
934  int body_end = scanner()->peek_location().end_pos;
935  log_->LogFunction(body_start, body_end,
936  function_state_->materialized_literal_count(),
937  function_state_->expected_property_count(),
938  strict_mode());
939 }
940 
941 
943  // CallRuntime ::
944  // '%' Identifier Arguments
945  Expect(Token::MOD, CHECK_OK);
946  if (!allow_natives_syntax()) {
947  *ok = false;
948  return Expression::Default();
949  }
950  // Allow "eval" or "arguments" for backward compatibility.
952  ParseArguments(ok);
953 
954  return Expression::Default();
955 }
956 
957 #undef CHECK_OK
958 
959 
960 } } // v8::internal
ParserRecorder * log_
Definition: preparser.h:581
ExpressionT ParseClassLiteral(IdentifierT name, Scanner::Location function_name_location, bool name_is_strict_reserved, int pos, bool *ok)
Definition: preparser.h:2721
IdentifierT ParseIdentifierOrStrictReservedWord(bool *is_strict_reserved, bool *ok)
Definition: preparser.h:1664
void Expect(Token::Value token, bool *ok)
Definition: preparser.h:328
void ReportMessageAt(Scanner::Location location, const char *message, bool is_reference_error=false)
Definition: preparser.h:450
IdentifierT ParseIdentifier(AllowEvalOrArgumentsAsIdentifier, bool *ok)
Definition: preparser.h:1637
Traits::Type::ExpressionList ParseArguments(bool *ok)
Definition: preparser.h:2106
void CheckOctalLiteral(int beg_pos, int end_pos, bool *ok)
Definition: preparser.h:381
bool CheckContextualKeyword(Vector< const char > keyword)
Definition: preparser.h:361
ExpressionT ParseAssignmentExpression(bool accept_IN, bool *ok)
Definition: preparser.h:2137
ExpressionT ParseExpression(bool accept_IN, bool *ok)
Definition: preparser.h:1870
void ReportUnexpectedToken(Token::Value token)
Definition: preparser.h:1608
virtual void LogFunction(int start, int end, int literals, int properties, StrictMode strict_mode)=0
virtual void LogMessage(int start, int end, const char *message, const char *argument_opt, bool is_reference_error)=0
static PreParserExpression UseStrictStringLiteral()
Definition: preparser.h:707
static PreParserExpression Default()
Definition: preparser.h:678
static PreParserExpression StringLiteral()
Definition: preparser.h:703
PreParserIdentifier AsIdentifier() const
Definition: preparser.h:733
static PreParserIdentifier Eval()
Definition: preparser.h:605
static PreParserIdentifier Arguments()
Definition: preparser.h:608
static PreParserIdentifier Prototype()
Definition: preparser.h:623
static PreParserIdentifier FutureStrictReserved()
Definition: preparser.h:614
static PreParserIdentifier FutureReserved()
Definition: preparser.h:611
static PreParserIdentifier Let()
Definition: preparser.h:617
static PreParserIdentifier Default()
Definition: preparser.h:602
static PreParserIdentifier Constructor()
Definition: preparser.h:626
static PreParserIdentifier Yield()
Definition: preparser.h:620
static PreParserStatement FunctionDeclaration()
Definition: preparser.h:884
static PreParserStatement Default()
Definition: preparser.h:880
static PreParserStatement ExpressionStatement(PreParserExpression expression)
Definition: preparser.h:891
Checkpoint(ParserBase< PreParserTraits > *parser)
Definition: preparser.cc:38
PreParserIdentifier GetNumberAsSymbol(Scanner *scanner)
Definition: preparser.cc:91
PreParserExpression ExpressionFromString(int pos, Scanner *scanner, PreParserFactory *factory=NULL)
Definition: preparser.cc:96
PreParserExpression ParseV8Intrinsic(bool *ok)
Definition: preparser.cc:105
static AstValueFactory * ast_value_factory()
Definition: preparser.h:1380
PreParserExpression ParseFunctionLiteral(PreParserIdentifier name, Scanner::Location function_name_location, bool name_is_strict_reserved, FunctionKind kind, int function_token_position, FunctionLiteral::FunctionType type, FunctionLiteral::ArityRestriction arity_restriction, bool *ok)
Definition: preparser.cc:110
PreParserIdentifier GetSymbol(Scanner *scanner)
Definition: preparser.cc:64
void ReportMessageAt(Scanner::Location location, const char *message, const char *arg=NULL, bool is_reference_error=false)
Definition: preparser.cc:42
Statement ParseReturnStatement(bool *ok)
Definition: preparser.cc:575
Statement ParseTryStatement(bool *ok)
Definition: preparser.cc:760
Statement ParseContinueStatement(bool *ok)
Definition: preparser.cc:539
void ParseLazyFunctionLiteralBody(bool *ok)
Definition: preparser.cc:927
Statement ParseVariableStatement(VariableDeclarationContext var_context, bool *ok)
Definition: preparser.cc:391
PreParseResult PreParseLazyFunction(StrictMode strict_mode, bool is_generator, ParserRecorder *log)
Definition: preparser.cc:121
Statement ParseFunctionDeclaration(bool *ok)
Definition: preparser.cc:338
Statement ParseWithStatement(bool *ok)
Definition: preparser.cc:601
Statement ParseStatement(bool *ok)
Definition: preparser.cc:234
Statement ParseWhileStatement(bool *ok)
Definition: preparser.cc:668
Expression ParseV8Intrinsic(bool *ok)
Definition: preparser.cc:942
Statement ParseSourceElement(bool *ok)
Definition: preparser.cc:172
bool CheckInOrOf(bool accept_OF)
Definition: preparser.cc:681
Statement ParseSwitchStatement(bool *ok)
Definition: preparser.cc:621
Statement ParseForStatement(bool *ok)
Definition: preparser.cc:690
Statement ParseClassDeclaration(bool *ok)
Definition: preparser.cc:359
Statement ParseExpressionOrLabelledStatement(bool *ok)
Definition: preparser.cc:493
Statement ParseVariableDeclarations(VariableDeclarationContext var_context, VariableDeclarationProperties *decl_props, int *num_decl, bool *ok)
Definition: preparser.cc:411
SourceElements ParseSourceElements(int end_token, bool *ok)
Definition: preparser.cc:203
Statement ParseDoWhileStatement(bool *ok)
Definition: preparser.cc:653
Expression ParseFunctionLiteral(Identifier name, Scanner::Location function_name_location, bool name_is_strict_reserved, FunctionKind kind, int function_token_pos, FunctionLiteral::FunctionType function_type, FunctionLiteral::ArityRestriction arity_restriction, bool *ok)
Definition: preparser.cc:823
Statement ParseThrowStatement(bool *ok)
Definition: preparser.cc:744
Statement ParseBlock(bool *ok)
Definition: preparser.cc:371
Statement ParseDebuggerStatement(bool *ok)
Definition: preparser.cc:802
Statement ParseIfStatement(bool *ok)
Definition: preparser.cc:522
Statement ParseBreakStatement(bool *ok)
Definition: preparser.cc:557
int FindSymbol(DuplicateFinder *finder, int value)
Definition: scanner.cc:1225
bool UnescapedLiteralMatches(const char *data, int length)
Definition: scanner.h:387
Location peek_location() const
Definition: scanner.h:363
Token::Value current_token()
Definition: scanner.h:353
Location location() const
Definition: scanner.h:356
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be expose gc extension under the specified name show built in functions in stack traces use random jit cookie to mask large constants minimum length for automatic enable preparsing CPU profiler sampling interval in microseconds trace out of bounds accesses to external arrays default size of stack region v8 is allowed to maximum length of function source code printed in a stack trace min size of a semi the new space consists of two semi spaces print one trace line following each garbage collection do not print trace line after scavenger collection print cumulative GC statistics in name
#define COMMA
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
#define CASE(Name)
#define DCHECK(condition)
Definition: logging.h:205
#define DCHECK_EQ(v1, v2)
Definition: logging.h:206
Vector< const char > CStrVector(const char *data)
Definition: vector.h:158
kExpectedNofPropertiesOffset function_token_position
Definition: objects-inl.h:5513
bool IsGeneratorFunction(FunctionKind kind)
Definition: globals.h:799
bool IsConciseMethod(FunctionKind kind)
Definition: globals.h:805
@ FUNCTION_SCOPE
Definition: globals.h:647
@ GLOBAL_SCOPE
Definition: globals.h:649
@ kNormalFunction
Definition: globals.h:776
@ kGeneratorFunction
Definition: globals.h:778
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20
#define IN
#define CHECK_OK
Definition: preparser.cc:816
@ STRING
static Location invalid()
Definition: scanner.h:337
Definitions and convenience functions for working with unicode.
int isfinite(double x)