2010-07-08 Oliver Hunt <oliver@apple.com>
authoroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 8 Jul 2010 21:54:08 +0000 (21:54 +0000)
committeroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 8 Jul 2010 21:54:08 +0000 (21:54 +0000)
        Reviewed by Gavin Barraclough.

        Make object-literal parsing conformant with the spec.
        https://bugs.webkit.org/show_bug.cgi?id=41892

        Bring our parsing of object literals into conformance with the ES5 spec.
        Basically disallow conflicting accessor vs. normal property definitions
        The bulk of this patch is just fiddling to maintain performance.

        * parser/ASTBuilder.h:
        (JSC::ASTBuilder::createGetterOrSetterProperty):
        (JSC::ASTBuilder::createProperty):
        (JSC::ASTBuilder::getName):
        (JSC::ASTBuilder::getType):
        * parser/JSParser.cpp:
        (JSC::jsParse):
        (JSC::JSParser::JSParser):
        (JSC::JSParser::parseProperty):
        (JSC::JSParser::parseObjectLiteral):
        (JSC::JSParser::parseStrictObjectLiteral):
        * parser/JSParser.h:
        * parser/Lexer.cpp:
        (JSC::Lexer::clear):
        * parser/Lexer.h:
        (JSC::Lexer::currentOffset):
        (JSC::Lexer::setOffset):
          Add logic to allow us to roll the lexer back in the input stream.
        * parser/Nodes.h:
        (JSC::PropertyNode::):
        (JSC::PropertyNode::type):
        * parser/Parser.cpp:
        (JSC::Parser::parse):
        * parser/SourceProvider.h:
        (JSC::SourceProvider::SourceProvider):
        (JSC::SourceProvider::isValid):
        (JSC::SourceProvider::setValid):
          SourceProvider now records whether the input text
          has already been validated.
        * parser/SyntaxChecker.h:
        (JSC::SyntaxChecker::SyntaxChecker):
        (JSC::SyntaxChecker::Property::Property):
        (JSC::SyntaxChecker::Property::operator!):
        (JSC::SyntaxChecker::createProperty):
        (JSC::SyntaxChecker::createPropertyList):
        (JSC::SyntaxChecker::createGetterOrSetterProperty):
          The SyntaxChecker mode now needs to maintain a bit more information
          to ensure that we can validate object literals correctly.
2010-07-08  Oliver Hunt  <oliver@apple.com>

        Reviewed by Gavin Barraclough.

        Need a short description and bug URL (OOPS!)

        * fast/js/object-literal-syntax-expected.txt: Added.
        * fast/js/object-literal-syntax.html: Added.
        * fast/js/parser-syntax-check-expected.txt:
        * fast/js/script-tests/object-literal-syntax.js: Added.
        * fast/js/script-tests/parser-syntax-check.js:
        * ietestcenter/Javascript/11.1.5_4-4-b-1-expected.txt:
        * ietestcenter/Javascript/11.1.5_4-4-b-2-expected.txt:
        * ietestcenter/Javascript/11.1.5_4-4-c-1-expected.txt:
        * ietestcenter/Javascript/11.1.5_4-4-c-2-expected.txt:
        * ietestcenter/Javascript/11.1.5_4-4-d-1-expected.txt:
        * ietestcenter/Javascript/11.1.5_4-4-d-2-expected.txt:
        * ietestcenter/Javascript/11.1.5_4-4-d-3-expected.txt:
        * ietestcenter/Javascript/11.1.5_4-4-d-4-expected.txt:
        * platform/chromium/test_expectations.txt:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@62848 268f45cc-cd09-0410-ab3c-d52691b4dbfc

25 files changed:
JavaScriptCore/ChangeLog
JavaScriptCore/parser/ASTBuilder.h
JavaScriptCore/parser/JSParser.cpp
JavaScriptCore/parser/JSParser.h
JavaScriptCore/parser/Lexer.cpp
JavaScriptCore/parser/Lexer.h
JavaScriptCore/parser/Nodes.h
JavaScriptCore/parser/Parser.cpp
JavaScriptCore/parser/SourceProvider.h
JavaScriptCore/parser/SyntaxChecker.h
LayoutTests/ChangeLog
LayoutTests/fast/js/object-literal-syntax-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/object-literal-syntax.html [new file with mode: 0644]
LayoutTests/fast/js/parser-syntax-check-expected.txt
LayoutTests/fast/js/script-tests/object-literal-syntax.js [new file with mode: 0644]
LayoutTests/fast/js/script-tests/parser-syntax-check.js
LayoutTests/ietestcenter/Javascript/11.1.5_4-4-b-1-expected.txt
LayoutTests/ietestcenter/Javascript/11.1.5_4-4-b-2-expected.txt
LayoutTests/ietestcenter/Javascript/11.1.5_4-4-c-1-expected.txt
LayoutTests/ietestcenter/Javascript/11.1.5_4-4-c-2-expected.txt
LayoutTests/ietestcenter/Javascript/11.1.5_4-4-d-1-expected.txt
LayoutTests/ietestcenter/Javascript/11.1.5_4-4-d-2-expected.txt
LayoutTests/ietestcenter/Javascript/11.1.5_4-4-d-3-expected.txt
LayoutTests/ietestcenter/Javascript/11.1.5_4-4-d-4-expected.txt
LayoutTests/platform/chromium/test_expectations.txt

