| OLD | NEW |
| (Empty) |
| 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 "src/allocation.h" | |
| 8 #include "src/base/logging.h" | |
| 9 #include "src/conversions-inl.h" | |
| 10 #include "src/conversions.h" | |
| 11 #include "src/globals.h" | |
| 12 #include "src/hashmap.h" | |
| 13 #include "src/list.h" | |
| 14 #include "src/preparse-data.h" | |
| 15 #include "src/preparse-data-format.h" | |
| 16 #include "src/preparser.h" | |
| 17 #include "src/unicode.h" | |
| 18 #include "src/utils.h" | |
| 19 | |
| 20 namespace v8 { | |
| 21 namespace internal { | |
| 22 | |
| 23 void PreParserTraits::ReportMessageAt(Scanner::Location location, | |
| 24 MessageTemplate::Template message, | |
| 25 const char* arg, | |
| 26 ParseErrorType error_type) { | |
| 27 ReportMessageAt(location.beg_pos, location.end_pos, message, arg, error_type); | |
| 28 } | |
| 29 | |
| 30 | |
| 31 void PreParserTraits::ReportMessageAt(int start_pos, int end_pos, | |
| 32 MessageTemplate::Template message, | |
| 33 const char* arg, | |
| 34 ParseErrorType error_type) { | |
| 35 pre_parser_->log_->LogMessage(start_pos, end_pos, message, arg, error_type); | |
| 36 } | |
| 37 | |
| 38 | |
| 39 PreParserIdentifier PreParserTraits::GetSymbol(Scanner* scanner) { | |
| 40 if (scanner->current_token() == Token::FUTURE_RESERVED_WORD) { | |
| 41 return PreParserIdentifier::FutureReserved(); | |
| 42 } else if (scanner->current_token() == | |
| 43 Token::FUTURE_STRICT_RESERVED_WORD) { | |
| 44 return PreParserIdentifier::FutureStrictReserved(); | |
| 45 } else if (scanner->current_token() == Token::LET) { | |
| 46 return PreParserIdentifier::Let(); | |
| 47 } else if (scanner->current_token() == Token::STATIC) { | |
| 48 return PreParserIdentifier::Static(); | |
| 49 } else if (scanner->current_token() == Token::YIELD) { | |
| 50 return PreParserIdentifier::Yield(); | |
| 51 } | |
| 52 if (scanner->UnescapedLiteralMatches("eval", 4)) { | |
| 53 return PreParserIdentifier::Eval(); | |
| 54 } | |
| 55 if (scanner->UnescapedLiteralMatches("arguments", 9)) { | |
| 56 return PreParserIdentifier::Arguments(); | |
| 57 } | |
| 58 if (scanner->UnescapedLiteralMatches("undefined", 9)) { | |
| 59 return PreParserIdentifier::Undefined(); | |
| 60 } | |
| 61 if (scanner->LiteralMatches("prototype", 9)) { | |
| 62 return PreParserIdentifier::Prototype(); | |
| 63 } | |
| 64 if (scanner->LiteralMatches("constructor", 11)) { | |
| 65 return PreParserIdentifier::Constructor(); | |
| 66 } | |
| 67 return PreParserIdentifier::Default(); | |
| 68 } | |
| 69 | |
| 70 | |
| 71 PreParserIdentifier PreParserTraits::GetNumberAsSymbol(Scanner* scanner) { | |
| 72 return PreParserIdentifier::Default(); | |
| 73 } | |
| 74 | |
| 75 | |
| 76 PreParserExpression PreParserTraits::ExpressionFromString( | |
| 77 int pos, Scanner* scanner, PreParserFactory* factory) { | |
| 78 if (scanner->UnescapedLiteralMatches("use strict", 10)) { | |
| 79 return PreParserExpression::UseStrictStringLiteral(); | |
| 80 } else if (scanner->UnescapedLiteralMatches("use strong", 10)) { | |
| 81 return PreParserExpression::UseStrongStringLiteral(); | |
| 82 } | |
| 83 return PreParserExpression::StringLiteral(); | |
| 84 } | |
| 85 | |
| 86 | |
| 87 PreParserExpression PreParserTraits::ParseV8Intrinsic(bool* ok) { | |
| 88 return pre_parser_->ParseV8Intrinsic(ok); | |
| 89 } | |
| 90 | |
| 91 | |
| 92 PreParserExpression PreParserTraits::ParseFunctionLiteral( | |
| 93 PreParserIdentifier name, Scanner::Location function_name_location, | |
| 94 FunctionNameValidity function_name_validity, FunctionKind kind, | |
| 95 int function_token_position, FunctionLiteral::FunctionType type, | |
| 96 FunctionLiteral::ArityRestriction arity_restriction, | |
| 97 LanguageMode language_mode, bool* ok) { | |
| 98 return pre_parser_->ParseFunctionLiteral( | |
| 99 name, function_name_location, function_name_validity, kind, | |
| 100 function_token_position, type, arity_restriction, language_mode, ok); | |
| 101 } | |
| 102 | |
| 103 | |
| 104 PreParser::PreParseResult PreParser::PreParseLazyFunction( | |
| 105 LanguageMode language_mode, FunctionKind kind, bool has_simple_parameters, | |
| 106 ParserRecorder* log, Scanner::BookmarkScope* bookmark) { | |
| 107 log_ = log; | |
| 108 // Lazy functions always have trivial outer scopes (no with/catch scopes). | |
| 109 Scope* top_scope = NewScope(scope_, SCRIPT_SCOPE); | |
| 110 PreParserFactory top_factory(NULL); | |
| 111 FunctionState top_state(&function_state_, &scope_, top_scope, kNormalFunction, | |
| 112 &top_factory); | |
| 113 scope_->SetLanguageMode(language_mode); | |
| 114 Scope* function_scope = NewScope(scope_, FUNCTION_SCOPE, kind); | |
| 115 if (!has_simple_parameters) function_scope->SetHasNonSimpleParameters(); | |
| 116 PreParserFactory function_factory(NULL); | |
| 117 FunctionState function_state(&function_state_, &scope_, function_scope, kind, | |
| 118 &function_factory); | |
| 119 DCHECK_EQ(Token::LBRACE, scanner()->current_token()); | |
| 120 bool ok = true; | |
| 121 int start_position = peek_position(); | |
| 122 ParseLazyFunctionLiteralBody(&ok, bookmark); | |
| 123 if (bookmark && bookmark->HasBeenReset()) { | |
| 124 // Do nothing, as we've just aborted scanning this function. | |
| 125 } else if (stack_overflow()) { | |
| 126 return kPreParseStackOverflow; | |
| 127 } else if (!ok) { | |
| 128 ReportUnexpectedToken(scanner()->current_token()); | |
| 129 } else { | |
| 130 DCHECK_EQ(Token::RBRACE, scanner()->peek()); | |
| 131 if (is_strict(scope_->language_mode())) { | |
| 132 int end_pos = scanner()->location().end_pos; | |
| 133 CheckStrictOctalLiteral(start_position, end_pos, &ok); | |
| 134 if (!ok) return kPreParseSuccess; | |
| 135 | |
| 136 if (is_strong(scope_->language_mode()) && IsSubclassConstructor(kind)) { | |
| 137 if (!function_state.super_location().IsValid()) { | |
| 138 ReportMessageAt(Scanner::Location(start_position, start_position + 1), | |
| 139 MessageTemplate::kStrongSuperCallMissing, | |
| 140 kReferenceError); | |
| 141 return kPreParseSuccess; | |
| 142 } | |
| 143 } | |
| 144 } | |
| 145 } | |
| 146 return kPreParseSuccess; | |
| 147 } | |
| 148 | |
| 149 | |
| 150 PreParserExpression PreParserTraits::ParseClassLiteral( | |
| 151 PreParserIdentifier name, Scanner::Location class_name_location, | |
| 152 bool name_is_strict_reserved, int pos, bool* ok) { | |
| 153 return pre_parser_->ParseClassLiteral(name, class_name_location, | |
| 154 name_is_strict_reserved, pos, ok); | |
| 155 } | |
| 156 | |
| 157 | |
| 158 // Preparsing checks a JavaScript program and emits preparse-data that helps | |
| 159 // a later parsing to be faster. | |
| 160 // See preparser-data.h for the data. | |
| 161 | |
| 162 // The PreParser checks that the syntax follows the grammar for JavaScript, | |
| 163 // and collects some information about the program along the way. | |
| 164 // The grammar check is only performed in order to understand the program | |
| 165 // sufficiently to deduce some information about it, that can be used | |
| 166 // to speed up later parsing. Finding errors is not the goal of pre-parsing, | |
| 167 // rather it is to speed up properly written and correct programs. | |
| 168 // That means that contextual checks (like a label being declared where | |
| 169 // it is used) are generally omitted. | |
| 170 | |
| 171 | |
| 172 PreParser::Statement PreParser::ParseStatementListItem(bool* ok) { | |
| 173 // ECMA 262 6th Edition | |
| 174 // StatementListItem[Yield, Return] : | |
| 175 // Statement[?Yield, ?Return] | |
| 176 // Declaration[?Yield] | |
| 177 // | |
| 178 // Declaration[Yield] : | |
| 179 // HoistableDeclaration[?Yield] | |
| 180 // ClassDeclaration[?Yield] | |
| 181 // LexicalDeclaration[In, ?Yield] | |
| 182 // | |
| 183 // HoistableDeclaration[Yield, Default] : | |
| 184 // FunctionDeclaration[?Yield, ?Default] | |
| 185 // GeneratorDeclaration[?Yield, ?Default] | |
| 186 // | |
| 187 // LexicalDeclaration[In, Yield] : | |
| 188 // LetOrConst BindingList[?In, ?Yield] ; | |
| 189 | |
| 190 switch (peek()) { | |
| 191 case Token::FUNCTION: | |
| 192 return ParseFunctionDeclaration(ok); | |
| 193 case Token::CLASS: | |
| 194 return ParseClassDeclaration(ok); | |
| 195 case Token::CONST: | |
| 196 if (allow_const()) { | |
| 197 return ParseVariableStatement(kStatementListItem, ok); | |
| 198 } | |
| 199 break; | |
| 200 case Token::LET: | |
| 201 if (IsNextLetKeyword()) { | |
| 202 return ParseVariableStatement(kStatementListItem, ok); | |
| 203 } | |
| 204 break; | |
| 205 default: | |
| 206 break; | |
| 207 } | |
| 208 return ParseStatement(ok); | |
| 209 } | |
| 210 | |
| 211 | |
| 212 void PreParser::ParseStatementList(int end_token, bool* ok, | |
| 213 Scanner::BookmarkScope* bookmark) { | |
| 214 // SourceElements :: | |
| 215 // (Statement)* <end_token> | |
| 216 | |
| 217 // Bookkeeping for trial parse if bookmark is set: | |
| 218 DCHECK_IMPLIES(bookmark, bookmark->HasBeenSet()); | |
| 219 bool maybe_reset = bookmark != nullptr; | |
| 220 int count_statements = 0; | |
| 221 | |
| 222 bool directive_prologue = true; | |
| 223 while (peek() != end_token) { | |
| 224 if (directive_prologue && peek() != Token::STRING) { | |
| 225 directive_prologue = false; | |
| 226 } | |
| 227 bool starts_with_identifier = peek() == Token::IDENTIFIER; | |
| 228 Scanner::Location token_loc = scanner()->peek_location(); | |
| 229 Scanner::Location old_this_loc = function_state_->this_location(); | |
| 230 Scanner::Location old_super_loc = function_state_->super_location(); | |
| 231 Statement statement = ParseStatementListItem(ok); | |
| 232 if (!*ok) return; | |
| 233 | |
| 234 if (is_strong(language_mode()) && scope_->is_function_scope() && | |
| 235 IsClassConstructor(function_state_->kind())) { | |
| 236 Scanner::Location this_loc = function_state_->this_location(); | |
| 237 Scanner::Location super_loc = function_state_->super_location(); | |
| 238 if (this_loc.beg_pos != old_this_loc.beg_pos && | |
| 239 this_loc.beg_pos != token_loc.beg_pos) { | |
| 240 ReportMessageAt(this_loc, MessageTemplate::kStrongConstructorThis); | |
| 241 *ok = false; | |
| 242 return; | |
| 243 } | |
| 244 if (super_loc.beg_pos != old_super_loc.beg_pos && | |
| 245 super_loc.beg_pos != token_loc.beg_pos) { | |
| 246 ReportMessageAt(super_loc, MessageTemplate::kStrongConstructorSuper); | |
| 247 *ok = false; | |
| 248 return; | |
| 249 } | |
| 250 } | |
| 251 | |
| 252 if (directive_prologue) { | |
| 253 bool use_strict_found = statement.IsUseStrictLiteral(); | |
| 254 bool use_strong_found = | |
| 255 statement.IsUseStrongLiteral() && allow_strong_mode(); | |
| 256 | |
| 257 if (use_strict_found) { | |
| 258 scope_->SetLanguageMode( | |
| 259 static_cast<LanguageMode>(scope_->language_mode() | STRICT)); | |
| 260 } else if (use_strong_found) { | |
| 261 scope_->SetLanguageMode(static_cast<LanguageMode>( | |
| 262 scope_->language_mode() | STRONG)); | |
| 263 if (IsClassConstructor(function_state_->kind())) { | |
| 264 // "use strong" cannot occur in a class constructor body, to avoid | |
| 265 // unintuitive strong class object semantics. | |
| 266 PreParserTraits::ReportMessageAt( | |
| 267 token_loc, MessageTemplate::kStrongConstructorDirective); | |
| 268 *ok = false; | |
| 269 return; | |
| 270 } | |
| 271 } else if (!statement.IsStringLiteral()) { | |
| 272 directive_prologue = false; | |
| 273 } | |
| 274 | |
| 275 if ((use_strict_found || use_strong_found) && | |
| 276 !scope_->HasSimpleParameters()) { | |
| 277 // TC39 deemed "use strict" directives to be an error when occurring | |
| 278 // in the body of a function with non-simple parameter list, on | |
| 279 // 29/7/2015. https://goo.gl/ueA7Ln | |
| 280 // | |
| 281 // In V8, this also applies to "use strong " directives. | |
| 282 PreParserTraits::ReportMessageAt( | |
| 283 token_loc, MessageTemplate::kIllegalLanguageModeDirective, | |
| 284 use_strict_found ? "use strict" : "use strong"); | |
| 285 *ok = false; | |
| 286 return; | |
| 287 } | |
| 288 } | |
| 289 | |
| 290 // If we're allowed to reset to a bookmark, we will do so when we see a long | |
| 291 // and trivial function. | |
| 292 // Our current definition of 'long and trivial' is: | |
| 293 // - over 200 statements | |
| 294 // - all starting with an identifier (i.e., no if, for, while, etc.) | |
| 295 if (maybe_reset && (!starts_with_identifier || | |
| 296 ++count_statements > kLazyParseTrialLimit)) { | |
| 297 if (count_statements > kLazyParseTrialLimit) { | |
| 298 bookmark->Reset(); | |
| 299 return; | |
| 300 } | |
| 301 maybe_reset = false; | |
| 302 } | |
| 303 } | |
| 304 } | |
| 305 | |
| 306 | |
| 307 #define CHECK_OK ok); \ | |
| 308 if (!*ok) return Statement::Default(); \ | |
| 309 ((void)0 | |
| 310 #define DUMMY ) // to make indentation work | |
| 311 #undef DUMMY | |
| 312 | |
| 313 | |
| 314 PreParser::Statement PreParser::ParseStatement(bool* ok) { | |
| 315 // Statement :: | |
| 316 // EmptyStatement | |
| 317 // ... | |
| 318 | |
| 319 if (peek() == Token::SEMICOLON) { | |
| 320 Next(); | |
| 321 return Statement::Default(); | |
| 322 } | |
| 323 return ParseSubStatement(ok); | |
| 324 } | |
| 325 | |
| 326 | |
| 327 PreParser::Statement PreParser::ParseSubStatement(bool* ok) { | |
| 328 // Statement :: | |
| 329 // Block | |
| 330 // VariableStatement | |
| 331 // EmptyStatement | |
| 332 // ExpressionStatement | |
| 333 // IfStatement | |
| 334 // IterationStatement | |
| 335 // ContinueStatement | |
| 336 // BreakStatement | |
| 337 // ReturnStatement | |
| 338 // WithStatement | |
| 339 // LabelledStatement | |
| 340 // SwitchStatement | |
| 341 // ThrowStatement | |
| 342 // TryStatement | |
| 343 // DebuggerStatement | |
| 344 | |
| 345 // Note: Since labels can only be used by 'break' and 'continue' | |
| 346 // statements, which themselves are only valid within blocks, | |
| 347 // iterations or 'switch' statements (i.e., BreakableStatements), | |
| 348 // labels can be simply ignored in all other cases; except for | |
| 349 // trivial labeled break statements 'label: break label' which is | |
| 350 // parsed into an empty statement. | |
| 351 | |
| 352 // Keep the source position of the statement | |
| 353 switch (peek()) { | |
| 354 case Token::LBRACE: | |
| 355 return ParseBlock(ok); | |
| 356 | |
| 357 case Token::SEMICOLON: | |
| 358 if (is_strong(language_mode())) { | |
| 359 PreParserTraits::ReportMessageAt(scanner()->peek_location(), | |
| 360 MessageTemplate::kStrongEmpty); | |
| 361 *ok = false; | |
| 362 return Statement::Default(); | |
| 363 } | |
| 364 Next(); | |
| 365 return Statement::Default(); | |
| 366 | |
| 367 case Token::IF: | |
| 368 return ParseIfStatement(ok); | |
| 369 | |
| 370 case Token::DO: | |
| 371 return ParseDoWhileStatement(ok); | |
| 372 | |
| 373 case Token::WHILE: | |
| 374 return ParseWhileStatement(ok); | |
| 375 | |
| 376 case Token::FOR: | |
| 377 return ParseForStatement(ok); | |
| 378 | |
| 379 case Token::CONTINUE: | |
| 380 return ParseContinueStatement(ok); | |
| 381 | |
| 382 case Token::BREAK: | |
| 383 return ParseBreakStatement(ok); | |
| 384 | |
| 385 case Token::RETURN: | |
| 386 return ParseReturnStatement(ok); | |
| 387 | |
| 388 case Token::WITH: | |
| 389 return ParseWithStatement(ok); | |
| 390 | |
| 391 case Token::SWITCH: | |
| 392 return ParseSwitchStatement(ok); | |
| 393 | |
| 394 case Token::THROW: | |
| 395 return ParseThrowStatement(ok); | |
| 396 | |
| 397 case Token::TRY: | |
| 398 return ParseTryStatement(ok); | |
| 399 | |
| 400 case Token::FUNCTION: { | |
| 401 Scanner::Location start_location = scanner()->peek_location(); | |
| 402 Statement statement = ParseFunctionDeclaration(CHECK_OK); | |
| 403 Scanner::Location end_location = scanner()->location(); | |
| 404 if (is_strict(language_mode())) { | |
| 405 PreParserTraits::ReportMessageAt(start_location.beg_pos, | |
| 406 end_location.end_pos, | |
| 407 MessageTemplate::kStrictFunction); | |
| 408 *ok = false; | |
| 409 return Statement::Default(); | |
| 410 } else { | |
| 411 return statement; | |
| 412 } | |
| 413 } | |
| 414 | |
| 415 case Token::DEBUGGER: | |
| 416 return ParseDebuggerStatement(ok); | |
| 417 | |
| 418 case Token::VAR: | |
| 419 return ParseVariableStatement(kStatement, ok); | |
| 420 | |
| 421 case Token::CONST: | |
| 422 // In ES6 CONST is not allowed as a Statement, only as a | |
| 423 // LexicalDeclaration, however we continue to allow it in sloppy mode for | |
| 424 // backwards compatibility. | |
| 425 if (is_sloppy(language_mode()) && allow_legacy_const()) { | |
| 426 return ParseVariableStatement(kStatement, ok); | |
| 427 } | |
| 428 | |
| 429 // Fall through. | |
| 430 default: | |
| 431 return ParseExpressionOrLabelledStatement(ok); | |
| 432 } | |
| 433 } | |
| 434 | |
| 435 | |
| 436 PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) { | |
| 437 // FunctionDeclaration :: | |
| 438 // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}' | |
| 439 // GeneratorDeclaration :: | |
| 440 // 'function' '*' Identifier '(' FormalParameterListopt ')' | |
| 441 // '{' FunctionBody '}' | |
| 442 Expect(Token::FUNCTION, CHECK_OK); | |
| 443 int pos = position(); | |
| 444 bool is_generator = Check(Token::MUL); | |
| 445 bool is_strict_reserved = false; | |
| 446 Identifier name = ParseIdentifierOrStrictReservedWord( | |
| 447 &is_strict_reserved, CHECK_OK); | |
| 448 ParseFunctionLiteral(name, scanner()->location(), | |
| 449 is_strict_reserved ? kFunctionNameIsStrictReserved | |
| 450 : kFunctionNameValidityUnknown, | |
| 451 is_generator ? FunctionKind::kGeneratorFunction | |
| 452 : FunctionKind::kNormalFunction, | |
| 453 pos, FunctionLiteral::DECLARATION, | |
| 454 FunctionLiteral::NORMAL_ARITY, language_mode(), | |
| 455 CHECK_OK); | |
| 456 return Statement::FunctionDeclaration(); | |
| 457 } | |
| 458 | |
| 459 | |
| 460 PreParser::Statement PreParser::ParseClassDeclaration(bool* ok) { | |
| 461 Expect(Token::CLASS, CHECK_OK); | |
| 462 if (!allow_harmony_sloppy() && is_sloppy(language_mode())) { | |
| 463 ReportMessage(MessageTemplate::kSloppyLexical); | |
| 464 *ok = false; | |
| 465 return Statement::Default(); | |
| 466 } | |
| 467 | |
| 468 int pos = position(); | |
| 469 bool is_strict_reserved = false; | |
| 470 Identifier name = | |
| 471 ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK); | |
| 472 ParseClassLiteral(name, scanner()->location(), is_strict_reserved, pos, | |
| 473 CHECK_OK); | |
| 474 return Statement::Default(); | |
| 475 } | |
| 476 | |
| 477 | |
| 478 PreParser::Statement PreParser::ParseBlock(bool* ok) { | |
| 479 // Block :: | |
| 480 // '{' StatementList '}' | |
| 481 | |
| 482 Expect(Token::LBRACE, CHECK_OK); | |
| 483 Statement final = Statement::Default(); | |
| 484 while (peek() != Token::RBRACE) { | |
| 485 final = ParseStatementListItem(CHECK_OK); | |
| 486 } | |
| 487 Expect(Token::RBRACE, ok); | |
| 488 return final; | |
| 489 } | |
| 490 | |
| 491 | |
| 492 PreParser::Statement PreParser::ParseVariableStatement( | |
| 493 VariableDeclarationContext var_context, | |
| 494 bool* ok) { | |
| 495 // VariableStatement :: | |
| 496 // VariableDeclarations ';' | |
| 497 | |
| 498 Statement result = ParseVariableDeclarations( | |
| 499 var_context, nullptr, nullptr, nullptr, nullptr, nullptr, CHECK_OK); | |
| 500 ExpectSemicolon(CHECK_OK); | |
| 501 return result; | |
| 502 } | |
| 503 | |
| 504 | |
| 505 // If the variable declaration declares exactly one non-const | |
| 506 // variable, then *var is set to that variable. In all other cases, | |
| 507 // *var is untouched; in particular, it is the caller's responsibility | |
| 508 // to initialize it properly. This mechanism is also used for the parsing | |
| 509 // of 'for-in' loops. | |
| 510 PreParser::Statement PreParser::ParseVariableDeclarations( | |
| 511 VariableDeclarationContext var_context, int* num_decl, bool* is_lexical, | |
| 512 bool* is_binding_pattern, Scanner::Location* first_initializer_loc, | |
| 513 Scanner::Location* bindings_loc, bool* ok) { | |
| 514 // VariableDeclarations :: | |
| 515 // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[','] | |
| 516 // | |
| 517 // The ES6 Draft Rev3 specifies the following grammar for const declarations | |
| 518 // | |
| 519 // ConstDeclaration :: | |
| 520 // const ConstBinding (',' ConstBinding)* ';' | |
| 521 // ConstBinding :: | |
| 522 // Identifier '=' AssignmentExpression | |
| 523 // | |
| 524 // TODO(ES6): | |
| 525 // ConstBinding :: | |
| 526 // BindingPattern '=' AssignmentExpression | |
| 527 bool require_initializer = false; | |
| 528 bool lexical = false; | |
| 529 bool is_pattern = false; | |
| 530 if (peek() == Token::VAR) { | |
| 531 if (is_strong(language_mode())) { | |
| 532 Scanner::Location location = scanner()->peek_location(); | |
| 533 ReportMessageAt(location, MessageTemplate::kStrongVar); | |
| 534 *ok = false; | |
| 535 return Statement::Default(); | |
| 536 } | |
| 537 Consume(Token::VAR); | |
| 538 } else if (peek() == Token::CONST && allow_const()) { | |
| 539 // TODO(ES6): The ES6 Draft Rev4 section 12.2.2 reads: | |
| 540 // | |
| 541 // ConstDeclaration : const ConstBinding (',' ConstBinding)* ';' | |
| 542 // | |
| 543 // * It is a Syntax Error if the code that matches this production is not | |
| 544 // contained in extended code. | |
| 545 // | |
| 546 // However disallowing const in sloppy mode will break compatibility with | |
| 547 // existing pages. Therefore we keep allowing const with the old | |
| 548 // non-harmony semantics in sloppy mode. | |
| 549 Consume(Token::CONST); | |
| 550 if (is_strict(language_mode()) || | |
| 551 (allow_harmony_sloppy() && !allow_legacy_const())) { | |
| 552 DCHECK(var_context != kStatement); | |
| 553 require_initializer = true; | |
| 554 lexical = true; | |
| 555 } | |
| 556 } else if (peek() == Token::LET && allow_let()) { | |
| 557 Consume(Token::LET); | |
| 558 DCHECK(var_context != kStatement); | |
| 559 lexical = true; | |
| 560 } else { | |
| 561 *ok = false; | |
| 562 return Statement::Default(); | |
| 563 } | |
| 564 | |
| 565 // The scope of a var/const declared variable anywhere inside a function | |
| 566 // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). The scope | |
| 567 // of a let declared variable is the scope of the immediately enclosing | |
| 568 // block. | |
| 569 int nvars = 0; // the number of variables declared | |
| 570 int bindings_start = peek_position(); | |
| 571 do { | |
| 572 // Parse binding pattern. | |
| 573 if (nvars > 0) Consume(Token::COMMA); | |
| 574 int decl_pos = peek_position(); | |
| 575 PreParserExpression pattern = PreParserExpression::Default(); | |
| 576 { | |
| 577 ExpressionClassifier pattern_classifier; | |
| 578 Token::Value next = peek(); | |
| 579 pattern = ParsePrimaryExpression(&pattern_classifier, CHECK_OK); | |
| 580 | |
| 581 ValidateBindingPattern(&pattern_classifier, CHECK_OK); | |
| 582 if (lexical) { | |
| 583 ValidateLetPattern(&pattern_classifier, CHECK_OK); | |
| 584 } | |
| 585 | |
| 586 if (!allow_harmony_destructuring_bind() && !pattern.IsIdentifier()) { | |
| 587 ReportUnexpectedToken(next); | |
| 588 *ok = false; | |
| 589 return Statement::Default(); | |
| 590 } | |
| 591 } | |
| 592 | |
| 593 is_pattern = pattern.IsObjectLiteral() || pattern.IsArrayLiteral(); | |
| 594 | |
| 595 bool is_for_iteration_variable = | |
| 596 var_context == kForStatement && | |
| 597 (peek() == Token::IN || PeekContextualKeyword(CStrVector("of"))); | |
| 598 | |
| 599 Scanner::Location variable_loc = scanner()->location(); | |
| 600 nvars++; | |
| 601 if (Check(Token::ASSIGN)) { | |
| 602 ExpressionClassifier classifier; | |
| 603 ParseAssignmentExpression(var_context != kForStatement, &classifier, | |
| 604 CHECK_OK); | |
| 605 ValidateExpression(&classifier, CHECK_OK); | |
| 606 | |
| 607 variable_loc.end_pos = scanner()->location().end_pos; | |
| 608 if (first_initializer_loc && !first_initializer_loc->IsValid()) { | |
| 609 *first_initializer_loc = variable_loc; | |
| 610 } | |
| 611 } else if ((require_initializer || is_pattern) && | |
| 612 !is_for_iteration_variable) { | |
| 613 PreParserTraits::ReportMessageAt( | |
| 614 Scanner::Location(decl_pos, scanner()->location().end_pos), | |
| 615 MessageTemplate::kDeclarationMissingInitializer, | |
| 616 is_pattern ? "destructuring" : "const"); | |
| 617 *ok = false; | |
| 618 return Statement::Default(); | |
| 619 } | |
| 620 } while (peek() == Token::COMMA); | |
| 621 | |
| 622 if (bindings_loc) { | |
| 623 *bindings_loc = | |
| 624 Scanner::Location(bindings_start, scanner()->location().end_pos); | |
| 625 } | |
| 626 | |
| 627 if (num_decl != nullptr) *num_decl = nvars; | |
| 628 if (is_lexical != nullptr) *is_lexical = lexical; | |
| 629 if (is_binding_pattern != nullptr) *is_binding_pattern = is_pattern; | |
| 630 return Statement::Default(); | |
| 631 } | |
| 632 | |
| 633 | |
| 634 PreParser::Statement PreParser::ParseExpressionOrLabelledStatement(bool* ok) { | |
| 635 // ExpressionStatement | LabelledStatement :: | |
| 636 // Expression ';' | |
| 637 // Identifier ':' Statement | |
| 638 | |
| 639 switch (peek()) { | |
| 640 case Token::FUNCTION: | |
| 641 case Token::LBRACE: | |
| 642 UNREACHABLE(); // Always handled by the callers. | |
| 643 case Token::CLASS: | |
| 644 ReportUnexpectedToken(Next()); | |
| 645 *ok = false; | |
| 646 return Statement::Default(); | |
| 647 | |
| 648 case Token::THIS: | |
| 649 if (!FLAG_strong_this) break; | |
| 650 // Fall through. | |
| 651 case Token::SUPER: | |
| 652 if (is_strong(language_mode()) && | |
| 653 IsClassConstructor(function_state_->kind())) { | |
| 654 bool is_this = peek() == Token::THIS; | |
| 655 Expression expr = Expression::Default(); | |
| 656 ExpressionClassifier classifier; | |
| 657 if (is_this) { | |
| 658 expr = ParseStrongInitializationExpression(&classifier, CHECK_OK); | |
| 659 } else { | |
| 660 expr = ParseStrongSuperCallExpression(&classifier, CHECK_OK); | |
| 661 } | |
| 662 ValidateExpression(&classifier, CHECK_OK); | |
| 663 switch (peek()) { | |
| 664 case Token::SEMICOLON: | |
| 665 Consume(Token::SEMICOLON); | |
| 666 break; | |
| 667 case Token::RBRACE: | |
| 668 case Token::EOS: | |
| 669 break; | |
| 670 default: | |
| 671 if (!scanner()->HasAnyLineTerminatorBeforeNext()) { | |
| 672 ReportMessageAt(function_state_->this_location(), | |
| 673 is_this | |
| 674 ? MessageTemplate::kStrongConstructorThis | |
| 675 : MessageTemplate::kStrongConstructorSuper); | |
| 676 *ok = false; | |
| 677 return Statement::Default(); | |
| 678 } | |
| 679 } | |
| 680 return Statement::ExpressionStatement(expr); | |
| 681 } | |
| 682 break; | |
| 683 | |
| 684 // TODO(arv): Handle `let [` | |
| 685 // https://code.google.com/p/v8/issues/detail?id=3847 | |
| 686 | |
| 687 default: | |
| 688 break; | |
| 689 } | |
| 690 | |
| 691 bool starts_with_identifier = peek_any_identifier(); | |
| 692 ExpressionClassifier classifier; | |
| 693 Expression expr = ParseExpression(true, &classifier, CHECK_OK); | |
| 694 ValidateExpression(&classifier, CHECK_OK); | |
| 695 | |
| 696 // Even if the expression starts with an identifier, it is not necessarily an | |
| 697 // identifier. For example, "foo + bar" starts with an identifier but is not | |
| 698 // an identifier. | |
| 699 if (starts_with_identifier && expr.IsIdentifier() && peek() == Token::COLON) { | |
| 700 // Expression is a single identifier, and not, e.g., a parenthesized | |
| 701 // identifier. | |
| 702 DCHECK(!expr.AsIdentifier().IsFutureReserved()); | |
| 703 DCHECK(is_sloppy(language_mode()) || | |
| 704 !IsFutureStrictReserved(expr.AsIdentifier())); | |
| 705 Consume(Token::COLON); | |
| 706 Statement statement = ParseStatement(ok); | |
| 707 return statement.IsJumpStatement() ? Statement::Default() : statement; | |
| 708 // Preparsing is disabled for extensions (because the extension details | |
| 709 // aren't passed to lazily compiled functions), so we don't | |
| 710 // accept "native function" in the preparser. | |
| 711 } | |
| 712 // Parsed expression statement. | |
| 713 // Detect attempts at 'let' declarations in sloppy mode. | |
| 714 if (!allow_harmony_sloppy_let() && peek() == Token::IDENTIFIER && | |
| 715 is_sloppy(language_mode()) && expr.IsIdentifier() && | |
| 716 expr.AsIdentifier().IsLet()) { | |
| 717 ReportMessage(MessageTemplate::kSloppyLexical, NULL); | |
| 718 *ok = false; | |
| 719 return Statement::Default(); | |
| 720 } | |
| 721 ExpectSemicolon(CHECK_OK); | |
| 722 return Statement::ExpressionStatement(expr); | |
| 723 } | |
| 724 | |
| 725 | |
| 726 PreParser::Statement PreParser::ParseIfStatement(bool* ok) { | |
| 727 // IfStatement :: | |
| 728 // 'if' '(' Expression ')' Statement ('else' Statement)? | |
| 729 | |
| 730 Expect(Token::IF, CHECK_OK); | |
| 731 Expect(Token::LPAREN, CHECK_OK); | |
| 732 ParseExpression(true, CHECK_OK); | |
| 733 Expect(Token::RPAREN, CHECK_OK); | |
| 734 Statement stat = ParseSubStatement(CHECK_OK); | |
| 735 if (peek() == Token::ELSE) { | |
| 736 Next(); | |
| 737 Statement else_stat = ParseSubStatement(CHECK_OK); | |
| 738 stat = (stat.IsJumpStatement() && else_stat.IsJumpStatement()) ? | |
| 739 Statement::Jump() : Statement::Default(); | |
| 740 } else { | |
| 741 stat = Statement::Default(); | |
| 742 } | |
| 743 return stat; | |
| 744 } | |
| 745 | |
| 746 | |
| 747 PreParser::Statement PreParser::ParseContinueStatement(bool* ok) { | |
| 748 // ContinueStatement :: | |
| 749 // 'continue' [no line terminator] Identifier? ';' | |
| 750 | |
| 751 Expect(Token::CONTINUE, CHECK_OK); | |
| 752 Token::Value tok = peek(); | |
| 753 if (!scanner()->HasAnyLineTerminatorBeforeNext() && | |
| 754 tok != Token::SEMICOLON && | |
| 755 tok != Token::RBRACE && | |
| 756 tok != Token::EOS) { | |
| 757 // ECMA allows "eval" or "arguments" as labels even in strict mode. | |
| 758 ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK); | |
| 759 } | |
| 760 ExpectSemicolon(CHECK_OK); | |
| 761 return Statement::Jump(); | |
| 762 } | |
| 763 | |
| 764 | |
| 765 PreParser::Statement PreParser::ParseBreakStatement(bool* ok) { | |
| 766 // BreakStatement :: | |
| 767 // 'break' [no line terminator] Identifier? ';' | |
| 768 | |
| 769 Expect(Token::BREAK, CHECK_OK); | |
| 770 Token::Value tok = peek(); | |
| 771 if (!scanner()->HasAnyLineTerminatorBeforeNext() && | |
| 772 tok != Token::SEMICOLON && | |
| 773 tok != Token::RBRACE && | |
| 774 tok != Token::EOS) { | |
| 775 // ECMA allows "eval" or "arguments" as labels even in strict mode. | |
| 776 ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK); | |
| 777 } | |
| 778 ExpectSemicolon(CHECK_OK); | |
| 779 return Statement::Jump(); | |
| 780 } | |
| 781 | |
| 782 | |
| 783 PreParser::Statement PreParser::ParseReturnStatement(bool* ok) { | |
| 784 // ReturnStatement :: | |
| 785 // 'return' [no line terminator] Expression? ';' | |
| 786 | |
| 787 // Consume the return token. It is necessary to do before | |
| 788 // reporting any errors on it, because of the way errors are | |
| 789 // reported (underlining). | |
| 790 Expect(Token::RETURN, CHECK_OK); | |
| 791 function_state_->set_return_location(scanner()->location()); | |
| 792 | |
| 793 // An ECMAScript program is considered syntactically incorrect if it | |
| 794 // contains a return statement that is not within the body of a | |
| 795 // function. See ECMA-262, section 12.9, page 67. | |
| 796 // This is not handled during preparsing. | |
| 797 | |
| 798 Token::Value tok = peek(); | |
| 799 if (!scanner()->HasAnyLineTerminatorBeforeNext() && | |
| 800 tok != Token::SEMICOLON && | |
| 801 tok != Token::RBRACE && | |
| 802 tok != Token::EOS) { | |
| 803 if (is_strong(language_mode()) && | |
| 804 IsClassConstructor(function_state_->kind())) { | |
| 805 int pos = peek_position(); | |
| 806 ReportMessageAt(Scanner::Location(pos, pos + 1), | |
| 807 MessageTemplate::kStrongConstructorReturnValue); | |
| 808 *ok = false; | |
| 809 return Statement::Default(); | |
| 810 } | |
| 811 ParseExpression(true, CHECK_OK); | |
| 812 } | |
| 813 ExpectSemicolon(CHECK_OK); | |
| 814 return Statement::Jump(); | |
| 815 } | |
| 816 | |
| 817 | |
| 818 PreParser::Statement PreParser::ParseWithStatement(bool* ok) { | |
| 819 // WithStatement :: | |
| 820 // 'with' '(' Expression ')' Statement | |
| 821 Expect(Token::WITH, CHECK_OK); | |
| 822 if (is_strict(language_mode())) { | |
| 823 ReportMessageAt(scanner()->location(), MessageTemplate::kStrictWith); | |
| 824 *ok = false; | |
| 825 return Statement::Default(); | |
| 826 } | |
| 827 Expect(Token::LPAREN, CHECK_OK); | |
| 828 ParseExpression(true, CHECK_OK); | |
| 829 Expect(Token::RPAREN, CHECK_OK); | |
| 830 | |
| 831 Scope* with_scope = NewScope(scope_, WITH_SCOPE); | |
| 832 BlockState block_state(&scope_, with_scope); | |
| 833 ParseSubStatement(CHECK_OK); | |
| 834 return Statement::Default(); | |
| 835 } | |
| 836 | |
| 837 | |
| 838 PreParser::Statement PreParser::ParseSwitchStatement(bool* ok) { | |
| 839 // SwitchStatement :: | |
| 840 // 'switch' '(' Expression ')' '{' CaseClause* '}' | |
| 841 | |
| 842 Expect(Token::SWITCH, CHECK_OK); | |
| 843 Expect(Token::LPAREN, CHECK_OK); | |
| 844 ParseExpression(true, CHECK_OK); | |
| 845 Expect(Token::RPAREN, CHECK_OK); | |
| 846 | |
| 847 Expect(Token::LBRACE, CHECK_OK); | |
| 848 Token::Value token = peek(); | |
| 849 while (token != Token::RBRACE) { | |
| 850 if (token == Token::CASE) { | |
| 851 Expect(Token::CASE, CHECK_OK); | |
| 852 ParseExpression(true, CHECK_OK); | |
| 853 } else { | |
| 854 Expect(Token::DEFAULT, CHECK_OK); | |
| 855 } | |
| 856 Expect(Token::COLON, CHECK_OK); | |
| 857 token = peek(); | |
| 858 Statement statement = Statement::Jump(); | |
| 859 while (token != Token::CASE && | |
| 860 token != Token::DEFAULT && | |
| 861 token != Token::RBRACE) { | |
| 862 statement = ParseStatementListItem(CHECK_OK); | |
| 863 token = peek(); | |
| 864 } | |
| 865 if (is_strong(language_mode()) && !statement.IsJumpStatement() && | |
| 866 token != Token::RBRACE) { | |
| 867 ReportMessageAt(scanner()->location(), | |
| 868 MessageTemplate::kStrongSwitchFallthrough); | |
| 869 *ok = false; | |
| 870 return Statement::Default(); | |
| 871 } | |
| 872 } | |
| 873 Expect(Token::RBRACE, ok); | |
| 874 return Statement::Default(); | |
| 875 } | |
| 876 | |
| 877 | |
| 878 PreParser::Statement PreParser::ParseDoWhileStatement(bool* ok) { | |
| 879 // DoStatement :: | |
| 880 // 'do' Statement 'while' '(' Expression ')' ';' | |
| 881 | |
| 882 Expect(Token::DO, CHECK_OK); | |
| 883 ParseSubStatement(CHECK_OK); | |
| 884 Expect(Token::WHILE, CHECK_OK); | |
| 885 Expect(Token::LPAREN, CHECK_OK); | |
| 886 ParseExpression(true, CHECK_OK); | |
| 887 Expect(Token::RPAREN, ok); | |
| 888 if (peek() == Token::SEMICOLON) Consume(Token::SEMICOLON); | |
| 889 return Statement::Default(); | |
| 890 } | |
| 891 | |
| 892 | |
| 893 PreParser::Statement PreParser::ParseWhileStatement(bool* ok) { | |
| 894 // WhileStatement :: | |
| 895 // 'while' '(' Expression ')' Statement | |
| 896 | |
| 897 Expect(Token::WHILE, CHECK_OK); | |
| 898 Expect(Token::LPAREN, CHECK_OK); | |
| 899 ParseExpression(true, CHECK_OK); | |
| 900 Expect(Token::RPAREN, CHECK_OK); | |
| 901 ParseSubStatement(ok); | |
| 902 return Statement::Default(); | |
| 903 } | |
| 904 | |
| 905 | |
| 906 PreParser::Statement PreParser::ParseForStatement(bool* ok) { | |
| 907 // ForStatement :: | |
| 908 // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement | |
| 909 | |
| 910 Expect(Token::FOR, CHECK_OK); | |
| 911 Expect(Token::LPAREN, CHECK_OK); | |
| 912 bool is_let_identifier_expression = false; | |
| 913 if (peek() != Token::SEMICOLON) { | |
| 914 ForEachStatement::VisitMode mode; | |
| 915 if (peek() == Token::VAR || (peek() == Token::CONST && allow_const()) || | |
| 916 (peek() == Token::LET && IsNextLetKeyword())) { | |
| 917 int decl_count; | |
| 918 bool is_lexical; | |
| 919 bool is_binding_pattern; | |
| 920 Scanner::Location first_initializer_loc = Scanner::Location::invalid(); | |
| 921 Scanner::Location bindings_loc = Scanner::Location::invalid(); | |
| 922 ParseVariableDeclarations(kForStatement, &decl_count, &is_lexical, | |
| 923 &is_binding_pattern, &first_initializer_loc, | |
| 924 &bindings_loc, CHECK_OK); | |
| 925 bool accept_IN = decl_count >= 1; | |
| 926 if (accept_IN && CheckInOrOf(&mode, ok)) { | |
| 927 if (!*ok) return Statement::Default(); | |
| 928 if (decl_count != 1) { | |
| 929 const char* loop_type = | |
| 930 mode == ForEachStatement::ITERATE ? "for-of" : "for-in"; | |
| 931 PreParserTraits::ReportMessageAt( | |
| 932 bindings_loc, MessageTemplate::kForInOfLoopMultiBindings, | |
| 933 loop_type); | |
| 934 *ok = false; | |
| 935 return Statement::Default(); | |
| 936 } | |
| 937 if (first_initializer_loc.IsValid() && | |
| 938 (is_strict(language_mode()) || mode == ForEachStatement::ITERATE || | |
| 939 is_lexical || is_binding_pattern)) { | |
| 940 if (mode == ForEachStatement::ITERATE) { | |
| 941 ReportMessageAt(first_initializer_loc, | |
| 942 MessageTemplate::kForOfLoopInitializer); | |
| 943 } else { | |
| 944 // TODO(caitp): This should be an error in sloppy mode, too. | |
| 945 ReportMessageAt(first_initializer_loc, | |
| 946 MessageTemplate::kForInLoopInitializer); | |
| 947 } | |
| 948 *ok = false; | |
| 949 return Statement::Default(); | |
| 950 } | |
| 951 ParseExpression(true, CHECK_OK); | |
| 952 Expect(Token::RPAREN, CHECK_OK); | |
| 953 ParseSubStatement(CHECK_OK); | |
| 954 return Statement::Default(); | |
| 955 } | |
| 956 } else { | |
| 957 int lhs_beg_pos = peek_position(); | |
| 958 Expression lhs = ParseExpression(false, CHECK_OK); | |
| 959 int lhs_end_pos = scanner()->location().end_pos; | |
| 960 is_let_identifier_expression = | |
| 961 lhs.IsIdentifier() && lhs.AsIdentifier().IsLet(); | |
| 962 if (CheckInOrOf(&mode, ok)) { | |
| 963 if (!*ok) return Statement::Default(); | |
| 964 lhs = CheckAndRewriteReferenceExpression( | |
| 965 lhs, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor, | |
| 966 kSyntaxError, CHECK_OK); | |
| 967 ParseExpression(true, CHECK_OK); | |
| 968 Expect(Token::RPAREN, CHECK_OK); | |
| 969 ParseSubStatement(CHECK_OK); | |
| 970 return Statement::Default(); | |
| 971 } | |
| 972 } | |
| 973 } | |
| 974 | |
| 975 // Parsed initializer at this point. | |
| 976 // Detect attempts at 'let' declarations in sloppy mode. | |
| 977 if (!allow_harmony_sloppy_let() && peek() == Token::IDENTIFIER && | |
| 978 is_sloppy(language_mode()) && is_let_identifier_expression) { | |
| 979 ReportMessage(MessageTemplate::kSloppyLexical, NULL); | |
| 980 *ok = false; | |
| 981 return Statement::Default(); | |
| 982 } | |
| 983 Expect(Token::SEMICOLON, CHECK_OK); | |
| 984 | |
| 985 if (peek() != Token::SEMICOLON) { | |
| 986 ParseExpression(true, CHECK_OK); | |
| 987 } | |
| 988 Expect(Token::SEMICOLON, CHECK_OK); | |
| 989 | |
| 990 if (peek() != Token::RPAREN) { | |
| 991 ParseExpression(true, CHECK_OK); | |
| 992 } | |
| 993 Expect(Token::RPAREN, CHECK_OK); | |
| 994 | |
| 995 ParseSubStatement(ok); | |
| 996 return Statement::Default(); | |
| 997 } | |
| 998 | |
| 999 | |
| 1000 PreParser::Statement PreParser::ParseThrowStatement(bool* ok) { | |
| 1001 // ThrowStatement :: | |
| 1002 // 'throw' [no line terminator] Expression ';' | |
| 1003 | |
| 1004 Expect(Token::THROW, CHECK_OK); | |
| 1005 if (scanner()->HasAnyLineTerminatorBeforeNext()) { | |
| 1006 ReportMessageAt(scanner()->location(), MessageTemplate::kNewlineAfterThrow); | |
| 1007 *ok = false; | |
| 1008 return Statement::Default(); | |
| 1009 } | |
| 1010 ParseExpression(true, CHECK_OK); | |
| 1011 ExpectSemicolon(ok); | |
| 1012 return Statement::Jump(); | |
| 1013 } | |
| 1014 | |
| 1015 | |
| 1016 PreParser::Statement PreParser::ParseTryStatement(bool* ok) { | |
| 1017 // TryStatement :: | |
| 1018 // 'try' Block Catch | |
| 1019 // 'try' Block Finally | |
| 1020 // 'try' Block Catch Finally | |
| 1021 // | |
| 1022 // Catch :: | |
| 1023 // 'catch' '(' Identifier ')' Block | |
| 1024 // | |
| 1025 // Finally :: | |
| 1026 // 'finally' Block | |
| 1027 | |
| 1028 Expect(Token::TRY, CHECK_OK); | |
| 1029 | |
| 1030 ParseBlock(CHECK_OK); | |
| 1031 | |
| 1032 Token::Value tok = peek(); | |
| 1033 if (tok != Token::CATCH && tok != Token::FINALLY) { | |
| 1034 ReportMessageAt(scanner()->location(), MessageTemplate::kNoCatchOrFinally); | |
| 1035 *ok = false; | |
| 1036 return Statement::Default(); | |
| 1037 } | |
| 1038 if (tok == Token::CATCH) { | |
| 1039 Consume(Token::CATCH); | |
| 1040 Expect(Token::LPAREN, CHECK_OK); | |
| 1041 ExpressionClassifier pattern_classifier; | |
| 1042 ParsePrimaryExpression(&pattern_classifier, CHECK_OK); | |
| 1043 ValidateBindingPattern(&pattern_classifier, CHECK_OK); | |
| 1044 Expect(Token::RPAREN, CHECK_OK); | |
| 1045 { | |
| 1046 // TODO(adamk): Make this CATCH_SCOPE | |
| 1047 Scope* with_scope = NewScope(scope_, WITH_SCOPE); | |
| 1048 BlockState block_state(&scope_, with_scope); | |
| 1049 ParseBlock(CHECK_OK); | |
| 1050 } | |
| 1051 tok = peek(); | |
| 1052 } | |
| 1053 if (tok == Token::FINALLY) { | |
| 1054 Consume(Token::FINALLY); | |
| 1055 ParseBlock(CHECK_OK); | |
| 1056 } | |
| 1057 return Statement::Default(); | |
| 1058 } | |
| 1059 | |
| 1060 | |
| 1061 PreParser::Statement PreParser::ParseDebuggerStatement(bool* ok) { | |
| 1062 // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser | |
| 1063 // contexts this is used as a statement which invokes the debugger as if a | |
| 1064 // break point is present. | |
| 1065 // DebuggerStatement :: | |
| 1066 // 'debugger' ';' | |
| 1067 | |
| 1068 Expect(Token::DEBUGGER, CHECK_OK); | |
| 1069 ExpectSemicolon(ok); | |
| 1070 return Statement::Default(); | |
| 1071 } | |
| 1072 | |
| 1073 | |
| 1074 #undef CHECK_OK | |
| 1075 #define CHECK_OK ok); \ | |
| 1076 if (!*ok) return Expression::Default(); \ | |
| 1077 ((void)0 | |
| 1078 #define DUMMY ) // to make indentation work | |
| 1079 #undef DUMMY | |
| 1080 | |
| 1081 | |
| 1082 PreParser::Expression PreParser::ParseFunctionLiteral( | |
| 1083 Identifier function_name, Scanner::Location function_name_location, | |
| 1084 FunctionNameValidity function_name_validity, FunctionKind kind, | |
| 1085 int function_token_pos, FunctionLiteral::FunctionType function_type, | |
| 1086 FunctionLiteral::ArityRestriction arity_restriction, | |
| 1087 LanguageMode language_mode, bool* ok) { | |
| 1088 // Function :: | |
| 1089 // '(' FormalParameterList? ')' '{' FunctionBody '}' | |
| 1090 | |
| 1091 // Parse function body. | |
| 1092 bool outer_is_script_scope = scope_->is_script_scope(); | |
| 1093 Scope* function_scope = NewScope(scope_, FUNCTION_SCOPE, kind); | |
| 1094 function_scope->SetLanguageMode(language_mode); | |
| 1095 PreParserFactory factory(NULL); | |
| 1096 FunctionState function_state(&function_state_, &scope_, function_scope, kind, | |
| 1097 &factory); | |
| 1098 DuplicateFinder duplicate_finder(scanner()->unicode_cache()); | |
| 1099 ExpressionClassifier formals_classifier(&duplicate_finder); | |
| 1100 | |
| 1101 Expect(Token::LPAREN, CHECK_OK); | |
| 1102 int start_position = scanner()->location().beg_pos; | |
| 1103 function_scope->set_start_position(start_position); | |
| 1104 PreParserFormalParameters formals(function_scope); | |
| 1105 ParseFormalParameterList(&formals, &formals_classifier, CHECK_OK); | |
| 1106 Expect(Token::RPAREN, CHECK_OK); | |
| 1107 int formals_end_position = scanner()->location().end_pos; | |
| 1108 | |
| 1109 CheckArityRestrictions(formals.arity, arity_restriction, | |
| 1110 formals.has_rest, start_position, | |
| 1111 formals_end_position, CHECK_OK); | |
| 1112 | |
| 1113 // See Parser::ParseFunctionLiteral for more information about lazy parsing | |
| 1114 // and lazy compilation. | |
| 1115 bool is_lazily_parsed = | |
| 1116 (outer_is_script_scope && allow_lazy() && !parenthesized_function_); | |
| 1117 parenthesized_function_ = false; | |
| 1118 | |
| 1119 Expect(Token::LBRACE, CHECK_OK); | |
| 1120 if (is_lazily_parsed) { | |
| 1121 ParseLazyFunctionLiteralBody(CHECK_OK); | |
| 1122 } else { | |
| 1123 ParseStatementList(Token::RBRACE, CHECK_OK); | |
| 1124 } | |
| 1125 Expect(Token::RBRACE, CHECK_OK); | |
| 1126 | |
| 1127 // Parsing the body may change the language mode in our scope. | |
| 1128 language_mode = function_scope->language_mode(); | |
| 1129 | |
| 1130 // Validate name and parameter names. We can do this only after parsing the | |
| 1131 // function, since the function can declare itself strict. | |
| 1132 CheckFunctionName(language_mode, function_name, function_name_validity, | |
| 1133 function_name_location, CHECK_OK); | |
| 1134 const bool allow_duplicate_parameters = | |
| 1135 is_sloppy(language_mode) && formals.is_simple && !IsConciseMethod(kind); | |
| 1136 ValidateFormalParameters(&formals_classifier, language_mode, | |
| 1137 allow_duplicate_parameters, CHECK_OK); | |
| 1138 | |
| 1139 if (is_strict(language_mode)) { | |
| 1140 int end_position = scanner()->location().end_pos; | |
| 1141 CheckStrictOctalLiteral(start_position, end_position, CHECK_OK); | |
| 1142 } | |
| 1143 | |
| 1144 if (is_strong(language_mode) && IsSubclassConstructor(kind)) { | |
| 1145 if (!function_state.super_location().IsValid()) { | |
| 1146 ReportMessageAt(function_name_location, | |
| 1147 MessageTemplate::kStrongSuperCallMissing, | |
| 1148 kReferenceError); | |
| 1149 *ok = false; | |
| 1150 return Expression::Default(); | |
| 1151 } | |
| 1152 } | |
| 1153 | |
| 1154 return Expression::Default(); | |
| 1155 } | |
| 1156 | |
| 1157 | |
| 1158 void PreParser::ParseLazyFunctionLiteralBody(bool* ok, | |
| 1159 Scanner::BookmarkScope* bookmark) { | |
| 1160 int body_start = position(); | |
| 1161 ParseStatementList(Token::RBRACE, ok, bookmark); | |
| 1162 if (!*ok) return; | |
| 1163 if (bookmark && bookmark->HasBeenReset()) return; | |
| 1164 | |
| 1165 // Position right after terminal '}'. | |
| 1166 DCHECK_EQ(Token::RBRACE, scanner()->peek()); | |
| 1167 int body_end = scanner()->peek_location().end_pos; | |
| 1168 log_->LogFunction(body_start, body_end, | |
| 1169 function_state_->materialized_literal_count(), | |
| 1170 function_state_->expected_property_count(), language_mode(), | |
| 1171 scope_->uses_super_property(), scope_->calls_eval()); | |
| 1172 } | |
| 1173 | |
| 1174 | |
| 1175 PreParserExpression PreParser::ParseClassLiteral( | |
| 1176 PreParserIdentifier name, Scanner::Location class_name_location, | |
| 1177 bool name_is_strict_reserved, int pos, bool* ok) { | |
| 1178 // All parts of a ClassDeclaration and ClassExpression are strict code. | |
| 1179 if (name_is_strict_reserved) { | |
| 1180 ReportMessageAt(class_name_location, | |
| 1181 MessageTemplate::kUnexpectedStrictReserved); | |
| 1182 *ok = false; | |
| 1183 return EmptyExpression(); | |
| 1184 } | |
| 1185 if (IsEvalOrArguments(name)) { | |
| 1186 ReportMessageAt(class_name_location, MessageTemplate::kStrictEvalArguments); | |
| 1187 *ok = false; | |
| 1188 return EmptyExpression(); | |
| 1189 } | |
| 1190 LanguageMode class_language_mode = language_mode(); | |
| 1191 if (is_strong(class_language_mode) && IsUndefined(name)) { | |
| 1192 ReportMessageAt(class_name_location, MessageTemplate::kStrongUndefined); | |
| 1193 *ok = false; | |
| 1194 return EmptyExpression(); | |
| 1195 } | |
| 1196 | |
| 1197 Scope* scope = NewScope(scope_, BLOCK_SCOPE); | |
| 1198 BlockState block_state(&scope_, scope); | |
| 1199 scope_->SetLanguageMode( | |
| 1200 static_cast<LanguageMode>(class_language_mode | STRICT)); | |
| 1201 // TODO(marja): Make PreParser use scope names too. | |
| 1202 // scope_->SetScopeName(name); | |
| 1203 | |
| 1204 bool has_extends = Check(Token::EXTENDS); | |
| 1205 if (has_extends) { | |
| 1206 ExpressionClassifier classifier; | |
| 1207 ParseLeftHandSideExpression(&classifier, CHECK_OK); | |
| 1208 ValidateExpression(&classifier, CHECK_OK); | |
| 1209 } | |
| 1210 | |
| 1211 ClassLiteralChecker checker(this); | |
| 1212 bool has_seen_constructor = false; | |
| 1213 | |
| 1214 Expect(Token::LBRACE, CHECK_OK); | |
| 1215 while (peek() != Token::RBRACE) { | |
| 1216 if (Check(Token::SEMICOLON)) continue; | |
| 1217 const bool in_class = true; | |
| 1218 const bool is_static = false; | |
| 1219 bool is_computed_name = false; // Classes do not care about computed | |
| 1220 // property names here. | |
| 1221 ExpressionClassifier classifier; | |
| 1222 ParsePropertyDefinition(&checker, in_class, has_extends, is_static, | |
| 1223 &is_computed_name, &has_seen_constructor, | |
| 1224 &classifier, CHECK_OK); | |
| 1225 ValidateExpression(&classifier, CHECK_OK); | |
| 1226 } | |
| 1227 | |
| 1228 Expect(Token::RBRACE, CHECK_OK); | |
| 1229 | |
| 1230 return Expression::Default(); | |
| 1231 } | |
| 1232 | |
| 1233 | |
| 1234 PreParser::Expression PreParser::ParseV8Intrinsic(bool* ok) { | |
| 1235 // CallRuntime :: | |
| 1236 // '%' Identifier Arguments | |
| 1237 Expect(Token::MOD, CHECK_OK); | |
| 1238 if (!allow_natives()) { | |
| 1239 *ok = false; | |
| 1240 return Expression::Default(); | |
| 1241 } | |
| 1242 // Allow "eval" or "arguments" for backward compatibility. | |
| 1243 ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK); | |
| 1244 Scanner::Location spread_pos; | |
| 1245 ExpressionClassifier classifier; | |
| 1246 ParseArguments(&spread_pos, &classifier, ok); | |
| 1247 ValidateExpression(&classifier, CHECK_OK); | |
| 1248 | |
| 1249 DCHECK(!spread_pos.IsValid()); | |
| 1250 | |
| 1251 return Expression::Default(); | |
| 1252 } | |
| 1253 | |
| 1254 | |
| 1255 PreParserExpression PreParser::ParseDoExpression(bool* ok) { | |
| 1256 // AssignmentExpression :: | |
| 1257 // do '{' StatementList '}' | |
| 1258 Expect(Token::DO, CHECK_OK); | |
| 1259 Expect(Token::LBRACE, CHECK_OK); | |
| 1260 Scope* block_scope = NewScope(scope_, BLOCK_SCOPE); | |
| 1261 { | |
| 1262 BlockState block_state(&scope_, block_scope); | |
| 1263 while (peek() != Token::RBRACE) { | |
| 1264 ParseStatementListItem(CHECK_OK); | |
| 1265 } | |
| 1266 Expect(Token::RBRACE, CHECK_OK); | |
| 1267 return PreParserExpression::Default(); | |
| 1268 } | |
| 1269 } | |
| 1270 | |
| 1271 #undef CHECK_OK | |
| 1272 | |
| 1273 | |
| 1274 } // namespace internal | |
| 1275 } // namespace v8 | |
| OLD | NEW |