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