index 8b7709f..82a218e 100644 (file)
@@ -1,3 +1,53 @@
+2010-07-08  Oliver Hunt  <oliver@apple.com>
+
+        Reviewed by Gavin Barraclough.
+
+        Make object-literal parsing conformant with the spec.
+        https://bugs.webkit.org/show_bug.cgi?id=41892
+
+        Bring our parsing of object literals into conformance with the ES5 spec.
+        Basically disallow conflicting accessor vs. normal property definitions
+        The bulk of this patch is just fiddling to maintain performance.
+
+        * parser/ASTBuilder.h:
+        (JSC::ASTBuilder::createGetterOrSetterProperty):
+        (JSC::ASTBuilder::createProperty):
+        (JSC::ASTBuilder::getName):
+        (JSC::ASTBuilder::getType):
+        * parser/JSParser.cpp:
+        (JSC::jsParse):
+        (JSC::JSParser::JSParser):
+        (JSC::JSParser::parseProperty):
+        (JSC::JSParser::parseObjectLiteral):
+        (JSC::JSParser::parseStrictObjectLiteral):
+        * parser/JSParser.h:
+        * parser/Lexer.cpp:
+        (JSC::Lexer::clear):
+        * parser/Lexer.h:
+        (JSC::Lexer::currentOffset):
+        (JSC::Lexer::setOffset):
+          Add logic to allow us to roll the lexer back in the input stream.
+        * parser/Nodes.h:
+        (JSC::PropertyNode::):
+        (JSC::PropertyNode::type):
+        * parser/Parser.cpp:
+        (JSC::Parser::parse):
+        * parser/SourceProvider.h:
+        (JSC::SourceProvider::SourceProvider):
+        (JSC::SourceProvider::isValid):
+        (JSC::SourceProvider::setValid):
+          SourceProvider now records whether the input text
+          has already been validated.
+        * parser/SyntaxChecker.h:
+        (JSC::SyntaxChecker::SyntaxChecker):
+        (JSC::SyntaxChecker::Property::Property):
+        (JSC::SyntaxChecker::Property::operator!):
+        (JSC::SyntaxChecker::createProperty):
+        (JSC::SyntaxChecker::createPropertyList):
+        (JSC::SyntaxChecker::createGetterOrSetterProperty):
+          The SyntaxChecker mode now needs to maintain a bit more information
+          to ensure that we can validate object literals correctly.
+
 2010-07-08  Darin Adler  <darin@apple.com>
 
         * runtime/JSGlobalData.cpp:
index 7ee1405..9d5de2d 100644 (file)
@@ -249,16 +249,9 @@ public:
         return FunctionBodyNode::create(m_globalData);
     }
     
-    PropertyNode* createGetterOrSetterProperty(const Identifier* getOrSet, const Identifier* name, ParameterNode* params, FunctionBodyNode* body, int openBracePos, int closeBracePos, int bodyStartLine, int bodyEndLine)
+    template <bool> PropertyNode* createGetterOrSetterProperty(PropertyNode::Type type, const Identifier* name, ParameterNode* params, FunctionBodyNode* body, int openBracePos, int closeBracePos, int bodyStartLine, int bodyEndLine)
     {
         ASSERT(name);
-        PropertyNode::Type type;
-        if (*getOrSet == m_globalData->propertyNames->get)
-            type = PropertyNode::Getter;
-        else if (*getOrSet == m_globalData->propertyNames->set)
-            type = PropertyNode::Setter;
-        else
-            return 0;
         body->setLoc(bodyStartLine, bodyEndLine);
         return new (m_globalData) PropertyNode(m_globalData, *name, new (m_globalData) FuncExprNode(m_globalData, m_globalData->propertyNames->nullIdentifier, body, m_lexer->sourceCode(openBracePos, closeBracePos, bodyStartLine), params), type);
     }
@@ -269,8 +262,8 @@ public:
     ArgumentListNode* createArgumentsList(ExpressionNode* arg) { return new (m_globalData) ArgumentListNode(m_globalData, arg); }
     ArgumentListNode* createArgumentsList(ArgumentListNode* args, ExpressionNode* arg) { return new (m_globalData) ArgumentListNode(m_globalData, args, arg); }
 
