Implement the [NamedConstructor] IDL in CodeGeneratorJS.pm
authorharaken@chromium.org <haraken@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 Nov 2011 14:55:50 +0000 (14:55 +0000)
committerharaken@chromium.org <haraken@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 Nov 2011 14:55:50 +0000 (14:55 +0000)
https://bugs.webkit.org/show_bug.cgi?id=73307

Reviewed by Adam Barth.

This patch implements the [NamedConstructor] IDL for JSC.
The spec: http://www.w3.org/TR/WebIDL/#NamedConstructor

Tests: bindings/scripts/test/JS/JSTestNamedConstructor.idl

* bindings/scripts/CodeGeneratorJS.pm:
(GenerateHeader): Removed unnecessary conditions '$dataNode->extendedAttributes->{"JSCustomConstructor"} || $dataNode->extendedAttributes->{"CustomConstructor"}'.
(GenerateImplementation): Calls GenerateConstructorDefinition() to generate a NamedConstructor.
(GenerateConstructorDeclaration): Generates a header for a NamedConstructor.
(GenerateConstructorDefinition): Generates a NamedConstructor implementation and getConstructData() for the NamedConstructor.
(IsConstructable): Added a NamedConstructor condition.

* bindings/scripts/test/JS/JSTestNamedConstructor.cpp: Updated a run-bindings-tests result.
(WebCore::JSTestNamedConstructorNamedConstructor::JSTestNamedConstructorNamedConstructor):
(WebCore::JSTestNamedConstructorNamedConstructor::finishCreation):
(WebCore::JSTestNamedConstructorNamedConstructor::constructJSTestNamedConstructor):
(WebCore::JSTestNamedConstructorNamedConstructor::getConstructData):
* bindings/scripts/test/JS/JSTestNamedConstructor.h: Ditto.
(WebCore::JSTestNamedConstructorNamedConstructor::create):
(WebCore::JSTestNamedConstructorNamedConstructor::createStructure):

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

Source/WebCore/ChangeLog
Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
Source/WebCore/bindings/scripts/test/JS/JSTestNamedConstructor.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestNamedConstructor.h

index e41d930..0d8dd4f 100644 (file)
@@ -1,3 +1,31 @@
+2011-11-30  Kentaro Hara  <haraken@chromium.org>
+
+        Implement the [NamedConstructor] IDL in CodeGeneratorJS.pm
+        https://bugs.webkit.org/show_bug.cgi?id=73307
+
+        Reviewed by Adam Barth.
+
+        This patch implements the [NamedConstructor] IDL for JSC.
+        The spec: http://www.w3.org/TR/WebIDL/#NamedConstructor
+
+        Tests: bindings/scripts/test/JS/JSTestNamedConstructor.idl
+
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GenerateHeader): Removed unnecessary conditions '$dataNode->extendedAttributes->{"JSCustomConstructor"} || $dataNode->extendedAttributes->{"CustomConstructor"}'.
+        (GenerateImplementation): Calls GenerateConstructorDefinition() to generate a NamedConstructor.
+        (GenerateConstructorDeclaration): Generates a header for a NamedConstructor.
+        (GenerateConstructorDefinition): Generates a NamedConstructor implementation and getConstructData() for the NamedConstructor.
+        (IsConstructable): Added a NamedConstructor condition.
+
+        * bindings/scripts/test/JS/JSTestNamedConstructor.cpp: Updated a run-bindings-tests result.
+        (WebCore::JSTestNamedConstructorNamedConstructor::JSTestNamedConstructorNamedConstructor):
+        (WebCore::JSTestNamedConstructorNamedConstructor::finishCreation):
+        (WebCore::JSTestNamedConstructorNamedConstructor::constructJSTestNamedConstructor):
+        (WebCore::JSTestNamedConstructorNamedConstructor::getConstructData):
+        * bindings/scripts/test/JS/JSTestNamedConstructor.h: Ditto.
+        (WebCore::JSTestNamedConstructorNamedConstructor::create):
+        (WebCore::JSTestNamedConstructorNamedConstructor::createStructure):
+
 2011-11-30  Takashi Toyoshima  <toyoshim@chromium.org>
 
         Add didUpdateBufferedAmount() callback to SocketStreamHandleClient
