Binding generator should support key value iterable
authoryouenn.fablet@crf.canon.fr <youenn.fablet@crf.canon.fr@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 22 Feb 2016 08:31:14 +0000 (08:31 +0000)
committeryouenn.fablet@crf.canon.fr <youenn.fablet@crf.canon.fr@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 22 Feb 2016 08:31:14 +0000 (08:31 +0000)
https://bugs.webkit.org/show_bug.cgi?id=154413

Reviewed by Darin Adler.

LayoutTests/imported/w3c:

* web-platform-tests/fetch/api/headers/headers-basic-expected.txt:
* web-platform-tests/fetch/api/headers/headers-basic.html:

Source/WebCore:

Covered by added layout and binding tests.

iterable<key, value> in a IDL file will trigger the generation of entries, keys, values, [Symbol.iterator] and forEach methods to the prototype.
Updated FetchHeaders and FontFaceSet to use it.

IDLParser.pm parses the iterable<> and adds an iterable field in the interface containing the iterable information and objects for the five operations.
IDLParser.pm is cleaned up a bit to remove previous Iterator support, which does not seem to be supported.

CodeGeneratorJS.pm is updated to generate the code for the five operations, using JSKeyValueIterator. Set iterators are not yet supported.
Moved definition of Iterator Key and Value Type to binding generated JSXX class based on iterable<> declaration in the IDL.

Added binding test and Fetch Headers tests.

* CMakeLists.txt:
* Modules/fetch/FetchHeaders.idl:
* WebCore.xcodeproj/project.pbxproj:
* bindings/js/JSBindingsAllInOne.cpp:
* bindings/js/JSFetchHeadersCustom.cpp: Removed.
* bindings/js/JSFontFaceSetCustom.cpp:
(WebCore::JSFontFaceSet::ready): Removed iterable custom methods.
* bindings/js/JSKeyValueIterator.h:
(WebCore::createKeyValueIterator):
(WebCore::keyValueIteratorForEach):
* bindings/scripts/CodeGeneratorJS.pm:
(GetFunctionName):
(PrototypeFunctionCount):
(PrototypePropertyCount):
(GeneratePropertiesHashTable):
(GenerateImplementation):
(GenerateImplementationFunctionCall):
(GenerateImplementationIterableFunctions):
* bindings/scripts/IDLParser.pm:
(parseOperationOrIterator):
(parseOperationOrIteratorRest):
(parseIterableRest):
(parseOptionalIterableInterface):
(applyMemberList):
(parseSpecial): Deleted.
* bindings/scripts/test/JS/JSTestObj.cpp:
(WebCore::JSTestObjPrototype::finishCreation):
(WebCore::jsTestObjPrototypeFunctionSymbolIterator):
(WebCore::jsTestObjPrototypeFunctionEntries):
(WebCore::jsTestObjPrototypeFunctionKeys):
(WebCore::jsTestObjPrototypeFunctionValues):
(WebCore::jsTestObjPrototypeFunctionForEach):
* bindings/scripts/test/TestObj.idl:
* css/FontFaceSet.idl:

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

22 files changed:
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/fetch/api/headers/headers-basic-expected.txt
LayoutTests/imported/w3c/web-platform-tests/fetch/api/headers/headers-basic.html
LayoutTests/imported/w3c/web-platform-tests/fetch/api/headers/headers-errors-expected.txt
LayoutTests/imported/w3c/web-platform-tests/fetch/api/headers/headers-errors.html
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/Modules/fetch/FetchHeaders.h
Source/WebCore/Modules/fetch/FetchHeaders.idl
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/bindings/js/JSBindingsAllInOne.cpp
Source/WebCore/bindings/js/JSFetchHeadersCustom.cpp [deleted file]
Source/WebCore/bindings/js/JSFontFaceSetCustom.cpp
Source/WebCore/bindings/js/JSKeyValueIterator.h
Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
Source/WebCore/bindings/scripts/IDLParser.pm
Source/WebCore/bindings/scripts/test/JS/JSTestObj.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestObj.h
Source/WebCore/bindings/scripts/test/TestObj.idl
Source/WebCore/css/FontFaceSet.cpp
Source/WebCore/css/FontFaceSet.h
Source/WebCore/css/FontFaceSet.idl

index 19817d3..efd7459 100644 (file)
@@ -1,3 +1,13 @@
+2016-02-22  Youenn Fablet  <youenn.fablet@crf.canon.fr>
+
+        Binding generator should support key value iterable
+        https://bugs.webkit.org/show_bug.cgi?id=154413
+
+        Reviewed by Darin Adler.
+
+        * web-platform-tests/fetch/api/headers/headers-basic-expected.txt:
+        * web-platform-tests/fetch/api/headers/headers-basic.html:
+
 2016-02-21  Chris Dumez  <cdumez@apple.com>
 
         Unreviewed, rebaseline html/dom/interfaces.html.
index 6db69ce..e297116 100644 (file)
@@ -15,4 +15,6 @@ PASS Check get method
 PASS Check keys method 
 PASS Check values method 
 PASS Check entries method 
+PASS Check Symbol.iterator method 
+PASS Check forEach method 
 
index 51ac89c..ddbb9a7 100644 (file)
         assert_true(actual.next().done);
         assert_true(actual.next().done);
       }, "Check entries method");
+
+      test(function() {
+        var headers = new Headers(headerEntriesDict);
+        var actual = headers[Symbol.iterator]();
+
+        sortedHeaderKeys.forEach(function(key) {
+            entry = actual.next();
+            assert_false(entry.done);
+            assert_equals(entry.value[0], key);
+            assert_equals(entry.value[1], sortedHeaderDict[key]);
+        });
+        assert_true(actual.next().done);
+        assert_true(actual.next().done);
+      }, "Check Symbol.iterator method");
+
+      test(function() {
+        var headers = new Headers(headerEntriesDict);
+        var reference = sortedHeaderKeys[Symbol.iterator]();
+        headers.forEach(function(value, key, container) {
+            assert_equals(headers, container);
+            entry = reference.next();
+            assert_false(entry.done);
+            assert_equals(key, entry.value);
+            assert_equals(value, sortedHeaderDict[entry.value]);
+        });
+        assert_true(reference.next().done);
+      }, "Check forEach method");
    </script>
   </body>
 </html>
