diff options
author | Anthony Ramine <n.oxyde@gmail.com> | 2015-12-15 23:24:16 +0100 |
---|---|---|
committer | Anthony Ramine <n.oxyde@gmail.com> | 2015-12-15 23:24:16 +0100 |
commit | c1718a0b1fb227df2fcad4394a65d430af404ab0 (patch) | |
tree | 648d2f06f458febeab43a4fce17b895ca2bf1b84 /components/script/dom | |
parent | 06947965b1635c4f5ff2aebcf5dfef35c6e95f23 (diff) | |
download | servo-c1718a0b1fb227df2fcad4394a65d430af404ab0.tar.gz servo-c1718a0b1fb227df2fcad4394a65d430af404ab0.zip |
Update WebIDL parser
Diffstat (limited to 'components/script/dom')
-rw-r--r-- | components/script/dom/bindings/codegen/parser/WebIDL.py | 608 |
1 files changed, 333 insertions, 275 deletions
diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index f210d2c6028..8bf415c269b 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.py @@ -540,6 +540,9 @@ class IDLExternalInterface(IDLObjectWithIdentifier, IDLExposureMixins): def validate(self): pass + def isIteratorInterface(self): + return False + def isExternal(self): return True @@ -640,7 +643,7 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins): self._callback = False self._finished = False self.members = [] - self.maplikeOrSetlike = None + self.maplikeOrSetlikeOrIterable = None self._partialInterfaces = [] self._extendedAttrDict = {} # namedConstructors needs deterministic ordering because bindings code @@ -664,6 +667,9 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins): self.totalMembersInSlots = 0 # Tracking of the number of own own members we have in slots self._ownMembersInSlots = 0 + # If this is an iterator interface, we need to know what iterable + # interface we're iterating for in order to get its nativeType. + self.iterableInterface = None IDLObjectWithScope.__init__(self, location, parentScope, name) IDLExposureMixins.__init__(self, location) @@ -682,6 +688,13 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins): except: return None + def isIterable(self): + return (self.maplikeOrSetlikeOrIterable and + self.maplikeOrSetlikeOrIterable.isIterable()) + + def isIteratorInterface(self): + return self.iterableInterface is not None + def resolveIdentifierConflict(self, scope, identifier, originalObject, newObject): assert isinstance(scope, IDLScope) assert isinstance(originalObject, IDLInterfaceMember) @@ -718,22 +731,22 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins): # need to be treated like regular interface members, do this before # things like exposure setting. for member in self.members: - if member.isMaplikeOrSetlike(): + if member.isMaplikeOrSetlikeOrIterable(): # Check that we only have one interface declaration (currently # there can only be one maplike/setlike declaration per # interface) - if self.maplikeOrSetlike: + if self.maplikeOrSetlikeOrIterable: raise WebIDLError("%s declaration used on " "interface that already has %s " "declaration" % - (member.maplikeOrSetlikeType, - self.maplikeOrSetlike.maplikeOrSetlikeType), - [self.maplikeOrSetlike.location, + (member.maplikeOrSetlikeOrIterableType, + self.maplikeOrSetlikeOrIterable.maplikeOrSetlikeOrIterableType), + [self.maplikeOrSetlikeOrIterable.location, member.location]) - self.maplikeOrSetlike = member + self.maplikeOrSetlikeOrIterable = member # If we've got a maplike or setlike declaration, we'll be building all of # our required methods in Codegen. Generate members now. - self.maplikeOrSetlike.expand(self.members, self.isJSImplemented()) + self.maplikeOrSetlikeOrIterable.expand(self.members, self.isJSImplemented()) # Now that we've merged in our partial interfaces, set the # _exposureGlobalNames on any members that don't have it set yet. Note @@ -884,14 +897,14 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins): # If we have a maplike or setlike, and the consequential interface # also does, throw an error. - if iface.maplikeOrSetlike and self.maplikeOrSetlike: - raise WebIDLError("Maplike/setlike interface %s cannot have " - "maplike/setlike interface %s as a " + if iface.maplikeOrSetlikeOrIterable and self.maplikeOrSetlikeOrIterable: + raise WebIDLError("Maplike/setlike/iterable interface %s cannot have " + "maplike/setlike/iterable interface %s as a " "consequential interface" % (self.identifier.name, iface.identifier.name), - [self.maplikeOrSetlike.location, - iface.maplikeOrSetlike.location]) + [self.maplikeOrSetlikeOrIterable.location, + iface.maplikeOrSetlikeOrIterable.location]) additionalMembers = iface.originalMembers for additionalMember in additionalMembers: for member in self.members: @@ -905,15 +918,15 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins): for ancestor in self.getInheritedInterfaces(): ancestor.interfacesBasedOnSelf.add(self) - if (ancestor.maplikeOrSetlike is not None and - self.maplikeOrSetlike is not None): + if (ancestor.maplikeOrSetlikeOrIterable is not None and + self.maplikeOrSetlikeOrIterable is not None): raise WebIDLError("Cannot have maplike/setlike on %s that " "inherits %s, which is already " "maplike/setlike" % (self.identifier.name, ancestor.identifier.name), - [self.maplikeOrSetlike.location, - ancestor.maplikeOrSetlike.location]) + [self.maplikeOrSetlikeOrIterable.location, + ancestor.maplikeOrSetlikeOrIterable.location]) for ancestorConsequential in ancestor.getConsequentialInterfaces(): ancestorConsequential.interfacesBasedOnSelf.add(self) @@ -997,12 +1010,12 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins): # At this point, we have all of our members. If the current interface # uses maplike/setlike, check for collisions anywhere in the current # interface or higher in the inheritance chain. - if self.maplikeOrSetlike: + if self.maplikeOrSetlikeOrIterable: testInterface = self isAncestor = False while testInterface: - self.maplikeOrSetlike.checkCollisions(testInterface.members, - isAncestor) + self.maplikeOrSetlikeOrIterable.checkCollisions(testInterface.members, + isAncestor) isAncestor = True testInterface = testInterface.parent @@ -1411,7 +1424,8 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins): identifier == "AvailableIn" or identifier == "Func" or identifier == "CheckAnyPermissions" or - identifier == "CheckAllPermissions"): + identifier == "CheckAllPermissions" or + identifier == "Deprecated"): # Known extended attributes that take a string value if not attr.hasValue(): raise WebIDLError("[%s] must have a value" % identifier, @@ -1821,15 +1835,9 @@ class IDLType(IDLObject): def isSharedArrayBuffer(self): return False - def isSharedArrayBufferView(self): - return False - def isTypedArray(self): return False - def isSharedTypedArray(self): - return False - def isCallbackInterface(self): return False @@ -1850,9 +1858,7 @@ class IDLType(IDLObject): return self.isInterface() and (self.isArrayBuffer() or self.isArrayBufferView() or self.isSharedArrayBuffer() or - self.isSharedArrayBufferView() or - self.isTypedArray() or - self.isSharedTypedArray()) + self.isTypedArray()) def isDictionary(self): return False @@ -2039,15 +2045,9 @@ class IDLNullableType(IDLType): def isSharedArrayBuffer(self): return self.inner.isSharedArrayBuffer() - def isSharedArrayBufferView(self): - return self.inner.isSharedArrayBufferView() - def isTypedArray(self): return self.inner.isTypedArray() - def isSharedTypedArray(self): - return self.inner.isSharedTypedArray() - def isDictionary(self): return self.inner.isDictionary() @@ -2554,15 +2554,9 @@ class IDLTypedefType(IDLType): def isSharedArrayBuffer(self): return self.inner.isSharedArrayBuffer() - def isSharedArrayBufferView(self): - return self.inner.isSharedArrayBufferView() - def isTypedArray(self): return self.inner.isTypedArray() - def isSharedTypedArray(self): - return self.inner.isSharedTypedArray() - def isInterface(self): return self.inner.isInterface() @@ -2832,7 +2826,6 @@ class IDLBuiltinType(IDLType): 'ArrayBuffer', 'ArrayBufferView', 'SharedArrayBuffer', - 'SharedArrayBufferView', 'Int8Array', 'Uint8Array', 'Uint8ClampedArray', @@ -2841,16 +2834,7 @@ class IDLBuiltinType(IDLType): 'Int32Array', 'Uint32Array', 'Float32Array', - 'Float64Array', - 'SharedInt8Array', - 'SharedUint8Array', - 'SharedUint8ClampedArray', - 'SharedInt16Array', - 'SharedUint16Array', - 'SharedInt32Array', - 'SharedUint32Array', - 'SharedFloat32Array', - 'SharedFloat64Array' + 'Float64Array' ) TagLookup = { @@ -2877,7 +2861,6 @@ class IDLBuiltinType(IDLType): Types.ArrayBuffer: IDLType.Tags.interface, Types.ArrayBufferView: IDLType.Tags.interface, Types.SharedArrayBuffer: IDLType.Tags.interface, - Types.SharedArrayBufferView: IDLType.Tags.interface, Types.Int8Array: IDLType.Tags.interface, Types.Uint8Array: IDLType.Tags.interface, Types.Uint8ClampedArray: IDLType.Tags.interface, @@ -2886,16 +2869,7 @@ class IDLBuiltinType(IDLType): Types.Int32Array: IDLType.Tags.interface, Types.Uint32Array: IDLType.Tags.interface, Types.Float32Array: IDLType.Tags.interface, - Types.Float64Array: IDLType.Tags.interface, - Types.SharedInt8Array: IDLType.Tags.interface, - Types.SharedUint8Array: IDLType.Tags.interface, - Types.SharedUint8ClampedArray: IDLType.Tags.interface, - Types.SharedInt16Array: IDLType.Tags.interface, - Types.SharedUint16Array: IDLType.Tags.interface, - Types.SharedInt32Array: IDLType.Tags.interface, - Types.SharedUint32Array: IDLType.Tags.interface, - Types.SharedFloat32Array: IDLType.Tags.interface, - Types.SharedFloat64Array: IDLType.Tags.interface + Types.Float64Array: IDLType.Tags.interface } def __init__(self, location, name, type): @@ -2938,17 +2912,10 @@ class IDLBuiltinType(IDLType): def isSharedArrayBuffer(self): return self._typeTag == IDLBuiltinType.Types.SharedArrayBuffer - def isSharedArrayBufferView(self): - return self._typeTag == IDLBuiltinType.Types.SharedArrayBufferView - def isTypedArray(self): return (self._typeTag >= IDLBuiltinType.Types.Int8Array and self._typeTag <= IDLBuiltinType.Types.Float64Array) - def isSharedTypedArray(self): - return (self._typeTag >= IDLBuiltinType.Types.SharedInt8Array and - self._typeTag <= IDLBuiltinType.Types.SharedFloat64Array) - def isInterface(self): # TypedArray things are interface types per the TypedArray spec, # but we handle them as builtins because SpiderMonkey implements @@ -2956,9 +2923,7 @@ class IDLBuiltinType(IDLType): return (self.isArrayBuffer() or self.isArrayBufferView() or self.isSharedArrayBuffer() or - self.isSharedArrayBufferView() or - self.isTypedArray() or - self.isSharedTypedArray()) + self.isTypedArray()) def isNonCallbackInterface(self): # All the interfaces we can be are non-callback @@ -3036,15 +3001,11 @@ class IDLBuiltinType(IDLType): # that's not an ArrayBufferView or typed array. (self.isArrayBufferView() and not other.isArrayBufferView() and not other.isTypedArray()) or - (self.isSharedArrayBufferView() and not other.isSharedArrayBufferView() and - not other.isSharedTypedArray()) or # Typed arrays are distinguishable from everything # except ArrayBufferView and the same type of typed # array (self.isTypedArray() and not other.isArrayBufferView() and not - (other.isTypedArray() and other.name == self.name)) or - (self.isSharedTypedArray() and not other.isSharedArrayBufferView() and not - (other.isSharedTypedArray() and other.name == self.name))))) + (other.isTypedArray() and other.name == self.name))))) def _getDependentObjects(self): return set() @@ -3119,9 +3080,6 @@ BuiltinTypes = { IDLBuiltinType.Types.SharedArrayBuffer: IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedArrayBuffer", IDLBuiltinType.Types.SharedArrayBuffer), - IDLBuiltinType.Types.SharedArrayBufferView: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedArrayBufferView", - IDLBuiltinType.Types.SharedArrayBufferView), IDLBuiltinType.Types.Int8Array: IDLBuiltinType(BuiltinLocation("<builtin type>"), "Int8Array", IDLBuiltinType.Types.Int8Array), @@ -3148,34 +3106,7 @@ BuiltinTypes = { IDLBuiltinType.Types.Float32Array), IDLBuiltinType.Types.Float64Array: IDLBuiltinType(BuiltinLocation("<builtin type>"), "Float64Array", - IDLBuiltinType.Types.Float64Array), - IDLBuiltinType.Types.SharedInt8Array: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedInt8Array", - IDLBuiltinType.Types.SharedInt8Array), - IDLBuiltinType.Types.SharedUint8Array: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedUint8Array", - IDLBuiltinType.Types.SharedUint8Array), - IDLBuiltinType.Types.SharedUint8ClampedArray: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedUint8ClampedArray", - IDLBuiltinType.Types.SharedUint8ClampedArray), - IDLBuiltinType.Types.SharedInt16Array: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedInt16Array", - IDLBuiltinType.Types.SharedInt16Array), - IDLBuiltinType.Types.SharedUint16Array: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedUint16Array", - IDLBuiltinType.Types.SharedUint16Array), - IDLBuiltinType.Types.SharedInt32Array: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedInt32Array", - IDLBuiltinType.Types.SharedInt32Array), - IDLBuiltinType.Types.SharedUint32Array: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedUint32Array", - IDLBuiltinType.Types.SharedUint32Array), - IDLBuiltinType.Types.SharedFloat32Array: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedFloat32Array", - IDLBuiltinType.Types.SharedFloat32Array), - IDLBuiltinType.Types.SharedFloat64Array: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedFloat64Array", - IDLBuiltinType.Types.SharedFloat64Array) + IDLBuiltinType.Types.Float64Array) } @@ -3266,7 +3197,7 @@ class IDLValue(IDLObject): (self.value == float("inf") or self.value == float("-inf") or math.isnan(self.value))): raise WebIDLError("Trying to convert unrestricted value %s to non-unrestricted" - % self.value, [location]); + % self.value, [location]) return IDLValue(self.location, type, self.value) elif self.type.isString() and type.isUSVString(): # Allow USVStrings to use default value just like @@ -3366,7 +3297,8 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins): 'Const', 'Attr', 'Method', - 'MaplikeOrSetlike' + 'MaplikeOrSetlike', + 'Iterable' ) Special = enum( @@ -3392,6 +3324,10 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins): def isConst(self): return self.tag == IDLInterfaceMember.Tags.Const + def isMaplikeOrSetlikeOrIterable(self): + return (self.tag == IDLInterfaceMember.Tags.MaplikeOrSetlike or + self.tag == IDLInterfaceMember.Tags.Iterable) + def isMaplikeOrSetlike(self): return self.tag == IDLInterfaceMember.Tags.MaplikeOrSetlike @@ -3469,58 +3405,42 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins): self.aliases.append(alias) -# MaplikeOrSetlike adds a trait to an interface, like map or iteration -# functions. To handle them while still getting all of the generated binding -# code taken care of, we treat them as macros that are expanded into members -# based on parsed values. -class IDLMaplikeOrSetlike(IDLInterfaceMember): - - MaplikeOrSetlikeTypes = enum( - 'maplike', - 'setlike' - ) - - def __init__(self, location, identifier, maplikeOrSetlikeType, - readonly, keyType, valueType): - IDLInterfaceMember.__init__(self, location, identifier, - IDLInterfaceMember.Tags.MaplikeOrSetlike) +class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember): + def __init__(self, location, identifier, ifaceType, keyType, valueType, ifaceKind): + IDLInterfaceMember.__init__(self, location, identifier, ifaceKind) assert isinstance(keyType, IDLType) - assert isinstance(valueType, IDLType) - self.maplikeOrSetlikeType = maplikeOrSetlikeType - self.readonly = readonly + assert ifaceType in ['maplike', 'setlike', 'iterable'] + if valueType is not None: + assert isinstance(valueType, IDLType) self.keyType = keyType self.valueType = valueType - self.slotIndex = None + self.maplikeOrSetlikeOrIterableType = ifaceType self.disallowedMemberNames = [] self.disallowedNonMethodNames = [] - # When generating JSAPI access code, we need to know the backing object - # type prefix to create the correct function. Generate here for reuse. - if self.isMaplike(): - self.prefix = 'Map' - elif self.isSetlike(): - self.prefix = 'Set' - - def __str__(self): - return "declared '%s' with key '%s'" % (self.maplikeOrSetlikeType, self.keyType) - def isMaplike(self): - return self.maplikeOrSetlikeType == "maplike" + return self.maplikeOrSetlikeOrIterableType == "maplike" def isSetlike(self): - return self.maplikeOrSetlikeType == "setlike" + return self.maplikeOrSetlikeOrIterableType == "setlike" + + def isIterable(self): + return self.maplikeOrSetlikeOrIterableType == "iterable" + + def hasValueType(self): + return self.valueType is not None def checkCollisions(self, members, isAncestor): for member in members: # Check that there are no disallowed members if (member.identifier.name in self.disallowedMemberNames and - not ((member.isMethod() and member.isMaplikeOrSetlikeMethod()) or + not ((member.isMethod() and member.isMaplikeOrSetlikeOrIterableMethod()) or (member.isAttr() and member.isMaplikeOrSetlikeAttr()))): raise WebIDLError("Member '%s' conflicts " "with reserved %s name." % (member.identifier.name, - self.maplikeOrSetlikeType), + self.maplikeOrSetlikeOrIterableType), [self.location, member.location]) # Check that there are no disallowed non-method members if (isAncestor or (member.isAttr() or member.isConst()) and @@ -3528,68 +3448,160 @@ class IDLMaplikeOrSetlike(IDLInterfaceMember): raise WebIDLError("Member '%s' conflicts " "with reserved %s method." % (member.identifier.name, - self.maplikeOrSetlikeType), + self.maplikeOrSetlikeOrIterableType), [self.location, member.location]) + def addMethod(self, name, members, allowExistingOperations, returnType, args=[], + chromeOnly=False, isPure=False, affectsNothing=False, newObject=False): + """ + Create an IDLMethod based on the parameters passed in. + + - members is the member list to add this function to, since this is + called during the member expansion portion of interface object + building. + + - chromeOnly is only True for read-only js implemented classes, to + implement underscore prefixed convenience functions which would + otherwise not be available, unlike the case of C++ bindings. + + - isPure is only True for idempotent functions, so it is not valid for + things like keys, values, etc. that return a new object every time. + + - affectsNothing means that nothing changes due to this method, which + affects JIT optimization behavior + + - newObject means the method creates and returns a new object. + + """ + # Only add name to lists for collision checks if it's not chrome + # only. + if chromeOnly: + name = "__" + name + else: + if not allowExistingOperations: + self.disallowedMemberNames.append(name) + else: + self.disallowedNonMethodNames.append(name) + # If allowExistingOperations is True, and another operation exists + # with the same name as the one we're trying to add, don't add the + # maplike/setlike operation. However, if the operation is static, + # then fail by way of creating the function, which will cause a + # naming conflict, per the spec. + if allowExistingOperations: + for m in members: + if m.identifier.name == name and m.isMethod() and not m.isStatic(): + return + method = IDLMethod(self.location, + IDLUnresolvedIdentifier(self.location, name, allowDoubleUnderscore=chromeOnly), + returnType, args, maplikeOrSetlikeOrIterable=self) + # We need to be able to throw from declaration methods + method.addExtendedAttributes( + [IDLExtendedAttribute(self.location, ("Throws",))]) + if chromeOnly: + method.addExtendedAttributes( + [IDLExtendedAttribute(self.location, ("ChromeOnly",))]) + if isPure: + method.addExtendedAttributes( + [IDLExtendedAttribute(self.location, ("Pure",))]) + # Following attributes are used for keys/values/entries. Can't mark + # them pure, since they return a new object each time they are run. + if affectsNothing: + method.addExtendedAttributes( + [IDLExtendedAttribute(self.location, ("DependsOn", "Everything")), + IDLExtendedAttribute(self.location, ("Affects", "Nothing"))]) + if newObject: + method.addExtendedAttributes( + [IDLExtendedAttribute(self.location, ("NewObject",))]) + members.append(method) + + def resolve(self, parentScope): + self.keyType.resolveType(parentScope) + if self.valueType: + self.valueType.resolveType(parentScope) + + def finish(self, scope): + IDLInterfaceMember.finish(self, scope) + if not self.keyType.isComplete(): + t = self.keyType.complete(scope) + + assert not isinstance(t, IDLUnresolvedType) + assert not isinstance(t, IDLTypedefType) + assert not isinstance(t.name, IDLUnresolvedIdentifier) + self.keyType = t + if self.valueType and not self.valueType.isComplete(): + t = self.valueType.complete(scope) + + assert not isinstance(t, IDLUnresolvedType) + assert not isinstance(t, IDLTypedefType) + assert not isinstance(t.name, IDLUnresolvedIdentifier) + self.valueType = t + + def validate(self): + IDLInterfaceMember.validate(self) + + def handleExtendedAttribute(self, attr): + IDLInterfaceMember.handleExtendedAttribute(self, attr) + + def _getDependentObjects(self): + if self.valueType: + return set([self.keyType, self.valueType]) + return set([self.keyType]) + +# Iterable adds ES6 iterator style functions and traits +# (keys/values/entries/@@iterator) to an interface. +class IDLIterable(IDLMaplikeOrSetlikeOrIterableBase): + + def __init__(self, location, identifier, keyType, valueType=None, scope=None): + IDLMaplikeOrSetlikeOrIterableBase.__init__(self, location, identifier, + "iterable", keyType, valueType, + IDLInterfaceMember.Tags.Iterable) + self.iteratorType = None + + def __str__(self): + return "declared iterable with key '%s' and value '%s'" % (self.keyType, self.valueType) + def expand(self, members, isJSImplemented): """ In order to take advantage of all of the method machinery in Codegen, we generate our functions as if they were part of the interface specification during parsing. """ - def addMethod(name, allowExistingOperations, returnType, args=[], - chromeOnly=False, isPure=False, affectsNothing=False): - """ - Create an IDLMethod based on the parameters passed in. chromeOnly is only - True for read-only js implemented classes, to implement underscore - prefixed convenience functions would otherwise not be available, - unlike the case of C++ bindings. isPure is only True for - idempotent functions, so it is not valid for things like keys, - values, etc. that return a new object every time. + # object entries() + self.addMethod("entries", members, False, self.iteratorType, + affectsNothing=True, newObject=True) + # object keys() + self.addMethod("keys", members, False, self.iteratorType, + affectsNothing=True, newObject=True) + # object values() + self.addMethod("values", members, False, self.iteratorType, + affectsNothing=True, newObject=True) - """ +# MaplikeOrSetlike adds ES6 map-or-set-like traits to an interface. +class IDLMaplikeOrSetlike(IDLMaplikeOrSetlikeOrIterableBase): - # Only add name to lists for collision checks if it's not chrome - # only. - if chromeOnly: - name = "__" + name - else: - if not allowExistingOperations: - self.disallowedMemberNames.append(name) - else: - self.disallowedNonMethodNames.append(name) - - # If allowExistingOperations is True, and another operation exists - # with the same name as the one we're trying to add, don't add the - # maplike/setlike operation. However, if the operation is static, - # then fail by way of creating the function, which will cause a - # naming conflict, per the spec. - if allowExistingOperations: - for m in members: - if m.identifier.name == name and m.isMethod() and not m.isStatic(): - return - - method = IDLMethod(self.location, - IDLUnresolvedIdentifier(self.location, name, allowDoubleUnderscore=chromeOnly), - returnType, args, maplikeOrSetlike=self) - - # We need to be able to throw from declaration methods - method.addExtendedAttributes( - [IDLExtendedAttribute(self.location, ("Throws",))]) - if chromeOnly: - method.addExtendedAttributes( - [IDLExtendedAttribute(self.location, ("ChromeOnly",))]) - if isPure: - method.addExtendedAttributes( - [IDLExtendedAttribute(self.location, ("Pure",))]) - # Following attributes are used for keys/values/entries. Can't mark - # them pure, since they return a new object each time they are run. - if affectsNothing: - method.addExtendedAttributes( - [IDLExtendedAttribute(self.location, ("DependsOn", "Everything")), - IDLExtendedAttribute(self.location, ("Affects", "Nothing"))]) - members.append(method) + def __init__(self, location, identifier, maplikeOrSetlikeType, + readonly, keyType, valueType): + IDLMaplikeOrSetlikeOrIterableBase.__init__(self, location, identifier, maplikeOrSetlikeType, + keyType, valueType, IDLInterfaceMember.Tags.MaplikeOrSetlike) + self.readonly = readonly + self.slotIndex = None + + # When generating JSAPI access code, we need to know the backing object + # type prefix to create the correct function. Generate here for reuse. + if self.isMaplike(): + self.prefix = 'Map' + elif self.isSetlike(): + self.prefix = 'Set' + + def __str__(self): + return "declared '%s' with key '%s'" % (self.maplikeOrSetlikeOrIterableType, self.keyType) + def expand(self, members, isJSImplemented): + """ + In order to take advantage of all of the method machinery in Codegen, + we generate our functions as if they were part of the interface + specification during parsing. + """ # Both maplike and setlike have a size attribute members.append(IDLAttribute(self.location, IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"), "size"), @@ -3599,14 +3611,14 @@ class IDLMaplikeOrSetlike(IDLInterfaceMember): self.reserved_ro_names = ["size"] # object entries() - addMethod("entries", False, BuiltinTypes[IDLBuiltinType.Types.object], - affectsNothing=True) + self.addMethod("entries", members, False, BuiltinTypes[IDLBuiltinType.Types.object], + affectsNothing=True) # object keys() - addMethod("keys", False, BuiltinTypes[IDLBuiltinType.Types.object], - affectsNothing=True) + self.addMethod("keys", members, False, BuiltinTypes[IDLBuiltinType.Types.object], + affectsNothing=True) # object values() - addMethod("values", False, BuiltinTypes[IDLBuiltinType.Types.object], - affectsNothing=True) + self.addMethod("values", members, False, BuiltinTypes[IDLBuiltinType.Types.object], + affectsNothing=True) # void forEach(callback(valueType, keyType), thisVal) foreachArguments = [IDLArgument(self.location, @@ -3618,8 +3630,8 @@ class IDLMaplikeOrSetlike(IDLInterfaceMember): "thisArg"), BuiltinTypes[IDLBuiltinType.Types.any], optional=True)] - addMethod("forEach", False, BuiltinTypes[IDLBuiltinType.Types.void], - foreachArguments) + self.addMethod("forEach", members, False, BuiltinTypes[IDLBuiltinType.Types.void], + foreachArguments) def getKeyArg(): return IDLArgument(self.location, @@ -3627,39 +3639,39 @@ class IDLMaplikeOrSetlike(IDLInterfaceMember): self.keyType) # boolean has(keyType key) - addMethod("has", False, BuiltinTypes[IDLBuiltinType.Types.boolean], - [getKeyArg()], isPure=True) + self.addMethod("has", members, False, BuiltinTypes[IDLBuiltinType.Types.boolean], + [getKeyArg()], isPure=True) if not self.readonly: # void clear() - addMethod("clear", True, BuiltinTypes[IDLBuiltinType.Types.void], - []) + self.addMethod("clear", members, True, BuiltinTypes[IDLBuiltinType.Types.void], + []) # boolean delete(keyType key) - addMethod("delete", True, - BuiltinTypes[IDLBuiltinType.Types.boolean], [getKeyArg()]) + self.addMethod("delete", members, True, + BuiltinTypes[IDLBuiltinType.Types.boolean], [getKeyArg()]) # Always generate underscored functions (e.g. __add, __clear) for js # implemented interfaces as convenience functions. if isJSImplemented: # void clear() - addMethod("clear", True, BuiltinTypes[IDLBuiltinType.Types.void], - [], chromeOnly=True) + self.addMethod("clear", members, True, BuiltinTypes[IDLBuiltinType.Types.void], + [], chromeOnly=True) # boolean delete(keyType key) - addMethod("delete", True, - BuiltinTypes[IDLBuiltinType.Types.boolean], [getKeyArg()], - chromeOnly=True) + self.addMethod("delete", members, True, + BuiltinTypes[IDLBuiltinType.Types.boolean], [getKeyArg()], + chromeOnly=True) if self.isSetlike(): if not self.readonly: # Add returns the set object it just added to. # object add(keyType key) - addMethod("add", True, - BuiltinTypes[IDLBuiltinType.Types.object], [getKeyArg()]) + self.addMethod("add", members, True, + BuiltinTypes[IDLBuiltinType.Types.object], [getKeyArg()]) if isJSImplemented: - addMethod("add", True, - BuiltinTypes[IDLBuiltinType.Types.object], [getKeyArg()], - chromeOnly=True) + self.addMethod("add", members, True, + BuiltinTypes[IDLBuiltinType.Types.object], [getKeyArg()], + chromeOnly=True) return # If we get this far, we're a maplike declaration. @@ -3672,8 +3684,8 @@ class IDLMaplikeOrSetlike(IDLInterfaceMember): # # TODO: Bug 1155340 may change this to use specific type to provide # more info to JIT. - addMethod("get", False, BuiltinTypes[IDLBuiltinType.Types.any], - [getKeyArg()], isPure=True) + self.addMethod("get", members, False, BuiltinTypes[IDLBuiltinType.Types.any], + [getKeyArg()], isPure=True) def getValueArg(): return IDLArgument(self.location, @@ -3681,42 +3693,11 @@ class IDLMaplikeOrSetlike(IDLInterfaceMember): self.valueType) if not self.readonly: - addMethod("set", True, BuiltinTypes[IDLBuiltinType.Types.object], - [getKeyArg(), getValueArg()]) + self.addMethod("set", members, True, BuiltinTypes[IDLBuiltinType.Types.object], + [getKeyArg(), getValueArg()]) if isJSImplemented: - addMethod("set", True, BuiltinTypes[IDLBuiltinType.Types.object], - [getKeyArg(), getValueArg()], chromeOnly=True) - - def resolve(self, parentScope): - self.keyType.resolveType(parentScope) - self.valueType.resolveType(parentScope) - - def finish(self, scope): - IDLInterfaceMember.finish(self, scope) - if not self.keyType.isComplete(): - t = self.keyType.complete(scope) - - assert not isinstance(t, IDLUnresolvedType) - assert not isinstance(t, IDLTypedefType) - assert not isinstance(t.name, IDLUnresolvedIdentifier) - self.keyType = t - if not self.valueType.isComplete(): - t = self.valueType.complete(scope) - - assert not isinstance(t, IDLUnresolvedType) - assert not isinstance(t, IDLTypedefType) - assert not isinstance(t.name, IDLUnresolvedIdentifier) - self.valueType = t - - def validate(self): - IDLInterfaceMember.validate(self) - - def handleExtendedAttribute(self, attr): - IDLInterfaceMember.handleExtendedAttribute(self, attr) - - def _getDependentObjects(self): - return set([self.keyType, self.valueType]) - + self.addMethod("set", members, True, BuiltinTypes[IDLBuiltinType.Types.object], + [getKeyArg(), getValueArg()], chromeOnly=True) class IDLConst(IDLInterfaceMember): def __init__(self, location, identifier, type, value): @@ -4026,6 +4007,11 @@ class IDLAttribute(IDLInterfaceMember): "readonly attributes" % attr.value(), [attr.location, self.location]) self._setDependsOn(attr.value()) + elif identifier == "UseCounter": + if self.stringifier: + raise WebIDLError("[UseCounter] must not be used on a " + "stringifier attribute", + [attr.location, self.location]) elif (identifier == "Pref" or identifier == "Deprecated" or identifier == "SetterThrows" or @@ -4313,7 +4299,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope): static=False, getter=False, setter=False, creator=False, deleter=False, specialType=NamedOrIndexed.Neither, legacycaller=False, stringifier=False, jsonifier=False, - maplikeOrSetlike=None): + maplikeOrSetlikeOrIterable=None): # REVIEW: specialType is NamedOrIndexed -- wow, this is messed up. IDLInterfaceMember.__init__(self, location, identifier, IDLInterfaceMember.Tags.Method) @@ -4341,8 +4327,8 @@ class IDLMethod(IDLInterfaceMember, IDLScope): self._stringifier = stringifier assert isinstance(jsonifier, bool) self._jsonifier = jsonifier - assert maplikeOrSetlike is None or isinstance(maplikeOrSetlike, IDLMaplikeOrSetlike) - self.maplikeOrSetlike = maplikeOrSetlike + assert maplikeOrSetlikeOrIterable is None or isinstance(maplikeOrSetlikeOrIterable, IDLMaplikeOrSetlikeOrIterableBase) + self.maplikeOrSetlikeOrIterable = maplikeOrSetlikeOrIterable self._specialType = specialType self._unforgeable = False self.dependsOn = "Everything" @@ -4424,12 +4410,21 @@ class IDLMethod(IDLInterfaceMember, IDLScope): def isJsonifier(self): return self._jsonifier - def isMaplikeOrSetlikeMethod(self): + def isMaplikeOrSetlikeOrIterableMethod(self): """ True if this method was generated as part of a maplike/setlike/etc interface (e.g. has/get methods) """ - return self.maplikeOrSetlike is not None + return self.maplikeOrSetlikeOrIterable is not None + + def isSpecial(self): + return (self.isGetter() or + self.isSetter() or + self.isCreator() or + self.isDeleter() or + self.isLegacycaller() or + self.isStringifier() or + self.isJsonifier()) def hasOverloads(self): return self._hasOverloads @@ -4443,7 +4438,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope): an non-identifier name, they actually DO have an identifier. """ return (self.identifier.name[:2] == "__" and - not self.isMaplikeOrSetlikeMethod()) + not self.isMaplikeOrSetlikeOrIterableMethod()) def resolve(self, parentScope): assert isinstance(parentScope, IDLScope) @@ -4712,6 +4707,11 @@ class IDLMethod(IDLInterfaceMember, IDLScope): raise WebIDLError("[Alias] takes an identifier or string", [attr.location]) self._addAlias(attr.value()) + elif identifier == "UseCounter": + if self.isSpecial(): + raise WebIDLError("[UseCounter] must not be used on a special " + "operation", + [attr.location, self.location]) elif (identifier == "Throws" or identifier == "NewObject" or identifier == "ChromeOnly" or @@ -4723,7 +4723,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope): identifier == "CheckAnyPermissions" or identifier == "CheckAllPermissions" or identifier == "BinaryName" or - identifier == "MethodIdentityTestable" or identifier == "StaticClassOverride"): # Known attributes that we don't need to do anything with here pass @@ -4946,7 +4945,8 @@ class Tokenizer(object): "SharedArrayBuffer": "SHAREDARRAYBUFFER", "or": "OR", "maplike": "MAPLIKE", - "setlike": "SETLIKE" + "setlike": "SETLIKE", + "iterable": "ITERABLE" } tokens.extend(keywords.values()) @@ -5100,8 +5100,9 @@ class Parser(Tokenizer): raise ex pass - p[0] = IDLInterface(location, self.globalScope(), identifier, parent, + iface = IDLInterface(location, self.globalScope(), identifier, parent, members, isKnownNonPartial=True) + p[0] = iface def p_InterfaceForwardDecl(self, p): """ @@ -5187,7 +5188,7 @@ class Parser(Tokenizer): def p_InterfaceMember(self, p): """ InterfaceMember : Const - | AttributeOrOperationOrMaplikeOrSetlike + | AttributeOrOperationOrMaplikeOrSetlikeOrIterable """ p[0] = p[1] @@ -5402,15 +5403,30 @@ class Parser(Tokenizer): """ p[0] = False - def p_AttributeOrOperationOrMaplikeOrSetlike(self, p): + def p_AttributeOrOperationOrMaplikeOrSetlikeOrIterable(self, p): """ - AttributeOrOperationOrMaplikeOrSetlike : Attribute - | Maplike - | Setlike - | Operation + AttributeOrOperationOrMaplikeOrSetlikeOrIterable : Attribute + | Maplike + | Setlike + | Iterable + | Operation """ p[0] = p[1] + def p_Iterable(self, p): + """ + Iterable : ITERABLE LT Type GT SEMICOLON + | ITERABLE LT Type COMMA Type GT SEMICOLON + """ + location = self.getLocation(p, 2) + identifier = IDLUnresolvedIdentifier(location, "__iterable", + allowDoubleUnderscore=True) + keyType = p[3] + valueType = None + if (len(p) > 6): + valueType = p[5] + p[0] = IDLIterable(location, identifier, keyType, valueType, self.globalScope()) + def p_Setlike(self, p): """ Setlike : ReadOnly SETLIKE LT Type GT SEMICOLON @@ -5783,6 +5799,7 @@ class Parser(Tokenizer): | IMPLEMENTS | INHERIT | INTERFACE + | ITERABLE | LEGACYCALLER | MAPLIKE | PARTIAL @@ -6432,7 +6449,7 @@ class Parser(Tokenizer): assert isinstance(scope, IDLScope) # xrange omits the last value. - for x in xrange(IDLBuiltinType.Types.ArrayBuffer, IDLBuiltinType.Types.SharedFloat64Array + 1): + for x in xrange(IDLBuiltinType.Types.ArrayBuffer, IDLBuiltinType.Types.Float64Array + 1): builtin = BuiltinTypes[x] name = builtin.name typedef = IDLTypedef(BuiltinLocation("<builtin type>"), scope, builtin, name) @@ -6461,7 +6478,49 @@ class Parser(Tokenizer): self._filename = None def finish(self): - # First, finish all the IDLImplementsStatements. In particular, we + # If we have interfaces that are iterable, create their + # iterator interfaces and add them to the productions array. + interfaceStatements = [p for p in self._productions if + isinstance(p, IDLInterface)] + + iterableIteratorIface = None + for iface in interfaceStatements: + iterable = None + # We haven't run finish() on the interface yet, so we don't know + # whether our interface is maplike/setlike/iterable or not. This + # means we have to loop through the members to see if we have an + # iterable member. + for m in iface.members: + if isinstance(m, IDLIterable): + iterable = m + break + if iterable: + def simpleExtendedAttr(str): + return IDLExtendedAttribute(iface.location, (str, )) + nextMethod = IDLMethod( + iface.location, + IDLUnresolvedIdentifier(iface.location, "next"), + BuiltinTypes[IDLBuiltinType.Types.object], []) + nextMethod.addExtendedAttributes([simpleExtendedAttr("Throws")]) + itr_ident = IDLUnresolvedIdentifier(iface.location, + iface.identifier.name + "Iterator") + itr_iface = IDLInterface(iface.location, self.globalScope(), + itr_ident, None, [nextMethod], + isKnownNonPartial=True) + itr_iface.addExtendedAttributes([simpleExtendedAttr("NoInterfaceObject")]) + # Make sure the exposure set for the iterator interface is the + # same as the exposure set for the iterable interface, because + # we're going to generate methods on the iterable that return + # instances of the iterator. + itr_iface._exposureGlobalNames = set(iface._exposureGlobalNames) + # Always append generated iterable interfaces after the + # interface they're a member of, otherwise nativeType generation + # won't work correctly. + itr_iface.iterableInterface = iface + self._productions.append(itr_iface) + iterable.iteratorType = IDLWrapperType(iface.location, itr_iface) + + # Then, finish all the IDLImplementsStatements. In particular, we # have to make sure we do those before we do the IDLInterfaces. # XXX khuey hates this bit and wants to nuke it from orbit. implementsStatements = [p for p in self._productions if @@ -6493,7 +6552,6 @@ class Parser(Tokenizer): _builtins = """ typedef unsigned long long DOMTimeStamp; typedef (ArrayBufferView or ArrayBuffer) BufferSource; - typedef (SharedArrayBufferView or SharedArrayBuffer) SharedBufferSource; """ |