index 8a37ce1..2af6fc4 100644 (file)
@@ -1099,7 +1099,7 @@ sub GenerateHeader
 
     push(@headerContent, "};\n\n");
 
-    if ($dataNode->extendedAttributes->{"JSCustomConstructor"} || $dataNode->extendedAttributes->{"CustomConstructor"} || !$dataNode->extendedAttributes->{"OmitConstructor"}) {
+    if (!$dataNode->extendedAttributes->{"OmitConstructor"}) {
         $headerIncludes{"JSDOMBinding.h"} = 1;
         GenerateConstructorDeclaration(\@headerContent, $className, $dataNode, $interfaceName);
     }
@@ -1436,6 +1436,9 @@ sub GenerateImplementation
 
         my $protoClassName = "${className}Prototype";
         GenerateConstructorDefinition(\@implContent, $className, $protoClassName, $interfaceName, $visibleClassName, $dataNode);
+        if ($dataNode->extendedAttributes->{"NamedConstructor"}) {
+            GenerateConstructorDefinition(\@implContent, $className, $protoClassName, $interfaceName, $visibleClassName, $dataNode, "GeneratingNamedConstructor");
+        }
     }
 
     # - Add functions and constants to a hashtable definition
@@ -3335,7 +3338,7 @@ sub GenerateConstructorDeclaration
     push(@$outputArray, "protected:\n");
     push(@$outputArray, "    static const unsigned StructureFlags = JSC::OverridesGetOwnPropertySlot | JSC::ImplementsHasInstance | DOMConstructorObject::StructureFlags;\n");
 
-    if (IsConstructable($dataNode)) {
+    if (IsConstructable($dataNode) && !$dataNode->extendedAttributes->{"NamedConstructor"}) {
         push(@$outputArray, "    static JSC::EncodedJSValue JSC_HOST_CALL construct${className}(JSC::ExecState*);\n");
         push(@$outputArray, "    static JSC::ConstructType getConstructData(JSC::JSCell*, JSC::ConstructData&);\n");
     }
@@ -3344,6 +3347,36 @@ sub GenerateConstructorDeclaration
     if (IsConstructorTemplate($dataNode, "Event")) {
         push(@$outputArray, "bool fill${interfaceName}Init(${interfaceName}Init&, JSDictionary&);\n\n");
     }
+
+    if ($dataNode->extendedAttributes->{"NamedConstructor"}) {
+        push(@$outputArray, <<END);
+class JS${interfaceName}NamedConstructor : public DOMConstructorWithDocument {
+public:
+    typedef DOMConstructorWithDocument Base;
+
+    static JS${interfaceName}NamedConstructor* create(JSC::ExecState* exec, JSC::Structure* structure, JSDOMGlobalObject* globalObject)
+    {
+        JS${interfaceName}NamedConstructor* constructor = new (JSC::allocateCell<JS${interfaceName}NamedConstructor>(*exec->heap())) JS${interfaceName}NamedConstructor(structure, globalObject);
+        constructor->finishCreation(exec, globalObject);
+        return constructor;
+    }
+
+    static JSC::Structure* createStructure(JSC::JSGlobalData& globalData, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+    {
+        return JSC::Structure::create(globalData, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), &s_info);
+    }
+
+    static const JSC::ClassInfo s_info;
+
+private:
+    JS${interfaceName}NamedConstructor(JSC::Structure*, JSDOMGlobalObject*);
+    static JSC::EncodedJSValue JSC_HOST_CALL constructJS${interfaceName}(JSC::ExecState*);
+    static JSC::ConstructType getConstructData(JSC::JSCell*, JSC::ConstructData&);
+    void finishCreation(JSC::ExecState*, JSDOMGlobalObject*);
+};
+
+END
+    }
 }
 
 sub GenerateConstructorDefinition