-    PropertyNode* createProperty(const Identifier* propertyName, ExpressionNode* node, PropertyNode::Type type) { return new (m_globalData) PropertyNode(m_globalData, *propertyName, node, type); }
-    PropertyNode* createProperty(double propertyName, ExpressionNode* node, PropertyNode::Type type) { return new (m_globalData) PropertyNode(m_globalData, propertyName, node, type); }
+    template <bool> PropertyNode* createProperty(const Identifier* propertyName, ExpressionNode* node, PropertyNode::Type type) { return new (m_globalData) PropertyNode(m_globalData, *propertyName, node, type); }
+    template <bool> PropertyNode* createProperty(JSGlobalData*, double propertyName, ExpressionNode* node, PropertyNode::Type type) { return new (m_globalData) PropertyNode(m_globalData, propertyName, node, type); }
     PropertyListNode* createPropertyList(PropertyNode* property) { return new (m_globalData) PropertyListNode(m_globalData, property); }
     PropertyListNode* createPropertyList(PropertyNode* property, PropertyListNode* tail) { return new (m_globalData) PropertyListNode(m_globalData, property, tail); }
 
@@ -576,7 +569,9 @@ public:
         assignmentStackDepth--;
         return result;
     }
-
+    
+    const Identifier& getName(Property property) { return property->name(); }
+    PropertyNode::Type getType(Property property) { return property->type(); }
 private:
     struct Scope {
         Scope(JSGlobalData* globalData)
index d9cacc7..14e5b5c 100644 (file)
@@ -32,6 +32,7 @@ using namespace JSC;
 #include "JSGlobalData.h"
 #include "NodeInfo.h"
 #include "ASTBuilder.h"
+#include <wtf/HashFunctions.h>
 #include <utility>
 
 using namespace std;
@@ -63,7 +64,7 @@ static const ptrdiff_t kMaxParserStackUsage = 128 * sizeof(void*) * 1024;
 
 class JSParser {
 public:
-    JSParser(Lexer*, JSGlobalData*);
+    JSParser(Lexer*, JSGlobalData*, SourceProvider*);
     bool parseProgram();
 private:
     struct AllowInOverride {
@@ -150,8 +151,9 @@ private:
     template <class TreeBuilder> ALWAYS_INLINE TreeExpression parsePrimaryExpression(TreeBuilder&);
     template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseArrayLiteral(TreeBuilder&);
     template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseObjectLiteral(TreeBuilder&);
+    template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseStrictObjectLiteral(TreeBuilder&);
     template <class TreeBuilder> ALWAYS_INLINE TreeArguments parseArguments(TreeBuilder&);
-    template <class TreeBuilder> ALWAYS_INLINE TreeProperty parseProperty(TreeBuilder&);
+    template <bool strict, class TreeBuilder> ALWAYS_INLINE TreeProperty parseProperty(TreeBuilder&);
     template <class TreeBuilder> ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&);
     template <class TreeBuilder> ALWAYS_INLINE TreeFormalParameterList parseFormalParameters(TreeBuilder&, bool& usesArguments);
     template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseVarDeclarationList(TreeBuilder&, int& declarations, const Identifier*& lastIdent, TreeExpression& lastInitializer, int& identStart, int& initStart, int& initEnd);
@@ -194,15 +196,16 @@ private:
     int m_lastTokenEnd;
     int m_assignmentCount;
     int m_nonLHSCount;
+    bool m_syntaxAlreadyValidated;
 };
 
-int jsParse(JSGlobalData* globalData)
+int jsParse(JSGlobalData* globalData, const SourceCode* source)
 {
-    JSParser parser(globalData->lexer, globalData);
+    JSParser parser(globalData->lexer, globalData, source->provider());
     return parser.parseProgram();
 }
 
-JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData)
+JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData, SourceProvider* provider)
     : m_lexer(lexer)
     , m_endAddress(0)
     , m_error(false)
@@ -213,6 +216,7 @@ JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData)
     , m_lastTokenEnd(0)
     , m_assignmentCount(0)
     , m_nonLHSCount(0)