index 6f3c53a..ef094c0 100644 (file)
@@ -15,4 +15,6 @@ PASS Check headers set with an invalid value invalidÄ€
 PASS Check headers append with an invalid name invalidÄ€ 
 PASS Check headers append with an invalid name [object Object] 
 PASS Check headers append with an invalid value invalidÄ€ 
+PASS Headers forEach throws if argument is not callable 
+PASS Headers forEach loop should stop if callback is throwing exception 
 
index 5f5eef2..194ff32 100644 (file)
           assert_throws(new TypeError() , function() { headers.append("name", value); });
         }, "Check headers append with an invalid value " + value);
       });
-    </script>
+
+      test(function() {
+        var headers = new Headers([["name", "value"]]);
+        assert_throws(new TypeError() , function() { headers.forEach(); });
+        assert_throws(new TypeError() , function() { headers.forEach(undefined); });
+        assert_throws(new TypeError() , function() { headers.forEach(1); });
+      }, "Headers forEach throws if argument is not callable");
+
+      test(function() {
+        var headers = new Headers([["name1", "value1"], ["name2", "value2"], ["name3", "value3"]]);
+        var counter = 0;
+        try {
+            headers.forEach(function(value, name) {
+                counter++;
+                if (name == "name2")
+                     throw "error";
+            });
+        } catch (e) {
+            assert_equals(counter, 2);
+            assert_equals(e, "error");
+            return;
+        }
+        assert_unreached();
+      }, "Headers forEach loop should stop if callback is throwing exception");
+   </script>
   </body>
 </html>
index c5a6449..9df01d0 100644 (file)
@@ -1161,7 +1161,6 @@ set(WebCore_SOURCES
     bindings/js/JSEventListener.cpp
     bindings/js/JSEventTargetCustom.cpp
     bindings/js/JSExceptionBase.cpp
-    bindings/js/JSFetchHeadersCustom.cpp
     bindings/js/JSFileReaderCustom.cpp
     bindings/js/JSGeolocationCustom.cpp
     bindings/js/JSHTMLAllCollectionCustom.cpp
index ae264e6..f741933 100644 (file)
@@ -1,3 +1,58 @@
+2016-02-22  Youenn Fablet  <youenn.fablet@crf.canon.fr>
+
+        Binding generator should support key value iterable
+        https://bugs.webkit.org/show_bug.cgi?id=154413
+
+        Reviewed by Darin Adler.
+
+        Covered by added layout and binding tests.
+
+        iterable<key, value> in a IDL file will trigger the generation of entries, keys, values, [Symbol.iterator] and forEach methods to the prototype.
+        Updated FetchHeaders and FontFaceSet to use it.
+
+        IDLParser.pm parses the iterable<> and adds an iterable field in the interface containing the iterable information and objects for the five operations.
+        IDLParser.pm is cleaned up a bit to remove previous Iterator support, which does not seem to be supported.
+
+        CodeGeneratorJS.pm is updated to generate the code for the five operations, using JSKeyValueIterator. Set iterators are not yet supported.
+        Moved definition of Iterator Key and Value Type to binding generated JSXX class based on iterable<> declaration in the IDL.
+
+        Added binding test and Fetch Headers tests.
+
+        * CMakeLists.txt:
+        * Modules/fetch/FetchHeaders.idl:
+        * WebCore.xcodeproj/project.pbxproj:
+        * bindings/js/JSBindingsAllInOne.cpp:
+        * bindings/js/JSFetchHeadersCustom.cpp: Removed.
+        * bindings/js/JSFontFaceSetCustom.cpp:
+        (WebCore::JSFontFaceSet::ready): Removed iterable custom methods.
+        * bindings/js/JSKeyValueIterator.h:
+        (WebCore::createKeyValueIterator):
+        (WebCore::keyValueIteratorForEach):
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GetFunctionName):
+        (PrototypeFunctionCount):
+        (PrototypePropertyCount):
+        (GeneratePropertiesHashTable):
+        (GenerateImplementation):
+        (GenerateImplementationFunctionCall):
+        (GenerateImplementationIterableFunctions):
+        * bindings/scripts/IDLParser.pm:
+        (parseOperationOrIterator):
+        (parseOperationOrIteratorRest):
+        (parseIterableRest):
+        (parseOptionalIterableInterface):
+        (applyMemberList):
+        (parseSpecial): Deleted.
+        * bindings/scripts/test/JS/JSTestObj.cpp:
+        (WebCore::JSTestObjPrototype::finishCreation):
+        (WebCore::jsTestObjPrototypeFunctionSymbolIterator):
+        (WebCore::jsTestObjPrototypeFunctionEntries):
+        (WebCore::jsTestObjPrototypeFunctionKeys):
+        (WebCore::jsTestObjPrototypeFunctionValues):
+        (WebCore::jsTestObjPrototypeFunctionForEach):
+        * bindings/scripts/test/TestObj.idl:
+        * css/FontFaceSet.idl:
+
 2016-02-21  Chris Dumez  <cdumez@apple.com>
 
         HTMLScriptElement.crossOrigin / HTMLImageElement.crossOrigin should only return known values