@@ -3355,48 +3388,64 @@ sub GenerateConstructorDefinition
     my $interfaceName = shift;
     my $visibleClassName = shift;
     my $dataNode = shift;
+    my $generatingNamedConstructor = shift;
 
-    my $constructorClassName = "${className}Constructor";
+    my $constructorClassName = $generatingNamedConstructor ? "${className}NamedConstructor" : "${className}Constructor";
     my $numberOfconstructParameters = $dataNode->extendedAttributes->{"ConstructorParameters"};
 
-    push(@$outputArray, "const ClassInfo ${constructorClassName}::s_info = { \"${visibleClassName}Constructor\", &DOMConstructorObject::s_info, &${constructorClassName}Table, 0, CREATE_METHOD_TABLE($constructorClassName) };\n\n");
-
-    push(@$outputArray, "${constructorClassName}::${constructorClassName}(Structure* structure, JSDOMGlobalObject* globalObject)\n");
-    push(@$outputArray, "    : DOMConstructorObject(structure, globalObject)\n");
-    push(@$outputArray, "{\n");
-    push(@$outputArray, "}\n\n");
+    if ($generatingNamedConstructor) {
+        push(@$outputArray, "const ClassInfo ${constructorClassName}::s_info = { \"${visibleClassName}Constructor\", &DOMConstructorObject::s_info, 0, 0, CREATE_METHOD_TABLE($constructorClassName) };\n\n");
+        push(@$outputArray, "${constructorClassName}::${constructorClassName}(Structure* structure, JSDOMGlobalObject* globalObject)\n");
+        push(@$outputArray, "    : DOMConstructorWithDocument(structure, globalObject)\n");
+        push(@$outputArray, "{\n");
+        push(@$outputArray, "}\n\n");
+    } else {
+        push(@$outputArray, "const ClassInfo ${constructorClassName}::s_info = { \"${visibleClassName}Constructor\", &DOMConstructorObject::s_info, &${constructorClassName}Table, 0, CREATE_METHOD_TABLE($constructorClassName) };\n\n");
+        push(@$outputArray, "${constructorClassName}::${constructorClassName}(Structure* structure, JSDOMGlobalObject* globalObject)\n");
+        push(@$outputArray, "    : DOMConstructorObject(structure, globalObject)\n");
+        push(@$outputArray, "{\n");
+        push(@$outputArray, "}\n\n");
+    }
 
     push(@$outputArray, "void ${constructorClassName}::finishCreation(ExecState* exec, JSDOMGlobalObject* globalObject)\n");
     push(@$outputArray, "{\n");
-    push(@$outputArray, "    Base::finishCreation(exec->globalData());\n");
-    push(@$outputArray, "    ASSERT(inherits(&s_info));\n");
     if ($interfaceName eq "DOMWindow") {
+        push(@$outputArray, "    Base::finishCreation(exec->globalData());\n");
+        push(@$outputArray, "    ASSERT(inherits(&s_info));\n");
         push(@$outputArray, "    putDirect(exec->globalData(), exec->propertyNames().prototype, globalObject->prototype(), DontDelete | ReadOnly);\n");
+    } elsif ($generatingNamedConstructor) {
+        push(@$outputArray, "    Base::finishCreation(globalObject);\n");
+        push(@$outputArray, "    ASSERT(inherits(&s_info));\n");
+        push(@$outputArray, "    putDirect(exec->globalData(), exec->propertyNames().prototype, ${className}Prototype::self(exec, globalObject), None);\n");
     } else {
+        push(@$outputArray, "    Base::finishCreation(exec->globalData());\n");
+        push(@$outputArray, "    ASSERT(inherits(&s_info));\n");
         push(@$outputArray, "    putDirect(exec->globalData(), exec->propertyNames().prototype, ${protoClassName}::self(exec, globalObject), DontDelete | ReadOnly);\n");
     }
     push(@$outputArray, "    putDirect(exec->globalData(), exec->propertyNames().length, jsNumber(${numberOfconstructParameters}), ReadOnly | DontDelete | DontEnum);\n") if $numberOfconstructParameters;
     push(@$outputArray, "}\n\n");
 