+    , m_syntaxAlreadyValidated(provider->isValid())
 {
     m_endAddress = *(globalData->stackGuards);
     if (!m_endAddress) {
@@ -1145,7 +1149,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseBinaryExpression(Tree
 }
 
 
-template <class TreeBuilder> TreeProperty JSParser::parseProperty(TreeBuilder& context)
+template <bool complete, class TreeBuilder> TreeProperty JSParser::parseProperty(TreeBuilder& context)
 {
     bool wasIdent = false;
     switch (token().m_type) {
@@ -1158,7 +1162,7 @@ template <class TreeBuilder> TreeProperty JSParser::parseProperty(TreeBuilder& c
             next();
             TreeExpression node = parseAssignmentExpression(context);
             failIfFalse(node);
-            return context.createProperty(ident, node, PropertyNode::Constant);
+            return context.template createProperty<complete>(ident, node, PropertyNode::Constant);
         }
         failIfFalse(wasIdent);
         matchOrFail(IDENT);
@@ -1168,9 +1172,15 @@ template <class TreeBuilder> TreeProperty JSParser::parseProperty(TreeBuilder& c
         int openBracePos = 0;
         int closeBracePos = 0;
         int bodyStartLine = 0;
-        failIfFalse(*ident == m_globalData->propertyNames->get || *ident == m_globalData->propertyNames->set);
+        PropertyNode::Type type;
+        if (*ident == m_globalData->propertyNames->get)
+            type = PropertyNode::Getter;
+        else if (*ident == m_globalData->propertyNames->set)
+            type = PropertyNode::Setter;
+        else
+            fail();
         failIfFalse(parseFunctionInfo<FunctionNeedsName>(context, accessorName, parameters, body, openBracePos, closeBracePos, bodyStartLine));
-        return context.createGetterOrSetterProperty(ident, accessorName, parameters, body, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
+        return context.template createGetterOrSetterProperty<complete>(type, accessorName, parameters, body, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
     }
     case NUMBER: {
         double propertyName = token().m_data.doubleValue;
@@ -1178,7 +1188,7 @@ template <class TreeBuilder> TreeProperty JSParser::parseProperty(TreeBuilder& c
         consumeOrFail(':');
         TreeExpression node = parseAssignmentExpression(context);
         failIfFalse(node);
-        return context.createProperty(propertyName, node, PropertyNode::Constant);
+        return context.template createProperty<complete>(m_globalData, propertyName, node, PropertyNode::Constant);
     }
     }
     fail();
@@ -1186,6 +1196,7 @@ template <class TreeBuilder> TreeProperty JSParser::parseProperty(TreeBuilder& c
 
 template <class TreeBuilder> TreeExpression JSParser::parseObjectLiteral(TreeBuilder& context)
 {
+    int startOffset = token().m_data.intValue;
     consumeOrFail(OPENBRACE);
 
     if (match(CLOSEBRACE)) {
@@ -1193,20 +1204,27 @@ template <class TreeBuilder> TreeExpression JSParser::parseObjectLiteral(TreeBui
         return context.createObjectLiteral();
     }
 
-    TreeProperty property = parseProperty(context);
+    TreeProperty property = parseProperty<false>(context);
     failIfFalse(property);
-
+    if (!m_syntaxAlreadyValidated && context.getType(property) != PropertyNode::Constant) {
+        m_lexer->setOffset(startOffset);
+        next();
+        return parseStrictObjectLiteral(context);
+    }
     TreePropertyList propertyList = context.createPropertyList(property);
     TreePropertyList tail = propertyList;
-
     while (match(',')) {
         next();
         // allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939
         if (match(CLOSEBRACE))
             break;
-        property = parseProperty(context);
+        property = parseProperty<false>(context);
         failIfFalse(property);
-
+        if (!m_syntaxAlreadyValidated && context.getType(property) != PropertyNode::Constant) {
+            m_lexer->setOffset(startOffset);
+            next();
+            return parseStrictObjectLiteral(context);
+        }
         tail = context.createPropertyList(property, tail);
     }
 
@@ -1215,6 +1233,52 @@ template <class TreeBuilder> TreeExpression JSParser::parseObjectLiteral(TreeBui
     return context.createObjectLiteral(propertyList);
 }
 
+template <class TreeBuilder> TreeExpression JSParser::parseStrictObjectLiteral(TreeBuilder& context)
+{
+    consumeOrFail(OPENBRACE);
+    
+    if (match(CLOSEBRACE)) {
+        next();
+        return context.createObjectLiteral();
+    }
+    
+    TreeProperty property = parseProperty<true>(context);
+    failIfFalse(property);
+    
+    typedef HashMap<RefPtr<UString::Rep>, unsigned, IdentifierRepHash> ObjectValidationMap;
+    ObjectValidationMap objectValidator;
+    // Add the first property
+    if (!m_syntaxAlreadyValidated)
+        objectValidator.add(context.getName(property).ustring().rep(), context.getType(property));
+    
+    TreePropertyList propertyList = context.createPropertyList(property);
+    TreePropertyList tail = propertyList;
+    while (match(',')) {
+        next();
+        // allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939
+        if (match(CLOSEBRACE))
+            break;
+        property = parseProperty<true>(context);
+        failIfFalse(property);
+        if (!m_syntaxAlreadyValidated) {
+            std::pair<ObjectValidationMap::iterator, bool> propertyEntryIter = objectValidator.add(context.getName(property).ustring().rep(), context.getType(property));
+            if (!propertyEntryIter.second) {
+                if ((context.getType(property) & propertyEntryIter.first->second) != PropertyNode::Constant) {
+                    // Can't have multiple getters or setters with the same name, nor can we define 
+                    // a property as both an accessor and a constant value
+                    failIfTrue(context.getType(property) & propertyEntryIter.first->second);
+                    failIfTrue((context.getType(property) | propertyEntryIter.first->second) & PropertyNode::Constant);
+                }
+            }
+        }
+        tail = context.createPropertyList(property, tail);
+    }
+    
+    consumeOrFail(CLOSEBRACE);
+    
+    return context.createObjectLiteral(propertyList);
+}
+
 template <class TreeBuilder> TreeExpression JSParser::parseArrayLiteral(TreeBuilder& context)
 {
     consumeOrFail('[');
index 554556f..ac5b18c 100644 (file)
@@ -30,6 +30,7 @@ namespace JSC {
 
 class Identifier;
 class JSGlobalData;
+class SourceCode;
 
 enum JSTokenType {
     NULLTOKEN = 258,
@@ -118,6 +119,6 @@ struct JSToken {
     JSTokenInfo m_info;
 };
 
-int jsParse(JSGlobalData*);
+int jsParse(JSGlobalData*, const SourceCode*);
 }
 #endif // JSParser_h
index 8cde5e1..eb27e8f 100644 (file)
@@ -1117,7 +1117,6 @@ bool Lexer::skipRegExp()
 void Lexer::clear()
 {
     m_arena = 0;
-    m_codeWithoutBOMs.clear();
 
     Vector<char> newBuffer8;
     m_buffer8.swap(newBuffer8);
index e7aabc0..9292c21 100644 (file)
@@ -61,6 +61,12 @@ namespace JSC {
         // Functions for use after parsing.
         bool sawError() const { return m_error; }
         void clear();
+        int currentOffset() { return m_code - m_codeStart; }
+        void setOffset(int offset)
+        {
+            m_code = m_codeStart + offset;
+            m_current = *m_code;
+        }
 
     private:
         friend class JSGlobalData;
@@ -115,8 +121,6 @@ namespace JSC {
         JSGlobalData* m_globalData;
 
         const HashTable m_keywordTable;
-
-        Vector<UChar> m_codeWithoutBOMs;
     };
 
     inline bool Lexer::isWhiteSpace(int ch)
index 57c8f4f..6206384 100644 (file)
@@ -404,12 +404,13 @@ namespace JSC {
 
     class PropertyNode : public ParserArenaFreeable {
     public:
-        enum Type { Constant, Getter, Setter };
+        enum Type { Constant = 1, Getter = 2, Setter = 4 };
 
         PropertyNode(JSGlobalData*, const Identifier& name, ExpressionNode* value, Type);
         PropertyNode(JSGlobalData*, double name, ExpressionNode* value, Type);
 
         const Identifier& name() const { return m_name; }
+        Type type() const { return m_type; }
 
     private:
         friend class PropertyListNode;
index e0a9b67..3bd352d 100644 (file)
@@ -53,7 +53,7 @@ void Parser::parse(JSGlobalData* globalData, int* errLine, UString* errMsg)
     Lexer& lexer = *globalData->lexer;
     lexer.setCode(*m_source, m_arena);
 
-    int parseError = jsParse(globalData);
+    int parseError = jsParse(globalData, m_source);
     int lineNumber = lexer.lineNumber();
     bool lexError = lexer.sawError();
     lexer.clear();
index 87ea960..6b9c028 100644 (file)
@@ -38,6 +38,7 @@ namespace JSC {
     public:
         SourceProvider(const UString& url)
             : m_url(url)
+            , m_validated(false)
         {
         }
         virtual ~SourceProvider() { }
@@ -49,8 +50,12 @@ namespace JSC {
         const UString& url() { return m_url; }
         intptr_t asID() { return reinterpret_cast<intptr_t>(this); }
 
+        bool isValid() const { return m_validated; }
+        void setValid() { m_validated = true; }
+
     private:
         UString m_url;
+        bool m_validated;
     };
 
     class UStringSourceProvider : public SourceProvider {
index cad89f6..e05facd 100644 (file)
@@ -29,7 +29,7 @@
 namespace JSC {
 class SyntaxChecker {
 public:
-    SyntaxChecker(JSGlobalData*, Lexer*)
+    SyntaxChecker(JSGlobalData* , Lexer*)
     {
     }
 
@@ -39,7 +39,25 @@ public:
     typedef int SourceElements;
     typedef int Arguments;
     typedef int Comma;
-    typedef int Property;
+    struct Property {
+        ALWAYS_INLINE Property(void* = 0)
+            : type((PropertyNode::Type)0)
+        {
+        }
+        ALWAYS_INLINE Property(const Identifier* ident, PropertyNode::Type ty)
+        : name(ident)
+        , type(ty)
+        {
+        }
+        ALWAYS_INLINE Property(PropertyNode::Type ty)
+            : name(0)
+            , type(ty)
+        {
+        }
+        ALWAYS_INLINE bool operator!() { return !type; }
+        const Identifier* name;
+        PropertyNode::Type type;
+    };
     typedef int PropertyList;
     typedef int ElementList;
     typedef int ArgumentsList;
@@ -90,10 +108,21 @@ public:
     int createArguments(int) { return 1; }
     int createArgumentsList(int) { return 1; }
     int createArgumentsList(int, int) { return 1; }
-    int createProperty(const Identifier*, int, PropertyNode::Type) { return 1; }
-    int createProperty(double, int, PropertyNode::Type) { return 1; }
-    int createPropertyList(int) { return 1; }
-    int createPropertyList(int, int) { return 1; }
+    template <bool complete> Property createProperty(const Identifier* name, int, PropertyNode::Type type)
+    {
+        ASSERT(name);
+        if (!complete)
+            return Property(type);
+        return Property(name, type);
+    }
+    template <bool complete> Property createProperty(JSGlobalData* globalData, double name, int, PropertyNode::Type type)
+    {
+        if (!complete)
+            return Property(type);
+        return Property(&globalData->parser->arena().identifierArena().makeNumericIdentifier(globalData, name), type);
+    }
+    int createPropertyList(Property) { return 1; }
+    int createPropertyList(Property, int) { return 1; }
     int createElementList(int, int) { return 1; }
     int createElementList(int, int, int) { return 1; }
     int createFormalParameterList(const Identifier&) { return 1; }
@@ -127,7 +156,13 @@ public:
     int createDebugger(int, int) { return 1; }
     int createConstStatement(int, int, int) { return 1; }
     int appendConstDecl(int, const Identifier*, int) { return 1; }
-    int createGetterOrSetterProperty(const Identifier*, const Identifier*, int, int, int, int, int, int) { return 1; }
+    template <bool strict> Property createGetterOrSetterProperty(PropertyNode::Type type, const Identifier* name, int, int, int, int, int, int)
+    {
+        ASSERT(name);
+        if (!strict)
+            return Property(type);
+        return Property(name, type);
+    }
 
     void appendStatement(int, int) { }
     void addVar(const Identifier*, bool) { }
@@ -151,6 +186,8 @@ public:
     
     void assignmentStackAppend(int, int, int, int, int, Operator) { }
     int createAssignment(int, int, int, int, int) { ASSERT_NOT_REACHED(); return 1; }
+    const Identifier& getName(const Property& property) { ASSERT(property.name); return *property.name; }
+    PropertyNode::Type getType(const Property& property) { return property.type; }
 };
 
 }
index d8d729c..74e1126 100644 (file)
@@ -1,3 +1,27 @@
+2010-07-08  Oliver Hunt  <oliver@apple.com>
+
+        Reviewed by Gavin Barraclough.
+
+        Make object-literal parsing conformant with the spec.
+        https://bugs.webkit.org/show_bug.cgi?id=41892
+
+        Add tests to ensure correct parsing of object literals.
+
+        * fast/js/object-literal-syntax-expected.txt: Added.
+        * fast/js/object-literal-syntax.html: Added.
+        * fast/js/parser-syntax-check-expected.txt:
+        * fast/js/script-tests/object-literal-syntax.js: Added.
+        * fast/js/script-tests/parser-syntax-check.js:
+        * ietestcenter/Javascript/11.1.5_4-4-b-1-expected.txt:
+        * ietestcenter/Javascript/11.1.5_4-4-b-2-expected.txt:
+        * ietestcenter/Javascript/11.1.5_4-4-c-1-expected.txt:
+        * ietestcenter/Javascript/11.1.5_4-4-c-2-expected.txt:
+        * ietestcenter/Javascript/11.1.5_4-4-d-1-expected.txt:
+        * ietestcenter/Javascript/11.1.5_4-4-d-2-expected.txt:
+        * ietestcenter/Javascript/11.1.5_4-4-d-3-expected.txt:
+        * ietestcenter/Javascript/11.1.5_4-4-d-4-expected.txt:
+        * platform/chromium/test_expectations.txt:
+
 2010-07-08  Jon Honeycutt  <jhoneycutt@apple.com>
 
         Missing plug-ins may cause an assertion failure
diff --git a/LayoutTests/fast/js/object-literal-syntax-expected.txt b/LayoutTests/fast/js/object-literal-syntax-expected.txt
new file mode 100644 (file)
index 0000000..ae5ddc9
--- /dev/null
@@ -0,0 +1,29 @@
+Make sure that we correctly identify parse errors in object literals
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS ({a:1, get a(){}}) threw exception SyntaxError: Parse error.
+PASS ({a:1, set a(){}}) threw exception SyntaxError: Parse error.
+PASS ({get a(){}, a:1}) threw exception SyntaxError: Parse error.
+PASS ({set a(){}, a:1}) threw exception SyntaxError: Parse error.
+PASS ({get a(){}, get a(){}}) threw exception SyntaxError: Parse error.
+PASS ({set a(){}, set a(){}}) threw exception SyntaxError: Parse error.
+PASS ({set a(){}, get a(){}, set a(){}}) threw exception SyntaxError: Parse error.
+PASS (function(){({a:1, get a(){}})}) threw exception SyntaxError: Parse error.
+PASS (function(){({a:1, set a(){}})}) threw exception SyntaxError: Parse error.
+PASS (function(){({get a(){}, a:1})}) threw exception SyntaxError: Parse error.
+PASS (function(){({set a(){}, a:1})}) threw exception SyntaxError: Parse error.
+PASS (function(){({get a(){}, get a(){}})}) threw exception SyntaxError: Parse error.
+PASS (function(){({set a(){}, set a(){}})}) threw exception SyntaxError: Parse error.
+PASS (function(){({set a(){}, get a(){}, set a(){}})}) threw exception SyntaxError: Parse error.
+PASS ({a:1, a:1, a:1}), true is true
+PASS ({get a(){}, set a(){}}), true is true
+PASS ({set a(){}, get a(){}}), true is true
+PASS (function(){({a:1, a:1, a:1})}), true is true
+PASS (function(){({get a(){}, set a(){}})}), true is true
+PASS (function(){({set a(){}, get a(){}})}), true is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/object-literal-syntax.html b/LayoutTests/fast/js/object-literal-syntax.html
new file mode 100644 (file)
index 0000000..b773910
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="resources/js-test-style.css">
+<script src="resources/js-test-pre.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script src="script-tests/object-literal-syntax.js"></script>
+<script src="resources/js-test-post.js"></script>
+</body>
+</html>
index 8066907..1879bc1 100644 (file)
@@ -186,8 +186,8 @@ PASS Invalid: "[,"
 PASS Invalid: "function f() { [, }"
 PASS Invalid: "(a,)"
 PASS Invalid: "function f() { (a,) }"
-PASS Valid:   "1 + {get get(){}, set set(a){}, get:4, set:get-set, }"
-PASS Valid:   "function f() { 1 + {get get(){}, set set(a){}, get:4, set:get-set, } }"
+PASS Valid:   "1 + {get get(){}, set set(a){}, get1:4, set1:get-set, }"
+PASS Valid:   "function f() { 1 + {get get(){}, set set(a){}, get1:4, set1:get-set, } }"
 PASS Invalid: "1 + {a"
 PASS Invalid: "function f() { 1 + {a }"
 PASS Invalid: "1 + {a:"
diff --git a/LayoutTests/fast/js/script-tests/object-literal-syntax.js b/LayoutTests/fast/js/script-tests/object-literal-syntax.js
new file mode 100644 (file)
index 0000000..3105144
--- /dev/null
@@ -0,0 +1,24 @@
+description("Make sure that we correctly identify parse errors in object literals");
+
+shouldThrow("({a:1, get a(){}})");
+shouldThrow("({a:1, set a(){}})");
+shouldThrow("({get a(){}, a:1})");
+shouldThrow("({set a(){}, a:1})");
+shouldThrow("({get a(){}, get a(){}})");
+shouldThrow("({set a(){}, set a(){}})");
+shouldThrow("({set a(){}, get a(){}, set a(){}})");
+shouldThrow("(function(){({a:1, get a(){}})})");
+shouldThrow("(function(){({a:1, set a(){}})})");
+shouldThrow("(function(){({get a(){}, a:1})})");
+shouldThrow("(function(){({set a(){}, a:1})})");
+shouldThrow("(function(){({get a(){}, get a(){}})})");
+shouldThrow("(function(){({set a(){}, set a(){}})})");
+shouldThrow("(function(){({set a(){}, get a(){}, set a(){}})})");
+shouldBeTrue("({a:1, a:1, a:1}), true");
+shouldBeTrue("({get a(){}, set a(){}}), true");
+shouldBeTrue("({set a(){}, get a(){}}), true");
+shouldBeTrue("(function(){({a:1, a:1, a:1})}), true");
+shouldBeTrue("(function(){({get a(){}, set a(){}})}), true");
+shouldBeTrue("(function(){({set a(){}, get a(){}})}), true");
+
+var successfullyParsed = true;
index daa4971..1c1316a 100644 (file)
@@ -153,7 +153,7 @@ valid  ("[] in [5,6] * [,5,] / [,,5,,] || [a,] && new [,b] % [,,]");
 invalid("[5,");
 invalid("[,");
 invalid("(a,)");
-valid  ("1 + {get get(){}, set set(a){}, get:4, set:get-set, }");
+valid  ("1 + {get get(){}, set set(a){}, get1:4, set1:get-set, }");
 invalid("1 + {a");
 invalid("1 + {a:");
 invalid("1 + {get l(");
index a2dc586..62434ea 100644 (file)
@@ -4,7 +4,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
 
 
 PASS ES5Harness.preconditionPassed is true
-FAIL ES5Harness.testPassed should be true (of type boolean). Was undefined (of type undefined).
+PASS ES5Harness.testPassed is true
 PASS successfullyParsed is true
 
 TEST COMPLETE
index f47d059..3b79107 100644 (file)
@@ -4,7 +4,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
 
 
 PASS ES5Harness.preconditionPassed is true
-FAIL ES5Harness.testPassed should be true (of type boolean). Was undefined (of type undefined).
+PASS ES5Harness.testPassed is true
 PASS successfullyParsed is true
 
 TEST COMPLETE
index 386186a..245f4ac 100644 (file)
@@ -4,7 +4,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
 
 
 PASS ES5Harness.preconditionPassed is true
-FAIL ES5Harness.testPassed should be true (of type boolean). Was undefined (of type undefined).
+PASS ES5Harness.testPassed is true
 PASS successfullyParsed is true
 
 TEST COMPLETE
index a1b54f5..979274b 100644 (file)
@@ -4,7 +4,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
 
 
 PASS ES5Harness.preconditionPassed is true
-FAIL ES5Harness.testPassed should be true (of type boolean). Was undefined (of type undefined).
+PASS ES5Harness.testPassed is true
 PASS successfullyParsed is true
 
 TEST COMPLETE
index 3e70ea5..4d0e4c4 100644 (file)
@@ -4,7 +4,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
 
 
 PASS ES5Harness.preconditionPassed is true
-FAIL ES5Harness.testPassed should be true (of type boolean). Was undefined (of type undefined).
+PASS ES5Harness.testPassed is true
 PASS successfullyParsed is true
 
 TEST COMPLETE
index c391c52..f97b2cf 100644 (file)
@@ -4,7 +4,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
 
 
 PASS ES5Harness.preconditionPassed is true
-FAIL ES5Harness.testPassed should be true (of type boolean). Was undefined (of type undefined).
+PASS ES5Harness.testPassed is true
 PASS successfullyParsed is true
 
 TEST COMPLETE
index a163742..e06f766 100644 (file)
@@ -4,7 +4,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
 
 
 PASS ES5Harness.preconditionPassed is true
-FAIL ES5Harness.testPassed should be true (of type boolean). Was undefined (of type undefined).
+PASS ES5Harness.testPassed is true
 PASS successfullyParsed is true
 
 TEST COMPLETE
index 8dab8ec..8d5bf21 100644 (file)
@@ -4,7 +4,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
 
 
 PASS ES5Harness.preconditionPassed is true
-FAIL ES5Harness.testPassed should be true (of type boolean). Was undefined (of type undefined).
+PASS ES5Harness.testPassed is true
 PASS successfullyParsed is true
 
 TEST COMPLETE
index b6e0b92..4326c34 100644 (file)
@@ -3019,3 +3019,13 @@ BUGAWONG WIN LINUX SKIP : ietestcenter/Javascript/15.4.4.15-3-14.html = TIMEOUT
 BUGAWONG WIN LINUX SKIP : ietestcenter/Javascript/15.4.4.15-3-29.html = TIMEOUT
 BUGAWONG WIN LINUX SKIP : ietestcenter/Javascript/15.4.4.15-3-8.html = TIMEOUT
 
+
+SKIP : fast/js/object-literal-syntax.html
+SKIP : ietestcenter/Javascript/11.1.5_4-4-b-1.html
+SKIP : ietestcenter/Javascript/11.1.5_4-4-b-2.html
+SKIP : ietestcenter/Javascript/11.1.5_4-4-c-1.html
+SKIP : ietestcenter/Javascript/11.1.5_4-4-c-2.html
+SKIP : ietestcenter/Javascript/11.1.5_4-4-d-1.html
+SKIP : ietestcenter/Javascript/11.1.5_4-4-d-2.html
+SKIP : ietestcenter/Javascript/11.1.5_4-4-d-3.html
+SKIP : ietestcenter/Javascript/11.1.5_4-4-d-4.html