| OLD | NEW |
| (Empty) |
| 1 // Copyright 2012 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 "src/parser.h" | |
| 6 | |
| 7 #include "src/api.h" | |
| 8 #include "src/ast.h" | |
| 9 #include "src/ast-literal-reindexer.h" | |
| 10 #include "src/bailout-reason.h" | |
| 11 #include "src/base/platform/platform.h" | |
| 12 #include "src/bootstrapper.h" | |
| 13 #include "src/char-predicates-inl.h" | |
| 14 #include "src/codegen.h" | |
| 15 #include "src/compiler.h" | |
| 16 #include "src/messages.h" | |
| 17 #include "src/parameter-initializer-rewriter.h" | |
| 18 #include "src/preparser.h" | |
| 19 #include "src/rewriter.h" | |
| 20 #include "src/runtime/runtime.h" | |
| 21 #include "src/scanner-character-streams.h" | |
| 22 #include "src/scopeinfo.h" | |
| 23 #include "src/string-stream.h" | |
| 24 | |
| 25 namespace v8 { | |
| 26 namespace internal { | |
| 27 | |
| 28 ScriptData::ScriptData(const byte* data, int length) | |
| 29 : owns_data_(false), rejected_(false), data_(data), length_(length) { | |
| 30 if (!IsAligned(reinterpret_cast<intptr_t>(data), kPointerAlignment)) { | |
| 31 byte* copy = NewArray<byte>(length); | |
| 32 DCHECK(IsAligned(reinterpret_cast<intptr_t>(copy), kPointerAlignment)); | |
| 33 CopyBytes(copy, data, length); | |
| 34 data_ = copy; | |
| 35 AcquireDataOwnership(); | |
| 36 } | |
| 37 } | |
| 38 | |
| 39 | |
| 40 ParseInfo::ParseInfo(Zone* zone) | |
| 41 : zone_(zone), | |
| 42 flags_(0), | |
| 43 source_stream_(nullptr), | |
| 44 source_stream_encoding_(ScriptCompiler::StreamedSource::ONE_BYTE), | |
| 45 extension_(nullptr), | |
| 46 compile_options_(ScriptCompiler::kNoCompileOptions), | |
| 47 script_scope_(nullptr), | |
| 48 unicode_cache_(nullptr), | |
| 49 stack_limit_(0), | |
| 50 hash_seed_(0), | |
| 51 cached_data_(nullptr), | |
| 52 ast_value_factory_(nullptr), | |
| 53 literal_(nullptr), | |
| 54 scope_(nullptr) {} | |
| 55 | |
| 56 | |
| 57 ParseInfo::ParseInfo(Zone* zone, Handle<JSFunction> function) | |
| 58 : ParseInfo(zone, Handle<SharedFunctionInfo>(function->shared())) { | |
| 59 set_closure(function); | |
| 60 set_context(Handle<Context>(function->context())); | |
| 61 } | |
| 62 | |
| 63 | |
| 64 ParseInfo::ParseInfo(Zone* zone, Handle<SharedFunctionInfo> shared) | |
| 65 : ParseInfo(zone) { | |
| 66 isolate_ = shared->GetIsolate(); | |
| 67 | |
| 68 set_lazy(); | |
| 69 set_hash_seed(isolate_->heap()->HashSeed()); | |
| 70 set_stack_limit(isolate_->stack_guard()->real_climit()); | |
| 71 set_unicode_cache(isolate_->unicode_cache()); | |
| 72 set_language_mode(shared->language_mode()); | |
| 73 set_shared_info(shared); | |
| 74 | |
| 75 Handle<Script> script(Script::cast(shared->script())); | |
| 76 set_script(script); | |
| 77 if (!script.is_null() && script->type() == Script::TYPE_NATIVE) { | |
| 78 set_native(); | |
| 79 } | |
| 80 } | |
| 81 | |
| 82 | |
| 83 ParseInfo::ParseInfo(Zone* zone, Handle<Script> script) : ParseInfo(zone) { | |
| 84 isolate_ = script->GetIsolate(); | |
| 85 | |
| 86 set_hash_seed(isolate_->heap()->HashSeed()); | |
| 87 set_stack_limit(isolate_->stack_guard()->real_climit()); | |
| 88 set_unicode_cache(isolate_->unicode_cache()); | |
| 89 set_script(script); | |
| 90 | |
| 91 if (script->type() == Script::TYPE_NATIVE) { | |
| 92 set_native(); | |
| 93 } | |
| 94 } | |
| 95 | |
| 96 | |
| 97 RegExpBuilder::RegExpBuilder(Zone* zone) | |
| 98 : zone_(zone), | |
| 99 pending_empty_(false), | |
| 100 characters_(NULL), | |
| 101 terms_(), | |
| 102 alternatives_() | |
| 103 #ifdef DEBUG | |
| 104 , last_added_(ADD_NONE) | |
| 105 #endif | |
| 106 {} | |
| 107 | |
| 108 | |
| 109 void RegExpBuilder::FlushCharacters() { | |
| 110 pending_empty_ = false; | |
| 111 if (characters_ != NULL) { | |
| 112 RegExpTree* atom = new(zone()) RegExpAtom(characters_->ToConstVector()); | |
| 113 characters_ = NULL; | |
| 114 text_.Add(atom, zone()); | |
| 115 LAST(ADD_ATOM); | |
| 116 } | |
| 117 } | |
| 118 | |
| 119 | |
| 120 void RegExpBuilder::FlushText() { | |
| 121 FlushCharacters(); | |
| 122 int num_text = text_.length(); | |
| 123 if (num_text == 0) { | |
| 124 return; | |
| 125 } else if (num_text == 1) { | |
| 126 terms_.Add(text_.last(), zone()); | |
| 127 } else { | |
| 128 RegExpText* text = new(zone()) RegExpText(zone()); | |
| 129 for (int i = 0; i < num_text; i++) | |
| 130 text_.Get(i)->AppendToText(text, zone()); | |
| 131 terms_.Add(text, zone()); | |
| 132 } | |
| 133 text_.Clear(); | |
| 134 } | |
| 135 | |
| 136 | |
| 137 void RegExpBuilder::AddCharacter(uc16 c) { | |
| 138 pending_empty_ = false; | |
| 139 if (characters_ == NULL) { | |
| 140 characters_ = new(zone()) ZoneList<uc16>(4, zone()); | |
| 141 } | |
| 142 characters_->Add(c, zone()); | |
| 143 LAST(ADD_CHAR); | |
| 144 } | |
| 145 | |
| 146 | |
| 147 void RegExpBuilder::AddEmpty() { | |
| 148 pending_empty_ = true; | |
| 149 } | |
| 150 | |
| 151 | |
| 152 void RegExpBuilder::AddAtom(RegExpTree* term) { | |
| 153 if (term->IsEmpty()) { | |
| 154 AddEmpty(); | |
| 155 return; | |
| 156 } | |
| 157 if (term->IsTextElement()) { | |
| 158 FlushCharacters(); | |
| 159 text_.Add(term, zone()); | |
| 160 } else { | |
| 161 FlushText(); | |
| 162 terms_.Add(term, zone()); | |
| 163 } | |
| 164 LAST(ADD_ATOM); | |
| 165 } | |
| 166 | |
| 167 | |
| 168 void RegExpBuilder::AddAssertion(RegExpTree* assert) { | |
| 169 FlushText(); | |
| 170 terms_.Add(assert, zone()); | |
| 171 LAST(ADD_ASSERT); | |
| 172 } | |
| 173 | |
| 174 | |
| 175 void RegExpBuilder::NewAlternative() { | |
| 176 FlushTerms(); | |
| 177 } | |
| 178 | |
| 179 | |
| 180 void RegExpBuilder::FlushTerms() { | |
| 181 FlushText(); | |
| 182 int num_terms = terms_.length(); | |
| 183 RegExpTree* alternative; | |
| 184 if (num_terms == 0) { | |
| 185 alternative = new (zone()) RegExpEmpty(); | |
| 186 } else if (num_terms == 1) { | |
| 187 alternative = terms_.last(); | |
| 188 } else { | |
| 189 alternative = new(zone()) RegExpAlternative(terms_.GetList(zone())); | |
| 190 } | |
| 191 alternatives_.Add(alternative, zone()); | |
| 192 terms_.Clear(); | |
| 193 LAST(ADD_NONE); | |
| 194 } | |
| 195 | |
| 196 | |
| 197 RegExpTree* RegExpBuilder::ToRegExp() { | |
| 198 FlushTerms(); | |
| 199 int num_alternatives = alternatives_.length(); | |
| 200 if (num_alternatives == 0) return new (zone()) RegExpEmpty(); | |
| 201 if (num_alternatives == 1) return alternatives_.last(); | |
| 202 return new(zone()) RegExpDisjunction(alternatives_.GetList(zone())); | |
| 203 } | |
| 204 | |
| 205 | |
| 206 void RegExpBuilder::AddQuantifierToAtom( | |
| 207 int min, int max, RegExpQuantifier::QuantifierType quantifier_type) { | |
| 208 if (pending_empty_) { | |
| 209 pending_empty_ = false; | |
| 210 return; | |
| 211 } | |
| 212 RegExpTree* atom; | |
| 213 if (characters_ != NULL) { | |
| 214 DCHECK(last_added_ == ADD_CHAR); | |
| 215 // Last atom was character. | |
| 216 Vector<const uc16> char_vector = characters_->ToConstVector(); | |
| 217 int num_chars = char_vector.length(); | |
| 218 if (num_chars > 1) { | |
| 219 Vector<const uc16> prefix = char_vector.SubVector(0, num_chars - 1); | |
| 220 text_.Add(new(zone()) RegExpAtom(prefix), zone()); | |
| 221 char_vector = char_vector.SubVector(num_chars - 1, num_chars); | |
| 222 } | |
| 223 characters_ = NULL; | |
| 224 atom = new(zone()) RegExpAtom(char_vector); | |
| 225 FlushText(); | |
| 226 } else if (text_.length() > 0) { | |
| 227 DCHECK(last_added_ == ADD_ATOM); | |
| 228 atom = text_.RemoveLast(); | |
| 229 FlushText(); | |
| 230 } else if (terms_.length() > 0) { | |
| 231 DCHECK(last_added_ == ADD_ATOM); | |
| 232 atom = terms_.RemoveLast(); | |
| 233 if (atom->max_match() == 0) { | |
| 234 // Guaranteed to only match an empty string. | |
| 235 LAST(ADD_TERM); | |
| 236 if (min == 0) { | |
| 237 return; | |
| 238 } | |
| 239 terms_.Add(atom, zone()); | |
| 240 return; | |
| 241 } | |
| 242 } else { | |
| 243 // Only call immediately after adding an atom or character! | |
| 244 UNREACHABLE(); | |
| 245 return; | |
| 246 } | |
| 247 terms_.Add( | |
| 248 new(zone()) RegExpQuantifier(min, max, quantifier_type, atom), zone()); | |
| 249 LAST(ADD_TERM); | |
| 250 } | |
| 251 | |
| 252 | |
| 253 FunctionEntry ParseData::GetFunctionEntry(int start) { | |
| 254 // The current pre-data entry must be a FunctionEntry with the given | |
| 255 // start position. | |
| 256 if ((function_index_ + FunctionEntry::kSize <= Length()) && | |
| 257 (static_cast<int>(Data()[function_index_]) == start)) { | |
| 258 int index = function_index_; | |
| 259 function_index_ += FunctionEntry::kSize; | |
| 260 Vector<unsigned> subvector(&(Data()[index]), FunctionEntry::kSize); | |
| 261 return FunctionEntry(subvector); | |
| 262 } | |
| 263 return FunctionEntry(); | |
| 264 } | |
| 265 | |
| 266 | |
| 267 int ParseData::FunctionCount() { | |
| 268 int functions_size = FunctionsSize(); | |
| 269 if (functions_size < 0) return 0; | |
| 270 if (functions_size % FunctionEntry::kSize != 0) return 0; | |
| 271 return functions_size / FunctionEntry::kSize; | |
| 272 } | |
| 273 | |
| 274 | |
| 275 bool ParseData::IsSane() { | |
| 276 if (!IsAligned(script_data_->length(), sizeof(unsigned))) return false; | |
| 277 // Check that the header data is valid and doesn't specify | |
| 278 // point to positions outside the store. | |
| 279 int data_length = Length(); | |
| 280 if (data_length < PreparseDataConstants::kHeaderSize) return false; | |
| 281 if (Magic() != PreparseDataConstants::kMagicNumber) return false; | |
| 282 if (Version() != PreparseDataConstants::kCurrentVersion) return false; | |
| 283 if (HasError()) return false; | |
| 284 // Check that the space allocated for function entries is sane. | |
| 285 int functions_size = FunctionsSize(); | |
| 286 if (functions_size < 0) return false; | |
| 287 if (functions_size % FunctionEntry::kSize != 0) return false; | |
| 288 // Check that the total size has room for header and function entries. | |
| 289 int minimum_size = | |
| 290 PreparseDataConstants::kHeaderSize + functions_size; | |
| 291 if (data_length < minimum_size) return false; | |
| 292 return true; | |
| 293 } | |
| 294 | |
| 295 | |
| 296 void ParseData::Initialize() { | |
| 297 // Prepares state for use. | |
| 298 int data_length = Length(); | |
| 299 if (data_length >= PreparseDataConstants::kHeaderSize) { | |
| 300 function_index_ = PreparseDataConstants::kHeaderSize; | |
| 301 } | |
| 302 } | |
| 303 | |
| 304 | |
| 305 bool ParseData::HasError() { | |
| 306 return Data()[PreparseDataConstants::kHasErrorOffset]; | |
| 307 } | |
| 308 | |
| 309 | |
| 310 unsigned ParseData::Magic() { | |
| 311 return Data()[PreparseDataConstants::kMagicOffset]; | |
| 312 } | |
| 313 | |
| 314 | |
| 315 unsigned ParseData::Version() { | |
| 316 return Data()[PreparseDataConstants::kVersionOffset]; | |
| 317 } | |
| 318 | |
| 319 | |
| 320 int ParseData::FunctionsSize() { | |
| 321 return static_cast<int>(Data()[PreparseDataConstants::kFunctionsSizeOffset]); | |
| 322 } | |
| 323 | |
| 324 | |
| 325 void Parser::SetCachedData(ParseInfo* info) { | |
| 326 if (compile_options_ == ScriptCompiler::kNoCompileOptions) { | |
| 327 cached_parse_data_ = NULL; | |
| 328 } else { | |
| 329 DCHECK(info->cached_data() != NULL); | |
| 330 if (compile_options_ == ScriptCompiler::kConsumeParserCache) { | |
| 331 cached_parse_data_ = ParseData::FromCachedData(*info->cached_data()); | |
| 332 } | |
| 333 } | |
| 334 } | |
| 335 | |
| 336 | |
| 337 FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope, | |
| 338 int pos, int end_pos, | |
| 339 LanguageMode language_mode) { | |
| 340 int materialized_literal_count = -1; | |
| 341 int expected_property_count = -1; | |
| 342 int parameter_count = 0; | |
| 343 const AstRawString* name = ast_value_factory()->empty_string(); | |
| 344 | |
| 345 | |
| 346 FunctionKind kind = call_super ? FunctionKind::kDefaultSubclassConstructor | |
| 347 : FunctionKind::kDefaultBaseConstructor; | |
| 348 Scope* function_scope = NewScope(scope, FUNCTION_SCOPE, kind); | |
| 349 SetLanguageMode(function_scope, | |
| 350 static_cast<LanguageMode>(language_mode | STRICT)); | |
| 351 // Set start and end position to the same value | |
| 352 function_scope->set_start_position(pos); | |
| 353 function_scope->set_end_position(pos); | |
| 354 ZoneList<Statement*>* body = NULL; | |
| 355 | |
| 356 { | |
| 357 AstNodeFactory function_factory(ast_value_factory()); | |
| 358 FunctionState function_state(&function_state_, &scope_, function_scope, | |
| 359 kind, &function_factory); | |
| 360 | |
| 361 body = new (zone()) ZoneList<Statement*>(call_super ? 2 : 1, zone()); | |
| 362 if (call_super) { | |
| 363 // %_DefaultConstructorCallSuper(new.target, %GetPrototype(<this-fun>)) | |
| 364 ZoneList<Expression*>* args = | |
| 365 new (zone()) ZoneList<Expression*>(2, zone()); | |
| 366 VariableProxy* new_target_proxy = scope_->NewUnresolved( | |
| 367 factory(), ast_value_factory()->new_target_string(), Variable::NORMAL, | |
| 368 pos); | |
| 369 args->Add(new_target_proxy, zone()); | |
| 370 VariableProxy* this_function_proxy = scope_->NewUnresolved( | |
| 371 factory(), ast_value_factory()->this_function_string(), | |
| 372 Variable::NORMAL, pos); | |
| 373 ZoneList<Expression*>* tmp = | |
| 374 new (zone()) ZoneList<Expression*>(1, zone()); | |
| 375 tmp->Add(this_function_proxy, zone()); | |
| 376 Expression* get_prototype = | |
| 377 factory()->NewCallRuntime(Runtime::kGetPrototype, tmp, pos); | |
| 378 args->Add(get_prototype, zone()); | |
| 379 CallRuntime* call = factory()->NewCallRuntime( | |
| 380 Runtime::kInlineDefaultConstructorCallSuper, args, pos); | |
| 381 body->Add(factory()->NewReturnStatement(call, pos), zone()); | |
| 382 } | |
| 383 | |
| 384 materialized_literal_count = function_state.materialized_literal_count(); | |
| 385 expected_property_count = function_state.expected_property_count(); | |
| 386 } | |
| 387 | |
| 388 FunctionLiteral* function_literal = factory()->NewFunctionLiteral( | |
| 389 name, ast_value_factory(), function_scope, body, | |
| 390 materialized_literal_count, expected_property_count, parameter_count, | |
| 391 FunctionLiteral::kNoDuplicateParameters, | |
| 392 FunctionLiteral::ANONYMOUS_EXPRESSION, FunctionLiteral::kIsFunction, | |
| 393 FunctionLiteral::kShouldLazyCompile, kind, pos); | |
| 394 | |
| 395 return function_literal; | |
| 396 } | |
| 397 | |
| 398 | |
| 399 // ---------------------------------------------------------------------------- | |
| 400 // Target is a support class to facilitate manipulation of the | |
| 401 // Parser's target_stack_ (the stack of potential 'break' and | |
| 402 // 'continue' statement targets). Upon construction, a new target is | |
| 403 // added; it is removed upon destruction. | |
| 404 | |
| 405 class Target BASE_EMBEDDED { | |
| 406 public: | |
| 407 Target(Target** variable, BreakableStatement* statement) | |
| 408 : variable_(variable), statement_(statement), previous_(*variable) { | |
| 409 *variable = this; | |
| 410 } | |
| 411 | |
| 412 ~Target() { | |
| 413 *variable_ = previous_; | |
| 414 } | |
| 415 | |
| 416 Target* previous() { return previous_; } | |
| 417 BreakableStatement* statement() { return statement_; } | |
| 418 | |
| 419 private: | |
| 420 Target** variable_; | |
| 421 BreakableStatement* statement_; | |
| 422 Target* previous_; | |
| 423 }; | |
| 424 | |
| 425 | |
| 426 class TargetScope BASE_EMBEDDED { | |
| 427 public: | |
| 428 explicit TargetScope(Target** variable) | |
| 429 : variable_(variable), previous_(*variable) { | |
| 430 *variable = NULL; | |
| 431 } | |
| 432 | |
| 433 ~TargetScope() { | |
| 434 *variable_ = previous_; | |
| 435 } | |
| 436 | |
| 437 private: | |
| 438 Target** variable_; | |
| 439 Target* previous_; | |
| 440 }; | |
| 441 | |
| 442 | |
| 443 // ---------------------------------------------------------------------------- | |
| 444 // The CHECK_OK macro is a convenient macro to enforce error | |
| 445 // handling for functions that may fail (by returning !*ok). | |
| 446 // | |
| 447 // CAUTION: This macro appends extra statements after a call, | |
| 448 // thus it must never be used where only a single statement | |
| 449 // is correct (e.g. an if statement branch w/o braces)! | |
| 450 | |
| 451 #define CHECK_OK ok); \ | |
| 452 if (!*ok) return NULL; \ | |
| 453 ((void)0 | |
| 454 #define DUMMY ) // to make indentation work | |
| 455 #undef DUMMY | |
| 456 | |
| 457 #define CHECK_FAILED /**/); \ | |
| 458 if (failed_) return NULL; \ | |
| 459 ((void)0 | |
| 460 #define DUMMY ) // to make indentation work | |
| 461 #undef DUMMY | |
| 462 | |
| 463 // ---------------------------------------------------------------------------- | |
| 464 // Implementation of Parser | |
| 465 | |
| 466 bool ParserTraits::IsEval(const AstRawString* identifier) const { | |
| 467 return identifier == parser_->ast_value_factory()->eval_string(); | |
| 468 } | |
| 469 | |
| 470 | |
| 471 bool ParserTraits::IsArguments(const AstRawString* identifier) const { | |
| 472 return identifier == parser_->ast_value_factory()->arguments_string(); | |
| 473 } | |
| 474 | |
| 475 | |
| 476 bool ParserTraits::IsEvalOrArguments(const AstRawString* identifier) const { | |
| 477 return IsEval(identifier) || IsArguments(identifier); | |
| 478 } | |
| 479 | |
| 480 bool ParserTraits::IsUndefined(const AstRawString* identifier) const { | |
| 481 return identifier == parser_->ast_value_factory()->undefined_string(); | |
| 482 } | |
| 483 | |
| 484 bool ParserTraits::IsPrototype(const AstRawString* identifier) const { | |
| 485 return identifier == parser_->ast_value_factory()->prototype_string(); | |
| 486 } | |
| 487 | |
| 488 | |
| 489 bool ParserTraits::IsConstructor(const AstRawString* identifier) const { | |
| 490 return identifier == parser_->ast_value_factory()->constructor_string(); | |
| 491 } | |
| 492 | |
| 493 | |
| 494 bool ParserTraits::IsThisProperty(Expression* expression) { | |
| 495 DCHECK(expression != NULL); | |
| 496 Property* property = expression->AsProperty(); | |
| 497 return property != NULL && property->obj()->IsVariableProxy() && | |
| 498 property->obj()->AsVariableProxy()->is_this(); | |
| 499 } | |
| 500 | |
| 501 | |
| 502 bool ParserTraits::IsIdentifier(Expression* expression) { | |
| 503 VariableProxy* operand = expression->AsVariableProxy(); | |
| 504 return operand != NULL && !operand->is_this(); | |
| 505 } | |
| 506 | |
| 507 | |
| 508 void ParserTraits::PushPropertyName(FuncNameInferrer* fni, | |
| 509 Expression* expression) { | |
| 510 if (expression->IsPropertyName()) { | |
| 511 fni->PushLiteralName(expression->AsLiteral()->AsRawPropertyName()); | |
| 512 } else { | |
| 513 fni->PushLiteralName( | |
| 514 parser_->ast_value_factory()->anonymous_function_string()); | |
| 515 } | |
| 516 } | |
| 517 | |
| 518 | |
| 519 void ParserTraits::CheckAssigningFunctionLiteralToProperty(Expression* left, | |
| 520 Expression* right) { | |
| 521 DCHECK(left != NULL); | |
| 522 if (left->IsProperty() && right->IsFunctionLiteral()) { | |
| 523 right->AsFunctionLiteral()->set_pretenure(); | |
| 524 } | |
| 525 } | |
| 526 | |
| 527 | |
| 528 void ParserTraits::CheckPossibleEvalCall(Expression* expression, | |
| 529 Scope* scope) { | |
| 530 VariableProxy* callee = expression->AsVariableProxy(); | |
| 531 if (callee != NULL && | |
| 532 callee->raw_name() == parser_->ast_value_factory()->eval_string()) { | |
| 533 scope->DeclarationScope()->RecordEvalCall(); | |
| 534 scope->RecordEvalCall(); | |
| 535 } | |
| 536 } | |
| 537 | |
| 538 | |
| 539 Expression* ParserTraits::MarkExpressionAsAssigned(Expression* expression) { | |
| 540 VariableProxy* proxy = | |
| 541 expression != NULL ? expression->AsVariableProxy() : NULL; | |
| 542 if (proxy != NULL) proxy->set_is_assigned(); | |
| 543 return expression; | |
| 544 } | |
| 545 | |
| 546 | |
| 547 bool ParserTraits::ShortcutNumericLiteralBinaryExpression( | |
| 548 Expression** x, Expression* y, Token::Value op, int pos, | |
| 549 AstNodeFactory* factory) { | |
| 550 if ((*x)->AsLiteral() && (*x)->AsLiteral()->raw_value()->IsNumber() && | |
| 551 y->AsLiteral() && y->AsLiteral()->raw_value()->IsNumber()) { | |
| 552 double x_val = (*x)->AsLiteral()->raw_value()->AsNumber(); | |
| 553 double y_val = y->AsLiteral()->raw_value()->AsNumber(); | |
| 554 switch (op) { | |
| 555 case Token::ADD: | |
| 556 *x = factory->NewNumberLiteral(x_val + y_val, pos); | |
| 557 return true; | |
| 558 case Token::SUB: | |
| 559 *x = factory->NewNumberLiteral(x_val - y_val, pos); | |
| 560 return true; | |
| 561 case Token::MUL: | |
| 562 *x = factory->NewNumberLiteral(x_val * y_val, pos); | |
| 563 return true; | |
| 564 case Token::DIV: | |
| 565 *x = factory->NewNumberLiteral(x_val / y_val, pos); | |
| 566 return true; | |
| 567 case Token::BIT_OR: { | |
| 568 int value = DoubleToInt32(x_val) | DoubleToInt32(y_val); | |
| 569 *x = factory->NewNumberLiteral(value, pos); | |
| 570 return true; | |
| 571 } | |
| 572 case Token::BIT_AND: { | |
| 573 int value = DoubleToInt32(x_val) & DoubleToInt32(y_val); | |
| 574 *x = factory->NewNumberLiteral(value, pos); | |
| 575 return true; | |
| 576 } | |
| 577 case Token::BIT_XOR: { | |
| 578 int value = DoubleToInt32(x_val) ^ DoubleToInt32(y_val); | |
| 579 *x = factory->NewNumberLiteral(value, pos); | |
| 580 return true; | |
| 581 } | |
| 582 case Token::SHL: { | |
| 583 int value = DoubleToInt32(x_val) << (DoubleToInt32(y_val) & 0x1f); | |
| 584 *x = factory->NewNumberLiteral(value, pos); | |
| 585 return true; | |
| 586 } | |
| 587 case Token::SHR: { | |
| 588 uint32_t shift = DoubleToInt32(y_val) & 0x1f; | |
| 589 uint32_t value = DoubleToUint32(x_val) >> shift; | |
| 590 *x = factory->NewNumberLiteral(value, pos); | |
| 591 return true; | |
| 592 } | |
| 593 case Token::SAR: { | |
| 594 uint32_t shift = DoubleToInt32(y_val) & 0x1f; | |
| 595 int value = ArithmeticShiftRight(DoubleToInt32(x_val), shift); | |
| 596 *x = factory->NewNumberLiteral(value, pos); | |
| 597 return true; | |
| 598 } | |
| 599 default: | |
| 600 break; | |
| 601 } | |
| 602 } | |
| 603 return false; | |
| 604 } | |
| 605 | |
| 606 | |
| 607 Expression* ParserTraits::BuildUnaryExpression(Expression* expression, | |
| 608 Token::Value op, int pos, | |
| 609 AstNodeFactory* factory) { | |
| 610 DCHECK(expression != NULL); | |
| 611 if (expression->IsLiteral()) { | |
| 612 const AstValue* literal = expression->AsLiteral()->raw_value(); | |
| 613 if (op == Token::NOT) { | |
| 614 // Convert the literal to a boolean condition and negate it. | |
| 615 bool condition = literal->BooleanValue(); | |
| 616 return factory->NewBooleanLiteral(!condition, pos); | |
| 617 } else if (literal->IsNumber()) { | |
| 618 // Compute some expressions involving only number literals. | |
| 619 double value = literal->AsNumber(); | |
| 620 switch (op) { | |
| 621 case Token::ADD: | |
| 622 return expression; | |
| 623 case Token::SUB: | |
| 624 return factory->NewNumberLiteral(-value, pos); | |
| 625 case Token::BIT_NOT: | |
| 626 return factory->NewNumberLiteral(~DoubleToInt32(value), pos); | |
| 627 default: | |
| 628 break; | |
| 629 } | |
| 630 } | |
| 631 } | |
| 632 // Desugar '+foo' => 'foo*1' | |
| 633 if (op == Token::ADD) { | |
| 634 return factory->NewBinaryOperation( | |
| 635 Token::MUL, expression, factory->NewNumberLiteral(1, pos, true), pos); | |
| 636 } | |
| 637 // The same idea for '-foo' => 'foo*(-1)'. | |
| 638 if (op == Token::SUB) { | |
| 639 return factory->NewBinaryOperation( | |
| 640 Token::MUL, expression, factory->NewNumberLiteral(-1, pos), pos); | |
| 641 } | |
| 642 // ...and one more time for '~foo' => 'foo^(~0)'. | |
| 643 if (op == Token::BIT_NOT) { | |
| 644 return factory->NewBinaryOperation( | |
| 645 Token::BIT_XOR, expression, factory->NewNumberLiteral(~0, pos), pos); | |
| 646 } | |
| 647 return factory->NewUnaryOperation(op, expression, pos); | |
| 648 } | |
| 649 | |
| 650 | |
| 651 Expression* ParserTraits::NewThrowReferenceError( | |
| 652 MessageTemplate::Template message, int pos) { | |
| 653 return NewThrowError(Runtime::kNewReferenceError, message, | |
| 654 parser_->ast_value_factory()->empty_string(), pos); | |
| 655 } | |
| 656 | |
| 657 | |
| 658 Expression* ParserTraits::NewThrowSyntaxError(MessageTemplate::Template message, | |
| 659 const AstRawString* arg, | |
| 660 int pos) { | |
| 661 return NewThrowError(Runtime::kNewSyntaxError, message, arg, pos); | |
| 662 } | |
| 663 | |
| 664 | |
| 665 Expression* ParserTraits::NewThrowTypeError(MessageTemplate::Template message, | |
| 666 const AstRawString* arg, int pos) { | |
| 667 return NewThrowError(Runtime::kNewTypeError, message, arg, pos); | |
| 668 } | |
| 669 | |
| 670 | |
| 671 Expression* ParserTraits::NewThrowError(Runtime::FunctionId id, | |
| 672 MessageTemplate::Template message, | |
| 673 const AstRawString* arg, int pos) { | |
| 674 Zone* zone = parser_->zone(); | |
| 675 ZoneList<Expression*>* args = new (zone) ZoneList<Expression*>(2, zone); | |
| 676 args->Add(parser_->factory()->NewSmiLiteral(message, pos), zone); | |
| 677 args->Add(parser_->factory()->NewStringLiteral(arg, pos), zone); | |
| 678 CallRuntime* call_constructor = | |
| 679 parser_->factory()->NewCallRuntime(id, args, pos); | |
| 680 return parser_->factory()->NewThrow(call_constructor, pos); | |
| 681 } | |
| 682 | |
| 683 | |
| 684 void ParserTraits::ReportMessageAt(Scanner::Location source_location, | |
| 685 MessageTemplate::Template message, | |
| 686 const char* arg, ParseErrorType error_type) { | |
| 687 if (parser_->stack_overflow()) { | |
| 688 // Suppress the error message (syntax error or such) in the presence of a | |
| 689 // stack overflow. The isolate allows only one pending exception at at time | |
| 690 // and we want to report the stack overflow later. | |
| 691 return; | |
| 692 } | |
| 693 parser_->pending_error_handler_.ReportMessageAt(source_location.beg_pos, | |
| 694 source_location.end_pos, | |
| 695 message, arg, error_type); | |
| 696 } | |
| 697 | |
| 698 | |
| 699 void ParserTraits::ReportMessage(MessageTemplate::Template message, | |
| 700 const char* arg, ParseErrorType error_type) { | |
| 701 Scanner::Location source_location = parser_->scanner()->location(); | |
| 702 ReportMessageAt(source_location, message, arg, error_type); | |
| 703 } | |
| 704 | |
| 705 | |
| 706 void ParserTraits::ReportMessage(MessageTemplate::Template message, | |
| 707 const AstRawString* arg, | |
| 708 ParseErrorType error_type) { | |
| 709 Scanner::Location source_location = parser_->scanner()->location(); | |
| 710 ReportMessageAt(source_location, message, arg, error_type); | |
| 711 } | |
| 712 | |
| 713 | |
| 714 void ParserTraits::ReportMessageAt(Scanner::Location source_location, | |
| 715 MessageTemplate::Template message, | |
| 716 const AstRawString* arg, | |
| 717 ParseErrorType error_type) { | |
| 718 if (parser_->stack_overflow()) { | |
| 719 // Suppress the error message (syntax error or such) in the presence of a | |
| 720 // stack overflow. The isolate allows only one pending exception at at time | |
| 721 // and we want to report the stack overflow later. | |
| 722 return; | |
| 723 } | |
| 724 parser_->pending_error_handler_.ReportMessageAt(source_location.beg_pos, | |
| 725 source_location.end_pos, | |
| 726 message, arg, error_type); | |
| 727 } | |
| 728 | |
| 729 | |
| 730 const AstRawString* ParserTraits::GetSymbol(Scanner* scanner) { | |
| 731 const AstRawString* result = | |
| 732 parser_->scanner()->CurrentSymbol(parser_->ast_value_factory()); | |
| 733 DCHECK(result != NULL); | |
| 734 return result; | |
| 735 } | |
| 736 | |
| 737 | |
| 738 const AstRawString* ParserTraits::GetNumberAsSymbol(Scanner* scanner) { | |
| 739 double double_value = parser_->scanner()->DoubleValue(); | |
| 740 char array[100]; | |
| 741 const char* string = | |
| 742 DoubleToCString(double_value, Vector<char>(array, arraysize(array))); | |
| 743 return parser_->ast_value_factory()->GetOneByteString(string); | |
| 744 } | |
| 745 | |
| 746 | |
| 747 const AstRawString* ParserTraits::GetNextSymbol(Scanner* scanner) { | |
| 748 return parser_->scanner()->NextSymbol(parser_->ast_value_factory()); | |
| 749 } | |
| 750 | |
| 751 | |
| 752 Expression* ParserTraits::ThisExpression(Scope* scope, AstNodeFactory* factory, | |
| 753 int pos) { | |
| 754 return scope->NewUnresolved(factory, | |
| 755 parser_->ast_value_factory()->this_string(), | |
| 756 Variable::THIS, pos, pos + 4); | |
| 757 } | |
| 758 | |
| 759 | |
| 760 Expression* ParserTraits::SuperPropertyReference(Scope* scope, | |
| 761 AstNodeFactory* factory, | |
| 762 int pos) { | |
| 763 // this_function[home_object_symbol] | |
| 764 VariableProxy* this_function_proxy = scope->NewUnresolved( | |
| 765 factory, parser_->ast_value_factory()->this_function_string(), | |
| 766 Variable::NORMAL, pos); | |
| 767 Expression* home_object_symbol_literal = | |
| 768 factory->NewSymbolLiteral("home_object_symbol", RelocInfo::kNoPosition); | |
| 769 Expression* home_object = factory->NewProperty( | |
| 770 this_function_proxy, home_object_symbol_literal, pos); | |
| 771 return factory->NewSuperPropertyReference( | |
| 772 ThisExpression(scope, factory, pos)->AsVariableProxy(), home_object, pos); | |
| 773 } | |
| 774 | |
| 775 | |
| 776 Expression* ParserTraits::SuperCallReference(Scope* scope, | |
| 777 AstNodeFactory* factory, int pos) { | |
| 778 VariableProxy* new_target_proxy = scope->NewUnresolved( | |
| 779 factory, parser_->ast_value_factory()->new_target_string(), | |
| 780 Variable::NORMAL, pos); | |
| 781 VariableProxy* this_function_proxy = scope->NewUnresolved( | |
| 782 factory, parser_->ast_value_factory()->this_function_string(), | |
| 783 Variable::NORMAL, pos); | |
| 784 return factory->NewSuperCallReference( | |
| 785 ThisExpression(scope, factory, pos)->AsVariableProxy(), new_target_proxy, | |
| 786 this_function_proxy, pos); | |
| 787 } | |
| 788 | |
| 789 | |
| 790 Expression* ParserTraits::NewTargetExpression(Scope* scope, | |
| 791 AstNodeFactory* factory, | |
| 792 int pos) { | |
| 793 static const int kNewTargetStringLength = 10; | |
| 794 auto proxy = scope->NewUnresolved( | |
| 795 factory, parser_->ast_value_factory()->new_target_string(), | |
| 796 Variable::NORMAL, pos, pos + kNewTargetStringLength); | |
| 797 proxy->set_is_new_target(); | |
| 798 return proxy; | |
| 799 } | |
| 800 | |
| 801 | |
| 802 Expression* ParserTraits::DefaultConstructor(bool call_super, Scope* scope, | |
| 803 int pos, int end_pos, | |
| 804 LanguageMode mode) { | |
| 805 return parser_->DefaultConstructor(call_super, scope, pos, end_pos, mode); | |
| 806 } | |
| 807 | |
| 808 | |
| 809 Literal* ParserTraits::ExpressionFromLiteral(Token::Value token, int pos, | |
| 810 Scanner* scanner, | |
| 811 AstNodeFactory* factory) { | |
| 812 switch (token) { | |
| 813 case Token::NULL_LITERAL: | |
| 814 return factory->NewNullLiteral(pos); | |
| 815 case Token::TRUE_LITERAL: | |
| 816 return factory->NewBooleanLiteral(true, pos); | |
| 817 case Token::FALSE_LITERAL: | |
| 818 return factory->NewBooleanLiteral(false, pos); | |
| 819 case Token::SMI: { | |
| 820 int value = scanner->smi_value(); | |
| 821 return factory->NewSmiLiteral(value, pos); | |
| 822 } | |
| 823 case Token::NUMBER: { | |
| 824 bool has_dot = scanner->ContainsDot(); | |
| 825 double value = scanner->DoubleValue(); | |
| 826 return factory->NewNumberLiteral(value, pos, has_dot); | |
| 827 } | |
| 828 default: | |
| 829 DCHECK(false); | |
| 830 } | |
| 831 return NULL; | |
| 832 } | |
| 833 | |
| 834 | |
| 835 Expression* ParserTraits::ExpressionFromIdentifier(const AstRawString* name, | |
| 836 int start_position, | |
| 837 int end_position, | |
| 838 Scope* scope, | |
| 839 AstNodeFactory* factory) { | |
| 840 if (parser_->fni_ != NULL) parser_->fni_->PushVariableName(name); | |
| 841 return scope->NewUnresolved(factory, name, Variable::NORMAL, start_position, | |
| 842 end_position); | |
| 843 } | |
| 844 | |
| 845 | |
| 846 Expression* ParserTraits::ExpressionFromString(int pos, Scanner* scanner, | |
| 847 AstNodeFactory* factory) { | |
| 848 const AstRawString* symbol = GetSymbol(scanner); | |
| 849 if (parser_->fni_ != NULL) parser_->fni_->PushLiteralName(symbol); | |
| 850 return factory->NewStringLiteral(symbol, pos); | |
| 851 } | |
| 852 | |
| 853 | |
| 854 Expression* ParserTraits::GetIterator(Expression* iterable, | |
| 855 AstNodeFactory* factory) { | |
| 856 Expression* iterator_symbol_literal = | |
| 857 factory->NewSymbolLiteral("iterator_symbol", RelocInfo::kNoPosition); | |
| 858 int pos = iterable->position(); | |
| 859 Expression* prop = | |
| 860 factory->NewProperty(iterable, iterator_symbol_literal, pos); | |
| 861 Zone* zone = parser_->zone(); | |
| 862 ZoneList<Expression*>* args = new (zone) ZoneList<Expression*>(0, zone); | |
| 863 return factory->NewCall(prop, args, pos); | |
| 864 } | |
| 865 | |
| 866 | |
| 867 Literal* ParserTraits::GetLiteralTheHole(int position, | |
| 868 AstNodeFactory* factory) { | |
| 869 return factory->NewTheHoleLiteral(RelocInfo::kNoPosition); | |
| 870 } | |
| 871 | |
| 872 | |
| 873 Expression* ParserTraits::ParseV8Intrinsic(bool* ok) { | |
| 874 return parser_->ParseV8Intrinsic(ok); | |
| 875 } | |
| 876 | |
| 877 | |
| 878 FunctionLiteral* ParserTraits::ParseFunctionLiteral( | |
| 879 const AstRawString* name, Scanner::Location function_name_location, | |
| 880 FunctionNameValidity function_name_validity, FunctionKind kind, | |
| 881 int function_token_position, FunctionLiteral::FunctionType type, | |
| 882 FunctionLiteral::ArityRestriction arity_restriction, | |
| 883 LanguageMode language_mode, bool* ok) { | |
| 884 return parser_->ParseFunctionLiteral( | |
| 885 name, function_name_location, function_name_validity, kind, | |
| 886 function_token_position, type, arity_restriction, language_mode, ok); | |
| 887 } | |
| 888 | |
| 889 | |
| 890 ClassLiteral* ParserTraits::ParseClassLiteral( | |
| 891 const AstRawString* name, Scanner::Location class_name_location, | |
| 892 bool name_is_strict_reserved, int pos, bool* ok) { | |
| 893 return parser_->ParseClassLiteral(name, class_name_location, | |
| 894 name_is_strict_reserved, pos, ok); | |
| 895 } | |
| 896 | |
| 897 | |
| 898 Parser::Parser(ParseInfo* info) | |
| 899 : ParserBase<ParserTraits>(info->zone(), &scanner_, info->stack_limit(), | |
| 900 info->extension(), info->ast_value_factory(), | |
| 901 NULL, this), | |
| 902 scanner_(info->unicode_cache()), | |
| 903 reusable_preparser_(NULL), | |
| 904 original_scope_(NULL), | |
| 905 target_stack_(NULL), | |
| 906 compile_options_(info->compile_options()), | |
| 907 cached_parse_data_(NULL), | |
| 908 total_preparse_skipped_(0), | |
| 909 pre_parse_timer_(NULL), | |
| 910 parsing_on_main_thread_(true) { | |
| 911 // Even though we were passed ParseInfo, we should not store it in | |
| 912 // Parser - this makes sure that Isolate is not accidentally accessed via | |
| 913 // ParseInfo during background parsing. | |
| 914 DCHECK(!info->script().is_null() || info->source_stream() != NULL); | |
| 915 set_allow_lazy(info->allow_lazy_parsing()); | |
| 916 set_allow_natives(FLAG_allow_natives_syntax || info->is_native()); | |
| 917 set_allow_harmony_sloppy(FLAG_harmony_sloppy); | |
| 918 set_allow_harmony_sloppy_function(FLAG_harmony_sloppy_function); | |
| 919 set_allow_harmony_sloppy_let(FLAG_harmony_sloppy_let); | |
| 920 set_allow_harmony_rest_parameters(FLAG_harmony_rest_parameters); | |
| 921 set_allow_harmony_default_parameters(FLAG_harmony_default_parameters); | |
| 922 set_allow_harmony_destructuring_bind(FLAG_harmony_destructuring_bind); | |
| 923 set_allow_strong_mode(FLAG_strong_mode); | |
| 924 set_allow_legacy_const(FLAG_legacy_const); | |
| 925 set_allow_harmony_do_expressions(FLAG_harmony_do_expressions); | |
| 926 for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount; | |
| 927 ++feature) { | |
| 928 use_counts_[feature] = 0; | |
| 929 } | |
| 930 if (info->ast_value_factory() == NULL) { | |
| 931 // info takes ownership of AstValueFactory. | |
| 932 info->set_ast_value_factory(new AstValueFactory(zone(), info->hash_seed())); | |
| 933 info->set_ast_value_factory_owned(); | |
| 934 ast_value_factory_ = info->ast_value_factory(); | |
| 935 } | |
| 936 } | |
| 937 | |
| 938 | |
| 939 FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) { | |
| 940 // TODO(bmeurer): We temporarily need to pass allow_nesting = true here, | |
| 941 // see comment for HistogramTimerScope class. | |
| 942 | |
| 943 // It's OK to use the Isolate & counters here, since this function is only | |
| 944 // called in the main thread. | |
| 945 DCHECK(parsing_on_main_thread_); | |
| 946 | |
| 947 HistogramTimerScope timer_scope(isolate->counters()->parse(), true); | |
| 948 Handle<String> source(String::cast(info->script()->source())); | |
| 949 isolate->counters()->total_parse_size()->Increment(source->length()); | |
| 950 base::ElapsedTimer timer; | |
| 951 if (FLAG_trace_parse) { | |
| 952 timer.Start(); | |
| 953 } | |
| 954 fni_ = new (zone()) FuncNameInferrer(ast_value_factory(), zone()); | |
| 955 | |
| 956 // Initialize parser state. | |
| 957 CompleteParserRecorder recorder; | |
| 958 | |
| 959 if (produce_cached_parse_data()) { | |
| 960 log_ = &recorder; | |
| 961 } else if (consume_cached_parse_data()) { | |
| 962 cached_parse_data_->Initialize(); | |
| 963 } | |
| 964 | |
| 965 source = String::Flatten(source); | |
| 966 FunctionLiteral* result; | |
| 967 | |
| 968 if (source->IsExternalTwoByteString()) { | |
| 969 // Notice that the stream is destroyed at the end of the branch block. | |
| 970 // The last line of the blocks can't be moved outside, even though they're | |
| 971 // identical calls. | |
| 972 ExternalTwoByteStringUtf16CharacterStream stream( | |
| 973 Handle<ExternalTwoByteString>::cast(source), 0, source->length()); | |
| 974 scanner_.Initialize(&stream); | |
| 975 result = DoParseProgram(info); | |
| 976 } else { | |
| 977 GenericStringUtf16CharacterStream stream(source, 0, source->length()); | |
| 978 scanner_.Initialize(&stream); | |
| 979 result = DoParseProgram(info); | |
| 980 } | |
| 981 if (result != NULL) { | |
| 982 DCHECK_EQ(scanner_.peek_location().beg_pos, source->length()); | |
| 983 } | |
| 984 HandleSourceURLComments(isolate, info->script()); | |
| 985 | |
| 986 if (FLAG_trace_parse && result != NULL) { | |
| 987 double ms = timer.Elapsed().InMillisecondsF(); | |
| 988 if (info->is_eval()) { | |
| 989 PrintF("[parsing eval"); | |
| 990 } else if (info->script()->name()->IsString()) { | |
| 991 String* name = String::cast(info->script()->name()); | |
| 992 base::SmartArrayPointer<char> name_chars = name->ToCString(); | |
| 993 PrintF("[parsing script: %s", name_chars.get()); | |
| 994 } else { | |
| 995 PrintF("[parsing script"); | |
| 996 } | |
| 997 PrintF(" - took %0.3f ms]\n", ms); | |
| 998 } | |
| 999 if (produce_cached_parse_data()) { | |
| 1000 if (result != NULL) *info->cached_data() = recorder.GetScriptData(); | |
| 1001 log_ = NULL; | |
| 1002 } | |
| 1003 return result; | |
| 1004 } | |
| 1005 | |
| 1006 | |
| 1007 FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) { | |
| 1008 // Note that this function can be called from the main thread or from a | |
| 1009 // background thread. We should not access anything Isolate / heap dependent | |
| 1010 // via ParseInfo, and also not pass it forward. | |
| 1011 DCHECK(scope_ == NULL); | |
| 1012 DCHECK(target_stack_ == NULL); | |
| 1013 | |
| 1014 Mode parsing_mode = FLAG_lazy && allow_lazy() ? PARSE_LAZILY : PARSE_EAGERLY; | |
| 1015 if (allow_natives() || extension_ != NULL) parsing_mode = PARSE_EAGERLY; | |
| 1016 | |
| 1017 FunctionLiteral* result = NULL; | |
| 1018 { | |
| 1019 // TODO(wingo): Add an outer SCRIPT_SCOPE corresponding to the native | |
| 1020 // context, which will have the "this" binding for script scopes. | |
| 1021 Scope* scope = NewScope(scope_, SCRIPT_SCOPE); | |
| 1022 info->set_script_scope(scope); | |
| 1023 if (!info->context().is_null() && !info->context()->IsNativeContext()) { | |
| 1024 scope = Scope::DeserializeScopeChain(info->isolate(), zone(), | |
| 1025 *info->context(), scope); | |
| 1026 // The Scope is backed up by ScopeInfo (which is in the V8 heap); this | |
| 1027 // means the Parser cannot operate independent of the V8 heap. Tell the | |
| 1028 // string table to internalize strings and values right after they're | |
| 1029 // created. This kind of parsing can only be done in the main thread. | |
| 1030 DCHECK(parsing_on_main_thread_); | |
| 1031 ast_value_factory()->Internalize(info->isolate()); | |
| 1032 } | |
| 1033 original_scope_ = scope; | |
| 1034 if (info->is_eval()) { | |
| 1035 if (!scope->is_script_scope() || is_strict(info->language_mode())) { | |
| 1036 parsing_mode = PARSE_EAGERLY; | |
| 1037 } | |
| 1038 scope = NewScope(scope, EVAL_SCOPE); | |
| 1039 } else if (info->is_module()) { | |
| 1040 scope = NewScope(scope, MODULE_SCOPE); | |
| 1041 } | |
| 1042 | |
| 1043 scope->set_start_position(0); | |
| 1044 | |
| 1045 // Enter 'scope' with the given parsing mode. | |
| 1046 ParsingModeScope parsing_mode_scope(this, parsing_mode); | |
| 1047 AstNodeFactory function_factory(ast_value_factory()); | |
| 1048 FunctionState function_state(&function_state_, &scope_, scope, | |
| 1049 kNormalFunction, &function_factory); | |
| 1050 | |
| 1051 // Don't count the mode in the use counters--give the program a chance | |
| 1052 // to enable script/module-wide strict/strong mode below. | |
| 1053 scope_->SetLanguageMode(info->language_mode()); | |
| 1054 ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16, zone()); | |
| 1055 bool ok = true; | |
| 1056 int beg_pos = scanner()->location().beg_pos; | |
| 1057 if (info->is_module()) { | |
| 1058 ParseModuleItemList(body, &ok); | |
| 1059 } else { | |
| 1060 ParseStatementList(body, Token::EOS, &ok); | |
| 1061 } | |
| 1062 | |
| 1063 // The parser will peek but not consume EOS. Our scope logically goes all | |
| 1064 // the way to the EOS, though. | |
| 1065 scope->set_end_position(scanner()->peek_location().beg_pos); | |
| 1066 | |
| 1067 if (ok && is_strict(language_mode())) { | |
| 1068 CheckStrictOctalLiteral(beg_pos, scanner()->location().end_pos, &ok); | |
| 1069 } | |
| 1070 if (ok && is_sloppy(language_mode()) && allow_harmony_sloppy_function()) { | |
| 1071 // TODO(littledan): Function bindings on the global object that modify | |
| 1072 // pre-existing bindings should be made writable, enumerable and | |
| 1073 // nonconfigurable if possible, whereas this code will leave attributes | |
| 1074 // unchanged if the property already exists. | |
| 1075 InsertSloppyBlockFunctionVarBindings(scope, &ok); | |
| 1076 } | |
| 1077 if (ok && (is_strict(language_mode()) || allow_harmony_sloppy() || | |
| 1078 allow_harmony_destructuring_bind())) { | |
| 1079 CheckConflictingVarDeclarations(scope_, &ok); | |
| 1080 } | |
| 1081 | |
| 1082 if (ok && info->parse_restriction() == ONLY_SINGLE_FUNCTION_LITERAL) { | |
| 1083 if (body->length() != 1 || | |
| 1084 !body->at(0)->IsExpressionStatement() || | |
| 1085 !body->at(0)->AsExpressionStatement()-> | |
| 1086 expression()->IsFunctionLiteral()) { | |
| 1087 ReportMessage(MessageTemplate::kSingleFunctionLiteral); | |
| 1088 ok = false; | |
| 1089 } | |
| 1090 } | |
| 1091 | |
| 1092 if (ok) { | |
| 1093 result = factory()->NewFunctionLiteral( | |
| 1094 ast_value_factory()->empty_string(), ast_value_factory(), scope_, | |
| 1095 body, function_state.materialized_literal_count(), | |
| 1096 function_state.expected_property_count(), 0, | |
| 1097 FunctionLiteral::kNoDuplicateParameters, | |
| 1098 FunctionLiteral::ANONYMOUS_EXPRESSION, FunctionLiteral::kGlobalOrEval, | |
| 1099 FunctionLiteral::kShouldLazyCompile, FunctionKind::kNormalFunction, | |
| 1100 0); | |
| 1101 } | |
| 1102 } | |
| 1103 | |
| 1104 // Make sure the target stack is empty. | |
| 1105 DCHECK(target_stack_ == NULL); | |
| 1106 | |
| 1107 return result; | |
| 1108 } | |
| 1109 | |
| 1110 | |
| 1111 FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info) { | |
| 1112 // It's OK to use the Isolate & counters here, since this function is only | |
| 1113 // called in the main thread. | |
| 1114 DCHECK(parsing_on_main_thread_); | |
| 1115 HistogramTimerScope timer_scope(isolate->counters()->parse_lazy()); | |
| 1116 Handle<String> source(String::cast(info->script()->source())); | |
| 1117 isolate->counters()->total_parse_size()->Increment(source->length()); | |
| 1118 base::ElapsedTimer timer; | |
| 1119 if (FLAG_trace_parse) { | |
| 1120 timer.Start(); | |
| 1121 } | |
| 1122 Handle<SharedFunctionInfo> shared_info = info->shared_info(); | |
| 1123 | |
| 1124 // Initialize parser state. | |
| 1125 source = String::Flatten(source); | |
| 1126 FunctionLiteral* result; | |
| 1127 if (source->IsExternalTwoByteString()) { | |
| 1128 ExternalTwoByteStringUtf16CharacterStream stream( | |
| 1129 Handle<ExternalTwoByteString>::cast(source), | |
| 1130 shared_info->start_position(), | |
| 1131 shared_info->end_position()); | |
| 1132 result = ParseLazy(isolate, info, &stream); | |
| 1133 } else { | |
| 1134 GenericStringUtf16CharacterStream stream(source, | |
| 1135 shared_info->start_position(), | |
| 1136 shared_info->end_position()); | |
| 1137 result = ParseLazy(isolate, info, &stream); | |
| 1138 } | |
| 1139 | |
| 1140 if (FLAG_trace_parse && result != NULL) { | |
| 1141 double ms = timer.Elapsed().InMillisecondsF(); | |
| 1142 base::SmartArrayPointer<char> name_chars = | |
| 1143 result->debug_name()->ToCString(); | |
| 1144 PrintF("[parsing function: %s - took %0.3f ms]\n", name_chars.get(), ms); | |
| 1145 } | |
| 1146 return result; | |
| 1147 } | |
| 1148 | |
| 1149 | |
| 1150 FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info, | |
| 1151 Utf16CharacterStream* source) { | |
| 1152 Handle<SharedFunctionInfo> shared_info = info->shared_info(); | |
| 1153 scanner_.Initialize(source); | |
| 1154 DCHECK(scope_ == NULL); | |
| 1155 DCHECK(target_stack_ == NULL); | |
| 1156 | |
| 1157 Handle<String> name(String::cast(shared_info->name())); | |
| 1158 DCHECK(ast_value_factory()); | |
| 1159 fni_ = new (zone()) FuncNameInferrer(ast_value_factory(), zone()); | |
| 1160 const AstRawString* raw_name = ast_value_factory()->GetString(name); | |
| 1161 fni_->PushEnclosingName(raw_name); | |
| 1162 | |
| 1163 ParsingModeScope parsing_mode(this, PARSE_EAGERLY); | |
| 1164 | |
| 1165 // Place holder for the result. | |
| 1166 FunctionLiteral* result = NULL; | |
| 1167 | |
| 1168 { | |
| 1169 // Parse the function literal. | |
| 1170 Scope* scope = NewScope(scope_, SCRIPT_SCOPE); | |
| 1171 info->set_script_scope(scope); | |
| 1172 if (!info->closure().is_null()) { | |
| 1173 // Ok to use Isolate here, since lazy function parsing is only done in the | |
| 1174 // main thread. | |
| 1175 DCHECK(parsing_on_main_thread_); | |
| 1176 scope = Scope::DeserializeScopeChain(isolate, zone(), | |
| 1177 info->closure()->context(), scope); | |
| 1178 } | |
| 1179 original_scope_ = scope; | |
| 1180 AstNodeFactory function_factory(ast_value_factory()); | |
| 1181 FunctionState function_state(&function_state_, &scope_, scope, | |
| 1182 shared_info->kind(), &function_factory); | |
| 1183 DCHECK(is_sloppy(scope->language_mode()) || | |
| 1184 is_strict(info->language_mode())); | |
| 1185 DCHECK(info->language_mode() == shared_info->language_mode()); | |
| 1186 FunctionLiteral::FunctionType function_type = shared_info->is_expression() | |
| 1187 ? (shared_info->is_anonymous() | |
| 1188 ? FunctionLiteral::ANONYMOUS_EXPRESSION | |
| 1189 : FunctionLiteral::NAMED_EXPRESSION) | |
| 1190 : FunctionLiteral::DECLARATION; | |
| 1191 bool ok = true; | |
| 1192 | |
| 1193 if (shared_info->is_arrow()) { | |
| 1194 Scope* scope = | |
| 1195 NewScope(scope_, FUNCTION_SCOPE, FunctionKind::kArrowFunction); | |
| 1196 SetLanguageMode(scope, shared_info->language_mode()); | |
| 1197 scope->set_start_position(shared_info->start_position()); | |
| 1198 ExpressionClassifier formals_classifier; | |
| 1199 ParserFormalParameters formals(scope); | |
| 1200 Checkpoint checkpoint(this); | |
| 1201 { | |
| 1202 // Parsing patterns as variable reference expression creates | |
| 1203 // NewUnresolved references in current scope. Entrer arrow function | |
| 1204 // scope for formal parameter parsing. | |
| 1205 BlockState block_state(&scope_, scope); | |
| 1206 if (Check(Token::LPAREN)) { | |
| 1207 // '(' StrictFormalParameters ')' | |
| 1208 ParseFormalParameterList(&formals, &formals_classifier, &ok); | |
| 1209 if (ok) ok = Check(Token::RPAREN); | |
| 1210 } else { | |
| 1211 // BindingIdentifier | |
| 1212 ParseFormalParameter(&formals, &formals_classifier, &ok); | |
| 1213 if (ok) { | |
| 1214 DeclareFormalParameter(formals.scope, formals.at(0), | |
| 1215 &formals_classifier); | |
| 1216 } | |
| 1217 } | |
| 1218 } | |
| 1219 | |
| 1220 if (ok) { | |
| 1221 checkpoint.Restore(&formals.materialized_literals_count); | |
| 1222 // Pass `accept_IN=true` to ParseArrowFunctionLiteral --- This should | |
| 1223 // not be observable, or else the preparser would have failed. | |
| 1224 Expression* expression = | |
| 1225 ParseArrowFunctionLiteral(true, formals, formals_classifier, &ok); | |
| 1226 if (ok) { | |
| 1227 // Scanning must end at the same position that was recorded | |
| 1228 // previously. If not, parsing has been interrupted due to a stack | |
| 1229 // overflow, at which point the partially parsed arrow function | |
| 1230 // concise body happens to be a valid expression. This is a problem | |
| 1231 // only for arrow functions with single expression bodies, since there | |
| 1232 // is no end token such as "}" for normal functions. | |
| 1233 if (scanner()->location().end_pos == shared_info->end_position()) { | |
| 1234 // The pre-parser saw an arrow function here, so the full parser | |
| 1235 // must produce a FunctionLiteral. | |
| 1236 DCHECK(expression->IsFunctionLiteral()); | |
| 1237 result = expression->AsFunctionLiteral(); | |
| 1238 } else { | |
| 1239 ok = false; | |
| 1240 } | |
| 1241 } | |
| 1242 } | |
| 1243 } else if (shared_info->is_default_constructor()) { | |
| 1244 result = DefaultConstructor(IsSubclassConstructor(shared_info->kind()), | |
| 1245 scope, shared_info->start_position(), | |
| 1246 shared_info->end_position(), | |
| 1247 shared_info->language_mode()); | |
| 1248 } else { | |
| 1249 result = ParseFunctionLiteral( | |
| 1250 raw_name, Scanner::Location::invalid(), kSkipFunctionNameCheck, | |
| 1251 shared_info->kind(), RelocInfo::kNoPosition, function_type, | |
| 1252 FunctionLiteral::NORMAL_ARITY, shared_info->language_mode(), &ok); | |
| 1253 } | |
| 1254 // Make sure the results agree. | |
| 1255 DCHECK(ok == (result != NULL)); | |
| 1256 } | |
| 1257 | |
| 1258 // Make sure the target stack is empty. | |
| 1259 DCHECK(target_stack_ == NULL); | |
| 1260 | |
| 1261 if (result != NULL) { | |
| 1262 Handle<String> inferred_name(shared_info->inferred_name()); | |
| 1263 result->set_inferred_name(inferred_name); | |
| 1264 } | |
| 1265 return result; | |
| 1266 } | |
| 1267 | |
| 1268 | |
| 1269 void* Parser::ParseStatementList(ZoneList<Statement*>* body, int end_token, | |
| 1270 bool* ok) { | |
| 1271 // StatementList :: | |
| 1272 // (StatementListItem)* <end_token> | |
| 1273 | |
| 1274 // Allocate a target stack to use for this set of source | |
| 1275 // elements. This way, all scripts and functions get their own | |
| 1276 // target stack thus avoiding illegal breaks and continues across | |
| 1277 // functions. | |
| 1278 TargetScope scope(&this->target_stack_); | |
| 1279 | |
| 1280 DCHECK(body != NULL); | |
| 1281 bool directive_prologue = true; // Parsing directive prologue. | |
| 1282 | |
| 1283 while (peek() != end_token) { | |
| 1284 if (directive_prologue && peek() != Token::STRING) { | |
| 1285 directive_prologue = false; | |
| 1286 } | |
| 1287 | |
| 1288 Scanner::Location token_loc = scanner()->peek_location(); | |
| 1289 Scanner::Location old_this_loc = function_state_->this_location(); | |
| 1290 Scanner::Location old_super_loc = function_state_->super_location(); | |
| 1291 Statement* stat = ParseStatementListItem(CHECK_OK); | |
| 1292 | |
| 1293 if (is_strong(language_mode()) && scope_->is_function_scope() && | |
| 1294 IsClassConstructor(function_state_->kind())) { | |
| 1295 Scanner::Location this_loc = function_state_->this_location(); | |
| 1296 Scanner::Location super_loc = function_state_->super_location(); | |
| 1297 if (this_loc.beg_pos != old_this_loc.beg_pos && | |
| 1298 this_loc.beg_pos != token_loc.beg_pos) { | |
| 1299 ReportMessageAt(this_loc, MessageTemplate::kStrongConstructorThis); | |
| 1300 *ok = false; | |
| 1301 return nullptr; | |
| 1302 } | |
| 1303 if (super_loc.beg_pos != old_super_loc.beg_pos && | |
| 1304 super_loc.beg_pos != token_loc.beg_pos) { | |
| 1305 ReportMessageAt(super_loc, MessageTemplate::kStrongConstructorSuper); | |
| 1306 *ok = false; | |
| 1307 return nullptr; | |
| 1308 } | |
| 1309 } | |
| 1310 | |
| 1311 if (stat == NULL || stat->IsEmpty()) { | |
| 1312 directive_prologue = false; // End of directive prologue. | |
| 1313 continue; | |
| 1314 } | |
| 1315 | |
| 1316 if (directive_prologue) { | |
| 1317 // A shot at a directive. | |
| 1318 ExpressionStatement* e_stat; | |
| 1319 Literal* literal; | |
| 1320 // Still processing directive prologue? | |
| 1321 if ((e_stat = stat->AsExpressionStatement()) != NULL && | |
| 1322 (literal = e_stat->expression()->AsLiteral()) != NULL && | |
| 1323 literal->raw_value()->IsString()) { | |
| 1324 // Check "use strict" directive (ES5 14.1), "use asm" directive, and | |
| 1325 // "use strong" directive (experimental). | |
| 1326 bool use_strict_found = | |
| 1327 literal->raw_value()->AsString() == | |
| 1328 ast_value_factory()->use_strict_string() && | |
| 1329 token_loc.end_pos - token_loc.beg_pos == | |
| 1330 ast_value_factory()->use_strict_string()->length() + 2; | |
| 1331 bool use_strong_found = | |
| 1332 allow_strong_mode() && | |
| 1333 literal->raw_value()->AsString() == | |
| 1334 ast_value_factory()->use_strong_string() && | |
| 1335 token_loc.end_pos - token_loc.beg_pos == | |
| 1336 ast_value_factory()->use_strong_string()->length() + 2; | |
| 1337 if (use_strict_found || use_strong_found) { | |
| 1338 // Strong mode implies strict mode. If there are several "use strict" | |
| 1339 // / "use strong" directives, do the strict mode changes only once. | |
| 1340 if (is_sloppy(scope_->language_mode())) { | |
| 1341 RaiseLanguageMode(STRICT); | |
| 1342 } | |
| 1343 | |
| 1344 if (use_strong_found) { | |
| 1345 RaiseLanguageMode(STRONG); | |
| 1346 if (IsClassConstructor(function_state_->kind())) { | |
| 1347 // "use strong" cannot occur in a class constructor body, to avoid | |
| 1348 // unintuitive strong class object semantics. | |
| 1349 ParserTraits::ReportMessageAt( | |
| 1350 token_loc, MessageTemplate::kStrongConstructorDirective); | |
| 1351 *ok = false; | |
| 1352 return nullptr; | |
| 1353 } | |
| 1354 } | |
| 1355 if (!scope_->HasSimpleParameters()) { | |
| 1356 // TC39 deemed "use strict" directives to be an error when occurring | |
| 1357 // in the body of a function with non-simple parameter list, on | |
| 1358 // 29/7/2015. https://goo.gl/ueA7Ln | |
| 1359 // | |
| 1360 // In V8, this also applies to "use strong " directives. | |
| 1361 const AstRawString* string = literal->raw_value()->AsString(); | |
| 1362 ParserTraits::ReportMessageAt( | |
| 1363 token_loc, MessageTemplate::kIllegalLanguageModeDirective, | |
| 1364 string); | |
| 1365 *ok = false; | |
| 1366 return nullptr; | |
| 1367 } | |
| 1368 // Because declarations in strict eval code don't leak into the scope | |
| 1369 // of the eval call, it is likely that functions declared in strict | |
| 1370 // eval code will be used within the eval code, so lazy parsing is | |
| 1371 // probably not a win. | |
| 1372 if (scope_->is_eval_scope()) mode_ = PARSE_EAGERLY; | |
| 1373 } else if (literal->raw_value()->AsString() == | |
| 1374 ast_value_factory()->use_asm_string() && | |
| 1375 token_loc.end_pos - token_loc.beg_pos == | |
| 1376 ast_value_factory()->use_asm_string()->length() + 2) { | |
| 1377 // Store the usage count; The actual use counter on the isolate is | |
| 1378 // incremented after parsing is done. | |
| 1379 ++use_counts_[v8::Isolate::kUseAsm]; | |
| 1380 scope_->SetAsmModule(); | |
| 1381 } else { | |
| 1382 // Should not change mode, but will increment UseCounter | |
| 1383 // if appropriate. Ditto usages below. | |
| 1384 RaiseLanguageMode(SLOPPY); | |
| 1385 } | |
| 1386 } else { | |
| 1387 // End of the directive prologue. | |
| 1388 directive_prologue = false; | |
| 1389 RaiseLanguageMode(SLOPPY); | |
| 1390 } | |
| 1391 } else { | |
| 1392 RaiseLanguageMode(SLOPPY); | |
| 1393 } | |
| 1394 | |
| 1395 body->Add(stat, zone()); | |
| 1396 } | |
| 1397 | |
| 1398 return 0; | |
| 1399 } | |
| 1400 | |
| 1401 | |
| 1402 Statement* Parser::ParseStatementListItem(bool* ok) { | |
| 1403 // (Ecma 262 6th Edition, 13.1): | |
| 1404 // StatementListItem: | |
| 1405 // Statement | |
| 1406 // Declaration | |
| 1407 | |
| 1408 if (peek() != Token::CLASS) { | |
| 1409 // No more classes follow; reset the start position for the consecutive | |
| 1410 // class declaration group. | |
| 1411 scope_->set_class_declaration_group_start(-1); | |
| 1412 } | |
| 1413 | |
| 1414 switch (peek()) { | |
| 1415 case Token::FUNCTION: | |
| 1416 return ParseFunctionDeclaration(NULL, ok); | |
| 1417 case Token::CLASS: | |
| 1418 if (scope_->class_declaration_group_start() < 0) { | |
| 1419 scope_->set_class_declaration_group_start( | |
| 1420 scanner()->peek_location().beg_pos); | |
| 1421 } | |
| 1422 return ParseClassDeclaration(NULL, ok); | |
| 1423 case Token::CONST: | |
| 1424 if (allow_const()) { | |
| 1425 return ParseVariableStatement(kStatementListItem, NULL, ok); | |
| 1426 } | |
| 1427 break; | |
| 1428 case Token::VAR: | |
| 1429 return ParseVariableStatement(kStatementListItem, NULL, ok); | |
| 1430 case Token::LET: | |
| 1431 if (IsNextLetKeyword()) { | |
| 1432 return ParseVariableStatement(kStatementListItem, NULL, ok); | |
| 1433 } | |
| 1434 break; | |
| 1435 default: | |
| 1436 break; | |
| 1437 } | |
| 1438 return ParseStatement(NULL, ok); | |
| 1439 } | |
| 1440 | |
| 1441 | |
| 1442 Statement* Parser::ParseModuleItem(bool* ok) { | |
| 1443 // (Ecma 262 6th Edition, 15.2): | |
| 1444 // ModuleItem : | |
| 1445 // ImportDeclaration | |
| 1446 // ExportDeclaration | |
| 1447 // StatementListItem | |
| 1448 | |
| 1449 switch (peek()) { | |
| 1450 case Token::IMPORT: | |
| 1451 return ParseImportDeclaration(ok); | |
| 1452 case Token::EXPORT: | |
| 1453 return ParseExportDeclaration(ok); | |
| 1454 default: | |
| 1455 return ParseStatementListItem(ok); | |
| 1456 } | |
| 1457 } | |
| 1458 | |
| 1459 | |
| 1460 void* Parser::ParseModuleItemList(ZoneList<Statement*>* body, bool* ok) { | |
| 1461 // (Ecma 262 6th Edition, 15.2): | |
| 1462 // Module : | |
| 1463 // ModuleBody? | |
| 1464 // | |
| 1465 // ModuleBody : | |
| 1466 // ModuleItem* | |
| 1467 | |
| 1468 DCHECK(scope_->is_module_scope()); | |
| 1469 RaiseLanguageMode(STRICT); | |
| 1470 | |
| 1471 while (peek() != Token::EOS) { | |
| 1472 Statement* stat = ParseModuleItem(CHECK_OK); | |
| 1473 if (stat && !stat->IsEmpty()) { | |
| 1474 body->Add(stat, zone()); | |
| 1475 } | |
| 1476 } | |
| 1477 | |
| 1478 // Check that all exports are bound. | |
| 1479 ModuleDescriptor* descriptor = scope_->module(); | |
| 1480 for (ModuleDescriptor::Iterator it = descriptor->iterator(); !it.done(); | |
| 1481 it.Advance()) { | |
| 1482 if (scope_->LookupLocal(it.local_name()) == NULL) { | |
| 1483 // TODO(adamk): Pass both local_name and export_name once ParserTraits | |
| 1484 // supports multiple arg error messages. | |
| 1485 // Also try to report this at a better location. | |
| 1486 ParserTraits::ReportMessage(MessageTemplate::kModuleExportUndefined, | |
| 1487 it.local_name()); | |
| 1488 *ok = false; | |
| 1489 return NULL; | |
| 1490 } | |
| 1491 } | |
| 1492 | |
| 1493 scope_->module()->Freeze(); | |
| 1494 return NULL; | |
| 1495 } | |
| 1496 | |
| 1497 | |
| 1498 const AstRawString* Parser::ParseModuleSpecifier(bool* ok) { | |
| 1499 // ModuleSpecifier : | |
| 1500 // StringLiteral | |
| 1501 | |
| 1502 Expect(Token::STRING, CHECK_OK); | |
| 1503 return GetSymbol(scanner()); | |
| 1504 } | |
| 1505 | |
| 1506 | |
| 1507 void* Parser::ParseExportClause(ZoneList<const AstRawString*>* export_names, | |
| 1508 ZoneList<Scanner::Location>* export_locations, | |
| 1509 ZoneList<const AstRawString*>* local_names, | |
| 1510 Scanner::Location* reserved_loc, bool* ok) { | |
| 1511 // ExportClause : | |
| 1512 // '{' '}' | |
| 1513 // '{' ExportsList '}' | |
| 1514 // '{' ExportsList ',' '}' | |
| 1515 // | |
| 1516 // ExportsList : | |
| 1517 // ExportSpecifier | |
| 1518 // ExportsList ',' ExportSpecifier | |
| 1519 // | |
| 1520 // ExportSpecifier : | |
| 1521 // IdentifierName | |
| 1522 // IdentifierName 'as' IdentifierName | |
| 1523 | |
| 1524 Expect(Token::LBRACE, CHECK_OK); | |
| 1525 | |
| 1526 Token::Value name_tok; | |
| 1527 while ((name_tok = peek()) != Token::RBRACE) { | |
| 1528 // Keep track of the first reserved word encountered in case our | |
| 1529 // caller needs to report an error. | |
| 1530 if (!reserved_loc->IsValid() && | |
| 1531 !Token::IsIdentifier(name_tok, STRICT, false)) { | |
| 1532 *reserved_loc = scanner()->location(); | |
| 1533 } | |
| 1534 const AstRawString* local_name = ParseIdentifierName(CHECK_OK); | |
| 1535 const AstRawString* export_name = NULL; | |
| 1536 if (CheckContextualKeyword(CStrVector("as"))) { | |
| 1537 export_name = ParseIdentifierName(CHECK_OK); | |
| 1538 } | |
| 1539 if (export_name == NULL) { | |
| 1540 export_name = local_name; | |
| 1541 } | |
| 1542 export_names->Add(export_name, zone()); | |
| 1543 local_names->Add(local_name, zone()); | |
| 1544 export_locations->Add(scanner()->location(), zone()); | |
| 1545 if (peek() == Token::RBRACE) break; | |
| 1546 Expect(Token::COMMA, CHECK_OK); | |
| 1547 } | |
| 1548 | |
| 1549 Expect(Token::RBRACE, CHECK_OK); | |
| 1550 | |
| 1551 return 0; | |
| 1552 } | |
| 1553 | |
| 1554 | |
| 1555 ZoneList<ImportDeclaration*>* Parser::ParseNamedImports(int pos, bool* ok) { | |
| 1556 // NamedImports : | |
| 1557 // '{' '}' | |
| 1558 // '{' ImportsList '}' | |
| 1559 // '{' ImportsList ',' '}' | |
| 1560 // | |
| 1561 // ImportsList : | |
| 1562 // ImportSpecifier | |
| 1563 // ImportsList ',' ImportSpecifier | |
| 1564 // | |
| 1565 // ImportSpecifier : | |
| 1566 // BindingIdentifier | |
| 1567 // IdentifierName 'as' BindingIdentifier | |
| 1568 | |
| 1569 Expect(Token::LBRACE, CHECK_OK); | |
| 1570 | |
| 1571 ZoneList<ImportDeclaration*>* result = | |
| 1572 new (zone()) ZoneList<ImportDeclaration*>(1, zone()); | |
| 1573 while (peek() != Token::RBRACE) { | |
| 1574 const AstRawString* import_name = ParseIdentifierName(CHECK_OK); | |
| 1575 const AstRawString* local_name = import_name; | |
| 1576 // In the presence of 'as', the left-side of the 'as' can | |
| 1577 // be any IdentifierName. But without 'as', it must be a valid | |
| 1578 // BindingIdentifier. | |
| 1579 if (CheckContextualKeyword(CStrVector("as"))) { | |
| 1580 local_name = ParseIdentifierName(CHECK_OK); | |
| 1581 } | |
| 1582 if (!Token::IsIdentifier(scanner()->current_token(), STRICT, false)) { | |
| 1583 *ok = false; | |
| 1584 ReportMessage(MessageTemplate::kUnexpectedReserved); | |
| 1585 return NULL; | |
| 1586 } else if (IsEvalOrArguments(local_name)) { | |
| 1587 *ok = false; | |
| 1588 ReportMessage(MessageTemplate::kStrictEvalArguments); | |
| 1589 return NULL; | |
| 1590 } else if (is_strong(language_mode()) && IsUndefined(local_name)) { | |
| 1591 *ok = false; | |
| 1592 ReportMessage(MessageTemplate::kStrongUndefined); | |
| 1593 return NULL; | |
| 1594 } | |
| 1595 VariableProxy* proxy = NewUnresolved(local_name, IMPORT); | |
| 1596 ImportDeclaration* declaration = | |
| 1597 factory()->NewImportDeclaration(proxy, import_name, NULL, scope_, pos); | |
| 1598 Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK); | |
| 1599 result->Add(declaration, zone()); | |
| 1600 if (peek() == Token::RBRACE) break; | |
| 1601 Expect(Token::COMMA, CHECK_OK); | |
| 1602 } | |
| 1603 | |
| 1604 Expect(Token::RBRACE, CHECK_OK); | |
| 1605 | |
| 1606 return result; | |
| 1607 } | |
| 1608 | |
| 1609 | |
| 1610 Statement* Parser::ParseImportDeclaration(bool* ok) { | |
| 1611 // ImportDeclaration : | |
| 1612 // 'import' ImportClause 'from' ModuleSpecifier ';' | |
| 1613 // 'import' ModuleSpecifier ';' | |
| 1614 // | |
| 1615 // ImportClause : | |
| 1616 // NameSpaceImport | |
| 1617 // NamedImports | |
| 1618 // ImportedDefaultBinding | |
| 1619 // ImportedDefaultBinding ',' NameSpaceImport | |
| 1620 // ImportedDefaultBinding ',' NamedImports | |
| 1621 // | |
| 1622 // NameSpaceImport : | |
| 1623 // '*' 'as' ImportedBinding | |
| 1624 | |
| 1625 int pos = peek_position(); | |
| 1626 Expect(Token::IMPORT, CHECK_OK); | |
| 1627 | |
| 1628 Token::Value tok = peek(); | |
| 1629 | |
| 1630 // 'import' ModuleSpecifier ';' | |
| 1631 if (tok == Token::STRING) { | |
| 1632 const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK); | |
| 1633 scope_->module()->AddModuleRequest(module_specifier, zone()); | |
| 1634 ExpectSemicolon(CHECK_OK); | |
| 1635 return factory()->NewEmptyStatement(pos); | |
| 1636 } | |
| 1637 | |
| 1638 // Parse ImportedDefaultBinding if present. | |
| 1639 ImportDeclaration* import_default_declaration = NULL; | |
| 1640 if (tok != Token::MUL && tok != Token::LBRACE) { | |
| 1641 const AstRawString* local_name = | |
| 1642 ParseIdentifier(kDontAllowRestrictedIdentifiers, CHECK_OK); | |
| 1643 VariableProxy* proxy = NewUnresolved(local_name, IMPORT); | |
| 1644 import_default_declaration = factory()->NewImportDeclaration( | |
| 1645 proxy, ast_value_factory()->default_string(), NULL, scope_, pos); | |
| 1646 Declare(import_default_declaration, DeclarationDescriptor::NORMAL, true, | |
| 1647 CHECK_OK); | |
| 1648 } | |
| 1649 | |
| 1650 const AstRawString* module_instance_binding = NULL; | |
| 1651 ZoneList<ImportDeclaration*>* named_declarations = NULL; | |
| 1652 if (import_default_declaration == NULL || Check(Token::COMMA)) { | |
| 1653 switch (peek()) { | |
| 1654 case Token::MUL: { | |
| 1655 Consume(Token::MUL); | |
| 1656 ExpectContextualKeyword(CStrVector("as"), CHECK_OK); | |
| 1657 module_instance_binding = | |
| 1658 ParseIdentifier(kDontAllowRestrictedIdentifiers, CHECK_OK); | |
| 1659 // TODO(ES6): Add an appropriate declaration. | |
| 1660 break; | |
| 1661 } | |
| 1662 | |
| 1663 case Token::LBRACE: | |
| 1664 named_declarations = ParseNamedImports(pos, CHECK_OK); | |
| 1665 break; | |
| 1666 | |
| 1667 default: | |
| 1668 *ok = false; | |
| 1669 ReportUnexpectedToken(scanner()->current_token()); | |
| 1670 return NULL; | |
| 1671 } | |
| 1672 } | |
| 1673 | |
| 1674 ExpectContextualKeyword(CStrVector("from"), CHECK_OK); | |
| 1675 const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK); | |
| 1676 scope_->module()->AddModuleRequest(module_specifier, zone()); | |
| 1677 | |
| 1678 if (module_instance_binding != NULL) { | |
| 1679 // TODO(ES6): Set the module specifier for the module namespace binding. | |
| 1680 } | |
| 1681 | |
| 1682 if (import_default_declaration != NULL) { | |
| 1683 import_default_declaration->set_module_specifier(module_specifier); | |
| 1684 } | |
| 1685 | |
| 1686 if (named_declarations != NULL) { | |
| 1687 for (int i = 0; i < named_declarations->length(); ++i) { | |
| 1688 named_declarations->at(i)->set_module_specifier(module_specifier); | |
| 1689 } | |
| 1690 } | |
| 1691 | |
| 1692 ExpectSemicolon(CHECK_OK); | |
| 1693 return factory()->NewEmptyStatement(pos); | |
| 1694 } | |
| 1695 | |
| 1696 | |
| 1697 Statement* Parser::ParseExportDefault(bool* ok) { | |
| 1698 // Supports the following productions, starting after the 'default' token: | |
| 1699 // 'export' 'default' FunctionDeclaration | |
| 1700 // 'export' 'default' ClassDeclaration | |
| 1701 // 'export' 'default' AssignmentExpression[In] ';' | |
| 1702 | |
| 1703 Expect(Token::DEFAULT, CHECK_OK); | |
| 1704 Scanner::Location default_loc = scanner()->location(); | |
| 1705 | |
| 1706 ZoneList<const AstRawString*> names(1, zone()); | |
| 1707 Statement* result = NULL; | |
| 1708 switch (peek()) { | |
| 1709 case Token::FUNCTION: | |
| 1710 // TODO(ES6): Support parsing anonymous function declarations here. | |
| 1711 result = ParseFunctionDeclaration(&names, CHECK_OK); | |
| 1712 break; | |
| 1713 | |
| 1714 case Token::CLASS: | |
| 1715 // TODO(ES6): Support parsing anonymous class declarations here. | |
| 1716 result = ParseClassDeclaration(&names, CHECK_OK); | |
| 1717 break; | |
| 1718 | |
| 1719 default: { | |
| 1720 int pos = peek_position(); | |
| 1721 ExpressionClassifier classifier; | |
| 1722 Expression* expr = ParseAssignmentExpression(true, &classifier, CHECK_OK); | |
| 1723 ValidateExpression(&classifier, CHECK_OK); | |
| 1724 | |
| 1725 ExpectSemicolon(CHECK_OK); | |
| 1726 result = factory()->NewExpressionStatement(expr, pos); | |
| 1727 break; | |
| 1728 } | |
| 1729 } | |
| 1730 | |
| 1731 const AstRawString* default_string = ast_value_factory()->default_string(); | |
| 1732 | |
| 1733 DCHECK_LE(names.length(), 1); | |
| 1734 if (names.length() == 1) { | |
| 1735 scope_->module()->AddLocalExport(default_string, names.first(), zone(), ok); | |
| 1736 if (!*ok) { | |
| 1737 ParserTraits::ReportMessageAt( | |
| 1738 default_loc, MessageTemplate::kDuplicateExport, default_string); | |
| 1739 return NULL; | |
| 1740 } | |
| 1741 } else { | |
| 1742 // TODO(ES6): Assign result to a const binding with the name "*default*" | |
| 1743 // and add an export entry with "*default*" as the local name. | |
| 1744 } | |
| 1745 | |
| 1746 return result; | |
| 1747 } | |
| 1748 | |
| 1749 | |
| 1750 Statement* Parser::ParseExportDeclaration(bool* ok) { | |
| 1751 // ExportDeclaration: | |
| 1752 // 'export' '*' 'from' ModuleSpecifier ';' | |
| 1753 // 'export' ExportClause ('from' ModuleSpecifier)? ';' | |
| 1754 // 'export' VariableStatement | |
| 1755 // 'export' Declaration | |
| 1756 // 'export' 'default' ... (handled in ParseExportDefault) | |
| 1757 | |
| 1758 int pos = peek_position(); | |
| 1759 Expect(Token::EXPORT, CHECK_OK); | |
| 1760 | |
| 1761 Statement* result = NULL; | |
| 1762 ZoneList<const AstRawString*> names(1, zone()); | |
| 1763 switch (peek()) { | |
| 1764 case Token::DEFAULT: | |
| 1765 return ParseExportDefault(ok); | |
| 1766 | |
| 1767 case Token::MUL: { | |
| 1768 Consume(Token::MUL); | |
| 1769 ExpectContextualKeyword(CStrVector("from"), CHECK_OK); | |
| 1770 const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK); | |
| 1771 scope_->module()->AddModuleRequest(module_specifier, zone()); | |
| 1772 // TODO(ES6): scope_->module()->AddStarExport(...) | |
| 1773 ExpectSemicolon(CHECK_OK); | |
| 1774 return factory()->NewEmptyStatement(pos); | |
| 1775 } | |
| 1776 | |
| 1777 case Token::LBRACE: { | |
| 1778 // There are two cases here: | |
| 1779 // | |
| 1780 // 'export' ExportClause ';' | |
| 1781 // and | |
| 1782 // 'export' ExportClause FromClause ';' | |
| 1783 // | |
| 1784 // In the first case, the exported identifiers in ExportClause must | |
| 1785 // not be reserved words, while in the latter they may be. We | |
| 1786 // pass in a location that gets filled with the first reserved word | |
| 1787 // encountered, and then throw a SyntaxError if we are in the | |
| 1788 // non-FromClause case. | |
| 1789 Scanner::Location reserved_loc = Scanner::Location::invalid(); | |
| 1790 ZoneList<const AstRawString*> export_names(1, zone()); | |
| 1791 ZoneList<Scanner::Location> export_locations(1, zone()); | |
| 1792 ZoneList<const AstRawString*> local_names(1, zone()); | |
| 1793 ParseExportClause(&export_names, &export_locations, &local_names, | |
| 1794 &reserved_loc, CHECK_OK); | |
| 1795 const AstRawString* indirect_export_module_specifier = NULL; | |
| 1796 if (CheckContextualKeyword(CStrVector("from"))) { | |
| 1797 indirect_export_module_specifier = ParseModuleSpecifier(CHECK_OK); | |
| 1798 } else if (reserved_loc.IsValid()) { | |
| 1799 // No FromClause, so reserved words are invalid in ExportClause. | |
| 1800 *ok = false; | |
| 1801 ReportMessageAt(reserved_loc, MessageTemplate::kUnexpectedReserved); | |
| 1802 return NULL; | |
| 1803 } | |
| 1804 ExpectSemicolon(CHECK_OK); | |
| 1805 const int length = export_names.length(); | |
| 1806 DCHECK_EQ(length, local_names.length()); | |
| 1807 DCHECK_EQ(length, export_locations.length()); | |
| 1808 if (indirect_export_module_specifier == NULL) { | |
| 1809 for (int i = 0; i < length; ++i) { | |
| 1810 scope_->module()->AddLocalExport(export_names[i], local_names[i], | |
| 1811 zone(), ok); | |
| 1812 if (!*ok) { | |
| 1813 ParserTraits::ReportMessageAt(export_locations[i], | |
| 1814 MessageTemplate::kDuplicateExport, | |
| 1815 export_names[i]); | |
| 1816 return NULL; | |
| 1817 } | |
| 1818 } | |
| 1819 } else { | |
| 1820 scope_->module()->AddModuleRequest(indirect_export_module_specifier, | |
| 1821 zone()); | |
| 1822 for (int i = 0; i < length; ++i) { | |
| 1823 // TODO(ES6): scope_->module()->AddIndirectExport(...);( | |
| 1824 } | |
| 1825 } | |
| 1826 return factory()->NewEmptyStatement(pos); | |
| 1827 } | |
| 1828 | |
| 1829 case Token::FUNCTION: | |
| 1830 result = ParseFunctionDeclaration(&names, CHECK_OK); | |
| 1831 break; | |
| 1832 | |
| 1833 case Token::CLASS: | |
| 1834 result = ParseClassDeclaration(&names, CHECK_OK); | |
| 1835 break; | |
| 1836 | |
| 1837 case Token::VAR: | |
| 1838 case Token::LET: | |
| 1839 case Token::CONST: | |
| 1840 result = ParseVariableStatement(kStatementListItem, &names, CHECK_OK); | |
| 1841 break; | |
| 1842 | |
| 1843 default: | |
| 1844 *ok = false; | |
| 1845 ReportUnexpectedToken(scanner()->current_token()); | |
| 1846 return NULL; | |
| 1847 } | |
| 1848 | |
| 1849 // Extract declared names into export declarations. | |
| 1850 ModuleDescriptor* descriptor = scope_->module(); | |
| 1851 for (int i = 0; i < names.length(); ++i) { | |
| 1852 descriptor->AddLocalExport(names[i], names[i], zone(), ok); | |
| 1853 if (!*ok) { | |
| 1854 // TODO(adamk): Possibly report this error at the right place. | |
| 1855 ParserTraits::ReportMessage(MessageTemplate::kDuplicateExport, names[i]); | |
| 1856 return NULL; | |
| 1857 } | |
| 1858 } | |
| 1859 | |
| 1860 DCHECK_NOT_NULL(result); | |
| 1861 return result; | |
| 1862 } | |
| 1863 | |
| 1864 | |
| 1865 Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels, | |
| 1866 bool* ok) { | |
| 1867 // Statement :: | |
| 1868 // EmptyStatement | |
| 1869 // ... | |
| 1870 | |
| 1871 if (peek() == Token::SEMICOLON) { | |
| 1872 Next(); | |
| 1873 return factory()->NewEmptyStatement(RelocInfo::kNoPosition); | |
| 1874 } | |
| 1875 return ParseSubStatement(labels, ok); | |
| 1876 } | |
| 1877 | |
| 1878 | |
| 1879 Statement* Parser::ParseSubStatement(ZoneList<const AstRawString*>* labels, | |
| 1880 bool* ok) { | |
| 1881 // Statement :: | |
| 1882 // Block | |
| 1883 // VariableStatement | |
| 1884 // EmptyStatement | |
| 1885 // ExpressionStatement | |
| 1886 // IfStatement | |
| 1887 // IterationStatement | |
| 1888 // ContinueStatement | |
| 1889 // BreakStatement | |
| 1890 // ReturnStatement | |
| 1891 // WithStatement | |
| 1892 // LabelledStatement | |
| 1893 // SwitchStatement | |
| 1894 // ThrowStatement | |
| 1895 // TryStatement | |
| 1896 // DebuggerStatement | |
| 1897 | |
| 1898 // Note: Since labels can only be used by 'break' and 'continue' | |
| 1899 // statements, which themselves are only valid within blocks, | |
| 1900 // iterations or 'switch' statements (i.e., BreakableStatements), | |
| 1901 // labels can be simply ignored in all other cases; except for | |
| 1902 // trivial labeled break statements 'label: break label' which is | |
| 1903 // parsed into an empty statement. | |
| 1904 switch (peek()) { | |
| 1905 case Token::LBRACE: | |
| 1906 return ParseBlock(labels, ok); | |
| 1907 | |
| 1908 case Token::SEMICOLON: | |
| 1909 if (is_strong(language_mode())) { | |
| 1910 ReportMessageAt(scanner()->peek_location(), | |
| 1911 MessageTemplate::kStrongEmpty); | |
| 1912 *ok = false; | |
| 1913 return NULL; | |
| 1914 } | |
| 1915 Next(); | |
| 1916 return factory()->NewEmptyStatement(RelocInfo::kNoPosition); | |
| 1917 | |
| 1918 case Token::IF: | |
| 1919 return ParseIfStatement(labels, ok); | |
| 1920 | |
| 1921 case Token::DO: | |
| 1922 return ParseDoWhileStatement(labels, ok); | |
| 1923 | |
| 1924 case Token::WHILE: | |
| 1925 return ParseWhileStatement(labels, ok); | |
| 1926 | |
| 1927 case Token::FOR: | |
| 1928 return ParseForStatement(labels, ok); | |
| 1929 | |
| 1930 case Token::CONTINUE: | |
| 1931 case Token::BREAK: | |
| 1932 case Token::RETURN: | |
| 1933 case Token::THROW: | |
| 1934 case Token::TRY: { | |
| 1935 // These statements must have their labels preserved in an enclosing | |
| 1936 // block | |
| 1937 if (labels == NULL) { | |
| 1938 return ParseStatementAsUnlabelled(labels, ok); | |
| 1939 } else { | |
| 1940 Block* result = | |
| 1941 factory()->NewBlock(labels, 1, false, RelocInfo::kNoPosition); | |
| 1942 Target target(&this->target_stack_, result); | |
| 1943 Statement* statement = ParseStatementAsUnlabelled(labels, CHECK_OK); | |
| 1944 if (result) result->statements()->Add(statement, zone()); | |
| 1945 return result; | |
| 1946 } | |
| 1947 } | |
| 1948 | |
| 1949 case Token::WITH: | |
| 1950 return ParseWithStatement(labels, ok); | |
| 1951 | |
| 1952 case Token::SWITCH: | |
| 1953 return ParseSwitchStatement(labels, ok); | |
| 1954 | |
| 1955 case Token::FUNCTION: { | |
| 1956 // FunctionDeclaration is only allowed in the context of SourceElements | |
| 1957 // (Ecma 262 5th Edition, clause 14): | |
| 1958 // SourceElement: | |
| 1959 // Statement | |
| 1960 // FunctionDeclaration | |
| 1961 // Common language extension is to allow function declaration in place | |
| 1962 // of any statement. This language extension is disabled in strict mode. | |
| 1963 // | |
| 1964 // In Harmony mode, this case also handles the extension: | |
| 1965 // Statement: | |
| 1966 // GeneratorDeclaration | |
| 1967 if (is_strict(language_mode())) { | |
| 1968 ReportMessageAt(scanner()->peek_location(), | |
| 1969 MessageTemplate::kStrictFunction); | |
| 1970 *ok = false; | |
| 1971 return NULL; | |
| 1972 } | |
| 1973 return ParseFunctionDeclaration(NULL, ok); | |
| 1974 } | |
| 1975 | |
| 1976 case Token::DEBUGGER: | |
| 1977 return ParseDebuggerStatement(ok); | |
| 1978 | |
| 1979 case Token::VAR: | |
| 1980 return ParseVariableStatement(kStatement, NULL, ok); | |
| 1981 | |
| 1982 case Token::CONST: | |
| 1983 // In ES6 CONST is not allowed as a Statement, only as a | |
| 1984 // LexicalDeclaration, however we continue to allow it in sloppy mode for | |
| 1985 // backwards compatibility. | |
| 1986 if (is_sloppy(language_mode()) && allow_legacy_const()) { | |
| 1987 return ParseVariableStatement(kStatement, NULL, ok); | |
| 1988 } | |
| 1989 | |
| 1990 // Fall through. | |
| 1991 default: | |
| 1992 return ParseExpressionOrLabelledStatement(labels, ok); | |
| 1993 } | |
| 1994 } | |
| 1995 | |
| 1996 Statement* Parser::ParseStatementAsUnlabelled( | |
| 1997 ZoneList<const AstRawString*>* labels, bool* ok) { | |
| 1998 switch (peek()) { | |
| 1999 case Token::CONTINUE: | |
| 2000 return ParseContinueStatement(ok); | |
| 2001 | |
| 2002 case Token::BREAK: | |
| 2003 return ParseBreakStatement(labels, ok); | |
| 2004 | |
| 2005 case Token::RETURN: | |
| 2006 return ParseReturnStatement(ok); | |
| 2007 | |
| 2008 case Token::THROW: | |
| 2009 return ParseThrowStatement(ok); | |
| 2010 | |
| 2011 case Token::TRY: | |
| 2012 return ParseTryStatement(ok); | |
| 2013 | |
| 2014 default: | |
| 2015 UNREACHABLE(); | |
| 2016 return NULL; | |
| 2017 } | |
| 2018 } | |
| 2019 | |
| 2020 | |
| 2021 VariableProxy* Parser::NewUnresolved(const AstRawString* name, | |
| 2022 VariableMode mode) { | |
| 2023 // If we are inside a function, a declaration of a var/const variable is a | |
| 2024 // truly local variable, and the scope of the variable is always the function | |
| 2025 // scope. | |
| 2026 // Let/const variables in harmony mode are always added to the immediately | |
| 2027 // enclosing scope. | |
| 2028 return DeclarationScope(mode)->NewUnresolved( | |
| 2029 factory(), name, Variable::NORMAL, scanner()->location().beg_pos, | |
| 2030 scanner()->location().end_pos); | |
| 2031 } | |
| 2032 | |
| 2033 | |
| 2034 Variable* Parser::Declare(Declaration* declaration, | |
| 2035 DeclarationDescriptor::Kind declaration_kind, | |
| 2036 bool resolve, bool* ok, Scope* scope) { | |
| 2037 VariableProxy* proxy = declaration->proxy(); | |
| 2038 DCHECK(proxy->raw_name() != NULL); | |
| 2039 const AstRawString* name = proxy->raw_name(); | |
| 2040 VariableMode mode = declaration->mode(); | |
| 2041 if (scope == nullptr) scope = scope_; | |
| 2042 Scope* declaration_scope = | |
| 2043 IsLexicalVariableMode(mode) ? scope : scope->DeclarationScope(); | |
| 2044 Variable* var = NULL; | |
| 2045 | |
| 2046 // If a suitable scope exists, then we can statically declare this | |
| 2047 // variable and also set its mode. In any case, a Declaration node | |
| 2048 // will be added to the scope so that the declaration can be added | |
| 2049 // to the corresponding activation frame at runtime if necessary. | |
| 2050 // For instance, var declarations inside a sloppy eval scope need | |
| 2051 // to be added to the calling function context. Similarly, strict | |
| 2052 // mode eval scope and lexical eval bindings do not leak variable | |
| 2053 // declarations to the caller's scope so we declare all locals, too. | |
| 2054 if (declaration_scope->is_function_scope() || | |
| 2055 declaration_scope->is_block_scope() || | |
| 2056 declaration_scope->is_module_scope() || | |
| 2057 declaration_scope->is_script_scope() || | |
| 2058 (declaration_scope->is_eval_scope() && | |
| 2059 (is_strict(declaration_scope->language_mode()) || | |
| 2060 IsLexicalVariableMode(mode)))) { | |
| 2061 // Declare the variable in the declaration scope. | |
| 2062 var = declaration_scope->LookupLocal(name); | |
| 2063 if (var == NULL) { | |
| 2064 // Declare the name. | |
| 2065 Variable::Kind kind = Variable::NORMAL; | |
| 2066 int declaration_group_start = -1; | |
| 2067 if (declaration->IsFunctionDeclaration()) { | |
| 2068 kind = Variable::FUNCTION; | |
| 2069 } else if (declaration->IsVariableDeclaration() && | |
| 2070 declaration->AsVariableDeclaration()->is_class_declaration()) { | |
| 2071 kind = Variable::CLASS; | |
| 2072 declaration_group_start = | |
| 2073 declaration->AsVariableDeclaration()->declaration_group_start(); | |
| 2074 } | |
| 2075 var = declaration_scope->DeclareLocal( | |
| 2076 name, mode, declaration->initialization(), kind, kNotAssigned, | |
| 2077 declaration_group_start); | |
| 2078 } else if (IsLexicalVariableMode(mode) || | |
| 2079 IsLexicalVariableMode(var->mode()) || | |
| 2080 ((mode == CONST_LEGACY || var->mode() == CONST_LEGACY) && | |
| 2081 !declaration_scope->is_script_scope())) { | |
| 2082 // The name was declared in this scope before; check for conflicting | |
| 2083 // re-declarations. We have a conflict if either of the declarations is | |
| 2084 // not a var (in script scope, we also have to ignore legacy const for | |
| 2085 // compatibility). There is similar code in runtime.cc in the Declare | |
| 2086 // functions. The function CheckConflictingVarDeclarations checks for | |
| 2087 // var and let bindings from different scopes whereas this is a check for | |
| 2088 // conflicting declarations within the same scope. This check also covers | |
| 2089 // the special case | |
| 2090 // | |
| 2091 // function () { let x; { var x; } } | |
| 2092 // | |
| 2093 // because the var declaration is hoisted to the function scope where 'x' | |
| 2094 // is already bound. | |
| 2095 DCHECK(IsDeclaredVariableMode(var->mode())); | |
| 2096 if (is_strict(language_mode()) || allow_harmony_sloppy()) { | |
| 2097 // In harmony we treat re-declarations as early errors. See | |
| 2098 // ES5 16 for a definition of early errors. | |
| 2099 if (declaration_kind == DeclarationDescriptor::NORMAL) { | |
| 2100 ParserTraits::ReportMessage(MessageTemplate::kVarRedeclaration, name); | |
| 2101 } else { | |
| 2102 ParserTraits::ReportMessage(MessageTemplate::kParamDupe); | |
| 2103 } | |
| 2104 *ok = false; | |
| 2105 return nullptr; | |
| 2106 } | |
| 2107 Expression* expression = NewThrowSyntaxError( | |
| 2108 MessageTemplate::kVarRedeclaration, name, declaration->position()); | |
| 2109 declaration_scope->SetIllegalRedeclaration(expression); | |
| 2110 } else if (mode == VAR) { | |
| 2111 var->set_maybe_assigned(); | |
| 2112 } | |
| 2113 } else if (declaration_scope->is_eval_scope() && | |
| 2114 is_sloppy(declaration_scope->language_mode()) && | |
| 2115 !IsLexicalVariableMode(mode)) { | |
| 2116 // In a var binding in a sloppy direct eval, pollute the enclosing scope | |
| 2117 // with this new binding by doing the following: | |
| 2118 // The proxy is bound to a lookup variable to force a dynamic declaration | |
| 2119 // using the DeclareLookupSlot runtime function. | |
| 2120 Variable::Kind kind = Variable::NORMAL; | |
| 2121 // TODO(sigurds) figure out if kNotAssigned is OK here | |
| 2122 var = new (zone()) Variable(declaration_scope, name, mode, kind, | |
| 2123 declaration->initialization(), kNotAssigned); | |
| 2124 var->AllocateTo(VariableLocation::LOOKUP, -1); | |
| 2125 var->SetFromEval(); | |
| 2126 resolve = true; | |
| 2127 } | |
| 2128 | |
| 2129 | |
| 2130 // We add a declaration node for every declaration. The compiler | |
| 2131 // will only generate code if necessary. In particular, declarations | |
| 2132 // for inner local variables that do not represent functions won't | |
| 2133 // result in any generated code. | |
| 2134 // | |
| 2135 // Note that we always add an unresolved proxy even if it's not | |
| 2136 // used, simply because we don't know in this method (w/o extra | |
| 2137 // parameters) if the proxy is needed or not. The proxy will be | |
| 2138 // bound during variable resolution time unless it was pre-bound | |
| 2139 // below. | |
| 2140 // | |
| 2141 // WARNING: This will lead to multiple declaration nodes for the | |
| 2142 // same variable if it is declared several times. This is not a | |
| 2143 // semantic issue as long as we keep the source order, but it may be | |
| 2144 // a performance issue since it may lead to repeated | |
| 2145 // RuntimeHidden_DeclareLookupSlot calls. | |
| 2146 declaration_scope->AddDeclaration(declaration); | |
| 2147 | |
| 2148 if (mode == CONST_LEGACY && declaration_scope->is_script_scope()) { | |
| 2149 // For global const variables we bind the proxy to a variable. | |
| 2150 DCHECK(resolve); // should be set by all callers | |
| 2151 Variable::Kind kind = Variable::NORMAL; | |
| 2152 var = new (zone()) Variable(declaration_scope, name, mode, kind, | |
| 2153 kNeedsInitialization, kNotAssigned); | |
| 2154 } | |
| 2155 | |
| 2156 // If requested and we have a local variable, bind the proxy to the variable | |
| 2157 // at parse-time. This is used for functions (and consts) declared inside | |
| 2158 // statements: the corresponding function (or const) variable must be in the | |
| 2159 // function scope and not a statement-local scope, e.g. as provided with a | |
| 2160 // 'with' statement: | |
| 2161 // | |
| 2162 // with (obj) { | |
| 2163 // function f() {} | |
| 2164 // } | |
| 2165 // | |
| 2166 // which is translated into: | |
| 2167 // | |
| 2168 // with (obj) { | |
| 2169 // // in this case this is not: 'var f; f = function () {};' | |
| 2170 // var f = function () {}; | |
| 2171 // } | |
| 2172 // | |
| 2173 // Note that if 'f' is accessed from inside the 'with' statement, it | |
| 2174 // will be allocated in the context (because we must be able to look | |
| 2175 // it up dynamically) but it will also be accessed statically, i.e., | |
| 2176 // with a context slot index and a context chain length for this | |
| 2177 // initialization code. Thus, inside the 'with' statement, we need | |
| 2178 // both access to the static and the dynamic context chain; the | |
| 2179 // runtime needs to provide both. | |
| 2180 if (resolve && var != NULL) { | |
| 2181 proxy->BindTo(var); | |
| 2182 } | |
| 2183 return var; | |
| 2184 } | |
| 2185 | |
| 2186 | |
| 2187 // Language extension which is only enabled for source files loaded | |
| 2188 // through the API's extension mechanism. A native function | |
| 2189 // declaration is resolved by looking up the function through a | |
| 2190 // callback provided by the extension. | |
| 2191 Statement* Parser::ParseNativeDeclaration(bool* ok) { | |
| 2192 int pos = peek_position(); | |
| 2193 Expect(Token::FUNCTION, CHECK_OK); | |
| 2194 // Allow "eval" or "arguments" for backward compatibility. | |
| 2195 const AstRawString* name = | |
| 2196 ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK); | |
| 2197 Expect(Token::LPAREN, CHECK_OK); | |
| 2198 bool done = (peek() == Token::RPAREN); | |
| 2199 while (!done) { | |
| 2200 ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK); | |
| 2201 done = (peek() == Token::RPAREN); | |
| 2202 if (!done) { | |
| 2203 Expect(Token::COMMA, CHECK_OK); | |
| 2204 } | |
| 2205 } | |
| 2206 Expect(Token::RPAREN, CHECK_OK); | |
| 2207 Expect(Token::SEMICOLON, CHECK_OK); | |
| 2208 | |
| 2209 // Make sure that the function containing the native declaration | |
| 2210 // isn't lazily compiled. The extension structures are only | |
| 2211 // accessible while parsing the first time not when reparsing | |
| 2212 // because of lazy compilation. | |
| 2213 DeclarationScope(VAR)->ForceEagerCompilation(); | |
| 2214 | |
| 2215 // TODO(1240846): It's weird that native function declarations are | |
| 2216 // introduced dynamically when we meet their declarations, whereas | |
| 2217 // other functions are set up when entering the surrounding scope. | |
| 2218 VariableProxy* proxy = NewUnresolved(name, VAR); | |
| 2219 Declaration* declaration = | |
| 2220 factory()->NewVariableDeclaration(proxy, VAR, scope_, pos); | |
| 2221 Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK); | |
| 2222 NativeFunctionLiteral* lit = factory()->NewNativeFunctionLiteral( | |
| 2223 name, extension_, RelocInfo::kNoPosition); | |
| 2224 return factory()->NewExpressionStatement( | |
| 2225 factory()->NewAssignment(Token::INIT, proxy, lit, RelocInfo::kNoPosition), | |
| 2226 pos); | |
| 2227 } | |
| 2228 | |
| 2229 | |
| 2230 Statement* Parser::ParseFunctionDeclaration( | |
| 2231 ZoneList<const AstRawString*>* names, bool* ok) { | |
| 2232 // FunctionDeclaration :: | |
| 2233 // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}' | |
| 2234 // GeneratorDeclaration :: | |
| 2235 // 'function' '*' Identifier '(' FormalParameterListopt ')' | |
| 2236 // '{' FunctionBody '}' | |
| 2237 Expect(Token::FUNCTION, CHECK_OK); | |
| 2238 int pos = position(); | |
| 2239 bool is_generator = Check(Token::MUL); | |
| 2240 bool is_strict_reserved = false; | |
| 2241 const AstRawString* name = ParseIdentifierOrStrictReservedWord( | |
| 2242 &is_strict_reserved, CHECK_OK); | |
| 2243 | |
| 2244 if (fni_ != NULL) { | |
| 2245 fni_->Enter(); | |
| 2246 fni_->PushEnclosingName(name); | |
| 2247 } | |
| 2248 FunctionLiteral* fun = ParseFunctionLiteral( | |
| 2249 name, scanner()->location(), | |
| 2250 is_strict_reserved ? kFunctionNameIsStrictReserved | |
| 2251 : kFunctionNameValidityUnknown, | |
| 2252 is_generator ? FunctionKind::kGeneratorFunction | |
| 2253 : FunctionKind::kNormalFunction, | |
| 2254 pos, FunctionLiteral::DECLARATION, FunctionLiteral::NORMAL_ARITY, | |
| 2255 language_mode(), CHECK_OK); | |
| 2256 if (fni_ != NULL) fni_->Leave(); | |
| 2257 | |
| 2258 // Even if we're not at the top-level of the global or a function | |
| 2259 // scope, we treat it as such and introduce the function with its | |
| 2260 // initial value upon entering the corresponding scope. | |
| 2261 // In ES6, a function behaves as a lexical binding, except in | |
| 2262 // a script scope, or the initial scope of eval or another function. | |
| 2263 VariableMode mode = | |
| 2264 is_strong(language_mode()) | |
| 2265 ? CONST | |
| 2266 : (is_strict(language_mode()) || allow_harmony_sloppy_function()) && | |
| 2267 !scope_->is_declaration_scope() | |
| 2268 ? LET | |
| 2269 : VAR; | |
| 2270 VariableProxy* proxy = NewUnresolved(name, mode); | |
| 2271 Declaration* declaration = | |
| 2272 factory()->NewFunctionDeclaration(proxy, mode, fun, scope_, pos); | |
| 2273 Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK); | |
| 2274 if (names) names->Add(name, zone()); | |
| 2275 EmptyStatement* empty = factory()->NewEmptyStatement(RelocInfo::kNoPosition); | |
| 2276 if (is_sloppy(language_mode()) && allow_harmony_sloppy_function() && | |
| 2277 !scope_->is_declaration_scope()) { | |
| 2278 SloppyBlockFunctionStatement* delegate = | |
| 2279 factory()->NewSloppyBlockFunctionStatement(empty, scope_); | |
| 2280 scope_->DeclarationScope()->sloppy_block_function_map()->Declare(name, | |
| 2281 delegate); | |
| 2282 return delegate; | |
| 2283 } | |
| 2284 return empty; | |
| 2285 } | |
| 2286 | |
| 2287 | |
| 2288 Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names, | |
| 2289 bool* ok) { | |
| 2290 // ClassDeclaration :: | |
| 2291 // 'class' Identifier ('extends' LeftHandExpression)? '{' ClassBody '}' | |
| 2292 // | |
| 2293 // A ClassDeclaration | |
| 2294 // | |
| 2295 // class C { ... } | |
| 2296 // | |
| 2297 // has the same semantics as: | |
| 2298 // | |
| 2299 // let C = class C { ... }; | |
| 2300 // | |
| 2301 // so rewrite it as such. | |
| 2302 | |
| 2303 Expect(Token::CLASS, CHECK_OK); | |
| 2304 if (!allow_harmony_sloppy() && is_sloppy(language_mode())) { | |
| 2305 ReportMessage(MessageTemplate::kSloppyLexical); | |
| 2306 *ok = false; | |
| 2307 return NULL; | |
| 2308 } | |
| 2309 | |
| 2310 int pos = position(); | |
| 2311 bool is_strict_reserved = false; | |
| 2312 const AstRawString* name = | |
| 2313 ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK); | |
| 2314 ClassLiteral* value = ParseClassLiteral(name, scanner()->location(), | |
| 2315 is_strict_reserved, pos, CHECK_OK); | |
| 2316 | |
| 2317 VariableMode mode = is_strong(language_mode()) ? CONST : LET; | |
| 2318 VariableProxy* proxy = NewUnresolved(name, mode); | |
| 2319 const bool is_class_declaration = true; | |
| 2320 Declaration* declaration = factory()->NewVariableDeclaration( | |
| 2321 proxy, mode, scope_, pos, is_class_declaration, | |
| 2322 scope_->class_declaration_group_start()); | |
| 2323 Variable* outer_class_variable = | |
| 2324 Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK); | |
| 2325 proxy->var()->set_initializer_position(position()); | |
| 2326 // This is needed because a class ("class Name { }") creates two bindings (one | |
| 2327 // in the outer scope, and one in the class scope). The method is a function | |
| 2328 // scope inside the inner scope (class scope). The consecutive class | |
| 2329 // declarations are in the outer scope. | |
| 2330 if (value->class_variable_proxy() && value->class_variable_proxy()->var() && | |
| 2331 outer_class_variable->is_class()) { | |
| 2332 // In some cases, the outer variable is not detected as a class variable; | |
| 2333 // this happens e.g., for lazy methods. They are excluded from strong mode | |
| 2334 // checks for now. TODO(marja, rossberg): re-create variables with the | |
| 2335 // correct Kind and remove this hack. | |
| 2336 value->class_variable_proxy() | |
| 2337 ->var() | |
| 2338 ->AsClassVariable() | |
| 2339 ->set_declaration_group_start( | |
| 2340 outer_class_variable->AsClassVariable()->declaration_group_start()); | |
| 2341 } | |
| 2342 | |
| 2343 Assignment* assignment = | |
| 2344 factory()->NewAssignment(Token::INIT, proxy, value, pos); | |
| 2345 Statement* assignment_statement = | |
| 2346 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition); | |
| 2347 if (names) names->Add(name, zone()); | |
| 2348 return assignment_statement; | |
| 2349 } | |
| 2350 | |
| 2351 | |
| 2352 Block* Parser::ParseBlock(ZoneList<const AstRawString*>* labels, bool* ok) { | |
| 2353 // The harmony mode uses block elements instead of statements. | |
| 2354 // | |
| 2355 // Block :: | |
| 2356 // '{' StatementList '}' | |
| 2357 | |
| 2358 // Construct block expecting 16 statements. | |
| 2359 Block* body = | |
| 2360 factory()->NewBlock(labels, 16, false, RelocInfo::kNoPosition); | |
| 2361 Scope* block_scope = NewScope(scope_, BLOCK_SCOPE); | |
| 2362 | |
| 2363 // Parse the statements and collect escaping labels. | |
| 2364 Expect(Token::LBRACE, CHECK_OK); | |
| 2365 block_scope->set_start_position(scanner()->location().beg_pos); | |
| 2366 { BlockState block_state(&scope_, block_scope); | |
| 2367 Target target(&this->target_stack_, body); | |
| 2368 | |
| 2369 while (peek() != Token::RBRACE) { | |
| 2370 Statement* stat = ParseStatementListItem(CHECK_OK); | |
| 2371 if (stat && !stat->IsEmpty()) { | |
| 2372 body->statements()->Add(stat, zone()); | |
| 2373 } | |
| 2374 } | |
| 2375 } | |
| 2376 Expect(Token::RBRACE, CHECK_OK); | |
| 2377 block_scope->set_end_position(scanner()->location().end_pos); | |
| 2378 block_scope = block_scope->FinalizeBlockScope(); | |
| 2379 body->set_scope(block_scope); | |
| 2380 return body; | |
| 2381 } | |
| 2382 | |
| 2383 | |
| 2384 Block* Parser::DeclarationParsingResult::BuildInitializationBlock( | |
| 2385 ZoneList<const AstRawString*>* names, bool* ok) { | |
| 2386 Block* result = descriptor.parser->factory()->NewBlock( | |
| 2387 NULL, 1, true, descriptor.declaration_pos); | |
| 2388 for (auto declaration : declarations) { | |
| 2389 PatternRewriter::DeclareAndInitializeVariables( | |
| 2390 result, &descriptor, &declaration, names, CHECK_OK); | |
| 2391 } | |
| 2392 return result; | |
| 2393 } | |
| 2394 | |
| 2395 | |
| 2396 Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context, | |
| 2397 ZoneList<const AstRawString*>* names, | |
| 2398 bool* ok) { | |
| 2399 // VariableStatement :: | |
| 2400 // VariableDeclarations ';' | |
| 2401 | |
| 2402 // The scope of a var/const declared variable anywhere inside a function | |
| 2403 // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). Thus we can | |
| 2404 // transform a source-level var/const declaration into a (Function) | |
| 2405 // Scope declaration, and rewrite the source-level initialization into an | |
| 2406 // assignment statement. We use a block to collect multiple assignments. | |
| 2407 // | |
| 2408 // We mark the block as initializer block because we don't want the | |
| 2409 // rewriter to add a '.result' assignment to such a block (to get compliant | |
| 2410 // behavior for code such as print(eval('var x = 7')), and for cosmetic | |
| 2411 // reasons when pretty-printing. Also, unless an assignment (initialization) | |
| 2412 // is inside an initializer block, it is ignored. | |
| 2413 | |
| 2414 DeclarationParsingResult parsing_result; | |
| 2415 ParseVariableDeclarations(var_context, &parsing_result, CHECK_OK); | |
| 2416 ExpectSemicolon(CHECK_OK); | |
| 2417 | |
| 2418 Block* result = parsing_result.BuildInitializationBlock(names, CHECK_OK); | |
| 2419 return result; | |
| 2420 } | |
| 2421 | |
| 2422 | |
| 2423 void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context, | |
| 2424 DeclarationParsingResult* parsing_result, | |
| 2425 bool* ok) { | |
| 2426 // VariableDeclarations :: | |
| 2427 // ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[','] | |
| 2428 // | |
| 2429 // The ES6 Draft Rev3 specifies the following grammar for const declarations | |
| 2430 // | |
| 2431 // ConstDeclaration :: | |
| 2432 // const ConstBinding (',' ConstBinding)* ';' | |
| 2433 // ConstBinding :: | |
| 2434 // Identifier '=' AssignmentExpression | |
| 2435 // | |
| 2436 // TODO(ES6): | |
| 2437 // ConstBinding :: | |
| 2438 // BindingPattern '=' AssignmentExpression | |
| 2439 | |
| 2440 parsing_result->descriptor.parser = this; | |
| 2441 parsing_result->descriptor.declaration_kind = DeclarationDescriptor::NORMAL; | |
| 2442 parsing_result->descriptor.declaration_pos = peek_position(); | |
| 2443 parsing_result->descriptor.initialization_pos = peek_position(); | |
| 2444 parsing_result->descriptor.mode = VAR; | |
| 2445 // True if the binding needs initialization. 'let' and 'const' declared | |
| 2446 // bindings are created uninitialized by their declaration nodes and | |
| 2447 // need initialization. 'var' declared bindings are always initialized | |
| 2448 // immediately by their declaration nodes. | |
| 2449 parsing_result->descriptor.needs_init = false; | |
| 2450 parsing_result->descriptor.is_const = false; | |
| 2451 if (peek() == Token::VAR) { | |
| 2452 if (is_strong(language_mode())) { | |
| 2453 Scanner::Location location = scanner()->peek_location(); | |
| 2454 ReportMessageAt(location, MessageTemplate::kStrongVar); | |
| 2455 *ok = false; | |
| 2456 return; | |
| 2457 } | |
| 2458 Consume(Token::VAR); | |
| 2459 } else if (peek() == Token::CONST && allow_const()) { | |
| 2460 Consume(Token::CONST); | |
| 2461 if (is_sloppy(language_mode()) && allow_legacy_const()) { | |
| 2462 parsing_result->descriptor.mode = CONST_LEGACY; | |
| 2463 ++use_counts_[v8::Isolate::kLegacyConst]; | |
| 2464 } else { | |
| 2465 DCHECK(is_strict(language_mode()) || allow_harmony_sloppy()); | |
| 2466 DCHECK(var_context != kStatement); | |
| 2467 parsing_result->descriptor.mode = CONST; | |
| 2468 } | |
| 2469 parsing_result->descriptor.is_const = true; | |
| 2470 parsing_result->descriptor.needs_init = true; | |
| 2471 } else if (peek() == Token::LET && allow_let()) { | |
| 2472 Consume(Token::LET); | |
| 2473 DCHECK(var_context != kStatement); | |
| 2474 parsing_result->descriptor.mode = LET; | |
| 2475 parsing_result->descriptor.needs_init = true; | |
| 2476 } else { | |
| 2477 UNREACHABLE(); // by current callers | |
| 2478 } | |
| 2479 | |
| 2480 parsing_result->descriptor.declaration_scope = | |
| 2481 DeclarationScope(parsing_result->descriptor.mode); | |
| 2482 parsing_result->descriptor.scope = scope_; | |
| 2483 parsing_result->descriptor.hoist_scope = nullptr; | |
| 2484 | |
| 2485 | |
| 2486 bool first_declaration = true; | |
| 2487 int bindings_start = peek_position(); | |
| 2488 bool is_for_iteration_variable; | |
| 2489 do { | |
| 2490 if (fni_ != NULL) fni_->Enter(); | |
| 2491 | |
| 2492 // Parse name. | |
| 2493 if (!first_declaration) Consume(Token::COMMA); | |
| 2494 | |
| 2495 Expression* pattern; | |
| 2496 int decl_pos = peek_position(); | |
| 2497 { | |
| 2498 ExpressionClassifier pattern_classifier; | |
| 2499 Token::Value next = peek(); | |
| 2500 pattern = ParsePrimaryExpression(&pattern_classifier, ok); | |
| 2501 if (!*ok) return; | |
| 2502 ValidateBindingPattern(&pattern_classifier, ok); | |
| 2503 if (!*ok) return; | |
| 2504 if (IsLexicalVariableMode(parsing_result->descriptor.mode)) { | |
| 2505 ValidateLetPattern(&pattern_classifier, ok); | |
| 2506 if (!*ok) return; | |
| 2507 } | |
| 2508 if (!allow_harmony_destructuring_bind() && !pattern->IsVariableProxy()) { | |
| 2509 ReportUnexpectedToken(next); | |
| 2510 *ok = false; | |
| 2511 return; | |
| 2512 } | |
| 2513 } | |
| 2514 | |
| 2515 bool is_pattern = pattern->IsObjectLiteral() || pattern->IsArrayLiteral(); | |
| 2516 | |
| 2517 Scanner::Location variable_loc = scanner()->location(); | |
| 2518 const AstRawString* single_name = | |
| 2519 pattern->IsVariableProxy() ? pattern->AsVariableProxy()->raw_name() | |
| 2520 : nullptr; | |
| 2521 if (single_name != nullptr) { | |
| 2522 if (fni_ != NULL) fni_->PushVariableName(single_name); | |
| 2523 } | |
| 2524 | |
| 2525 is_for_iteration_variable = | |
| 2526 var_context == kForStatement && | |
| 2527 (peek() == Token::IN || PeekContextualKeyword(CStrVector("of"))); | |
| 2528 if (is_for_iteration_variable && | |
| 2529 (parsing_result->descriptor.mode == CONST || | |
| 2530 parsing_result->descriptor.mode == CONST_LEGACY)) { | |
| 2531 parsing_result->descriptor.needs_init = false; | |
| 2532 } | |
| 2533 | |
| 2534 Expression* value = NULL; | |
| 2535 // Harmony consts have non-optional initializers. | |
| 2536 int initializer_position = RelocInfo::kNoPosition; | |
| 2537 if (Check(Token::ASSIGN)) { | |
| 2538 ExpressionClassifier classifier; | |
| 2539 value = ParseAssignmentExpression(var_context != kForStatement, | |
| 2540 &classifier, ok); | |
| 2541 if (!*ok) return; | |
| 2542 ValidateExpression(&classifier, ok); | |
| 2543 if (!*ok) return; | |
| 2544 variable_loc.end_pos = scanner()->location().end_pos; | |
| 2545 | |
| 2546 if (!parsing_result->first_initializer_loc.IsValid()) { | |
| 2547 parsing_result->first_initializer_loc = variable_loc; | |
| 2548 } | |
| 2549 | |
| 2550 // Don't infer if it is "a = function(){...}();"-like expression. | |
| 2551 if (single_name) { | |
| 2552 if (fni_ != NULL && value->AsCall() == NULL && | |
| 2553 value->AsCallNew() == NULL) { | |
| 2554 fni_->Infer(); | |
| 2555 } else { | |
| 2556 fni_->RemoveLastFunction(); | |
| 2557 } | |
| 2558 } | |
| 2559 // End position of the initializer is after the assignment expression. | |
| 2560 initializer_position = scanner()->location().end_pos; | |
| 2561 } else { | |
| 2562 if ((parsing_result->descriptor.mode == CONST || is_pattern) && | |
| 2563 !is_for_iteration_variable) { | |
| 2564 ParserTraits::ReportMessageAt( | |
| 2565 Scanner::Location(decl_pos, scanner()->location().end_pos), | |
| 2566 MessageTemplate::kDeclarationMissingInitializer, | |
| 2567 is_pattern ? "destructuring" : "const"); | |
| 2568 *ok = false; | |
| 2569 return; | |
| 2570 } | |
| 2571 // End position of the initializer is after the variable. | |
| 2572 initializer_position = position(); | |
| 2573 } | |
| 2574 | |
| 2575 // Make sure that 'const x' and 'let x' initialize 'x' to undefined. | |
| 2576 if (value == NULL && parsing_result->descriptor.needs_init) { | |
| 2577 value = GetLiteralUndefined(position()); | |
| 2578 } | |
| 2579 | |
| 2580 if (single_name && fni_ != NULL) fni_->Leave(); | |
| 2581 parsing_result->declarations.Add(DeclarationParsingResult::Declaration( | |
| 2582 pattern, initializer_position, value)); | |
| 2583 first_declaration = false; | |
| 2584 } while (peek() == Token::COMMA); | |
| 2585 | |
| 2586 parsing_result->bindings_loc = | |
| 2587 Scanner::Location(bindings_start, scanner()->location().end_pos); | |
| 2588 } | |
| 2589 | |
| 2590 | |
| 2591 static bool ContainsLabel(ZoneList<const AstRawString*>* labels, | |
| 2592 const AstRawString* label) { | |
| 2593 DCHECK(label != NULL); | |
| 2594 if (labels != NULL) { | |
| 2595 for (int i = labels->length(); i-- > 0; ) { | |
| 2596 if (labels->at(i) == label) { | |
| 2597 return true; | |
| 2598 } | |
| 2599 } | |
| 2600 } | |
| 2601 return false; | |
| 2602 } | |
| 2603 | |
| 2604 | |
| 2605 Statement* Parser::ParseExpressionOrLabelledStatement( | |
| 2606 ZoneList<const AstRawString*>* labels, bool* ok) { | |
| 2607 // ExpressionStatement | LabelledStatement :: | |
| 2608 // Expression ';' | |
| 2609 // Identifier ':' Statement | |
| 2610 // | |
| 2611 // ExpressionStatement[Yield] : | |
| 2612 // [lookahead ∉ {{, function, class, let [}] Expression[In, ?Yield] ; | |
| 2613 | |
| 2614 int pos = peek_position(); | |
| 2615 | |
| 2616 switch (peek()) { | |
| 2617 case Token::FUNCTION: | |
| 2618 case Token::LBRACE: | |
| 2619 UNREACHABLE(); // Always handled by the callers. | |
| 2620 case Token::CLASS: | |
| 2621 ReportUnexpectedToken(Next()); | |
| 2622 *ok = false; | |
| 2623 return nullptr; | |
| 2624 | |
| 2625 case Token::THIS: | |
| 2626 if (!FLAG_strong_this) break; | |
| 2627 // Fall through. | |
| 2628 case Token::SUPER: | |
| 2629 if (is_strong(language_mode()) && | |
| 2630 IsClassConstructor(function_state_->kind())) { | |
| 2631 bool is_this = peek() == Token::THIS; | |
| 2632 Expression* expr; | |
| 2633 ExpressionClassifier classifier; | |
| 2634 if (is_this) { | |
| 2635 expr = ParseStrongInitializationExpression(&classifier, CHECK_OK); | |
| 2636 } else { | |
| 2637 expr = ParseStrongSuperCallExpression(&classifier, CHECK_OK); | |
| 2638 } | |
| 2639 ValidateExpression(&classifier, CHECK_OK); | |
| 2640 switch (peek()) { | |
| 2641 case Token::SEMICOLON: | |
| 2642 Consume(Token::SEMICOLON); | |
| 2643 break; | |
| 2644 case Token::RBRACE: | |
| 2645 case Token::EOS: | |
| 2646 break; | |
| 2647 default: | |
| 2648 if (!scanner()->HasAnyLineTerminatorBeforeNext()) { | |
| 2649 ReportMessageAt(function_state_->this_location(), | |
| 2650 is_this | |
| 2651 ? MessageTemplate::kStrongConstructorThis | |
| 2652 : MessageTemplate::kStrongConstructorSuper); | |
| 2653 *ok = false; | |
| 2654 return nullptr; | |
| 2655 } | |
| 2656 } | |
| 2657 return factory()->NewExpressionStatement(expr, pos); | |
| 2658 } | |
| 2659 break; | |
| 2660 | |
| 2661 default: | |
| 2662 break; | |
| 2663 } | |
| 2664 | |
| 2665 bool starts_with_idenfifier = peek_any_identifier(); | |
| 2666 Expression* expr = ParseExpression(true, CHECK_OK); | |
| 2667 if (peek() == Token::COLON && starts_with_idenfifier && expr != NULL && | |
| 2668 expr->AsVariableProxy() != NULL && | |
| 2669 !expr->AsVariableProxy()->is_this()) { | |
| 2670 // Expression is a single identifier, and not, e.g., a parenthesized | |
| 2671 // identifier. | |
| 2672 VariableProxy* var = expr->AsVariableProxy(); | |
| 2673 const AstRawString* label = var->raw_name(); | |
| 2674 // TODO(1240780): We don't check for redeclaration of labels | |
| 2675 // during preparsing since keeping track of the set of active | |
| 2676 // labels requires nontrivial changes to the way scopes are | |
| 2677 // structured. However, these are probably changes we want to | |
| 2678 // make later anyway so we should go back and fix this then. | |
| 2679 if (ContainsLabel(labels, label) || TargetStackContainsLabel(label)) { | |
| 2680 ParserTraits::ReportMessage(MessageTemplate::kLabelRedeclaration, label); | |
| 2681 *ok = false; | |
| 2682 return NULL; | |
| 2683 } | |
| 2684 if (labels == NULL) { | |
| 2685 labels = new(zone()) ZoneList<const AstRawString*>(4, zone()); | |
| 2686 } | |
| 2687 labels->Add(label, zone()); | |
| 2688 // Remove the "ghost" variable that turned out to be a label | |
| 2689 // from the top scope. This way, we don't try to resolve it | |
| 2690 // during the scope processing. | |
| 2691 scope_->RemoveUnresolved(var); | |
| 2692 Expect(Token::COLON, CHECK_OK); | |
| 2693 return ParseStatement(labels, ok); | |
| 2694 } | |
| 2695 | |
| 2696 // If we have an extension, we allow a native function declaration. | |
| 2697 // A native function declaration starts with "native function" with | |
| 2698 // no line-terminator between the two words. | |
| 2699 if (extension_ != NULL && peek() == Token::FUNCTION && | |
| 2700 !scanner()->HasAnyLineTerminatorBeforeNext() && expr != NULL && | |
| 2701 expr->AsVariableProxy() != NULL && | |
| 2702 expr->AsVariableProxy()->raw_name() == | |
| 2703 ast_value_factory()->native_string() && | |
| 2704 !scanner()->literal_contains_escapes()) { | |
| 2705 return ParseNativeDeclaration(ok); | |
| 2706 } | |
| 2707 | |
| 2708 // Parsed expression statement, followed by semicolon. | |
| 2709 // Detect attempts at 'let' declarations in sloppy mode. | |
| 2710 if (!allow_harmony_sloppy_let() && peek() == Token::IDENTIFIER && | |
| 2711 expr->AsVariableProxy() != NULL && | |
| 2712 expr->AsVariableProxy()->raw_name() == | |
| 2713 ast_value_factory()->let_string()) { | |
| 2714 ReportMessage(MessageTemplate::kSloppyLexical, NULL); | |
| 2715 *ok = false; | |
| 2716 return NULL; | |
| 2717 } | |
| 2718 ExpectSemicolon(CHECK_OK); | |
| 2719 return factory()->NewExpressionStatement(expr, pos); | |
| 2720 } | |
| 2721 | |
| 2722 | |
| 2723 IfStatement* Parser::ParseIfStatement(ZoneList<const AstRawString*>* labels, | |
| 2724 bool* ok) { | |
| 2725 // IfStatement :: | |
| 2726 // 'if' '(' Expression ')' Statement ('else' Statement)? | |
| 2727 | |
| 2728 int pos = peek_position(); | |
| 2729 Expect(Token::IF, CHECK_OK); | |
| 2730 Expect(Token::LPAREN, CHECK_OK); | |
| 2731 Expression* condition = ParseExpression(true, CHECK_OK); | |
| 2732 Expect(Token::RPAREN, CHECK_OK); | |
| 2733 Statement* then_statement = ParseSubStatement(labels, CHECK_OK); | |
| 2734 Statement* else_statement = NULL; | |
| 2735 if (peek() == Token::ELSE) { | |
| 2736 Next(); | |
| 2737 else_statement = ParseSubStatement(labels, CHECK_OK); | |
| 2738 } else { | |
| 2739 else_statement = factory()->NewEmptyStatement(RelocInfo::kNoPosition); | |
| 2740 } | |
| 2741 return factory()->NewIfStatement( | |
| 2742 condition, then_statement, else_statement, pos); | |
| 2743 } | |
| 2744 | |
| 2745 | |
| 2746 Statement* Parser::ParseContinueStatement(bool* ok) { | |
| 2747 // ContinueStatement :: | |
| 2748 // 'continue' Identifier? ';' | |
| 2749 | |
| 2750 int pos = peek_position(); | |
| 2751 Expect(Token::CONTINUE, CHECK_OK); | |
| 2752 const AstRawString* label = NULL; | |
| 2753 Token::Value tok = peek(); | |
| 2754 if (!scanner()->HasAnyLineTerminatorBeforeNext() && | |
| 2755 tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) { | |
| 2756 // ECMA allows "eval" or "arguments" as labels even in strict mode. | |
| 2757 label = ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK); | |
| 2758 } | |
| 2759 IterationStatement* target = LookupContinueTarget(label, CHECK_OK); | |
| 2760 if (target == NULL) { | |
| 2761 // Illegal continue statement. | |
| 2762 MessageTemplate::Template message = MessageTemplate::kIllegalContinue; | |
| 2763 if (label != NULL) { | |
| 2764 message = MessageTemplate::kUnknownLabel; | |
| 2765 } | |
| 2766 ParserTraits::ReportMessage(message, label); | |
| 2767 *ok = false; | |
| 2768 return NULL; | |
| 2769 } | |
| 2770 ExpectSemicolon(CHECK_OK); | |
| 2771 return factory()->NewContinueStatement(target, pos); | |
| 2772 } | |
| 2773 | |
| 2774 | |
| 2775 Statement* Parser::ParseBreakStatement(ZoneList<const AstRawString*>* labels, | |
| 2776 bool* ok) { | |
| 2777 // BreakStatement :: | |
| 2778 // 'break' Identifier? ';' | |
| 2779 | |
| 2780 int pos = peek_position(); | |
| 2781 Expect(Token::BREAK, CHECK_OK); | |
| 2782 const AstRawString* label = NULL; | |
| 2783 Token::Value tok = peek(); | |
| 2784 if (!scanner()->HasAnyLineTerminatorBeforeNext() && | |
| 2785 tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) { | |
| 2786 // ECMA allows "eval" or "arguments" as labels even in strict mode. | |
| 2787 label = ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK); | |
| 2788 } | |
| 2789 // Parse labeled break statements that target themselves into | |
| 2790 // empty statements, e.g. 'l1: l2: l3: break l2;' | |
| 2791 if (label != NULL && ContainsLabel(labels, label)) { | |
| 2792 ExpectSemicolon(CHECK_OK); | |
| 2793 return factory()->NewEmptyStatement(pos); | |
| 2794 } | |
| 2795 BreakableStatement* target = NULL; | |
| 2796 target = LookupBreakTarget(label, CHECK_OK); | |
| 2797 if (target == NULL) { | |
| 2798 // Illegal break statement. | |
| 2799 MessageTemplate::Template message = MessageTemplate::kIllegalBreak; | |
| 2800 if (label != NULL) { | |
| 2801 message = MessageTemplate::kUnknownLabel; | |
| 2802 } | |
| 2803 ParserTraits::ReportMessage(message, label); | |
| 2804 *ok = false; | |
| 2805 return NULL; | |
| 2806 } | |
| 2807 ExpectSemicolon(CHECK_OK); | |
| 2808 return factory()->NewBreakStatement(target, pos); | |
| 2809 } | |
| 2810 | |
| 2811 | |
| 2812 Statement* Parser::ParseReturnStatement(bool* ok) { | |
| 2813 // ReturnStatement :: | |
| 2814 // 'return' Expression? ';' | |
| 2815 | |
| 2816 // Consume the return token. It is necessary to do that before | |
| 2817 // reporting any errors on it, because of the way errors are | |
| 2818 // reported (underlining). | |
| 2819 Expect(Token::RETURN, CHECK_OK); | |
| 2820 Scanner::Location loc = scanner()->location(); | |
| 2821 function_state_->set_return_location(loc); | |
| 2822 | |
| 2823 Token::Value tok = peek(); | |
| 2824 Statement* result; | |
| 2825 Expression* return_value; | |
| 2826 if (scanner()->HasAnyLineTerminatorBeforeNext() || | |
| 2827 tok == Token::SEMICOLON || | |
| 2828 tok == Token::RBRACE || | |
| 2829 tok == Token::EOS) { | |
| 2830 if (IsSubclassConstructor(function_state_->kind())) { | |
| 2831 return_value = ThisExpression(scope_, factory(), loc.beg_pos); | |
| 2832 } else { | |
| 2833 return_value = GetLiteralUndefined(position()); | |
| 2834 } | |
| 2835 } else { | |
| 2836 if (is_strong(language_mode()) && | |
| 2837 IsClassConstructor(function_state_->kind())) { | |
| 2838 int pos = peek_position(); | |
| 2839 ReportMessageAt(Scanner::Location(pos, pos + 1), | |
| 2840 MessageTemplate::kStrongConstructorReturnValue); | |
| 2841 *ok = false; | |
| 2842 return NULL; | |
| 2843 } | |
| 2844 | |
| 2845 int pos = peek_position(); | |
| 2846 return_value = ParseExpression(true, CHECK_OK); | |
| 2847 | |
| 2848 if (IsSubclassConstructor(function_state_->kind())) { | |
| 2849 // For subclass constructors we need to return this in case of undefined | |
| 2850 // and throw an exception in case of a non object. | |
| 2851 // | |
| 2852 // return expr; | |
| 2853 // | |
| 2854 // Is rewritten as: | |
| 2855 // | |
| 2856 // return (temp = expr) === undefined ? this : | |
| 2857 // %_IsSpecObject(temp) ? temp : throw new TypeError(...); | |
| 2858 Variable* temp = scope_->NewTemporary( | |
| 2859 ast_value_factory()->empty_string()); | |
| 2860 Assignment* assign = factory()->NewAssignment( | |
| 2861 Token::ASSIGN, factory()->NewVariableProxy(temp), return_value, pos); | |
| 2862 | |
| 2863 Expression* throw_expression = | |
| 2864 NewThrowTypeError(MessageTemplate::kDerivedConstructorReturn, | |
| 2865 ast_value_factory()->empty_string(), pos); | |
| 2866 | |
| 2867 // %_IsSpecObject(temp) | |
| 2868 ZoneList<Expression*>* is_spec_object_args = | |
| 2869 new (zone()) ZoneList<Expression*>(1, zone()); | |
| 2870 is_spec_object_args->Add(factory()->NewVariableProxy(temp), zone()); | |
| 2871 Expression* is_spec_object_call = factory()->NewCallRuntime( | |
| 2872 Runtime::kInlineIsSpecObject, is_spec_object_args, pos); | |
| 2873 | |
| 2874 // %_IsSpecObject(temp) ? temp : throw_expression | |
| 2875 Expression* is_object_conditional = factory()->NewConditional( | |
| 2876 is_spec_object_call, factory()->NewVariableProxy(temp), | |
| 2877 throw_expression, pos); | |
| 2878 | |
| 2879 // temp === undefined | |
| 2880 Expression* is_undefined = factory()->NewCompareOperation( | |
| 2881 Token::EQ_STRICT, assign, | |
| 2882 factory()->NewUndefinedLiteral(RelocInfo::kNoPosition), pos); | |
| 2883 | |
| 2884 // is_undefined ? this : is_object_conditional | |
| 2885 return_value = factory()->NewConditional( | |
| 2886 is_undefined, ThisExpression(scope_, factory(), pos), | |
| 2887 is_object_conditional, pos); | |
| 2888 } | |
| 2889 } | |
| 2890 ExpectSemicolon(CHECK_OK); | |
| 2891 | |
| 2892 if (is_generator()) { | |
| 2893 Expression* generator = factory()->NewVariableProxy( | |
| 2894 function_state_->generator_object_variable()); | |
| 2895 Expression* yield = factory()->NewYield( | |
| 2896 generator, return_value, Yield::kFinal, loc.beg_pos); | |
| 2897 result = factory()->NewExpressionStatement(yield, loc.beg_pos); | |
| 2898 } else { | |
| 2899 result = factory()->NewReturnStatement(return_value, loc.beg_pos); | |
| 2900 } | |
| 2901 | |
| 2902 Scope* decl_scope = scope_->DeclarationScope(); | |
| 2903 if (decl_scope->is_script_scope() || decl_scope->is_eval_scope()) { | |
| 2904 ReportMessageAt(loc, MessageTemplate::kIllegalReturn); | |
| 2905 *ok = false; | |
| 2906 return NULL; | |
| 2907 } | |
| 2908 return result; | |
| 2909 } | |
| 2910 | |
| 2911 | |
| 2912 Statement* Parser::ParseWithStatement(ZoneList<const AstRawString*>* labels, | |
| 2913 bool* ok) { | |
| 2914 // WithStatement :: | |
| 2915 // 'with' '(' Expression ')' Statement | |
| 2916 | |
| 2917 Expect(Token::WITH, CHECK_OK); | |
| 2918 int pos = position(); | |
| 2919 | |
| 2920 if (is_strict(language_mode())) { | |
| 2921 ReportMessage(MessageTemplate::kStrictWith); | |
| 2922 *ok = false; | |
| 2923 return NULL; | |
| 2924 } | |
| 2925 | |
| 2926 Expect(Token::LPAREN, CHECK_OK); | |
| 2927 Expression* expr = ParseExpression(true, CHECK_OK); | |
| 2928 Expect(Token::RPAREN, CHECK_OK); | |
| 2929 | |
| 2930 scope_->DeclarationScope()->RecordWithStatement(); | |
| 2931 Scope* with_scope = NewScope(scope_, WITH_SCOPE); | |
| 2932 Block* body; | |
| 2933 { BlockState block_state(&scope_, with_scope); | |
| 2934 with_scope->set_start_position(scanner()->peek_location().beg_pos); | |
| 2935 | |
| 2936 // The body of the with statement must be enclosed in an additional | |
| 2937 // lexical scope in case the body is a FunctionDeclaration. | |
| 2938 body = factory()->NewBlock(labels, 1, false, RelocInfo::kNoPosition); | |
| 2939 Scope* block_scope = NewScope(scope_, BLOCK_SCOPE); | |
| 2940 block_scope->set_start_position(scanner()->location().beg_pos); | |
| 2941 { | |
| 2942 BlockState block_state(&scope_, block_scope); | |
| 2943 Target target(&this->target_stack_, body); | |
| 2944 Statement* stmt = ParseSubStatement(labels, CHECK_OK); | |
| 2945 body->statements()->Add(stmt, zone()); | |
| 2946 block_scope->set_end_position(scanner()->location().end_pos); | |
| 2947 block_scope = block_scope->FinalizeBlockScope(); | |
| 2948 body->set_scope(block_scope); | |
| 2949 } | |
| 2950 | |
| 2951 with_scope->set_end_position(scanner()->location().end_pos); | |
| 2952 } | |
| 2953 return factory()->NewWithStatement(with_scope, expr, body, pos); | |
| 2954 } | |
| 2955 | |
| 2956 | |
| 2957 CaseClause* Parser::ParseCaseClause(bool* default_seen_ptr, bool* ok) { | |
| 2958 // CaseClause :: | |
| 2959 // 'case' Expression ':' StatementList | |
| 2960 // 'default' ':' StatementList | |
| 2961 | |
| 2962 Expression* label = NULL; // NULL expression indicates default case | |
| 2963 if (peek() == Token::CASE) { | |
| 2964 Expect(Token::CASE, CHECK_OK); | |
| 2965 label = ParseExpression(true, CHECK_OK); | |
| 2966 } else { | |
| 2967 Expect(Token::DEFAULT, CHECK_OK); | |
| 2968 if (*default_seen_ptr) { | |
| 2969 ReportMessage(MessageTemplate::kMultipleDefaultsInSwitch); | |
| 2970 *ok = false; | |
| 2971 return NULL; | |
| 2972 } | |
| 2973 *default_seen_ptr = true; | |
| 2974 } | |
| 2975 Expect(Token::COLON, CHECK_OK); | |
| 2976 int pos = position(); | |
| 2977 ZoneList<Statement*>* statements = | |
| 2978 new(zone()) ZoneList<Statement*>(5, zone()); | |
| 2979 Statement* stat = NULL; | |
| 2980 while (peek() != Token::CASE && | |
| 2981 peek() != Token::DEFAULT && | |
| 2982 peek() != Token::RBRACE) { | |
| 2983 stat = ParseStatementListItem(CHECK_OK); | |
| 2984 statements->Add(stat, zone()); | |
| 2985 } | |
| 2986 if (is_strong(language_mode()) && stat != NULL && !stat->IsJump() && | |
| 2987 peek() != Token::RBRACE) { | |
| 2988 ReportMessageAt(scanner()->location(), | |
| 2989 MessageTemplate::kStrongSwitchFallthrough); | |
| 2990 *ok = false; | |
| 2991 return NULL; | |
| 2992 } | |
| 2993 return factory()->NewCaseClause(label, statements, pos); | |
| 2994 } | |
| 2995 | |
| 2996 | |
| 2997 Statement* Parser::ParseSwitchStatement(ZoneList<const AstRawString*>* labels, | |
| 2998 bool* ok) { | |
| 2999 // SwitchStatement :: | |
| 3000 // 'switch' '(' Expression ')' '{' CaseClause* '}' | |
| 3001 // In order to get the CaseClauses to execute in their own lexical scope, | |
| 3002 // but without requiring downstream code to have special scope handling | |
| 3003 // code for switch statements, desugar into blocks as follows: | |
| 3004 // { // To group the statements--harmless to evaluate Expression in scope | |
| 3005 // .tag_variable = Expression; | |
| 3006 // { // To give CaseClauses a scope | |
| 3007 // switch (.tag_variable) { CaseClause* } | |
| 3008 // } | |
| 3009 // } | |
| 3010 | |
| 3011 Block* switch_block = | |
| 3012 factory()->NewBlock(NULL, 2, false, RelocInfo::kNoPosition); | |
| 3013 int switch_pos = peek_position(); | |
| 3014 | |
| 3015 Expect(Token::SWITCH, CHECK_OK); | |
| 3016 Expect(Token::LPAREN, CHECK_OK); | |
| 3017 Expression* tag = ParseExpression(true, CHECK_OK); | |
| 3018 Expect(Token::RPAREN, CHECK_OK); | |
| 3019 | |
| 3020 Variable* tag_variable = | |
| 3021 scope_->NewTemporary(ast_value_factory()->dot_switch_tag_string()); | |
| 3022 Assignment* tag_assign = factory()->NewAssignment( | |
| 3023 Token::ASSIGN, factory()->NewVariableProxy(tag_variable), tag, | |
| 3024 tag->position()); | |
| 3025 Statement* tag_statement = | |
| 3026 factory()->NewExpressionStatement(tag_assign, RelocInfo::kNoPosition); | |
| 3027 switch_block->statements()->Add(tag_statement, zone()); | |
| 3028 | |
| 3029 // make statement: undefined; | |
| 3030 // This is needed so the tag isn't returned as the value, in case the switch | |
| 3031 // statements don't have a value. | |
| 3032 switch_block->statements()->Add( | |
| 3033 factory()->NewExpressionStatement( | |
| 3034 factory()->NewUndefinedLiteral(RelocInfo::kNoPosition), | |
| 3035 RelocInfo::kNoPosition), | |
| 3036 zone()); | |
| 3037 | |
| 3038 Block* cases_block = | |
| 3039 factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition); | |
| 3040 Scope* cases_scope = NewScope(scope_, BLOCK_SCOPE); | |
| 3041 cases_scope->SetNonlinear(); | |
| 3042 | |
| 3043 SwitchStatement* switch_statement = | |
| 3044 factory()->NewSwitchStatement(labels, switch_pos); | |
| 3045 | |
| 3046 cases_scope->set_start_position(scanner()->location().beg_pos); | |
| 3047 { | |
| 3048 BlockState cases_block_state(&scope_, cases_scope); | |
| 3049 Target target(&this->target_stack_, switch_statement); | |
| 3050 | |
| 3051 Expression* tag_read = factory()->NewVariableProxy(tag_variable); | |
| 3052 | |
| 3053 bool default_seen = false; | |
| 3054 ZoneList<CaseClause*>* cases = | |
| 3055 new (zone()) ZoneList<CaseClause*>(4, zone()); | |
| 3056 Expect(Token::LBRACE, CHECK_OK); | |
| 3057 while (peek() != Token::RBRACE) { | |
| 3058 CaseClause* clause = ParseCaseClause(&default_seen, CHECK_OK); | |
| 3059 cases->Add(clause, zone()); | |
| 3060 } | |
| 3061 switch_statement->Initialize(tag_read, cases); | |
| 3062 cases_block->statements()->Add(switch_statement, zone()); | |
| 3063 } | |
| 3064 Expect(Token::RBRACE, CHECK_OK); | |
| 3065 | |
| 3066 cases_scope->set_end_position(scanner()->location().end_pos); | |
| 3067 cases_scope = cases_scope->FinalizeBlockScope(); | |
| 3068 cases_block->set_scope(cases_scope); | |
| 3069 | |
| 3070 switch_block->statements()->Add(cases_block, zone()); | |
| 3071 | |
| 3072 return switch_block; | |
| 3073 } | |
| 3074 | |
| 3075 | |
| 3076 Statement* Parser::ParseThrowStatement(bool* ok) { | |
| 3077 // ThrowStatement :: | |
| 3078 // 'throw' Expression ';' | |
| 3079 | |
| 3080 Expect(Token::THROW, CHECK_OK); | |
| 3081 int pos = position(); | |
| 3082 if (scanner()->HasAnyLineTerminatorBeforeNext()) { | |
| 3083 ReportMessage(MessageTemplate::kNewlineAfterThrow); | |
| 3084 *ok = false; | |
| 3085 return NULL; | |
| 3086 } | |
| 3087 Expression* exception = ParseExpression(true, CHECK_OK); | |
| 3088 ExpectSemicolon(CHECK_OK); | |
| 3089 | |
| 3090 return factory()->NewExpressionStatement( | |
| 3091 factory()->NewThrow(exception, pos), pos); | |
| 3092 } | |
| 3093 | |
| 3094 | |
| 3095 TryStatement* Parser::ParseTryStatement(bool* ok) { | |
| 3096 // TryStatement :: | |
| 3097 // 'try' Block Catch | |
| 3098 // 'try' Block Finally | |
| 3099 // 'try' Block Catch Finally | |
| 3100 // | |
| 3101 // Catch :: | |
| 3102 // 'catch' '(' Identifier ')' Block | |
| 3103 // | |
| 3104 // Finally :: | |
| 3105 // 'finally' Block | |
| 3106 | |
| 3107 Expect(Token::TRY, CHECK_OK); | |
| 3108 int pos = position(); | |
| 3109 | |
| 3110 Block* try_block = ParseBlock(NULL, CHECK_OK); | |
| 3111 | |
| 3112 Token::Value tok = peek(); | |
| 3113 if (tok != Token::CATCH && tok != Token::FINALLY) { | |
| 3114 ReportMessage(MessageTemplate::kNoCatchOrFinally); | |
| 3115 *ok = false; | |
| 3116 return NULL; | |
| 3117 } | |
| 3118 | |
| 3119 Scope* catch_scope = NULL; | |
| 3120 Variable* catch_variable = NULL; | |
| 3121 Block* catch_block = NULL; | |
| 3122 if (tok == Token::CATCH) { | |
| 3123 Consume(Token::CATCH); | |
| 3124 | |
| 3125 Expect(Token::LPAREN, CHECK_OK); | |
| 3126 catch_scope = NewScope(scope_, CATCH_SCOPE); | |
| 3127 catch_scope->set_start_position(scanner()->location().beg_pos); | |
| 3128 | |
| 3129 ExpressionClassifier pattern_classifier; | |
| 3130 Expression* pattern = ParsePrimaryExpression(&pattern_classifier, CHECK_OK); | |
| 3131 ValidateBindingPattern(&pattern_classifier, CHECK_OK); | |
| 3132 | |
| 3133 const AstRawString* name = ast_value_factory()->dot_catch_string(); | |
| 3134 bool is_simple = pattern->IsVariableProxy(); | |
| 3135 if (is_simple) { | |
| 3136 auto proxy = pattern->AsVariableProxy(); | |
| 3137 scope_->RemoveUnresolved(proxy); | |
| 3138 name = proxy->raw_name(); | |
| 3139 } | |
| 3140 | |
| 3141 catch_variable = catch_scope->DeclareLocal(name, VAR, kCreatedInitialized, | |
| 3142 Variable::NORMAL); | |
| 3143 | |
| 3144 Expect(Token::RPAREN, CHECK_OK); | |
| 3145 | |
| 3146 { | |
| 3147 BlockState block_state(&scope_, catch_scope); | |
| 3148 | |
| 3149 // TODO(adamk): Make a version of ParseBlock that takes a scope and | |
| 3150 // a block. | |
| 3151 catch_block = | |
| 3152 factory()->NewBlock(nullptr, 16, false, RelocInfo::kNoPosition); | |
| 3153 Scope* block_scope = NewScope(scope_, BLOCK_SCOPE); | |
| 3154 | |
| 3155 block_scope->set_start_position(scanner()->location().beg_pos); | |
| 3156 { | |
| 3157 BlockState block_state(&scope_, block_scope); | |
| 3158 Target target(&this->target_stack_, catch_block); | |
| 3159 | |
| 3160 if (!is_simple) { | |
| 3161 DeclarationDescriptor descriptor; | |
| 3162 descriptor.declaration_kind = DeclarationDescriptor::NORMAL; | |
| 3163 descriptor.parser = this; | |
| 3164 descriptor.declaration_scope = scope_; | |
| 3165 descriptor.scope = scope_; | |
| 3166 descriptor.hoist_scope = nullptr; | |
| 3167 descriptor.mode = LET; | |
| 3168 descriptor.is_const = false; | |
| 3169 descriptor.needs_init = true; | |
| 3170 descriptor.declaration_pos = pattern->position(); | |
| 3171 descriptor.initialization_pos = pattern->position(); | |
| 3172 | |
| 3173 DeclarationParsingResult::Declaration decl( | |
| 3174 pattern, pattern->position(), | |
| 3175 factory()->NewVariableProxy(catch_variable)); | |
| 3176 | |
| 3177 PatternRewriter::DeclareAndInitializeVariables( | |
| 3178 catch_block, &descriptor, &decl, nullptr, CHECK_OK); | |
| 3179 } | |
| 3180 | |
| 3181 Expect(Token::LBRACE, CHECK_OK); | |
| 3182 while (peek() != Token::RBRACE) { | |
| 3183 Statement* stat = ParseStatementListItem(CHECK_OK); | |
| 3184 if (stat && !stat->IsEmpty()) { | |
| 3185 catch_block->statements()->Add(stat, zone()); | |
| 3186 } | |
| 3187 } | |
| 3188 Consume(Token::RBRACE); | |
| 3189 } | |
| 3190 block_scope->set_end_position(scanner()->location().end_pos); | |
| 3191 block_scope = block_scope->FinalizeBlockScope(); | |
| 3192 catch_block->set_scope(block_scope); | |
| 3193 } | |
| 3194 | |
| 3195 catch_scope->set_end_position(scanner()->location().end_pos); | |
| 3196 tok = peek(); | |
| 3197 } | |
| 3198 | |
| 3199 Block* finally_block = NULL; | |
| 3200 DCHECK(tok == Token::FINALLY || catch_block != NULL); | |
| 3201 if (tok == Token::FINALLY) { | |
| 3202 Consume(Token::FINALLY); | |
| 3203 finally_block = ParseBlock(NULL, CHECK_OK); | |
| 3204 } | |
| 3205 | |
| 3206 // Simplify the AST nodes by converting: | |
| 3207 // 'try B0 catch B1 finally B2' | |
| 3208 // to: | |
| 3209 // 'try { try B0 catch B1 } finally B2' | |
| 3210 | |
| 3211 if (catch_block != NULL && finally_block != NULL) { | |
| 3212 // If we have both, create an inner try/catch. | |
| 3213 DCHECK(catch_scope != NULL && catch_variable != NULL); | |
| 3214 TryCatchStatement* statement = | |
| 3215 factory()->NewTryCatchStatement(try_block, catch_scope, catch_variable, | |
| 3216 catch_block, RelocInfo::kNoPosition); | |
| 3217 try_block = factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition); | |
| 3218 try_block->statements()->Add(statement, zone()); | |
| 3219 catch_block = NULL; // Clear to indicate it's been handled. | |
| 3220 } | |
| 3221 | |
| 3222 TryStatement* result = NULL; | |
| 3223 if (catch_block != NULL) { | |
| 3224 DCHECK(finally_block == NULL); | |
| 3225 DCHECK(catch_scope != NULL && catch_variable != NULL); | |
| 3226 result = factory()->NewTryCatchStatement(try_block, catch_scope, | |
| 3227 catch_variable, catch_block, pos); | |
| 3228 } else { | |
| 3229 DCHECK(finally_block != NULL); | |
| 3230 result = factory()->NewTryFinallyStatement(try_block, finally_block, pos); | |
| 3231 } | |
| 3232 | |
| 3233 return result; | |
| 3234 } | |
| 3235 | |
| 3236 | |
| 3237 DoWhileStatement* Parser::ParseDoWhileStatement( | |
| 3238 ZoneList<const AstRawString*>* labels, bool* ok) { | |
| 3239 // DoStatement :: | |
| 3240 // 'do' Statement 'while' '(' Expression ')' ';' | |
| 3241 | |
| 3242 DoWhileStatement* loop = | |
| 3243 factory()->NewDoWhileStatement(labels, peek_position()); | |
| 3244 Target target(&this->target_stack_, loop); | |
| 3245 | |
| 3246 Expect(Token::DO, CHECK_OK); | |
| 3247 Statement* body = ParseSubStatement(NULL, CHECK_OK); | |
| 3248 Expect(Token::WHILE, CHECK_OK); | |
| 3249 Expect(Token::LPAREN, CHECK_OK); | |
| 3250 | |
| 3251 Expression* cond = ParseExpression(true, CHECK_OK); | |
| 3252 Expect(Token::RPAREN, CHECK_OK); | |
| 3253 | |
| 3254 // Allow do-statements to be terminated with and without | |
| 3255 // semi-colons. This allows code such as 'do;while(0)return' to | |
| 3256 // parse, which would not be the case if we had used the | |
| 3257 // ExpectSemicolon() functionality here. | |
| 3258 if (peek() == Token::SEMICOLON) Consume(Token::SEMICOLON); | |
| 3259 | |
| 3260 if (loop != NULL) loop->Initialize(cond, body); | |
| 3261 return loop; | |
| 3262 } | |
| 3263 | |
| 3264 | |
| 3265 WhileStatement* Parser::ParseWhileStatement( | |
| 3266 ZoneList<const AstRawString*>* labels, bool* ok) { | |
| 3267 // WhileStatement :: | |
| 3268 // 'while' '(' Expression ')' Statement | |
| 3269 | |
| 3270 WhileStatement* loop = factory()->NewWhileStatement(labels, peek_position()); | |
| 3271 Target target(&this->target_stack_, loop); | |
| 3272 | |
| 3273 Expect(Token::WHILE, CHECK_OK); | |
| 3274 Expect(Token::LPAREN, CHECK_OK); | |
| 3275 Expression* cond = ParseExpression(true, CHECK_OK); | |
| 3276 Expect(Token::RPAREN, CHECK_OK); | |
| 3277 Statement* body = ParseSubStatement(NULL, CHECK_OK); | |
| 3278 | |
| 3279 if (loop != NULL) loop->Initialize(cond, body); | |
| 3280 return loop; | |
| 3281 } | |
| 3282 | |
| 3283 | |
| 3284 // !%_IsSpecObject(result = iterator.next()) && | |
| 3285 // %ThrowIteratorResultNotAnObject(result) | |
| 3286 Expression* Parser::BuildIteratorNextResult(Expression* iterator, | |
| 3287 Variable* result, int pos) { | |
| 3288 Expression* next_literal = factory()->NewStringLiteral( | |
| 3289 ast_value_factory()->next_string(), RelocInfo::kNoPosition); | |
| 3290 Expression* next_property = | |
| 3291 factory()->NewProperty(iterator, next_literal, RelocInfo::kNoPosition); | |
| 3292 ZoneList<Expression*>* next_arguments = | |
| 3293 new (zone()) ZoneList<Expression*>(0, zone()); | |
| 3294 Expression* next_call = | |
| 3295 factory()->NewCall(next_property, next_arguments, pos); | |
| 3296 Expression* result_proxy = factory()->NewVariableProxy(result); | |
| 3297 Expression* left = | |
| 3298 factory()->NewAssignment(Token::ASSIGN, result_proxy, next_call, pos); | |
| 3299 | |
| 3300 // %_IsSpecObject(...) | |
| 3301 ZoneList<Expression*>* is_spec_object_args = | |
| 3302 new (zone()) ZoneList<Expression*>(1, zone()); | |
| 3303 is_spec_object_args->Add(left, zone()); | |
| 3304 Expression* is_spec_object_call = factory()->NewCallRuntime( | |
| 3305 Runtime::kInlineIsSpecObject, is_spec_object_args, pos); | |
| 3306 | |
| 3307 // %ThrowIteratorResultNotAnObject(result) | |
| 3308 Expression* result_proxy_again = factory()->NewVariableProxy(result); | |
| 3309 ZoneList<Expression*>* throw_arguments = | |
| 3310 new (zone()) ZoneList<Expression*>(1, zone()); | |
| 3311 throw_arguments->Add(result_proxy_again, zone()); | |
| 3312 Expression* throw_call = factory()->NewCallRuntime( | |
| 3313 Runtime::kThrowIteratorResultNotAnObject, throw_arguments, pos); | |
| 3314 | |
| 3315 return factory()->NewBinaryOperation( | |
| 3316 Token::AND, | |
| 3317 factory()->NewUnaryOperation(Token::NOT, is_spec_object_call, pos), | |
| 3318 throw_call, pos); | |
| 3319 } | |
| 3320 | |
| 3321 | |
| 3322 void Parser::InitializeForEachStatement(ForEachStatement* stmt, | |
| 3323 Expression* each, | |
| 3324 Expression* subject, | |
| 3325 Statement* body) { | |
| 3326 ForOfStatement* for_of = stmt->AsForOfStatement(); | |
| 3327 | |
| 3328 if (for_of != NULL) { | |
| 3329 Variable* iterator = scope_->NewTemporary( | |
| 3330 ast_value_factory()->dot_iterator_string()); | |
| 3331 Variable* result = scope_->NewTemporary( | |
| 3332 ast_value_factory()->dot_result_string()); | |
| 3333 | |
| 3334 Expression* assign_iterator; | |
| 3335 Expression* next_result; | |
| 3336 Expression* result_done; | |
| 3337 Expression* assign_each; | |
| 3338 | |
| 3339 // iterator = subject[Symbol.iterator]() | |
| 3340 assign_iterator = factory()->NewAssignment( | |
| 3341 Token::ASSIGN, factory()->NewVariableProxy(iterator), | |
| 3342 GetIterator(subject, factory()), subject->position()); | |
| 3343 | |
| 3344 // !%_IsSpecObject(result = iterator.next()) && | |
| 3345 // %ThrowIteratorResultNotAnObject(result) | |
| 3346 { | |
| 3347 // result = iterator.next() | |
| 3348 Expression* iterator_proxy = factory()->NewVariableProxy(iterator); | |
| 3349 next_result = | |
| 3350 BuildIteratorNextResult(iterator_proxy, result, subject->position()); | |
| 3351 } | |
| 3352 | |
| 3353 // result.done | |
| 3354 { | |
| 3355 Expression* done_literal = factory()->NewStringLiteral( | |
| 3356 ast_value_factory()->done_string(), RelocInfo::kNoPosition); | |
| 3357 Expression* result_proxy = factory()->NewVariableProxy(result); | |
| 3358 result_done = factory()->NewProperty( | |
| 3359 result_proxy, done_literal, RelocInfo::kNoPosition); | |
| 3360 } | |
| 3361 | |
| 3362 // each = result.value | |
| 3363 { | |
| 3364 Expression* value_literal = factory()->NewStringLiteral( | |
| 3365 ast_value_factory()->value_string(), RelocInfo::kNoPosition); | |
| 3366 Expression* result_proxy = factory()->NewVariableProxy(result); | |
| 3367 Expression* result_value = factory()->NewProperty( | |
| 3368 result_proxy, value_literal, RelocInfo::kNoPosition); | |
| 3369 assign_each = factory()->NewAssignment(Token::ASSIGN, each, result_value, | |
| 3370 RelocInfo::kNoPosition); | |
| 3371 } | |
| 3372 | |
| 3373 for_of->Initialize(each, subject, body, | |
| 3374 assign_iterator, | |
| 3375 next_result, | |
| 3376 result_done, | |
| 3377 assign_each); | |
| 3378 } else { | |
| 3379 stmt->Initialize(each, subject, body); | |
| 3380 } | |
| 3381 } | |
| 3382 | |
| 3383 | |
| 3384 Statement* Parser::DesugarLexicalBindingsInForStatement( | |
| 3385 Scope* inner_scope, bool is_const, ZoneList<const AstRawString*>* names, | |
| 3386 ForStatement* loop, Statement* init, Expression* cond, Statement* next, | |
| 3387 Statement* body, bool* ok) { | |
| 3388 // ES6 13.7.4.8 specifies that on each loop iteration the let variables are | |
| 3389 // copied into a new environment. Moreover, the "next" statement must be | |
| 3390 // evaluated not in the environment of the just completed iteration but in | |
| 3391 // that of the upcoming one. We achieve this with the following desugaring. | |
| 3392 // Extra care is needed to preserve the completion value of the original loop. | |
| 3393 // | |
| 3394 // We are given a for statement of the form | |
| 3395 // | |
| 3396 // labels: for (let/const x = i; cond; next) body | |
| 3397 // | |
| 3398 // and rewrite it as follows. Here we write {{ ... }} for init-blocks, ie., | |
| 3399 // blocks whose ignore_completion_value_ flag is set. | |
| 3400 // | |
| 3401 // { | |
| 3402 // let/const x = i; | |
| 3403 // temp_x = x; | |
| 3404 // first = 1; | |
| 3405 // undefined; | |
| 3406 // outer: for (;;) { | |
| 3407 // let/const x = temp_x; | |
| 3408 // {{ if (first == 1) { | |
| 3409 // first = 0; | |
| 3410 // } else { | |
| 3411 // next; | |
| 3412 // } | |
| 3413 // flag = 1; | |
| 3414 // if (!cond) break; | |
| 3415 // }} | |
| 3416 // labels: for (; flag == 1; flag = 0, temp_x = x) { | |
| 3417 // body | |
| 3418 // } | |
| 3419 // {{ if (flag == 1) // Body used break. | |
| 3420 // break; | |
| 3421 // }} | |
| 3422 // } | |
| 3423 // } | |
| 3424 | |
| 3425 DCHECK(names->length() > 0); | |
| 3426 Scope* for_scope = scope_; | |
| 3427 ZoneList<Variable*> temps(names->length(), zone()); | |
| 3428 | |
| 3429 Block* outer_block = factory()->NewBlock(NULL, names->length() + 4, false, | |
| 3430 RelocInfo::kNoPosition); | |
| 3431 | |
| 3432 // Add statement: let/const x = i. | |
| 3433 outer_block->statements()->Add(init, zone()); | |
| 3434 | |
| 3435 const AstRawString* temp_name = ast_value_factory()->dot_for_string(); | |
| 3436 | |
| 3437 // For each lexical variable x: | |
| 3438 // make statement: temp_x = x. | |
| 3439 for (int i = 0; i < names->length(); i++) { | |
| 3440 VariableProxy* proxy = NewUnresolved(names->at(i), LET); | |
| 3441 Variable* temp = scope_->NewTemporary(temp_name); | |
| 3442 VariableProxy* temp_proxy = factory()->NewVariableProxy(temp); | |
| 3443 Assignment* assignment = factory()->NewAssignment( | |
| 3444 Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition); | |
| 3445 Statement* assignment_statement = factory()->NewExpressionStatement( | |
| 3446 assignment, RelocInfo::kNoPosition); | |
| 3447 outer_block->statements()->Add(assignment_statement, zone()); | |
| 3448 temps.Add(temp, zone()); | |
| 3449 } | |
| 3450 | |
| 3451 Variable* first = NULL; | |
| 3452 // Make statement: first = 1. | |
| 3453 if (next) { | |
| 3454 first = scope_->NewTemporary(temp_name); | |
| 3455 VariableProxy* first_proxy = factory()->NewVariableProxy(first); | |
| 3456 Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition); | |
| 3457 Assignment* assignment = factory()->NewAssignment( | |
| 3458 Token::ASSIGN, first_proxy, const1, RelocInfo::kNoPosition); | |
| 3459 Statement* assignment_statement = | |
| 3460 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition); | |
| 3461 outer_block->statements()->Add(assignment_statement, zone()); | |
| 3462 } | |
| 3463 | |
| 3464 // make statement: undefined; | |
| 3465 outer_block->statements()->Add( | |
| 3466 factory()->NewExpressionStatement( | |
| 3467 factory()->NewUndefinedLiteral(RelocInfo::kNoPosition), | |
| 3468 RelocInfo::kNoPosition), | |
| 3469 zone()); | |
| 3470 | |
| 3471 // Make statement: outer: for (;;) | |
| 3472 // Note that we don't actually create the label, or set this loop up as an | |
| 3473 // explicit break target, instead handing it directly to those nodes that | |
| 3474 // need to know about it. This should be safe because we don't run any code | |
| 3475 // in this function that looks up break targets. | |
| 3476 ForStatement* outer_loop = | |
| 3477 factory()->NewForStatement(NULL, RelocInfo::kNoPosition); | |
| 3478 outer_block->statements()->Add(outer_loop, zone()); | |
| 3479 | |
| 3480 outer_block->set_scope(for_scope); | |
| 3481 scope_ = inner_scope; | |
| 3482 | |
| 3483 Block* inner_block = | |
| 3484 factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition); | |
| 3485 Block* ignore_completion_block = factory()->NewBlock( | |
| 3486 NULL, names->length() + 3, true, RelocInfo::kNoPosition); | |
| 3487 ZoneList<Variable*> inner_vars(names->length(), zone()); | |
| 3488 // For each let variable x: | |
| 3489 // make statement: let/const x = temp_x. | |
| 3490 VariableMode mode = is_const ? CONST : LET; | |
| 3491 for (int i = 0; i < names->length(); i++) { | |
| 3492 VariableProxy* proxy = NewUnresolved(names->at(i), mode); | |
| 3493 Declaration* declaration = factory()->NewVariableDeclaration( | |
| 3494 proxy, mode, scope_, RelocInfo::kNoPosition); | |
| 3495 Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK); | |
| 3496 inner_vars.Add(declaration->proxy()->var(), zone()); | |
| 3497 VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i)); | |
| 3498 Assignment* assignment = factory()->NewAssignment( | |
| 3499 Token::INIT, proxy, temp_proxy, RelocInfo::kNoPosition); | |
| 3500 Statement* assignment_statement = | |
| 3501 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition); | |
| 3502 DCHECK(init->position() != RelocInfo::kNoPosition); | |
| 3503 proxy->var()->set_initializer_position(init->position()); | |
| 3504 ignore_completion_block->statements()->Add(assignment_statement, zone()); | |
| 3505 } | |
| 3506 | |
| 3507 // Make statement: if (first == 1) { first = 0; } else { next; } | |
| 3508 if (next) { | |
| 3509 DCHECK(first); | |
| 3510 Expression* compare = NULL; | |
| 3511 // Make compare expression: first == 1. | |
| 3512 { | |
| 3513 Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition); | |
| 3514 VariableProxy* first_proxy = factory()->NewVariableProxy(first); | |
| 3515 compare = factory()->NewCompareOperation(Token::EQ, first_proxy, const1, | |
| 3516 RelocInfo::kNoPosition); | |
| 3517 } | |
| 3518 Statement* clear_first = NULL; | |
| 3519 // Make statement: first = 0. | |
| 3520 { | |
| 3521 VariableProxy* first_proxy = factory()->NewVariableProxy(first); | |
| 3522 Expression* const0 = factory()->NewSmiLiteral(0, RelocInfo::kNoPosition); | |
| 3523 Assignment* assignment = factory()->NewAssignment( | |
| 3524 Token::ASSIGN, first_proxy, const0, RelocInfo::kNoPosition); | |
| 3525 clear_first = | |
| 3526 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition); | |
| 3527 } | |
| 3528 Statement* clear_first_or_next = factory()->NewIfStatement( | |
| 3529 compare, clear_first, next, RelocInfo::kNoPosition); | |
| 3530 ignore_completion_block->statements()->Add(clear_first_or_next, zone()); | |
| 3531 } | |
| 3532 | |
| 3533 Variable* flag = scope_->NewTemporary(temp_name); | |
| 3534 // Make statement: flag = 1. | |
| 3535 { | |
| 3536 VariableProxy* flag_proxy = factory()->NewVariableProxy(flag); | |
| 3537 Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition); | |
| 3538 Assignment* assignment = factory()->NewAssignment( | |
| 3539 Token::ASSIGN, flag_proxy, const1, RelocInfo::kNoPosition); | |
| 3540 Statement* assignment_statement = | |
| 3541 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition); | |
| 3542 ignore_completion_block->statements()->Add(assignment_statement, zone()); | |
| 3543 } | |
| 3544 | |
| 3545 // Make statement: if (!cond) break. | |
| 3546 if (cond) { | |
| 3547 Statement* stop = | |
| 3548 factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition); | |
| 3549 Statement* noop = factory()->NewEmptyStatement(RelocInfo::kNoPosition); | |
| 3550 ignore_completion_block->statements()->Add( | |
| 3551 factory()->NewIfStatement(cond, noop, stop, cond->position()), zone()); | |
| 3552 } | |
| 3553 | |
| 3554 inner_block->statements()->Add(ignore_completion_block, zone()); | |
| 3555 // Make cond expression for main loop: flag == 1. | |
| 3556 Expression* flag_cond = NULL; | |
| 3557 { | |
| 3558 Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition); | |
| 3559 VariableProxy* flag_proxy = factory()->NewVariableProxy(flag); | |
| 3560 flag_cond = factory()->NewCompareOperation(Token::EQ, flag_proxy, const1, | |
| 3561 RelocInfo::kNoPosition); | |
| 3562 } | |
| 3563 | |
| 3564 // Create chain of expressions "flag = 0, temp_x = x, ..." | |
| 3565 Statement* compound_next_statement = NULL; | |
| 3566 { | |
| 3567 Expression* compound_next = NULL; | |
| 3568 // Make expression: flag = 0. | |
| 3569 { | |
| 3570 VariableProxy* flag_proxy = factory()->NewVariableProxy(flag); | |
| 3571 Expression* const0 = factory()->NewSmiLiteral(0, RelocInfo::kNoPosition); | |
| 3572 compound_next = factory()->NewAssignment(Token::ASSIGN, flag_proxy, | |
| 3573 const0, RelocInfo::kNoPosition); | |
| 3574 } | |
| 3575 | |
| 3576 // Make the comma-separated list of temp_x = x assignments. | |
| 3577 int inner_var_proxy_pos = scanner()->location().beg_pos; | |
| 3578 for (int i = 0; i < names->length(); i++) { | |
| 3579 VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i)); | |
| 3580 VariableProxy* proxy = | |
| 3581 factory()->NewVariableProxy(inner_vars.at(i), inner_var_proxy_pos); | |
| 3582 Assignment* assignment = factory()->NewAssignment( | |
| 3583 Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition); | |
| 3584 compound_next = factory()->NewBinaryOperation( | |
| 3585 Token::COMMA, compound_next, assignment, RelocInfo::kNoPosition); | |
| 3586 } | |
| 3587 | |
| 3588 compound_next_statement = factory()->NewExpressionStatement( | |
| 3589 compound_next, RelocInfo::kNoPosition); | |
| 3590 } | |
| 3591 | |
| 3592 // Make statement: labels: for (; flag == 1; flag = 0, temp_x = x) | |
| 3593 // Note that we re-use the original loop node, which retains its labels | |
| 3594 // and ensures that any break or continue statements in body point to | |
| 3595 // the right place. | |
| 3596 loop->Initialize(NULL, flag_cond, compound_next_statement, body); | |
| 3597 inner_block->statements()->Add(loop, zone()); | |
| 3598 | |
| 3599 // Make statement: {{if (flag == 1) break;}} | |
| 3600 { | |
| 3601 Expression* compare = NULL; | |
| 3602 // Make compare expresion: flag == 1. | |
| 3603 { | |
| 3604 Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition); | |
| 3605 VariableProxy* flag_proxy = factory()->NewVariableProxy(flag); | |
| 3606 compare = factory()->NewCompareOperation(Token::EQ, flag_proxy, const1, | |
| 3607 RelocInfo::kNoPosition); | |
| 3608 } | |
| 3609 Statement* stop = | |
| 3610 factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition); | |
| 3611 Statement* empty = factory()->NewEmptyStatement(RelocInfo::kNoPosition); | |
| 3612 Statement* if_flag_break = | |
| 3613 factory()->NewIfStatement(compare, stop, empty, RelocInfo::kNoPosition); | |
| 3614 Block* ignore_completion_block = | |
| 3615 factory()->NewBlock(NULL, 1, true, RelocInfo::kNoPosition); | |
| 3616 ignore_completion_block->statements()->Add(if_flag_break, zone()); | |
| 3617 inner_block->statements()->Add(ignore_completion_block, zone()); | |
| 3618 } | |
| 3619 | |
| 3620 inner_scope->set_end_position(scanner()->location().end_pos); | |
| 3621 inner_block->set_scope(inner_scope); | |
| 3622 scope_ = for_scope; | |
| 3623 | |
| 3624 outer_loop->Initialize(NULL, NULL, NULL, inner_block); | |
| 3625 return outer_block; | |
| 3626 } | |
| 3627 | |
| 3628 | |
| 3629 Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, | |
| 3630 bool* ok) { | |
| 3631 // ForStatement :: | |
| 3632 // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement | |
| 3633 | |
| 3634 int stmt_pos = peek_position(); | |
| 3635 bool is_const = false; | |
| 3636 Statement* init = NULL; | |
| 3637 ZoneList<const AstRawString*> lexical_bindings(1, zone()); | |
| 3638 | |
| 3639 // Create an in-between scope for let-bound iteration variables. | |
| 3640 Scope* saved_scope = scope_; | |
| 3641 Scope* for_scope = NewScope(scope_, BLOCK_SCOPE); | |
| 3642 scope_ = for_scope; | |
| 3643 Expect(Token::FOR, CHECK_OK); | |
| 3644 Expect(Token::LPAREN, CHECK_OK); | |
| 3645 for_scope->set_start_position(scanner()->location().beg_pos); | |
| 3646 bool is_let_identifier_expression = false; | |
| 3647 DeclarationParsingResult parsing_result; | |
| 3648 if (peek() != Token::SEMICOLON) { | |
| 3649 if (peek() == Token::VAR || (peek() == Token::CONST && allow_const()) || | |
| 3650 (peek() == Token::LET && IsNextLetKeyword())) { | |
| 3651 ParseVariableDeclarations(kForStatement, &parsing_result, CHECK_OK); | |
| 3652 is_const = parsing_result.descriptor.mode == CONST; | |
| 3653 | |
| 3654 int num_decl = parsing_result.declarations.length(); | |
| 3655 bool accept_IN = num_decl >= 1; | |
| 3656 ForEachStatement::VisitMode mode; | |
| 3657 int each_beg_pos = scanner()->location().beg_pos; | |
| 3658 int each_end_pos = scanner()->location().end_pos; | |
| 3659 | |
| 3660 if (accept_IN && CheckInOrOf(&mode, ok)) { | |
| 3661 if (!*ok) return nullptr; | |
| 3662 if (num_decl != 1) { | |
| 3663 const char* loop_type = | |
| 3664 mode == ForEachStatement::ITERATE ? "for-of" : "for-in"; | |
| 3665 ParserTraits::ReportMessageAt( | |
| 3666 parsing_result.bindings_loc, | |
| 3667 MessageTemplate::kForInOfLoopMultiBindings, loop_type); | |
| 3668 *ok = false; | |
| 3669 return nullptr; | |
| 3670 } | |
| 3671 DeclarationParsingResult::Declaration& decl = | |
| 3672 parsing_result.declarations[0]; | |
| 3673 if (parsing_result.first_initializer_loc.IsValid() && | |
| 3674 (is_strict(language_mode()) || mode == ForEachStatement::ITERATE || | |
| 3675 IsLexicalVariableMode(parsing_result.descriptor.mode) || | |
| 3676 !decl.pattern->IsVariableProxy())) { | |
| 3677 if (mode == ForEachStatement::ITERATE) { | |
| 3678 ReportMessageAt(parsing_result.first_initializer_loc, | |
| 3679 MessageTemplate::kForOfLoopInitializer); | |
| 3680 } else { | |
| 3681 // TODO(caitp): This should be an error in sloppy mode too. | |
| 3682 ReportMessageAt(parsing_result.first_initializer_loc, | |
| 3683 MessageTemplate::kForInLoopInitializer); | |
| 3684 } | |
| 3685 *ok = false; | |
| 3686 return nullptr; | |
| 3687 } | |
| 3688 | |
| 3689 Block* init_block = nullptr; | |
| 3690 | |
| 3691 // special case for legacy for (var/const x =.... in) | |
| 3692 if (!IsLexicalVariableMode(parsing_result.descriptor.mode) && | |
| 3693 decl.pattern->IsVariableProxy() && decl.initializer != nullptr) { | |
| 3694 const AstRawString* name = | |
| 3695 decl.pattern->AsVariableProxy()->raw_name(); | |
| 3696 VariableProxy* single_var = scope_->NewUnresolved( | |
| 3697 factory(), name, Variable::NORMAL, each_beg_pos, each_end_pos); | |
| 3698 init_block = factory()->NewBlock( | |
| 3699 nullptr, 2, true, parsing_result.descriptor.declaration_pos); | |
| 3700 init_block->statements()->Add( | |
| 3701 factory()->NewExpressionStatement( | |
| 3702 factory()->NewAssignment(Token::ASSIGN, single_var, | |
| 3703 decl.initializer, | |
| 3704 RelocInfo::kNoPosition), | |
| 3705 RelocInfo::kNoPosition), | |
| 3706 zone()); | |
| 3707 } | |
| 3708 | |
| 3709 // Rewrite a for-in/of statement of the form | |
| 3710 // | |
| 3711 // for (let/const/var x in/of e) b | |
| 3712 // | |
| 3713 // into | |
| 3714 // | |
| 3715 // { | |
| 3716 // <let x' be a temporary variable> | |
| 3717 // for (x' in/of e) { | |
| 3718 // let/const/var x; | |
| 3719 // x = x'; | |
| 3720 // b; | |
| 3721 // } | |
| 3722 // let x; // for TDZ | |
| 3723 // } | |
| 3724 | |
| 3725 Variable* temp = scope_->NewTemporary( | |
| 3726 ast_value_factory()->dot_for_string()); | |
| 3727 ForEachStatement* loop = | |
| 3728 factory()->NewForEachStatement(mode, labels, stmt_pos); | |
| 3729 Target target(&this->target_stack_, loop); | |
| 3730 | |
| 3731 Expression* enumerable = ParseExpression(true, CHECK_OK); | |
| 3732 | |
| 3733 Expect(Token::RPAREN, CHECK_OK); | |
| 3734 | |
| 3735 Scope* body_scope = NewScope(scope_, BLOCK_SCOPE); | |
| 3736 body_scope->set_start_position(scanner()->location().beg_pos); | |
| 3737 scope_ = body_scope; | |
| 3738 | |
| 3739 Statement* body = ParseSubStatement(NULL, CHECK_OK); | |
| 3740 | |
| 3741 Block* body_block = | |
| 3742 factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition); | |
| 3743 | |
| 3744 auto each_initialization_block = | |
| 3745 factory()->NewBlock(nullptr, 1, true, RelocInfo::kNoPosition); | |
| 3746 { | |
| 3747 auto descriptor = parsing_result.descriptor; | |
| 3748 descriptor.declaration_pos = RelocInfo::kNoPosition; | |
| 3749 descriptor.initialization_pos = RelocInfo::kNoPosition; | |
| 3750 decl.initializer = factory()->NewVariableProxy(temp); | |
| 3751 | |
| 3752 PatternRewriter::DeclareAndInitializeVariables( | |
| 3753 each_initialization_block, &descriptor, &decl, | |
| 3754 IsLexicalVariableMode(descriptor.mode) ? &lexical_bindings | |
| 3755 : nullptr, | |
| 3756 CHECK_OK); | |
| 3757 } | |
| 3758 | |
| 3759 body_block->statements()->Add(each_initialization_block, zone()); | |
| 3760 body_block->statements()->Add(body, zone()); | |
| 3761 VariableProxy* temp_proxy = | |
| 3762 factory()->NewVariableProxy(temp, each_beg_pos, each_end_pos); | |
| 3763 InitializeForEachStatement(loop, temp_proxy, enumerable, body_block); | |
| 3764 scope_ = for_scope; | |
| 3765 body_scope->set_end_position(scanner()->location().end_pos); | |
| 3766 body_scope = body_scope->FinalizeBlockScope(); | |
| 3767 if (body_scope != nullptr) { | |
| 3768 body_block->set_scope(body_scope); | |
| 3769 } | |
| 3770 | |
| 3771 // Create a TDZ for any lexically-bound names. | |
| 3772 if (IsLexicalVariableMode(parsing_result.descriptor.mode)) { | |
| 3773 DCHECK_NULL(init_block); | |
| 3774 | |
| 3775 init_block = | |
| 3776 factory()->NewBlock(nullptr, 1, false, RelocInfo::kNoPosition); | |
| 3777 | |
| 3778 for (int i = 0; i < lexical_bindings.length(); ++i) { | |
| 3779 // TODO(adamk): This needs to be some sort of special | |
| 3780 // INTERNAL variable that's invisible to the debugger | |
| 3781 // but visible to everything else. | |
| 3782 VariableProxy* tdz_proxy = NewUnresolved(lexical_bindings[i], LET); | |
| 3783 Declaration* tdz_decl = factory()->NewVariableDeclaration( | |
| 3784 tdz_proxy, LET, scope_, RelocInfo::kNoPosition); | |
| 3785 Variable* tdz_var = Declare(tdz_decl, DeclarationDescriptor::NORMAL, | |
| 3786 true, CHECK_OK); | |
| 3787 tdz_var->set_initializer_position(position()); | |
| 3788 } | |
| 3789 } | |
| 3790 | |
| 3791 scope_ = saved_scope; | |
| 3792 for_scope->set_end_position(scanner()->location().end_pos); | |
| 3793 for_scope = for_scope->FinalizeBlockScope(); | |
| 3794 // Parsed for-in loop w/ variable declarations. | |
| 3795 if (init_block != nullptr) { | |
| 3796 init_block->statements()->Add(loop, zone()); | |
| 3797 if (for_scope != nullptr) { | |
| 3798 init_block->set_scope(for_scope); | |
| 3799 } | |
| 3800 return init_block; | |
| 3801 } else { | |
| 3802 DCHECK_NULL(for_scope); | |
| 3803 return loop; | |
| 3804 } | |
| 3805 } else { | |
| 3806 init = parsing_result.BuildInitializationBlock( | |
| 3807 IsLexicalVariableMode(parsing_result.descriptor.mode) | |
| 3808 ? &lexical_bindings | |
| 3809 : nullptr, | |
| 3810 CHECK_OK); | |
| 3811 } | |
| 3812 } else { | |
| 3813 int lhs_beg_pos = peek_position(); | |
| 3814 Expression* expression = ParseExpression(false, CHECK_OK); | |
| 3815 int lhs_end_pos = scanner()->location().end_pos; | |
| 3816 ForEachStatement::VisitMode mode; | |
| 3817 is_let_identifier_expression = | |
| 3818 expression->IsVariableProxy() && | |
| 3819 expression->AsVariableProxy()->raw_name() == | |
| 3820 ast_value_factory()->let_string(); | |
| 3821 | |
| 3822 if (CheckInOrOf(&mode, ok)) { | |
| 3823 if (!*ok) return nullptr; | |
| 3824 expression = this->CheckAndRewriteReferenceExpression( | |
| 3825 expression, lhs_beg_pos, lhs_end_pos, | |
| 3826 MessageTemplate::kInvalidLhsInFor, kSyntaxError, CHECK_OK); | |
| 3827 | |
| 3828 ForEachStatement* loop = | |
| 3829 factory()->NewForEachStatement(mode, labels, stmt_pos); | |
| 3830 Target target(&this->target_stack_, loop); | |
| 3831 | |
| 3832 Expression* enumerable = ParseExpression(true, CHECK_OK); | |
| 3833 Expect(Token::RPAREN, CHECK_OK); | |
| 3834 | |
| 3835 // Make a block around the statement in case a lexical binding | |
| 3836 // is introduced, e.g. by a FunctionDeclaration. | |
| 3837 // This block must not use for_scope as its scope because if a | |
| 3838 // lexical binding is introduced which overlaps with the for-in/of, | |
| 3839 // expressions in head of the loop should actually have variables | |
| 3840 // resolved in the outer scope. | |
| 3841 Scope* body_scope = NewScope(for_scope, BLOCK_SCOPE); | |
| 3842 scope_ = body_scope; | |
| 3843 Block* block = | |
| 3844 factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition); | |
| 3845 Statement* body = ParseSubStatement(NULL, CHECK_OK); | |
| 3846 block->statements()->Add(body, zone()); | |
| 3847 InitializeForEachStatement(loop, expression, enumerable, block); | |
| 3848 scope_ = saved_scope; | |
| 3849 body_scope->set_end_position(scanner()->location().end_pos); | |
| 3850 body_scope = body_scope->FinalizeBlockScope(); | |
| 3851 if (body_scope != nullptr) { | |
| 3852 block->set_scope(body_scope); | |
| 3853 } | |
| 3854 for_scope->set_end_position(scanner()->location().end_pos); | |
| 3855 for_scope = for_scope->FinalizeBlockScope(); | |
| 3856 DCHECK(for_scope == nullptr); | |
| 3857 // Parsed for-in loop. | |
| 3858 return loop; | |
| 3859 | |
| 3860 } else { | |
| 3861 init = factory()->NewExpressionStatement(expression, lhs_beg_pos); | |
| 3862 } | |
| 3863 } | |
| 3864 } | |
| 3865 | |
| 3866 // Standard 'for' loop | |
| 3867 ForStatement* loop = factory()->NewForStatement(labels, stmt_pos); | |
| 3868 Target target(&this->target_stack_, loop); | |
| 3869 | |
| 3870 // Parsed initializer at this point. | |
| 3871 // Detect attempts at 'let' declarations in sloppy mode. | |
| 3872 if (!allow_harmony_sloppy_let() && peek() == Token::IDENTIFIER && | |
| 3873 is_sloppy(language_mode()) && is_let_identifier_expression) { | |
| 3874 ReportMessage(MessageTemplate::kSloppyLexical, NULL); | |
| 3875 *ok = false; | |
| 3876 return NULL; | |
| 3877 } | |
| 3878 Expect(Token::SEMICOLON, CHECK_OK); | |
| 3879 | |
| 3880 // If there are let bindings, then condition and the next statement of the | |
| 3881 // for loop must be parsed in a new scope. | |
| 3882 Scope* inner_scope = NULL; | |
| 3883 if (lexical_bindings.length() > 0) { | |
| 3884 inner_scope = NewScope(for_scope, BLOCK_SCOPE); | |
| 3885 inner_scope->set_start_position(scanner()->location().beg_pos); | |
| 3886 scope_ = inner_scope; | |
| 3887 } | |
| 3888 | |
| 3889 Expression* cond = NULL; | |
| 3890 if (peek() != Token::SEMICOLON) { | |
| 3891 cond = ParseExpression(true, CHECK_OK); | |
| 3892 } | |
| 3893 Expect(Token::SEMICOLON, CHECK_OK); | |
| 3894 | |
| 3895 Statement* next = NULL; | |
| 3896 if (peek() != Token::RPAREN) { | |
| 3897 Expression* exp = ParseExpression(true, CHECK_OK); | |
| 3898 next = factory()->NewExpressionStatement(exp, exp->position()); | |
| 3899 } | |
| 3900 Expect(Token::RPAREN, CHECK_OK); | |
| 3901 | |
| 3902 Statement* body = ParseSubStatement(NULL, CHECK_OK); | |
| 3903 | |
| 3904 Statement* result = NULL; | |
| 3905 if (lexical_bindings.length() > 0) { | |
| 3906 scope_ = for_scope; | |
| 3907 result = DesugarLexicalBindingsInForStatement( | |
| 3908 inner_scope, is_const, &lexical_bindings, loop, init, cond, | |
| 3909 next, body, CHECK_OK); | |
| 3910 scope_ = saved_scope; | |
| 3911 for_scope->set_end_position(scanner()->location().end_pos); | |
| 3912 } else { | |
| 3913 scope_ = saved_scope; | |
| 3914 for_scope->set_end_position(scanner()->location().end_pos); | |
| 3915 for_scope = for_scope->FinalizeBlockScope(); | |
| 3916 if (for_scope) { | |
| 3917 // Rewrite a for statement of the form | |
| 3918 // for (const x = i; c; n) b | |
| 3919 // | |
| 3920 // into | |
| 3921 // | |
| 3922 // { | |
| 3923 // const x = i; | |
| 3924 // for (; c; n) b | |
| 3925 // } | |
| 3926 // | |
| 3927 // or, desugar | |
| 3928 // for (; c; n) b | |
| 3929 // into | |
| 3930 // { | |
| 3931 // for (; c; n) b | |
| 3932 // } | |
| 3933 // just in case b introduces a lexical binding some other way, e.g., if b | |
| 3934 // is a FunctionDeclaration. | |
| 3935 Block* block = | |
| 3936 factory()->NewBlock(NULL, 2, false, RelocInfo::kNoPosition); | |
| 3937 if (init != nullptr) { | |
| 3938 block->statements()->Add(init, zone()); | |
| 3939 } | |
| 3940 block->statements()->Add(loop, zone()); | |
| 3941 block->set_scope(for_scope); | |
| 3942 loop->Initialize(NULL, cond, next, body); | |
| 3943 result = block; | |
| 3944 } else { | |
| 3945 loop->Initialize(init, cond, next, body); | |
| 3946 result = loop; | |
| 3947 } | |
| 3948 } | |
| 3949 return result; | |
| 3950 } | |
| 3951 | |
| 3952 | |
| 3953 DebuggerStatement* Parser::ParseDebuggerStatement(bool* ok) { | |
| 3954 // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser | |
| 3955 // contexts this is used as a statement which invokes the debugger as i a | |
| 3956 // break point is present. | |
| 3957 // DebuggerStatement :: | |
| 3958 // 'debugger' ';' | |
| 3959 | |
| 3960 int pos = peek_position(); | |
| 3961 Expect(Token::DEBUGGER, CHECK_OK); | |
| 3962 ExpectSemicolon(CHECK_OK); | |
| 3963 return factory()->NewDebuggerStatement(pos); | |
| 3964 } | |
| 3965 | |
| 3966 | |
| 3967 bool CompileTimeValue::IsCompileTimeValue(Expression* expression) { | |
| 3968 if (expression->IsLiteral()) return true; | |
| 3969 MaterializedLiteral* lit = expression->AsMaterializedLiteral(); | |
| 3970 return lit != NULL && lit->is_simple(); | |
| 3971 } | |
| 3972 | |
| 3973 | |
| 3974 Handle<FixedArray> CompileTimeValue::GetValue(Isolate* isolate, | |
| 3975 Expression* expression) { | |
| 3976 Factory* factory = isolate->factory(); | |
| 3977 DCHECK(IsCompileTimeValue(expression)); | |
| 3978 Handle<FixedArray> result = factory->NewFixedArray(2, TENURED); | |
| 3979 ObjectLiteral* object_literal = expression->AsObjectLiteral(); | |
| 3980 if (object_literal != NULL) { | |
| 3981 DCHECK(object_literal->is_simple()); | |
| 3982 if (object_literal->fast_elements()) { | |
| 3983 result->set(kLiteralTypeSlot, Smi::FromInt(OBJECT_LITERAL_FAST_ELEMENTS)); | |
| 3984 } else { | |
| 3985 result->set(kLiteralTypeSlot, Smi::FromInt(OBJECT_LITERAL_SLOW_ELEMENTS)); | |
| 3986 } | |
| 3987 result->set(kElementsSlot, *object_literal->constant_properties()); | |
| 3988 } else { | |
| 3989 ArrayLiteral* array_literal = expression->AsArrayLiteral(); | |
| 3990 DCHECK(array_literal != NULL && array_literal->is_simple()); | |
| 3991 result->set(kLiteralTypeSlot, Smi::FromInt(ARRAY_LITERAL)); | |
| 3992 result->set(kElementsSlot, *array_literal->constant_elements()); | |
| 3993 } | |
| 3994 return result; | |
| 3995 } | |
| 3996 | |
| 3997 | |
| 3998 CompileTimeValue::LiteralType CompileTimeValue::GetLiteralType( | |
| 3999 Handle<FixedArray> value) { | |
| 4000 Smi* literal_type = Smi::cast(value->get(kLiteralTypeSlot)); | |
| 4001 return static_cast<LiteralType>(literal_type->value()); | |
| 4002 } | |
| 4003 | |
| 4004 | |
| 4005 Handle<FixedArray> CompileTimeValue::GetElements(Handle<FixedArray> value) { | |
| 4006 return Handle<FixedArray>(FixedArray::cast(value->get(kElementsSlot))); | |
| 4007 } | |
| 4008 | |
| 4009 | |
| 4010 void ParserTraits::ParseArrowFunctionFormalParameters( | |
| 4011 ParserFormalParameters* parameters, Expression* expr, | |
| 4012 const Scanner::Location& params_loc, bool* ok) { | |
| 4013 if (parameters->Arity() >= Code::kMaxArguments) { | |
| 4014 ReportMessageAt(params_loc, MessageTemplate::kMalformedArrowFunParamList); | |
| 4015 *ok = false; | |
| 4016 return; | |
| 4017 } | |
| 4018 | |
| 4019 // ArrowFunctionFormals :: | |
| 4020 // Binary(Token::COMMA, NonTailArrowFunctionFormals, Tail) | |
| 4021 // Tail | |
| 4022 // NonTailArrowFunctionFormals :: | |
| 4023 // Binary(Token::COMMA, NonTailArrowFunctionFormals, VariableProxy) | |
| 4024 // VariableProxy | |
| 4025 // Tail :: | |
| 4026 // VariableProxy | |
| 4027 // Spread(VariableProxy) | |
| 4028 // | |
| 4029 // As we need to visit the parameters in left-to-right order, we recurse on | |
| 4030 // the left-hand side of comma expressions. | |
| 4031 // | |
| 4032 if (expr->IsBinaryOperation()) { | |
| 4033 BinaryOperation* binop = expr->AsBinaryOperation(); | |
| 4034 // The classifier has already run, so we know that the expression is a valid | |
| 4035 // arrow function formals production. | |
| 4036 DCHECK_EQ(binop->op(), Token::COMMA); | |
| 4037 Expression* left = binop->left(); | |
| 4038 Expression* right = binop->right(); | |
| 4039 ParseArrowFunctionFormalParameters(parameters, left, params_loc, ok); | |
| 4040 if (!*ok) return; | |
| 4041 // LHS of comma expression should be unparenthesized. | |
| 4042 expr = right; | |
| 4043 } | |
| 4044 | |
| 4045 // Only the right-most expression may be a rest parameter. | |
| 4046 DCHECK(!parameters->has_rest); | |
| 4047 | |
| 4048 bool is_rest = expr->IsSpread(); | |
| 4049 if (is_rest) { | |
| 4050 expr = expr->AsSpread()->expression(); | |
| 4051 parameters->has_rest = true; | |
| 4052 parameters->rest_array_literal_index = | |
| 4053 parser_->function_state_->NextMaterializedLiteralIndex(); | |
| 4054 ++parameters->materialized_literals_count; | |
| 4055 } | |
| 4056 if (parameters->is_simple) { | |
| 4057 parameters->is_simple = !is_rest && expr->IsVariableProxy(); | |
| 4058 } | |
| 4059 | |
| 4060 Expression* initializer = nullptr; | |
| 4061 if (expr->IsVariableProxy()) { | |
| 4062 // When the formal parameter was originally seen, it was parsed as a | |
| 4063 // VariableProxy and recorded as unresolved in the scope. Here we undo that | |
| 4064 // parse-time side-effect for parameters that are single-names (not | |
| 4065 // patterns; for patterns that happens uniformly in | |
| 4066 // PatternRewriter::VisitVariableProxy). | |
| 4067 parser_->scope_->RemoveUnresolved(expr->AsVariableProxy()); | |
| 4068 } else if (expr->IsAssignment()) { | |
| 4069 Assignment* assignment = expr->AsAssignment(); | |
| 4070 DCHECK(parser_->allow_harmony_default_parameters()); | |
| 4071 DCHECK(!assignment->is_compound()); | |
| 4072 initializer = assignment->value(); | |
| 4073 expr = assignment->target(); | |
| 4074 | |
| 4075 // TODO(adamk): Only call this if necessary. | |
| 4076 RewriteParameterInitializerScope(parser_->stack_limit(), initializer, | |
| 4077 parser_->scope_, parameters->scope); | |
| 4078 } | |
| 4079 | |
| 4080 // TODO(adamk): params_loc.end_pos is not the correct initializer position, | |
| 4081 // but it should be conservative enough to trigger hole checks for variables | |
| 4082 // referenced in the initializer (if any). | |
| 4083 AddFormalParameter(parameters, expr, initializer, params_loc.end_pos, | |
| 4084 is_rest); | |
| 4085 } | |
| 4086 | |
| 4087 | |
| 4088 DoExpression* Parser::ParseDoExpression(bool* ok) { | |
| 4089 // AssignmentExpression :: | |
| 4090 // do '{' StatementList '}' | |
| 4091 int pos = peek_position(); | |
| 4092 | |
| 4093 Expect(Token::DO, CHECK_OK); | |
| 4094 Variable* result = | |
| 4095 scope_->NewTemporary(ast_value_factory()->dot_result_string()); | |
| 4096 Block* block = ParseBlock(nullptr, CHECK_OK); | |
| 4097 DoExpression* expr = factory()->NewDoExpression(block, result, pos); | |
| 4098 if (!Rewriter::Rewrite(this, expr, ast_value_factory())) { | |
| 4099 *ok = false; | |
| 4100 return nullptr; | |
| 4101 } | |
| 4102 return expr; | |
| 4103 } | |
| 4104 | |
| 4105 | |
| 4106 void ParserTraits::ParseArrowFunctionFormalParameterList( | |
| 4107 ParserFormalParameters* parameters, Expression* expr, | |
| 4108 const Scanner::Location& params_loc, | |
| 4109 Scanner::Location* duplicate_loc, bool* ok) { | |
| 4110 if (expr->IsEmptyParentheses()) return; | |
| 4111 | |
| 4112 ParseArrowFunctionFormalParameters(parameters, expr, params_loc, ok); | |
| 4113 if (!*ok) return; | |
| 4114 | |
| 4115 ExpressionClassifier classifier; | |
| 4116 if (!parameters->is_simple) { | |
| 4117 classifier.RecordNonSimpleParameter(); | |
| 4118 } | |
| 4119 for (int i = 0; i < parameters->Arity(); ++i) { | |
| 4120 auto parameter = parameters->at(i); | |
| 4121 DeclareFormalParameter(parameters->scope, parameter, &classifier); | |
| 4122 if (!duplicate_loc->IsValid()) { | |
| 4123 *duplicate_loc = classifier.duplicate_formal_parameter_error().location; | |
| 4124 } | |
| 4125 } | |
| 4126 DCHECK_EQ(parameters->is_simple, parameters->scope->has_simple_parameters()); | |
| 4127 } | |
| 4128 | |
| 4129 | |
| 4130 void ParserTraits::ReindexLiterals(const ParserFormalParameters& parameters) { | |
| 4131 if (parser_->function_state_->materialized_literal_count() > 0) { | |
| 4132 AstLiteralReindexer reindexer; | |
| 4133 | |
| 4134 for (const auto p : parameters.params) { | |
| 4135 if (p.pattern != nullptr) reindexer.Reindex(p.pattern); | |
| 4136 if (p.initializer != nullptr) reindexer.Reindex(p.initializer); | |
| 4137 } | |
| 4138 | |
| 4139 if (parameters.has_rest) { | |
| 4140 parameters.rest_array_literal_index = reindexer.NextIndex(); | |
| 4141 } | |
| 4142 | |
| 4143 DCHECK(reindexer.count() <= | |
| 4144 parser_->function_state_->materialized_literal_count()); | |
| 4145 } | |
| 4146 } | |
| 4147 | |
| 4148 | |
| 4149 FunctionLiteral* Parser::ParseFunctionLiteral( | |
| 4150 const AstRawString* function_name, Scanner::Location function_name_location, | |
| 4151 FunctionNameValidity function_name_validity, FunctionKind kind, | |
| 4152 int function_token_pos, FunctionLiteral::FunctionType function_type, | |
| 4153 FunctionLiteral::ArityRestriction arity_restriction, | |
| 4154 LanguageMode language_mode, bool* ok) { | |
| 4155 // Function :: | |
| 4156 // '(' FormalParameterList? ')' '{' FunctionBody '}' | |
| 4157 // | |
| 4158 // Getter :: | |
| 4159 // '(' ')' '{' FunctionBody '}' | |
| 4160 // | |
| 4161 // Setter :: | |
| 4162 // '(' PropertySetParameterList ')' '{' FunctionBody '}' | |
| 4163 | |
| 4164 int pos = function_token_pos == RelocInfo::kNoPosition | |
| 4165 ? peek_position() : function_token_pos; | |
| 4166 | |
| 4167 bool is_generator = IsGeneratorFunction(kind); | |
| 4168 | |
| 4169 // Anonymous functions were passed either the empty symbol or a null | |
| 4170 // handle as the function name. Remember if we were passed a non-empty | |
| 4171 // handle to decide whether to invoke function name inference. | |
| 4172 bool should_infer_name = function_name == NULL; | |
| 4173 | |
| 4174 // We want a non-null handle as the function name. | |
| 4175 if (should_infer_name) { | |
| 4176 function_name = ast_value_factory()->empty_string(); | |
| 4177 } | |
| 4178 | |
| 4179 // Function declarations are function scoped in normal mode, so they are | |
| 4180 // hoisted. In harmony block scoping mode they are block scoped, so they | |
| 4181 // are not hoisted. | |
| 4182 // | |
| 4183 // One tricky case are function declarations in a local sloppy-mode eval: | |
| 4184 // their declaration is hoisted, but they still see the local scope. E.g., | |
| 4185 // | |
| 4186 // function() { | |
| 4187 // var x = 0 | |
| 4188 // try { throw 1 } catch (x) { eval("function g() { return x }") } | |
| 4189 // return g() | |
| 4190 // } | |
| 4191 // | |
| 4192 // needs to return 1. To distinguish such cases, we need to detect | |
| 4193 // (1) whether a function stems from a sloppy eval, and | |
| 4194 // (2) whether it actually hoists across the eval. | |
| 4195 // Unfortunately, we do not represent sloppy eval scopes, so we do not have | |
| 4196 // either information available directly, especially not when lazily compiling | |
| 4197 // a function like 'g'. We hence rely on the following invariants: | |
| 4198 // - (1) is the case iff the innermost scope of the deserialized scope chain | |
| 4199 // under which we compile is _not_ a declaration scope. This holds because | |
| 4200 // in all normal cases, function declarations are fully hoisted to a | |
| 4201 // declaration scope and compiled relative to that. | |
| 4202 // - (2) is the case iff the current declaration scope is still the original | |
| 4203 // one relative to the deserialized scope chain. Otherwise we must be | |
| 4204 // compiling a function in an inner declaration scope in the eval, e.g. a | |
| 4205 // nested function, and hoisting works normally relative to that. | |
| 4206 Scope* declaration_scope = scope_->DeclarationScope(); | |
| 4207 Scope* original_declaration_scope = original_scope_->DeclarationScope(); | |
| 4208 Scope* scope = function_type == FunctionLiteral::DECLARATION && | |
| 4209 is_sloppy(language_mode) && | |
| 4210 !allow_harmony_sloppy_function() && | |
| 4211 (original_scope_ == original_declaration_scope || | |
| 4212 declaration_scope != original_declaration_scope) | |
| 4213 ? NewScope(declaration_scope, FUNCTION_SCOPE, kind) | |
| 4214 : NewScope(scope_, FUNCTION_SCOPE, kind); | |
| 4215 SetLanguageMode(scope, language_mode); | |
| 4216 ZoneList<Statement*>* body = NULL; | |
| 4217 int arity = -1; | |
| 4218 int materialized_literal_count = -1; | |
| 4219 int expected_property_count = -1; | |
| 4220 DuplicateFinder duplicate_finder(scanner()->unicode_cache()); | |
| 4221 ExpressionClassifier formals_classifier(&duplicate_finder); | |
| 4222 FunctionLiteral::EagerCompileHint eager_compile_hint = | |
| 4223 parenthesized_function_ ? FunctionLiteral::kShouldEagerCompile | |
| 4224 : FunctionLiteral::kShouldLazyCompile; | |
| 4225 bool should_be_used_once_hint = false; | |
| 4226 // Parse function. | |
| 4227 { | |
| 4228 AstNodeFactory function_factory(ast_value_factory()); | |
| 4229 FunctionState function_state(&function_state_, &scope_, scope, kind, | |
| 4230 &function_factory); | |
| 4231 scope_->SetScopeName(function_name); | |
| 4232 | |
| 4233 if (is_generator) { | |
| 4234 // For generators, allocating variables in contexts is currently a win | |
| 4235 // because it minimizes the work needed to suspend and resume an | |
| 4236 // activation. | |
| 4237 scope_->ForceContextAllocation(); | |
| 4238 | |
| 4239 // Calling a generator returns a generator object. That object is stored | |
| 4240 // in a temporary variable, a definition that is used by "yield" | |
| 4241 // expressions. This also marks the FunctionState as a generator. | |
| 4242 Variable* temp = scope_->NewTemporary( | |
| 4243 ast_value_factory()->dot_generator_object_string()); | |
| 4244 function_state.set_generator_object_variable(temp); | |
| 4245 } | |
| 4246 | |
| 4247 Expect(Token::LPAREN, CHECK_OK); | |
| 4248 int start_position = scanner()->location().beg_pos; | |
| 4249 scope_->set_start_position(start_position); | |
| 4250 ParserFormalParameters formals(scope); | |
| 4251 ParseFormalParameterList(&formals, &formals_classifier, CHECK_OK); | |
| 4252 arity = formals.Arity(); | |
| 4253 Expect(Token::RPAREN, CHECK_OK); | |
| 4254 int formals_end_position = scanner()->location().end_pos; | |
| 4255 | |
| 4256 CheckArityRestrictions(arity, arity_restriction, | |
| 4257 formals.has_rest, start_position, | |
| 4258 formals_end_position, CHECK_OK); | |
| 4259 Expect(Token::LBRACE, CHECK_OK); | |
| 4260 | |
| 4261 // Determine if the function can be parsed lazily. Lazy parsing is different | |
| 4262 // from lazy compilation; we need to parse more eagerly than we compile. | |
| 4263 | |
| 4264 // We can only parse lazily if we also compile lazily. The heuristics for | |
| 4265 // lazy compilation are: | |
| 4266 // - It must not have been prohibited by the caller to Parse (some callers | |
| 4267 // need a full AST). | |
| 4268 // - The outer scope must allow lazy compilation of inner functions. | |
| 4269 // - The function mustn't be a function expression with an open parenthesis | |
| 4270 // before; we consider that a hint that the function will be called | |
| 4271 // immediately, and it would be a waste of time to make it lazily | |
| 4272 // compiled. | |
| 4273 // These are all things we can know at this point, without looking at the | |
| 4274 // function itself. | |
| 4275 | |
| 4276 // In addition, we need to distinguish between these cases: | |
| 4277 // (function foo() { | |
| 4278 // bar = function() { return 1; } | |
| 4279 // })(); | |
| 4280 // and | |
| 4281 // (function foo() { | |
| 4282 // var a = 1; | |
| 4283 // bar = function() { return a; } | |
| 4284 // })(); | |
| 4285 | |
| 4286 // Now foo will be parsed eagerly and compiled eagerly (optimization: assume | |
| 4287 // parenthesis before the function means that it will be called | |
| 4288 // immediately). The inner function *must* be parsed eagerly to resolve the | |
| 4289 // possible reference to the variable in foo's scope. However, it's possible | |
| 4290 // that it will be compiled lazily. | |
| 4291 | |
| 4292 // To make this additional case work, both Parser and PreParser implement a | |
| 4293 // logic where only top-level functions will be parsed lazily. | |
| 4294 bool is_lazily_parsed = mode() == PARSE_LAZILY && | |
| 4295 scope_->AllowsLazyParsing() && | |
| 4296 !parenthesized_function_; | |
| 4297 parenthesized_function_ = false; // The bit was set for this function only. | |
| 4298 | |
| 4299 // Eager or lazy parse? | |
| 4300 // If is_lazily_parsed, we'll parse lazy. If we can set a bookmark, we'll | |
| 4301 // pass it to SkipLazyFunctionBody, which may use it to abort lazy | |
| 4302 // parsing if it suspect that wasn't a good idea. If so, or if we didn't | |
| 4303 // try to lazy parse in the first place, we'll have to parse eagerly. | |
| 4304 Scanner::BookmarkScope bookmark(scanner()); | |
| 4305 if (is_lazily_parsed) { | |
| 4306 Scanner::BookmarkScope* maybe_bookmark = | |
| 4307 bookmark.Set() ? &bookmark : nullptr; | |
| 4308 SkipLazyFunctionBody(&materialized_literal_count, | |
| 4309 &expected_property_count, /*CHECK_OK*/ ok, | |
| 4310 maybe_bookmark); | |
| 4311 | |
| 4312 materialized_literal_count += formals.materialized_literals_count + | |
| 4313 function_state.materialized_literal_count(); | |
| 4314 | |
| 4315 if (bookmark.HasBeenReset()) { | |
| 4316 // Trigger eager (re-)parsing, just below this block. | |
| 4317 is_lazily_parsed = false; | |
| 4318 | |
| 4319 // This is probably an initialization function. Inform the compiler it | |
| 4320 // should also eager-compile this function, and that we expect it to be | |
| 4321 // used once. | |
| 4322 eager_compile_hint = FunctionLiteral::kShouldEagerCompile; | |
| 4323 should_be_used_once_hint = true; | |
| 4324 } | |
| 4325 } | |
| 4326 if (!is_lazily_parsed) { | |
| 4327 // Determine whether the function body can be discarded after parsing. | |
| 4328 // The preconditions are: | |
| 4329 // - Lazy compilation has to be enabled. | |
| 4330 // - Neither V8 natives nor native function declarations can be allowed, | |
| 4331 // since parsing one would retroactively force the function to be | |
| 4332 // eagerly compiled. | |
| 4333 // - The invoker of this parser can't depend on the AST being eagerly | |
| 4334 // built (either because the function is about to be compiled, or | |
| 4335 // because the AST is going to be inspected for some reason). | |
| 4336 // - Because of the above, we can't be attempting to parse a | |
| 4337 // FunctionExpression; even without enclosing parentheses it might be | |
| 4338 // immediately invoked. | |
| 4339 // - The function literal shouldn't be hinted to eagerly compile. | |
| 4340 bool use_temp_zone = | |
| 4341 FLAG_lazy && !allow_natives() && extension_ == NULL && allow_lazy() && | |
| 4342 function_type == FunctionLiteral::DECLARATION && | |
| 4343 eager_compile_hint != FunctionLiteral::kShouldEagerCompile; | |
| 4344 // Open a new BodyScope, which sets our AstNodeFactory to allocate in the | |
| 4345 // new temporary zone if the preconditions are satisfied, and ensures that | |
| 4346 // the previous zone is always restored after parsing the body. | |
| 4347 // For the purpose of scope analysis, some ZoneObjects allocated by the | |
| 4348 // factory must persist after the function body is thrown away and | |
| 4349 // temp_zone is deallocated. These objects are instead allocated in a | |
| 4350 // parser-persistent zone (see parser_zone_ in AstNodeFactory). | |
| 4351 { | |
| 4352 Zone temp_zone; | |
| 4353 AstNodeFactory::BodyScope inner(factory(), &temp_zone, use_temp_zone); | |
| 4354 | |
| 4355 body = ParseEagerFunctionBody(function_name, pos, formals, kind, | |
| 4356 function_type, CHECK_OK); | |
| 4357 } | |
| 4358 materialized_literal_count = function_state.materialized_literal_count(); | |
| 4359 expected_property_count = function_state.expected_property_count(); | |
| 4360 if (use_temp_zone) { | |
| 4361 // If the preconditions are correct the function body should never be | |
| 4362 // accessed, but do this anyway for better behaviour if they're wrong. | |
| 4363 body = NULL; | |
| 4364 } | |
| 4365 } | |
| 4366 | |
| 4367 // Parsing the body may change the language mode in our scope. | |
| 4368 language_mode = scope->language_mode(); | |
| 4369 | |
| 4370 if (is_strong(language_mode) && IsSubclassConstructor(kind)) { | |
| 4371 if (!function_state.super_location().IsValid()) { | |
| 4372 ReportMessageAt(function_name_location, | |
| 4373 MessageTemplate::kStrongSuperCallMissing, | |
| 4374 kReferenceError); | |
| 4375 *ok = false; | |
| 4376 return nullptr; | |
| 4377 } | |
| 4378 } | |
| 4379 | |
| 4380 // Validate name and parameter names. We can do this only after parsing the | |
| 4381 // function, since the function can declare itself strict. | |
| 4382 CheckFunctionName(language_mode, function_name, function_name_validity, | |
| 4383 function_name_location, CHECK_OK); | |
| 4384 const bool allow_duplicate_parameters = | |
| 4385 is_sloppy(language_mode) && formals.is_simple && !IsConciseMethod(kind); | |
| 4386 ValidateFormalParameters(&formals_classifier, language_mode, | |
| 4387 allow_duplicate_parameters, CHECK_OK); | |
| 4388 | |
| 4389 if (is_strict(language_mode)) { | |
| 4390 CheckStrictOctalLiteral(scope->start_position(), scope->end_position(), | |
| 4391 CHECK_OK); | |
| 4392 } | |
| 4393 if (is_sloppy(language_mode) && allow_harmony_sloppy_function()) { | |
| 4394 InsertSloppyBlockFunctionVarBindings(scope, CHECK_OK); | |
| 4395 } | |
| 4396 if (is_strict(language_mode) || allow_harmony_sloppy() || | |
| 4397 allow_harmony_destructuring_bind()) { | |
| 4398 CheckConflictingVarDeclarations(scope, CHECK_OK); | |
| 4399 } | |
| 4400 } | |
| 4401 | |
| 4402 bool has_duplicate_parameters = | |
| 4403 !formals_classifier.is_valid_formal_parameter_list_without_duplicates(); | |
| 4404 FunctionLiteral::ParameterFlag duplicate_parameters = | |
| 4405 has_duplicate_parameters ? FunctionLiteral::kHasDuplicateParameters | |
| 4406 : FunctionLiteral::kNoDuplicateParameters; | |
| 4407 | |
| 4408 FunctionLiteral* function_literal = factory()->NewFunctionLiteral( | |
| 4409 function_name, ast_value_factory(), scope, body, | |
| 4410 materialized_literal_count, expected_property_count, arity, | |
| 4411 duplicate_parameters, function_type, FunctionLiteral::kIsFunction, | |
| 4412 eager_compile_hint, kind, pos); | |
| 4413 function_literal->set_function_token_position(function_token_pos); | |
| 4414 if (should_be_used_once_hint) | |
| 4415 function_literal->set_should_be_used_once_hint(); | |
| 4416 | |
| 4417 if (fni_ != NULL && should_infer_name) fni_->AddFunction(function_literal); | |
| 4418 return function_literal; | |
| 4419 } | |
| 4420 | |
| 4421 | |
| 4422 void Parser::SkipLazyFunctionBody(int* materialized_literal_count, | |
| 4423 int* expected_property_count, bool* ok, | |
| 4424 Scanner::BookmarkScope* bookmark) { | |
| 4425 DCHECK_IMPLIES(bookmark, bookmark->HasBeenSet()); | |
| 4426 if (produce_cached_parse_data()) CHECK(log_); | |
| 4427 | |
| 4428 int function_block_pos = position(); | |
| 4429 if (consume_cached_parse_data() && !cached_parse_data_->rejected()) { | |
| 4430 // If we have cached data, we use it to skip parsing the function body. The | |
| 4431 // data contains the information we need to construct the lazy function. | |
| 4432 FunctionEntry entry = | |
| 4433 cached_parse_data_->GetFunctionEntry(function_block_pos); | |
| 4434 // Check that cached data is valid. If not, mark it as invalid (the embedder | |
| 4435 // handles it). Note that end position greater than end of stream is safe, | |
| 4436 // and hard to check. | |
| 4437 if (entry.is_valid() && entry.end_pos() > function_block_pos) { | |
| 4438 scanner()->SeekForward(entry.end_pos() - 1); | |
| 4439 | |
| 4440 scope_->set_end_position(entry.end_pos()); | |
| 4441 Expect(Token::RBRACE, ok); | |
| 4442 if (!*ok) { | |
| 4443 return; | |
| 4444 } | |
| 4445 total_preparse_skipped_ += scope_->end_position() - function_block_pos; | |
| 4446 *materialized_literal_count = entry.literal_count(); | |
| 4447 *expected_property_count = entry.property_count(); | |
| 4448 SetLanguageMode(scope_, entry.language_mode()); | |
| 4449 if (entry.uses_super_property()) scope_->RecordSuperPropertyUsage(); | |
| 4450 if (entry.calls_eval()) scope_->RecordEvalCall(); | |
| 4451 return; | |
| 4452 } | |
| 4453 cached_parse_data_->Reject(); | |
| 4454 } | |
| 4455 // With no cached data, we partially parse the function, without building an | |
| 4456 // AST. This gathers the data needed to build a lazy function. | |
| 4457 SingletonLogger logger; | |
| 4458 PreParser::PreParseResult result = | |
| 4459 ParseLazyFunctionBodyWithPreParser(&logger, bookmark); | |
| 4460 if (bookmark && bookmark->HasBeenReset()) { | |
| 4461 return; // Return immediately if pre-parser devided to abort parsing. | |
| 4462 } | |
| 4463 if (result == PreParser::kPreParseStackOverflow) { | |
| 4464 // Propagate stack overflow. | |
| 4465 set_stack_overflow(); | |
| 4466 *ok = false; | |
| 4467 return; | |
| 4468 } | |
| 4469 if (logger.has_error()) { | |
| 4470 ParserTraits::ReportMessageAt( | |
| 4471 Scanner::Location(logger.start(), logger.end()), logger.message(), | |
| 4472 logger.argument_opt(), logger.error_type()); | |
| 4473 *ok = false; | |
| 4474 return; | |
| 4475 } | |
| 4476 scope_->set_end_position(logger.end()); | |
| 4477 Expect(Token::RBRACE, ok); | |
| 4478 if (!*ok) { | |
| 4479 return; | |
| 4480 } | |
| 4481 total_preparse_skipped_ += scope_->end_position() - function_block_pos; | |
| 4482 *materialized_literal_count = logger.literals(); | |
| 4483 *expected_property_count = logger.properties(); | |
| 4484 SetLanguageMode(scope_, logger.language_mode()); | |
| 4485 if (logger.uses_super_property()) { | |
| 4486 scope_->RecordSuperPropertyUsage(); | |
| 4487 } | |
| 4488 if (logger.calls_eval()) { | |
| 4489 scope_->RecordEvalCall(); | |
| 4490 } | |
| 4491 if (produce_cached_parse_data()) { | |
| 4492 DCHECK(log_); | |
| 4493 // Position right after terminal '}'. | |
| 4494 int body_end = scanner()->location().end_pos; | |
| 4495 log_->LogFunction(function_block_pos, body_end, *materialized_literal_count, | |
| 4496 *expected_property_count, scope_->language_mode(), | |
| 4497 scope_->uses_super_property(), scope_->calls_eval()); | |
| 4498 } | |
| 4499 } | |
| 4500 | |
| 4501 | |
| 4502 Statement* Parser::BuildAssertIsCoercible(Variable* var) { | |
| 4503 // if (var === null || var === undefined) | |
| 4504 // throw /* type error kNonCoercible) */; | |
| 4505 | |
| 4506 Expression* condition = factory()->NewBinaryOperation( | |
| 4507 Token::OR, factory()->NewCompareOperation( | |
| 4508 Token::EQ_STRICT, factory()->NewVariableProxy(var), | |
| 4509 factory()->NewUndefinedLiteral(RelocInfo::kNoPosition), | |
| 4510 RelocInfo::kNoPosition), | |
| 4511 factory()->NewCompareOperation( | |
| 4512 Token::EQ_STRICT, factory()->NewVariableProxy(var), | |
| 4513 factory()->NewNullLiteral(RelocInfo::kNoPosition), | |
| 4514 RelocInfo::kNoPosition), | |
| 4515 RelocInfo::kNoPosition); | |
| 4516 Expression* throw_type_error = this->NewThrowTypeError( | |
| 4517 MessageTemplate::kNonCoercible, ast_value_factory()->empty_string(), | |
| 4518 RelocInfo::kNoPosition); | |
| 4519 IfStatement* if_statement = factory()->NewIfStatement( | |
| 4520 condition, factory()->NewExpressionStatement(throw_type_error, | |
| 4521 RelocInfo::kNoPosition), | |
| 4522 factory()->NewEmptyStatement(RelocInfo::kNoPosition), | |
| 4523 RelocInfo::kNoPosition); | |
| 4524 return if_statement; | |
| 4525 } | |
| 4526 | |
| 4527 | |
| 4528 Block* Parser::BuildParameterInitializationBlock( | |
| 4529 const ParserFormalParameters& parameters, bool* ok) { | |
| 4530 DCHECK(!parameters.is_simple); | |
| 4531 DCHECK(scope_->is_function_scope()); | |
| 4532 Block* init_block = | |
| 4533 factory()->NewBlock(NULL, 1, true, RelocInfo::kNoPosition); | |
| 4534 for (int i = 0; i < parameters.params.length(); ++i) { | |
| 4535 auto parameter = parameters.params[i]; | |
| 4536 DeclarationDescriptor descriptor; | |
| 4537 descriptor.declaration_kind = DeclarationDescriptor::PARAMETER; | |
| 4538 descriptor.parser = this; | |
| 4539 descriptor.declaration_scope = scope_; | |
| 4540 descriptor.scope = scope_; | |
| 4541 descriptor.hoist_scope = nullptr; | |
| 4542 descriptor.mode = LET; | |
| 4543 descriptor.is_const = false; | |
| 4544 descriptor.needs_init = true; | |
| 4545 descriptor.declaration_pos = parameter.pattern->position(); | |
| 4546 // The position that will be used by the AssignmentExpression | |
| 4547 // which copies from the temp parameter to the pattern. | |
| 4548 // | |
| 4549 // TODO(adamk): Should this be RelocInfo::kNoPosition, since | |
| 4550 // it's just copying from a temp var to the real param var? | |
| 4551 descriptor.initialization_pos = parameter.pattern->position(); | |
| 4552 // The initializer position which will end up in, | |
| 4553 // Variable::initializer_position(), used for hole check elimination. | |
| 4554 int initializer_position = parameter.pattern->position(); | |
| 4555 Expression* initial_value = | |
| 4556 factory()->NewVariableProxy(parameters.scope->parameter(i)); | |
| 4557 if (parameter.initializer != nullptr) { | |
| 4558 // IS_UNDEFINED($param) ? initializer : $param | |
| 4559 DCHECK(!parameter.is_rest); | |
| 4560 auto condition = factory()->NewCompareOperation( | |
| 4561 Token::EQ_STRICT, | |
| 4562 factory()->NewVariableProxy(parameters.scope->parameter(i)), | |
| 4563 factory()->NewUndefinedLiteral(RelocInfo::kNoPosition), | |
| 4564 RelocInfo::kNoPosition); | |
| 4565 initial_value = factory()->NewConditional( | |
| 4566 condition, parameter.initializer, initial_value, | |
| 4567 RelocInfo::kNoPosition); | |
| 4568 descriptor.initialization_pos = parameter.initializer->position(); | |
| 4569 initializer_position = parameter.initializer_end_position; | |
| 4570 } else if (parameter.is_rest) { | |
| 4571 // $rest = []; | |
| 4572 // for (var $argument_index = $rest_index; | |
| 4573 // $argument_index < %_ArgumentsLength(); | |
| 4574 // ++$argument_index) { | |
| 4575 // %AppendElement($rest, %_Arguments($argument_index)); | |
| 4576 // } | |
| 4577 // let <param> = $rest; | |
| 4578 DCHECK(parameter.pattern->IsVariableProxy()); | |
| 4579 DCHECK_EQ(i, parameters.params.length() - 1); | |
| 4580 | |
| 4581 Variable* temp_var = parameters.scope->parameter(i); | |
| 4582 auto empty_values = new (zone()) ZoneList<Expression*>(0, zone()); | |
| 4583 auto empty_array = factory()->NewArrayLiteral( | |
| 4584 empty_values, parameters.rest_array_literal_index, | |
| 4585 is_strong(language_mode()), RelocInfo::kNoPosition); | |
| 4586 | |
| 4587 auto init_array = factory()->NewAssignment( | |
| 4588 Token::INIT, factory()->NewVariableProxy(temp_var), empty_array, | |
| 4589 RelocInfo::kNoPosition); | |
| 4590 | |
| 4591 auto loop = factory()->NewForStatement(NULL, RelocInfo::kNoPosition); | |
| 4592 | |
| 4593 auto argument_index = | |
| 4594 parameters.scope->NewTemporary(ast_value_factory()->empty_string()); | |
| 4595 auto init = factory()->NewExpressionStatement( | |
| 4596 factory()->NewAssignment( | |
| 4597 Token::INIT, factory()->NewVariableProxy(argument_index), | |
| 4598 factory()->NewSmiLiteral(i, RelocInfo::kNoPosition), | |
| 4599 RelocInfo::kNoPosition), | |
| 4600 RelocInfo::kNoPosition); | |
| 4601 | |
| 4602 auto empty_arguments = new (zone()) ZoneList<Expression*>(0, zone()); | |
| 4603 | |
| 4604 // $arguments_index < arguments.length | |
| 4605 auto cond = factory()->NewCompareOperation( | |
| 4606 Token::LT, factory()->NewVariableProxy(argument_index), | |
| 4607 factory()->NewCallRuntime(Runtime::kInlineArgumentsLength, | |
| 4608 empty_arguments, RelocInfo::kNoPosition), | |
| 4609 RelocInfo::kNoPosition); | |
| 4610 | |
| 4611 // ++argument_index | |
| 4612 auto next = factory()->NewExpressionStatement( | |
| 4613 factory()->NewCountOperation( | |
| 4614 Token::INC, true, factory()->NewVariableProxy(argument_index), | |
| 4615 RelocInfo::kNoPosition), | |
| 4616 RelocInfo::kNoPosition); | |
| 4617 | |
| 4618 // %_Arguments($arguments_index) | |
| 4619 auto arguments_args = new (zone()) ZoneList<Expression*>(1, zone()); | |
| 4620 arguments_args->Add(factory()->NewVariableProxy(argument_index), zone()); | |
| 4621 | |
| 4622 // %AppendElement($rest, %_Arguments($arguments_index)) | |
| 4623 auto append_element_args = new (zone()) ZoneList<Expression*>(2, zone()); | |
| 4624 | |
| 4625 append_element_args->Add(factory()->NewVariableProxy(temp_var), zone()); | |
| 4626 append_element_args->Add( | |
| 4627 factory()->NewCallRuntime(Runtime::kInlineArguments, arguments_args, | |
| 4628 RelocInfo::kNoPosition), | |
| 4629 zone()); | |
| 4630 | |
| 4631 auto body = factory()->NewExpressionStatement( | |
| 4632 factory()->NewCallRuntime(Runtime::kAppendElement, | |
| 4633 append_element_args, | |
| 4634 RelocInfo::kNoPosition), | |
| 4635 RelocInfo::kNoPosition); | |
| 4636 | |
| 4637 loop->Initialize(init, cond, next, body); | |
| 4638 | |
| 4639 init_block->statements()->Add( | |
| 4640 factory()->NewExpressionStatement(init_array, RelocInfo::kNoPosition), | |
| 4641 zone()); | |
| 4642 | |
| 4643 init_block->statements()->Add(loop, zone()); | |
| 4644 } | |
| 4645 | |
| 4646 Scope* param_scope = scope_; | |
| 4647 Block* param_block = init_block; | |
| 4648 if (!parameter.is_simple() && scope_->calls_sloppy_eval()) { | |
| 4649 param_scope = NewScope(scope_, BLOCK_SCOPE); | |
| 4650 param_scope->set_is_declaration_scope(); | |
| 4651 param_scope->set_start_position(parameter.pattern->position()); | |
| 4652 param_scope->set_end_position(RelocInfo::kNoPosition); | |
| 4653 param_scope->RecordEvalCall(); | |
| 4654 param_block = factory()->NewBlock(NULL, 8, true, RelocInfo::kNoPosition); | |
| 4655 param_block->set_scope(param_scope); | |
| 4656 descriptor.hoist_scope = scope_; | |
| 4657 } | |
| 4658 | |
| 4659 { | |
| 4660 BlockState block_state(&scope_, param_scope); | |
| 4661 DeclarationParsingResult::Declaration decl( | |
| 4662 parameter.pattern, initializer_position, initial_value); | |
| 4663 PatternRewriter::DeclareAndInitializeVariables(param_block, &descriptor, | |
| 4664 &decl, nullptr, CHECK_OK); | |
| 4665 } | |
| 4666 | |
| 4667 if (!parameter.is_simple() && scope_->calls_sloppy_eval()) { | |
| 4668 param_scope = param_scope->FinalizeBlockScope(); | |
| 4669 if (param_scope != nullptr) { | |
| 4670 CheckConflictingVarDeclarations(param_scope, CHECK_OK); | |
| 4671 } | |
| 4672 init_block->statements()->Add(param_block, zone()); | |
| 4673 } | |
| 4674 } | |
| 4675 return init_block; | |
| 4676 } | |
| 4677 | |
| 4678 | |
| 4679 ZoneList<Statement*>* Parser::ParseEagerFunctionBody( | |
| 4680 const AstRawString* function_name, int pos, | |
| 4681 const ParserFormalParameters& parameters, FunctionKind kind, | |
| 4682 FunctionLiteral::FunctionType function_type, bool* ok) { | |
| 4683 // Everything inside an eagerly parsed function will be parsed eagerly | |
| 4684 // (see comment above). | |
| 4685 ParsingModeScope parsing_mode(this, PARSE_EAGERLY); | |
| 4686 ZoneList<Statement*>* result = new(zone()) ZoneList<Statement*>(8, zone()); | |
| 4687 | |
| 4688 static const int kFunctionNameAssignmentIndex = 0; | |
| 4689 if (function_type == FunctionLiteral::NAMED_EXPRESSION) { | |
| 4690 DCHECK(function_name != NULL); | |
| 4691 // If we have a named function expression, we add a local variable | |
| 4692 // declaration to the body of the function with the name of the | |
| 4693 // function and let it refer to the function itself (closure). | |
| 4694 // Not having parsed the function body, the language mode may still change, | |
| 4695 // so we reserve a spot and create the actual const assignment later. | |
| 4696 DCHECK_EQ(kFunctionNameAssignmentIndex, result->length()); | |
| 4697 result->Add(NULL, zone()); | |
| 4698 } | |
| 4699 | |
| 4700 ZoneList<Statement*>* body = result; | |
| 4701 Scope* inner_scope = scope_; | |
| 4702 Block* inner_block = nullptr; | |
| 4703 if (!parameters.is_simple) { | |
| 4704 inner_scope = NewScope(scope_, BLOCK_SCOPE); | |
| 4705 inner_scope->set_is_declaration_scope(); | |
| 4706 inner_scope->set_start_position(scanner()->location().beg_pos); | |
| 4707 inner_block = factory()->NewBlock(NULL, 8, true, RelocInfo::kNoPosition); | |
| 4708 inner_block->set_scope(inner_scope); | |
| 4709 body = inner_block->statements(); | |
| 4710 } | |
| 4711 | |
| 4712 { | |
| 4713 BlockState block_state(&scope_, inner_scope); | |
| 4714 | |
| 4715 // For generators, allocate and yield an iterator on function entry. | |
| 4716 if (IsGeneratorFunction(kind)) { | |
| 4717 ZoneList<Expression*>* arguments = | |
| 4718 new(zone()) ZoneList<Expression*>(0, zone()); | |
| 4719 CallRuntime* allocation = factory()->NewCallRuntime( | |
| 4720 Runtime::kCreateJSGeneratorObject, arguments, pos); | |
| 4721 VariableProxy* init_proxy = factory()->NewVariableProxy( | |
| 4722 function_state_->generator_object_variable()); | |
| 4723 Assignment* assignment = factory()->NewAssignment( | |
| 4724 Token::INIT, init_proxy, allocation, RelocInfo::kNoPosition); | |
| 4725 VariableProxy* get_proxy = factory()->NewVariableProxy( | |
| 4726 function_state_->generator_object_variable()); | |
| 4727 Yield* yield = factory()->NewYield( | |
| 4728 get_proxy, assignment, Yield::kInitial, RelocInfo::kNoPosition); | |
| 4729 body->Add(factory()->NewExpressionStatement( | |
| 4730 yield, RelocInfo::kNoPosition), zone()); | |
| 4731 } | |
| 4732 | |
| 4733 ParseStatementList(body, Token::RBRACE, CHECK_OK); | |
| 4734 | |
| 4735 if (IsGeneratorFunction(kind)) { | |
| 4736 VariableProxy* get_proxy = factory()->NewVariableProxy( | |
| 4737 function_state_->generator_object_variable()); | |
| 4738 Expression* undefined = | |
| 4739 factory()->NewUndefinedLiteral(RelocInfo::kNoPosition); | |
| 4740 Yield* yield = factory()->NewYield(get_proxy, undefined, Yield::kFinal, | |
| 4741 RelocInfo::kNoPosition); | |
| 4742 body->Add(factory()->NewExpressionStatement( | |
| 4743 yield, RelocInfo::kNoPosition), zone()); | |
| 4744 } | |
| 4745 | |
| 4746 if (IsSubclassConstructor(kind)) { | |
| 4747 body->Add( | |
| 4748 factory()->NewReturnStatement( | |
| 4749 this->ThisExpression(scope_, factory(), RelocInfo::kNoPosition), | |
| 4750 RelocInfo::kNoPosition), | |
| 4751 zone()); | |
| 4752 } | |
| 4753 } | |
| 4754 | |
| 4755 Expect(Token::RBRACE, CHECK_OK); | |
| 4756 scope_->set_end_position(scanner()->location().end_pos); | |
| 4757 | |
| 4758 if (!parameters.is_simple) { | |
| 4759 DCHECK_NOT_NULL(inner_scope); | |
| 4760 DCHECK_EQ(body, inner_block->statements()); | |
| 4761 SetLanguageMode(scope_, inner_scope->language_mode()); | |
| 4762 Block* init_block = BuildParameterInitializationBlock(parameters, CHECK_OK); | |
| 4763 DCHECK_NOT_NULL(init_block); | |
| 4764 | |
| 4765 inner_scope->set_end_position(scanner()->location().end_pos); | |
| 4766 inner_scope = inner_scope->FinalizeBlockScope(); | |
| 4767 if (inner_scope != nullptr) { | |
| 4768 CheckConflictingVarDeclarations(inner_scope, CHECK_OK); | |
| 4769 InsertShadowingVarBindingInitializers(inner_block); | |
| 4770 } | |
| 4771 | |
| 4772 result->Add(init_block, zone()); | |
| 4773 result->Add(inner_block, zone()); | |
| 4774 } | |
| 4775 | |
| 4776 if (function_type == FunctionLiteral::NAMED_EXPRESSION) { | |
| 4777 // Now that we know the language mode, we can create the const assignment | |
| 4778 // in the previously reserved spot. | |
| 4779 // NOTE: We create a proxy and resolve it here so that in the | |
| 4780 // future we can change the AST to only refer to VariableProxies | |
| 4781 // instead of Variables and Proxies as is the case now. | |
| 4782 VariableMode fvar_mode = is_strict(language_mode()) ? CONST : CONST_LEGACY; | |
| 4783 Variable* fvar = new (zone()) | |
| 4784 Variable(scope_, function_name, fvar_mode, Variable::NORMAL, | |
| 4785 kCreatedInitialized, kNotAssigned); | |
| 4786 VariableProxy* proxy = factory()->NewVariableProxy(fvar); | |
| 4787 VariableDeclaration* fvar_declaration = factory()->NewVariableDeclaration( | |
| 4788 proxy, fvar_mode, scope_, RelocInfo::kNoPosition); | |
| 4789 scope_->DeclareFunctionVar(fvar_declaration); | |
| 4790 | |
| 4791 VariableProxy* fproxy = factory()->NewVariableProxy(fvar); | |
| 4792 result->Set(kFunctionNameAssignmentIndex, | |
| 4793 factory()->NewExpressionStatement( | |
| 4794 factory()->NewAssignment(Token::INIT, fproxy, | |
| 4795 factory()->NewThisFunction(pos), | |
| 4796 RelocInfo::kNoPosition), | |
| 4797 RelocInfo::kNoPosition)); | |
| 4798 } | |
| 4799 | |
| 4800 return result; | |
| 4801 } | |
| 4802 | |
| 4803 | |
| 4804 PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser( | |
| 4805 SingletonLogger* logger, Scanner::BookmarkScope* bookmark) { | |
| 4806 // This function may be called on a background thread too; record only the | |
| 4807 // main thread preparse times. | |
| 4808 if (pre_parse_timer_ != NULL) { | |
| 4809 pre_parse_timer_->Start(); | |
| 4810 } | |
| 4811 DCHECK_EQ(Token::LBRACE, scanner()->current_token()); | |
| 4812 | |
| 4813 if (reusable_preparser_ == NULL) { | |
| 4814 reusable_preparser_ = new PreParser(zone(), &scanner_, ast_value_factory(), | |
| 4815 NULL, stack_limit_); | |
| 4816 reusable_preparser_->set_allow_lazy(true); | |
| 4817 #define SET_ALLOW(name) reusable_preparser_->set_allow_##name(allow_##name()); | |
| 4818 SET_ALLOW(natives); | |
| 4819 SET_ALLOW(harmony_sloppy); | |
| 4820 SET_ALLOW(harmony_sloppy_let); | |
| 4821 SET_ALLOW(harmony_rest_parameters); | |
| 4822 SET_ALLOW(harmony_default_parameters); | |
| 4823 SET_ALLOW(harmony_destructuring_bind); | |
| 4824 SET_ALLOW(strong_mode); | |
| 4825 SET_ALLOW(harmony_do_expressions); | |
| 4826 #undef SET_ALLOW | |
| 4827 } | |
| 4828 PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction( | |
| 4829 language_mode(), function_state_->kind(), scope_->has_simple_parameters(), | |
| 4830 logger, bookmark); | |
| 4831 if (pre_parse_timer_ != NULL) { | |
| 4832 pre_parse_timer_->Stop(); | |
| 4833 } | |
| 4834 return result; | |
| 4835 } | |
| 4836 | |
| 4837 | |
| 4838 ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name, | |
| 4839 Scanner::Location class_name_location, | |
| 4840 bool name_is_strict_reserved, int pos, | |
| 4841 bool* ok) { | |
| 4842 // All parts of a ClassDeclaration and ClassExpression are strict code. | |
| 4843 if (name_is_strict_reserved) { | |
| 4844 ReportMessageAt(class_name_location, | |
| 4845 MessageTemplate::kUnexpectedStrictReserved); | |
| 4846 *ok = false; | |
| 4847 return NULL; | |
| 4848 } | |
| 4849 if (IsEvalOrArguments(name)) { | |
| 4850 ReportMessageAt(class_name_location, MessageTemplate::kStrictEvalArguments); | |
| 4851 *ok = false; | |
| 4852 return NULL; | |
| 4853 } | |
| 4854 if (is_strong(language_mode()) && IsUndefined(name)) { | |
| 4855 ReportMessageAt(class_name_location, MessageTemplate::kStrongUndefined); | |
| 4856 *ok = false; | |
| 4857 return NULL; | |
| 4858 } | |
| 4859 | |
| 4860 Scope* block_scope = NewScope(scope_, BLOCK_SCOPE); | |
| 4861 BlockState block_state(&scope_, block_scope); | |
| 4862 RaiseLanguageMode(STRICT); | |
| 4863 scope_->SetScopeName(name); | |
| 4864 | |
| 4865 VariableProxy* proxy = NULL; | |
| 4866 if (name != NULL) { | |
| 4867 proxy = NewUnresolved(name, CONST); | |
| 4868 const bool is_class_declaration = true; | |
| 4869 Declaration* declaration = factory()->NewVariableDeclaration( | |
| 4870 proxy, CONST, block_scope, pos, is_class_declaration, | |
| 4871 scope_->class_declaration_group_start()); | |
| 4872 Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK); | |
| 4873 } | |
| 4874 | |
| 4875 Expression* extends = NULL; | |
| 4876 if (Check(Token::EXTENDS)) { | |
| 4877 block_scope->set_start_position(scanner()->location().end_pos); | |
| 4878 ExpressionClassifier classifier; | |
| 4879 extends = ParseLeftHandSideExpression(&classifier, CHECK_OK); | |
| 4880 ValidateExpression(&classifier, CHECK_OK); | |
| 4881 } else { | |
| 4882 block_scope->set_start_position(scanner()->location().end_pos); | |
| 4883 } | |
| 4884 | |
| 4885 | |
| 4886 ClassLiteralChecker checker(this); | |
| 4887 ZoneList<ObjectLiteral::Property*>* properties = NewPropertyList(4, zone()); | |
| 4888 FunctionLiteral* constructor = NULL; | |
| 4889 bool has_seen_constructor = false; | |
| 4890 | |
| 4891 Expect(Token::LBRACE, CHECK_OK); | |
| 4892 | |
| 4893 const bool has_extends = extends != nullptr; | |
| 4894 while (peek() != Token::RBRACE) { | |
| 4895 if (Check(Token::SEMICOLON)) continue; | |
| 4896 if (fni_ != NULL) fni_->Enter(); | |
| 4897 const bool in_class = true; | |
| 4898 const bool is_static = false; | |
| 4899 bool is_computed_name = false; // Classes do not care about computed | |
| 4900 // property names here. | |
| 4901 ExpressionClassifier classifier; | |
| 4902 ObjectLiteral::Property* property = ParsePropertyDefinition( | |
| 4903 &checker, in_class, has_extends, is_static, &is_computed_name, | |
| 4904 &has_seen_constructor, &classifier, CHECK_OK); | |
| 4905 ValidateExpression(&classifier, CHECK_OK); | |
| 4906 | |
| 4907 if (has_seen_constructor && constructor == NULL) { | |
| 4908 constructor = GetPropertyValue(property)->AsFunctionLiteral(); | |
| 4909 DCHECK_NOT_NULL(constructor); | |
| 4910 } else { | |
| 4911 properties->Add(property, zone()); | |
| 4912 } | |
| 4913 | |
| 4914 if (fni_ != NULL) { | |
| 4915 fni_->Infer(); | |
| 4916 fni_->Leave(); | |
| 4917 } | |
| 4918 } | |
| 4919 | |
| 4920 Expect(Token::RBRACE, CHECK_OK); | |
| 4921 int end_pos = scanner()->location().end_pos; | |
| 4922 | |
| 4923 if (constructor == NULL) { | |
| 4924 constructor = DefaultConstructor(extends != NULL, block_scope, pos, end_pos, | |
| 4925 block_scope->language_mode()); | |
| 4926 } | |
| 4927 | |
| 4928 // Note that we do not finalize this block scope because strong | |
| 4929 // mode uses it as a sentinel value indicating an anonymous class. | |
| 4930 block_scope->set_end_position(end_pos); | |
| 4931 | |
| 4932 if (name != NULL) { | |
| 4933 DCHECK_NOT_NULL(proxy); | |
| 4934 proxy->var()->set_initializer_position(end_pos); | |
| 4935 } | |
| 4936 | |
| 4937 return factory()->NewClassLiteral(name, block_scope, proxy, extends, | |
| 4938 constructor, properties, pos, end_pos); | |
| 4939 } | |
| 4940 | |
| 4941 | |
| 4942 Expression* Parser::ParseV8Intrinsic(bool* ok) { | |
| 4943 // CallRuntime :: | |
| 4944 // '%' Identifier Arguments | |
| 4945 | |
| 4946 int pos = peek_position(); | |
| 4947 Expect(Token::MOD, CHECK_OK); | |
| 4948 // Allow "eval" or "arguments" for backward compatibility. | |
| 4949 const AstRawString* name = ParseIdentifier(kAllowRestrictedIdentifiers, | |
| 4950 CHECK_OK); | |
| 4951 Scanner::Location spread_pos; | |
| 4952 ExpressionClassifier classifier; | |
| 4953 ZoneList<Expression*>* args = | |
| 4954 ParseArguments(&spread_pos, &classifier, CHECK_OK); | |
| 4955 ValidateExpression(&classifier, CHECK_OK); | |
| 4956 | |
| 4957 DCHECK(!spread_pos.IsValid()); | |
| 4958 | |
| 4959 if (extension_ != NULL) { | |
| 4960 // The extension structures are only accessible while parsing the | |
| 4961 // very first time not when reparsing because of lazy compilation. | |
| 4962 scope_->DeclarationScope()->ForceEagerCompilation(); | |
| 4963 } | |
| 4964 | |
| 4965 const Runtime::Function* function = Runtime::FunctionForName(name->string()); | |
| 4966 | |
| 4967 if (function != NULL) { | |
| 4968 // Check for possible name clash. | |
| 4969 DCHECK_EQ(Context::kNotFound, | |
| 4970 Context::IntrinsicIndexForName(name->string())); | |
| 4971 // Check for built-in IS_VAR macro. | |
| 4972 if (function->function_id == Runtime::kIS_VAR) { | |
| 4973 DCHECK_EQ(Runtime::RUNTIME, function->intrinsic_type); | |
| 4974 // %IS_VAR(x) evaluates to x if x is a variable, | |
| 4975 // leads to a parse error otherwise. Could be implemented as an | |
| 4976 // inline function %_IS_VAR(x) to eliminate this special case. | |
| 4977 if (args->length() == 1 && args->at(0)->AsVariableProxy() != NULL) { | |
| 4978 return args->at(0); | |
| 4979 } else { | |
| 4980 ReportMessage(MessageTemplate::kNotIsvar); | |
| 4981 *ok = false; | |
| 4982 return NULL; | |
| 4983 } | |
| 4984 } | |
| 4985 | |
| 4986 // Check that the expected number of arguments are being passed. | |
| 4987 if (function->nargs != -1 && function->nargs != args->length()) { | |
| 4988 ReportMessage(MessageTemplate::kIllegalAccess); | |
| 4989 *ok = false; | |
| 4990 return NULL; | |
| 4991 } | |
| 4992 | |
| 4993 return factory()->NewCallRuntime(function, args, pos); | |
| 4994 } | |
| 4995 | |
| 4996 int context_index = Context::IntrinsicIndexForName(name->string()); | |
| 4997 | |
| 4998 // Check that the function is defined. | |
| 4999 if (context_index == Context::kNotFound) { | |
| 5000 ParserTraits::ReportMessage(MessageTemplate::kNotDefined, name); | |
| 5001 *ok = false; | |
| 5002 return NULL; | |
| 5003 } | |
| 5004 | |
| 5005 return factory()->NewCallRuntime(context_index, args, pos); | |
| 5006 } | |
| 5007 | |
| 5008 | |
| 5009 Literal* Parser::GetLiteralUndefined(int position) { | |
| 5010 return factory()->NewUndefinedLiteral(position); | |
| 5011 } | |
| 5012 | |
| 5013 | |
| 5014 void Parser::CheckConflictingVarDeclarations(Scope* scope, bool* ok) { | |
| 5015 Declaration* decl = scope->CheckConflictingVarDeclarations(); | |
| 5016 if (decl != NULL) { | |
| 5017 // In ES6, conflicting variable bindings are early errors. | |
| 5018 const AstRawString* name = decl->proxy()->raw_name(); | |
| 5019 int position = decl->proxy()->position(); | |
| 5020 Scanner::Location location = position == RelocInfo::kNoPosition | |
| 5021 ? Scanner::Location::invalid() | |
| 5022 : Scanner::Location(position, position + 1); | |
| 5023 ParserTraits::ReportMessageAt(location, MessageTemplate::kVarRedeclaration, | |
| 5024 name); | |
| 5025 *ok = false; | |
| 5026 } | |
| 5027 } | |
| 5028 | |
| 5029 | |
| 5030 void Parser::InsertShadowingVarBindingInitializers(Block* inner_block) { | |
| 5031 // For each var-binding that shadows a parameter, insert an assignment | |
| 5032 // initializing the variable with the parameter. | |
| 5033 Scope* inner_scope = inner_block->scope(); | |
| 5034 DCHECK(inner_scope->is_declaration_scope()); | |
| 5035 Scope* function_scope = inner_scope->outer_scope(); | |
| 5036 DCHECK(function_scope->is_function_scope()); | |
| 5037 ZoneList<Declaration*>* decls = inner_scope->declarations(); | |
| 5038 for (int i = 0; i < decls->length(); ++i) { | |
| 5039 Declaration* decl = decls->at(i); | |
| 5040 if (decl->mode() != VAR || !decl->IsVariableDeclaration()) continue; | |
| 5041 const AstRawString* name = decl->proxy()->raw_name(); | |
| 5042 Variable* parameter = function_scope->LookupLocal(name); | |
| 5043 if (parameter == nullptr) continue; | |
| 5044 VariableProxy* to = inner_scope->NewUnresolved(factory(), name); | |
| 5045 VariableProxy* from = factory()->NewVariableProxy(parameter); | |
| 5046 Expression* assignment = factory()->NewAssignment( | |
| 5047 Token::ASSIGN, to, from, RelocInfo::kNoPosition); | |
| 5048 Statement* statement = factory()->NewExpressionStatement( | |
| 5049 assignment, RelocInfo::kNoPosition); | |
| 5050 inner_block->statements()->InsertAt(0, statement, zone()); | |
| 5051 } | |
| 5052 } | |
| 5053 | |
| 5054 | |
| 5055 void Parser::InsertSloppyBlockFunctionVarBindings(Scope* scope, bool* ok) { | |
| 5056 // For each variable which is used as a function declaration in a sloppy | |
| 5057 // block, | |
| 5058 DCHECK(scope->is_declaration_scope()); | |
| 5059 SloppyBlockFunctionMap* map = scope->sloppy_block_function_map(); | |
| 5060 for (ZoneHashMap::Entry* p = map->Start(); p != nullptr; p = map->Next(p)) { | |
| 5061 AstRawString* name = static_cast<AstRawString*>(p->key); | |
| 5062 // If the variable wouldn't conflict with a lexical declaration, | |
| 5063 Variable* var = scope->LookupLocal(name); | |
| 5064 if (var == nullptr || !IsLexicalVariableMode(var->mode())) { | |
| 5065 // Declare a var-style binding for the function in the outer scope | |
| 5066 VariableProxy* proxy = scope->NewUnresolved(factory(), name); | |
| 5067 Declaration* declaration = factory()->NewVariableDeclaration( | |
| 5068 proxy, VAR, scope, RelocInfo::kNoPosition); | |
| 5069 Declare(declaration, DeclarationDescriptor::NORMAL, true, ok, scope); | |
| 5070 DCHECK(ok); // Based on the preceding check, this should not fail | |
| 5071 if (!ok) return; | |
| 5072 | |
| 5073 // Write in assignments to var for each block-scoped function declaration | |
| 5074 auto delegates = static_cast<SloppyBlockFunctionMap::Vector*>(p->value); | |
| 5075 for (SloppyBlockFunctionStatement* delegate : *delegates) { | |
| 5076 // Read from the local lexical scope and write to the function scope | |
| 5077 VariableProxy* to = scope->NewUnresolved(factory(), name); | |
| 5078 VariableProxy* from = delegate->scope()->NewUnresolved(factory(), name); | |
| 5079 Expression* assignment = factory()->NewAssignment( | |
| 5080 Token::ASSIGN, to, from, RelocInfo::kNoPosition); | |
| 5081 Statement* statement = factory()->NewExpressionStatement( | |
| 5082 assignment, RelocInfo::kNoPosition); | |
| 5083 delegate->set_statement(statement); | |
| 5084 } | |
| 5085 } | |
| 5086 } | |
| 5087 } | |
| 5088 | |
| 5089 | |
| 5090 // ---------------------------------------------------------------------------- | |
| 5091 // Parser support | |
| 5092 | |
| 5093 bool Parser::TargetStackContainsLabel(const AstRawString* label) { | |
| 5094 for (Target* t = target_stack_; t != NULL; t = t->previous()) { | |
| 5095 if (ContainsLabel(t->statement()->labels(), label)) return true; | |
| 5096 } | |
| 5097 return false; | |
| 5098 } | |
| 5099 | |
| 5100 | |
| 5101 BreakableStatement* Parser::LookupBreakTarget(const AstRawString* label, | |
| 5102 bool* ok) { | |
| 5103 bool anonymous = label == NULL; | |
| 5104 for (Target* t = target_stack_; t != NULL; t = t->previous()) { | |
| 5105 BreakableStatement* stat = t->statement(); | |
| 5106 if ((anonymous && stat->is_target_for_anonymous()) || | |
| 5107 (!anonymous && ContainsLabel(stat->labels(), label))) { | |
| 5108 return stat; | |
| 5109 } | |
| 5110 } | |
| 5111 return NULL; | |
| 5112 } | |
| 5113 | |
| 5114 | |
| 5115 IterationStatement* Parser::LookupContinueTarget(const AstRawString* label, | |
| 5116 bool* ok) { | |
| 5117 bool anonymous = label == NULL; | |
| 5118 for (Target* t = target_stack_; t != NULL; t = t->previous()) { | |
| 5119 IterationStatement* stat = t->statement()->AsIterationStatement(); | |
| 5120 if (stat == NULL) continue; | |
| 5121 | |
| 5122 DCHECK(stat->is_target_for_anonymous()); | |
| 5123 if (anonymous || ContainsLabel(stat->labels(), label)) { | |
| 5124 return stat; | |
| 5125 } | |
| 5126 } | |
| 5127 return NULL; | |
| 5128 } | |
| 5129 | |
| 5130 | |
| 5131 void Parser::HandleSourceURLComments(Isolate* isolate, Handle<Script> script) { | |
| 5132 if (scanner_.source_url()->length() > 0) { | |
| 5133 Handle<String> source_url = scanner_.source_url()->Internalize(isolate); | |
| 5134 script->set_source_url(*source_url); | |
| 5135 } | |
| 5136 if (scanner_.source_mapping_url()->length() > 0) { | |
| 5137 Handle<String> source_mapping_url = | |
| 5138 scanner_.source_mapping_url()->Internalize(isolate); | |
| 5139 script->set_source_mapping_url(*source_mapping_url); | |
| 5140 } | |
| 5141 } | |
| 5142 | |
| 5143 | |
| 5144 void Parser::Internalize(Isolate* isolate, Handle<Script> script, bool error) { | |
| 5145 // Internalize strings. | |
| 5146 ast_value_factory()->Internalize(isolate); | |
| 5147 | |
| 5148 // Error processing. | |
| 5149 if (error) { | |
| 5150 if (stack_overflow()) { | |
| 5151 isolate->StackOverflow(); | |
| 5152 } else { | |
| 5153 DCHECK(pending_error_handler_.has_pending_error()); | |
| 5154 pending_error_handler_.ThrowPendingError(isolate, script); | |
| 5155 } | |
| 5156 } | |
| 5157 | |
| 5158 // Move statistics to Isolate. | |
| 5159 for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount; | |
| 5160 ++feature) { | |
| 5161 for (int i = 0; i < use_counts_[feature]; ++i) { | |
| 5162 isolate->CountUsage(v8::Isolate::UseCounterFeature(feature)); | |
| 5163 } | |
| 5164 } | |
| 5165 isolate->counters()->total_preparse_skipped()->Increment( | |
| 5166 total_preparse_skipped_); | |
| 5167 } | |
| 5168 | |
| 5169 | |
| 5170 // ---------------------------------------------------------------------------- | |
| 5171 // Regular expressions | |
| 5172 | |
| 5173 | |
| 5174 RegExpParser::RegExpParser(FlatStringReader* in, Handle<String>* error, | |
| 5175 bool multiline, bool unicode, Isolate* isolate, | |
| 5176 Zone* zone) | |
| 5177 : isolate_(isolate), | |
| 5178 zone_(zone), | |
| 5179 error_(error), | |
| 5180 captures_(NULL), | |
| 5181 in_(in), | |
| 5182 current_(kEndMarker), | |
| 5183 next_pos_(0), | |
| 5184 captures_started_(0), | |
| 5185 capture_count_(0), | |
| 5186 has_more_(true), | |
| 5187 multiline_(multiline), | |
| 5188 unicode_(unicode), | |
| 5189 simple_(false), | |
| 5190 contains_anchor_(false), | |
| 5191 is_scanned_for_captures_(false), | |
| 5192 failed_(false) { | |
| 5193 Advance(); | |
| 5194 } | |
| 5195 | |
| 5196 | |
| 5197 uc32 RegExpParser::Next() { | |
| 5198 if (has_next()) { | |
| 5199 return in()->Get(next_pos_); | |
| 5200 } else { | |
| 5201 return kEndMarker; | |
| 5202 } | |
| 5203 } | |
| 5204 | |
| 5205 | |
| 5206 void RegExpParser::Advance() { | |
| 5207 if (next_pos_ < in()->length()) { | |
| 5208 StackLimitCheck check(isolate()); | |
| 5209 if (check.HasOverflowed()) { | |
| 5210 ReportError(CStrVector(Isolate::kStackOverflowMessage)); | |
| 5211 } else if (zone()->excess_allocation()) { | |
| 5212 ReportError(CStrVector("Regular expression too large")); | |
| 5213 } else { | |
| 5214 current_ = in()->Get(next_pos_); | |
| 5215 next_pos_++; | |
| 5216 } | |
| 5217 } else { | |
| 5218 current_ = kEndMarker; | |
| 5219 // Advance so that position() points to 1-after-the-last-character. This is | |
| 5220 // important so that Reset() to this position works correctly. | |
| 5221 next_pos_ = in()->length() + 1; | |
| 5222 has_more_ = false; | |
| 5223 } | |
| 5224 } | |
| 5225 | |
| 5226 | |
| 5227 void RegExpParser::Reset(int pos) { | |
| 5228 next_pos_ = pos; | |
| 5229 has_more_ = (pos < in()->length()); | |
| 5230 Advance(); | |
| 5231 } | |
| 5232 | |
| 5233 | |
| 5234 void RegExpParser::Advance(int dist) { | |
| 5235 next_pos_ += dist - 1; | |
| 5236 Advance(); | |
| 5237 } | |
| 5238 | |
| 5239 | |
| 5240 bool RegExpParser::simple() { | |
| 5241 return simple_; | |
| 5242 } | |
| 5243 | |
| 5244 | |
| 5245 bool RegExpParser::IsSyntaxCharacter(uc32 c) { | |
| 5246 return c == '^' || c == '$' || c == '\\' || c == '.' || c == '*' || | |
| 5247 c == '+' || c == '?' || c == '(' || c == ')' || c == '[' || c == ']' || | |
| 5248 c == '{' || c == '}' || c == '|'; | |
| 5249 } | |
| 5250 | |
| 5251 | |
| 5252 RegExpTree* RegExpParser::ReportError(Vector<const char> message) { | |
| 5253 failed_ = true; | |
| 5254 *error_ = isolate()->factory()->NewStringFromAscii(message).ToHandleChecked(); | |
| 5255 // Zip to the end to make sure the no more input is read. | |
| 5256 current_ = kEndMarker; | |
| 5257 next_pos_ = in()->length(); | |
| 5258 return NULL; | |
| 5259 } | |
| 5260 | |
| 5261 | |
| 5262 // Pattern :: | |
| 5263 // Disjunction | |
| 5264 RegExpTree* RegExpParser::ParsePattern() { | |
| 5265 RegExpTree* result = ParseDisjunction(CHECK_FAILED); | |
| 5266 DCHECK(!has_more()); | |
| 5267 // If the result of parsing is a literal string atom, and it has the | |
| 5268 // same length as the input, then the atom is identical to the input. | |
| 5269 if (result->IsAtom() && result->AsAtom()->length() == in()->length()) { | |
| 5270 simple_ = true; | |
| 5271 } | |
| 5272 return result; | |
| 5273 } | |
| 5274 | |
| 5275 | |
| 5276 // Disjunction :: | |
| 5277 // Alternative | |
| 5278 // Alternative | Disjunction | |
| 5279 // Alternative :: | |
| 5280 // [empty] | |
| 5281 // Term Alternative | |
| 5282 // Term :: | |
| 5283 // Assertion | |
| 5284 // Atom | |
| 5285 // Atom Quantifier | |
| 5286 RegExpTree* RegExpParser::ParseDisjunction() { | |
| 5287 // Used to store current state while parsing subexpressions. | |
| 5288 RegExpParserState initial_state(NULL, INITIAL, RegExpLookaround::LOOKAHEAD, 0, | |
| 5289 zone()); | |
| 5290 RegExpParserState* state = &initial_state; | |
| 5291 // Cache the builder in a local variable for quick access. | |
| 5292 RegExpBuilder* builder = initial_state.builder(); | |
| 5293 while (true) { | |
| 5294 switch (current()) { | |
| 5295 case kEndMarker: | |
| 5296 if (state->IsSubexpression()) { | |
| 5297 // Inside a parenthesized group when hitting end of input. | |
| 5298 ReportError(CStrVector("Unterminated group") CHECK_FAILED); | |
| 5299 } | |
| 5300 DCHECK_EQ(INITIAL, state->group_type()); | |
| 5301 // Parsing completed successfully. | |
| 5302 return builder->ToRegExp(); | |
| 5303 case ')': { | |
| 5304 if (!state->IsSubexpression()) { | |
| 5305 ReportError(CStrVector("Unmatched ')'") CHECK_FAILED); | |
| 5306 } | |
| 5307 DCHECK_NE(INITIAL, state->group_type()); | |
| 5308 | |
| 5309 Advance(); | |
| 5310 // End disjunction parsing and convert builder content to new single | |
| 5311 // regexp atom. | |
| 5312 RegExpTree* body = builder->ToRegExp(); | |
| 5313 | |
| 5314 int end_capture_index = captures_started(); | |
| 5315 | |
| 5316 int capture_index = state->capture_index(); | |
| 5317 SubexpressionType group_type = state->group_type(); | |
| 5318 | |
| 5319 // Build result of subexpression. | |
| 5320 if (group_type == CAPTURE) { | |
| 5321 RegExpCapture* capture = GetCapture(capture_index); | |
| 5322 capture->set_body(body); | |
| 5323 body = capture; | |
| 5324 } else if (group_type != GROUPING) { | |
| 5325 DCHECK(group_type == POSITIVE_LOOKAROUND || | |
| 5326 group_type == NEGATIVE_LOOKAROUND); | |
| 5327 bool is_positive = (group_type == POSITIVE_LOOKAROUND); | |
| 5328 body = new (zone()) RegExpLookaround( | |
| 5329 body, is_positive, end_capture_index - capture_index, capture_index, | |
| 5330 state->lookaround_type()); | |
| 5331 } | |
| 5332 | |
| 5333 // Restore previous state. | |
| 5334 state = state->previous_state(); | |
| 5335 builder = state->builder(); | |
| 5336 | |
| 5337 builder->AddAtom(body); | |
| 5338 // For compatability with JSC and ES3, we allow quantifiers after | |
| 5339 // lookaheads, and break in all cases. | |
| 5340 break; | |
| 5341 } | |
| 5342 case '|': { | |
| 5343 Advance(); | |
| 5344 builder->NewAlternative(); | |
| 5345 continue; | |
| 5346 } | |
| 5347 case '*': | |
| 5348 case '+': | |
| 5349 case '?': | |
| 5350 return ReportError(CStrVector("Nothing to repeat")); | |
| 5351 case '^': { | |
| 5352 Advance(); | |
| 5353 if (multiline_) { | |
| 5354 builder->AddAssertion( | |
| 5355 new(zone()) RegExpAssertion(RegExpAssertion::START_OF_LINE)); | |
| 5356 } else { | |
| 5357 builder->AddAssertion( | |
| 5358 new(zone()) RegExpAssertion(RegExpAssertion::START_OF_INPUT)); | |
| 5359 set_contains_anchor(); | |
| 5360 } | |
| 5361 continue; | |
| 5362 } | |
| 5363 case '$': { | |
| 5364 Advance(); | |
| 5365 RegExpAssertion::AssertionType assertion_type = | |
| 5366 multiline_ ? RegExpAssertion::END_OF_LINE : | |
| 5367 RegExpAssertion::END_OF_INPUT; | |
| 5368 builder->AddAssertion(new(zone()) RegExpAssertion(assertion_type)); | |
| 5369 continue; | |
| 5370 } | |
| 5371 case '.': { | |
| 5372 Advance(); | |
| 5373 // everything except \x0a, \x0d, \u2028 and \u2029 | |
| 5374 ZoneList<CharacterRange>* ranges = | |
| 5375 new(zone()) ZoneList<CharacterRange>(2, zone()); | |
| 5376 CharacterRange::AddClassEscape('.', ranges, zone()); | |
| 5377 RegExpTree* atom = new(zone()) RegExpCharacterClass(ranges, false); | |
| 5378 builder->AddAtom(atom); | |
| 5379 break; | |
| 5380 } | |
| 5381 case '(': { | |
| 5382 SubexpressionType subexpr_type = CAPTURE; | |
| 5383 RegExpLookaround::Type lookaround_type = state->lookaround_type(); | |
| 5384 Advance(); | |
| 5385 if (current() == '?') { | |
| 5386 switch (Next()) { | |
| 5387 case ':': | |
| 5388 subexpr_type = GROUPING; | |
| 5389 break; | |
| 5390 case '=': | |
| 5391 lookaround_type = RegExpLookaround::LOOKAHEAD; | |
| 5392 subexpr_type = POSITIVE_LOOKAROUND; | |
| 5393 break; | |
| 5394 case '!': | |
| 5395 lookaround_type = RegExpLookaround::LOOKAHEAD; | |
| 5396 subexpr_type = NEGATIVE_LOOKAROUND; | |
| 5397 break; | |
| 5398 case '<': | |
| 5399 if (FLAG_harmony_regexp_lookbehind) { | |
| 5400 Advance(); | |
| 5401 lookaround_type = RegExpLookaround::LOOKBEHIND; | |
| 5402 if (Next() == '=') { | |
| 5403 subexpr_type = POSITIVE_LOOKAROUND; | |
| 5404 break; | |
| 5405 } else if (Next() == '!') { | |
| 5406 subexpr_type = NEGATIVE_LOOKAROUND; | |
| 5407 break; | |
| 5408 } | |
| 5409 } | |
| 5410 // Fall through. | |
| 5411 default: | |
| 5412 ReportError(CStrVector("Invalid group") CHECK_FAILED); | |
| 5413 break; | |
| 5414 } | |
| 5415 Advance(2); | |
| 5416 } else { | |
| 5417 if (captures_started_ >= kMaxCaptures) { | |
| 5418 ReportError(CStrVector("Too many captures") CHECK_FAILED); | |
| 5419 } | |
| 5420 captures_started_++; | |
| 5421 } | |
| 5422 // Store current state and begin new disjunction parsing. | |
| 5423 state = new (zone()) RegExpParserState( | |
| 5424 state, subexpr_type, lookaround_type, captures_started_, zone()); | |
| 5425 builder = state->builder(); | |
| 5426 continue; | |
| 5427 } | |
| 5428 case '[': { | |
| 5429 RegExpTree* atom = ParseCharacterClass(CHECK_FAILED); | |
| 5430 builder->AddAtom(atom); | |
| 5431 break; | |
| 5432 } | |
| 5433 // Atom :: | |
| 5434 // \ AtomEscape | |
| 5435 case '\\': | |
| 5436 switch (Next()) { | |
| 5437 case kEndMarker: | |
| 5438 return ReportError(CStrVector("\\ at end of pattern")); | |
| 5439 case 'b': | |
| 5440 Advance(2); | |
| 5441 builder->AddAssertion( | |
| 5442 new(zone()) RegExpAssertion(RegExpAssertion::BOUNDARY)); | |
| 5443 continue; | |
| 5444 case 'B': | |
| 5445 Advance(2); | |
| 5446 builder->AddAssertion( | |
| 5447 new(zone()) RegExpAssertion(RegExpAssertion::NON_BOUNDARY)); | |
| 5448 continue; | |
| 5449 // AtomEscape :: | |
| 5450 // CharacterClassEscape | |
| 5451 // | |
| 5452 // CharacterClassEscape :: one of | |
| 5453 // d D s S w W | |
| 5454 case 'd': case 'D': case 's': case 'S': case 'w': case 'W': { | |
| 5455 uc32 c = Next(); | |
| 5456 Advance(2); | |
| 5457 ZoneList<CharacterRange>* ranges = | |
| 5458 new(zone()) ZoneList<CharacterRange>(2, zone()); | |
| 5459 CharacterRange::AddClassEscape(c, ranges, zone()); | |
| 5460 RegExpTree* atom = new(zone()) RegExpCharacterClass(ranges, false); | |
| 5461 builder->AddAtom(atom); | |
| 5462 break; | |
| 5463 } | |
| 5464 case '1': case '2': case '3': case '4': case '5': case '6': | |
| 5465 case '7': case '8': case '9': { | |
| 5466 int index = 0; | |
| 5467 if (ParseBackReferenceIndex(&index)) { | |
| 5468 if (state->IsInsideCaptureGroup(index)) { | |
| 5469 // The backreference is inside the capture group it refers to. | |
| 5470 // Nothing can possibly have been captured yet. | |
| 5471 builder->AddEmpty(); | |
| 5472 } else { | |
| 5473 RegExpCapture* capture = GetCapture(index); | |
| 5474 RegExpTree* atom = new (zone()) RegExpBackReference(capture); | |
| 5475 builder->AddAtom(atom); | |
| 5476 } | |
| 5477 break; | |
| 5478 } | |
| 5479 uc32 first_digit = Next(); | |
| 5480 if (first_digit == '8' || first_digit == '9') { | |
| 5481 // If the 'u' flag is present, only syntax characters can be escaped, | |
| 5482 // no other identity escapes are allowed. If the 'u' flag is not | |
| 5483 // present, all identity escapes are allowed. | |
| 5484 if (!FLAG_harmony_unicode_regexps || !unicode_) { | |
| 5485 builder->AddCharacter(first_digit); | |
| 5486 Advance(2); | |
| 5487 } else { | |
| 5488 return ReportError(CStrVector("Invalid escape")); | |
| 5489 } | |
| 5490 break; | |
| 5491 } | |
| 5492 } | |
| 5493 // FALLTHROUGH | |
| 5494 case '0': { | |
| 5495 Advance(); | |
| 5496 uc32 octal = ParseOctalLiteral(); | |
| 5497 builder->AddCharacter(octal); | |
| 5498 break; | |
| 5499 } | |
| 5500 // ControlEscape :: one of | |
| 5501 // f n r t v | |
| 5502 case 'f': | |
| 5503 Advance(2); | |
| 5504 builder->AddCharacter('\f'); | |
| 5505 break; | |
| 5506 case 'n': | |
| 5507 Advance(2); | |
| 5508 builder->AddCharacter('\n'); | |
| 5509 break; | |
| 5510 case 'r': | |
| 5511 Advance(2); | |
| 5512 builder->AddCharacter('\r'); | |
| 5513 break; | |
| 5514 case 't': | |
| 5515 Advance(2); | |
| 5516 builder->AddCharacter('\t'); | |
| 5517 break; | |
| 5518 case 'v': | |
| 5519 Advance(2); | |
| 5520 builder->AddCharacter('\v'); | |
| 5521 break; | |
| 5522 case 'c': { | |
| 5523 Advance(); | |
| 5524 uc32 controlLetter = Next(); | |
| 5525 // Special case if it is an ASCII letter. | |
| 5526 // Convert lower case letters to uppercase. | |
| 5527 uc32 letter = controlLetter & ~('a' ^ 'A'); | |
| 5528 if (letter < 'A' || 'Z' < letter) { | |
| 5529 // controlLetter is not in range 'A'-'Z' or 'a'-'z'. | |
| 5530 // This is outside the specification. We match JSC in | |
| 5531 // reading the backslash as a literal character instead | |
| 5532 // of as starting an escape. | |
| 5533 builder->AddCharacter('\\'); | |
| 5534 } else { | |
| 5535 Advance(2); | |
| 5536 builder->AddCharacter(controlLetter & 0x1f); | |
| 5537 } | |
| 5538 break; | |
| 5539 } | |
| 5540 case 'x': { | |
| 5541 Advance(2); | |
| 5542 uc32 value; | |
| 5543 if (ParseHexEscape(2, &value)) { | |
| 5544 builder->AddCharacter(value); | |
| 5545 } else if (!FLAG_harmony_unicode_regexps || !unicode_) { | |
| 5546 builder->AddCharacter('x'); | |
| 5547 } else { | |
| 5548 // If the 'u' flag is present, invalid escapes are not treated as | |
| 5549 // identity escapes. | |
| 5550 return ReportError(CStrVector("Invalid escape")); | |
| 5551 } | |
| 5552 break; | |
| 5553 } | |
| 5554 case 'u': { | |
| 5555 Advance(2); | |
| 5556 uc32 value; | |
| 5557 if (ParseUnicodeEscape(&value)) { | |
| 5558 builder->AddCharacter(value); | |
| 5559 } else if (!FLAG_harmony_unicode_regexps || !unicode_) { | |
| 5560 builder->AddCharacter('u'); | |
| 5561 } else { | |
| 5562 // If the 'u' flag is present, invalid escapes are not treated as | |
| 5563 // identity escapes. | |
| 5564 return ReportError(CStrVector("Invalid unicode escape")); | |
| 5565 } | |
| 5566 break; | |
| 5567 } | |
| 5568 default: | |
| 5569 Advance(); | |
| 5570 // If the 'u' flag is present, only syntax characters can be escaped, no | |
| 5571 // other identity escapes are allowed. If the 'u' flag is not present, | |
| 5572 // all identity escapes are allowed. | |
| 5573 if (!FLAG_harmony_unicode_regexps || !unicode_ || | |
| 5574 IsSyntaxCharacter(current())) { | |
| 5575 builder->AddCharacter(current()); | |
| 5576 Advance(); | |
| 5577 } else { | |
| 5578 return ReportError(CStrVector("Invalid escape")); | |
| 5579 } | |
| 5580 break; | |
| 5581 } | |
| 5582 break; | |
| 5583 case '{': { | |
| 5584 int dummy; | |
| 5585 if (ParseIntervalQuantifier(&dummy, &dummy)) { | |
| 5586 ReportError(CStrVector("Nothing to repeat") CHECK_FAILED); | |
| 5587 } | |
| 5588 // fallthrough | |
| 5589 } | |
| 5590 default: | |
| 5591 builder->AddCharacter(current()); | |
| 5592 Advance(); | |
| 5593 break; | |
| 5594 } // end switch(current()) | |
| 5595 | |
| 5596 int min; | |
| 5597 int max; | |
| 5598 switch (current()) { | |
| 5599 // QuantifierPrefix :: | |
| 5600 // * | |
| 5601 // + | |
| 5602 // ? | |
| 5603 // { | |
| 5604 case '*': | |
| 5605 min = 0; | |
| 5606 max = RegExpTree::kInfinity; | |
| 5607 Advance(); | |
| 5608 break; | |
| 5609 case '+': | |
| 5610 min = 1; | |
| 5611 max = RegExpTree::kInfinity; | |
| 5612 Advance(); | |
| 5613 break; | |
| 5614 case '?': | |
| 5615 min = 0; | |
| 5616 max = 1; | |
| 5617 Advance(); | |
| 5618 break; | |
| 5619 case '{': | |
| 5620 if (ParseIntervalQuantifier(&min, &max)) { | |
| 5621 if (max < min) { | |
| 5622 ReportError(CStrVector("numbers out of order in {} quantifier.") | |
| 5623 CHECK_FAILED); | |
| 5624 } | |
| 5625 break; | |
| 5626 } else { | |
| 5627 continue; | |
| 5628 } | |
| 5629 default: | |
| 5630 continue; | |
| 5631 } | |
| 5632 RegExpQuantifier::QuantifierType quantifier_type = RegExpQuantifier::GREEDY; | |
| 5633 if (current() == '?') { | |
| 5634 quantifier_type = RegExpQuantifier::NON_GREEDY; | |
| 5635 Advance(); | |
| 5636 } else if (FLAG_regexp_possessive_quantifier && current() == '+') { | |
| 5637 // FLAG_regexp_possessive_quantifier is a debug-only flag. | |
| 5638 quantifier_type = RegExpQuantifier::POSSESSIVE; | |
| 5639 Advance(); | |
| 5640 } | |
| 5641 builder->AddQuantifierToAtom(min, max, quantifier_type); | |
| 5642 } | |
| 5643 } | |
| 5644 | |
| 5645 | |
| 5646 #ifdef DEBUG | |
| 5647 // Currently only used in an DCHECK. | |
| 5648 static bool IsSpecialClassEscape(uc32 c) { | |
| 5649 switch (c) { | |
| 5650 case 'd': case 'D': | |
| 5651 case 's': case 'S': | |
| 5652 case 'w': case 'W': | |
| 5653 return true; | |
| 5654 default: | |
| 5655 return false; | |
| 5656 } | |
| 5657 } | |
| 5658 #endif | |
| 5659 | |
| 5660 | |
| 5661 // In order to know whether an escape is a backreference or not we have to scan | |
| 5662 // the entire regexp and find the number of capturing parentheses. However we | |
| 5663 // don't want to scan the regexp twice unless it is necessary. This mini-parser | |
| 5664 // is called when needed. It can see the difference between capturing and | |
| 5665 // noncapturing parentheses and can skip character classes and backslash-escaped | |
| 5666 // characters. | |
| 5667 void RegExpParser::ScanForCaptures() { | |
| 5668 // Start with captures started previous to current position | |
| 5669 int capture_count = captures_started(); | |
| 5670 // Add count of captures after this position. | |
| 5671 int n; | |
| 5672 while ((n = current()) != kEndMarker) { | |
| 5673 Advance(); | |
| 5674 switch (n) { | |
| 5675 case '\\': | |
| 5676 Advance(); | |
| 5677 break; | |
| 5678 case '[': { | |
| 5679 int c; | |
| 5680 while ((c = current()) != kEndMarker) { | |
| 5681 Advance(); | |
| 5682 if (c == '\\') { | |
| 5683 Advance(); | |
| 5684 } else { | |
| 5685 if (c == ']') break; | |
| 5686 } | |
| 5687 } | |
| 5688 break; | |
| 5689 } | |
| 5690 case '(': | |
| 5691 if (current() != '?') capture_count++; | |
| 5692 break; | |
| 5693 } | |
| 5694 } | |
| 5695 capture_count_ = capture_count; | |
| 5696 is_scanned_for_captures_ = true; | |
| 5697 } | |
| 5698 | |
| 5699 | |
| 5700 bool RegExpParser::ParseBackReferenceIndex(int* index_out) { | |
| 5701 DCHECK_EQ('\\', current()); | |
| 5702 DCHECK('1' <= Next() && Next() <= '9'); | |
| 5703 // Try to parse a decimal literal that is no greater than the total number | |
| 5704 // of left capturing parentheses in the input. | |
| 5705 int start = position(); | |
| 5706 int value = Next() - '0'; | |
| 5707 Advance(2); | |
| 5708 while (true) { | |
| 5709 uc32 c = current(); | |
| 5710 if (IsDecimalDigit(c)) { | |
| 5711 value = 10 * value + (c - '0'); | |
| 5712 if (value > kMaxCaptures) { | |
| 5713 Reset(start); | |
| 5714 return false; | |
| 5715 } | |
| 5716 Advance(); | |
| 5717 } else { | |
| 5718 break; | |
| 5719 } | |
| 5720 } | |
| 5721 if (value > captures_started()) { | |
| 5722 if (!is_scanned_for_captures_) { | |
| 5723 int saved_position = position(); | |
| 5724 ScanForCaptures(); | |
| 5725 Reset(saved_position); | |
| 5726 } | |
| 5727 if (value > capture_count_) { | |
| 5728 Reset(start); | |
| 5729 return false; | |
| 5730 } | |
| 5731 } | |
| 5732 *index_out = value; | |
| 5733 return true; | |
| 5734 } | |
| 5735 | |
| 5736 | |
| 5737 RegExpCapture* RegExpParser::GetCapture(int index) { | |
| 5738 // The index for the capture groups are one-based. Its index in the list is | |
| 5739 // zero-based. | |
| 5740 int know_captures = | |
| 5741 is_scanned_for_captures_ ? capture_count_ : captures_started_; | |
| 5742 DCHECK(index <= know_captures); | |
| 5743 if (captures_ == NULL) { | |
| 5744 captures_ = new (zone()) ZoneList<RegExpCapture*>(know_captures, zone()); | |
| 5745 } | |
| 5746 while (captures_->length() < know_captures) { | |
| 5747 captures_->Add(new (zone()) RegExpCapture(captures_->length() + 1), zone()); | |
| 5748 } | |
| 5749 return captures_->at(index - 1); | |
| 5750 } | |
| 5751 | |
| 5752 | |
| 5753 bool RegExpParser::RegExpParserState::IsInsideCaptureGroup(int index) { | |
| 5754 for (RegExpParserState* s = this; s != NULL; s = s->previous_state()) { | |
| 5755 if (s->group_type() != CAPTURE) continue; | |
| 5756 // Return true if we found the matching capture index. | |
| 5757 if (index == s->capture_index()) return true; | |
| 5758 // Abort if index is larger than what has been parsed up till this state. | |
| 5759 if (index > s->capture_index()) return false; | |
| 5760 } | |
| 5761 return false; | |
| 5762 } | |
| 5763 | |
| 5764 | |
| 5765 // QuantifierPrefix :: | |
| 5766 // { DecimalDigits } | |
| 5767 // { DecimalDigits , } | |
| 5768 // { DecimalDigits , DecimalDigits } | |
| 5769 // | |
| 5770 // Returns true if parsing succeeds, and set the min_out and max_out | |
| 5771 // values. Values are truncated to RegExpTree::kInfinity if they overflow. | |
| 5772 bool RegExpParser::ParseIntervalQuantifier(int* min_out, int* max_out) { | |
| 5773 DCHECK_EQ(current(), '{'); | |
| 5774 int start = position(); | |
| 5775 Advance(); | |
| 5776 int min = 0; | |
| 5777 if (!IsDecimalDigit(current())) { | |
| 5778 Reset(start); | |
| 5779 return false; | |
| 5780 } | |
| 5781 while (IsDecimalDigit(current())) { | |
| 5782 int next = current() - '0'; | |
| 5783 if (min > (RegExpTree::kInfinity - next) / 10) { | |
| 5784 // Overflow. Skip past remaining decimal digits and return -1. | |
| 5785 do { | |
| 5786 Advance(); | |
| 5787 } while (IsDecimalDigit(current())); | |
| 5788 min = RegExpTree::kInfinity; | |
| 5789 break; | |
| 5790 } | |
| 5791 min = 10 * min + next; | |
| 5792 Advance(); | |
| 5793 } | |
| 5794 int max = 0; | |
| 5795 if (current() == '}') { | |
| 5796 max = min; | |
| 5797 Advance(); | |
| 5798 } else if (current() == ',') { | |
| 5799 Advance(); | |
| 5800 if (current() == '}') { | |
| 5801 max = RegExpTree::kInfinity; | |
| 5802 Advance(); | |
| 5803 } else { | |
| 5804 while (IsDecimalDigit(current())) { | |
| 5805 int next = current() - '0'; | |
| 5806 if (max > (RegExpTree::kInfinity - next) / 10) { | |
| 5807 do { | |
| 5808 Advance(); | |
| 5809 } while (IsDecimalDigit(current())); | |
| 5810 max = RegExpTree::kInfinity; | |
| 5811 break; | |
| 5812 } | |
| 5813 max = 10 * max + next; | |
| 5814 Advance(); | |
| 5815 } | |
| 5816 if (current() != '}') { | |
| 5817 Reset(start); | |
| 5818 return false; | |
| 5819 } | |
| 5820 Advance(); | |
| 5821 } | |
| 5822 } else { | |
| 5823 Reset(start); | |
| 5824 return false; | |
| 5825 } | |
| 5826 *min_out = min; | |
| 5827 *max_out = max; | |
| 5828 return true; | |
| 5829 } | |
| 5830 | |
| 5831 | |
| 5832 uc32 RegExpParser::ParseOctalLiteral() { | |
| 5833 DCHECK(('0' <= current() && current() <= '7') || current() == kEndMarker); | |
| 5834 // For compatibility with some other browsers (not all), we parse | |
| 5835 // up to three octal digits with a value below 256. | |
| 5836 uc32 value = current() - '0'; | |
| 5837 Advance(); | |
| 5838 if ('0' <= current() && current() <= '7') { | |
| 5839 value = value * 8 + current() - '0'; | |
| 5840 Advance(); | |
| 5841 if (value < 32 && '0' <= current() && current() <= '7') { | |
| 5842 value = value * 8 + current() - '0'; | |
| 5843 Advance(); | |
| 5844 } | |
| 5845 } | |
| 5846 return value; | |
| 5847 } | |
| 5848 | |
| 5849 | |
| 5850 bool RegExpParser::ParseHexEscape(int length, uc32* value) { | |
| 5851 int start = position(); | |
| 5852 uc32 val = 0; | |
| 5853 for (int i = 0; i < length; ++i) { | |
| 5854 uc32 c = current(); | |
| 5855 int d = HexValue(c); | |
| 5856 if (d < 0) { | |
| 5857 Reset(start); | |
| 5858 return false; | |
| 5859 } | |
| 5860 val = val * 16 + d; | |
| 5861 Advance(); | |
| 5862 } | |
| 5863 *value = val; | |
| 5864 return true; | |
| 5865 } | |
| 5866 | |
| 5867 | |
| 5868 bool RegExpParser::ParseUnicodeEscape(uc32* value) { | |
| 5869 // Accept both \uxxxx and \u{xxxxxx} (if harmony unicode escapes are | |
| 5870 // allowed). In the latter case, the number of hex digits between { } is | |
| 5871 // arbitrary. \ and u have already been read. | |
| 5872 if (current() == '{' && FLAG_harmony_unicode_regexps && unicode_) { | |
| 5873 int start = position(); | |
| 5874 Advance(); | |
| 5875 if (ParseUnlimitedLengthHexNumber(0x10ffff, value)) { | |
| 5876 if (current() == '}') { | |
| 5877 Advance(); | |
| 5878 return true; | |
| 5879 } | |
| 5880 } | |
| 5881 Reset(start); | |
| 5882 return false; | |
| 5883 } | |
| 5884 // \u but no {, or \u{...} escapes not allowed. | |
| 5885 return ParseHexEscape(4, value); | |
| 5886 } | |
| 5887 | |
| 5888 | |
| 5889 bool RegExpParser::ParseUnlimitedLengthHexNumber(int max_value, uc32* value) { | |
| 5890 uc32 x = 0; | |
| 5891 int d = HexValue(current()); | |
| 5892 if (d < 0) { | |
| 5893 return false; | |
| 5894 } | |
| 5895 while (d >= 0) { | |
| 5896 x = x * 16 + d; | |
| 5897 if (x > max_value) { | |
| 5898 return false; | |
| 5899 } | |
| 5900 Advance(); | |
| 5901 d = HexValue(current()); | |
| 5902 } | |
| 5903 *value = x; | |
| 5904 return true; | |
| 5905 } | |
| 5906 | |
| 5907 | |
| 5908 uc32 RegExpParser::ParseClassCharacterEscape() { | |
| 5909 DCHECK(current() == '\\'); | |
| 5910 DCHECK(has_next() && !IsSpecialClassEscape(Next())); | |
| 5911 Advance(); | |
| 5912 switch (current()) { | |
| 5913 case 'b': | |
| 5914 Advance(); | |
| 5915 return '\b'; | |
| 5916 // ControlEscape :: one of | |
| 5917 // f n r t v | |
| 5918 case 'f': | |
| 5919 Advance(); | |
| 5920 return '\f'; | |
| 5921 case 'n': | |
| 5922 Advance(); | |
| 5923 return '\n'; | |
| 5924 case 'r': | |
| 5925 Advance(); | |
| 5926 return '\r'; | |
| 5927 case 't': | |
| 5928 Advance(); | |
| 5929 return '\t'; | |
| 5930 case 'v': | |
| 5931 Advance(); | |
| 5932 return '\v'; | |
| 5933 case 'c': { | |
| 5934 uc32 controlLetter = Next(); | |
| 5935 uc32 letter = controlLetter & ~('A' ^ 'a'); | |
| 5936 // For compatibility with JSC, inside a character class | |
| 5937 // we also accept digits and underscore as control characters. | |
| 5938 if ((controlLetter >= '0' && controlLetter <= '9') || | |
| 5939 controlLetter == '_' || | |
| 5940 (letter >= 'A' && letter <= 'Z')) { | |
| 5941 Advance(2); | |
| 5942 // Control letters mapped to ASCII control characters in the range | |
| 5943 // 0x00-0x1f. | |
| 5944 return controlLetter & 0x1f; | |
| 5945 } | |
| 5946 // We match JSC in reading the backslash as a literal | |
| 5947 // character instead of as starting an escape. | |
| 5948 return '\\'; | |
| 5949 } | |
| 5950 case '0': case '1': case '2': case '3': case '4': case '5': | |
| 5951 case '6': case '7': | |
| 5952 // For compatibility, we interpret a decimal escape that isn't | |
| 5953 // a back reference (and therefore either \0 or not valid according | |
| 5954 // to the specification) as a 1..3 digit octal character code. | |
| 5955 return ParseOctalLiteral(); | |
| 5956 case 'x': { | |
| 5957 Advance(); | |
| 5958 uc32 value; | |
| 5959 if (ParseHexEscape(2, &value)) { | |
| 5960 return value; | |
| 5961 } | |
| 5962 if (!FLAG_harmony_unicode_regexps || !unicode_) { | |
| 5963 // If \x is not followed by a two-digit hexadecimal, treat it | |
| 5964 // as an identity escape. | |
| 5965 return 'x'; | |
| 5966 } | |
| 5967 // If the 'u' flag is present, invalid escapes are not treated as | |
| 5968 // identity escapes. | |
| 5969 ReportError(CStrVector("Invalid escape")); | |
| 5970 return 0; | |
| 5971 } | |
| 5972 case 'u': { | |
| 5973 Advance(); | |
| 5974 uc32 value; | |
| 5975 if (ParseUnicodeEscape(&value)) { | |
| 5976 return value; | |
| 5977 } | |
| 5978 if (!FLAG_harmony_unicode_regexps || !unicode_) { | |
| 5979 return 'u'; | |
| 5980 } | |
| 5981 // If the 'u' flag is present, invalid escapes are not treated as | |
| 5982 // identity escapes. | |
| 5983 ReportError(CStrVector("Invalid unicode escape")); | |
| 5984 return 0; | |
| 5985 } | |
| 5986 default: { | |
| 5987 uc32 result = current(); | |
| 5988 // If the 'u' flag is present, only syntax characters can be escaped, no | |
| 5989 // other identity escapes are allowed. If the 'u' flag is not present, all | |
| 5990 // identity escapes are allowed. | |
| 5991 if (!FLAG_harmony_unicode_regexps || !unicode_ || | |
| 5992 IsSyntaxCharacter(result)) { | |
| 5993 Advance(); | |
| 5994 return result; | |
| 5995 } | |
| 5996 ReportError(CStrVector("Invalid escape")); | |
| 5997 return 0; | |
| 5998 } | |
| 5999 } | |
| 6000 return 0; | |
| 6001 } | |
| 6002 | |
| 6003 | |
| 6004 CharacterRange RegExpParser::ParseClassAtom(uc16* char_class) { | |
| 6005 DCHECK_EQ(0, *char_class); | |
| 6006 uc32 first = current(); | |
| 6007 if (first == '\\') { | |
| 6008 switch (Next()) { | |
| 6009 case 'w': case 'W': case 'd': case 'D': case 's': case 'S': { | |
| 6010 *char_class = Next(); | |
| 6011 Advance(2); | |
| 6012 return CharacterRange::Singleton(0); // Return dummy value. | |
| 6013 } | |
| 6014 case kEndMarker: | |
| 6015 return ReportError(CStrVector("\\ at end of pattern")); | |
| 6016 default: | |
| 6017 uc32 c = ParseClassCharacterEscape(CHECK_FAILED); | |
| 6018 return CharacterRange::Singleton(c); | |
| 6019 } | |
| 6020 } else { | |
| 6021 Advance(); | |
| 6022 return CharacterRange::Singleton(first); | |
| 6023 } | |
| 6024 } | |
| 6025 | |
| 6026 | |
| 6027 static const uc16 kNoCharClass = 0; | |
| 6028 | |
| 6029 // Adds range or pre-defined character class to character ranges. | |
| 6030 // If char_class is not kInvalidClass, it's interpreted as a class | |
| 6031 // escape (i.e., 's' means whitespace, from '\s'). | |
| 6032 static inline void AddRangeOrEscape(ZoneList<CharacterRange>* ranges, | |
| 6033 uc16 char_class, | |
| 6034 CharacterRange range, | |
| 6035 Zone* zone) { | |
| 6036 if (char_class != kNoCharClass) { | |
| 6037 CharacterRange::AddClassEscape(char_class, ranges, zone); | |
| 6038 } else { | |
| 6039 ranges->Add(range, zone); | |
| 6040 } | |
| 6041 } | |
| 6042 | |
| 6043 | |
| 6044 RegExpTree* RegExpParser::ParseCharacterClass() { | |
| 6045 static const char* kUnterminated = "Unterminated character class"; | |
| 6046 static const char* kRangeOutOfOrder = "Range out of order in character class"; | |
| 6047 | |
| 6048 DCHECK_EQ(current(), '['); | |
| 6049 Advance(); | |
| 6050 bool is_negated = false; | |
| 6051 if (current() == '^') { | |
| 6052 is_negated = true; | |
| 6053 Advance(); | |
| 6054 } | |
| 6055 ZoneList<CharacterRange>* ranges = | |
| 6056 new(zone()) ZoneList<CharacterRange>(2, zone()); | |
| 6057 while (has_more() && current() != ']') { | |
| 6058 uc16 char_class = kNoCharClass; | |
| 6059 CharacterRange first = ParseClassAtom(&char_class CHECK_FAILED); | |
| 6060 if (current() == '-') { | |
| 6061 Advance(); | |
| 6062 if (current() == kEndMarker) { | |
| 6063 // If we reach the end we break out of the loop and let the | |
| 6064 // following code report an error. | |
| 6065 break; | |
| 6066 } else if (current() == ']') { | |
| 6067 AddRangeOrEscape(ranges, char_class, first, zone()); | |
| 6068 ranges->Add(CharacterRange::Singleton('-'), zone()); | |
| 6069 break; | |
| 6070 } | |
| 6071 uc16 char_class_2 = kNoCharClass; | |
| 6072 CharacterRange next = ParseClassAtom(&char_class_2 CHECK_FAILED); | |
| 6073 if (char_class != kNoCharClass || char_class_2 != kNoCharClass) { | |
| 6074 // Either end is an escaped character class. Treat the '-' verbatim. | |
| 6075 AddRangeOrEscape(ranges, char_class, first, zone()); | |
| 6076 ranges->Add(CharacterRange::Singleton('-'), zone()); | |
| 6077 AddRangeOrEscape(ranges, char_class_2, next, zone()); | |
| 6078 continue; | |
| 6079 } | |
| 6080 if (first.from() > next.to()) { | |
| 6081 return ReportError(CStrVector(kRangeOutOfOrder) CHECK_FAILED); | |
| 6082 } | |
| 6083 ranges->Add(CharacterRange::Range(first.from(), next.to()), zone()); | |
| 6084 } else { | |
| 6085 AddRangeOrEscape(ranges, char_class, first, zone()); | |
| 6086 } | |
| 6087 } | |
| 6088 if (!has_more()) { | |
| 6089 return ReportError(CStrVector(kUnterminated) CHECK_FAILED); | |
| 6090 } | |
| 6091 Advance(); | |
| 6092 if (ranges->length() == 0) { | |
| 6093 ranges->Add(CharacterRange::Everything(), zone()); | |
| 6094 is_negated = !is_negated; | |
| 6095 } | |
| 6096 return new (zone()) RegExpCharacterClass(ranges, is_negated); | |
| 6097 } | |
| 6098 | |
| 6099 | |
| 6100 // ---------------------------------------------------------------------------- | |
| 6101 // The Parser interface. | |
| 6102 | |
| 6103 bool RegExpParser::ParseRegExp(Isolate* isolate, Zone* zone, | |
| 6104 FlatStringReader* input, bool multiline, | |
| 6105 bool unicode, RegExpCompileData* result) { | |
| 6106 DCHECK(result != NULL); | |
| 6107 RegExpParser parser(input, &result->error, multiline, unicode, isolate, zone); | |
| 6108 RegExpTree* tree = parser.ParsePattern(); | |
| 6109 if (parser.failed()) { | |
| 6110 DCHECK(tree == NULL); | |
| 6111 DCHECK(!result->error.is_null()); | |
| 6112 } else { | |
| 6113 DCHECK(tree != NULL); | |
| 6114 DCHECK(result->error.is_null()); | |
| 6115 result->tree = tree; | |
| 6116 int capture_count = parser.captures_started(); | |
| 6117 result->simple = tree->IsAtom() && parser.simple() && capture_count == 0; | |
| 6118 result->contains_anchor = parser.contains_anchor(); | |
| 6119 result->capture_count = capture_count; | |
| 6120 } | |
| 6121 return !parser.failed(); | |
| 6122 } | |
| 6123 | |
| 6124 | |
| 6125 bool Parser::ParseStatic(ParseInfo* info) { | |
| 6126 Parser parser(info); | |
| 6127 if (parser.Parse(info)) { | |
| 6128 info->set_language_mode(info->literal()->language_mode()); | |
| 6129 return true; | |
| 6130 } | |
| 6131 return false; | |
| 6132 } | |
| 6133 | |
| 6134 | |
| 6135 bool Parser::Parse(ParseInfo* info) { | |
| 6136 DCHECK(info->literal() == NULL); | |
| 6137 FunctionLiteral* result = NULL; | |
| 6138 // Ok to use Isolate here; this function is only called in the main thread. | |
| 6139 DCHECK(parsing_on_main_thread_); | |
| 6140 Isolate* isolate = info->isolate(); | |
| 6141 pre_parse_timer_ = isolate->counters()->pre_parse(); | |
| 6142 if (FLAG_trace_parse || allow_natives() || extension_ != NULL) { | |
| 6143 // If intrinsics are allowed, the Parser cannot operate independent of the | |
| 6144 // V8 heap because of Runtime. Tell the string table to internalize strings | |
| 6145 // and values right after they're created. | |
| 6146 ast_value_factory()->Internalize(isolate); | |
| 6147 } | |
| 6148 | |
| 6149 if (info->is_lazy()) { | |
| 6150 DCHECK(!info->is_eval()); | |
| 6151 if (info->shared_info()->is_function()) { | |
| 6152 result = ParseLazy(isolate, info); | |
| 6153 } else { | |
| 6154 result = ParseProgram(isolate, info); | |
| 6155 } | |
| 6156 } else { | |
| 6157 SetCachedData(info); | |
| 6158 result = ParseProgram(isolate, info); | |
| 6159 } | |
| 6160 info->set_literal(result); | |
| 6161 | |
| 6162 Internalize(isolate, info->script(), result == NULL); | |
| 6163 DCHECK(ast_value_factory()->IsInternalized()); | |
| 6164 return (result != NULL); | |
| 6165 } | |
| 6166 | |
| 6167 | |
| 6168 void Parser::ParseOnBackground(ParseInfo* info) { | |
| 6169 parsing_on_main_thread_ = false; | |
| 6170 | |
| 6171 DCHECK(info->literal() == NULL); | |
| 6172 FunctionLiteral* result = NULL; | |
| 6173 fni_ = new (zone()) FuncNameInferrer(ast_value_factory(), zone()); | |
| 6174 | |
| 6175 CompleteParserRecorder recorder; | |
| 6176 if (produce_cached_parse_data()) log_ = &recorder; | |
| 6177 | |
| 6178 DCHECK(info->source_stream() != NULL); | |
| 6179 ExternalStreamingStream stream(info->source_stream(), | |
| 6180 info->source_stream_encoding()); | |
| 6181 scanner_.Initialize(&stream); | |
| 6182 DCHECK(info->context().is_null() || info->context()->IsNativeContext()); | |
| 6183 | |
| 6184 // When streaming, we don't know the length of the source until we have parsed | |
| 6185 // it. The raw data can be UTF-8, so we wouldn't know the source length until | |
| 6186 // we have decoded it anyway even if we knew the raw data length (which we | |
| 6187 // don't). We work around this by storing all the scopes which need their end | |
| 6188 // position set at the end of the script (the top scope and possible eval | |
| 6189 // scopes) and set their end position after we know the script length. | |
| 6190 result = DoParseProgram(info); | |
| 6191 | |
| 6192 info->set_literal(result); | |
| 6193 | |
| 6194 // We cannot internalize on a background thread; a foreground task will take | |
| 6195 // care of calling Parser::Internalize just before compilation. | |
| 6196 | |
| 6197 if (produce_cached_parse_data()) { | |
| 6198 if (result != NULL) *info->cached_data() = recorder.GetScriptData(); | |
| 6199 log_ = NULL; | |
| 6200 } | |
| 6201 } | |
| 6202 | |
| 6203 | |
| 6204 ParserTraits::TemplateLiteralState Parser::OpenTemplateLiteral(int pos) { | |
| 6205 return new (zone()) ParserTraits::TemplateLiteral(zone(), pos); | |
| 6206 } | |
| 6207 | |
| 6208 | |
| 6209 void Parser::AddTemplateSpan(TemplateLiteralState* state, bool tail) { | |
| 6210 int pos = scanner()->location().beg_pos; | |
| 6211 int end = scanner()->location().end_pos - (tail ? 1 : 2); | |
| 6212 const AstRawString* tv = scanner()->CurrentSymbol(ast_value_factory()); | |
| 6213 const AstRawString* trv = scanner()->CurrentRawSymbol(ast_value_factory()); | |
| 6214 Literal* cooked = factory()->NewStringLiteral(tv, pos); | |
| 6215 Literal* raw = factory()->NewStringLiteral(trv, pos); | |
| 6216 (*state)->AddTemplateSpan(cooked, raw, end, zone()); | |
| 6217 } | |
| 6218 | |
| 6219 | |
| 6220 void Parser::AddTemplateExpression(TemplateLiteralState* state, | |
| 6221 Expression* expression) { | |
| 6222 (*state)->AddExpression(expression, zone()); | |
| 6223 } | |
| 6224 | |
| 6225 | |
| 6226 Expression* Parser::CloseTemplateLiteral(TemplateLiteralState* state, int start, | |
| 6227 Expression* tag) { | |
| 6228 TemplateLiteral* lit = *state; | |
| 6229 int pos = lit->position(); | |
| 6230 const ZoneList<Expression*>* cooked_strings = lit->cooked(); | |
| 6231 const ZoneList<Expression*>* raw_strings = lit->raw(); | |
| 6232 const ZoneList<Expression*>* expressions = lit->expressions(); | |
| 6233 DCHECK_EQ(cooked_strings->length(), raw_strings->length()); | |
| 6234 DCHECK_EQ(cooked_strings->length(), expressions->length() + 1); | |
| 6235 | |
| 6236 if (!tag) { | |
| 6237 // Build tree of BinaryOps to simplify code-generation | |
| 6238 Expression* expr = cooked_strings->at(0); | |
| 6239 int i = 0; | |
| 6240 while (i < expressions->length()) { | |
| 6241 Expression* sub = expressions->at(i++); | |
| 6242 Expression* cooked_str = cooked_strings->at(i); | |
| 6243 | |
| 6244 // Let middle be ToString(sub). | |
| 6245 ZoneList<Expression*>* args = | |
| 6246 new (zone()) ZoneList<Expression*>(1, zone()); | |
| 6247 args->Add(sub, zone()); | |
| 6248 Expression* middle = factory()->NewCallRuntime(Runtime::kInlineToString, | |
| 6249 args, sub->position()); | |
| 6250 | |
| 6251 expr = factory()->NewBinaryOperation( | |
| 6252 Token::ADD, factory()->NewBinaryOperation( | |
| 6253 Token::ADD, expr, middle, expr->position()), | |
| 6254 cooked_str, sub->position()); | |
| 6255 } | |
| 6256 return expr; | |
| 6257 } else { | |
| 6258 uint32_t hash = ComputeTemplateLiteralHash(lit); | |
| 6259 | |
| 6260 int cooked_idx = function_state_->NextMaterializedLiteralIndex(); | |
| 6261 int raw_idx = function_state_->NextMaterializedLiteralIndex(); | |
| 6262 | |
| 6263 // $getTemplateCallSite | |
| 6264 ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(4, zone()); | |
| 6265 args->Add(factory()->NewArrayLiteral( | |
| 6266 const_cast<ZoneList<Expression*>*>(cooked_strings), | |
| 6267 cooked_idx, is_strong(language_mode()), pos), | |
| 6268 zone()); | |
| 6269 args->Add( | |
| 6270 factory()->NewArrayLiteral( | |
| 6271 const_cast<ZoneList<Expression*>*>(raw_strings), raw_idx, | |
| 6272 is_strong(language_mode()), pos), | |
| 6273 zone()); | |
| 6274 | |
| 6275 // Ensure hash is suitable as a Smi value | |
| 6276 Smi* hash_obj = Smi::cast(Internals::IntToSmi(static_cast<int>(hash))); | |
| 6277 args->Add(factory()->NewSmiLiteral(hash_obj->value(), pos), zone()); | |
| 6278 | |
| 6279 this->CheckPossibleEvalCall(tag, scope_); | |
| 6280 Expression* call_site = factory()->NewCallRuntime( | |
| 6281 Context::GET_TEMPLATE_CALL_SITE_INDEX, args, start); | |
| 6282 | |
| 6283 // Call TagFn | |
| 6284 ZoneList<Expression*>* call_args = | |
| 6285 new (zone()) ZoneList<Expression*>(expressions->length() + 1, zone()); | |
| 6286 call_args->Add(call_site, zone()); | |
| 6287 call_args->AddAll(*expressions, zone()); | |
| 6288 return factory()->NewCall(tag, call_args, pos); | |
| 6289 } | |
| 6290 } | |
| 6291 | |
| 6292 | |
| 6293 uint32_t Parser::ComputeTemplateLiteralHash(const TemplateLiteral* lit) { | |
| 6294 const ZoneList<Expression*>* raw_strings = lit->raw(); | |
| 6295 int total = raw_strings->length(); | |
| 6296 DCHECK(total); | |
| 6297 | |
| 6298 uint32_t running_hash = 0; | |
| 6299 | |
| 6300 for (int index = 0; index < total; ++index) { | |
| 6301 if (index) { | |
| 6302 running_hash = StringHasher::ComputeRunningHashOneByte( | |
| 6303 running_hash, "${}", 3); | |
| 6304 } | |
| 6305 | |
| 6306 const AstRawString* raw_string = | |
| 6307 raw_strings->at(index)->AsLiteral()->raw_value()->AsString(); | |
| 6308 if (raw_string->is_one_byte()) { | |
| 6309 const char* data = reinterpret_cast<const char*>(raw_string->raw_data()); | |
| 6310 running_hash = StringHasher::ComputeRunningHashOneByte( | |
| 6311 running_hash, data, raw_string->length()); | |
| 6312 } else { | |
| 6313 const uc16* data = reinterpret_cast<const uc16*>(raw_string->raw_data()); | |
| 6314 running_hash = StringHasher::ComputeRunningHash(running_hash, data, | |
| 6315 raw_string->length()); | |
| 6316 } | |
| 6317 } | |
| 6318 | |
| 6319 return running_hash; | |
| 6320 } | |
| 6321 | |
| 6322 | |
| 6323 ZoneList<v8::internal::Expression*>* Parser::PrepareSpreadArguments( | |
| 6324 ZoneList<v8::internal::Expression*>* list) { | |
| 6325 ZoneList<v8::internal::Expression*>* args = | |
| 6326 new (zone()) ZoneList<v8::internal::Expression*>(1, zone()); | |
| 6327 if (list->length() == 1) { | |
| 6328 // Spread-call with single spread argument produces an InternalArray | |
| 6329 // containing the values from the array. | |
| 6330 // | |
| 6331 // Function is called or constructed with the produced array of arguments | |
| 6332 // | |
| 6333 // EG: Apply(Func, Spread(spread0)) | |
| 6334 ZoneList<Expression*>* spread_list = | |
| 6335 new (zone()) ZoneList<Expression*>(0, zone()); | |
| 6336 spread_list->Add(list->at(0)->AsSpread()->expression(), zone()); | |
| 6337 args->Add(factory()->NewCallRuntime(Context::SPREAD_ITERABLE_INDEX, | |
| 6338 spread_list, RelocInfo::kNoPosition), | |
| 6339 zone()); | |
| 6340 return args; | |
| 6341 } else { | |
| 6342 // Spread-call with multiple arguments produces array literals for each | |
| 6343 // sequences of unspread arguments, and converts each spread iterable to | |
| 6344 // an Internal array. Finally, all of these produced arrays are flattened | |
| 6345 // into a single InternalArray, containing the arguments for the call. | |
| 6346 // | |
| 6347 // EG: Apply(Func, Flatten([unspread0, unspread1], Spread(spread0), | |
| 6348 // Spread(spread1), [unspread2, unspread3])) | |
| 6349 int i = 0; | |
| 6350 int n = list->length(); | |
| 6351 while (i < n) { | |
| 6352 if (!list->at(i)->IsSpread()) { | |
| 6353 ZoneList<v8::internal::Expression*>* unspread = | |
| 6354 new (zone()) ZoneList<v8::internal::Expression*>(1, zone()); | |
| 6355 | |
| 6356 // Push array of unspread parameters | |
| 6357 while (i < n && !list->at(i)->IsSpread()) { | |
| 6358 unspread->Add(list->at(i++), zone()); | |
| 6359 } | |
| 6360 int literal_index = function_state_->NextMaterializedLiteralIndex(); | |
| 6361 args->Add(factory()->NewArrayLiteral(unspread, literal_index, | |
| 6362 is_strong(language_mode()), | |
| 6363 RelocInfo::kNoPosition), | |
| 6364 zone()); | |
| 6365 | |
| 6366 if (i == n) break; | |
| 6367 } | |
| 6368 | |
| 6369 // Push eagerly spread argument | |
| 6370 ZoneList<v8::internal::Expression*>* spread_list = | |
| 6371 new (zone()) ZoneList<v8::internal::Expression*>(1, zone()); | |
| 6372 spread_list->Add(list->at(i++)->AsSpread()->expression(), zone()); | |
| 6373 args->Add(factory()->NewCallRuntime(Context::SPREAD_ITERABLE_INDEX, | |
| 6374 spread_list, RelocInfo::kNoPosition), | |
| 6375 zone()); | |
| 6376 } | |
| 6377 | |
| 6378 list = new (zone()) ZoneList<v8::internal::Expression*>(1, zone()); | |
| 6379 list->Add(factory()->NewCallRuntime(Context::SPREAD_ARGUMENTS_INDEX, args, | |
| 6380 RelocInfo::kNoPosition), | |
| 6381 zone()); | |
| 6382 return list; | |
| 6383 } | |
| 6384 UNREACHABLE(); | |
| 6385 } | |
| 6386 | |
| 6387 | |
| 6388 Expression* Parser::SpreadCall(Expression* function, | |
| 6389 ZoneList<v8::internal::Expression*>* args, | |
| 6390 int pos) { | |
| 6391 if (function->IsSuperCallReference()) { | |
| 6392 // Super calls | |
| 6393 // %reflect_construct(%GetPrototype(<this-function>), args, new.target)) | |
| 6394 ZoneList<Expression*>* tmp = new (zone()) ZoneList<Expression*>(1, zone()); | |
| 6395 tmp->Add(function->AsSuperCallReference()->this_function_var(), zone()); | |
| 6396 Expression* get_prototype = | |
| 6397 factory()->NewCallRuntime(Runtime::kGetPrototype, tmp, pos); | |
| 6398 args->InsertAt(0, get_prototype, zone()); | |
| 6399 args->Add(function->AsSuperCallReference()->new_target_var(), zone()); | |
| 6400 return factory()->NewCallRuntime(Context::REFLECT_CONSTRUCT_INDEX, args, | |
| 6401 pos); | |
| 6402 } else { | |
| 6403 if (function->IsProperty()) { | |
| 6404 // Method calls | |
| 6405 if (function->AsProperty()->IsSuperAccess()) { | |
| 6406 Expression* home = | |
| 6407 ThisExpression(scope_, factory(), RelocInfo::kNoPosition); | |
| 6408 args->InsertAt(0, function, zone()); | |
| 6409 args->InsertAt(1, home, zone()); | |
| 6410 } else { | |
| 6411 Variable* temp = | |
| 6412 scope_->NewTemporary(ast_value_factory()->empty_string()); | |
| 6413 VariableProxy* obj = factory()->NewVariableProxy(temp); | |
| 6414 Assignment* assign_obj = factory()->NewAssignment( | |
| 6415 Token::ASSIGN, obj, function->AsProperty()->obj(), | |
| 6416 RelocInfo::kNoPosition); | |
| 6417 function = factory()->NewProperty( | |
| 6418 assign_obj, function->AsProperty()->key(), RelocInfo::kNoPosition); | |
| 6419 args->InsertAt(0, function, zone()); | |
| 6420 obj = factory()->NewVariableProxy(temp); | |
| 6421 args->InsertAt(1, obj, zone()); | |
| 6422 } | |
| 6423 } else { | |
| 6424 // Non-method calls | |
| 6425 args->InsertAt(0, function, zone()); | |
| 6426 args->InsertAt(1, factory()->NewUndefinedLiteral(RelocInfo::kNoPosition), | |
| 6427 zone()); | |
| 6428 } | |
| 6429 return factory()->NewCallRuntime(Context::REFLECT_APPLY_INDEX, args, pos); | |
| 6430 } | |
| 6431 } | |
| 6432 | |
| 6433 | |
| 6434 Expression* Parser::SpreadCallNew(Expression* function, | |
| 6435 ZoneList<v8::internal::Expression*>* args, | |
| 6436 int pos) { | |
| 6437 args->InsertAt(0, function, zone()); | |
| 6438 | |
| 6439 return factory()->NewCallRuntime(Context::REFLECT_CONSTRUCT_INDEX, args, pos); | |
| 6440 } | |
| 6441 | |
| 6442 | |
| 6443 void Parser::SetLanguageMode(Scope* scope, LanguageMode mode) { | |
| 6444 v8::Isolate::UseCounterFeature feature; | |
| 6445 if (is_sloppy(mode)) | |
| 6446 feature = v8::Isolate::kSloppyMode; | |
| 6447 else if (is_strong(mode)) | |
| 6448 feature = v8::Isolate::kStrongMode; | |
| 6449 else if (is_strict(mode)) | |
| 6450 feature = v8::Isolate::kStrictMode; | |
| 6451 else | |
| 6452 UNREACHABLE(); | |
| 6453 ++use_counts_[feature]; | |
| 6454 scope->SetLanguageMode(mode); | |
| 6455 } | |
| 6456 | |
| 6457 | |
| 6458 void Parser::RaiseLanguageMode(LanguageMode mode) { | |
| 6459 SetLanguageMode(scope_, | |
| 6460 static_cast<LanguageMode>(scope_->language_mode() | mode)); | |
| 6461 } | |
| 6462 | |
| 6463 } // namespace internal | |
| 6464 } // namespace v8 | |
| OLD | NEW |