-    my $hasStaticFunctions = 0;
-    foreach my $function (@{$dataNode->functions}) {
-        if ($function->isStatic) {
-            $hasStaticFunctions = 1;
-            last;
+    if (!$generatingNamedConstructor) {
+        my $hasStaticFunctions = 0;
+        foreach my $function (@{$dataNode->functions}) {
+            if ($function->isStatic) {
+                $hasStaticFunctions = 1;
+                last;
+            }
         }
-    }
 
-    my $kind = $hasStaticFunctions ? "Property" : "Value";
+        my $kind = $hasStaticFunctions ? "Property" : "Value";
 
-    push(@$outputArray, "bool ${constructorClassName}::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)\n");
-    push(@$outputArray, "{\n");
-    push(@$outputArray, "    return getStatic${kind}Slot<${constructorClassName}, JSDOMWrapper>(exec, &${constructorClassName}Table, static_cast<${constructorClassName}*>(cell), propertyName, slot);\n");
-    push(@$outputArray, "}\n\n");
+        push(@$outputArray, "bool ${constructorClassName}::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)\n");
+        push(@$outputArray, "{\n");
+        push(@$outputArray, "    return getStatic${kind}Slot<${constructorClassName}, JSDOMWrapper>(exec, &${constructorClassName}Table, static_cast<${constructorClassName}*>(cell), propertyName, slot);\n");
+        push(@$outputArray, "}\n\n");
 
-    push(@$outputArray, "bool ${constructorClassName}::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)\n");
-    push(@$outputArray, "{\n");
-    push(@$outputArray, "    return getStatic${kind}Descriptor<${constructorClassName}, JSDOMWrapper>(exec, &${constructorClassName}Table, static_cast<${constructorClassName}*>(object), propertyName, descriptor);\n");
-    push(@$outputArray, "}\n\n");
+        push(@$outputArray, "bool ${constructorClassName}::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)\n");
+        push(@$outputArray, "{\n");
+        push(@$outputArray, "    return getStatic${kind}Descriptor<${constructorClassName}, JSDOMWrapper>(exec, &${constructorClassName}Table, static_cast<${constructorClassName}*>(object), propertyName, descriptor);\n");
+        push(@$outputArray, "}\n\n");
+    }
 
     if (IsConstructable($dataNode)) {
         if (IsConstructorTemplate($dataNode, "Event")) {
@@ -3463,7 +3512,7 @@ END
 }
 
 END
-        } elsif (!($dataNode->extendedAttributes->{"JSCustomConstructor"} || $dataNode->extendedAttributes->{"CustomConstructor"})) {
+        } elsif (!($dataNode->extendedAttributes->{"JSCustomConstructor"} || $dataNode->extendedAttributes->{"CustomConstructor"}) && (!$dataNode->extendedAttributes->{"NamedConstructor"} || $generatingNamedConstructor)) {
             push(@$outputArray, "EncodedJSValue JSC_HOST_CALL ${constructorClassName}::construct${className}(ExecState* exec)\n");
             push(@$outputArray, "{\n");
 
@@ -3493,6 +3542,9 @@ END
                 push(@$outputArray, "    if (!context)\n");
                 push(@$outputArray, "        return throwVMError(exec, createReferenceError(exec, \"${interfaceName} constructor associated document is unavailable\"));\n");
             }
+            if ($generatingNamedConstructor) {
+                push(@constructorArgList, "jsConstructor->document()");
+            }
 
             my $index = 0;
             foreach my $parameter (@{$function->parameters}) {
@@ -3505,7 +3557,12 @@ END
                 push(@constructorArgList, "ec");
             }
             my $constructorArg = join(", ", @constructorArgList);
-            push(@$outputArray, "    RefPtr<${interfaceName}> object = ${interfaceName}::create(${constructorArg});\n");
+            if ($generatingNamedConstructor) {
+                push(@$outputArray, "    RefPtr<${interfaceName}> object = ${interfaceName}::createForJSConstructor(${constructorArg});\n");
+            } else {
+                push(@$outputArray, "    RefPtr<${interfaceName}> object = ${interfaceName}::create(${constructorArg});\n");
+            }
+
             if ($dataNode->extendedAttributes->{"ConstructorRaisesException"}) {
                 push(@$outputArray, "    if (ec) {\n");
                 push(@$outputArray, "        setDOMException(exec, ec);\n");
@@ -3517,11 +3574,13 @@ END
             push(@$outputArray, "}\n\n");
         }
 
-        push(@$outputArray, "ConstructType ${constructorClassName}::getConstructData(JSCell*, ConstructData& constructData)\n");
-        push(@$outputArray, "{\n");
-        push(@$outputArray, "    constructData.native.function = construct${className};\n");
-        push(@$outputArray, "    return ConstructTypeHost;\n");
-        push(@$outputArray, "}\n\n");
+        if (!$dataNode->extendedAttributes->{"NamedConstructor"} || $generatingNamedConstructor) {
+            push(@$outputArray, "ConstructType ${constructorClassName}::getConstructData(JSCell*, ConstructData& constructData)\n");
+            push(@$outputArray, "{\n");
+            push(@$outputArray, "    constructData.native.function = construct${className};\n");
+            push(@$outputArray, "    return ConstructTypeHost;\n");
+            push(@$outputArray, "}\n\n");
+        }
     }
 }
 
