[WebIDL] Move more types over to the new JSConverter based toJS functions
authorweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 25 Oct 2016 18:35:03 +0000 (18:35 +0000)
committerweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 25 Oct 2016 18:35:03 +0000 (18:35 +0000)
https://bugs.webkit.org/show_bug.cgi?id=163920

Reviewed by Darin Adler.

- Adds WebIDL-extension type IDLDate, and use it for Date conversions.
- Move JSDOMIterator over to using IDLType based conversions. Make them more
  explicit by adding a traits template argument which describes the iterator.
- Add correct parsing for WebIDL iterable, parsing the parameter types into
  domTypes.
- Support non-Optional nullable types via trait-like functions on IDLTypes.

* bindings/generic/IDLTypes.h:
(WebCore::IDLType::isNullValue):
(WebCore::IDLType::extractValueFromNullable):
(WebCore::IDLString::isNullValue):
(WebCore::IDLString::extractValueFromNullable):
(WebCore::IDLInterface::isNullValue):
(WebCore::IDLInterface::extractValueFromNullable):
(WebCore::IDLDate::isNullValue):
(WebCore::IDLDate::extractValueFromNullable):
Add isNullValue and extractValueFromNullable functions to allow non-Optional
based nullable types.

* Modules/plugins/QuickTimePluginReplacement.mm:
(WebCore::QuickTimePluginReplacement::installReplacement):
* bindings/js/IDBBindingUtilities.cpp:
(WebCore::toJS):
* bindings/js/JSCSSStyleDeclarationCustom.cpp:
(WebCore::stylePropertyGetter):
* bindings/js/JSCustomElementInterface.cpp:
(WebCore::JSCustomElementInterface::invokeAttributeChangedCallback):
Switch to IDLType based toJS.

* bindings/js/JSDOMBinding.cpp:
(WebCore::jsStringOrNull): Deleted.
(WebCore::jsDateOrNull): Deleted.
* bindings/js/JSDOMBinding.h:
(WebCore::jsPair): Deleted.
(WebCore::toJSNullableString): Deleted.
Remove now unusued toJS functions.

* bindings/js/JSDOMConvert.h:
(WebCore::JSConverter<IDLNullable<T>>::convert):
Use new functions to detect and extract nullable values.

(WebCore::Converter<IDLBufferSource>::convert):
Moved to be with the other converters.

(WebCore::Converter<IDLDate>::convert):
(WebCore::JSConverter<IDLDate>::convert):
Added.

* bindings/js/JSDOMIterator.h:
(WebCore::jsPair):
(WebCore::iteratorCreate):
(WebCore::IteratorTraits>::asJS):
(WebCore::appendForEachArguments):
(WebCore::iteratorForEach):
(WebCore::IteratorTraits>::destroy):
(WebCore::IteratorTraits>::next):
(WebCore::IteratorTraits>::finishCreation):
(WebCore::IteratorInspector::decltype): Deleted.
(WebCore::IteratorInspector::test): Deleted.
(WebCore::JSDOMIterator<JSWrapper>::asJS): Deleted.
(WebCore::JSDOMIterator<JSWrapper>::destroy): Deleted.
(WebCore::JSDOMIterator<JSWrapper>::next): Deleted.
(WebCore::JSDOMIteratorPrototype<JSWrapper>::next): Deleted.
(WebCore::JSDOMIteratorPrototype<JSWrapper>::finishCreation): Deleted.
Switch to new Traits based model, and have the generated code pass in
the type (map or set) and key/value types. With the explicit types known,
we can use the new toJS functions.

Also, moved the jsPair functions here from JSDOMBinding.h, since this was
the only place it was used.

* bindings/scripts/CodeGeneratorJS.pm:
(GenerateImplementationIterableFunctions):
Add iterator trait definition and update for new parameters to JSDOMIterator
and JSDOMIteratorPrototype.

(GetBaseIDLType):
Add IDLDate, and move IDLBufferSource up to the simple path.

(JSValueToNativeIsHandledByDOMConvert):
Allow Date.

(JSValueToNative):
Remove special case for Date.

(NativeToJSValueIsHandledByDOMConvert):
Allow Date and remove restriction of nullable string-like types.

(NativeToJSValueDOMConvertNeedsState):
Add Date to list of types needing state.

(NativeToJSValue):
Remove special cases for Date and nullable-strings.

* bindings/scripts/IDLParser.pm:
(parseOptionalIterableInterface):
Add correct parsing of iterable.

* bindings/scripts/test/JS/JSTestIterable.cpp:
* bindings/scripts/test/JS/JSTestNode.cpp:
* bindings/scripts/test/JS/JSTestObj.cpp:
Update test results.

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

15 files changed:
Source/WebCore/ChangeLog
Source/WebCore/Modules/plugins/QuickTimePluginReplacement.mm
Source/WebCore/bindings/generic/IDLTypes.h
Source/WebCore/bindings/js/IDBBindingUtilities.cpp
Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp
Source/WebCore/bindings/js/JSCustomElementInterface.cpp
Source/WebCore/bindings/js/JSDOMBinding.cpp
Source/WebCore/bindings/js/JSDOMBinding.h
Source/WebCore/bindings/js/JSDOMConvert.h
Source/WebCore/bindings/js/JSDOMIterator.h
Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
Source/WebCore/bindings/scripts/IDLParser.pm
Source/WebCore/bindings/scripts/test/JS/JSTestIterable.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestNode.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestObj.cpp

index 596249f..a09b10d 100644 (file)
@@ -1,3 +1,114 @@
+2016-10-24  Sam Weinig  <sam@webkit.org>
+
+        [WebIDL] Move more types over to the new JSConverter based toJS functions
+        https://bugs.webkit.org/show_bug.cgi?id=163920
+
+        Reviewed by Darin Adler.
+
+        - Adds WebIDL-extension type IDLDate, and use it for Date conversions.
+        - Move JSDOMIterator over to using IDLType based conversions. Make them more
+          explicit by adding a traits template argument which describes the iterator.
+        - Add correct parsing for WebIDL iterable, parsing the parameter types into
+          domTypes.
+        - Support non-Optional nullable types via trait-like functions on IDLTypes.
+
+
+        * bindings/generic/IDLTypes.h:
+        (WebCore::IDLType::isNullValue):
+        (WebCore::IDLType::extractValueFromNullable):
+        (WebCore::IDLString::isNullValue):
+        (WebCore::IDLString::extractValueFromNullable):
+        (WebCore::IDLInterface::isNullValue):
+        (WebCore::IDLInterface::extractValueFromNullable):
+        (WebCore::IDLDate::isNullValue):
+        (WebCore::IDLDate::extractValueFromNullable):
+        Add isNullValue and extractValueFromNullable functions to allow non-Optional
+        based nullable types.
+        
+        * Modules/plugins/QuickTimePluginReplacement.mm:
+        (WebCore::QuickTimePluginReplacement::installReplacement):
+        * bindings/js/IDBBindingUtilities.cpp:
+        (WebCore::toJS):
+        * bindings/js/JSCSSStyleDeclarationCustom.cpp:
+        (WebCore::stylePropertyGetter):
+        * bindings/js/JSCustomElementInterface.cpp:
+        (WebCore::JSCustomElementInterface::invokeAttributeChangedCallback):
+        Switch to IDLType based toJS.
+
+        * bindings/js/JSDOMBinding.cpp:
+        (WebCore::jsStringOrNull): Deleted.
+        (WebCore::jsDateOrNull): Deleted.
+        * bindings/js/JSDOMBinding.h:
+        (WebCore::jsPair): Deleted.
+        (WebCore::toJSNullableString): Deleted.
+        Remove now unusued toJS functions.
+
+        * bindings/js/JSDOMConvert.h:
+        (WebCore::JSConverter<IDLNullable<T>>::convert):
+        Use new functions to detect and extract nullable values.
+
+        (WebCore::Converter<IDLBufferSource>::convert):
+        Moved to be with the other converters.
+
+        (WebCore::Converter<IDLDate>::convert):
+        (WebCore::JSConverter<IDLDate>::convert):
+        Added.
+
+        * bindings/js/JSDOMIterator.h:
+        (WebCore::jsPair):
+        (WebCore::iteratorCreate):
+        (WebCore::IteratorTraits>::asJS):
+        (WebCore::appendForEachArguments):
+        (WebCore::iteratorForEach):
+        (WebCore::IteratorTraits>::destroy):
+        (WebCore::IteratorTraits>::next):
+        (WebCore::IteratorTraits>::finishCreation):
+        (WebCore::IteratorInspector::decltype): Deleted.
+        (WebCore::IteratorInspector::test): Deleted.
+        (WebCore::JSDOMIterator<JSWrapper>::asJS): Deleted.
+        (WebCore::JSDOMIterator<JSWrapper>::destroy): Deleted.
+        (WebCore::JSDOMIterator<JSWrapper>::next): Deleted.
+        (WebCore::JSDOMIteratorPrototype<JSWrapper>::next): Deleted.
+        (WebCore::JSDOMIteratorPrototype<JSWrapper>::finishCreation): Deleted.
+        Switch to new Traits based model, and have the generated code pass in 
+        the type (map or set) and key/value types. With the explicit types known,
+        we can use the new toJS functions.
+        
+        Also, moved the jsPair functions here from JSDOMBinding.h, since this was
+        the only place it was used.
+
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GenerateImplementationIterableFunctions):
+        Add iterator trait definition and update for new parameters to JSDOMIterator
+        and JSDOMIteratorPrototype.
+
+        (GetBaseIDLType):
+        Add IDLDate, and move IDLBufferSource up to the simple path.
+
+        (JSValueToNativeIsHandledByDOMConvert):
+        Allow Date.
+
+        (JSValueToNative):
+        Remove special case for Date.
+
+        (NativeToJSValueIsHandledByDOMConvert):
+        Allow Date and remove restriction of nullable string-like types.
+
+        (NativeToJSValueDOMConvertNeedsState):
+        Add Date to list of types needing state.
+
+        (NativeToJSValue):
+        Remove special cases for Date and nullable-strings.
+
+        * bindings/scripts/IDLParser.pm:
+        (parseOptionalIterableInterface):
+        Add correct parsing of iterable.
+
+        * bindings/scripts/test/JS/JSTestIterable.cpp:
+        * bindings/scripts/test/JS/JSTestNode.cpp:
+        * bindings/scripts/test/JS/JSTestObj.cpp:
+        Update test results.
+
 2016-10-25  Eric Carlson  <eric.carlson@apple.com>
 
         [MediaStream] Add "has capture device" bit to media state flags