index f3581d3..57ff73f 100644 (file)
@@ -65,11 +65,6 @@ public:
     class Iterator {
     public:
         explicit Iterator(FetchHeaders&);
-
-        // FIXME: Binding generator should be able to generate iterator key and value types.
-        using Key = String;
-        using Value = String;
-
         bool next(String& nextKey, String& nextValue);
 
     private:
index f633397..f237a78 100644 (file)
@@ -40,11 +40,7 @@ interface FetchHeaders {
     [RaisesException] boolean has(DOMString name);
     [RaisesException] void set(DOMString name, DOMString value);
 
-    // FIXME: Support iterable within binding generator.
-    //iterable<DOMString, DOMString>;
-    [Custom] any entries();
-    [Custom] any keys();
-    [Custom] any values();
+    iterable<DOMString, DOMString>;
 
     [Private, RaisesException, ImplementedAs=append] void appendFromJS(DOMString name, DOMString value);
     [Private, RaisesException] void initializeWith(FetchHeaders headers);
index 9ce0d73..66a614e 100644 (file)
                41D015CB0F4B5C71004A662F /* ContentType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41D015C90F4B5C71004A662F /* ContentType.cpp */; };
                41E1B1D00FF5986900576B3B /* AbstractWorker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41E1B1CA0FF5986900576B3B /* AbstractWorker.cpp */; };
                41E1B1D10FF5986900576B3B /* AbstractWorker.h in Headers */ = {isa = PBXBuildFile; fileRef = 41E1B1CB0FF5986900576B3B /* AbstractWorker.h */; };
-               41E910A71C60FD6C007A453F /* JSFetchHeadersCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41E910A61C60FD6C007A453F /* JSFetchHeadersCustom.cpp */; };
                41F062140F5F192600A07EAC /* InspectorDatabaseResource.h in Headers */ = {isa = PBXBuildFile; fileRef = 41F062120F5F192600A07EAC /* InspectorDatabaseResource.h */; };
                41F062150F5F192600A07EAC /* InspectorDatabaseResource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41F062130F5F192600A07EAC /* InspectorDatabaseResource.cpp */; };
                41F066E40F64BCF600A07EAC /* ScriptGlobalObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 41F066E20F64BCF600A07EAC /* ScriptGlobalObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
                41E1B1CA0FF5986900576B3B /* AbstractWorker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AbstractWorker.cpp; sourceTree = "<group>"; };
                41E1B1CB0FF5986900576B3B /* AbstractWorker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AbstractWorker.h; sourceTree = "<group>"; };
                41E1B1CC0FF5986900576B3B /* AbstractWorker.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AbstractWorker.idl; sourceTree = "<group>"; };
-               41E910A61C60FD6C007A453F /* JSFetchHeadersCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSFetchHeadersCustom.cpp; sourceTree = "<group>"; };
                41F062120F5F192600A07EAC /* InspectorDatabaseResource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorDatabaseResource.h; sourceTree = "<group>"; };
                41F062130F5F192600A07EAC /* InspectorDatabaseResource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorDatabaseResource.cpp; sourceTree = "<group>"; };
                41F066E20F64BCF600A07EAC /* ScriptGlobalObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptGlobalObject.h; sourceTree = "<group>"; };
                                BC2ED5540C6B9BD300920BFF /* JSElementCustom.cpp */,
                                ADEC78F718EE5308001315C2 /* JSElementCustom.h */,
                                BCEFAF4D0C317E6900FA81F6 /* JSEventCustom.cpp */,
-                               41E910A61C60FD6C007A453F /* JSFetchHeadersCustom.cpp */,
                                2E7582ED12764F260062628B /* JSFileReaderCustom.cpp */,
                                FE80D7A60E9C1ED2000D6F75 /* JSGeolocationCustom.cpp */,
                                BCE7B1920D4E86960075A539 /* JSHistoryCustom.cpp */,
                                97B38E28151C4273004622E9 /* DOMWindowNotifications.cpp in Sources */,
                                97D2AD0314B823A60093DF32 /* DOMWindowProperty.cpp in Sources */,
                                AA2A5AD716A4861A00975A25 /* DOMWindowSpeechSynthesis.cpp in Sources */,
-                               41E910A71C60FD6C007A453F /* JSFetchHeadersCustom.cpp in Sources */,
                                A8CCBB48151F831600AB7CE9 /* DOMWindowWebDatabase.cpp in Sources */,
                                BC53DA481143134D000D817E /* DOMWrapperWorld.cpp in Sources */,
                                1A1D13810A5325520064BF5F /* DOMXPath.mm in Sources */,
index 7e23f05..dd47901 100644 (file)
@@ -77,7 +77,6 @@
 #include "JSEventListener.cpp"
 #include "JSEventTargetCustom.cpp"
 #include "JSExceptionBase.cpp"
-#include "JSFetchHeadersCustom.cpp"
 #include "JSFileReaderCustom.cpp"
 #include "JSGeolocationCustom.cpp"
 #include "JSHTMLAllCollectionCustom.cpp"