@@ -3529,7 +3588,7 @@ sub IsConstructable
 {
     my $dataNode = shift;
 
-    return $dataNode->extendedAttributes->{"CustomConstructor"} || $dataNode->extendedAttributes->{"JSCustomConstructor"} || $dataNode->extendedAttributes->{"Constructor"} || $dataNode->extendedAttributes->{"JSConstructorTemplate"} || $dataNode->extendedAttributes->{"ConstructorTemplate"};
+    return $dataNode->extendedAttributes->{"CustomConstructor"} || $dataNode->extendedAttributes->{"JSCustomConstructor"} || $dataNode->extendedAttributes->{"Constructor"} || $dataNode->extendedAttributes->{"NamedConstructor"} || $dataNode->extendedAttributes->{"JSConstructorTemplate"} || $dataNode->extendedAttributes->{"ConstructorTemplate"};
 }
 
 sub IsConstructorTemplate
index b73f880..f215faf 100644 (file)
 #include "config.h"
 #include "JSTestNamedConstructor.h"
 
+#include "ExceptionCode.h"
+#include "JSDOMBinding.h"
 #include "TestNamedConstructor.h"
+#include <runtime/Error.h>
 #include <wtf/GetPtr.h>
 
 using namespace JSC;
@@ -93,6 +96,49 @@ bool JSTestNamedConstructorConstructor::getOwnPropertyDescriptor(JSObject* objec
     return getStaticValueDescriptor<JSTestNamedConstructorConstructor, JSDOMWrapper>(exec, &JSTestNamedConstructorConstructorTable, static_cast<JSTestNamedConstructorConstructor*>(object), propertyName, descriptor);
 }
 
