diff options
35 files changed, 727 insertions, 221 deletions
diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index df88cf120dd..e18b6e34a2c 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.py @@ -1,16 +1,18 @@ # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# file, You can obtain one at http://mozilla.org/MPL/2.0/. """ A WebIDL parser. """ +from __future__ import print_function from ply import lex, yacc import re import os import traceback import math import string -from collections import defaultdict +from collections import defaultdict, OrderedDict +from itertools import chain # Machinery @@ -40,32 +42,22 @@ def parseInt(literal): return value * sign -# Magic for creating enums -def M_add_class_attribs(attribs, start): - def foo(name, bases, dict_): - for v, k in enumerate(attribs): - dict_[k] = start + v - assert 'length' not in dict_ - dict_['length'] = start + len(attribs) - return type(name, bases, dict_) - return foo - - def enum(*names, **kw): - if len(kw) == 1: - base = kw['base'].__class__ - start = base.length - else: - assert len(kw) == 0 - base = object - start = 0 - - class Foo(base): - __metaclass__ = M_add_class_attribs(names, start) - + class Foo(object): + attrs = OrderedDict() + def __init__(self, names): + for v, k in enumerate(names): + self.attrs[k] = v + def __getattr__(self, attr): + if attr in self.attrs: + return self.attrs[attr] + raise AttributeError def __setattr__(self, name, value): # this makes it read-only raise NotImplementedError - return Foo() + + if "base" not in kw: + return Foo(names) + return Foo(chain(kw["base"].attrs.keys(), names)) class WebIDLError(Exception): @@ -482,9 +474,6 @@ class IDLExposureMixins(): def isExposedOnMainThread(self): return self.isExposedInWindow() - def isExposedOffMainThread(self): - return len(self.exposureSet - {'Window', 'FakeTestPrimaryGlobal'}) > 0 - def isExposedInAnyWorker(self): return len(self.getWorkerExposureSet()) > 0 @@ -568,6 +557,9 @@ class IDLExternalInterface(IDLObjectWithIdentifier, IDLExposureMixins): def isNavigatorProperty(self): return False + def isSerializable(self): + return False + def _getDependentObjects(self): return set() @@ -704,6 +696,7 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): # outputs the constructs in the order that namedConstructors enumerates # them. self.namedConstructors = list() + self.legacyWindowAliases = [] self.implementedInterfaces = set() self._consequential = False self._isKnownNonPartial = False @@ -774,6 +767,16 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): IDLExposureMixins.finish(self, scope) + if len(self.legacyWindowAliases) > 0: + if not self.hasInterfaceObject(): + raise WebIDLError("Interface %s unexpectedly has [LegacyWindowAlias] " + "and [NoInterfaceObject] together" % self.identifier.name, + [self.location]) + if not self.isExposedInWindow(): + raise WebIDLError("Interface %s has [LegacyWindowAlias] " + "but not exposed in Window" % self.identifier.name, + [self.location]) + # Now go ahead and merge in our partial interfaces. for partial in self._partialInterfaces: partial.finish(scope) @@ -962,7 +965,6 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): # self.members. Sort our consequential interfaces by name # just so we have a consistent order. for iface in sorted(self.getConsequentialInterfaces(), - cmp=cmp, key=lambda x: x.identifier.name): # Flag the interface as being someone's consequential interface iface.setIsConsequentialInterfaceOf(self) @@ -1325,6 +1327,7 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): for bindingAlias in member.bindingAliases: checkDuplicateNames(member, bindingAlias, "BindingAlias") + # Conditional exposure makes no sense for interfaces with no # interface object, unless they're navigator properties. # And SecureContext makes sense for interfaces with no interface object, @@ -1640,6 +1643,11 @@ class IDLInterface(IDLInterfaceOrNamespace): raise WebIDLError(str(identifier) + " must take no arguments", [attr.location]) + if self.globalNames: + raise WebIDLError("[%s] must not be specified together with " + "[Global]" % identifier, + [self.location, attr.location]) + args = attr.args() if attr.hasArgs() else [] retType = IDLWrapperType(self.location, self) @@ -1700,6 +1708,10 @@ class IDLInterface(IDLInterfaceOrNamespace): "an interface with inherited interfaces", [attr.location, self.location]) elif identifier == "Global": + if self.ctor() or self.namedConstructors: + raise WebIDLError("[Global] cannot be specified on an " + "interface with a constructor", + [attr.location, self.location]); if attr.hasValue(): self.globalNames = [attr.value()] elif attr.hasArgs(): @@ -1723,6 +1735,18 @@ class IDLInterface(IDLInterfaceOrNamespace): self.parentScope.addIfaceGlobalNames(self.identifier.name, [self.identifier.name]) self._isOnGlobalProtoChain = True + elif identifier == "LegacyWindowAlias": + if attr.hasValue(): + self.legacyWindowAliases = [attr.value()] + elif attr.hasArgs(): + self.legacyWindowAliases = attr.args() + else: + raise WebIDLError("[%s] must either take an identifier " + "or take an identifier list" % identifier, + [attr.location]) + for alias in self.legacyWindowAliases: + unresolved = IDLUnresolvedIdentifier(attr.location, alias) + IDLObjectWithIdentifier(attr.location, self.parentScope, unresolved) elif identifier == "SecureContext": if not attr.noArguments(): raise WebIDLError("[%s] must take no arguments" % identifier, @@ -1744,6 +1768,7 @@ class IDLInterface(IDLInterfaceOrNamespace): identifier == "LegacyUnenumerableNamedProperties" or identifier == "RunConstructorInCallerCompartment" or identifier == "WantsEventListenerHooks" or + identifier == "Serializable" or identifier == "Abstract" or identifier == "Inline"): # Known extended attributes that do not take values @@ -1770,6 +1795,19 @@ class IDLInterface(IDLInterfaceOrNamespace): attrlist = attr.listValue() self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True + def validate(self): + IDLInterfaceOrNamespace.validate(self) + if self.parent and self.isSerializable() and not self.parent.isSerializable(): + raise WebIDLError( + "Serializable interface inherits from non-serializable " + "interface. Per spec, that means the object should not be " + "serializable, so chances are someone made a mistake here " + "somewhere.", + [self.location, self.parent.location]) + + def isSerializable(self): + return self.getExtendedAttribute("Serializable") + class IDLNamespace(IDLInterfaceOrNamespace): def __init__(self, location, parentScope, name, members, isKnownNonPartial): @@ -1805,7 +1843,9 @@ class IDLNamespace(IDLInterfaceOrNamespace): if not attr.noArguments(): raise WebIDLError("[%s] must not have arguments" % identifier, [attr.location]) - elif identifier == "Pref" or identifier == "Func": + elif (identifier == "Pref" or + identifier == "HeaderFile" or + identifier == "Func"): # Known extended attributes that take a string value if not attr.hasValue(): raise WebIDLError("[%s] must have a value" % identifier, @@ -1818,6 +1858,9 @@ class IDLNamespace(IDLInterfaceOrNamespace): attrlist = attr.listValue() self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True + def isSerializable(self): + return False + class IDLDictionary(IDLObjectWithScope): def __init__(self, location, parentScope, name, parent, members): @@ -1877,7 +1920,7 @@ class IDLDictionary(IDLObjectWithScope): assert member.type.isComplete() # Members of a dictionary are sorted in lexicographic order - self.members.sort(cmp=cmp, key=lambda x: x.identifier.name) + self.members.sort(key=lambda x: x.identifier.name) inheritedMembers = [] ancestor = self.parent @@ -2232,7 +2275,7 @@ class IDLUnresolvedType(IDLType): assert obj if obj.isType(): - print obj + print(obj) assert not obj.isType() if obj.isTypedef(): assert self.name.name == obj.identifier.name @@ -3562,8 +3605,6 @@ class IDLNullValue(IDLObject): def coerceToType(self, type, location): if (not isinstance(type, IDLNullableType) and not (type.isUnion() and type.hasNullableType) and - not (type.isUnion() and type.hasDictionaryType()) and - not type.isDictionary() and not type.isAny()): raise WebIDLError("Cannot coerce null value to type %s." % type, [location]) @@ -3612,6 +3653,35 @@ class IDLEmptySequenceValue(IDLObject): return set() +class IDLDefaultDictionaryValue(IDLObject): + def __init__(self, location): + IDLObject.__init__(self, location) + self.type = None + self.value = None + + def coerceToType(self, type, location): + if type.isUnion(): + # We use the flat member types here, because if we have a nullable + # member type, or a nested union, we want the type the value + # actually coerces to, not the nullable or nested union type. + for subtype in type.unroll().flatMemberTypes: + try: + return self.coerceToType(subtype, location) + except: + pass + + if not type.isDictionary(): + raise WebIDLError("Cannot coerce default dictionary value to type %s." % type, + [location]) + + defaultDictionaryValue = IDLDefaultDictionaryValue(self.location) + defaultDictionaryValue.type = type + return defaultDictionaryValue + + def _getDependentObjects(self): + return set() + + class IDLUndefinedValue(IDLObject): def __init__(self, location): IDLObject.__init__(self, location) @@ -3689,7 +3759,7 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins): def finish(self, scope): # We better be exposed _somewhere_. if (len(self._exposureGlobalNames) == 0): - print self.identifier.name + print(self.identifier.name) assert len(self._exposureGlobalNames) != 0 IDLExposureMixins.finish(self, scope) @@ -4577,7 +4647,9 @@ class IDLArgument(IDLObjectWithIdentifier): elif identifier == "TreatNonCallableAsNull": self._allowTreatNonCallableAsNull = True elif (self.dictionaryMember and - (identifier == "ChromeOnly" or identifier == "Func")): + (identifier == "ChromeOnly" or + identifier == "Func" or + identifier == "Pref")): if not self.optional: raise WebIDLError("[%s] must not be used on a required " "dictionary member" % identifier, @@ -4609,14 +4681,7 @@ class IDLArgument(IDLObjectWithIdentifier): assert not isinstance(type.name, IDLUnresolvedIdentifier) self.type = type - if ((self.type.isDictionary() or - self.type.isUnion() and self.type.unroll().hasDictionaryType()) and - self.optional and not self.defaultValue and not self.variadic and - not self.dictionaryMember): - # Default optional non-variadic dictionary arguments to null, - # for simplicity, so the codegen doesn't have to special-case this. - self.defaultValue = IDLNullValue(self.location) - elif self.type.isAny(): + if self.type.isAny(): assert (self.defaultValue is None or isinstance(self.defaultValue, IDLNullValue)) # optional 'any' values always have a default value @@ -4648,7 +4713,7 @@ class IDLArgument(IDLObjectWithIdentifier): class IDLCallback(IDLObjectWithScope): - def __init__(self, location, parentScope, identifier, returnType, arguments): + def __init__(self, location, parentScope, identifier, returnType, arguments, isConstructor): assert isinstance(returnType, IDLType) self._returnType = returnType @@ -4663,10 +4728,15 @@ class IDLCallback(IDLObjectWithScope): self._treatNonCallableAsNull = False self._treatNonObjectAsNull = False + self._isRunScriptBoundary = False + self._isConstructor = isConstructor def isCallback(self): return True + def isConstructor(self): + return self._isConstructor + def signatures(self): return [(self._returnType, self._arguments)] @@ -4699,7 +4769,16 @@ class IDLCallback(IDLObjectWithScope): if attr.identifier() == "TreatNonCallableAsNull": self._treatNonCallableAsNull = True elif attr.identifier() == "TreatNonObjectAsNull": + if self._isConstructor: + raise WebIDLError("[TreatNonObjectAsNull] is not supported " + "on constructors", [self.location]) self._treatNonObjectAsNull = True + elif attr.identifier() == "MOZ_CAN_RUN_SCRIPT_BOUNDARY": + if self._isConstructor: + raise WebIDLError("[MOZ_CAN_RUN_SCRIPT_BOUNDARY] is not " + "permitted on constructors", + [self.location]) + self._isRunScriptBoundary = True else: unhandledAttrs.append(attr) if self._treatNonCallableAsNull and self._treatNonObjectAsNull: @@ -4711,6 +4790,9 @@ class IDLCallback(IDLObjectWithScope): def _getDependentObjects(self): return set([self._returnType] + self._arguments) + def isRunScriptBoundary(self): + return self._isRunScriptBoundary; + class IDLCallbackType(IDLType): def __init__(self, location, callback): @@ -4757,6 +4839,9 @@ class IDLMethodOverload: deps.add(self.returnType) return deps + def includesRestrictedFloatArgument(self): + return any(arg.type.includesRestrictedFloat() for arg in self.arguments) + class IDLMethod(IDLInterfaceMember, IDLScope): @@ -4928,10 +5013,25 @@ class IDLMethod(IDLInterfaceMember, IDLScope): def addOverload(self, method): assert len(method._overloads) == 1 - if self._extendedAttrDict != method ._extendedAttrDict: - raise WebIDLError("Extended attributes differ on different " - "overloads of %s" % method.identifier, - [self.location, method.location]) + if self._extendedAttrDict != method._extendedAttrDict: + extendedAttrDiff = set(self._extendedAttrDict.keys()) ^ set(method._extendedAttrDict.keys()) + + if extendedAttrDiff == { "LenientFloat" }: + if "LenientFloat" not in self._extendedAttrDict: + for overload in self._overloads: + if overload.includesRestrictedFloatArgument(): + raise WebIDLError("Restricted float behavior differs on different " + "overloads of %s" % method.identifier, + [overload.location, method.location]) + self._extendedAttrDict["LenientFloat"] = method._extendedAttrDict["LenientFloat"] + elif method._overloads[0].includesRestrictedFloatArgument(): + raise WebIDLError("Restricted float behavior differs on different " + "overloads of %s" % method.identifier, + [self.location, method.location]) + else: + raise WebIDLError("Extended attributes differ on different " + "overloads of %s" % method.identifier, + [self.location, method.location]) self._overloads.extend(method._overloads) @@ -5039,6 +5139,15 @@ class IDLMethod(IDLInterfaceMember, IDLScope): "must be optional", [argument.location]) + if (not argument.defaultValue and + all(arg.optional for arg in arguments[idx+1:])): + raise WebIDLError("Dictionary argument without any " + "required fields or union argument " + "containing such dictionary not " + "followed by a required argument " + "must have a default value", + [argument.location]) + # An argument cannot be a Nullable Dictionary if argument.type.nullable(): raise WebIDLError("An argument cannot be a nullable " @@ -5162,12 +5271,12 @@ class IDLMethod(IDLInterfaceMember, IDLScope): [attr.location, self.location]) elif identifier == "LenientFloat": # This is called before we've done overload resolution - assert len(self.signatures()) == 1 - sig = self.signatures()[0] - if not sig[0].isVoid(): + overloads = self._overloads + assert len(overloads) == 1 + if not overloads[0].returnType.isVoid(): raise WebIDLError("[LenientFloat] used on a non-void method", [attr.location, self.location]) - if not any(arg.type.includesRestrictedFloat() for arg in sig[1]): + if not overloads[0].includesRestrictedFloatArgument(): raise WebIDLError("[LenientFloat] used on an operation with no " "restricted float type arguments", [attr.location, self.location]) @@ -5238,7 +5347,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope): if self.signatures()[0][0] != BuiltinTypes[IDLBuiltinType.Types.object]: raise WebIDLError("The return type of the default toJSON " "operation must be 'object'", - [attr.location, self.location]); + [attr.location, self.location]) elif (identifier == "Throws" or identifier == "CanOOM" or identifier == "NewObject" or @@ -5251,7 +5360,8 @@ class IDLMethod(IDLInterfaceMember, IDLScope): identifier == "NeedsSubjectPrincipal" or identifier == "NeedsCallerType" or identifier == "StaticClassOverride" or - identifier == "NonEnumerable"): + identifier == "NonEnumerable" or + identifier == "Unexposed"): # Known attributes that we don't need to do anything with here pass else: @@ -5478,6 +5588,7 @@ class Tokenizer(object): "iterable": "ITERABLE", "namespace": "NAMESPACE", "ReadableStream": "READABLESTREAM", + "constructor": "CONSTRUCTOR", } tokens.extend(keywords.values()) @@ -5604,6 +5715,7 @@ class Parser(Tokenizer): def p_CallbackRestOrInterface(self, p): """ CallbackRestOrInterface : CallbackRest + | CallbackConstructorRest | Interface """ assert p[1] @@ -5637,7 +5749,7 @@ class Parser(Tokenizer): [location, existingObj.location]) existingObj.setNonPartial(*nonPartialArgs) return existingObj - except Exception, ex: + except Exception as ex: if isinstance(ex, WebIDLError): raise ex pass @@ -5675,7 +5787,7 @@ class Parser(Tokenizer): "%s and %s" % (identifier.name, p[0]), [location, p[0].location]) return - except Exception, ex: + except Exception as ex: if isinstance(ex, WebIDLError): raise ex pass @@ -5739,7 +5851,7 @@ class Parser(Tokenizer): "non-%s object" % (prettyname, prettyname), [location, nonPartialObject.location]) - except Exception, ex: + except Exception as ex: if isinstance(ex, WebIDLError): raise ex pass @@ -5905,12 +6017,23 @@ class Parser(Tokenizer): """ DefaultValue : ConstValue | LBRACKET RBRACKET + | LBRACE RBRACE """ if len(p) == 2: p[0] = p[1] else: - assert len(p) == 3 # Must be [] - p[0] = IDLEmptySequenceValue(self.getLocation(p, 1)) + assert len(p) == 3 # Must be [] or {} + if p[1] == "[": + p[0] = IDLEmptySequenceValue(self.getLocation(p, 1)) + else: + assert p[1] == "{" + p[0] = IDLDefaultDictionaryValue(self.getLocation(p, 1)) + + def p_DefaultValueNull(self, p): + """ + DefaultValue : NULL + """ + p[0] = IDLNullValue(self.getLocation(p, 1)) def p_Exception(self, p): """ @@ -5967,7 +6090,15 @@ class Parser(Tokenizer): """ identifier = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1]) p[0] = IDLCallback(self.getLocation(p, 1), self.globalScope(), - identifier, p[3], p[5]) + identifier, p[3], p[5], isConstructor=False) + + def p_CallbackConstructorRest(self, p): + """ + CallbackConstructorRest : CONSTRUCTOR IDENTIFIER EQUALS ReturnType LPAREN ArgumentList RPAREN SEMICOLON + """ + identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) + p[0] = IDLCallback(self.getLocation(p, 2), self.globalScope(), + identifier, p[4], p[6], isConstructor=True) def p_ExceptionMembers(self, p): """ @@ -6041,12 +6172,6 @@ class Parser(Tokenizer): stringType = BuiltinTypes[IDLBuiltinType.Types.domstring] p[0] = IDLValue(location, stringType, p[1]) - def p_ConstValueNull(self, p): - """ - ConstValue : NULL - """ - p[0] = IDLNullValue(self.getLocation(p, 1)) - def p_BooleanLiteralTrue(self, p): """ BooleanLiteral : TRUE @@ -6442,6 +6567,7 @@ class Parser(Tokenizer): | ATTRIBUTE | CALLBACK | CONST + | CONSTRUCTOR | DELETER | DICTIONARY | ENUM @@ -6566,6 +6692,7 @@ class Parser(Tokenizer): | BYTE | LEGACYCALLER | CONST + | CONSTRUCTOR | DELETER | DOUBLE | EXCEPTION @@ -6619,9 +6746,9 @@ class Parser(Tokenizer): """ p[0] = p[2].withExtendedAttributes(p[1]) - def p_SingleTypeNonAnyType(self, p): + def p_SingleTypeDistinguishableType(self, p): """ - SingleType : NonAnyType + SingleType : DistinguishableType """ p[0] = p[1] @@ -6631,6 +6758,14 @@ class Parser(Tokenizer): """ p[0] = BuiltinTypes[IDLBuiltinType.Types.any] + # Note: Promise<void> is allowed, so we want to parametrize on ReturnType, + # not Type. Promise types can't be null, hence no "Null" in there. + def p_SingleTypePromiseType(self, p): + """ + SingleType : PROMISE LT ReturnType GT + """ + p[0] = IDLPromiseType(self.getLocation(p, 1), p[3]) + def p_UnionType(self, p): """ UnionType : LPAREN UnionMemberType OR UnionMemberType UnionMemberTypes RPAREN @@ -6639,9 +6774,9 @@ class Parser(Tokenizer): types.extend(p[5]) p[0] = IDLUnionType(self.getLocation(p, 1), types) - def p_UnionMemberTypeNonAnyType(self, p): + def p_UnionMemberTypeDistinguishableType(self, p): """ - UnionMemberType : ExtendedAttributeList NonAnyType + UnionMemberType : ExtendedAttributeList DistinguishableType """ p[0] = p[2].withExtendedAttributes(p[1]) @@ -6664,13 +6799,13 @@ class Parser(Tokenizer): """ p[0] = [] - def p_NonAnyType(self, p): + def p_DistinguishableType(self, p): """ - NonAnyType : PrimitiveType Null - | ARRAYBUFFER Null - | SHAREDARRAYBUFFER Null - | READABLESTREAM Null - | OBJECT Null + DistinguishableType : PrimitiveType Null + | ARRAYBUFFER Null + | SHAREDARRAYBUFFER Null + | READABLESTREAM Null + | OBJECT Null """ if p[1] == "object": type = BuiltinTypes[IDLBuiltinType.Types.object] @@ -6685,40 +6820,32 @@ class Parser(Tokenizer): p[0] = self.handleNullable(type, p[2]) - def p_NonAnyTypeStringType(self, p): + def p_DistinguishableTypeStringType(self, p): """ - NonAnyType : StringType Null + DistinguishableType : StringType Null """ p[0] = self.handleNullable(p[1], p[2]) - def p_NonAnyTypeSequenceType(self, p): + def p_DistinguishableTypeSequenceType(self, p): """ - NonAnyType : SEQUENCE LT TypeWithExtendedAttributes GT Null + DistinguishableType : SEQUENCE LT TypeWithExtendedAttributes GT Null """ innerType = p[3] type = IDLSequenceType(self.getLocation(p, 1), innerType) p[0] = self.handleNullable(type, p[5]) - # Note: Promise<void> is allowed, so we want to parametrize on ReturnType, - # not Type. Promise types can't be null, hence no "Null" in there. - def p_NonAnyTypePromiseType(self, p): + def p_DistinguishableTypeRecordType(self, p): """ - NonAnyType : PROMISE LT ReturnType GT - """ - p[0] = IDLPromiseType(self.getLocation(p, 1), p[3]) - - def p_NonAnyTypeRecordType(self, p): - """ - NonAnyType : RECORD LT StringType COMMA TypeWithExtendedAttributes GT Null + DistinguishableType : RECORD LT StringType COMMA TypeWithExtendedAttributes GT Null """ keyType = p[3] valueType = p[5] type = IDLRecordType(self.getLocation(p, 1), keyType, valueType) p[0] = self.handleNullable(type, p[7]) - def p_NonAnyTypeScopedName(self, p): + def p_DistinguishableTypeScopedName(self, p): """ - NonAnyType : ScopedName Null + DistinguishableType : ScopedName Null """ assert isinstance(p[1], IDLUnresolvedIdentifier) @@ -6748,28 +6875,26 @@ class Parser(Tokenizer): type = IDLUnresolvedType(self.getLocation(p, 1), p[1]) p[0] = self.handleNullable(type, p[2]) - def p_NonAnyTypeDate(self, p): + def p_DistinguishableTypeDate(self, p): """ - NonAnyType : DATE Null + DistinguishableType : DATE Null """ p[0] = self.handleNullable(BuiltinTypes[IDLBuiltinType.Types.date], p[2]) def p_ConstType(self, p): """ - ConstType : PrimitiveType Null + ConstType : PrimitiveType """ - type = BuiltinTypes[p[1]] - p[0] = self.handleNullable(type, p[2]) + p[0] = BuiltinTypes[p[1]] def p_ConstTypeIdentifier(self, p): """ - ConstType : IDENTIFIER Null + ConstType : IDENTIFIER """ identifier = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1]) - type = IDLUnresolvedType(self.getLocation(p, 1), identifier) - p[0] = self.handleNullable(type, p[2]) + p[0] = IDLUnresolvedType(self.getLocation(p, 1), identifier) def p_PrimitiveTypeUint(self, p): """ @@ -7040,8 +7165,8 @@ class Parser(Tokenizer): def _installBuiltins(self, scope): assert isinstance(scope, IDLScope) - # xrange omits the last value. - for x in xrange(IDLBuiltinType.Types.ArrayBuffer, IDLBuiltinType.Types.Float64Array + 1): + # range omits the last value. + for x in range(IDLBuiltinType.Types.ArrayBuffer, IDLBuiltinType.Types.Float64Array + 1): builtin = BuiltinTypes[x] name = builtin.name typedef = IDLTypedef(BuiltinLocation("<builtin type>"), scope, builtin, name) @@ -7185,14 +7310,14 @@ def main(): f = open(fullPath, 'rb') lines = f.readlines() f.close() - print fullPath + print(fullPath) parser.parse(''.join(lines), fullPath) parser.finish() - except WebIDLError, e: + except WebIDLError as e: if options.verbose_errors: traceback.print_exc() else: - print e + print(e) if __name__ == '__main__': main() diff --git a/components/script/dom/bindings/codegen/parser/abstract.patch b/components/script/dom/bindings/codegen/parser/abstract.patch index 8e6c272b2c5..e2db398a051 100644 --- a/components/script/dom/bindings/codegen/parser/abstract.patch +++ b/components/script/dom/bindings/codegen/parser/abstract.patch @@ -1,12 +1,12 @@ --- WebIDL.py +++ WebIDL.py -@@ -1786,7 +1786,8 @@ class IDLInterface(IDLInterfaceOrNamespace): - identifier == "ProbablyShortLivingWrapper" or +@@ -1768,7 +1768,8 @@ class IDLInterface(IDLInterfaceOrNamespace): identifier == "LegacyUnenumerableNamedProperties" or identifier == "RunConstructorInCallerCompartment" or -- identifier == "WantsEventListenerHooks"): -+ identifier == "WantsEventListenerHooks" or + identifier == "WantsEventListenerHooks" or +- identifier == "Serializable"): ++ identifier == "Serializable" or + identifier == "Abstract"): # Known extended attributes that do not take values if not attr.noArguments(): - raise WebIDLError("[%s] must take no arguments" % identifier,
\ No newline at end of file + raise WebIDLError("[%s] must take no arguments" % identifier, diff --git a/components/script/dom/bindings/codegen/parser/callback-location.patch b/components/script/dom/bindings/codegen/parser/callback-location.patch index 00b3b034396..b7a308df631 100644 --- a/components/script/dom/bindings/codegen/parser/callback-location.patch +++ b/components/script/dom/bindings/codegen/parser/callback-location.patch @@ -1,7 +1,7 @@ --- WebIDL.py +++ WebIDL.py -@@ -2275,7 +2275,7 @@ class IDLUnresolvedType(IDLType): - return typedefType.complete(scope) +@@ -2283,7 +2283,7 @@ class IDLUnresolvedType(IDLType): + return typedefType.complete(scope).withExtendedAttributes(self.extraTypeAttributes) elif obj.isCallback() and not obj.isInterface(): assert self.name.name == obj.identifier.name - return IDLCallbackType(self.location, obj) @@ -9,7 +9,7 @@ name = self.name.resolve(scope, None) return IDLWrapperType(self.location, obj) -@@ -6688,7 +6688,7 @@ class Parser(Tokenizer): +@@ -6854,7 +6854,7 @@ class Parser(Tokenizer): type = IDLTypedefType(self.getLocation(p, 1), obj.innerType, obj.identifier.name) elif obj.isCallback() and not obj.isInterface(): diff --git a/components/script/dom/bindings/codegen/parser/debug.patch b/components/script/dom/bindings/codegen/parser/debug.patch index 49cb962cbba..f9b3d940399 100644 --- a/components/script/dom/bindings/codegen/parser/debug.patch +++ b/components/script/dom/bindings/codegen/parser/debug.patch @@ -1,6 +1,6 @@ --- WebIDL.py +++ WebIDL.py -@@ -6959,7 +6959,8 @@ class Parser(Tokenizer): +@@ -7123,7 +7123,8 @@ class Parser(Tokenizer): self.parser = yacc.yacc(module=self, outputdir=outputdir, tabmodule='webidlyacc', diff --git a/components/script/dom/bindings/codegen/parser/inline.patch b/components/script/dom/bindings/codegen/parser/inline.patch index e2b16f9b158..8337effd0f1 100644 --- a/components/script/dom/bindings/codegen/parser/inline.patch +++ b/components/script/dom/bindings/codegen/parser/inline.patch @@ -1,9 +1,9 @@ --- WebIDL.py +++ WebIDL.py -@@ -1787,7 +1787,8 @@ class IDLInterface(IDLInterfaceOrNamespace): - identifier == "LegacyUnenumerableNamedProperties" or +@@ -1769,7 +1769,8 @@ class IDLInterface(IDLInterfaceOrNamespace): identifier == "RunConstructorInCallerCompartment" or identifier == "WantsEventListenerHooks" or + identifier == "Serializable" or - identifier == "Abstract"): + identifier == "Abstract" or + identifier == "Inline"): diff --git a/components/script/dom/bindings/codegen/parser/pref-main-thread.patch b/components/script/dom/bindings/codegen/parser/pref-main-thread.patch deleted file mode 100644 index a90d0593693..00000000000 --- a/components/script/dom/bindings/codegen/parser/pref-main-thread.patch +++ /dev/null @@ -1,27 +0,0 @@ ---- WebIDL.py -+++ WebIDL.py -@@ -1362,12 +1362,6 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): - for bindingAlias in member.bindingAliases: - checkDuplicateNames(member, bindingAlias, "BindingAlias") - -- -- if self.getExtendedAttribute("Pref") and self.isExposedOffMainThread(): -- raise WebIDLError("[Pref] used on an interface that is not " -- "main-thread-only", -- [self.location]) -- - # Conditional exposure makes no sense for interfaces with no - # interface object, unless they're navigator properties. - # And SecureContext makes sense for interfaces with no interface object, -@@ -3619,11 +3613,6 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins): - IDLExposureMixins.finish(self, scope) - - def validate(self): -- if self.getExtendedAttribute("Pref") and self.isExposedOffMainThread(): -- raise WebIDLError("[Pref] used on an interface member that is not " -- "main-thread-only", -- [self.location]) -- - if self.isAttr() or self.isMethod(): - if self.affects == "Everything" and self.dependsOn != "Everything": - raise WebIDLError("Interface member is flagged as affecting " diff --git a/components/script/dom/bindings/codegen/parser/runtests.py b/components/script/dom/bindings/codegen/parser/runtests.py index 10dbc3292f7..0599bf55fec 100644 --- a/components/script/dom/bindings/codegen/parser/runtests.py +++ b/components/script/dom/bindings/codegen/parser/runtests.py @@ -62,7 +62,7 @@ def run_tests(tests, verbose): harness.start() try: _test.WebIDLTest.__call__(WebIDL.Parser(), harness) - except Exception, ex: + except Exception as ex: print("TEST-UNEXPECTED-FAIL | Unhandled exception in test %s: %s" % (testpath, ex)) traceback.print_exc() finally: diff --git a/components/script/dom/bindings/codegen/parser/tests/test_attr.py b/components/script/dom/bindings/codegen/parser/tests/test_attr.py index ad7aabc1918..35f680aaa82 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_attr.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_attr.py @@ -133,7 +133,7 @@ def WebIDLTest(parser, harness): }; """) results = parser.finish() - except Exception, x: + except Exception as x: threw = True harness.ok(threw, "Should not allow [SetterThrows] on readonly attributes") @@ -146,7 +146,7 @@ def WebIDLTest(parser, harness): }; """) results = parser.finish() - except Exception, x: + except Exception as x: threw = True harness.ok(threw, "Should spell [Throws] correctly") @@ -159,7 +159,7 @@ def WebIDLTest(parser, harness): }; """) results = parser.finish() - except Exception, x: + except Exception as x: threw = True harness.ok(threw, "Should not allow [SameObject] on attributes not of interface type") @@ -172,6 +172,6 @@ def WebIDLTest(parser, harness): }; """) results = parser.finish() - except Exception, x: + except Exception as x: threw = True harness.ok(not threw, "Should allow [SameObject] on attributes of interface type") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_callback.py b/components/script/dom/bindings/codegen/parser/tests/test_callback.py index 4dfda1c3c76..c304d085ce5 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_callback.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_callback.py @@ -32,3 +32,6 @@ def WebIDLTest(parser, harness): harness.ok(not isinstance(t, WebIDL.IDLWrapperType), "Attr has the right type") harness.ok(isinstance(t, WebIDL.IDLNullableType), "Attr has the right type") harness.ok(t.isCallback(), "Attr has the right type") + + callback = results[1] + harness.ok(not callback.isConstructor(), "callback is not constructor") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_callback_constructor.py b/components/script/dom/bindings/codegen/parser/tests/test_callback_constructor.py new file mode 100644 index 00000000000..4999deef623 --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_callback_constructor.py @@ -0,0 +1,63 @@ +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse(""" + interface TestCallbackConstructor { + attribute CallbackConstructorType? constructorAttribute; + }; + + callback constructor CallbackConstructorType = TestCallbackConstructor (unsigned long arg); + """) + + results = parser.finish() + + harness.ok(True, "TestCallbackConstructor interface parsed without error.") + harness.check(len(results), 2, "Should be two productions.") + iface = results[0] + harness.ok(isinstance(iface, WebIDL.IDLInterface), + "Should be an IDLInterface") + harness.check(iface.identifier.QName(), "::TestCallbackConstructor", "Interface has the right QName") + harness.check(iface.identifier.name, "TestCallbackConstructor", "Interface has the right name") + harness.check(len(iface.members), 1, "Expect %s members" % 1) + + attr = iface.members[0] + harness.ok(isinstance(attr, WebIDL.IDLAttribute), + "Should be an IDLAttribute") + harness.ok(attr.isAttr(), "Should be an attribute") + harness.ok(not attr.isMethod(), "Attr is not an method") + harness.ok(not attr.isConst(), "Attr is not a const") + harness.check(attr.identifier.QName(), "::TestCallbackConstructor::constructorAttribute", "Attr has the right QName") + harness.check(attr.identifier.name, "constructorAttribute", "Attr has the right name") + t = attr.type + harness.ok(not isinstance(t, WebIDL.IDLWrapperType), "Attr has the right type") + harness.ok(isinstance(t, WebIDL.IDLNullableType), "Attr has the right type") + harness.ok(t.isCallback(), "Attr has the right type") + + callback = results[1] + harness.ok(callback.isConstructor(), "Callback is constructor") + + parser.reset() + threw = False + try: + parser.parse(""" + [TreatNonObjectAsNull] + callback constructor CallbackConstructorType = object (); + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should throw on TreatNonObjectAsNull callback constructors") + + parser.reset() + threw = False + try: + parser.parse(""" + [MOZ_CAN_RUN_SCRIPT_BOUNDARY] + callback constructor CallbackConstructorType = object (); + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should not permit MOZ_CAN_RUN_SCRIPT_BOUNDARY callback constructors") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_cereactions.py b/components/script/dom/bindings/codegen/parser/tests/test_cereactions.py index dba16f53302..f726907c2fc 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_cereactions.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_cereactions.py @@ -38,7 +38,7 @@ def WebIDLTest(parser, harness): """) results = parser.finish() - except Exception, e: + except Exception as e: harness.ok(False, "Shouldn't have thrown for [CEReactions] used on writable attribute. %s" % e) threw = True @@ -52,7 +52,7 @@ def WebIDLTest(parser, harness): """) results = parser.finish() - except Exception, e: + except Exception as e: harness.ok(False, "Shouldn't have thrown for [CEReactions] used on regular operations. %s" % e) threw = True diff --git a/components/script/dom/bindings/codegen/parser/tests/test_conditional_dictionary_member.py b/components/script/dom/bindings/codegen/parser/tests/test_conditional_dictionary_member.py index 433b7e501a4..066300e8bb4 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_conditional_dictionary_member.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_conditional_dictionary_member.py @@ -44,7 +44,7 @@ def WebIDLTest(parser, harness): }; """) results = parser.finish() - except Exception, exception: + except Exception as exception: pass harness.ok(exception, "Should have thrown.") @@ -70,7 +70,7 @@ def WebIDLTest(parser, harness): }; """) results = parser.finish() - except Exception, exception: + except Exception as exception: pass harness.ok(exception, "Should have thrown (2).") @@ -100,7 +100,7 @@ def WebIDLTest(parser, harness): }; """) results = parser.finish() - except Exception, exception: + except Exception as exception: pass harness.ok(exception, "Should have thrown (3).") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_const.py b/components/script/dom/bindings/codegen/parser/tests/test_const.py index 80b6fb0e9c8..918f284a226 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_const.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_const.py @@ -12,9 +12,6 @@ expected = [ ("::TestConsts::ll", "ll", "LongLong", -8), ("::TestConsts::t", "t", "Boolean", True), ("::TestConsts::f", "f", "Boolean", False), - ("::TestConsts::n", "n", "BooleanOrNull", None), - ("::TestConsts::nt", "nt", "BooleanOrNull", True), - ("::TestConsts::nf", "nf", "BooleanOrNull", False), ("::TestConsts::fl", "fl", "Float", 0.2), ("::TestConsts::db", "db", "Double", 0.2), ("::TestConsts::ufl", "ufl", "UnrestrictedFloat", 0.2), @@ -39,9 +36,6 @@ def WebIDLTest(parser, harness): const long long ll = -010; const boolean t = true; const boolean f = false; - const boolean? n = null; - const boolean? nt = true; - const boolean? nf = false; const float fl = 0.2; const double db = 0.2; const unrestricted float ufl = 0.2; @@ -78,3 +72,16 @@ def WebIDLTest(parser, harness): "Const's value has the same type as the type") harness.check(const.value.value, value, "Const value has the right value.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface TestConsts { + const boolean? zero = 0; + }; + """) + parser.finish() + except: + threw = True + harness.ok(threw, "Nullable types are not allowed for consts.") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_constructor_global.py b/components/script/dom/bindings/codegen/parser/tests/test_constructor_global.py new file mode 100644 index 00000000000..14d42caf09c --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_constructor_global.py @@ -0,0 +1,87 @@ +def WebIDLTest(parser, harness): + threw = False + try: + parser.parse(""" + [Constructor, Global] + interface TestConstructorGlobal { + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Global, Constructor] + interface TestConstructorGlobal { + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Global, NamedConstructor=FooBar] + interface TestNamedConstructorGlobal { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [NamedConstructor=FooBar, Global] + interface TestNamedConstructorGlobal { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Global, HTMLConstructor] + interface TestHTMLConstructorGlobal { + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [HTMLConstructor, Global] + interface TestHTMLConstructorGlobal { + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_constructor_no_interface_object.py b/components/script/dom/bindings/codegen/parser/tests/test_constructor_no_interface_object.py index 40708e7870e..e5413350a28 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_constructor_no_interface_object.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_constructor_no_interface_object.py @@ -13,6 +13,7 @@ def WebIDLTest(parser, harness): harness.ok(threw, "Should have thrown.") + parser = parser.reset() threw = False try: parser.parse(""" diff --git a/components/script/dom/bindings/codegen/parser/tests/test_dictionary.py b/components/script/dom/bindings/codegen/parser/tests/test_dictionary.py index 361b83ea52b..770f76b22f0 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_dictionary.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_dictionary.py @@ -174,6 +174,22 @@ def WebIDLTest(parser, harness): dictionary A { }; interface X { + void doFoo(optional A arg); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Trailing dictionary arg must have a default value") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary A { + }; + interface X { void doFoo((A or DOMString) arg); }; """) @@ -191,6 +207,23 @@ def WebIDLTest(parser, harness): dictionary A { }; interface X { + void doFoo(optional (A or DOMString) arg); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Trailing union arg containing a dictionary must have a default value") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary A { + }; + interface X { void doFoo(A arg1, optional long arg2); }; """) @@ -207,6 +240,22 @@ def WebIDLTest(parser, harness): dictionary A { }; interface X { + void doFoo(optional A arg1, optional long arg2); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Dictionary arg followed by optional arg must have default value") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary A { + }; + interface X { void doFoo(A arg1, optional long arg2, long arg3); }; """) @@ -236,6 +285,24 @@ def WebIDLTest(parser, harness): "be optional") parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary A { + }; + interface X { + void doFoo(optional (A or DOMString) arg1, optional long arg2); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Union arg containing dictionary followed by optional arg must " + "have a default value") + + parser = parser.reset() parser.parse(""" dictionary A { }; @@ -326,7 +393,7 @@ def WebIDLTest(parser, harness): dictionary A { }; interface X { - void doFoo(optional A arg); + void doFoo(optional A arg = {}); }; """) results = parser.finish() @@ -337,13 +404,24 @@ def WebIDLTest(parser, harness): dictionary A { }; interface X { - void doFoo(optional (A or DOMString) arg); + void doFoo(optional (A or DOMString) arg = {}); }; """) results = parser.finish() harness.ok(True, "Union arg containing a dictionary should actually parse") parser = parser.reset() + parser.parse(""" + dictionary A { + }; + interface X { + void doFoo(optional (A or DOMString) arg = "abc"); + }; + """) + results = parser.finish() + harness.ok(True, "Union arg containing a dictionary with string default should actually parse") + + parser = parser.reset() threw = False try: parser.parse(""" diff --git a/components/script/dom/bindings/codegen/parser/tests/test_distinguishability.py b/components/script/dom/bindings/codegen/parser/tests/test_distinguishability.py index 73a32b0acfb..e88c2b50d98 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_distinguishability.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_distinguishability.py @@ -3,13 +3,16 @@ def firstArgType(method): def WebIDLTest(parser, harness): parser.parse(""" + // Give our dictionary a required member so we don't need to + // mess with optional and default values. dictionary Dict { + required long member; }; callback interface Foo { }; interface Bar { // Bit of a pain to get things that have dictionary types - void passDict(optional Dict arg); + void passDict(Dict arg); void passFoo(Foo arg); void passNullableUnion((object? or DOMString) arg); void passNullable(Foo? arg); @@ -156,8 +159,8 @@ def WebIDLTest(parser, harness): "AncestorInterface", "UnrelatedInterface", "ImplementedInterface", "CallbackInterface", "CallbackInterface?", "CallbackInterface2", - "object", "Callback", "Callback2", "optional Dict", - "optional Dict2", "sequence<long>", "sequence<short>", + "object", "Callback", "Callback2", "Dict", + "Dict2", "sequence<long>", "sequence<short>", "record<DOMString, object>", "record<USVString, Dict>", "record<ByteString, long>", @@ -165,7 +168,7 @@ def WebIDLTest(parser, harness): "Promise<any>", "Promise<any>?", "USVString", "ArrayBuffer", "ArrayBufferView", "SharedArrayBuffer", "Uint8Array", "Uint16Array", - "(long or Callback)", "optional (long or Dict)", + "(long or Callback)", "(long or Dict)", ] # When we can parse Date, we need to add it here. # XXXbz we can, and should really do that... @@ -174,7 +177,7 @@ def WebIDLTest(parser, harness): def allBut(list1, list2): return [a for a in list1 if a not in list2 and (a != "any" and a != "Promise<any>" and a != "Promise<any>?")] - unions = [ "(long or Callback)", "optional (long or Dict)" ] + unions = [ "(long or Callback)", "(long or Dict)" ] numerics = [ "long", "short", "long?", "short?" ] booleans = [ "boolean", "boolean?" ] primitives = numerics + booleans @@ -189,7 +192,7 @@ def WebIDLTest(parser, harness): interfaces = [ "Interface", "Interface?", "AncestorInterface", "UnrelatedInterface", "ImplementedInterface" ] + bufferSourceTypes + sharedBufferSourceTypes nullables = (["long?", "short?", "boolean?", "Interface?", - "CallbackInterface?", "optional Dict", "optional Dict2", + "CallbackInterface?", "Dict", "Dict2", "Date?", "any", "Promise<any>?"] + allBut(unions, [ "(long or Callback)" ])) dates = [ "Date", "Date?" ] @@ -233,8 +236,8 @@ def WebIDLTest(parser, harness): setDistinguishable("object", nonObjects) setDistinguishable("Callback", nonUserObjects) setDistinguishable("Callback2", nonUserObjects) - setDistinguishable("optional Dict", allBut(nonUserObjects, nullables)) - setDistinguishable("optional Dict2", allBut(nonUserObjects, nullables)) + setDistinguishable("Dict", allBut(nonUserObjects, nullables)) + setDistinguishable("Dict2", allBut(nonUserObjects, nullables)) setDistinguishable("sequence<long>", allBut(argTypes, sequences + ["object"])) setDistinguishable("sequence<short>", @@ -254,7 +257,7 @@ def WebIDLTest(parser, harness): setDistinguishable("SharedArrayBuffer", allBut(argTypes, ["SharedArrayBuffer", "object"])) setDistinguishable("(long or Callback)", allBut(nonUserObjects, numerics)) - setDistinguishable("optional (long or Dict)", + setDistinguishable("(long or Dict)", allBut(nonUserObjects, numerics + nullables)) def areDistinguishable(type1, type2): @@ -273,8 +276,10 @@ def WebIDLTest(parser, harness): callback interface CallbackInterface2 {}; callback Callback = any(); callback Callback2 = long(short arg); - dictionary Dict {}; - dictionary Dict2 {}; + // Give our dictionaries required members so we don't need to + // mess with optional and default values. + dictionary Dict { required long member; }; + dictionary Dict2 { required long member; }; interface TestInterface {%s }; """ diff --git a/components/script/dom/bindings/codegen/parser/tests/test_empty_sequence_default_value.py b/components/script/dom/bindings/codegen/parser/tests/test_empty_sequence_default_value.py index 350ae72f022..a713266c88e 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_empty_sequence_default_value.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_empty_sequence_default_value.py @@ -10,7 +10,7 @@ def WebIDLTest(parser, harness): """) results = parser.finish() - except Exception,x: + except Exception as x: threw = True harness.ok(threw, "Constant cannot have [] as a default value") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_error_colno.py b/components/script/dom/bindings/codegen/parser/tests/test_error_colno.py index ca0674aec04..7afd15513c6 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_error_colno.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_error_colno.py @@ -8,7 +8,7 @@ def WebIDLTest(parser, harness): try: parser.parse(input) results = parser.finish() - except WebIDL.WebIDLError, e: + except WebIDL.WebIDLError as e: threw = True lines = str(e).split('\n') diff --git a/components/script/dom/bindings/codegen/parser/tests/test_error_lineno.py b/components/script/dom/bindings/codegen/parser/tests/test_error_lineno.py index f11222e7a4d..70bb1883682 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_error_lineno.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_error_lineno.py @@ -14,7 +14,7 @@ interface ?""" try: parser.parse(input) results = parser.finish() - except WebIDL.WebIDLError, e: + except WebIDL.WebIDLError as e: threw = True lines = str(e).split('\n') diff --git a/components/script/dom/bindings/codegen/parser/tests/test_exposed_extended_attribute.py b/components/script/dom/bindings/codegen/parser/tests/test_exposed_extended_attribute.py index 48957098bfe..a6c04e30caf 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_exposed_extended_attribute.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_exposed_extended_attribute.py @@ -124,7 +124,7 @@ def WebIDLTest(parser, harness): """) results = parser.finish() - except Exception,x: + except Exception as x: threw = True harness.ok(threw, "Should have thrown on invalid Exposed value on interface.") @@ -140,7 +140,7 @@ def WebIDLTest(parser, harness): """) results = parser.finish() - except Exception,x: + except Exception as x: threw = True harness.ok(threw, "Should have thrown on invalid Exposed value on attribute.") @@ -156,7 +156,7 @@ def WebIDLTest(parser, harness): """) results = parser.finish() - except Exception,x: + except Exception as x: threw = True harness.ok(threw, "Should have thrown on invalid Exposed value on operation.") @@ -172,7 +172,7 @@ def WebIDLTest(parser, harness): """) results = parser.finish() - except Exception,x: + except Exception as x: threw = True harness.ok(threw, "Should have thrown on invalid Exposed value on constant.") @@ -192,7 +192,7 @@ def WebIDLTest(parser, harness): """) results = parser.finish() - except Exception,x: + except Exception as x: threw = True harness.ok(threw, "Should have thrown on member exposed where its interface is not.") @@ -216,7 +216,7 @@ def WebIDLTest(parser, harness): """) results = parser.finish() - except Exception,x: + except Exception as x: threw = True harness.ok(threw, "Should have thrown on LHS of implements being exposed where RHS is not.") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_float_types.py b/components/script/dom/bindings/codegen/parser/tests/test_float_types.py index 718f09c114b..b7325cf9d26 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_float_types.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_float_types.py @@ -68,7 +68,7 @@ def WebIDLTest(parser, harness): long m(float arg); }; """) - except Exception, x: + except Exception as x: threw = True harness.ok(threw, "[LenientFloat] only allowed on void methods") @@ -81,7 +81,7 @@ def WebIDLTest(parser, harness): void m(unrestricted float arg); }; """) - except Exception, x: + except Exception as x: threw = True harness.ok(threw, "[LenientFloat] only allowed on methods with unrestricted float args") @@ -94,7 +94,7 @@ def WebIDLTest(parser, harness): void m(sequence<unrestricted float> arg); }; """) - except Exception, x: + except Exception as x: threw = True harness.ok(threw, "[LenientFloat] only allowed on methods with unrestricted float args (2)") @@ -107,7 +107,7 @@ def WebIDLTest(parser, harness): void m((unrestricted float or FloatTypes) arg); }; """) - except Exception, x: + except Exception as x: threw = True harness.ok(threw, "[LenientFloat] only allowed on methods with unrestricted float args (3)") @@ -120,6 +120,6 @@ def WebIDLTest(parser, harness): readonly attribute float foo; }; """) - except Exception, x: + except Exception as x: threw = True harness.ok(threw, "[LenientFloat] only allowed on writable attributes") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_identifier_conflict.py b/components/script/dom/bindings/codegen/parser/tests/test_identifier_conflict.py index b510a30c044..0e9a6654aa7 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_identifier_conflict.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_identifier_conflict.py @@ -9,7 +9,7 @@ def WebIDLTest(parser, harness): """) results = parser.finish() harness.ok(False, "Should fail to parse") - except Exception, e: + except Exception as e: harness.ok("Name collision" in e.message, "Should have name collision for interface") @@ -21,7 +21,7 @@ def WebIDLTest(parser, harness): """) results = parser.finish() harness.ok(False, "Should fail to parse") - except Exception, e: + except Exception as e: harness.ok("Name collision" in e.message, "Should have name collision for dictionary") @@ -33,7 +33,7 @@ def WebIDLTest(parser, harness): """) results = parser.finish() harness.ok(False, "Should fail to parse") - except Exception, e: + except Exception as e: harness.ok("Multiple unresolvable definitions" in e.message, "Should have name collision for dictionary") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_interface.py b/components/script/dom/bindings/codegen/parser/tests/test_interface.py index a23243abe61..ea3e842907a 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_interface.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_interface.py @@ -374,3 +374,89 @@ def WebIDLTest(parser, harness): threw = True harness.ok(threw, "Should not allow unknown extended attributes on interfaces") + + parser = parser.reset() + parser.parse(""" + [Global] interface Window {}; + [Exposed=Window, LegacyWindowAlias=A] + interface B {}; + [Exposed=Window, LegacyWindowAlias=(C, D)] + interface E {}; + """); + results = parser.finish(); + harness.check(results[1].legacyWindowAliases, ["A"], + "Should support a single identifier") + harness.check(results[2].legacyWindowAliases, ["C", "D"], + "Should support an identifier list") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [LegacyWindowAlias] + interface A {}; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should not allow [LegacyWindowAlias] with no value") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Exposed=Worker, LegacyWindowAlias=B] + interface A {}; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should not allow [LegacyWindowAlias] without Window exposure") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Global] interface Window {}; + interface A {}; + [Exposed=Window, LegacyWindowAlias=A] + interface B {}; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should not allow [LegacyWindowAlias] to conflict with other identifiers") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Global] interface Window {}; + [Exposed=Window, LegacyWindowAlias=A] + interface B {}; + interface A {}; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should not allow [LegacyWindowAlias] to conflict with other identifiers") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Global] interface Window {}; + [Exposed=Window, LegacyWindowAlias=A] + interface B {}; + [Exposed=Window, LegacyWindowAlias=A] + interface C {}; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should not allow [LegacyWindowAlias] to conflict with other identifiers") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_interface_maplikesetlikeiterable.py b/components/script/dom/bindings/codegen/parser/tests/test_interface_maplikesetlikeiterable.py index ee5d870c200..72aa7617b84 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_interface_maplikesetlikeiterable.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_interface_maplikesetlikeiterable.py @@ -37,10 +37,10 @@ def WebIDLTest(parser, harness): p.finish() harness.ok(False, prefix + " - Interface passed when should've failed") - except WebIDL.WebIDLError, e: + except WebIDL.WebIDLError as e: harness.ok(True, prefix + " - Interface failed as expected") - except Exception, e: + except Exception as e: harness.ok(False, prefix + " - Interface failed but not as a WebIDLError exception: %s" % e) diff --git a/components/script/dom/bindings/codegen/parser/tests/test_lenientSetter.py b/components/script/dom/bindings/codegen/parser/tests/test_lenientSetter.py index 50e9df658e9..78a9ffe9eaa 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_lenientSetter.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_lenientSetter.py @@ -1,6 +1,6 @@ # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# file, You can obtain one at http://mozilla.org/MPL/2.0/. def should_throw(parser, harness, message, code): parser = parser.reset(); diff --git a/components/script/dom/bindings/codegen/parser/tests/test_method.py b/components/script/dom/bindings/codegen/parser/tests/test_method.py index 29e6d6b25b7..88ee874386c 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_method.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_method.py @@ -120,7 +120,7 @@ def WebIDLTest(parser, harness): }; """) results = parser.finish() - except Exception, x: + except Exception as x: threw = True harness.ok(not threw, "Should allow integer to float type corecion") @@ -133,7 +133,7 @@ def WebIDLTest(parser, harness): }; """) results = parser.finish() - except Exception, x: + except Exception as x: threw = True harness.ok(threw, "Should not allow [GetterThrows] on methods") @@ -146,7 +146,7 @@ def WebIDLTest(parser, harness): }; """) results = parser.finish() - except Exception, x: + except Exception as x: threw = True harness.ok(threw, "Should not allow [SetterThrows] on methods") @@ -159,7 +159,7 @@ def WebIDLTest(parser, harness): }; """) results = parser.finish() - except Exception, x: + except Exception as x: threw = True harness.ok(threw, "Should spell [Throws] correctly on methods") @@ -172,6 +172,85 @@ def WebIDLTest(parser, harness): }; """) results = parser.finish() - except Exception, x: + except Exception as x: threw = True harness.ok(threw, "Should not allow __noSuchMethod__ methods") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A { + [Throws, LenientFloat] + void foo(float myFloat); + [Throws] + void foo(); + }; + """) + results = parser.finish() + except Exception as x: + threw = True + harness.ok(not threw, "Should allow LenientFloat to be only in a specific overload") + + parser = parser.reset() + parser.parse(""" + interface A { + [Throws] + void foo(); + [Throws, LenientFloat] + void foo(float myFloat); + }; + """) + results = parser.finish() + iface = results[0] + methods = iface.members + lenientFloat = methods[0].getExtendedAttribute("LenientFloat") + harness.ok(lenientFloat is not None, "LenientFloat in overloads must be added to the method") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A { + [Throws, LenientFloat] + void foo(float myFloat); + [Throws] + void foo(float myFloat, float yourFloat); + }; + """) + results = parser.finish() + except Exception as x: + threw = True + harness.ok(threw, "Should prevent overloads from getting different restricted float behavior") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A { + [Throws] + void foo(float myFloat, float yourFloat); + [Throws, LenientFloat] + void foo(float myFloat); + }; + """) + results = parser.finish() + except Exception as x: + threw = True + harness.ok(threw, "Should prevent overloads from getting different restricted float behavior (2)") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A { + [Throws, LenientFloat] + void foo(float myFloat); + [Throws, LenientFloat] + void foo(short myShort); + }; + """) + results = parser.finish() + except Exception as x: + threw = True + harness.ok(threw, "Should prevent overloads from getting redundant [LenientFloat]") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_namespace.py b/components/script/dom/bindings/codegen/parser/tests/test_namespace.py index 74533a1770e..62edb270c63 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_namespace.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_namespace.py @@ -70,7 +70,7 @@ def WebIDLTest(parser, harness): """) results = parser.finish() - except Exception, x: + except Exception as x: threw = True harness.ok(threw, "Should have thrown.") @@ -85,7 +85,7 @@ def WebIDLTest(parser, harness): """) results = parser.finish() - except Exception, x: + except Exception as x: threw = True harness.ok(threw, "Should have thrown.") @@ -104,7 +104,7 @@ def WebIDLTest(parser, harness): """) results = parser.finish() - except Exception, x: + except Exception as x: threw = True harness.ok(threw, "Should have thrown.") @@ -123,7 +123,7 @@ def WebIDLTest(parser, harness): """) results = parser.finish() - except Exception, x: + except Exception as x: threw = True harness.ok(threw, "Should have thrown.") @@ -142,7 +142,7 @@ def WebIDLTest(parser, harness): """) results = parser.finish() - except Exception, x: + except Exception as x: threw = True harness.ok(threw, "Should have thrown.") @@ -161,7 +161,7 @@ def WebIDLTest(parser, harness): """) results = parser.finish() - except Exception, x: + except Exception as x: threw = True harness.ok(threw, "Should have thrown.") @@ -180,7 +180,7 @@ def WebIDLTest(parser, harness): """) results = parser.finish() - except Exception, x: + except Exception as x: threw = True harness.ok(threw, "Should have thrown.") @@ -199,7 +199,7 @@ def WebIDLTest(parser, harness): """) results = parser.finish() - except Exception, x: + except Exception as x: threw = True harness.ok(threw, "Should have thrown.") @@ -218,6 +218,6 @@ def WebIDLTest(parser, harness): """) results = parser.finish() - except Exception, x: + except Exception as x: threw = True harness.ok(threw, "Should have thrown.") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_record.py b/components/script/dom/bindings/codegen/parser/tests/test_record.py index c3fe29fa060..d50572caf07 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_record.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_record.py @@ -33,7 +33,7 @@ def WebIDLTest(parser, harness): """) results = parser.finish() - except Exception,x: + except Exception as x: threw = True harness.ok(threw, "Should have thrown because record can't have void as value type.") @@ -47,7 +47,7 @@ def WebIDLTest(parser, harness): """) results = parser.finish() - except Exception,x: + except Exception as x: threw = True harness.ok(threw, "Should have thrown on dictionary containing itself via record.") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_replaceable.py b/components/script/dom/bindings/codegen/parser/tests/test_replaceable.py index 78b1bf7e60b..93ee42ed919 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_replaceable.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_replaceable.py @@ -1,6 +1,6 @@ # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# file, You can obtain one at http://mozilla.org/MPL/2.0/. def should_throw(parser, harness, message, code): parser = parser.reset(); diff --git a/components/script/dom/bindings/codegen/parser/tests/test_typedef.py b/components/script/dom/bindings/codegen/parser/tests/test_typedef.py index 8921985c5ca..b5fc1c68890 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_typedef.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_typedef.py @@ -4,15 +4,15 @@ def WebIDLTest(parser, harness): typedef long? mynullablelong; interface Foo { const mylong X = 5; - const mynullablelong Y = 7; - const mynullablelong Z = null; - void foo(mylong arg); + void foo(optional mynullablelong arg = 7); + void bar(optional mynullablelong arg = null); + void baz(mylong arg); }; """) results = parser.finish() - harness.check(results[2].members[1].type.name, "LongOrNull", + harness.check(results[2].members[1].signatures()[0][1][0].type.name, "LongOrNull", "Should expand typedefs") parser = parser.reset() diff --git a/components/script/dom/bindings/codegen/parser/tests/test_unenumerable_own_properties.py b/components/script/dom/bindings/codegen/parser/tests/test_unenumerable_own_properties.py index d017d5ce092..d28cc1ec052 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_unenumerable_own_properties.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_unenumerable_own_properties.py @@ -24,7 +24,7 @@ def WebIDLTest(parser, harness): """) results = parser.finish() - except Exception, x: + except Exception as x: threw = True harness.ok(threw, "Should have thrown.") @@ -39,7 +39,7 @@ def WebIDLTest(parser, harness): """) results = parser.finish() - except Exception, x: + except Exception as x: threw = True harness.ok(threw, "Should have thrown.") @@ -59,6 +59,6 @@ def WebIDLTest(parser, harness): """) results = parser.finish() - except Exception, x: + except Exception as x: threw = True harness.ok(threw, "Should have thrown.") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_unforgeable.py b/components/script/dom/bindings/codegen/parser/tests/test_unforgeable.py index 3787e8c6af1..44a168670ed 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_unforgeable.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_unforgeable.py @@ -111,7 +111,7 @@ def WebIDLTest(parser, harness): """) results = parser.finish() - except Exception,x: + except Exception as x: threw = True harness.ok(threw, "Should have thrown when shadowing unforgeable attribute on " @@ -130,7 +130,7 @@ def WebIDLTest(parser, harness): """) results = parser.finish() - except Exception,x: + except Exception as x: threw = True harness.ok(threw, "Should have thrown when shadowing unforgeable operation on " diff --git a/components/script/dom/bindings/codegen/parser/tests/test_union.py b/components/script/dom/bindings/codegen/parser/tests/test_union.py index 9c4f2a56ab6..801314fd0bd 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_union.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_union.py @@ -17,7 +17,7 @@ def combinations(iterable, r): n = len(pool) if r > n: return - indices = range(r) + indices = list(range(r)) yield tuple(pool[i] for i in indices) while True: for i in reversed(range(r)): diff --git a/components/script/dom/bindings/codegen/parser/update.sh b/components/script/dom/bindings/codegen/parser/update.sh index 213aba6df89..fee9720ab2d 100755 --- a/components/script/dom/bindings/codegen/parser/update.sh +++ b/components/script/dom/bindings/codegen/parser/update.sh @@ -1,7 +1,6 @@ wget https://hg.mozilla.org/mozilla-central/raw-file/tip/dom/bindings/parser/WebIDL.py -O WebIDL.py patch < abstract.patch patch < debug.patch -patch < pref-main-thread.patch patch < callback-location.patch patch < union-typedef.patch patch < inline.patch |