Skip to content

Commit

Permalink
#488: basic support for DOM iterables, {NodeList,DOMTokenList}.forEac…
Browse files Browse the repository at this point in the history
…h M1216751 M1290636
  • Loading branch information
classilla committed Mar 21, 2018
1 parent 83c11df commit 9470d4f
Show file tree
Hide file tree
Showing 6 changed files with 252 additions and 227 deletions.
114 changes: 79 additions & 35 deletions dom/bindings/Codegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -1136,11 +1136,13 @@ def addHeaderForFunc(func):
if desc.interface.maplikeOrSetlikeOrIterable:
# We need ToJSValue.h for maplike/setlike type conversions
bindingHeaders.add("mozilla/dom/ToJSValue.h")
# Add headers for the key and value types of the maplike, since
# they'll be needed for convenience functions
addHeadersForType((desc.interface.maplikeOrSetlikeOrIterable.keyType,
desc, None))
if desc.interface.maplikeOrSetlikeOrIterable.valueType:
# Add headers for the key and value types of the
# maplike/setlike/iterable, since they'll be needed for
# convenience functions
if desc.interface.maplikeOrSetlikeOrIterable.hasKeyType():
addHeadersForType((desc.interface.maplikeOrSetlikeOrIterable.keyType,
desc, None))
if desc.interface.maplikeOrSetlikeOrIterable.hasValueType():
addHeadersForType((desc.interface.maplikeOrSetlikeOrIterable.valueType,
desc, None))

Expand Down Expand Up @@ -2269,34 +2271,50 @@ def hasIterator(methods, regular):
"condition": MemberCondition()
})

# Generate the maplike/setlike iterator, if one wasn't already
# generated by a method. If we already have an @@iterator symbol, fail.
if descriptor.interface.maplikeOrSetlikeOrIterable:
if hasIterator(methods, self.regular):
raise TypeError("Cannot have maplike/setlike/iterable interface with "
"other members that generate @@iterator "
"on interface %s, such as indexed getters "
"or aliased functions." %
self.descriptor.interface.identifier.name)
for m in methods:
if (m.isMaplikeOrSetlikeOrIterableMethod() and
(((m.maplikeOrSetlikeOrIterable.isMaplike() or
(m.maplikeOrSetlikeOrIterable.isIterable() and
m.maplikeOrSetlikeOrIterable.hasValueType())) and
m.identifier.name == "entries") or
(((m.maplikeOrSetlikeOrIterable.isSetlike() or
(m.maplikeOrSetlikeOrIterable.isIterable() and
not m.maplikeOrSetlikeOrIterable.hasValueType()))) and
m.identifier.name == "values"))):
self.regular.append({
"name": "@@iterator",
"methodName": m.identifier.name,
"length": methodLength(m),
"flags": "0",
"condition": PropertyDefiner.getControllingCondition(m,
descriptor),
})
break
# Generate the keys/values/entries aliases for value iterables.
maplikeOrSetlikeOrIterable = descriptor.interface.maplikeOrSetlikeOrIterable
if (not static and
not unforgeable and
maplikeOrSetlikeOrIterable and
maplikeOrSetlikeOrIterable.isIterable() and
maplikeOrSetlikeOrIterable.isValueIterator()):
# Add our keys/values/entries/forEach
self.regular.append({
"name": "keys",
"methodInfo": False,
"selfHostedName": "ArrayKeys",
"length": 0,
"flags": "JSPROP_ENUMERATE",
"condition": PropertyDefiner.getControllingCondition(m,
descriptor)
})
self.regular.append({
"name": "values",
"methodInfo": False,
"selfHostedName": "ArrayValues",
"length": 0,
"flags": "JSPROP_ENUMERATE",
"condition": PropertyDefiner.getControllingCondition(m,
descriptor)
})
self.regular.append({
"name": "entries",
"methodInfo": False,
"selfHostedName": "ArrayEntries",
"length": 0,
"flags": "JSPROP_ENUMERATE",
"condition": PropertyDefiner.getControllingCondition(m,
descriptor)
})
self.regular.append({
"name": "forEach",
"methodInfo": False,
"selfHostedName": "ArrayForEach",
"length": 1,
"flags": "JSPROP_ENUMERATE",
"condition": PropertyDefiner.getControllingCondition(m,
descriptor)
})

if not static:
stringifier = descriptor.operations['Stringifier']
Expand Down Expand Up @@ -13008,8 +13026,9 @@ def __init__(self, config, descriptors, mainCallbacks, workerCallbacks,
# arguments to helper functions, and they'll need to be forward
# declared in the header.
if d.interface.maplikeOrSetlikeOrIterable:
builder.forwardDeclareForType(d.interface.maplikeOrSetlikeOrIterable.keyType,
config)
if d.interface.maplikeOrSetlikeOrIterable.hasKeyType():
builder.forwardDeclareForType(d.interface.maplikeOrSetlikeOrIterable.keyType,
config)
if d.interface.maplikeOrSetlikeOrIterable.hasValueType():
builder.forwardDeclareForType(d.interface.maplikeOrSetlikeOrIterable.valueType,
config)
Expand Down Expand Up @@ -15735,6 +15754,31 @@ class CGIterableMethodGenerator(CGGeneric):
using CGCallGenerator.
"""
def __init__(self, descriptor, iterable, methodName):
if methodName == "forEach":
CGGeneric.__init__(self, fill(
"""
if (!JS::IsCallable(arg0)) {
ThrowErrorMessage(cx, MSG_NOT_CALLABLE, "Argument 1 of ${ifaceName}.forEach");
return false;
}
JS::AutoValueArray<3> callArgs(cx);
callArgs[2].setObject(*obj);
JS::Rooted<JS::Value> ignoredReturnVal(cx);
for (size_t i = 0; i < self->GetIterableLength(); ++i) {
if (!ToJSValue(cx, self->GetValueAtIndex(i), callArgs[0])) {
return false;
}
if (!ToJSValue(cx, self->GetKeyAtIndex(i), callArgs[1])) {
return false;
}
if (!JS::Call(cx, arg1, arg0, JS::HandleValueArray(callArgs),
&ignoredReturnVal)) {
return false;
}
}
""",
ifaceName=descriptor.interface.identifier.name))
return
CGGeneric.__init__(self, fill(
"""
typedef ${iterClass} itrType;
Expand Down
7 changes: 2 additions & 5 deletions dom/bindings/Configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -893,8 +893,5 @@ def getAllTypes(descriptors, dictionaries, callbacks):
def iteratorNativeType(descriptor):
assert descriptor.interface.isIterable()
iterableDecl = descriptor.interface.maplikeOrSetlikeOrIterable
if iterableDecl.valueType is None:
iterClass = "OneTypeIterableIterator"
else:
iterClass = "TwoTypeIterableIterator"
return "mozilla::dom::%s<%s>" % (iterClass, descriptor.nativeType)
assert iterableDecl.isPairIterator()
return "mozilla::dom::IterableIterator<%s>" % descriptor.nativeType
Loading

0 comments on commit 9470d4f

Please sign in to comment.