Revert "Revert "Upgrade to 5.0.71.48"" DO NOT MERGE
This reverts commit f2e3994fa5148cc3d9946666f0b0596290192b0e,
and updates the x64 makefile properly so it doesn't break that
build.
FPIIM-449
Change-Id: Ib83e35bfbae6af627451c926a9650ec57c045605
(cherry picked from commit 109988c7ccb6f3fd1a58574fa3dfb88beaef6632)
diff --git a/src/parsing/expression-classifier.h b/src/parsing/expression-classifier.h
index 96ccf87..fa1a2f9 100644
--- a/src/parsing/expression-classifier.h
+++ b/src/parsing/expression-classifier.h
@@ -13,6 +13,7 @@
namespace internal {
+template <typename Traits>
class ExpressionClassifier {
public:
struct Error {
@@ -55,15 +56,25 @@
enum FunctionProperties { NonSimpleParameter = 1 << 0 };
- ExpressionClassifier()
- : invalid_productions_(0),
+ explicit ExpressionClassifier(const Traits* t)
+ : zone_(t->zone()),
+ non_patterns_to_rewrite_(t->GetNonPatternList()),
+ invalid_productions_(0),
function_properties_(0),
- duplicate_finder_(nullptr) {}
+ duplicate_finder_(nullptr) {
+ non_pattern_begin_ = non_patterns_to_rewrite_->length();
+ }
- explicit ExpressionClassifier(DuplicateFinder* duplicate_finder)
- : invalid_productions_(0),
+ ExpressionClassifier(const Traits* t, DuplicateFinder* duplicate_finder)
+ : zone_(t->zone()),
+ non_patterns_to_rewrite_(t->GetNonPatternList()),
+ invalid_productions_(0),
function_properties_(0),
- duplicate_finder_(duplicate_finder) {}
+ duplicate_finder_(duplicate_finder) {
+ non_pattern_begin_ = non_patterns_to_rewrite_->length();
+ }
+
+ ~ExpressionClassifier() { Discard(); }
bool is_valid(unsigned productions) const {
return (invalid_productions_ & productions) == 0;
@@ -281,12 +292,14 @@
assignment_pattern_error_ = Error();
}
- void Accumulate(const ExpressionClassifier& inner,
- unsigned productions = StandardProductions) {
+ void Accumulate(ExpressionClassifier* inner,
+ unsigned productions = StandardProductions,
+ bool merge_non_patterns = true) {
+ if (merge_non_patterns) MergeNonPatterns(inner);
// Propagate errors from inner, but don't overwrite already recorded
// errors.
unsigned non_arrow_inner_invalid_productions =
- inner.invalid_productions_ & ~ArrowFormalParametersProduction;
+ inner->invalid_productions_ & ~ArrowFormalParametersProduction;
if (non_arrow_inner_invalid_productions == 0) return;
unsigned non_arrow_productions =
productions & ~ArrowFormalParametersProduction;
@@ -296,27 +309,27 @@
if (errors != 0) {
invalid_productions_ |= errors;
if (errors & ExpressionProduction)
- expression_error_ = inner.expression_error_;
+ expression_error_ = inner->expression_error_;
if (errors & FormalParameterInitializerProduction)
formal_parameter_initializer_error_ =
- inner.formal_parameter_initializer_error_;
+ inner->formal_parameter_initializer_error_;
if (errors & BindingPatternProduction)
- binding_pattern_error_ = inner.binding_pattern_error_;
+ binding_pattern_error_ = inner->binding_pattern_error_;
if (errors & AssignmentPatternProduction)
- assignment_pattern_error_ = inner.assignment_pattern_error_;
+ assignment_pattern_error_ = inner->assignment_pattern_error_;
if (errors & DistinctFormalParametersProduction)
duplicate_formal_parameter_error_ =
- inner.duplicate_formal_parameter_error_;
+ inner->duplicate_formal_parameter_error_;
if (errors & StrictModeFormalParametersProduction)
strict_mode_formal_parameter_error_ =
- inner.strict_mode_formal_parameter_error_;
+ inner->strict_mode_formal_parameter_error_;
if (errors & StrongModeFormalParametersProduction)
strong_mode_formal_parameter_error_ =
- inner.strong_mode_formal_parameter_error_;
+ inner->strong_mode_formal_parameter_error_;
if (errors & LetPatternProduction)
- let_pattern_error_ = inner.let_pattern_error_;
+ let_pattern_error_ = inner->let_pattern_error_;
if (errors & CoverInitializedNameProduction)
- cover_initialized_name_error_ = inner.cover_initialized_name_error_;
+ cover_initialized_name_error_ = inner->cover_initialized_name_error_;
}
// As an exception to the above, the result continues to be a valid arrow
@@ -325,16 +338,31 @@
is_valid_arrow_formal_parameters()) {
// Also copy function properties if expecting an arrow function
// parameter.
- function_properties_ |= inner.function_properties_;
+ function_properties_ |= inner->function_properties_;
- if (!inner.is_valid_binding_pattern()) {
+ if (!inner->is_valid_binding_pattern()) {
invalid_productions_ |= ArrowFormalParametersProduction;
- arrow_formal_parameters_error_ = inner.binding_pattern_error_;
+ arrow_formal_parameters_error_ = inner->binding_pattern_error_;
}
}
}
+ V8_INLINE int GetNonPatternBegin() const { return non_pattern_begin_; }
+
+ V8_INLINE void Discard() {
+ DCHECK_LE(non_pattern_begin_, non_patterns_to_rewrite_->length());
+ non_patterns_to_rewrite_->Rewind(non_pattern_begin_);
+ }
+
+ V8_INLINE void MergeNonPatterns(ExpressionClassifier* inner) {
+ DCHECK_LE(non_pattern_begin_, inner->non_pattern_begin_);
+ inner->non_pattern_begin_ = inner->non_patterns_to_rewrite_->length();
+ }
+
private:
+ Zone* zone_;
+ ZoneList<typename Traits::Type::Expression>* non_patterns_to_rewrite_;
+ int non_pattern_begin_;
unsigned invalid_productions_;
unsigned function_properties_;
Error expression_error_;
@@ -350,6 +378,7 @@
DuplicateFinder* duplicate_finder_;
};
+
} // namespace internal
} // namespace v8
diff --git a/src/parsing/json-parser.h b/src/parsing/json-parser.h
deleted file mode 100644
index e23c733..0000000
--- a/src/parsing/json-parser.h
+++ /dev/null
@@ -1,842 +0,0 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef V8_PARSING_JSON_PARSER_H_
-#define V8_PARSING_JSON_PARSER_H_
-
-#include "src/char-predicates.h"
-#include "src/conversions.h"
-#include "src/debug/debug.h"
-#include "src/factory.h"
-#include "src/messages.h"
-#include "src/parsing/scanner.h"
-#include "src/parsing/token.h"
-#include "src/transitions.h"
-#include "src/types.h"
-
-namespace v8 {
-namespace internal {
-
-enum ParseElementResult { kElementFound, kElementNotFound, kNullHandle };
-
-
-// A simple json parser.
-template <bool seq_one_byte>
-class JsonParser BASE_EMBEDDED {
- public:
- MUST_USE_RESULT static MaybeHandle<Object> Parse(Handle<String> source) {
- return JsonParser(source).ParseJson();
- }
-
- static const int kEndOfString = -1;
-
- private:
- explicit JsonParser(Handle<String> source)
- : source_(source),
- source_length_(source->length()),
- isolate_(source->map()->GetHeap()->isolate()),
- factory_(isolate_->factory()),
- object_constructor_(isolate_->native_context()->object_function(),
- isolate_),
- position_(-1) {
- source_ = String::Flatten(source_);
- pretenure_ = (source_length_ >= kPretenureTreshold) ? TENURED : NOT_TENURED;
-
- // Optimized fast case where we only have Latin1 characters.
- if (seq_one_byte) {
- seq_source_ = Handle<SeqOneByteString>::cast(source_);
- }
- }
-
- // Parse a string containing a single JSON value.
- MaybeHandle<Object> ParseJson();
-
- inline void Advance() {
- position_++;
- if (position_ >= source_length_) {
- c0_ = kEndOfString;
- } else if (seq_one_byte) {
- c0_ = seq_source_->SeqOneByteStringGet(position_);
- } else {
- c0_ = source_->Get(position_);
- }
- }
-
- // The JSON lexical grammar is specified in the ECMAScript 5 standard,
- // section 15.12.1.1. The only allowed whitespace characters between tokens
- // are tab, carriage-return, newline and space.
-
- inline void AdvanceSkipWhitespace() {
- do {
- Advance();
- } while (c0_ == ' ' || c0_ == '\t' || c0_ == '\n' || c0_ == '\r');
- }
-
- inline void SkipWhitespace() {
- while (c0_ == ' ' || c0_ == '\t' || c0_ == '\n' || c0_ == '\r') {
- Advance();
- }
- }
-
- inline uc32 AdvanceGetChar() {
- Advance();
- return c0_;
- }
-
- // Checks that current charater is c.
- // If so, then consume c and skip whitespace.
- inline bool MatchSkipWhiteSpace(uc32 c) {
- if (c0_ == c) {
- AdvanceSkipWhitespace();
- return true;
- }
- return false;
- }
-
- // A JSON string (production JSONString) is subset of valid JavaScript string
- // literals. The string must only be double-quoted (not single-quoted), and
- // the only allowed backslash-escapes are ", /, \, b, f, n, r, t and
- // four-digit hex escapes (uXXXX). Any other use of backslashes is invalid.
- Handle<String> ParseJsonString() {
- return ScanJsonString<false>();
- }
-
- bool ParseJsonString(Handle<String> expected) {
- int length = expected->length();
- if (source_->length() - position_ - 1 > length) {
- DisallowHeapAllocation no_gc;
- String::FlatContent content = expected->GetFlatContent();
- if (content.IsOneByte()) {
- DCHECK_EQ('"', c0_);
- const uint8_t* input_chars = seq_source_->GetChars() + position_ + 1;
- const uint8_t* expected_chars = content.ToOneByteVector().start();
- for (int i = 0; i < length; i++) {
- uint8_t c0 = input_chars[i];
- if (c0 != expected_chars[i] || c0 == '"' || c0 < 0x20 || c0 == '\\') {
- return false;
- }
- }
- if (input_chars[length] == '"') {
- position_ = position_ + length + 1;
- AdvanceSkipWhitespace();
- return true;
- }
- }
- }
- return false;
- }
-
- Handle<String> ParseJsonInternalizedString() {
- return ScanJsonString<true>();
- }
-
- template <bool is_internalized>
- Handle<String> ScanJsonString();
- // Creates a new string and copies prefix[start..end] into the beginning
- // of it. Then scans the rest of the string, adding characters after the
- // prefix. Called by ScanJsonString when reaching a '\' or non-Latin1 char.
- template <typename StringType, typename SinkChar>
- Handle<String> SlowScanJsonString(Handle<String> prefix, int start, int end);
-
- // A JSON number (production JSONNumber) is a subset of the valid JavaScript
- // decimal number literals.
- // It includes an optional minus sign, must have at least one
- // digit before and after a decimal point, may not have prefixed zeros (unless
- // the integer part is zero), and may include an exponent part (e.g., "e-10").
- // Hexadecimal and octal numbers are not allowed.
- Handle<Object> ParseJsonNumber();
-
- // Parse a single JSON value from input (grammar production JSONValue).
- // A JSON value is either a (double-quoted) string literal, a number literal,
- // one of "true", "false", or "null", or an object or array literal.
- Handle<Object> ParseJsonValue();
-
- // Parse a JSON object literal (grammar production JSONObject).
- // An object literal is a squiggly-braced and comma separated sequence
- // (possibly empty) of key/value pairs, where the key is a JSON string
- // literal, the value is a JSON value, and the two are separated by a colon.
- // A JSON array doesn't allow numbers and identifiers as keys, like a
- // JavaScript array.
- Handle<Object> ParseJsonObject();
-
- // Helper for ParseJsonObject. Parses the form "123": obj, which is recorded
- // as an element, not a property.
- ParseElementResult ParseElement(Handle<JSObject> json_object);
-
- // Parses a JSON array literal (grammar production JSONArray). An array
- // literal is a square-bracketed and comma separated sequence (possibly empty)
- // of JSON values.
- // A JSON array doesn't allow leaving out values from the sequence, nor does
- // it allow a terminal comma, like a JavaScript array does.
- Handle<Object> ParseJsonArray();
-
-
- // Mark that a parsing error has happened at the current token, and
- // return a null handle. Primarily for readability.
- inline Handle<Object> ReportUnexpectedCharacter() {
- return Handle<Object>::null();
- }
-
- inline Isolate* isolate() { return isolate_; }
- inline Factory* factory() { return factory_; }
- inline Handle<JSFunction> object_constructor() { return object_constructor_; }
-
- static const int kInitialSpecialStringLength = 32;
- static const int kPretenureTreshold = 100 * 1024;
-
-
- private:
- Zone* zone() { return &zone_; }
-
- void CommitStateToJsonObject(Handle<JSObject> json_object, Handle<Map> map,
- ZoneList<Handle<Object> >* properties);
-
- Handle<String> source_;
- int source_length_;
- Handle<SeqOneByteString> seq_source_;
-
- PretenureFlag pretenure_;
- Isolate* isolate_;
- Factory* factory_;
- Zone zone_;
- Handle<JSFunction> object_constructor_;
- uc32 c0_;
- int position_;
-};
-
-template <bool seq_one_byte>
-MaybeHandle<Object> JsonParser<seq_one_byte>::ParseJson() {
- // Advance to the first character (possibly EOS)
- AdvanceSkipWhitespace();
- Handle<Object> result = ParseJsonValue();
- if (result.is_null() || c0_ != kEndOfString) {
- // Some exception (for example stack overflow) is already pending.
- if (isolate_->has_pending_exception()) return Handle<Object>::null();
-
- // Parse failed. Current character is the unexpected token.
- Factory* factory = this->factory();
- MessageTemplate::Template message;
- Handle<String> argument;
-
- switch (c0_) {
- case kEndOfString:
- message = MessageTemplate::kUnexpectedEOS;
- break;
- case '-':
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- message = MessageTemplate::kUnexpectedTokenNumber;
- break;
- case '"':
- message = MessageTemplate::kUnexpectedTokenString;
- break;
- default:
- message = MessageTemplate::kUnexpectedToken;
- argument = factory->LookupSingleCharacterStringFromCode(c0_);
- break;
- }
-
- Handle<Script> script(factory->NewScript(source_));
- // We should sent compile error event because we compile JSON object in
- // separated source file.
- isolate()->debug()->OnCompileError(script);
- MessageLocation location(script, position_, position_ + 1);
- Handle<Object> error = factory->NewSyntaxError(message, argument);
- return isolate()->template Throw<Object>(error, &location);
- }
- return result;
-}
-
-
-// Parse any JSON value.
-template <bool seq_one_byte>
-Handle<Object> JsonParser<seq_one_byte>::ParseJsonValue() {
- StackLimitCheck stack_check(isolate_);
- if (stack_check.HasOverflowed()) {
- isolate_->StackOverflow();
- return Handle<Object>::null();
- }
-
- if (stack_check.InterruptRequested()) {
- ExecutionAccess access(isolate_);
- // Avoid blocking GC in long running parser (v8:3974).
- isolate_->stack_guard()->HandleGCInterrupt();
- }
-
- if (c0_ == '"') return ParseJsonString();
- if ((c0_ >= '0' && c0_ <= '9') || c0_ == '-') return ParseJsonNumber();
- if (c0_ == '{') return ParseJsonObject();
- if (c0_ == '[') return ParseJsonArray();
- if (c0_ == 'f') {
- if (AdvanceGetChar() == 'a' && AdvanceGetChar() == 'l' &&
- AdvanceGetChar() == 's' && AdvanceGetChar() == 'e') {
- AdvanceSkipWhitespace();
- return factory()->false_value();
- }
- return ReportUnexpectedCharacter();
- }
- if (c0_ == 't') {
- if (AdvanceGetChar() == 'r' && AdvanceGetChar() == 'u' &&
- AdvanceGetChar() == 'e') {
- AdvanceSkipWhitespace();
- return factory()->true_value();
- }
- return ReportUnexpectedCharacter();
- }
- if (c0_ == 'n') {
- if (AdvanceGetChar() == 'u' && AdvanceGetChar() == 'l' &&
- AdvanceGetChar() == 'l') {
- AdvanceSkipWhitespace();
- return factory()->null_value();
- }
- return ReportUnexpectedCharacter();
- }
- return ReportUnexpectedCharacter();
-}
-
-
-template <bool seq_one_byte>
-ParseElementResult JsonParser<seq_one_byte>::ParseElement(
- Handle<JSObject> json_object) {
- uint32_t index = 0;
- // Maybe an array index, try to parse it.
- if (c0_ == '0') {
- // With a leading zero, the string has to be "0" only to be an index.
- Advance();
- } else {
- do {
- int d = c0_ - '0';
- if (index > 429496729U - ((d + 3) >> 3)) break;
- index = (index * 10) + d;
- Advance();
- } while (IsDecimalDigit(c0_));
- }
-
- if (c0_ == '"') {
- // Successfully parsed index, parse and store element.
- AdvanceSkipWhitespace();
-
- if (c0_ == ':') {
- AdvanceSkipWhitespace();
- Handle<Object> value = ParseJsonValue();
- if (!value.is_null()) {
- JSObject::SetOwnElementIgnoreAttributes(json_object, index, value, NONE)
- .Assert();
- return kElementFound;
- } else {
- return kNullHandle;
- }
- }
- }
- return kElementNotFound;
-}
-
-// Parse a JSON object. Position must be right at '{'.
-template <bool seq_one_byte>
-Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() {
- HandleScope scope(isolate());
- Handle<JSObject> json_object =
- factory()->NewJSObject(object_constructor(), pretenure_);
- Handle<Map> map(json_object->map());
- int descriptor = 0;
- ZoneList<Handle<Object> > properties(8, zone());
- DCHECK_EQ(c0_, '{');
-
- bool transitioning = true;
-
- AdvanceSkipWhitespace();
- if (c0_ != '}') {
- do {
- if (c0_ != '"') return ReportUnexpectedCharacter();
-
- int start_position = position_;
- Advance();
-
- if (IsDecimalDigit(c0_)) {
- ParseElementResult element_result = ParseElement(json_object);
- if (element_result == kNullHandle) return Handle<Object>::null();
- if (element_result == kElementFound) continue;
- }
- // Not an index, fallback to the slow path.
-
- position_ = start_position;
-#ifdef DEBUG
- c0_ = '"';
-#endif
-
- Handle<String> key;
- Handle<Object> value;
-
- // Try to follow existing transitions as long as possible. Once we stop
- // transitioning, no transition can be found anymore.
- DCHECK(transitioning);
- // First check whether there is a single expected transition. If so, try
- // to parse it first.
- bool follow_expected = false;
- Handle<Map> target;
- if (seq_one_byte) {
- key = TransitionArray::ExpectedTransitionKey(map);
- follow_expected = !key.is_null() && ParseJsonString(key);
- }
- // If the expected transition hits, follow it.
- if (follow_expected) {
- target = TransitionArray::ExpectedTransitionTarget(map);
- } else {
- // If the expected transition failed, parse an internalized string and
- // try to find a matching transition.
- key = ParseJsonInternalizedString();
- if (key.is_null()) return ReportUnexpectedCharacter();
-
- target = TransitionArray::FindTransitionToField(map, key);
- // If a transition was found, follow it and continue.
- transitioning = !target.is_null();
- }
- if (c0_ != ':') return ReportUnexpectedCharacter();
-
- AdvanceSkipWhitespace();
- value = ParseJsonValue();
- if (value.is_null()) return ReportUnexpectedCharacter();
-
- if (transitioning) {
- PropertyDetails details =
- target->instance_descriptors()->GetDetails(descriptor);
- Representation expected_representation = details.representation();
-
- if (value->FitsRepresentation(expected_representation)) {
- if (expected_representation.IsHeapObject() &&
- !target->instance_descriptors()
- ->GetFieldType(descriptor)
- ->NowContains(value)) {
- Handle<HeapType> value_type(
- value->OptimalType(isolate(), expected_representation));
- Map::GeneralizeFieldType(target, descriptor,
- expected_representation, value_type);
- }
- DCHECK(target->instance_descriptors()
- ->GetFieldType(descriptor)
- ->NowContains(value));
- properties.Add(value, zone());
- map = target;
- descriptor++;
- continue;
- } else {
- transitioning = false;
- }
- }
-
- DCHECK(!transitioning);
-
- // Commit the intermediate state to the object and stop transitioning.
- CommitStateToJsonObject(json_object, map, &properties);
-
- JSObject::DefinePropertyOrElementIgnoreAttributes(json_object, key, value)
- .Check();
- } while (transitioning && MatchSkipWhiteSpace(','));
-
- // If we transitioned until the very end, transition the map now.
- if (transitioning) {
- CommitStateToJsonObject(json_object, map, &properties);
- } else {
- while (MatchSkipWhiteSpace(',')) {
- HandleScope local_scope(isolate());
- if (c0_ != '"') return ReportUnexpectedCharacter();
-
- int start_position = position_;
- Advance();
-
- if (IsDecimalDigit(c0_)) {
- ParseElementResult element_result = ParseElement(json_object);
- if (element_result == kNullHandle) return Handle<Object>::null();
- if (element_result == kElementFound) continue;
- }
- // Not an index, fallback to the slow path.
-
- position_ = start_position;
-#ifdef DEBUG
- c0_ = '"';
-#endif
-
- Handle<String> key;
- Handle<Object> value;
-
- key = ParseJsonInternalizedString();
- if (key.is_null() || c0_ != ':') return ReportUnexpectedCharacter();
-
- AdvanceSkipWhitespace();
- value = ParseJsonValue();
- if (value.is_null()) return ReportUnexpectedCharacter();
-
- JSObject::DefinePropertyOrElementIgnoreAttributes(json_object, key,
- value).Check();
- }
- }
-
- if (c0_ != '}') {
- return ReportUnexpectedCharacter();
- }
- }
- AdvanceSkipWhitespace();
- return scope.CloseAndEscape(json_object);
-}
-
-
-template <bool seq_one_byte>
-void JsonParser<seq_one_byte>::CommitStateToJsonObject(
- Handle<JSObject> json_object, Handle<Map> map,
- ZoneList<Handle<Object> >* properties) {
- JSObject::AllocateStorageForMap(json_object, map);
- DCHECK(!json_object->map()->is_dictionary_map());
-
- DisallowHeapAllocation no_gc;
-
- int length = properties->length();
- for (int i = 0; i < length; i++) {
- Handle<Object> value = (*properties)[i];
- json_object->WriteToField(i, *value);
- }
-}
-
-
-// Parse a JSON array. Position must be right at '['.
-template <bool seq_one_byte>
-Handle<Object> JsonParser<seq_one_byte>::ParseJsonArray() {
- HandleScope scope(isolate());
- ZoneList<Handle<Object> > elements(4, zone());
- DCHECK_EQ(c0_, '[');
-
- AdvanceSkipWhitespace();
- if (c0_ != ']') {
- do {
- Handle<Object> element = ParseJsonValue();
- if (element.is_null()) return ReportUnexpectedCharacter();
- elements.Add(element, zone());
- } while (MatchSkipWhiteSpace(','));
- if (c0_ != ']') {
- return ReportUnexpectedCharacter();
- }
- }
- AdvanceSkipWhitespace();
- // Allocate a fixed array with all the elements.
- Handle<FixedArray> fast_elements =
- factory()->NewFixedArray(elements.length(), pretenure_);
- for (int i = 0, n = elements.length(); i < n; i++) {
- fast_elements->set(i, *elements[i]);
- }
- Handle<Object> json_array = factory()->NewJSArrayWithElements(
- fast_elements, FAST_ELEMENTS, Strength::WEAK, pretenure_);
- return scope.CloseAndEscape(json_array);
-}
-
-
-template <bool seq_one_byte>
-Handle<Object> JsonParser<seq_one_byte>::ParseJsonNumber() {
- bool negative = false;
- int beg_pos = position_;
- if (c0_ == '-') {
- Advance();
- negative = true;
- }
- if (c0_ == '0') {
- Advance();
- // Prefix zero is only allowed if it's the only digit before
- // a decimal point or exponent.
- if (IsDecimalDigit(c0_)) return ReportUnexpectedCharacter();
- } else {
- int i = 0;
- int digits = 0;
- if (c0_ < '1' || c0_ > '9') return ReportUnexpectedCharacter();
- do {
- i = i * 10 + c0_ - '0';
- digits++;
- Advance();
- } while (IsDecimalDigit(c0_));
- if (c0_ != '.' && c0_ != 'e' && c0_ != 'E' && digits < 10) {
- SkipWhitespace();
- return Handle<Smi>(Smi::FromInt((negative ? -i : i)), isolate());
- }
- }
- if (c0_ == '.') {
- Advance();
- if (!IsDecimalDigit(c0_)) return ReportUnexpectedCharacter();
- do {
- Advance();
- } while (IsDecimalDigit(c0_));
- }
- if (AsciiAlphaToLower(c0_) == 'e') {
- Advance();
- if (c0_ == '-' || c0_ == '+') Advance();
- if (!IsDecimalDigit(c0_)) return ReportUnexpectedCharacter();
- do {
- Advance();
- } while (IsDecimalDigit(c0_));
- }
- int length = position_ - beg_pos;
- double number;
- if (seq_one_byte) {
- Vector<const uint8_t> chars(seq_source_->GetChars() + beg_pos, length);
- number = StringToDouble(isolate()->unicode_cache(), chars,
- NO_FLAGS, // Hex, octal or trailing junk.
- std::numeric_limits<double>::quiet_NaN());
- } else {
- Vector<uint8_t> buffer = Vector<uint8_t>::New(length);
- String::WriteToFlat(*source_, buffer.start(), beg_pos, position_);
- Vector<const uint8_t> result =
- Vector<const uint8_t>(buffer.start(), length);
- number = StringToDouble(isolate()->unicode_cache(),
- result,
- NO_FLAGS, // Hex, octal or trailing junk.
- 0.0);
- buffer.Dispose();
- }
- SkipWhitespace();
- return factory()->NewNumber(number, pretenure_);
-}
-
-
-template <typename StringType>
-inline void SeqStringSet(Handle<StringType> seq_str, int i, uc32 c);
-
-template <>
-inline void SeqStringSet(Handle<SeqTwoByteString> seq_str, int i, uc32 c) {
- seq_str->SeqTwoByteStringSet(i, c);
-}
-
-template <>
-inline void SeqStringSet(Handle<SeqOneByteString> seq_str, int i, uc32 c) {
- seq_str->SeqOneByteStringSet(i, c);
-}
-
-template <typename StringType>
-inline Handle<StringType> NewRawString(Factory* factory,
- int length,
- PretenureFlag pretenure);
-
-template <>
-inline Handle<SeqTwoByteString> NewRawString(Factory* factory,
- int length,
- PretenureFlag pretenure) {
- return factory->NewRawTwoByteString(length, pretenure).ToHandleChecked();
-}
-
-template <>
-inline Handle<SeqOneByteString> NewRawString(Factory* factory,
- int length,
- PretenureFlag pretenure) {
- return factory->NewRawOneByteString(length, pretenure).ToHandleChecked();
-}
-
-
-// Scans the rest of a JSON string starting from position_ and writes
-// prefix[start..end] along with the scanned characters into a
-// sequential string of type StringType.
-template <bool seq_one_byte>
-template <typename StringType, typename SinkChar>
-Handle<String> JsonParser<seq_one_byte>::SlowScanJsonString(
- Handle<String> prefix, int start, int end) {
- int count = end - start;
- int max_length = count + source_length_ - position_;
- int length = Min(max_length, Max(kInitialSpecialStringLength, 2 * count));
- Handle<StringType> seq_string =
- NewRawString<StringType>(factory(), length, pretenure_);
- // Copy prefix into seq_str.
- SinkChar* dest = seq_string->GetChars();
- String::WriteToFlat(*prefix, dest, start, end);
-
- while (c0_ != '"') {
- // Check for control character (0x00-0x1f) or unterminated string (<0).
- if (c0_ < 0x20) return Handle<String>::null();
- if (count >= length) {
- // We need to create a longer sequential string for the result.
- return SlowScanJsonString<StringType, SinkChar>(seq_string, 0, count);
- }
- if (c0_ != '\\') {
- // If the sink can contain UC16 characters, or source_ contains only
- // Latin1 characters, there's no need to test whether we can store the
- // character. Otherwise check whether the UC16 source character can fit
- // in the Latin1 sink.
- if (sizeof(SinkChar) == kUC16Size || seq_one_byte ||
- c0_ <= String::kMaxOneByteCharCode) {
- SeqStringSet(seq_string, count++, c0_);
- Advance();
- } else {
- // StringType is SeqOneByteString and we just read a non-Latin1 char.
- return SlowScanJsonString<SeqTwoByteString, uc16>(seq_string, 0, count);
- }
- } else {
- Advance(); // Advance past the \.
- switch (c0_) {
- case '"':
- case '\\':
- case '/':
- SeqStringSet(seq_string, count++, c0_);
- break;
- case 'b':
- SeqStringSet(seq_string, count++, '\x08');
- break;
- case 'f':
- SeqStringSet(seq_string, count++, '\x0c');
- break;
- case 'n':
- SeqStringSet(seq_string, count++, '\x0a');
- break;
- case 'r':
- SeqStringSet(seq_string, count++, '\x0d');
- break;
- case 't':
- SeqStringSet(seq_string, count++, '\x09');
- break;
- case 'u': {
- uc32 value = 0;
- for (int i = 0; i < 4; i++) {
- Advance();
- int digit = HexValue(c0_);
- if (digit < 0) {
- return Handle<String>::null();
- }
- value = value * 16 + digit;
- }
- if (sizeof(SinkChar) == kUC16Size ||
- value <= String::kMaxOneByteCharCode) {
- SeqStringSet(seq_string, count++, value);
- break;
- } else {
- // StringType is SeqOneByteString and we just read a non-Latin1
- // char.
- position_ -= 6; // Rewind position_ to \ in \uxxxx.
- Advance();
- return SlowScanJsonString<SeqTwoByteString, uc16>(seq_string,
- 0,
- count);
- }
- }
- default:
- return Handle<String>::null();
- }
- Advance();
- }
- }
-
- DCHECK_EQ('"', c0_);
- // Advance past the last '"'.
- AdvanceSkipWhitespace();
-
- // Shrink seq_string length to count and return.
- return SeqString::Truncate(seq_string, count);
-}
-
-
-template <bool seq_one_byte>
-template <bool is_internalized>
-Handle<String> JsonParser<seq_one_byte>::ScanJsonString() {
- DCHECK_EQ('"', c0_);
- Advance();
- if (c0_ == '"') {
- AdvanceSkipWhitespace();
- return factory()->empty_string();
- }
-
- if (seq_one_byte && is_internalized) {
- // Fast path for existing internalized strings. If the the string being
- // parsed is not a known internalized string, contains backslashes or
- // unexpectedly reaches the end of string, return with an empty handle.
- uint32_t running_hash = isolate()->heap()->HashSeed();
- int position = position_;
- uc32 c0 = c0_;
- do {
- if (c0 == '\\') {
- c0_ = c0;
- int beg_pos = position_;
- position_ = position;
- return SlowScanJsonString<SeqOneByteString, uint8_t>(source_,
- beg_pos,
- position_);
- }
- if (c0 < 0x20) return Handle<String>::null();
- running_hash = StringHasher::AddCharacterCore(running_hash,
- static_cast<uint16_t>(c0));
- position++;
- if (position >= source_length_) return Handle<String>::null();
- c0 = seq_source_->SeqOneByteStringGet(position);
- } while (c0 != '"');
- int length = position - position_;
- uint32_t hash = (length <= String::kMaxHashCalcLength)
- ? StringHasher::GetHashCore(running_hash)
- : static_cast<uint32_t>(length);
- Vector<const uint8_t> string_vector(
- seq_source_->GetChars() + position_, length);
- StringTable* string_table = isolate()->heap()->string_table();
- uint32_t capacity = string_table->Capacity();
- uint32_t entry = StringTable::FirstProbe(hash, capacity);
- uint32_t count = 1;
- Handle<String> result;
- while (true) {
- Object* element = string_table->KeyAt(entry);
- if (element == isolate()->heap()->undefined_value()) {
- // Lookup failure.
- result = factory()->InternalizeOneByteString(
- seq_source_, position_, length);
- break;
- }
- if (element != isolate()->heap()->the_hole_value() &&
- String::cast(element)->IsOneByteEqualTo(string_vector)) {
- result = Handle<String>(String::cast(element), isolate());
-#ifdef DEBUG
- uint32_t hash_field =
- (hash << String::kHashShift) | String::kIsNotArrayIndexMask;
- DCHECK_EQ(static_cast<int>(result->Hash()),
- static_cast<int>(hash_field >> String::kHashShift));
-#endif
- break;
- }
- entry = StringTable::NextProbe(entry, count++, capacity);
- }
- position_ = position;
- // Advance past the last '"'.
- AdvanceSkipWhitespace();
- return result;
- }
-
- int beg_pos = position_;
- // Fast case for Latin1 only without escape characters.
- do {
- // Check for control character (0x00-0x1f) or unterminated string (<0).
- if (c0_ < 0x20) return Handle<String>::null();
- if (c0_ != '\\') {
- if (seq_one_byte || c0_ <= String::kMaxOneByteCharCode) {
- Advance();
- } else {
- return SlowScanJsonString<SeqTwoByteString, uc16>(source_,
- beg_pos,
- position_);
- }
- } else {
- return SlowScanJsonString<SeqOneByteString, uint8_t>(source_,
- beg_pos,
- position_);
- }
- } while (c0_ != '"');
- int length = position_ - beg_pos;
- Handle<String> result =
- factory()->NewRawOneByteString(length, pretenure_).ToHandleChecked();
- uint8_t* dest = SeqOneByteString::cast(*result)->GetChars();
- String::WriteToFlat(*source_, dest, beg_pos, position_);
-
- DCHECK_EQ('"', c0_);
- // Advance past the last '"'.
- AdvanceSkipWhitespace();
- return result;
-}
-
-} // namespace internal
-} // namespace v8
-
-#endif // V8_PARSING_JSON_PARSER_H_
diff --git a/src/parsing/parser-base.h b/src/parsing/parser-base.h
index d9da445..6be19b3 100644
--- a/src/parsing/parser-base.h
+++ b/src/parsing/parser-base.h
@@ -88,6 +88,7 @@
typedef typename Traits::Type::Literal LiteralT;
typedef typename Traits::Type::ObjectLiteralProperty ObjectLiteralPropertyT;
typedef typename Traits::Type::StatementList StatementListT;
+ typedef typename Traits::Type::ExpressionClassifier ExpressionClassifier;
ParserBase(Zone* zone, Scanner* scanner, uintptr_t stack_limit,
v8::Extension* extension, AstValueFactory* ast_value_factory,
@@ -116,7 +117,8 @@
allow_strong_mode_(false),
allow_legacy_const_(true),
allow_harmony_do_expressions_(false),
- allow_harmony_function_name_(false) {}
+ allow_harmony_function_name_(false),
+ allow_harmony_function_sent_(false) {}
#define ALLOW_ACCESSORS(name) \
bool allow_##name() const { return allow_##name##_; } \
@@ -134,6 +136,7 @@
ALLOW_ACCESSORS(legacy_const);
ALLOW_ACCESSORS(harmony_do_expressions);
ALLOW_ACCESSORS(harmony_function_name);
+ ALLOW_ACCESSORS(harmony_function_sent);
#undef ALLOW_ACCESSORS
uintptr_t stack_limit() const { return stack_limit_; }
@@ -242,11 +245,37 @@
return destructuring_assignments_to_rewrite_;
}
+ List<ExpressionT>& expressions_in_tail_position() {
+ return expressions_in_tail_position_;
+ }
+ void AddExpressionInTailPosition(ExpressionT expression) {
+ if (collect_expressions_in_tail_position_) {
+ expressions_in_tail_position_.Add(expression);
+ }
+ }
+
+ bool collect_expressions_in_tail_position() const {
+ return collect_expressions_in_tail_position_;
+ }
+ void set_collect_expressions_in_tail_position(bool collect) {
+ collect_expressions_in_tail_position_ = collect;
+ }
+
+ ZoneList<ExpressionT>* non_patterns_to_rewrite() {
+ return &non_patterns_to_rewrite_;
+ }
+
+ private:
void AddDestructuringAssignment(DestructuringAssignment pair) {
destructuring_assignments_to_rewrite_.Add(pair);
}
- private:
+ V8_INLINE Scope* scope() { return *scope_stack_; }
+
+ void AddNonPatternForRewriting(ExpressionT expr) {
+ non_patterns_to_rewrite_.Add(expr, (*scope_stack_)->zone());
+ }
+
// Used to assign an index to each literal that needs materialization in
// the function. Includes regexp literals, and boilerplate for object and
// array literals.
@@ -276,12 +305,14 @@
Scope* outer_scope_;
List<DestructuringAssignment> destructuring_assignments_to_rewrite_;
-
- void RewriteDestructuringAssignments();
+ List<ExpressionT> expressions_in_tail_position_;
+ bool collect_expressions_in_tail_position_;
+ ZoneList<ExpressionT> non_patterns_to_rewrite_;
typename Traits::Type::Factory* factory_;
friend class ParserTraits;
+ friend class PreParserTraits;
friend class Checkpoint;
};
@@ -436,6 +467,9 @@
scanner()->is_next_contextual_keyword(keyword);
}
+ void ExpectMetaProperty(Vector<const char> property_name,
+ const char* full_name, int pos, bool* ok);
+
void ExpectContextualKeyword(Vector<const char> keyword, bool* ok) {
Expect(Token::IDENTIFIER, ok);
if (!*ok) return;
@@ -461,6 +495,10 @@
return false;
}
+ bool PeekInOrOf() {
+ return peek() == Token::IN || PeekContextualKeyword(CStrVector("of"));
+ }
+
// Checks whether an octal literal was last seen between beg_pos and end_pos.
// If so, reports an error. Only called for strict mode and template strings.
void CheckOctalLiteral(int beg_pos, int end_pos,
@@ -563,8 +601,8 @@
Scanner::Location location, Token::Value token,
MessageTemplate::Template message = MessageTemplate::kUnexpectedToken);
-
- void ReportClassifierError(const ExpressionClassifier::Error& error) {
+ void ReportClassifierError(
+ const typename ExpressionClassifier::Error& error) {
Traits::ReportMessageAt(error.location, error.message, error.arg,
error.type);
}
@@ -642,7 +680,7 @@
// neither a valid binding pattern nor a valid parenthesized formal
// parameter list, show the "arrow formal parameters" error if the formals
// started with a parenthesis, and the binding pattern error otherwise.
- const ExpressionClassifier::Error& error =
+ const typename ExpressionClassifier::Error& error =
parenthesized_formals ? classifier->arrow_formal_parameters_error()
: classifier->binding_pattern_error();
ReportClassifierError(error);
@@ -715,10 +753,6 @@
}
IdentifierT ParseIdentifierName(bool* ok);
- // Parses an identifier and determines whether or not it is 'get' or 'set'.
- IdentifierT ParseIdentifierNameOrGetOrSet(bool* is_get, bool* is_set,
- bool* ok);
-
ExpressionT ParseRegExpLiteral(bool seen_equal,
ExpressionClassifier* classifier, bool* ok);
@@ -728,12 +762,9 @@
ExpressionT ParseExpression(bool accept_IN, bool* ok);
ExpressionT ParseExpression(bool accept_IN, ExpressionClassifier* classifier,
bool* ok);
- ExpressionT ParseExpression(bool accept_IN, int flags,
- ExpressionClassifier* classifier, bool* ok);
ExpressionT ParseArrayLiteral(ExpressionClassifier* classifier, bool* ok);
ExpressionT ParsePropertyName(IdentifierT* name, bool* is_get, bool* is_set,
- bool* is_static, bool* is_computed_name,
- bool* is_identifier, bool* is_escaped_keyword,
+ bool* is_computed_name,
ExpressionClassifier* classifier, bool* ok);
ExpressionT ParseObjectLiteral(ExpressionClassifier* classifier, bool* ok);
ObjectLiteralPropertyT ParsePropertyDefinition(
@@ -744,21 +775,9 @@
Scanner::Location* first_spread_pos, ExpressionClassifier* classifier,
bool* ok);
- enum AssignmentExpressionFlags {
- kIsNormalAssignment = 0,
- kIsPossiblePatternElement = 1 << 0,
- kIsPossibleArrowFormals = 1 << 1
- };
-
- ExpressionT ParseAssignmentExpression(bool accept_IN, int flags,
- ExpressionClassifier* classifier,
- bool* ok);
ExpressionT ParseAssignmentExpression(bool accept_IN,
ExpressionClassifier* classifier,
- bool* ok) {
- return ParseAssignmentExpression(accept_IN, kIsNormalAssignment, classifier,
- ok);
- }
+ bool* ok);
ExpressionT ParseYieldExpression(ExpressionClassifier* classifier, bool* ok);
ExpressionT ParseConditionalExpression(bool accept_IN,
ExpressionClassifier* classifier,
@@ -794,9 +813,9 @@
ExpressionClassifier* classifier, bool* ok);
void ParseFormalParameterList(FormalParametersT* parameters,
ExpressionClassifier* classifier, bool* ok);
- void CheckArityRestrictions(
- int param_count, FunctionLiteral::ArityRestriction arity_restriction,
- bool has_rest, int formals_start_pos, int formals_end_pos, bool* ok);
+ void CheckArityRestrictions(int param_count, FunctionKind function_type,
+ bool has_rest, int formals_start_pos,
+ int formals_end_pos, bool* ok);
bool IsNextLetKeyword();
@@ -829,6 +848,10 @@
return true;
}
+ bool IsValidPattern(ExpressionT expression) {
+ return expression->IsObjectLiteral() || expression->IsArrayLiteral();
+ }
+
// Keep track of eval() calls since they disable all local variable
// optimizations. This checks if expression is an eval call, and if yes,
// forwards the information to scope.
@@ -932,9 +955,9 @@
bool allow_legacy_const_;
bool allow_harmony_do_expressions_;
bool allow_harmony_function_name_;
+ bool allow_harmony_function_sent_;
};
-
template <class Traits>
ParserBase<Traits>::FunctionState::FunctionState(
FunctionState** function_state_stack, Scope** scope_stack, Scope* scope,
@@ -950,6 +973,8 @@
outer_function_state_(*function_state_stack),
scope_stack_(scope_stack),
outer_scope_(*scope_stack),
+ collect_expressions_in_tail_position_(true),
+ non_patterns_to_rewrite_(0, scope->zone()),
factory_(factory) {
*scope_stack_ = scope;
*function_state_stack = this;
@@ -967,7 +992,6 @@
void ParserBase<Traits>::GetUnexpectedTokenMessage(
Token::Value token, MessageTemplate::Template* message, const char** arg,
MessageTemplate::Template default_) {
- // Four of the tokens are treated specially
switch (token) {
case Token::EOS:
*message = MessageTemplate::kUnexpectedEOS;
@@ -1037,7 +1061,7 @@
template <class Traits>
typename ParserBase<Traits>::IdentifierT ParserBase<Traits>::ParseIdentifier(
AllowRestrictedIdentifiers allow_restricted_identifiers, bool* ok) {
- ExpressionClassifier classifier;
+ ExpressionClassifier classifier(this);
auto result = ParseAndClassifyIdentifier(&classifier, ok);
if (!*ok) return Traits::EmptyIdentifier();
@@ -1091,10 +1115,8 @@
scanner()->location(), MessageTemplate::kStrongUndefined);
if (is_strong(language_mode())) {
// TODO(dslomov): allow 'undefined' in nested patterns.
- classifier->RecordBindingPatternError(
- scanner()->location(), MessageTemplate::kStrongUndefined);
- classifier->RecordAssignmentPatternError(
- scanner()->location(), MessageTemplate::kStrongUndefined);
+ classifier->RecordPatternError(scanner()->location(),
+ MessageTemplate::kStrongUndefined);
}
}
@@ -1116,7 +1138,9 @@
*ok = false;
return Traits::EmptyIdentifier();
}
- if (next == Token::LET) {
+ if (next == Token::LET ||
+ (next == Token::ESCAPED_STRICT_RESERVED_WORD &&
+ scanner()->is_literal_contextual_keyword(CStrVector("let")))) {
classifier->RecordLetPatternError(scanner()->location(),
MessageTemplate::kLetInLexicalBinding);
}
@@ -1172,18 +1196,6 @@
template <class Traits>
-typename ParserBase<Traits>::IdentifierT
-ParserBase<Traits>::ParseIdentifierNameOrGetOrSet(bool* is_get,
- bool* is_set,
- bool* ok) {
- IdentifierT result = ParseIdentifierName(ok);
- if (!*ok) return Traits::EmptyIdentifier();
- scanner()->IsGetOrSet(is_get, is_set);
- return result;
-}
-
-
-template <class Traits>
typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseRegExpLiteral(
bool seen_equal, ExpressionClassifier* classifier, bool* ok) {
int pos = peek_position();
@@ -1269,8 +1281,7 @@
return this->ExpressionFromLiteral(Next(), beg_pos, scanner(), factory());
case Token::SMI:
case Token::NUMBER:
- classifier->RecordBindingPatternError(
- scanner()->peek_location(), MessageTemplate::kUnexpectedTokenNumber);
+ BindingPatternUnexpectedToken(classifier);
return this->ExpressionFromLiteral(Next(), beg_pos, scanner(), factory());
case Token::IDENTIFIER:
@@ -1286,8 +1297,7 @@
}
case Token::STRING: {
- classifier->RecordBindingPatternError(
- scanner()->peek_location(), MessageTemplate::kUnexpectedTokenString);
+ BindingPatternUnexpectedToken(classifier);
Consume(Token::STRING);
return this->ExpressionFromString(beg_pos, scanner(), factory());
}
@@ -1323,7 +1333,9 @@
if (!classifier->is_valid_binding_pattern()) {
ArrowFormalParametersUnexpectedToken(classifier);
}
- BindingPatternUnexpectedToken(classifier);
+ classifier->RecordPatternError(scanner()->peek_location(),
+ MessageTemplate::kUnexpectedToken,
+ Token::String(Token::LPAREN));
Consume(Token::LPAREN);
if (Check(Token::RPAREN)) {
// ()=>x. The continuation that looks for the => is in
@@ -1331,20 +1343,23 @@
classifier->RecordExpressionError(scanner()->location(),
MessageTemplate::kUnexpectedToken,
Token::String(Token::RPAREN));
- classifier->RecordBindingPatternError(scanner()->location(),
- MessageTemplate::kUnexpectedToken,
- Token::String(Token::RPAREN));
return factory()->NewEmptyParentheses(beg_pos);
} else if (Check(Token::ELLIPSIS)) {
// (...x)=>x. The continuation that looks for the => is in
// ParseAssignmentExpression.
int ellipsis_pos = position();
+ int expr_pos = peek_position();
classifier->RecordExpressionError(scanner()->location(),
MessageTemplate::kUnexpectedToken,
Token::String(Token::ELLIPSIS));
classifier->RecordNonSimpleParameter();
ExpressionT expr =
this->ParseAssignmentExpression(true, classifier, CHECK_OK);
+ if (!this->IsIdentifier(expr) && !IsValidPattern(expr)) {
+ classifier->RecordArrowFormalParametersError(
+ Scanner::Location(ellipsis_pos, scanner()->location().end_pos),
+ MessageTemplate::kInvalidRestParameter);
+ }
if (peek() == Token::COMMA) {
ReportMessageAt(scanner()->peek_location(),
MessageTemplate::kParamAfterRest);
@@ -1352,17 +1367,13 @@
return this->EmptyExpression();
}
Expect(Token::RPAREN, CHECK_OK);
- return factory()->NewSpread(expr, ellipsis_pos);
+ return factory()->NewSpread(expr, ellipsis_pos, expr_pos);
}
// Heuristically try to detect immediately called functions before
// seeing the call parentheses.
parenthesized_function_ = (peek() == Token::FUNCTION);
- ExpressionT expr = this->ParseExpression(true, kIsPossibleArrowFormals,
- classifier, CHECK_OK);
+ ExpressionT expr = this->ParseExpression(true, classifier, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
- if (peek() != Token::ARROW) {
- expr->set_is_parenthesized();
- }
return expr;
}
@@ -1390,9 +1401,7 @@
case Token::TEMPLATE_SPAN:
case Token::TEMPLATE_TAIL:
- classifier->RecordBindingPatternError(
- scanner()->peek_location(),
- MessageTemplate::kUnexpectedTemplateString);
+ BindingPatternUnexpectedToken(classifier);
return this->ParseTemplateLiteral(Traits::NoTemplateTag(), beg_pos,
classifier, ok);
@@ -1423,9 +1432,9 @@
template <class Traits>
typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression(
bool accept_IN, bool* ok) {
- ExpressionClassifier classifier;
+ ExpressionClassifier classifier(this);
ExpressionT result = ParseExpression(accept_IN, &classifier, CHECK_OK);
- result = Traits::RewriteNonPattern(result, &classifier, CHECK_OK);
+ Traits::RewriteNonPattern(&classifier, CHECK_OK);
return result;
}
@@ -1433,21 +1442,14 @@
template <class Traits>
typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression(
bool accept_IN, ExpressionClassifier* classifier, bool* ok) {
- return ParseExpression(accept_IN, kIsNormalAssignment, classifier, ok);
-}
-
-
-template <class Traits>
-typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression(
- bool accept_IN, int flags, ExpressionClassifier* classifier, bool* ok) {
// Expression ::
// AssignmentExpression
// Expression ',' AssignmentExpression
- ExpressionClassifier binding_classifier;
- ExpressionT result = this->ParseAssignmentExpression(
- accept_IN, flags, &binding_classifier, CHECK_OK);
- classifier->Accumulate(binding_classifier,
+ ExpressionClassifier binding_classifier(this);
+ ExpressionT result =
+ this->ParseAssignmentExpression(accept_IN, &binding_classifier, CHECK_OK);
+ classifier->Accumulate(&binding_classifier,
ExpressionClassifier::AllProductions);
bool is_simple_parameter_list = this->IsIdentifier(result);
bool seen_rest = false;
@@ -1469,14 +1471,21 @@
Consume(Token::ELLIPSIS);
seen_rest = is_rest = true;
}
- int pos = position();
+ int pos = position(), expr_pos = peek_position();
ExpressionT right = this->ParseAssignmentExpression(
- accept_IN, flags, &binding_classifier, CHECK_OK);
- if (is_rest) right = factory()->NewSpread(right, pos);
+ accept_IN, &binding_classifier, CHECK_OK);
+ classifier->Accumulate(&binding_classifier,
+ ExpressionClassifier::AllProductions);
+ if (is_rest) {
+ if (!this->IsIdentifier(right) && !IsValidPattern(right)) {
+ classifier->RecordArrowFormalParametersError(
+ Scanner::Location(pos, scanner()->location().end_pos),
+ MessageTemplate::kInvalidRestParameter);
+ }
+ right = factory()->NewSpread(right, pos, expr_pos);
+ }
is_simple_parameter_list =
is_simple_parameter_list && this->IsIdentifier(right);
- classifier->Accumulate(binding_classifier,
- ExpressionClassifier::AllProductions);
result = factory()->NewBinaryOperation(Token::COMMA, result, right, pos);
}
if (!is_simple_parameter_list || seen_rest) {
@@ -1511,9 +1520,10 @@
} else if (peek() == Token::ELLIPSIS) {
int start_pos = peek_position();
Consume(Token::ELLIPSIS);
+ int expr_pos = peek_position();
ExpressionT argument =
this->ParseAssignmentExpression(true, classifier, CHECK_OK);
- elem = factory()->NewSpread(argument, start_pos);
+ elem = factory()->NewSpread(argument, start_pos, expr_pos);
if (first_spread_index < 0) {
first_spread_index = values->length();
@@ -1534,8 +1544,10 @@
MessageTemplate::kElementAfterRest);
}
} else {
- elem = this->ParseAssignmentExpression(true, kIsPossiblePatternElement,
- classifier, CHECK_OK);
+ int beg_pos = peek_position();
+ elem = this->ParseAssignmentExpression(true, classifier, CHECK_OK);
+ CheckDestructuringElement(elem, classifier, beg_pos,
+ scanner()->location().end_pos);
}
values->Add(elem, zone_);
if (peek() != Token::RBRACK) {
@@ -1547,15 +1559,20 @@
// Update the scope information before the pre-parsing bailout.
int literal_index = function_state_->NextMaterializedLiteralIndex();
- return factory()->NewArrayLiteral(values, first_spread_index, literal_index,
- is_strong(language_mode()), pos);
+ ExpressionT result =
+ factory()->NewArrayLiteral(values, first_spread_index, literal_index,
+ is_strong(language_mode()), pos);
+ if (first_spread_index >= 0) {
+ result = factory()->NewRewritableExpression(result);
+ Traits::QueueNonPatternForRewriting(result);
+ }
+ return result;
}
template <class Traits>
typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParsePropertyName(
- IdentifierT* name, bool* is_get, bool* is_set, bool* is_static,
- bool* is_computed_name, bool* is_identifier, bool* is_escaped_keyword,
+ IdentifierT* name, bool* is_get, bool* is_set, bool* is_computed_name,
ExpressionClassifier* classifier, bool* ok) {
Token::Value token = peek();
int pos = peek_position();
@@ -1588,29 +1605,19 @@
case Token::LBRACK: {
*is_computed_name = true;
Consume(Token::LBRACK);
- ExpressionClassifier computed_name_classifier;
+ ExpressionClassifier computed_name_classifier(this);
ExpressionT expression =
ParseAssignmentExpression(true, &computed_name_classifier, CHECK_OK);
- expression = Traits::RewriteNonPattern(
- expression, &computed_name_classifier, CHECK_OK);
- classifier->Accumulate(computed_name_classifier,
+ Traits::RewriteNonPattern(&computed_name_classifier, CHECK_OK);
+ classifier->Accumulate(&computed_name_classifier,
ExpressionClassifier::ExpressionProductions);
Expect(Token::RBRACK, CHECK_OK);
return expression;
}
- case Token::ESCAPED_KEYWORD:
- *is_escaped_keyword = true;
- *name = ParseIdentifierNameOrGetOrSet(is_get, is_set, CHECK_OK);
- break;
-
- case Token::STATIC:
- *is_static = true;
-
- // Fall through.
default:
- *is_identifier = true;
- *name = ParseIdentifierNameOrGetOrSet(is_get, is_set, CHECK_OK);
+ *name = ParseIdentifierName(CHECK_OK);
+ scanner()->IsGetOrSet(is_get, is_set);
break;
}
@@ -1631,27 +1638,19 @@
ExpressionT value = this->EmptyExpression();
bool is_get = false;
bool is_set = false;
- bool name_is_static = false;
bool is_generator = Check(Token::MUL);
Token::Value name_token = peek();
int next_beg_pos = scanner()->peek_location().beg_pos;
int next_end_pos = scanner()->peek_location().end_pos;
- bool is_identifier = false;
- bool is_escaped_keyword = false;
- ExpressionT name_expression = ParsePropertyName(
- name, &is_get, &is_set, &name_is_static, is_computed_name, &is_identifier,
- &is_escaped_keyword, classifier,
- CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+ ExpressionT name_expression =
+ ParsePropertyName(name, &is_get, &is_set, is_computed_name, classifier,
+ CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
if (fni_ != nullptr && !*is_computed_name) {
this->PushLiteralName(fni_, *name);
}
- bool escaped_static =
- is_escaped_keyword &&
- scanner()->is_literal_contextual_keyword(CStrVector("static"));
-
if (!in_class && !is_generator) {
DCHECK(!is_static);
@@ -1663,15 +1662,18 @@
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
}
Consume(Token::COLON);
+ int beg_pos = peek_position();
value = this->ParseAssignmentExpression(
- true, kIsPossiblePatternElement, classifier,
- CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+ true, classifier, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+ CheckDestructuringElement(value, classifier, beg_pos,
+ scanner()->location().end_pos);
return factory()->NewObjectLiteralProperty(name_expression, value, false,
*is_computed_name);
}
- if ((is_identifier || is_escaped_keyword) &&
+ if (Token::IsIdentifier(name_token, language_mode(),
+ this->is_generator()) &&
(peek() == Token::COMMA || peek() == Token::RBRACE ||
peek() == Token::ASSIGN)) {
// PropertyDefinition
@@ -1680,14 +1682,6 @@
//
// CoverInitializedName
// IdentifierReference Initializer?
- if (!Token::IsIdentifier(name_token, language_mode(),
- this->is_generator())) {
- if (!escaped_static) {
- ReportUnexpectedTokenAt(scanner()->location(), name_token);
- *ok = false;
- return this->EmptyObjectLiteralProperty();
- }
- }
if (classifier->duplicate_finder() != nullptr &&
scanner()->FindSymbol(classifier->duplicate_finder(), 1) != 0) {
classifier->RecordDuplicateFormalParameterError(scanner()->location());
@@ -1703,18 +1697,22 @@
if (peek() == Token::ASSIGN) {
Consume(Token::ASSIGN);
- ExpressionClassifier rhs_classifier;
+ ExpressionClassifier rhs_classifier(this);
ExpressionT rhs = this->ParseAssignmentExpression(
true, &rhs_classifier, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
- rhs = Traits::RewriteNonPattern(
- rhs, &rhs_classifier, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
- classifier->Accumulate(rhs_classifier,
+ Traits::RewriteNonPattern(&rhs_classifier,
+ CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+ classifier->Accumulate(&rhs_classifier,
ExpressionClassifier::ExpressionProductions);
value = factory()->NewAssignment(Token::ASSIGN, lhs, rhs,
RelocInfo::kNoPosition);
classifier->RecordCoverInitializedNameError(
Scanner::Location(next_beg_pos, scanner()->location().end_pos),
MessageTemplate::kInvalidCoverInitializedName);
+
+ if (allow_harmony_function_name()) {
+ Traits::SetFunctionNameFromIdentifierRef(rhs, lhs);
+ }
} else {
value = lhs;
}
@@ -1725,12 +1723,6 @@
}
}
- if (in_class && escaped_static && !is_static) {
- ReportUnexpectedTokenAt(scanner()->location(), name_token);
- *ok = false;
- return this->EmptyObjectLiteralProperty();
- }
-
// Method definitions are never valid in patterns.
classifier->RecordPatternError(
Scanner::Location(next_beg_pos, scanner()->location().end_pos),
@@ -1755,28 +1747,24 @@
: FunctionKind::kBaseConstructor;
}
- if (!in_class) kind = WithObjectLiteralBit(kind);
-
value = this->ParseFunctionLiteral(
*name, scanner()->location(), kSkipFunctionNameCheck, kind,
- RelocInfo::kNoPosition, FunctionLiteral::kAnonymousExpression,
- FunctionLiteral::kNormalArity, language_mode(),
- CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+ RelocInfo::kNoPosition, FunctionLiteral::kAccessorOrMethod,
+ language_mode(), CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
return factory()->NewObjectLiteralProperty(name_expression, value,
ObjectLiteralProperty::COMPUTED,
is_static, *is_computed_name);
}
- if (in_class && name_is_static && !is_static) {
+ if (in_class && name_token == Token::STATIC && !is_static) {
// ClassElement (static)
// 'static' MethodDefinition
*name = this->EmptyIdentifier();
ObjectLiteralPropertyT property = ParsePropertyDefinition(
checker, true, has_extends, true, is_computed_name, nullptr, classifier,
name, ok);
- property = Traits::RewriteNonPatternObjectLiteralProperty(property,
- classifier, ok);
+ Traits::RewriteNonPattern(classifier, ok);
return property;
}
@@ -1789,8 +1777,8 @@
name_token = peek();
name_expression = ParsePropertyName(
- name, &dont_care, &dont_care, &dont_care, is_computed_name, &dont_care,
- &dont_care, classifier, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+ name, &dont_care, &dont_care, is_computed_name, classifier,
+ CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
if (!*is_computed_name) {
checker->CheckProperty(name_token, kAccessorProperty, is_static,
@@ -1798,12 +1786,10 @@
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
}
- FunctionKind kind = FunctionKind::kAccessorFunction;
- if (!in_class) kind = WithObjectLiteralBit(kind);
typename Traits::Type::FunctionLiteral value = this->ParseFunctionLiteral(
- *name, scanner()->location(), kSkipFunctionNameCheck, kind,
- RelocInfo::kNoPosition, FunctionLiteral::kAnonymousExpression,
- is_get ? FunctionLiteral::kGetterArity : FunctionLiteral::kSetterArity,
+ *name, scanner()->location(), kSkipFunctionNameCheck,
+ is_get ? FunctionKind::kGetterFunction : FunctionKind::kSetterFunction,
+ RelocInfo::kNoPosition, FunctionLiteral::kAccessorOrMethod,
language_mode(), CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
// Make sure the name expression is a string since we need a Name for
@@ -1913,17 +1899,17 @@
while (!done) {
int start_pos = peek_position();
bool is_spread = Check(Token::ELLIPSIS);
+ int expr_pos = peek_position();
ExpressionT argument = this->ParseAssignmentExpression(
true, classifier, CHECK_OK_CUSTOM(NullExpressionList));
- argument = Traits::RewriteNonPattern(argument, classifier,
- CHECK_OK_CUSTOM(NullExpressionList));
+ Traits::RewriteNonPattern(classifier, CHECK_OK_CUSTOM(NullExpressionList));
if (is_spread) {
if (!spread_arg.IsValid()) {
spread_arg.beg_pos = start_pos;
spread_arg.end_pos = peek_position();
}
- argument = factory()->NewSpread(argument, start_pos);
+ argument = factory()->NewSpread(argument, start_pos, expr_pos);
}
result->Add(argument, zone_);
@@ -1967,7 +1953,7 @@
// Precedence = 2
template <class Traits>
typename ParserBase<Traits>::ExpressionT
-ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN, int flags,
+ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
ExpressionClassifier* classifier,
bool* ok) {
// AssignmentExpression ::
@@ -1975,8 +1961,6 @@
// ArrowFunction
// YieldExpression
// LeftHandSideExpression AssignmentOperator AssignmentExpression
- bool maybe_pattern_element = flags & kIsPossiblePatternElement;
- bool maybe_arrow_formals = flags & kIsPossibleArrowFormals;
bool is_destructuring_assignment = false;
int lhs_beg_pos = peek_position();
@@ -1986,7 +1970,8 @@
FuncNameInferrer::State fni_state(fni_);
ParserBase<Traits>::Checkpoint checkpoint(this);
- ExpressionClassifier arrow_formals_classifier(classifier->duplicate_finder());
+ ExpressionClassifier arrow_formals_classifier(this,
+ classifier->duplicate_finder());
bool parenthesized_formals = peek() == Token::LPAREN;
if (!parenthesized_formals) {
ArrowFormalParametersUnexpectedToken(&arrow_formals_classifier);
@@ -1994,7 +1979,9 @@
ExpressionT expression = this->ParseConditionalExpression(
accept_IN, &arrow_formals_classifier, CHECK_OK);
if (peek() == Token::ARROW) {
- BindingPatternUnexpectedToken(classifier);
+ classifier->RecordPatternError(scanner()->peek_location(),
+ MessageTemplate::kUnexpectedToken,
+ Token::String(Token::ARROW));
ValidateArrowFormalParameters(&arrow_formals_classifier, expression,
parenthesized_formals, CHECK_OK);
Scanner::Location loc(lhs_beg_pos, scanner()->location().end_pos);
@@ -2022,11 +2009,6 @@
}
expression = this->ParseArrowFunctionLiteral(
accept_IN, parameters, arrow_formals_classifier, CHECK_OK);
- if (maybe_pattern_element) {
- classifier->RecordPatternError(
- Scanner::Location(lhs_beg_pos, scanner()->location().end_pos),
- MessageTemplate::kInvalidDestructuringTarget);
- }
if (fni_ != nullptr) fni_->Infer();
@@ -2039,44 +2021,42 @@
// "expression" was not itself an arrow function parameter list, but it might
// form part of one. Propagate speculative formal parameter error locations.
+ // Do not merge pending non-pattern expressions yet!
classifier->Accumulate(
- arrow_formals_classifier,
+ &arrow_formals_classifier,
ExpressionClassifier::StandardProductions |
- ExpressionClassifier::FormalParametersProductions |
- ExpressionClassifier::CoverInitializedNameProduction);
-
- bool maybe_pattern =
- (expression->IsObjectLiteral() || expression->IsArrayLiteral()) &&
- !expression->is_parenthesized();
+ ExpressionClassifier::FormalParametersProductions |
+ ExpressionClassifier::CoverInitializedNameProduction,
+ false);
if (!Token::IsAssignmentOp(peek())) {
// Parsed conditional expression only (no assignment).
- if (maybe_pattern_element) {
- CheckDestructuringElement(expression, classifier, lhs_beg_pos,
- scanner()->location().end_pos);
- }
+ // Now pending non-pattern expressions must be merged.
+ classifier->MergeNonPatterns(&arrow_formals_classifier);
return expression;
}
+ // Now pending non-pattern expressions must be discarded.
+ arrow_formals_classifier.Discard();
+
if (!(allow_harmony_destructuring_bind() ||
allow_harmony_default_parameters())) {
BindingPatternUnexpectedToken(classifier);
}
- if (allow_harmony_destructuring_assignment() && maybe_pattern &&
+ if (allow_harmony_destructuring_assignment() && IsValidPattern(expression) &&
peek() == Token::ASSIGN) {
classifier->ForgiveCoverInitializedNameError();
ValidateAssignmentPattern(classifier, CHECK_OK);
is_destructuring_assignment = true;
- } else if (maybe_arrow_formals) {
+ } else if (allow_harmony_default_parameters() &&
+ !allow_harmony_destructuring_assignment()) {
+ // TODO(adamk): This branch should be removed once the destructuring
+ // assignment and default parameter flags are removed.
expression = this->ClassifyAndRewriteReferenceExpression(
classifier, expression, lhs_beg_pos, scanner()->location().end_pos,
MessageTemplate::kInvalidLhsInAssignment);
} else {
- if (maybe_pattern_element) {
- CheckDestructuringElement(expression, classifier, lhs_beg_pos,
- scanner()->location().end_pos);
- }
expression = this->CheckAndRewriteReferenceExpression(
expression, lhs_beg_pos, scanner()->location().end_pos,
MessageTemplate::kInvalidLhsInAssignment, CHECK_OK);
@@ -2086,20 +2066,20 @@
Token::Value op = Next(); // Get assignment operator.
if (op != Token::ASSIGN) {
- classifier->RecordBindingPatternError(scanner()->location(),
- MessageTemplate::kUnexpectedToken,
- Token::String(op));
+ classifier->RecordPatternError(scanner()->location(),
+ MessageTemplate::kUnexpectedToken,
+ Token::String(op));
}
int pos = position();
- ExpressionClassifier rhs_classifier;
+ ExpressionClassifier rhs_classifier(this);
ExpressionT right =
this->ParseAssignmentExpression(accept_IN, &rhs_classifier, CHECK_OK);
- right = Traits::RewriteNonPattern(right, &rhs_classifier, CHECK_OK);
+ Traits::RewriteNonPattern(&rhs_classifier, CHECK_OK);
classifier->Accumulate(
- rhs_classifier, ExpressionClassifier::ExpressionProductions |
- ExpressionClassifier::CoverInitializedNameProduction);
+ &rhs_classifier, ExpressionClassifier::ExpressionProductions |
+ ExpressionClassifier::CoverInitializedNameProduction);
// TODO(1231235): We try to estimate the set of properties set by
// constructors. We define a new property whenever there is an
@@ -2110,12 +2090,6 @@
function_state_->AddProperty();
}
- if (op != Token::ASSIGN && maybe_pattern_element) {
- classifier->RecordAssignmentPatternError(
- Scanner::Location(lhs_beg_pos, scanner()->location().end_pos),
- MessageTemplate::kInvalidDestructuringTarget);
- }
-
this->CheckAssigningFunctionLiteralToProperty(expression, right);
if (fni_ != NULL) {
@@ -2137,7 +2111,7 @@
ExpressionT result = factory()->NewAssignment(op, expression, right, pos);
if (is_destructuring_assignment) {
- result = factory()->NewRewritableAssignmentExpression(result);
+ result = factory()->NewRewritableExpression(result);
Traits::QueueDestructuringAssignmentForRewriting(result);
}
@@ -2179,16 +2153,12 @@
// Delegating yields require an RHS; fall through.
default:
expression = ParseAssignmentExpression(false, classifier, CHECK_OK);
- expression =
- Traits::RewriteNonPattern(expression, classifier, CHECK_OK);
+ Traits::RewriteNonPattern(classifier, CHECK_OK);
break;
}
}
if (kind == Yield::kDelegating) {
- // var iterator = subject[Symbol.iterator]();
- // Hackily disambiguate o from o.next and o [Symbol.iterator]().
- // TODO(verwaest): Come up with a better solution.
- expression = this->GetIterator(expression, factory(), pos + 1);
+ return Traits::RewriteYieldStar(generator_object, expression, pos);
}
// Hackily disambiguate o from o.next and o [Symbol.iterator]().
// TODO(verwaest): Come up with a better solution.
@@ -2213,7 +2183,7 @@
ExpressionT expression =
this->ParseBinaryExpression(4, accept_IN, classifier, CHECK_OK);
if (peek() != Token::CONDITIONAL) return expression;
- expression = Traits::RewriteNonPattern(expression, classifier, CHECK_OK);
+ Traits::RewriteNonPattern(classifier, CHECK_OK);
ArrowFormalParametersUnexpectedToken(classifier);
BindingPatternUnexpectedToken(classifier);
Consume(Token::CONDITIONAL);
@@ -2221,11 +2191,11 @@
// expressions we always accept the 'in' keyword; see ECMA-262,
// section 11.12, page 58.
ExpressionT left = ParseAssignmentExpression(true, classifier, CHECK_OK);
- left = Traits::RewriteNonPattern(left, classifier, CHECK_OK);
+ Traits::RewriteNonPattern(classifier, CHECK_OK);
Expect(Token::COLON, CHECK_OK);
ExpressionT right =
ParseAssignmentExpression(accept_IN, classifier, CHECK_OK);
- right = Traits::RewriteNonPattern(right, classifier, CHECK_OK);
+ Traits::RewriteNonPattern(classifier, CHECK_OK);
return factory()->NewConditional(expression, left, right, pos);
}
@@ -2241,7 +2211,7 @@
for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) {
// prec1 >= 4
while (Precedence(peek(), accept_IN) == prec1) {
- x = Traits::RewriteNonPattern(x, classifier, CHECK_OK);
+ Traits::RewriteNonPattern(classifier, CHECK_OK);
BindingPatternUnexpectedToken(classifier);
ArrowFormalParametersUnexpectedToken(classifier);
Token::Value op = Next();
@@ -2249,7 +2219,7 @@
int pos = position();
ExpressionT y =
ParseBinaryExpression(prec1 + 1, accept_IN, classifier, CHECK_OK);
- y = Traits::RewriteNonPattern(y, classifier, CHECK_OK);
+ Traits::RewriteNonPattern(classifier, CHECK_OK);
if (this->ShortcutNumericLiteralBinaryExpression(&x, y, op, pos,
factory())) {
@@ -2271,13 +2241,15 @@
ReportMessageAt(op_location, MessageTemplate::kStrongEqual);
*ok = false;
return this->EmptyExpression();
+ } else if (FLAG_harmony_instanceof && cmp == Token::INSTANCEOF) {
+ x = Traits::RewriteInstanceof(x, y, pos);
+ } else {
+ x = factory()->NewCompareOperation(cmp, x, y, pos);
+ if (cmp != op) {
+ // The comparison was negated - add a NOT.
+ x = factory()->NewUnaryOperation(Token::NOT, x, pos);
+ }
}
- x = factory()->NewCompareOperation(cmp, x, y, pos);
- if (cmp != op) {
- // The comparison was negated - add a NOT.
- x = factory()->NewUnaryOperation(Token::NOT, x, pos);
- }
-
} else {
// We have a "normal" binary operation.
x = factory()->NewBinaryOperation(op, x, y, pos);
@@ -2312,7 +2284,7 @@
op = Next();
int pos = position();
ExpressionT expression = ParseUnaryExpression(classifier, CHECK_OK);
- expression = Traits::RewriteNonPattern(expression, classifier, CHECK_OK);
+ Traits::RewriteNonPattern(classifier, CHECK_OK);
if (op == Token::DELETE && is_strict(language_mode())) {
if (is_strong(language_mode())) {
@@ -2339,7 +2311,7 @@
expression, beg_pos, scanner()->location().end_pos,
MessageTemplate::kInvalidLhsInPrefixOp, CHECK_OK);
this->MarkExpressionAsAssigned(expression);
- expression = Traits::RewriteNonPattern(expression, classifier, CHECK_OK);
+ Traits::RewriteNonPattern(classifier, CHECK_OK);
return factory()->NewCountOperation(op,
true /* prefix */,
@@ -2371,7 +2343,7 @@
expression, lhs_beg_pos, scanner()->location().end_pos,
MessageTemplate::kInvalidLhsInPostfixOp, CHECK_OK);
expression = this->MarkExpressionAsAssigned(expression);
- expression = Traits::RewriteNonPattern(expression, classifier, CHECK_OK);
+ Traits::RewriteNonPattern(classifier, CHECK_OK);
Token::Value next = Next();
expression =
@@ -2397,19 +2369,20 @@
while (true) {
switch (peek()) {
case Token::LBRACK: {
+ Traits::RewriteNonPattern(classifier, CHECK_OK);
BindingPatternUnexpectedToken(classifier);
ArrowFormalParametersUnexpectedToken(classifier);
Consume(Token::LBRACK);
int pos = position();
ExpressionT index = ParseExpression(true, classifier, CHECK_OK);
- index = Traits::RewriteNonPattern(index, classifier, CHECK_OK);
+ Traits::RewriteNonPattern(classifier, CHECK_OK);
result = factory()->NewProperty(result, index, pos);
Expect(Token::RBRACK, CHECK_OK);
break;
}
case Token::LPAREN: {
- result = Traits::RewriteNonPattern(result, classifier, CHECK_OK);
+ Traits::RewriteNonPattern(classifier, CHECK_OK);
BindingPatternUnexpectedToken(classifier);
ArrowFormalParametersUnexpectedToken(classifier);
@@ -2473,6 +2446,7 @@
}
case Token::PERIOD: {
+ Traits::RewriteNonPattern(classifier, CHECK_OK);
BindingPatternUnexpectedToken(classifier);
ArrowFormalParametersUnexpectedToken(classifier);
Consume(Token::PERIOD);
@@ -2486,6 +2460,7 @@
case Token::TEMPLATE_SPAN:
case Token::TEMPLATE_TAIL: {
+ Traits::RewriteNonPattern(classifier, CHECK_OK);
BindingPatternUnexpectedToken(classifier);
ArrowFormalParametersUnexpectedToken(classifier);
result = ParseTemplateLiteral(result, position(), classifier, CHECK_OK);
@@ -2537,7 +2512,7 @@
} else {
result = this->ParseMemberWithNewPrefixesExpression(classifier, CHECK_OK);
}
- result = Traits::RewriteNonPattern(result, classifier, CHECK_OK);
+ Traits::RewriteNonPattern(classifier, CHECK_OK);
if (peek() == Token::LPAREN) {
// NewExpression with arguments.
Scanner::Location spread_pos;
@@ -2584,6 +2559,23 @@
Consume(Token::FUNCTION);
int function_token_position = position();
+
+ if (allow_harmony_function_sent() && peek() == Token::PERIOD) {
+ // function.sent
+ int pos = position();
+ ExpectMetaProperty(CStrVector("sent"), "function.sent", pos, CHECK_OK);
+
+ if (!is_generator()) {
+ // TODO(neis): allow escaping into closures?
+ ReportMessageAt(scanner()->location(),
+ MessageTemplate::kUnexpectedFunctionSent);
+ *ok = false;
+ return this->EmptyExpression();
+ }
+
+ return this->FunctionSentExpression(scope_, factory(), pos);
+ }
+
bool is_generator = Check(Token::MUL);
IdentifierT name = this->EmptyIdentifier();
bool is_strict_reserved_name = false;
@@ -2602,8 +2594,7 @@
: kFunctionNameValidityUnknown,
is_generator ? FunctionKind::kGeneratorFunction
: FunctionKind::kNormalFunction,
- function_token_position, function_type, FunctionLiteral::kNormalArity,
- language_mode(), CHECK_OK);
+ function_token_position, function_type, language_mode(), CHECK_OK);
} else if (peek() == Token::SUPER) {
const bool is_new = false;
result = ParseSuperExpression(is_new, classifier, CHECK_OK);
@@ -2637,7 +2628,7 @@
Consume(Token::LBRACK);
int pos = position();
ExpressionT index = this->ParseExpression(true, classifier, CHECK_OK);
- index = Traits::RewriteNonPattern(index, classifier, CHECK_OK);
+ Traits::RewriteNonPattern(classifier, CHECK_OK);
left = factory()->NewProperty(this_expr, index, pos);
if (fni_ != NULL) {
this->PushPropertyName(fni_, index);
@@ -2673,7 +2664,7 @@
ExpressionT right =
this->ParseAssignmentExpression(true, classifier, CHECK_OK);
- right = Traits::RewriteNonPattern(right, classifier, CHECK_OK);
+ Traits::RewriteNonPattern(classifier, CHECK_OK);
this->CheckAssigningFunctionLiteralToProperty(left, right);
function_state_->AddProperty();
if (fni_ != NULL) {
@@ -2796,13 +2787,26 @@
return this->EmptyExpression();
}
+template <class Traits>
+void ParserBase<Traits>::ExpectMetaProperty(Vector<const char> property_name,
+ const char* full_name, int pos,
+ bool* ok) {
+ Consume(Token::PERIOD);
+ ExpectContextualKeyword(property_name, ok);
+ if (!*ok) return;
+ if (scanner()->literal_contains_escapes()) {
+ Traits::ReportMessageAt(
+ Scanner::Location(pos, scanner()->location().end_pos),
+ MessageTemplate::kInvalidEscapedMetaProperty, full_name);
+ *ok = false;
+ }
+}
template <class Traits>
typename ParserBase<Traits>::ExpressionT
ParserBase<Traits>::ParseNewTargetExpression(bool* ok) {
int pos = position();
- Consume(Token::PERIOD);
- ExpectContextualKeyword(CStrVector("target"), CHECK_OK);
+ ExpectMetaProperty(CStrVector("target"), "new.target", pos, CHECK_OK);
if (!scope_->ReceiverScope()->is_function_scope()) {
ReportMessageAt(scanner()->location(),
@@ -2824,13 +2828,14 @@
while (true) {
switch (peek()) {
case Token::LBRACK: {
+ Traits::RewriteNonPattern(classifier, CHECK_OK);
BindingPatternUnexpectedToken(classifier);
ArrowFormalParametersUnexpectedToken(classifier);
Consume(Token::LBRACK);
int pos = position();
ExpressionT index = this->ParseExpression(true, classifier, CHECK_OK);
- index = Traits::RewriteNonPattern(index, classifier, CHECK_OK);
+ Traits::RewriteNonPattern(classifier, CHECK_OK);
expression = factory()->NewProperty(expression, index, pos);
if (fni_ != NULL) {
this->PushPropertyName(fni_, index);
@@ -2839,6 +2844,7 @@
break;
}
case Token::PERIOD: {
+ Traits::RewriteNonPattern(classifier, CHECK_OK);
BindingPatternUnexpectedToken(classifier);
ArrowFormalParametersUnexpectedToken(classifier);
@@ -2854,6 +2860,7 @@
}
case Token::TEMPLATE_SPAN:
case Token::TEMPLATE_TAIL: {
+ Traits::RewriteNonPattern(classifier, CHECK_OK);
BindingPatternUnexpectedToken(classifier);
ArrowFormalParametersUnexpectedToken(classifier);
int pos;
@@ -2908,14 +2915,19 @@
ExpressionT initializer = Traits::EmptyExpression();
if (!is_rest && allow_harmony_default_parameters() && Check(Token::ASSIGN)) {
- ExpressionClassifier init_classifier;
+ ExpressionClassifier init_classifier(this);
initializer = ParseAssignmentExpression(true, &init_classifier, ok);
if (!*ok) return;
- initializer = Traits::RewriteNonPattern(initializer, &init_classifier, ok);
+ Traits::RewriteNonPattern(&init_classifier, ok);
ValidateFormalParameterInitializer(&init_classifier, ok);
if (!*ok) return;
parameters->is_simple = false;
+ init_classifier.Discard();
classifier->RecordNonSimpleParameter();
+
+ if (allow_harmony_function_name()) {
+ Traits::SetFunctionNameFromIdentifierRef(initializer, pattern);
+ }
}
Traits::AddFormalParameter(parameters, pattern, initializer,
@@ -2972,33 +2984,29 @@
}
}
-
template <class Traits>
-void ParserBase<Traits>::CheckArityRestrictions(
- int param_count, FunctionLiteral::ArityRestriction arity_restriction,
- bool has_rest, int formals_start_pos, int formals_end_pos, bool* ok) {
- switch (arity_restriction) {
- case FunctionLiteral::kGetterArity:
- if (param_count != 0) {
- ReportMessageAt(Scanner::Location(formals_start_pos, formals_end_pos),
- MessageTemplate::kBadGetterArity);
- *ok = false;
- }
- break;
- case FunctionLiteral::kSetterArity:
- if (param_count != 1) {
- ReportMessageAt(Scanner::Location(formals_start_pos, formals_end_pos),
- MessageTemplate::kBadSetterArity);
- *ok = false;
- }
- if (has_rest) {
- ReportMessageAt(Scanner::Location(formals_start_pos, formals_end_pos),
- MessageTemplate::kBadSetterRestParameter);
- *ok = false;
- }
- break;
- default:
- break;
+void ParserBase<Traits>::CheckArityRestrictions(int param_count,
+ FunctionKind function_kind,
+ bool has_rest,
+ int formals_start_pos,
+ int formals_end_pos, bool* ok) {
+ if (IsGetterFunction(function_kind)) {
+ if (param_count != 0) {
+ ReportMessageAt(Scanner::Location(formals_start_pos, formals_end_pos),
+ MessageTemplate::kBadGetterArity);
+ *ok = false;
+ }
+ } else if (IsSetterFunction(function_kind)) {
+ if (param_count != 1) {
+ ReportMessageAt(Scanner::Location(formals_start_pos, formals_end_pos),
+ MessageTemplate::kBadSetterArity);
+ *ok = false;
+ }
+ if (has_rest) {
+ ReportMessageAt(Scanner::Location(formals_start_pos, formals_end_pos),
+ MessageTemplate::kBadSetterRestParameter);
+ *ok = false;
+ }
}
}
@@ -3082,10 +3090,10 @@
// Single-expression body
int pos = position();
parenthesized_function_ = false;
- ExpressionClassifier classifier;
+ ExpressionClassifier classifier(this);
ExpressionT expression =
ParseAssignmentExpression(accept_IN, &classifier, CHECK_OK);
- expression = Traits::RewriteNonPattern(expression, &classifier, CHECK_OK);
+ Traits::RewriteNonPattern(&classifier, CHECK_OK);
body = this->NewStatementList(1, zone());
this->AddParameterInitializationBlock(formal_parameters, body, CHECK_OK);
body->Add(factory()->NewReturnStatement(expression, pos), zone());
@@ -3191,7 +3199,7 @@
int expr_pos = peek_position();
ExpressionT expression = this->ParseExpression(true, classifier, CHECK_OK);
- expression = Traits::RewriteNonPattern(expression, classifier, CHECK_OK);
+ Traits::RewriteNonPattern(classifier, CHECK_OK);
Traits::AddTemplateExpression(&ts, expression);
if (peek() != Token::RBRACE) {
@@ -3245,7 +3253,7 @@
ParserBase<Traits>::CheckAndRewriteReferenceExpression(
ExpressionT expression, int beg_pos, int end_pos,
MessageTemplate::Template message, ParseErrorType type, bool* ok) {
- ExpressionClassifier classifier;
+ ExpressionClassifier classifier(this);
ExpressionT result = ClassifyAndRewriteReferenceExpression(
&classifier, expression, beg_pos, end_pos, message, type);
ValidateExpression(&classifier, ok);
@@ -3299,21 +3307,11 @@
void ParserBase<Traits>::CheckDestructuringElement(
ExpressionT expression, ExpressionClassifier* classifier, int begin,
int end) {
- static const MessageTemplate::Template message =
- MessageTemplate::kInvalidDestructuringTarget;
- const Scanner::Location location(begin, end);
- if (expression->IsArrayLiteral() || expression->IsObjectLiteral() ||
- expression->IsAssignment()) {
- if (expression->is_parenthesized()) {
- classifier->RecordPatternError(location, message);
- }
- return;
- }
-
- if (expression->IsProperty()) {
- classifier->RecordBindingPatternError(location, message);
- } else if (!this->IsAssignableIdentifier(expression)) {
- classifier->RecordPatternError(location, message);
+ if (!IsValidPattern(expression) && !expression->IsAssignment() &&
+ !IsValidReferenceExpression(expression)) {
+ classifier->RecordAssignmentPatternError(
+ Scanner::Location(begin, end),
+ MessageTemplate::kInvalidDestructuringTarget);
}
}
@@ -3375,6 +3373,8 @@
return;
}
}
+
+
} // namespace internal
} // namespace v8
diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc
index b1b8c13..968e8ed 100644
--- a/src/parsing/parser.cc
+++ b/src/parsing/parser.cc
@@ -6,6 +6,7 @@
#include "src/api.h"
#include "src/ast/ast.h"
+#include "src/ast/ast-expression-rewriter.h"
#include "src/ast/ast-expression-visitor.h"
#include "src/ast/ast-literal-reindexer.h"
#include "src/ast/scopeinfo.h"
@@ -22,6 +23,7 @@
#include "src/parsing/scanner-character-streams.h"
#include "src/runtime/runtime.h"
#include "src/string-stream.h"
+#include "src/tracing/trace-event.h"
namespace v8 {
namespace internal {
@@ -178,15 +180,14 @@
}
}
-
-FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope,
+FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name,
+ bool call_super, Scope* scope,
int pos, int end_pos,
LanguageMode language_mode) {
int materialized_literal_count = -1;
int expected_property_count = -1;
int parameter_count = 0;
- const AstRawString* name = ast_value_factory()->empty_string();
-
+ if (name == nullptr) name = ast_value_factory()->empty_string();
FunctionKind kind = call_super ? FunctionKind::kDefaultSubclassConstructor
: FunctionKind::kDefaultBaseConstructor;
@@ -642,10 +643,16 @@
}
-Expression* ParserTraits::DefaultConstructor(bool call_super, Scope* scope,
- int pos, int end_pos,
- LanguageMode mode) {
- return parser_->DefaultConstructor(call_super, scope, pos, end_pos, mode);
+Expression* ParserTraits::FunctionSentExpression(Scope* scope,
+ AstNodeFactory* factory,
+ int pos) {
+ // We desugar function.sent into %GeneratorGetInput(generator).
+ Zone* zone = parser_->zone();
+ ZoneList<Expression*>* args = new (zone) ZoneList<Expression*>(1, zone);
+ VariableProxy* generator = factory->NewVariableProxy(
+ parser_->function_state_->generator_object_variable());
+ args->Add(generator, zone);
+ return factory->NewCallRuntime(Runtime::kGeneratorGetInput, args, pos);
}
@@ -721,11 +728,10 @@
const AstRawString* name, Scanner::Location function_name_location,
FunctionNameValidity function_name_validity, FunctionKind kind,
int function_token_position, FunctionLiteral::FunctionType type,
- FunctionLiteral::ArityRestriction arity_restriction,
LanguageMode language_mode, bool* ok) {
return parser_->ParseFunctionLiteral(
name, function_name_location, function_name_validity, kind,
- function_token_position, type, arity_restriction, language_mode, ok);
+ function_token_position, type, language_mode, ok);
}
@@ -767,6 +773,7 @@
set_allow_legacy_const(FLAG_legacy_const);
set_allow_harmony_do_expressions(FLAG_harmony_do_expressions);
set_allow_harmony_function_name(FLAG_harmony_function_name);
+ set_allow_harmony_function_sent(FLAG_harmony_function_sent);
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
++feature) {
use_counts_[feature] = 0;
@@ -789,6 +796,7 @@
DCHECK(parsing_on_main_thread_);
HistogramTimerScope timer_scope(isolate->counters()->parse(), true);
+ TRACE_EVENT0("v8", "V8.Parse");
Handle<String> source(String::cast(info->script()->source()));
isolate->counters()->total_parse_size()->Increment(source->length());
base::ElapsedTimer timer;
@@ -935,13 +943,9 @@
if (ok) {
ParserTraits::RewriteDestructuringAssignments();
- result = factory()->NewFunctionLiteral(
- ast_value_factory()->empty_string(), scope_, body,
- function_state.materialized_literal_count(),
- function_state.expected_property_count(), 0,
- FunctionLiteral::kNoDuplicateParameters,
- FunctionLiteral::kGlobalOrEval, FunctionLiteral::kShouldLazyCompile,
- FunctionKind::kNormalFunction, 0);
+ result = factory()->NewScriptOrEvalFunctionLiteral(
+ scope_, body, function_state.materialized_literal_count(),
+ function_state.expected_property_count());
}
}
@@ -957,6 +961,7 @@
// called in the main thread.
DCHECK(parsing_on_main_thread_);
HistogramTimerScope timer_scope(isolate->counters()->parse_lazy());
+ TRACE_EVENT0("v8", "V8.ParseLazy");
Handle<String> source(String::cast(info->script()->source()));
isolate->counters()->total_parse_size()->Increment(source->length());
base::ElapsedTimer timer;
@@ -990,6 +995,18 @@
return result;
}
+static FunctionLiteral::FunctionType ComputeFunctionType(
+ Handle<SharedFunctionInfo> shared_info) {
+ if (shared_info->is_declaration()) {
+ return FunctionLiteral::kDeclaration;
+ } else if (shared_info->is_named_expression()) {
+ return FunctionLiteral::kNamedExpression;
+ } else if (IsConciseMethod(shared_info->kind()) ||
+ IsAccessorFunction(shared_info->kind())) {
+ return FunctionLiteral::kAccessorOrMethod;
+ }
+ return FunctionLiteral::kAnonymousExpression;
+}
FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
Utf16CharacterStream* source) {
@@ -1028,11 +1045,7 @@
is_strict(info->language_mode()));
DCHECK(info->language_mode() == shared_info->language_mode());
FunctionLiteral::FunctionType function_type =
- shared_info->is_expression()
- ? (shared_info->is_anonymous()
- ? FunctionLiteral::kAnonymousExpression
- : FunctionLiteral::kNamedExpression)
- : FunctionLiteral::kDeclaration;
+ ComputeFunctionType(shared_info);
bool ok = true;
if (shared_info->is_arrow()) {
@@ -1050,7 +1063,7 @@
SetLanguageMode(scope, shared_info->language_mode());
scope->set_start_position(shared_info->start_position());
- ExpressionClassifier formals_classifier;
+ ExpressionClassifier formals_classifier(this);
ParserFormalParameters formals(scope);
Checkpoint checkpoint(this);
{
@@ -1096,15 +1109,15 @@
}
}
} else if (shared_info->is_default_constructor()) {
- result = DefaultConstructor(IsSubclassConstructor(shared_info->kind()),
- scope, shared_info->start_position(),
- shared_info->end_position(),
- shared_info->language_mode());
+ result = DefaultConstructor(
+ raw_name, IsSubclassConstructor(shared_info->kind()), scope,
+ shared_info->start_position(), shared_info->end_position(),
+ shared_info->language_mode());
} else {
- result = ParseFunctionLiteral(
- raw_name, Scanner::Location::invalid(), kSkipFunctionNameCheck,
- shared_info->kind(), RelocInfo::kNoPosition, function_type,
- FunctionLiteral::kNormalArity, shared_info->language_mode(), &ok);
+ result = ParseFunctionLiteral(raw_name, Scanner::Location::invalid(),
+ kSkipFunctionNameCheck, shared_info->kind(),
+ RelocInfo::kNoPosition, function_type,
+ shared_info->language_mode(), &ok);
}
// Make sure the results agree.
DCHECK(ok == (result != NULL));
@@ -1260,20 +1273,11 @@
// Statement
// Declaration
- if (peek() != Token::CLASS) {
- // No more classes follow; reset the start position for the consecutive
- // class declaration group.
- scope_->set_class_declaration_group_start(-1);
- }
-
switch (peek()) {
case Token::FUNCTION:
return ParseFunctionDeclaration(NULL, ok);
case Token::CLASS:
- if (scope_->class_declaration_group_start() < 0) {
- scope_->set_class_declaration_group_start(
- scanner()->peek_location().beg_pos);
- }
+ Consume(Token::CLASS);
return ParseClassDeclaration(NULL, ok);
case Token::CONST:
if (allow_const()) {
@@ -1345,7 +1349,6 @@
}
}
- scope_->module()->Freeze();
return NULL;
}
@@ -1558,24 +1561,53 @@
Expect(Token::DEFAULT, CHECK_OK);
Scanner::Location default_loc = scanner()->location();
+ const AstRawString* default_string = ast_value_factory()->default_string();
ZoneList<const AstRawString*> names(1, zone());
- Statement* result = NULL;
+ Statement* result = nullptr;
+ Expression* default_export = nullptr;
switch (peek()) {
- case Token::FUNCTION:
- // TODO(ES6): Support parsing anonymous function declarations here.
- result = ParseFunctionDeclaration(&names, CHECK_OK);
+ case Token::FUNCTION: {
+ Consume(Token::FUNCTION);
+ int pos = position();
+ bool is_generator = Check(Token::MUL);
+ if (peek() == Token::LPAREN) {
+ // FunctionDeclaration[+Default] ::
+ // 'function' '(' FormalParameters ')' '{' FunctionBody '}'
+ //
+ // GeneratorDeclaration[+Default] ::
+ // 'function' '*' '(' FormalParameters ')' '{' FunctionBody '}'
+ default_export = ParseFunctionLiteral(
+ default_string, Scanner::Location::invalid(),
+ kSkipFunctionNameCheck,
+ is_generator ? FunctionKind::kGeneratorFunction
+ : FunctionKind::kNormalFunction,
+ pos, FunctionLiteral::kDeclaration, language_mode(), CHECK_OK);
+ result = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
+ } else {
+ result = ParseFunctionDeclaration(pos, is_generator, &names, CHECK_OK);
+ }
break;
+ }
case Token::CLASS:
- // TODO(ES6): Support parsing anonymous class declarations here.
- result = ParseClassDeclaration(&names, CHECK_OK);
+ Consume(Token::CLASS);
+ if (peek() == Token::EXTENDS || peek() == Token::LBRACE) {
+ // ClassDeclaration[+Default] ::
+ // 'class' ('extends' LeftHandExpression)? '{' ClassBody '}'
+ default_export =
+ ParseClassLiteral(default_string, Scanner::Location::invalid(),
+ false, position(), CHECK_OK);
+ result = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
+ } else {
+ result = ParseClassDeclaration(&names, CHECK_OK);
+ }
break;
default: {
int pos = peek_position();
- ExpressionClassifier classifier;
+ ExpressionClassifier classifier(this);
Expression* expr = ParseAssignmentExpression(true, &classifier, CHECK_OK);
- expr = ParserTraits::RewriteNonPattern(expr, &classifier, CHECK_OK);
+ RewriteNonPattern(&classifier, CHECK_OK);
ExpectSemicolon(CHECK_OK);
result = factory()->NewExpressionStatement(expr, pos);
@@ -1583,19 +1615,18 @@
}
}
- const AstRawString* default_string = ast_value_factory()->default_string();
-
DCHECK_LE(names.length(), 1);
if (names.length() == 1) {
scope_->module()->AddLocalExport(default_string, names.first(), zone(), ok);
if (!*ok) {
ParserTraits::ReportMessageAt(
default_loc, MessageTemplate::kDuplicateExport, default_string);
- return NULL;
+ return nullptr;
}
} else {
// TODO(ES6): Assign result to a const binding with the name "*default*"
// and add an export entry with "*default*" as the local name.
+ USE(default_export);
}
return result;
@@ -1686,6 +1717,7 @@
break;
case Token::CLASS:
+ Consume(Token::CLASS);
result = ParseClassDeclaration(&names, CHECK_OK);
break;
@@ -1921,42 +1953,44 @@
if (var == NULL) {
// Declare the name.
Variable::Kind kind = Variable::NORMAL;
- int declaration_group_start = -1;
if (is_function_declaration) {
kind = Variable::FUNCTION;
- } else if (declaration->IsVariableDeclaration() &&
- declaration->AsVariableDeclaration()->is_class_declaration()) {
- kind = Variable::CLASS;
- declaration_group_start =
- declaration->AsVariableDeclaration()->declaration_group_start();
}
var = declaration_scope->DeclareLocal(
- name, mode, declaration->initialization(), kind, kNotAssigned,
- declaration_group_start);
- } else if (((IsLexicalVariableMode(mode) ||
- IsLexicalVariableMode(var->mode())) &&
- // Allow duplicate function decls for web compat, see bug 4693.
- (is_strict(language_mode()) || !is_function_declaration ||
- !var->is_function())) ||
- ((mode == CONST_LEGACY || var->mode() == CONST_LEGACY) &&
- !declaration_scope->is_script_scope())) {
- // The name was declared in this scope before; check for conflicting
- // re-declarations. We have a conflict if either of the declarations is
- // not a var (in script scope, we also have to ignore legacy const for
- // compatibility). There is similar code in runtime.cc in the Declare
- // functions. The function CheckConflictingVarDeclarations checks for
- // var and let bindings from different scopes whereas this is a check for
- // conflicting declarations within the same scope. This check also covers
- // the special case
- //
- // function () { let x; { var x; } }
- //
- // because the var declaration is hoisted to the function scope where 'x'
- // is already bound.
- DCHECK(IsDeclaredVariableMode(var->mode()));
- if (is_strict(language_mode()) ||
- (allow_harmony_sloppy() && mode != CONST_LEGACY &&
- var->mode() != CONST_LEGACY)) {
+ name, mode, declaration->initialization(), kind, kNotAssigned);
+ } else if ((mode == CONST_LEGACY || var->mode() == CONST_LEGACY) &&
+ !declaration_scope->is_script_scope()) {
+ // Duplicate legacy const definitions throw at runtime.
+ DCHECK(is_sloppy(language_mode()));
+ Expression* expression = NewThrowSyntaxError(
+ MessageTemplate::kVarRedeclaration, name, declaration->position());
+ declaration_scope->SetIllegalRedeclaration(expression);
+ } else if ((IsLexicalVariableMode(mode) ||
+ IsLexicalVariableMode(var->mode())) &&
+ // Lexical bindings may appear for some parameters in sloppy
+ // mode even with --harmony-sloppy off.
+ (is_strict(language_mode()) || allow_harmony_sloppy())) {
+ // Allow duplicate function decls for web compat, see bug 4693.
+ if (is_sloppy(language_mode()) && is_function_declaration &&
+ var->is_function()) {
+ DCHECK(IsLexicalVariableMode(mode) &&
+ IsLexicalVariableMode(var->mode()));
+ ++use_counts_[v8::Isolate::kSloppyModeBlockScopedFunctionRedefinition];
+ } else {
+ // The name was declared in this scope before; check for conflicting
+ // re-declarations. We have a conflict if either of the declarations
+ // is not a var (in script scope, we also have to ignore legacy const
+ // for compatibility). There is similar code in runtime.cc in the
+ // Declare functions. The function CheckConflictingVarDeclarations
+ // checks for var and let bindings from different scopes whereas this
+ // is a check for conflicting declarations within the same scope. This
+ // check also covers the special case
+ //
+ // function () { let x; { var x; } }
+ //
+ // because the var declaration is hoisted to the function scope where
+ // 'x' is already bound.
+ DCHECK(IsDeclaredVariableMode(var->mode()));
// In harmony we treat re-declarations as early errors. See
// ES5 16 for a definition of early errors.
if (declaration_kind == DeclarationDescriptor::NORMAL) {
@@ -1967,9 +2001,6 @@
*ok = false;
return nullptr;
}
- Expression* expression = NewThrowSyntaxError(
- MessageTemplate::kVarRedeclaration, name, declaration->position());
- declaration_scope->SetIllegalRedeclaration(expression);
} else if (mode == VAR) {
var->set_maybe_assigned();
}
@@ -2093,14 +2124,22 @@
Statement* Parser::ParseFunctionDeclaration(
ZoneList<const AstRawString*>* names, bool* ok) {
- // FunctionDeclaration ::
- // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
- // GeneratorDeclaration ::
- // 'function' '*' Identifier '(' FormalParameterListopt ')'
- // '{' FunctionBody '}'
Expect(Token::FUNCTION, CHECK_OK);
int pos = position();
bool is_generator = Check(Token::MUL);
+ return ParseFunctionDeclaration(pos, is_generator, names, ok);
+}
+
+
+Statement* Parser::ParseFunctionDeclaration(
+ int pos, bool is_generator, ZoneList<const AstRawString*>* names,
+ bool* ok) {
+ // FunctionDeclaration ::
+ // 'function' Identifier '(' FormalParameters ')' '{' FunctionBody '}'
+ // GeneratorDeclaration ::
+ // 'function' '*' Identifier '(' FormalParameters ')' '{' FunctionBody '}'
+ //
+ // 'function' and '*' (if present) have been consumed by the caller.
bool is_strict_reserved = false;
const AstRawString* name = ParseIdentifierOrStrictReservedWord(
&is_strict_reserved, CHECK_OK);
@@ -2113,8 +2152,7 @@
: kFunctionNameValidityUnknown,
is_generator ? FunctionKind::kGeneratorFunction
: FunctionKind::kNormalFunction,
- pos, FunctionLiteral::kDeclaration, FunctionLiteral::kNormalArity,
- language_mode(), CHECK_OK);
+ pos, FunctionLiteral::kDeclaration, language_mode(), CHECK_OK);
// Even if we're not at the top-level of the global or a function
// scope, we treat it as such and introduce the function with its
@@ -2151,6 +2189,8 @@
// ClassDeclaration ::
// 'class' Identifier ('extends' LeftHandExpression)? '{' ClassBody '}'
//
+ // 'class' is expected to be consumed by the caller.
+ //
// A ClassDeclaration
//
// class C { ... }
@@ -2161,7 +2201,6 @@
//
// so rewrite it as such.
- Expect(Token::CLASS, CHECK_OK);
if (!allow_harmony_sloppy() && is_sloppy(language_mode())) {
ReportMessage(MessageTemplate::kSloppyLexical);
*ok = false;
@@ -2177,30 +2216,10 @@
VariableMode mode = is_strong(language_mode()) ? CONST : LET;
VariableProxy* proxy = NewUnresolved(name, mode);
- const bool is_class_declaration = true;
- Declaration* declaration = factory()->NewVariableDeclaration(
- proxy, mode, scope_, pos, is_class_declaration,
- scope_->class_declaration_group_start());
- Variable* outer_class_variable =
- Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
+ Declaration* declaration =
+ factory()->NewVariableDeclaration(proxy, mode, scope_, pos);
+ Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
proxy->var()->set_initializer_position(position());
- // This is needed because a class ("class Name { }") creates two bindings (one
- // in the outer scope, and one in the class scope). The method is a function
- // scope inside the inner scope (class scope). The consecutive class
- // declarations are in the outer scope.
- if (value->class_variable_proxy() && value->class_variable_proxy()->var() &&
- outer_class_variable->is_class()) {
- // In some cases, the outer variable is not detected as a class variable;
- // this happens e.g., for lazy methods. They are excluded from strong mode
- // checks for now. TODO(marja, rossberg): re-create variables with the
- // correct Kind and remove this hack.
- value->class_variable_proxy()
- ->var()
- ->AsClassVariable()
- ->set_declaration_group_start(
- outer_class_variable->AsClassVariable()->declaration_group_start());
- }
-
Assignment* assignment =
factory()->NewAssignment(Token::INIT, proxy, value, pos);
Statement* assignment_statement =
@@ -2281,17 +2300,16 @@
// is inside an initializer block, it is ignored.
DeclarationParsingResult parsing_result;
- ParseVariableDeclarations(var_context, &parsing_result, CHECK_OK);
+ Block* result =
+ ParseVariableDeclarations(var_context, &parsing_result, names, CHECK_OK);
ExpectSemicolon(CHECK_OK);
-
- Block* result = parsing_result.BuildInitializationBlock(names, CHECK_OK);
return result;
}
-
-void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
- DeclarationParsingResult* parsing_result,
- bool* ok) {
+Block* Parser::ParseVariableDeclarations(
+ VariableDeclarationContext var_context,
+ DeclarationParsingResult* parsing_result,
+ ZoneList<const AstRawString*>* names, bool* ok) {
// VariableDeclarations ::
// ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[',']
//
@@ -2311,17 +2329,19 @@
parsing_result->descriptor.declaration_pos = peek_position();
parsing_result->descriptor.initialization_pos = peek_position();
parsing_result->descriptor.mode = VAR;
- // True if the binding needs initialization. 'let' and 'const' declared
- // bindings are created uninitialized by their declaration nodes and
- // need initialization. 'var' declared bindings are always initialized
- // immediately by their declaration nodes.
- parsing_result->descriptor.needs_init = false;
+
+ Block* init_block = nullptr;
+ if (var_context != kForStatement) {
+ init_block = factory()->NewBlock(
+ NULL, 1, true, parsing_result->descriptor.declaration_pos);
+ }
+
if (peek() == Token::VAR) {
if (is_strong(language_mode())) {
Scanner::Location location = scanner()->peek_location();
ReportMessageAt(location, MessageTemplate::kStrongVar);
*ok = false;
- return;
+ return nullptr;
}
Consume(Token::VAR);
} else if (peek() == Token::CONST && allow_const()) {
@@ -2334,12 +2354,10 @@
DCHECK(var_context != kStatement);
parsing_result->descriptor.mode = CONST;
}
- parsing_result->descriptor.needs_init = true;
} else if (peek() == Token::LET && allow_let()) {
Consume(Token::LET);
DCHECK(var_context != kStatement);
parsing_result->descriptor.mode = LET;
- parsing_result->descriptor.needs_init = true;
} else {
UNREACHABLE(); // by current callers
}
@@ -2350,7 +2368,6 @@
bool first_declaration = true;
int bindings_start = peek_position();
- bool is_for_iteration_variable;
do {
FuncNameInferrer::State fni_state(fni_);
@@ -2360,27 +2377,20 @@
Expression* pattern;
int decl_pos = peek_position();
{
- ExpressionClassifier pattern_classifier;
+ ExpressionClassifier pattern_classifier(this);
Token::Value next = peek();
- pattern = ParsePrimaryExpression(&pattern_classifier, ok);
- if (!*ok) return;
- ValidateBindingPattern(&pattern_classifier, ok);
- if (!*ok) return;
+ pattern = ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
+ ValidateBindingPattern(&pattern_classifier, CHECK_OK);
if (IsLexicalVariableMode(parsing_result->descriptor.mode)) {
- ValidateLetPattern(&pattern_classifier, ok);
- if (!*ok) return;
+ ValidateLetPattern(&pattern_classifier, CHECK_OK);
}
if (!allow_harmony_destructuring_bind() && !pattern->IsVariableProxy()) {
ReportUnexpectedToken(next);
*ok = false;
- return;
+ return nullptr;
}
}
- bool is_pattern =
- (pattern->IsObjectLiteral() || pattern->IsArrayLiteral()) &&
- !pattern->is_parenthesized();
-
Scanner::Location variable_loc = scanner()->location();
const AstRawString* single_name =
pattern->IsVariableProxy() ? pattern->AsVariableProxy()->raw_name()
@@ -2389,25 +2399,13 @@
if (fni_ != NULL) fni_->PushVariableName(single_name);
}
- is_for_iteration_variable =
- var_context == kForStatement &&
- (peek() == Token::IN || PeekContextualKeyword(CStrVector("of")));
- if (is_for_iteration_variable &&
- (parsing_result->descriptor.mode == CONST ||
- parsing_result->descriptor.mode == CONST_LEGACY)) {
- parsing_result->descriptor.needs_init = false;
- }
-
Expression* value = NULL;
- // Harmony consts have non-optional initializers.
int initializer_position = RelocInfo::kNoPosition;
if (Check(Token::ASSIGN)) {
- ExpressionClassifier classifier;
+ ExpressionClassifier classifier(this);
value = ParseAssignmentExpression(var_context != kForStatement,
- &classifier, ok);
- if (!*ok) return;
- value = ParserTraits::RewriteNonPattern(value, &classifier, ok);
- if (!*ok) return;
+ &classifier, CHECK_OK);
+ RewriteNonPattern(&classifier, CHECK_OK);
variable_loc.end_pos = scanner()->location().end_pos;
if (!parsing_result->first_initializer_loc.IsValid()) {
@@ -2424,48 +2422,60 @@
}
}
- if (allow_harmony_function_name() && single_name) {
- if (value->IsFunctionLiteral()) {
- auto function_literal = value->AsFunctionLiteral();
- if (function_literal->is_anonymous()) {
- function_literal->set_raw_name(single_name);
- }
- } else if (value->IsClassLiteral()) {
- auto class_literal = value->AsClassLiteral();
- if (class_literal->raw_name() == nullptr) {
- class_literal->set_raw_name(single_name);
- }
- }
+ if (allow_harmony_function_name()) {
+ ParserTraits::SetFunctionNameFromIdentifierRef(value, pattern);
}
// End position of the initializer is after the assignment expression.
initializer_position = scanner()->location().end_pos;
} else {
- if ((parsing_result->descriptor.mode == CONST || is_pattern) &&
- !is_for_iteration_variable) {
- ParserTraits::ReportMessageAt(
- Scanner::Location(decl_pos, scanner()->location().end_pos),
- MessageTemplate::kDeclarationMissingInitializer,
- is_pattern ? "destructuring" : "const");
- *ok = false;
- return;
+ // Initializers may be either required or implied unless this is a
+ // for-in/of iteration variable.
+ if (var_context != kForStatement || !PeekInOrOf()) {
+ // ES6 'const' and binding patterns require initializers.
+ if (parsing_result->descriptor.mode == CONST ||
+ !pattern->IsVariableProxy()) {
+ ParserTraits::ReportMessageAt(
+ Scanner::Location(decl_pos, scanner()->location().end_pos),
+ MessageTemplate::kDeclarationMissingInitializer,
+ !pattern->IsVariableProxy() ? "destructuring" : "const");
+ *ok = false;
+ return nullptr;
+ }
+
+ // 'let x' and (legacy) 'const x' initialize 'x' to undefined.
+ if (parsing_result->descriptor.mode == LET ||
+ parsing_result->descriptor.mode == CONST_LEGACY) {
+ value = GetLiteralUndefined(position());
+ }
}
+
// End position of the initializer is after the variable.
initializer_position = position();
}
- // Make sure that 'const x' and 'let x' initialize 'x' to undefined.
- if (value == NULL && parsing_result->descriptor.needs_init) {
- value = GetLiteralUndefined(position());
+ DeclarationParsingResult::Declaration decl(pattern, initializer_position,
+ value);
+ if (var_context == kForStatement) {
+ // Save the declaration for further handling in ParseForStatement.
+ parsing_result->declarations.Add(decl);
+ } else {
+ // Immediately declare the variable otherwise. This avoids O(N^2)
+ // behavior (where N is the number of variables in a single
+ // declaration) in the PatternRewriter having to do with removing
+ // and adding VariableProxies to the Scope (see bug 4699).
+ DCHECK_NOT_NULL(init_block);
+ PatternRewriter::DeclareAndInitializeVariables(
+ init_block, &parsing_result->descriptor, &decl, names, CHECK_OK);
}
-
- parsing_result->declarations.Add(DeclarationParsingResult::Declaration(
- pattern, initializer_position, value));
first_declaration = false;
} while (peek() == Token::COMMA);
parsing_result->bindings_loc =
Scanner::Location(bindings_start, scanner()->location().end_pos);
+
+ DCHECK(*ok);
+ return init_block;
}
@@ -2511,13 +2521,13 @@
IsClassConstructor(function_state_->kind())) {
bool is_this = peek() == Token::THIS;
Expression* expr;
- ExpressionClassifier classifier;
+ ExpressionClassifier classifier(this);
if (is_this) {
expr = ParseStrongInitializationExpression(&classifier, CHECK_OK);
} else {
expr = ParseStrongSuperCallExpression(&classifier, CHECK_OK);
}
- expr = ParserTraits::RewriteNonPattern(expr, &classifier, CHECK_OK);
+ RewriteNonPattern(&classifier, CHECK_OK);
switch (peek()) {
case Token::SEMICOLON:
Consume(Token::SEMICOLON);
@@ -2728,23 +2738,22 @@
if (IsSubclassConstructor(function_state_->kind())) {
// For subclass constructors we need to return this in case of undefined
- // and throw an exception in case of a non object.
+ // return a Smi (transformed into an exception in the ConstructStub)
+ // for a non object.
//
// return expr;
//
// Is rewritten as:
//
// return (temp = expr) === undefined ? this :
- // %_IsJSReceiver(temp) ? temp : throw new TypeError(...);
+ // %_IsJSReceiver(temp) ? temp : 1;
+
+ // temp = expr
Variable* temp = scope_->NewTemporary(
ast_value_factory()->empty_string());
Assignment* assign = factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(temp), return_value, pos);
- Expression* throw_expression =
- NewThrowTypeError(MessageTemplate::kDerivedConstructorReturn,
- ast_value_factory()->empty_string(), pos);
-
// %_IsJSReceiver(temp)
ZoneList<Expression*>* is_spec_object_args =
new (zone()) ZoneList<Expression*>(1, zone());
@@ -2755,7 +2764,7 @@
// %_IsJSReceiver(temp) ? temp : throw_expression
Expression* is_object_conditional = factory()->NewConditional(
is_spec_object_call, factory()->NewVariableProxy(temp),
- throw_expression, pos);
+ factory()->NewSmiLiteral(1, pos), pos);
// temp === undefined
Expression* is_undefined = factory()->NewCompareOperation(
@@ -2768,7 +2777,10 @@
is_object_conditional, pos);
}
- return_value->MarkTail();
+ // ES6 14.6.1 Static Semantics: IsInTailPosition
+ if (FLAG_harmony_tailcalls && !is_sloppy(language_mode())) {
+ function_state_->AddExpressionInTailPosition(return_value);
+ }
}
ExpectSemicolon(CHECK_OK);
@@ -2974,6 +2986,40 @@
factory()->NewThrow(exception, pos), pos);
}
+class Parser::DontCollectExpressionsInTailPositionScope {
+ public:
+ DontCollectExpressionsInTailPositionScope(
+ Parser::FunctionState* function_state)
+ : function_state_(function_state),
+ old_value_(function_state->collect_expressions_in_tail_position()) {
+ function_state->set_collect_expressions_in_tail_position(false);
+ }
+ ~DontCollectExpressionsInTailPositionScope() {
+ function_state_->set_collect_expressions_in_tail_position(old_value_);
+ }
+
+ private:
+ Parser::FunctionState* function_state_;
+ bool old_value_;
+};
+
+// Collects all return expressions at tail call position in this scope
+// to a separate list.
+class Parser::CollectExpressionsInTailPositionToListScope {
+ public:
+ CollectExpressionsInTailPositionToListScope(
+ Parser::FunctionState* function_state, List<Expression*>* list)
+ : function_state_(function_state), list_(list) {
+ function_state->expressions_in_tail_position().Swap(list_);
+ }
+ ~CollectExpressionsInTailPositionToListScope() {
+ function_state_->expressions_in_tail_position().Swap(list_);
+ }
+
+ private:
+ Parser::FunctionState* function_state_;
+ List<Expression*>* list_;
+};
TryStatement* Parser::ParseTryStatement(bool* ok) {
// TryStatement ::
@@ -2990,7 +3036,11 @@
Expect(Token::TRY, CHECK_OK);
int pos = position();
- Block* try_block = ParseBlock(NULL, CHECK_OK);
+ Block* try_block;
+ {
+ DontCollectExpressionsInTailPositionScope no_tail_calls(function_state_);
+ try_block = ParseBlock(NULL, CHECK_OK);
+ }
Token::Value tok = peek();
if (tok != Token::CATCH && tok != Token::FINALLY) {
@@ -3002,6 +3052,7 @@
Scope* catch_scope = NULL;
Variable* catch_variable = NULL;
Block* catch_block = NULL;
+ List<Expression*> expressions_in_tail_position_in_catch_block;
if (tok == Token::CATCH) {
Consume(Token::CATCH);
@@ -3009,7 +3060,7 @@
catch_scope = NewScope(scope_, CATCH_SCOPE);
catch_scope->set_start_position(scanner()->location().beg_pos);
- ExpressionClassifier pattern_classifier;
+ ExpressionClassifier pattern_classifier(this);
Expression* pattern = ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
ValidateBindingPattern(&pattern_classifier, CHECK_OK);
@@ -3027,6 +3078,9 @@
Expect(Token::RPAREN, CHECK_OK);
{
+ CollectExpressionsInTailPositionToListScope
+ collect_expressions_in_tail_position_scope(
+ function_state_, &expressions_in_tail_position_in_catch_block);
BlockState block_state(&scope_, catch_scope);
// TODO(adamk): Make a version of ParseBlock that takes a scope and
@@ -3047,7 +3101,6 @@
descriptor.scope = scope_;
descriptor.hoist_scope = nullptr;
descriptor.mode = LET;
- descriptor.needs_init = true;
descriptor.declaration_pos = pattern->position();
descriptor.initialization_pos = pattern->position();
@@ -3102,6 +3155,11 @@
TryStatement* result = NULL;
if (catch_block != NULL) {
+ // For a try-catch construct append return expressions from the catch block
+ // to the list of return expressions.
+ function_state_->expressions_in_tail_position().AddAll(
+ expressions_in_tail_position_in_catch_block);
+
DCHECK(finally_block == NULL);
DCHECK(catch_scope != NULL && catch_variable != NULL);
result = factory()->NewTryCatchStatement(try_block, catch_scope,
@@ -3262,6 +3320,7 @@
}
for_of->Initialize(each, subject, body,
+ iterator,
assign_iterator,
next_result,
result_done,
@@ -3288,9 +3347,8 @@
}
}
-
Statement* Parser::DesugarLexicalBindingsInForStatement(
- Scope* inner_scope, bool is_const, ZoneList<const AstRawString*>* names,
+ Scope* inner_scope, VariableMode mode, ZoneList<const AstRawString*>* names,
ForStatement* loop, Statement* init, Expression* cond, Statement* next,
Statement* body, bool* ok) {
// ES6 13.7.4.8 specifies that on each loop iteration the let variables are
@@ -3331,7 +3389,6 @@
// }
DCHECK(names->length() > 0);
- Scope* for_scope = scope_;
ZoneList<Variable*> temps(names->length(), zone());
Block* outer_block = factory()->NewBlock(NULL, names->length() + 4, false,
@@ -3384,150 +3441,155 @@
ForStatement* outer_loop =
factory()->NewForStatement(NULL, RelocInfo::kNoPosition);
outer_block->statements()->Add(outer_loop, zone());
-
- outer_block->set_scope(for_scope);
- scope_ = inner_scope;
+ outer_block->set_scope(scope_);
Block* inner_block =
factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition);
- Block* ignore_completion_block = factory()->NewBlock(
- NULL, names->length() + 3, true, RelocInfo::kNoPosition);
- ZoneList<Variable*> inner_vars(names->length(), zone());
- // For each let variable x:
- // make statement: let/const x = temp_x.
- VariableMode mode = is_const ? CONST : LET;
- for (int i = 0; i < names->length(); i++) {
- VariableProxy* proxy = NewUnresolved(names->at(i), mode);
- Declaration* declaration = factory()->NewVariableDeclaration(
- proxy, mode, scope_, RelocInfo::kNoPosition);
- Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
- inner_vars.Add(declaration->proxy()->var(), zone());
- VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
- Assignment* assignment = factory()->NewAssignment(
- Token::INIT, proxy, temp_proxy, RelocInfo::kNoPosition);
- Statement* assignment_statement =
- factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
- DCHECK(init->position() != RelocInfo::kNoPosition);
- proxy->var()->set_initializer_position(init->position());
- ignore_completion_block->statements()->Add(assignment_statement, zone());
- }
-
- // Make statement: if (first == 1) { first = 0; } else { next; }
- if (next) {
- DCHECK(first);
- Expression* compare = NULL;
- // Make compare expression: first == 1.
- {
- Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
- VariableProxy* first_proxy = factory()->NewVariableProxy(first);
- compare = factory()->NewCompareOperation(Token::EQ, first_proxy, const1,
- RelocInfo::kNoPosition);
- }
- Statement* clear_first = NULL;
- // Make statement: first = 0.
- {
- VariableProxy* first_proxy = factory()->NewVariableProxy(first);
- Expression* const0 = factory()->NewSmiLiteral(0, RelocInfo::kNoPosition);
- Assignment* assignment = factory()->NewAssignment(
- Token::ASSIGN, first_proxy, const0, RelocInfo::kNoPosition);
- clear_first =
- factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
- }
- Statement* clear_first_or_next = factory()->NewIfStatement(
- compare, clear_first, next, RelocInfo::kNoPosition);
- ignore_completion_block->statements()->Add(clear_first_or_next, zone());
- }
-
- Variable* flag = scope_->NewTemporary(temp_name);
- // Make statement: flag = 1.
{
- VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
- Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
- Assignment* assignment = factory()->NewAssignment(
- Token::ASSIGN, flag_proxy, const1, RelocInfo::kNoPosition);
- Statement* assignment_statement =
- factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
- ignore_completion_block->statements()->Add(assignment_statement, zone());
- }
+ BlockState block_state(&scope_, inner_scope);
- // Make statement: if (!cond) break.
- if (cond) {
- Statement* stop =
- factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition);
- Statement* noop = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
- ignore_completion_block->statements()->Add(
- factory()->NewIfStatement(cond, noop, stop, cond->position()), zone());
- }
-
- inner_block->statements()->Add(ignore_completion_block, zone());
- // Make cond expression for main loop: flag == 1.
- Expression* flag_cond = NULL;
- {
- Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
- VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
- flag_cond = factory()->NewCompareOperation(Token::EQ, flag_proxy, const1,
- RelocInfo::kNoPosition);
- }
-
- // Create chain of expressions "flag = 0, temp_x = x, ..."
- Statement* compound_next_statement = NULL;
- {
- Expression* compound_next = NULL;
- // Make expression: flag = 0.
- {
- VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
- Expression* const0 = factory()->NewSmiLiteral(0, RelocInfo::kNoPosition);
- compound_next = factory()->NewAssignment(Token::ASSIGN, flag_proxy,
- const0, RelocInfo::kNoPosition);
- }
-
- // Make the comma-separated list of temp_x = x assignments.
- int inner_var_proxy_pos = scanner()->location().beg_pos;
+ Block* ignore_completion_block = factory()->NewBlock(
+ NULL, names->length() + 3, true, RelocInfo::kNoPosition);
+ ZoneList<Variable*> inner_vars(names->length(), zone());
+ // For each let variable x:
+ // make statement: let/const x = temp_x.
for (int i = 0; i < names->length(); i++) {
+ VariableProxy* proxy = NewUnresolved(names->at(i), mode);
+ Declaration* declaration = factory()->NewVariableDeclaration(
+ proxy, mode, scope_, RelocInfo::kNoPosition);
+ Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
+ inner_vars.Add(declaration->proxy()->var(), zone());
VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
- VariableProxy* proxy =
- factory()->NewVariableProxy(inner_vars.at(i), inner_var_proxy_pos);
Assignment* assignment = factory()->NewAssignment(
- Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition);
- compound_next = factory()->NewBinaryOperation(
- Token::COMMA, compound_next, assignment, RelocInfo::kNoPosition);
+ Token::INIT, proxy, temp_proxy, RelocInfo::kNoPosition);
+ Statement* assignment_statement =
+ factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
+ DCHECK(init->position() != RelocInfo::kNoPosition);
+ proxy->var()->set_initializer_position(init->position());
+ ignore_completion_block->statements()->Add(assignment_statement, zone());
}
- compound_next_statement = factory()->NewExpressionStatement(
- compound_next, RelocInfo::kNoPosition);
- }
+ // Make statement: if (first == 1) { first = 0; } else { next; }
+ if (next) {
+ DCHECK(first);
+ Expression* compare = NULL;
+ // Make compare expression: first == 1.
+ {
+ Expression* const1 =
+ factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
+ VariableProxy* first_proxy = factory()->NewVariableProxy(first);
+ compare = factory()->NewCompareOperation(Token::EQ, first_proxy, const1,
+ RelocInfo::kNoPosition);
+ }
+ Statement* clear_first = NULL;
+ // Make statement: first = 0.
+ {
+ VariableProxy* first_proxy = factory()->NewVariableProxy(first);
+ Expression* const0 =
+ factory()->NewSmiLiteral(0, RelocInfo::kNoPosition);
+ Assignment* assignment = factory()->NewAssignment(
+ Token::ASSIGN, first_proxy, const0, RelocInfo::kNoPosition);
+ clear_first = factory()->NewExpressionStatement(assignment,
+ RelocInfo::kNoPosition);
+ }
+ Statement* clear_first_or_next = factory()->NewIfStatement(
+ compare, clear_first, next, RelocInfo::kNoPosition);
+ ignore_completion_block->statements()->Add(clear_first_or_next, zone());
+ }
- // Make statement: labels: for (; flag == 1; flag = 0, temp_x = x)
- // Note that we re-use the original loop node, which retains its labels
- // and ensures that any break or continue statements in body point to
- // the right place.
- loop->Initialize(NULL, flag_cond, compound_next_statement, body);
- inner_block->statements()->Add(loop, zone());
+ Variable* flag = scope_->NewTemporary(temp_name);
+ // Make statement: flag = 1.
+ {
+ VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
+ Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
+ Assignment* assignment = factory()->NewAssignment(
+ Token::ASSIGN, flag_proxy, const1, RelocInfo::kNoPosition);
+ Statement* assignment_statement =
+ factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
+ ignore_completion_block->statements()->Add(assignment_statement, zone());
+ }
- // Make statement: {{if (flag == 1) break;}}
- {
- Expression* compare = NULL;
- // Make compare expresion: flag == 1.
+ // Make statement: if (!cond) break.
+ if (cond) {
+ Statement* stop =
+ factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition);
+ Statement* noop = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
+ ignore_completion_block->statements()->Add(
+ factory()->NewIfStatement(cond, noop, stop, cond->position()),
+ zone());
+ }
+
+ inner_block->statements()->Add(ignore_completion_block, zone());
+ // Make cond expression for main loop: flag == 1.
+ Expression* flag_cond = NULL;
{
Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
- compare = factory()->NewCompareOperation(Token::EQ, flag_proxy, const1,
- RelocInfo::kNoPosition);
+ flag_cond = factory()->NewCompareOperation(Token::EQ, flag_proxy, const1,
+ RelocInfo::kNoPosition);
}
- Statement* stop =
- factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition);
- Statement* empty = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
- Statement* if_flag_break =
- factory()->NewIfStatement(compare, stop, empty, RelocInfo::kNoPosition);
- Block* ignore_completion_block =
- factory()->NewBlock(NULL, 1, true, RelocInfo::kNoPosition);
- ignore_completion_block->statements()->Add(if_flag_break, zone());
- inner_block->statements()->Add(ignore_completion_block, zone());
- }
- inner_scope->set_end_position(scanner()->location().end_pos);
- inner_block->set_scope(inner_scope);
- scope_ = for_scope;
+ // Create chain of expressions "flag = 0, temp_x = x, ..."
+ Statement* compound_next_statement = NULL;
+ {
+ Expression* compound_next = NULL;
+ // Make expression: flag = 0.
+ {
+ VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
+ Expression* const0 =
+ factory()->NewSmiLiteral(0, RelocInfo::kNoPosition);
+ compound_next = factory()->NewAssignment(
+ Token::ASSIGN, flag_proxy, const0, RelocInfo::kNoPosition);
+ }
+
+ // Make the comma-separated list of temp_x = x assignments.
+ int inner_var_proxy_pos = scanner()->location().beg_pos;
+ for (int i = 0; i < names->length(); i++) {
+ VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
+ VariableProxy* proxy =
+ factory()->NewVariableProxy(inner_vars.at(i), inner_var_proxy_pos);
+ Assignment* assignment = factory()->NewAssignment(
+ Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition);
+ compound_next = factory()->NewBinaryOperation(
+ Token::COMMA, compound_next, assignment, RelocInfo::kNoPosition);
+ }
+
+ compound_next_statement = factory()->NewExpressionStatement(
+ compound_next, RelocInfo::kNoPosition);
+ }
+
+ // Make statement: labels: for (; flag == 1; flag = 0, temp_x = x)
+ // Note that we re-use the original loop node, which retains its labels
+ // and ensures that any break or continue statements in body point to
+ // the right place.
+ loop->Initialize(NULL, flag_cond, compound_next_statement, body);
+ inner_block->statements()->Add(loop, zone());
+
+ // Make statement: {{if (flag == 1) break;}}
+ {
+ Expression* compare = NULL;
+ // Make compare expresion: flag == 1.
+ {
+ Expression* const1 =
+ factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
+ VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
+ compare = factory()->NewCompareOperation(Token::EQ, flag_proxy, const1,
+ RelocInfo::kNoPosition);
+ }
+ Statement* stop =
+ factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition);
+ Statement* empty = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
+ Statement* if_flag_break = factory()->NewIfStatement(
+ compare, stop, empty, RelocInfo::kNoPosition);
+ Block* ignore_completion_block =
+ factory()->NewBlock(NULL, 1, true, RelocInfo::kNoPosition);
+ ignore_completion_block->statements()->Add(if_flag_break, zone());
+ inner_block->statements()->Add(ignore_completion_block, zone());
+ }
+
+ inner_scope->set_end_position(scanner()->location().end_pos);
+ inner_block->set_scope(inner_scope);
+ }
outer_loop->Initialize(NULL, NULL, NULL, inner_block);
return outer_block;
@@ -3536,18 +3598,14 @@
Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
bool* ok) {
- // ForStatement ::
- // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
-
int stmt_pos = peek_position();
- bool is_const = false;
Statement* init = NULL;
ZoneList<const AstRawString*> lexical_bindings(1, zone());
// Create an in-between scope for let-bound iteration variables.
- Scope* saved_scope = scope_;
Scope* for_scope = NewScope(scope_, BLOCK_SCOPE);
- scope_ = for_scope;
+
+ BlockState block_state(&scope_, for_scope);
Expect(Token::FOR, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
for_scope->set_start_position(scanner()->location().beg_pos);
@@ -3556,23 +3614,20 @@
if (peek() != Token::SEMICOLON) {
if (peek() == Token::VAR || (peek() == Token::CONST && allow_const()) ||
(peek() == Token::LET && IsNextLetKeyword())) {
- ParseVariableDeclarations(kForStatement, &parsing_result, CHECK_OK);
- is_const = parsing_result.descriptor.mode == CONST;
+ ParseVariableDeclarations(kForStatement, &parsing_result, nullptr,
+ CHECK_OK);
- int num_decl = parsing_result.declarations.length();
- bool accept_IN = num_decl >= 1;
ForEachStatement::VisitMode mode;
int each_beg_pos = scanner()->location().beg_pos;
int each_end_pos = scanner()->location().end_pos;
- if (accept_IN && CheckInOrOf(&mode, ok)) {
+ if (CheckInOrOf(&mode, ok)) {
if (!*ok) return nullptr;
- if (num_decl != 1) {
- const char* loop_type =
- mode == ForEachStatement::ITERATE ? "for-of" : "for-in";
+ if (parsing_result.declarations.length() != 1) {
ParserTraits::ReportMessageAt(
parsing_result.bindings_loc,
- MessageTemplate::kForInOfLoopMultiBindings, loop_type);
+ MessageTemplate::kForInOfLoopMultiBindings,
+ ForEachStatement::VisitModeString(mode));
*ok = false;
return nullptr;
}
@@ -3582,14 +3637,10 @@
(is_strict(language_mode()) || mode == ForEachStatement::ITERATE ||
IsLexicalVariableMode(parsing_result.descriptor.mode) ||
!decl.pattern->IsVariableProxy())) {
- if (mode == ForEachStatement::ITERATE) {
- ReportMessageAt(parsing_result.first_initializer_loc,
- MessageTemplate::kForOfLoopInitializer);
- } else {
- // TODO(caitp): This should be an error in sloppy mode too.
- ReportMessageAt(parsing_result.first_initializer_loc,
- MessageTemplate::kForInLoopInitializer);
- }
+ ParserTraits::ReportMessageAt(
+ parsing_result.first_initializer_loc,
+ MessageTemplate::kForInOfLoopInitializer,
+ ForEachStatement::VisitModeString(mode));
*ok = false;
return nullptr;
}
@@ -3599,6 +3650,7 @@
// special case for legacy for (var/const x =.... in)
if (!IsLexicalVariableMode(parsing_result.descriptor.mode) &&
decl.pattern->IsVariableProxy() && decl.initializer != nullptr) {
+ ++use_counts_[v8::Isolate::kForInInitializer];
const AstRawString* name =
decl.pattern->AsVariableProxy()->raw_name();
VariableProxy* single_var = scope_->NewUnresolved(
@@ -3630,52 +3682,59 @@
// let x; // for TDZ
// }
- Variable* temp = scope_->NewTemporary(
- ast_value_factory()->dot_for_string());
+ Variable* temp =
+ scope_->NewTemporary(ast_value_factory()->dot_for_string());
ForEachStatement* loop =
factory()->NewForEachStatement(mode, labels, stmt_pos);
Target target(&this->target_stack_, loop);
- Expression* enumerable = ParseExpression(true, CHECK_OK);
+ Expression* enumerable;
+ if (mode == ForEachStatement::ITERATE) {
+ ExpressionClassifier classifier(this);
+ enumerable = ParseAssignmentExpression(true, &classifier, CHECK_OK);
+ RewriteNonPattern(&classifier, CHECK_OK);
+ } else {
+ enumerable = ParseExpression(true, CHECK_OK);
+ }
Expect(Token::RPAREN, CHECK_OK);
Scope* body_scope = NewScope(scope_, BLOCK_SCOPE);
body_scope->set_start_position(scanner()->location().beg_pos);
- scope_ = body_scope;
-
- Statement* body = ParseSubStatement(NULL, CHECK_OK);
Block* body_block =
factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition);
- auto each_initialization_block =
- factory()->NewBlock(nullptr, 1, true, RelocInfo::kNoPosition);
{
- auto descriptor = parsing_result.descriptor;
- descriptor.declaration_pos = RelocInfo::kNoPosition;
- descriptor.initialization_pos = RelocInfo::kNoPosition;
- decl.initializer = factory()->NewVariableProxy(temp);
+ BlockState block_state(&scope_, body_scope);
- PatternRewriter::DeclareAndInitializeVariables(
- each_initialization_block, &descriptor, &decl,
- IsLexicalVariableMode(descriptor.mode) ? &lexical_bindings
- : nullptr,
- CHECK_OK);
+ Statement* body = ParseSubStatement(NULL, CHECK_OK);
+
+ auto each_initialization_block =
+ factory()->NewBlock(nullptr, 1, true, RelocInfo::kNoPosition);
+ {
+ auto descriptor = parsing_result.descriptor;
+ descriptor.declaration_pos = RelocInfo::kNoPosition;
+ descriptor.initialization_pos = RelocInfo::kNoPosition;
+ decl.initializer = factory()->NewVariableProxy(temp);
+
+ PatternRewriter::DeclareAndInitializeVariables(
+ each_initialization_block, &descriptor, &decl,
+ IsLexicalVariableMode(descriptor.mode) ? &lexical_bindings
+ : nullptr,
+ CHECK_OK);
+ }
+
+ body_block->statements()->Add(each_initialization_block, zone());
+ body_block->statements()->Add(body, zone());
+ VariableProxy* temp_proxy =
+ factory()->NewVariableProxy(temp, each_beg_pos, each_end_pos);
+ InitializeForEachStatement(loop, temp_proxy, enumerable, body_block,
+ false);
}
-
- body_block->statements()->Add(each_initialization_block, zone());
- body_block->statements()->Add(body, zone());
- VariableProxy* temp_proxy =
- factory()->NewVariableProxy(temp, each_beg_pos, each_end_pos);
- InitializeForEachStatement(loop, temp_proxy, enumerable, body_block,
- false);
- scope_ = for_scope;
body_scope->set_end_position(scanner()->location().end_pos);
body_scope = body_scope->FinalizeBlockScope();
- if (body_scope != nullptr) {
- body_block->set_scope(body_scope);
- }
+ body_block->set_scope(body_scope);
// Create a TDZ for any lexically-bound names.
if (IsLexicalVariableMode(parsing_result.descriptor.mode)) {
@@ -3688,28 +3747,31 @@
// TODO(adamk): This needs to be some sort of special
// INTERNAL variable that's invisible to the debugger
// but visible to everything else.
- VariableProxy* tdz_proxy = NewUnresolved(lexical_bindings[i], LET);
+ VariableProxy* tdz_proxy =
+ NewUnresolved(lexical_bindings[i], LET);
Declaration* tdz_decl = factory()->NewVariableDeclaration(
tdz_proxy, LET, scope_, RelocInfo::kNoPosition);
- Variable* tdz_var = Declare(tdz_decl, DeclarationDescriptor::NORMAL,
- true, CHECK_OK);
+ Variable* tdz_var = Declare(
+ tdz_decl, DeclarationDescriptor::NORMAL, true, CHECK_OK);
tdz_var->set_initializer_position(position());
}
}
- scope_ = saved_scope;
+ Statement* final_loop = loop->IsForOfStatement()
+ ? FinalizeForOfStatement(
+ loop->AsForOfStatement(), RelocInfo::kNoPosition)
+ : loop;
+
for_scope->set_end_position(scanner()->location().end_pos);
for_scope = for_scope->FinalizeBlockScope();
// Parsed for-in loop w/ variable declarations.
if (init_block != nullptr) {
- init_block->statements()->Add(loop, zone());
- if (for_scope != nullptr) {
- init_block->set_scope(for_scope);
- }
+ init_block->statements()->Add(final_loop, zone());
+ init_block->set_scope(for_scope);
return init_block;
} else {
DCHECK_NULL(for_scope);
- return loop;
+ return final_loop;
}
} else {
init = parsing_result.BuildInitializationBlock(
@@ -3720,7 +3782,7 @@
}
} else {
int lhs_beg_pos = peek_position();
- ExpressionClassifier classifier;
+ ExpressionClassifier classifier(this);
Expression* expression = ParseExpression(false, &classifier, CHECK_OK);
int lhs_end_pos = scanner()->location().end_pos;
ForEachStatement::VisitMode mode;
@@ -3738,8 +3800,7 @@
if (is_destructuring) {
ValidateAssignmentPattern(&classifier, CHECK_OK);
} else {
- expression =
- ParserTraits::RewriteNonPattern(expression, &classifier, CHECK_OK);
+ RewriteNonPattern(&classifier, CHECK_OK);
}
if (is_for_each) {
@@ -3753,7 +3814,15 @@
factory()->NewForEachStatement(mode, labels, stmt_pos);
Target target(&this->target_stack_, loop);
- Expression* enumerable = ParseExpression(true, CHECK_OK);
+ Expression* enumerable;
+ if (mode == ForEachStatement::ITERATE) {
+ ExpressionClassifier classifier(this);
+ enumerable = ParseAssignmentExpression(true, &classifier, CHECK_OK);
+ RewriteNonPattern(&classifier, CHECK_OK);
+ } else {
+ enumerable = ParseExpression(true, CHECK_OK);
+ }
+
Expect(Token::RPAREN, CHECK_OK);
// Make a block around the statement in case a lexical binding
@@ -3763,24 +3832,28 @@
// expressions in head of the loop should actually have variables
// resolved in the outer scope.
Scope* body_scope = NewScope(for_scope, BLOCK_SCOPE);
- scope_ = body_scope;
- Block* block =
- factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition);
- Statement* body = ParseSubStatement(NULL, CHECK_OK);
- block->statements()->Add(body, zone());
- InitializeForEachStatement(loop, expression, enumerable, block,
- is_destructuring);
- scope_ = saved_scope;
- body_scope->set_end_position(scanner()->location().end_pos);
- body_scope = body_scope->FinalizeBlockScope();
- if (body_scope != nullptr) {
+ {
+ BlockState block_state(&scope_, body_scope);
+ Block* block =
+ factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition);
+ Statement* body = ParseSubStatement(NULL, CHECK_OK);
+ block->statements()->Add(body, zone());
+ InitializeForEachStatement(loop, expression, enumerable, block,
+ is_destructuring);
+ body_scope->set_end_position(scanner()->location().end_pos);
+ body_scope = body_scope->FinalizeBlockScope();
block->set_scope(body_scope);
}
+
+ Statement* final_loop = loop->IsForOfStatement()
+ ? FinalizeForOfStatement(
+ loop->AsForOfStatement(), RelocInfo::kNoPosition)
+ : loop;
+
for_scope->set_end_position(scanner()->location().end_pos);
for_scope = for_scope->FinalizeBlockScope();
DCHECK(for_scope == nullptr);
- // Parsed for-in loop.
- return loop;
+ return final_loop;
} else {
init = factory()->NewExpressionStatement(expression, lhs_beg_pos);
@@ -3802,40 +3875,42 @@
}
Expect(Token::SEMICOLON, CHECK_OK);
+ Expression* cond = NULL;
+ Statement* next = NULL;
+ Statement* body = NULL;
+
// If there are let bindings, then condition and the next statement of the
// for loop must be parsed in a new scope.
- Scope* inner_scope = NULL;
+ Scope* inner_scope = scope_;
if (lexical_bindings.length() > 0) {
inner_scope = NewScope(for_scope, BLOCK_SCOPE);
inner_scope->set_start_position(scanner()->location().beg_pos);
- scope_ = inner_scope;
}
+ {
+ BlockState block_state(&scope_, inner_scope);
- Expression* cond = NULL;
- if (peek() != Token::SEMICOLON) {
- cond = ParseExpression(true, CHECK_OK);
+ if (peek() != Token::SEMICOLON) {
+ cond = ParseExpression(true, CHECK_OK);
+ }
+ Expect(Token::SEMICOLON, CHECK_OK);
+
+ if (peek() != Token::RPAREN) {
+ Expression* exp = ParseExpression(true, CHECK_OK);
+ next = factory()->NewExpressionStatement(exp, exp->position());
+ }
+ Expect(Token::RPAREN, CHECK_OK);
+
+ body = ParseSubStatement(NULL, CHECK_OK);
}
- Expect(Token::SEMICOLON, CHECK_OK);
-
- Statement* next = NULL;
- if (peek() != Token::RPAREN) {
- Expression* exp = ParseExpression(true, CHECK_OK);
- next = factory()->NewExpressionStatement(exp, exp->position());
- }
- Expect(Token::RPAREN, CHECK_OK);
-
- Statement* body = ParseSubStatement(NULL, CHECK_OK);
Statement* result = NULL;
if (lexical_bindings.length() > 0) {
- scope_ = for_scope;
+ BlockState block_state(&scope_, for_scope);
result = DesugarLexicalBindingsInForStatement(
- inner_scope, is_const, &lexical_bindings, loop, init, cond,
- next, body, CHECK_OK);
- scope_ = saved_scope;
+ inner_scope, parsing_result.descriptor.mode, &lexical_bindings, loop,
+ init, cond, next, body, CHECK_OK);
for_scope->set_end_position(scanner()->location().end_pos);
} else {
- scope_ = saved_scope;
for_scope->set_end_position(scanner()->location().end_pos);
for_scope = for_scope->FinalizeBlockScope();
if (for_scope) {
@@ -4035,7 +4110,7 @@
ParseArrowFunctionFormalParameters(parameters, expr, params_loc, ok);
if (!*ok) return;
- ExpressionClassifier classifier;
+ Type::ExpressionClassifier classifier(parser_);
if (!parameters->is_simple) {
classifier.RecordNonSimpleParameter();
}
@@ -4069,7 +4144,6 @@
const AstRawString* function_name, Scanner::Location function_name_location,
FunctionNameValidity function_name_validity, FunctionKind kind,
int function_token_pos, FunctionLiteral::FunctionType function_type,
- FunctionLiteral::ArityRestriction arity_restriction,
LanguageMode language_mode, bool* ok) {
// Function ::
// '(' FormalParameterList? ')' '{' FunctionBody '}'
@@ -4137,17 +4211,18 @@
int materialized_literal_count = -1;
int expected_property_count = -1;
DuplicateFinder duplicate_finder(scanner()->unicode_cache());
- ExpressionClassifier formals_classifier(&duplicate_finder);
FunctionLiteral::EagerCompileHint eager_compile_hint =
parenthesized_function_ ? FunctionLiteral::kShouldEagerCompile
: FunctionLiteral::kShouldLazyCompile;
bool should_be_used_once_hint = false;
+ bool has_duplicate_parameters;
// Parse function.
{
AstNodeFactory function_factory(ast_value_factory());
FunctionState function_state(&function_state_, &scope_, scope, kind,
&function_factory);
scope_->SetScopeName(function_name);
+ ExpressionClassifier formals_classifier(this, &duplicate_finder);
if (is_generator) {
// For generators, allocating variables in contexts is currently a win
@@ -4172,11 +4247,15 @@
Expect(Token::RPAREN, CHECK_OK);
int formals_end_position = scanner()->location().end_pos;
- CheckArityRestrictions(arity, arity_restriction,
- formals.has_rest, start_position,
+ CheckArityRestrictions(arity, kind, formals.has_rest, start_position,
formals_end_position, CHECK_OK);
Expect(Token::LBRACE, CHECK_OK);
+ // Don't include the rest parameter into the function's formal parameter
+ // count (esp. the SharedFunctionInfo::internal_formal_parameter_count,
+ // which says whether we need to create an arguments adaptor frame).
+ if (formals.has_rest) arity--;
+
// Determine if the function can be parsed lazily. Lazy parsing is different
// from lazy compilation; we need to parse more eagerly than we compile.
@@ -4321,10 +4400,10 @@
// If body can be inspected, rewrite queued destructuring assignments
ParserTraits::RewriteDestructuringAssignments();
}
+ has_duplicate_parameters =
+ !formals_classifier.is_valid_formal_parameter_list_without_duplicates();
}
- bool has_duplicate_parameters =
- !formals_classifier.is_valid_formal_parameter_list_without_duplicates();
FunctionLiteral::ParameterFlag duplicate_parameters =
has_duplicate_parameters ? FunctionLiteral::kHasDuplicateParameters
: FunctionLiteral::kNoDuplicateParameters;
@@ -4337,10 +4416,6 @@
if (should_be_used_once_hint)
function_literal->set_should_be_used_once_hint();
- if (scope->has_rest_parameter()) {
- function_literal->set_dont_optimize_reason(kRestParameter);
- }
-
if (fni_ != NULL && should_infer_name) fni_->AddFunction(function_literal);
return function_literal;
}
@@ -4461,15 +4536,18 @@
scope_(scope) {}
private:
- void VisitExpression(Expression* expr) {
- RewritableAssignmentExpression* to_rewrite =
- expr->AsRewritableAssignmentExpression();
+ void VisitExpression(Expression* expr) override {
+ RewritableExpression* to_rewrite = expr->AsRewritableExpression();
if (to_rewrite == nullptr || to_rewrite->is_rewritten()) return;
Parser::PatternRewriter::RewriteDestructuringAssignment(parser_, to_rewrite,
scope_);
}
+ // Code in function literals does not need to be eagerly rewritten, it will be
+ // rewritten when scheduled.
+ void VisitFunctionLiteral(FunctionLiteral* expr) override {}
+
private:
Parser* parser_;
Scope* scope_;
@@ -4497,7 +4575,6 @@
descriptor.scope = scope_;
descriptor.hoist_scope = nullptr;
descriptor.mode = LET;
- descriptor.needs_init = true;
descriptor.declaration_pos = parameter.pattern->position();
// The position that will be used by the AssignmentExpression
// which copies from the temp parameter to the pattern.
@@ -4597,35 +4674,72 @@
{
BlockState block_state(&scope_, inner_scope);
- // For generators, allocate and yield an iterator on function entry.
if (IsGeneratorFunction(kind)) {
- ZoneList<Expression*>* arguments =
- new(zone()) ZoneList<Expression*>(0, zone());
- CallRuntime* allocation = factory()->NewCallRuntime(
- Runtime::kCreateJSGeneratorObject, arguments, pos);
- VariableProxy* init_proxy = factory()->NewVariableProxy(
- function_state_->generator_object_variable());
- Assignment* assignment = factory()->NewAssignment(
- Token::INIT, init_proxy, allocation, RelocInfo::kNoPosition);
- VariableProxy* get_proxy = factory()->NewVariableProxy(
- function_state_->generator_object_variable());
- Yield* yield = factory()->NewYield(
- get_proxy, assignment, Yield::kInitial, RelocInfo::kNoPosition);
- body->Add(factory()->NewExpressionStatement(
- yield, RelocInfo::kNoPosition), zone());
- }
+ // We produce:
+ //
+ // try { InitialYield; ...body...; FinalYield }
+ // finally { %GeneratorClose(generator) }
+ //
+ // - InitialYield yields the actual generator object.
+ // - FinalYield yields {value: foo, done: true} where foo is the
+ // completion value of body. (This is needed here in case the body
+ // falls through without an explicit return.)
+ // - Any return statement inside the body will be converted into a similar
+ // FinalYield.
+ // - If the generator terminates for whatever reason, we must close it.
+ // Hence the finally clause.
- ParseStatementList(body, Token::RBRACE, CHECK_OK);
+ Block* try_block =
+ factory()->NewBlock(nullptr, 3, false, RelocInfo::kNoPosition);
- if (IsGeneratorFunction(kind)) {
+ {
+ ZoneList<Expression*>* arguments =
+ new (zone()) ZoneList<Expression*>(0, zone());
+ CallRuntime* allocation = factory()->NewCallRuntime(
+ Runtime::kCreateJSGeneratorObject, arguments, pos);
+ VariableProxy* init_proxy = factory()->NewVariableProxy(
+ function_state_->generator_object_variable());
+ Assignment* assignment = factory()->NewAssignment(
+ Token::INIT, init_proxy, allocation, RelocInfo::kNoPosition);
+ VariableProxy* get_proxy = factory()->NewVariableProxy(
+ function_state_->generator_object_variable());
+ Yield* yield = factory()->NewYield(
+ get_proxy, assignment, Yield::kInitial, RelocInfo::kNoPosition);
+ try_block->statements()->Add(
+ factory()->NewExpressionStatement(yield, RelocInfo::kNoPosition),
+ zone());
+ }
+
+ ParseStatementList(try_block->statements(), Token::RBRACE, CHECK_OK);
+
VariableProxy* get_proxy = factory()->NewVariableProxy(
function_state_->generator_object_variable());
Expression* undefined =
factory()->NewUndefinedLiteral(RelocInfo::kNoPosition);
Yield* yield = factory()->NewYield(get_proxy, undefined, Yield::kFinal,
RelocInfo::kNoPosition);
- body->Add(factory()->NewExpressionStatement(
- yield, RelocInfo::kNoPosition), zone());
+ try_block->statements()->Add(
+ factory()->NewExpressionStatement(yield, RelocInfo::kNoPosition),
+ zone());
+
+ Block* finally_block =
+ factory()->NewBlock(nullptr, 1, false, RelocInfo::kNoPosition);
+ ZoneList<Expression*>* args =
+ new (zone()) ZoneList<Expression*>(1, zone());
+ VariableProxy* call_proxy = factory()->NewVariableProxy(
+ function_state_->generator_object_variable());
+ args->Add(call_proxy, zone());
+ Expression* call = factory()->NewCallRuntime(
+ Runtime::kGeneratorClose, args, RelocInfo::kNoPosition);
+ finally_block->statements()->Add(
+ factory()->NewExpressionStatement(call, RelocInfo::kNoPosition),
+ zone());
+
+ body->Add(factory()->NewTryFinallyStatement(try_block, finally_block,
+ RelocInfo::kNoPosition),
+ zone());
+ } else {
+ ParseStatementList(body, Token::RBRACE, CHECK_OK);
}
if (IsSubclassConstructor(kind)) {
@@ -4682,6 +4796,13 @@
RelocInfo::kNoPosition));
}
+ // ES6 14.6.1 Static Semantics: IsInTailPosition
+ // Mark collected return expressions that are in tail call position.
+ const List<Expression*>& expressions_in_tail_position =
+ function_state_->expressions_in_tail_position();
+ for (int i = 0; i < expressions_in_tail_position.length(); ++i) {
+ expressions_in_tail_position[i]->MarkTail();
+ }
return result;
}
@@ -4693,6 +4814,8 @@
if (pre_parse_timer_ != NULL) {
pre_parse_timer_->Start();
}
+ TRACE_EVENT0("v8", "V8.PreParse");
+
DCHECK_EQ(Token::LBRACE, scanner()->current_token());
if (reusable_preparser_ == NULL) {
@@ -4709,6 +4832,7 @@
SET_ALLOW(strong_mode);
SET_ALLOW(harmony_do_expressions);
SET_ALLOW(harmony_function_name);
+ SET_ALLOW(harmony_function_sent);
#undef SET_ALLOW
}
PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction(
@@ -4751,19 +4875,17 @@
VariableProxy* proxy = NULL;
if (name != NULL) {
proxy = NewUnresolved(name, CONST);
- const bool is_class_declaration = true;
- Declaration* declaration = factory()->NewVariableDeclaration(
- proxy, CONST, block_scope, pos, is_class_declaration,
- scope_->class_declaration_group_start());
+ Declaration* declaration =
+ factory()->NewVariableDeclaration(proxy, CONST, block_scope, pos);
Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
}
Expression* extends = NULL;
if (Check(Token::EXTENDS)) {
block_scope->set_start_position(scanner()->location().end_pos);
- ExpressionClassifier classifier;
+ ExpressionClassifier classifier(this);
extends = ParseLeftHandSideExpression(&classifier, CHECK_OK);
- extends = ParserTraits::RewriteNonPattern(extends, &classifier, CHECK_OK);
+ RewriteNonPattern(&classifier, CHECK_OK);
} else {
block_scope->set_start_position(scanner()->location().end_pos);
}
@@ -4784,25 +4906,27 @@
const bool is_static = false;
bool is_computed_name = false; // Classes do not care about computed
// property names here.
- ExpressionClassifier classifier;
- const AstRawString* name = nullptr;
+ ExpressionClassifier classifier(this);
+ const AstRawString* property_name = nullptr;
ObjectLiteral::Property* property = ParsePropertyDefinition(
&checker, in_class, has_extends, is_static, &is_computed_name,
- &has_seen_constructor, &classifier, &name, CHECK_OK);
- property = ParserTraits::RewriteNonPatternObjectLiteralProperty(
- property, &classifier, CHECK_OK);
+ &has_seen_constructor, &classifier, &property_name, CHECK_OK);
+ RewriteNonPattern(&classifier, CHECK_OK);
if (has_seen_constructor && constructor == NULL) {
constructor = GetPropertyValue(property)->AsFunctionLiteral();
DCHECK_NOT_NULL(constructor);
+ constructor->set_raw_name(
+ name != nullptr ? name : ast_value_factory()->empty_string());
} else {
properties->Add(property, zone());
}
if (fni_ != NULL) fni_->Infer();
- if (allow_harmony_function_name()) {
- SetFunctionNameFromPropertyName(property, name);
+ if (allow_harmony_function_name() &&
+ property_name != ast_value_factory()->constructor_string()) {
+ SetFunctionNameFromPropertyName(property, property_name);
}
}
@@ -4810,8 +4934,8 @@
int end_pos = scanner()->location().end_pos;
if (constructor == NULL) {
- constructor = DefaultConstructor(extends != NULL, block_scope, pos, end_pos,
- block_scope->language_mode());
+ constructor = DefaultConstructor(name, extends != NULL, block_scope, pos,
+ end_pos, block_scope->language_mode());
}
// Note that we do not finalize this block scope because strong
@@ -4823,8 +4947,8 @@
proxy->var()->set_initializer_position(end_pos);
}
- return factory()->NewClassLiteral(name, block_scope, proxy, extends,
- constructor, properties, pos, end_pos);
+ return factory()->NewClassLiteral(block_scope, proxy, extends, constructor,
+ properties, pos, end_pos);
}
@@ -4838,10 +4962,9 @@
const AstRawString* name = ParseIdentifier(kAllowRestrictedIdentifiers,
CHECK_OK);
Scanner::Location spread_pos;
- ExpressionClassifier classifier;
+ ExpressionClassifier classifier(this);
ZoneList<Expression*>* args =
ParseArguments(&spread_pos, &classifier, CHECK_OK);
- args = RewriteNonPatternArguments(args, &classifier, CHECK_OK);
DCHECK(!spread_pos.IsValid());
@@ -5051,6 +5174,12 @@
isolate->CountUsage(v8::Isolate::UseCounterFeature(feature));
}
}
+ if (scanner_.FoundHtmlComment()) {
+ isolate->CountUsage(v8::Isolate::kHtmlComment);
+ if (script->line_offset() == 0 && script->column_offset() == 0) {
+ isolate->CountUsage(v8::Isolate::kHtmlCommentInExternalScript);
+ }
+ }
isolate->counters()->total_preparse_skipped()->Increment(
total_preparse_skipped_);
}
@@ -5404,145 +5533,1381 @@
}
-Expression* ParserTraits::RewriteNonPattern(
- Expression* expr, const ExpressionClassifier* classifier, bool* ok) {
- return parser_->RewriteNonPattern(expr, classifier, ok);
+void ParserTraits::RewriteNonPattern(Type::ExpressionClassifier* classifier,
+ bool* ok) {
+ parser_->RewriteNonPattern(classifier, ok);
}
-ZoneList<Expression*>* ParserTraits::RewriteNonPatternArguments(
- ZoneList<Expression*>* args, const ExpressionClassifier* classifier,
- bool* ok) {
- return parser_->RewriteNonPatternArguments(args, classifier, ok);
+Zone* ParserTraits::zone() const {
+ return parser_->function_state_->scope()->zone();
}
-ObjectLiteralProperty* ParserTraits::RewriteNonPatternObjectLiteralProperty(
- ObjectLiteralProperty* property, const ExpressionClassifier* classifier,
- bool* ok) {
- return parser_->RewriteNonPatternObjectLiteralProperty(property, classifier,
- ok);
+ZoneList<Expression*>* ParserTraits::GetNonPatternList() const {
+ return parser_->function_state_->non_patterns_to_rewrite();
}
-Expression* Parser::RewriteNonPattern(Expression* expr,
- const ExpressionClassifier* classifier,
- bool* ok) {
- // For the time being, this does no rewriting at all.
- ValidateExpression(classifier, ok);
- return expr;
-}
+class NonPatternRewriter : public AstExpressionRewriter {
+ public:
+ NonPatternRewriter(uintptr_t stack_limit, Parser* parser)
+ : AstExpressionRewriter(stack_limit), parser_(parser) {}
+ ~NonPatternRewriter() override {}
-
-ZoneList<Expression*>* Parser::RewriteNonPatternArguments(
- ZoneList<Expression*>* args, const ExpressionClassifier* classifier,
- bool* ok) {
- // For the time being, this does no rewriting at all.
- ValidateExpression(classifier, ok);
- return args;
-}
-
-
-ObjectLiteralProperty* Parser::RewriteNonPatternObjectLiteralProperty(
- ObjectLiteralProperty* property, const ExpressionClassifier* classifier,
- bool* ok) {
- if (property != nullptr) {
- Expression* key = RewriteNonPattern(property->key(), classifier, ok);
- property->set_key(key);
- Expression* value = RewriteNonPattern(property->value(), classifier, ok);
- property->set_value(value);
+ private:
+ bool RewriteExpression(Expression* expr) override {
+ if (expr->IsRewritableExpression()) return true;
+ // Rewrite only what could have been a pattern but is not.
+ if (expr->IsArrayLiteral()) {
+ // Spread rewriting in array literals.
+ ArrayLiteral* lit = expr->AsArrayLiteral();
+ VisitExpressions(lit->values());
+ replacement_ = parser_->RewriteSpreads(lit);
+ return false;
+ }
+ if (expr->IsObjectLiteral()) {
+ return true;
+ }
+ if (expr->IsBinaryOperation() &&
+ expr->AsBinaryOperation()->op() == Token::COMMA) {
+ return true;
+ }
+ // Everything else does not need rewriting.
+ return false;
}
- return property;
+
+ void VisitObjectLiteralProperty(ObjectLiteralProperty* property) override {
+ if (property == nullptr) return;
+ // Do not rewrite (computed) key expressions
+ AST_REWRITE_PROPERTY(Expression, property, value);
+ }
+
+ Parser* parser_;
+};
+
+
+void Parser::RewriteNonPattern(ExpressionClassifier* classifier, bool* ok) {
+ ValidateExpression(classifier, ok);
+ if (!*ok) return;
+ auto non_patterns_to_rewrite = function_state_->non_patterns_to_rewrite();
+ int begin = classifier->GetNonPatternBegin();
+ int end = non_patterns_to_rewrite->length();
+ if (begin < end) {
+ NonPatternRewriter rewriter(stack_limit_, this);
+ for (int i = begin; i < end; i++) {
+ DCHECK(non_patterns_to_rewrite->at(i)->IsRewritableExpression());
+ rewriter.Rewrite(non_patterns_to_rewrite->at(i));
+ }
+ non_patterns_to_rewrite->Rewind(begin);
+ }
}
void Parser::RewriteDestructuringAssignments() {
- FunctionState* func = function_state_;
if (!allow_harmony_destructuring_assignment()) return;
- const List<DestructuringAssignment>& assignments =
- func->destructuring_assignments_to_rewrite();
+ const auto& assignments =
+ function_state_->destructuring_assignments_to_rewrite();
for (int i = assignments.length() - 1; i >= 0; --i) {
// Rewrite list in reverse, so that nested assignment patterns are rewritten
// correctly.
- DestructuringAssignment pair = assignments.at(i);
- RewritableAssignmentExpression* to_rewrite =
- pair.assignment->AsRewritableAssignmentExpression();
- Scope* scope = pair.scope;
+ const DestructuringAssignment& pair = assignments.at(i);
+ RewritableExpression* to_rewrite =
+ pair.assignment->AsRewritableExpression();
DCHECK_NOT_NULL(to_rewrite);
if (!to_rewrite->is_rewritten()) {
- PatternRewriter::RewriteDestructuringAssignment(this, to_rewrite, scope);
+ PatternRewriter::RewriteDestructuringAssignment(this, to_rewrite,
+ pair.scope);
}
}
}
+Expression* Parser::RewriteSpreads(ArrayLiteral* lit) {
+ // Array literals containing spreads are rewritten using do expressions, e.g.
+ // [1, 2, 3, ...x, 4, ...y, 5]
+ // is roughly rewritten as:
+ // do {
+ // $R = [1, 2, 3];
+ // for ($i of x) %AppendElement($R, $i);
+ // %AppendElement($R, 4);
+ // for ($j of y) %AppendElement($R, $j);
+ // %AppendElement($R, 5);
+ // $R
+ // }
+ // where $R, $i and $j are fresh temporary variables.
+ ZoneList<Expression*>::iterator s = lit->FirstSpread();
+ if (s == lit->EndValue()) return nullptr; // no spread, no rewriting...
+ Variable* result =
+ scope_->NewTemporary(ast_value_factory()->dot_result_string());
+ // NOTE: The value assigned to R is the whole original array literal,
+ // spreads included. This will be fixed before the rewritten AST is returned.
+ // $R = lit
+ Expression* init_result =
+ factory()->NewAssignment(Token::INIT, factory()->NewVariableProxy(result),
+ lit, RelocInfo::kNoPosition);
+ Block* do_block =
+ factory()->NewBlock(nullptr, 16, false, RelocInfo::kNoPosition);
+ do_block->statements()->Add(
+ factory()->NewExpressionStatement(init_result, RelocInfo::kNoPosition),
+ zone());
+ // Traverse the array literal starting from the first spread.
+ while (s != lit->EndValue()) {
+ Expression* value = *s++;
+ Spread* spread = value->AsSpread();
+ if (spread == nullptr) {
+ // If the element is not a spread, we're adding a single:
+ // %AppendElement($R, value)
+ ZoneList<Expression*>* append_element_args = NewExpressionList(2, zone());
+ append_element_args->Add(factory()->NewVariableProxy(result), zone());
+ append_element_args->Add(value, zone());
+ do_block->statements()->Add(
+ factory()->NewExpressionStatement(
+ factory()->NewCallRuntime(Runtime::kAppendElement,
+ append_element_args,
+ RelocInfo::kNoPosition),
+ RelocInfo::kNoPosition),
+ zone());
+ } else {
+ // If it's a spread, we're adding a for/of loop iterating through it.
+ Variable* each =
+ scope_->NewTemporary(ast_value_factory()->dot_for_string());
+ Expression* subject = spread->expression();
+ Variable* iterator =
+ scope_->NewTemporary(ast_value_factory()->dot_iterator_string());
+ Variable* element =
+ scope_->NewTemporary(ast_value_factory()->dot_result_string());
+ // iterator = subject[Symbol.iterator]()
+ Expression* assign_iterator = factory()->NewAssignment(
+ Token::ASSIGN, factory()->NewVariableProxy(iterator),
+ GetIterator(subject, factory(), spread->expression_position()),
+ subject->position());
+ // !%_IsJSReceiver(element = iterator.next()) &&
+ // %ThrowIteratorResultNotAnObject(element)
+ Expression* next_element;
+ {
+ // element = iterator.next()
+ Expression* iterator_proxy = factory()->NewVariableProxy(iterator);
+ next_element = BuildIteratorNextResult(iterator_proxy, element,
+ spread->expression_position());
+ }
+ // element.done
+ Expression* element_done;
+ {
+ Expression* done_literal = factory()->NewStringLiteral(
+ ast_value_factory()->done_string(), RelocInfo::kNoPosition);
+ Expression* element_proxy = factory()->NewVariableProxy(element);
+ element_done = factory()->NewProperty(element_proxy, done_literal,
+ RelocInfo::kNoPosition);
+ }
+ // each = element.value
+ Expression* assign_each;
+ {
+ Expression* value_literal = factory()->NewStringLiteral(
+ ast_value_factory()->value_string(), RelocInfo::kNoPosition);
+ Expression* element_proxy = factory()->NewVariableProxy(element);
+ Expression* element_value = factory()->NewProperty(
+ element_proxy, value_literal, RelocInfo::kNoPosition);
+ assign_each = factory()->NewAssignment(
+ Token::ASSIGN, factory()->NewVariableProxy(each), element_value,
+ RelocInfo::kNoPosition);
+ }
+ // %AppendElement($R, each)
+ Statement* append_body;
+ {
+ ZoneList<Expression*>* append_element_args =
+ NewExpressionList(2, zone());
+ append_element_args->Add(factory()->NewVariableProxy(result), zone());
+ append_element_args->Add(factory()->NewVariableProxy(each), zone());
+ append_body = factory()->NewExpressionStatement(
+ factory()->NewCallRuntime(Runtime::kAppendElement,
+ append_element_args,
+ RelocInfo::kNoPosition),
+ RelocInfo::kNoPosition);
+ }
+ // for (each of spread) %AppendElement($R, each)
+ ForEachStatement* loop = factory()->NewForEachStatement(
+ ForEachStatement::ITERATE, nullptr, RelocInfo::kNoPosition);
+ ForOfStatement* for_of = loop->AsForOfStatement();
+ for_of->Initialize(factory()->NewVariableProxy(each), subject,
+ append_body, iterator, assign_iterator, next_element,
+ element_done, assign_each);
+ do_block->statements()->Add(for_of, zone());
+ }
+ }
+ // Now, rewind the original array literal to truncate everything from the
+ // first spread (included) until the end. This fixes $R's initialization.
+ lit->RewindSpreads();
+ return factory()->NewDoExpression(do_block, result, lit->position());
+}
+
+
void ParserTraits::QueueDestructuringAssignmentForRewriting(Expression* expr) {
- DCHECK(expr->IsRewritableAssignmentExpression());
+ DCHECK(expr->IsRewritableExpression());
parser_->function_state_->AddDestructuringAssignment(
Parser::DestructuringAssignment(expr, parser_->scope_));
}
+void ParserTraits::QueueNonPatternForRewriting(Expression* expr) {
+ DCHECK(expr->IsRewritableExpression());
+ parser_->function_state_->AddNonPatternForRewriting(expr);
+}
+
+
void ParserTraits::SetFunctionNameFromPropertyName(
ObjectLiteralProperty* property, const AstRawString* name) {
Expression* value = property->value();
- if (!value->IsFunctionLiteral() && !value->IsClassLiteral()) return;
- // TODO(adamk): Support computed names.
+ // Computed name setting must happen at runtime.
if (property->is_computed_name()) return;
+
+ // Getter and setter names are handled here because their names
+ // change in ES2015, even though they are not anonymous.
+ auto function = value->AsFunctionLiteral();
+ if (function != nullptr) {
+ bool is_getter = property->kind() == ObjectLiteralProperty::GETTER;
+ bool is_setter = property->kind() == ObjectLiteralProperty::SETTER;
+ if (is_getter || is_setter) {
+ DCHECK_NOT_NULL(name);
+ const AstRawString* prefix =
+ is_getter ? parser_->ast_value_factory()->get_space_string()
+ : parser_->ast_value_factory()->set_space_string();
+ function->set_raw_name(
+ parser_->ast_value_factory()->NewConsString(prefix, name));
+ return;
+ }
+ }
+
+ if (!value->IsAnonymousFunctionDefinition()) return;
DCHECK_NOT_NULL(name);
// Ignore "__proto__" as a name when it's being used to set the [[Prototype]]
// of an object literal.
if (property->kind() == ObjectLiteralProperty::PROTOTYPE) return;
- if (value->IsFunctionLiteral()) {
- auto function = value->AsFunctionLiteral();
- if (function->is_anonymous()) {
- if (property->kind() == ObjectLiteralProperty::GETTER) {
- function->set_raw_name(parser_->ast_value_factory()->NewConsString(
- parser_->ast_value_factory()->get_space_string(), name));
- } else if (property->kind() == ObjectLiteralProperty::SETTER) {
- function->set_raw_name(parser_->ast_value_factory()->NewConsString(
- parser_->ast_value_factory()->set_space_string(), name));
- } else {
- function->set_raw_name(name);
- DCHECK_EQ(ObjectLiteralProperty::COMPUTED, property->kind());
- }
- }
+ if (function != nullptr) {
+ function->set_raw_name(name);
+ DCHECK_EQ(ObjectLiteralProperty::COMPUTED, property->kind());
} else {
DCHECK(value->IsClassLiteral());
DCHECK_EQ(ObjectLiteralProperty::COMPUTED, property->kind());
- auto class_literal = value->AsClassLiteral();
- if (class_literal->raw_name() == nullptr) {
- class_literal->set_raw_name(name);
- }
+ value->AsClassLiteral()->constructor()->set_raw_name(name);
}
}
void ParserTraits::SetFunctionNameFromIdentifierRef(Expression* value,
Expression* identifier) {
- if (!value->IsFunctionLiteral() && !value->IsClassLiteral()) return;
+ if (!value->IsAnonymousFunctionDefinition()) return;
if (!identifier->IsVariableProxy()) return;
auto name = identifier->AsVariableProxy()->raw_name();
DCHECK_NOT_NULL(name);
- if (value->IsFunctionLiteral()) {
- auto function = value->AsFunctionLiteral();
- if (function->is_anonymous()) {
- function->set_raw_name(name);
- }
+ auto function = value->AsFunctionLiteral();
+ if (function != nullptr) {
+ function->set_raw_name(name);
} else {
DCHECK(value->IsClassLiteral());
- auto class_literal = value->AsClassLiteral();
- if (class_literal->raw_name() == nullptr) {
- class_literal->set_raw_name(name);
- }
+ value->AsClassLiteral()->constructor()->set_raw_name(name);
}
}
+// Desugaring of yield*
+// ====================
+//
+// With the help of do-expressions and function.sent, we desugar yield* into a
+// loop containing a "raw" yield (a yield that doesn't wrap an iterator result
+// object around its argument). Concretely, "yield* iterable" turns into
+// roughly the following code:
+//
+// do {
+// const kNext = 0;
+// const kReturn = 1;
+// const kThrow = 2;
+//
+// let input = function.sent;
+// let mode = kNext;
+// let output = undefined;
+//
+// let iterator = iterable[Symbol.iterator]();
+// if (!IS_RECEIVER(iterator)) throw MakeTypeError(kSymbolIteratorInvalid);
+//
+// while (true) {
+// // From the generator to the iterator:
+// // Forward input according to resume mode and obtain output.
+// switch (mode) {
+// case kNext:
+// output = iterator.next(input);
+// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
+// break;
+// case kReturn:
+// IteratorClose(iterator, input, output); // See below.
+// break;
+// case kThrow:
+// let iteratorThrow = iterator.throw;
+// if (IS_NULL_OR_UNDEFINED(iteratorThrow)) {
+// IteratorClose(iterator); // See below.
+// throw MakeTypeError(kThrowMethodMissing);
+// }
+// output = %_Call(iteratorThrow, iterator, input);
+// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
+// break;
+// }
+// if (output.done) break;
+//
+// // From the generator to its user:
+// // Forward output, receive new input, and determine resume mode.
+// mode = kReturn;
+// try {
+// try {
+// RawYield(output); // See explanation above.
+// mode = kNext;
+// } catch (error) {
+// mode = kThrow;
+// }
+// } finally {
+// input = function.sent;
+// continue;
+// }
+// }
+//
+// output.value;
+// }
+//
+// IteratorClose(iterator) expands to the following:
+//
+// let iteratorReturn = iterator.return;
+// if (IS_NULL_OR_UNDEFINED(iteratorReturn)) return;
+// let output = %_Call(iteratorReturn, iterator);
+// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
+//
+// IteratorClose(iterator, input, output) expands to the following:
+//
+// let iteratorReturn = iterator.return;
+// if (IS_NULL_OR_UNDEFINED(iteratorReturn)) return input;
+// output = %_Call(iteratorReturn, iterator, input);
+// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
+
+
+Expression* ParserTraits::RewriteYieldStar(
+ Expression* generator, Expression* iterable, int pos) {
+
+ const int nopos = RelocInfo::kNoPosition;
+
+ auto factory = parser_->factory();
+ auto avfactory = parser_->ast_value_factory();
+ auto scope = parser_->scope_;
+ auto zone = parser_->zone();
+
+
+ // Forward definition for break/continue statements.
+ WhileStatement* loop = factory->NewWhileStatement(nullptr, nopos);
+
+
+ // let input = undefined;
+ Variable* var_input = scope->NewTemporary(avfactory->empty_string());
+ Statement* initialize_input;
+ {
+ Expression* input_proxy = factory->NewVariableProxy(var_input);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, input_proxy, factory->NewUndefinedLiteral(nopos), nopos);
+ initialize_input = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+
+ // let mode = kNext;
+ Variable* var_mode = scope->NewTemporary(avfactory->empty_string());
+ Statement* initialize_mode;
+ {
+ Expression* mode_proxy = factory->NewVariableProxy(var_mode);
+ Expression* knext = factory->NewSmiLiteral(JSGeneratorObject::NEXT, nopos);
+ Expression* assignment =
+ factory->NewAssignment(Token::ASSIGN, mode_proxy, knext, nopos);
+ initialize_mode = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+
+ // let output = undefined;
+ Variable* var_output = scope->NewTemporary(avfactory->empty_string());
+ Statement* initialize_output;
+ {
+ Expression* output_proxy = factory->NewVariableProxy(var_output);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, output_proxy, factory->NewUndefinedLiteral(nopos),
+ nopos);
+ initialize_output = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+
+ // let iterator = iterable[Symbol.iterator];
+ Variable* var_iterator = scope->NewTemporary(avfactory->empty_string());
+ Statement* get_iterator;
+ {
+ Expression* iterator = GetIterator(iterable, factory, nopos);
+ Expression* iterator_proxy = factory->NewVariableProxy(var_iterator);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, iterator_proxy, iterator, nopos);
+ get_iterator = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+
+ // if (!IS_RECEIVER(iterator)) throw MakeTypeError(kSymbolIteratorInvalid);
+ Statement* validate_iterator;
+ {
+ Expression* is_receiver_call;
+ {
+ auto args = new (zone) ZoneList<Expression*>(1, zone);
+ args->Add(factory->NewVariableProxy(var_iterator), zone);
+ is_receiver_call =
+ factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
+ }
+
+ Statement* throw_call;
+ {
+ Expression* call = NewThrowTypeError(
+ MessageTemplate::kSymbolIteratorInvalid, avfactory->empty_string(),
+ nopos);
+ throw_call = factory->NewExpressionStatement(call, nopos);
+ }
+
+ validate_iterator = factory->NewIfStatement(
+ is_receiver_call, factory->NewEmptyStatement(nopos), throw_call, nopos);
+ }
+
+
+ // output = iterator.next(input);
+ Statement* call_next;
+ {
+ Expression* iterator_proxy = factory->NewVariableProxy(var_iterator);
+ Expression* literal =
+ factory->NewStringLiteral(avfactory->next_string(), nopos);
+ Expression* next_property =
+ factory->NewProperty(iterator_proxy, literal, nopos);
+ Expression* input_proxy = factory->NewVariableProxy(var_input);
+ auto args = new (zone) ZoneList<Expression*>(1, zone);
+ args->Add(input_proxy, zone);
+ Expression* call = factory->NewCall(next_property, args, nopos);
+ Expression* output_proxy = factory->NewVariableProxy(var_output);
+ Expression* assignment =
+ factory->NewAssignment(Token::ASSIGN, output_proxy, call, nopos);
+ call_next = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+
+ // if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
+ Statement* validate_next_output;
+ {
+ Expression* is_receiver_call;
+ {
+ auto args = new (zone) ZoneList<Expression*>(1, zone);
+ args->Add(factory->NewVariableProxy(var_output), zone);
+ is_receiver_call =
+ factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
+ }
+
+ Statement* throw_call;
+ {
+ auto args = new (zone) ZoneList<Expression*>(1, zone);
+ args->Add(factory->NewVariableProxy(var_output), zone);
+ Expression* call = factory->NewCallRuntime(
+ Runtime::kThrowIteratorResultNotAnObject, args, nopos);
+ throw_call = factory->NewExpressionStatement(call, nopos);
+ }
+
+ validate_next_output = factory->NewIfStatement(
+ is_receiver_call, factory->NewEmptyStatement(nopos), throw_call, nopos);
+ }
+
+
+ // let iteratorThrow = iterator.throw;
+ Variable* var_throw = scope->NewTemporary(avfactory->empty_string());
+ Statement* get_throw;
+ {
+ Expression* iterator_proxy = factory->NewVariableProxy(var_iterator);
+ Expression* literal =
+ factory->NewStringLiteral(avfactory->throw_string(), nopos);
+ Expression* property =
+ factory->NewProperty(iterator_proxy, literal, nopos);
+ Expression* throw_proxy = factory->NewVariableProxy(var_throw);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, throw_proxy, property, nopos);
+ get_throw = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+
+ // if (IS_NULL_OR_UNDEFINED(iteratorThrow) {
+ // IteratorClose(iterator);
+ // throw MakeTypeError(kThrowMethodMissing);
+ // }
+ Statement* check_throw;
+ {
+ Expression* condition = factory->NewCompareOperation(
+ Token::EQ, factory->NewVariableProxy(var_throw),
+ factory->NewNullLiteral(nopos), nopos);
+
+ Expression* call = NewThrowTypeError(
+ MessageTemplate::kThrowMethodMissing,
+ avfactory->empty_string(), nopos);
+ Statement* throw_call = factory->NewExpressionStatement(call, nopos);
+
+ Block* then = factory->NewBlock(nullptr, 4+1, false, nopos);
+ Variable* var_tmp = scope->NewTemporary(avfactory->empty_string());
+ BuildIteratorClose(
+ then->statements(), var_iterator, factory->NewUndefinedLiteral(nopos),
+ var_tmp);
+ then->statements()->Add(throw_call, zone);
+ check_throw = factory->NewIfStatement(
+ condition, then, factory->NewEmptyStatement(nopos), nopos);
+ }
+
+
+ // output = %_Call(iteratorThrow, iterator, input);
+ Statement* call_throw;
+ {
+ auto args = new (zone) ZoneList<Expression*>(3, zone);
+ args->Add(factory->NewVariableProxy(var_throw), zone);
+ args->Add(factory->NewVariableProxy(var_iterator), zone);
+ args->Add(factory->NewVariableProxy(var_input), zone);
+ Expression* call =
+ factory->NewCallRuntime(Runtime::kInlineCall, args, nopos);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, factory->NewVariableProxy(var_output), call, nopos);
+ call_throw = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+
+ // if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
+ Statement* validate_throw_output;
+ {
+ Expression* is_receiver_call;
+ {
+ auto args = new (zone) ZoneList<Expression*>(1, zone);
+ args->Add(factory->NewVariableProxy(var_output), zone);
+ is_receiver_call =
+ factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
+ }
+
+ Statement* throw_call;
+ {
+ auto args = new (zone) ZoneList<Expression*>(1, zone);
+ args->Add(factory->NewVariableProxy(var_output), zone);
+ Expression* call = factory->NewCallRuntime(
+ Runtime::kThrowIteratorResultNotAnObject, args, nopos);
+ throw_call = factory->NewExpressionStatement(call, nopos);
+ }
+
+ validate_throw_output = factory->NewIfStatement(
+ is_receiver_call, factory->NewEmptyStatement(nopos), throw_call, nopos);
+ }
+
+
+ // if (output.done) break;
+ Statement* if_done;
+ {
+ Expression* output_proxy = factory->NewVariableProxy(var_output);
+ Expression* literal =
+ factory->NewStringLiteral(avfactory->done_string(), nopos);
+ Expression* property = factory->NewProperty(output_proxy, literal, nopos);
+ BreakStatement* break_loop = factory->NewBreakStatement(loop, nopos);
+ if_done = factory->NewIfStatement(
+ property, break_loop, factory->NewEmptyStatement(nopos), nopos);
+ }
+
+
+ // mode = kReturn;
+ Statement* set_mode_return;
+ {
+ Expression* mode_proxy = factory->NewVariableProxy(var_mode);
+ Expression* kreturn =
+ factory->NewSmiLiteral(JSGeneratorObject::RETURN, nopos);
+ Expression* assignment =
+ factory->NewAssignment(Token::ASSIGN, mode_proxy, kreturn, nopos);
+ set_mode_return = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+
+ // RawYield(output);
+ Statement* yield_output;
+ {
+ Expression* output_proxy = factory->NewVariableProxy(var_output);
+ Yield* yield = factory->NewYield(
+ generator, output_proxy, Yield::kInitial, nopos);
+ yield_output = factory->NewExpressionStatement(yield, nopos);
+ }
+
+
+ // mode = kNext;
+ Statement* set_mode_next;
+ {
+ Expression* mode_proxy = factory->NewVariableProxy(var_mode);
+ Expression* knext = factory->NewSmiLiteral(JSGeneratorObject::NEXT, nopos);
+ Expression* assignment =
+ factory->NewAssignment(Token::ASSIGN, mode_proxy, knext, nopos);
+ set_mode_next = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+
+ // mode = kThrow;
+ Statement* set_mode_throw;
+ {
+ Expression* mode_proxy = factory->NewVariableProxy(var_mode);
+ Expression* kthrow =
+ factory->NewSmiLiteral(JSGeneratorObject::THROW, nopos);
+ Expression* assignment =
+ factory->NewAssignment(Token::ASSIGN, mode_proxy, kthrow, nopos);
+ set_mode_throw = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+
+ // input = function.sent;
+ Statement* get_input;
+ {
+ Expression* function_sent = FunctionSentExpression(scope, factory, nopos);
+ Expression* input_proxy = factory->NewVariableProxy(var_input);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, input_proxy, function_sent, nopos);
+ get_input = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+
+ // output.value;
+ Statement* get_value;
+ {
+ Expression* output_proxy = factory->NewVariableProxy(var_output);
+ Expression* literal =
+ factory->NewStringLiteral(avfactory->value_string(), nopos);
+ Expression* property = factory->NewProperty(output_proxy, literal, nopos);
+ get_value = factory->NewExpressionStatement(property, nopos);
+ }
+
+
+ // Now put things together.
+
+
+ // try { ... } catch(e) { ... }
+ Statement* try_catch;
+ {
+ Block* try_block = factory->NewBlock(nullptr, 2, false, nopos);
+ try_block->statements()->Add(yield_output, zone);
+ try_block->statements()->Add(set_mode_next, zone);
+
+ Block* catch_block = factory->NewBlock(nullptr, 1, false, nopos);
+ catch_block->statements()->Add(set_mode_throw, zone);
+
+ Scope* catch_scope = NewScope(scope, CATCH_SCOPE);
+ const AstRawString* name = avfactory->dot_catch_string();
+ Variable* catch_variable =
+ catch_scope->DeclareLocal(name, VAR, kCreatedInitialized,
+ Variable::NORMAL);
+
+ try_catch = factory->NewTryCatchStatement(
+ try_block, catch_scope, catch_variable, catch_block, nopos);
+ }
+
+
+ // try { ... } finally { ... }
+ Statement* try_finally;
+ {
+ Block* try_block = factory->NewBlock(nullptr, 1, false, nopos);
+ try_block->statements()->Add(try_catch, zone);
+
+ Block* finally = factory->NewBlock(nullptr, 2, false, nopos);
+ finally->statements()->Add(get_input, zone);
+ finally->statements()->Add(
+ factory->NewContinueStatement(loop, nopos), zone);
+
+ try_finally = factory->NewTryFinallyStatement(try_block, finally, nopos);
+ }
+
+
+ // switch (mode) { ... }
+ SwitchStatement* switch_mode = factory->NewSwitchStatement(nullptr, nopos);
+ {
+ auto case_next = new (zone) ZoneList<Statement*>(3, zone);
+ case_next->Add(call_next, zone);
+ case_next->Add(validate_next_output, zone);
+ case_next->Add(factory->NewBreakStatement(switch_mode, nopos), zone);
+
+ auto case_return = new (zone) ZoneList<Statement*>(5, zone);
+ BuildIteratorClose(case_return, var_iterator,
+ factory->NewVariableProxy(var_input, nopos), var_output);
+ case_return->Add(factory->NewBreakStatement(switch_mode, nopos), zone);
+
+ auto case_throw = new (zone) ZoneList<Statement*>(5, zone);
+ case_throw->Add(get_throw, zone);
+ case_throw->Add(check_throw, zone);
+ case_throw->Add(call_throw, zone);
+ case_throw->Add(validate_throw_output, zone);
+ case_throw->Add(factory->NewBreakStatement(switch_mode, nopos), zone);
+
+ auto cases = new (zone) ZoneList<CaseClause*>(3, zone);
+ Expression* knext = factory->NewSmiLiteral(JSGeneratorObject::NEXT, nopos);
+ Expression* kreturn =
+ factory->NewSmiLiteral(JSGeneratorObject::RETURN, nopos);
+ Expression* kthrow =
+ factory->NewSmiLiteral(JSGeneratorObject::THROW, nopos);
+ cases->Add(factory->NewCaseClause(knext, case_next, nopos), zone);
+ cases->Add(factory->NewCaseClause(kreturn, case_return, nopos), zone);
+ cases->Add(factory->NewCaseClause(kthrow, case_throw, nopos), zone);
+
+ switch_mode->Initialize(factory->NewVariableProxy(var_mode), cases);
+ }
+
+
+ // while (true) { ... }
+ // Already defined earlier: WhileStatement* loop = ...
+ {
+ Block* loop_body = factory->NewBlock(nullptr, 4, false, nopos);
+ loop_body->statements()->Add(switch_mode, zone);
+ loop_body->statements()->Add(if_done, zone);
+ loop_body->statements()->Add(set_mode_return, zone);
+ loop_body->statements()->Add(try_finally, zone);
+
+ loop->Initialize(factory->NewBooleanLiteral(true, nopos), loop_body);
+ }
+
+
+ // do { ... }
+ DoExpression* yield_star;
+ {
+ // The rewriter needs to process the get_value statement only, hence we
+ // put the preceding statements into an init block.
+
+ Block* do_block_ = factory->NewBlock(nullptr, 6, true, nopos);
+ do_block_->statements()->Add(initialize_input, zone);
+ do_block_->statements()->Add(initialize_mode, zone);
+ do_block_->statements()->Add(initialize_output, zone);
+ do_block_->statements()->Add(get_iterator, zone);
+ do_block_->statements()->Add(validate_iterator, zone);
+ do_block_->statements()->Add(loop, zone);
+
+ Block* do_block = factory->NewBlock(nullptr, 2, false, nopos);
+ do_block->statements()->Add(do_block_, zone);
+ do_block->statements()->Add(get_value, zone);
+
+ Variable* dot_result = scope->NewTemporary(avfactory->dot_result_string());
+ yield_star = factory->NewDoExpression(do_block, dot_result, nopos);
+ Rewriter::Rewrite(parser_, yield_star, avfactory);
+ }
+
+ return yield_star;
+}
+
+// Desugaring of (lhs) instanceof (rhs)
+// ====================================
+//
+// We desugar instanceof into a load of property @@hasInstance on the rhs.
+// We end up with roughly the following code (O, C):
+//
+// do {
+// let O = lhs;
+// let C = rhs;
+// if (!IS_RECEIVER(C)) throw MakeTypeError(kNonObjectInInstanceOfCheck);
+// let handler_result = C[Symbol.hasInstance];
+// if (handler_result === undefined) {
+// if (!IS_CALLABLE(C)) {
+// throw MakeTypeError(kCalledNonCallableInstanceOf);
+// }
+// handler_result = %ordinary_has_instance(C, O);
+// } else {
+// handler_result = !!(%_Call(handler_result, C, O));
+// }
+// handler_result;
+// }
+//
+Expression* ParserTraits::RewriteInstanceof(Expression* lhs, Expression* rhs,
+ int pos) {
+ const int nopos = RelocInfo::kNoPosition;
+
+ auto factory = parser_->factory();
+ auto avfactory = parser_->ast_value_factory();
+ auto scope = parser_->scope_;
+ auto zone = parser_->zone();
+
+ // let O = lhs;
+ Variable* var_O = scope->NewTemporary(avfactory->empty_string());
+ Statement* get_O;
+ {
+ Expression* O_proxy = factory->NewVariableProxy(var_O);
+ Expression* assignment =
+ factory->NewAssignment(Token::ASSIGN, O_proxy, lhs, nopos);
+ get_O = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+ // let C = lhs;
+ Variable* var_C = scope->NewTemporary(avfactory->empty_string());
+ Statement* get_C;
+ {
+ Expression* C_proxy = factory->NewVariableProxy(var_C);
+ Expression* assignment =
+ factory->NewAssignment(Token::ASSIGN, C_proxy, rhs, nopos);
+ get_C = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+ // if (!IS_RECEIVER(C)) throw MakeTypeError(kNonObjectInInstanceOfCheck);
+ Statement* validate_C;
+ {
+ auto args = new (zone) ZoneList<Expression*>(1, zone);
+ args->Add(factory->NewVariableProxy(var_C), zone);
+ Expression* is_receiver_call =
+ factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
+ Expression* call =
+ NewThrowTypeError(MessageTemplate::kNonObjectInInstanceOfCheck,
+ avfactory->empty_string(), nopos);
+ Statement* throw_call = factory->NewExpressionStatement(call, nopos);
+
+ validate_C =
+ factory->NewIfStatement(is_receiver_call,
+ factory->NewEmptyStatement(nopos),
+ throw_call,
+ nopos);
+ }
+
+ // let handler_result = C[Symbol.hasInstance];
+ Variable* var_handler_result = scope->NewTemporary(avfactory->empty_string());
+ Statement* initialize_handler;
+ {
+ Expression* hasInstance_symbol_literal =
+ factory->NewSymbolLiteral("hasInstance_symbol", RelocInfo::kNoPosition);
+ Expression* prop = factory->NewProperty(factory->NewVariableProxy(var_C),
+ hasInstance_symbol_literal, pos);
+ Expression* handler_proxy = factory->NewVariableProxy(var_handler_result);
+ Expression* assignment =
+ factory->NewAssignment(Token::ASSIGN, handler_proxy, prop, nopos);
+ initialize_handler = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+ // if (handler_result === undefined) {
+ // if (!IS_CALLABLE(C)) {
+ // throw MakeTypeError(kCalledNonCallableInstanceOf);
+ // }
+ // result = %ordinary_has_instance(C, O);
+ // } else {
+ // handler_result = !!%_Call(handler_result, C, O);
+ // }
+ Statement* call_handler;
+ {
+ Expression* condition = factory->NewCompareOperation(
+ Token::EQ_STRICT, factory->NewVariableProxy(var_handler_result),
+ factory->NewUndefinedLiteral(nopos), nopos);
+
+ Block* then_side = factory->NewBlock(nullptr, 2, false, nopos);
+ {
+ Expression* throw_expr =
+ NewThrowTypeError(MessageTemplate::kCalledNonCallableInstanceOf,
+ avfactory->empty_string(), nopos);
+ Statement* validate_C = CheckCallable(var_C, throw_expr);
+ ZoneList<Expression*>* args = new (zone) ZoneList<Expression*>(2, zone);
+ args->Add(factory->NewVariableProxy(var_C), zone);
+ args->Add(factory->NewVariableProxy(var_O), zone);
+ CallRuntime* call = factory->NewCallRuntime(
+ Context::ORDINARY_HAS_INSTANCE_INDEX, args, pos);
+ Expression* result_proxy = factory->NewVariableProxy(var_handler_result);
+ Expression* assignment =
+ factory->NewAssignment(Token::ASSIGN, result_proxy, call, nopos);
+ Statement* assignment_return =
+ factory->NewExpressionStatement(assignment, nopos);
+
+ then_side->statements()->Add(validate_C, zone);
+ then_side->statements()->Add(assignment_return, zone);
+ }
+
+ Statement* else_side;
+ {
+ auto args = new (zone) ZoneList<Expression*>(3, zone);
+ args->Add(factory->NewVariableProxy(var_handler_result), zone);
+ args->Add(factory->NewVariableProxy(var_C), zone);
+ args->Add(factory->NewVariableProxy(var_O), zone);
+ Expression* call =
+ factory->NewCallRuntime(Runtime::kInlineCall, args, nopos);
+ Expression* inner_not =
+ factory->NewUnaryOperation(Token::NOT, call, nopos);
+ Expression* outer_not =
+ factory->NewUnaryOperation(Token::NOT, inner_not, nopos);
+ Expression* result_proxy = factory->NewVariableProxy(var_handler_result);
+ Expression* assignment =
+ factory->NewAssignment(Token::ASSIGN, result_proxy, outer_not, nopos);
+
+ else_side = factory->NewExpressionStatement(assignment, nopos);
+ }
+ call_handler =
+ factory->NewIfStatement(condition, then_side, else_side, nopos);
+ }
+
+ // do { ... }
+ DoExpression* instanceof;
+ {
+ Block* block = factory->NewBlock(nullptr, 5, true, nopos);
+ block->statements()->Add(get_O, zone);
+ block->statements()->Add(get_C, zone);
+ block->statements()->Add(validate_C, zone);
+ block->statements()->Add(initialize_handler, zone);
+ block->statements()->Add(call_handler, zone);
+
+ // Here is the desugared instanceof.
+ instanceof = factory->NewDoExpression(block, var_handler_result, nopos);
+ Rewriter::Rewrite(parser_, instanceof, avfactory);
+ }
+
+ return instanceof;
+}
+
+Statement* ParserTraits::CheckCallable(Variable* var, Expression* error) {
+ auto factory = parser_->factory();
+ auto avfactory = parser_->ast_value_factory();
+ const int nopos = RelocInfo::kNoPosition;
+ Statement* validate_var;
+ {
+ Expression* type_of = factory->NewUnaryOperation(
+ Token::TYPEOF, factory->NewVariableProxy(var), nopos);
+ Expression* function_literal =
+ factory->NewStringLiteral(avfactory->function_string(), nopos);
+ Expression* condition = factory->NewCompareOperation(
+ Token::EQ_STRICT, type_of, function_literal, nopos);
+
+ Statement* throw_call = factory->NewExpressionStatement(error, nopos);
+
+ validate_var = factory->NewIfStatement(
+ condition, factory->NewEmptyStatement(nopos), throw_call, nopos);
+ }
+ return validate_var;
+}
+
+void ParserTraits::BuildIteratorClose(ZoneList<Statement*>* statements,
+ Variable* iterator,
+ Expression* input,
+ Variable* var_output) {
+ //
+ // This function adds four statements to [statements], corresponding to the
+ // following code:
+ //
+ // let iteratorReturn = iterator.return;
+ // if (IS_NULL_OR_UNDEFINED(iteratorReturn) return input;
+ // output = %_Call(iteratorReturn, iterator);
+ // if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
+ //
+
+ const int nopos = RelocInfo::kNoPosition;
+ auto factory = parser_->factory();
+ auto avfactory = parser_->ast_value_factory();
+ auto zone = parser_->zone();
+
+ // let iteratorReturn = iterator.return;
+ Variable* var_return = var_output; // Reusing the output variable.
+ Statement* get_return;
+ {
+ Expression* iterator_proxy = factory->NewVariableProxy(iterator);
+ Expression* literal =
+ factory->NewStringLiteral(avfactory->return_string(), nopos);
+ Expression* property =
+ factory->NewProperty(iterator_proxy, literal, nopos);
+ Expression* return_proxy = factory->NewVariableProxy(var_return);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, return_proxy, property, nopos);
+ get_return = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+ // if (IS_NULL_OR_UNDEFINED(iteratorReturn) return input;
+ Statement* check_return;
+ {
+ Expression* condition = factory->NewCompareOperation(
+ Token::EQ, factory->NewVariableProxy(var_return),
+ factory->NewNullLiteral(nopos), nopos);
+
+ Statement* return_input = factory->NewReturnStatement(input, nopos);
+
+ check_return = factory->NewIfStatement(
+ condition, return_input, factory->NewEmptyStatement(nopos), nopos);
+ }
+
+ // output = %_Call(iteratorReturn, iterator);
+ Statement* call_return;
+ {
+ auto args = new (zone) ZoneList<Expression*>(3, zone);
+ args->Add(factory->NewVariableProxy(var_return), zone);
+ args->Add(factory->NewVariableProxy(iterator), zone);
+
+ Expression* call =
+ factory->NewCallRuntime(Runtime::kInlineCall, args, nopos);
+ Expression* output_proxy = factory->NewVariableProxy(var_output);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, output_proxy, call, nopos);
+ call_return = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+ // if (!IS_RECEIVER(output)) %ThrowIteratorResultNotAnObject(output);
+ Statement* validate_output;
+ {
+ Expression* is_receiver_call;
+ {
+ auto args = new (zone) ZoneList<Expression*>(1, zone);
+ args->Add(factory->NewVariableProxy(var_output), zone);
+ is_receiver_call =
+ factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
+ }
+
+ Statement* throw_call;
+ {
+ auto args = new (zone) ZoneList<Expression*>(1, zone);
+ args->Add(factory->NewVariableProxy(var_output), zone);
+ Expression* call = factory->NewCallRuntime(
+ Runtime::kThrowIteratorResultNotAnObject, args, nopos);
+ throw_call = factory->NewExpressionStatement(call, nopos);
+ }
+
+ validate_output = factory->NewIfStatement(
+ is_receiver_call, factory->NewEmptyStatement(nopos), throw_call, nopos);
+ }
+
+ statements->Add(get_return, zone);
+ statements->Add(check_return, zone);
+ statements->Add(call_return, zone);
+ statements->Add(validate_output, zone);
+}
+
+
+// Runtime encoding of different completion modes.
+enum ForOfLoopBodyCompletion { BODY_COMPLETED, BODY_ABORTED, BODY_THREW };
+
+void ParserTraits::BuildIteratorCloseForCompletion(
+ ZoneList<Statement*>* statements, Variable* iterator,
+ Variable* completion) {
+ //
+ // This function adds two statements to [statements], corresponding to the
+ // following code:
+ //
+ // let iteratorReturn = iterator.return;
+ // if (!IS_NULL_OR_UNDEFINED(iteratorReturn)) {
+ // let output;
+ // if (completion === BODY_THREW) {
+ // if (!IS_CALLABLE(iteratorReturn)) {
+ // throw MakeTypeError(kReturnMethodNotCallable);
+ // }
+ // try { output = %_Call(iteratorReturn, iterator) } catch (_) { }
+ // } else {
+ // output = %_Call(iteratorReturn, iterator);
+ // }
+ // if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
+ // }
+ //
+
+ const int nopos = RelocInfo::kNoPosition;
+ auto factory = parser_->factory();
+ auto avfactory = parser_->ast_value_factory();
+ auto scope = parser_->scope_;
+ auto zone = parser_->zone();
+
+ // let output;
+ Variable* var_output = scope->NewTemporary(avfactory->empty_string());
+
+ // let iteratorReturn = iterator.return;
+ Variable* var_return = var_output; // Reusing the output variable.
+ Statement* get_return;
+ {
+ Expression* iterator_proxy = factory->NewVariableProxy(iterator);
+ Expression* literal =
+ factory->NewStringLiteral(avfactory->return_string(), nopos);
+ Expression* property =
+ factory->NewProperty(iterator_proxy, literal, nopos);
+ Expression* return_proxy = factory->NewVariableProxy(var_return);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, return_proxy, property, nopos);
+ get_return = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+ // if (!IS_CALLABLE(iteratorReturn)) {
+ // throw MakeTypeError(kReturnMethodNotCallable);
+ // }
+ Statement* check_return_callable;
+ {
+ Expression* throw_expr = NewThrowTypeError(
+ MessageTemplate::kReturnMethodNotCallable,
+ avfactory->empty_string(), nopos);
+ check_return_callable = CheckCallable(var_return, throw_expr);
+ }
+
+ // output = %_Call(iteratorReturn, iterator);
+ Statement* call_return;
+ {
+ auto args = new (zone) ZoneList<Expression*>(2, zone);
+ args->Add(factory->NewVariableProxy(var_return), zone);
+ args->Add(factory->NewVariableProxy(iterator), zone);
+ Expression* call =
+ factory->NewCallRuntime(Runtime::kInlineCall, args, nopos);
+
+ Expression* output_proxy = factory->NewVariableProxy(var_output);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, output_proxy, call, nopos);
+ call_return = factory->NewExpressionStatement(assignment, nopos);
+ }
+
+ // try { output = %_Call(iteratorReturn, iterator) } catch (_) { }
+ Statement* try_call_return;
+ {
+ auto args = new (zone) ZoneList<Expression*>(2, zone);
+ args->Add(factory->NewVariableProxy(var_return), zone);
+ args->Add(factory->NewVariableProxy(iterator), zone);
+
+ Expression* call =
+ factory->NewCallRuntime(Runtime::kInlineCall, args, nopos);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, factory->NewVariableProxy(var_output), call, nopos);
+
+ Block* try_block = factory->NewBlock(nullptr, 1, false, nopos);
+ try_block->statements()->Add(
+ factory->NewExpressionStatement(assignment, nopos), zone);
+
+ Block* catch_block = factory->NewBlock(nullptr, 0, false, nopos);
+
+ Scope* catch_scope = NewScope(scope, CATCH_SCOPE);
+ Variable* catch_variable = catch_scope->DeclareLocal(
+ avfactory->dot_catch_string(), VAR, kCreatedInitialized,
+ Variable::NORMAL);
+
+ try_call_return = factory->NewTryCatchStatement(
+ try_block, catch_scope, catch_variable, catch_block, nopos);
+ }
+
+ // if (completion === ABRUPT_THROW) {
+ // #check_return_callable;
+ // #try_call_return;
+ // } else {
+ // #call_return;
+ // }
+ Statement* call_return_carefully;
+ {
+ Expression* condition = factory->NewCompareOperation(
+ Token::EQ_STRICT, factory->NewVariableProxy(completion),
+ factory->NewSmiLiteral(BODY_THREW, nopos), nopos);
+
+ Block* then_block = factory->NewBlock(nullptr, 2, false, nopos);
+ then_block->statements()->Add(check_return_callable, zone);
+ then_block->statements()->Add(try_call_return, zone);
+
+ call_return_carefully =
+ factory->NewIfStatement(condition, then_block, call_return, nopos);
+ }
+
+ // if (!IS_RECEIVER(output)) %ThrowIteratorResultNotAnObject(output);
+ Statement* validate_output;
+ {
+ Expression* is_receiver_call;
+ {
+ auto args = new (zone) ZoneList<Expression*>(1, zone);
+ args->Add(factory->NewVariableProxy(var_output), zone);
+ is_receiver_call =
+ factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
+ }
+
+ Statement* throw_call;
+ {
+ auto args = new (zone) ZoneList<Expression*>(1, zone);
+ args->Add(factory->NewVariableProxy(var_output), zone);
+ Expression* call = factory->NewCallRuntime(
+ Runtime::kThrowIteratorResultNotAnObject, args, nopos);
+ throw_call = factory->NewExpressionStatement(call, nopos);
+ }
+
+ validate_output = factory->NewIfStatement(
+ is_receiver_call, factory->NewEmptyStatement(nopos), throw_call, nopos);
+ }
+
+ // if (!IS_NULL_OR_UNDEFINED(iteratorReturn)) { ... }
+ Statement* maybe_call_return;
+ {
+ Expression* condition = factory->NewCompareOperation(
+ Token::EQ, factory->NewVariableProxy(var_return),
+ factory->NewNullLiteral(nopos), nopos);
+
+ Block* block = factory->NewBlock(nullptr, 2, false, nopos);
+ block->statements()->Add(call_return_carefully, zone);
+ block->statements()->Add(validate_output, zone);
+
+ maybe_call_return = factory->NewIfStatement(
+ condition, factory->NewEmptyStatement(nopos), block, nopos);
+ }
+
+
+ statements->Add(get_return, zone);
+ statements->Add(maybe_call_return, zone);
+}
+
+
+Statement* ParserTraits::FinalizeForOfStatement(ForOfStatement* loop, int pos) {
+ if (!FLAG_harmony_iterator_close) return loop;
+
+ //
+ // This function replaces the loop with the following wrapping:
+ //
+ // let completion = BODY_COMPLETED;
+ // try {
+ // #loop;
+ // } catch(e) {
+ // if (completion === BODY_ABORTED) completion = BODY_THREW;
+ // throw e;
+ // } finally {
+ // if (!(completion === BODY_COMPLETED || IS_UNDEFINED(#iterator))) {
+ // #BuildIteratorClose(#iterator, completion) // See above.
+ // }
+ // }
+ //
+ // where the loop's body is wrapped as follows:
+ //
+ // {
+ // {{completion = BODY_ABORTED;}}
+ // #loop-body
+ // {{completion = BODY_COMPLETED;}}
+ // }
+
+ const int nopos = RelocInfo::kNoPosition;
+ auto factory = parser_->factory();
+ auto avfactory = parser_->ast_value_factory();
+ auto scope = parser_->scope_;
+ auto zone = parser_->zone();
+
+ // let completion = BODY_COMPLETED;
+ Variable* var_completion = scope->NewTemporary(avfactory->empty_string());
+ Statement* initialize_completion;
+ {
+ Expression* proxy = factory->NewVariableProxy(var_completion);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, proxy,
+ factory->NewSmiLiteral(BODY_COMPLETED, nopos), nopos);
+ initialize_completion =
+ factory->NewExpressionStatement(assignment, nopos);
+ }
+
+ // if (completion === BODY_ABORTED) completion = BODY_THREW;
+ Statement* set_completion_throw;
+ {
+ Expression* condition = factory->NewCompareOperation(
+ Token::EQ_STRICT, factory->NewVariableProxy(var_completion),
+ factory->NewSmiLiteral(BODY_ABORTED, nopos), nopos);
+
+ Expression* proxy = factory->NewVariableProxy(var_completion);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, proxy, factory->NewSmiLiteral(BODY_THREW, nopos),
+ nopos);
+ Statement* statement = factory->NewExpressionStatement(assignment, nopos);
+ set_completion_throw = factory->NewIfStatement(
+ condition, statement, factory->NewEmptyStatement(nopos), nopos);
+ }
+
+ // if (!(completion === BODY_COMPLETED || IS_UNDEFINED(#iterator))) {
+ // #BuildIteratorClose(#iterator, completion)
+ // }
+ Block* maybe_close;
+ {
+ Expression* condition1 = factory->NewCompareOperation(
+ Token::EQ_STRICT, factory->NewVariableProxy(var_completion),
+ factory->NewSmiLiteral(BODY_COMPLETED, nopos), nopos);
+ Expression* condition2 = factory->NewCompareOperation(
+ Token::EQ_STRICT, factory->NewVariableProxy(loop->iterator()),
+ factory->NewUndefinedLiteral(nopos), nopos);
+ Expression* condition = factory->NewBinaryOperation(
+ Token::OR, condition1, condition2, nopos);
+
+ Block* block = factory->NewBlock(nullptr, 2, false, nopos);
+ BuildIteratorCloseForCompletion(
+ block->statements(), loop->iterator(), var_completion);
+ DCHECK(block->statements()->length() == 2);
+
+ maybe_close = factory->NewBlock(nullptr, 1, false, nopos);
+ maybe_close->statements()->Add(factory->NewIfStatement(
+ condition, factory->NewEmptyStatement(nopos), block, nopos), zone);
+ }
+
+ // try { #try_block }
+ // catch(e) {
+ // #set_completion_throw;
+ // throw e;
+ // }
+ Statement* try_catch;
+ {
+ Scope* catch_scope = NewScope(scope, CATCH_SCOPE);
+ Variable* catch_variable = catch_scope->DeclareLocal(
+ avfactory->dot_catch_string(), VAR, kCreatedInitialized,
+ Variable::NORMAL);
+
+ Statement* rethrow;
+ {
+ Expression* proxy = factory->NewVariableProxy(catch_variable);
+ rethrow = factory->NewExpressionStatement(
+ factory->NewThrow(proxy, nopos), nopos);
+ }
+
+ Block* try_block = factory->NewBlock(nullptr, 1, false, nopos);
+ try_block->statements()->Add(loop, zone);
+
+ Block* catch_block = factory->NewBlock(nullptr, 2, false, nopos);
+ catch_block->statements()->Add(set_completion_throw, zone);
+ catch_block->statements()->Add(rethrow, zone);
+
+ try_catch = factory->NewTryCatchStatement(
+ try_block, catch_scope, catch_variable, catch_block, nopos);
+ }
+
+ // try { #try_catch } finally { #maybe_close }
+ Statement* try_finally;
+ {
+ Block* try_block = factory->NewBlock(nullptr, 1, false, nopos);
+ try_block->statements()->Add(try_catch, zone);
+
+ try_finally =
+ factory->NewTryFinallyStatement(try_block, maybe_close, nopos);
+ }
+
+ // #initialize_completion;
+ // #try_finally;
+ Statement* final_loop;
+ {
+ Block* block = factory->NewBlock(nullptr, 2, false, nopos);
+ block->statements()->Add(initialize_completion, zone);
+ block->statements()->Add(try_finally, zone);
+ final_loop = block;
+ }
+
+ // {{completion = BODY_ABORTED;}}
+ Statement* set_completion_break;
+ {
+ Expression* proxy = factory->NewVariableProxy(var_completion);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, proxy,
+ factory->NewSmiLiteral(BODY_ABORTED, nopos), nopos);
+
+ Block* block = factory->NewBlock(nullptr, 1, true, nopos);
+ block->statements()->Add(
+ factory->NewExpressionStatement(assignment, nopos), zone);
+ set_completion_break = block;
+ }
+
+ // {{completion = BODY_COMPLETED;}}
+ Statement* set_completion_normal;
+ {
+ Expression* proxy = factory->NewVariableProxy(var_completion);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, proxy, factory->NewSmiLiteral(BODY_COMPLETED, nopos),
+ nopos);
+
+ Block* block = factory->NewBlock(nullptr, 1, true, nopos);
+ block->statements()->Add(
+ factory->NewExpressionStatement(assignment, nopos), zone);
+ set_completion_normal = block;
+ }
+
+ // { #set_completion_break; #loop-body; #set_completion_normal }
+ Block* new_body = factory->NewBlock(nullptr, 2, false, nopos);
+ new_body->statements()->Add(set_completion_break, zone);
+ new_body->statements()->Add(loop->body(), zone);
+ new_body->statements()->Add(set_completion_normal, zone);
+
+ loop->set_body(new_body);
+ return final_loop;
+}
+
+
} // namespace internal
} // namespace v8
diff --git a/src/parsing/parser.h b/src/parsing/parser.h
index 7d50221..d4fb62f 100644
--- a/src/parsing/parser.h
+++ b/src/parsing/parser.h
@@ -335,6 +335,9 @@
typedef v8::internal::AstProperties AstProperties;
+ typedef v8::internal::ExpressionClassifier<ParserTraits>
+ ExpressionClassifier;
+
// Return types for traversing functions.
typedef const AstRawString* Identifier;
typedef v8::internal::Expression* Expression;
@@ -461,6 +464,8 @@
MessageTemplate::Template message,
const AstRawString* arg, int pos);
+ Statement* FinalizeForOfStatement(ForOfStatement* loop, int pos);
+
// Reporting errors.
void ReportMessageAt(Scanner::Location source_location,
MessageTemplate::Template message,
@@ -513,8 +518,8 @@
int pos);
Expression* NewTargetExpression(Scope* scope, AstNodeFactory* factory,
int pos);
- Expression* DefaultConstructor(bool call_super, Scope* scope, int pos,
- int end_pos, LanguageMode language_mode);
+ Expression* FunctionSentExpression(Scope* scope, AstNodeFactory* factory,
+ int pos);
Literal* ExpressionFromLiteral(Token::Value token, int pos, Scanner* scanner,
AstNodeFactory* factory);
Expression* ExpressionFromIdentifier(const AstRawString* name,
@@ -547,7 +552,7 @@
int initializer_end_position, bool is_rest);
V8_INLINE void DeclareFormalParameter(
Scope* scope, const ParserFormalParameters::Parameter& parameter,
- ExpressionClassifier* classifier);
+ Type::ExpressionClassifier* classifier);
void ParseArrowFunctionFormalParameters(ParserFormalParameters* parameters,
Expression* params,
const Scanner::Location& params_loc,
@@ -567,7 +572,6 @@
const AstRawString* name, Scanner::Location function_name_location,
FunctionNameValidity function_name_validity, FunctionKind kind,
int function_token_position, FunctionLiteral::FunctionType type,
- FunctionLiteral::ArityRestriction arity_restriction,
LanguageMode language_mode, bool* ok);
V8_INLINE void SkipLazyFunctionBody(
int* materialized_literal_count, int* expected_property_count, bool* ok,
@@ -642,6 +646,7 @@
V8_INLINE void QueueDestructuringAssignmentForRewriting(
Expression* assignment);
+ V8_INLINE void QueueNonPatternForRewriting(Expression* expr);
void SetFunctionNameFromPropertyName(ObjectLiteralProperty* property,
const AstRawString* name);
@@ -650,17 +655,28 @@
Expression* identifier);
// Rewrite expressions that are not used as patterns
- V8_INLINE Expression* RewriteNonPattern(
- Expression* expr, const ExpressionClassifier* classifier, bool* ok);
- V8_INLINE ZoneList<Expression*>* RewriteNonPatternArguments(
- ZoneList<Expression*>* args, const ExpressionClassifier* classifier,
- bool* ok);
- V8_INLINE ObjectLiteralProperty* RewriteNonPatternObjectLiteralProperty(
- ObjectLiteralProperty* property, const ExpressionClassifier* classifier,
- bool* ok);
+ V8_INLINE void RewriteNonPattern(Type::ExpressionClassifier* classifier,
+ bool* ok);
+
+ V8_INLINE Zone* zone() const;
+
+ V8_INLINE ZoneList<Expression*>* GetNonPatternList() const;
+
+ Expression* RewriteYieldStar(
+ Expression* generator, Expression* expression, int pos);
+
+ Expression* RewriteInstanceof(Expression* lhs, Expression* rhs, int pos);
private:
Parser* parser_;
+
+ void BuildIteratorClose(
+ ZoneList<Statement*>* statements, Variable* iterator,
+ Expression* input, Variable* output);
+ void BuildIteratorCloseForCompletion(
+ ZoneList<Statement*>* statements, Variable* iterator,
+ Variable* body_threw);
+ Statement* CheckCallable(Variable* var, Expression* error);
};
@@ -744,6 +760,9 @@
bool* ok);
Statement* ParseFunctionDeclaration(ZoneList<const AstRawString*>* names,
bool* ok);
+ Statement* ParseFunctionDeclaration(int pos, bool is_generator,
+ ZoneList<const AstRawString*>* names,
+ bool* ok);
Statement* ParseClassDeclaration(ZoneList<const AstRawString*>* names,
bool* ok);
Statement* ParseNativeDeclaration(bool* ok);
@@ -754,6 +773,7 @@
ZoneList<const AstRawString*>* names,
bool* ok);
DoExpression* ParseDoExpression(bool* ok);
+ Expression* ParseYieldStarExpression(bool* ok);
struct DeclarationDescriptor {
enum Kind { NORMAL, PARAMETER };
@@ -761,7 +781,6 @@
Scope* scope;
Scope* hoist_scope;
VariableMode mode;
- bool needs_init;
int declaration_pos;
int initialization_pos;
Kind declaration_kind;
@@ -801,8 +820,9 @@
const DeclarationParsingResult::Declaration* declaration,
ZoneList<const AstRawString*>* names, bool* ok);
- static void RewriteDestructuringAssignment(
- Parser* parser, RewritableAssignmentExpression* expr, Scope* Scope);
+ static void RewriteDestructuringAssignment(Parser* parser,
+ RewritableExpression* expr,
+ Scope* Scope);
static Expression* RewriteDestructuringAssignment(Parser* parser,
Assignment* assignment,
@@ -872,10 +892,10 @@
bool* ok_;
};
-
- void ParseVariableDeclarations(VariableDeclarationContext var_context,
- DeclarationParsingResult* parsing_result,
- bool* ok);
+ Block* ParseVariableDeclarations(VariableDeclarationContext var_context,
+ DeclarationParsingResult* parsing_result,
+ ZoneList<const AstRawString*>* names,
+ bool* ok);
Statement* ParseExpressionOrLabelledStatement(
ZoneList<const AstRawString*>* labels, bool* ok);
IfStatement* ParseIfStatement(ZoneList<const AstRawString*>* labels,
@@ -896,6 +916,8 @@
Statement* ParseForStatement(ZoneList<const AstRawString*>* labels, bool* ok);
Statement* ParseThrowStatement(bool* ok);
Expression* MakeCatchContext(Handle<String> id, VariableProxy* value);
+ class DontCollectExpressionsInTailPositionScope;
+ class CollectExpressionsInTailPositionToListScope;
TryStatement* ParseTryStatement(bool* ok);
DebuggerStatement* ParseDebuggerStatement(bool* ok);
@@ -910,9 +932,9 @@
Expression* subject, Statement* body,
bool is_destructuring);
Statement* DesugarLexicalBindingsInForStatement(
- Scope* inner_scope, bool is_const, ZoneList<const AstRawString*>* names,
- ForStatement* loop, Statement* init, Expression* cond, Statement* next,
- Statement* body, bool* ok);
+ Scope* inner_scope, VariableMode mode,
+ ZoneList<const AstRawString*>* names, ForStatement* loop, Statement* init,
+ Expression* cond, Statement* next, Statement* body, bool* ok);
void RewriteDoExpression(Expression* expr, bool* ok);
@@ -920,7 +942,6 @@
const AstRawString* name, Scanner::Location function_name_location,
FunctionNameValidity function_name_validity, FunctionKind kind,
int function_token_position, FunctionLiteral::FunctionType type,
- FunctionLiteral::ArityRestriction arity_restriction,
LanguageMode language_mode, bool* ok);
@@ -966,8 +987,9 @@
Statement* BuildAssertIsCoercible(Variable* var);
// Factory methods.
- FunctionLiteral* DefaultConstructor(bool call_super, Scope* scope, int pos,
- int end_pos, LanguageMode language_mode);
+ FunctionLiteral* DefaultConstructor(const AstRawString* name, bool call_super,
+ Scope* scope, int pos, int end_pos,
+ LanguageMode language_mode);
// Skip over a lazy function, either using cached data if we have it, or
// by parsing the function with PreParser. Consumes the ending }.
@@ -1013,14 +1035,10 @@
V8_INLINE void RewriteDestructuringAssignments();
- V8_INLINE Expression* RewriteNonPattern(
- Expression* expr, const ExpressionClassifier* classifier, bool* ok);
- V8_INLINE ZoneList<Expression*>* RewriteNonPatternArguments(
- ZoneList<Expression*>* args, const ExpressionClassifier* classifier,
- bool* ok);
- V8_INLINE ObjectLiteralProperty* RewriteNonPatternObjectLiteralProperty(
- ObjectLiteralProperty* property, const ExpressionClassifier* classifier,
- bool* ok);
+ friend class NonPatternRewriter;
+ V8_INLINE Expression* RewriteSpreads(ArrayLiteral* lit);
+
+ V8_INLINE void RewriteNonPattern(ExpressionClassifier* classifier, bool* ok);
friend class InitializerRewriter;
void RewriteParameterInitializer(Expression* expr, Scope* scope);
@@ -1171,7 +1189,7 @@
void ParserTraits::DeclareFormalParameter(
Scope* scope, const ParserFormalParameters::Parameter& parameter,
- ExpressionClassifier* classifier) {
+ Type::ExpressionClassifier* classifier) {
bool is_duplicate = false;
bool is_simple = classifier->is_simple_parameter_list();
auto name = is_simple || parameter.is_rest
diff --git a/src/parsing/pattern-rewriter.cc b/src/parsing/pattern-rewriter.cc
index 6e20282..768a948 100644
--- a/src/parsing/pattern-rewriter.cc
+++ b/src/parsing/pattern-rewriter.cc
@@ -33,7 +33,7 @@
void Parser::PatternRewriter::RewriteDestructuringAssignment(
- Parser* parser, RewritableAssignmentExpression* to_rewrite, Scope* scope) {
+ Parser* parser, RewritableExpression* to_rewrite, Scope* scope) {
PatternRewriter rewriter;
DCHECK(!to_rewrite->is_rewritten());
@@ -58,8 +58,7 @@
Parser* parser, Assignment* assignment, Scope* scope) {
DCHECK_NOT_NULL(assignment);
DCHECK_EQ(Token::ASSIGN, assignment->op());
- auto to_rewrite =
- parser->factory()->NewRewritableAssignmentExpression(assignment);
+ auto to_rewrite = parser->factory()->NewRewritableExpression(assignment);
RewriteDestructuringAssignment(parser, to_rewrite, scope);
return to_rewrite->expression();
}
@@ -78,7 +77,11 @@
Parser::PatternRewriter::PatternContext
Parser::PatternRewriter::SetAssignmentContextIfNeeded(Expression* node) {
PatternContext old_context = context();
- if (node->IsAssignment() && node->AsAssignment()->op() == Token::ASSIGN) {
+ // AssignmentExpressions may occur in the Initializer position of a
+ // SingleNameBinding. Such expressions should not prompt a change in the
+ // pattern's context.
+ if (node->IsAssignment() && node->AsAssignment()->op() == Token::ASSIGN &&
+ !IsInitializerContext()) {
set_context(ASSIGNMENT);
}
return old_context;
@@ -91,8 +94,8 @@
// AssignmentElement nodes
PatternContext old_context = context();
bool is_destructuring_assignment =
- node->IsRewritableAssignmentExpression() &&
- !node->AsRewritableAssignmentExpression()->is_rewritten();
+ node->IsRewritableExpression() &&
+ !node->AsRewritableExpression()->is_rewritten();
bool is_assignment =
node->IsAssignment() && node->AsAssignment()->op() == Token::ASSIGN;
if (is_destructuring_assignment || is_assignment) {
@@ -324,10 +327,11 @@
}
-void Parser::PatternRewriter::VisitRewritableAssignmentExpression(
- RewritableAssignmentExpression* node) {
- if (!IsAssignmentContext()) {
- // Mark the assignment as rewritten to prevent redundant rewriting, and
+void Parser::PatternRewriter::VisitRewritableExpression(
+ RewritableExpression* node) {
+ // If this is not a destructuring assignment...
+ if (!IsAssignmentContext() || !node->expression()->IsAssignment()) {
+ // Mark the node as rewritten to prevent redundant rewriting, and
// perform BindingPattern rewriting
DCHECK(!node->is_rewritten());
node->Rewrite(node->expression());
diff --git a/src/parsing/preparser.cc b/src/parsing/preparser.cc
index 64511ac..d335c8b 100644
--- a/src/parsing/preparser.cc
+++ b/src/parsing/preparser.cc
@@ -94,11 +94,10 @@
PreParserIdentifier name, Scanner::Location function_name_location,
FunctionNameValidity function_name_validity, FunctionKind kind,
int function_token_position, FunctionLiteral::FunctionType type,
- FunctionLiteral::ArityRestriction arity_restriction,
LanguageMode language_mode, bool* ok) {
return pre_parser_->ParseFunctionLiteral(
name, function_name_location, function_name_validity, kind,
- function_token_position, type, arity_restriction, language_mode, ok);
+ function_token_position, type, language_mode, ok);
}
@@ -451,8 +450,7 @@
: kFunctionNameValidityUnknown,
is_generator ? FunctionKind::kGeneratorFunction
: FunctionKind::kNormalFunction,
- pos, FunctionLiteral::kDeclaration,
- FunctionLiteral::kNormalArity, language_mode(),
+ pos, FunctionLiteral::kDeclaration, language_mode(),
CHECK_OK);
return Statement::FunctionDeclaration();
}
@@ -575,7 +573,7 @@
int decl_pos = peek_position();
PreParserExpression pattern = PreParserExpression::Default();
{
- ExpressionClassifier pattern_classifier;
+ ExpressionClassifier pattern_classifier(this);
Token::Value next = peek();
pattern = ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
@@ -591,17 +589,12 @@
}
}
- is_pattern = (pattern.IsObjectLiteral() || pattern.IsArrayLiteral()) &&
- !pattern.is_parenthesized();
-
- bool is_for_iteration_variable =
- var_context == kForStatement &&
- (peek() == Token::IN || PeekContextualKeyword(CStrVector("of")));
+ is_pattern = pattern.IsObjectLiteral() || pattern.IsArrayLiteral();
Scanner::Location variable_loc = scanner()->location();
nvars++;
if (Check(Token::ASSIGN)) {
- ExpressionClassifier classifier;
+ ExpressionClassifier classifier(this);
ParseAssignmentExpression(var_context != kForStatement, &classifier,
CHECK_OK);
ValidateExpression(&classifier, CHECK_OK);
@@ -611,7 +604,7 @@
*first_initializer_loc = variable_loc;
}
} else if ((require_initializer || is_pattern) &&
- !is_for_iteration_variable) {
+ (var_context != kForStatement || !PeekInOrOf())) {
PreParserTraits::ReportMessageAt(
Scanner::Location(decl_pos, scanner()->location().end_pos),
MessageTemplate::kDeclarationMissingInitializer,
@@ -655,7 +648,7 @@
IsClassConstructor(function_state_->kind())) {
bool is_this = peek() == Token::THIS;
Expression expr = Expression::Default();
- ExpressionClassifier classifier;
+ ExpressionClassifier classifier(this);
if (is_this) {
expr = ParseStrongInitializationExpression(&classifier, CHECK_OK);
} else {
@@ -691,7 +684,7 @@
}
bool starts_with_identifier = peek_any_identifier();
- ExpressionClassifier classifier;
+ ExpressionClassifier classifier(this);
Expression expr = ParseExpression(true, &classifier, CHECK_OK);
ValidateExpression(&classifier, CHECK_OK);
@@ -924,40 +917,40 @@
ParseVariableDeclarations(kForStatement, &decl_count, &is_lexical,
&is_binding_pattern, &first_initializer_loc,
&bindings_loc, CHECK_OK);
- bool accept_IN = decl_count >= 1;
- if (accept_IN && CheckInOrOf(&mode, ok)) {
+ if (CheckInOrOf(&mode, ok)) {
if (!*ok) return Statement::Default();
if (decl_count != 1) {
- const char* loop_type =
- mode == ForEachStatement::ITERATE ? "for-of" : "for-in";
PreParserTraits::ReportMessageAt(
bindings_loc, MessageTemplate::kForInOfLoopMultiBindings,
- loop_type);
+ ForEachStatement::VisitModeString(mode));
*ok = false;
return Statement::Default();
}
if (first_initializer_loc.IsValid() &&
(is_strict(language_mode()) || mode == ForEachStatement::ITERATE ||
is_lexical || is_binding_pattern)) {
- if (mode == ForEachStatement::ITERATE) {
- ReportMessageAt(first_initializer_loc,
- MessageTemplate::kForOfLoopInitializer);
- } else {
- // TODO(caitp): This should be an error in sloppy mode, too.
- ReportMessageAt(first_initializer_loc,
- MessageTemplate::kForInLoopInitializer);
- }
+ PreParserTraits::ReportMessageAt(
+ first_initializer_loc, MessageTemplate::kForInOfLoopInitializer,
+ ForEachStatement::VisitModeString(mode));
*ok = false;
return Statement::Default();
}
- ParseExpression(true, CHECK_OK);
+
+ if (mode == ForEachStatement::ITERATE) {
+ ExpressionClassifier classifier(this);
+ ParseAssignmentExpression(true, &classifier, CHECK_OK);
+ RewriteNonPattern(&classifier, CHECK_OK);
+ } else {
+ ParseExpression(true, CHECK_OK);
+ }
+
Expect(Token::RPAREN, CHECK_OK);
ParseSubStatement(CHECK_OK);
return Statement::Default();
}
} else {
int lhs_beg_pos = peek_position();
- ExpressionClassifier classifier;
+ ExpressionClassifier classifier(this);
Expression lhs = ParseExpression(false, &classifier, CHECK_OK);
int lhs_end_pos = scanner()->location().end_pos;
is_let_identifier_expression =
@@ -980,7 +973,15 @@
lhs, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor,
kSyntaxError, CHECK_OK);
}
- ParseExpression(true, CHECK_OK);
+
+ if (mode == ForEachStatement::ITERATE) {
+ ExpressionClassifier classifier(this);
+ ParseAssignmentExpression(true, &classifier, CHECK_OK);
+ RewriteNonPattern(&classifier, CHECK_OK);
+ } else {
+ ParseExpression(true, CHECK_OK);
+ }
+
Expect(Token::RPAREN, CHECK_OK);
ParseSubStatement(CHECK_OK);
return Statement::Default();
@@ -1054,7 +1055,7 @@
if (tok == Token::CATCH) {
Consume(Token::CATCH);
Expect(Token::LPAREN, CHECK_OK);
- ExpressionClassifier pattern_classifier;
+ ExpressionClassifier pattern_classifier(this);
ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
ValidateBindingPattern(&pattern_classifier, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
@@ -1099,7 +1100,6 @@
Identifier function_name, Scanner::Location function_name_location,
FunctionNameValidity function_name_validity, FunctionKind kind,
int function_token_pos, FunctionLiteral::FunctionType function_type,
- FunctionLiteral::ArityRestriction arity_restriction,
LanguageMode language_mode, bool* ok) {
// Function ::
// '(' FormalParameterList? ')' '{' FunctionBody '}'
@@ -1112,7 +1112,7 @@
FunctionState function_state(&function_state_, &scope_, function_scope, kind,
&factory);
DuplicateFinder duplicate_finder(scanner()->unicode_cache());
- ExpressionClassifier formals_classifier(&duplicate_finder);
+ ExpressionClassifier formals_classifier(this, &duplicate_finder);
Expect(Token::LPAREN, CHECK_OK);
int start_position = scanner()->location().beg_pos;
@@ -1122,8 +1122,7 @@
Expect(Token::RPAREN, CHECK_OK);
int formals_end_position = scanner()->location().end_pos;
- CheckArityRestrictions(formals.arity, arity_restriction,
- formals.has_rest, start_position,
+ CheckArityRestrictions(formals.arity, kind, formals.has_rest, start_position,
formals_end_position, CHECK_OK);
// See Parser::ParseFunctionLiteral for more information about lazy parsing
@@ -1219,7 +1218,7 @@
bool has_extends = Check(Token::EXTENDS);
if (has_extends) {
- ExpressionClassifier classifier;
+ ExpressionClassifier classifier(this);
ParseLeftHandSideExpression(&classifier, CHECK_OK);
ValidateExpression(&classifier, CHECK_OK);
}
@@ -1235,7 +1234,7 @@
bool is_computed_name = false; // Classes do not care about computed
// property names here.
Identifier name;
- ExpressionClassifier classifier;
+ ExpressionClassifier classifier(this);
ParsePropertyDefinition(&checker, in_class, has_extends, is_static,
&is_computed_name, &has_seen_constructor,
&classifier, &name, CHECK_OK);
@@ -1259,7 +1258,7 @@
// Allow "eval" or "arguments" for backward compatibility.
ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
Scanner::Location spread_pos;
- ExpressionClassifier classifier;
+ ExpressionClassifier classifier(this);
ParseArguments(&spread_pos, &classifier, ok);
ValidateExpression(&classifier, CHECK_OK);
diff --git a/src/parsing/preparser.h b/src/parsing/preparser.h
index 59100f1..253251c 100644
--- a/src/parsing/preparser.h
+++ b/src/parsing/preparser.h
@@ -279,12 +279,6 @@
int position() const { return RelocInfo::kNoPosition; }
void set_function_token_position(int position) {}
- // Parenthesized expressions in the form `( Expression )`.
- void set_is_parenthesized() {
- code_ = ParenthesizedField::update(code_, true);
- }
- bool is_parenthesized() const { return ParenthesizedField::decode(code_); }
-
private:
enum Type {
kExpression,
@@ -491,8 +485,7 @@
PreParserExpression right, int pos) {
return PreParserExpression::Default();
}
- PreParserExpression NewRewritableAssignmentExpression(
- PreParserExpression expression) {
+ PreParserExpression NewRewritableExpression(PreParserExpression expression) {
return expression;
}
PreParserExpression NewAssignment(Token::Value op,
@@ -550,7 +543,8 @@
return PreParserExpression::Default();
}
- PreParserExpression NewSpread(PreParserExpression expression, int pos) {
+ PreParserExpression NewSpread(PreParserExpression expression, int pos,
+ int expr_pos) {
return PreParserExpression::Spread(expression);
}
@@ -592,6 +586,9 @@
typedef int AstProperties;
+ typedef v8::internal::ExpressionClassifier<PreParserTraits>
+ ExpressionClassifier;
+
// Return types for traversing functions.
typedef PreParserIdentifier Identifier;
typedef PreParserExpression Expression;
@@ -797,8 +794,9 @@
return PreParserExpression::Default();
}
- static PreParserExpression DefaultConstructor(bool call_super, Scope* scope,
- int pos, int end_pos) {
+ static PreParserExpression FunctionSentExpression(Scope* scope,
+ PreParserFactory* factory,
+ int pos) {
return PreParserExpression::Default();
}
@@ -887,7 +885,7 @@
++parameters->arity;
}
void DeclareFormalParameter(Scope* scope, PreParserIdentifier parameter,
- ExpressionClassifier* classifier) {
+ Type::ExpressionClassifier* classifier) {
if (!classifier->is_simple_parameter_list()) {
scope->SetHasNonSimpleParameters();
}
@@ -902,7 +900,6 @@
PreParserIdentifier name, Scanner::Location function_name_location,
FunctionNameValidity function_name_validity, FunctionKind kind,
int function_token_position, FunctionLiteral::FunctionType type,
- FunctionLiteral::ArityRestriction arity_restriction,
LanguageMode language_mode, bool* ok);
PreParserExpression ParseClassLiteral(PreParserIdentifier name,
@@ -926,21 +923,24 @@
inline void RewriteDestructuringAssignments() {}
inline void QueueDestructuringAssignmentForRewriting(PreParserExpression) {}
+ inline void QueueNonPatternForRewriting(PreParserExpression) {}
void SetFunctionNameFromPropertyName(PreParserExpression,
PreParserIdentifier) {}
void SetFunctionNameFromIdentifierRef(PreParserExpression,
PreParserExpression) {}
- inline PreParserExpression RewriteNonPattern(
- PreParserExpression expr, const ExpressionClassifier* classifier,
- bool* ok);
- inline PreParserExpression RewriteNonPatternArguments(
- PreParserExpression args, const ExpressionClassifier* classifier,
- bool* ok);
- inline PreParserExpression RewriteNonPatternObjectLiteralProperty(
- PreParserExpression property, const ExpressionClassifier* classifier,
- bool* ok);
+ inline void RewriteNonPattern(Type::ExpressionClassifier* classifier,
+ bool* ok);
+
+ V8_INLINE Zone* zone() const;
+ V8_INLINE ZoneList<PreParserExpression>* GetNonPatternList() const;
+
+ inline PreParserExpression RewriteYieldStar(
+ PreParserExpression generator, PreParserExpression expr, int pos);
+ inline PreParserExpression RewriteInstanceof(PreParserExpression lhs,
+ PreParserExpression rhs,
+ int pos);
private:
PreParser* pre_parser_;
@@ -1071,7 +1071,6 @@
Identifier name, Scanner::Location function_name_location,
FunctionNameValidity function_name_validity, FunctionKind kind,
int function_token_pos, FunctionLiteral::FunctionType function_type,
- FunctionLiteral::ArityRestriction arity_restriction,
LanguageMode language_mode, bool* ok);
void ParseLazyFunctionLiteralBody(bool* ok,
Scanner::BookmarkScope* bookmark = nullptr);
@@ -1123,30 +1122,34 @@
}
-PreParserExpression PreParserTraits::RewriteNonPattern(
- PreParserExpression expr, const ExpressionClassifier* classifier,
- bool* ok) {
+void PreParserTraits::RewriteNonPattern(Type::ExpressionClassifier* classifier,
+ bool* ok) {
pre_parser_->ValidateExpression(classifier, ok);
- return expr;
}
-PreParserExpression PreParserTraits::RewriteNonPatternArguments(
- PreParserExpression args, const ExpressionClassifier* classifier,
- bool* ok) {
- pre_parser_->ValidateExpression(classifier, ok);
- return args;
+Zone* PreParserTraits::zone() const {
+ return pre_parser_->function_state_->scope()->zone();
}
-PreParserExpression PreParserTraits::RewriteNonPatternObjectLiteralProperty(
- PreParserExpression property, const ExpressionClassifier* classifier,
- bool* ok) {
- pre_parser_->ValidateExpression(classifier, ok);
- return property;
+ZoneList<PreParserExpression>* PreParserTraits::GetNonPatternList() const {
+ return pre_parser_->function_state_->non_patterns_to_rewrite();
}
+PreParserExpression PreParserTraits::RewriteYieldStar(
+ PreParserExpression generator, PreParserExpression expression, int pos) {
+ return pre_parser_->factory()->NewYield(
+ generator, expression, Yield::kDelegating, pos);
+}
+
+PreParserExpression PreParserTraits::RewriteInstanceof(PreParserExpression lhs,
+ PreParserExpression rhs,
+ int pos) {
+ return PreParserExpression::Default();
+}
+
PreParserStatementList PreParser::ParseEagerFunctionBody(
PreParserIdentifier function_name, int pos,
const PreParserFormalParameters& parameters, FunctionKind kind,
diff --git a/src/parsing/rewriter.cc b/src/parsing/rewriter.cc
index 4da60ac..c8e8fed 100644
--- a/src/parsing/rewriter.cc
+++ b/src/parsing/rewriter.cc
@@ -31,6 +31,7 @@
result_assigned_(false),
replacement_(nullptr),
is_set_(false),
+ zone_(ast_value_factory->zone()),
scope_(scope),
factory_(ast_value_factory) {
InitializeAstVisitor(parser->stack_limit());
@@ -148,7 +149,7 @@
is_set_ = is_set_ && set_in_then;
replacement_ = node;
- if (FLAG_harmony_completion && !is_set_) {
+ if (!is_set_) {
is_set_ = true;
replacement_ = AssignUndefinedBefore(node);
}
@@ -164,7 +165,7 @@
is_set_ = is_set_ && set_after;
replacement_ = node;
- if (FLAG_harmony_completion && !is_set_) {
+ if (!is_set_) {
is_set_ = true;
replacement_ = AssignUndefinedBefore(node);
}
@@ -208,7 +209,7 @@
is_set_ = is_set_ && set_in_try;
replacement_ = node;
- if (FLAG_harmony_completion && !is_set_) {
+ if (!is_set_) {
is_set_ = true;
replacement_ = AssignUndefinedBefore(node);
}
@@ -225,6 +226,7 @@
// at the end again: ".backup = .result; ...; .result = .backup"
// This is necessary because the finally block does not normally contribute
// to the completion value.
+ CHECK(scope() != nullptr);
Variable* backup = scope()->NewTemporary(
factory()->ast_value_factory()->dot_result_string());
Expression* backup_proxy = factory()->NewVariableProxy(backup);
@@ -245,7 +247,7 @@
node->set_try_block(replacement_->AsBlock());
replacement_ = node;
- if (FLAG_harmony_completion && !is_set_) {
+ if (!is_set_) {
is_set_ = true;
replacement_ = AssignUndefinedBefore(node);
}
@@ -263,7 +265,7 @@
is_set_ = is_set_ && set_after;
replacement_ = node;
- if (FLAG_harmony_completion && !is_set_) {
+ if (!is_set_) {
is_set_ = true;
replacement_ = AssignUndefinedBefore(node);
}
@@ -287,7 +289,7 @@
node->set_statement(replacement_);
replacement_ = node;
- if (FLAG_harmony_completion && !is_set_) {
+ if (!is_set_) {
is_set_ = true;
replacement_ = AssignUndefinedBefore(node);
}
diff --git a/src/parsing/scanner.cc b/src/parsing/scanner.cc
index 7317593..2d5a579 100644
--- a/src/parsing/scanner.cc
+++ b/src/parsing/scanner.cc
@@ -39,7 +39,8 @@
Scanner::Scanner(UnicodeCache* unicode_cache)
: unicode_cache_(unicode_cache),
bookmark_c0_(kNoBookmark),
- octal_pos_(Location::invalid()) {
+ octal_pos_(Location::invalid()),
+ found_html_comment_(false) {
bookmark_current_.literal_chars = &bookmark_current_literal_;
bookmark_current_.raw_literal_chars = &bookmark_current_raw_literal_;
bookmark_next_.literal_chars = &bookmark_next_literal_;
@@ -438,7 +439,10 @@
Advance();
if (c0_ == '-') {
Advance();
- if (c0_ == '-') return SkipSingleLineComment();
+ if (c0_ == '-') {
+ found_html_comment_ = true;
+ return SkipSingleLineComment();
+ }
PushBack('-'); // undo Advance()
}
PushBack('!'); // undo Advance()
@@ -1206,7 +1210,9 @@
(keyword_length <= 8 || input[8] == keyword[8]) && \
(keyword_length <= 9 || input[9] == keyword[9])) { \
if (escaped) { \
- return token == Token::FUTURE_STRICT_RESERVED_WORD \
+ /* TODO(adamk): YIELD should be handled specially. */ \
+ return (token == Token::FUTURE_STRICT_RESERVED_WORD || \
+ token == Token::LET || token == Token::STATIC) \
? Token::ESCAPED_STRICT_RESERVED_WORD \
: Token::ESCAPED_KEYWORD; \
} \
diff --git a/src/parsing/scanner.h b/src/parsing/scanner.h
index 1d0aba0..3f9bbb5 100644
--- a/src/parsing/scanner.h
+++ b/src/parsing/scanner.h
@@ -448,6 +448,8 @@
bool IdentifierIsFutureStrictReserved(const AstRawString* string) const;
+ bool FoundHtmlComment() const { return found_html_comment_; }
+
private:
// The current and look-ahead token.
struct TokenDesc {
@@ -473,6 +475,7 @@
current_.literal_chars = NULL;
current_.raw_literal_chars = NULL;
next_next_.token = Token::UNINITIALIZED;
+ found_html_comment_ = false;
}
// Support BookmarkScope functionality.
@@ -752,6 +755,9 @@
// Whether there is a multi-line comment that contains a
// line-terminator after the current token, and before the next.
bool has_multiline_comment_before_next_;
+
+ // Whether this scanner encountered an HTML comment.
+ bool found_html_comment_;
};
} // namespace internal
diff --git a/src/parsing/token.h b/src/parsing/token.h
index fee1f7e..7a62b4d 100644
--- a/src/parsing/token.h
+++ b/src/parsing/token.h
@@ -280,6 +280,22 @@
}
}
+ static bool EvalComparison(Value op, double op1, double op2) {
+ DCHECK(IsArithmeticCompareOp(op));
+ switch (op) {
+ case Token::EQ:
+ case Token::EQ_STRICT: return (op1 == op2);
+ case Token::NE: return (op1 != op2);
+ case Token::LT: return (op1 < op2);
+ case Token::GT: return (op1 > op2);
+ case Token::LTE: return (op1 <= op2);
+ case Token::GTE: return (op1 >= op2);
+ default:
+ UNREACHABLE();
+ return false;
+ }
+ }
+
static bool IsBitOp(Value op) {
return (BIT_OR <= op && op <= SHR) || op == BIT_NOT;
}