index 0b4df15..535eb6a 100644 (file)
@@ -210,8 +210,8 @@ bool QuickTimePluginReplacement::installReplacement(ShadowRoot& root)
     argList.append(toJS(exec, globalObject, &root));
     argList.append(toJS(exec, globalObject, m_parentElement));
     argList.append(toJS(exec, globalObject, this));
-    argList.append(toJS<String>(exec, globalObject, m_names));
-    argList.append(toJS<String>(exec, globalObject, m_values));
+    argList.append(toJS<IDLSequence<IDLNullable<IDLDOMString>>>(*exec, *globalObject, m_names));
+    argList.append(toJS<IDLSequence<IDLNullable<IDLDOMString>>>(*exec, *globalObject, m_values));
     JSC::JSValue replacement = call(exec, replacementObject, callType, callData, globalObject, argList);
     if (UNLIKELY(scope.exception())) {
         scope.clearException();
index 2c932fe..d5e7a79 100644 (file)
@@ -41,11 +41,13 @@ template <typename Value> class DOMPromise;
 template<typename T>
 struct IDLType {
     using ImplementationType = T;
+
     using NullableType = Optional<ImplementationType>;
+    static NullableType nullValue() { return Nullopt; }
+    static bool isNullValue(const NullableType& value) { return !value; }
+    static ImplementationType extractValueFromNullable(const NullableType& value) { return value.value(); }
 };
 
-struct IDLDummy;
-
 // IDLUnsupportedType is a special type that serves as a base class for currently unsupported types.
 struct IDLUnsupportedType : IDLType<void> { };
 
@@ -78,6 +80,9 @@ struct IDLUnrestrictedDouble : IDLFloatingPoint<double, true> { };
 
 struct IDLString : IDLType<String> {
     using NullableType = String;
+    static String nullValue() { return String(); }
+    static bool isNullValue(const String& value) { return value.isNull(); }
+    static const String& extractValueFromNullable(const String& value) { return value; }
 };
 struct IDLDOMString : IDLString { };
 struct IDLByteString : IDLUnsupportedType { };
@@ -87,7 +92,11 @@ struct IDLObject : IDLUnsupportedType { };
 
 template<typename T> struct IDLInterface : IDLType<RefPtr<T>> {
     using RawType = T;
+
     using NullableType = RefPtr<T>;
+    static RefPtr<T> nullValue() { return nullptr; }
+    static bool isNullValue(const RefPtr<T>& value) { return !value; }
+    static const RefPtr<T>& extractValueFromNullable(const RefPtr<T>& value) { return value; }
 };
 
 template<typename T> struct IDLDictionary : IDLType<T> { };
@@ -119,6 +128,15 @@ struct IDLUnion : IDLType<Variant<typename Ts::ImplementationType...>> {
     using TypeList = brigand::list<Ts...>;
 };
 
+// Non-WebIDL extensions
+
+struct IDLDate : IDLType<double> { 
+    using NullableType = double;
+    static double nullValue() { return std::numeric_limits<double>::quiet_NaN(); }
+    static bool isNullValue(double value) { return std::isnan(value); }
+    static double extractValueFromNullable(double value) { return value; }
+};
+
 struct IDLBufferSource : IDLType<BufferSource> { };
 
 // Helper predicates
index b63ef3c..571dbc1 100644 (file)
@@ -107,9 +107,9 @@ JSValue toJS(ExecState& state, JSGlobalObject& globalObject, IDBKey* key)
     case KeyType::String:
         return jsStringWithCache(&state, key->string());
     case KeyType::Date:
-        // FIXME: This should probably be jsDate() as per:
+        // FIXME: This should probably be toJS<IDLDate>(...) as per:
         // http://w3c.github.io/IndexedDB/#request-convert-a-key-to-a-value
-        return jsDateOrNull(&state, key->date());
+        return toJS<IDLNullable<IDLDate>>(state, key->date());
     case KeyType::Number:
         return jsNumber(key->number());
     case KeyType::Min:
index 35e4a22..ae830e0 100644 (file)
@@ -283,9 +283,9 @@ static CSSPropertyInfo parseJavaScriptCSSPropertyName(PropertyName propertyName)
 static inline JSValue stylePropertyGetter(ExecState& state, JSCSSStyleDeclaration& thisObject, CSSPropertyID propertyID, const RefPtr<CSSValue>& value)
 {
     if (value)
-        return jsStringOrNull(&state, value->cssText());
+        return toJS<IDLNullable<IDLDOMString>>(state, value->cssText());
     // If the property is a shorthand property (such as "padding"), it can only be accessed using getPropertyValue.
-    return jsStringWithCache(&state, thisObject.wrapped().getPropertyValueInternal(propertyID));
+    return toJS<IDLDOMString>(state, thisObject.wrapped().getPropertyValueInternal(propertyID));
 }
 
 static inline JSValue stylePropertyGetter(ExecState& state, JSCSSStyleDeclaration& thisObject, CSSPropertyID propertyID)
index ff3f301..4c38c15 100644 (file)
@@ -289,10 +289,10 @@ void JSCustomElementInterface::setAttributeChangedCallback(JSC::JSObject* callba
 void JSCustomElementInterface::invokeAttributeChangedCallback(Element& element, const QualifiedName& attributeName, const AtomicString& oldValue, const AtomicString& newValue)
 {
     invokeCallback(element, m_attributeChangedCallback.get(), [&](ExecState* state, JSDOMGlobalObject*, MarkedArgumentBuffer& args) {
-        args.append(jsStringWithCache(state, attributeName.localName()));
-        args.append(jsStringOrNull(state, oldValue));
-        args.append(jsStringOrNull(state, newValue));
-        args.append(jsStringOrNull(state, attributeName.namespaceURI()));
+        args.append(toJS<IDLDOMString>(*state, attributeName.localName()));
+        args.append(toJS<IDLNullable<IDLDOMString>>(*state, oldValue));
+        args.append(toJS<IDLNullable<IDLDOMString>>(*state, newValue));
+        args.append(toJS<IDLNullable<IDLDOMString>>(*state, attributeName.namespaceURI()));
     });
 }
 
index d80b1bb..f2985dd 100644 (file)
@@ -64,13 +64,6 @@ void addImpureProperty(const AtomicString& propertyName)
     JSDOMWindow::commonVM().addImpureProperty(propertyName);
 }
 
-JSValue jsStringOrNull(ExecState* exec, const String& s)
-{
-    if (s.isNull())
-        return jsNull();
-    return jsStringWithCache(exec, s);
-}
-
 JSValue jsOwnedStringOrNull(ExecState* exec, const String& s)
 {
     if (s.isNull())
@@ -90,13 +83,6 @@ JSValue jsString(ExecState* exec, const URL& url)
     return jsStringWithCache(exec, url.string());
 }
 
-JSValue jsStringOrNull(ExecState* exec, const URL& url)
-{
-    if (url.isNull())
-        return jsNull();
-    return jsStringWithCache(exec, url.string());
-}
-
 JSValue jsStringOrUndefined(ExecState* exec, const URL& url)
 {
     if (url.isNull())
@@ -171,14 +157,6 @@ JSValue jsDate(ExecState* exec, double value)
     return DateInstance::create(exec->vm(), exec->lexicalGlobalObject()->dateStructure(), value);
 }
 
-JSValue jsDateOrNull(ExecState* exec, double value)
-{
-    // For nullable Date types, we use NaN as null value.
-    if (std::isnan(value))
-        return jsNull();
-    return DateInstance::create(exec->vm(), exec->lexicalGlobalObject()->dateStructure(), value);
-}
-
 double valueToDate(ExecState* exec, JSValue value)
 {
     if (value.isNumber())
index 80eac6d..b3769dc 100644 (file)
@@ -202,9 +202,6 @@ WEBCORE_EXPORT void setDOMExceptionSlow(JSC::ExecState*, JSC::ThrowScope&, Excep
 
 JSC::JSValue jsString(JSC::ExecState*, const URL&); // empty if the URL is null
 
-JSC::JSValue jsStringOrNull(JSC::ExecState*, const String&); // null if the string is null
-JSC::JSValue jsStringOrNull(JSC::ExecState*, const URL&); // null if the URL is null
-
 JSC::JSValue jsStringOrUndefined(JSC::ExecState*, const String&); // undefined if the string is null
 JSC::JSValue jsStringOrUndefined(JSC::ExecState*, const URL&); // undefined if the URL is null
 
@@ -257,7 +254,6 @@ WEBCORE_EXPORT int64_t toInt64(JSC::ExecState&, JSC::JSValue);
 WEBCORE_EXPORT uint64_t toUInt64(JSC::ExecState&, JSC::JSValue);
 
 JSC::JSValue jsDate(JSC::ExecState*, double value);
-JSC::JSValue jsDateOrNull(JSC::ExecState*, double value);
 
 // NaN if the value can't be converted to a date.
 double valueToDate(JSC::ExecState*, JSC::JSValue);
@@ -273,17 +269,12 @@ template<typename T> JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, Ref<
 template<typename T> JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, RefPtr<T>&&);
 template<typename T> JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, const Vector<T>&);
 template<typename T> JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, const Vector<RefPtr<T>>&);
-JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, const String&);
 JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, const JSC::PrivateName&);
 
 JSC::JSValue toJSIterator(JSC::ExecState&, JSDOMGlobalObject&, JSC::JSValue);
 template<typename T> JSC::JSValue toJSIterator(JSC::ExecState&, JSDOMGlobalObject&, const T&);
-
 JSC::JSValue toJSIteratorEnd(JSC::ExecState&);
 
-JSC::JSValue jsPair(JSC::ExecState&, JSDOMGlobalObject*, JSC::JSValue, JSC::JSValue);
-template<typename FirstType, typename SecondType> JSC::JSValue jsPair(JSC::ExecState&, JSDOMGlobalObject*, const FirstType&, const SecondType&);
-
 RefPtr<JSC::ArrayBufferView> toArrayBufferView(JSC::JSValue);
 RefPtr<JSC::Int8Array> toInt8Array(JSC::JSValue);
 RefPtr<JSC::Int16Array> toInt16Array(JSC::JSValue);
@@ -405,9 +396,6 @@ struct BindingCaller {
 // ExceptionOr handling.
 void propagateException(JSC::ExecState&, JSC::ThrowScope&, ExceptionOr<void>&&);
 template<typename T> JSC::JSValue toJS(JSC::ExecState&, JSDOMGlobalObject&, JSC::ThrowScope&, ExceptionOr<T>&&);
-JSC::JSValue toJSDate(JSC::ExecState&, JSC::ThrowScope&, ExceptionOr<double>&&);
-JSC::JSValue toJSNullableDate(JSC::ExecState&, JSC::ThrowScope&, ExceptionOr<Optional<double>>&&);
-JSC::JSValue toJSNullableString(JSC::ExecState&, JSC::ThrowScope&, ExceptionOr<String>&&);
 template<typename T> JSC::JSValue toJSNewlyCreated(JSC::ExecState&, JSDOMGlobalObject&, JSC::ThrowScope&, ExceptionOr<T>&& value);
 
 // Inline functions and template definitions.
@@ -683,11 +671,6 @@ template<typename T> inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalO
     return array;
 }
 
-inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject*, const String& value)
-{
-    return jsStringOrNull(exec, value);
-}
-
 inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject*, const JSC::PrivateName& privateName)
 {
     return JSC::Symbol::create(exec->vm(), privateName.uid());
@@ -708,19 +691,6 @@ inline JSC::JSValue toJSIteratorEnd(JSC::ExecState& state)
     return createIteratorResultObject(&state, JSC::jsUndefined(), true);
 }
 
-inline JSC::JSValue jsPair(JSC::ExecState& state, JSDOMGlobalObject* globalObject, JSC::JSValue value1, JSC::JSValue value2)
-{
-    JSC::MarkedArgumentBuffer args;
-    args.append(value1);
-    args.append(value2);
-    return constructArray(&state, 0, globalObject, args);
-}
-
-template<typename FirstType, typename SecondType> inline JSC::JSValue jsPair(JSC::ExecState& state, JSDOMGlobalObject* globalObject, const FirstType& value1, const SecondType& value2)
-{
-    return jsPair(state, globalObject, toJS(&state, globalObject, value1), toJS(&state, globalObject, value2));
-}
-
 inline RefPtr<JSC::ArrayBufferView> toArrayBufferView(JSC::JSValue value)
 {
     auto* wrapper = JSC::jsDynamicCast<JSC::JSArrayBufferView*>(value);
@@ -817,13 +787,4 @@ template<typename T> inline JSC::JSValue toJSNewlyCreated(JSC::ExecState& state,
     return toJSNewlyCreated(&state, &globalObject, value.releaseReturnValue());
 }
 
-inline JSC::JSValue toJSNullableString(JSC::ExecState& state, JSC::ThrowScope& throwScope, ExceptionOr<String>&& value)
-{
-    if (UNLIKELY(value.hasException())) {
-        propagateException(state, throwScope, value.releaseException());
-        return { };
-    }
-    return jsStringOrNull(&state, value.releaseReturnValue());
-}
-
 } // namespace WebCore
index 4e60674..6a64d38 100644 (file)
@@ -164,10 +164,8 @@ template<typename T> struct Converter<IDLNullable<T>> : DefaultConverter<IDLNull
         // NOTE: Handled elsewhere.
 
         // 2. Otherwise, if V is null or undefined, then return the IDL nullable type T? value null.
-        if (value.isUndefinedOrNull()) {
-            // FIXME: Should we make it part of the IDLType to provide the null value?
-            return ReturnType();
-        }
+        if (value.isUndefinedOrNull())
+            return T::nullValue();
 
         // 3. Otherwise, return the result of converting V using the rules for the inner IDL type T.
         return Converter<T>::convert(state, value);