diff --git a/Source/WebCore/bindings/js/JSFetchHeadersCustom.cpp b/Source/WebCore/bindings/js/JSFetchHeadersCustom.cpp
deleted file mode 100644 (file)
index 2582cbf..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2016 Canon Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted, provided that the following conditions
- * are required to be met:
- *
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- * 3.  Neither the name of Canon Inc. nor the names of
- *     its contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY CANON INC. AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL CANON INC. AND ITS CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "JSFetchHeaders.h"
-
-#if ENABLE(FETCH_API)
-
-#include "JSKeyValueIterator.h"
-
-namespace WebCore {
-
-// FIXME: Move this code to JSFetchHeaders.
-using FetchHeadersIterator = JSKeyValueIterator<JSFetchHeaders>;
-using FetchHeadersIteratorPrototype = JSKeyValueIteratorPrototype<JSFetchHeaders>;
-
-template<>
-const JSC::ClassInfo FetchHeadersIterator::s_info = { "Headers Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(FetchHeadersIterator) };
-
-template<>
-const JSC::ClassInfo FetchHeadersIteratorPrototype::s_info = { "Headers Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(FetchHeadersIteratorPrototype) };
-
-JSC::JSValue JSFetchHeaders::entries(JSC::ExecState&)
-{
-    return createIterator<JSFetchHeaders>(*globalObject(), *this, IterationKind::KeyValue);
-}
-
-JSC::JSValue JSFetchHeaders::keys(JSC::ExecState&)
-{
-    return createIterator<JSFetchHeaders>(*globalObject(), *this, IterationKind::Key);
-}
-
-JSC::JSValue JSFetchHeaders::values(JSC::ExecState&)
-{
-    return createIterator<JSFetchHeaders>(*globalObject(), *this, IterationKind::Value);
-}
-
-}
-
-#endif
index cd84985..9a3ad30 100644 (file)
 
 namespace WebCore {
 
-using FontFaceSetIterator = JSKeyValueIterator<JSFontFaceSet>;
-using FontFaceSetIteratorPrototype = JSKeyValueIteratorPrototype<JSFontFaceSet>;
-
-template<>
-const JSC::ClassInfo FontFaceSetIterator::s_info = { "Font Face Set Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(FontFaceSetIterator) };
-
-template<>
-const JSC::ClassInfo FontFaceSetIteratorPrototype::s_info = { "Font Face Set Iterator Prototype", &Base::s_info, 0, CREATE_METHOD_TABLE(FontFaceSetIteratorPrototype) };
-
 JSC::JSValue JSFontFaceSet::ready(JSC::ExecState& execState) const
 {
     auto& promise = wrapped().promise(execState);
     return promise.deferred().promise();
 }
 
-JSC::JSValue JSFontFaceSet::entries(JSC::ExecState&)
-{
-    return createIterator<JSFontFaceSet>(*globalObject(), *this, IterationKind::KeyValue);
-}
-
-JSC::JSValue JSFontFaceSet::keys(JSC::ExecState&)
-{
-    return createIterator<JSFontFaceSet>(*globalObject(), *this, IterationKind::Key);
-}
-
-JSC::JSValue JSFontFaceSet::values(JSC::ExecState&)
-{
-    return createIterator<JSFontFaceSet>(*globalObject(), *this, IterationKind::Value);
-}
-
 }
index fbbffd0..067bb96 100644 (file)
@@ -105,9 +105,40 @@ private:
 };
 
 template<typename JSWrapper>
-JSKeyValueIterator<JSWrapper>* createIterator(JSDOMGlobalObject& globalObject, JSWrapper& wrapper, IterationKind kind)
+JSC::EncodedJSValue createKeyValueIterator(JSC::ExecState& state, IterationKind kind, const char* propertyName)
 {
-    return JSKeyValueIterator<JSWrapper>::create(globalObject.vm(), getDOMStructure<JSKeyValueIterator<JSWrapper>>(globalObject.vm(), globalObject), wrapper, kind);
+    auto wrapper = JSC::jsDynamicCast<JSWrapper*>(state.thisValue());
+    if (UNLIKELY(!wrapper))
+        return throwThisTypeError(state, JSWrapper::info()->className, propertyName);
+    JSDOMGlobalObject& globalObject = *wrapper->globalObject();
+    return JSC::JSValue::encode(JSKeyValueIterator<JSWrapper>::create(globalObject.vm(), getDOMStructure<JSKeyValueIterator<JSWrapper>>(globalObject.vm(), globalObject), *wrapper, kind));
+}
+
+template<typename JSWrapper>
+JSC::EncodedJSValue keyValueIteratorForEach(JSC::ExecState& state, const char* propertyName)
+{
+    auto wrapper = JSC::jsDynamicCast<JSWrapper*>(state.thisValue());
+    if (UNLIKELY(!wrapper))
+        return throwThisTypeError(state, JSWrapper::info()->className, propertyName);
+
+    JSC::CallData callData;
+    JSC::CallType callType = JSC::getCallData(state.argument(0), callData);
+    if (callType == JSC::CallTypeNone)
+        return throwVMTypeError(&state);
+
+    typename JSWrapper::IteratorKey nextKey;
+    typename JSWrapper::IteratorValue nextValue;
+    auto iterator = wrapper->wrapped().createIterator();
+    while (!iterator.next(nextKey, nextValue)) {
+        JSC::MarkedArgumentBuffer arguments;
+        arguments.append(toJS(&state, wrapper->globalObject(), nextValue));
+        arguments.append(toJS(&state, wrapper->globalObject(), nextKey));
+        arguments.append(wrapper);
+        JSC::call(&state, state.argument(0), callType, callData, wrapper, arguments);
+        if (state.hadException())
+            break;
+    } 
+    return JSC::JSValue::encode(JSC::jsUndefined());
 }
 
 template<typename JSWrapper>
@@ -120,8 +151,8 @@ void JSKeyValueIterator<JSWrapper>::destroy(JSCell* cell)
 template<typename JSWrapper>
 bool JSKeyValueIterator<JSWrapper>::next(JSC::ExecState& state, JSC::JSValue& value)
 {
-    typename DOMWrapped::Iterator::Key nextKey;
-    typename DOMWrapped::Iterator::Value nextValue;
+    typename JSWrapper::IteratorKey nextKey;
+    typename JSWrapper::IteratorValue nextValue;
     if (m_iterator.next(nextKey, nextValue)) {
         value = JSC::jsUndefined();
         return true;
index 7075342..fc09187 100644 (file)
@@ -11,7 +11,7 @@
 # Copyright (C) 2012 Ericsson AB. All rights reserved.
 # Copyright (C) 2007, 2008, 2009, 2012 Google Inc.
 # Copyright (C) 2013 Samsung Electronics. All rights reserved.
-# Copyright (C) 2015 Canon Inc. All rights reserved.
+# Copyright (C) 2015, 2016 Canon Inc. All rights reserved.
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Library General Public
@@ -605,8 +605,11 @@ sub GetFunctionName
         return GetJSBuiltinFunctionName($className, $function);
     }
 
+    my $functionName = $function->signature->name;
+    $functionName = "SymbolIterator" if $functionName eq "[Symbol.Iterator]";
+
     my $kind = $function->isStatic ? "Constructor" : (OperationShouldBeOnInstance($interface, $function) ? "Instance" : "Prototype");
-    return $codeGenerator->WK_lcfirst($className) . $kind . "Function" . $codeGenerator->WK_ucfirst($function->signature->name);
+    return $codeGenerator->WK_lcfirst($className) . $kind . "Function" . $codeGenerator->WK_ucfirst($functionName);
 }
 
 sub GetSpecialAccessorFunctionForType
@@ -764,6 +767,8 @@ sub PrototypeFunctionCount
         $count++ if !$function->isStatic && !OperationShouldBeOnInstance($interface, $function);
     }
 
+    $count += scalar @{$interface->iterable->functions} if $interface->iterable;
+
     return $count;
 }
 