+const ClassInfo JSTestNamedConstructorNamedConstructor::s_info = { "TestNamedConstructorConstructor", &DOMConstructorObject::s_info, 0, 0, CREATE_METHOD_TABLE(JSTestNamedConstructorNamedConstructor) };
+
+JSTestNamedConstructorNamedConstructor::JSTestNamedConstructorNamedConstructor(Structure* structure, JSDOMGlobalObject* globalObject)
+    : DOMConstructorWithDocument(structure, globalObject)
+{
+}
+
+void JSTestNamedConstructorNamedConstructor::finishCreation(ExecState* exec, JSDOMGlobalObject* globalObject)
+{
+    Base::finishCreation(globalObject);
+    ASSERT(inherits(&s_info));
+    putDirect(exec->globalData(), exec->propertyNames().prototype, JSTestNamedConstructorPrototype::self(exec, globalObject), None);
+}
+
+EncodedJSValue JSC_HOST_CALL JSTestNamedConstructorNamedConstructor::constructJSTestNamedConstructor(ExecState* exec)
+{
+    JSTestNamedConstructorNamedConstructor* jsConstructor = static_cast<JSTestNamedConstructorNamedConstructor*>(exec->callee());
+    if (exec->argumentCount() < 1)
+        return throwVMError(exec, createTypeError(exec, "Not enough arguments"));
+    ExceptionCode ec = 0;
+    const String& str1(ustringToString(MAYBE_MISSING_PARAMETER(exec, 0, MissingIsUndefined).isEmpty() ? UString() : MAYBE_MISSING_PARAMETER(exec, 0, MissingIsUndefined).toString(exec)));
+    if (exec->hadException())
+        return JSValue::encode(jsUndefined());
+    const String& str2(ustringToString(MAYBE_MISSING_PARAMETER(exec, 1, MissingIsUndefined).isEmpty() ? UString() : MAYBE_MISSING_PARAMETER(exec, 1, MissingIsUndefined).toString(exec)));
+    if (exec->hadException())
+        return JSValue::encode(jsUndefined());
+    const String& str3(ustringToString(MAYBE_MISSING_PARAMETER(exec, 2, MissingIsEmpty).isEmpty() ? UString() : MAYBE_MISSING_PARAMETER(exec, 2, MissingIsEmpty).toString(exec)));
+    if (exec->hadException())
+        return JSValue::encode(jsUndefined());
+    RefPtr<TestNamedConstructor> object = TestNamedConstructor::createForJSConstructor(jsConstructor->document(), str1, str2, str3, ec);
+    if (ec) {
+        setDOMException(exec, ec);
+        return JSValue::encode(JSValue());
+    }
+    return JSValue::encode(asObject(toJS(exec, jsConstructor->globalObject(), object.get())));
+}
+
+ConstructType JSTestNamedConstructorNamedConstructor::getConstructData(JSCell*, ConstructData& constructData)
+{
+    constructData.native.function = constructJSTestNamedConstructor;
+    return ConstructTypeHost;
+}
+
 /* Hash table for prototype */
 #if ENABLE(JIT)
 #define THUNK_GENERATOR(generator) , generator
index fe2fd50..a3f7b71 100644 (file)
@@ -128,6 +128,31 @@ protected:
     static const unsigned StructureFlags = JSC::OverridesGetOwnPropertySlot | JSC::ImplementsHasInstance | DOMConstructorObject::StructureFlags;
 };
 
+class JSTestNamedConstructorNamedConstructor : public DOMConstructorWithDocument {
+public:
+    typedef DOMConstructorWithDocument Base;
+
+    static JSTestNamedConstructorNamedConstructor* create(JSC::ExecState* exec, JSC::Structure* structure, JSDOMGlobalObject* globalObject)
+    {
+        JSTestNamedConstructorNamedConstructor* constructor = new (JSC::allocateCell<JSTestNamedConstructorNamedConstructor>(*exec->heap())) JSTestNamedConstructorNamedConstructor(structure, globalObject);
+        constructor->finishCreation(exec, globalObject);
+        return constructor;
+    }
+
+    static JSC::Structure* createStructure(JSC::JSGlobalData& globalData, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+    {
+        return JSC::Structure::create(globalData, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), &s_info);
+    }
+
+    static const JSC::ClassInfo s_info;
+
+private:
+    JSTestNamedConstructorNamedConstructor(JSC::Structure*, JSDOMGlobalObject*);
+    static JSC::EncodedJSValue JSC_HOST_CALL constructJSTestNamedConstructor(JSC::ExecState*);
+    static JSC::ConstructType getConstructData(JSC::JSCell*, JSC::ConstructData&);
+    void finishCreation(JSC::ExecState*, JSDOMGlobalObject*);
+};
+
 // Attributes
 
 JSC::JSValue jsTestNamedConstructorConstructor(JSC::ExecState*, JSC::JSValue, const JSC::Identifier&);