@@ -180,26 +178,23 @@ template<typename T> struct JSConverter<IDLNullable<T>> {
     static constexpr bool needsState = JSConverter<T>::needsState;
     static constexpr bool needsGlobalObject = JSConverter<T>::needsGlobalObject;
 
-    // FIXME: These only work if ImplementationType is an Optional. We should generalize
-    // this so it can work for types that don't use Optional to represent nullness, like
-    // String and interface types.
     static JSC::JSValue convert(const ImplementationType& value)
     {
-        if (!value)
+        if (T::isNullValue(value))
             return JSC::jsNull();
-        return JSConverter<T>::convert(value.value());
+        return JSConverter<T>::convert(T::extractValueFromNullable(value));
     }
     static JSC::JSValue convert(JSC::ExecState& state, const ImplementationType& value)
     {
-        if (!value)
+        if (T::isNullValue(value))
             return JSC::jsNull();
-        return JSConverter<T>::convert(state, value.value());
+        return JSConverter<T>::convert(state, T::extractValueFromNullable(value));
     }
     static JSC::JSValue convert(JSC::ExecState& state, JSDOMGlobalObject& globalObject, const ImplementationType& value)
     {
-        if (!value)
+        if (T::isNullValue(value))
             return JSC::jsNull();
-        return JSConverter<T>::convert(state, globalObject, value.value());
+        return JSConverter<T>::convert(state, globalObject, T::extractValueFromNullable(value));
     }
 };
 
@@ -1010,6 +1005,47 @@ template<typename... T> struct JSConverter<IDLUnion<T...>> {
 };
 
 // MARK: -
+// MARK: BufferSource type
+
+template<> struct Converter<IDLBufferSource> : DefaultConverter<IDLBufferSource> {
+    using ReturnType = BufferSource;
+
+    static ReturnType convert(JSC::ExecState& state, JSC::JSValue value)
+    {
+        JSC::VM& vm = state.vm();
+        auto scope = DECLARE_THROW_SCOPE(vm);
+
+        if (JSC::ArrayBuffer* buffer = JSC::toArrayBuffer(value))
+            return { static_cast<uint8_t*>(buffer->data()), buffer->byteLength() };
+        if (RefPtr<JSC::ArrayBufferView> bufferView = toArrayBufferView(value))
+            return { static_cast<uint8_t*>(bufferView->baseAddress()), bufferView->byteLength() };
+
+        throwTypeError(&state, scope, ASCIILiteral("Only ArrayBuffer and ArrayBufferView objects can be passed as BufferSource arguments"));
+        return { nullptr, 0 };
+    }
+};
+
+// MARK: -
+// MARK: Date type
+
+template<> struct Converter<IDLDate> : DefaultConverter<IDLDate> {
+    static double convert(JSC::ExecState& state, JSC::JSValue value)
+    {
+        return valueToDate(&state, value);
+    }
+};
+
+template<> struct JSConverter<IDLDate> {
+    static constexpr bool needsState = true;
+    static constexpr bool needsGlobalObject = false;
+
+    static JSC::JSValue convert(JSC::ExecState& state, double value)
+    {
+        return jsDate(&state, value);
+    }
+};
+
+// MARK: -
 // MARK: Support for variadic tail convertions
 
 namespace Detail {
@@ -1076,25 +1112,4 @@ template<typename IDLType> typename Detail::VariadicConverter<IDLType>::Result c
     return { length, WTFMove(result) };
 }
 
-// MARK: -
-// MARK: BufferSource type
-
-template<> struct Converter<IDLBufferSource> : DefaultConverter<IDLBufferSource> {
-    using ReturnType = BufferSource;
-
-    static ReturnType convert(JSC::ExecState& state, JSC::JSValue value)
-    {
-        JSC::VM& vm = state.vm();
-        auto scope = DECLARE_THROW_SCOPE(vm);
-
-        if (JSC::ArrayBuffer* buffer = JSC::toArrayBuffer(value))
-            return { static_cast<uint8_t*>(buffer->data()), buffer->byteLength() };
-        if (RefPtr<JSC::ArrayBufferView> bufferView = toArrayBufferView(value))
-            return { static_cast<uint8_t*>(bufferView->baseAddress()), bufferView->byteLength() };
-
-        throwTypeError(&state, scope, ASCIILiteral("Only ArrayBuffer and ArrayBufferView objects can be passed as BufferSource arguments"));
-        return { nullptr, 0 };
-    }
-};
-
 } // namespace WebCore
index e9eb55d..8a87d84 100644 (file)
@@ -24,8 +24,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef JSDOMIterator_h
-#define JSDOMIterator_h
+#pragma once
 
 #include "JSDOMBinding.h"
 #include <runtime/IteratorPrototype.h>