@@ -1045,6 +1050,16 @@ sub GenerateHeader
         push(@headerContent, "    static void destroy(JSC::JSCell*);\n");
     }
 
+    if ($interface->iterable) {
+        push(@headerContent, "\n");
+        if ($interface->iterable->keyType) {
+            my $keyType = GetNativeType($interface->iterable->keyType);
+            push(@headerContent, "    using IteratorKey = $keyType;\n");
+        }
+        my $valueType = GetNativeType($interface->iterable->valueType);
+        push(@headerContent, "    using IteratorValue = $valueType;\n");
+    }
+
     # Class info
     if ($interfaceName eq "Node") {
         push(@headerContent, "\n");
@@ -1419,11 +1434,15 @@ sub GeneratePropertiesHashTable
         }
     }
 
-    foreach my $function (@{$interface->functions}) {
+    my @functions = @{$interface->functions};
+    push(@functions, @{$interface->iterable->functions}) if $interface->iterable;
+    foreach my $function (@functions) {
         next if ($function->signature->extendedAttributes->{"Private"});
         next if ($function->isStatic);
         next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
         next if OperationShouldBeOnInstance($interface, $function) != $isInstance;
+        next if $function->signature->name eq "[Symbol.Iterator]";
+
         my $name = $function->signature->name;
         push(@$hashKeys, $name);
 
@@ -1829,14 +1848,17 @@ sub GenerateImplementation
     push(@implContent, "\nusing namespace JSC;\n\n");
     push(@implContent, "namespace WebCore {\n\n");
 
+    my @functions = @{$interface->functions};
+    push(@functions, @{$interface->iterable->functions}) if $interface->iterable;
+
     my $numConstants = @{$interface->constants};
-    my $numFunctions = @{$interface->functions};
+    my $numFunctions = @functions;
     my $numAttributes = @{$interface->attributes};
 
     if ($numFunctions > 0) {
         my $inAppleCopyright = 0;
         push(@implContent,"// Functions\n\n");
-        foreach my $function (@{$interface->functions}) {
+        foreach my $function (@functions) {
             next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
             next if $function->signature->extendedAttributes->{"ForwardDeclareInHeader"};
             next if $function->signature->extendedAttributes->{"CustomBinding"};
@@ -2117,6 +2139,11 @@ sub GenerateImplementation
                 push(@implContent, "    putDirect(vm, clientData.builtinNames()." . $function->signature->name . "PrivateName(), JSFunction::create(vm, globalObject(), 0, String(), " . GetFunctionName($interface, $className, $function) . "), ReadOnly | DontEnum);\n");
             }
 
+            if ($interface->iterable) {
+                my $functionName = GetFunctionName($interface, $className, @{$interface->iterable->functions}[0]);
+                push(@implContent, "    putDirect(vm, vm.propertyNames->iteratorSymbol, JSFunction::create(vm, globalObject(), 0, ASCIILiteral(\"[Symbol.Iterator]\"), $functionName), ReadOnly | DontEnum);\n");
+            }
+
             push(@implContent, "}\n\n");
         } else {
             push(@implContent, "void ${className}Prototype::finishCreation(VM& vm)\n");
@@ -2984,6 +3011,10 @@ sub GenerateImplementation
 
     }
 
+    if ($interface->iterable) {
+        GenerateImplementationIterableFunctions($interface);
+    }
+
     if ($needsVisitChildren) {
         push(@implContent, "void ${className}::visitChildren(JSCell* cell, SlotVisitor& visitor)\n");
         push(@implContent, "{\n");
@@ -3916,6 +3947,59 @@ sub GenerateImplementationFunctionCall()
     }
 }
 
+sub GenerateImplementationIterableFunctions
+{
+    my $interface = shift;
+
+    if (not $interface->iterable->isKeyValue) {
+        die "No support yet for set iterators";
+    }
+
+    my $interfaceName = $interface->name;
+    my $className = "JS$interfaceName";
+    my $visibleInterfaceName = $codeGenerator->GetVisibleInterfaceName($interface);
+
+    AddToImplIncludes("JSKeyValueIterator.h");
+
+    push(@implContent,  <<END);
+using ${interfaceName}Iterator = JSKeyValueIterator<${className}>;
+using ${interfaceName}IteratorPrototype = JSKeyValueIteratorPrototype<${className}>;
+
+template<>
+const JSC::ClassInfo ${interfaceName}Iterator::s_info = { "${visibleInterfaceName} Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(${interfaceName}Iterator) };
+
+template<>
+const JSC::ClassInfo ${interfaceName}IteratorPrototype::s_info = { "${visibleInterfaceName} Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(${interfaceName}IteratorPrototype) };
+
+END
+
+    foreach my $function (@{$interface->iterable->functions}) {
+        my $propertyName = $function->signature->name;
+        my $functionName = GetFunctionName($interface, $className, $function);
+
+        if (not $propertyName eq "forEach") {
+            my $iterationKind = "KeyValue";
+            $iterationKind = "Key" if $propertyName eq "keys";
+            $iterationKind = "Value" if $propertyName eq "values";
+            push(@implContent,  <<END);
+JSC::EncodedJSValue JSC_HOST_CALL ${functionName}(JSC::ExecState* state)
+{
+    return createKeyValueIterator<${className}>(*state, IterationKind::${iterationKind}, "${propertyName}");
+}
+
+END
+        } else {
+            push(@implContent,  <<END);
+JSC::EncodedJSValue JSC_HOST_CALL ${functionName}(JSC::ExecState* state)
+{
+    return keyValueIteratorForEach<${className}>(*state, "${propertyName}");
+}
+
+END
+        }
+    }
+}
+
 sub GetNativeTypeFromSignature
 {
     my $signature = shift;
index 4727cf7..470054e 100644 (file)
@@ -55,6 +55,7 @@ struct( domInterface => {
     isException => '$', # Used for exception interfaces
     isCallback => '$', # Used for callback interfaces
     isPartial => '$', # Used for partial interfaces
+    iterable => '$', # Used for iterable interfaces
 });
 
 # Used to represent domInterface contents (name of method, signature)
@@ -85,6 +86,15 @@ struct( domSignature => {
     default => '$', # Default value for parameters
 });
 
+# 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
+    functions => '@', # Iterable functions (entries, keys, values, [Symbol.Iterator], forEach)
+});
+
+
 # Used to represent string constants
 struct( domConstant => {
     name => '$',      # DOM Constant identifier
@@ -325,9 +335,8 @@ my $nextPrimitiveType_2 = '^(double|float|unrestricted)$';
 my $nextArgumentList_1 = '^(\(|::|ByteString|DOMString|Date|\[|any|boolean|byte|double|float|in|int|long|object|octet|optional|sequence|short|unrestricted|unsigned)$';
 my $nextNonAnyType_1 = '^(boolean|byte|double|float|int|long|octet|short|unrestricted|unsigned)$';
 my $nextInterfaceMember_1 = '^(\(|::|ByteString|DOMString|Date|any|attribute|boolean|byte|creator|deleter|double|float|getter|inherit|int|legacycaller|long|object|octet|readonly|sequence|serializer|setter|short|static|stringifier|unrestricted|unsigned|void)$';
-my $nextOptionalIteratorInterfaceOrObject_1 = '^(;|=)$';
-my $nextAttributeOrOperationOrIterator_1 = '^(static|stringifier)$';
-my $nextAttributeOrOperationOrIterator_2 = '^(\(|::|ByteString|DOMString|Date|any|boolean|byte|creator|deleter|double|float|getter|int|legacycaller|long|object|octet|sequence|setter|short|unrestricted|unsigned|void)$';
+my $nextAttributeOrOperation_1 = '^(static|stringifier)$';
+my $nextAttributeOrOperation_2 = '^(\(|::|ByteString|DOMString|Date|any|boolean|byte|creator|deleter|double|float|getter|int|legacycaller|long|object|octet|sequence|setter|short|unrestricted|unsigned|void)$';
 my $nextUnrestrictedFloatType_1 = '^(double|float)$';
 my $nextExtendedAttributeRest3_1 = '^(\,|::|\])$';
 my $nextExceptionField_1 = '^(\(|::|ByteString|DOMString|Date|any|boolean|byte|double|float|int|long|object|octet|sequence|short|unrestricted|unsigned)$';
@@ -961,7 +970,7 @@ sub parseAttributeOrOperationOrIterator
     if ($next->value() eq "serializer") {
         return $self->parseSerializer($extendedAttributeList);
     }
-    if ($next->value() =~ /$nextAttributeOrOperationOrIterator_1/) {
+    if ($next->value() =~ /$nextAttributeOrOperation_1/) {
         my $qualifier = $self->parseQualifier();
         my $newDataNode = $self->parseAttributeOrOperationRest($extendedAttributeList);
         if (defined($newDataNode) && $qualifier eq "static") {
@@ -972,7 +981,7 @@ sub parseAttributeOrOperationOrIterator
     if ($next->value() =~ /$nextAttribute_1/) {
         return $self->parseAttribute($extendedAttributeList);
     }
-    if ($next->type() == IdentifierToken || $next->value() =~ /$nextAttributeOrOperationOrIterator_2/) {
+    if ($next->type() == IdentifierToken || $next->value() =~ /$nextAttributeOrOperation_2/) {
         return $self->parseOperationOrIterator($extendedAttributeList);
     }
     $self->assertUnexpectedToken($next->value(), __LINE__);
@@ -1206,13 +1215,17 @@ sub parseOperationOrIterator
     if ($next->value() =~ /$nextSpecials_1/) {
         return $self->parseSpecialOperation($extendedAttributeList);
     }
+    if ($next->value() eq "iterable") {
+        return $self->parseIterableRest($extendedAttributeList);
+    }
     if ($next->type() == IdentifierToken || $next->value() =~ /$nextAttributeOrOperationRest_1/) {
         my $returnType = $self->parseReturnType();
-        my $interface = $self->parseOperationOrIteratorRest($extendedAttributeList);
-        if (defined ($interface)) {
-            $interface->signature->type($returnType);
+        my $next = $self->nextToken();
+        if ($next->type() == IdentifierToken || $next->value() eq "(") {
+            my $operation = $self->parseOperationRest($extendedAttributeList);
+            $operation->signature->type($returnType);
+            return $operation;
         }
-        return $interface;
     }
     $self->assertUnexpectedToken($next->value(), __LINE__);
 }
@@ -1280,62 +1293,76 @@ sub parseSpecial
     $self->assertUnexpectedToken($next->value(), __LINE__);
 }
 
-sub parseOperationOrIteratorRest
+sub parseIterableRest
 {
     my $self = shift;
     my $extendedAttributeList = shift;
 
     my $next = $self->nextToken();
-    if ($next->value() eq "iterator") {
-        return $self->parseIteratorRest($extendedAttributeList);
-    }
-    if ($next->type() == IdentifierToken || $next->value() eq "(") {
-        return $self->parseOperationRest($extendedAttributeList);
-    }
-    $self->assertUnexpectedToken($next->value(), __LINE__);
-}
-
-sub parseIteratorRest
-{
-    my $self = shift;
-    my $extendedAttributeList = shift;
-
-    my $next = $self->nextToken();
-    if ($next->value() eq "iterator") {
-        $self->assertTokenValue($self->getToken(), "iterator", __LINE__);
-        $self->parseOptionalIteratorInterfaceOrObject($extendedAttributeList);
+    if ($next->value() eq "iterable") {
+        $self->assertTokenValue($self->getToken(), "iterable", __LINE__);
+        my $iterableNode = $self->parseOptionalIterableInterface($extendedAttributeList);
         $self->assertTokenValue($self->getToken(), ";", __LINE__);
-        return;
+        return $iterableNode;
     }
     $self->assertUnexpectedToken($next->value(), __LINE__);
 }
 
-sub parseOptionalIteratorInterfaceOrObject
+sub parseOptionalIterableInterface
 {
     my $self = shift;
     my $extendedAttributeList = shift;
 
-    my $next = $self->nextToken();
-    if ($next->value() =~ /$nextOptionalIteratorInterfaceOrObject_1/) {
-        return $self->parseOptionalIteratorInterface($extendedAttributeList);
-    }
-    if ($next->value() eq "object") {
-        $self->assertTokenValue($self->getToken(), "object", __LINE__);
-        return;
+    my $symbolIteratorFunction = domFunction->new();
+    $symbolIteratorFunction->signature(domSignature->new());
+    $symbolIteratorFunction->signature->extendedAttributes($extendedAttributeList);
+    $symbolIteratorFunction->signature->name("[Symbol.Iterator]");
+
+    my $entriesFunction = domFunction->new();
+    $entriesFunction->signature(domSignature->new());
+    $entriesFunction->signature->extendedAttributes($extendedAttributeList);
+    $entriesFunction->signature->name("entries");
+
+    my $keysFunction = domFunction->new();
+    $keysFunction->signature(domSignature->new());
+    $keysFunction->signature->extendedAttributes($extendedAttributeList);
+    $keysFunction->signature->name("keys");
+
+    my $valuesFunction = domFunction->new();
+    $valuesFunction->signature(domSignature->new());
+    $valuesFunction->signature->extendedAttributes($extendedAttributeList);
+    $valuesFunction->signature->name("values");
+
+    my $forEachFunction = domFunction->new();
+    $forEachFunction->signature(domSignature->new());
+    $forEachFunction->signature->extendedAttributes($extendedAttributeList);
+    $forEachFunction->signature->name("forEach");
+    my $forEachArgument = domSignature->new();
+    $forEachArgument->name("callback");
+    $forEachArgument->type("any");
+    push(@{$forEachFunction->parameters}, ($forEachArgument));
+
+    my $newDataNode = domIterable->new();
+    push(@{$newDataNode->functions}, $symbolIteratorFunction);
+    push(@{$newDataNode->functions}, $entriesFunction);
+    push(@{$newDataNode->functions}, $keysFunction);
+    push(@{$newDataNode->functions}, $valuesFunction);
+    push(@{$newDataNode->functions}, $forEachFunction);
+
+    $self->assertTokenValue($self->getToken(), "<", __LINE__);
+    my $type1 = $self->getToken()->value();
+    if ($self->nextToken()->value() eq ",") {
+        $self->assertTokenValue($self->getToken(), ",", __LINE__);
+        $newDataNode->isKeyValue(1);
+        $newDataNode->keyType($type1);
+        $newDataNode->valueType($self->getToken()->value());
+    } else {
+        $newDataNode->isKeyValue(0);
+        $newDataNode->valueType($type1);
     }
-    $self->assertUnexpectedToken($next->value(), __LINE__);
-}
-
-sub parseOptionalIteratorInterface
-{
-    my $self = shift;
-    my $extendedAttributeList = shift;
+    $self->assertTokenValue($self->getToken(), ">", __LINE__);
 
-    my $next = $self->nextToken();
-    if ($next->value() eq "=") {
-        $self->assertTokenValue($self->getToken(), "=", __LINE__);
-        $self->assertTokenType($self->getToken(), IdentifierToken);
-    }
+    return $newDataNode;
 }
 
 sub parseOperationRest
@@ -2177,6 +2204,10 @@ sub applyMemberList
             push(@{$interface->constants}, $item);
             next;
         }
+        if (ref($item) eq "domIterable") {
+            $interface->iterable($item);
+            next;
+        }
         if (ref($item) eq "domFunction") {
             if ($item->signature->name eq "") {
                 push(@{$interface->anonymousFunctions}, $item);
index a0c7ef8..96a0dfc 100644 (file)
@@ -34,6 +34,7 @@
 #include "JSDOMStringList.h"
 #include "JSDocument.h"
 #include "JSEventListener.h"
+#include "JSKeyValueIterator.h"
 #include "JSNode.h"
 #include "JSSVGDocument.h"
 #include "JSSVGPoint.h"
@@ -179,6 +180,11 @@ JSC::EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionTestPromiseFunction(
 JSC::EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionTestPromiseFunctionWithFloatArgument(JSC::ExecState*);
 JSC::EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionTestPromiseFunctionWithException(JSC::ExecState*);
 JSC::EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionTestPromiseFunctionWithOptionalIntArgument(JSC::ExecState*);
+JSC::EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionSymbolIterator(JSC::ExecState*);
+JSC::EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionEntries(JSC::ExecState*);
+JSC::EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionKeys(JSC::ExecState*);
+JSC::EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionValues(JSC::ExecState*);
+JSC::EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionForEach(JSC::ExecState*);
 
 // Attributes
 
@@ -695,6 +701,10 @@ static const HashTableValue JSTestObjPrototypeTableValues[] =
     { "testPromiseFunctionWithFloatArgument", JSC::Function, NoIntrinsic, { (intptr_t)static_cast<NativeFunction>(jsTestObjPrototypeFunctionTestPromiseFunctionWithFloatArgument), (intptr_t) (1) } },
     { "testPromiseFunctionWithException", JSC::Function, NoIntrinsic, { (intptr_t)static_cast<NativeFunction>(jsTestObjPrototypeFunctionTestPromiseFunctionWithException), (intptr_t) (0) } },
     { "testPromiseFunctionWithOptionalIntArgument", JSC::Function, NoIntrinsic, { (intptr_t)static_cast<NativeFunction>(jsTestObjPrototypeFunctionTestPromiseFunctionWithOptionalIntArgument), (intptr_t) (0) } },
+    { "entries", JSC::Function, NoIntrinsic, { (intptr_t)static_cast<NativeFunction>(jsTestObjPrototypeFunctionEntries), (intptr_t) (0) } },
+    { "keys", JSC::Function, NoIntrinsic, { (intptr_t)static_cast<NativeFunction>(jsTestObjPrototypeFunctionKeys), (intptr_t) (0) } },
+    { "values", JSC::Function, NoIntrinsic, { (intptr_t)static_cast<NativeFunction>(jsTestObjPrototypeFunctionValues), (intptr_t) (0) } },
+    { "forEach", JSC::Function, NoIntrinsic, { (intptr_t)static_cast<NativeFunction>(jsTestObjPrototypeFunctionForEach), (intptr_t) (1) } },
 #if ENABLE(Condition1)
     { "CONDITIONAL_CONST", DontDelete | ReadOnly | ConstantInteger, NoIntrinsic, { (long long)(0) } },
 #else
@@ -722,6 +732,7 @@ void JSTestObjPrototype::finishCreation(VM& vm)
     reifyStaticProperties(vm, JSTestObjPrototypeTableValues, *this);
     JSVMClientData& clientData = *static_cast<JSVMClientData*>(vm.clientData);
     putDirect(vm, clientData.builtinNames().privateMethodPrivateName(), JSFunction::create(vm, globalObject(), 0, String(), jsTestObjPrototypeFunctionPrivateMethod), ReadOnly | DontEnum);
+    putDirect(vm, vm.propertyNames->iteratorSymbol, JSFunction::create(vm, globalObject(), 0, ASCIILiteral("[Symbol.Iterator]"), jsTestObjPrototypeFunctionSymbolIterator), ReadOnly | DontEnum);
 }
 
 const ClassInfo JSTestObj::s_info = { "TestObject", &Base::s_info, &JSTestObjTable, CREATE_METHOD_TABLE(JSTestObj) };
@@ -4886,6 +4897,40 @@ static inline EncodedJSValue jsTestObjPrototypeFunctionTestPromiseFunctionWithOp
     return JSValue::encode(jsUndefined());
 }
 
+using TestObjIterator = JSKeyValueIterator<JSTestObj>;
+using TestObjIteratorPrototype = JSKeyValueIteratorPrototype<JSTestObj>;
+
+template<>
+const JSC::ClassInfo TestObjIterator::s_info = { "TestObject Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(TestObjIterator) };
+
+template<>
+const JSC::ClassInfo TestObjIteratorPrototype::s_info = { "TestObject Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(TestObjIteratorPrototype) };
+
+JSC::EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionSymbolIterator(JSC::ExecState* state)
+{
+    return createKeyValueIterator<JSTestObj>(*state, IterationKind::KeyValue, "[Symbol.Iterator]");
+}
+
+JSC::EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionEntries(JSC::ExecState* state)
+{
+    return createKeyValueIterator<JSTestObj>(*state, IterationKind::KeyValue, "entries");
+}
+
+JSC::EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionKeys(JSC::ExecState* state)
+{
+    return createKeyValueIterator<JSTestObj>(*state, IterationKind::Key, "keys");
+}
+
+JSC::EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionValues(JSC::ExecState* state)
+{
+    return createKeyValueIterator<JSTestObj>(*state, IterationKind::Value, "values");
+}
+
+JSC::EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionForEach(JSC::ExecState* state)
+{
+    return keyValueIteratorForEach<JSTestObj>(*state, "forEach");
+}
+
 void JSTestObj::visitChildren(JSCell* cell, SlotVisitor& visitor)
 {
     auto* thisObject = jsCast<JSTestObj*>(cell);
index 734f236..9179249 100644 (file)
@@ -45,6 +45,9 @@ public:
     static bool getOwnPropertySlot(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&);
     static void destroy(JSC::JSCell*);
 
+    using IteratorKey = String;
+    using IteratorValue = TestObj*;
+
     DECLARE_INFO;
 
     static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
index 785fccb..4d73b90 100644 (file)
@@ -82,6 +82,8 @@ enum _optional { "", "OptionalValue1", "OptionalValue2", "OptionalValue3" };
     // TypedArray attribute
     attribute Float32Array typedArrayAttr;
 
+    iterable<DOMString, TestObj>;
+
     // Methods
     void    voidMethod();
     void    voidMethodWithArgs(long longArg, DOMString strArg, TestObj objArg);
index 7ed7746..8c46aee 100644 (file)
@@ -60,7 +60,7 @@ FontFaceSet::Iterator::Iterator(FontFaceSet& set)
 {
 }
 
-bool FontFaceSet::Iterator::next(RefPtr<FontFace>& key, RefPtr<FontFace>& value)
+bool FontFaceSet::Iterator::next(FontFace*& key, FontFace*& value)
 {
     if (m_index == m_target->size())
         return true;
index c05ed18..2906e27 100644 (file)
@@ -72,11 +72,7 @@ public:
     class Iterator {
     public:
         explicit Iterator(FontFaceSet&);
-
-        using Key = RefPtr<FontFace>;
-        using Value = RefPtr<FontFace>;
-
-        bool next(Key& nextKey, Value& nextValue);
+        bool next(FontFace*& nextKey, FontFace*& nextValue);
 
     private:
         Ref<FontFaceSet> m_target;
index 4ff685d..de7492d 100644 (file)
@@ -32,12 +32,12 @@ enum FontFaceSetLoadStatus {
     ConstructorCallWith=ScriptState&Document,
     Constructor(sequence<FontFace> initialFaces)
 ] interface FontFaceSet : EventTarget {
-    [Custom] Object entries();
-    // forEach(): Maybe implement this in Javascript on top of keys().
     boolean has(FontFace font);
-    [Custom] Object keys();
-    [Custom] Object values();
-    // @iterator
+
+    // FIXME: We should add support for the setlike declaration.
+    // As a first step this map iterable declaration should be changed to a set iterable.
+    iterable<FontFace, FontFace>;
+
     readonly attribute long size;
 
     FontFaceSet add(FontFace font);
@@ -53,4 +53,4 @@ enum FontFaceSetLoadStatus {
 
     [Custom] readonly attribute Promise ready;
     readonly attribute FontFaceSetLoadStatus status;
-};
\ No newline at end of file
+};