| Index: src/preparser.h
|
| diff --git a/src/preparser.h b/src/preparser.h
|
| index 9358d6bd18957e21fbf6334b70ce09186dd9e0a6..44bd85c85e2d01070068afa4bb39fe4b972477dd 100644
|
| --- a/src/preparser.h
|
| +++ b/src/preparser.h
|
| @@ -35,9 +35,98 @@
|
| namespace v8 {
|
|
|
| namespace internal {
|
| -class UnicodeCache;
|
| +
|
| +// Used to detect duplicates in object literals. Each of the values
|
| +// kGetterProperty, kSetterProperty and kValueProperty represents
|
| +// a type of object literal property. When parsing a property, its
|
| +// type value is stored in the DuplicateFinder for the property name.
|
| +// Values are chosen so that having intersection bits means the there is
|
| +// an incompatibility.
|
| +// I.e., you can add a getter to a property that already has a setter, since
|
| +// kGetterProperty and kSetterProperty doesn't intersect, but not if it
|
| +// already has a getter or a value. Adding the getter to an existing
|
| +// setter will store the value (kGetterProperty | kSetterProperty), which
|
| +// is incompatible with adding any further properties.
|
| +enum PropertyKind {
|
| + kNone = 0,
|
| + // Bit patterns representing different object literal property types.
|
| + kGetterProperty = 1,
|
| + kSetterProperty = 2,
|
| + kValueProperty = 7,
|
| + // Helper constants.
|
| + kValueFlag = 4
|
| +};
|
| +
|
| +
|
| +// Validation per 11.1.5 Object Initialiser
|
| +template<typename P>
|
| +class ObjectLiteralChecker {
|
| + public:
|
| + ObjectLiteralChecker(P* parser, Scanner* scanner, LanguageMode mode)
|
| + : parser_(parser),
|
| + scanner_(scanner),
|
| + finder_(scanner->unicode_cache()),
|
| + language_mode_(mode) { }
|
| +
|
| + void CheckProperty(Token::Value property, PropertyKind type, bool* ok);
|
| +
|
| + private:
|
| + // Checks the type of conflict based on values coming from PropertyType.
|
| + bool HasConflict(PropertyKind type1, PropertyKind type2) {
|
| + return (type1 & type2) != 0;
|
| + }
|
| + bool IsDataDataConflict(PropertyKind type1, PropertyKind type2) {
|
| + return ((type1 & type2) & kValueFlag) != 0;
|
| + }
|
| + bool IsDataAccessorConflict(PropertyKind type1, PropertyKind type2) {
|
| + return ((type1 ^ type2) & kValueFlag) != 0;
|
| + }
|
| + bool IsAccessorAccessorConflict(PropertyKind type1, PropertyKind type2) {
|
| + return ((type1 | type2) & kValueFlag) == 0;
|
| + }
|
| +
|
| + P* parser_;
|
| + Scanner* scanner_;
|
| + DuplicateFinder finder_;
|
| + LanguageMode language_mode_;
|
| +};
|
| +
|
| +
|
| +template<typename P>
|
| +void ObjectLiteralChecker<P>::CheckProperty(Token::Value property,
|
| + PropertyKind type,
|
| + bool* ok) {
|
| + int old;
|
| + if (property == Token::NUMBER) {
|
| + old = finder_.AddNumber(scanner_->literal_ascii_string(), type);
|
| + } else if (scanner_->is_literal_ascii()) {
|
| + old = finder_.AddAsciiSymbol(scanner_->literal_ascii_string(), type);
|
| + } else {
|
| + old = finder_.AddUtf16Symbol(scanner_->literal_utf16_string(), type);
|
| + }
|
| + PropertyKind old_type = static_cast<PropertyKind>(old);
|
| + if (HasConflict(old_type, type)) {
|
| + if (IsDataDataConflict(old_type, type)) {
|
| + // Both are data properties.
|
| + if (language_mode_ == CLASSIC_MODE) return;
|
| + parser_->ReportMessageAt(scanner_->location(),
|
| + "strict_duplicate_property");
|
| + } else if (IsDataAccessorConflict(old_type, type)) {
|
| + // Both a data and an accessor property with the same name.
|
| + parser_->ReportMessageAt(scanner_->location(),
|
| + "accessor_data_property");
|
| + } else {
|
| + ASSERT(IsAccessorAccessorConflict(old_type, type));
|
| + // Both accessors of the same type.
|
| + parser_->ReportMessageAt(scanner_->location(),
|
| + "accessor_get_set");
|
| + }
|
| + *ok = false;
|
| + }
|
| }
|
|
|
| +} // v8::internal
|
| +
|
| namespace preparser {
|
|
|
| typedef uint8_t byte;
|
| @@ -57,53 +146,6 @@ typedef uint8_t byte;
|
|
|
| namespace i = v8::internal;
|
|
|
| -class DuplicateFinder {
|
| - public:
|
| - explicit DuplicateFinder(i::UnicodeCache* constants)
|
| - : unicode_constants_(constants),
|
| - backing_store_(16),
|
| - map_(&Match) { }
|
| -
|
| - int AddAsciiSymbol(i::Vector<const char> key, int value);
|
| - int AddUtf16Symbol(i::Vector<const uint16_t> key, int value);
|
| - // Add a a number literal by converting it (if necessary)
|
| - // to the string that ToString(ToNumber(literal)) would generate.
|
| - // and then adding that string with AddAsciiSymbol.
|
| - // This string is the actual value used as key in an object literal,
|
| - // and the one that must be different from the other keys.
|
| - int AddNumber(i::Vector<const char> key, int value);
|
| -
|
| - private:
|
| - int AddSymbol(i::Vector<const byte> key, bool is_ascii, int value);
|
| - // Backs up the key and its length in the backing store.
|
| - // The backup is stored with a base 127 encoding of the
|
| - // length (plus a bit saying whether the string is ASCII),
|
| - // followed by the bytes of the key.
|
| - byte* BackupKey(i::Vector<const byte> key, bool is_ascii);
|
| -
|
| - // Compare two encoded keys (both pointing into the backing store)
|
| - // for having the same base-127 encoded lengths and ASCII-ness,
|
| - // and then having the same 'length' bytes following.
|
| - static bool Match(void* first, void* second);
|
| - // Creates a hash from a sequence of bytes.
|
| - static uint32_t Hash(i::Vector<const byte> key, bool is_ascii);
|
| - // Checks whether a string containing a JS number is its canonical
|
| - // form.
|
| - static bool IsNumberCanonical(i::Vector<const char> key);
|
| -
|
| - // Size of buffer. Sufficient for using it to call DoubleToCString in
|
| - // from conversions.h.
|
| - static const int kBufferSize = 100;
|
| -
|
| - i::UnicodeCache* unicode_constants_;
|
| - // Backing store used to store strings used as hashmap keys.
|
| - i::SequenceCollector<unsigned char> backing_store_;
|
| - i::HashMap map_;
|
| - // Buffer used for string->number->canonical string conversions.
|
| - char number_buffer_[kBufferSize];
|
| -};
|
| -
|
| -
|
| class PreParser {
|
| public:
|
| enum PreParseResult {
|
| @@ -183,45 +225,6 @@ class PreParser {
|
| i::ParserRecorder* log);
|
|
|
| private:
|
| - // Used to detect duplicates in object literals. Each of the values
|
| - // kGetterProperty, kSetterProperty and kValueProperty represents
|
| - // a type of object literal property. When parsing a property, its
|
| - // type value is stored in the DuplicateFinder for the property name.
|
| - // Values are chosen so that having intersection bits means the there is
|
| - // an incompatibility.
|
| - // I.e., you can add a getter to a property that already has a setter, since
|
| - // kGetterProperty and kSetterProperty doesn't intersect, but not if it
|
| - // already has a getter or a value. Adding the getter to an existing
|
| - // setter will store the value (kGetterProperty | kSetterProperty), which
|
| - // is incompatible with adding any further properties.
|
| - enum PropertyType {
|
| - kNone = 0,
|
| - // Bit patterns representing different object literal property types.
|
| - kGetterProperty = 1,
|
| - kSetterProperty = 2,
|
| - kValueProperty = 7,
|
| - // Helper constants.
|
| - kValueFlag = 4
|
| - };
|
| -
|
| - // Checks the type of conflict based on values coming from PropertyType.
|
| - bool HasConflict(int type1, int type2) { return (type1 & type2) != 0; }
|
| - bool IsDataDataConflict(int type1, int type2) {
|
| - return ((type1 & type2) & kValueFlag) != 0;
|
| - }
|
| - bool IsDataAccessorConflict(int type1, int type2) {
|
| - return ((type1 ^ type2) & kValueFlag) != 0;
|
| - }
|
| - bool IsAccessorAccessorConflict(int type1, int type2) {
|
| - return ((type1 | type2) & kValueFlag) == 0;
|
| - }
|
| -
|
| -
|
| - void CheckDuplicate(DuplicateFinder* finder,
|
| - i::Token::Value property,
|
| - int type,
|
| - bool* ok);
|
| -
|
| // These types form an algebra over syntactic categories that is just
|
| // rich enough to let us recognize and propagate the constructs that
|
| // are either being counted in the preparser data, or is important
|
| @@ -531,7 +534,7 @@ class PreParser {
|
| void ReportUnexpectedToken(i::Token::Value token);
|
| void ReportMessageAt(i::Scanner::Location location,
|
| const char* type,
|
| - const char* name_opt) {
|
| + const char* name_opt = NULL) {
|
| log_->LogMessage(location.beg_pos, location.end_pos, type, name_opt);
|
| }
|
| void ReportMessageAt(int start_pos,
|
| @@ -686,7 +689,10 @@ class PreParser {
|
| bool allow_generators_;
|
| bool allow_for_of_;
|
| bool parenthesized_function_;
|
| +
|
| + friend class i::ObjectLiteralChecker<PreParser>;
|
| };
|
| +
|
| } } // v8::preparser
|
|
|
| #endif // V8_PREPARSER_H
|
|
|