@@ -36,8 +35,15 @@ namespace WebCore {
 
 void addValueIterableMethods(JSC::JSGlobalObject&, JSC::JSObject&);
 
-template<typename JSWrapper>
-class JSDOMIteratorPrototype : public JSC::JSNonFinalObject {
+enum class JSDOMIteratorType { Set, Map };
+
+// struct IteratorTraits {
+//     static constexpr JSDOMIteratorType type = [Map|Set];
+//     using KeyType = [IDLType|void];
+//     using ValueType = [IDLType];
+// };
+
+template<typename JSWrapper, typename IteratorTraits> class JSDOMIteratorPrototype : public JSC::JSNonFinalObject {
 public:
     using Base = JSC::JSNonFinalObject;
     using DOMWrapped = typename JSWrapper::DOMWrapped;
@@ -64,24 +70,18 @@ private:
     void finishCreation(JSC::VM&, JSC::JSGlobalObject*);
 };
 
-template<typename IteratorValue>
-class IteratorInspector {
-private:
-    template<typename T> static constexpr auto test(int) -> decltype(std::declval<T>()->key, std::declval<T>()->value, bool()) { return true; }
-    template<typename T> static constexpr bool test(...) { return false; }
-public:
-    static constexpr bool isMap = test<IteratorValue>(0);
-    static constexpr bool isSet = !isMap;
-};
-
 enum class IterationKind { Key, Value, KeyValue };
 
-template<typename JSWrapper>
-class JSDOMIterator: public JSDOMObject {
+template<typename JSWrapper, typename IteratorTraits> class JSDOMIterator : public JSDOMObject {
 public:
-    using DOMWrapped = typename std::remove_reference<decltype(std::declval<JSWrapper>().wrapped())>::type;
     using Base = JSDOMObject;
 
+    using Wrapper = JSWrapper;
+    using Traits = IteratorTraits;
+
+    using DOMWrapped = typename Wrapper::DOMWrapped;
+    using Prototype = JSDOMIteratorPrototype<Wrapper, Traits>;
+
     DECLARE_INFO;
 
     static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
@@ -96,10 +96,9 @@ public:
         return instance;
     }
 
-    static JSDOMIteratorPrototype<JSWrapper>* createPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
+    static Prototype* createPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
     {
-        return JSDOMIteratorPrototype<JSWrapper>::create(vm, globalObject,
-            JSDOMIteratorPrototype<JSWrapper>::createStructure(vm, globalObject, globalObject->iteratorPrototype()));
+        return Prototype::create(vm, globalObject, Prototype::createStructure(vm, globalObject, globalObject->iteratorPrototype()));
     }
 
     JSC::JSValue next(JSC::ExecState&);
@@ -112,10 +111,8 @@ private:
     {
     }
 
-    template<typename IteratorValue> typename std::enable_if<IteratorInspector<IteratorValue>::isMap, JSC::JSValue>::type
-    asJS(JSC::ExecState&, IteratorValue&);
-    template<typename IteratorValue> typename std::enable_if<IteratorInspector<IteratorValue>::isSet, JSC::JSValue>::type
-    asJS(JSC::ExecState&, IteratorValue&);
+    template<typename IteratorValue, typename T = Traits> typename std::enable_if<T::type == JSDOMIteratorType::Map, JSC::JSValue>::type asJS(JSC::ExecState&, IteratorValue&);
+    template<typename IteratorValue, typename T = Traits> typename std::enable_if<T::type == JSDOMIteratorType::Set, JSC::JSValue>::type asJS(JSC::ExecState&, IteratorValue&);
 
     static void destroy(JSC::JSCell*);
 
@@ -123,61 +120,91 @@ private:
     IterationKind m_kind;
 };
 
-template<typename JSWrapper>
-JSC::JSValue iteratorCreate(JSWrapper&, IterationKind);
-template<typename JSWrapper>
-JSC::JSValue iteratorForEach(JSC::ExecState&, JSWrapper&, JSC::ThrowScope&);
+inline JSC::JSValue jsPair(JSC::ExecState& state, JSDOMGlobalObject& globalObject, JSC::JSValue value1, JSC::JSValue value2)
+{
+    JSC::MarkedArgumentBuffer arguments;
+    arguments.append(value1);
+    arguments.append(value2);
+    return constructArray(&state, nullptr, &globalObject, arguments);
+}
+
+template<typename FirstType, typename SecondType, typename T, typename U> 
+inline JSC::JSValue jsPair(JSC::ExecState& state, JSDOMGlobalObject& globalObject, const T& value1, const U& value2)
+{
+    return jsPair(state, globalObject, toJS<FirstType>(state, globalObject, value1), toJS<SecondType>(state, globalObject, value2));
+}
+
+template<typename JSIterator>
+JSC::JSValue iteratorCreate(typename JSIterator::Wrapper&, IterationKind);
+template<typename JSIterator>
+JSC::JSValue iteratorForEach(JSC::ExecState&, typename JSIterator::Wrapper&, JSC::ThrowScope&);
 
-template<typename JSWrapper>
-JSC::JSValue iteratorCreate(JSWrapper& thisObject, IterationKind kind)
+template<typename JSIterator>
+JSC::JSValue iteratorCreate(typename JSIterator::Wrapper& thisObject, IterationKind kind)
 {
     ASSERT(thisObject.globalObject());
     JSDOMGlobalObject& globalObject = *thisObject.globalObject();
-    return JSDOMIterator<JSWrapper>::create(globalObject.vm(), getDOMStructure<JSDOMIterator<JSWrapper>>(globalObject.vm(), globalObject), thisObject, kind);
+    return JSIterator::create(globalObject.vm(), getDOMStructure<JSIterator>(globalObject.vm(), globalObject), thisObject, kind);
 }
 
-template<typename JSWrapper>
-template<typename IteratorValue> inline typename std::enable_if<IteratorInspector<IteratorValue>::isMap, JSC::JSValue>::type
-JSDOMIterator<JSWrapper>::asJS(JSC::ExecState& state, IteratorValue& value)
+template<typename JSWrapper, typename IteratorTraits>
+template<typename IteratorValue, typename T> 
+inline typename std::enable_if<T::type == JSDOMIteratorType::Map, JSC::JSValue>::type JSDOMIterator<JSWrapper, IteratorTraits>::asJS(JSC::ExecState& state, IteratorValue& value)
 {
     ASSERT(value);
-    if (m_kind != IterationKind::KeyValue)
-        return toJS(&state, globalObject(), (m_kind == IterationKind::Key) ? value->key : value->value);
-
-    return jsPair(state, globalObject(), value->key, value->value);
+    
+    switch (m_kind) {
+    case IterationKind::Key:
+        return toJS<typename Traits::KeyType>(state, *globalObject(), value->key);
+    case IterationKind::Value:
+        return toJS<typename Traits::ValueType>(state, *globalObject(), value->value);
+    case IterationKind::KeyValue:
+        return jsPair<typename Traits::KeyType, typename Traits::ValueType>(state, *globalObject(), value->key, value->value);
+    };
+    
+    ASSERT_NOT_REACHED();
+    return { };
 }
 
-template<typename JSWrapper>
-template<typename IteratorValue> inline typename std::enable_if<IteratorInspector<IteratorValue>::isSet, JSC::JSValue>::type
-JSDOMIterator<JSWrapper>::asJS(JSC::ExecState& state, IteratorValue& value)
+template<typename JSWrapper, typename IteratorTraits>
+template<typename IteratorValue, typename T>
+inline typename std::enable_if<T::type == JSDOMIteratorType::Set, JSC::JSValue>::type JSDOMIterator<JSWrapper, IteratorTraits>::asJS(JSC::ExecState& state, IteratorValue& value)
 {
     ASSERT(value);
-    JSC::JSValue result = toJS(&state, globalObject(), *value);
-    if (m_kind != IterationKind::KeyValue)
+
+    auto globalObject = this->globalObject();
+    auto result = toJS<typename Traits::ValueType>(state, *globalObject, value);
+
+    switch (m_kind) {
+    case IterationKind::Key:
+    case IterationKind::Value:
         return result;
+    case IterationKind::KeyValue:
+        return jsPair(state, *globalObject, result, result);
+    };
 
-    return jsPair(state, globalObject(), result, result);
+    ASSERT_NOT_REACHED();
+    return { };
 }
 
-template<typename IteratorValue> typename std::enable_if<IteratorInspector<IteratorValue>::isMap, void>::type
-appendForEachArguments(JSC::ExecState& state, JSDOMGlobalObject* globalObject, JSC::MarkedArgumentBuffer& arguments, IteratorValue& value)
+template<typename JSIterator, typename IteratorValue>
+typename std::enable_if<JSIterator::Traits::type == JSDOMIteratorType::Map, void>::type appendForEachArguments(JSC::ExecState& state, JSDOMGlobalObject& globalObject, JSC::MarkedArgumentBuffer& arguments, IteratorValue& value)
 {
     ASSERT(value);
-    arguments.append(toJS(&state, globalObject, value->value));
-    arguments.append(toJS(&state, globalObject, value->key));
+    arguments.append(toJS<typename JSIterator::Traits::ValueType>(state, globalObject, value->value));
+    arguments.append(toJS<typename JSIterator::Traits::KeyType>(state, globalObject, value->key));
 }
 
-template<typename IteratorValue> typename std::enable_if<IteratorInspector<IteratorValue>::isSet, void>::type
-appendForEachArguments(JSC::ExecState& state, JSDOMGlobalObject* globalObject, JSC::MarkedArgumentBuffer& arguments, IteratorValue& value)
+template<typename JSIterator, typename IteratorValue> 
+typename std::enable_if<JSIterator::Traits::type == JSDOMIteratorType::Set, void>::type appendForEachArguments(JSC::ExecState& state, JSDOMGlobalObject& globalObject, JSC::MarkedArgumentBuffer& arguments, IteratorValue& value)
 {
     ASSERT(value);
-    JSC::JSValue argument = toJS(&state, globalObject, *value);
+    auto argument = toJS<typename JSIterator::Traits::ValueType>(state, globalObject, value);
     arguments.append(argument);
     arguments.append(argument);
 }
 
-template<typename JSWrapper>
-JSC::JSValue iteratorForEach(JSC::ExecState& state, JSWrapper& thisObject, JSC::ThrowScope& scope)
+template<typename JSIterator> JSC::JSValue iteratorForEach(JSC::ExecState& state, typename JSIterator::Wrapper& thisObject, JSC::ThrowScope& scope)
 {
     JSC::JSValue callback = state.argument(0);
     JSC::JSValue thisValue = state.argument(1);
@@ -190,7 +217,7 @@ JSC::JSValue iteratorForEach(JSC::ExecState& state, JSWrapper& thisObject, JSC::
     auto iterator = thisObject.wrapped().createIterator();
     while (auto value = iterator.next()) {
         JSC::MarkedArgumentBuffer arguments;
-        appendForEachArguments(state, thisObject.globalObject(), arguments, value);
+        appendForEachArguments<JSIterator>(state, *thisObject.globalObject(), arguments, value);
         arguments.append(&thisObject);
         JSC::call(&state, callback, callType, callData, thisValue, arguments);
         if (UNLIKELY(scope.exception()))
@@ -199,15 +226,15 @@ JSC::JSValue iteratorForEach(JSC::ExecState& state, JSWrapper& thisObject, JSC::
     return JSC::jsUndefined();
 }
 
-template<typename JSWrapper>
-void JSDOMIterator<JSWrapper>::destroy(JSCell* cell)
+template<typename JSWrapper, typename IteratorTraits>
+void JSDOMIterator<JSWrapper, IteratorTraits>::destroy(JSCell* cell)
 {
-    JSDOMIterator<JSWrapper>* thisObject = JSC::jsCast<JSDOMIterator<JSWrapper>*>(cell);
-    thisObject->JSDOMIterator<JSWrapper>::~JSDOMIterator();
+    JSDOMIterator<JSWrapper, IteratorTraits>* thisObject = JSC::jsCast<JSDOMIterator<JSWrapper, IteratorTraits>*>(cell);
+    thisObject->JSDOMIterator<JSWrapper, IteratorTraits>::~JSDOMIterator();
 }
 
-template<typename JSWrapper>
-JSC::JSValue JSDOMIterator<JSWrapper>::next(JSC::ExecState& state)
+template<typename JSWrapper, typename IteratorTraits>
+JSC::JSValue JSDOMIterator<JSWrapper, IteratorTraits>::next(JSC::ExecState& state)
 {
     if (m_iterator) {
         auto iteratorValue = m_iterator->next();
@@ -218,21 +245,21 @@ JSC::JSValue JSDOMIterator<JSWrapper>::next(JSC::ExecState& state)
     return createIteratorResultObject(&state, JSC::jsUndefined(), true);
 }
 
-template<typename JSWrapper>
-JSC::EncodedJSValue JSC_HOST_CALL JSDOMIteratorPrototype<JSWrapper>::next(JSC::ExecState* state)
+template<typename JSWrapper, typename IteratorTraits>
+JSC::EncodedJSValue JSC_HOST_CALL JSDOMIteratorPrototype<JSWrapper, IteratorTraits>::next(JSC::ExecState* state)
 {
     JSC::VM& vm = state->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
 
-    auto iterator = JSC::jsDynamicCast<JSDOMIterator<JSWrapper>*>(state->thisValue());
+    auto iterator = JSC::jsDynamicCast<JSDOMIterator<JSWrapper, IteratorTraits>*>(state->thisValue());
     if (!iterator)
         return JSC::JSValue::encode(throwTypeError(state, scope, ASCIILiteral("Cannot call next() on a non-Iterator object")));
 
     return JSC::JSValue::encode(iterator->next(*state));
 }
 
-template<typename JSWrapper>
-void JSDOMIteratorPrototype<JSWrapper>::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
+template<typename JSWrapper, typename IteratorTraits>
+void JSDOMIteratorPrototype<JSWrapper, IteratorTraits>::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
 {
     Base::finishCreation(vm);
     ASSERT(inherits(info()));
@@ -241,5 +268,3 @@ void JSDOMIteratorPrototype<JSWrapper>::finishCreation(JSC::VM& vm, JSC::JSGloba
 }
 
 }
-
-#endif // !defined(JSDOMIterator_h)
index 83b265a..77cd974 100644 (file)
@@ -4865,15 +4865,29 @@ sub GenerateImplementationIterableFunctions
 
     return unless IsKeyValueIterableInterface($interface);
 
+    my $iteratorName = "${interfaceName}Iterator";
+    my $iteratorPrototypeName = "${interfaceName}IteratorPrototype";
+
+    my $iteratorTraitsName = "${interfaceName}IteratorTraits";
+    my $iteratorTraitsType = $interface->iterable->isKeyValue ? "JSDOMIteratorType::Map" : "JSDOMIteratorType::Set";
+    my $iteratorTraitsKeyType = $interface->iterable->isKeyValue ? GetIDLType($interface, $interface->iterable->idlKeyType) : "void";
+    my $iteratorTraitsValueType = GetIDLType($interface, $interface->iterable->idlValueType);
+
     push(@implContent,  <<END);
-using ${interfaceName}Iterator = JSDOMIterator<${className}>;
-using ${interfaceName}IteratorPrototype = JSDOMIteratorPrototype<${className}>;
+struct ${iteratorTraitsName} {
+    static constexpr JSDOMIteratorType type = ${iteratorTraitsType};
+    using KeyType = ${iteratorTraitsKeyType};
+    using ValueType = ${iteratorTraitsValueType};
+};
+
+using ${iteratorName} = JSDOMIterator<${className}, ${iteratorTraitsName}>;
+using ${iteratorPrototypeName} = JSDOMIteratorPrototype<${className}, ${iteratorTraitsName}>;
 
 template<>
-const JSC::ClassInfo ${interfaceName}Iterator::s_info = { "${visibleInterfaceName} Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(${interfaceName}Iterator) };
+const JSC::ClassInfo ${iteratorName}::s_info = { "${visibleInterfaceName} Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(${iteratorName}) };
 
 template<>
-const JSC::ClassInfo ${interfaceName}IteratorPrototype::s_info = { "${visibleInterfaceName} Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(${interfaceName}IteratorPrototype) };
+const JSC::ClassInfo ${iteratorPrototypeName}::s_info = { "${visibleInterfaceName} Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(${iteratorPrototypeName}) };
 
 END
 
@@ -4885,7 +4899,7 @@ END
             push(@implContent,  <<END);
 static inline EncodedJSValue ${functionName}Caller(ExecState* state, JS$interfaceName* thisObject, JSC::ThrowScope& throwScope)
 {
-    return JSValue::encode(iteratorForEach<${className}>(*state, *thisObject, throwScope));
+    return JSValue::encode(iteratorForEach<${iteratorName}>(*state, *thisObject, throwScope));
 }
 
 END
@@ -4898,7 +4912,7 @@ END
             push(@implContent,  <<END);
 static inline EncodedJSValue ${functionName}Caller(ExecState*, JS$interfaceName* thisObject, JSC::ThrowScope&)
 {
-    return JSValue::encode(iteratorCreate<${className}>(*thisObject, IterationKind::${iterationKind}));
+    return JSValue::encode(iteratorCreate<${iteratorName}>(*thisObject, IterationKind::${iterationKind}));
 }
 
 END
@@ -5047,6 +5061,10 @@ sub GetBaseIDLType
         "DOMString" => "IDLDOMString",
         "ByteString" => "IDLByteString",
         "USVString" => "IDLUSVString",
+        
+        # Non-WebIDL extensions
+        "Date" => "IDLDate",
+        "BufferSource" => "IDLBufferSource",
     );
 
     return $IDLTypes{$idlType->name} if exists $IDLTypes{$idlType->name};
@@ -5055,7 +5073,6 @@ sub GetBaseIDLType
     return "IDLSequence<" . GetIDLType($interface, @{$idlType->subtypes}[0]) . ">" if $codeGenerator->IsSequenceType($idlType->name);
     return "IDLFrozenArray<" . GetIDLType($interface, @{$idlType->subtypes}[0]) . ">" if $codeGenerator->IsFrozenArrayType($idlType->name);
     return "IDLUnion<" . join(", ", GetIDLUnionMemberTypes($interface, $idlType)) . ">" if $idlType->isUnion;
-    return "IDLBufferSource" if $idlType->name eq "BufferSource";
     return "IDLInterface<" . $idlType->name . ">";
 }
 
@@ -5177,9 +5194,10 @@ sub JSValueToNativeIsHandledByDOMConvert
     my $idlType = shift;
 
     return 1 if $idlType->isUnion;
-    return 1 if $idlType->name eq "BufferSource";
     return 1 if $idlType->name eq "any";
     return 1 if $idlType->name eq "boolean";
+    return 1 if $idlType->name eq "Date";
+    return 1 if $idlType->name eq "BufferSource";
     return 1 if $codeGenerator->IsIntegerType($idlType->name);
     return 1 if $codeGenerator->IsFloatingPointType($idlType->name);
     return 1 if $codeGenerator->IsSequenceOrFrozenArrayType($idlType->name);
@@ -5241,7 +5259,6 @@ sub JSValueToNative
         return ("Dictionary($statePointer, $value)", 0);
     }
 
-    return ("valueToDate($statePointer, $value)", 1) if $type eq "Date";
     return ("to$type($value)", 1) if $codeGenerator->IsTypedArrayType($type);
     return ("parseEnumeration<" . GetEnumerationClassName($type, $interface) . ">($stateReference, $value)", 1) if $codeGenerator->IsEnumType($type);
 
@@ -5258,11 +5275,10 @@ sub JSValueToNative
 sub NativeToJSValueIsHandledByDOMConvert
 {
     my ($idlType) = @_;
-
-    return 0 if $idlType->isNullable && ($codeGenerator->IsStringType($idlType->name) || $codeGenerator->IsEnumType($idlType->name));
     
     return 1 if $idlType->name eq "any";
     return 1 if $idlType->name eq "boolean";
+    return 1 if $idlType->name eq "Date";
     return 1 if $codeGenerator->IsIntegerType($idlType->name);
     return 1 if $codeGenerator->IsFloatingPointType($idlType->name);
     return 1 if $codeGenerator->IsStringType($idlType->name);
@@ -5282,6 +5298,7 @@ sub NativeToJSValueDOMConvertNeedsState
     return 1 if $codeGenerator->IsSequenceOrFrozenArrayType($idlType->name);
     return 1 if $codeGenerator->IsStringType($idlType->name);
     return 1 if $codeGenerator->IsEnumType($idlType->name);
+    return 1 if $idlType->name eq "Date";
 
     return 0;
 }
@@ -5360,18 +5377,6 @@ sub NativeToJSValue
         return "toJS<$IDLType>(" . join(", ", @conversionArguments) . ")";
     }
 
-    return "toJSNullableDate($stateReference, throwScope, $value)" if $type eq "Date" && $isNullable && $mayThrowException;
-    return "jsDateOrNull($statePointer, $value)" if $type eq "Date" && $isNullable;
-    return "toJSDate($stateReference, throwScope, $value)" if $type eq "Date" && $mayThrowException;
-    return "jsDate($statePointer, $value)" if $type eq "Date";
-
-    if ($codeGenerator->IsStringType($type)) {
-        AddToImplIncludes("URL.h", $conditional);
-        return "toJSNullableString($stateReference, throwScope, $value)" if $isNullable && $mayThrowException;
-        return "jsStringOrNull($statePointer, $value)" if $isNullable;
-        assert("Unhandled string type");
-    }
-
     if ($type eq "SerializedScriptValue") {
         AddToImplIncludes("SerializedScriptValue.h", $conditional);
         return "$value ? $value->deserialize($stateReference, $globalObject) : jsNull()";
index 94cb2ce..9170cd2 100644 (file)
@@ -103,8 +103,10 @@ struct( domSignature => {
 # Used to represent Iterable interfaces
 struct( domIterable => {
     isKeyValue => '$',# Is map iterable or set iterable
-    keyType => '$',   # Key type for map iterables
-    valueType => '$', # Value type for map or set iterables
+    keyType => '$',   # Key type name for map iterables (DEPRECATED - please use idlKeyType)
+    valueType => '$', # Value type name for map or set iterables (DEPRECATED - please use idlValueType)
+    idlKeyType => '$',   # Key type for map iterables
+    idlValueType => '$', # Value type for map or set iterables
     functions => '@', # Iterable functions (entries, keys, values, [Symbol.Iterator], forEach)
     extendedAttributes => '$', # Extended attributes
 });
@@ -1514,15 +1516,21 @@ sub parseOptionalIterableInterface
     push(@{$newDataNode->functions}, $forEachFunction);
 
     $self->assertTokenValue($self->getToken(), "<", __LINE__);
-    my $type1 = $self->getToken()->value();
+    my $type1 = $self->parseType();
+
     if ($self->nextToken()->value() eq ",") {
         $self->assertTokenValue($self->getToken(), ",", __LINE__);
+
+        my $type2 = $self->parseType();
         $newDataNode->isKeyValue(1);
-        $newDataNode->keyType($type1);
-        $newDataNode->valueType($self->getToken()->value());
+        $newDataNode->idlKeyType($type1);
+        $newDataNode->keyType($type1->name);
+        $newDataNode->idlValueType($type2);
+        $newDataNode->valueType($type2->name);
     } else {
         $newDataNode->isKeyValue(0);
-        $newDataNode->valueType($type1);
+        $newDataNode->idlValueType($type1);
+        $newDataNode->valueType($type1->name);
     }
     $self->assertTokenValue($self->getToken(), ">", __LINE__);
 
index c510a9f..9affdc4 100644 (file)
@@ -163,8 +163,14 @@ JSValue JSTestIterable::getConstructor(VM& vm, const JSGlobalObject* globalObjec
     return getDOMConstructor<JSTestIterableConstructor>(vm, *jsCast<const JSDOMGlobalObject*>(globalObject));
 }
 
-using TestIterableIterator = JSDOMIterator<JSTestIterable>;
-using TestIterableIteratorPrototype = JSDOMIteratorPrototype<JSTestIterable>;
+struct TestIterableIteratorTraits {
+    static constexpr JSDOMIteratorType type = JSDOMIteratorType::Set;
+    using KeyType = void;
+    using ValueType = IDLInterface<TestNode>;
+};
+
+using TestIterableIterator = JSDOMIterator<JSTestIterable, TestIterableIteratorTraits>;
+using TestIterableIteratorPrototype = JSDOMIteratorPrototype<JSTestIterable, TestIterableIteratorTraits>;
 
 template<>
 const JSC::ClassInfo TestIterableIterator::s_info = { "TestIterable Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(TestIterableIterator) };
@@ -174,7 +180,7 @@ const JSC::ClassInfo TestIterableIteratorPrototype::s_info = { "TestIterable Ite
 
 static inline EncodedJSValue jsTestIterablePrototypeFunctionSymbolIteratorCaller(ExecState*, JSTestIterable* thisObject, JSC::ThrowScope&)
 {
-    return JSValue::encode(iteratorCreate<JSTestIterable>(*thisObject, IterationKind::Value));
+    return JSValue::encode(iteratorCreate<TestIterableIterator>(*thisObject, IterationKind::Value));
 }
 
 JSC::EncodedJSValue JSC_HOST_CALL jsTestIterablePrototypeFunctionSymbolIterator(JSC::ExecState* state)
@@ -184,7 +190,7 @@ JSC::EncodedJSValue JSC_HOST_CALL jsTestIterablePrototypeFunctionSymbolIterator(
 
 static inline EncodedJSValue jsTestIterablePrototypeFunctionEntriesCaller(ExecState*, JSTestIterable* thisObject, JSC::ThrowScope&)
 {
-    return JSValue::encode(iteratorCreate<JSTestIterable>(*thisObject, IterationKind::KeyValue));
+    return JSValue::encode(iteratorCreate<TestIterableIterator>(*thisObject, IterationKind::KeyValue));
 }
 
 JSC::EncodedJSValue JSC_HOST_CALL jsTestIterablePrototypeFunctionEntries(JSC::ExecState* state)
@@ -194,7 +200,7 @@ JSC::EncodedJSValue JSC_HOST_CALL jsTestIterablePrototypeFunctionEntries(JSC::Ex
 
 static inline EncodedJSValue jsTestIterablePrototypeFunctionKeysCaller(ExecState*, JSTestIterable* thisObject, JSC::ThrowScope&)
 {
-    return JSValue::encode(iteratorCreate<JSTestIterable>(*thisObject, IterationKind::Key));
+    return JSValue::encode(iteratorCreate<TestIterableIterator>(*thisObject, IterationKind::Key));
 }
 
 JSC::EncodedJSValue JSC_HOST_CALL jsTestIterablePrototypeFunctionKeys(JSC::ExecState* state)
@@ -204,7 +210,7 @@ JSC::EncodedJSValue JSC_HOST_CALL jsTestIterablePrototypeFunctionKeys(JSC::ExecS
 
 static inline EncodedJSValue jsTestIterablePrototypeFunctionValuesCaller(ExecState*, JSTestIterable* thisObject, JSC::ThrowScope&)
 {
-    return JSValue::encode(iteratorCreate<JSTestIterable>(*thisObject, IterationKind::Value));
+    return JSValue::encode(iteratorCreate<TestIterableIterator>(*thisObject, IterationKind::Value));
 }
 
 JSC::EncodedJSValue JSC_HOST_CALL jsTestIterablePrototypeFunctionValues(JSC::ExecState* state)
@@ -214,7 +220,7 @@ JSC::EncodedJSValue JSC_HOST_CALL jsTestIterablePrototypeFunctionValues(JSC::Exe
 
 static inline EncodedJSValue jsTestIterablePrototypeFunctionForEachCaller(ExecState* state, JSTestIterable* thisObject, JSC::ThrowScope& throwScope)
 {
-    return JSValue::encode(iteratorForEach<JSTestIterable>(*state, *thisObject, throwScope));
+    return JSValue::encode(iteratorForEach<TestIterableIterator>(*state, *thisObject, throwScope));
 }
 
 JSC::EncodedJSValue JSC_HOST_CALL jsTestIterablePrototypeFunctionForEach(JSC::ExecState* state)
index dc7f949..f769673 100644 (file)
@@ -264,8 +264,14 @@ static inline JSC::EncodedJSValue jsTestNodePrototypeFunctionTestWorkerPromiseCa
     return JSValue::encode(jsUndefined());
 }
 
-using TestNodeIterator = JSDOMIterator<JSTestNode>;
-using TestNodeIteratorPrototype = JSDOMIteratorPrototype<JSTestNode>;
+struct TestNodeIteratorTraits {
+    static constexpr JSDOMIteratorType type = JSDOMIteratorType::Set;
+    using KeyType = void;
+    using ValueType = IDLInterface<TestNode>;
+};
+
+using TestNodeIterator = JSDOMIterator<JSTestNode, TestNodeIteratorTraits>;
+using TestNodeIteratorPrototype = JSDOMIteratorPrototype<JSTestNode, TestNodeIteratorTraits>;
 
 template<>
 const JSC::ClassInfo TestNodeIterator::s_info = { "TestNode Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(TestNodeIterator) };
@@ -275,7 +281,7 @@ const JSC::ClassInfo TestNodeIteratorPrototype::s_info = { "TestNode Iterator",
 
 static inline EncodedJSValue jsTestNodePrototypeFunctionSymbolIteratorCaller(ExecState*, JSTestNode* thisObject, JSC::ThrowScope&)
 {
-    return JSValue::encode(iteratorCreate<JSTestNode>(*thisObject, IterationKind::Value));
+    return JSValue::encode(iteratorCreate<TestNodeIterator>(*thisObject, IterationKind::Value));
 }
 
 JSC::EncodedJSValue JSC_HOST_CALL jsTestNodePrototypeFunctionSymbolIterator(JSC::ExecState* state)
@@ -285,7 +291,7 @@ JSC::EncodedJSValue JSC_HOST_CALL jsTestNodePrototypeFunctionSymbolIterator(JSC:
 
 static inline EncodedJSValue jsTestNodePrototypeFunctionEntriesCaller(ExecState*, JSTestNode* thisObject, JSC::ThrowScope&)
 {
-    return JSValue::encode(iteratorCreate<JSTestNode>(*thisObject, IterationKind::KeyValue));
+    return JSValue::encode(iteratorCreate<TestNodeIterator>(*thisObject, IterationKind::KeyValue));
 }
 
 JSC::EncodedJSValue JSC_HOST_CALL jsTestNodePrototypeFunctionEntries(JSC::ExecState* state)
@@ -295,7 +301,7 @@ JSC::EncodedJSValue JSC_HOST_CALL jsTestNodePrototypeFunctionEntries(JSC::ExecSt
 
 static inline EncodedJSValue jsTestNodePrototypeFunctionKeysCaller(ExecState*, JSTestNode* thisObject, JSC::ThrowScope&)
 {
-    return JSValue::encode(iteratorCreate<JSTestNode>(*thisObject, IterationKind::Key));
+    return JSValue::encode(iteratorCreate<TestNodeIterator>(*thisObject, IterationKind::Key));
 }
 
 JSC::EncodedJSValue JSC_HOST_CALL jsTestNodePrototypeFunctionKeys(JSC::ExecState* state)
@@ -305,7 +311,7 @@ JSC::EncodedJSValue JSC_HOST_CALL jsTestNodePrototypeFunctionKeys(JSC::ExecState
 
 static inline EncodedJSValue jsTestNodePrototypeFunctionValuesCaller(ExecState*, JSTestNode* thisObject, JSC::ThrowScope&)
 {
-    return JSValue::encode(iteratorCreate<JSTestNode>(*thisObject, IterationKind::Value));
+    return JSValue::encode(iteratorCreate<TestNodeIterator>(*thisObject, IterationKind::Value));
 }
 
 JSC::EncodedJSValue JSC_HOST_CALL jsTestNodePrototypeFunctionValues(JSC::ExecState* state)
@@ -315,7 +321,7 @@ JSC::EncodedJSValue JSC_HOST_CALL jsTestNodePrototypeFunctionValues(JSC::ExecSta
 
 static inline EncodedJSValue jsTestNodePrototypeFunctionForEachCaller(ExecState* state, JSTestNode* thisObject, JSC::ThrowScope& throwScope)
 {
-    return JSValue::encode(iteratorForEach<JSTestNode>(*state, *thisObject, throwScope));
+    return JSValue::encode(iteratorForEach<TestNodeIterator>(*state, *thisObject, throwScope));
 }
 
 JSC::EncodedJSValue JSC_HOST_CALL jsTestNodePrototypeFunctionForEach(JSC::ExecState* state)
index 25f868e..69a1ec6 100644 (file)
@@ -3130,7 +3130,7 @@ static inline JSValue jsTestObjNullableStringAttributeGetter(ExecState& state, J
     UNUSED_PARAM(throwScope);
     UNUSED_PARAM(state);
     auto& impl = thisObject.wrapped();
-    JSValue result = jsStringOrNull(&state, impl.nullableStringAttribute());
+    JSValue result = toJS<IDLNullable<IDLDOMString>>(state, impl.nullableStringAttribute());
     return result;
 }
 
@@ -3162,7 +3162,7 @@ static inline JSValue jsTestObjNullableStringSettableAttributeGetter(ExecState&
     UNUSED_PARAM(throwScope);
     UNUSED_PARAM(state);
     auto& impl = thisObject.wrapped();
-    JSValue result = jsStringOrNull(&state, impl.nullableStringSettableAttribute());
+    JSValue result = toJS<IDLNullable<IDLDOMString>>(state, impl.nullableStringSettableAttribute());
     return result;
 }
 
@@ -3178,7 +3178,7 @@ static inline JSValue jsTestObjNullableUSVStringSettableAttributeGetter(ExecStat
     UNUSED_PARAM(throwScope);
     UNUSED_PARAM(state);
     auto& impl = thisObject.wrapped();
-    JSValue result = jsStringOrNull(&state, impl.nullableUSVStringSettableAttribute());
+    JSValue result = toJS<IDLNullable<IDLUSVString>>(state, impl.nullableUSVStringSettableAttribute());
     return result;
 }
 
@@ -5128,7 +5128,7 @@ static inline JSC::EncodedJSValue jsTestObjPrototypeFunctionNullableStringMethod
     UNUSED_PARAM(state);
     UNUSED_PARAM(throwScope);
     auto& impl = castedThis->wrapped();
-    JSValue result = jsStringOrNull(state, impl.nullableStringMethod());
+    JSValue result = toJS<IDLNullable<IDLDOMString>>(*state, impl.nullableStringMethod());
     return JSValue::encode(result);
 }
 
@@ -5137,7 +5137,7 @@ EncodedJSValue JSC_HOST_CALL jsTestObjConstructorFunctionNullableStringStaticMet
     VM& vm = state->vm();
     auto throwScope = DECLARE_THROW_SCOPE(vm);
     UNUSED_PARAM(throwScope);
-    JSValue result = jsStringOrNull(state, TestObj::nullableStringStaticMethod());
+    JSValue result = toJS<IDLNullable<IDLDOMString>>(*state, TestObj::nullableStringStaticMethod());
     return JSValue::encode(result);
 }
 
@@ -5157,7 +5157,7 @@ static inline JSC::EncodedJSValue jsTestObjPrototypeFunctionNullableStringSpecia
         return throwVMError(state, throwScope, createNotEnoughArgumentsError(state));
     auto index = convert<IDLUnsignedLong>(*state, state->uncheckedArgument(0), NormalConversion);
     RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
-    JSValue result = jsStringOrNull(state, impl.nullableStringSpecialMethod(WTFMove(index)));
+    JSValue result = toJS<IDLNullable<IDLDOMString>>(*state, impl.nullableStringSpecialMethod(WTFMove(index)));
     return JSValue::encode(result);
 }