From 43ca26068935e014b1a41a6a02f45d05436577b4 Mon Sep 17 00:00:00 2001 From: Alan Jeffrey Date: Fri, 12 May 2017 15:02:35 -0500 Subject: Renamed BrowsingContext to WindowProxy in script. --- components/script/dom/bindings/codegen/Bindings.conf | 3 +-- components/script/dom/bindings/codegen/CodegenRust.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf index 5647679f446..2f0b8e7b66b 100644 --- a/components/script/dom/bindings/codegen/Bindings.conf +++ b/components/script/dom/bindings/codegen/Bindings.conf @@ -34,8 +34,7 @@ DOMInterfaces = { }, 'WindowProxy' : { - 'nativeType': 'BrowsingContext', - 'path': 'dom::browsingcontext::BrowsingContext', + 'path': 'dom::windowproxy::WindowProxy', 'register': False, } diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index e7a0541c4da..102c1a17d57 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -5638,7 +5638,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'dom::bindings::weakref::DOM_WEAK_SLOT', 'dom::bindings::weakref::WeakBox', 'dom::bindings::weakref::WeakReferenceable', - 'dom::browsingcontext::BrowsingContext', + 'dom::windowproxy::WindowProxy', 'dom::globalscope::GlobalScope', 'mem::heap_size_of_raw_self_and_children', 'libc', -- cgit v1.2.3 From e566bc7b1c65e54601f5420bfa071bab9c1b83a3 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Fri, 9 Jun 2017 13:57:30 +0200 Subject: Update the WebIDL parser --- .../script/dom/bindings/codegen/CodegenRust.py | 175 ++++---- .../script/dom/bindings/codegen/parser/WebIDL.py | 455 ++++++++++++++------- .../codegen/parser/tests/test_cereactions.py | 162 ++++++++ .../codegen/parser/tests/test_constructor.py | 166 +++++++- .../tests/test_constructor_no_interface_object.py | 33 ++ .../parser/tests/test_distinguishability.py | 35 +- .../parser/tests/test_identifier_conflict.py | 39 ++ .../tests/test_interface_maplikesetlikeiterable.py | 111 ++++- .../bindings/codegen/parser/tests/test_mozmap.py | 39 -- .../codegen/parser/tests/test_newobject.py | 70 ++++ .../bindings/codegen/parser/tests/test_promise.py | 102 ++++- .../bindings/codegen/parser/tests/test_record.py | 53 +++ .../codegen/parser/tests/test_special_methods.py | 41 +- 13 files changed, 1175 insertions(+), 306 deletions(-) create mode 100644 components/script/dom/bindings/codegen/parser/tests/test_cereactions.py create mode 100644 components/script/dom/bindings/codegen/parser/tests/test_identifier_conflict.py delete mode 100644 components/script/dom/bindings/codegen/parser/tests/test_mozmap.py create mode 100644 components/script/dom/bindings/codegen/parser/tests/test_newobject.py create mode 100644 components/script/dom/bindings/codegen/parser/tests/test_record.py (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 102c1a17d57..bf6ca70e6c0 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -17,11 +17,12 @@ import functools from WebIDL import ( BuiltinTypes, IDLBuiltinType, - IDLNullValue, + IDLInterfaceMember, IDLNullableType, + IDLNullValue, IDLObject, + IDLPromiseType, IDLType, - IDLInterfaceMember, IDLUndefinedValue, IDLWrapperType, ) @@ -94,14 +95,14 @@ def stripTrailingWhitespace(text): def innerContainerType(type): - assert type.isSequence() or type.isMozMap() + assert type.isSequence() or type.isRecord() return type.inner.inner if type.nullable() else type.inner def wrapInNativeContainerType(type, inner): if type.isSequence(): containerType = "Vec" - elif type.isMozMap(): + elif type.isRecord(): containerType = "MozMap" else: raise TypeError("Unexpected container type %s", type) @@ -697,7 +698,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, assert not (isEnforceRange and isClamp) # These are mutually exclusive - if type.isSequence() or type.isMozMap(): + if type.isSequence() or type.isRecord(): innerInfo = getJSToNativeConversionInfo(innerContainerType(type), descriptorProvider, isMember=isMember) @@ -754,6 +755,56 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, return handleOptional(templateBody, declType, default) + if type.isPromise(): + assert not type.nullable() + # Per spec, what we're supposed to do is take the original + # Promise.resolve and call it with the original Promise as this + # value to make a Promise out of whatever value we actually have + # here. The question is which global we should use. There are + # a couple cases to consider: + # + # 1) Normal call to API with a Promise argument. This is a case the + # spec covers, and we should be using the current Realm's + # Promise. That means the current compartment. + # 2) Promise return value from a callback or callback interface. + # This is in theory a case the spec covers but in practice it + # really doesn't define behavior here because it doesn't define + # what Realm we're in after the callback returns, which is when + # the argument conversion happens. We will use the current + # compartment, which is the compartment of the callable (which + # may itself be a cross-compartment wrapper itself), which makes + # as much sense as anything else. In practice, such an API would + # once again be providing a Promise to signal completion of an + # operation, which would then not be exposed to anyone other than + # our own implementation code. + templateBody = fill( + """ + { // Scope for our JSAutoCompartment. + + rooted!(in(cx) let globalObj = CurrentGlobalOrNull(cx)); + let promiseGlobal = GlobalScope::from_object_maybe_wrapped(globalObj.handle().get()); + + rooted!(in(cx) let mut valueToResolve = $${val}.get()); + if !JS_WrapValue(cx, valueToResolve.handle_mut()) { + $*{exceptionCode} + } + match Promise::Resolve(&promiseGlobal, cx, valueToResolve.handle()) { + Ok(value) => value, + Err(error) => { + throw_dom_exception(cx, &promiseGlobal, error); + $*{exceptionCode} + } + } + } + """, + exceptionCode=exceptionCode) + + if isArgument: + declType = CGGeneric("&Promise") + else: + declType = CGGeneric("Rc") + return handleOptional(templateBody, declType, handleDefaultNull("None")) + if type.isGeckoInterface(): assert not isEnforceRange and not isClamp @@ -780,79 +831,34 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, elif isArgument: descriptorType = descriptor.argumentType - templateBody = "" - isPromise = descriptor.interface.identifier.name == "Promise" - if isPromise: - # Per spec, what we're supposed to do is take the original - # Promise.resolve and call it with the original Promise as this - # value to make a Promise out of whatever value we actually have - # here. The question is which global we should use. There are - # a couple cases to consider: - # - # 1) Normal call to API with a Promise argument. This is a case the - # spec covers, and we should be using the current Realm's - # Promise. That means the current compartment. - # 2) Promise return value from a callback or callback interface. - # This is in theory a case the spec covers but in practice it - # really doesn't define behavior here because it doesn't define - # what Realm we're in after the callback returns, which is when - # the argument conversion happens. We will use the current - # compartment, which is the compartment of the callable (which - # may itself be a cross-compartment wrapper itself), which makes - # as much sense as anything else. In practice, such an API would - # once again be providing a Promise to signal completion of an - # operation, which would then not be exposed to anyone other than - # our own implementation code. - templateBody = fill( - """ - { // Scope for our JSAutoCompartment. - - rooted!(in(cx) let globalObj = CurrentGlobalOrNull(cx)); - let promiseGlobal = GlobalScope::from_object_maybe_wrapped(globalObj.handle().get()); + if descriptor.interface.isConsequential(): + raise TypeError("Consequential interface %s being used as an " + "argument" % descriptor.interface.identifier.name) - rooted!(in(cx) let mut valueToResolve = $${val}.get()); - if !JS_WrapValue(cx, valueToResolve.handle_mut()) { - $*{exceptionCode} - } - match Promise::Resolve(&promiseGlobal, cx, valueToResolve.handle()) { - Ok(value) => value, - Err(error) => { - throw_dom_exception(cx, &promiseGlobal, error); - $*{exceptionCode} - } - } - } - """, - exceptionCode=exceptionCode) + if failureCode is None: + substitutions = { + "sourceDescription": sourceDescription, + "interface": descriptor.interface.identifier.name, + "exceptionCode": exceptionCode, + } + unwrapFailureCode = string.Template( + 'throw_type_error(cx, "${sourceDescription} does not ' + 'implement interface ${interface}.");\n' + '${exceptionCode}').substitute(substitutions) else: - if descriptor.interface.isConsequential(): - raise TypeError("Consequential interface %s being used as an " - "argument" % descriptor.interface.identifier.name) - - if failureCode is None: - substitutions = { - "sourceDescription": sourceDescription, - "interface": descriptor.interface.identifier.name, - "exceptionCode": exceptionCode, - } - unwrapFailureCode = string.Template( - 'throw_type_error(cx, "${sourceDescription} does not ' - 'implement interface ${interface}.");\n' - '${exceptionCode}').substitute(substitutions) - else: - unwrapFailureCode = failureCode + unwrapFailureCode = failureCode - templateBody = fill( - """ - match ${function}($${val}) { - Ok(val) => val, - Err(()) => { - $*{failureCode} - } + templateBody = fill( + """ + match ${function}($${val}) { + Ok(val) => val, + Err(()) => { + $*{failureCode} } - """, - failureCode=unwrapFailureCode + "\n", - function=conversionFunction) + } + """, + failureCode=unwrapFailureCode + "\n", + function=conversionFunction) declType = CGGeneric(descriptorType) if type.nullable(): @@ -1323,7 +1329,7 @@ def typeNeedsCx(type, retVal=False): # Returns a conversion behavior suitable for a type def getConversionConfigForType(type, isEnforceRange, isClamp, treatNullAs): - if type.isSequence() or type.isMozMap(): + if type.isSequence() or type.isRecord(): return getConversionConfigForType(innerContainerType(type), isEnforceRange, isClamp, treatNullAs) if type.isDOMString(): assert not isEnforceRange and not isClamp @@ -1381,6 +1387,9 @@ def getRetvalDeclarationForType(returnType, descriptorProvider): if returnType.nullable(): result = CGWrapper(result, pre="Option<", post=">") return result + if returnType.isPromise(): + assert not returnType.nullable() + return CGGeneric("Rc") if returnType.isGeckoInterface(): descriptor = descriptorProvider.getDescriptor( returnType.unroll().inner.identifier.name) @@ -1408,7 +1417,7 @@ def getRetvalDeclarationForType(returnType, descriptorProvider): if returnType.nullable(): result = CGWrapper(result, pre="Option<", post=">") return result - if returnType.isSequence() or returnType.isMozMap(): + if returnType.isSequence() or returnType.isRecord(): result = getRetvalDeclarationForType(innerContainerType(returnType), descriptorProvider) result = wrapInNativeContainerType(returnType, result) if returnType.nullable(): @@ -1946,8 +1955,10 @@ class CGImports(CGWrapper): if parentName: descriptor = descriptorProvider.getDescriptor(parentName) extras += [descriptor.path, descriptor.bindingPath] - elif t.isType() and t.isMozMap(): + elif t.isType() and t.isRecord(): extras += ['dom::bindings::mozmap::MozMap'] + elif isinstance(t, IDLPromiseType): + extras += ["dom::promise::Promise"] else: if t.isEnum(): extras += [getModuleFromObject(t) + '::' + getIdentifier(t).name + 'Values'] @@ -3819,7 +3830,9 @@ class CGMemberJITInfo(CGThing): return "JSVAL_TYPE_UNDEFINED" if t.isSequence(): return "JSVAL_TYPE_OBJECT" - if t.isMozMap(): + if t.isRecord(): + return "JSVAL_TYPE_OBJECT" + if t.isPromise(): return "JSVAL_TYPE_OBJECT" if t.isGeckoInterface(): return "JSVAL_TYPE_OBJECT" @@ -4055,7 +4068,7 @@ def getUnionTypeTemplateVars(type, descriptorProvider): elif type.isDictionary(): name = type.name typeName = name - elif type.isSequence() or type.isMozMap(): + elif type.isSequence() or type.isRecord(): name = type.name inner = getUnionTypeTemplateVars(innerContainerType(type), descriptorProvider) typeName = wrapInNativeContainerType(type, CGGeneric(inner["typeName"])).define() @@ -4208,7 +4221,7 @@ class CGUnionConversionStruct(CGThing): else: object = None - mozMapMemberTypes = filter(lambda t: t.isMozMap(), memberTypes) + mozMapMemberTypes = filter(lambda t: t.isRecord(), memberTypes) if len(mozMapMemberTypes) > 0: assert len(mozMapMemberTypes) == 1 typeName = mozMapMemberTypes[0].name @@ -6870,6 +6883,8 @@ def process_arg(expr, arg): expr += ".r()" else: expr = "&" + expr + elif isinstance(arg.type, IDLPromiseType): + expr = "&" + expr return expr diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index dc9fa036141..820dc108fbf 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.py @@ -305,8 +305,8 @@ class IDLScope(IDLObject): # because we need to merge overloads of NamedConstructors and we need to # detect conflicts in those across interfaces. See also the comment in # IDLInterface.addExtendedAttributes for "NamedConstructor". - if (originalObject.tag == IDLInterfaceMember.Tags.Method and - newObject.tag == IDLInterfaceMember.Tags.Method): + if (isinstance(originalObject, IDLMethod) and + isinstance(newObject, IDLMethod)): return originalObject.addOverload(newObject) # Default to throwing, derived classes can override. @@ -367,8 +367,6 @@ class IDLUnresolvedIdentifier(IDLObject): [location]) if name[0] == '_' and not allowDoubleUnderscore: name = name[1:] - # TODO: Bug 872377, Restore "toJSON" to below list. - # We sometimes need custom serialization, so allow toJSON for now. if (name in ["constructor", "toString"] and not allowForbidden): raise WebIDLError("Cannot use reserved identifier '%s'" % (name), @@ -515,6 +513,9 @@ class IDLExposureMixins(): def isExposedInWorkerDebugger(self): return len(self.getWorkerDebuggerExposureSet()) > 0 + def isExposedInAnyWorklet(self): + return len(self.getWorkletExposureSet()) > 0 + def isExposedInSystemGlobals(self): return 'BackstagePass' in self.exposureSet @@ -534,6 +535,10 @@ class IDLExposureMixins(): workerScopes = self._globalScope.globalNameMapping["Worker"] return workerScopes.intersection(self.exposureSet) + def getWorkletExposureSet(self): + workletScopes = self._globalScope.globalNameMapping["Worklet"] + return workletScopes.intersection(self.exposureSet) + def getWorkerDebuggerExposureSet(self): workerDebuggerScopes = self._globalScope.globalNameMapping["WorkerDebugger"] return workerDebuggerScopes.intersection(self.exposureSet) @@ -568,7 +573,10 @@ class IDLExternalInterface(IDLObjectWithIdentifier, IDLExposureMixins): return False def addExtendedAttributes(self, attrs): - assert len(attrs) == 0 + if len(attrs) != 0: + raise WebIDLError("There are no extended attributes that are " + "allowed on external interfaces", + [attrs[0].location, self.location]) def resolve(self, parentScope): pass @@ -579,7 +587,7 @@ class IDLExternalInterface(IDLObjectWithIdentifier, IDLExposureMixins): def isJSImplemented(self): return False - def isProbablyShortLivingObject(self): + def hasProbablyShortLivingWrapper(self): return False def isNavigatorProperty(self): @@ -1090,7 +1098,10 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): # {getter,setter,creator,deleter}, at most one stringifier, # and at most one legacycaller. Note that this last is not # quite per spec, but in practice no one overloads - # legacycallers. + # legacycallers. Also note that in practice we disallow + # indexed deleters, but it simplifies some other code to + # treat deleter analogously to getter/setter/creator by + # prefixing it with "named". specialMembersSeen = {} for member in self.members: if not member.isMethod(): @@ -1192,6 +1203,12 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): self.identifier.name, locations) + ctor = self.ctor() + if ctor is not None: + ctor.validate() + for namedCtor in self.namedConstructors: + namedCtor.validate() + indexedGetter = None hasLengthAttribute = False for member in self.members: @@ -1308,7 +1325,7 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): if not indexedGetter: raise WebIDLError("Interface with value iterator does not " "support indexed properties", - [self.location]) + [self.location, iterableDecl.location]) if iterableDecl.valueType != indexedGetter.signatures()[0][0]: raise WebIDLError("Iterable type does not match indexed " @@ -1319,7 +1336,7 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): if not hasLengthAttribute: raise WebIDLError('Interface with value iterator does not ' 'have an integer-typed "length" attribute', - [self.location]) + [self.location, iterableDecl.location]) else: assert iterableDecl.isPairIterator() if indexedGetter: @@ -1328,6 +1345,11 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): [self.location, iterableDecl.location, indexedGetter.location]) + if indexedGetter and not hasLengthAttribute: + raise WebIDLError('Interface with an indexed getter does not have ' + 'an integer-typed "length" attribute', + [self.location, indexedGetter.location]) + def isExternal(self): return False @@ -1458,6 +1480,10 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): assert self.identifier.name == partial.identifier.name self._partialInterfaces.append(partial) + def getPartialInterfaces(self): + # Don't let people mutate our guts. + return list(self._partialInterfaces) + def getJSImplementation(self): classId = self.getExtendedAttribute("JSImplementation") if not classId: @@ -1469,10 +1495,10 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): def isJSImplemented(self): return bool(self.getJSImplementation()) - def isProbablyShortLivingObject(self): + def hasProbablyShortLivingWrapper(self): current = self while current: - if current.getExtendedAttribute("ProbablyShortLivingObject"): + if current.getExtendedAttribute("ProbablyShortLivingWrapper"): return True current = current.parent return False @@ -1526,10 +1552,8 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): def hasMembersInSlots(self): return self._ownMembersInSlots != 0 - conditionExtendedAttributes = [ "Pref", "ChromeOnly", "Func", "AvailableIn", - "SecureContext", - "CheckAnyPermissions", - "CheckAllPermissions" ] + conditionExtendedAttributes = [ "Pref", "ChromeOnly", "Func", + "SecureContext" ] def isExposedConditionally(self, exclusions=[]): return any(((not a in exclusions) and self.getExtendedAttribute(a)) for a in self.conditionExtendedAttributes) @@ -1566,7 +1590,7 @@ class IDLInterface(IDLInterfaceOrNamespace): [self.location]) self._noInterfaceObject = True - elif identifier == "Constructor" or identifier == "NamedConstructor" or identifier == "ChromeConstructor": + elif identifier == "Constructor" or identifier == "NamedConstructor" or identifier == "ChromeConstructor" or identifier == "HTMLConstructor": if identifier == "Constructor" and not self.hasInterfaceObject(): raise WebIDLError(str(identifier) + " and NoInterfaceObject are incompatible", [self.location]) @@ -1579,15 +1603,20 @@ class IDLInterface(IDLInterfaceOrNamespace): raise WebIDLError(str(identifier) + " and NoInterfaceObject are incompatible", [self.location]) + if identifier == "HTMLConstructor": + if not self.hasInterfaceObject(): + raise WebIDLError(str(identifier) + " and NoInterfaceObject are incompatible", + [self.location]) + + if not attr.noArguments(): + raise WebIDLError(str(identifier) + " must take no arguments", + [attr.location]) + args = attr.args() if attr.hasArgs() else [] - if self.identifier.name == "Promise": - promiseType = BuiltinTypes[IDLBuiltinType.Types.any] - else: - promiseType = None - retType = IDLWrapperType(self.location, self, promiseType) + retType = IDLWrapperType(self.location, self) - if identifier == "Constructor" or identifier == "ChromeConstructor": + if identifier == "Constructor" or identifier == "ChromeConstructor" or identifier == "HTMLConstructor": name = "constructor" allowForbidden = True else: @@ -1598,7 +1627,8 @@ class IDLInterface(IDLInterfaceOrNamespace): allowForbidden=allowForbidden) method = IDLMethod(self.location, methodIdentifier, retType, - args, static=True) + args, static=True, + htmlConstructor=(identifier == "HTMLConstructor")) # Constructors are always NewObject and are always # assumed to be able to throw (since there's no way to # indicate otherwise) and never have any other @@ -1610,7 +1640,7 @@ class IDLInterface(IDLInterfaceOrNamespace): method.addExtendedAttributes( [IDLExtendedAttribute(self.location, ("ChromeOnly",))]) - if identifier == "Constructor" or identifier == "ChromeConstructor": + if identifier == "Constructor" or identifier == "ChromeConstructor" or identifier == "HTMLConstructor": method.resolve(self) else: # We need to detect conflicts for NamedConstructors across @@ -1692,7 +1722,7 @@ class IDLInterface(IDLInterfaceOrNamespace): identifier == "Unforgeable" or identifier == "UnsafeInPrerendering" or identifier == "LegacyEventInit" or - identifier == "ProbablyShortLivingObject" or + identifier == "ProbablyShortLivingWrapper" or identifier == "LegacyUnenumerableNamedProperties" or identifier == "NonOrdinaryGetPrototypeOf" or identifier == "Abstract" or @@ -1853,7 +1883,7 @@ class IDLDictionary(IDLObjectWithScope): if (memberType.nullable() or memberType.isSequence() or - memberType.isMozMap()): + memberType.isRecord()): return typeContainsDictionary(memberType.inner, dictionary) if memberType.isDictionary(): @@ -1901,7 +1931,10 @@ class IDLDictionary(IDLObjectWithScope): [member.location] + locations) def addExtendedAttributes(self, attrs): - assert len(attrs) == 0 + if len(attrs) != 0: + raise WebIDLError("There are no extended attributes that are " + "allowed on dictionaries", + [attrs[0].location, self.location]) def _getDependentObjects(self): deps = set(self.members) @@ -1935,7 +1968,10 @@ class IDLEnum(IDLObjectWithIdentifier): return True def addExtendedAttributes(self, attrs): - assert len(attrs) == 0 + if len(attrs) != 0: + raise WebIDLError("There are no extended attributes that are " + "allowed on enums", + [attrs[0].location, self.location]) def _getDependentObjects(self): return set() @@ -1974,7 +2010,8 @@ class IDLType(IDLObject): 'callback', 'union', 'sequence', - 'mozmap' + 'record', + 'promise', ) def __init__(self, location, name): @@ -2024,7 +2061,7 @@ class IDLType(IDLObject): def isSequence(self): return False - def isMozMap(self): + def isRecord(self): return False def isArrayBuffer(self): @@ -2107,7 +2144,11 @@ class IDLType(IDLObject): return self.nullable() and self.inner.callback._treatNonObjectAsNull def addExtendedAttributes(self, attrs): - assert len(attrs) == 0 + if len(attrs) != 0: + raise WebIDLError("There are no extended attributes that are " + "allowed on types, for now (but this is " + "changing; see bug 1359269)", + [attrs[0].location, self.location]) def resolveType(self, parentScope): pass @@ -2128,9 +2169,8 @@ class IDLUnresolvedType(IDLType): Unresolved types are interface types """ - def __init__(self, location, name, promiseInnerType=None): + def __init__(self, location, name): IDLType.__init__(self, location, name) - self._promiseInnerType = promiseInnerType def isComplete(self): return False @@ -2157,18 +2197,15 @@ class IDLUnresolvedType(IDLType): assert self.name.name == obj.identifier.name return IDLCallbackType(obj.location, obj) - if self._promiseInnerType and not self._promiseInnerType.isComplete(): - self._promiseInnerType = self._promiseInnerType.complete(scope) - name = self.name.resolve(scope, None) - return IDLWrapperType(self.location, obj, self._promiseInnerType) + return IDLWrapperType(self.location, obj) def isDistinguishableFrom(self, other): raise TypeError("Can't tell whether an unresolved type is or is not " "distinguishable from other things") -class IDLParameterizedType(IDLType): +class IDLParametrizedType(IDLType): def __init__(self, location, name, innerType): IDLType.__init__(self, location, name) self.builtin = False @@ -2191,7 +2228,7 @@ class IDLParameterizedType(IDLType): return self.inner._getDependentObjects() -class IDLNullableType(IDLParameterizedType): +class IDLNullableType(IDLParametrizedType): def __init__(self, location, innerType): assert not innerType.isVoid() assert not innerType == BuiltinTypes[IDLBuiltinType.Types.any] @@ -2199,7 +2236,7 @@ class IDLNullableType(IDLParameterizedType): name = innerType.name if innerType.isComplete(): name += "OrNull" - IDLParameterizedType.__init__(self, location, name, innerType) + IDLParametrizedType.__init__(self, location, name, innerType) def __eq__(self, other): return isinstance(other, IDLNullableType) and self.inner == other.inner @@ -2249,8 +2286,8 @@ class IDLNullableType(IDLParameterizedType): def isSequence(self): return self.inner.isSequence() - def isMozMap(self): - return self.inner.isMozMap() + def isRecord(self): + return self.inner.isRecord() def isArrayBuffer(self): return self.inner.isArrayBuffer() @@ -2271,7 +2308,9 @@ class IDLNullableType(IDLParameterizedType): return self.inner.isInterface() def isPromise(self): - return self.inner.isPromise() + # There is no such thing as a nullable Promise. + assert not self.inner.isPromise() + return False def isCallbackInterface(self): return self.inner.isCallbackInterface() @@ -2307,18 +2346,20 @@ class IDLNullableType(IDLParameterizedType): return self def isDistinguishableFrom(self, other): - if (other.nullable() or (other.isUnion() and other.hasNullableType) or - other.isDictionary()): + if (other.nullable() or + other.isDictionary() or + (other.isUnion() and + (other.hasNullableType or other.hasDictionaryType()))): # Can't tell which type null should become return False return self.inner.isDistinguishableFrom(other) -class IDLSequenceType(IDLParameterizedType): +class IDLSequenceType(IDLParametrizedType): def __init__(self, location, parameterType): assert not parameterType.isVoid() - IDLParameterizedType.__init__(self, location, parameterType.name, parameterType) + IDLParametrizedType.__init__(self, location, parameterType.name, parameterType) # Need to set self.name up front if our inner type is already complete, # since in that case our .complete() won't be called. if self.inner.isComplete(): @@ -2383,34 +2424,38 @@ class IDLSequenceType(IDLParameterizedType): return (other.isPrimitive() or other.isString() or other.isEnum() or other.isDate() or other.isInterface() or other.isDictionary() or - other.isCallback() or other.isMozMap()) + other.isCallback() or other.isRecord()) -class IDLMozMapType(IDLParameterizedType): - def __init__(self, location, parameterType): - assert not parameterType.isVoid() +class IDLRecordType(IDLParametrizedType): + def __init__(self, location, keyType, valueType): + assert keyType.isString() + assert keyType.isComplete() + assert not valueType.isVoid() + + IDLParametrizedType.__init__(self, location, valueType.name, valueType) + self.keyType = keyType - IDLParameterizedType.__init__(self, location, parameterType.name, parameterType) # Need to set self.name up front if our inner type is already complete, # since in that case our .complete() won't be called. if self.inner.isComplete(): - self.name = self.inner.name + "MozMap" + self.name = self.keyType.name + self.inner.name + "Record" def __eq__(self, other): - return isinstance(other, IDLMozMapType) and self.inner == other.inner + return isinstance(other, IDLRecordType) and self.inner == other.inner def __str__(self): - return self.inner.__str__() + "MozMap" + return self.keyType.__str__() + self.inner.__str__() + "Record" - def isMozMap(self): + def isRecord(self): return True def tag(self): - return IDLType.Tags.mozmap + return IDLType.Tags.record def complete(self, scope): self.inner = self.inner.complete(scope) - self.name = self.inner.name + "MozMap" + self.name = self.keyType.name + self.inner.name + "Record" return self def unroll(self): @@ -2608,8 +2653,8 @@ class IDLTypedefType(IDLType): def isSequence(self): return self.inner.isSequence() - def isMozMap(self): - return self.inner.isMozMap() + def isRecord(self): + return self.inner.isRecord() def isDictionary(self): return self.inner.isDictionary() @@ -2679,20 +2724,21 @@ class IDLTypedef(IDLObjectWithIdentifier): return True def addExtendedAttributes(self, attrs): - assert len(attrs) == 0 + if len(attrs) != 0: + raise WebIDLError("There are no extended attributes that are " + "allowed on typedefs", + [attrs[0].location, self.location]) def _getDependentObjects(self): return self.innerType._getDependentObjects() class IDLWrapperType(IDLType): - def __init__(self, location, inner, promiseInnerType=None): + def __init__(self, location, inner): IDLType.__init__(self, location, inner.identifier.name) self.inner = inner self._identifier = inner.identifier self.builtin = False - assert not promiseInnerType or inner.identifier.name == "Promise" - self._promiseInnerType = promiseInnerType def __eq__(self, other): return (isinstance(other, IDLWrapperType) and @@ -2742,14 +2788,6 @@ class IDLWrapperType(IDLType): def isEnum(self): return isinstance(self.inner, IDLEnum) - def isPromise(self): - return (isinstance(self.inner, IDLInterface) and - self.inner.identifier.name == "Promise") - - def promiseInnerType(self): - assert self.isPromise() - return self._promiseInnerType - def isSerializable(self): if self.isInterface(): if self.inner.isExternal(): @@ -2781,8 +2819,6 @@ class IDLWrapperType(IDLType): assert False def isDistinguishableFrom(self, other): - if self.isPromise(): - return False if other.isPromise(): return False if other.isUnion(): @@ -2792,7 +2828,7 @@ class IDLWrapperType(IDLType): if self.isEnum(): return (other.isPrimitive() or other.isInterface() or other.isObject() or other.isCallback() or other.isDictionary() or - other.isSequence() or other.isMozMap() or other.isDate()) + other.isSequence() or other.isRecord() or other.isDate()) if self.isDictionary() and other.nullable(): return False if (other.isPrimitive() or other.isString() or other.isEnum() or @@ -2814,7 +2850,7 @@ class IDLWrapperType(IDLType): (self.isNonCallbackInterface() or other.isNonCallbackInterface())) if (other.isDictionary() or other.isCallback() or - other.isMozMap()): + other.isRecord()): return self.isNonCallbackInterface() # Not much else |other| can be @@ -2829,10 +2865,6 @@ class IDLWrapperType(IDLType): # Let's say true, though ideally we'd only do this when # exposureSet contains the primary global's name. return True - if (self.isPromise() and - # Check the internal type - not self.promiseInnerType().unroll().isExposedInAllOf(exposureSet)): - return False return iface.exposureSet.issuperset(exposureSet) def _getDependentObjects(self): @@ -2860,6 +2892,45 @@ class IDLWrapperType(IDLType): return set() +class IDLPromiseType(IDLParametrizedType): + def __init__(self, location, innerType): + IDLParametrizedType.__init__(self, location, "Promise", innerType) + + def __eq__(self, other): + return (isinstance(other, IDLPromiseType) and + self.promiseInnerType() == other.promiseInnerType()) + + def __str__(self): + return self.inner.__str__() + "Promise" + + def isPromise(self): + return True + + def promiseInnerType(self): + return self.inner + + def tag(self): + return IDLType.Tags.promise + + def complete(self, scope): + self.inner = self.promiseInnerType().complete(scope) + return self + + def unroll(self): + # We do not unroll our inner. Just stop at ourselves. That + # lets us add headers for both ourselves and our inner as + # needed. + return self + + def isDistinguishableFrom(self, other): + # Promises are not distinguishable from anything. + return False + + def isExposedInAllOf(self, exposureSet): + # Check the internal type + return self.promiseInnerType().unroll().isExposedInAllOf(exposureSet) + + class IDLBuiltinType(IDLType): Types = enum( @@ -3024,17 +3095,17 @@ class IDLBuiltinType(IDLType): return (other.isNumeric() or other.isString() or other.isEnum() or other.isInterface() or other.isObject() or other.isCallback() or other.isDictionary() or - other.isSequence() or other.isMozMap() or other.isDate()) + other.isSequence() or other.isRecord() or other.isDate()) if self.isNumeric(): return (other.isBoolean() or other.isString() or other.isEnum() or other.isInterface() or other.isObject() or other.isCallback() or other.isDictionary() or - other.isSequence() or other.isMozMap() or other.isDate()) + other.isSequence() or other.isRecord() or other.isDate()) if self.isString(): return (other.isPrimitive() or other.isInterface() or other.isObject() or other.isCallback() or other.isDictionary() or - other.isSequence() or other.isMozMap() or other.isDate()) + other.isSequence() or other.isRecord() or other.isDate()) if self.isAny(): # Can't tell "any" apart from anything return False @@ -3044,7 +3115,7 @@ class IDLBuiltinType(IDLType): return (other.isPrimitive() or other.isString() or other.isEnum() or other.isInterface() or other.isCallback() or other.isDictionary() or other.isSequence() or - other.isMozMap()) + other.isRecord()) if self.isVoid(): return not other.isVoid() # Not much else we could be! @@ -3052,7 +3123,7 @@ class IDLBuiltinType(IDLType): # Like interfaces, but we know we're not a callback return (other.isPrimitive() or other.isString() or other.isEnum() or other.isCallback() or other.isDictionary() or - other.isSequence() or other.isMozMap() or other.isDate() or + other.isSequence() or other.isRecord() or other.isDate() or (other.isInterface() and ( # ArrayBuffer is distinguishable from everything # that's not an ArrayBuffer or a callback interface @@ -3456,6 +3527,14 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins): raise WebIDLError("A [NewObject] method is not idempotent, " "so it has to depend on something other than DOM state.", [self.location]) + if (self.getExtendedAttribute("Cached") or + self.getExtendedAttribute("StoreInSlot")): + raise WebIDLError("A [NewObject] attribute shouldnt be " + "[Cached] or [StoreInSlot], since the point " + "of those is to keep returning the same " + "thing across multiple calls, which is not " + "what [NewObject] does.", + [self.location]) def _setDependsOn(self, dependsOn): if self.dependsOn != "Everything": @@ -3527,8 +3606,10 @@ class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember): (member.identifier.name, self.maplikeOrSetlikeOrIterableType), [self.location, member.location]) - # Check that there are no disallowed non-method members - if (isAncestor or (member.isAttr() or member.isConst()) and + # Check that there are no disallowed non-method members. + # Ancestor members are always disallowed here; own members + # are disallowed only if they're non-methods. + if ((isAncestor or member.isAttr() or member.isConst()) and member.identifier.name in self.disallowedNonMethodNames): raise WebIDLError("Member '%s' conflicts " "with reserved %s method." % @@ -3730,6 +3811,7 @@ class IDLMaplikeOrSetlike(IDLMaplikeOrSetlikeOrIterableBase): True, maplikeOrSetlike=self)) self.reserved_ro_names = ["size"] + self.disallowedMemberNames.append("size") # object entries() self.addMethod("entries", members, False, BuiltinTypes[IDLBuiltinType.Types.object], @@ -3820,6 +3902,9 @@ class IDLConst(IDLInterfaceMember): if type.isDictionary(): raise WebIDLError("A constant cannot be of a dictionary type", [self.location]) + if type.isRecord(): + raise WebIDLError("A constant cannot be of a record type", + [self.location]) self.type = type self.value = value @@ -3931,8 +4016,8 @@ class IDLAttribute(IDLInterfaceMember): if self.type.isSequence() and not self.getExtendedAttribute("Cached"): raise WebIDLError("A non-cached attribute cannot be of a sequence " "type", [self.location]) - if self.type.isMozMap() and not self.getExtendedAttribute("Cached"): - raise WebIDLError("A non-cached attribute cannot be of a MozMap " + if self.type.isRecord() and not self.getExtendedAttribute("Cached"): + raise WebIDLError("A non-cached attribute cannot be of a record " "type", [self.location]) if self.type.isUnion(): for f in self.type.unroll().flatMemberTypes: @@ -3948,25 +4033,30 @@ class IDLAttribute(IDLInterfaceMember): "one of its member types's member " "types, and so on) is a sequence " "type", [self.location, f.location]) - if f.isMozMap(): + if f.isRecord(): raise WebIDLError("An attribute cannot be of a union " "type if one of its member types (or " "one of its member types's member " - "types, and so on) is a MozMap " + "types, and so on) is a record " "type", [self.location, f.location]) if not self.type.isInterface() and self.getExtendedAttribute("PutForwards"): raise WebIDLError("An attribute with [PutForwards] must have an " "interface type as its type", [self.location]) - if not self.type.isInterface() and self.getExtendedAttribute("SameObject"): + if (not self.type.isInterface() and + self.getExtendedAttribute("SameObject")): raise WebIDLError("An attribute with [SameObject] must have an " "interface type as its type", [self.location]) + if self.type.isPromise() and not self.readonly: + raise WebIDLError("Promise-returning attributes must be readonly", + [self.location]) + def validate(self): def typeContainsChromeOnlyDictionaryMember(type): if (type.nullable() or type.isSequence() or - type.isMozMap()): + type.isRecord()): return typeContainsChromeOnlyDictionaryMember(type.inner) if type.isUnion(): @@ -4012,27 +4102,36 @@ class IDLAttribute(IDLInterfaceMember): [self.location, location]) if self.getExtendedAttribute("Frozen"): if (not self.type.isSequence() and not self.type.isDictionary() and - not self.type.isMozMap()): + not self.type.isRecord()): raise WebIDLError("[Frozen] is only allowed on " "sequence-valued, dictionary-valued, and " - "MozMap-valued attributes", + "record-valued attributes", [self.location]) if not self.type.unroll().isExposedInAllOf(self.exposureSet): raise WebIDLError("Attribute returns a type that is not exposed " "everywhere where the attribute is exposed", [self.location]) + if self.getExtendedAttribute("CEReactions"): + if self.readonly: + raise WebIDLError("[CEReactions] is not allowed on " + "readonly attributes", + [self.location]) def handleExtendedAttribute(self, attr): identifier = attr.identifier() - if identifier == "SetterThrows" and self.readonly: + if ((identifier == "SetterThrows" or identifier == "SetterCanOOM") + and self.readonly): raise WebIDLError("Readonly attributes must not be flagged as " - "[SetterThrows]", + "[%s]" % identifier, [self.location]) - elif (((identifier == "Throws" or identifier == "GetterThrows") and + elif (((identifier == "Throws" or identifier == "GetterThrows" or + identifier == "CanOOM" or identifier == "GetterCanOOM") and self.getExtendedAttribute("StoreInSlot")) or (identifier == "StoreInSlot" and (self.getExtendedAttribute("Throws") or - self.getExtendedAttribute("GetterThrows")))): + self.getExtendedAttribute("GetterThrows") or + self.getExtendedAttribute("CanOOM") or + self.getExtendedAttribute("GetterCanOOM")))): raise WebIDLError("Throwing things can't be [StoreInSlot]", [attr.location]) elif identifier == "LenientThis": @@ -4066,6 +4165,10 @@ class IDLAttribute(IDLInterfaceMember): if not self.readonly: raise WebIDLError("[PutForwards] is only allowed on readonly " "attributes", [attr.location, self.location]) + if self.type.isPromise(): + raise WebIDLError("[PutForwards] is not allowed on " + "Promise-typed attributes", + [attr.location, self.location]) if self.isStatic(): raise WebIDLError("[PutForwards] is only allowed on non-static " "attributes", [attr.location, self.location]) @@ -4083,6 +4186,10 @@ class IDLAttribute(IDLInterfaceMember): if not self.readonly: raise WebIDLError("[Replaceable] is only allowed on readonly " "attributes", [attr.location, self.location]) + if self.type.isPromise(): + raise WebIDLError("[Replaceable] is not allowed on " + "Promise-typed attributes", + [attr.location, self.location]) if self.isStatic(): raise WebIDLError("[Replaceable] is only allowed on non-static " "attributes", [attr.location, self.location]) @@ -4097,6 +4204,10 @@ class IDLAttribute(IDLInterfaceMember): if not self.readonly: raise WebIDLError("[LenientSetter] is only allowed on readonly " "attributes", [attr.location, self.location]) + if self.type.isPromise(): + raise WebIDLError("[LenientSetter] is not allowed on " + "Promise-typed attributes", + [attr.location, self.location]) if self.isStatic(): raise WebIDLError("[LenientSetter] is only allowed on non-static " "attributes", [attr.location, self.location]) @@ -4191,17 +4302,27 @@ class IDLAttribute(IDLInterfaceMember): raise WebIDLError("[Unscopable] is only allowed on non-static " "attributes and operations", [attr.location, self.location]) + elif identifier == "CEReactions": + if not attr.noArguments(): + raise WebIDLError("[CEReactions] must take no arguments", + [attr.location]) elif (identifier == "Pref" or identifier == "Deprecated" or identifier == "SetterThrows" or identifier == "Throws" or identifier == "GetterThrows" or + identifier == "SetterCanOOM" or + identifier == "CanOOM" or + identifier == "GetterCanOOM" or identifier == "ChromeOnly" or identifier == "Func" or identifier == "SecureContext" or identifier == "Frozen" or identifier == "NewObject" or identifier == "UnsafeInPrerendering" or + identifier == "NeedsSubjectPrincipal" or + identifier == "NeedsCallerType" or + identifier == "ReturnValueNeedsContainsHack" or identifier == "BinaryName"): # Known attributes that we don't need to do anything with here pass @@ -4482,7 +4603,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope): static=False, getter=False, setter=False, creator=False, deleter=False, specialType=NamedOrIndexed.Neither, legacycaller=False, stringifier=False, jsonifier=False, - maplikeOrSetlikeOrIterable=None): + maplikeOrSetlikeOrIterable=None, htmlConstructor=False): # REVIEW: specialType is NamedOrIndexed -- wow, this is messed up. IDLInterfaceMember.__init__(self, location, identifier, IDLInterfaceMember.Tags.Method) @@ -4512,6 +4633,10 @@ class IDLMethod(IDLInterfaceMember, IDLScope): self._jsonifier = jsonifier assert maplikeOrSetlikeOrIterable is None or isinstance(maplikeOrSetlikeOrIterable, IDLMaplikeOrSetlikeOrIterableBase) self.maplikeOrSetlikeOrIterable = maplikeOrSetlikeOrIterable + assert isinstance(htmlConstructor, bool) + # The identifier of a HTMLConstructor must be 'constructor'. + assert not htmlConstructor or identifier.name == "constructor" + self._htmlConstructor = htmlConstructor self._specialType = specialType self._unforgeable = False self.dependsOn = "Everything" @@ -4612,6 +4737,9 @@ class IDLMethod(IDLInterfaceMember, IDLScope): self.isStringifier() or self.isJsonifier()) + def isHTMLConstructor(self): + return self._htmlConstructor + def hasOverloads(self): return self._hasOverloads @@ -4667,6 +4795,8 @@ class IDLMethod(IDLInterfaceMember, IDLScope): assert not method.isStringifier() assert not self.isJsonifier() assert not method.isJsonifier() + assert not self.isHTMLConstructor() + assert not method.isHTMLConstructor() return self @@ -4743,9 +4873,10 @@ class IDLMethod(IDLInterfaceMember, IDLScope): # optional arguments must be optional. if (not argument.optional and all(arg.optional for arg in arguments[idx+1:])): - raise WebIDLError("Dictionary argument or union " - "argument containing a dictionary " - "not followed by a required argument " + raise WebIDLError("Dictionary argument without any " + "required fields or union argument " + "containing such dictionary not " + "followed by a required argument " "must be optional", [argument.location]) @@ -4831,13 +4962,12 @@ class IDLMethod(IDLInterfaceMember, IDLScope): def handleExtendedAttribute(self, attr): identifier = attr.identifier() - if identifier == "GetterThrows": - raise WebIDLError("Methods must not be flagged as " - "[GetterThrows]", - [attr.location, self.location]) - elif identifier == "SetterThrows": + if (identifier == "GetterThrows" or + identifier == "SetterThrows" or + identifier == "GetterCanOOM" or + identifier == "SetterCanOOM"): raise WebIDLError("Methods must not be flagged as " - "[SetterThrows]", + "[%s]" % identifier, [attr.location, self.location]) elif identifier == "Unforgeable": if self.isStatic(): @@ -4909,7 +5039,17 @@ class IDLMethod(IDLInterfaceMember, IDLScope): raise WebIDLError("[Unscopable] is only allowed on non-static " "attributes and operations", [attr.location, self.location]) + elif identifier == "CEReactions": + if not attr.noArguments(): + raise WebIDLError("[CEReactions] must take no arguments", + [attr.location]) + + if self.isSpecial() and not self.isSetter() and not self.isDeleter(): + raise WebIDLError("[CEReactions] is only allowed on operation, " + "attribute, setter, and deleter", + [attr.location, self.location]) elif (identifier == "Throws" or + identifier == "CanOOM" or identifier == "NewObject" or identifier == "ChromeOnly" or identifier == "UnsafeInPrerendering" or @@ -4918,6 +5058,8 @@ class IDLMethod(IDLInterfaceMember, IDLScope): identifier == "Func" or identifier == "SecureContext" or identifier == "BinaryName" or + identifier == "NeedsSubjectPrincipal" or + identifier == "NeedsCallerType" or identifier == "StaticClassOverride"): # Known attributes that we don't need to do anything with here pass @@ -4980,7 +5122,10 @@ class IDLImplementsStatement(IDLObject): pass def addExtendedAttributes(self, attrs): - assert len(attrs) == 0 + if len(attrs) != 0: + raise WebIDLError("There are no extended attributes that are " + "allowed on implements statements", + [attrs[0].location, self.location]) class IDLExtendedAttribute(IDLObject): @@ -5119,7 +5264,7 @@ class Tokenizer(object): "Promise": "PROMISE", "required": "REQUIRED", "sequence": "SEQUENCE", - "MozMap": "MOZMAP", + "record": "RECORD", "short": "SHORT", "unsigned": "UNSIGNED", "void": "VOID", @@ -5837,6 +5982,9 @@ class Parser(Tokenizer): specialType = IDLMethod.NamedOrIndexed.Named elif argType == BuiltinTypes[IDLBuiltinType.Types.unsigned_long]: specialType = IDLMethod.NamedOrIndexed.Indexed + if deleter: + raise WebIDLError("There is no such thing as an indexed deleter.", + [self.getLocation(p, 1)]) else: raise WebIDLError("%s has wrong argument type (must be DOMString or UnsignedLong)" % ("getter" if getter else "deleter"), @@ -6245,7 +6393,7 @@ class Parser(Tokenizer): | OCTET | OPTIONAL | SEQUENCE - | MOZMAP + | RECORD | SETTER | SHORT | STATIC @@ -6324,7 +6472,7 @@ class Parser(Tokenizer): def p_NonAnyType(self, p): """ - NonAnyType : PrimitiveOrStringType Null + NonAnyType : PrimitiveType Null | ARRAYBUFFER Null | SHAREDARRAYBUFFER Null | OBJECT Null @@ -6340,6 +6488,12 @@ class Parser(Tokenizer): p[0] = self.handleNullable(type, p[2]) + def p_NonAnyTypeStringType(self, p): + """ + NonAnyType : StringType Null + """ + p[0] = self.handleNullable(p[1], p[2]) + def p_NonAnyTypeSequenceType(self, p): """ NonAnyType : SEQUENCE LT Type GT Null @@ -6348,25 +6502,22 @@ class Parser(Tokenizer): type = IDLSequenceType(self.getLocation(p, 1), innerType) p[0] = self.handleNullable(type, p[5]) - # Note: Promise is allowed, so we want to parametrize on - # ReturnType, not Type. Also, we want this to end up picking up - # the Promise interface for now, hence the games with IDLUnresolvedType. + # Note: Promise 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): """ - NonAnyType : PROMISE LT ReturnType GT Null + NonAnyType : PROMISE LT ReturnType GT """ - innerType = p[3] - promiseIdent = IDLUnresolvedIdentifier(self.getLocation(p, 1), "Promise") - type = IDLUnresolvedType(self.getLocation(p, 1), promiseIdent, p[3]) - p[0] = self.handleNullable(type, p[5]) + p[0] = IDLPromiseType(self.getLocation(p, 1), p[3]) - def p_NonAnyTypeMozMapType(self, p): + def p_NonAnyTypeRecordType(self, p): """ - NonAnyType : MOZMAP LT Type GT Null + NonAnyType : RECORD LT StringType COMMA Type GT Null """ - innerType = p[3] - type = IDLMozMapType(self.getLocation(p, 1), innerType) - p[0] = self.handleNullable(type, p[5]) + 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): """ @@ -6409,7 +6560,7 @@ class Parser(Tokenizer): def p_ConstType(self, p): """ - ConstType : PrimitiveOrStringType Null + ConstType : PrimitiveType Null """ type = BuiltinTypes[p[1]] p[0] = self.handleNullable(type, p[2]) @@ -6423,69 +6574,75 @@ class Parser(Tokenizer): type = IDLUnresolvedType(self.getLocation(p, 1), identifier) p[0] = self.handleNullable(type, p[2]) - def p_PrimitiveOrStringTypeUint(self, p): + def p_PrimitiveTypeUint(self, p): """ - PrimitiveOrStringType : UnsignedIntegerType + PrimitiveType : UnsignedIntegerType """ p[0] = p[1] - def p_PrimitiveOrStringTypeBoolean(self, p): + def p_PrimitiveTypeBoolean(self, p): """ - PrimitiveOrStringType : BOOLEAN + PrimitiveType : BOOLEAN """ p[0] = IDLBuiltinType.Types.boolean - def p_PrimitiveOrStringTypeByte(self, p): + def p_PrimitiveTypeByte(self, p): """ - PrimitiveOrStringType : BYTE + PrimitiveType : BYTE """ p[0] = IDLBuiltinType.Types.byte - def p_PrimitiveOrStringTypeOctet(self, p): + def p_PrimitiveTypeOctet(self, p): """ - PrimitiveOrStringType : OCTET + PrimitiveType : OCTET """ p[0] = IDLBuiltinType.Types.octet - def p_PrimitiveOrStringTypeFloat(self, p): + def p_PrimitiveTypeFloat(self, p): """ - PrimitiveOrStringType : FLOAT + PrimitiveType : FLOAT """ p[0] = IDLBuiltinType.Types.float - def p_PrimitiveOrStringTypeUnrestictedFloat(self, p): + def p_PrimitiveTypeUnrestictedFloat(self, p): """ - PrimitiveOrStringType : UNRESTRICTED FLOAT + PrimitiveType : UNRESTRICTED FLOAT """ p[0] = IDLBuiltinType.Types.unrestricted_float - def p_PrimitiveOrStringTypeDouble(self, p): + def p_PrimitiveTypeDouble(self, p): """ - PrimitiveOrStringType : DOUBLE + PrimitiveType : DOUBLE """ p[0] = IDLBuiltinType.Types.double - def p_PrimitiveOrStringTypeUnrestictedDouble(self, p): + def p_PrimitiveTypeUnrestictedDouble(self, p): """ - PrimitiveOrStringType : UNRESTRICTED DOUBLE + PrimitiveType : UNRESTRICTED DOUBLE """ p[0] = IDLBuiltinType.Types.unrestricted_double - def p_PrimitiveOrStringTypeDOMString(self, p): + def p_StringType(self, p): + """ + StringType : BuiltinStringType + """ + p[0] = BuiltinTypes[p[1]] + + def p_BuiltinStringTypeDOMString(self, p): """ - PrimitiveOrStringType : DOMSTRING + BuiltinStringType : DOMSTRING """ p[0] = IDLBuiltinType.Types.domstring - def p_PrimitiveOrStringTypeBytestring(self, p): + def p_BuiltinStringTypeBytestring(self, p): """ - PrimitiveOrStringType : BYTESTRING + BuiltinStringType : BYTESTRING """ p[0] = IDLBuiltinType.Types.bytestring - def p_PrimitiveOrStringTypeUSVString(self, p): + def p_BuiltinStringTypeUSVString(self, p): """ - PrimitiveOrStringType : USVSTRING + BuiltinStringType : USVSTRING """ p[0] = IDLBuiltinType.Types.usvstring diff --git a/components/script/dom/bindings/codegen/parser/tests/test_cereactions.py b/components/script/dom/bindings/codegen/parser/tests/test_cereactions.py new file mode 100644 index 00000000000..2f9397d903e --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_cereactions.py @@ -0,0 +1,162 @@ +def WebIDLTest(parser, harness): + threw = False + try: + parser.parse(""" + interface Foo { + [CEReactions(DOMString a)] void foo(boolean arg2); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown for [CEReactions] with an argument") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Foo { + [CEReactions(DOMString b)] readonly attribute boolean bar; + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown for [CEReactions] with an argument") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Foo { + [CEReactions] attribute boolean bar; + }; + """) + + results = parser.finish() + except Exception, e: + harness.ok(False, "Shouldn't have thrown for [CEReactions] used on writable attribute. %s" % e) + threw = True + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Foo { + [CEReactions] void foo(boolean arg2); + }; + """) + + results = parser.finish() + except Exception, e: + harness.ok(False, "Shouldn't have thrown for [CEReactions] used on regular operations. %s" % e) + threw = True + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Foo { + [CEReactions] readonly attribute boolean A; + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown for [CEReactions] used on a readonly attribute") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [CEReactions] + interface Foo { + } + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown for [CEReactions] used on a interface") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Foo { + [CEReactions] getter any(DOMString name); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should have thrown for [CEReactions] used on a named getter") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Foo { + [CEReactions] creator boolean (DOMString name, boolean value); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should have thrown for [CEReactions] used on a named creator") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Foo { + [CEReactions] legacycaller double compute(double x); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should have thrown for [CEReactions] used on a legacycaller") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Foo { + [CEReactions] stringifier DOMString (); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should have thrown for [CEReactions] used on a stringifier") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Foo { + [CEReactions] jsonifier; + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown for [CEReactions] used on a jsonifier") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_constructor.py b/components/script/dom/bindings/codegen/parser/tests/test_constructor.py index 348204c7dc1..6c68a6c79cf 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_constructor.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_constructor.py @@ -13,7 +13,7 @@ def WebIDLTest(parser, harness): def checkMethod(method, QName, name, signatures, static=True, getter=False, setter=False, creator=False, deleter=False, legacycaller=False, stringifier=False, - chromeOnly=False): + chromeOnly=False, htmlConstructor=False): harness.ok(isinstance(method, WebIDL.IDLMethod), "Should be an IDLMethod") harness.ok(method.isMethod(), "Method is a method") @@ -29,6 +29,7 @@ def WebIDLTest(parser, harness): harness.check(method.isLegacycaller(), legacycaller, "Method has the correct legacycaller value") harness.check(method.isStringifier(), stringifier, "Method has the correct stringifier value") harness.check(method.getExtendedAttribute("ChromeOnly") is not None, chromeOnly, "Method has the correct value for ChromeOnly") + harness.check(method.isHTMLConstructor(), htmlConstructor, "Method has the correct htmlConstructor value") harness.check(len(method.signatures()), len(signatures), "Method has the correct number of signatures") sigpairs = zip(method.signatures(), signatures) @@ -93,6 +94,21 @@ def WebIDLTest(parser, harness): "constructor", [("TestChromeConstructor (Wrapper)", [])], chromeOnly=True) + parser = parser.reset() + parser.parse(""" + [HTMLConstructor] + interface TestHTMLConstructor { + }; + """) + results = parser.finish() + harness.check(len(results), 1, "Should be one production") + harness.ok(isinstance(results[0], WebIDL.IDLInterface), + "Should be an IDLInterface") + + checkMethod(results[0].ctor(), "::TestHTMLConstructor::constructor", + "constructor", [("TestHTMLConstructor (Wrapper)", [])], + htmlConstructor=True) + parser = parser.reset() threw = False try: @@ -107,3 +123,151 @@ def WebIDLTest(parser, harness): threw = True harness.ok(threw, "Can't have both a Constructor and a ChromeConstructor") + + # Test HTMLConstructor with argument + parser = parser.reset() + threw = False + try: + parser.parse(""" + [HTMLConstructor(DOMString a)] + interface TestHTMLConstructorWithArgs { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "HTMLConstructor should take no argument") + + # Test HTMLConstructor on a callback interface + parser = parser.reset() + threw = False + try: + parser.parse(""" + [HTMLConstructor] + callback interface TestHTMLConstructorOnCallbackInterface { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "HTMLConstructor can't be used on a callback interface") + + # Test HTMLConstructor and Constructor + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Constructor, + HTMLConstructor] + interface TestHTMLConstructorAndConstructor { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Can't have both a Constructor and a HTMLConstructor") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [HTMLConstructor, + Constructor] + interface TestHTMLConstructorAndConstructor { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Can't have both a HTMLConstructor and a Constructor") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [HTMLConstructor, + Constructor(DOMString a)] + interface TestHTMLConstructorAndConstructor { + }; + """) + except: + threw = True + + harness.ok(threw, "Can't have both a HTMLConstructor and a Constructor") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Constructor(DOMString a), + HTMLConstructor] + interface TestHTMLConstructorAndConstructor { + }; + """) + except: + threw = True + + harness.ok(threw, "Can't have both a HTMLConstructor and a Constructor") + + # Test HTMLConstructor and ChromeConstructor + parser = parser.reset() + threw = False + try: + parser.parse(""" + [ChromeConstructor, + HTMLConstructor] + interface TestHTMLConstructorAndChromeConstructor { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Can't have both a HTMLConstructor and a ChromeConstructor") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [HTMLConstructor, + ChromeConstructor] + interface TestHTMLConstructorAndChromeConstructor { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Can't have both a HTMLConstructor and a ChromeConstructor") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [ChromeConstructor(DOMString a), + HTMLConstructor] + interface TestHTMLConstructorAndChromeConstructor { + }; + """) + results = parser.finish() + except: + threw = True + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [HTMLConstructor, + ChromeConstructor(DOMString a)] + interface TestHTMLConstructorAndChromeConstructor { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Can't have both a HTMLConstructor and a ChromeConstructor") 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 2b09ae71e69..40708e7870e 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 @@ -34,3 +34,36 @@ def WebIDLTest(parser, harness): interface TestNamedConstructorNoInterfaceObject { }; """) + + # Test HTMLConstructor and NoInterfaceObject + parser = parser.reset() + + threw = False + try: + parser.parse(""" + [NoInterfaceObject, HTMLConstructor] + interface TestHTMLConstructorNoInterfaceObject { + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + + threw = False + try: + parser.parse(""" + [HTMLConstructor, NoInterfaceObject] + interface TestHTMLConstructorNoInterfaceObject { + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") 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 d7780c1ffa1..73a32b0acfb 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_distinguishability.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_distinguishability.py @@ -158,21 +158,27 @@ def WebIDLTest(parser, harness): "CallbackInterface?", "CallbackInterface2", "object", "Callback", "Callback2", "optional Dict", "optional Dict2", "sequence", "sequence", - "MozMap", "MozMap", "MozMap", + "record", + "record", + "record", "Date", "Date?", "any", "Promise", "Promise?", "USVString", "ArrayBuffer", "ArrayBufferView", "SharedArrayBuffer", - "Uint8Array", "Uint16Array" ] - # When we can parse Date and RegExp, we need to add them here. + "Uint8Array", "Uint16Array", + "(long or Callback)", "optional (long or Dict)", + ] + # When we can parse Date, we need to add it here. + # XXXbz we can, and should really do that... # Try to categorize things a bit to keep list lengths down def allBut(list1, list2): return [a for a in list1 if a not in list2 and (a != "any" and a != "Promise" and a != "Promise?")] + unions = [ "(long or Callback)", "optional (long or Dict)" ] numerics = [ "long", "short", "long?", "short?" ] booleans = [ "boolean", "boolean?" ] primitives = numerics + booleans - nonNumerics = allBut(argTypes, numerics) + nonNumerics = allBut(argTypes, numerics + unions) nonBooleans = allBut(argTypes, booleans) strings = [ "DOMString", "ByteString", "Enum", "Enum2", "USVString" ] nonStrings = allBut(argTypes, strings) @@ -182,16 +188,18 @@ def WebIDLTest(parser, harness): sharedBufferSourceTypes = ["SharedArrayBuffer"] interfaces = [ "Interface", "Interface?", "AncestorInterface", "UnrelatedInterface", "ImplementedInterface" ] + bufferSourceTypes + sharedBufferSourceTypes - nullables = ["long?", "short?", "boolean?", "Interface?", - "CallbackInterface?", "optional Dict", "optional Dict2", - "Date?", "any", "Promise?"] + nullables = (["long?", "short?", "boolean?", "Interface?", + "CallbackInterface?", "optional Dict", "optional Dict2", + "Date?", "any", "Promise?"] + + allBut(unions, [ "(long or Callback)" ])) dates = [ "Date", "Date?" ] sequences = [ "sequence", "sequence" ] nonUserObjects = nonObjects + interfaces + dates + sequences otherObjects = allBut(argTypes, nonUserObjects + ["object"]) notRelatedInterfaces = (nonObjects + ["UnrelatedInterface"] + otherObjects + dates + sequences + bufferSourceTypes + sharedBufferSourceTypes) - mozMaps = [ "MozMap", "MozMap", "MozMap" ] + records = [ "record", "record", + "record" ] # Build a representation of the distinguishability table as a dict # of dicts, holding True values where needed, holes elsewhere. @@ -231,9 +239,9 @@ def WebIDLTest(parser, harness): allBut(argTypes, sequences + ["object"])) setDistinguishable("sequence", allBut(argTypes, sequences + ["object"])) - setDistinguishable("MozMap", nonUserObjects) - setDistinguishable("MozMap", nonUserObjects) - setDistinguishable("MozMap", nonUserObjects) + setDistinguishable("record", nonUserObjects) + setDistinguishable("record", nonUserObjects) + setDistinguishable("record", nonUserObjects) setDistinguishable("Date", allBut(argTypes, dates + ["object"])) setDistinguishable("Date?", allBut(argTypes, dates + nullables + ["object"])) setDistinguishable("any", []) @@ -244,6 +252,10 @@ def WebIDLTest(parser, harness): setDistinguishable("Uint8Array", allBut(argTypes, ["ArrayBufferView", "Uint8Array", "object"])) setDistinguishable("Uint16Array", allBut(argTypes, ["ArrayBufferView", "Uint16Array", "object"])) setDistinguishable("SharedArrayBuffer", allBut(argTypes, ["SharedArrayBuffer", "object"])) + setDistinguishable("(long or Callback)", + allBut(nonUserObjects, numerics)) + setDistinguishable("optional (long or Dict)", + allBut(nonUserObjects, numerics + nullables)) def areDistinguishable(type1, type2): return data[type1].get(type2, False) @@ -263,7 +275,6 @@ def WebIDLTest(parser, harness): callback Callback2 = long(short arg); dictionary Dict {}; dictionary Dict2 {}; - interface _Promise {}; interface TestInterface {%s }; """ 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 new file mode 100644 index 00000000000..b510a30c044 --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_identifier_conflict.py @@ -0,0 +1,39 @@ +# Import the WebIDL module, so we can do isinstance checks and whatnot +import WebIDL + +def WebIDLTest(parser, harness): + try: + parser.parse(""" + enum Foo { "a" }; + interface Foo; + """) + results = parser.finish() + harness.ok(False, "Should fail to parse") + except Exception, e: + harness.ok("Name collision" in e.message, + "Should have name collision for interface") + + parser = parser.reset() + try: + parser.parse(""" + dictionary Foo { long x; }; + enum Foo { "a" }; + """) + results = parser.finish() + harness.ok(False, "Should fail to parse") + except Exception, e: + harness.ok("Name collision" in e.message, + "Should have name collision for dictionary") + + parser = parser.reset() + try: + parser.parse(""" + enum Foo { "a" }; + enum Foo { "b" }; + """) + results = parser.finish() + harness.ok(False, "Should fail to parse") + except Exception, 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_maplikesetlikeiterable.py b/components/script/dom/bindings/codegen/parser/tests/test_interface_maplikesetlikeiterable.py index 159b50f84ff..ee5d870c200 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 @@ -88,6 +88,8 @@ def WebIDLTest(parser, harness): disallowedNonMethodNames = ["clear", "delete"] mapDisallowedNonMethodNames = ["set"] + disallowedNonMethodNames setDisallowedNonMethodNames = ["add"] + disallowedNonMethodNames + unrelatedMembers = [("unrelatedAttribute", WebIDL.IDLAttribute), + ("unrelatedMethod", WebIDL.IDLMethod)] # # Simple Usage Tests @@ -99,52 +101,147 @@ def WebIDLTest(parser, harness): iterable; readonly attribute unsigned long length; getter long(unsigned long index); + attribute long unrelatedAttribute; + long unrelatedMethod(); }; - """, valueIterableMembers) + """, valueIterableMembers + unrelatedMembers) + + shouldPass("Iterable (key only) inheriting from parent", + """ + interface Foo1 : Foo2 { + iterable; + readonly attribute unsigned long length; + getter long(unsigned long index); + }; + interface Foo2 { + attribute long unrelatedAttribute; + long unrelatedMethod(); + }; + """, valueIterableMembers, numProductions=2) shouldPass("Iterable (key and value)", """ interface Foo1 { iterable; + attribute long unrelatedAttribute; + long unrelatedMethod(); }; - """, iterableMembers, + """, iterableMembers + unrelatedMembers, # numProductions == 2 because of the generated iterator iface, numProductions=2) + shouldPass("Iterable (key and value) inheriting from parent", + """ + interface Foo1 : Foo2 { + iterable; + }; + interface Foo2 { + attribute long unrelatedAttribute; + long unrelatedMethod(); + }; + """, iterableMembers, + # numProductions == 3 because of the generated iterator iface, + numProductions=3) + shouldPass("Maplike (readwrite)", """ interface Foo1 { maplike; + attribute long unrelatedAttribute; + long unrelatedMethod(); + }; + """, mapRWMembers + unrelatedMembers) + + shouldPass("Maplike (readwrite) inheriting from parent", + """ + interface Foo1 : Foo2 { + maplike; + }; + interface Foo2 { + attribute long unrelatedAttribute; + long unrelatedMethod(); }; - """, mapRWMembers) + """, mapRWMembers, numProductions=2) shouldPass("Maplike (readwrite)", """ interface Foo1 { maplike; + attribute long unrelatedAttribute; + long unrelatedMethod(); + }; + """, mapRWMembers + unrelatedMembers) + + shouldPass("Maplike (readwrite) inheriting from parent", + """ + interface Foo1 : Foo2 { + maplike; }; - """, mapRWMembers) + interface Foo2 { + attribute long unrelatedAttribute; + long unrelatedMethod(); + }; + """, mapRWMembers, numProductions=2) shouldPass("Maplike (readonly)", """ interface Foo1 { readonly maplike; + attribute long unrelatedAttribute; + long unrelatedMethod(); + }; + """, mapROMembers + unrelatedMembers) + + shouldPass("Maplike (readonly) inheriting from parent", + """ + interface Foo1 : Foo2 { + readonly maplike; + }; + interface Foo2 { + attribute long unrelatedAttribute; + long unrelatedMethod(); }; - """, mapROMembers) + """, mapROMembers, numProductions=2) shouldPass("Setlike (readwrite)", """ interface Foo1 { setlike; + attribute long unrelatedAttribute; + long unrelatedMethod(); }; - """, setRWMembers) + """, setRWMembers + unrelatedMembers) + + shouldPass("Setlike (readwrite) inheriting from parent", + """ + interface Foo1 : Foo2 { + setlike; + }; + interface Foo2 { + attribute long unrelatedAttribute; + long unrelatedMethod(); + }; + """, setRWMembers, numProductions=2) shouldPass("Setlike (readonly)", """ interface Foo1 { readonly setlike; + attribute long unrelatedAttribute; + long unrelatedMethod(); + }; + """, setROMembers + unrelatedMembers) + + shouldPass("Setlike (readonly) inheriting from parent", + """ + interface Foo1 : Foo2 { + readonly setlike; + }; + interface Foo2 { + attribute long unrelatedAttribute; + long unrelatedMethod(); }; - """, setROMembers) + """, setROMembers, numProductions=2) shouldPass("Inheritance of maplike/setlike", """ diff --git a/components/script/dom/bindings/codegen/parser/tests/test_mozmap.py b/components/script/dom/bindings/codegen/parser/tests/test_mozmap.py deleted file mode 100644 index 1a36fdd62c4..00000000000 --- a/components/script/dom/bindings/codegen/parser/tests/test_mozmap.py +++ /dev/null @@ -1,39 +0,0 @@ -import WebIDL - -def WebIDLTest(parser, harness): - parser.parse(""" - dictionary Dict {}; - interface MozMapArg { - void foo(MozMap arg); - }; - """) - - results = parser.finish() - - harness.check(len(results), 2, "Should know about two things"); - harness.ok(isinstance(results[1], WebIDL.IDLInterface), - "Should have an interface here"); - members = results[1].members - harness.check(len(members), 1, "Should have one member") - harness.ok(members[0].isMethod(), "Should have method") - signature = members[0].signatures()[0] - args = signature[1] - harness.check(len(args), 1, "Should have one arg") - harness.ok(args[0].type.isMozMap(), "Should have a MozMap type here") - harness.ok(args[0].type.inner.isDictionary(), - "Should have a dictionary inner type") - - parser = parser.reset() - threw = False - try: - parser.parse(""" - interface MozMapVoidArg { - void foo(MozMap arg); - }; - """) - - results = parser.finish() - except Exception,x: - threw = True - - harness.ok(threw, "Should have thrown.") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_newobject.py b/components/script/dom/bindings/codegen/parser/tests/test_newobject.py new file mode 100644 index 00000000000..26785c6a270 --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_newobject.py @@ -0,0 +1,70 @@ +# Import the WebIDL module, so we can do isinstance checks and whatnot +import WebIDL + +def WebIDLTest(parser, harness): + # Basic functionality + parser.parse( + """ + interface Iface { + [NewObject] readonly attribute Iface attr; + [NewObject] Iface method(); + }; + """) + results = parser.finish() + harness.ok(results, "Should not have thrown on basic [NewObject] usage") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface Iface { + [Pure, NewObject] readonly attribute Iface attr; + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "[NewObject] attributes must depend on something") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface Iface { + [Pure, NewObject] Iface method(); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "[NewObject] methods must depend on something") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface Iface { + [Cached, NewObject, Affects=Nothing] readonly attribute Iface attr; + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "[NewObject] attributes must not be [Cached]") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface Iface { + [StoreInSlot, NewObject, Affects=Nothing] readonly attribute Iface attr; + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "[NewObject] attributes must not be [StoreInSlot]") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_promise.py b/components/script/dom/bindings/codegen/parser/tests/test_promise.py index 55bc0768092..43c74029dc5 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_promise.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_promise.py @@ -2,7 +2,6 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - interface _Promise {}; interface A { legacycaller Promise foo(); }; @@ -18,7 +17,6 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - interface _Promise {}; interface A { Promise foo(); long foo(long arg); @@ -35,7 +33,6 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - interface _Promise {}; interface A { long foo(long arg); Promise foo(); @@ -48,9 +45,36 @@ def WebIDLTest(parser, harness): "Should not allow overloads which have both Promise and " "non-Promise return types.") + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A { + Promise? foo(); + }; + """) + results = parser.finish(); + except: + threw = True + harness.ok(threw, + "Should not allow nullable Promise return values.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A { + void foo(Promise? arg); + }; + """) + results = parser.finish(); + except: + threw = True + harness.ok(threw, + "Should not allow nullable Promise arguments.") + parser = parser.reset() parser.parse(""" - interface _Promise {}; interface A { Promise foo(); Promise foo(long arg); @@ -61,3 +85,73 @@ def WebIDLTest(parser, harness): harness.ok(True, "Should allow overloads which only have Promise and return " "types.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A { + attribute Promise attr; + }; + """) + results = parser.finish(); + except: + threw = True + harness.ok(threw, + "Should not allow writable Promise-typed attributes.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A { + [LenientSetter] readonly attribute Promise attr; + }; + """) + results = parser.finish(); + except: + threw = True + harness.ok(threw, + "Should not allow [LenientSetter] Promise-typed attributes.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A { + [PutForwards=bar] readonly attribute Promise attr; + }; + """) + results = parser.finish(); + except: + threw = True + harness.ok(threw, + "Should not allow [PutForwards] Promise-typed attributes.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A { + [Replaceable] readonly attribute Promise attr; + }; + """) + results = parser.finish(); + except: + threw = True + harness.ok(threw, + "Should not allow [Replaceable] Promise-typed attributes.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface A { + [SameObject] readonly attribute Promise attr; + }; + """) + results = parser.finish(); + except: + threw = True + harness.ok(threw, + "Should not allow [SameObject] Promise-typed attributes.") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_record.py b/components/script/dom/bindings/codegen/parser/tests/test_record.py new file mode 100644 index 00000000000..c3fe29fa060 --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_record.py @@ -0,0 +1,53 @@ +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse(""" + dictionary Dict {}; + interface RecordArg { + void foo(record arg); + }; + """) + + results = parser.finish() + + harness.check(len(results), 2, "Should know about two things"); + harness.ok(isinstance(results[1], WebIDL.IDLInterface), + "Should have an interface here"); + members = results[1].members + harness.check(len(members), 1, "Should have one member") + harness.ok(members[0].isMethod(), "Should have method") + signature = members[0].signatures()[0] + args = signature[1] + harness.check(len(args), 1, "Should have one arg") + harness.ok(args[0].type.isRecord(), "Should have a record type here") + harness.ok(args[0].type.inner.isDictionary(), + "Should have a dictionary inner type") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface RecordVoidArg { + void foo(record arg); + }; + """) + + results = parser.finish() + except Exception,x: + threw = True + harness.ok(threw, "Should have thrown because record can't have void as value type.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary Dict { + record val; + }; + """) + + results = parser.finish() + except Exception,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_special_methods.py b/components/script/dom/bindings/codegen/parser/tests/test_special_methods.py index 695cfe4f250..1e3a95b9bc2 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_special_methods.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_special_methods.py @@ -6,15 +6,14 @@ def WebIDLTest(parser, harness): getter long long (unsigned long index); setter long long (unsigned long index, long long value); creator long long (unsigned long index, long long value); - deleter long long (unsigned long index); getter boolean (DOMString name); setter boolean (DOMString name, boolean value); creator boolean (DOMString name, boolean value); deleter boolean (DOMString name); + readonly attribute unsigned long length; }; interface SpecialMethodsCombination { - getter deleter long long (unsigned long index); setter creator long long (unsigned long index, long long value); getter deleter boolean (DOMString name); setter creator boolean (DOMString name, boolean value); @@ -49,25 +48,39 @@ def WebIDLTest(parser, harness): setter=True) checkMethod(iface.members[2], "::SpecialMethods::__indexedcreator", "__indexedcreator", creator=True) - checkMethod(iface.members[3], "::SpecialMethods::__indexeddeleter", "__indexeddeleter", - deleter=True) - checkMethod(iface.members[4], "::SpecialMethods::__namedgetter", "__namedgetter", + checkMethod(iface.members[3], "::SpecialMethods::__namedgetter", "__namedgetter", getter=True) - checkMethod(iface.members[5], "::SpecialMethods::__namedsetter", "__namedsetter", + checkMethod(iface.members[4], "::SpecialMethods::__namedsetter", "__namedsetter", setter=True) - checkMethod(iface.members[6], "::SpecialMethods::__namedcreator", "__namedcreator", + checkMethod(iface.members[5], "::SpecialMethods::__namedcreator", "__namedcreator", creator=True) - checkMethod(iface.members[7], "::SpecialMethods::__nameddeleter", "__nameddeleter", + checkMethod(iface.members[6], "::SpecialMethods::__nameddeleter", "__nameddeleter", deleter=True) iface = results[1] - harness.check(len(iface.members), 4, "Expect 4 members") + harness.check(len(iface.members), 3, "Expect 3 members") - checkMethod(iface.members[0], "::SpecialMethodsCombination::__indexedgetterdeleter", - "__indexedgetterdeleter", getter=True, deleter=True) - checkMethod(iface.members[1], "::SpecialMethodsCombination::__indexedsettercreator", + checkMethod(iface.members[0], "::SpecialMethodsCombination::__indexedsettercreator", "__indexedsettercreator", setter=True, creator=True) - checkMethod(iface.members[2], "::SpecialMethodsCombination::__namedgetterdeleter", + checkMethod(iface.members[1], "::SpecialMethodsCombination::__namedgetterdeleter", "__namedgetterdeleter", getter=True, deleter=True) - checkMethod(iface.members[3], "::SpecialMethodsCombination::__namedsettercreator", + checkMethod(iface.members[2], "::SpecialMethodsCombination::__namedsettercreator", "__namedsettercreator", setter=True, creator=True) + + parser = parser.reset(); + + threw = False + try: + parser.parse( + """ + interface IndexedDeleter { + deleter void(unsigned long index); + }; + """) + parser.finish() + except: + threw = True + + harness.ok(threw, "There are no indexed deleters") + + -- cgit v1.2.3 From 0713257adde476cc0a0f74365acf52f19fcd9440 Mon Sep 17 00:00:00 2001 From: Connor Brewster Date: Mon, 12 Jun 2017 21:50:53 -0600 Subject: Generate GetConstructorObject for all interfaces --- components/script/dom/bindings/codegen/CodegenRust.py | 2 +- components/script/dom/bindings/codegen/Configuration.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index bf6ca70e6c0..130d2008448 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2863,7 +2863,7 @@ create_noncallback_interface_object(cx, %(length)s, interface.handle_mut()); assert!(!interface.is_null());""" % properties)) - if self.descriptor.hasDescendants(): + if self.descriptor.shouldCacheConstructor(): code.append(CGGeneric("""\ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); (*cache)[PrototypeList::Constructor::%(id)s as usize] = interface.get(); diff --git a/components/script/dom/bindings/codegen/Configuration.py b/components/script/dom/bindings/codegen/Configuration.py index 0fe9bf6c004..df6c0a36c76 100644 --- a/components/script/dom/bindings/codegen/Configuration.py +++ b/components/script/dom/bindings/codegen/Configuration.py @@ -398,7 +398,11 @@ class Descriptor(DescriptorProvider): assert self.interface.hasInterfaceObject() if self.interface.getExtendedAttribute("Inline"): return False - return self.interface.isCallback() or self.interface.isNamespace() or self.hasDescendants() + return (self.interface.isCallback() or self.interface.isNamespace() or + self.hasDescendants() or self.interface.getExtendedAttribute("HTMLConstructor")) + + def shouldCacheConstructor(self): + return self.hasDescendants() or self.interface.getExtendedAttribute("HTMLConstructor") def isExposedConditionally(self): return self.interface.isExposedConditionally() -- cgit v1.2.3 From 2333b39569a0cc598289c948aefea64aa9aa4858 Mon Sep 17 00:00:00 2001 From: Connor Brewster Date: Wed, 7 Jun 2017 13:55:42 -0600 Subject: Implement HTMLConstructor --- .../script/dom/bindings/codegen/CodegenRust.py | 84 ++++++++++++++++++++-- 1 file changed, 78 insertions(+), 6 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 130d2008448..5f60a9fc5fa 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -5301,11 +5301,79 @@ class CGClassConstructHook(CGAbstractExternMethod): preamble += "let global = Root::downcast::(global).unwrap();\n" % list(self.exposureSet)[0] preamble += """let args = CallArgs::from_vp(vp, argc);\n""" preamble = CGGeneric(preamble) - name = self.constructor.identifier.name - nativeName = MakeNativeName(self.descriptor.binaryNameFor(name)) - callGenerator = CGMethodCall(["&global"], nativeName, True, - self.descriptor, self.constructor) - return CGList([preamble, callGenerator]) + if self.constructor.isHTMLConstructor(): + signatures = self.constructor.signatures() + assert len(signatures) == 1 + constructorCall = CGGeneric("""\ +// Step 2 https://html.spec.whatwg.org/multipage/#htmlconstructor +// The custom element definition cannot use an element interface as its constructor + +// The new_target might be a cross-compartment wrapper. Get the underlying object +// so we can do the spec's object-identity checks. +rooted!(in(cx) let new_target = UnwrapObject(args.new_target().to_object(), 1)); +if new_target.is_null() { + throw_dom_exception(cx, global.upcast::(), Error::Type("new.target is null".to_owned())); + return false; +} + +if args.callee() == new_target.get() { + throw_dom_exception(cx, global.upcast::(), + Error::Type("new.target must not be the active function object".to_owned())); + return false; +} + +// Step 6 +rooted!(in(cx) let mut prototype = ptr::null_mut()); +{ + rooted!(in(cx) let mut proto_val = UndefinedValue()); + let _ac = JSAutoCompartment::new(cx, new_target.get()); + if !JS_GetProperty(cx, new_target.handle(), b"prototype\\0".as_ptr() as *const _, proto_val.handle_mut()) { + return false; + } + + if !proto_val.is_object() { + // Step 7 of https://html.spec.whatwg.org/multipage/#htmlconstructor. + // This fallback behavior is designed to match analogous behavior for the + // JavaScript built-ins. So we enter the compartment of our underlying + // newTarget object and fall back to the prototype object from that global. + // XXX The spec says to use GetFunctionRealm(), which is not actually + // the same thing as what we have here (e.g. in the case of scripted callable proxies + // whose target is not same-compartment with the proxy, or bound functions, etc). + // https://bugzilla.mozilla.org/show_bug.cgi?id=1317658 + + rooted!(in(cx) let global_object = CurrentGlobalOrNull(cx)); + GetProtoObject(cx, global_object.handle(), prototype.handle_mut()); + } else { + // Step 6 + prototype.set(proto_val.to_object()); + }; +} + +// Wrap prototype in this context since it is from the newTarget compartment +if !JS_WrapObject(cx, prototype.handle_mut()) { + return false; +} + +let result: Result, Error> = html_constructor(&global, &args); +let result = match result { + Ok(result) => result, + Err(e) => { + throw_dom_exception(cx, global.upcast::(), e); + return false; + }, +}; + +JS_SetPrototype(cx, result.reflector().get_jsobject(), prototype.handle()); + +(result).to_jsval(cx, args.rval()); +return true; +""" % self.descriptor.name) + else: + name = self.constructor.identifier.name + nativeName = MakeNativeName(self.descriptor.binaryNameFor(name)) + constructorCall = CGMethodCall(["&global"], nativeName, True, + self.descriptor, self.constructor) + return CGList([preamble, constructorCall]) class CGClassFinalizeHook(CGAbstractClassHook): @@ -5517,9 +5585,11 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::jsapi::JS_ObjectIsDate', 'js::jsapi::JS_SetImmutablePrototype', 'js::jsapi::JS_SetProperty', + 'js::jsapi::JS_SetPrototype', 'js::jsapi::JS_SetReservedSlot', 'js::jsapi::JS_SplicePrototype', 'js::jsapi::JS_WrapValue', + 'js::jsapi::JS_WrapObject', 'js::jsapi::MutableHandle', 'js::jsapi::MutableHandleObject', 'js::jsapi::MutableHandleValue', @@ -5547,6 +5617,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::glue::RUST_JSID_IS_STRING', 'js::glue::RUST_SYMBOL_TO_JSID', 'js::glue::int_to_jsid', + 'js::glue::UnwrapObject', 'js::panic::maybe_resume_unwind', 'js::panic::wrap_panic', 'js::rust::GCMethods', @@ -5561,14 +5632,15 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'dom::bindings::interface::ConstructorClassHook', 'dom::bindings::interface::InterfaceConstructorBehavior', 'dom::bindings::interface::NonCallbackInterfaceObjectClass', - 'dom::bindings::interface::create_callback_interface_object', 'dom::bindings::interface::create_global_object', + 'dom::bindings::interface::create_callback_interface_object', 'dom::bindings::interface::create_interface_prototype_object', 'dom::bindings::interface::create_named_constructors', 'dom::bindings::interface::create_noncallback_interface_object', 'dom::bindings::interface::define_guarded_constants', 'dom::bindings::interface::define_guarded_methods', 'dom::bindings::interface::define_guarded_properties', + 'dom::bindings::interface::html_constructor', 'dom::bindings::interface::is_exposed_in', 'dom::bindings::iterable::Iterable', 'dom::bindings::iterable::IteratorType', -- cgit v1.2.3 From 438191e0b207fd6294a465149a37c63f32ce9161 Mon Sep 17 00:00:00 2001 From: Connor Brewster Date: Mon, 10 Jul 2017 10:45:26 -0600 Subject: Implement CEReactions codegen --- components/script/dom/bindings/codegen/CodegenRust.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 5f60a9fc5fa..efb39208b44 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -3152,7 +3152,7 @@ class CGCallGenerator(CGThing): """ def __init__(self, errorResult, arguments, argsPre, returnType, extendedAttributes, descriptor, nativeMethodName, - static, object="this"): + static, object="this", hasCEReactions=False): CGThing.__init__(self) assert errorResult is None or isinstance(errorResult, str) @@ -3185,6 +3185,9 @@ class CGCallGenerator(CGThing): call = CGWrapper(call, pre="%s." % object) call = CGList([call, CGWrapper(args, pre="(", post=")")]) + if hasCEReactions: + self.cgRoot.append(CGGeneric("push_new_element_queue();\n")) + self.cgRoot.append(CGList([ CGGeneric("let result: "), result, @@ -3193,6 +3196,9 @@ class CGCallGenerator(CGThing): CGGeneric(";"), ])) + if hasCEReactions: + self.cgRoot.append(CGGeneric("pop_current_element_queue();\n")) + if isFallible: if static: glob = "global.upcast::()" @@ -3267,11 +3273,12 @@ class CGPerSignatureCall(CGThing): idlNode.maplikeOrSetlikeOrIterable, idlNode.identifier.name)) else: + hasCEReactions = idlNode.getExtendedAttribute("CEReactions") cgThings.append(CGCallGenerator( errorResult, self.getArguments(), self.argsPre, returnType, self.extendedAttributes, descriptor, nativeMethodName, - static)) + static, hasCEReactions=hasCEReactions)) self.cgRoot = CGList(cgThings, "\n") @@ -5642,6 +5649,8 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'dom::bindings::interface::define_guarded_properties', 'dom::bindings::interface::html_constructor', 'dom::bindings::interface::is_exposed_in', + 'dom::bindings::interface::pop_current_element_queue', + 'dom::bindings::interface::push_new_element_queue', 'dom::bindings::iterable::Iterable', 'dom::bindings::iterable::IteratorType', 'dom::bindings::js::JS', -- cgit v1.2.3 From 354d94059b7071d4164e01affd0f643940e3c50b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 2 Aug 2017 11:48:49 +0200 Subject: Generate DOM bindings imports for webidl typedefs --- .../script/dom/bindings/codegen/CodegenRust.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index efb39208b44..482b713e10c 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1848,7 +1848,8 @@ class CGImports(CGWrapper): """ Generates the appropriate import/use statements. """ - def __init__(self, child, descriptors, callbacks, dictionaries, enums, imports, config, ignored_warnings=None): + def __init__(self, child, descriptors, callbacks, dictionaries, enums, typedefs, imports, config, + ignored_warnings=None): """ Adds a set of imports. """ @@ -1937,6 +1938,11 @@ class CGImports(CGWrapper): for d in dictionaries: types += componentTypes(d) + # Import the type names used in the typedefs that are being defined. + for t in typedefs: + if not t.innerType.isCallback(): + types += componentTypes(t.innerType) + # Normalize the types we've collected and remove any ones which can't be imported. types = removeWrapperAndNullableTypes(types) @@ -2292,6 +2298,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config): callbacks=[], dictionaries=[], enums=[], + typedefs=[], imports=imports, config=config, ignored_warnings=[]) @@ -5507,15 +5514,17 @@ class CGWeakReferenceableTrait(CGThing): return self.code -def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries=None, enums=None): +def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries=None, enums=None, typedefs=None): if not callbacks: callbacks = [] if not dictionaries: dictionaries = [] if not enums: enums = [] + if not typedefs: + typedefs = [] - return CGImports(cgthings, descriptors, callbacks, dictionaries, enums, [ + return CGImports(cgthings, descriptors, callbacks, dictionaries, enums, typedefs, [ 'core::nonzero::NonZero', 'js', 'js::JSCLASS_GLOBAL_SLOT_COUNT', @@ -6220,7 +6229,7 @@ class CGBindingRoot(CGThing): # Do codegen for all the enums. cgthings = [CGEnum(e) for e in enums] - # Do codegen for all the typdefs + # Do codegen for all the typedefs for t in typedefs: typeName = getRetvalDeclarationForType(t.innerType, config.getDescriptorProvider()) substs = { @@ -6258,7 +6267,7 @@ class CGBindingRoot(CGThing): # Add imports curr = generate_imports(config, curr, callbackDescriptors, mainCallbacks, - dictionaries, enums) + dictionaries, enums, typedefs) # Add the auto-generated comment. curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT) @@ -7060,7 +7069,7 @@ class GlobalGenRoots(): CGRegisterProxyHandlers(config), ], "\n") - return CGImports(code, descriptors=[], callbacks=[], dictionaries=[], enums=[], imports=[ + return CGImports(code, descriptors=[], callbacks=[], dictionaries=[], enums=[], typedefs=[], imports=[ 'dom::bindings::codegen::Bindings', 'dom::bindings::codegen::PrototypeList::Proxies', 'libc', -- cgit v1.2.3 From 1a9f4cad0871bcde9420f633c527b933ac288057 Mon Sep 17 00:00:00 2001 From: Connor Brewster Date: Thu, 20 Jul 2017 16:35:46 -0600 Subject: Fix compartment mismatch issue --- components/script/dom/bindings/codegen/CodegenRust.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 482b713e10c..7f97868a378 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -5377,7 +5377,12 @@ let result = match result { }, }; -JS_SetPrototype(cx, result.reflector().get_jsobject(), prototype.handle()); +rooted!(in(cx) let mut element = result.reflector().get_jsobject().get()); +if !JS_WrapObject(cx, element.handle_mut()) { + return false; +} + +JS_SetPrototype(cx, element.handle(), prototype.handle()); (result).to_jsval(cx, args.rval()); return true; -- cgit v1.2.3 From f16a0466239b50f74cddfd619161575aad5691fb Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Wed, 30 Aug 2017 13:20:34 +0200 Subject: Update the WebIDL parser --- .../script/dom/bindings/codegen/parser/WebIDL.py | 39 +++++++++++++++++----- 1 file changed, 31 insertions(+), 8 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index 820dc108fbf..5045eae6493 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.py @@ -2064,6 +2064,9 @@ class IDLType(IDLObject): def isRecord(self): return False + def isReadableStream(self): + return False + def isArrayBuffer(self): return False @@ -2091,12 +2094,12 @@ class IDLType(IDLObject): def isSpiderMonkeyInterface(self): """ Returns a boolean indicating whether this type is an 'interface' - type that is implemented in Spidermonkey. At the moment, this - only returns true for the types from the TypedArray spec. """ + type that is implemented in SpiderMonkey. """ return self.isInterface() and (self.isArrayBuffer() or self.isArrayBufferView() or self.isSharedArrayBuffer() or - self.isTypedArray()) + self.isTypedArray() or + self.isReadableStream()) def isDictionary(self): return False @@ -2289,6 +2292,9 @@ class IDLNullableType(IDLParametrizedType): def isRecord(self): return self.inner.isRecord() + def isReadableStream(self): + return self.inner.isReadableStream() + def isArrayBuffer(self): return self.inner.isArrayBuffer() @@ -2656,6 +2662,9 @@ class IDLTypedefType(IDLType): def isRecord(self): return self.inner.isRecord() + def isReadableStream(self): + return self.inner.isReadableStream() + def isDictionary(self): return self.inner.isDictionary() @@ -2970,7 +2979,8 @@ class IDLBuiltinType(IDLType): 'Int32Array', 'Uint32Array', 'Float32Array', - 'Float64Array' + 'Float64Array', + 'ReadableStream', ) TagLookup = { @@ -3005,7 +3015,8 @@ class IDLBuiltinType(IDLType): Types.Int32Array: IDLType.Tags.interface, Types.Uint32Array: IDLType.Tags.interface, Types.Float32Array: IDLType.Tags.interface, - Types.Float64Array: IDLType.Tags.interface + Types.Float64Array: IDLType.Tags.interface, + Types.ReadableStream: IDLType.Tags.interface, } def __init__(self, location, name, type): @@ -3052,6 +3063,9 @@ class IDLBuiltinType(IDLType): return (self._typeTag >= IDLBuiltinType.Types.Int8Array and self._typeTag <= IDLBuiltinType.Types.Float64Array) + def isReadableStream(self): + return self._typeTag == IDLBuiltinType.Types.ReadableStream + def isInterface(self): # TypedArray things are interface types per the TypedArray spec, # but we handle them as builtins because SpiderMonkey implements @@ -3059,7 +3073,8 @@ class IDLBuiltinType(IDLType): return (self.isArrayBuffer() or self.isArrayBufferView() or self.isSharedArrayBuffer() or - self.isTypedArray()) + self.isTypedArray() or + self.isReadableStream()) def isNonCallbackInterface(self): # All the interfaces we can be are non-callback @@ -3129,6 +3144,7 @@ class IDLBuiltinType(IDLType): # that's not an ArrayBuffer or a callback interface (self.isArrayBuffer() and not other.isArrayBuffer()) or (self.isSharedArrayBuffer() and not other.isSharedArrayBuffer()) or + (self.isReadableStream() and not other.isReadableStream()) or # ArrayBufferView is distinguishable from everything # that's not an ArrayBufferView or typed array. (self.isArrayBufferView() and not other.isArrayBufferView() and @@ -3238,7 +3254,10 @@ BuiltinTypes = { IDLBuiltinType.Types.Float32Array), IDLBuiltinType.Types.Float64Array: IDLBuiltinType(BuiltinLocation(""), "Float64Array", - IDLBuiltinType.Types.Float64Array) + IDLBuiltinType.Types.Float64Array), + IDLBuiltinType.Types.ReadableStream: + IDLBuiltinType(BuiltinLocation(""), "ReadableStream", + IDLBuiltinType.Types.ReadableStream), } @@ -5287,7 +5306,8 @@ class Tokenizer(object): "maplike": "MAPLIKE", "setlike": "SETLIKE", "iterable": "ITERABLE", - "namespace": "NAMESPACE" + "namespace": "NAMESPACE", + "ReadableStream": "READABLESTREAM", } tokens.extend(keywords.values()) @@ -6475,6 +6495,7 @@ class Parser(Tokenizer): NonAnyType : PrimitiveType Null | ARRAYBUFFER Null | SHAREDARRAYBUFFER Null + | READABLESTREAM Null | OBJECT Null """ if p[1] == "object": @@ -6483,6 +6504,8 @@ class Parser(Tokenizer): type = BuiltinTypes[IDLBuiltinType.Types.ArrayBuffer] elif p[1] == "SharedArrayBuffer": type = BuiltinTypes[IDLBuiltinType.Types.SharedArrayBuffer] + elif p[1] == "ReadableStream": + type = BuiltinTypes[IDLBuiltinType.Types.ReadableStream] else: type = BuiltinTypes[p[1]] -- cgit v1.2.3 From b29e56eefcf0710bec318781de9bce5aabb5348a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Sun, 17 Sep 2017 07:32:01 +0200 Subject: script: Fix code generation for named getters. Fixes part of #18535 --- components/script/dom/bindings/codegen/CodegenRust.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 7f97868a378..0ad87747a12 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -4938,8 +4938,6 @@ class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod): set += ("if RUST_JSID_IS_STRING(id) {\n" + CGIndenter(CGProxyNamedSetter(self.descriptor)).define() + " return (*opresult).succeed();\n" + - "} else {\n" + - " return false;\n" + "}\n") else: set += ("if RUST_JSID_IS_STRING(id) {\n" + @@ -4948,7 +4946,7 @@ class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod): " return (*opresult).failNoNamedSetter();\n" " }\n" "}\n") - set += "return proxyhandler::define_property(%s);" % ", ".join(a.name for a in self.args) + set += "return proxyhandler::define_property(%s);" % ", ".join(a.name for a in self.args) return set def definition_body(self): -- cgit v1.2.3 From f5d16fc069533b810a76a2fa611882e1b9c8743c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Sun, 17 Sep 2017 19:25:58 +0200 Subject: script: Fix integer-JSID handling in named getters. Fixes #10686 --- components/script/dom/bindings/codegen/CodegenRust.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 0ad87747a12..c42ec783716 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -4750,7 +4750,7 @@ class CGProxyNamedOperation(CGProxySpecialOperation): def define(self): # Our first argument is the id we're getting. argName = self.arguments[0].identifier.name - return ("let %s = string_jsid_to_string(cx, id);\n" + return ("let %s = jsid_to_string(cx, id).expect(\"Not a string-convertible JSID?\");\n" "let this = UnwrapProxy(proxy);\n" "let this = &*this;\n" % argName + CGProxySpecialOperation.define(self)) @@ -4868,7 +4868,7 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod): # ResolveOwnProperty or EnumerateOwnProperties filter out named # properties that shadow prototype properties. namedGet = """ -if RUST_JSID_IS_STRING(id) { +if RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id) { let mut has_on_proto = false; if !has_property_on_prototype(cx, proxy, id, &mut has_on_proto) { return false; @@ -4935,12 +4935,12 @@ class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod): if self.descriptor.hasUnforgeableMembers: raise TypeError("Can't handle a named setter on an interface that has " "unforgeables. Figure out how that should work!") - set += ("if RUST_JSID_IS_STRING(id) {\n" + + set += ("if RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id) {\n" + CGIndenter(CGProxyNamedSetter(self.descriptor)).define() + " return (*opresult).succeed();\n" + "}\n") else: - set += ("if RUST_JSID_IS_STRING(id) {\n" + + set += ("if RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id) {\n" + CGIndenter(CGProxyNamedGetter(self.descriptor)).define() + " if result.is_some() {\n" " return (*opresult).failNoNamedSetter();\n" @@ -5095,7 +5095,7 @@ class CGDOMJSProxyHandler_hasOwn(CGAbstractExternMethod): namedGetter = self.descriptor.operations['NamedGetter'] if namedGetter: named = """\ -if RUST_JSID_IS_STRING(id) { +if RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id) { let mut has_on_proto = false; if !has_property_on_prototype(cx, proxy, id, &mut has_on_proto) { return false; @@ -5175,7 +5175,7 @@ if !expando.is_null() { namedGetter = self.descriptor.operations['NamedGetter'] if namedGetter: - getNamed = ("if RUST_JSID_IS_STRING(id) {\n" + + getNamed = ("if RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id) {\n" + CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() + "}\n") else: @@ -5633,6 +5633,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::glue::GetProxyPrivate', 'js::glue::NewProxyObject', 'js::glue::ProxyTraps', + 'js::glue::RUST_JSID_IS_INT', 'js::glue::RUST_JSID_IS_STRING', 'js::glue::RUST_SYMBOL_TO_JSID', 'js::glue::int_to_jsid', @@ -5720,6 +5721,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'dom::bindings::conversions::root_from_handlevalue', 'dom::bindings::conversions::root_from_object', 'dom::bindings::conversions::string_jsid_to_string', + 'dom::bindings::conversions::jsid_to_string', 'dom::bindings::codegen::PrototypeList', 'dom::bindings::codegen::RegisterBindings', 'dom::bindings::codegen::UnionTypes', -- cgit v1.2.3 From 6edefb829c2417b763478cde3fbbc483ed196b04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Sun, 17 Sep 2017 19:33:11 +0200 Subject: script: remove unused function. --- components/script/dom/bindings/codegen/CodegenRust.py | 1 - 1 file changed, 1 deletion(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index c42ec783716..afb189ec795 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -5720,7 +5720,6 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'dom::bindings::conversions::root_from_handleobject', 'dom::bindings::conversions::root_from_handlevalue', 'dom::bindings::conversions::root_from_object', - 'dom::bindings::conversions::string_jsid_to_string', 'dom::bindings::conversions::jsid_to_string', 'dom::bindings::codegen::PrototypeList', 'dom::bindings::codegen::RegisterBindings', -- cgit v1.2.3 From 90fb2847207678e7feee06eaf17d75ac359d6a07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Mon, 18 Sep 2017 06:55:08 +0200 Subject: script: Properly implement LegacyPlatformGetOwnProperty in WebIDL. We were missing the "ignoreNamedProperties" bit, which my previous patch uncovers. --- .../script/dom/bindings/codegen/CodegenRust.py | 33 ++++++++++++++++------ 1 file changed, 24 insertions(+), 9 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index afb189ec795..174bda2b0ca 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -4817,15 +4817,14 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod): "bool", args) self.descriptor = descriptor + # https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty def getBody(self): indexedGetter = self.descriptor.operations['IndexedGetter'] - indexedSetter = self.descriptor.operations['IndexedSetter'] get = "" - if indexedGetter or indexedSetter: + if indexedGetter: get = "let index = get_array_index_from_id(cx, id);\n" - if indexedGetter: attrs = "JSPROP_ENUMERATE" if self.descriptor.operations['IndexedSetter'] is None: attrs += " | JSPROP_READONLY" @@ -4864,11 +4863,16 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod): 'successCode': fillDescriptor, 'pre': 'rooted!(in(cx) let mut result_root = UndefinedValue());' } + + # See the similar-looking in CGDOMJSProxyHandler_get for the spec quote. + condition = "RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id)" + if indexedGetter: + condition = "index.is_none() && (%s)" % condition # Once we start supporting OverrideBuiltins we need to make # ResolveOwnProperty or EnumerateOwnProperties filter out named # properties that shadow prototype properties. namedGet = """ -if RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id) { +if %s { let mut has_on_proto = false; if !has_property_on_prototype(cx, proxy, id, &mut has_on_proto) { return false; @@ -4877,7 +4881,7 @@ if RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id) { %s } } -""" % CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues), 8).define() +""" % (condition, CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues), 8).define()) else: namedGet = "" @@ -5093,9 +5097,12 @@ class CGDOMJSProxyHandler_hasOwn(CGAbstractExternMethod): indexed = "" namedGetter = self.descriptor.operations['NamedGetter'] + condition = "RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id)" + if indexedGetter: + condition = "index.is_none() && (%s)" % condition if namedGetter: named = """\ -if RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id) { +if %s { let mut has_on_proto = false; if !has_property_on_prototype(cx, proxy, id, &mut has_on_proto) { return false; @@ -5107,7 +5114,7 @@ if RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id) { } } -""" % CGIndenter(CGProxyNamedGetter(self.descriptor), 8).define() +""" % (condition, CGIndenter(CGProxyNamedGetter(self.descriptor), 8).define()) else: named = "" @@ -5136,6 +5143,7 @@ class CGDOMJSProxyHandler_get(CGAbstractExternMethod): CGAbstractExternMethod.__init__(self, descriptor, "get", "bool", args) self.descriptor = descriptor + # https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty def getBody(self): getFromExpando = """\ rooted!(in(cx) let mut expando = ptr::null_mut()); @@ -5175,9 +5183,16 @@ if !expando.is_null() { namedGetter = self.descriptor.operations['NamedGetter'] if namedGetter: - getNamed = ("if RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id) {\n" + + condition = "RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id)" + # From step 1: + # If O supports indexed properties and P is an array index, then: + # + # 3. Set ignoreNamedProps to true. + if indexedGetter: + condition = "index.is_none() && (%s)" % condition + getNamed = ("if %s {\n" + CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() + - "}\n") + "}\n") % condition else: getNamed = "" -- cgit v1.2.3 From 658dc8a5013973ceff3c91291d5536043b2e8e58 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Thu, 21 Sep 2017 15:35:04 +0200 Subject: Rename a couple of Promise methods --- components/script/dom/bindings/codegen/CodegenRust.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 174bda2b0ca..9a98848108b 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -788,7 +788,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, if !JS_WrapValue(cx, valueToResolve.handle_mut()) { $*{exceptionCode} } - match Promise::Resolve(&promiseGlobal, cx, valueToResolve.handle()) { + match Promise::new_resolved(&promiseGlobal, cx, valueToResolve.handle()) { Ok(value) => value, Err(error) => { throw_dom_exception(cx, &promiseGlobal, error); -- cgit v1.2.3 From e481e8934a0c37a4b1eba19862ff732ec9bf19c9 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Fri, 26 May 2017 12:40:50 -0400 Subject: Don't generate union conversion functions for object variants. --- components/script/dom/bindings/codegen/CodegenRust.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 9a98848108b..208d4b1d923 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -4313,10 +4313,14 @@ class CGUnionConversionStruct(CGThing): returnType = "Result, ()>" % templateVars["typeName"] jsConversion = templateVars["jsConversion"] + # Any code to convert to Object is unused, since we're already converting + # from an Object value. + if t.name == 'Object': + return CGGeneric('') + return CGWrapper( CGIndenter(jsConversion, 4), - # TryConvertToObject is unused, but not generating it while generating others is tricky. - pre="#[allow(dead_code)] unsafe fn TryConvertTo%s(cx: *mut JSContext, value: HandleValue) -> %s {\n" + pre="unsafe fn TryConvertTo%s(cx: *mut JSContext, value: HandleValue) -> %s {\n" % (t.name, returnType), post="\n}") -- cgit v1.2.3 From da65698c5c5934220b82493b3f7bb2ab05a2e512 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Fri, 26 May 2017 12:29:31 -0400 Subject: Be more conservative about safety of dictionary and union values. Mark dictionaries containing GC values as must_root, and wrap them in RootedTraceableBox in automatically-generated APIs. To accommodate union variants that are now flagged as unsafe, add RootedTraceableBox to union variants that need to be rooted, rather than wrapping the entire union value. --- .../script/dom/bindings/codegen/CodegenRust.py | 43 ++++++++++++++++++---- 1 file changed, 35 insertions(+), 8 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 208d4b1d923..4d31da25efe 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -723,9 +723,6 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, if type.nullable(): declType = CGWrapper(declType, pre="Option<", post=" >") - if isMember != "Dictionary" and type_needs_tracing(type): - declType = CGTemplatedType("RootedTraceableBox", declType) - templateBody = ("match FromJSValConvertible::from_jsval(cx, ${val}, ()) {\n" " Ok(ConversionResult::Success(value)) => value,\n" " Ok(ConversionResult::Failure(error)) => {\n" @@ -1427,6 +1424,8 @@ def getRetvalDeclarationForType(returnType, descriptorProvider): nullable = returnType.nullable() dictName = returnType.inner.name if nullable else returnType.name result = CGGeneric(dictName) + if type_needs_tracing(returnType): + result = CGWrapper(result, pre="RootedTraceableBox<", post=">") if nullable: result = CGWrapper(result, pre="Option<", post=">") return result @@ -2262,6 +2261,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config): 'dom::bindings::str::ByteString', 'dom::bindings::str::DOMString', 'dom::bindings::str::USVString', + 'dom::bindings::trace::RootedTraceableBox', 'dom::types::*', 'js::error::throw_type_error', 'js::jsapi::HandleValue', @@ -4132,15 +4132,23 @@ class CGUnionStruct(CGThing): self.type = type self.descriptorProvider = descriptorProvider + def membersNeedTracing(self): + for t in self.type.flatMemberTypes: + if type_needs_tracing(t): + return True + return False + def define(self): - templateVars = map(lambda t: getUnionTypeTemplateVars(t, self.descriptorProvider), + templateVars = map(lambda t: (getUnionTypeTemplateVars(t, self.descriptorProvider), + type_needs_tracing(t)), self.type.flatMemberTypes) enumValues = [ - " %s(%s)," % (v["name"], v["typeName"]) for v in templateVars + " %s(%s)," % (v["name"], "RootedTraceableBox<%s>" % v["typeName"] if trace else v["typeName"]) + for (v, trace) in templateVars ] enumConversions = [ " %s::%s(ref inner) => inner.to_jsval(cx, rval)," - % (self.type, v["name"]) for v in templateVars + % (self.type, v["name"]) for (v, _) in templateVars ] return ("""\ #[derive(JSTraceable)] @@ -4167,6 +4175,12 @@ class CGUnionConversionStruct(CGThing): self.type = type self.descriptorProvider = descriptorProvider + def membersNeedTracing(self): + for t in self.type.flatMemberTypes: + if type_needs_tracing(t): + return True + return False + def from_jsval(self): memberTypes = self.type.flatMemberTypes names = [] @@ -4310,7 +4324,10 @@ class CGUnionConversionStruct(CGThing): def try_method(self, t): templateVars = getUnionTypeTemplateVars(t, self.descriptorProvider) - returnType = "Result, ()>" % templateVars["typeName"] + actualType = templateVars["typeName"] + if type_needs_tracing(t): + actualType = "RootedTraceableBox<%s>" % actualType + returnType = "Result, ()>" % actualType jsConversion = templateVars["jsConversion"] # Any code to convert to Object is unused, since we're already converting @@ -6022,13 +6039,17 @@ class CGDictionary(CGThing): (self.makeMemberName(m[0].identifier.name), self.getMemberType(m)) for m in self.memberInfo] + mustRoot = "#[must_root]\n" if self.membersNeedTracing() else "" + return (string.Template( "#[derive(JSTraceable)]\n" + "${mustRoot}" + "pub struct ${selfName} {\n" + "${inheritance}" + "\n".join(memberDecls) + "\n" + "}").substitute({"selfName": self.makeClassName(d), - "inheritance": inheritance})) + "inheritance": inheritance, + "mustRoot": mustRoot})) def impl(self): d = self.dictionary @@ -6120,6 +6141,12 @@ class CGDictionary(CGThing): "insertMembers": CGIndenter(memberInserts, indentLevel=8).define(), }) + def membersNeedTracing(self): + for member, _ in self.memberInfo: + if type_needs_tracing(member.type): + return True + return False + @staticmethod def makeDictionaryName(dictionary): return dictionary.identifier.name -- cgit v1.2.3 From b169689f32db6d497b04f3a5b173cba4acd33e93 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Fri, 26 May 2017 13:25:05 -0400 Subject: Store rootable dictionary members of dictionaries in RootedTraceableBox. --- .../script/dom/bindings/codegen/CodegenRust.py | 27 +++++++++++++++------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 4d31da25efe..5b2b987c233 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1096,9 +1096,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, declType = CGGeneric(typeName) empty = "%s::empty(cx)" % typeName - if isMember != "Dictionary" and type_needs_tracing(type): + if type_needs_tracing(type): declType = CGTemplatedType("RootedTraceableBox", declType) - empty = "RootedTraceableBox::new(%s)" % empty template = ("match FromJSValConvertible::from_jsval(cx, ${val}, ()) {\n" " Ok(ConversionResult::Success(dictionary)) => dictionary,\n" @@ -6094,16 +6093,24 @@ class CGDictionary(CGThing): memberInits = CGList([memberInit(m) for m in self.memberInfo]) memberInserts = CGList([memberInsert(m) for m in self.memberInfo]) + actualType = self.makeClassName(d) + preInitial = "" + postInitial = "" + if self.membersNeedTracing(): + actualType = "RootedTraceableBox<%s>" % actualType + preInitial = "RootedTraceableBox::new(" + postInitial = ")" + return string.Template( "impl ${selfName} {\n" - " pub unsafe fn empty(cx: *mut JSContext) -> ${selfName} {\n" + " pub unsafe fn empty(cx: *mut JSContext) -> ${actualType} {\n" " match ${selfName}::new(cx, HandleValue::null()) {\n" " Ok(ConversionResult::Success(v)) => v,\n" " _ => unreachable!(),\n" " }\n" " }\n" " pub unsafe fn new(cx: *mut JSContext, val: HandleValue) \n" - " -> Result, ()> {\n" + " -> Result, ()> {\n" " let object = if val.get().is_null_or_undefined() {\n" " ptr::null_mut()\n" " } else if val.get().is_object() {\n" @@ -6113,17 +6120,18 @@ class CGDictionary(CGThing): " return Err(());\n" " };\n" " rooted!(in(cx) let object = object);\n" - " Ok(ConversionResult::Success(${selfName} {\n" + " let dictionary = ${preInitial}${selfName} {\n" "${initParent}" "${initMembers}" - " }))\n" + " }${postInitial};\n" + " Ok(ConversionResult::Success(dictionary))\n" " }\n" "}\n" "\n" - "impl FromJSValConvertible for ${selfName} {\n" + "impl FromJSValConvertible for ${actualType} {\n" " type Config = ();\n" " unsafe fn from_jsval(cx: *mut JSContext, value: HandleValue, _option: ())\n" - " -> Result, ()> {\n" + " -> Result, ()> {\n" " ${selfName}::new(cx, value)\n" " }\n" "}\n" @@ -6136,9 +6144,12 @@ class CGDictionary(CGThing): " }\n" "}\n").substitute({ "selfName": self.makeClassName(d), + "actualType": actualType, "initParent": CGIndenter(CGGeneric(initParent), indentLevel=12).define(), "initMembers": CGIndenter(memberInits, indentLevel=12).define(), "insertMembers": CGIndenter(memberInserts, indentLevel=8).define(), + "preInitial": CGGeneric(preInitial).define(), + "postInitial": CGGeneric(postInitial).define(), }) def membersNeedTracing(self): -- cgit v1.2.3 From 16166d66731d7040a91ddbed6ffd05d4fc64c97b Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Fri, 26 May 2017 13:46:13 -0400 Subject: Derive the Default trait for dictionaries containing GC values. --- components/script/dom/bindings/codegen/CodegenRust.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 5b2b987c233..aa58afe1913 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -4028,12 +4028,18 @@ impl super::%s { } } +impl Default for super::%s { + fn default() -> super::%s { + pairs[0].1 + } +} + impl ToJSValConvertible for super::%s { unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) { pairs[*self as usize].0.to_jsval(cx, rval); } } - """ % (ident, pairs, ident, ident) + """ % (ident, pairs, ident, ident, ident, ident) self.cgRoot = CGList([ CGGeneric(decl), CGNamespace.build([ident + "Values"], @@ -6038,17 +6044,22 @@ class CGDictionary(CGThing): (self.makeMemberName(m[0].identifier.name), self.getMemberType(m)) for m in self.memberInfo] - mustRoot = "#[must_root]\n" if self.membersNeedTracing() else "" + derive = ["JSTraceable"] + mustRoot = "" + if self.membersNeedTracing(): + mustRoot = "#[must_root]\n" + derive += ["Default"] return (string.Template( - "#[derive(JSTraceable)]\n" + "#[derive(${derive})]\n" "${mustRoot}" + "pub struct ${selfName} {\n" + "${inheritance}" + "\n".join(memberDecls) + "\n" + "}").substitute({"selfName": self.makeClassName(d), "inheritance": inheritance, - "mustRoot": mustRoot})) + "mustRoot": mustRoot, + "derive": ', '.join(derive)})) def impl(self): d = self.dictionary -- cgit v1.2.3 From f5eb8445b05d892b432d769f5e036f786e223fd4 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Fri, 26 May 2017 14:27:05 -0400 Subject: Initialize rooted dictionaries to a stable value before setting fields. --- .../script/dom/bindings/codegen/CodegenRust.py | 52 +++++++++++++--------- 1 file changed, 30 insertions(+), 22 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index aa58afe1913..05db89f3766 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1045,12 +1045,12 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, if defaultValue is None: default = None elif isinstance(defaultValue, IDLNullValue): - default = "Heap::new(NullValue())" + default = "NullValue()" elif isinstance(defaultValue, IDLUndefinedValue): - default = "Heap::new(UndefinedValue())" + default = "UndefinedValue()" else: raise TypeError("Can't handle non-null, non-undefined default value here") - return handleOptional("Heap::new(${val}.get())", declType, default) + return handleOptional("${val}.get()", declType, default) declType = CGGeneric("HandleValue") @@ -1077,8 +1077,6 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, if isMember in ("Dictionary", "Union"): declType = CGGeneric("Heap<*mut JSObject>") - templateBody = "Heap::new(%s)" % templateBody - default = "Heap::new(%s)" % default else: # TODO: Need to root somehow # https://github.com/servo/servo/issues/6382 @@ -5708,6 +5706,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'dom::bindings::iterable::Iterable', 'dom::bindings::iterable::IteratorType', 'dom::bindings::js::JS', + 'dom::bindings::js::OptionalHeapSetter', 'dom::bindings::js::Root', 'dom::bindings::js::RootedReference', 'dom::bindings::namespace::NamespaceObjectClass', @@ -6064,7 +6063,7 @@ class CGDictionary(CGThing): def impl(self): d = self.dictionary if d.parent: - initParent = ("parent: {\n" + initParent = ("{\n" " match try!(%s::%s::new(cx, val)) {\n" " ConversionResult::Success(v) => v,\n" " ConversionResult::Failure(error) => {\n" @@ -6072,16 +6071,20 @@ class CGDictionary(CGThing): " return Err(());\n" " }\n" " }\n" - "},\n" % (self.makeModuleName(d.parent), - self.makeClassName(d.parent))) + "}" % (self.makeModuleName(d.parent), + self.makeClassName(d.parent))) else: initParent = "" - def memberInit(memberInfo): + def memberInit(memberInfo, isInitial): member, _ = memberInfo name = self.makeMemberName(member.identifier.name) conversion = self.getMemberConversion(memberInfo, member.type) - return CGGeneric("%s: %s,\n" % (name, conversion.define())) + if isInitial: + return CGGeneric("%s: %s,\n" % (name, conversion.define())) + if member.type.isAny() or member.type.isObject(): + return CGGeneric("dictionary.%s.set(%s);\n" % (name, conversion.define())) + return CGGeneric("dictionary.%s = %s;\n" % (name, conversion.define())) def varInsert(varName, dictionaryName): insertion = ("rooted!(in(cx) let mut %s_js = UndefinedValue());\n" @@ -6101,16 +6104,21 @@ class CGDictionary(CGThing): (name, name, varInsert(name, member.identifier.name).define())) return CGGeneric("%s\n" % insertion.define()) - memberInits = CGList([memberInit(m) for m in self.memberInfo]) memberInserts = CGList([memberInsert(m) for m in self.memberInfo]) - actualType = self.makeClassName(d) - preInitial = "" - postInitial = "" + selfName = self.makeClassName(d) if self.membersNeedTracing(): - actualType = "RootedTraceableBox<%s>" % actualType - preInitial = "RootedTraceableBox::new(" - postInitial = ")" + actualType = "RootedTraceableBox<%s>" % selfName + preInitial = "let mut dictionary = RootedTraceableBox::new(%s::default());\n" % selfName + initParent = initParent = ("dictionary.parent = %s;\n" % initParent) if initParent else "" + memberInits = CGList([memberInit(m, False) for m in self.memberInfo]) + postInitial = "" + else: + actualType = selfName + preInitial = "let dictionary = %s {\n" % selfName + postInitial = "};\n" + initParent = ("parent: %s,\n" % initParent) if initParent else "" + memberInits = CGList([memberInit(m, True) for m in self.memberInfo]) return string.Template( "impl ${selfName} {\n" @@ -6131,10 +6139,10 @@ class CGDictionary(CGThing): " return Err(());\n" " };\n" " rooted!(in(cx) let object = object);\n" - " let dictionary = ${preInitial}${selfName} {\n" + "${preInitial}" "${initParent}" "${initMembers}" - " }${postInitial};\n" + "${postInitial}" " Ok(ConversionResult::Success(dictionary))\n" " }\n" "}\n" @@ -6154,13 +6162,13 @@ class CGDictionary(CGThing): " rval.set(ObjectOrNullValue(obj.get()))\n" " }\n" "}\n").substitute({ - "selfName": self.makeClassName(d), + "selfName": selfName, "actualType": actualType, "initParent": CGIndenter(CGGeneric(initParent), indentLevel=12).define(), "initMembers": CGIndenter(memberInits, indentLevel=12).define(), "insertMembers": CGIndenter(memberInserts, indentLevel=8).define(), - "preInitial": CGGeneric(preInitial).define(), - "postInitial": CGGeneric(postInitial).define(), + "preInitial": CGIndenter(CGGeneric(preInitial), indentLevel=12).define(), + "postInitial": CGIndenter(CGGeneric(postInitial), indentLevel=12).define(), }) def membersNeedTracing(self): -- cgit v1.2.3 From 77b3e911c11b2472efa4d7aea944f6aee56171c4 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Fri, 26 May 2017 10:47:09 -0400 Subject: Remove almost all uses of Heap::new. --- components/script/dom/bindings/codegen/CodegenRust.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 05db89f3766..30d847da19f 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -6699,7 +6699,7 @@ class CallbackMember(CGNativeMember): replacements["argCount"] = self.argCountStr replacements["argvDecl"] = string.Template( "rooted_vec!(let mut argv);\n" - "argv.extend((0..${argCount}).map(|_| Heap::new(UndefinedValue())));\n" + "argv.extend((0..${argCount}).map(|_| Heap::default()));\n" ).substitute(replacements) else: # Avoid weird 0-sized arrays @@ -6774,7 +6774,11 @@ class CallbackMember(CGNativeMember): conversion = wrapForType( "argv_root.handle_mut()", result=argval, - successCode="argv[%s] = Heap::new(argv_root.get());" % jsvalIndex, + successCode=("{\n" + + "let arg = &mut argv[%s];\n" + + "*arg = Heap::default();\n" + + "arg.set(argv_root.get());\n" + + "}") % jsvalIndex, pre="rooted!(in(cx) let mut argv_root = UndefinedValue());") if arg.variadic: conversion = string.Template( @@ -6790,7 +6794,7 @@ class CallbackMember(CGNativeMember): " // This is our current trailing argument; reduce argc\n" " argc -= 1;\n" "} else {\n" - " argv[%d] = Heap::new(UndefinedValue());\n" + " argv[%d] = Heap::default();\n" "}" % (i + 1, i)) return conversion -- cgit v1.2.3 From 44822c364c2f1970705834fb0f95df1411089f9d Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Mon, 26 Jun 2017 07:46:19 -0400 Subject: Use more named string interpolation. --- .../script/dom/bindings/codegen/CodegenRust.py | 23 ++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 30d847da19f..68ab0a33c18 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -4011,33 +4011,36 @@ pub enum %s { pairs = ",\n ".join(['("%s", super::%s::%s)' % (val, ident, getEnumValueName(val)) for val in enum.values()]) - inner = """\ + inner = string.Template("""\ use dom::bindings::conversions::ToJSValConvertible; use js::jsapi::{JSContext, MutableHandleValue}; use js::jsval::JSVal; -pub const pairs: &'static [(&'static str, super::%s)] = &[ - %s, +pub const pairs: &'static [(&'static str, super::${ident})] = &[ + ${pairs}, ]; -impl super::%s { +impl super::${ident} { pub fn as_str(&self) -> &'static str { pairs[*self as usize].0 } } -impl Default for super::%s { - fn default() -> super::%s { - pairs[0].1 - } +impl Default for super::${ident} { + fn default() -> super::${ident} { + pairs[0].1 + } } -impl ToJSValConvertible for super::%s { +impl ToJSValConvertible for super::${ident} { unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) { pairs[*self as usize].0.to_jsval(cx, rval); } } - """ % (ident, pairs, ident, ident, ident, ident) + """).substitute({ + 'ident': ident, + 'pairs': pairs + }) self.cgRoot = CGList([ CGGeneric(decl), CGNamespace.build([ident + "Values"], -- cgit v1.2.3 From 0e3c54c1911ba2c3bf305ee04f04fcd9bf2fc2fe Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Mon, 25 Sep 2017 23:30:24 +0200 Subject: Rename dom::bindings::js to dom::bindings::root --- components/script/dom/bindings/codegen/CodegenRust.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 68ab0a33c18..03c2076951b 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2253,8 +2253,8 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config): 'dom::bindings::conversions::StringificationBehavior', 'dom::bindings::conversions::root_from_handlevalue', 'dom::bindings::error::throw_not_in_union', - 'dom::bindings::js::Root', 'dom::bindings::mozmap::MozMap', + 'dom::bindings::root::Root', 'dom::bindings::str::ByteString', 'dom::bindings::str::DOMString', 'dom::bindings::str::USVString', @@ -5708,14 +5708,14 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'dom::bindings::interface::push_new_element_queue', 'dom::bindings::iterable::Iterable', 'dom::bindings::iterable::IteratorType', - 'dom::bindings::js::JS', - 'dom::bindings::js::OptionalHeapSetter', - 'dom::bindings::js::Root', - 'dom::bindings::js::RootedReference', 'dom::bindings::namespace::NamespaceObjectClass', 'dom::bindings::namespace::create_namespace_object', 'dom::bindings::reflector::MutDomObject', 'dom::bindings::reflector::DomObject', + 'dom::bindings::root::JS', + 'dom::bindings::root::OptionalHeapSetter', + 'dom::bindings::root::Root', + 'dom::bindings::root::RootedReference', 'dom::bindings::utils::AsVoidPtr', 'dom::bindings::utils::DOMClass', 'dom::bindings::utils::DOMJSClass', @@ -7195,7 +7195,7 @@ class GlobalGenRoots(): imports = [CGGeneric("use dom::types::*;\n"), CGGeneric("use dom::bindings::conversions::{DerivedFrom, get_dom_class};\n"), CGGeneric("use dom::bindings::inheritance::Castable;\n"), - CGGeneric("use dom::bindings::js::{JS, LayoutJS, Root};\n"), + CGGeneric("use dom::bindings::root::{JS, LayoutJS, Root};\n"), CGGeneric("use dom::bindings::trace::JSTraceable;\n"), CGGeneric("use dom::bindings::reflector::DomObject;\n"), CGGeneric("use js::jsapi::JSTracer;\n\n"), -- cgit v1.2.3 From 7be32fb2371a14ba61b008a37e79761f66c073c7 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Mon, 25 Sep 2017 23:56:32 +0200 Subject: Rename JS to Dom --- components/script/dom/bindings/codegen/CodegenRust.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 03c2076951b..3f99ea37a41 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1272,7 +1272,7 @@ class CGArgumentConverter(CGThing): arg = "arg%d" % index if argument.type.isGeckoInterface(): init = "rooted_vec!(let mut %s)" % arg - innerConverter.append(CGGeneric("%s.push(JS::from_ref(&*slot));" % arg)) + innerConverter.append(CGGeneric("%s.push(Dom::from_ref(&*slot));" % arg)) else: init = "let mut %s = vec![]" % arg innerConverter.append(CGGeneric("%s.push(slot);" % arg)) @@ -5712,7 +5712,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'dom::bindings::namespace::create_namespace_object', 'dom::bindings::reflector::MutDomObject', 'dom::bindings::reflector::DomObject', - 'dom::bindings::root::JS', + 'dom::bindings::root::Dom', 'dom::bindings::root::OptionalHeapSetter', 'dom::bindings::root::Root', 'dom::bindings::root::RootedReference', @@ -6961,7 +6961,7 @@ class CallbackGetter(CallbackMember): needThisHandling=False) def getRvalDecl(self): - return "JS::Rooted rval(cx, JS::UndefinedValue());\n" + return "Dom::Rooted rval(cx, JS::UndefinedValue());\n" def getCall(self): replacements = { @@ -7195,7 +7195,7 @@ class GlobalGenRoots(): imports = [CGGeneric("use dom::types::*;\n"), CGGeneric("use dom::bindings::conversions::{DerivedFrom, get_dom_class};\n"), CGGeneric("use dom::bindings::inheritance::Castable;\n"), - CGGeneric("use dom::bindings::root::{JS, LayoutJS, Root};\n"), + CGGeneric("use dom::bindings::root::{Dom, LayoutJS, Root};\n"), CGGeneric("use dom::bindings::trace::JSTraceable;\n"), CGGeneric("use dom::bindings::reflector::DomObject;\n"), CGGeneric("use js::jsapi::JSTracer;\n\n"), -- cgit v1.2.3 From e2dac78d3600cb4b2b4474f1db4f0fcaadbe24ea Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Tue, 26 Sep 2017 01:30:06 +0200 Subject: Rename LayoutJS to LayoutDom --- components/script/dom/bindings/codegen/CodegenRust.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 3f99ea37a41..888a17a3a8c 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -7195,7 +7195,7 @@ class GlobalGenRoots(): imports = [CGGeneric("use dom::types::*;\n"), CGGeneric("use dom::bindings::conversions::{DerivedFrom, get_dom_class};\n"), CGGeneric("use dom::bindings::inheritance::Castable;\n"), - CGGeneric("use dom::bindings::root::{Dom, LayoutJS, Root};\n"), + CGGeneric("use dom::bindings::root::{Dom, LayoutDom, Root};\n"), CGGeneric("use dom::bindings::trace::JSTraceable;\n"), CGGeneric("use dom::bindings::reflector::DomObject;\n"), CGGeneric("use js::jsapi::JSTracer;\n\n"), -- cgit v1.2.3 From f87c2a8d7616112ca924e30292db2d244cf87eec Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Tue, 26 Sep 2017 01:53:40 +0200 Subject: Rename Root to DomRoot In a later PR, DomRoot will become a type alias of Root>, where Root will be able to handle all the things that need to be rooted that have a stable traceable address that doesn't move for the whole lifetime of the root. Stay tuned. --- .../script/dom/bindings/codegen/CodegenRust.py | 26 +++++++++++++--------- .../script/dom/bindings/codegen/Configuration.py | 2 +- 2 files changed, 16 insertions(+), 12 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 888a17a3a8c..8880707f7d5 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2254,7 +2254,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config): 'dom::bindings::conversions::root_from_handlevalue', 'dom::bindings::error::throw_not_in_union', 'dom::bindings::mozmap::MozMap', - 'dom::bindings::root::Root', + 'dom::bindings::root::DomRoot', 'dom::bindings::str::ByteString', 'dom::bindings::str::DOMString', 'dom::bindings::str::USVString', @@ -2558,7 +2558,7 @@ class CGWrapMethod(CGAbstractMethod): args = [Argument('*mut JSContext', 'cx'), Argument('&GlobalScope', 'scope'), Argument("Box<%s>" % descriptor.concreteType, 'object')] - retval = 'Root<%s>' % descriptor.concreteType + retval = 'DomRoot<%s>' % descriptor.concreteType CGAbstractMethod.__init__(self, descriptor, 'Wrap', retval, args, pub=True, unsafe=True) @@ -2580,7 +2580,7 @@ assert!(!proto.is_null()); %(copyUnforgeable)s (*raw).init_reflector(obj.get()); -Root::from_ref(&*raw)""" % {'copyUnforgeable': unforgeable, 'createObject': create}) +DomRoot::from_ref(&*raw)""" % {'copyUnforgeable': unforgeable, 'createObject': create}) class CGWrapGlobalMethod(CGAbstractMethod): @@ -2592,7 +2592,7 @@ class CGWrapGlobalMethod(CGAbstractMethod): assert descriptor.isGlobal() args = [Argument('*mut JSContext', 'cx'), Argument("Box<%s>" % descriptor.concreteType, 'object')] - retval = 'Root<%s>' % descriptor.concreteType + retval = 'DomRoot<%s>' % descriptor.concreteType CGAbstractMethod.__init__(self, descriptor, 'Wrap', retval, args, pub=True, unsafe=True) self.properties = properties @@ -2638,7 +2638,7 @@ assert!(immutable); %(unforgeable)s -Root::from_ref(&*raw)\ +DomRoot::from_ref(&*raw)\ """ % values) @@ -3421,7 +3421,9 @@ class CGAbstractStaticBindingMethod(CGAbstractMethod): def definition_body(self): preamble = "let global = GlobalScope::from_object(JS_CALLEE(cx, vp).to_object());\n" if len(self.exposureSet) == 1: - preamble += "let global = Root::downcast::(global).unwrap();\n" % list(self.exposureSet)[0] + preamble += """ +let global = DomRoot::downcast::(global).unwrap(); +""" % list(self.exposureSet)[0] return CGList([CGGeneric(preamble), self.generate_code()]) def generate_code(self): @@ -5352,7 +5354,9 @@ class CGClassConstructHook(CGAbstractExternMethod): def definition_body(self): preamble = """let global = GlobalScope::from_object(JS_CALLEE(cx, vp).to_object());\n""" if len(self.exposureSet) == 1: - preamble += "let global = Root::downcast::(global).unwrap();\n" % list(self.exposureSet)[0] + preamble += """\ +let global = DomRoot::downcast::(global).unwrap(); +""" % list(self.exposureSet)[0] preamble += """let args = CallArgs::from_vp(vp, argc);\n""" preamble = CGGeneric(preamble) if self.constructor.isHTMLConstructor(): @@ -5408,7 +5412,7 @@ if !JS_WrapObject(cx, prototype.handle_mut()) { return false; } -let result: Result, Error> = html_constructor(&global, &args); +let result: Result, Error> = html_constructor(&global, &args); let result = match result { Ok(result) => result, Err(e) => { @@ -5713,8 +5717,8 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'dom::bindings::reflector::MutDomObject', 'dom::bindings::reflector::DomObject', 'dom::bindings::root::Dom', + 'dom::bindings::root::DomRoot', 'dom::bindings::root::OptionalHeapSetter', - 'dom::bindings::root::Root', 'dom::bindings::root::RootedReference', 'dom::bindings::utils::AsVoidPtr', 'dom::bindings::utils::DOMClass', @@ -6281,7 +6285,7 @@ class CGRegisterProxyHandlers(CGThing): class CGBindingRoot(CGThing): """ - Root codegen class for binding generation. Instantiate the class, and call + DomRoot codegen class for binding generation. Instantiate the class, and call declare or define to generate header or cpp code (respectively). """ def __init__(self, config, prefix, webIDLFile): @@ -7195,7 +7199,7 @@ class GlobalGenRoots(): imports = [CGGeneric("use dom::types::*;\n"), CGGeneric("use dom::bindings::conversions::{DerivedFrom, get_dom_class};\n"), CGGeneric("use dom::bindings::inheritance::Castable;\n"), - CGGeneric("use dom::bindings::root::{Dom, LayoutDom, Root};\n"), + CGGeneric("use dom::bindings::root::{Dom, DomRoot, LayoutDom};\n"), CGGeneric("use dom::bindings::trace::JSTraceable;\n"), CGGeneric("use dom::bindings::reflector::DomObject;\n"), CGGeneric("use js::jsapi::JSTracer;\n\n"), diff --git a/components/script/dom/bindings/codegen/Configuration.py b/components/script/dom/bindings/codegen/Configuration.py index df6c0a36c76..56141e52b09 100644 --- a/components/script/dom/bindings/codegen/Configuration.py +++ b/components/script/dom/bindings/codegen/Configuration.py @@ -212,7 +212,7 @@ class Descriptor(DescriptorProvider): self.argumentType = "???" self.nativeType = ty else: - self.returnType = "Root<%s>" % typeName + self.returnType = "DomRoot<%s>" % typeName self.argumentType = "&%s" % typeName self.nativeType = "*const %s" % typeName if self.interface.isIteratorInterface(): -- cgit v1.2.3 From 3d0b7fbc413f975d6302428947132366f0e339d5 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 4 Jun 2016 15:20:04 +0200 Subject: Implement EventListenerOptions for EventTarget For now, only "capture" is supported. --- components/script/dom/bindings/codegen/CodegenRust.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 8880707f7d5..a82ad040041 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -6142,8 +6142,7 @@ class CGDictionary(CGThing): " } else if val.get().is_object() {\n" " val.get().to_object()\n" " } else {\n" - " throw_type_error(cx, \"Value not an object.\");\n" - " return Err(());\n" + " return Ok(ConversionResult::Failure(\"Value is not an object.\".into()));\n" " };\n" " rooted!(in(cx) let object = object);\n" "${preInitial}" -- cgit v1.2.3 From e2fafd2dfc7a1b66fb224c83e15042d8f6d595c0 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 14 Oct 2017 12:54:57 +0200 Subject: Replace NonZero<*mut JSObject> with a wrapper to enable local trait impls. --- components/script/dom/bindings/codegen/CodegenRust.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index a82ad040041..084945fad6b 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1407,7 +1407,7 @@ def getRetvalDeclarationForType(returnType, descriptorProvider): if returnType.isAny(): return CGGeneric("JSVal") if returnType.isObject() or returnType.isSpiderMonkeyInterface(): - result = CGGeneric("NonZero<*mut JSObject>") + result = CGGeneric("NonNullJSObjectPtr") if returnType.nullable(): result = CGWrapper(result, pre="Option<", post=">") return result @@ -2253,6 +2253,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config): 'dom::bindings::conversions::StringificationBehavior', 'dom::bindings::conversions::root_from_handlevalue', 'dom::bindings::error::throw_not_in_union', + 'dom::bindings::nonnull::NonNullJSObjectPtr', 'dom::bindings::mozmap::MozMap', 'dom::bindings::root::DomRoot', 'dom::bindings::str::ByteString', @@ -5785,6 +5786,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'dom::bindings::proxyhandler::get_expando_object', 'dom::bindings::proxyhandler::get_property_descriptor', 'dom::bindings::mozmap::MozMap', + 'dom::bindings::nonnull::NonNullJSObjectPtr', 'dom::bindings::num::Finite', 'dom::bindings::str::ByteString', 'dom::bindings::str::DOMString', -- cgit v1.2.3 From 99b052d3a6d59ad17ed2bf3d3c54af2bb40d926a Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 14 Oct 2017 13:05:28 +0200 Subject: Move remaining uses of NonZero to our nonzero crate --- components/script/dom/bindings/codegen/CodegenRust.py | 1 - 1 file changed, 1 deletion(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 084945fad6b..5d4e66f71f4 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -5575,7 +5575,6 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries typedefs = [] return CGImports(cgthings, descriptors, callbacks, dictionaries, enums, typedefs, [ - 'core::nonzero::NonZero', 'js', 'js::JSCLASS_GLOBAL_SLOT_COUNT', 'js::JSCLASS_IS_DOMJSCLASS', -- cgit v1.2.3 From 3bb76a5be590a40451ead6c926d19ea2d705ad03 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 12 Oct 2017 20:27:10 +0200 Subject: =?UTF-8?q?Don=E2=80=99t=20rely=20on=20unstable=20'const=20fn's=20?= =?UTF-8?q?in=20rust-mozjs,=20so=20we=20can=20remove=20them.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../script/dom/bindings/codegen/CodegenRust.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 5d4e66f71f4..feb39a532f6 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -3661,18 +3661,16 @@ class CGMemberJITInfo(CGThing): protoID: PrototypeList::ID::${name} as u16, depth: ${depth}, _bitfield_1: - JSJitInfo::new_bitfield_1( - JSJitInfo_OpType::${opType} as u8, - JSJitInfo_AliasSet::${aliasSet} as u8, - JSValueType::${returnType} as u8, - ${isInfallible}, - ${isMovable}, - ${isEliminatable}, - ${isAlwaysInSlot}, - ${isLazilyCachedInSlot}, - ${isTypedMethod}, - ${slotIndex} as u16, - ) + ((JSJitInfo_OpType::${opType} as u8 as u32) << 0) | + ((JSJitInfo_AliasSet::${aliasSet} as u8 as u32) << 4) | + ((JSValueType::${returnType} as u8 as u32) << 8) | + ((${isInfallible} as u32) << 16) | + ((${isMovable} as u32) << 17) | + ((${isEliminatable} as u32) << 18) | + ((${isAlwaysInSlot} as u32) << 19) | + ((${isLazilyCachedInSlot} as u32) << 20) | + ((${isTypedMethod} as u32) << 21) | + ((${slotIndex} as u32) << 22) } """, opName=opName, -- cgit v1.2.3 From 49e4540ece8641afcb6534a9c3b74e88895f5447 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 14 Oct 2017 14:05:05 +0200 Subject: Update rust-mozjs --- .../script/dom/bindings/codegen/CodegenRust.py | 23 +++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index feb39a532f6..d0b5e678db8 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -3660,17 +3660,18 @@ class CGMemberJITInfo(CGThing): call: ${opName} as *const os::raw::c_void, protoID: PrototypeList::ID::${name} as u16, depth: ${depth}, - _bitfield_1: - ((JSJitInfo_OpType::${opType} as u8 as u32) << 0) | - ((JSJitInfo_AliasSet::${aliasSet} as u8 as u32) << 4) | - ((JSValueType::${returnType} as u8 as u32) << 8) | - ((${isInfallible} as u32) << 16) | - ((${isMovable} as u32) << 17) | - ((${isEliminatable} as u32) << 18) | - ((${isAlwaysInSlot} as u32) << 19) | - ((${isLazilyCachedInSlot} as u32) << 20) | - ((${isTypedMethod} as u32) << 21) | - ((${slotIndex} as u32) << 22) + _bitfield_1: new_jsjitinfo_bitfield_1!( + JSJitInfo_OpType::${opType} as u8, + JSJitInfo_AliasSet::${aliasSet} as u8, + JSValueType::${returnType} as u8, + ${isInfallible}, + ${isMovable}, + ${isEliminatable}, + ${isAlwaysInSlot}, + ${isLazilyCachedInSlot}, + ${isTypedMethod}, + ${slotIndex}, + ), } """, opName=opName, -- cgit v1.2.3 From 4506f0d30cbbb02df32e9c16135ef288ad6b7e2e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 18 Oct 2017 10:42:01 +1100 Subject: Replace all uses of the `heapsize` crate with `malloc_size_of`. Servo currently uses `heapsize`, but Stylo/Gecko use `malloc_size_of`. `malloc_size_of` is better -- it handles various cases that `heapsize` does not -- so this patch changes Servo to use `malloc_size_of`. This patch makes the following changes to the `malloc_size_of` crate. - Adds `MallocSizeOf` trait implementations for numerous types, some built-in (e.g. `VecDeque`), some external and Servo-only (e.g. `string_cache`). - Makes `enclosing_size_of_op` optional, because vanilla jemalloc doesn't support that operation. - For `HashSet`/`HashMap`, falls back to a computed estimate when `enclosing_size_of_op` isn't available. - Adds an extern "C" `malloc_size_of` function that does the actual heap measurement; this is based on the same functions from the `heapsize` crate. This patch makes the following changes elsewhere. - Converts all the uses of `heapsize` to instead use `malloc_size_of`. - Disables the "heapsize"/"heap_size" feature for the external crates that provide it. - Removes the `HeapSizeOf` implementation from `hashglobe`. - Adds `ignore` annotations to a few `Rc`/`Arc`, because `malloc_size_of` doesn't derive those types, unlike `heapsize`. --- components/script/dom/bindings/codegen/CodegenRust.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index d0b5e678db8..3251290f398 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2029,7 +2029,7 @@ def DOMClass(descriptor): # padding. protoList.extend(['PrototypeList::ID::Last'] * (descriptor.config.maxProtoChainLength - len(protoList))) prototypeChainString = ', '.join(protoList) - heapSizeOf = 'heap_size_of_raw_self_and_children::<%s>' % descriptor.concreteType + mallocSizeOf = 'malloc_size_of_including_raw_self::<%s>' % descriptor.concreteType if descriptor.isGlobal(): globals_ = camel_to_upper_snake(descriptor.name) else: @@ -2038,9 +2038,9 @@ def DOMClass(descriptor): DOMClass { interface_chain: [ %s ], type_id: %s, - heap_size_of: %s as unsafe fn(_) -> _, + malloc_size_of: %s as unsafe fn(&mut _, _) -> _, global: InterfaceObjectMap::%s, -}""" % (prototypeChainString, DOMClassTypeId(descriptor), heapSizeOf, globals_) +}""" % (prototypeChainString, DOMClassTypeId(descriptor), mallocSizeOf, globals_) class CGDOMJSClass(CGThing): @@ -4005,7 +4005,7 @@ class CGEnum(CGThing): ident = enum.identifier.name decl = """\ #[repr(usize)] -#[derive(JSTraceable, PartialEq, Copy, Clone, HeapSizeOf, Debug)] +#[derive(Copy, Clone, Debug, JSTraceable, MallocSizeOf, PartialEq)] pub enum %s { %s } @@ -5794,7 +5794,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'dom::bindings::weakref::WeakReferenceable', 'dom::windowproxy::WindowProxy', 'dom::globalscope::GlobalScope', - 'mem::heap_size_of_raw_self_and_children', + 'mem::malloc_size_of_including_raw_self', 'libc', 'servo_config::prefs::PREFS', 'std::borrow::ToOwned', -- cgit v1.2.3 From e8e2d0a4b24475b018dbc7e59ea46fdceaf20815 Mon Sep 17 00:00:00 2001 From: Bastien Orivel Date: Mon, 9 Oct 2017 17:03:40 +0200 Subject: Update bitflags to 1.0 in every servo crate It still needs dependencies update to remove all the other bitflags versions. --- components/script/dom/bindings/codegen/CodegenRust.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 3251290f398..859e98931a5 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2039,7 +2039,7 @@ DOMClass { interface_chain: [ %s ], type_id: %s, malloc_size_of: %s as unsafe fn(&mut _, _) -> _, - global: InterfaceObjectMap::%s, + global: InterfaceObjectMap::Globals::%s, }""" % (prototypeChainString, DOMClassTypeId(descriptor), mallocSizeOf, globals_) @@ -2445,7 +2445,7 @@ class CGConstructorEnabled(CGAbstractMethod): iface = self.descriptor.interface bits = " | ".join(sorted( - "InterfaceObjectMap::" + camel_to_upper_snake(i) for i in iface.exposureSet + "InterfaceObjectMap::Globals::" + camel_to_upper_snake(i) for i in iface.exposureSet )) conditions.append("is_exposed_in(aObj, %s)" % bits) @@ -7092,9 +7092,9 @@ class GlobalGenRoots(): for (idx, d) in enumerate(global_descriptors) ) global_flags = CGWrapper(CGIndenter(CGList([ - CGGeneric("const %s = %#x," % args) + CGGeneric("const %s = %#x;" % args) for args in flags - ], "\n")), pre="pub flags Globals: u8 {\n", post="\n}") + ], "\n")), pre="pub struct Globals: u8 {\n", post="\n}") globals_ = CGWrapper(CGIndenter(global_flags), pre="bitflags! {\n", post="\n}") phf = CGGeneric("include!(concat!(env!(\"OUT_DIR\"), \"/InterfaceObjectMapPhf.rs\"));") -- cgit v1.2.3 From 11c64178d86979e8d50f11cff66c2b0e8fe666c1 Mon Sep 17 00:00:00 2001 From: Gecko Backout Date: Thu, 19 Oct 2017 21:26:51 +0000 Subject: Backed out changeset e64e659c077d: servo PR #18809 and revendor for reftest failures, e.g. in layout/reftests/bugs/392435-1.html. r=backout on a CLOSED TREE Backs out https://github.com/servo/servo/pull/18809 --- components/script/dom/bindings/codegen/CodegenRust.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 859e98931a5..3251290f398 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2039,7 +2039,7 @@ DOMClass { interface_chain: [ %s ], type_id: %s, malloc_size_of: %s as unsafe fn(&mut _, _) -> _, - global: InterfaceObjectMap::Globals::%s, + global: InterfaceObjectMap::%s, }""" % (prototypeChainString, DOMClassTypeId(descriptor), mallocSizeOf, globals_) @@ -2445,7 +2445,7 @@ class CGConstructorEnabled(CGAbstractMethod): iface = self.descriptor.interface bits = " | ".join(sorted( - "InterfaceObjectMap::Globals::" + camel_to_upper_snake(i) for i in iface.exposureSet + "InterfaceObjectMap::" + camel_to_upper_snake(i) for i in iface.exposureSet )) conditions.append("is_exposed_in(aObj, %s)" % bits) @@ -7092,9 +7092,9 @@ class GlobalGenRoots(): for (idx, d) in enumerate(global_descriptors) ) global_flags = CGWrapper(CGIndenter(CGList([ - CGGeneric("const %s = %#x;" % args) + CGGeneric("const %s = %#x," % args) for args in flags - ], "\n")), pre="pub struct Globals: u8 {\n", post="\n}") + ], "\n")), pre="pub flags Globals: u8 {\n", post="\n}") globals_ = CGWrapper(CGIndenter(global_flags), pre="bitflags! {\n", post="\n}") phf = CGGeneric("include!(concat!(env!(\"OUT_DIR\"), \"/InterfaceObjectMapPhf.rs\"));") -- cgit v1.2.3 From 3ed5899a64e2e386b3ed94954c5d41048c02335b Mon Sep 17 00:00:00 2001 From: Imanol Fernandez Date: Tue, 24 Oct 2017 18:44:18 +0200 Subject: Fix Const IDL value compilation errors in codegen --- components/script/dom/bindings/codegen/CodegenRust.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 3251290f398..b7438e6be0a 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1198,12 +1198,12 @@ def convertConstIDLValueToJSVal(value): if tag == IDLType.Tags.uint32: return "ConstantVal::UintVal(%s)" % (value.value) if tag in [IDLType.Tags.int64, IDLType.Tags.uint64]: - return "ConstantVal::DoubleVal(%s)" % (value.value) + return "ConstantVal::DoubleVal(%s as f64)" % (value.value) if tag == IDLType.Tags.bool: return "ConstantVal::BoolVal(true)" if value.value else "ConstantVal::BoolVal(false)" if tag in [IDLType.Tags.unrestricted_float, IDLType.Tags.float, IDLType.Tags.unrestricted_double, IDLType.Tags.double]: - return "ConstantVal::DoubleVal(%s)" % (value.value) + return "ConstantVal::DoubleVal(%s as f64)" % (value.value) raise TypeError("Const value of unhandled type: " + value.type) @@ -4077,7 +4077,17 @@ class CGConstant(CGThing): def define(self): name = self.constant.identifier.name value = convertConstIDLValueToRust(self.constant.value) - return "pub const %s: %s = %s;\n" % (name, builtinNames[self.constant.value.type.tag()], value) + + tag = self.constant.value.type.tag() + const_type = builtinNames[self.constant.value.type.tag()] + # Finite or Finite cannot be used un a constant declaration. + # Remote the Finite type from restricted float and double tag declarations. + if tag == IDLType.Tags.float: + const_type = "f32" + elif tag == IDLType.Tags.double: + const_type = "f64" + + return "pub const %s: %s = %s;\n" % (name, const_type, value) def getUnionTypeTemplateVars(type, descriptorProvider): -- cgit v1.2.3 From 29b4eec14187c96a1518af6a954bd00194375382 Mon Sep 17 00:00:00 2001 From: Bastien Orivel Date: Mon, 30 Oct 2017 12:15:30 +0100 Subject: Bump bitflags to 1.0 in every servo crate --- components/script/dom/bindings/codegen/CodegenRust.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index b7438e6be0a..c32c8f2c090 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2039,7 +2039,7 @@ DOMClass { interface_chain: [ %s ], type_id: %s, malloc_size_of: %s as unsafe fn(&mut _, _) -> _, - global: InterfaceObjectMap::%s, + global: InterfaceObjectMap::Globals::%s, }""" % (prototypeChainString, DOMClassTypeId(descriptor), mallocSizeOf, globals_) @@ -2445,7 +2445,7 @@ class CGConstructorEnabled(CGAbstractMethod): iface = self.descriptor.interface bits = " | ".join(sorted( - "InterfaceObjectMap::" + camel_to_upper_snake(i) for i in iface.exposureSet + "InterfaceObjectMap::Globals::" + camel_to_upper_snake(i) for i in iface.exposureSet )) conditions.append("is_exposed_in(aObj, %s)" % bits) @@ -7102,9 +7102,9 @@ class GlobalGenRoots(): for (idx, d) in enumerate(global_descriptors) ) global_flags = CGWrapper(CGIndenter(CGList([ - CGGeneric("const %s = %#x," % args) + CGGeneric("const %s = %#x;" % args) for args in flags - ], "\n")), pre="pub flags Globals: u8 {\n", post="\n}") + ], "\n")), pre="pub struct Globals: u8 {\n", post="\n}") globals_ = CGWrapper(CGIndenter(global_flags), pre="bitflags! {\n", post="\n}") phf = CGGeneric("include!(concat!(env!(\"OUT_DIR\"), \"/InterfaceObjectMapPhf.rs\"));") -- cgit v1.2.3 From ce8486ab9b3af974a7c738a08a9da460360ce117 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Mon, 6 Nov 2017 22:52:40 -0800 Subject: Import sequence inner types if it appears in dictionary members --- components/script/dom/bindings/codegen/Configuration.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/Configuration.py b/components/script/dom/bindings/codegen/Configuration.py index 56141e52b09..0ab27151bb6 100644 --- a/components/script/dom/bindings/codegen/Configuration.py +++ b/components/script/dom/bindings/codegen/Configuration.py @@ -4,7 +4,7 @@ import os -from WebIDL import IDLExternalInterface, IDLWrapperType, WebIDLError +from WebIDL import IDLExternalInterface, IDLSequenceType, IDLWrapperType, WebIDLError class Configuration: @@ -457,7 +457,7 @@ def getTypesFromDictionary(dictionary): types = [] curDict = dictionary while curDict: - types.extend([m.type for m in curDict.members]) + types.extend([getUnwrappedType(m.type) for m in curDict.members]) curDict = curDict.parent return types @@ -473,6 +473,12 @@ def getTypesFromCallback(callback): return types +def getUnwrappedType(type): + while isinstance(type, IDLSequenceType): + type = type.inner + return type + + def iteratorNativeType(descriptor, infer=False): assert descriptor.interface.isIterable() iterableDecl = descriptor.interface.maplikeOrSetlikeOrIterable -- cgit v1.2.3 From 2974dae4315420d1e7252029c2c30198ea62ac61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Fri, 10 Nov 2017 17:57:02 +0100 Subject: Fix binding generation for overloaded functions with optionals and default values --- components/script/dom/bindings/codegen/CodegenRust.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index c32c8f2c090..b408d0a670f 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -483,7 +483,8 @@ class CGMethodCall(CGThing): else: # Just throw; we have no idea what we're supposed to # do with this. - caseBody.append(CGGeneric("return Throw(cx, NS_ERROR_XPC_BAD_CONVERT_JS);")) + caseBody.append(CGGeneric("throw_internal_error(cx, \"Could not convert JavaScript argument\");\n" + "return false;")) argCountCases.append(CGCase(str(argCount), CGList(caseBody, "\n"))) @@ -5591,6 +5592,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::JSCLASS_RESERVED_SLOTS_MASK', 'js::JS_CALLEE', 'js::error::throw_type_error', + 'js::error::throw_internal_error', 'js::jsapi::AutoIdVector', 'js::jsapi::Call', 'js::jsapi::CallArgs', -- cgit v1.2.3 From d71ff786c65bc9183824620a11607a4cbd06a7b3 Mon Sep 17 00:00:00 2001 From: olmanz Date: Thu, 16 Nov 2017 13:06:50 +0100 Subject: Moved function html_constructor() from interface.rs to new file htmlconstructor.rs --- components/script/dom/bindings/codegen/CodegenRust.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index b408d0a670f..8d91f84a6e4 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -5717,7 +5717,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'dom::bindings::interface::define_guarded_constants', 'dom::bindings::interface::define_guarded_methods', 'dom::bindings::interface::define_guarded_properties', - 'dom::bindings::interface::html_constructor', + 'dom::bindings::htmlconstructor::html_constructor', 'dom::bindings::interface::is_exposed_in', 'dom::bindings::interface::pop_current_element_queue', 'dom::bindings::interface::push_new_element_queue', -- cgit v1.2.3 From 83adc7b769902a56935f84450ab891c03f0efc3e Mon Sep 17 00:00:00 2001 From: olmanz Date: Thu, 16 Nov 2017 19:14:12 +0100 Subject: Moved pop_current_element_queue() and push_new_element_queue() to htmlconstructor.rs --- components/script/dom/bindings/codegen/CodegenRust.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 8d91f84a6e4..a0b73b40985 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -5719,8 +5719,8 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'dom::bindings::interface::define_guarded_properties', 'dom::bindings::htmlconstructor::html_constructor', 'dom::bindings::interface::is_exposed_in', - 'dom::bindings::interface::pop_current_element_queue', - 'dom::bindings::interface::push_new_element_queue', + 'dom::bindings::htmlconstructor::pop_current_element_queue', + 'dom::bindings::htmlconstructor::push_new_element_queue', 'dom::bindings::iterable::Iterable', 'dom::bindings::iterable::IteratorType', 'dom::bindings::namespace::NamespaceObjectClass', -- cgit v1.2.3 From a01d1eabefeb9ec6a65c518234647ddbf15e7f92 Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Sun, 24 Dec 2017 20:44:41 +0100 Subject: Root sequence<{any,object}> IDL arguments using CustomAutoRooter Also pulls in mozjs 0.1.10 to support the change. --- .../script/dom/bindings/codegen/CodegenRust.py | 43 +++++++++++++++++++--- 1 file changed, 38 insertions(+), 5 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index a0b73b40985..6f0dd003e8d 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -562,6 +562,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, isDefinitelyObject=False, isMember=False, isArgument=False, + isAutoRooted=False, invalidEnumValueFatal=True, defaultValue=None, treatNullAs="Default", @@ -702,7 +703,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, if type.isSequence() or type.isRecord(): innerInfo = getJSToNativeConversionInfo(innerContainerType(type), descriptorProvider, - isMember=isMember) + isMember=isMember, + isAutoRooted=isAutoRooted) declType = wrapInNativeContainerType(type, innerInfo.declType) config = getConversionConfigForType(type, isEnforceRange, isClamp, treatNullAs) @@ -1038,10 +1040,14 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, assert not isEnforceRange and not isClamp assert isMember != "Union" - if isMember == "Dictionary": + if isMember == "Dictionary" or isAutoRooted: # TODO: Need to properly root dictionaries # https://github.com/servo/servo/issues/6381 - declType = CGGeneric("Heap") + if isMember == "Dictionary": + declType = CGGeneric("Heap") + # AutoRooter can trace properly inner raw GC thing pointers + else: + declType = CGGeneric("JSVal") if defaultValue is None: default = None @@ -1238,6 +1244,7 @@ class CGArgumentConverter(CGThing): isEnforceRange=argument.enforceRange, isClamp=argument.clamp, isMember="Variadic" if argument.variadic else False, + isAutoRooted=type_needs_auto_root(argument.type), allowTreatNonObjectAsNull=argument.allowTreatNonCallableAsNull()) template = info.template default = info.default @@ -1260,8 +1267,15 @@ class CGArgumentConverter(CGThing): else: assert not default + arg = "arg%d" % index + self.converter = instantiateJSToNativeConversionTemplate( - template, replacementVariables, declType, "arg%d" % index) + template, replacementVariables, declType, arg) + + # The auto rooting is done only after the conversion is performed + if type_needs_auto_root(argument.type): + self.converter.append(CGGeneric("auto_root!(in(cx) let %s = %s);" % (arg, arg))) + else: assert argument.optional variadicConversion = { @@ -5698,6 +5712,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::panic::maybe_resume_unwind', 'js::panic::wrap_panic', 'js::rust::GCMethods', + 'js::rust::CustomAutoRooterGuard', 'js::rust::define_methods', 'js::rust::define_properties', 'js::rust::get_object_class', @@ -6421,9 +6436,24 @@ def type_needs_tracing(t): assert False, (t, type(t)) +def type_needs_auto_root(t): + """ + Certain IDL types, such as `sequence` or `sequence` need to be + traced and wrapped via (Custom)AutoRooter + """ + assert isinstance(t, IDLObject), (t, type(t)) + + if t.isType(): + if t.isSequence() and (t.inner.isAny() or t.inner.isObject()): + return True + + return False + + def argument_type(descriptorProvider, ty, optional=False, defaultValue=None, variadic=False): info = getJSToNativeConversionInfo( - ty, descriptorProvider, isArgument=True) + ty, descriptorProvider, isArgument=True, + isAutoRooted=type_needs_auto_root(ty)) declType = info.declType if variadic: @@ -6437,6 +6467,9 @@ def argument_type(descriptorProvider, ty, optional=False, defaultValue=None, var if ty.isDictionary() and not type_needs_tracing(ty): declType = CGWrapper(declType, pre="&") + if type_needs_auto_root(ty): + declType = CGTemplatedType("CustomAutoRooterGuard", declType) + return declType.define() -- cgit v1.2.3 From 4d459bce32a48e040399b3e05e66ba5ea26dd7f1 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 4 Jan 2018 18:13:44 +0100 Subject: Fix tyvar_behind_raw_pointer warnings https://github.com/rust-lang/rust/issues/46906 --- .../script/dom/bindings/codegen/CodegenRust.py | 42 +++++++++++----------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 6f0dd003e8d..4a377aa351f 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2539,7 +2539,7 @@ def CopyUnforgeablePropertiesToInstance(descriptor): # reflector, so we can make sure we don't get confused by named getters. if descriptor.proxy: copyCode += """\ -rooted!(in(cx) let mut expando = ptr::null_mut()); +rooted!(in(cx) let mut expando = ptr::null_mut::()); ensure_expando_object(cx, obj.handle(), expando.handle_mut()); """ obj = "expando" @@ -2554,7 +2554,7 @@ ensure_expando_object(cx, obj.handle(), expando.handle_mut()); else: copyFunc = "JS_InitializePropertiesFromCompatibleNativeObject" copyCode += """\ -rooted!(in(cx) let mut unforgeable_holder = ptr::null_mut()); +rooted!(in(cx) let mut unforgeable_holder = ptr::null_mut::()); unforgeable_holder.handle_mut().set( JS_GetReservedSlot(proto.get(), DOM_PROTO_UNFORGEABLE_HOLDER_SLOT).to_object()); assert!(%(copyFunc)s(cx, %(obj)s.handle(), unforgeable_holder.handle())); @@ -2586,7 +2586,7 @@ let scope = scope.reflector().get_jsobject(); assert!(!scope.get().is_null()); assert!(((*get_object_class(scope.get())).flags & JSCLASS_IS_GLOBAL) != 0); -rooted!(in(cx) let mut proto = ptr::null_mut()); +rooted!(in(cx) let mut proto = ptr::null_mut::()); let _ac = JSAutoCompartment::new(cx, scope.get()); GetProtoObject(cx, scope, proto.handle_mut()); assert!(!proto.is_null()); @@ -2631,7 +2631,7 @@ class CGWrapGlobalMethod(CGAbstractMethod): let raw = Box::into_raw(object); let _rt = RootedTraceable::new(&*raw); -rooted!(in(cx) let mut obj = ptr::null_mut()); +rooted!(in(cx) let mut obj = ptr::null_mut::()); create_global_object( cx, &Class.base, @@ -2643,7 +2643,7 @@ assert!(!obj.is_null()); (*raw).init_reflector(obj.get()); let _ac = JSAutoCompartment::new(cx, obj.get()); -rooted!(in(cx) let mut proto = ptr::null_mut()); +rooted!(in(cx) let mut proto = ptr::null_mut::()); GetProtoObject(cx, obj.handle(), proto.handle_mut()); assert!(JS_SplicePrototype(cx, obj.handle(), proto.handle())); let mut immutable = false; @@ -2771,7 +2771,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): return CGGeneric("""\ rooted!(in(cx) let proto = %(proto)s); assert!(!proto.is_null()); -rooted!(in(cx) let mut namespace = ptr::null_mut()); +rooted!(in(cx) let mut namespace = ptr::null_mut::()); create_namespace_object(cx, global, proto.handle(), &NAMESPACE_OBJECT_CLASS, %(methods)s, %(name)s, namespace.handle_mut()); assert!(!namespace.is_null()); @@ -2784,7 +2784,7 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); if self.descriptor.interface.isCallback(): assert not self.descriptor.interface.ctor() and self.descriptor.interface.hasConstants() return CGGeneric("""\ -rooted!(in(cx) let mut interface = ptr::null_mut()); +rooted!(in(cx) let mut interface = ptr::null_mut::()); create_callback_interface_object(cx, global, sConstants, %(name)s, interface.handle_mut()); assert!(!interface.is_null()); assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); @@ -2807,7 +2807,7 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); toBindingNamespace(parentName)) code = [CGGeneric("""\ -rooted!(in(cx) let mut prototype_proto = ptr::null_mut()); +rooted!(in(cx) let mut prototype_proto = ptr::null_mut::()); %s; assert!(!prototype_proto.is_null());""" % getPrototypeProto)] @@ -2835,7 +2835,7 @@ assert!(!prototype_proto.is_null());""" % getPrototypeProto)] proto_properties = properties code.append(CGGeneric(""" -rooted!(in(cx) let mut prototype = ptr::null_mut()); +rooted!(in(cx) let mut prototype = ptr::null_mut::()); create_interface_prototype_object(cx, prototype_proto.handle(), &PrototypeClass, @@ -2862,7 +2862,7 @@ assert!((*cache)[PrototypeList::ID::%(id)s as usize].is_null()); if parentName: parentName = toBindingNamespace(parentName) code.append(CGGeneric(""" -rooted!(in(cx) let mut interface_proto = ptr::null_mut()); +rooted!(in(cx) let mut interface_proto = ptr::null_mut::()); %s::GetConstructorObject(cx, global, interface_proto.handle_mut());""" % parentName)) else: code.append(CGGeneric(""" @@ -2870,7 +2870,7 @@ rooted!(in(cx) let interface_proto = JS_GetFunctionPrototype(cx, global));""")) code.append(CGGeneric("""\ assert!(!interface_proto.is_null()); -rooted!(in(cx) let mut interface = ptr::null_mut()); +rooted!(in(cx) let mut interface = ptr::null_mut::()); create_noncallback_interface_object(cx, global, interface_proto.handle(), @@ -2973,7 +2973,7 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); holderClass = "&Class.base as *const JSClass" holderProto = "prototype.handle()" code.append(CGGeneric(""" -rooted!(in(cx) let mut unforgeable_holder = ptr::null_mut()); +rooted!(in(cx) let mut unforgeable_holder = ptr::null_mut::()); unforgeable_holder.handle_mut().set( JS_NewObjectWithoutMetadata(cx, %(holderClass)s, %(holderProto)s)); assert!(!unforgeable_holder.is_null()); @@ -3151,7 +3151,7 @@ if !ConstructorEnabled(cx, global) { return; } -rooted!(in(cx) let mut proto = ptr::null_mut()); +rooted!(in(cx) let mut proto = ptr::null_mut::()); %s(cx, global, proto.handle_mut()); assert!(!proto.is_null());""" % (function,)) @@ -4941,7 +4941,7 @@ if %s { # FIXME(#11868) Should assign to desc.obj, desc.get() is a copy. return get + """\ -rooted!(in(cx) let mut expando = ptr::null_mut()); +rooted!(in(cx) let mut expando = ptr::null_mut::()); get_expando_object(proxy, expando.handle_mut()); //if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) { if !expando.is_null() { @@ -5071,7 +5071,7 @@ class CGDOMJSProxyHandler_ownPropertyKeys(CGAbstractExternMethod): body += dedent( """ - rooted!(in(cx) let mut expando = ptr::null_mut()); + rooted!(in(cx) let mut expando = ptr::null_mut::()); get_expando_object(proxy, expando.handle_mut()); if !expando.is_null() { GetPropertyKeys(cx, expando.handle(), JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props); @@ -5114,7 +5114,7 @@ class CGDOMJSProxyHandler_getOwnEnumerablePropertyKeys(CGAbstractExternMethod): body += dedent( """ - rooted!(in(cx) let mut expando = ptr::null_mut()); + rooted!(in(cx) let mut expando = ptr::null_mut::()); get_expando_object(proxy, expando.handle_mut()); if !expando.is_null() { GetPropertyKeys(cx, expando.handle(), JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props); @@ -5173,7 +5173,7 @@ if %s { named = "" return indexed + """\ -rooted!(in(cx) let mut expando = ptr::null_mut()); +rooted!(in(cx) let mut expando = ptr::null_mut::()); get_expando_object(proxy, expando.handle_mut()); if !expando.is_null() { let ok = JS_HasPropertyById(cx, expando.handle(), id, bp); @@ -5200,7 +5200,7 @@ class CGDOMJSProxyHandler_get(CGAbstractExternMethod): # https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty def getBody(self): getFromExpando = """\ -rooted!(in(cx) let mut expando = ptr::null_mut()); +rooted!(in(cx) let mut expando = ptr::null_mut::()); get_expando_object(proxy, expando.handle_mut()); if !expando.is_null() { let mut hasProp = false; @@ -5406,7 +5406,7 @@ if args.callee() == new_target.get() { } // Step 6 -rooted!(in(cx) let mut prototype = ptr::null_mut()); +rooted!(in(cx) let mut prototype = ptr::null_mut::()); { rooted!(in(cx) let mut proto_val = UndefinedValue()); let _ac = JSAutoCompartment::new(cx, new_target.get()); @@ -6594,7 +6594,7 @@ class CGCallback(CGClass): bodyWithThis = string.Template( setupCall + - "rooted!(in(s.get_context()) let mut thisObjJS = ptr::null_mut());\n" + "rooted!(in(s.get_context()) let mut thisObjJS = ptr::null_mut::());\n" "wrap_call_this_object(s.get_context(), thisObj, thisObjJS.handle_mut());\n" "if thisObjJS.is_null() {\n" " return Err(JSFailed);\n" @@ -6605,7 +6605,7 @@ class CGCallback(CGClass): }) bodyWithoutThis = string.Template( setupCall + - "rooted!(in(s.get_context()) let thisObjJS = ptr::null_mut());\n" + "rooted!(in(s.get_context()) let thisObjJS = ptr::null_mut::());\n" "return ${methodName}(${callArgs});").substitute({ "callArgs": ", ".join(argnamesWithoutThis), "methodName": 'self.' + method.name, -- cgit v1.2.3 From 52eda6082fd32d3e28f3600858afd8f5bbc918fe Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 22 Jan 2018 12:42:05 +0100 Subject: Replace NonNullJSObjectPtr with std::ptr::NonNull --- components/script/dom/bindings/codegen/CodegenRust.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 4a377aa351f..92f6b3a71b6 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1422,7 +1422,7 @@ def getRetvalDeclarationForType(returnType, descriptorProvider): if returnType.isAny(): return CGGeneric("JSVal") if returnType.isObject() or returnType.isSpiderMonkeyInterface(): - result = CGGeneric("NonNullJSObjectPtr") + result = CGGeneric("NonNull") if returnType.nullable(): result = CGWrapper(result, pre="Option<", post=">") return result @@ -2268,7 +2268,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config): 'dom::bindings::conversions::StringificationBehavior', 'dom::bindings::conversions::root_from_handlevalue', 'dom::bindings::error::throw_not_in_union', - 'dom::bindings::nonnull::NonNullJSObjectPtr', + 'std::ptr::NonNull', 'dom::bindings::mozmap::MozMap', 'dom::bindings::root::DomRoot', 'dom::bindings::str::ByteString', @@ -5811,7 +5811,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'dom::bindings::proxyhandler::get_expando_object', 'dom::bindings::proxyhandler::get_property_descriptor', 'dom::bindings::mozmap::MozMap', - 'dom::bindings::nonnull::NonNullJSObjectPtr', + 'std::ptr::NonNull', 'dom::bindings::num::Finite', 'dom::bindings::str::ByteString', 'dom::bindings::str::DOMString', -- cgit v1.2.3 From f903da0a7bba2806e3a200eee8414a629d27ffa8 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Thu, 25 Jan 2018 11:25:23 +0100 Subject: Make callbacks' new methods unsafe They take raw pointers to contexts and objects. --- components/script/dom/bindings/codegen/CodegenRust.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 92f6b3a71b6..cc9a37a5ecc 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -4549,7 +4549,7 @@ class ClassConstructor(ClassItem): "});\n" "// Note: callback cannot be moved after calling init.\n" "match Rc::get_mut(&mut ret) {\n" - " Some(ref mut callback) => unsafe { callback.parent.init(%s, %s) },\n" + " Some(ref mut callback) => callback.parent.init(%s, %s),\n" " None => unreachable!(),\n" "};\n" "ret") % (cgClass.name, '\n'.join(initializers), @@ -4564,7 +4564,7 @@ class ClassConstructor(ClassItem): body = ' {\n' + body + '}' return string.Template("""\ -pub fn ${decorators}new(${args}) -> Rc<${className}>${body} +pub unsafe fn ${decorators}new(${args}) -> Rc<${className}>${body} """).substitute({'decorators': self.getDecorators(True), 'className': cgClass.getNameString(), 'args': args, -- cgit v1.2.3 From 74dabbdc62b49862c115eccb38fb9e010041cf28 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Thu, 25 Jan 2018 11:37:24 +0100 Subject: Kill dead callback codegen code --- .../script/dom/bindings/codegen/CodegenRust.py | 65 ++-------------------- 1 file changed, 4 insertions(+), 61 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index cc9a37a5ecc..00ba2ce2148 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -6529,8 +6529,7 @@ class CGNativeMember(ClassMethod): class CGCallback(CGClass): - def __init__(self, idlObject, descriptorProvider, baseName, methods, - getters=[], setters=[]): + def __init__(self, idlObject, descriptorProvider, baseName, methods): self.baseName = baseName self._deps = idlObject.getDeps() name = idlObject.identifier.name @@ -6549,7 +6548,7 @@ class CGCallback(CGClass): CGClass.__init__(self, name, bases=[ClassBase(baseName)], constructors=self.getConstructors(), - methods=realMethods + getters + setters, + methods=realMethods, decorators="#[derive(JSTraceable, PartialEq)]\n#[allow_unrooted_interior]") def getConstructors(self): @@ -6672,16 +6671,13 @@ class CGCallbackInterface(CGCallback): def __init__(self, descriptor): iface = descriptor.interface attrs = [m for m in iface.members if m.isAttr() and not m.isStatic()] - getters = [CallbackGetter(a, descriptor) for a in attrs] - setters = [CallbackSetter(a, descriptor) for a in attrs - if not a.readonly] + assert not attrs methods = [m for m in iface.members if m.isMethod() and not m.isStatic() and not m.isIdentifierLess()] methods = [CallbackOperation(m, sig, descriptor) for m in methods for sig in m.signatures()] assert not iface.isJSImplemented() or not iface.ctor() - CGCallback.__init__(self, iface, descriptor, "CallbackInterface", - methods, getters=getters, setters=setters) + CGCallback.__init__(self, iface, descriptor, "CallbackInterface", methods) class FakeMember(): @@ -6998,59 +6994,6 @@ class CallbackOperation(CallbackOperationBase): descriptor, descriptor.interface.isSingleOperationInterface()) -class CallbackGetter(CallbackMember): - def __init__(self, attr, descriptor): - self.ensureASCIIName(attr) - self.attrName = attr.identifier.name - CallbackMember.__init__(self, - (attr.type, []), - callbackGetterName(attr), - descriptor, - needThisHandling=False) - - def getRvalDecl(self): - return "Dom::Rooted rval(cx, JS::UndefinedValue());\n" - - def getCall(self): - replacements = { - "attrName": self.attrName - } - return string.Template( - 'if (!JS_GetProperty(cx, mCallback, "${attrName}", &rval)) {\n' - ' return Err(JSFailed);\n' - '}\n').substitute(replacements) - - -class CallbackSetter(CallbackMember): - def __init__(self, attr, descriptor): - self.ensureASCIIName(attr) - self.attrName = attr.identifier.name - CallbackMember.__init__(self, - (BuiltinTypes[IDLBuiltinType.Types.void], - [FakeArgument(attr.type, attr)]), - callbackSetterName(attr), - descriptor, - needThisHandling=False) - - def getRvalDecl(self): - # We don't need an rval - return "" - - def getCall(self): - replacements = { - "attrName": self.attrName, - "argv": "argv.handleAt(0)", - } - return string.Template( - 'MOZ_ASSERT(argv.length() == 1);\n' - 'if (!JS_SetProperty(cx, mCallback, "${attrName}", ${argv})) {\n' - ' return Err(JSFailed);\n' - '}\n').substitute(replacements) - - def getArgcDecl(self): - return None - - class CGIterableMethodGenerator(CGGeneric): """ Creates methods for iterable interfaces. Unwrapping/wrapping -- cgit v1.2.3 From de426baeccfecb5a02e5db876d9a127ee9379c2e Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Thu, 25 Jan 2018 12:07:13 +0100 Subject: Make the private callback methods taking a raw this pointer unsafe --- .../script/dom/bindings/codegen/CodegenRust.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 00ba2ce2148..d2d090f8350 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -4417,7 +4417,7 @@ class ClassMethod(ClassItem): def __init__(self, name, returnType, args, inline=False, static=False, virtual=False, const=False, bodyInHeader=False, templateArgs=None, visibility='public', body=None, - breakAfterReturnDecl="\n", + breakAfterReturnDecl="\n", unsafe=False, breakAfterSelf="\n", override=False): """ override indicates whether to flag the method as MOZ_OVERRIDE @@ -4436,6 +4436,7 @@ class ClassMethod(ClassItem): self.breakAfterReturnDecl = breakAfterReturnDecl self.breakAfterSelf = breakAfterSelf self.override = override + self.unsafe = unsafe ClassItem.__init__(self, name, visibility) def getDecorators(self, declaring): @@ -4468,7 +4469,7 @@ class ClassMethod(ClassItem): return string.Template( "${decorators}%s" - "${visibility}fn ${name}${templateClause}(${args})${returnType}${const}${override}${body}%s" % + "${visibility}${unsafe}fn ${name}${templateClause}(${args})${returnType}${const}${override}${body}%s" % (self.breakAfterReturnDecl, self.breakAfterSelf) ).substitute({ 'templateClause': templateClause, @@ -4479,7 +4480,8 @@ class ClassMethod(ClassItem): 'override': ' MOZ_OVERRIDE' if self.override else '', 'args': args, 'body': body, - 'visibility': self.visibility + ' ' if self.visibility != 'priv' else '' + 'visibility': self.visibility + ' ' if self.visibility != 'priv' else '', + 'unsafe': "unsafe " if self.unsafe else "", }) def define(self, cgClass): @@ -6495,7 +6497,8 @@ def return_type(descriptorProvider, rettype, infallible): class CGNativeMember(ClassMethod): def __init__(self, descriptorProvider, member, name, signature, extendedAttrs, - breakAfter=True, passJSBitsAsNeeded=True, visibility="public"): + breakAfter=True, passJSBitsAsNeeded=True, visibility="public", + unsafe=False): """ If passJSBitsAsNeeded is false, we don't automatically pass in a JSContext* or a JSObject* based on the return and argument types. @@ -6514,6 +6517,7 @@ class CGNativeMember(ClassMethod): const=(not member.isStatic() and member.isAttr() and not signature[0].isVoid()), breakAfterSelf=breakAfterSelf, + unsafe=unsafe, visibility=visibility) def getReturnType(self, type): @@ -6598,14 +6602,14 @@ class CGCallback(CGClass): "if thisObjJS.is_null() {\n" " return Err(JSFailed);\n" "}\n" - "return ${methodName}(${callArgs});").substitute({ + "unsafe { ${methodName}(${callArgs}) }").substitute({ "callArgs": ", ".join(argnamesWithThis), "methodName": 'self.' + method.name, }) bodyWithoutThis = string.Template( setupCall + "rooted!(in(s.get_context()) let thisObjJS = ptr::null_mut::());\n" - "return ${methodName}(${callArgs});").substitute({ + "unsafe { ${methodName}(${callArgs}) }").substitute({ "callArgs": ", ".join(argnamesWithoutThis), "methodName": 'self.' + method.name, }) @@ -6728,6 +6732,7 @@ class CallbackMember(CGNativeMember): name, (self.retvalType, args), extendedAttrs={}, passJSBitsAsNeeded=False, + unsafe=needThisHandling, visibility=visibility) # We have to do all the generation of our body now, because # the caller relies on us throwing if we can't manage it. @@ -6761,10 +6766,7 @@ class CallbackMember(CGNativeMember): "${convertArgs}" "${doCall}" "${returnResult}").substitute(replacements) - return CGWrapper(CGIndenter(CGList([ - CGGeneric(pre), - CGGeneric(body), - ], "\n"), 4), pre="unsafe {\n", post="\n}").define() + return pre + "\n" + body def getResultConversion(self): replacements = { -- cgit v1.2.3 From 17ecbaf8ff9ee6987f17cf00a243c136b1b0610e Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Sat, 10 Mar 2018 14:35:09 +0100 Subject: Support objects in WebIDL unions Fixes #17011 --- .../script/dom/bindings/codegen/CodegenRust.py | 25 +++++++++++----------- 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index d2d090f8350..55e72086f12 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1075,20 +1075,24 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, if type.isObject(): assert not isEnforceRange and not isClamp - # TODO: Need to root somehow - # https://github.com/servo/servo/issues/6382 + templateBody = "${val}.get().to_object()" default = "ptr::null_mut()" - templateBody = wrapObjectTemplate("${val}.get().to_object()", - default, - isDefinitelyObject, type, failureCode) - if isMember in ("Dictionary", "Union"): + # TODO: Do we need to do the same for dictionaries? + if isMember == "Union": + templateBody = "RootedTraceableBox::from_box(Heap::boxed(%s))" % templateBody + default = "RootedTraceableBox::new(Heap::default())" + declType = CGGeneric("RootedTraceableBox>") + elif isMember == "Dictionary": declType = CGGeneric("Heap<*mut JSObject>") else: # TODO: Need to root somehow # https://github.com/servo/servo/issues/6382 declType = CGGeneric("*mut JSObject") + templateBody = wrapObjectTemplate(templateBody, default, + isDefinitelyObject, type, failureCode) + return handleOptional(templateBody, declType, handleDefaultNull(default)) @@ -4291,11 +4295,13 @@ class CGUnionConversionStruct(CGThing): else: mozMapObject = None - hasObjectTypes = interfaceObject or arrayObject or dateObject or object or mozMapObject + hasObjectTypes = object or interfaceObject or arrayObject or dateObject or mozMapObject if hasObjectTypes: # "object" is not distinguishable from other types assert not object or not (interfaceObject or arrayObject or dateObject or callbackObject or mozMapObject) templateBody = CGList([], "\n") + if object: + templateBody.append(object) if interfaceObject: templateBody.append(interfaceObject) if arrayObject: @@ -4363,11 +4369,6 @@ class CGUnionConversionStruct(CGThing): returnType = "Result, ()>" % actualType jsConversion = templateVars["jsConversion"] - # Any code to convert to Object is unused, since we're already converting - # from an Object value. - if t.name == 'Object': - return CGGeneric('') - return CGWrapper( CGIndenter(jsConversion, 4), pre="unsafe fn TryConvertTo%s(cx: *mut JSContext, value: HandleValue) -> %s {\n" -- cgit v1.2.3 From e025bbb07964eb64317d9a6d63d4a55ba79cd8ae Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Sun, 4 Mar 2018 20:32:08 +0100 Subject: WIP: Accept typed array arguments in codegen --- .../script/dom/bindings/codegen/CodegenRust.py | 58 +++++++++++++++++++++- 1 file changed, 56 insertions(+), 2 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 55e72086f12..3e39bc231d4 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -870,8 +870,50 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, return handleOptional(templateBody, declType, handleDefaultNull("None")) - if type.isSpiderMonkeyInterface(): - raise TypeError("Can't handle SpiderMonkey interface arguments yet") + if type.isTypedArray() or type.isArrayBuffer() or type.isArrayBufferView() or type.isSharedArrayBuffer(): + if failureCode is None: + substitutions = { + "sourceDescription": sourceDescription, + "exceptionCode": exceptionCode, + } + unwrapFailureCode = string.Template( + 'throw_type_error(cx, "${sourceDescription} is not a typed array.");\n' + '${exceptionCode}').substitute(substitutions) + else: + unwrapFailureCode = failureCode + + typeName = type.name + if isMember == "Union": + typeName = "Heap" + typeName + + templateBody = fill( + """ + match typedarray::${ty}::from($${val}.get().to_object()) { + Ok(val) => val, + Err(()) => { + $*{failureCode} + } + } + """, + ty=typeName, + failureCode=unwrapFailureCode + "\n", + ) + + if isMember == "Union": + templateBody = "RootedTraceableBox::new(%s)" % templateBody + + declType = CGGeneric("typedarray::%s" % type.name) + if type.nullable(): + templateBody = "Some(%s)" % templateBody + declType = CGWrapper(declType, pre="Option<", post=">") + + templateBody = wrapObjectTemplate(templateBody, "None", + isDefinitelyObject, type, failureCode) + + return handleOptional(templateBody, declType, handleDefaultNull("None")) + + elif type.isSpiderMonkeyInterface(): + raise TypeError("Can't handle SpiderMonkey interface arguments other than typed arrays yet") if type.isDOMString(): nullBehavior = getConversionConfigForType(type, isEnforceRange, isClamp, treatNullAs) @@ -2287,6 +2329,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config): 'js::jsapi::JSObject', 'js::jsapi::MutableHandleValue', 'js::jsval::JSVal', + 'js::typedarray' ] # Now find all the things we'll need as arguments and return values because @@ -4138,6 +4181,9 @@ def getUnionTypeTemplateVars(type, descriptorProvider): elif type.isObject(): name = type.name typeName = "Heap<*mut JSObject>" + elif type.isTypedArray() or type.isArrayBuffer() or type.isArrayBufferView() or type.isSharedArrayBuffer(): + name = type.name + typeName = "typedarray::Heap" + name else: raise TypeError("Can't handle %s in unions yet" % type) @@ -5688,6 +5734,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::jsapi::MutableHandleValue', 'js::jsapi::ObjectOpResult', 'js::jsapi::PropertyDescriptor', + 'js::jsapi::Rooted', 'js::jsapi::RootedId', 'js::jsapi::RootedObject', 'js::jsapi::RootedString', @@ -5719,6 +5766,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::rust::define_methods', 'js::rust::define_properties', 'js::rust::get_object_class', + 'js::typedarray', 'dom', 'dom::bindings', 'dom::bindings::codegen::InterfaceObjectMap', @@ -6419,6 +6467,9 @@ def type_needs_tracing(t): if t.isUnion(): return any(type_needs_tracing(member) for member in t.flatMemberTypes) + if t.isTypedArray() or t.isArrayBuffer() or t.isArrayBufferView() or t.isSharedArrayBuffer(): + return True + return False if t.isDictionary(): @@ -6449,6 +6500,9 @@ def type_needs_auto_root(t): if t.isType(): if t.isSequence() and (t.inner.isAny() or t.inner.isObject()): return True + # SpiderMonkey interfaces + if t.isTypedArray() or t.isArrayBuffer() or t.isArrayBufferView() or t.isSharedArrayBuffer(): + return True return False -- cgit v1.2.3 From 6beb32e28e8652027a28bc8400dbe2d6e78cb286 Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Tue, 13 Mar 2018 13:05:04 +0100 Subject: Support nullable typed arrays in codegen --- components/script/dom/bindings/codegen/CodegenRust.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 3e39bc231d4..6ab7dd8b1d3 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -882,7 +882,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, else: unwrapFailureCode = failureCode - typeName = type.name + typeName = type.unroll().name # unroll because it may be nullable + if isMember == "Union": typeName = "Heap" + typeName @@ -902,7 +903,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, if isMember == "Union": templateBody = "RootedTraceableBox::new(%s)" % templateBody - declType = CGGeneric("typedarray::%s" % type.name) + declType = CGGeneric("typedarray::%s" % typeName) if type.nullable(): templateBody = "Some(%s)" % templateBody declType = CGWrapper(declType, pre="Option<", post=">") -- cgit v1.2.3 From c29fcb80f3051ed9f315d736179d95282e57729c Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Tue, 13 Mar 2018 13:23:01 +0100 Subject: Use helper `is_typed_array` function --- components/script/dom/bindings/codegen/CodegenRust.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 6ab7dd8b1d3..1207b050797 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -870,7 +870,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, return handleOptional(templateBody, declType, handleDefaultNull("None")) - if type.isTypedArray() or type.isArrayBuffer() or type.isArrayBufferView() or type.isSharedArrayBuffer(): + if is_typed_array(type): if failureCode is None: substitutions = { "sourceDescription": sourceDescription, @@ -4182,7 +4182,7 @@ def getUnionTypeTemplateVars(type, descriptorProvider): elif type.isObject(): name = type.name typeName = "Heap<*mut JSObject>" - elif type.isTypedArray() or type.isArrayBuffer() or type.isArrayBufferView() or type.isSharedArrayBuffer(): + elif is_typed_array(type): name = type.name typeName = "typedarray::Heap" + name else: @@ -6468,7 +6468,7 @@ def type_needs_tracing(t): if t.isUnion(): return any(type_needs_tracing(member) for member in t.flatMemberTypes) - if t.isTypedArray() or t.isArrayBuffer() or t.isArrayBufferView() or t.isSharedArrayBuffer(): + if is_typed_array(t): return True return False @@ -6491,6 +6491,12 @@ def type_needs_tracing(t): assert False, (t, type(t)) +def is_typed_array(t): + assert isinstance(t, IDLObject), (t, type(t)) + + return t.isTypedArray() or t.isArrayBuffer() or t.isArrayBufferView() or t.isSharedArrayBuffer() + + def type_needs_auto_root(t): """ Certain IDL types, such as `sequence` or `sequence` need to be @@ -6501,8 +6507,8 @@ def type_needs_auto_root(t): if t.isType(): if t.isSequence() and (t.inner.isAny() or t.inner.isObject()): return True - # SpiderMonkey interfaces - if t.isTypedArray() or t.isArrayBuffer() or t.isArrayBufferView() or t.isSharedArrayBuffer(): + # SpiderMonkey interfaces, we currently don't support any other except typed arrays + if is_typed_array(t): return True return False -- cgit v1.2.3 From 760e0a5b5792fb3c8967aee53cc41e1e25adf07d Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Tue, 13 Mar 2018 14:57:09 +0100 Subject: Root JS object members in dictionaries --- components/script/dom/bindings/codegen/CodegenRust.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 1207b050797..916c8770d34 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1121,13 +1121,10 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, templateBody = "${val}.get().to_object()" default = "ptr::null_mut()" - # TODO: Do we need to do the same for dictionaries? - if isMember == "Union": + if isMember in ("Dictionary", "Union"): templateBody = "RootedTraceableBox::from_box(Heap::boxed(%s))" % templateBody default = "RootedTraceableBox::new(Heap::default())" declType = CGGeneric("RootedTraceableBox>") - elif isMember == "Dictionary": - declType = CGGeneric("Heap<*mut JSObject>") else: # TODO: Need to root somehow # https://github.com/servo/servo/issues/6382 @@ -6168,7 +6165,8 @@ class CGDictionary(CGThing): conversion = self.getMemberConversion(memberInfo, member.type) if isInitial: return CGGeneric("%s: %s,\n" % (name, conversion.define())) - if member.type.isAny() or member.type.isObject(): + # TODO: Root Heap using RootedTraceableBox + if member.type.isAny(): return CGGeneric("dictionary.%s.set(%s);\n" % (name, conversion.define())) return CGGeneric("dictionary.%s = %s;\n" % (name, conversion.define())) -- cgit v1.2.3 From 64dc0c4b9eeba6f5c56a917a0d32125df9248ed2 Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Fri, 16 Mar 2018 15:54:36 +0100 Subject: Root `any` members in dictionaries --- .../script/dom/bindings/codegen/CodegenRust.py | 23 +++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 916c8770d34..24054de8e95 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1084,13 +1084,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, assert isMember != "Union" if isMember == "Dictionary" or isAutoRooted: - # TODO: Need to properly root dictionaries - # https://github.com/servo/servo/issues/6381 - if isMember == "Dictionary": - declType = CGGeneric("Heap") - # AutoRooter can trace properly inner raw GC thing pointers - else: - declType = CGGeneric("JSVal") + templateBody = "${val}.get()" if defaultValue is None: default = None @@ -1100,7 +1094,17 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, default = "UndefinedValue()" else: raise TypeError("Can't handle non-null, non-undefined default value here") - return handleOptional("${val}.get()", declType, default) + + if isMember == "Dictionary": + templateBody = "RootedTraceableBox::from_box(Heap::boxed(%s))" % templateBody + if default is not None: + default = "RootedTraceableBox::from_box(Heap::boxed(%s))" % default + declType = CGGeneric("RootedTraceableBox>") + # AutoRooter can trace properly inner raw GC thing pointers + else: + declType = CGGeneric("JSVal") + + return handleOptional(templateBody, declType, default) declType = CGGeneric("HandleValue") @@ -6165,9 +6169,6 @@ class CGDictionary(CGThing): conversion = self.getMemberConversion(memberInfo, member.type) if isInitial: return CGGeneric("%s: %s,\n" % (name, conversion.define())) - # TODO: Root Heap using RootedTraceableBox - if member.type.isAny(): - return CGGeneric("dictionary.%s.set(%s);\n" % (name, conversion.define())) return CGGeneric("dictionary.%s = %s;\n" % (name, conversion.define())) def varInsert(varName, dictionaryName): -- cgit v1.2.3 From 20f21cb5f85c48e7106177db6aa41fa54365d6cc Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Thu, 22 Mar 2018 20:38:26 +0100 Subject: Adapt uniform[fv] and similar to accept typed array args --- components/script/dom/bindings/codegen/CodegenRust.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 24054de8e95..6e0632fe97d 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -418,11 +418,15 @@ class CGMethodCall(CGThing): template = info.template declType = info.declType + argName = "arg%d" % distinguishingIndex + testCode = instantiateJSToNativeConversionTemplate( template, {"val": distinguishingArg}, declType, - "arg%d" % distinguishingIndex) + argName) + if type_needs_auto_root(type): + testCode.append(CGGeneric("auto_root!(in(cx) let %s = %s);" % (argName, argName))) # Indent by 4, since we need to indent further than our "do" statement caseBody.append(CGIndenter(testCode, 4)) -- cgit v1.2.3 From 2437a8472e3c2f9201fa4fc3fca06537ebf52d62 Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Fri, 23 Mar 2018 18:06:55 +0100 Subject: Unify argument auto rooting in codegen --- components/script/dom/bindings/codegen/CodegenRust.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 6e0632fe97d..de991f35ed9 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -418,15 +418,12 @@ class CGMethodCall(CGThing): template = info.template declType = info.declType - argName = "arg%d" % distinguishingIndex - testCode = instantiateJSToNativeConversionTemplate( template, {"val": distinguishingArg}, declType, - argName) - if type_needs_auto_root(type): - testCode.append(CGGeneric("auto_root!(in(cx) let %s = %s);" % (argName, argName))) + "arg%d" % distinguishingIndex, + needsAutoRoot=type_needs_auto_root(type)) # Indent by 4, since we need to indent further than our "do" statement caseBody.append(CGIndenter(testCode, 4)) @@ -1215,7 +1212,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, def instantiateJSToNativeConversionTemplate(templateBody, replacements, - declType, declName): + declType, declName, + needsAutoRoot=False): """ Take the templateBody and declType as returned by getJSToNativeConversionInfo, a set of replacements as required by the @@ -1240,6 +1238,8 @@ def instantiateJSToNativeConversionTemplate(templateBody, replacements, else: result.append(conversion) + if needsAutoRoot: + result.append(CGGeneric("auto_root!(in(cx) let %s = %s);" % (declName, declName))) # Add an empty CGGeneric to get an extra newline after the argument # conversion. result.append(CGGeneric("")) @@ -1322,11 +1322,8 @@ class CGArgumentConverter(CGThing): arg = "arg%d" % index self.converter = instantiateJSToNativeConversionTemplate( - template, replacementVariables, declType, arg) - - # The auto rooting is done only after the conversion is performed - if type_needs_auto_root(argument.type): - self.converter.append(CGGeneric("auto_root!(in(cx) let %s = %s);" % (arg, arg))) + template, replacementVariables, declType, arg, + needsAutoRoot=type_needs_auto_root(argument.type)) else: assert argument.optional -- cgit v1.2.3 From 356c57e628255ed338b32246ce5e7de75da621f0 Mon Sep 17 00:00:00 2001 From: Marcin Mielniczuk Date: Wed, 28 Mar 2018 21:28:30 +0200 Subject: Adapt Servo for mozjs 0.6 and the changes introduced in servo/rust-mozjs#393 --- .../script/dom/bindings/codegen/CodegenRust.py | 159 ++++++++++++--------- 1 file changed, 88 insertions(+), 71 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index de991f35ed9..5b286394051 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2326,11 +2326,11 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config): 'dom::bindings::trace::RootedTraceableBox', 'dom::types::*', 'js::error::throw_type_error', - 'js::jsapi::HandleValue', + 'js::rust::HandleValue', 'js::jsapi::Heap', 'js::jsapi::JSContext', 'js::jsapi::JSObject', - 'js::jsapi::MutableHandleValue', + 'js::rust::MutableHandleValue', 'js::jsval::JSVal', 'js::typedarray' ] @@ -2590,7 +2590,7 @@ def CopyUnforgeablePropertiesToInstance(descriptor): if descriptor.proxy: copyCode += """\ rooted!(in(cx) let mut expando = ptr::null_mut::()); -ensure_expando_object(cx, obj.handle(), expando.handle_mut()); +ensure_expando_object(cx, obj.handle().into(), expando.handle_mut()); """ obj = "expando" else: @@ -2887,13 +2887,13 @@ assert!(!prototype_proto.is_null());""" % getPrototypeProto)] code.append(CGGeneric(""" rooted!(in(cx) let mut prototype = ptr::null_mut::()); create_interface_prototype_object(cx, - prototype_proto.handle(), + prototype_proto.handle().into(), &PrototypeClass, %(methods)s, %(attrs)s, %(consts)s, %(unscopables)s, - prototype.handle_mut()); + prototype.handle_mut().into()); assert!(!prototype.is_null()); assert!((*cache)[PrototypeList::ID::%(id)s as usize].is_null()); (*cache)[PrototypeList::ID::%(id)s as usize] = prototype.get(); @@ -2922,7 +2922,7 @@ assert!(!interface_proto.is_null()); rooted!(in(cx) let mut interface = ptr::null_mut::()); create_noncallback_interface_object(cx, - global, + global.into(), interface_proto.handle(), &INTERFACE_OBJECT_CLASS, %(static_methods)s, @@ -3044,7 +3044,7 @@ class CGGetPerInterfaceObject(CGAbstractMethod): def __init__(self, descriptor, name, idPrefix="", pub=False): args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'global'), - Argument('MutableHandleObject', 'rval')] + Argument('MutableHandleObject', 'mut rval')] CGAbstractMethod.__init__(self, descriptor, name, 'void', args, pub=pub, unsafe=True) self.id = idPrefix + "::" + MakeNativeName(self.descriptor.name) @@ -4080,7 +4080,8 @@ pub enum %s { inner = string.Template("""\ use dom::bindings::conversions::ToJSValConvertible; -use js::jsapi::{JSContext, MutableHandleValue}; +use js::jsapi::JSContext; +use js::rust::MutableHandleValue; use js::jsval::JSVal; pub const pairs: &'static [(&'static str, super::${ident})] = &[ @@ -4856,7 +4857,7 @@ class CGProxyNamedOperation(CGProxySpecialOperation): def define(self): # Our first argument is the id we're getting. argName = self.arguments[0].identifier.name - return ("let %s = jsid_to_string(cx, id).expect(\"Not a string-convertible JSID?\");\n" + return ("let %s = jsid_to_string(cx, Handle::from_raw(id)).expect(\"Not a string-convertible JSID?\");\n" "let this = UnwrapProxy(proxy);\n" "let this = &*this;\n" % argName + CGProxySpecialOperation.define(self)) @@ -4899,7 +4900,7 @@ class CGProxyNamedDeleter(CGProxyNamedOperation): class CGProxyUnwrap(CGAbstractMethod): def __init__(self, descriptor): - args = [Argument('HandleObject', 'obj')] + args = [Argument('RawHandleObject', 'obj')] CGAbstractMethod.__init__(self, descriptor, "UnwrapProxy", '*const ' + descriptor.concreteType, args, alwaysInline=True, unsafe=True) @@ -4916,9 +4917,9 @@ return box_;""" % self.descriptor.concreteType) class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod): def __init__(self, descriptor): - args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'), - Argument('HandleId', 'id'), - Argument('MutableHandle', 'desc')] + args = [Argument('*mut JSContext', 'cx'), Argument('RawHandleObject', 'proxy'), + Argument('RawHandleId', 'id'), + Argument('RawMutableHandle', 'desc')] CGAbstractExternMethod.__init__(self, descriptor, "getOwnPropertyDescriptor", "bool", args) self.descriptor = descriptor @@ -4929,14 +4930,14 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod): get = "" if indexedGetter: - get = "let index = get_array_index_from_id(cx, id);\n" + get = "let index = get_array_index_from_id(cx, Handle::from_raw(id));\n" attrs = "JSPROP_ENUMERATE" if self.descriptor.operations['IndexedSetter'] is None: attrs += " | JSPROP_READONLY" # FIXME(#11868) Should assign to desc.value, desc.get() is a copy. fillDescriptor = ("desc.get().value = result_root.get();\n" - "fill_property_descriptor(desc, proxy.get(), %s);\n" + "fill_property_descriptor(MutableHandle::from_raw(desc), proxy.get(), %s);\n" "return true;" % attrs) templateValues = { 'jsvalRef': 'result_root.handle_mut()', @@ -4962,7 +4963,7 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod): attrs = "0" # FIXME(#11868) Should assign to desc.value, desc.get() is a copy. fillDescriptor = ("desc.get().value = result_root.get();\n" - "fill_property_descriptor(desc, proxy.get(), %s);\n" + "fill_property_descriptor(MutableHandle::from_raw(desc), proxy.get(), %s);\n" "return true;" % attrs) templateValues = { 'jsvalRef': 'result_root.handle_mut()', @@ -4980,7 +4981,7 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod): namedGet = """ if %s { let mut has_on_proto = false; - if !has_property_on_prototype(cx, proxy, id, &mut has_on_proto) { + if !has_property_on_prototype(cx, proxy_lt, id_lt, &mut has_on_proto) { return false; } if !has_on_proto { @@ -4996,8 +4997,10 @@ if %s { rooted!(in(cx) let mut expando = ptr::null_mut::()); get_expando_object(proxy, expando.handle_mut()); //if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) { +let proxy_lt = Handle::from_raw(proxy); +let id_lt = Handle::from_raw(id); if !expando.is_null() { - if !JS_GetPropertyDescriptorById(cx, expando.handle(), id, desc) { + if !JS_GetPropertyDescriptorById(cx, expando.handle().into(), id, desc) { return false; } if !desc.obj.is_null() { @@ -5016,9 +5019,9 @@ return true;""" class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod): def __init__(self, descriptor): - args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'), - Argument('HandleId', 'id'), - Argument('Handle', 'desc'), + args = [Argument('*mut JSContext', 'cx'), Argument('RawHandleObject', 'proxy'), + Argument('RawHandleId', 'id'), + Argument('RawHandle', 'desc'), Argument('*mut ObjectOpResult', 'opresult')] CGAbstractExternMethod.__init__(self, descriptor, "defineProperty", "bool", args) self.descriptor = descriptor @@ -5028,7 +5031,7 @@ class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod): indexedSetter = self.descriptor.operations['IndexedSetter'] if indexedSetter: - set += ("let index = get_array_index_from_id(cx, id);\n" + + set += ("let index = get_array_index_from_id(cx, Handle::from_raw(id));\n" + "if let Some(index) = index {\n" + " let this = UnwrapProxy(proxy);\n" + " let this = &*this;\n" + @@ -5036,7 +5039,7 @@ class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod): " return (*opresult).succeed();\n" + "}\n") elif self.descriptor.operations['IndexedGetter']: - set += ("if get_array_index_from_id(cx, id).is_some() {\n" + + set += ("if get_array_index_from_id(cx, Handle::from_raw(id)).is_some() {\n" + " return (*opresult).failNoIndexedSetter();\n" + "}\n") @@ -5065,8 +5068,8 @@ class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod): class CGDOMJSProxyHandler_delete(CGAbstractExternMethod): def __init__(self, descriptor): - args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'), - Argument('HandleId', 'id'), + args = [Argument('*mut JSContext', 'cx'), Argument('RawHandleObject', 'proxy'), + Argument('RawHandleId', 'id'), Argument('*mut ObjectOpResult', 'res')] CGAbstractExternMethod.__init__(self, descriptor, "delete", "bool", args) self.descriptor = descriptor @@ -5088,7 +5091,7 @@ class CGDOMJSProxyHandler_delete(CGAbstractExternMethod): class CGDOMJSProxyHandler_ownPropertyKeys(CGAbstractExternMethod): def __init__(self, descriptor): args = [Argument('*mut JSContext', 'cx'), - Argument('HandleObject', 'proxy'), + Argument('RawHandleObject', 'proxy'), Argument('*mut AutoIdVector', 'props')] CGAbstractExternMethod.__init__(self, descriptor, "own_property_keys", "bool", args) self.descriptor = descriptor @@ -5143,7 +5146,7 @@ class CGDOMJSProxyHandler_getOwnEnumerablePropertyKeys(CGAbstractExternMethod): assert (descriptor.operations["IndexedGetter"] and descriptor.interface.getExtendedAttribute("LegacyUnenumerableNamedProperties")) args = [Argument('*mut JSContext', 'cx'), - Argument('HandleObject', 'proxy'), + Argument('RawHandleObject', 'proxy'), Argument('*mut AutoIdVector', 'props')] CGAbstractExternMethod.__init__(self, descriptor, "getOwnEnumerablePropertyKeys", "bool", args) @@ -5183,15 +5186,15 @@ class CGDOMJSProxyHandler_getOwnEnumerablePropertyKeys(CGAbstractExternMethod): class CGDOMJSProxyHandler_hasOwn(CGAbstractExternMethod): def __init__(self, descriptor): - args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'), - Argument('HandleId', 'id'), Argument('*mut bool', 'bp')] + args = [Argument('*mut JSContext', 'cx'), Argument('RawHandleObject', 'proxy'), + Argument('RawHandleId', 'id'), Argument('*mut bool', 'bp')] CGAbstractExternMethod.__init__(self, descriptor, "hasOwn", "bool", args) self.descriptor = descriptor def getBody(self): indexedGetter = self.descriptor.operations['IndexedGetter'] if indexedGetter: - indexed = ("let index = get_array_index_from_id(cx, id);\n" + + indexed = ("let index = get_array_index_from_id(cx, Handle::from_raw(id));\n" + "if let Some(index) = index {\n" + " let this = UnwrapProxy(proxy);\n" + " let this = &*this;\n" + @@ -5210,7 +5213,7 @@ class CGDOMJSProxyHandler_hasOwn(CGAbstractExternMethod): named = """\ if %s { let mut has_on_proto = false; - if !has_property_on_prototype(cx, proxy, id, &mut has_on_proto) { + if !has_property_on_prototype(cx, proxy_lt, id_lt, &mut has_on_proto) { return false; } if !has_on_proto { @@ -5226,9 +5229,11 @@ if %s { return indexed + """\ rooted!(in(cx) let mut expando = ptr::null_mut::()); +let proxy_lt = Handle::from_raw(proxy); +let id_lt = Handle::from_raw(id); get_expando_object(proxy, expando.handle_mut()); if !expando.is_null() { - let ok = JS_HasPropertyById(cx, expando.handle(), id, bp); + let ok = JS_HasPropertyById(cx, expando.handle().into(), id, bp); if !ok || *bp { return ok; } @@ -5243,9 +5248,9 @@ return true;""" class CGDOMJSProxyHandler_get(CGAbstractExternMethod): def __init__(self, descriptor): - args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'), - Argument('HandleValue', 'receiver'), Argument('HandleId', 'id'), - Argument('MutableHandleValue', 'vp')] + args = [Argument('*mut JSContext', 'cx'), Argument('RawHandleObject', 'proxy'), + Argument('RawHandleValue', 'receiver'), Argument('RawHandleId', 'id'), + Argument('RawMutableHandleValue', 'vp')] CGAbstractExternMethod.__init__(self, descriptor, "get", "bool", args) self.descriptor = descriptor @@ -5256,23 +5261,23 @@ rooted!(in(cx) let mut expando = ptr::null_mut::()); get_expando_object(proxy, expando.handle_mut()); if !expando.is_null() { let mut hasProp = false; - if !JS_HasPropertyById(cx, expando.handle(), id, &mut hasProp) { + if !JS_HasPropertyById(cx, expando.handle().into(), id, &mut hasProp) { return false; } if hasProp { - return JS_ForwardGetPropertyTo(cx, expando.handle(), id, receiver, vp); + return JS_ForwardGetPropertyTo(cx, expando.handle().into(), id, receiver, vp); } }""" templateValues = { - 'jsvalRef': 'vp', + 'jsvalRef': 'vp_lt', 'successCode': 'return true;', } indexedGetter = self.descriptor.operations['IndexedGetter'] if indexedGetter: - getIndexedOrExpando = ("let index = get_array_index_from_id(cx, id);\n" + + getIndexedOrExpando = ("let index = get_array_index_from_id(cx, id_lt);\n" + "if let Some(index) = index {\n" + " let this = UnwrapProxy(proxy);\n" + " let this = &*this;\n" + @@ -5305,10 +5310,14 @@ if !expando.is_null() { return """\ //MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy), //"Should not have a XrayWrapper here"); +let proxy_lt = Handle::from_raw(proxy); +let vp_lt = MutableHandle::from_raw(vp); +let id_lt = Handle::from_raw(id); +let receiver_lt = Handle::from_raw(receiver); %s let mut found = false; -if !get_property_on_prototype(cx, proxy, receiver, id, &mut found, vp) { +if !get_property_on_prototype(cx, proxy_lt, receiver_lt, id_lt, &mut found, vp_lt) { return false; } @@ -5325,7 +5334,7 @@ return true;""" % (getIndexedOrExpando, getNamed) class CGDOMJSProxyHandler_className(CGAbstractExternMethod): def __init__(self, descriptor): - args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', '_proxy')] + args = [Argument('*mut JSContext', 'cx'), Argument('RawHandleObject', '_proxy')] CGAbstractExternMethod.__init__(self, descriptor, "className", "*const i8", args, doesNotPanic=True) self.descriptor = descriptor @@ -5660,16 +5669,20 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::error::throw_type_error', 'js::error::throw_internal_error', 'js::jsapi::AutoIdVector', - 'js::jsapi::Call', + 'js::rust::wrappers::Call', 'js::jsapi::CallArgs', 'js::jsapi::CurrentGlobalOrNull', 'js::jsapi::FreeOp', - 'js::jsapi::GetPropertyKeys', + 'js::rust::wrappers::GetPropertyKeys', 'js::jsapi::GetWellKnownSymbol', - 'js::jsapi::Handle', - 'js::jsapi::HandleId', - 'js::jsapi::HandleObject', - 'js::jsapi::HandleValue', + 'js::rust::Handle', + 'js::jsapi::Handle as RawHandle', + 'js::rust::HandleId', + 'js::jsapi::HandleId as RawHandleId', + 'js::rust::HandleObject', + 'js::jsapi::HandleObject as RawHandleObject', + 'js::rust::HandleValue', + 'js::jsapi::HandleValue as RawHandleValue', 'js::jsapi::HandleValueArray', 'js::jsapi::Heap', 'js::jsapi::INTERNED_STRING_TO_JSID', @@ -5704,37 +5717,40 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::jsapi::JSTypedMethodJitInfo', 'js::jsapi::JSValueType', 'js::jsapi::JS_AtomizeAndPinString', - 'js::jsapi::JS_CallFunctionValue', - 'js::jsapi::JS_CopyPropertiesFrom', - 'js::jsapi::JS_DefineProperty', - 'js::jsapi::JS_DefinePropertyById2', + 'js::rust::wrappers::JS_CallFunctionValue', + 'js::rust::wrappers::JS_CopyPropertiesFrom', + 'js::rust::wrappers::JS_DefineProperty', + 'js::rust::wrappers::JS_DefinePropertyById2', 'js::jsapi::JS_ForwardGetPropertyTo', 'js::jsapi::JS_GetErrorPrototype', - 'js::jsapi::JS_GetFunctionPrototype', + 'js::rust::wrappers::JS_GetFunctionPrototype', 'js::jsapi::JS_GetGlobalForObject', 'js::jsapi::JS_GetIteratorPrototype', - 'js::jsapi::JS_GetObjectPrototype', - 'js::jsapi::JS_GetProperty', + 'js::rust::wrappers::JS_GetObjectPrototype', + 'js::rust::wrappers::JS_GetProperty', 'js::jsapi::JS_GetPropertyById', 'js::jsapi::JS_GetPropertyDescriptorById', 'js::jsapi::JS_GetReservedSlot', 'js::jsapi::JS_HasProperty', 'js::jsapi::JS_HasPropertyById', - 'js::jsapi::JS_InitializePropertiesFromCompatibleNativeObject', + 'js::rust::wrappers::JS_InitializePropertiesFromCompatibleNativeObject', 'js::jsapi::JS_NewObject', - 'js::jsapi::JS_NewObjectWithGivenProto', - 'js::jsapi::JS_NewObjectWithoutMetadata', - 'js::jsapi::JS_ObjectIsDate', - 'js::jsapi::JS_SetImmutablePrototype', - 'js::jsapi::JS_SetProperty', - 'js::jsapi::JS_SetPrototype', + 'js::rust::wrappers::JS_NewObjectWithGivenProto', + 'js::rust::wrappers::JS_NewObjectWithoutMetadata', + 'js::rust::wrappers::JS_ObjectIsDate', + 'js::rust::wrappers::JS_SetImmutablePrototype', + 'js::rust::wrappers::JS_SetProperty', + 'js::rust::wrappers::JS_SetPrototype', 'js::jsapi::JS_SetReservedSlot', - 'js::jsapi::JS_SplicePrototype', - 'js::jsapi::JS_WrapValue', - 'js::jsapi::JS_WrapObject', - 'js::jsapi::MutableHandle', - 'js::jsapi::MutableHandleObject', - 'js::jsapi::MutableHandleValue', + 'js::rust::wrappers::JS_SplicePrototype', + 'js::rust::wrappers::JS_WrapValue', + 'js::rust::wrappers::JS_WrapObject', + 'js::rust::MutableHandle', + 'js::jsapi::MutableHandle as RawMutableHandle', + 'js::rust::MutableHandleObject', + 'js::jsapi::MutableHandleObject as RawMutableHandleObject', + 'js::rust::MutableHandleValue', + 'js::jsapi::MutableHandleValue as RawMutableHandleValue', 'js::jsapi::ObjectOpResult', 'js::jsapi::PropertyDescriptor', 'js::jsapi::Rooted', @@ -5755,7 +5771,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::glue::CallJitSetterOp', 'js::glue::CreateProxyHandler', 'js::glue::GetProxyPrivate', - 'js::glue::NewProxyObject', + 'js::rust::wrappers::NewProxyObject', 'js::glue::ProxyTraps', 'js::glue::RUST_JSID_IS_INT', 'js::glue::RUST_JSID_IS_STRING', @@ -6241,7 +6257,7 @@ class CGDictionary(CGThing): "}\n" "\n" "impl ToJSValConvertible for ${selfName} {\n" - " unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {\n" + " unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {\n" " rooted!(in(cx) let obj = JS_NewObject(cx, ptr::null()));\n" "${insertMembers}" " rval.set(ObjectOrNullValue(obj.get()))\n" @@ -7132,7 +7148,8 @@ class GlobalGenRoots(): def InterfaceObjectMap(config): mods = [ "dom::bindings::codegen", - "js::jsapi::{HandleObject, JSContext}", + "js::jsapi::JSContext", + "js::rust::HandleObject", "phf", ] imports = CGList([CGGeneric("use %s;" % mod) for mod in mods], "\n") @@ -7166,7 +7183,7 @@ class GlobalGenRoots(): pairs.append((ctor.identifier.name, binding, binding)) pairs.sort(key=operator.itemgetter(0)) mappings = [ - CGGeneric('"%s": "codegen::Bindings::%s::%s::DefineDOMInterface as unsafe fn(_, _)"' % pair) + CGGeneric('"%s": "codegen::Bindings::%s::%s::DefineDOMInterface"' % pair) for pair in pairs ] return CGWrapper( -- cgit v1.2.3 From 938f1362e7f1b1f8a121eacc36e24c9ac6236e13 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Tue, 3 Apr 2018 14:06:07 +0200 Subject: Update the WebIDL parser --- .../script/dom/bindings/codegen/CodegenRust.py | 2 +- .../script/dom/bindings/codegen/Configuration.py | 2 - .../script/dom/bindings/codegen/parser/WebIDL.py | 157 ++++++++++++--------- .../dom/bindings/codegen/parser/abstract.patch | 6 +- .../codegen/parser/tests/test_cereactions.py | 15 -- .../codegen/parser/tests/test_constructor.py | 3 +- .../parser/tests/test_duplicate_qualifiers.py | 28 ---- .../parser/tests/test_global_extended_attr.py | 18 --- .../bindings/codegen/parser/tests/test_method.py | 3 +- .../test_special_method_signature_mismatch.py | 70 --------- .../codegen/parser/tests/test_special_methods.py | 27 +--- .../tests/test_special_methods_uniqueness.py | 17 +-- 12 files changed, 104 insertions(+), 244 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 5b286394051..e7423c670eb 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -4800,7 +4800,7 @@ class CGProxySpecialOperation(CGPerSignatureCall): False, descriptor, operation, len(arguments)) - if operation.isSetter() or operation.isCreator(): + if operation.isSetter(): # arguments[0] is the index or name of the item that we're setting. argument = arguments[1] info = getJSToNativeConversionInfo( diff --git a/components/script/dom/bindings/codegen/Configuration.py b/components/script/dom/bindings/codegen/Configuration.py index 0ab27151bb6..4f56c4b55c3 100644 --- a/components/script/dom/bindings/codegen/Configuration.py +++ b/components/script/dom/bindings/codegen/Configuration.py @@ -279,8 +279,6 @@ class Descriptor(DescriptorProvider): addIndexedOrNamedOperation('Getter', m) if m.isSetter(): addIndexedOrNamedOperation('Setter', m) - if m.isCreator(): - addIndexedOrNamedOperation('Creator', m) if m.isDeleter(): addIndexedOrNamedOperation('Deleter', m) diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index 5045eae6493..b2daa1bce20 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.py @@ -1095,12 +1095,12 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): testInterface = testInterface.parent # Ensure that there's at most one of each {named,indexed} - # {getter,setter,creator,deleter}, at most one stringifier, + # {getter,setter,deleter}, at most one stringifier, # and at most one legacycaller. Note that this last is not # quite per spec, but in practice no one overloads # legacycallers. Also note that in practice we disallow # indexed deleters, but it simplifies some other code to - # treat deleter analogously to getter/setter/creator by + # treat deleter analogously to getter/setter by # prefixing it with "named". specialMembersSeen = {} for member in self.members: @@ -1111,8 +1111,6 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): memberType = "getters" elif member.isSetter(): memberType = "setters" - elif member.isCreator(): - memberType = "creators" elif member.isDeleter(): memberType = "deleters" elif member.isStringifier(): @@ -1158,8 +1156,8 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): ancestor = ancestor.parent if self._isOnGlobalProtoChain: - # Make sure we have no named setters, creators, or deleters - for memberType in ["setter", "creator", "deleter"]: + # Make sure we have no named setters or deleters + for memberType in ["setter", "deleter"]: memberId = "named " + memberType + "s" if memberId in specialMembersSeen: raise WebIDLError("Interface with [Global] has a named %s" % @@ -1183,6 +1181,22 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): parent = parent.parent def validate(self): + + def checkDuplicateNames(member, name, attributeName): + for m in self.members: + if m.identifier.name == name: + raise WebIDLError("[%s=%s] has same name as interface member" % + (attributeName, name), + [member.location, m.location]) + if m.isMethod() and m != member and name in m.aliases: + raise WebIDLError("conflicting [%s=%s] definitions" % + (attributeName, name), + [member.location, m.location]) + if m.isAttr() and m != member and name in m.bindingAliases: + raise WebIDLError("conflicting [%s=%s] definitions" % + (attributeName, name), + [member.location, m.location]) + # We don't support consequential unforgeable interfaces. Need to check # this here, because in finish() an interface might not know yet that # it's consequential. @@ -1295,15 +1309,15 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): raise WebIDLError("[Alias] must not be used on an " "[Unforgeable] operation", [member.location]) - for m in self.members: - if m.identifier.name == alias: - raise WebIDLError("[Alias=%s] has same name as " - "interface member" % alias, - [member.location, m.location]) - if m.isMethod() and m != member and alias in m.aliases: - raise WebIDLError("duplicate [Alias=%s] definitions" % - alias, - [member.location, m.location]) + + checkDuplicateNames(member, alias, "Alias") + + # Check that the name of a [BindingAlias] doesn't conflict with an + # interface member. + if member.isAttr(): + 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. @@ -1720,10 +1734,10 @@ class IDLInterface(IDLInterfaceOrNamespace): identifier == "OverrideBuiltins" or identifier == "ChromeOnly" or identifier == "Unforgeable" or - identifier == "UnsafeInPrerendering" or identifier == "LegacyEventInit" or identifier == "ProbablyShortLivingWrapper" or identifier == "LegacyUnenumerableNamedProperties" or + identifier == "RunConstructorInCallerCompartment" or identifier == "NonOrdinaryGetPrototypeOf" or identifier == "Abstract" or identifier == "Inline"): @@ -1780,10 +1794,16 @@ class IDLNamespace(IDLInterfaceOrNamespace): if not attr.hasValue(): raise WebIDLError("[%s] must have a value" % identifier, [attr.location]) - elif identifier == "ProtoObjectHack": + elif (identifier == "ProtoObjectHack" or + identifier == "ChromeOnly"): if not attr.noArguments(): raise WebIDLError("[%s] must not have arguments" % identifier, [attr.location]) + elif identifier == "Pref": + # Known extended attributes that take a string value + if not attr.hasValue(): + raise WebIDLError("[%s] must have a value" % identifier, + [attr.location]) else: raise WebIDLError("Unknown extended attribute %s on namespace" % identifier, @@ -3581,6 +3601,11 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins): [self.location]) self.aliases.append(alias) + def _addBindingAlias(self, bindingAlias): + if bindingAlias in self.bindingAliases: + raise WebIDLError("Duplicate [BindingAlias=%s] on attribute" % bindingAlias, + [self.location]) + self.bindingAliases.append(bindingAlias) class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember): @@ -3701,6 +3726,11 @@ class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember): if isIteratorAlias: method.addExtendedAttributes( [IDLExtendedAttribute(self.location, ("Alias", "@@iterator"))]) + # Methods generated for iterables should be enumerable, but the ones for + # maplike/setlike should not be. + if not self.isIterable(): + method.addExtendedAttributes( + [IDLExtendedAttribute(self.location, ("NonEnumerable",))]) members.append(method) def resolve(self, parentScope): @@ -3824,11 +3854,15 @@ class IDLMaplikeOrSetlike(IDLMaplikeOrSetlikeOrIterableBase): specification during parsing. """ # Both maplike and setlike have a size attribute - members.append(IDLAttribute(self.location, - IDLUnresolvedIdentifier(BuiltinLocation(""), "size"), - BuiltinTypes[IDLBuiltinType.Types.unsigned_long], - True, - maplikeOrSetlike=self)) + sizeAttr = IDLAttribute(self.location, + IDLUnresolvedIdentifier(BuiltinLocation(""), "size"), + BuiltinTypes[IDLBuiltinType.Types.unsigned_long], + True, + maplikeOrSetlike=self) + # This should be non-enumerable. + sizeAttr.addExtendedAttributes( + [IDLExtendedAttribute(self.location, ("NonEnumerable",))]) + members.append(sizeAttr) self.reserved_ro_names = ["size"] self.disallowedMemberNames.append("size") @@ -3964,7 +3998,9 @@ class IDLConst(IDLInterfaceMember): elif (identifier == "Pref" or identifier == "ChromeOnly" or identifier == "Func" or - identifier == "SecureContext"): + identifier == "SecureContext" or + identifier == "NonEnumerable" or + identifier == "NeedsWindowsUndef"): # Known attributes that we don't need to do anything with here pass else: @@ -4000,6 +4036,7 @@ class IDLAttribute(IDLInterfaceMember): self.dependsOn = "Everything" self.affects = "Everything" self.navigatorObjectGetter = navigatorObjectGetter + self.bindingAliases = [] if static and identifier.name == "prototype": raise WebIDLError("The identifier of a static attribute must not be 'prototype'", @@ -4138,11 +4175,17 @@ class IDLAttribute(IDLInterfaceMember): def handleExtendedAttribute(self, attr): identifier = attr.identifier() - if ((identifier == "SetterThrows" or identifier == "SetterCanOOM") + if ((identifier == "SetterThrows" or identifier == "SetterCanOOM" or + identifier == "SetterNeedsSubjectPrincipal") and self.readonly): raise WebIDLError("Readonly attributes must not be flagged as " "[%s]" % identifier, [self.location]) + elif identifier == "BindingAlias": + if not attr.hasValue(): + raise WebIDLError("[BindingAlias] takes an identifier or string", + [attr.location]) + self._addBindingAlias(attr.value()) elif (((identifier == "Throws" or identifier == "GetterThrows" or identifier == "CanOOM" or identifier == "GetterCanOOM") and self.getExtendedAttribute("StoreInSlot")) or @@ -4338,11 +4381,13 @@ class IDLAttribute(IDLInterfaceMember): identifier == "SecureContext" or identifier == "Frozen" or identifier == "NewObject" or - identifier == "UnsafeInPrerendering" or identifier == "NeedsSubjectPrincipal" or + identifier == "SetterNeedsSubjectPrincipal" or + identifier == "GetterNeedsSubjectPrincipal" or identifier == "NeedsCallerType" or identifier == "ReturnValueNeedsContainsHack" or - identifier == "BinaryName"): + identifier == "BinaryName" or + identifier == "NonEnumerable"): # Known attributes that we don't need to do anything with here pass else: @@ -4606,7 +4651,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope): Special = enum( 'Getter', 'Setter', - 'Creator', 'Deleter', 'LegacyCaller', base=IDLInterfaceMember.Special @@ -4619,7 +4663,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope): ) def __init__(self, location, identifier, returnType, arguments, - static=False, getter=False, setter=False, creator=False, + static=False, getter=False, setter=False, deleter=False, specialType=NamedOrIndexed.Neither, legacycaller=False, stringifier=False, jsonifier=False, maplikeOrSetlikeOrIterable=None, htmlConstructor=False): @@ -4640,8 +4684,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope): self._getter = getter assert isinstance(setter, bool) self._setter = setter - assert isinstance(creator, bool) - self._creator = creator assert isinstance(deleter, bool) self._deleter = deleter assert isinstance(legacycaller, bool) @@ -4682,7 +4724,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope): assert not arguments[0].optional and not arguments[0].variadic assert not self._getter or not overload.returnType.isVoid() - if self._setter or self._creator: + if self._setter: assert len(self._overloads) == 1 arguments = self._overloads[0].arguments assert len(arguments) == 2 @@ -4715,9 +4757,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope): def isSetter(self): return self._setter - def isCreator(self): - return self._creator - def isDeleter(self): return self._deleter @@ -4750,7 +4789,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope): def isSpecial(self): return (self.isGetter() or self.isSetter() or - self.isCreator() or self.isDeleter() or self.isLegacycaller() or self.isStringifier() or @@ -4806,8 +4844,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope): assert not method.isGetter() assert not self.isSetter() assert not method.isSetter() - assert not self.isCreator() - assert not method.isCreator() assert not self.isDeleter() assert not method.isDeleter() assert not self.isStringifier() @@ -4984,7 +5020,9 @@ class IDLMethod(IDLInterfaceMember, IDLScope): if (identifier == "GetterThrows" or identifier == "SetterThrows" or identifier == "GetterCanOOM" or - identifier == "SetterCanOOM"): + identifier == "SetterCanOOM" or + identifier == "SetterNeedsSubjectPrincipal" or + identifier == "GetterNeedsSubjectPrincipal"): raise WebIDLError("Methods must not be flagged as " "[%s]" % identifier, [attr.location, self.location]) @@ -5071,7 +5109,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope): identifier == "CanOOM" or identifier == "NewObject" or identifier == "ChromeOnly" or - identifier == "UnsafeInPrerendering" or identifier == "Pref" or identifier == "Deprecated" or identifier == "Func" or @@ -5079,7 +5116,8 @@ class IDLMethod(IDLInterfaceMember, IDLScope): identifier == "BinaryName" or identifier == "NeedsSubjectPrincipal" or identifier == "NeedsCallerType" or - identifier == "StaticClassOverride"): + identifier == "StaticClassOverride" or + identifier == "NonEnumerable"): # Known attributes that we don't need to do anything with here pass else: @@ -5262,7 +5300,6 @@ class Tokenizer(object): "static": "STATIC", "getter": "GETTER", "setter": "SETTER", - "creator": "CREATOR", "deleter": "DELETER", "legacycaller": "LEGACYCALLER", "optional": "OPTIONAL", @@ -5977,13 +6014,12 @@ class Parser(Tokenizer): getter = True if IDLMethod.Special.Getter in p[1] else False setter = True if IDLMethod.Special.Setter in p[1] else False - creator = True if IDLMethod.Special.Creator in p[1] else False deleter = True if IDLMethod.Special.Deleter in p[1] else False legacycaller = True if IDLMethod.Special.LegacyCaller in p[1] else False if getter or deleter: - if setter or creator: - raise WebIDLError("getter and deleter are incompatible with setter and creator", + if setter: + raise WebIDLError("getter and deleter are incompatible with setter", [self.getLocation(p, 1)]) (returnType, identifier, arguments) = p[2] @@ -6018,10 +6054,9 @@ class Parser(Tokenizer): if returnType.isVoid(): raise WebIDLError("getter cannot have void return type", [self.getLocation(p, 2)]) - if setter or creator: + if setter: if len(arguments) != 2: - raise WebIDLError("%s has wrong number of arguments" % - ("setter" if setter else "creator"), + raise WebIDLError("setter has wrong number of arguments", [self.getLocation(p, 2)]) argType = arguments[0].type if argType == BuiltinTypes[IDLBuiltinType.Types.domstring]: @@ -6029,18 +6064,15 @@ class Parser(Tokenizer): elif argType == BuiltinTypes[IDLBuiltinType.Types.unsigned_long]: specialType = IDLMethod.NamedOrIndexed.Indexed else: - raise WebIDLError("%s has wrong argument type (must be DOMString or UnsignedLong)" % - ("setter" if setter else "creator"), + raise WebIDLError("settter has wrong argument type (must be DOMString or UnsignedLong)", [arguments[0].location]) if arguments[0].optional or arguments[0].variadic: - raise WebIDLError("%s cannot have %s argument" % - ("setter" if setter else "creator", - "optional" if arguments[0].optional else "variadic"), + raise WebIDLError("setter cannot have %s argument" % + ("optional" if arguments[0].optional else "variadic"), [arguments[0].location]) if arguments[1].optional or arguments[1].variadic: - raise WebIDLError("%s cannot have %s argument" % - ("setter" if setter else "creator", - "optional" if arguments[1].optional else "variadic"), + raise WebIDLError("setter cannot have %s argument" % + ("optional" if arguments[1].optional else "variadic"), [arguments[1].location]) if stringifier: @@ -6053,7 +6085,7 @@ class Parser(Tokenizer): # identifier might be None. This is only permitted for special methods. if not identifier: - if (not getter and not setter and not creator and + if (not getter and not setter and not deleter and not legacycaller and not stringifier): raise WebIDLError("Identifier required for non-special methods", [self.getLocation(p, 2)]) @@ -6061,19 +6093,18 @@ class Parser(Tokenizer): location = BuiltinLocation("") identifier = IDLUnresolvedIdentifier( location, - "__%s%s%s%s%s%s%s" % + "__%s%s%s%s%s%s" % ("named" if specialType == IDLMethod.NamedOrIndexed.Named else "indexed" if specialType == IDLMethod.NamedOrIndexed.Indexed else "", "getter" if getter else "", "setter" if setter else "", "deleter" if deleter else "", - "creator" if creator else "", "legacycaller" if legacycaller else "", "stringifier" if stringifier else ""), allowDoubleUnderscore=True) method = IDLMethod(self.getLocation(p, 2), identifier, returnType, arguments, - static=static, getter=getter, setter=setter, creator=creator, + static=static, getter=getter, setter=setter, deleter=deleter, specialType=specialType, legacycaller=legacycaller, stringifier=stringifier) p[0] = method @@ -6149,12 +6180,6 @@ class Parser(Tokenizer): """ p[0] = IDLMethod.Special.Setter - def p_SpecialCreator(self, p): - """ - Special : CREATOR - """ - p[0] = IDLMethod.Special.Creator - def p_SpecialDeleter(self, p): """ Special : DELETER @@ -6246,7 +6271,6 @@ class Parser(Tokenizer): | ATTRIBUTE | CALLBACK | CONST - | CREATOR | DELETER | DICTIONARY | ENUM @@ -6396,7 +6420,6 @@ class Parser(Tokenizer): | BYTE | LEGACYCALLER | CONST - | CREATOR | DELETER | DOUBLE | EXCEPTION diff --git a/components/script/dom/bindings/codegen/parser/abstract.patch b/components/script/dom/bindings/codegen/parser/abstract.patch index a8e2ddcf759..e43d12eb988 100644 --- a/components/script/dom/bindings/codegen/parser/abstract.patch +++ b/components/script/dom/bindings/codegen/parser/abstract.patch @@ -1,9 +1,9 @@ --- WebIDL.py +++ WebIDL.py -@@ -1416,7 +1416,8 @@ - identifier == "LegacyEventInit" or - identifier == "ProbablyShortLivingObject" or +@@ -1744,7 +1744,8 @@ + identifier == "ProbablyShortLivingWrapper" or identifier == "LegacyUnenumerableNamedProperties" or + identifier == "RunConstructorInCallerCompartment" or - identifier == "NonOrdinaryGetPrototypeOf"): + identifier == "NonOrdinaryGetPrototypeOf" or + identifier == "Abstract"): 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 2f9397d903e..a1e5e78630f 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_cereactions.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_cereactions.py @@ -101,21 +101,6 @@ def WebIDLTest(parser, harness): harness.ok(threw, "Should have thrown for [CEReactions] used on a named getter") - parser = parser.reset() - threw = False - try: - parser.parse(""" - interface Foo { - [CEReactions] creator boolean (DOMString name, boolean value); - }; - """) - results = parser.finish() - except: - threw = True - - harness.ok(threw, - "Should have thrown for [CEReactions] used on a named creator") - parser = parser.reset() threw = False try: diff --git a/components/script/dom/bindings/codegen/parser/tests/test_constructor.py b/components/script/dom/bindings/codegen/parser/tests/test_constructor.py index 6c68a6c79cf..c722d7bc5c7 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_constructor.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_constructor.py @@ -11,7 +11,7 @@ def WebIDLTest(parser, harness): harness.check(argument.variadic, variadic, "Argument has the right variadic value") def checkMethod(method, QName, name, signatures, - static=True, getter=False, setter=False, creator=False, + static=True, getter=False, setter=False, deleter=False, legacycaller=False, stringifier=False, chromeOnly=False, htmlConstructor=False): harness.ok(isinstance(method, WebIDL.IDLMethod), @@ -24,7 +24,6 @@ def WebIDLTest(parser, harness): harness.check(method.isStatic(), static, "Method has the correct static value") harness.check(method.isGetter(), getter, "Method has the correct getter value") harness.check(method.isSetter(), setter, "Method has the correct setter value") - harness.check(method.isCreator(), creator, "Method has the correct creator value") harness.check(method.isDeleter(), deleter, "Method has the correct deleter value") harness.check(method.isLegacycaller(), legacycaller, "Method has the correct legacycaller value") harness.check(method.isStringifier(), stringifier, "Method has the correct stringifier value") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_duplicate_qualifiers.py b/components/script/dom/bindings/codegen/parser/tests/test_duplicate_qualifiers.py index 799f2e0e0ed..4874b3aafe6 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_duplicate_qualifiers.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_duplicate_qualifiers.py @@ -27,20 +27,6 @@ def WebIDLTest(parser, harness): harness.ok(threw, "Should have thrown.") - threw = False - try: - parser.parse(""" - interface DuplicateQualifiers3 { - creator creator byte foo(unsigned long index, byte value); - }; - """) - - results = parser.finish() - except: - threw = True - - harness.ok(threw, "Should have thrown.") - threw = False try: parser.parse(""" @@ -68,17 +54,3 @@ def WebIDLTest(parser, harness): threw = True harness.ok(threw, "Should have thrown.") - - threw = False - try: - results = parser.parse(""" - interface DuplicateQualifiers6 { - creator setter creator byte foo(unsigned long index, byte value); - }; - """) - - results = parser.finish() - except: - threw = True - - harness.ok(threw, "Should have thrown.") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_global_extended_attr.py b/components/script/dom/bindings/codegen/parser/tests/test_global_extended_attr.py index c752cecd298..bc20da40bbe 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_global_extended_attr.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_global_extended_attr.py @@ -32,24 +32,6 @@ def WebIDLTest(parser, harness): "Should have thrown for [Global] used on an interface with a " "named setter") - parser = parser.reset() - threw = False - try: - parser.parse(""" - [Global] - interface Foo { - getter any(DOMString name); - creator void(DOMString name, any arg); - }; - """) - results = parser.finish() - except: - threw = True - - harness.ok(threw, - "Should have thrown for [Global] used on an interface with a " - "named creator") - parser = parser.reset() threw = False try: 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 cf7f1b40d76..29e6d6b25b7 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_method.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_method.py @@ -41,7 +41,7 @@ def WebIDLTest(parser, harness): harness.check(argument.variadic, variadic, "Argument has the right variadic value") def checkMethod(method, QName, name, signatures, - static=False, getter=False, setter=False, creator=False, + static=False, getter=False, setter=False, deleter=False, legacycaller=False, stringifier=False): harness.ok(isinstance(method, WebIDL.IDLMethod), "Should be an IDLMethod") @@ -53,7 +53,6 @@ def WebIDLTest(parser, harness): harness.check(method.isStatic(), static, "Method has the correct static value") harness.check(method.isGetter(), getter, "Method has the correct getter value") harness.check(method.isSetter(), setter, "Method has the correct setter value") - harness.check(method.isCreator(), creator, "Method has the correct creator value") harness.check(method.isDeleter(), deleter, "Method has the correct deleter value") harness.check(method.isLegacycaller(), legacycaller, "Method has the correct legacycaller value") harness.check(method.isStringifier(), stringifier, "Method has the correct stringifier value") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_special_method_signature_mismatch.py b/components/script/dom/bindings/codegen/parser/tests/test_special_method_signature_mismatch.py index 5ea1743d36a..52cfcb96817 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_special_method_signature_mismatch.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_special_method_signature_mismatch.py @@ -222,73 +222,3 @@ def WebIDLTest(parser, harness): threw = True harness.ok(threw, "Should have thrown.") - - threw = False - try: - parser.parse(""" - interface SpecialMethodSignatureMismatch20 { - creator long long foo(long index, long long value); - }; - """) - - results = parser.finish() - except: - threw = True - - harness.ok(threw, "Should have thrown.") - - threw = False - try: - parser.parse(""" - interface SpecialMethodSignatureMismatch22 { - creator boolean foo(unsigned long index, boolean value, long long extraArg); - }; - """) - - results = parser.finish() - except: - threw = True - - harness.ok(threw, "Should have thrown.") - - threw = False - try: - parser.parse(""" - interface SpecialMethodSignatureMismatch23 { - creator boolean foo(unsigned long index, boolean... value); - }; - """) - - results = parser.finish() - except: - threw = True - - harness.ok(threw, "Should have thrown.") - - threw = False - try: - parser.parse(""" - interface SpecialMethodSignatureMismatch24 { - creator boolean foo(unsigned long index, optional boolean value); - }; - """) - - results = parser.finish() - except: - threw = True - - harness.ok(threw, "Should have thrown.") - - threw = False - try: - parser.parse(""" - interface SpecialMethodSignatureMismatch25 { - creator boolean foo(); - }; - """) - - results = parser.finish() - except: - threw = True - - harness.ok(threw, "Should have thrown.") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_special_methods.py b/components/script/dom/bindings/codegen/parser/tests/test_special_methods.py index 1e3a95b9bc2..7f911733b62 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_special_methods.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_special_methods.py @@ -5,25 +5,21 @@ def WebIDLTest(parser, harness): interface SpecialMethods { getter long long (unsigned long index); setter long long (unsigned long index, long long value); - creator long long (unsigned long index, long long value); getter boolean (DOMString name); setter boolean (DOMString name, boolean value); - creator boolean (DOMString name, boolean value); deleter boolean (DOMString name); readonly attribute unsigned long length; }; interface SpecialMethodsCombination { - setter creator long long (unsigned long index, long long value); getter deleter boolean (DOMString name); - setter creator boolean (DOMString name, boolean value); }; """) results = parser.finish() def checkMethod(method, QName, name, - static=False, getter=False, setter=False, creator=False, + static=False, getter=False, setter=False, deleter=False, legacycaller=False, stringifier=False): harness.ok(isinstance(method, WebIDL.IDLMethod), "Should be an IDLMethod") @@ -32,7 +28,6 @@ def WebIDLTest(parser, harness): harness.check(method.isStatic(), static, "Method has the correct static value") harness.check(method.isGetter(), getter, "Method has the correct getter value") harness.check(method.isSetter(), setter, "Method has the correct setter value") - harness.check(method.isCreator(), creator, "Method has the correct creator value") harness.check(method.isDeleter(), deleter, "Method has the correct deleter value") harness.check(method.isLegacycaller(), legacycaller, "Method has the correct legacycaller value") harness.check(method.isStringifier(), stringifier, "Method has the correct stringifier value") @@ -40,32 +35,24 @@ def WebIDLTest(parser, harness): harness.check(len(results), 2, "Expect 2 interfaces") iface = results[0] - harness.check(len(iface.members), 8, "Expect 8 members") + harness.check(len(iface.members), 6, "Expect 6 members") checkMethod(iface.members[0], "::SpecialMethods::__indexedgetter", "__indexedgetter", getter=True) checkMethod(iface.members[1], "::SpecialMethods::__indexedsetter", "__indexedsetter", setter=True) - checkMethod(iface.members[2], "::SpecialMethods::__indexedcreator", "__indexedcreator", - creator=True) - checkMethod(iface.members[3], "::SpecialMethods::__namedgetter", "__namedgetter", + checkMethod(iface.members[2], "::SpecialMethods::__namedgetter", "__namedgetter", getter=True) - checkMethod(iface.members[4], "::SpecialMethods::__namedsetter", "__namedsetter", + checkMethod(iface.members[3], "::SpecialMethods::__namedsetter", "__namedsetter", setter=True) - checkMethod(iface.members[5], "::SpecialMethods::__namedcreator", "__namedcreator", - creator=True) - checkMethod(iface.members[6], "::SpecialMethods::__nameddeleter", "__nameddeleter", + checkMethod(iface.members[4], "::SpecialMethods::__nameddeleter", "__nameddeleter", deleter=True) iface = results[1] - harness.check(len(iface.members), 3, "Expect 3 members") + harness.check(len(iface.members), 1, "Expect 1 member") - checkMethod(iface.members[0], "::SpecialMethodsCombination::__indexedsettercreator", - "__indexedsettercreator", setter=True, creator=True) - checkMethod(iface.members[1], "::SpecialMethodsCombination::__namedgetterdeleter", + checkMethod(iface.members[0], "::SpecialMethodsCombination::__namedgetterdeleter", "__namedgetterdeleter", getter=True, deleter=True) - checkMethod(iface.members[2], "::SpecialMethodsCombination::__namedsettercreator", - "__namedsettercreator", setter=True, creator=True) parser = parser.reset(); diff --git a/components/script/dom/bindings/codegen/parser/tests/test_special_methods_uniqueness.py b/components/script/dom/bindings/codegen/parser/tests/test_special_methods_uniqueness.py index 42e2c5bb71b..9bf3d903463 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_special_methods_uniqueness.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_special_methods_uniqueness.py @@ -35,23 +35,8 @@ def WebIDLTest(parser, harness): try: parser.parse(""" interface SpecialMethodUniqueness1 { - setter creator boolean (DOMString name); - creator boolean (DOMString name); - }; - """) - - results = parser.finish() - except: - threw = True - - harness.ok(threw, "Should have thrown.") - - threw = False - try: - parser.parse(""" - interface SpecialMethodUniqueness1 { setter boolean (DOMString name); - creator setter boolean (DOMString name); + setter boolean (DOMString name); }; """) -- cgit v1.2.3 From d0cc9d2cd56a197fdfb72d8c0168d4cf2bb23bdb Mon Sep 17 00:00:00 2001 From: Alan Jeffrey Date: Wed, 30 May 2018 14:44:47 -0500 Subject: Updated to mozjs v0.7.1. --- components/script/dom/bindings/codegen/CodegenRust.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index e7423c670eb..01b52d916ae 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -361,7 +361,7 @@ class CGMethodCall(CGThing): for i in range(0, distinguishingIndex)] # Select the right overload from our set. - distinguishingArg = "args.get(%d)" % distinguishingIndex + distinguishingArg = "HandleValue::from_raw(args.get(%d))" % distinguishingIndex def pickFirstSignature(condition, filterLambda): sigs = filter(filterLambda, possibleSignatures) @@ -1284,7 +1284,7 @@ class CGArgumentConverter(CGThing): } replacementVariables = { - "val": string.Template("${args}.get(${index})").substitute(replacer), + "val": string.Template("HandleValue::from_raw(${args}.get(${index}))").substitute(replacer), } info = getJSToNativeConversionInfo( @@ -1328,7 +1328,7 @@ class CGArgumentConverter(CGThing): else: assert argument.optional variadicConversion = { - "val": string.Template("${args}.get(variadicArg)").substitute(replacer), + "val": string.Template("HandleValue::from_raw(${args}.get(variadicArg))").substitute(replacer), } innerConverter = [instantiateJSToNativeConversionTemplate( template, variadicConversion, declType, "slot")] @@ -3365,7 +3365,7 @@ class CGPerSignatureCall(CGThing): return 'infallible' not in self.extendedAttributes def wrap_return_value(self): - return wrapForType('args.rval()') + return wrapForType('MutableHandleValue::from_raw(args.rval())') def define(self): return (self.cgRoot.define() + "\n" + self.wrap_return_value()) @@ -3516,7 +3516,7 @@ class CGSpecializedMethod(CGAbstractExternMethod): self.descriptor, self.method), pre="let this = &*this;\n" "let args = &*args;\n" - "let argc = args._base.argc_;\n") + "let argc = args.argc_;\n") @staticmethod def makeNativeName(descriptor, method): @@ -3675,7 +3675,7 @@ if !v.is_object() { return false; } rooted!(in(cx) let target_obj = v.to_object()); -JS_SetProperty(cx, target_obj.handle(), %s as *const u8 as *const libc::c_char, args.get(0)) +JS_SetProperty(cx, target_obj.handle(), %s as *const u8 as *const libc::c_char, HandleValue::from_raw(args.get(0))) """ % (str_to_const_array(attrName), attrName, str_to_const_array(forwardToAttrName))) @@ -3693,7 +3693,7 @@ class CGSpecializedReplaceableSetter(CGSpecializedSetter): assert all(ord(c) < 128 for c in name) return CGGeneric("""\ JS_DefineProperty(cx, obj, %s as *const u8 as *const libc::c_char, - args.get(0), JSPROP_ENUMERATE, None, None)""" % name) + HandleValue::from_raw(args.get(0)), JSPROP_ENUMERATE, None, None)""" % name) class CGMemberJITInfo(CGThing): @@ -5514,7 +5514,7 @@ if !JS_WrapObject(cx, element.handle_mut()) { JS_SetPrototype(cx, element.handle(), prototype.handle()); -(result).to_jsval(cx, args.rval()); +(result).to_jsval(cx, MutableHandleValue::from_raw(args.rval())); return true; """ % self.descriptor.name) else: -- cgit v1.2.3 From ad198993b127ef87f129add8336f8bb7dfd30e4d Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 29 Jun 2018 10:34:09 -0700 Subject: Assert that DOM structs have the correct first field DOM structs embed their parent type as their first field. This introduces a `.parent()` method to the DOM struct that returns its first field, and codegens a type assert that ensures that `.parent()` returns the parent struct. This generates: On `#[dom_struct]`: ```rust impl HasParent for Type { type Parent = ParentType; fn as_parent(&self) -> ParentType { &self.first_field } } ``` In the codegen files: ```rust impl Type { fn __assert_parent_type(&self) { let _: &ParentType = self.as_parent(); } } ```` --- .../script/dom/bindings/codegen/CodegenRust.py | 52 +++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 01b52d916ae..ae76667707e 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2116,6 +2116,10 @@ class CGDOMJSClass(CGThing): self.descriptor = descriptor def define(self): + parentName = self.descriptor.getParentName() + if not parentName: + parentName = "::dom::bindings::reflector::Reflector" + args = { "domClass": DOMClass(self.descriptor), "enumerateHook": "None", @@ -2161,7 +2165,51 @@ static Class: DOMJSClass = DOMJSClass { reserved: [0 as *mut _; 3], }, dom_class: %(domClass)s -};""" % args +}; +""" % args + + +class CGAssertInheritance(CGThing): + """ + Generate a type assertion for inheritance + """ + def __init__(self, descriptor): + CGThing.__init__(self) + self.descriptor = descriptor + + def define(self): + parent = self.descriptor.interface.parent + parentName = "" + if parent: + parentName = parent.identifier.name + else: + parentName = "::dom::bindings::reflector::Reflector" + + selfName = self.descriptor.interface.identifier.name + + if selfName == "PaintRenderingContext2D": + # PaintRenderingContext2D embeds a CanvasRenderingContext2D + # instead of a Reflector as an optimization, + # but this is fine since CanvasRenderingContext2D + # also has a reflector + # + # FIXME *RenderingContext2D should use Inline + parentName = "::dom::canvasrenderingcontext2d::CanvasRenderingContext2D" + args = { + "parentName": parentName, + "selfName": selfName, + } + + return """\ +impl %(selfName)s { + fn __assert_parent_type(&self) { + use dom::bindings::inheritance::HasParent; + // If this type assertion fails, make sure the first field of your + // DOM struct is of the correct type -- it must be the parent class. + let _: &%(parentName)s = self.as_parent(); + } +} +""" % args def str_to_const_array(s): @@ -6011,6 +6059,8 @@ class CGDescriptor(CGThing): pass else: cgThings.append(CGDOMJSClass(descriptor)) + if not descriptor.interface.isIteratorInterface(): + cgThings.append(CGAssertInheritance(descriptor)) pass if descriptor.isGlobal(): -- cgit v1.2.3 From cceaede96a18e67d93c087d6d499f27eda022025 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 6 Jul 2018 11:14:44 -0700 Subject: Make (dictionary)::empty() safe It currently works by constructing from null (which will throw a runtime error if there are non-defaultable members). This changes it so that we no longer need a JSContext to construct this, so it can be safely constructed. In the case of non-defaultable members, this method simply does not exist. --- .../script/dom/bindings/codegen/CodegenRust.py | 56 ++++++++++++++++++---- 1 file changed, 48 insertions(+), 8 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index ae76667707e..6015a4b126a 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -744,7 +744,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, if defaultValue: assert isinstance(defaultValue, IDLNullValue) dictionary, = dictionaries - default = "%s::%s(%s::%s::empty(cx))" % ( + default = "%s::%s(%s::%s::empty())" % ( union_native_type(type), dictionary.name, CGDictionary.makeModuleName(dictionary.inner), @@ -1148,7 +1148,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, typeName = "%s::%s" % (CGDictionary.makeModuleName(type.inner), CGDictionary.makeDictionaryName(type.inner)) declType = CGGeneric(typeName) - empty = "%s::empty(cx)" % typeName + empty = "%s::empty()" % typeName if type_needs_tracing(type): declType = CGTemplatedType("RootedTraceableBox", declType) @@ -6274,12 +6274,7 @@ class CGDictionary(CGThing): return string.Template( "impl ${selfName} {\n" - " pub unsafe fn empty(cx: *mut JSContext) -> ${actualType} {\n" - " match ${selfName}::new(cx, HandleValue::null()) {\n" - " Ok(ConversionResult::Success(v)) => v,\n" - " _ => unreachable!(),\n" - " }\n" - " }\n" + "${empty}\n" " pub unsafe fn new(cx: *mut JSContext, val: HandleValue) \n" " -> Result, ()> {\n" " let object = if val.get().is_null_or_undefined() {\n" @@ -6315,6 +6310,7 @@ class CGDictionary(CGThing): "}\n").substitute({ "selfName": selfName, "actualType": actualType, + "empty": CGIndenter(CGGeneric(self.makeEmpty()), indentLevel=4).define(), "initParent": CGIndenter(CGGeneric(initParent), indentLevel=12).define(), "initMembers": CGIndenter(memberInits, indentLevel=12).define(), "insertMembers": CGIndenter(memberInserts, indentLevel=8).define(), @@ -6380,6 +6376,50 @@ class CGDictionary(CGThing): return CGGeneric(conversion) + def makeEmpty(self): + if self.hasRequiredFields(self.dictionary): + return "" + parentTemplate = "parent: %s::%s::empty(),\n" + fieldTemplate = "%s: %s,\n" + functionTemplate = ( + "pub fn empty() -> Self {\n" + " Self {\n" + "%s" + " }\n" + "}" + ) + if self.membersNeedTracing(): + parentTemplate = "dictionary.parent = %s::%s::empty();\n" + fieldTemplate = "dictionary.%s = %s;\n" + functionTemplate = ( + "pub fn empty() -> RootedTraceableBox {\n" + " let mut dictionary = RootedTraceableBox::new(Self::default());\n" + "%s" + " dictionary\n" + "}" + ) + s = "" + if self.dictionary.parent: + s += parentTemplate % (self.makeModuleName(self.dictionary.parent), + self.makeClassName(self.dictionary.parent)) + for member, info in self.memberInfo: + if not member.optional: + return "" + default = info.default + if not default: + default = "None" + s += fieldTemplate % (self.makeMemberName(member.identifier.name), default) + return functionTemplate % CGIndenter(CGGeneric(s), 12).define() + + def hasRequiredFields(self, dictionary): + if dictionary.parent: + if self.hasRequiredFields(dictionary.parent): + return True + for member in dictionary.members: + if not member.optional: + return True + return False + @staticmethod def makeMemberName(name): # Can't use Rust keywords as member names. -- cgit v1.2.3 From f2ee941da2f56b22d2258057a83998306e862350 Mon Sep 17 00:00:00 2001 From: Gregory Terzian Date: Sun, 1 Jul 2018 20:30:05 +0800 Subject: Introduce DOMTracker, cancel eventsource fetch when aborting document load --- components/script/dom/bindings/codegen/Bindings.conf | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf index 2f0b8e7b66b..b97d199147b 100644 --- a/components/script/dom/bindings/codegen/Bindings.conf +++ b/components/script/dom/bindings/codegen/Bindings.conf @@ -26,6 +26,10 @@ DOMInterfaces = { 'weakReferenceable': True, }, +'EventSource': { + 'weakReferenceable': True, +}, + #FIXME(jdm): This should be 'register': False, but then we don't generate enum types 'TestBinding': {}, -- cgit v1.2.3 From 74c1e00d8163f255bb4141ff3549bbdedd7ea766 Mon Sep 17 00:00:00 2001 From: Alan Jeffrey Date: Fri, 1 Jun 2018 17:24:25 -0500 Subject: Upgraded to SM 60 --- .../script/dom/bindings/codegen/CodegenRust.py | 86 +++++++++++++--------- 1 file changed, 52 insertions(+), 34 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 6015a4b126a..449fda3b7ea 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1775,7 +1775,7 @@ class AttrDefiner(PropertyDefiner): if len(array) == 0: return "" - flags = "JSPROP_ENUMERATE | JSPROP_SHARED" + flags = "JSPROP_ENUMERATE" if self.unforgeable: flags += " | JSPROP_PERMANENT" @@ -1822,15 +1822,18 @@ class AttrDefiner(PropertyDefiner): ' JSPropertySpec {\n' ' name: %s as *const u8 as *const libc::c_char,\n' ' flags: (%s) as u8,\n' - ' getter: %s,\n' - ' setter: %s\n' - ' }', - ' JSPropertySpec {\n' - ' name: 0 as *const libc::c_char,\n' - ' flags: 0,\n' - ' getter: JSNativeWrapper { op: None, info: 0 as *const JSJitInfo },\n' - ' setter: JSNativeWrapper { op: None, info: 0 as *const JSJitInfo }\n' + ' __bindgen_anon_1: JSPropertySpec__bindgen_ty_1 {\n' + ' accessors: JSPropertySpec__bindgen_ty_1__bindgen_ty_1 {\n' + ' getter: JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_1 {\n' + ' native: %s,\n' + ' },\n' + ' setter: JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_2 {\n' + ' native: %s,\n' + ' }\n' + ' }\n' + ' }\n' ' }', + ' JSPropertySpec::ZERO', 'JSPropertySpec', PropertyDefiner.getControllingCondition, specData) @@ -2124,7 +2127,7 @@ class CGDOMJSClass(CGThing): "domClass": DOMClass(self.descriptor), "enumerateHook": "None", "finalizeHook": FINALIZE_HOOK_NAME, - "flags": "0", + "flags": "JSCLASS_FOREGROUND_FINALIZE", "name": str_to_const_array(self.descriptor.interface.identifier.name), "resolveHook": "None", "slots": "1", @@ -2133,7 +2136,7 @@ class CGDOMJSClass(CGThing): if self.descriptor.isGlobal(): assert not self.descriptor.weakReferenceable args["enumerateHook"] = "Some(enumerate_global)" - args["flags"] = "JSCLASS_IS_GLOBAL | JSCLASS_DOM_GLOBAL" + args["flags"] = "JSCLASS_IS_GLOBAL | JSCLASS_DOM_GLOBAL | JSCLASS_FOREGROUND_FINALIZE" args["slots"] = "JSCLASS_GLOBAL_SLOT_COUNT + 1" args["resolveHook"] = "Some(resolve_global)" args["traceHook"] = "js::jsapi::JS_GlobalObjectTraceHook" @@ -2143,9 +2146,8 @@ class CGDOMJSClass(CGThing): static CLASS_OPS: js::jsapi::JSClassOps = js::jsapi::JSClassOps { addProperty: None, delProperty: None, - getProperty: None, - setProperty: None, enumerate: %(enumerateHook)s, + newEnumerate: None, resolve: %(resolveHook)s, mayResolve: None, finalize: Some(%(finalizeHook)s), @@ -2583,10 +2585,11 @@ def CreateBindingJSObject(descriptor, parent=None): let handler = RegisterBindings::PROXY_HANDLERS[PrototypeList::Proxies::%s as usize]; rooted!(in(cx) let private = PrivateValue(raw as *const libc::c_void)); let obj = NewProxyObject(cx, handler, - private.handle(), + Handle::from_raw(UndefinedHandleValue), proto.get(), %s.get(), ptr::null_mut(), ptr::null_mut()); assert!(!obj.is_null()); +SetProxyReservedSlot(obj, 0, &private.get()); rooted!(in(cx) let obj = obj);\ """ % (descriptor.name, parent) else: @@ -2594,11 +2597,13 @@ rooted!(in(cx) let obj = obj);\ " cx, &Class.base as *const JSClass, proto.handle()));\n" "assert!(!obj.is_null());\n" "\n" - "JS_SetReservedSlot(obj.get(), DOM_OBJECT_SLOT,\n" - " PrivateValue(raw as *const libc::c_void));") + "let val = PrivateValue(raw as *const libc::c_void);\n" + "\n" + "JS_SetReservedSlot(obj.get(), DOM_OBJECT_SLOT, &val);") if descriptor.weakReferenceable: create += """ -JS_SetReservedSlot(obj.get(), DOM_WEAK_SLOT, PrivateValue(ptr::null()));""" +let val = PrivateValue(ptr::null()); +JS_SetReservedSlot(obj.get(), DOM_WEAK_SLOT, &val);""" return create @@ -2652,9 +2657,10 @@ ensure_expando_object(cx, obj.handle().into(), expando.handle_mut()); else: copyFunc = "JS_InitializePropertiesFromCompatibleNativeObject" copyCode += """\ +let mut slot = UndefinedValue(); +JS_GetReservedSlot(proto.get(), DOM_PROTO_UNFORGEABLE_HOLDER_SLOT, &mut slot); rooted!(in(cx) let mut unforgeable_holder = ptr::null_mut::()); -unforgeable_holder.handle_mut().set( - JS_GetReservedSlot(proto.get(), DOM_PROTO_UNFORGEABLE_HOLDER_SLOT).to_object()); +unforgeable_holder.handle_mut().set(slot.to_object()); assert!(%(copyFunc)s(cx, %(obj)s.handle(), unforgeable_holder.handle())); """ % {'copyFunc': copyFunc, 'obj': obj} @@ -3013,7 +3019,7 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); CGGeneric(fill( """ assert!(${defineFn}(cx, prototype.handle(), ${prop}, aliasedVal.handle(), - JSPROP_ENUMERATE, None, None)); + JSPROP_ENUMERATE as u32)); """, defineFn=defineFn, prop=prop)) @@ -3078,8 +3084,8 @@ assert!(!unforgeable_holder.is_null()); """ % {'holderClass': holderClass, 'holderProto': holderProto})) code.append(InitUnforgeablePropertiesOnHolder(self.descriptor, self.properties)) code.append(CGGeneric("""\ -JS_SetReservedSlot(prototype.get(), DOM_PROTO_UNFORGEABLE_HOLDER_SLOT, - ObjectValue(unforgeable_holder.get()))""")) +let val = ObjectValue(unforgeable_holder.get()); +JS_SetReservedSlot(prototype.get(), DOM_PROTO_UNFORGEABLE_HOLDER_SLOT, &val)""")) return CGList(code, "\n") @@ -3533,11 +3539,13 @@ class CGAbstractStaticBindingMethod(CGAbstractMethod): self.exposureSet = descriptor.interface.exposureSet def definition_body(self): - preamble = "let global = GlobalScope::from_object(JS_CALLEE(cx, vp).to_object());\n" + preamble = """\ +let args = CallArgs::from_vp(vp, argc); +let global = GlobalScope::from_object(args.callee()); +""" if len(self.exposureSet) == 1: - preamble += """ -let global = DomRoot::downcast::(global).unwrap(); -""" % list(self.exposureSet)[0] + preamble += ("let global = DomRoot::downcast::(global).unwrap();\n" % + list(self.exposureSet)[0]) return CGList([CGGeneric(preamble), self.generate_code()]) def generate_code(self): @@ -3741,7 +3749,7 @@ class CGSpecializedReplaceableSetter(CGSpecializedSetter): assert all(ord(c) < 128 for c in name) return CGGeneric("""\ JS_DefineProperty(cx, obj, %s as *const u8 as *const libc::c_char, - HandleValue::from_raw(args.get(0)), JSPROP_ENUMERATE, None, None)""" % name) + HandleValue::from_raw(args.get(0)), JSPROP_ENUMERATE as u32)""" % name) class CGMemberJITInfo(CGThing): @@ -4959,7 +4967,9 @@ class CGProxyUnwrap(CGAbstractMethod): obj = js::UnwrapObject(obj); }*/ //MOZ_ASSERT(IsProxy(obj)); -let box_ = GetProxyPrivate(obj.get()).to_private() as *const %s; + let mut slot = UndefinedValue(); + GetProxyReservedSlot(obj.get(), 0, &mut slot); + let box_ = slot.to_private() as *const %s; return box_;""" % self.descriptor.concreteType) @@ -4985,7 +4995,7 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod): attrs += " | JSPROP_READONLY" # FIXME(#11868) Should assign to desc.value, desc.get() is a copy. fillDescriptor = ("desc.get().value = result_root.get();\n" - "fill_property_descriptor(MutableHandle::from_raw(desc), proxy.get(), %s);\n" + "fill_property_descriptor(MutableHandle::from_raw(desc), proxy.get(), (%s) as u32);\n" "return true;" % attrs) templateValues = { 'jsvalRef': 'result_root.handle_mut()', @@ -5011,7 +5021,7 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod): attrs = "0" # FIXME(#11868) Should assign to desc.value, desc.get() is a copy. fillDescriptor = ("desc.get().value = result_root.get();\n" - "fill_property_descriptor(MutableHandle::from_raw(desc), proxy.get(), %s);\n" + "fill_property_descriptor(MutableHandle::from_raw(desc), proxy.get(), (%s) as u32);\n" "return true;" % attrs) templateValues = { 'jsvalRef': 'result_root.handle_mut()', @@ -5425,7 +5435,9 @@ finalize_global(obj); """ elif descriptor.weakReferenceable: release += """\ -let weak_box_ptr = JS_GetReservedSlot(obj, DOM_WEAK_SLOT).to_private() as *mut WeakBox<%s>; +let mut slot = UndefinedValue(); +JS_GetReservedSlot(obj, DOM_WEAK_SLOT, &mut slot); +let weak_box_ptr = slot.to_private() as *mut WeakBox<%s>; if !weak_box_ptr.is_null() { let count = { let weak_box = &*weak_box_ptr; @@ -5736,6 +5748,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::jsapi::INTERNED_STRING_TO_JSID', 'js::jsapi::IsCallable', 'js::jsapi::JSAutoCompartment', + 'js::jsapi::JSCLASS_FOREGROUND_FINALIZE', 'js::jsapi::JSCLASS_RESERVED_SLOTS_SHIFT', 'js::jsapi::JSClass', 'js::jsapi::JSContext', @@ -5757,8 +5770,11 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::jsapi::JSPROP_ENUMERATE', 'js::jsapi::JSPROP_PERMANENT', 'js::jsapi::JSPROP_READONLY', - 'js::jsapi::JSPROP_SHARED', 'js::jsapi::JSPropertySpec', + 'js::jsapi::JSPropertySpec__bindgen_ty_1', + 'js::jsapi::JSPropertySpec__bindgen_ty_1__bindgen_ty_1', + 'js::jsapi::JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_1', + 'js::jsapi::JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_2', 'js::jsapi::JSString', 'js::jsapi::JSTracer', 'js::jsapi::JSType', @@ -5778,7 +5794,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::rust::wrappers::JS_GetProperty', 'js::jsapi::JS_GetPropertyById', 'js::jsapi::JS_GetPropertyDescriptorById', - 'js::jsapi::JS_GetReservedSlot', + 'js::glue::JS_GetReservedSlot', 'js::jsapi::JS_HasProperty', 'js::jsapi::JS_HasPropertyById', 'js::rust::wrappers::JS_InitializePropertiesFromCompatibleNativeObject', @@ -5813,12 +5829,14 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::jsval::ObjectOrNullValue', 'js::jsval::PrivateValue', 'js::jsval::UndefinedValue', + 'js::jsapi::UndefinedHandleValue', 'js::glue::AppendToAutoIdVector', 'js::glue::CallJitGetterOp', 'js::glue::CallJitMethodOp', 'js::glue::CallJitSetterOp', 'js::glue::CreateProxyHandler', - 'js::glue::GetProxyPrivate', + 'js::glue::GetProxyReservedSlot', + 'js::glue::SetProxyReservedSlot', 'js::rust::wrappers::NewProxyObject', 'js::glue::ProxyTraps', 'js::glue::RUST_JSID_IS_INT', -- cgit v1.2.3 From 900a19058e5f282fdb914ac16801d11f4a2c0159 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Mon, 27 Aug 2018 12:08:17 +0200 Subject: Support unions of objects in overloads Part of #20513, implementing the parts useful for WebGL. --- .../script/dom/bindings/codegen/CodegenRust.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 449fda3b7ea..6da269d61cb 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -344,12 +344,17 @@ class CGMethodCall(CGThing): distinguishingIndex = method.distinguishingIndexForArgCount(argCount) - # We can't handle unions at the distinguishing index. + # We can't handle unions of non-object values at the distinguishing index. for (returnType, args) in possibleSignatures: - if args[distinguishingIndex].type.isUnion(): - raise TypeError("No support for unions as distinguishing " - "arguments yet: %s", - args[distinguishingIndex].location) + type = args[distinguishingIndex].type + if type.isUnion(): + if type.nullable(): + type = type.inner + for type in type.flatMemberTypes: + if not (type.isObject() or type.isNonCallbackInterface()): + raise TypeError("No support for unions with non-object variants " + "as distinguishing arguments yet: %s", + args[distinguishingIndex].location) # Convert all our arguments up to the distinguishing index. # Doesn't matter which of the possible signatures we use, since @@ -388,6 +393,7 @@ class CGMethodCall(CGThing): interfacesSigs = [ s for s in possibleSignatures if (s[1][distinguishingIndex].type.isObject() or + s[1][distinguishingIndex].type.isUnion() or s[1][distinguishingIndex].type.isNonCallbackInterface())] # There might be more than one of these; we need to check # which ones we unwrap to. @@ -2366,7 +2372,6 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config): 'dom::bindings::conversions::ConversionBehavior', 'dom::bindings::conversions::StringificationBehavior', 'dom::bindings::conversions::root_from_handlevalue', - 'dom::bindings::error::throw_not_in_union', 'std::ptr::NonNull', 'dom::bindings::mozmap::MozMap', 'dom::bindings::root::DomRoot', @@ -4450,8 +4455,8 @@ class CGUnionConversionStruct(CGThing): other.append(booleanConversion[0]) conversions.append(CGList(other, "\n\n")) conversions.append(CGGeneric( - "throw_not_in_union(cx, \"%s\");\n" - "Err(())" % ", ".join(names))) + "Ok(ConversionResult::Failure(\"argument could not be converted to any of: %s\".into()))" % ", ".join(names) + )) method = CGWrapper( CGIndenter(CGList(conversions, "\n\n")), pre="unsafe fn from_jsval(cx: *mut JSContext,\n" -- cgit v1.2.3 From baa94702e4a19ff1c1f8c448ae3feb83445b4e01 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Tue, 4 Sep 2018 13:57:10 +0200 Subject: Properly set desc.obj in CodegenRust.py (fixes #11868) --- components/script/dom/bindings/codegen/CodegenRust.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 6da269d61cb..39409e7deaa 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -4982,7 +4982,7 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod): def __init__(self, descriptor): args = [Argument('*mut JSContext', 'cx'), Argument('RawHandleObject', 'proxy'), Argument('RawHandleId', 'id'), - Argument('RawMutableHandle', 'desc')] + Argument('RawMutableHandle', 'mut desc')] CGAbstractExternMethod.__init__(self, descriptor, "getOwnPropertyDescriptor", "bool", args) self.descriptor = descriptor @@ -5055,7 +5055,6 @@ if %s { else: namedGet = "" - # FIXME(#11868) Should assign to desc.obj, desc.get() is a copy. return get + """\ rooted!(in(cx) let mut expando = ptr::null_mut::()); get_expando_object(proxy, expando.handle_mut()); @@ -5068,7 +5067,7 @@ if !expando.is_null() { } if !desc.obj.is_null() { // Pretend the property lives on the wrapper. - desc.get().obj = proxy.get(); + desc.obj = proxy.get(); return true; } } -- cgit v1.2.3 From 2b574bbdf8f1306c4b31060fec54fee919cc3a18 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Fri, 14 Sep 2018 11:15:35 +0200 Subject: Update the WebIDL parser --- .../script/dom/bindings/codegen/parser/WebIDL.py | 153 +++++++++------- .../dom/bindings/codegen/parser/abstract.patch | 2 +- .../dom/bindings/codegen/parser/inline.patch | 2 +- .../codegen/parser/tests/test_cereactions.py | 14 -- .../codegen/parser/tests/test_interface.py | 29 ---- .../bindings/codegen/parser/tests/test_toJSON.py | 192 +++++++++++++++++++++ 6 files changed, 284 insertions(+), 108 deletions(-) create mode 100644 components/script/dom/bindings/codegen/parser/tests/test_toJSON.py (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index b2daa1bce20..b56a1765d57 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.py @@ -684,7 +684,7 @@ def globalNameSetToExposureSet(globalScope, nameSet, exposureSet): class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): def __init__(self, location, parentScope, name, parent, members, - isKnownNonPartial): + isKnownNonPartial, toStringTag): assert isinstance(parentScope, IDLScope) assert isinstance(name, IDLUnresolvedIdentifier) assert isKnownNonPartial or not parent @@ -722,6 +722,8 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): # interface we're iterating for in order to get its nativeType. self.iterableInterface = None + self.toStringTag = toStringTag + IDLObjectWithScope.__init__(self, location, parentScope, name) IDLExposureMixins.__init__(self, location) @@ -1017,10 +1019,9 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): [self.location]) for m in self.members: - if ((m.isMethod() and m.isJsonifier()) or - m.identifier.name == "toJSON"): + if m.identifier.name == "toJSON": raise WebIDLError("Unforgeable interface %s has a " - "jsonifier so we won't be able to add " + "toJSON so we won't be able to add " "one ourselves" % self.identifier.name, [self.location, m.location]) @@ -1044,6 +1045,12 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): (member.getExtendedAttribute("StoreInSlot") or member.getExtendedAttribute("Cached"))) or member.isMaplikeOrSetlike()): + if self.isJSImplemented() and not member.isMaplikeOrSetlike(): + raise WebIDLError("Interface %s is JS-implemented and we " + "don't support [Cached] or [StoreInSlot] " + "on JS-implemented interfaces" % + self.identifier.name, + [self.location, member.location]) if member.slotIndices is None: member.slotIndices = dict() member.slotIndices[self.identifier.name] = self.totalMembersInSlots @@ -1115,15 +1122,12 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): memberType = "deleters" elif member.isStringifier(): memberType = "stringifiers" - elif member.isJsonifier(): - memberType = "jsonifiers" elif member.isLegacycaller(): memberType = "legacycallers" else: continue - if (memberType != "stringifiers" and memberType != "legacycallers" and - memberType != "jsonifiers"): + if (memberType != "stringifiers" and memberType != "legacycallers"): if member.isNamed(): memberType = "named " + memberType else: @@ -1573,9 +1577,12 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): class IDLInterface(IDLInterfaceOrNamespace): def __init__(self, location, parentScope, name, parent, members, - isKnownNonPartial): + isKnownNonPartial, classNameOverride=None, + toStringTag=None): IDLInterfaceOrNamespace.__init__(self, location, parentScope, name, - parent, members, isKnownNonPartial) + parent, members, isKnownNonPartial, + toStringTag) + self.classNameOverride = classNameOverride def __str__(self): return "Interface '%s'" % self.identifier.name @@ -1583,6 +1590,11 @@ class IDLInterface(IDLInterfaceOrNamespace): def isInterface(self): return True + def getClassName(self): + if self.classNameOverride: + return self.classNameOverride + return self.identifier.name + def addExtendedAttributes(self, attrs): for attr in attrs: identifier = attr.identifier() @@ -1677,14 +1689,6 @@ class IDLInterface(IDLInterfaceOrNamespace): elif newMethod not in self.namedConstructors: raise WebIDLError("NamedConstructor conflicts with a NamedConstructor of a different interface", [method.location, newMethod.location]) - elif (identifier == "ArrayClass"): - if not attr.noArguments(): - raise WebIDLError("[ArrayClass] must take no arguments", - [attr.location]) - if self.parent: - raise WebIDLError("[ArrayClass] must not be specified on " - "an interface with inherited interfaces", - [attr.location, self.location]) elif (identifier == "ExceptionClass"): if not attr.noArguments(): raise WebIDLError("[ExceptionClass] must take no arguments", @@ -1738,6 +1742,7 @@ class IDLInterface(IDLInterfaceOrNamespace): identifier == "ProbablyShortLivingWrapper" or identifier == "LegacyUnenumerableNamedProperties" or identifier == "RunConstructorInCallerCompartment" or + identifier == "WantsEventListenerHooks" or identifier == "NonOrdinaryGetPrototypeOf" or identifier == "Abstract" or identifier == "Inline"): @@ -1769,7 +1774,8 @@ class IDLInterface(IDLInterfaceOrNamespace): class IDLNamespace(IDLInterfaceOrNamespace): def __init__(self, location, parentScope, name, members, isKnownNonPartial): IDLInterfaceOrNamespace.__init__(self, location, parentScope, name, - None, members, isKnownNonPartial) + None, members, isKnownNonPartial, + toStringTag=None) def __str__(self): return "Namespace '%s'" % self.identifier.name @@ -2152,7 +2158,7 @@ class IDLType(IDLObject): # Should only call this on float types assert self.isFloat() - def isSerializable(self): + def isJSONType(self): return False def tag(self): @@ -2350,8 +2356,8 @@ class IDLNullableType(IDLParametrizedType): def isUnion(self): return self.inner.isUnion() - def isSerializable(self): - return self.inner.isSerializable() + def isJSONType(self): + return self.inner.isJSONType() def tag(self): return self.inner.tag() @@ -2430,8 +2436,8 @@ class IDLSequenceType(IDLParametrizedType): def isEnum(self): return False - def isSerializable(self): - return self.inner.isSerializable() + def isJSONType(self): + return self.inner.isJSONType() def tag(self): return IDLType.Tags.sequence @@ -2476,6 +2482,9 @@ class IDLRecordType(IDLParametrizedType): def isRecord(self): return True + def isJSONType(self): + return self.inner.isJSONType() + def tag(self): return IDLType.Tags.record @@ -2525,8 +2534,8 @@ class IDLUnionType(IDLType): def isUnion(self): return True - def isSerializable(self): - return all(m.isSerializable() for m in self.memberTypes) + def isJSONType(self): + return all(m.isJSONType() for m in self.memberTypes) def includesRestrictedFloat(self): return any(t.includesRestrictedFloat() for t in self.memberTypes) @@ -2676,6 +2685,9 @@ class IDLTypedefType(IDLType): def isVoid(self): return self.inner.isVoid() + def isJSONType(self): + return self.inner.isJSONType() + def isSequence(self): return self.inner.isSequence() @@ -2817,15 +2829,25 @@ class IDLWrapperType(IDLType): def isEnum(self): return isinstance(self.inner, IDLEnum) - def isSerializable(self): + def isJSONType(self): if self.isInterface(): if self.inner.isExternal(): return False - return any(m.isMethod() and m.isJsonifier() for m in self.inner.members) + iface = self.inner + while iface: + if any(m.isMethod() and m.isToJSON() for m in iface.members): + return True + iface = iface.parent + return False elif self.isEnum(): return True elif self.isDictionary(): - return all(m.type.isSerializable() for m in self.inner.members) + dictionary = self.inner + while dictionary: + if not all(m.type.isJSONType() for m in dictionary.members): + return False + dictionary = dictionary.parent + return True else: raise WebIDLError("IDLWrapperType wraps type %s that we don't know if " "is serializable" % type(self.inner), [self.location]) @@ -3111,8 +3133,8 @@ class IDLBuiltinType(IDLType): return (self._typeTag == IDLBuiltinType.Types.unrestricted_float or self._typeTag == IDLBuiltinType.Types.unrestricted_double) - def isSerializable(self): - return self.isPrimitive() or self.isString() or self.isDate() + def isJSONType(self): + return self.isPrimitive() or self.isString() or self.isObject() def includesRestrictedFloat(self): return self.isFloat() and not self.isUnrestricted() @@ -4665,7 +4687,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope): def __init__(self, location, identifier, returnType, arguments, static=False, getter=False, setter=False, deleter=False, specialType=NamedOrIndexed.Neither, - legacycaller=False, stringifier=False, jsonifier=False, + legacycaller=False, stringifier=False, maplikeOrSetlikeOrIterable=None, htmlConstructor=False): # REVIEW: specialType is NamedOrIndexed -- wow, this is messed up. IDLInterfaceMember.__init__(self, location, identifier, @@ -4690,8 +4712,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope): self._legacycaller = legacycaller assert isinstance(stringifier, bool) self._stringifier = stringifier - assert isinstance(jsonifier, bool) - self._jsonifier = jsonifier assert maplikeOrSetlikeOrIterable is None or isinstance(maplikeOrSetlikeOrIterable, IDLMaplikeOrSetlikeOrIterableBase) self.maplikeOrSetlikeOrIterable = maplikeOrSetlikeOrIterable assert isinstance(htmlConstructor, bool) @@ -4739,12 +4759,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope): assert len(overload.arguments) == 0 assert overload.returnType == BuiltinTypes[IDLBuiltinType.Types.domstring] - if self._jsonifier: - assert len(self._overloads) == 1 - overload = self._overloads[0] - assert len(overload.arguments) == 0 - assert overload.returnType == BuiltinTypes[IDLBuiltinType.Types.object] - def isStatic(self): return self._static @@ -4776,8 +4790,11 @@ class IDLMethod(IDLInterfaceMember, IDLScope): def isStringifier(self): return self._stringifier - def isJsonifier(self): - return self._jsonifier + def isToJSON(self): + return self.identifier.name == "toJSON" + + def isDefaultToJSON(self): + return self.isToJSON() and self.getExtendedAttribute("Default") def isMaplikeOrSetlikeOrIterableMethod(self): """ @@ -4791,8 +4808,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope): self.isSetter() or self.isDeleter() or self.isLegacycaller() or - self.isStringifier() or - self.isJsonifier()) + self.isStringifier()) def isHTMLConstructor(self): return self._htmlConstructor @@ -4848,8 +4864,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope): assert not method.isDeleter() assert not self.isStringifier() assert not method.isStringifier() - assert not self.isJsonifier() - assert not method.isJsonifier() assert not self.isHTMLConstructor() assert not method.isHTMLConstructor() @@ -4972,6 +4986,19 @@ class IDLMethod(IDLInterfaceMember, IDLScope): " methods on JS-implemented classes only.", [self.location]) + # Ensure that toJSON methods satisfy the spec constraints on them. + if self.identifier.name == "toJSON": + if len(self.signatures()) != 1: + raise WebIDLError("toJSON method has multiple overloads", + [self._overloads[0].location, + self._overloads[1].location]) + if len(self.signatures()[0][1]) != 0: + raise WebIDLError("toJSON method has arguments", + [self.location]) + if not self.signatures()[0][0].isJSONType(): + raise WebIDLError("toJSON method has non-JSON return type", + [self.location]) + def overloadsForArgCount(self, argc): return [overload for overload in self._overloads if len(overload.arguments) == argc or @@ -5105,6 +5132,19 @@ class IDLMethod(IDLInterfaceMember, IDLScope): raise WebIDLError("[CEReactions] is only allowed on operation, " "attribute, setter, and deleter", [attr.location, self.location]) + elif identifier == "Default": + if not attr.noArguments(): + raise WebIDLError("[Default] must take no arguments", + [attr.location]) + + if not self.isToJSON(): + raise WebIDLError("[Default] is only allowed on toJSON operations", + [attr.location, self.location]) + + 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]); elif (identifier == "Throws" or identifier == "CanOOM" or identifier == "NewObject" or @@ -5292,7 +5332,6 @@ class Tokenizer(object): "false": "FALSE", "serializer": "SERIALIZER", "stringifier": "STRINGIFIER", - "jsonifier": "JSONIFIER", "unrestricted": "UNRESTRICTED", "attribute": "ATTRIBUTE", "readonly": "READONLY", @@ -6123,19 +6162,6 @@ class Parser(Tokenizer): stringifier=True) p[0] = method - def p_Jsonifier(self, p): - """ - Operation : JSONIFIER SEMICOLON - """ - identifier = IDLUnresolvedIdentifier(BuiltinLocation(""), - "__jsonifier", allowDoubleUnderscore=True) - method = IDLMethod(self.getLocation(p, 1), - identifier, - returnType=BuiltinTypes[IDLBuiltinType.Types.object], - arguments=[], - jsonifier=True) - p[0] = method - def p_QualifierStatic(self, p): """ Qualifier : STATIC @@ -6289,7 +6315,6 @@ class Parser(Tokenizer): | SETTER | STATIC | STRINGIFIER - | JSONIFIER | TYPEDEF | UNRESTRICTED | NAMESPACE @@ -6441,7 +6466,6 @@ class Parser(Tokenizer): | SHORT | STATIC | STRINGIFIER - | JSONIFIER | TRUE | TYPEDEF | UNSIGNED @@ -6958,9 +6982,12 @@ class Parser(Tokenizer): nextMethod.addExtendedAttributes([simpleExtendedAttr("Throws")]) itr_ident = IDLUnresolvedIdentifier(iface.location, iface.identifier.name + "Iterator") + toStringTag = iface.identifier.name + " Iterator" itr_iface = IDLInterface(iface.location, self.globalScope(), itr_ident, None, [nextMethod], - isKnownNonPartial=True) + isKnownNonPartial=True, + classNameOverride=toStringTag, + toStringTag=toStringTag) 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 diff --git a/components/script/dom/bindings/codegen/parser/abstract.patch b/components/script/dom/bindings/codegen/parser/abstract.patch index e43d12eb988..cf4c89b84d0 100644 --- a/components/script/dom/bindings/codegen/parser/abstract.patch +++ b/components/script/dom/bindings/codegen/parser/abstract.patch @@ -1,9 +1,9 @@ --- WebIDL.py +++ WebIDL.py @@ -1744,7 +1744,8 @@ - identifier == "ProbablyShortLivingWrapper" or identifier == "LegacyUnenumerableNamedProperties" or identifier == "RunConstructorInCallerCompartment" or + identifier == "WantsEventListenerHooks" or - identifier == "NonOrdinaryGetPrototypeOf"): + identifier == "NonOrdinaryGetPrototypeOf" or + identifier == "Abstract"): diff --git a/components/script/dom/bindings/codegen/parser/inline.patch b/components/script/dom/bindings/codegen/parser/inline.patch index 5d1056d2b58..028fb9345d0 100644 --- a/components/script/dom/bindings/codegen/parser/inline.patch +++ b/components/script/dom/bindings/codegen/parser/inline.patch @@ -9,4 +9,4 @@ + identifier == "Inline"): # 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/tests/test_cereactions.py b/components/script/dom/bindings/codegen/parser/tests/test_cereactions.py index a1e5e78630f..dba16f53302 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_cereactions.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_cereactions.py @@ -131,17 +131,3 @@ def WebIDLTest(parser, harness): harness.ok(threw, "Should have thrown for [CEReactions] used on a stringifier") - parser = parser.reset() - threw = False - try: - parser.parse(""" - interface Foo { - [CEReactions] jsonifier; - }; - """) - - results = parser.finish() - except: - threw = True - - harness.ok(threw, "Should have thrown for [CEReactions] used on a jsonifier") 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 e8ed67b54b3..a23243abe61 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_interface.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_interface.py @@ -374,32 +374,3 @@ def WebIDLTest(parser, harness): threw = True harness.ok(threw, "Should not allow unknown extended attributes on interfaces") - - parser = parser.reset() - threw = False - try: - parser.parse(""" - interface B {}; - [ArrayClass] - interface A : B { - }; - """) - results = parser.finish() - except: - threw = True - harness.ok(threw, - "Should not allow [ArrayClass] on interfaces with parents") - - parser = parser.reset() - threw = False - try: - parser.parse(""" - [ArrayClass] - interface A { - }; - """) - results = parser.finish() - except: - threw = True - harness.ok(not threw, - "Should allow [ArrayClass] on interfaces without parents") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_toJSON.py b/components/script/dom/bindings/codegen/parser/tests/test_toJSON.py new file mode 100644 index 00000000000..b8b4f796ccb --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_toJSON.py @@ -0,0 +1,192 @@ +def WebIDLTest(parser, harness): + threw = False + try: + parser.parse( + """ + interface Test { + object toJSON(); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(not threw, "Should allow a toJSON method.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface Test { + object toJSON(object arg); + object toJSON(long arg); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "Should not allow overloads of a toJSON method.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface Test { + object toJSON(object arg); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "Should not allow a toJSON method with arguments.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface Test { + long toJSON(); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(not threw, "Should allow a toJSON method with 'long' as return type.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface Test { + [Default] object toJSON(); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(not threw, "Should allow a default toJSON method with 'object' as return type.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface Test { + [Default] long toJSON(); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "Should not allow a default toJSON method with non-'object' as return type.") + + JsonTypes = [ "byte", "octet", "short", "unsigned short", "long", "unsigned long", "long long", + "unsigned long long", "float", "unrestricted float", "double", "unrestricted double", "boolean", + "DOMString", "ByteString", "USVString", "Enum", "InterfaceWithToJSON", "object" ] + + nonJsonTypes = [ "InterfaceWithoutToJSON", "any", "Int8Array", "Int16Array", "Int32Array","Uint8Array", + "Uint16Array", "Uint32Array", "Uint8ClampedArray", "Float32Array", "Float64Array", "ArrayBuffer" ] + + def doTest(testIDL, shouldThrow, description): + p = parser.reset() + threw = False + try: + p.parse(testIDL + + """ + enum Enum { "a", "b", "c" }; + interface InterfaceWithToJSON { long toJSON(); }; + interface InterfaceWithoutToJSON {}; + """); + p.finish(); + except Exception as x: + threw = True + harness.ok(x.message == "toJSON method has non-JSON return type", x) + harness.check(threw, shouldThrow, description) + + + for type in JsonTypes: + doTest("interface Test { %s toJSON(); };" % type, False, + "%s should be a JSON type" % type) + + doTest("interface Test { sequence<%s> toJSON(); };" % type, False, + "sequence<%s> should be a JSON type" % type) + + doTest("dictionary Foo { %s foo; }; " + "interface Test { Foo toJSON(); }; " % type, False, + "dictionary containing only JSON type (%s) should be a JSON type" % type) + + doTest("dictionary Foo { %s foo; }; dictionary Bar : Foo { }; " + "interface Test { Bar toJSON(); }; " % type, False, + "dictionary whose ancestors only contain JSON types should be a JSON type") + + doTest("dictionary Foo { any foo; }; dictionary Bar : Foo { %s bar; };" + "interface Test { Bar toJSON(); };" % type, True, + "dictionary whose ancestors contain non-JSON types should not be a JSON type") + + doTest("interface Test { record toJSON(); };" % type, False, + "record should be a JSON type" % type) + + doTest("interface Test { record toJSON(); };" % type, False, + "record should be a JSON type" % type) + + doTest("interface Test { record toJSON(); };" % type, False, + "record should be a JSON type" % type) + + otherUnionType = "Foo" if type != "object" else "long" + doTest("interface Foo { object toJSON(); };" + "interface Test { (%s or %s) toJSON(); };" % (otherUnionType, type), False, + "union containing only JSON types (%s or %s) should be a JSON type" %(otherUnionType, type)) + + doTest("interface test { %s? toJSON(); };" % type, False, + "Nullable type (%s) should be a JSON type" % type) + + doTest("interface Foo : InterfaceWithoutToJSON { %s toJSON(); };" + "interface Test { Foo toJSON(); };" % type, False, + "interface with toJSON should be a JSON type") + + doTest("interface Foo : InterfaceWithToJSON { };" + "interface Test { Foo toJSON(); };", False, + "inherited interface with toJSON should be a JSON type") + + for type in nonJsonTypes: + doTest("interface Test { %s toJSON(); };" % type, True, + "%s should not be a JSON type" % type) + + doTest("interface Test { sequence<%s> toJSON(); };" % type, True, + "sequence<%s> should not be a JSON type" % type) + + doTest("dictionary Foo { %s foo; }; " + "interface Test { Foo toJSON(); }; " % type, True, + "Dictionary containing a non-JSON type (%s) should not be a JSON type" % type) + + doTest("dictionary Foo { %s foo; }; dictionary Bar : Foo { }; " + "interface Test { Bar toJSON(); }; " % type, True, + "dictionary whose ancestors only contain non-JSON types should not be a JSON type") + + doTest("interface Test { record toJSON(); };" % type, True, + "record should not be a JSON type" % type) + + doTest("interface Test { record toJSON(); };" % type, True, + "record should not be a JSON type" % type) + + doTest("interface Test { record toJSON(); };" % type, True, + "record should not be a JSON type" % type) + + if type != "any": + doTest("interface Foo { object toJSON(); }; " + "interface Test { (Foo or %s) toJSON(); };" % type, True, + "union containing a non-JSON type (%s) should not be a JSON type" % type) + + doTest("interface test { %s? toJSON(); };" % type, True, + "Nullable type (%s) should not be a JSON type" % type) + + doTest("dictionary Foo { long foo; any bar; };" + "interface Test { Foo toJSON(); };", True, + "dictionary containing a non-JSON type should not be a JSON type") + + doTest("interface Foo : InterfaceWithoutToJSON { }; " + "interface Test { Foo toJSON(); };", True, + "interface without toJSON should not be a JSON type") -- cgit v1.2.3 From a846ed1654fb16ca8505f5290613bdc8bd17bb26 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 5 Oct 2018 14:25:53 +0200 Subject: Upgrade to rustc 1.31.0-nightly (8c4ad4e9e 2018-10-04) CC https://github.com/rust-lang/rust/issues/54846 --- components/script/dom/bindings/codegen/CodegenRust.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 39409e7deaa..fd2df0799c6 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2278,7 +2278,14 @@ static NAMESPACE_OBJECT_CLASS: NamespaceObjectClass = unsafe { return """\ static INTERFACE_OBJECT_CLASS: NonCallbackInterfaceObjectClass = NonCallbackInterfaceObjectClass::new( - &%(constructorBehavior)s, + { + // Intermediate `const` because as of nightly-2018-10-05, + // rustc is conservative in promotion to `'static` of the return values of `const fn`s: + // https://github.com/rust-lang/rust/issues/54846 + // https://github.com/rust-lang/rust/pull/53851 + const BEHAVIOR: InterfaceConstructorBehavior = %(constructorBehavior)s; + &BEHAVIOR + }, %(representation)s, PrototypeList::ID::%(id)s, %(depth)s); -- cgit v1.2.3 From 8b2892113693e6d2eddfc29dd49bbf7d54954912 Mon Sep 17 00:00:00 2001 From: CYBAI Date: Mon, 7 May 2018 20:31:29 +0800 Subject: Make expectionCode of Promise have newline character automatically In the `fill` method, it will check if the exception code is empty string or has newline character in the end of string or not. However, we didn't do any change to exceptionCode when type is Promise. Thus, we add the newline character to make it pass the checking in `fill` method. See more detail from the log of IRC: https://mozilla.logbot.info/servo/20180501#c14692647 --- components/script/dom/bindings/codegen/CodegenRust.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index fd2df0799c6..c9271bb03dc 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -6207,7 +6207,7 @@ class CGDictionary(CGThing): descriptorProvider, isMember="Dictionary", defaultValue=member.defaultValue, - exceptionCode="return Err(());")) + exceptionCode="return Err(());\n")) for member in dictionary.members] def define(self): -- cgit v1.2.3 From 99589d2f2ae2c9fc87eaa23dcd2ea1bdf74a45a6 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Thu, 1 Nov 2018 14:54:23 -0700 Subject: Handle default empty sequence values --- .../script/dom/bindings/codegen/CodegenRust.py | 33 ++++++++++++---------- 1 file changed, 18 insertions(+), 15 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index c9271bb03dc..8d0b68003c5 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -17,6 +17,7 @@ import functools from WebIDL import ( BuiltinTypes, IDLBuiltinType, + IDLEmptySequenceValue, IDLInterfaceMember, IDLNullableType, IDLNullValue, @@ -673,17 +674,19 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, ('throw_type_error(cx, \"%s is not callable.\");\n' '%s' % (firstCap(sourceDescription), exceptionCode))) - # A helper function for handling null default values. Checks that the - # default value, if it exists, is null. - def handleDefaultNull(nullValue): + # A helper function for handling default values. + def handleDefault(nullValue): if defaultValue is None: return None - if not isinstance(defaultValue, IDLNullValue): - raise TypeError("Can't handle non-null default value here") + if isinstance(defaultValue, IDLNullValue): + assert type.nullable() or type.isDictionary() + return nullValue + elif isinstance(defaultValue, IDLEmptySequenceValue): + assert type.isSequence() + return "Vec::new()" - assert type.nullable() or type.isDictionary() - return nullValue + raise TypeError("Can't handle non-null or non-empty sequence default value here") # A helper function for wrapping up the template body for # possibly-nullable objecty stuff @@ -726,7 +729,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, " _ => { %s },\n" "}" % (config, indent(failOrPropagate, 8), exceptionCode)) - return handleOptional(templateBody, declType, handleDefaultNull("None")) + return handleOptional(templateBody, declType, handleDefault("None")) if type.isUnion(): declType = CGGeneric(union_native_type(type)) @@ -758,7 +761,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, else: default = None else: - default = handleDefaultNull("None") + default = handleDefault("None") return handleOptional(templateBody, declType, default) @@ -810,7 +813,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, declType = CGGeneric("&Promise") else: declType = CGGeneric("Rc") - return handleOptional(templateBody, declType, handleDefaultNull("None")) + return handleOptional(templateBody, declType, handleDefault("None")) if type.isGeckoInterface(): assert not isEnforceRange and not isClamp @@ -828,7 +831,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, isDefinitelyObject, type, failureCode) - return handleOptional(template, declType, handleDefaultNull("None")) + return handleOptional(template, declType, handleDefault("None")) conversionFunction = "root_from_handlevalue" descriptorType = descriptor.returnType @@ -875,7 +878,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, templateBody = wrapObjectTemplate(templateBody, "None", isDefinitelyObject, type, failureCode) - return handleOptional(templateBody, declType, handleDefaultNull("None")) + return handleOptional(templateBody, declType, handleDefault("None")) if is_typed_array(type): if failureCode is None: @@ -918,7 +921,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, templateBody = wrapObjectTemplate(templateBody, "None", isDefinitelyObject, type, failureCode) - return handleOptional(templateBody, declType, handleDefaultNull("None")) + return handleOptional(templateBody, declType, handleDefault("None")) elif type.isSpiderMonkeyInterface(): raise TypeError("Can't handle SpiderMonkey interface arguments other than typed arrays yet") @@ -1145,7 +1148,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, isDefinitelyObject, type, failureCode) return handleOptional(templateBody, declType, - handleDefaultNull(default)) + handleDefault(default)) if type.isDictionary(): # There are no nullable dictionaries @@ -1167,7 +1170,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, " _ => { %s },\n" "}" % (indent(failOrPropagate, 8), exceptionCode)) - return handleOptional(template, declType, handleDefaultNull(empty)) + return handleOptional(template, declType, handleDefault(empty)) if type.isVoid(): # This one only happens for return values, and its easy: Just -- cgit v1.2.3 From acabd50f037837c2dc75233988690e0184cd511c Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 1 Nov 2018 14:38:55 +0100 Subject: Use 2018-style paths in generated DOM bindings --- .../script/dom/bindings/codegen/Bindings.conf | 2 +- .../script/dom/bindings/codegen/CodegenRust.py | 286 ++++++++++----------- .../script/dom/bindings/codegen/Configuration.py | 12 +- 3 files changed, 150 insertions(+), 150 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf index b97d199147b..cdd41dc3b74 100644 --- a/components/script/dom/bindings/codegen/Bindings.conf +++ b/components/script/dom/bindings/codegen/Bindings.conf @@ -38,7 +38,7 @@ DOMInterfaces = { }, 'WindowProxy' : { - 'path': 'dom::windowproxy::WindowProxy', + 'path': 'crate::dom::windowproxy::WindowProxy', 'register': False, } diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 8d0b68003c5..da0d27ce764 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2034,9 +2034,9 @@ class CGImports(CGWrapper): descriptor = descriptorProvider.getDescriptor(parentName) extras += [descriptor.path, descriptor.bindingPath] elif t.isType() and t.isRecord(): - extras += ['dom::bindings::mozmap::MozMap'] + extras += ['crate::dom::bindings::mozmap::MozMap'] elif isinstance(t, IDLPromiseType): - extras += ["dom::promise::Promise"] + extras += ['crate::dom::promise::Promise'] else: if t.isEnum(): extras += [getModuleFromObject(t) + '::' + getIdentifier(t).name + 'Values'] @@ -2086,15 +2086,15 @@ def DOMClassTypeId(desc): inner = "" if desc.hasDescendants(): if desc.interface.getExtendedAttribute("Abstract"): - return "::dom::bindings::codegen::InheritTypes::TopTypeId { abstract_: () }" + return "crate::dom::bindings::codegen::InheritTypes::TopTypeId { abstract_: () }" name = desc.interface.identifier.name - inner = "(::dom::bindings::codegen::InheritTypes::%sTypeId::%s)" % (name, name) + inner = "(crate::dom::bindings::codegen::InheritTypes::%sTypeId::%s)" % (name, name) elif len(protochain) == 1: - return "::dom::bindings::codegen::InheritTypes::TopTypeId { alone: () }" + return "crate::dom::bindings::codegen::InheritTypes::TopTypeId { alone: () }" reversed_protochain = list(reversed(protochain)) for (child, parent) in zip(reversed_protochain, reversed_protochain[1:]): - inner = "(::dom::bindings::codegen::InheritTypes::%sTypeId::%s%s)" % (parent, child, inner) - return "::dom::bindings::codegen::InheritTypes::TopTypeId { %s: %s }" % (protochain[0].lower(), inner) + inner = "(crate::dom::bindings::codegen::InheritTypes::%sTypeId::%s%s)" % (parent, child, inner) + return "crate::dom::bindings::codegen::InheritTypes::TopTypeId { %s: %s }" % (protochain[0].lower(), inner) def DOMClass(descriptor): @@ -2130,7 +2130,7 @@ class CGDOMJSClass(CGThing): def define(self): parentName = self.descriptor.getParentName() if not parentName: - parentName = "::dom::bindings::reflector::Reflector" + parentName = "crate::dom::bindings::reflector::Reflector" args = { "domClass": DOMClass(self.descriptor), @@ -2194,7 +2194,7 @@ class CGAssertInheritance(CGThing): if parent: parentName = parent.identifier.name else: - parentName = "::dom::bindings::reflector::Reflector" + parentName = "crate::dom::bindings::reflector::Reflector" selfName = self.descriptor.interface.identifier.name @@ -2205,7 +2205,7 @@ class CGAssertInheritance(CGThing): # also has a reflector # # FIXME *RenderingContext2D should use Inline - parentName = "::dom::canvasrenderingcontext2d::CanvasRenderingContext2D" + parentName = "crate::dom::canvasrenderingcontext2d::CanvasRenderingContext2D" args = { "parentName": parentName, "selfName": selfName, @@ -2214,7 +2214,7 @@ class CGAssertInheritance(CGThing): return """\ impl %(selfName)s { fn __assert_parent_type(&self) { - use dom::bindings::inheritance::HasParent; + use crate::dom::bindings::inheritance::HasParent; // If this type assertion fails, make sure the first field of your // DOM struct is of the correct type -- it must be the parent class. let _: &%(parentName)s = self.as_parent(); @@ -2374,22 +2374,22 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config): """ imports = [ - 'dom', - 'dom::bindings::codegen::PrototypeList', - 'dom::bindings::conversions::ConversionResult', - 'dom::bindings::conversions::FromJSValConvertible', - 'dom::bindings::conversions::ToJSValConvertible', - 'dom::bindings::conversions::ConversionBehavior', - 'dom::bindings::conversions::StringificationBehavior', - 'dom::bindings::conversions::root_from_handlevalue', + 'crate::dom', + 'crate::dom::bindings::codegen::PrototypeList', + 'crate::dom::bindings::conversions::ConversionResult', + 'crate::dom::bindings::conversions::FromJSValConvertible', + 'crate::dom::bindings::conversions::ToJSValConvertible', + 'crate::dom::bindings::conversions::ConversionBehavior', + 'crate::dom::bindings::conversions::StringificationBehavior', + 'crate::dom::bindings::conversions::root_from_handlevalue', 'std::ptr::NonNull', - 'dom::bindings::mozmap::MozMap', - 'dom::bindings::root::DomRoot', - 'dom::bindings::str::ByteString', - 'dom::bindings::str::DOMString', - 'dom::bindings::str::USVString', - 'dom::bindings::trace::RootedTraceableBox', - 'dom::types::*', + 'crate::dom::bindings::mozmap::MozMap', + 'crate::dom::bindings::root::DomRoot', + 'crate::dom::bindings::str::ByteString', + 'crate::dom::bindings::str::DOMString', + 'crate::dom::bindings::str::USVString', + 'crate::dom::bindings::trace::RootedTraceableBox', + 'crate::dom::types::*', 'js::error::throw_type_error', 'js::rust::HandleValue', 'js::jsapi::Heap', @@ -4150,7 +4150,7 @@ pub enum %s { pairs = ",\n ".join(['("%s", super::%s::%s)' % (val, ident, getEnumValueName(val)) for val in enum.values()]) inner = string.Template("""\ -use dom::bindings::conversions::ToJSValConvertible; +use crate::dom::bindings::conversions::ToJSValConvertible; use js::jsapi::JSContext; use js::rust::MutableHandleValue; use js::jsval::JSVal; @@ -5866,112 +5866,112 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::rust::define_properties', 'js::rust::get_object_class', 'js::typedarray', - 'dom', - 'dom::bindings', - 'dom::bindings::codegen::InterfaceObjectMap', - 'dom::bindings::constant::ConstantSpec', - 'dom::bindings::constant::ConstantVal', - 'dom::bindings::interface::ConstructorClassHook', - 'dom::bindings::interface::InterfaceConstructorBehavior', - 'dom::bindings::interface::NonCallbackInterfaceObjectClass', - 'dom::bindings::interface::create_global_object', - 'dom::bindings::interface::create_callback_interface_object', - 'dom::bindings::interface::create_interface_prototype_object', - 'dom::bindings::interface::create_named_constructors', - 'dom::bindings::interface::create_noncallback_interface_object', - 'dom::bindings::interface::define_guarded_constants', - 'dom::bindings::interface::define_guarded_methods', - 'dom::bindings::interface::define_guarded_properties', - 'dom::bindings::htmlconstructor::html_constructor', - 'dom::bindings::interface::is_exposed_in', - 'dom::bindings::htmlconstructor::pop_current_element_queue', - 'dom::bindings::htmlconstructor::push_new_element_queue', - 'dom::bindings::iterable::Iterable', - 'dom::bindings::iterable::IteratorType', - 'dom::bindings::namespace::NamespaceObjectClass', - 'dom::bindings::namespace::create_namespace_object', - 'dom::bindings::reflector::MutDomObject', - 'dom::bindings::reflector::DomObject', - 'dom::bindings::root::Dom', - 'dom::bindings::root::DomRoot', - 'dom::bindings::root::OptionalHeapSetter', - 'dom::bindings::root::RootedReference', - 'dom::bindings::utils::AsVoidPtr', - 'dom::bindings::utils::DOMClass', - 'dom::bindings::utils::DOMJSClass', - 'dom::bindings::utils::DOM_PROTO_UNFORGEABLE_HOLDER_SLOT', - 'dom::bindings::utils::JSCLASS_DOM_GLOBAL', - 'dom::bindings::utils::ProtoOrIfaceArray', - 'dom::bindings::utils::enumerate_global', - 'dom::bindings::utils::finalize_global', - 'dom::bindings::utils::find_enum_value', - 'dom::bindings::utils::generic_getter', - 'dom::bindings::utils::generic_lenient_getter', - 'dom::bindings::utils::generic_lenient_setter', - 'dom::bindings::utils::generic_method', - 'dom::bindings::utils::generic_setter', - 'dom::bindings::utils::get_array_index_from_id', - 'dom::bindings::utils::get_dictionary_property', - 'dom::bindings::utils::get_property_on_prototype', - 'dom::bindings::utils::get_proto_or_iface_array', - 'dom::bindings::utils::has_property_on_prototype', - 'dom::bindings::utils::is_platform_object', - 'dom::bindings::utils::resolve_global', - 'dom::bindings::utils::set_dictionary_property', - 'dom::bindings::utils::trace_global', - 'dom::bindings::trace::JSTraceable', - 'dom::bindings::trace::RootedTraceable', - 'dom::bindings::trace::RootedTraceableBox', - 'dom::bindings::callback::CallSetup', - 'dom::bindings::callback::CallbackContainer', - 'dom::bindings::callback::CallbackInterface', - 'dom::bindings::callback::CallbackFunction', - 'dom::bindings::callback::CallbackObject', - 'dom::bindings::callback::ExceptionHandling', - 'dom::bindings::callback::wrap_call_this_object', - 'dom::bindings::conversions::ConversionBehavior', - 'dom::bindings::conversions::ConversionResult', - 'dom::bindings::conversions::DOM_OBJECT_SLOT', - 'dom::bindings::conversions::FromJSValConvertible', - 'dom::bindings::conversions::IDLInterface', - 'dom::bindings::conversions::StringificationBehavior', - 'dom::bindings::conversions::ToJSValConvertible', - 'dom::bindings::conversions::is_array_like', - 'dom::bindings::conversions::native_from_handlevalue', - 'dom::bindings::conversions::native_from_object', - 'dom::bindings::conversions::private_from_object', - 'dom::bindings::conversions::root_from_handleobject', - 'dom::bindings::conversions::root_from_handlevalue', - 'dom::bindings::conversions::root_from_object', - 'dom::bindings::conversions::jsid_to_string', - 'dom::bindings::codegen::PrototypeList', - 'dom::bindings::codegen::RegisterBindings', - 'dom::bindings::codegen::UnionTypes', - 'dom::bindings::error::Error', - 'dom::bindings::error::ErrorResult', - 'dom::bindings::error::Fallible', - 'dom::bindings::error::Error::JSFailed', - 'dom::bindings::error::throw_dom_exception', - 'dom::bindings::guard::Condition', - 'dom::bindings::guard::Guard', - 'dom::bindings::inheritance::Castable', - 'dom::bindings::proxyhandler', - 'dom::bindings::proxyhandler::ensure_expando_object', - 'dom::bindings::proxyhandler::fill_property_descriptor', - 'dom::bindings::proxyhandler::get_expando_object', - 'dom::bindings::proxyhandler::get_property_descriptor', - 'dom::bindings::mozmap::MozMap', + 'crate::dom', + 'crate::dom::bindings', + 'crate::dom::bindings::codegen::InterfaceObjectMap', + 'crate::dom::bindings::constant::ConstantSpec', + 'crate::dom::bindings::constant::ConstantVal', + 'crate::dom::bindings::interface::ConstructorClassHook', + 'crate::dom::bindings::interface::InterfaceConstructorBehavior', + 'crate::dom::bindings::interface::NonCallbackInterfaceObjectClass', + 'crate::dom::bindings::interface::create_global_object', + 'crate::dom::bindings::interface::create_callback_interface_object', + 'crate::dom::bindings::interface::create_interface_prototype_object', + 'crate::dom::bindings::interface::create_named_constructors', + 'crate::dom::bindings::interface::create_noncallback_interface_object', + 'crate::dom::bindings::interface::define_guarded_constants', + 'crate::dom::bindings::interface::define_guarded_methods', + 'crate::dom::bindings::interface::define_guarded_properties', + 'crate::dom::bindings::htmlconstructor::html_constructor', + 'crate::dom::bindings::interface::is_exposed_in', + 'crate::dom::bindings::htmlconstructor::pop_current_element_queue', + 'crate::dom::bindings::htmlconstructor::push_new_element_queue', + 'crate::dom::bindings::iterable::Iterable', + 'crate::dom::bindings::iterable::IteratorType', + 'crate::dom::bindings::namespace::NamespaceObjectClass', + 'crate::dom::bindings::namespace::create_namespace_object', + 'crate::dom::bindings::reflector::MutDomObject', + 'crate::dom::bindings::reflector::DomObject', + 'crate::dom::bindings::root::Dom', + 'crate::dom::bindings::root::DomRoot', + 'crate::dom::bindings::root::OptionalHeapSetter', + 'crate::dom::bindings::root::RootedReference', + 'crate::dom::bindings::utils::AsVoidPtr', + 'crate::dom::bindings::utils::DOMClass', + 'crate::dom::bindings::utils::DOMJSClass', + 'crate::dom::bindings::utils::DOM_PROTO_UNFORGEABLE_HOLDER_SLOT', + 'crate::dom::bindings::utils::JSCLASS_DOM_GLOBAL', + 'crate::dom::bindings::utils::ProtoOrIfaceArray', + 'crate::dom::bindings::utils::enumerate_global', + 'crate::dom::bindings::utils::finalize_global', + 'crate::dom::bindings::utils::find_enum_value', + 'crate::dom::bindings::utils::generic_getter', + 'crate::dom::bindings::utils::generic_lenient_getter', + 'crate::dom::bindings::utils::generic_lenient_setter', + 'crate::dom::bindings::utils::generic_method', + 'crate::dom::bindings::utils::generic_setter', + 'crate::dom::bindings::utils::get_array_index_from_id', + 'crate::dom::bindings::utils::get_dictionary_property', + 'crate::dom::bindings::utils::get_property_on_prototype', + 'crate::dom::bindings::utils::get_proto_or_iface_array', + 'crate::dom::bindings::utils::has_property_on_prototype', + 'crate::dom::bindings::utils::is_platform_object', + 'crate::dom::bindings::utils::resolve_global', + 'crate::dom::bindings::utils::set_dictionary_property', + 'crate::dom::bindings::utils::trace_global', + 'crate::dom::bindings::trace::JSTraceable', + 'crate::dom::bindings::trace::RootedTraceable', + 'crate::dom::bindings::trace::RootedTraceableBox', + 'crate::dom::bindings::callback::CallSetup', + 'crate::dom::bindings::callback::CallbackContainer', + 'crate::dom::bindings::callback::CallbackInterface', + 'crate::dom::bindings::callback::CallbackFunction', + 'crate::dom::bindings::callback::CallbackObject', + 'crate::dom::bindings::callback::ExceptionHandling', + 'crate::dom::bindings::callback::wrap_call_this_object', + 'crate::dom::bindings::conversions::ConversionBehavior', + 'crate::dom::bindings::conversions::ConversionResult', + 'crate::dom::bindings::conversions::DOM_OBJECT_SLOT', + 'crate::dom::bindings::conversions::FromJSValConvertible', + 'crate::dom::bindings::conversions::IDLInterface', + 'crate::dom::bindings::conversions::StringificationBehavior', + 'crate::dom::bindings::conversions::ToJSValConvertible', + 'crate::dom::bindings::conversions::is_array_like', + 'crate::dom::bindings::conversions::native_from_handlevalue', + 'crate::dom::bindings::conversions::native_from_object', + 'crate::dom::bindings::conversions::private_from_object', + 'crate::dom::bindings::conversions::root_from_handleobject', + 'crate::dom::bindings::conversions::root_from_handlevalue', + 'crate::dom::bindings::conversions::root_from_object', + 'crate::dom::bindings::conversions::jsid_to_string', + 'crate::dom::bindings::codegen::PrototypeList', + 'crate::dom::bindings::codegen::RegisterBindings', + 'crate::dom::bindings::codegen::UnionTypes', + 'crate::dom::bindings::error::Error', + 'crate::dom::bindings::error::ErrorResult', + 'crate::dom::bindings::error::Fallible', + 'crate::dom::bindings::error::Error::JSFailed', + 'crate::dom::bindings::error::throw_dom_exception', + 'crate::dom::bindings::guard::Condition', + 'crate::dom::bindings::guard::Guard', + 'crate::dom::bindings::inheritance::Castable', + 'crate::dom::bindings::proxyhandler', + 'crate::dom::bindings::proxyhandler::ensure_expando_object', + 'crate::dom::bindings::proxyhandler::fill_property_descriptor', + 'crate::dom::bindings::proxyhandler::get_expando_object', + 'crate::dom::bindings::proxyhandler::get_property_descriptor', + 'crate::dom::bindings::mozmap::MozMap', 'std::ptr::NonNull', - 'dom::bindings::num::Finite', - 'dom::bindings::str::ByteString', - 'dom::bindings::str::DOMString', - 'dom::bindings::str::USVString', - 'dom::bindings::weakref::DOM_WEAK_SLOT', - 'dom::bindings::weakref::WeakBox', - 'dom::bindings::weakref::WeakReferenceable', - 'dom::windowproxy::WindowProxy', - 'dom::globalscope::GlobalScope', - 'mem::malloc_size_of_including_raw_self', + 'crate::dom::bindings::num::Finite', + 'crate::dom::bindings::str::ByteString', + 'crate::dom::bindings::str::DOMString', + 'crate::dom::bindings::str::USVString', + 'crate::dom::bindings::weakref::DOM_WEAK_SLOT', + 'crate::dom::bindings::weakref::WeakBox', + 'crate::dom::bindings::weakref::WeakReferenceable', + 'crate::dom::windowproxy::WindowProxy', + 'crate::dom::globalscope::GlobalScope', + 'crate::mem::malloc_size_of_including_raw_self', 'libc', 'servo_config::prefs::PREFS', 'std::borrow::ToOwned', @@ -7269,7 +7269,7 @@ class GlobalGenRoots(): @staticmethod def InterfaceObjectMap(config): mods = [ - "dom::bindings::codegen", + "crate::dom::bindings::codegen", "js::jsapi::JSContext", "js::rust::HandleObject", "phf", @@ -7351,8 +7351,8 @@ class GlobalGenRoots(): ], "\n") return CGImports(code, descriptors=[], callbacks=[], dictionaries=[], enums=[], typedefs=[], imports=[ - 'dom::bindings::codegen::Bindings', - 'dom::bindings::codegen::PrototypeList::Proxies', + 'crate::dom::bindings::codegen::Bindings', + 'crate::dom::bindings::codegen::PrototypeList::Proxies', 'libc', ], config=config, ignored_warnings=[]) @@ -7362,8 +7362,8 @@ class GlobalGenRoots(): for d in config.getDescriptors(register=True, isCallback=False, isIteratorInterface=False)]) - curr = CGList([CGGeneric("pub use dom::%s::%s;\n" % (name.lower(), - MakeNativeName(name))) + curr = CGList([CGGeneric("pub use crate::dom::%s::%s;\n" % (name.lower(), + MakeNativeName(name))) for name in descriptors]) curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT) return curr @@ -7386,12 +7386,12 @@ class GlobalGenRoots(): def InheritTypes(config): descriptors = config.getDescriptors(register=True, isCallback=False) - imports = [CGGeneric("use dom::types::*;\n"), - CGGeneric("use dom::bindings::conversions::{DerivedFrom, get_dom_class};\n"), - CGGeneric("use dom::bindings::inheritance::Castable;\n"), - CGGeneric("use dom::bindings::root::{Dom, DomRoot, LayoutDom};\n"), - CGGeneric("use dom::bindings::trace::JSTraceable;\n"), - CGGeneric("use dom::bindings::reflector::DomObject;\n"), + imports = [CGGeneric("use crate::dom::types::*;\n"), + CGGeneric("use crate::dom::bindings::conversions::{DerivedFrom, get_dom_class};\n"), + CGGeneric("use crate::dom::bindings::inheritance::Castable;\n"), + CGGeneric("use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom};\n"), + CGGeneric("use crate::dom::bindings::trace::JSTraceable;\n"), + CGGeneric("use crate::dom::bindings::reflector::DomObject;\n"), CGGeneric("use js::jsapi::JSTracer;\n\n"), CGGeneric("use std::mem;\n\n")] allprotos = [] diff --git a/components/script/dom/bindings/codegen/Configuration.py b/components/script/dom/bindings/codegen/Configuration.py index 4f56c4b55c3..92e0705d32b 100644 --- a/components/script/dom/bindings/codegen/Configuration.py +++ b/components/script/dom/bindings/codegen/Configuration.py @@ -204,9 +204,9 @@ class Descriptor(DescriptorProvider): self.returnType = 'Rc<%s>' % typeName self.argumentType = '&%s' % typeName self.nativeType = typeName - pathDefault = 'dom::types::%s' % typeName + pathDefault = 'crate::dom::types::%s' % typeName elif self.interface.isCallback(): - ty = 'dom::bindings::codegen::Bindings::%sBinding::%s' % (ifaceName, ifaceName) + ty = 'crate::dom::bindings::codegen::Bindings::%sBinding::%s' % (ifaceName, ifaceName) pathDefault = ty self.returnType = "Rc<%s>" % ty self.argumentType = "???" @@ -216,14 +216,14 @@ class Descriptor(DescriptorProvider): self.argumentType = "&%s" % typeName self.nativeType = "*const %s" % typeName if self.interface.isIteratorInterface(): - pathDefault = 'dom::bindings::iterable::IterableIterator' + pathDefault = 'crate::dom::bindings::iterable::IterableIterator' else: - pathDefault = 'dom::types::%s' % MakeNativeName(typeName) + pathDefault = 'crate::dom::types::%s' % MakeNativeName(typeName) self.concreteType = typeName self.register = desc.get('register', True) self.path = desc.get('path', pathDefault) - self.bindingPath = 'dom::bindings::codegen::Bindings::%s' % ('::'.join([ifaceName + 'Binding'] * 2)) + self.bindingPath = 'crate::dom::bindings::codegen::Bindings::%s' % ('::'.join([ifaceName + 'Binding'] * 2)) self.outerObjectHook = desc.get('outerObjectHook', 'None') self.proxy = False self.weakReferenceable = desc.get('weakReferenceable', False) @@ -422,7 +422,7 @@ def MakeNativeName(name): def getModuleFromObject(object): - return ('dom::bindings::codegen::Bindings::' + + return ('crate::dom::bindings::codegen::Bindings::' + os.path.basename(object.location.filename()).split('.webidl')[0] + 'Binding') -- cgit v1.2.3 From 9f9bf8f6bc1897aa7c637a4a0d4021ec6b6c2819 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 1 Nov 2018 19:15:13 +0100 Subject: Switch most crates to the 2018 edition --- components/script/dom/bindings/codegen/CodegenRust.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index da0d27ce764..b50efc90207 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -5686,7 +5686,11 @@ class CGInterfaceTrait(CGThing): yield name, arguments, rettype def fmt(arguments): - return "".join(", %s: %s" % argument for argument in arguments) + keywords = {"async"} + return "".join( + ", %s: %s" % (name if name not in keywords else "r#" + name, type_) + for name, type_ in arguments + ) def contains_unsafe_arg(arguments): if not arguments or len(arguments) == 0: @@ -6250,7 +6254,7 @@ class CGDictionary(CGThing): d = self.dictionary if d.parent: initParent = ("{\n" - " match try!(%s::%s::new(cx, val)) {\n" + " match r#try!(%s::%s::new(cx, val)) {\n" " ConversionResult::Success(v) => v,\n" " ConversionResult::Failure(error) => {\n" " throw_type_error(cx, &error);\n" @@ -6396,7 +6400,7 @@ class CGDictionary(CGThing): conversion = ( "{\n" " rooted!(in(cx) let mut rval = UndefinedValue());\n" - " match try!(get_dictionary_property(cx, object.handle(), \"%s\", rval.handle_mut())) {\n" + " match r#try!(get_dictionary_property(cx, object.handle(), \"%s\", rval.handle_mut())) {\n" " true => {\n" "%s\n" " },\n" @@ -7167,7 +7171,7 @@ class CallbackOperationBase(CallbackMethod): "methodName": self.methodName } getCallableFromProp = string.Template( - 'try!(self.parent.get_callable_property(cx, "${methodName}"))' + 'r#try!(self.parent.get_callable_property(cx, "${methodName}"))' ).substitute(replacements) if not self.singleOperation: return 'rooted!(in(cx) let callable =\n' + getCallableFromProp + ');\n' -- cgit v1.2.3 From a1a14459c141afc6ac6771b8a6c9ca374537edf2 Mon Sep 17 00:00:00 2001 From: Jan Andre Ikenmeyer Date: Mon, 19 Nov 2018 14:47:12 +0100 Subject: Update MPL license to https (part 3) --- components/script/dom/bindings/codegen/BindingGen.py | 2 +- components/script/dom/bindings/codegen/Bindings.conf | 2 +- components/script/dom/bindings/codegen/CodegenRust.py | 2 +- components/script/dom/bindings/codegen/Configuration.py | 2 +- components/script/dom/bindings/codegen/GlobalGen.py | 2 +- components/script/dom/bindings/codegen/parser/WebIDL.py | 2 +- components/script/dom/bindings/codegen/parser/runtests.py | 2 +- .../script/dom/bindings/codegen/parser/tests/test_lenientSetter.py | 2 +- components/script/dom/bindings/codegen/parser/tests/test_replaceable.py | 2 +- components/script/dom/bindings/codegen/pythonpath.py | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/BindingGen.py b/components/script/dom/bindings/codegen/BindingGen.py index 79576b67e58..63cc68e46e5 100644 --- a/components/script/dom/bindings/codegen/BindingGen.py +++ b/components/script/dom/bindings/codegen/BindingGen.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 http://mozilla.org/MPL/2.0/. +# file, You can obtain one at https://mozilla.org/MPL/2.0/. import sys import os diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf index cdd41dc3b74..d23583b76ef 100644 --- a/components/script/dom/bindings/codegen/Bindings.conf +++ b/components/script/dom/bindings/codegen/Bindings.conf @@ -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 http://mozilla.org/MPL/2.0/. +# file, You can obtain one at https://mozilla.org/MPL/2.0/. # DOM Bindings Configuration. # diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index b50efc90207..e82beb913bc 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.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 http://mozilla.org/MPL/2.0/. +# file, You can obtain one at https://mozilla.org/MPL/2.0/. # Common codegen classes. diff --git a/components/script/dom/bindings/codegen/Configuration.py b/components/script/dom/bindings/codegen/Configuration.py index 92e0705d32b..47a65d37d4b 100644 --- a/components/script/dom/bindings/codegen/Configuration.py +++ b/components/script/dom/bindings/codegen/Configuration.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 http://mozilla.org/MPL/2.0/. +# file, You can obtain one at https://mozilla.org/MPL/2.0/. import os diff --git a/components/script/dom/bindings/codegen/GlobalGen.py b/components/script/dom/bindings/codegen/GlobalGen.py index 966e4bdbcd2..20dea28a9d1 100644 --- a/components/script/dom/bindings/codegen/GlobalGen.py +++ b/components/script/dom/bindings/codegen/GlobalGen.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 http://mozilla.org/MPL/2.0/. +# file, You can obtain one at https://mozilla.org/MPL/2.0/. # We do one global pass over all the WebIDL to generate our prototype enum # and generate information for subsequent phases. diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index b56a1765d57..59e32fb7b17 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.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 http://mozilla.org/MPL/2.0/. +# file, You can obtain one at https://mozilla.org/MPL/2.0/. """ A WebIDL parser. """ diff --git a/components/script/dom/bindings/codegen/parser/runtests.py b/components/script/dom/bindings/codegen/parser/runtests.py index b8d45ef31b5..10dbc3292f7 100644 --- a/components/script/dom/bindings/codegen/parser/runtests.py +++ b/components/script/dom/bindings/codegen/parser/runtests.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 http://mozilla.org/MPL/2.0/. +# file, You can obtain one at https://mozilla.org/MPL/2.0/. import os, sys import glob 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 78a9ffe9eaa..50e9df658e9 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 http://mozilla.org/MPL/2.0/. +# file, You can obtain one at https://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_replaceable.py b/components/script/dom/bindings/codegen/parser/tests/test_replaceable.py index 93ee42ed919..78b1bf7e60b 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 http://mozilla.org/MPL/2.0/. +# file, You can obtain one at https://mozilla.org/MPL/2.0/. def should_throw(parser, harness, message, code): parser = parser.reset(); diff --git a/components/script/dom/bindings/codegen/pythonpath.py b/components/script/dom/bindings/codegen/pythonpath.py index 793089551b5..67739c3625f 100644 --- a/components/script/dom/bindings/codegen/pythonpath.py +++ b/components/script/dom/bindings/codegen/pythonpath.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 http://mozilla.org/MPL/2.0/. +# file, You can obtain one at https://mozilla.org/MPL/2.0/. """ Run a python script, adding extra directories to the python path. -- cgit v1.2.3 From 644101e1e42a98996ff98c4cb8fb3cb6dd18be94 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Sun, 2 Dec 2018 14:23:09 -0500 Subject: Update to new JS runtime creation APIs. --- components/script/dom/bindings/codegen/CodegenRust.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index e82beb913bc..e7399d66307 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2592,7 +2592,7 @@ class CGConstructorEnabled(CGAbstractMethod): return CGList((CGGeneric(cond) for cond in conditions), " &&\n") -def CreateBindingJSObject(descriptor, parent=None): +def CreateBindingJSObject(descriptor): assert not descriptor.isGlobal() create = "let raw = Box::into_raw(object);\nlet _rt = RootedTraceable::new(&*raw);\n" if descriptor.proxy: @@ -2601,12 +2601,11 @@ let handler = RegisterBindings::PROXY_HANDLERS[PrototypeList::Proxies::%s as usi rooted!(in(cx) let private = PrivateValue(raw as *const libc::c_void)); let obj = NewProxyObject(cx, handler, Handle::from_raw(UndefinedHandleValue), - proto.get(), %s.get(), - ptr::null_mut(), ptr::null_mut()); + proto.get()); assert!(!obj.is_null()); SetProxyReservedSlot(obj, 0, &private.get()); rooted!(in(cx) let obj = obj);\ -""" % (descriptor.name, parent) +""" % (descriptor.name) else: create += ("rooted!(in(cx) let obj = JS_NewObjectWithGivenProto(\n" " cx, &Class.base as *const JSClass, proto.handle()));\n" @@ -2699,7 +2698,7 @@ class CGWrapMethod(CGAbstractMethod): def definition_body(self): unforgeable = CopyUnforgeablePropertiesToInstance(self.descriptor) - create = CreateBindingJSObject(self.descriptor, "scope") + create = CreateBindingJSObject(self.descriptor) return CGGeneric("""\ let scope = scope.reflector().get_jsobject(); assert!(!scope.get().is_null()); -- cgit v1.2.3 From abd577bfd4583de268aff26e70b480e397504d70 Mon Sep 17 00:00:00 2001 From: Piotr Szpetkowski Date: Wed, 30 Jan 2019 20:54:12 +0100 Subject: Update bool pattern matching into if-else --- components/script/dom/bindings/codegen/CodegenRust.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index e7399d66307..1db23e50992 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -6399,13 +6399,10 @@ class CGDictionary(CGThing): conversion = ( "{\n" " rooted!(in(cx) let mut rval = UndefinedValue());\n" - " match r#try!(get_dictionary_property(cx, object.handle(), \"%s\", rval.handle_mut())) {\n" - " true => {\n" + " if r#try!(get_dictionary_property(cx, object.handle(), \"%s\", rval.handle_mut())) {\n" "%s\n" - " },\n" - " false => {\n" + " } else {\n" "%s\n" - " },\n" " }\n" "}") % (member.identifier.name, indent(conversion), indent(default)) -- cgit v1.2.3 From 8f5db8a7e114ec9a6705da5284f9e5abc3bc7cd2 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 25 Feb 2019 11:48:45 +0530 Subject: Update webidl.py from upstream --- .../script/dom/bindings/codegen/parser/WebIDL.py | 148 +++++++++++++++------ .../dom/bindings/codegen/parser/abstract.patch | 10 +- .../codegen/parser/callback-location.patch | 14 +- .../script/dom/bindings/codegen/parser/debug.patch | 2 +- .../dom/bindings/codegen/parser/inline.patch | 6 +- .../bindings/codegen/parser/pref-main-thread.patch | 28 ---- .../codegen/parser/tests/test_dictionary.py | 43 ++++++ .../codegen/parser/tests/test_lenientSetter.py | 2 +- .../codegen/parser/tests/test_replaceable.py | 2 +- .../codegen/parser/undo-dictionary-optional.patch | 12 ++ .../bindings/codegen/parser/union-typedef.patch | 16 +-- .../script/dom/bindings/codegen/parser/update.sh | 1 + 12 files changed, 191 insertions(+), 93 deletions(-) delete mode 100644 components/script/dom/bindings/codegen/parser/pref-main-thread.patch create mode 100644 components/script/dom/bindings/codegen/parser/undo-dictionary-optional.patch (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index 59e32fb7b17..95cf21a65ed 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.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/. """ A WebIDL parser. """ @@ -248,8 +248,14 @@ class IDLScope(IDLObject): return self.QName() def QName(self): - if self._name: - return self._name.QName() + "::" + # It's possible for us to be called before __init__ has been called, for + # the IDLObjectWithScope case. In that case, self._name won't be set yet. + if hasattr(self, "_name"): + name = self._name + else: + name = None + if name: + return name.QName() + "::" return "::" def ensureUnique(self, identifier, object): @@ -327,6 +333,13 @@ class IDLScope(IDLObject): assert identifier.scope == self return self._lookupIdentifier(identifier) + def addIfaceGlobalNames(self, interfaceName, globalNames): + """Record the global names (from |globalNames|) that can be used in + [Exposed] to expose things in a global named |interfaceName|""" + self.globalNames.update(globalNames) + for name in globalNames: + self.globalNameMapping[name].add(interfaceName) + class IDLIdentifier(IDLObject): def __init__(self, location, scope, name): @@ -504,8 +517,10 @@ class IDLExposureMixins(): return 'Window' in self.exposureSet def isExposedOnMainThread(self): - return (self.isExposedInWindow() or - self.isExposedInSystemGlobals()) + return self.isExposedInWindow() + + def isExposedOffMainThread(self): + return len(self.exposureSet - {'Window', 'FakeTestPrimaryGlobal'}) > 0 def isExposedInAnyWorker(self): return len(self.getWorkerExposureSet()) > 0 @@ -516,9 +531,6 @@ class IDLExposureMixins(): def isExposedInAnyWorklet(self): return len(self.getWorkletExposureSet()) > 0 - def isExposedInSystemGlobals(self): - return 'BackstagePass' in self.exposureSet - def isExposedInSomeButNotAllWorkers(self): """ Returns true if the Exposed extended attribute for this interface @@ -597,6 +609,34 @@ class IDLExternalInterface(IDLObjectWithIdentifier, IDLExposureMixins): return set() +class IDLPartialDictionary(IDLObject): + def __init__(self, location, name, members, nonPartialDictionary): + assert isinstance(name, IDLUnresolvedIdentifier) + + IDLObject.__init__(self, location) + self.identifier = name + self.members = members + self._nonPartialDictionary = nonPartialDictionary + self._finished = False + nonPartialDictionary.addPartialDictionary(self) + + def addExtendedAttributes(self, attrs): + pass + + def finish(self, scope): + if self._finished: + return + self._finished = True + + # Need to make sure our non-partial dictionary gets + # finished so it can report cases when we only have partial + # dictionaries. + self._nonPartialDictionary.finish(scope) + + def validate(self): + pass + + class IDLPartialInterfaceOrNamespace(IDLObject): def __init__(self, location, name, members, nonPartialInterfaceOrNamespace): assert isinstance(name, IDLUnresolvedIdentifier) @@ -1322,7 +1362,6 @@ 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, @@ -1704,9 +1743,8 @@ class IDLInterface(IDLInterfaceOrNamespace): self.globalNames = attr.args() else: self.globalNames = [self.identifier.name] - self.parentScope.globalNames.update(self.globalNames) - for globalName in self.globalNames: - self.parentScope.globalNameMapping[globalName].add(self.identifier.name) + self.parentScope.addIfaceGlobalNames(self.identifier.name, + self.globalNames) self._isOnGlobalProtoChain = True elif identifier == "PrimaryGlobal": if not attr.noArguments(): @@ -1719,8 +1757,8 @@ class IDLInterface(IDLInterfaceOrNamespace): self.parentScope.primaryGlobalAttr.location]) self.parentScope.primaryGlobalAttr = attr self.parentScope.primaryGlobalName = self.identifier.name - self.parentScope.globalNames.add(self.identifier.name) - self.parentScope.globalNameMapping[self.identifier.name].add(self.identifier.name) + self.parentScope.addIfaceGlobalNames(self.identifier.name, + [self.identifier.name]) self._isOnGlobalProtoChain = True elif identifier == "SecureContext": if not attr.noArguments(): @@ -1743,7 +1781,6 @@ class IDLInterface(IDLInterfaceOrNamespace): identifier == "LegacyUnenumerableNamedProperties" or identifier == "RunConstructorInCallerCompartment" or identifier == "WantsEventListenerHooks" or - identifier == "NonOrdinaryGetPrototypeOf" or identifier == "Abstract" or identifier == "Inline"): # Known extended attributes that do not take values @@ -1805,7 +1842,7 @@ class IDLNamespace(IDLInterfaceOrNamespace): if not attr.noArguments(): raise WebIDLError("[%s] must not have arguments" % identifier, [attr.location]) - elif identifier == "Pref": + elif identifier == "Pref" or identifier == "Func": # Known extended attributes that take a string value if not attr.hasValue(): raise WebIDLError("[%s] must have a value" % identifier, @@ -1828,6 +1865,7 @@ class IDLDictionary(IDLObjectWithScope): self.parent = parent self._finished = False self.members = list(members) + self._partialDictionaries = [] IDLObjectWithScope.__init__(self, location, parentScope, name) @@ -1864,6 +1902,11 @@ class IDLDictionary(IDLObjectWithScope): # looking at them. self.parent.finish(scope) + # Now go ahead and merge in our partial dictionaries. + for partial in self._partialDictionaries: + partial.finish(scope) + self.members.extend(partial.members) + for member in self.members: member.resolve(self) if not member.isComplete(): @@ -1968,6 +2011,9 @@ class IDLDictionary(IDLObjectWithScope): deps.add(self.parent) return deps + def addPartialDictionary(self, partial): + assert self.identifier.name == partial.identifier.name + self._partialDictionaries.append(partial) class IDLEnum(IDLObjectWithIdentifier): def __init__(self, location, parentScope, name, values): @@ -4333,7 +4379,7 @@ class IDLAttribute(IDLInterfaceMember): [attr.location, self.location]) elif (identifier == "CrossOriginReadable" or identifier == "CrossOriginWritable"): - if not attr.noArguments() and identifier == "CrossOriginReadable": + if not attr.noArguments(): raise WebIDLError("[%s] must take no arguments" % identifier, [attr.location]) if self.isStatic(): @@ -4525,7 +4571,7 @@ class IDLArgument(IDLObjectWithIdentifier): if ((self.type.isDictionary() or self.type.isUnion() and self.type.unroll().hasDictionaryType()) and self.optional and not self.defaultValue and not self.variadic): - # Default optional non-variadic dictionaries to null, + # 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(): @@ -5089,6 +5135,10 @@ class IDLMethod(IDLInterfaceMember, IDLScope): if not attr.noArguments(): raise WebIDLError("[%s] must take no arguments" % identifier, [attr.location]) + if identifier == "CrossOriginCallable" and self.isStatic(): + raise WebIDLError("[CrossOriginCallable] is only allowed on non-static " + "attributes" + [attr.location, self.location]) elif identifier == "Pure": if not attr.noArguments(): raise WebIDLError("[Pure] must take no arguments", @@ -5293,7 +5343,7 @@ class Tokenizer(object): return t def t_IDENTIFIER(self, t): - r'[A-Z_a-z][0-9A-Z_a-z-]*' + r'[_-]?[A-Za-z][0-9A-Z_a-z-]*' t.type = self.keywords.get(t.value, 'IDENTIFIER') return t @@ -5518,9 +5568,10 @@ class Parser(Tokenizer): def handleNonPartialObject(self, location, identifier, constructor, constructorArgs, nonPartialArgs): """ - This handles non-partial objects (interfaces and namespaces) by - checking for an existing partial object, and promoting it to - non-partial as needed. The return value is the non-partial object. + This handles non-partial objects (interfaces, namespaces and + dictionaries) by checking for an existing partial object, and promoting + it to non-partial as needed. The return value is the non-partial + object. constructorArgs are all the args for the constructor except the last one: isKnownNonPartial. @@ -5610,6 +5661,7 @@ class Parser(Tokenizer): """ PartialDefinition : PartialInterface | PartialNamespace + | PartialDictionary """ p[0] = p[1] @@ -5617,17 +5669,17 @@ class Parser(Tokenizer): nonPartialConstructorArgs, partialConstructorArgs): """ - This handles partial objects (interfaces and namespaces) by checking for - an existing non-partial object, and adding ourselves to it as needed. - The return value is our partial object. For now we just use - IDLPartialInterfaceOrNamespace for partial objects. + This handles partial objects (interfaces, namespaces and dictionaries) + by checking for an existing non-partial object, and adding ourselves to + it as needed. The return value is our partial object. We use + IDLPartialInterfaceOrNamespace for partial interfaces or namespaces, + and IDLPartialDictionary for partial dictionaries. nonPartialConstructorArgs are all the args for the non-partial constructor except the last two: members and isKnownNonPartial. - partialConstructorArgs are the arguments for the - IDLPartialInterfaceOrNamespace constructor, except the last one (the - non-partial object). + partialConstructorArgs are the arguments for the partial object + constructor, except the last one (the non-partial object). """ # The name of the class starts with "IDL", so strip that off. # Also, starts with a capital letter after that, so nix that @@ -5652,9 +5704,19 @@ class Parser(Tokenizer): nonPartialObject = nonPartialConstructor( # No members, False for isKnownNonPartial *(nonPartialConstructorArgs + [[], False])) - partialInterface = IDLPartialInterfaceOrNamespace( - *(partialConstructorArgs + [nonPartialObject])) - return partialInterface + + partialObject = None + if isinstance(nonPartialObject, IDLDictionary): + partialObject = IDLPartialDictionary( + *(partialConstructorArgs + [nonPartialObject])) + elif isinstance(nonPartialObject, (IDLInterface, IDLNamespace)): + partialObject = IDLPartialInterfaceOrNamespace( + *(partialConstructorArgs + [nonPartialObject])) + else: + raise WebIDLError("Unknown partial object type %s" % + type(partialObject)) + + return partialObject def p_PartialInterface(self, p): """ @@ -5682,6 +5744,19 @@ class Parser(Tokenizer): [location, self.globalScope(), identifier], [location, identifier, members]) + def p_PartialDictionary(self, p): + """ + PartialDictionary : DICTIONARY IDENTIFIER LBRACE DictionaryMembers RBRACE SEMICOLON + """ + location = self.getLocation(p, 1) + identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) + members = p[4] + + p[0] = self.handlePartialObject( + location, identifier, IDLDictionary, + [location, self.globalScope(), identifier], + [location, identifier, members]) + def p_Inheritance(self, p): """ Inheritance : COLON ScopedName @@ -6894,16 +6969,13 @@ class Parser(Tokenizer): logger.reportGrammarErrors() self._globalScope = IDLScope(BuiltinLocation(""), None, None) + # To make our test harness work, pretend like we have a primary global already. # Note that we _don't_ set _globalScope.primaryGlobalAttr, # so we'll still be able to detect multiple PrimaryGlobal extended attributes. self._globalScope.primaryGlobalName = "FakeTestPrimaryGlobal" - self._globalScope.globalNames.add("FakeTestPrimaryGlobal") - self._globalScope.globalNameMapping["FakeTestPrimaryGlobal"].add("FakeTestPrimaryGlobal") - # And we add the special-cased "System" global name, which - # doesn't have any corresponding interfaces. - self._globalScope.globalNames.add("System") - self._globalScope.globalNameMapping["System"].add("BackstagePass") + self._globalScope.addIfaceGlobalNames("FakeTestPrimaryGlobal", ["FakeTestPrimaryGlobal"]) + self._installBuiltins(self._globalScope) self._productions = [] diff --git a/components/script/dom/bindings/codegen/parser/abstract.patch b/components/script/dom/bindings/codegen/parser/abstract.patch index cf4c89b84d0..8e6c272b2c5 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 -@@ -1744,7 +1744,8 @@ +@@ -1786,7 +1786,8 @@ class IDLInterface(IDLInterfaceOrNamespace): + identifier == "ProbablyShortLivingWrapper" or identifier == "LegacyUnenumerableNamedProperties" or identifier == "RunConstructorInCallerCompartment" or - identifier == "WantsEventListenerHooks" or -- identifier == "NonOrdinaryGetPrototypeOf"): -+ identifier == "NonOrdinaryGetPrototypeOf" or +- identifier == "WantsEventListenerHooks"): ++ identifier == "WantsEventListenerHooks" or + identifier == "Abstract"): # Known extended attributes that do not take values if not attr.noArguments(): - raise WebIDLError("[%s] must take no arguments" % identifier, + raise WebIDLError("[%s] must take no arguments" % identifier, \ No newline at end of file diff --git a/components/script/dom/bindings/codegen/parser/callback-location.patch b/components/script/dom/bindings/codegen/parser/callback-location.patch index fac5d035801..00b3b034396 100644 --- a/components/script/dom/bindings/codegen/parser/callback-location.patch +++ b/components/script/dom/bindings/codegen/parser/callback-location.patch @@ -1,17 +1,15 @@ -diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py -index da32340..81c52b7 100644 --- WebIDL.py +++ WebIDL.py -@@ -2170,7 +2170,7 @@ class IDLUnresolvedType(IDLType): +@@ -2275,7 +2275,7 @@ class IDLUnresolvedType(IDLType): return typedefType.complete(scope) elif obj.isCallback() and not obj.isInterface(): assert self.name.name == obj.identifier.name - return IDLCallbackType(self.location, obj) + return IDLCallbackType(obj.location, obj) - - if self._promiseInnerType and not self._promiseInnerType.isComplete(): - self._promiseInnerType = self._promiseInnerType.complete(scope) -@@ -6521,7 +6521,7 @@ class Parser(Tokenizer): + + name = self.name.resolve(scope, None) + return IDLWrapperType(self.location, obj) +@@ -6688,7 +6688,7 @@ class Parser(Tokenizer): type = IDLTypedefType(self.getLocation(p, 1), obj.innerType, obj.identifier.name) elif obj.isCallback() and not obj.isInterface(): @@ -19,4 +17,4 @@ index da32340..81c52b7 100644 + type = IDLCallbackType(obj.location, obj) else: type = IDLWrapperType(self.getLocation(p, 1), p[1]) - p[0] = self.handleModifiers(type, p[2]) + p[0] = self.handleNullable(type, p[2]) diff --git a/components/script/dom/bindings/codegen/parser/debug.patch b/components/script/dom/bindings/codegen/parser/debug.patch index ca391c38273..49cb962cbba 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 -@@ -6823,7 +6823,8 @@ class Parser(Tokenizer): +@@ -6959,7 +6959,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 028fb9345d0..e2b16f9b158 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 -@@ -1695,7 +1695,8 @@ class IDLInterface(IDLInterfaceOrNamespace): - identifier == "ProbablyShortLivingObject" or +@@ -1787,7 +1787,8 @@ class IDLInterface(IDLInterfaceOrNamespace): identifier == "LegacyUnenumerableNamedProperties" or - identifier == "NonOrdinaryGetPrototypeOf" or + identifier == "RunConstructorInCallerCompartment" or + identifier == "WantsEventListenerHooks" 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 7be2dcbfc5e..00000000000 --- a/components/script/dom/bindings/codegen/parser/pref-main-thread.patch +++ /dev/null @@ -1,28 +0,0 @@ ---- WebIDL.py -+++ WebIDL.py -@@ -1239,12 +1239,6 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins): - alias, - [member.location, m.location]) - -- if (self.getExtendedAttribute("Pref") and -- self._exposureGlobalNames != set([self.parentScope.primaryGlobalName])): -- raise WebIDLError("[Pref] used on an interface that is not %s-only" % -- self.parentScope.primaryGlobalName, -- [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, -@@ -3459,12 +3453,6 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins): - IDLExposureMixins.finish(self, scope) - - def validate(self): -- if (self.getExtendedAttribute("Pref") and -- self.exposureSet != set([self._globalScope.primaryGlobalName])): -- raise WebIDLError("[Pref] used on an interface member that is not " -- "%s-only" % self._globalScope.primaryGlobalName, -- [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/tests/test_dictionary.py b/components/script/dom/bindings/codegen/parser/tests/test_dictionary.py index 2c0fa61239d..361b83ea52b 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_dictionary.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_dictionary.py @@ -26,6 +26,31 @@ def WebIDLTest(parser, harness): harness.check(dict2.members[1].identifier.name, "child", "'a' really comes before 'c'") + # Test partial dictionary. + parser = parser.reset(); + parser.parse(""" + dictionary A { + long c; + long g; + }; + partial dictionary A { + long h; + long d; + }; + """) + results = parser.finish() + + dict1 = results[0]; + harness.check(len(dict1.members), 4, "Dict1 has four members") + harness.check(dict1.members[0].identifier.name, "c", + "c should be first") + harness.check(dict1.members[1].identifier.name, "d", + "d should come after c") + harness.check(dict1.members[2].identifier.name, "g", + "g should come after d") + harness.check(dict1.members[3].identifier.name, "h", + "h should be last") + # Now reset our parser parser = parser.reset() threw = False @@ -42,6 +67,24 @@ def WebIDLTest(parser, harness): harness.ok(threw, "Should not allow name duplication in a dictionary") + # Test no name duplication across normal and partial dictionary. + parser = parser.reset(); + threw = False + try: + parser.parse(""" + dictionary A { + long prop = 5; + }; + partial dictionary A { + long prop; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow name duplication across normal and partial dictionary") + # Now reset our parser again parser = parser.reset() threw = False 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_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/undo-dictionary-optional.patch b/components/script/dom/bindings/codegen/parser/undo-dictionary-optional.patch new file mode 100644 index 00000000000..b414a536415 --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/undo-dictionary-optional.patch @@ -0,0 +1,12 @@ +--- WebIDL.py ++++ WebIDL.py +@@ -4570,8 +4570,7 @@ class IDLArgument(IDLObjectWithIdentifier): + + 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): ++ self.optional and not self.defaultValue and not self.variadic): + # 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) diff --git a/components/script/dom/bindings/codegen/parser/union-typedef.patch b/components/script/dom/bindings/codegen/parser/union-typedef.patch index 3021e14193f..ec045300b6d 100644 --- a/components/script/dom/bindings/codegen/parser/union-typedef.patch +++ b/components/script/dom/bindings/codegen/parser/union-typedef.patch @@ -1,22 +1,22 @@ --- WebIDL.py +++ WebIDL.py -@@ -2481,10 +2481,18 @@ class IDLUnionType(IDLType): +@@ -2613,10 +2613,18 @@ class IDLUnionType(IDLType): return type.name for (i, type) in enumerate(self.memberTypes): +- if not type.isComplete(): + # Exclude typedefs because if given "typedef (B or C) test", + # we want AOrTest, not AOrBOrC + if not type.isComplete() and not isinstance(type, IDLTypedefType): -+ self.memberTypes[i] = type.complete(scope) -+ -+ self.name = "Or".join(typeName(type) for type in self.memberTypes) + self.memberTypes[i] = type.complete(scope) + + self.name = "Or".join(typeName(type) for type in self.memberTypes) + + # We do this again to complete the typedef types + for (i, type) in enumerate(self.memberTypes): - if not type.isComplete(): - self.memberTypes[i] = type.complete(scope) - -- self.name = "Or".join(typeName(type) for type in self.memberTypes) ++ if not type.isComplete(): ++ self.memberTypes[i] = type.complete(scope) ++ self.flatMemberTypes = list(self.memberTypes) i = 0 while i < len(self.flatMemberTypes): diff --git a/components/script/dom/bindings/codegen/parser/update.sh b/components/script/dom/bindings/codegen/parser/update.sh index 213aba6df89..0386b0294fe 100755 --- a/components/script/dom/bindings/codegen/parser/update.sh +++ b/components/script/dom/bindings/codegen/parser/update.sh @@ -5,6 +5,7 @@ patch < pref-main-thread.patch patch < callback-location.patch patch < union-typedef.patch patch < inline.patch +patch < undo-dictionary-optional.patch wget https://hg.mozilla.org/mozilla-central/archive/tip.tar.gz/dom/bindings/parser/tests/ -O tests.tar.gz rm -r tests -- cgit v1.2.3 From 5fa80a8be0a2cdbb5e84856da6a041958aacc238 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sat, 2 Mar 2019 11:43:56 +0530 Subject: Move pref-main-thread.patch back --- .../bindings/codegen/parser/pref-main-thread.patch | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 components/script/dom/bindings/codegen/parser/pref-main-thread.patch (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/parser/pref-main-thread.patch b/components/script/dom/bindings/codegen/parser/pref-main-thread.patch new file mode 100644 index 00000000000..a90d0593693 --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/pref-main-thread.patch @@ -0,0 +1,27 @@ +--- 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 " -- cgit v1.2.3 From 7b48df53a142507f6f11b9645b605be816db5ab1 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sat, 2 Mar 2019 11:48:31 +0530 Subject: Update WebIDL.py to 4166cae81546 https://hg.mozilla.org/integration/autoland/rev/4166cae81546f54accae807413f806d20bf30920 Pulls in changes from https://bugzilla.mozilla.org/show_bug.cgi?id=1359269 --- .../script/dom/bindings/codegen/CodegenRust.py | 26 +- .../script/dom/bindings/codegen/parser/WebIDL.py | 347 ++++++++++++--------- .../parser/tests/test_attributes_on_types.py | 238 ++++++++++++++ .../parser/tests/test_extended_attributes.py | 8 +- .../tests/test_typedef_identifier_conflict.py | 16 + 5 files changed, 466 insertions(+), 169 deletions(-) create mode 100644 components/script/dom/bindings/codegen/parser/tests/test_attributes_on_types.py create mode 100644 components/script/dom/bindings/codegen/parser/tests/test_typedef_identifier_conflict.py (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 1db23e50992..dea6e104213 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -573,9 +573,6 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, isAutoRooted=False, invalidEnumValueFatal=True, defaultValue=None, - treatNullAs="Default", - isEnforceRange=False, - isClamp=False, exceptionCode=None, allowTreatNonObjectAsNull=False, isCallbackReturnValue=False, @@ -603,12 +600,6 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, If defaultValue is not None, it's the IDL default value for this conversion - If isEnforceRange is true, we're converting an integer and throwing if the - value is out of range. - - If isClamp is true, we're converting an integer and clamping if the - value is out of range. - If allowTreatNonObjectAsNull is true, then [TreatNonObjectAsNull] extended attributes on nullable callback functions will be honored. @@ -631,6 +622,13 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, # We should not have a defaultValue if we know we're an object assert not isDefinitelyObject or defaultValue is None + isEnforceRange = type.enforceRange + isClamp = type.clamp + if type.treatNullAsEmpty: + treatNullAs = "EmptyString" + else: + treatNullAs = "Default" + # If exceptionCode is not set, we'll just rethrow the exception we got. # Note that we can't just set failureCode to exceptionCode, because setting # failureCode will prevent pending exceptions from being set in cases when @@ -1301,9 +1299,6 @@ class CGArgumentConverter(CGThing): descriptorProvider, invalidEnumValueFatal=invalidEnumValueFatal, defaultValue=argument.defaultValue, - treatNullAs=argument.treatNullAs, - isEnforceRange=argument.enforceRange, - isClamp=argument.clamp, isMember="Variadic" if argument.variadic else False, isAutoRooted=type_needs_auto_root(argument.type), allowTreatNonObjectAsNull=argument.allowTreatNonCallableAsNull()) @@ -3508,9 +3503,6 @@ class FakeArgument(): self.variadic = False self.defaultValue = None self._allowTreatNonObjectAsNull = allowTreatNonObjectAsNull - self.treatNullAs = interfaceMember.treatNullAs - self.enforceRange = False - self.clamp = False def allowTreatNonCallableAsNull(self): return self._allowTreatNonObjectAsNull @@ -4874,7 +4866,7 @@ class CGProxySpecialOperation(CGPerSignatureCall): # arguments[0] is the index or name of the item that we're setting. argument = arguments[1] info = getJSToNativeConversionInfo( - argument.type, descriptor, treatNullAs=argument.treatNullAs, + argument.type, descriptor, exceptionCode="return false;") template = info.template declType = info.declType @@ -6886,7 +6878,7 @@ class CGCallbackInterface(CGCallback): class FakeMember(): def __init__(self): - self.treatNullAs = "Default" + pass def isStatic(self): return False diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index 95cf21a65ed..5879f8b0064 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.py @@ -420,48 +420,11 @@ class IDLObjectWithIdentifier(IDLObject): if parentScope: self.resolve(parentScope) - self.treatNullAs = "Default" - def resolve(self, parentScope): assert isinstance(parentScope, IDLScope) assert isinstance(self.identifier, IDLUnresolvedIdentifier) self.identifier.resolve(parentScope, self) - def checkForStringHandlingExtendedAttributes(self, attrs, - isDictionaryMember=False, - isOptional=False): - """ - A helper function to deal with TreatNullAs. Returns the list - of attrs it didn't handle itself. - """ - assert isinstance(self, IDLArgument) or isinstance(self, IDLAttribute) - unhandledAttrs = list() - for attr in attrs: - if not attr.hasValue(): - unhandledAttrs.append(attr) - continue - - identifier = attr.identifier() - value = attr.value() - if identifier == "TreatNullAs": - if not self.type.isDOMString() or self.type.nullable(): - raise WebIDLError("[TreatNullAs] is only allowed on " - "arguments or attributes whose type is " - "DOMString", - [self.location]) - if isDictionaryMember: - raise WebIDLError("[TreatNullAs] is not allowed for " - "dictionary members", [self.location]) - if value != 'EmptyString': - raise WebIDLError("[TreatNullAs] must take the identifier " - "'EmptyString', not '%s'" % value, - [self.location]) - self.treatNullAs = value - else: - unhandledAttrs.append(attr) - - return unhandledAttrs - class IDLObjectWithScope(IDLObjectWithIdentifier, IDLScope): def __init__(self, location, parentScope, identifier): @@ -2090,9 +2053,15 @@ class IDLType(IDLObject): IDLObject.__init__(self, location) self.name = name self.builtin = False + self.clamp = False + self.treatNullAsEmpty = False + self.enforceRange = False + self._extendedAttrDict = {} def __eq__(self, other): - return other and self.builtin == other.builtin and self.name == other.name + return (other and self.builtin == other.builtin and self.name == other.name and + self.clamp == other.clamp and self.enforceRange == other.enforceRange and + self.treatNullAsEmpty == other.treatNullAsEmpty) def __ne__(self, other): return not self == other @@ -2218,12 +2187,14 @@ class IDLType(IDLObject): assert self.tag() == IDLType.Tags.callback return self.nullable() and self.inner.callback._treatNonObjectAsNull - def addExtendedAttributes(self, attrs): - if len(attrs) != 0: - raise WebIDLError("There are no extended attributes that are " - "allowed on types, for now (but this is " - "changing; see bug 1359269)", + def withExtendedAttributes(self, attrs): + if len(attrs) > 0: + raise WebIDLError("Extended attributes on types only supported for builtins", [attrs[0].location, self.location]) + return self + + def getExtendedAttribute(self, name): + return self._extendedAttrDict.get(name, None) def resolveType(self, parentScope): pass @@ -2244,8 +2215,9 @@ class IDLUnresolvedType(IDLType): Unresolved types are interface types """ - def __init__(self, location, name): + def __init__(self, location, name, attrs=[]): IDLType.__init__(self, location, name) + self.extraTypeAttributes = attrs def isComplete(self): return False @@ -2267,7 +2239,7 @@ class IDLUnresolvedType(IDLType): typedefType = IDLTypedefType(self.location, obj.innerType, obj.identifier) assert not typedefType.isComplete() - return typedefType.complete(scope) + return typedefType.complete(scope).withExtendedAttributes(self.extraTypeAttributes) elif obj.isCallback() and not obj.isInterface(): assert self.name.name == obj.identifier.name return IDLCallbackType(obj.location, obj) @@ -2275,6 +2247,9 @@ class IDLUnresolvedType(IDLType): name = self.name.resolve(scope, None) return IDLWrapperType(self.location, obj) + def withExtendedAttributes(self, attrs): + return IDLUnresolvedType(self.location, self.name, attrs) + def isDistinguishableFrom(self, other): raise TypeError("Can't tell whether an unresolved type is or is not " "distinguishable from other things") @@ -2790,12 +2765,17 @@ class IDLTypedefType(IDLType): def _getDependentObjects(self): return self.inner._getDependentObjects() + def withExtendedAttributes(self, attrs): + return IDLTypedefType(self.location, self.inner.withExtendedAttributes(attrs), self.name) + class IDLTypedef(IDLObjectWithIdentifier): def __init__(self, location, parentScope, innerType, name): + # Set self.innerType first, because IDLObjectWithIdentifier.__init__ + # will call our __str__, which wants to use it. + self.innerType = innerType identifier = IDLUnresolvedIdentifier(location, name) IDLObjectWithIdentifier.__init__(self, location, parentScope, identifier) - self.innerType = innerType def __str__(self): return "Typedef %s %s" % (self.identifier.name, self.innerType) @@ -3107,10 +3087,59 @@ class IDLBuiltinType(IDLType): Types.ReadableStream: IDLType.Tags.interface, } - def __init__(self, location, name, type): + def __init__(self, location, name, type, clamp=False, enforceRange=False, treatNullAsEmpty=False, + attrLocation=[]): + """ + The mutually exclusive clamp/enforceRange/treatNullAsEmpty arguments are used to create instances + of this type with the appropriate attributes attached. Use .clamped(), .rangeEnforced(), and .treatNullAs(). + + attrLocation is an array of source locations of these attributes for error reporting. + """ IDLType.__init__(self, location, name) self.builtin = True self._typeTag = type + self._clamped = None + self._rangeEnforced = None + self._withTreatNullAs = None + if self.isNumeric(): + if clamp: + self.clamp = True + self.name = "Clamped" + self.name + self._extendedAttrDict["Clamp"] = True + elif enforceRange: + self.enforceRange = True + self.name = "RangeEnforced" + self.name + self._extendedAttrDict["EnforceRange"] = True + elif clamp or enforceRange: + raise WebIDLError("Non-numeric types cannot be [Clamp] or [EnforceRange]", attrLocation) + if self.isDOMString(): + if treatNullAsEmpty: + self.treatNullAsEmpty = True + self.name = "NullIsEmpty" + self.name + self._extendedAttrDict["TreatNullAs"] = ["EmptyString"] + elif treatNullAsEmpty: + raise WebIDLError("Non-string types cannot be [TreatNullAs]", attrLocation) + + def clamped(self, attrLocation): + if not self._clamped: + self._clamped = IDLBuiltinType(self.location, self.name, + self._typeTag, clamp=True, + attrLocation=attrLocation) + return self._clamped + + def rangeEnforced(self, attrLocation): + if not self._rangeEnforced: + self._rangeEnforced = IDLBuiltinType(self.location, self.name, + self._typeTag, enforceRange=True, + attrLocation=attrLocation) + return self._rangeEnforced + + def withTreatNullAs(self, attrLocation): + if not self._withTreatNullAs: + self._withTreatNullAs = IDLBuiltinType(self.location, self.name, + self._typeTag, treatNullAsEmpty=True, + attrLocation=attrLocation) + return self._withTreatNullAs def isPrimitive(self): return self._typeTag <= IDLBuiltinType.Types.double @@ -3246,6 +3275,45 @@ class IDLBuiltinType(IDLType): def _getDependentObjects(self): return set() + def withExtendedAttributes(self, attrs): + ret = self + for attribute in attrs: + identifier = attribute.identifier() + if identifier == "Clamp": + if not attribute.noArguments(): + raise WebIDLError("[Clamp] must take no arguments", + [attribute.location]) + if ret.enforceRange or self.enforceRange: + raise WebIDLError("[EnforceRange] and [Clamp] are mutually exclusive", + [self.location, attribute.location]) + ret = self.clamped([self.location, attribute.location]) + elif identifier == "EnforceRange": + if not attribute.noArguments(): + raise WebIDLError("[EnforceRange] must take no arguments", + [attribute.location]) + if ret.clamp or self.clamp: + raise WebIDLError("[EnforceRange] and [Clamp] are mutually exclusive", + [self.location, attribute.location]) + ret = self.rangeEnforced([self.location, attribute.location]) + elif identifier == "TreatNullAs": + if not self.isDOMString(): + raise WebIDLError("[TreatNullAs] only allowed on DOMStrings", + [self.location, attribute.location]) + assert not self.nullable() + if not attribute.hasValue(): + raise WebIDLError("[TreatNullAs] must take an identifier argument" + [attribute.location]) + value = attribute.value() + if value != 'EmptyString': + raise WebIDLError("[TreatNullAs] must take the identifier " + "'EmptyString', not '%s'" % value, + [attribute.location]) + ret = self.withTreatNullAs([self.location, attribute.location]) + else: + raise WebIDLError("Unhandled extended attribute on type", + [self.location, attribute.location]) + return ret + BuiltinTypes = { IDLBuiltinType.Types.byte: IDLBuiltinType(BuiltinLocation(""), "Byte", @@ -3460,6 +3528,10 @@ class IDLValue(IDLObject): # extra normalization step. assert self.type.isDOMString() return self + elif self.type.isDOMString() and type.treatNullAsEmpty: + # TreatNullAsEmpty is a different type for resolution reasons, + # however once you have a value it doesn't matter + return self elif self.type.isString() and type.isByteString(): # Allow ByteStrings to use a default value like DOMString. # No coercion is required as Codegen.py will handle the @@ -4096,8 +4168,6 @@ class IDLAttribute(IDLInterfaceMember): self.lenientThis = False self._unforgeable = False self.stringifier = stringifier - self.enforceRange = False - self.clamp = False self.slotIndices = None assert maplikeOrSetlike is None or isinstance(maplikeOrSetlike, IDLMaplikeOrSetlike) self.maplikeOrSetlike = maplikeOrSetlike @@ -4134,6 +4204,9 @@ class IDLAttribute(IDLInterfaceMember): assert not isinstance(t.name, IDLUnresolvedIdentifier) self.type = t + if self.readonly and (self.type.clamp or self.type.enforceRange or self.type.treatNullAsEmpty): + raise WebIDLError("A readonly attribute cannot be [Clamp] or [EnforceRange]", + [self.location]) if self.type.isDictionary() and not self.getExtendedAttribute("Cached"): raise WebIDLError("An attribute cannot be of a dictionary type", [self.location]) @@ -4357,16 +4430,6 @@ class IDLAttribute(IDLInterfaceMember): raise WebIDLError("[LenientFloat] used on an attribute with a " "non-restricted-float type", [attr.location, self.location]) - elif identifier == "EnforceRange": - if self.readonly: - raise WebIDLError("[EnforceRange] used on a readonly attribute", - [attr.location, self.location]) - self.enforceRange = True - elif identifier == "Clamp": - if self.readonly: - raise WebIDLError("[Clamp] used on a readonly attribute", - [attr.location, self.location]) - self.clamp = True elif identifier == "StoreInSlot": if self.getExtendedAttribute("Cached"): raise WebIDLError("[StoreInSlot] and [Cached] must not be " @@ -4468,10 +4531,6 @@ class IDLAttribute(IDLInterfaceMember): self.type.resolveType(parentScope) IDLObjectWithIdentifier.resolve(self, parentScope) - def addExtendedAttributes(self, attrs): - attrs = self.checkForStringHandlingExtendedAttributes(attrs) - IDLInterfaceMember.addExtendedAttributes(self, attrs) - def hasLenientThis(self): return self.lenientThis @@ -4491,7 +4550,7 @@ class IDLAttribute(IDLInterfaceMember): class IDLArgument(IDLObjectWithIdentifier): - def __init__(self, location, identifier, type, optional=False, defaultValue=None, variadic=False, dictionaryMember=False): + def __init__(self, location, identifier, type, optional=False, defaultValue=None, variadic=False, dictionaryMember=False, allowTypeAttributes=False): IDLObjectWithIdentifier.__init__(self, location, None, identifier) assert isinstance(type, IDLType) @@ -4502,37 +4561,19 @@ class IDLArgument(IDLObjectWithIdentifier): self.variadic = variadic self.dictionaryMember = dictionaryMember self._isComplete = False - self.enforceRange = False - self.clamp = False self._allowTreatNonCallableAsNull = False self._extendedAttrDict = {} + self.allowTypeAttributes = allowTypeAttributes assert not variadic or optional assert not variadic or not defaultValue def addExtendedAttributes(self, attrs): - attrs = self.checkForStringHandlingExtendedAttributes( - attrs, - isDictionaryMember=self.dictionaryMember, - isOptional=self.optional) for attribute in attrs: identifier = attribute.identifier() - if identifier == "Clamp": - if not attribute.noArguments(): - raise WebIDLError("[Clamp] must take no arguments", - [attribute.location]) - if self.enforceRange: - raise WebIDLError("[EnforceRange] and [Clamp] are mutually exclusive", - [self.location]) - self.clamp = True - elif identifier == "EnforceRange": - if not attribute.noArguments(): - raise WebIDLError("[EnforceRange] must take no arguments", - [attribute.location]) - if self.clamp: - raise WebIDLError("[EnforceRange] and [Clamp] are mutually exclusive", - [self.location]) - self.enforceRange = True + if self.allowTypeAttributes and (identifier == "EnforceRange" or identifier == "Clamp" or + identifier == "TreatNullAs"): + self.type = self.type.withExtendedAttributes([attribute]) elif identifier == "TreatNonCallableAsNull": self._allowTreatNonCallableAsNull = True elif (self.dictionaryMember and @@ -4583,6 +4624,8 @@ class IDLArgument(IDLObjectWithIdentifier): # codegen doesn't have to special-case this. self.defaultValue = IDLUndefinedValue(self.location) + if self.dictionaryMember and self.type.treatNullAsEmpty: + raise WebIDLError("Dictionary members cannot be [TreatNullAs]", [self.location]) # Now do the coercing thing; this needs to happen after the # above creation of a default value. if self.defaultValue: @@ -5811,31 +5854,42 @@ class Parser(Tokenizer): # We're at the end of the list p[0] = [] return - # Add our extended attributes p[2].addExtendedAttributes(p[1]) p[0] = [p[2]] p[0].extend(p[3]) - def p_DictionaryMember(self, p): + def p_DictionaryMemberRequired(self, p): """ - DictionaryMember : Required Type IDENTIFIER Default SEMICOLON + DictionaryMember : REQUIRED TypeWithExtendedAttributes IDENTIFIER SEMICOLON """ - # These quack a lot like optional arguments, so just treat them that way. + # These quack a lot like required arguments, so just treat them that way. t = p[2] assert isinstance(t, IDLType) identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3]) - defaultValue = p[4] - optional = not p[1] - - if not optional and defaultValue: - raise WebIDLError("Required dictionary members can't have a default value.", - [self.getLocation(p, 4)]) p[0] = IDLArgument(self.getLocation(p, 3), identifier, t, - optional=optional, - defaultValue=defaultValue, variadic=False, + optional=False, + defaultValue=None, variadic=False, dictionaryMember=True) + def p_DictionaryMember(self, p): + """ + DictionaryMember : Type IDENTIFIER Default SEMICOLON + """ + # These quack a lot like optional arguments, so just treat them that way. + t = p[1] + assert isinstance(t, IDLType) + identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) + defaultValue = p[3] + + # Any attributes that precede this may apply to the type, so + # we configure the argument to forward type attributes down instead of producing + # a parse error + p[0] = IDLArgument(self.getLocation(p, 2), identifier, t, + optional=True, + defaultValue=defaultValue, variadic=False, + dictionaryMember=True, allowTypeAttributes=True) + def p_Default(self, p): """ Default : EQUALS DefaultValue @@ -5923,7 +5977,7 @@ class Parser(Tokenizer): def p_Typedef(self, p): """ - Typedef : TYPEDEF Type IDENTIFIER SEMICOLON + Typedef : TYPEDEF TypeWithExtendedAttributes IDENTIFIER SEMICOLON """ typedef = IDLTypedef(self.getLocation(p, 1), self.globalScope(), p[2], p[3]) @@ -6016,8 +6070,8 @@ class Parser(Tokenizer): def p_Iterable(self, p): """ - Iterable : ITERABLE LT Type GT SEMICOLON - | ITERABLE LT Type COMMA Type GT SEMICOLON + Iterable : ITERABLE LT TypeWithExtendedAttributes GT SEMICOLON + | ITERABLE LT TypeWithExtendedAttributes COMMA TypeWithExtendedAttributes GT SEMICOLON """ location = self.getLocation(p, 2) identifier = IDLUnresolvedIdentifier(location, "__iterable", @@ -6033,7 +6087,7 @@ class Parser(Tokenizer): def p_Setlike(self, p): """ - Setlike : ReadOnly SETLIKE LT Type GT SEMICOLON + Setlike : ReadOnly SETLIKE LT TypeWithExtendedAttributes GT SEMICOLON """ readonly = p[1] maplikeOrSetlikeType = p[2] @@ -6047,7 +6101,7 @@ class Parser(Tokenizer): def p_Maplike(self, p): """ - Maplike : ReadOnly MAPLIKE LT Type COMMA Type GT SEMICOLON + Maplike : ReadOnly MAPLIKE LT TypeWithExtendedAttributes COMMA TypeWithExtendedAttributes GT SEMICOLON """ readonly = p[1] maplikeOrSetlikeType = p[2] @@ -6085,7 +6139,7 @@ class Parser(Tokenizer): def p_AttributeRest(self, p): """ - AttributeRest : ReadOnly ATTRIBUTE Type AttributeName SEMICOLON + AttributeRest : ReadOnly ATTRIBUTE TypeWithExtendedAttributes AttributeName SEMICOLON """ location = self.getLocation(p, 2) readonly = p[1] @@ -6339,32 +6393,47 @@ class Parser(Tokenizer): def p_Argument(self, p): """ - Argument : ExtendedAttributeList Optional Type Ellipsis ArgumentName Default + Argument : ExtendedAttributeList ArgumentRest """ - t = p[3] + p[0] = p[2] + p[0].addExtendedAttributes(p[1]) + + def p_ArgumentRestOptional(self, p): + """ + ArgumentRest : OPTIONAL TypeWithExtendedAttributes ArgumentName Default + """ + t = p[2] assert isinstance(t, IDLType) - identifier = IDLUnresolvedIdentifier(self.getLocation(p, 5), p[5]) + identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3]) - optional = p[2] - variadic = p[4] - defaultValue = p[6] + defaultValue = p[4] - if not optional and defaultValue: - raise WebIDLError("Mandatory arguments can't have a default value.", - [self.getLocation(p, 6)]) # We can't test t.isAny() here and give it a default value as needed, # since at this point t is not a fully resolved type yet (e.g. it might # be a typedef). We'll handle the 'any' case in IDLArgument.complete. - if variadic: - if optional: - raise WebIDLError("Variadic arguments should not be marked optional.", - [self.getLocation(p, 2)]) - optional = variadic + p[0] = IDLArgument(self.getLocation(p, 3), identifier, t, True, defaultValue, False) - p[0] = IDLArgument(self.getLocation(p, 5), identifier, t, optional, defaultValue, variadic) - p[0].addExtendedAttributes(p[1]) + def p_ArgumentRest(self, p): + """ + ArgumentRest : Type Ellipsis ArgumentName + """ + t = p[1] + assert isinstance(t, IDLType) + identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3]) + + variadic = p[2] + + # We can't test t.isAny() here and give it a default value as needed, + # since at this point t is not a fully resolved type yet (e.g. it might + # be a typedef). We'll handle the 'any' case in IDLArgument.complete. + + # variadic implies optional + # Any attributes that precede this may apply to the type, so + # we configure the argument to forward type attributes down instead of producing + # a parse error + p[0] = IDLArgument(self.getLocation(p, 3), identifier, t, variadic, None, variadic, allowTypeAttributes=True) def p_ArgumentName(self, p): """ @@ -6403,30 +6472,6 @@ class Parser(Tokenizer): """ p[0] = p[1] - def p_Optional(self, p): - """ - Optional : OPTIONAL - """ - p[0] = True - - def p_OptionalEmpty(self, p): - """ - Optional : - """ - p[0] = False - - def p_Required(self, p): - """ - Required : REQUIRED - """ - p[0] = True - - def p_RequiredEmpty(self, p): - """ - Required : - """ - p[0] = False - def p_Ellipsis(self, p): """ Ellipsis : ELLIPSIS @@ -6567,6 +6612,12 @@ class Parser(Tokenizer): """ p[0] = self.handleNullable(p[1], p[2]) + def p_TypeWithExtendedAttributes(self, p): + """ + TypeWithExtendedAttributes : ExtendedAttributeList Type + """ + p[0] = p[2].withExtendedAttributes(p[1]) + def p_SingleTypeNonAnyType(self, p): """ SingleType : NonAnyType @@ -6589,9 +6640,9 @@ class Parser(Tokenizer): def p_UnionMemberTypeNonAnyType(self, p): """ - UnionMemberType : NonAnyType + UnionMemberType : ExtendedAttributeList NonAnyType """ - p[0] = p[1] + p[0] = p[2].withExtendedAttributes(p[1]) def p_UnionMemberType(self, p): """ @@ -6641,7 +6692,7 @@ class Parser(Tokenizer): def p_NonAnyTypeSequenceType(self, p): """ - NonAnyType : SEQUENCE LT Type GT Null + NonAnyType : SEQUENCE LT TypeWithExtendedAttributes GT Null """ innerType = p[3] type = IDLSequenceType(self.getLocation(p, 1), innerType) @@ -6657,7 +6708,7 @@ class Parser(Tokenizer): def p_NonAnyTypeRecordType(self, p): """ - NonAnyType : RECORD LT StringType COMMA Type GT Null + NonAnyType : RECORD LT StringType COMMA TypeWithExtendedAttributes GT Null """ keyType = p[3] valueType = p[5] diff --git a/components/script/dom/bindings/codegen/parser/tests/test_attributes_on_types.py b/components/script/dom/bindings/codegen/parser/tests/test_attributes_on_types.py new file mode 100644 index 00000000000..1128d58317a --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_attributes_on_types.py @@ -0,0 +1,238 @@ +# Import the WebIDL module, so we can do isinstance checks and whatnot +import WebIDL + +def WebIDLTest(parser, harness): + # Basic functionality + threw = False + try: + parser.parse(""" + typedef [EnforceRange] long Foo; + typedef [Clamp] long Bar; + typedef [TreatNullAs=EmptyString] DOMString Baz; + dictionary A { + required [EnforceRange] long a; + required [Clamp] long b; + [ChromeOnly, EnforceRange] long c; + Foo d; + }; + interface B { + attribute Foo typedefFoo; + attribute [EnforceRange] long foo; + attribute [Clamp] long bar; + attribute [TreatNullAs=EmptyString] DOMString baz; + void method([EnforceRange] long foo, [Clamp] long bar, + [TreatNullAs=EmptyString] DOMString baz); + void method2(optional [EnforceRange] long foo, optional [Clamp] long bar, + optional [TreatNullAs=EmptyString] DOMString baz); + }; + interface Setlike { + setlike<[Clamp] long>; + }; + interface Maplike { + maplike<[Clamp] long, [EnforceRange] long>; + }; + interface Iterable { + iterable<[Clamp] long, [EnforceRange] long>; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(not threw, "Should not have thrown on parsing normal") + if not threw: + harness.check(results[0].innerType.enforceRange, True, "Foo is [EnforceRange]") + harness.check(results[1].innerType.clamp, True, "Bar is [Clamp]") + harness.check(results[2].innerType.treatNullAsEmpty, True, "Baz is [TreatNullAs=EmptyString]") + A = results[3] + harness.check(A.members[0].type.enforceRange, True, "A.a is [EnforceRange]") + harness.check(A.members[1].type.clamp, True, "A.b is [Clamp]") + harness.check(A.members[2].type.enforceRange, True, "A.c is [EnforceRange]") + harness.check(A.members[3].type.enforceRange, True, "A.d is [EnforceRange]") + B = results[4] + harness.check(B.members[0].type.enforceRange, True, "B.typedefFoo is [EnforceRange]") + harness.check(B.members[1].type.enforceRange, True, "B.foo is [EnforceRange]") + harness.check(B.members[2].type.clamp, True, "B.bar is [Clamp]") + harness.check(B.members[3].type.treatNullAsEmpty, True, "B.baz is [TreatNullAs=EmptyString]") + method = B.members[4].signatures()[0][1] + harness.check(method[0].type.enforceRange, True, "foo argument of method is [EnforceRange]") + harness.check(method[1].type.clamp, True, "bar argument of method is [Clamp]") + harness.check(method[2].type.treatNullAsEmpty, True, "baz argument of method is [TreatNullAs=EmptyString]") + method2 = B.members[5].signatures()[0][1] + harness.check(method[0].type.enforceRange, True, "foo argument of method2 is [EnforceRange]") + harness.check(method[1].type.clamp, True, "bar argument of method2 is [Clamp]") + harness.check(method[2].type.treatNullAsEmpty, True, "baz argument of method2 is [TreatNullAs=EmptyString]") + + ATTRIBUTES = [("[Clamp]", "long"), ("[EnforceRange]", "long"), ("[TreatNullAs=EmptyString]", "DOMString")] + TEMPLATES = [ + ("required dictionary members", """ + dictionary Foo { + %s required %s foo; + }; + """), + ("optional arguments", """ + interface Foo { + void foo(%s optional %s foo); + }; + """), + ("typedefs", """ + %s typedef %s foo; + """), + ("attributes", """ + interface Foo { + %s attribute %s foo; + }; + """), + ("readonly attributes", """ + interface Foo { + readonly attribute %s %s foo; + }; + """), + ("readonly unresolved attributes", """ + interface Foo { + readonly attribute Bar baz; + }; + typedef %s %s Bar; + """) + ]; + + for (name, template) in TEMPLATES: + parser = parser.reset() + threw = False + try: + parser.parse(template % ("", "long")) + parser.finish() + except: + threw = True + harness.ok(not threw, "Template for %s parses without attributes" % name) + for (attribute, type) in ATTRIBUTES: + parser = parser.reset() + threw = False + try: + parser.parse(template % (attribute, type)) + parser.finish() + except: + threw = True + harness.ok(threw, + "Should not allow %s on %s" % (attribute, name)) + + parser = parser.reset() + threw = False + try: + parser.parse(""" + typedef [Clamp, EnforceRange] long Foo; + """) + parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow mixing [Clamp] and [EnforceRange]") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + typedef [EnforceRange, Clamp] long Foo; + """) + parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow mixing [Clamp] and [EnforceRange]") + + + parser = parser.reset() + threw = False + try: + parser.parse(""" + typedef [Clamp] long Foo; + typedef [EnforceRange] Foo bar; + """) + parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow mixing [Clamp] and [EnforceRange] via typedefs") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + typedef [EnforceRange] long Foo; + typedef [Clamp] Foo bar; + """) + parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow mixing [Clamp] and [EnforceRange] via typedefs") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + typedef [Clamp] DOMString Foo; + """) + parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow [Clamp] on DOMString") + + + parser = parser.reset() + threw = False + try: + parser.parse(""" + typedef [EnforceRange] DOMString Foo; + """) + parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow [EnforceRange] on DOMString") + + + parser = parser.reset() + threw = False + try: + parser.parse(""" + typedef [TreatNullAs=EmptyString] long Foo; + """) + parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow [TreatNullAs] on long") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Foo { + void foo([Clamp] Bar arg); + }; + typedef long Bar; + """) + results = parser.finish() + except: + threw = True + harness.ok(not threw, "Should allow type attributes on unresolved types") + harness.check(results[0].members[0].signatures()[0][1][0].type.clamp, True, + "Unresolved types with type attributes should correctly resolve with attributes") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Foo { + void foo(Bar arg); + }; + typedef [Clamp] long Bar; + """) + results = parser.finish() + except: + threw = True + harness.ok(not threw, "Should allow type attributes on typedefs") + harness.check(results[0].members[0].signatures()[0][1][0].type.clamp, True, + "Unresolved types that resolve to typedefs with attributes should correctly resolve with attributes") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_extended_attributes.py b/components/script/dom/bindings/codegen/parser/tests/test_extended_attributes.py index 85a70d98f2c..97184ec2478 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_extended_attributes.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_extended_attributes.py @@ -56,9 +56,9 @@ def WebIDLTest(parser, harness): results = parser.finish() # Pull out the first argument out of the arglist of the first (and # only) signature. - harness.ok(results[0].members[0].signatures()[0][1][0].clamp, + harness.ok(results[0].members[0].signatures()[0][1][0].type.clamp, "Should be clamped") - harness.ok(not results[0].members[1].signatures()[0][1][0].clamp, + harness.ok(not results[0].members[1].signatures()[0][1][0].type.clamp, "Should not be clamped") parser = parser.reset() @@ -86,9 +86,9 @@ def WebIDLTest(parser, harness): results = parser.finish() # Pull out the first argument out of the arglist of the first (and # only) signature. - harness.ok(results[0].members[0].signatures()[0][1][0].enforceRange, + harness.ok(results[0].members[0].signatures()[0][1][0].type.enforceRange, "Should be enforceRange") - harness.ok(not results[0].members[1].signatures()[0][1][0].enforceRange, + harness.ok(not results[0].members[1].signatures()[0][1][0].type.enforceRange, "Should not be enforceRange") parser = parser.reset() diff --git a/components/script/dom/bindings/codegen/parser/tests/test_typedef_identifier_conflict.py b/components/script/dom/bindings/codegen/parser/tests/test_typedef_identifier_conflict.py new file mode 100644 index 00000000000..0ea38ce437b --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_typedef_identifier_conflict.py @@ -0,0 +1,16 @@ +def WebIDLTest(parser, harness): + exception = None + try: + parser.parse( + """ + typedef long foo; + typedef long foo; + """) + + results = parser.finish() + except Exception as e: + exception = e + + harness.ok(exception, "Should have thrown.") + harness.ok("Multiple unresolvable definitions of identifier 'foo'" in str(exception), + "Should have a sane exception message") -- cgit v1.2.3 From caa05948bf250944b259a5a95a8e6ef1db6a947b Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 12 Feb 2019 18:24:44 -0800 Subject: Add aspect/frameRate/sampleRate parameters --- components/script/dom/bindings/codegen/CodegenRust.py | 1 + 1 file changed, 1 insertion(+) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index dea6e104213..1bd01651e76 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2379,6 +2379,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config): 'crate::dom::bindings::conversions::root_from_handlevalue', 'std::ptr::NonNull', 'crate::dom::bindings::mozmap::MozMap', + 'crate::dom::bindings::num::Finite', 'crate::dom::bindings::root::DomRoot', 'crate::dom::bindings::str::ByteString', 'crate::dom::bindings::str::DOMString', -- cgit v1.2.3 From ce635b715bc61d82e3d5bafb2964c960e7cc5f9c Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 12 Feb 2019 18:38:38 -0800 Subject: Add support for default dict values being boolean, use in MediaStreamConstraints --- components/script/dom/bindings/codegen/CodegenRust.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 1bd01651e76..fe88275bf20 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -747,7 +747,15 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, for memberType in type.unroll().flatMemberTypes if memberType.isDictionary() ] - if dictionaries: + if defaultValue and not isinstance(defaultValue, IDLNullValue): + tag = defaultValue.type.tag() + if tag is IDLType.Tags.bool: + default = "%s::Boolean(%s)" % ( + union_native_type(type), + "true" if defaultValue.value else "false") + else: + raise("We don't currently support default values that aren't null or boolean") + elif dictionaries: if defaultValue: assert isinstance(defaultValue, IDLNullValue) dictionary, = dictionaries -- cgit v1.2.3 From 5fe5e5d6debef5adf234b650ee1b758e683a5230 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sun, 10 Mar 2019 13:20:07 +0100 Subject: Remove most RootedReference uses We can replace all uses of RootedReference for Option by Option::deref calls. --- components/script/dom/bindings/codegen/CodegenRust.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index fe88275bf20..9c5e4864dab 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -7250,8 +7250,10 @@ def camel_to_upper_snake(s): def process_arg(expr, arg): if arg.type.isGeckoInterface() and not arg.type.unroll().inner.isCallback(): - if arg.type.nullable() or arg.type.isSequence() or arg.optional: + if arg.variadic or arg.type.isSequence() or arg.type.nullable() and arg.optional: expr += ".r()" + elif arg.type.nullable() or arg.optional: + expr += ".deref()" else: expr = "&" + expr elif isinstance(arg.type, IDLPromiseType): -- cgit v1.2.3 From 1744a42dad62a4051ab56f109393850c8aafe961 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sun, 10 Mar 2019 18:24:35 +0100 Subject: Don't use RootedReference for Option in codegen anymore --- components/script/dom/bindings/codegen/CodegenRust.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 9c5e4864dab..3f15a316af3 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -7250,9 +7250,11 @@ def camel_to_upper_snake(s): def process_arg(expr, arg): if arg.type.isGeckoInterface() and not arg.type.unroll().inner.isCallback(): - if arg.variadic or arg.type.isSequence() or arg.type.nullable() and arg.optional: + if arg.variadic or arg.type.isSequence(): expr += ".r()" - elif arg.type.nullable() or arg.optional: + elif arg.type.nullable() and arg.optional and not arg.defaultValue: + expr += ".as_ref().map(Option::deref)" + elif arg.type.nullable() or arg.optional and not arg.defaultValue: expr += ".deref()" else: expr = "&" + expr -- cgit v1.2.3 From 4d527b20eef23422d52e8f097a98b9ae00723fc3 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sun, 10 Mar 2019 18:37:14 +0100 Subject: Simplify RootedReference and make it specifically about slicesIt's now called DomSlice. --- components/script/dom/bindings/codegen/CodegenRust.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 3f15a316af3..df156fb0eb7 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -5899,7 +5899,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'crate::dom::bindings::root::Dom', 'crate::dom::bindings::root::DomRoot', 'crate::dom::bindings::root::OptionalHeapSetter', - 'crate::dom::bindings::root::RootedReference', + 'crate::dom::bindings::root::DomSlice', 'crate::dom::bindings::utils::AsVoidPtr', 'crate::dom::bindings::utils::DOMClass', 'crate::dom::bindings::utils::DOMJSClass', -- cgit v1.2.3 From 8bfd4dc1e2f9c71ff3d1f9964565c43a6ae02278 Mon Sep 17 00:00:00 2001 From: Peter Hall Date: Thu, 14 Feb 2019 12:53:59 +0000 Subject: #8539 Config preferences backend restructure --- components/script/dom/bindings/codegen/CodegenRust.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index df156fb0eb7..ea21989178b 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2586,7 +2586,7 @@ class CGConstructorEnabled(CGAbstractMethod): pref = iface.getExtendedAttribute("Pref") if pref: assert isinstance(pref, list) and len(pref) == 1 - conditions.append('PREFS.get("%s").as_boolean().unwrap_or(false)' % pref[0]) + conditions.append('prefs::pref_map().get("%s").as_bool().unwrap_or(false)' % pref[0]) func = iface.getExtendedAttribute("Func") if func: @@ -5977,7 +5977,8 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'crate::dom::globalscope::GlobalScope', 'crate::mem::malloc_size_of_including_raw_self', 'libc', - 'servo_config::prefs::PREFS', + 'servo_config::pref', + 'servo_config::prefs', 'std::borrow::ToOwned', 'std::cmp', 'std::mem', -- cgit v1.2.3 From 97deef4e19d192cdee2a7ef68b8639631f8d0194 Mon Sep 17 00:00:00 2001 From: Jan Andre Ikenmeyer Date: Fri, 10 May 2019 15:03:19 +0200 Subject: Update MPL license to https --- components/script/dom/bindings/codegen/parser/WebIDL.py | 2 +- .../script/dom/bindings/codegen/parser/tests/test_lenientSetter.py | 2 +- components/script/dom/bindings/codegen/parser/tests/test_replaceable.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index 5879f8b0064..31692bd1a2e 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.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 http://mozilla.org/MPL/2.0/. +# file, You can obtain one at https://mozilla.org/MPL/2.0/. """ A WebIDL parser. """ 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 78a9ffe9eaa..50e9df658e9 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 http://mozilla.org/MPL/2.0/. +# file, You can obtain one at https://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_replaceable.py b/components/script/dom/bindings/codegen/parser/tests/test_replaceable.py index 93ee42ed919..78b1bf7e60b 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 http://mozilla.org/MPL/2.0/. +# file, You can obtain one at https://mozilla.org/MPL/2.0/. def should_throw(parser, harness, message, code): parser = parser.reset(); -- cgit v1.2.3 From 4328713f71d5bc389ecd47e78bfe9b8087b8c104 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Mon, 6 May 2019 11:38:34 -0400 Subject: Update to SpiderMonkey 66. --- .../script/dom/bindings/codegen/CodegenRust.py | 37 +++++++++++----------- 1 file changed, 18 insertions(+), 19 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index ea21989178b..27bfdce71b4 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -458,7 +458,7 @@ class CGMethodCall(CGThing): pickFirstSignature("%s.get().is_object() && " "{ rooted!(in(cx) let obj = %s.get().to_object()); " "let mut is_date = false; " - "assert!(JS_ObjectIsDate(cx, obj.handle(), &mut is_date)); " + "assert!(ObjectIsDate(cx, obj.handle(), &mut is_date)); " "is_date }" % (distinguishingArg, distinguishingArg), lambda s: (s[1][distinguishingIndex].type.isDate() or @@ -795,7 +795,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, # our own implementation code. templateBody = fill( """ - { // Scope for our JSAutoCompartment. + { // Scope for our JSAutoRealm. rooted!(in(cx) let globalObj = CurrentGlobalOrNull(cx)); let promiseGlobal = GlobalScope::from_object_maybe_wrapped(globalObj.handle().get()); @@ -2709,7 +2709,7 @@ assert!(!scope.get().is_null()); assert!(((*get_object_class(scope.get())).flags & JSCLASS_IS_GLOBAL) != 0); rooted!(in(cx) let mut proto = ptr::null_mut::()); -let _ac = JSAutoCompartment::new(cx, scope.get()); +let _ac = JSAutoRealm::new(cx, scope.get()); GetProtoObject(cx, scope, proto.handle_mut()); assert!(!proto.is_null()); @@ -2764,7 +2764,7 @@ assert!(!obj.is_null()); (*raw).init_reflector(obj.get()); -let _ac = JSAutoCompartment::new(cx, obj.get()); +let _ac = JSAutoRealm::new(cx, obj.get()); rooted!(in(cx) let mut proto = ptr::null_mut::()); GetProtoObject(cx, obj.handle(), proto.handle_mut()); assert!(JS_SplicePrototype(cx, obj.handle(), proto.handle())); @@ -2883,7 +2883,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): name = self.descriptor.interface.identifier.name if self.descriptor.interface.isNamespace(): if self.descriptor.interface.getExtendedAttribute("ProtoObjectHack"): - proto = "JS_GetObjectPrototype(cx, global)" + proto = "GetRealmObjectPrototype(cx)" else: proto = "JS_NewPlainObject(cx)" if self.properties.static_methods.length(): @@ -2919,11 +2919,12 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); parentName = self.descriptor.getParentName() if not parentName: if self.descriptor.interface.getExtendedAttribute("ExceptionClass"): - getPrototypeProto = "prototype_proto.set(JS_GetErrorPrototype(cx))" + protoGetter = "GetRealmErrorPrototype" elif self.descriptor.interface.isIteratorInterface(): - getPrototypeProto = "prototype_proto.set(JS_GetIteratorPrototype(cx))" + protoGetter = "GetRealmIteratorPrototype" else: - getPrototypeProto = "prototype_proto.set(JS_GetObjectPrototype(cx, global))" + protoGetter = "GetRealmObjectPrototype" + getPrototypeProto = "prototype_proto.set(%s(cx))" % protoGetter else: getPrototypeProto = ("%s::GetProtoObject(cx, global, prototype_proto.handle_mut())" % toBindingNamespace(parentName)) @@ -2981,14 +2982,13 @@ assert!((*cache)[PrototypeList::ID::%(id)s as usize].is_null()); else: properties["length"] = 0 parentName = self.descriptor.getParentName() + code.append(CGGeneric("rooted!(in(cx) let mut interface_proto = ptr::null_mut::());")) if parentName: parentName = toBindingNamespace(parentName) code.append(CGGeneric(""" -rooted!(in(cx) let mut interface_proto = ptr::null_mut::()); %s::GetConstructorObject(cx, global, interface_proto.handle_mut());""" % parentName)) else: - code.append(CGGeneric(""" -rooted!(in(cx) let interface_proto = JS_GetFunctionPrototype(cx, global));""")) + code.append(CGGeneric("interface_proto.set(GetRealmFunctionPrototype(cx));")) code.append(CGGeneric("""\ assert!(!interface_proto.is_null()); @@ -5544,7 +5544,7 @@ if args.callee() == new_target.get() { rooted!(in(cx) let mut prototype = ptr::null_mut::()); { rooted!(in(cx) let mut proto_val = UndefinedValue()); - let _ac = JSAutoCompartment::new(cx, new_target.get()); + let _ac = JSAutoRealm::new(cx, new_target.get()); if !JS_GetProperty(cx, new_target.handle(), b"prototype\\0".as_ptr() as *const _, proto_val.handle_mut()) { return false; } @@ -5765,7 +5765,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::jsapi::Heap', 'js::jsapi::INTERNED_STRING_TO_JSID', 'js::jsapi::IsCallable', - 'js::jsapi::JSAutoCompartment', + 'js::jsapi::JSAutoRealm', 'js::jsapi::JSCLASS_FOREGROUND_FINALIZE', 'js::jsapi::JSCLASS_RESERVED_SLOTS_SHIFT', 'js::jsapi::JSClass', @@ -5804,11 +5804,10 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::rust::wrappers::JS_DefineProperty', 'js::rust::wrappers::JS_DefinePropertyById2', 'js::jsapi::JS_ForwardGetPropertyTo', - 'js::jsapi::JS_GetErrorPrototype', - 'js::rust::wrappers::JS_GetFunctionPrototype', - 'js::jsapi::JS_GetGlobalForObject', - 'js::jsapi::JS_GetIteratorPrototype', - 'js::rust::wrappers::JS_GetObjectPrototype', + 'js::jsapi::GetRealmErrorPrototype', + 'js::jsapi::GetRealmFunctionPrototype', + 'js::jsapi::GetRealmIteratorPrototype', + 'js::jsapi::GetRealmObjectPrototype', 'js::rust::wrappers::JS_GetProperty', 'js::jsapi::JS_GetPropertyById', 'js::jsapi::JS_GetPropertyDescriptorById', @@ -5819,7 +5818,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::jsapi::JS_NewObject', 'js::rust::wrappers::JS_NewObjectWithGivenProto', 'js::rust::wrappers::JS_NewObjectWithoutMetadata', - 'js::rust::wrappers::JS_ObjectIsDate', + 'js::rust::wrappers::ObjectIsDate', 'js::rust::wrappers::JS_SetImmutablePrototype', 'js::rust::wrappers::JS_SetProperty', 'js::rust::wrappers::JS_SetPrototype', -- cgit v1.2.3 From 7dbff6efb7ce93ecfb04883cd1dffa24a03ed0ad Mon Sep 17 00:00:00 2001 From: Bastien Orivel Date: Fri, 24 May 2019 22:24:41 +0200 Subject: Add an inCompartments config for bindings --- components/script/dom/bindings/codegen/Bindings.conf | 8 ++++++++ components/script/dom/bindings/codegen/CodegenRust.py | 15 +++++++++++---- components/script/dom/bindings/codegen/Configuration.py | 1 + 3 files changed, 20 insertions(+), 4 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf index d23583b76ef..0f847e4eead 100644 --- a/components/script/dom/bindings/codegen/Bindings.conf +++ b/components/script/dom/bindings/codegen/Bindings.conf @@ -40,6 +40,14 @@ DOMInterfaces = { 'WindowProxy' : { 'path': 'crate::dom::windowproxy::WindowProxy', 'register': False, +}, + +'Window': { + 'inCompartments': ['Fetch'], +}, + +'WorkerGlobalScope': { + 'inCompartments': ['Fetch'], } } diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 27bfdce71b4..9032012dea7 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -3316,6 +3316,8 @@ class CGCallGenerator(CGThing): if "cx" not in argsPre and needsCx: args.prepend(CGGeneric("cx")) + if nativeMethodName in descriptor.inCompartmentMethods: + args.append(CGGeneric("InCompartment::in_compartment(&AlreadyInCompartment::assert_for_cx(cx))")); # Build up our actual call self.cgRoot = CGList([], "\n") @@ -5640,7 +5642,7 @@ class CGInterfaceTrait(CGThing): name = CGSpecializedMethod.makeNativeName(descriptor, m) infallible = 'infallible' in descriptor.getExtendedAttributes(m) for idx, (rettype, arguments) in enumerate(m.signatures()): - arguments = method_arguments(descriptor, rettype, arguments) + arguments = method_arguments(descriptor, rettype, arguments, inCompartment=name in descriptor.inCompartmentMethods) rettype = return_type(descriptor, rettype, infallible) yield name + ('_' * idx), arguments, rettype elif m.isAttr() and not m.isStatic(): @@ -5671,7 +5673,7 @@ class CGInterfaceTrait(CGThing): if operation.isGetter(): if not rettype.nullable(): rettype = IDLNullableType(rettype.location, rettype) - arguments = method_arguments(descriptor, rettype, arguments) + arguments = method_arguments(descriptor, rettype, arguments, inCompartment=name in descriptor.inCompartmentMethods) # If this interface 'supports named properties', then we # should be able to access 'supported property names' @@ -5681,7 +5683,7 @@ class CGInterfaceTrait(CGThing): if operation.isNamed(): yield "SupportedPropertyNames", [], "Vec" else: - arguments = method_arguments(descriptor, rettype, arguments) + arguments = method_arguments(descriptor, rettype, arguments, inCompartment=name in descriptor.inCompartmentMethods) rettype = return_type(descriptor, rettype, infallible) yield name, arguments, rettype @@ -5975,6 +5977,8 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'crate::dom::windowproxy::WindowProxy', 'crate::dom::globalscope::GlobalScope', 'crate::mem::malloc_size_of_including_raw_self', + 'crate::compartments::InCompartment', + 'crate::compartments::AlreadyInCompartment', 'libc', 'servo_config::pref', 'servo_config::prefs', @@ -6676,7 +6680,7 @@ def argument_type(descriptorProvider, ty, optional=False, defaultValue=None, var return declType.define() -def method_arguments(descriptorProvider, returnType, arguments, passJSBits=True, trailing=None): +def method_arguments(descriptorProvider, returnType, arguments, passJSBits=True, trailing=None, inCompartment=False): if needCx(returnType, arguments, passJSBits): yield "cx", "*mut JSContext" @@ -6688,6 +6692,9 @@ def method_arguments(descriptorProvider, returnType, arguments, passJSBits=True, if trailing: yield trailing + if inCompartment: + yield "_comp", "InCompartment" + def return_type(descriptorProvider, rettype, infallible): result = getRetvalDeclarationForType(rettype, descriptorProvider) diff --git a/components/script/dom/bindings/codegen/Configuration.py b/components/script/dom/bindings/codegen/Configuration.py index 47a65d37d4b..81f61a648f1 100644 --- a/components/script/dom/bindings/codegen/Configuration.py +++ b/components/script/dom/bindings/codegen/Configuration.py @@ -223,6 +223,7 @@ class Descriptor(DescriptorProvider): self.concreteType = typeName self.register = desc.get('register', True) self.path = desc.get('path', pathDefault) + self.inCompartmentMethods = [name for name in desc.get('inCompartments', [])] self.bindingPath = 'crate::dom::bindings::codegen::Bindings::%s' % ('::'.join([ifaceName + 'Binding'] * 2)) self.outerObjectHook = desc.get('outerObjectHook', 'None') self.proxy = False -- cgit v1.2.3 From 0b29caa5548b0e307f2a891f5082b940c10d5762 Mon Sep 17 00:00:00 2001 From: Bastien Orivel Date: Sat, 25 May 2019 14:43:44 +0200 Subject: Add support for attributes to the inCompartments binding parameter --- components/script/dom/bindings/codegen/Bindings.conf | 6 +++++- components/script/dom/bindings/codegen/CodegenRust.py | 9 ++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf index 0f847e4eead..c8eba92d7b0 100644 --- a/components/script/dom/bindings/codegen/Bindings.conf +++ b/components/script/dom/bindings/codegen/Bindings.conf @@ -48,6 +48,10 @@ DOMInterfaces = { 'WorkerGlobalScope': { 'inCompartments': ['Fetch'], -} +}, + +'TestBinding': { + 'inCompartments': ['PromiseAttribute'], +}, } diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 9032012dea7..a4a74cff753 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -5627,13 +5627,16 @@ class CGInterfaceTrait(CGThing): def __init__(self, descriptor): CGThing.__init__(self) - def attribute_arguments(needCx, argument=None): + def attribute_arguments(needCx, argument=None, inCompartment=False): if needCx: yield "cx", "*mut JSContext" if argument: yield "value", argument_type(descriptor, argument) + if inCompartment: + yield "_comp", "InCompartment" + def members(): for m in descriptor.interface.members: if (m.isMethod() and not m.isStatic() and @@ -5649,7 +5652,7 @@ class CGInterfaceTrait(CGThing): name = CGSpecializedGetter.makeNativeName(descriptor, m) infallible = 'infallible' in descriptor.getExtendedAttributes(m, getter=True) yield (name, - attribute_arguments(typeNeedsCx(m.type, True)), + attribute_arguments(typeNeedsCx(m.type, True), inCompartment=name in descriptor.inCompartmentMethods), return_type(descriptor, m.type, infallible)) if not m.readonly: @@ -5659,7 +5662,7 @@ class CGInterfaceTrait(CGThing): rettype = "()" else: rettype = "ErrorResult" - yield name, attribute_arguments(typeNeedsCx(m.type, False), m.type), rettype + yield name, attribute_arguments(typeNeedsCx(m.type, False), m.type, inCompartment=name in descriptor.inCompartmentMethods), rettype if descriptor.proxy: for name, operation in descriptor.operations.iteritems(): -- cgit v1.2.3 From 292d468cd1552dd5644e8e0e2bf617b8bcac7655 Mon Sep 17 00:00:00 2001 From: Bastien Orivel Date: Sat, 25 May 2019 17:00:10 +0200 Subject: Use the newly added inCompartments option everywhere it can be --- .../script/dom/bindings/codegen/Bindings.conf | 85 +++++++++++++++++++++- 1 file changed, 82 insertions(+), 3 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf index c8eba92d7b0..e3de60005bc 100644 --- a/components/script/dom/bindings/codegen/Bindings.conf +++ b/components/script/dom/bindings/codegen/Bindings.conf @@ -31,7 +31,9 @@ DOMInterfaces = { }, #FIXME(jdm): This should be 'register': False, but then we don't generate enum types -'TestBinding': {}, +'TestBinding': { + 'inCompartments': ['PromiseAttribute', 'PromiseNativeHandler'], +}, 'URL': { 'weakReferenceable': True, @@ -50,8 +52,85 @@ DOMInterfaces = { 'inCompartments': ['Fetch'], }, -'TestBinding': { - 'inCompartments': ['PromiseAttribute'], +'CustomElementRegistry': { + 'inCompartments': ['WhenDefined'], +}, + +'AudioContext': { + 'inCompartments': ['Suspend', 'Close'], +}, + +'NavigationPreloadManager': { + 'inCompartments': ['Enable', 'Disable', 'SetHeaderValue', 'GetState'], +}, + +'HTMLMediaElement': { + 'inCompartments': ['Play'], +}, + +'BluetoothRemoteGATTDescriptor': { + 'inCompartments': ['ReadValue', 'WriteValue'], +}, + +'OfflineAudioContext': { + 'inCompartments': ['StartRendering'], +}, + +'BluetoothRemoteGATTServer': { + 'inCompartments': ['Connect'], +}, + +'ServiceWorkerContainer': { + 'inCompartments': ['Register'], +}, + +'Navigator': { + 'inCompartments': ['GetVRDisplays'], +}, + +'MediaDevices': { + 'inCompartments': ['GetUserMedia'], }, +'XRSession': { + 'inCompartments': ['UpdateRenderState', 'RequestReferenceSpace'], +}, + +'Bluetooth': { + 'inCompartments': ['RequestDevice', 'GetAvailability'], +}, + +'BaseAudioContext': { + 'inCompartments': ['Resume', 'DecodeAudioData'], +}, + +'RTCPeerConnection': { + 'inCompartments': ['AddIceCandidate', 'CreateOffer', 'CreateAnswer', 'SetLocalDescription', 'SetRemoteDescription'], +}, + +'BluetoothRemoteGATTCharacteristic': { + 'inCompartments': ['ReadValue', 'WriteValue', 'StartNotifications', 'StopNotifications'], +}, + +'VRDisplay': { + 'inCompartments': ['RequestPresent', 'ExitPresent'], +}, + +'Worklet': { + 'inCompartments': ['AddModule'], +}, + +'TestWorklet': { + 'inCompartments': ['AddModule'], +}, + +'BluetoothDevice': { + 'inCompartments': ['WatchAdvertisements'], +}, + +'XR': { + 'inCompartments': ['SupportsSessionMode', 'RequestSession'], +} + + } -- cgit v1.2.3 From b7e10a82247545c2f9894e9fb61540caf0b7f157 Mon Sep 17 00:00:00 2001 From: Bastien Orivel Date: Sat, 25 May 2019 23:23:42 +0200 Subject: Make tidy happy --- .../script/dom/bindings/codegen/CodegenRust.py | 28 +++++++++++++++------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index a4a74cff753..d365537e464 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -3317,7 +3317,7 @@ class CGCallGenerator(CGThing): if "cx" not in argsPre and needsCx: args.prepend(CGGeneric("cx")) if nativeMethodName in descriptor.inCompartmentMethods: - args.append(CGGeneric("InCompartment::in_compartment(&AlreadyInCompartment::assert_for_cx(cx))")); + args.append(CGGeneric("InCompartment::in_compartment(&AlreadyInCompartment::assert_for_cx(cx))")) # Build up our actual call self.cgRoot = CGList([], "\n") @@ -5634,8 +5634,8 @@ class CGInterfaceTrait(CGThing): if argument: yield "value", argument_type(descriptor, argument) - if inCompartment: - yield "_comp", "InCompartment" + if inCompartment: + yield "_comp", "InCompartment" def members(): for m in descriptor.interface.members: @@ -5645,14 +5645,18 @@ class CGInterfaceTrait(CGThing): name = CGSpecializedMethod.makeNativeName(descriptor, m) infallible = 'infallible' in descriptor.getExtendedAttributes(m) for idx, (rettype, arguments) in enumerate(m.signatures()): - arguments = method_arguments(descriptor, rettype, arguments, inCompartment=name in descriptor.inCompartmentMethods) + arguments = method_arguments(descriptor, rettype, arguments, + inCompartment=name in descriptor.inCompartmentMethods) rettype = return_type(descriptor, rettype, infallible) yield name + ('_' * idx), arguments, rettype elif m.isAttr() and not m.isStatic(): name = CGSpecializedGetter.makeNativeName(descriptor, m) infallible = 'infallible' in descriptor.getExtendedAttributes(m, getter=True) yield (name, - attribute_arguments(typeNeedsCx(m.type, True), inCompartment=name in descriptor.inCompartmentMethods), + attribute_arguments( + typeNeedsCx(m.type, True), + inCompartment=name in descriptor.inCompartmentMethods + ), return_type(descriptor, m.type, infallible)) if not m.readonly: @@ -5662,7 +5666,13 @@ class CGInterfaceTrait(CGThing): rettype = "()" else: rettype = "ErrorResult" - yield name, attribute_arguments(typeNeedsCx(m.type, False), m.type, inCompartment=name in descriptor.inCompartmentMethods), rettype + yield (name, + attribute_arguments( + typeNeedsCx(m.type, False), + m.type, + inCompartment=name in descriptor.inCompartmentMethods + ), + rettype) if descriptor.proxy: for name, operation in descriptor.operations.iteritems(): @@ -5676,7 +5686,8 @@ class CGInterfaceTrait(CGThing): if operation.isGetter(): if not rettype.nullable(): rettype = IDLNullableType(rettype.location, rettype) - arguments = method_arguments(descriptor, rettype, arguments, inCompartment=name in descriptor.inCompartmentMethods) + arguments = method_arguments(descriptor, rettype, arguments, + inCompartment=name in descriptor.inCompartmentMethods) # If this interface 'supports named properties', then we # should be able to access 'supported property names' @@ -5686,7 +5697,8 @@ class CGInterfaceTrait(CGThing): if operation.isNamed(): yield "SupportedPropertyNames", [], "Vec" else: - arguments = method_arguments(descriptor, rettype, arguments, inCompartment=name in descriptor.inCompartmentMethods) + arguments = method_arguments(descriptor, rettype, arguments, + inCompartment=name in descriptor.inCompartmentMethods) rettype = return_type(descriptor, rettype, infallible) yield name, arguments, rettype -- cgit v1.2.3 From 63714c90fb5bbad86f28fc188120b2ecfd3337ab Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Sun, 2 Jun 2019 23:38:12 -0400 Subject: Upgrade to Spidermonkey 67. --- .../script/dom/bindings/codegen/CodegenRust.py | 23 +++++++++------------- 1 file changed, 9 insertions(+), 14 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index d365537e464..dcbdea765d4 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -466,7 +466,7 @@ class CGMethodCall(CGThing): # Check for vanilla JS objects # XXXbz Do we need to worry about security wrappers? - pickFirstSignature("%s.get().is_object() && !is_platform_object(%s.get().to_object())" % + pickFirstSignature("%s.get().is_object() && !is_platform_object(%s.get().to_object(), cx)" % (distinguishingArg, distinguishingArg), lambda s: (s[1][distinguishingIndex].type.isCallback() or s[1][distinguishingIndex].type.isCallbackInterface() or @@ -798,7 +798,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, { // Scope for our JSAutoRealm. rooted!(in(cx) let globalObj = CurrentGlobalOrNull(cx)); - let promiseGlobal = GlobalScope::from_object_maybe_wrapped(globalObj.handle().get()); + let promiseGlobal = GlobalScope::from_object_maybe_wrapped(globalObj.handle().get(), cx); rooted!(in(cx) let mut valueToResolve = $${val}.get()); if !JS_WrapValue(cx, valueToResolve.handle_mut()) { @@ -866,7 +866,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, templateBody = fill( """ - match ${function}($${val}) { + match ${function}($${val}, cx) { Ok(val) => val, Err(()) => { $*{failureCode} @@ -2158,8 +2158,8 @@ class CGDOMJSClass(CGThing): static CLASS_OPS: js::jsapi::JSClassOps = js::jsapi::JSClassOps { addProperty: None, delProperty: None, - enumerate: %(enumerateHook)s, - newEnumerate: None, + enumerate: None, + newEnumerate: %(enumerateHook)s, resolve: %(resolveHook)s, mayResolve: None, finalize: Some(%(finalizeHook)s), @@ -3223,7 +3223,6 @@ let traps = ProxyTraps { set: None, call: None, construct: None, - getPropertyDescriptor: Some(get_property_descriptor), hasOwn: Some(hasOwn), getOwnEnumerablePropertyKeys: Some(%(getOwnEnumerablePropertyKeys)s), nativeCall: None, @@ -4980,10 +4979,6 @@ class CGProxyUnwrap(CGAbstractMethod): def definition_body(self): return CGGeneric("""\ -/*if (xpc::WrapperFactory::IsXrayWrapper(obj)) { - obj = js::UnwrapObject(obj); -}*/ -//MOZ_ASSERT(IsProxy(obj)); let mut slot = UndefinedValue(); GetProxyReservedSlot(obj.get(), 0, &mut slot); let box_ = slot.to_private() as *const %s; @@ -5430,7 +5425,7 @@ class CGAbstractClassHook(CGAbstractExternMethod): def definition_body_prologue(self): return CGGeneric(""" -let this = native_from_object::<%s>(obj).unwrap(); +let this = native_from_object_static::<%s>(obj).unwrap(); """ % self.descriptor.concreteType) def definition_body(self): @@ -5530,7 +5525,7 @@ let global = DomRoot::downcast::(global).unwrap(); // The new_target might be a cross-compartment wrapper. Get the underlying object // so we can do the spec's object-identity checks. -rooted!(in(cx) let new_target = UnwrapObject(args.new_target().to_object(), 1)); +rooted!(in(cx) let new_target = UnwrapObjectDynamic(args.new_target().to_object(), cx, 1)); if new_target.is_null() { throw_dom_exception(cx, global.upcast::(), Error::Type("new.target is null".to_owned())); return false; @@ -5877,7 +5872,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::glue::RUST_JSID_IS_STRING', 'js::glue::RUST_SYMBOL_TO_JSID', 'js::glue::int_to_jsid', - 'js::glue::UnwrapObject', + 'js::glue::UnwrapObjectDynamic', 'js::panic::maybe_resume_unwind', 'js::panic::wrap_panic', 'js::rust::GCMethods', @@ -5959,6 +5954,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'crate::dom::bindings::conversions::is_array_like', 'crate::dom::bindings::conversions::native_from_handlevalue', 'crate::dom::bindings::conversions::native_from_object', + 'crate::dom::bindings::conversions::native_from_object_static', 'crate::dom::bindings::conversions::private_from_object', 'crate::dom::bindings::conversions::root_from_handleobject', 'crate::dom::bindings::conversions::root_from_handlevalue', @@ -5979,7 +5975,6 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'crate::dom::bindings::proxyhandler::ensure_expando_object', 'crate::dom::bindings::proxyhandler::fill_property_descriptor', 'crate::dom::bindings::proxyhandler::get_expando_object', - 'crate::dom::bindings::proxyhandler::get_property_descriptor', 'crate::dom::bindings::mozmap::MozMap', 'std::ptr::NonNull', 'crate::dom::bindings::num::Finite', -- cgit v1.2.3 From 3c7ceff46d38d78971ca2d011d7c86a1835d787e Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 27 Jun 2019 17:35:20 -0700 Subject: Improve support for nested dictionaries --- components/script/dom/bindings/codegen/parser/WebIDL.py | 3 ++- .../bindings/codegen/parser/undo-dictionary-optional.patch | 12 ------------ components/script/dom/bindings/codegen/parser/update.sh | 1 - 3 files changed, 2 insertions(+), 14 deletions(-) delete mode 100644 components/script/dom/bindings/codegen/parser/undo-dictionary-optional.patch (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index 31692bd1a2e..df88cf120dd 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.py @@ -4611,7 +4611,8 @@ class IDLArgument(IDLObjectWithIdentifier): if ((self.type.isDictionary() or self.type.isUnion() and self.type.unroll().hasDictionaryType()) and - self.optional and not self.defaultValue and not self.variadic): + 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) diff --git a/components/script/dom/bindings/codegen/parser/undo-dictionary-optional.patch b/components/script/dom/bindings/codegen/parser/undo-dictionary-optional.patch deleted file mode 100644 index b414a536415..00000000000 --- a/components/script/dom/bindings/codegen/parser/undo-dictionary-optional.patch +++ /dev/null @@ -1,12 +0,0 @@ ---- WebIDL.py -+++ WebIDL.py -@@ -4570,8 +4570,7 @@ class IDLArgument(IDLObjectWithIdentifier): - - 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): -+ self.optional and not self.defaultValue and not self.variadic): - # 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) diff --git a/components/script/dom/bindings/codegen/parser/update.sh b/components/script/dom/bindings/codegen/parser/update.sh index 0386b0294fe..213aba6df89 100755 --- a/components/script/dom/bindings/codegen/parser/update.sh +++ b/components/script/dom/bindings/codegen/parser/update.sh @@ -5,7 +5,6 @@ patch < pref-main-thread.patch patch < callback-location.patch patch < union-typedef.patch patch < inline.patch -patch < undo-dictionary-optional.patch wget https://hg.mozilla.org/mozilla-central/archive/tip.tar.gz/dom/bindings/parser/tests/ -O tests.tar.gz rm -r tests -- cgit v1.2.3 From 40dbb2c1008f9629e6794d980fdc9374a8bbbb59 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Fri, 5 Jul 2019 11:03:34 +0900 Subject: Implement DOMPoint.fromPoint --- components/script/dom/bindings/codegen/CodegenRust.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index dcbdea765d4..114b403d077 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -6414,7 +6414,8 @@ class CGDictionary(CGThing): conversion = ( "{\n" " rooted!(in(cx) let mut rval = UndefinedValue());\n" - " if r#try!(get_dictionary_property(cx, object.handle(), \"%s\", rval.handle_mut())) {\n" + " if r#try!(get_dictionary_property(cx, object.handle(), \"%s\", rval.handle_mut()))" + " && !rval.is_undefined() {\n" "%s\n" " } else {\n" "%s\n" -- cgit v1.2.3 From 56f31c85ef9cc79140f375641302310c6680ded4 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Thu, 11 Jul 2019 13:16:10 +0900 Subject: Sync WebIDL.py with gecko --- .../script/dom/bindings/codegen/parser/WebIDL.py | 337 ++++++++++++++------- .../dom/bindings/codegen/parser/abstract.patch | 10 +- .../codegen/parser/callback-location.patch | 6 +- .../script/dom/bindings/codegen/parser/debug.patch | 2 +- .../dom/bindings/codegen/parser/inline.patch | 4 +- .../bindings/codegen/parser/pref-main-thread.patch | 27 -- .../script/dom/bindings/codegen/parser/runtests.py | 2 +- .../dom/bindings/codegen/parser/tests/test_attr.py | 8 +- .../bindings/codegen/parser/tests/test_callback.py | 3 + .../parser/tests/test_callback_constructor.py | 63 ++++ .../codegen/parser/tests/test_cereactions.py | 4 +- .../tests/test_conditional_dictionary_member.py | 6 +- .../bindings/codegen/parser/tests/test_const.py | 19 +- .../parser/tests/test_constructor_global.py | 87 ++++++ .../tests/test_constructor_no_interface_object.py | 1 + .../codegen/parser/tests/test_dictionary.py | 82 ++++- .../parser/tests/test_distinguishability.py | 27 +- .../tests/test_empty_sequence_default_value.py | 2 +- .../codegen/parser/tests/test_error_colno.py | 2 +- .../codegen/parser/tests/test_error_lineno.py | 2 +- .../tests/test_exposed_extended_attribute.py | 12 +- .../codegen/parser/tests/test_float_types.py | 10 +- .../parser/tests/test_identifier_conflict.py | 6 +- .../codegen/parser/tests/test_interface.py | 86 ++++++ .../tests/test_interface_maplikesetlikeiterable.py | 4 +- .../codegen/parser/tests/test_lenientSetter.py | 2 +- .../bindings/codegen/parser/tests/test_method.py | 89 +++++- .../codegen/parser/tests/test_namespace.py | 18 +- .../bindings/codegen/parser/tests/test_record.py | 4 +- .../codegen/parser/tests/test_replaceable.py | 2 +- .../bindings/codegen/parser/tests/test_typedef.py | 8 +- .../tests/test_unenumerable_own_properties.py | 6 +- .../codegen/parser/tests/test_unforgeable.py | 4 +- .../bindings/codegen/parser/tests/test_union.py | 2 +- .../script/dom/bindings/codegen/parser/update.sh | 1 - 35 files changed, 727 insertions(+), 221 deletions(-) delete mode 100644 components/script/dom/bindings/codegen/parser/pref-main-thread.patch create mode 100644 components/script/dom/bindings/codegen/parser/tests/test_callback_constructor.py create mode 100644 components/script/dom/bindings/codegen/parser/tests/test_constructor_global.py (limited to 'components/script/dom/bindings/codegen') 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 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 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(""), 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 @@ -167,6 +167,22 @@ def WebIDLTest(parser, harness): harness.ok(threw, "Trailing dictionary arg must be optional") + parser = parser.reset() + threw = False + try: + parser.parse(""" + 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: @@ -184,6 +200,23 @@ def WebIDLTest(parser, harness): harness.ok(threw, "Trailing union arg containing a dictionary must be optional") + parser = parser.reset() + threw = False + try: + parser.parse(""" + 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: @@ -200,6 +233,22 @@ def WebIDLTest(parser, harness): harness.ok(threw, "Dictionary arg followed by optional arg must be optional") + parser = parser.reset() + threw = False + try: + parser.parse(""" + 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: @@ -235,6 +284,24 @@ def WebIDLTest(parser, harness): "Union arg containing dictionary followed by optional arg must " "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,12 +404,23 @@ 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: 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", "sequence", + "object", "Callback", "Callback2", "Dict", + "Dict2", "sequence", "sequence", "record", "record", "record", @@ -165,7 +168,7 @@ def WebIDLTest(parser, harness): "Promise", "Promise?", "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" and a != "Promise?")] - 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?"] + 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", allBut(argTypes, sequences + ["object"])) setDistinguishable("sequence", @@ -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 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 -- cgit v1.2.3 From 01151274f1487e630852680ba38ab5a651db44ec Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Sat, 6 Jul 2019 16:20:50 +0900 Subject: Require default dictionary value for optional dicts --- components/script/dom/bindings/codegen/CodegenRust.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 114b403d077..98df7a8b51f 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -17,6 +17,7 @@ import functools from WebIDL import ( BuiltinTypes, IDLBuiltinType, + IDLDefaultDictionaryValue, IDLEmptySequenceValue, IDLInterfaceMember, IDLNullableType, @@ -678,13 +679,16 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, return None if isinstance(defaultValue, IDLNullValue): - assert type.nullable() or type.isDictionary() + assert type.nullable() + return nullValue + elif isinstance(defaultValue, IDLDefaultDictionaryValue): + assert type.isDictionary() return nullValue elif isinstance(defaultValue, IDLEmptySequenceValue): assert type.isSequence() return "Vec::new()" - raise TypeError("Can't handle non-null or non-empty sequence default value here") + raise TypeError("Can't handle non-null, non-empty sequence or non-empty dictionary default value here") # A helper function for wrapping up the template body for # possibly-nullable objecty stuff @@ -747,17 +751,19 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, for memberType in type.unroll().flatMemberTypes if memberType.isDictionary() ] - if defaultValue and not isinstance(defaultValue, IDLNullValue): + if (defaultValue and + not isinstance(defaultValue, IDLNullValue) and + not isinstance(defaultValue, IDLDefaultDictionaryValue)): tag = defaultValue.type.tag() if tag is IDLType.Tags.bool: default = "%s::Boolean(%s)" % ( union_native_type(type), "true" if defaultValue.value else "false") else: - raise("We don't currently support default values that aren't null or boolean") + raise("We don't currently support default values that aren't null, boolean or default dictionary") elif dictionaries: if defaultValue: - assert isinstance(defaultValue, IDLNullValue) + assert isinstance(defaultValue, IDLDefaultDictionaryValue) dictionary, = dictionaries default = "%s::%s(%s::%s::empty())" % ( union_native_type(type), -- cgit v1.2.3 From 871239a3e302d4aefdbbad1b0141511dcd66afc4 Mon Sep 17 00:00:00 2001 From: sreeise Date: Tue, 28 May 2019 03:23:47 -0400 Subject: Change bindings generation to make Exposed annotation aware of members/partial interfaces --- .../script/dom/bindings/codegen/CodegenRust.py | 28 +++++++++++++++------- .../script/dom/bindings/codegen/parser/WebIDL.py | 5 ++++ .../bindings/codegen/parser/exposed-globals.patch | 27 +++++++++++++++++++++ .../script/dom/bindings/codegen/parser/update.sh | 1 + 4 files changed, 53 insertions(+), 8 deletions(-) create mode 100644 components/script/dom/bindings/codegen/parser/exposed-globals.patch (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 98df7a8b51f..e0c7725fa52 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1513,7 +1513,7 @@ def getRetvalDeclarationForType(returnType, descriptorProvider): returnType) -def MemberCondition(pref, func): +def MemberCondition(pref, func, exposed): """ A string representing the condition for a member to actually be exposed. Any of the arguments can be None. If not None, they should have the @@ -1521,14 +1521,18 @@ def MemberCondition(pref, func): pref: The name of the preference. func: The name of the function. + exposed: One or more names of an exposed global. """ assert pref is None or isinstance(pref, str) assert func is None or isinstance(func, str) - assert func is None or pref is None + assert exposed is None or isinstance(exposed, set) + assert func is None or pref is None or exposed is None if pref: return 'Condition::Pref("%s")' % pref if func: return 'Condition::Func(%s)' % func + if exposed: + return ["Condition::Exposed(InterfaceObjectMap::Globals::%s)" % camel_to_upper_snake(i) for i in exposed] return "Condition::Satisfied" @@ -1571,7 +1575,8 @@ class PropertyDefiner: PropertyDefiner.getStringAttr(interfaceMember, "Pref"), PropertyDefiner.getStringAttr(interfaceMember, - "Func")) + "Func"), + interfaceMember.exposedSet()) def generateGuardedArray(self, array, name, specTemplate, specTerminator, specType, getCondition, getDataTuple): @@ -1609,8 +1614,13 @@ class PropertyDefiner: if specTerminator: currentSpecs.append(specTerminator) specs.append("&[\n" + ",\n".join(currentSpecs) + "]\n") - prefableSpecs.append( - prefableTemplate % (cond, name + "_specs", len(specs) - 1)) + if isinstance(cond, list): + for i in cond: + prefableSpecs.append( + prefableTemplate % (i, name + "_specs", len(specs) - 1)) + else: + prefableSpecs.append( + prefableTemplate % (cond, name + "_specs", len(specs) - 1)) specsArray = ("const %s_specs: &'static [&'static[%s]] = &[\n" + ",\n".join(specs) + "\n" + @@ -2640,8 +2650,8 @@ def InitUnforgeablePropertiesOnHolder(descriptor, properties): """ unforgeables = [] - defineUnforgeableAttrs = "define_guarded_properties(cx, unforgeable_holder.handle(), %s);" - defineUnforgeableMethods = "define_guarded_methods(cx, unforgeable_holder.handle(), %s);" + defineUnforgeableAttrs = "define_guarded_properties(cx, unforgeable_holder.handle(), %s, global);" + defineUnforgeableMethods = "define_guarded_methods(cx, unforgeable_holder.handle(), %s, global);" unforgeableMembers = [ (defineUnforgeableAttrs, properties.unforgeable_attrs), @@ -2751,7 +2761,7 @@ class CGWrapGlobalMethod(CGAbstractMethod): ("define_guarded_methods", self.properties.methods), ("define_guarded_constants", self.properties.consts) ] - members = ["%s(cx, obj.handle(), %s);" % (function, array.variableName()) + members = ["%s(cx, obj.handle(), %s, obj.handle());" % (function, array.variableName()) for (function, array) in pairs if array.length() > 0] values["members"] = "\n".join(members) @@ -2966,6 +2976,7 @@ assert!(!prototype_proto.is_null());""" % getPrototypeProto)] code.append(CGGeneric(""" rooted!(in(cx) let mut prototype = ptr::null_mut::()); create_interface_prototype_object(cx, + global.into(), prototype_proto.handle().into(), &PrototypeClass, %(methods)s, @@ -7543,6 +7554,7 @@ impl %(base)s { for m in descriptor.interface.members: if PropertyDefiner.getStringAttr(m, 'Pref') or \ PropertyDefiner.getStringAttr(m, 'Func') or \ + PropertyDefiner.getStringAttr(m, 'Exposed') or \ (m.isMethod() and m.isIdentifierLess()): continue display = m.identifier.name + ('()' if m.isMethod() else '') diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index e18b6e34a2c..7ea8423e860 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.py @@ -3723,6 +3723,7 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins): IDLObjectWithIdentifier.__init__(self, location, None, identifier) IDLExposureMixins.__init__(self, location) self.tag = tag + self.exposed = set() if extendedAttrDict is None: self._extendedAttrDict = {} else: @@ -3756,12 +3757,16 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins): def getExtendedAttribute(self, name): return self._extendedAttrDict.get(name, None) + def exposedSet(self): + return self.exposed + def finish(self, scope): # We better be exposed _somewhere_. if (len(self._exposureGlobalNames) == 0): print(self.identifier.name) assert len(self._exposureGlobalNames) != 0 IDLExposureMixins.finish(self, scope) + globalNameSetToExposureSet(scope, self._exposureGlobalNames, self.exposed) def validate(self): if self.isAttr() or self.isMethod(): diff --git a/components/script/dom/bindings/codegen/parser/exposed-globals.patch b/components/script/dom/bindings/codegen/parser/exposed-globals.patch new file mode 100644 index 00000000000..02ad787f5e0 --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/exposed-globals.patch @@ -0,0 +1,27 @@ +--- WebIDL.py ++++ WebIDL.py +@@ -3653,6 +3653,7 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins): + IDLObjectWithIdentifier.__init__(self, location, None, identifier) + IDLExposureMixins.__init__(self, location) + self.tag = tag ++ self.exposed = set() + if extendedAttrDict is None: + self._extendedAttrDict = {} + else: +@@ -3686,12 +3687,16 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins): + def getExtendedAttribute(self, name): + return self._extendedAttrDict.get(name, None) + ++ def exposedSet(self): ++ return self.exposed ++ + def finish(self, scope): + # We better be exposed _somewhere_. + if (len(self._exposureGlobalNames) == 0): + print self.identifier.name + assert len(self._exposureGlobalNames) != 0 + IDLExposureMixins.finish(self, scope) ++ globalNameSetToExposureSet(scope, self._exposureGlobalNames, self.exposed) + + def validate(self): + if self.isAttr() or self.isMethod(): diff --git a/components/script/dom/bindings/codegen/parser/update.sh b/components/script/dom/bindings/codegen/parser/update.sh index fee9720ab2d..570b8b4506d 100755 --- a/components/script/dom/bindings/codegen/parser/update.sh +++ b/components/script/dom/bindings/codegen/parser/update.sh @@ -4,6 +4,7 @@ patch < debug.patch patch < callback-location.patch patch < union-typedef.patch patch < inline.patch +patch < exposed-globals.patch wget https://hg.mozilla.org/mozilla-central/archive/tip.tar.gz/dom/bindings/parser/tests/ -O tests.tar.gz rm -r tests -- cgit v1.2.3 From cd0eb88a3e4077590ff9419399d8226c1694de5b Mon Sep 17 00:00:00 2001 From: marmeladema Date: Sat, 20 Jul 2019 15:34:26 +0100 Subject: ConstructorEnabled now takes a SafeJSContext instead of a JSContext a first argument. The function cannot be made safe because of call to unsafe function is_exposed_in. --- components/script/dom/bindings/codegen/CodegenRust.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index e0c7725fa52..6f70e5e64f1 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2586,7 +2586,7 @@ class CGConstructorEnabled(CGAbstractMethod): def __init__(self, descriptor): CGAbstractMethod.__init__(self, descriptor, 'ConstructorEnabled', 'bool', - [Argument("*mut JSContext", "aCx"), + [Argument("SafeJSContext", "aCx"), Argument("HandleObject", "aObj")], unsafe=True) @@ -3285,7 +3285,7 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod): return CGGeneric("""\ assert!(!global.get().is_null()); -if !ConstructorEnabled(cx, global) { +if !ConstructorEnabled(SafeJSContext::from_ptr(cx), global) { return; } @@ -6006,6 +6006,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'crate::mem::malloc_size_of_including_raw_self', 'crate::compartments::InCompartment', 'crate::compartments::AlreadyInCompartment', + 'crate::script_runtime::JSContext as SafeJSContext', 'libc', 'servo_config::pref', 'servo_config::prefs', -- cgit v1.2.3 From 35dc5320ab1a9e71db8212304f44969efa3c342b Mon Sep 17 00:00:00 2001 From: marmeladema Date: Sat, 20 Jul 2019 17:30:10 +0100 Subject: Wrap(Global)Method now takes a SafeJSContext instead of a JSContext as first argument. --- .../script/dom/bindings/codegen/CodegenRust.py | 45 +++++++++++----------- 1 file changed, 23 insertions(+), 22 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 6f70e5e64f1..3f3dafdf357 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2618,17 +2618,17 @@ def CreateBindingJSObject(descriptor): if descriptor.proxy: create += """ let handler = RegisterBindings::PROXY_HANDLERS[PrototypeList::Proxies::%s as usize]; -rooted!(in(cx) let private = PrivateValue(raw as *const libc::c_void)); -let obj = NewProxyObject(cx, handler, +rooted!(in(*cx) let private = PrivateValue(raw as *const libc::c_void)); +let obj = NewProxyObject(*cx, handler, Handle::from_raw(UndefinedHandleValue), proto.get()); assert!(!obj.is_null()); SetProxyReservedSlot(obj, 0, &private.get()); -rooted!(in(cx) let obj = obj);\ +rooted!(in(*cx) let obj = obj);\ """ % (descriptor.name) else: - create += ("rooted!(in(cx) let obj = JS_NewObjectWithGivenProto(\n" - " cx, &Class.base as *const JSClass, proto.handle()));\n" + create += ("rooted!(in(*cx) let obj = JS_NewObjectWithGivenProto(\n" + " *cx, &Class.base as *const JSClass, proto.handle()));\n" "assert!(!obj.is_null());\n" "\n" "let val = PrivateValue(raw as *const libc::c_void);\n" @@ -2676,8 +2676,8 @@ def CopyUnforgeablePropertiesToInstance(descriptor): # reflector, so we can make sure we don't get confused by named getters. if descriptor.proxy: copyCode += """\ -rooted!(in(cx) let mut expando = ptr::null_mut::()); -ensure_expando_object(cx, obj.handle().into(), expando.handle_mut()); +rooted!(in(*cx) let mut expando = ptr::null_mut::()); +ensure_expando_object(*cx, obj.handle().into(), expando.handle_mut()); """ obj = "expando" else: @@ -2693,9 +2693,9 @@ ensure_expando_object(cx, obj.handle().into(), expando.handle_mut()); copyCode += """\ let mut slot = UndefinedValue(); JS_GetReservedSlot(proto.get(), DOM_PROTO_UNFORGEABLE_HOLDER_SLOT, &mut slot); -rooted!(in(cx) let mut unforgeable_holder = ptr::null_mut::()); +rooted!(in(*cx) let mut unforgeable_holder = ptr::null_mut::()); unforgeable_holder.handle_mut().set(slot.to_object()); -assert!(%(copyFunc)s(cx, %(obj)s.handle(), unforgeable_holder.handle())); +assert!(%(copyFunc)s(*cx, %(obj)s.handle(), unforgeable_holder.handle())); """ % {'copyFunc': copyFunc, 'obj': obj} return copyCode @@ -2709,7 +2709,7 @@ class CGWrapMethod(CGAbstractMethod): def __init__(self, descriptor): assert not descriptor.interface.isCallback() assert not descriptor.isGlobal() - args = [Argument('*mut JSContext', 'cx'), + args = [Argument('SafeJSContext', 'cx'), Argument('&GlobalScope', 'scope'), Argument("Box<%s>" % descriptor.concreteType, 'object')] retval = 'DomRoot<%s>' % descriptor.concreteType @@ -2724,9 +2724,9 @@ let scope = scope.reflector().get_jsobject(); assert!(!scope.get().is_null()); assert!(((*get_object_class(scope.get())).flags & JSCLASS_IS_GLOBAL) != 0); -rooted!(in(cx) let mut proto = ptr::null_mut::()); -let _ac = JSAutoRealm::new(cx, scope.get()); -GetProtoObject(cx, scope, proto.handle_mut()); +rooted!(in(*cx) let mut proto = ptr::null_mut::()); +let _ac = JSAutoRealm::new(*cx, scope.get()); +GetProtoObject(*cx, scope, proto.handle_mut()); assert!(!proto.is_null()); %(createObject)s @@ -2744,7 +2744,7 @@ class CGWrapGlobalMethod(CGAbstractMethod): def __init__(self, descriptor, properties): assert not descriptor.interface.isCallback() assert descriptor.isGlobal() - args = [Argument('*mut JSContext', 'cx'), + args = [Argument('SafeJSContext', 'cx'), Argument("Box<%s>" % descriptor.concreteType, 'object')] retval = 'DomRoot<%s>' % descriptor.concreteType CGAbstractMethod.__init__(self, descriptor, 'Wrap', retval, args, @@ -2761,7 +2761,7 @@ class CGWrapGlobalMethod(CGAbstractMethod): ("define_guarded_methods", self.properties.methods), ("define_guarded_constants", self.properties.consts) ] - members = ["%s(cx, obj.handle(), %s, obj.handle());" % (function, array.variableName()) + members = ["%s(*cx, obj.handle(), %s, obj.handle());" % (function, array.variableName()) for (function, array) in pairs if array.length() > 0] values["members"] = "\n".join(members) @@ -2769,9 +2769,9 @@ class CGWrapGlobalMethod(CGAbstractMethod): let raw = Box::into_raw(object); let _rt = RootedTraceable::new(&*raw); -rooted!(in(cx) let mut obj = ptr::null_mut::()); +rooted!(in(*cx) let mut obj = ptr::null_mut::()); create_global_object( - cx, + *cx, &Class.base, raw as *const libc::c_void, _trace, @@ -2780,12 +2780,12 @@ assert!(!obj.is_null()); (*raw).init_reflector(obj.get()); -let _ac = JSAutoRealm::new(cx, obj.get()); -rooted!(in(cx) let mut proto = ptr::null_mut::()); -GetProtoObject(cx, obj.handle(), proto.handle_mut()); -assert!(JS_SplicePrototype(cx, obj.handle(), proto.handle())); +let _ac = JSAutoRealm::new(*cx, obj.get()); +rooted!(in(*cx) let mut proto = ptr::null_mut::()); +GetProtoObject(*cx, obj.handle(), proto.handle_mut()); +assert!(JS_SplicePrototype(*cx, obj.handle(), proto.handle())); let mut immutable = false; -assert!(JS_SetImmutablePrototype(cx, obj.handle(), &mut immutable)); +assert!(JS_SetImmutablePrototype(*cx, obj.handle(), &mut immutable)); assert!(immutable); %(members)s @@ -6022,6 +6022,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'std::rc::Rc', 'std::default::Default', 'std::ffi::CString', + 'std::ops::Deref', ], config) -- cgit v1.2.3 From 0a5a9bc7bca487cb2712b6b77a1936be276cd1e1 Mon Sep 17 00:00:00 2001 From: marmeladema Date: Sat, 20 Jul 2019 18:21:49 +0100 Subject: CreateInterfaceObjects now takes a SafeJSContext instead of a JSContext as first argument. --- .../script/dom/bindings/codegen/CodegenRust.py | 58 +++++++++++----------- 1 file changed, 29 insertions(+), 29 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 3f3dafdf357..12f6b61a533 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2650,8 +2650,8 @@ def InitUnforgeablePropertiesOnHolder(descriptor, properties): """ unforgeables = [] - defineUnforgeableAttrs = "define_guarded_properties(cx, unforgeable_holder.handle(), %s, global);" - defineUnforgeableMethods = "define_guarded_methods(cx, unforgeable_holder.handle(), %s, global);" + defineUnforgeableAttrs = "define_guarded_properties(*cx, unforgeable_holder.handle(), %s, global);" + defineUnforgeableMethods = "define_guarded_methods(*cx, unforgeable_holder.handle(), %s, global);" unforgeableMembers = [ (defineUnforgeableAttrs, properties.unforgeable_attrs), @@ -2888,7 +2888,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): properties should be a PropertyArrays instance. """ def __init__(self, descriptor, properties, haveUnscopables): - args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'global'), + args = [Argument('SafeJSContext', 'cx'), Argument('HandleObject', 'global'), Argument('*mut ProtoOrIfaceArray', 'cache')] CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'void', args, unsafe=True) @@ -2899,18 +2899,18 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): name = self.descriptor.interface.identifier.name if self.descriptor.interface.isNamespace(): if self.descriptor.interface.getExtendedAttribute("ProtoObjectHack"): - proto = "GetRealmObjectPrototype(cx)" + proto = "GetRealmObjectPrototype(*cx)" else: - proto = "JS_NewPlainObject(cx)" + proto = "JS_NewPlainObject(*cx)" if self.properties.static_methods.length(): methods = self.properties.static_methods.variableName() else: methods = "&[]" return CGGeneric("""\ -rooted!(in(cx) let proto = %(proto)s); +rooted!(in(*cx) let proto = %(proto)s); assert!(!proto.is_null()); -rooted!(in(cx) let mut namespace = ptr::null_mut::()); -create_namespace_object(cx, global, proto.handle(), &NAMESPACE_OBJECT_CLASS, +rooted!(in(*cx) let mut namespace = ptr::null_mut::()); +create_namespace_object(*cx, global, proto.handle(), &NAMESPACE_OBJECT_CLASS, %(methods)s, %(name)s, namespace.handle_mut()); assert!(!namespace.is_null()); assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); @@ -2922,8 +2922,8 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); if self.descriptor.interface.isCallback(): assert not self.descriptor.interface.ctor() and self.descriptor.interface.hasConstants() return CGGeneric("""\ -rooted!(in(cx) let mut interface = ptr::null_mut::()); -create_callback_interface_object(cx, global, sConstants, %(name)s, interface.handle_mut()); +rooted!(in(*cx) let mut interface = ptr::null_mut::()); +create_callback_interface_object(*cx, global, sConstants, %(name)s, interface.handle_mut()); assert!(!interface.is_null()); assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); (*cache)[PrototypeList::Constructor::%(id)s as usize] = interface.get(); @@ -2940,13 +2940,13 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); protoGetter = "GetRealmIteratorPrototype" else: protoGetter = "GetRealmObjectPrototype" - getPrototypeProto = "prototype_proto.set(%s(cx))" % protoGetter + getPrototypeProto = "prototype_proto.set(%s(*cx))" % protoGetter else: - getPrototypeProto = ("%s::GetProtoObject(cx, global, prototype_proto.handle_mut())" % + getPrototypeProto = ("%s::GetProtoObject(*cx, global, prototype_proto.handle_mut())" % toBindingNamespace(parentName)) code = [CGGeneric("""\ -rooted!(in(cx) let mut prototype_proto = ptr::null_mut::()); +rooted!(in(*cx) let mut prototype_proto = ptr::null_mut::()); %s; assert!(!prototype_proto.is_null());""" % getPrototypeProto)] @@ -2974,8 +2974,8 @@ assert!(!prototype_proto.is_null());""" % getPrototypeProto)] proto_properties = properties code.append(CGGeneric(""" -rooted!(in(cx) let mut prototype = ptr::null_mut::()); -create_interface_prototype_object(cx, +rooted!(in(*cx) let mut prototype = ptr::null_mut::()); +create_interface_prototype_object(*cx, global.into(), prototype_proto.handle().into(), &PrototypeClass, @@ -2999,18 +2999,18 @@ assert!((*cache)[PrototypeList::ID::%(id)s as usize].is_null()); else: properties["length"] = 0 parentName = self.descriptor.getParentName() - code.append(CGGeneric("rooted!(in(cx) let mut interface_proto = ptr::null_mut::());")) + code.append(CGGeneric("rooted!(in(*cx) let mut interface_proto = ptr::null_mut::());")) if parentName: parentName = toBindingNamespace(parentName) code.append(CGGeneric(""" -%s::GetConstructorObject(cx, global, interface_proto.handle_mut());""" % parentName)) +%s::GetConstructorObject(*cx, global, interface_proto.handle_mut());""" % parentName)) else: - code.append(CGGeneric("interface_proto.set(GetRealmFunctionPrototype(cx));")) + code.append(CGGeneric("interface_proto.set(GetRealmFunctionPrototype(*cx));")) code.append(CGGeneric("""\ assert!(!interface_proto.is_null()); -rooted!(in(cx) let mut interface = ptr::null_mut::()); -create_noncallback_interface_object(cx, +rooted!(in(*cx) let mut interface = ptr::null_mut::()); +create_noncallback_interface_object(*cx, global.into(), interface_proto.handle(), &INTERFACE_OBJECT_CLASS, @@ -3035,8 +3035,8 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); if aliasedMembers: def defineAlias(alias): if alias == "@@iterator": - symbolJSID = "RUST_SYMBOL_TO_JSID(GetWellKnownSymbol(cx, SymbolCode::iterator))" - getSymbolJSID = CGGeneric(fill("rooted!(in(cx) let iteratorId = ${symbolJSID});", + symbolJSID = "RUST_SYMBOL_TO_JSID(GetWellKnownSymbol(*cx, SymbolCode::iterator))" + getSymbolJSID = CGGeneric(fill("rooted!(in(*cx) let iteratorId = ${symbolJSID});", symbolJSID=symbolJSID)) defineFn = "JS_DefinePropertyById2" prop = "iteratorId.handle()" @@ -3053,7 +3053,7 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); # match the enumerability of the property being aliased. CGGeneric(fill( """ - assert!(${defineFn}(cx, prototype.handle(), ${prop}, aliasedVal.handle(), + assert!(${defineFn}(*cx, prototype.handle(), ${prop}, aliasedVal.handle(), JSPROP_ENUMERATE as u32)); """, defineFn=defineFn, @@ -3064,7 +3064,7 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); return CGList([ CGGeneric(fill( """ - assert!(JS_GetProperty(cx, prototype.handle(), + assert!(JS_GetProperty(*cx, prototype.handle(), ${prop} as *const u8 as *const _, aliasedVal.handle_mut())); """, @@ -3076,7 +3076,7 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); // Set up aliases on the interface prototype object we just created. """)), - CGGeneric("rooted!(in(cx) let mut aliasedVal = UndefinedValue());\n\n") + CGGeneric("rooted!(in(*cx) let mut aliasedVal = UndefinedValue());\n\n") ] + [defineAliasesFor(m) for m in sorted(aliasedMembers)]) code.append(defineAliases) @@ -3091,7 +3091,7 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); specs.append(CGGeneric("(%s as ConstructorClassHook, %s, %d)" % (hook, name, length))) values = CGIndenter(CGList(specs, "\n"), 4) code.append(CGWrapper(values, pre="%s = [\n" % decl, post="\n];")) - code.append(CGGeneric("create_named_constructors(cx, global, &named_constructors, prototype.handle());")) + code.append(CGGeneric("create_named_constructors(*cx, global, &named_constructors, prototype.handle());")) if self.descriptor.hasUnforgeableMembers: # We want to use the same JSClass and prototype as the object we'll @@ -3112,9 +3112,9 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); holderClass = "&Class.base as *const JSClass" holderProto = "prototype.handle()" code.append(CGGeneric(""" -rooted!(in(cx) let mut unforgeable_holder = ptr::null_mut::()); +rooted!(in(*cx) let mut unforgeable_holder = ptr::null_mut::()); unforgeable_holder.handle_mut().set( - JS_NewObjectWithoutMetadata(cx, %(holderClass)s, %(holderProto)s)); + JS_NewObjectWithoutMetadata(*cx, %(holderClass)s, %(holderProto)s)); assert!(!unforgeable_holder.is_null()); """ % {'holderClass': holderClass, 'holderProto': holderProto})) code.append(InitUnforgeablePropertiesOnHolder(self.descriptor, self.properties)) @@ -3149,7 +3149,7 @@ if !rval.get().is_null() { return; } -CreateInterfaceObjects(cx, global, proto_or_iface_array); +CreateInterfaceObjects(SafeJSContext::from_ptr(cx), global, proto_or_iface_array); rval.set((*proto_or_iface_array)[%(id)s as usize]); assert!(!rval.get().is_null()); """ % {"id": self.id}) -- cgit v1.2.3 From aa0e4f5c76ceed459e3d53df47802ba9b388d913 Mon Sep 17 00:00:00 2001 From: marmeladema Date: Sun, 21 Jul 2019 01:01:22 +0100 Subject: GetPerInterfaceObject methods now takes a SafeJSContext instead of a JSContext as first argument. --- components/script/dom/bindings/codegen/CodegenRust.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 12f6b61a533..e656a7ab3ce 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2726,7 +2726,7 @@ assert!(((*get_object_class(scope.get())).flags & JSCLASS_IS_GLOBAL) != 0); rooted!(in(*cx) let mut proto = ptr::null_mut::()); let _ac = JSAutoRealm::new(*cx, scope.get()); -GetProtoObject(*cx, scope, proto.handle_mut()); +GetProtoObject(cx, scope, proto.handle_mut()); assert!(!proto.is_null()); %(createObject)s @@ -2782,7 +2782,7 @@ assert!(!obj.is_null()); let _ac = JSAutoRealm::new(*cx, obj.get()); rooted!(in(*cx) let mut proto = ptr::null_mut::()); -GetProtoObject(*cx, obj.handle(), proto.handle_mut()); +GetProtoObject(cx, obj.handle(), proto.handle_mut()); assert!(JS_SplicePrototype(*cx, obj.handle(), proto.handle())); let mut immutable = false; assert!(JS_SetImmutablePrototype(*cx, obj.handle(), &mut immutable)); @@ -2942,7 +2942,7 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); protoGetter = "GetRealmObjectPrototype" getPrototypeProto = "prototype_proto.set(%s(*cx))" % protoGetter else: - getPrototypeProto = ("%s::GetProtoObject(*cx, global, prototype_proto.handle_mut())" % + getPrototypeProto = ("%s::GetProtoObject(cx, global, prototype_proto.handle_mut())" % toBindingNamespace(parentName)) code = [CGGeneric("""\ @@ -3003,7 +3003,7 @@ assert!((*cache)[PrototypeList::ID::%(id)s as usize].is_null()); if parentName: parentName = toBindingNamespace(parentName) code.append(CGGeneric(""" -%s::GetConstructorObject(*cx, global, interface_proto.handle_mut());""" % parentName)) +%s::GetConstructorObject(cx, global, interface_proto.handle_mut());""" % parentName)) else: code.append(CGGeneric("interface_proto.set(GetRealmFunctionPrototype(*cx));")) code.append(CGGeneric("""\ @@ -3131,7 +3131,7 @@ class CGGetPerInterfaceObject(CGAbstractMethod): constructor object). """ def __init__(self, descriptor, name, idPrefix="", pub=False): - args = [Argument('*mut JSContext', 'cx'), + args = [Argument('SafeJSContext', 'cx'), Argument('HandleObject', 'global'), Argument('MutableHandleObject', 'mut rval')] CGAbstractMethod.__init__(self, descriptor, name, @@ -3149,7 +3149,7 @@ if !rval.get().is_null() { return; } -CreateInterfaceObjects(SafeJSContext::from_ptr(cx), global, proto_or_iface_array); +CreateInterfaceObjects(cx, global, proto_or_iface_array); rval.set((*proto_or_iface_array)[%(id)s as usize]); assert!(!rval.get().is_null()); """ % {"id": self.id}) @@ -3290,7 +3290,7 @@ if !ConstructorEnabled(SafeJSContext::from_ptr(cx), global) { } rooted!(in(cx) let mut proto = ptr::null_mut::()); -%s(cx, global, proto.handle_mut()); +%s(SafeJSContext::from_ptr(cx), global, proto.handle_mut()); assert!(!proto.is_null());""" % (function,)) @@ -5574,7 +5574,7 @@ rooted!(in(cx) let mut prototype = ptr::null_mut::()); // https://bugzilla.mozilla.org/show_bug.cgi?id=1317658 rooted!(in(cx) let global_object = CurrentGlobalOrNull(cx)); - GetProtoObject(cx, global_object.handle(), prototype.handle_mut()); + GetProtoObject(SafeJSContext::from_ptr(cx), global_object.handle(), prototype.handle_mut()); } else { // Step 6 prototype.set(proto_val.to_object()); -- cgit v1.2.3 From 6e4caf11537cb8db83405afe461b74470f3a7e5a Mon Sep 17 00:00:00 2001 From: marmeladema Date: Sun, 21 Jul 2019 01:25:29 +0100 Subject: DefineDOMInterfaceMethod now takes a SafeJSContext instead of a JSContext as first argument. --- components/script/dom/bindings/codegen/CodegenRust.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index e656a7ab3ce..d4c606183ca 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -3268,7 +3268,7 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod): def __init__(self, descriptor): assert descriptor.interface.hasInterfaceObject() args = [ - Argument('*mut JSContext', 'cx'), + Argument('SafeJSContext', 'cx'), Argument('HandleObject', 'global'), ] CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', @@ -3285,12 +3285,12 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod): return CGGeneric("""\ assert!(!global.get().is_null()); -if !ConstructorEnabled(SafeJSContext::from_ptr(cx), global) { +if !ConstructorEnabled(cx, global) { return; } -rooted!(in(cx) let mut proto = ptr::null_mut::()); -%s(SafeJSContext::from_ptr(cx), global, proto.handle_mut()); +rooted!(in(*cx) let mut proto = ptr::null_mut::()); +%s(cx, global, proto.handle_mut()); assert!(!proto.is_null());""" % (function,)) @@ -7312,7 +7312,7 @@ class GlobalGenRoots(): def InterfaceObjectMap(config): mods = [ "crate::dom::bindings::codegen", - "js::jsapi::JSContext", + "crate::script_runtime::JSContext", "js::rust::HandleObject", "phf", ] -- cgit v1.2.3 From 2fb3f1f98327ee1de698dfed83124350f58ff52a Mon Sep 17 00:00:00 2001 From: marmeladema Date: Sun, 21 Jul 2019 16:05:04 +0100 Subject: Callbacks now uses safe JSContext instead of raw JSContext --- components/script/dom/bindings/codegen/CodegenRust.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index d4c606183ca..71b7a279b7a 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -836,7 +836,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, if descriptor.interface.isCallback(): name = descriptor.nativeType declType = CGWrapper(CGGeneric(name), pre="Rc<", post=">") - template = "%s::new(cx, ${val}.get().to_object())" % name + template = "%s::new(SafeJSContext::from_ptr(cx), ${val}.get().to_object())" % name if type.nullable(): declType = CGWrapper(declType, pre="Option<", post=">") template = wrapObjectTemplate("Some(%s)" % template, "None", @@ -2364,7 +2364,7 @@ class CGGeneric(CGThing): class CGCallbackTempRoot(CGGeneric): def __init__(self, name): - CGGeneric.__init__(self, "%s::new(cx, ${val}.get().to_object())" % name) + CGGeneric.__init__(self, "%s::new(SafeJSContext::from_ptr(cx), ${val}.get().to_object())" % name) def getAllTypes(descriptors, dictionaries, callbacks, typedefs): @@ -6795,7 +6795,7 @@ class CGCallback(CGClass): def getConstructors(self): return [ClassConstructor( - [Argument("*mut JSContext", "aCx"), Argument("*mut JSObject", "aCallback")], + [Argument("SafeJSContext", "aCx"), Argument("*mut JSObject", "aCallback")], bodyInHeader=True, visibility="pub", explicit=False, @@ -6891,7 +6891,7 @@ class CGCallbackFunctionImpl(CGGeneric): def __init__(self, callback): impl = string.Template("""\ impl CallbackContainer for ${type} { - unsafe fn new(cx: *mut JSContext, callback: *mut JSObject) -> Rc<${type}> { + unsafe fn new(cx: SafeJSContext, callback: *mut JSObject) -> Rc<${type}> { ${type}::new(cx, callback) } -- cgit v1.2.3 From 808fa65aef163879b82baddc4af0a5445f806c81 Mon Sep 17 00:00:00 2001 From: marmeladema Date: Sun, 21 Jul 2019 22:22:44 +0100 Subject: Convert internal methods to handle safe JSContext instead of raw JSContext --- .../script/dom/bindings/codegen/CodegenRust.py | 280 +++++++++++---------- 1 file changed, 144 insertions(+), 136 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 71b7a279b7a..70da52b765e 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -323,7 +323,7 @@ class CGMethodCall(CGThing): if requiredArgs > 0: code = ( "if argc < %d {\n" - " throw_type_error(cx, \"Not enough arguments to %s.\");\n" + " throw_type_error(*cx, \"Not enough arguments to %s.\");\n" " return false;\n" "}" % (requiredArgs, methodName)) self.cgRoot.prepend( @@ -448,7 +448,7 @@ class CGMethodCall(CGThing): # XXXbz Now we're supposed to check for distinguishingArg being # an array or a platform object that supports indexed # properties... skip that last for now. It's a bit of a pain. - pickFirstSignature("%s.get().is_object() && is_array_like(cx, %s)" % + pickFirstSignature("%s.get().is_object() && is_array_like(*cx, %s)" % (distinguishingArg, distinguishingArg), lambda s: (s[1][distinguishingIndex].type.isSequence() or @@ -457,9 +457,9 @@ class CGMethodCall(CGThing): # Check for Date objects # XXXbz Do we need to worry about security wrappers around the Date? pickFirstSignature("%s.get().is_object() && " - "{ rooted!(in(cx) let obj = %s.get().to_object()); " + "{ rooted!(in(*cx) let obj = %s.get().to_object()); " "let mut is_date = false; " - "assert!(ObjectIsDate(cx, obj.handle(), &mut is_date)); " + "assert!(ObjectIsDate(*cx, obj.handle(), &mut is_date)); " "is_date }" % (distinguishingArg, distinguishingArg), lambda s: (s[1][distinguishingIndex].type.isDate() or @@ -467,7 +467,7 @@ class CGMethodCall(CGThing): # Check for vanilla JS objects # XXXbz Do we need to worry about security wrappers? - pickFirstSignature("%s.get().is_object() && !is_platform_object(%s.get().to_object(), cx)" % + pickFirstSignature("%s.get().is_object() && !is_platform_object(%s.get().to_object(), *cx)" % (distinguishingArg, distinguishingArg), lambda s: (s[1][distinguishingIndex].type.isCallback() or s[1][distinguishingIndex].type.isCallbackInterface() or @@ -492,7 +492,7 @@ class CGMethodCall(CGThing): else: # Just throw; we have no idea what we're supposed to # do with this. - caseBody.append(CGGeneric("throw_internal_error(cx, \"Could not convert JavaScript argument\");\n" + caseBody.append(CGGeneric("throw_internal_error(*cx, \"Could not convert JavaScript argument\");\n" "return false;")) argCountCases.append(CGCase(str(argCount), @@ -505,7 +505,7 @@ class CGMethodCall(CGThing): overloadCGThings.append( CGSwitch("argcount", argCountCases, - CGGeneric("throw_type_error(cx, \"Not enough arguments to %s.\");\n" + CGGeneric("throw_type_error(*cx, \"Not enough arguments to %s.\");\n" "return false;" % methodName))) # XXXjdm Avoid unreachable statement warnings # overloadCGThings.append( @@ -638,7 +638,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, exceptionCode = "return false;\n" if failureCode is None: - failOrPropagate = "throw_type_error(cx, &error);\n%s" % exceptionCode + failOrPropagate = "throw_type_error(*cx, &error);\n%s" % exceptionCode else: failOrPropagate = failureCode @@ -657,20 +657,20 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, return CGWrapper( CGGeneric( failureCode or - ('throw_type_error(cx, "%s is not an object.");\n' + ('throw_type_error(*cx, "%s is not an object.");\n' '%s' % (firstCap(sourceDescription), exceptionCode))), post="\n") def onFailureInvalidEnumValue(failureCode, passedVarName): return CGGeneric( failureCode or - ('throw_type_error(cx, &format!("\'{}\' is not a valid enum value for enumeration \'%s\'.", %s)); %s' + ('throw_type_error(*cx, &format!("\'{}\' is not a valid enum value for enumeration \'%s\'.", %s)); %s' % (type.name, passedVarName, exceptionCode))) def onFailureNotCallable(failureCode): return CGGeneric( failureCode or - ('throw_type_error(cx, \"%s is not callable.\");\n' + ('throw_type_error(*cx, \"%s is not callable.\");\n' '%s' % (firstCap(sourceDescription), exceptionCode))) # A helper function for handling default values. @@ -723,7 +723,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, if type.nullable(): declType = CGWrapper(declType, pre="Option<", post=" >") - templateBody = ("match FromJSValConvertible::from_jsval(cx, ${val}, %s) {\n" + templateBody = ("match FromJSValConvertible::from_jsval(*cx, ${val}, %s) {\n" " Ok(ConversionResult::Success(value)) => value,\n" " Ok(ConversionResult::Failure(error)) => {\n" "%s\n" @@ -738,7 +738,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, if type.nullable(): declType = CGWrapper(declType, pre="Option<", post=" >") - templateBody = ("match FromJSValConvertible::from_jsval(cx, ${val}, ()) {\n" + templateBody = ("match FromJSValConvertible::from_jsval(*cx, ${val}, ()) {\n" " Ok(ConversionResult::Success(value)) => value,\n" " Ok(ConversionResult::Failure(error)) => {\n" "%s\n" @@ -803,17 +803,17 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, """ { // Scope for our JSAutoRealm. - rooted!(in(cx) let globalObj = CurrentGlobalOrNull(cx)); - let promiseGlobal = GlobalScope::from_object_maybe_wrapped(globalObj.handle().get(), cx); + rooted!(in(*cx) let globalObj = CurrentGlobalOrNull(*cx)); + let promiseGlobal = GlobalScope::from_object_maybe_wrapped(globalObj.handle().get(), *cx); - rooted!(in(cx) let mut valueToResolve = $${val}.get()); - if !JS_WrapValue(cx, valueToResolve.handle_mut()) { + rooted!(in(*cx) let mut valueToResolve = $${val}.get()); + if !JS_WrapValue(*cx, valueToResolve.handle_mut()) { $*{exceptionCode} } - match Promise::new_resolved(&promiseGlobal, cx, valueToResolve.handle()) { + match Promise::new_resolved(&promiseGlobal, *cx, valueToResolve.handle()) { Ok(value) => value, Err(error) => { - throw_dom_exception(cx, &promiseGlobal, error); + throw_dom_exception(*cx, &promiseGlobal, error); $*{exceptionCode} } } @@ -836,7 +836,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, if descriptor.interface.isCallback(): name = descriptor.nativeType declType = CGWrapper(CGGeneric(name), pre="Rc<", post=">") - template = "%s::new(SafeJSContext::from_ptr(cx), ${val}.get().to_object())" % name + template = "%s::new(cx, ${val}.get().to_object())" % name if type.nullable(): declType = CGWrapper(declType, pre="Option<", post=">") template = wrapObjectTemplate("Some(%s)" % template, "None", @@ -864,7 +864,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, "exceptionCode": exceptionCode, } unwrapFailureCode = string.Template( - 'throw_type_error(cx, "${sourceDescription} does not ' + 'throw_type_error(*cx, "${sourceDescription} does not ' 'implement interface ${interface}.");\n' '${exceptionCode}').substitute(substitutions) else: @@ -872,7 +872,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, templateBody = fill( """ - match ${function}($${val}, cx) { + match ${function}($${val}, *cx) { Ok(val) => val, Err(()) => { $*{failureCode} @@ -899,7 +899,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, "exceptionCode": exceptionCode, } unwrapFailureCode = string.Template( - 'throw_type_error(cx, "${sourceDescription} is not a typed array.");\n' + 'throw_type_error(*cx, "${sourceDescription} is not a typed array.");\n' '${exceptionCode}').substitute(substitutions) else: unwrapFailureCode = failureCode @@ -942,7 +942,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, nullBehavior = getConversionConfigForType(type, isEnforceRange, isClamp, treatNullAs) conversionCode = ( - "match FromJSValConvertible::from_jsval(cx, ${val}, %s) {\n" + "match FromJSValConvertible::from_jsval(*cx, ${val}, %s) {\n" " Ok(ConversionResult::Success(strval)) => strval,\n" " Ok(ConversionResult::Failure(error)) => {\n" "%s\n" @@ -971,7 +971,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, assert not isEnforceRange and not isClamp conversionCode = ( - "match FromJSValConvertible::from_jsval(cx, ${val}, ()) {\n" + "match FromJSValConvertible::from_jsval(*cx, ${val}, ()) {\n" " Ok(ConversionResult::Success(strval)) => strval,\n" " Ok(ConversionResult::Failure(error)) => {\n" "%s\n" @@ -1000,7 +1000,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, assert not isEnforceRange and not isClamp conversionCode = ( - "match FromJSValConvertible::from_jsval(cx, ${val}, ()) {\n" + "match FromJSValConvertible::from_jsval(*cx, ${val}, ()) {\n" " Ok(ConversionResult::Success(strval)) => strval,\n" " Ok(ConversionResult::Failure(error)) => {\n" "%s\n" @@ -1038,7 +1038,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, handleInvalidEnumValueCode = "return true;" template = ( - "match find_enum_value(cx, ${val}, %(pairs)s) {\n" + "match find_enum_value(*cx, ${val}, %(pairs)s) {\n" " Err(_) => { %(exceptionCode)s },\n" " Ok((None, search)) => { %(handleInvalidEnumValueCode)s },\n" " Ok((Some(&value), _)) => value,\n" @@ -1174,7 +1174,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, if type_needs_tracing(type): declType = CGTemplatedType("RootedTraceableBox", declType) - template = ("match FromJSValConvertible::from_jsval(cx, ${val}, ()) {\n" + template = ("match FromJSValConvertible::from_jsval(*cx, ${val}, ()) {\n" " Ok(ConversionResult::Success(dictionary)) => dictionary,\n" " Ok(ConversionResult::Failure(error)) => {\n" "%s\n" @@ -1202,7 +1202,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, declType = CGWrapper(declType, pre="Option<", post=">") template = ( - "match FromJSValConvertible::from_jsval(cx, ${val}, %s) {\n" + "match FromJSValConvertible::from_jsval(*cx, ${val}, %s) {\n" " Ok(ConversionResult::Success(v)) => v,\n" " Ok(ConversionResult::Failure(error)) => {\n" "%s\n" @@ -1260,7 +1260,7 @@ def instantiateJSToNativeConversionTemplate(templateBody, replacements, result.append(conversion) if needsAutoRoot: - result.append(CGGeneric("auto_root!(in(cx) let %s = %s);" % (declName, declName))) + result.append(CGGeneric("auto_root!(in(*cx) let %s = %s);" % (declName, declName))) # Add an empty CGGeneric to get an extra newline after the argument # conversion. result.append(CGGeneric("")) @@ -1383,7 +1383,7 @@ def wrapForType(jsvalRef, result='result', successCode='return true;', pre=''): * 'successCode': the code to run once we have done the conversion. * 'pre': code to run before the conversion if rooting is necessary """ - wrap = "%s\n(%s).to_jsval(cx, %s);" % (pre, result, jsvalRef) + wrap = "%s\n(%s).to_jsval(*cx, %s);" % (pre, result, jsvalRef) if successCode: wrap += "\n%s" % successCode return wrap @@ -2364,7 +2364,7 @@ class CGGeneric(CGThing): class CGCallbackTempRoot(CGGeneric): def __init__(self, name): - CGGeneric.__init__(self, "%s::new(SafeJSContext::from_ptr(cx), ${val}.get().to_object())" % name) + CGGeneric.__init__(self, "%s::new(cx, ${val}.get().to_object())" % name) def getAllTypes(descriptors, dictionaries, callbacks, typedefs): @@ -2410,6 +2410,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config): 'crate::dom::bindings::str::USVString', 'crate::dom::bindings::trace::RootedTraceableBox', 'crate::dom::types::*', + 'crate::script_runtime::JSContext as SafeJSContext', 'js::error::throw_type_error', 'js::rust::HandleValue', 'js::jsapi::Heap', @@ -3331,9 +3332,9 @@ class CGCallGenerator(CGThing): needsCx = needCx(returnType, (a for (a, _) in arguments), True) if "cx" not in argsPre and needsCx: - args.prepend(CGGeneric("cx")) + args.prepend(CGGeneric("*cx")) if nativeMethodName in descriptor.inCompartmentMethods: - args.append(CGGeneric("InCompartment::in_compartment(&AlreadyInCompartment::assert_for_cx(cx))")) + args.append(CGGeneric("InCompartment::in_compartment(&AlreadyInCompartment::assert_for_cx(*cx))")) # Build up our actual call self.cgRoot = CGList([], "\n") @@ -3369,7 +3370,7 @@ class CGCallGenerator(CGThing): "let result = match result {\n" " Ok(result) => result,\n" " Err(e) => {\n" - " throw_dom_exception(cx, %s, e);\n" + " throw_dom_exception(*cx, %s, e);\n" " return%s;\n" " },\n" "};" % (glob, errorResult))) @@ -3593,7 +3594,7 @@ class CGSpecializedMethod(CGAbstractExternMethod): def __init__(self, descriptor, method): self.method = method name = method.identifier.name - args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', '_obj'), + args = [Argument('SafeJSContext', 'cx'), Argument('HandleObject', '_obj'), Argument('*const %s' % descriptor.concreteType, 'this'), Argument('*const JSJitMethodCallArgs', 'args')] CGAbstractExternMethod.__init__(self, descriptor, name, 'bool', args) @@ -3628,9 +3629,10 @@ class CGStaticMethod(CGAbstractStaticBindingMethod): def generate_code(self): nativeName = CGSpecializedMethod.makeNativeName(self.descriptor, self.method) + safeContext = CGGeneric("let cx = SafeJSContext::from_ptr(cx);\n") setupArgs = CGGeneric("let args = CallArgs::from_vp(vp, argc);\n") call = CGMethodCall(["&global"], nativeName, True, self.descriptor, self.method) - return CGList([setupArgs, call]) + return CGList([safeContext, setupArgs, call]) class CGSpecializedGetter(CGAbstractExternMethod): @@ -3641,7 +3643,7 @@ class CGSpecializedGetter(CGAbstractExternMethod): def __init__(self, descriptor, attr): self.attr = attr name = 'get_' + descriptor.internalNameFor(attr.identifier.name) - args = [Argument('*mut JSContext', 'cx'), + args = [Argument('SafeJSContext', 'cx'), Argument('HandleObject', '_obj'), Argument('*const %s' % descriptor.concreteType, 'this'), Argument('JSJitGetterCallArgs', 'args')] @@ -3682,10 +3684,11 @@ class CGStaticGetter(CGAbstractStaticBindingMethod): def generate_code(self): nativeName = CGSpecializedGetter.makeNativeName(self.descriptor, self.attr) + safeContext = CGGeneric("let cx = SafeJSContext::from_ptr(cx);\n") setupArgs = CGGeneric("let args = CallArgs::from_vp(vp, argc);\n") call = CGGetterCall(["&global"], self.attr.type, nativeName, self.descriptor, self.attr) - return CGList([setupArgs, call]) + return CGList([safeContext, setupArgs, call]) class CGSpecializedSetter(CGAbstractExternMethod): @@ -3696,7 +3699,7 @@ class CGSpecializedSetter(CGAbstractExternMethod): def __init__(self, descriptor, attr): self.attr = attr name = 'set_' + descriptor.internalNameFor(attr.identifier.name) - args = [Argument('*mut JSContext', 'cx'), + args = [Argument('SafeJSContext', 'cx'), Argument('HandleObject', 'obj'), Argument('*const %s' % descriptor.concreteType, 'this'), Argument('JSJitSetterCallArgs', 'args')] @@ -3730,15 +3733,16 @@ class CGStaticSetter(CGAbstractStaticBindingMethod): def generate_code(self): nativeName = CGSpecializedSetter.makeNativeName(self.descriptor, self.attr) + safeContext = CGGeneric("let cx = SafeJSContext::from_ptr(cx);\n") checkForArg = CGGeneric( "let args = CallArgs::from_vp(vp, argc);\n" "if argc == 0 {\n" - " throw_type_error(cx, \"Not enough arguments to %s setter.\");\n" + " throw_type_error(*cx, \"Not enough arguments to %s setter.\");\n" " return false;\n" "}" % self.attr.identifier.name) call = CGSetterCall(["&global"], self.attr.type, nativeName, self.descriptor, self.attr) - return CGList([checkForArg, call]) + return CGList([safeContext, checkForArg, call]) class CGSpecializedForwardingSetter(CGSpecializedSetter): @@ -3755,16 +3759,16 @@ class CGSpecializedForwardingSetter(CGSpecializedSetter): assert all(ord(c) < 128 for c in attrName) assert all(ord(c) < 128 for c in forwardToAttrName) return CGGeneric("""\ -rooted!(in(cx) let mut v = UndefinedValue()); -if !JS_GetProperty(cx, obj, %s as *const u8 as *const libc::c_char, v.handle_mut()) { +rooted!(in(*cx) let mut v = UndefinedValue()); +if !JS_GetProperty(*cx, obj, %s as *const u8 as *const libc::c_char, v.handle_mut()) { return false; } if !v.is_object() { - throw_type_error(cx, "Value.%s is not an object."); + throw_type_error(*cx, "Value.%s is not an object."); return false; } -rooted!(in(cx) let target_obj = v.to_object()); -JS_SetProperty(cx, target_obj.handle(), %s as *const u8 as *const libc::c_char, HandleValue::from_raw(args.get(0))) +rooted!(in(*cx) let target_obj = v.to_object()); +JS_SetProperty(*cx, target_obj.handle(), %s as *const u8 as *const libc::c_char, HandleValue::from_raw(args.get(0))) """ % (str_to_const_array(attrName), attrName, str_to_const_array(forwardToAttrName))) @@ -3781,7 +3785,7 @@ class CGSpecializedReplaceableSetter(CGSpecializedSetter): # JS_DefineProperty can only deal with ASCII. assert all(ord(c) < 128 for c in name) return CGGeneric("""\ -JS_DefineProperty(cx, obj, %s as *const u8 as *const libc::c_char, +JS_DefineProperty(*cx, obj, %s as *const u8 as *const libc::c_char, HandleValue::from_raw(args.get(0)), JSPROP_ENUMERATE as u32)""" % name) @@ -4370,7 +4374,7 @@ class CGUnionConversionStruct(CGThing): def get_match(name): return ( - "match %s::TryConvertTo%s(cx, value) {\n" + "match %s::TryConvertTo%s(SafeJSContext::from_ptr(cx), value) {\n" " Err(_) => return Err(()),\n" " Ok(Some(value)) => return Ok(ConversionResult::Success(%s::%s(value))),\n" " Ok(None) => (),\n" @@ -4510,7 +4514,7 @@ class CGUnionConversionStruct(CGThing): return CGWrapper( CGIndenter(jsConversion, 4), - pre="unsafe fn TryConvertTo%s(cx: *mut JSContext, value: HandleValue) -> %s {\n" + pre="unsafe fn TryConvertTo%s(cx: SafeJSContext, value: HandleValue) -> %s {\n" % (t.name, returnType), post="\n}") @@ -4903,7 +4907,7 @@ class CGProxySpecialOperation(CGPerSignatureCall): } self.cgRoot.prepend(instantiateJSToNativeConversionTemplate( template, templateValues, declType, argument.identifier.name)) - self.cgRoot.prepend(CGGeneric("rooted!(in(cx) let value = desc.value);")) + self.cgRoot.prepend(CGGeneric("rooted!(in(*cx) let value = desc.value);")) def getArguments(self): args = [(a, process_arg(a.identifier.name, a)) for a in self.arguments] @@ -4946,7 +4950,7 @@ class CGProxyNamedOperation(CGProxySpecialOperation): def define(self): # Our first argument is the id we're getting. argName = self.arguments[0].identifier.name - return ("let %s = jsid_to_string(cx, Handle::from_raw(id)).expect(\"Not a string-convertible JSID?\");\n" + return ("let %s = jsid_to_string(*cx, Handle::from_raw(id)).expect(\"Not a string-convertible JSID?\");\n" "let this = UnwrapProxy(proxy);\n" "let this = &*this;\n" % argName + CGProxySpecialOperation.define(self)) @@ -5015,9 +5019,9 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod): def getBody(self): indexedGetter = self.descriptor.operations['IndexedGetter'] - get = "" + get = "let cx = SafeJSContext::from_ptr(cx);\n" if indexedGetter: - get = "let index = get_array_index_from_id(cx, Handle::from_raw(id));\n" + get += "let index = get_array_index_from_id(*cx, Handle::from_raw(id));\n" attrs = "JSPROP_ENUMERATE" if self.descriptor.operations['IndexedSetter'] is None: @@ -5029,7 +5033,7 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod): templateValues = { 'jsvalRef': 'result_root.handle_mut()', 'successCode': fillDescriptor, - 'pre': 'rooted!(in(cx) let mut result_root = UndefinedValue());' + 'pre': 'rooted!(in(*cx) let mut result_root = UndefinedValue());' } get += ("if let Some(index) = index {\n" + " let this = UnwrapProxy(proxy);\n" + @@ -5055,7 +5059,7 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod): templateValues = { 'jsvalRef': 'result_root.handle_mut()', 'successCode': fillDescriptor, - 'pre': 'rooted!(in(cx) let mut result_root = UndefinedValue());' + 'pre': 'rooted!(in(*cx) let mut result_root = UndefinedValue());' } # See the similar-looking in CGDOMJSProxyHandler_get for the spec quote. @@ -5068,7 +5072,7 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod): namedGet = """ if %s { let mut has_on_proto = false; - if !has_property_on_prototype(cx, proxy_lt, id_lt, &mut has_on_proto) { + if !has_property_on_prototype(*cx, proxy_lt, id_lt, &mut has_on_proto) { return false; } if !has_on_proto { @@ -5080,13 +5084,13 @@ if %s { namedGet = "" return get + """\ -rooted!(in(cx) let mut expando = ptr::null_mut::()); +rooted!(in(*cx) let mut expando = ptr::null_mut::()); get_expando_object(proxy, expando.handle_mut()); //if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) { let proxy_lt = Handle::from_raw(proxy); let id_lt = Handle::from_raw(id); if !expando.is_null() { - if !JS_GetPropertyDescriptorById(cx, expando.handle().into(), id, desc) { + if !JS_GetPropertyDescriptorById(*cx, expando.handle().into(), id, desc) { return false; } if !desc.obj.is_null() { @@ -5113,11 +5117,11 @@ class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod): self.descriptor = descriptor def getBody(self): - set = "" + set = "let cx = SafeJSContext::from_ptr(cx);\n" indexedSetter = self.descriptor.operations['IndexedSetter'] if indexedSetter: - set += ("let index = get_array_index_from_id(cx, Handle::from_raw(id));\n" + + set += ("let index = get_array_index_from_id(*cx, Handle::from_raw(id));\n" + "if let Some(index) = index {\n" + " let this = UnwrapProxy(proxy);\n" + " let this = &*this;\n" + @@ -5125,7 +5129,7 @@ class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod): " return (*opresult).succeed();\n" + "}\n") elif self.descriptor.operations['IndexedGetter']: - set += ("if get_array_index_from_id(cx, Handle::from_raw(id)).is_some() {\n" + + set += ("if get_array_index_from_id(*cx, Handle::from_raw(id)).is_some() {\n" + " return (*opresult).failNoIndexedSetter();\n" + "}\n") @@ -5145,7 +5149,7 @@ class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod): " return (*opresult).failNoNamedSetter();\n" " }\n" "}\n") - set += "return proxyhandler::define_property(%s);" % ", ".join(a.name for a in self.args) + set += "return proxyhandler::define_property(*cx, %s);" % ", ".join(a.name for a in self.args[1:]) return set def definition_body(self): @@ -5161,13 +5165,13 @@ class CGDOMJSProxyHandler_delete(CGAbstractExternMethod): self.descriptor = descriptor def getBody(self): - set = "" + set = "let cx = SafeJSContext::from_ptr(cx);\n" if self.descriptor.operations['NamedDeleter']: if self.descriptor.hasUnforgeableMembers: raise TypeError("Can't handle a deleter on an interface that has " "unforgeables. Figure out how that should work!") set += CGProxyNamedDeleter(self.descriptor).define() - set += "return proxyhandler::delete(%s);" % ", ".join(a.name for a in self.args) + set += "return proxyhandler::delete(*cx, %s);" % ", ".join(a.name for a in self.args[1:]) return set def definition_body(self): @@ -5185,6 +5189,7 @@ class CGDOMJSProxyHandler_ownPropertyKeys(CGAbstractExternMethod): def getBody(self): body = dedent( """ + let cx = SafeJSContext::from_ptr(cx); let unwrapped_proxy = UnwrapProxy(proxy); """) @@ -5192,7 +5197,7 @@ class CGDOMJSProxyHandler_ownPropertyKeys(CGAbstractExternMethod): body += dedent( """ for i in 0..(*unwrapped_proxy).Length() { - rooted!(in(cx) let rooted_jsid = int_to_jsid(i as i32)); + rooted!(in(*cx) let rooted_jsid = int_to_jsid(i as i32)); AppendToAutoIdVector(props, rooted_jsid.handle().get()); } """) @@ -5202,20 +5207,20 @@ class CGDOMJSProxyHandler_ownPropertyKeys(CGAbstractExternMethod): """ for name in (*unwrapped_proxy).SupportedPropertyNames() { let cstring = CString::new(name).unwrap(); - let jsstring = JS_AtomizeAndPinString(cx, cstring.as_ptr()); - rooted!(in(cx) let rooted = jsstring); - let jsid = INTERNED_STRING_TO_JSID(cx, rooted.handle().get()); - rooted!(in(cx) let rooted_jsid = jsid); + let jsstring = JS_AtomizeAndPinString(*cx, cstring.as_ptr()); + rooted!(in(*cx) let rooted = jsstring); + let jsid = INTERNED_STRING_TO_JSID(*cx, rooted.handle().get()); + rooted!(in(*cx) let rooted_jsid = jsid); AppendToAutoIdVector(props, rooted_jsid.handle().get()); } """) body += dedent( """ - rooted!(in(cx) let mut expando = ptr::null_mut::()); + rooted!(in(*cx) let mut expando = ptr::null_mut::()); get_expando_object(proxy, expando.handle_mut()); if !expando.is_null() { - GetPropertyKeys(cx, expando.handle(), JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props); + GetPropertyKeys(*cx, expando.handle(), JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props); } return true; @@ -5241,6 +5246,7 @@ class CGDOMJSProxyHandler_getOwnEnumerablePropertyKeys(CGAbstractExternMethod): def getBody(self): body = dedent( """ + let cx = SafeJSContext::from_ptr(cx); let unwrapped_proxy = UnwrapProxy(proxy); """) @@ -5248,17 +5254,17 @@ class CGDOMJSProxyHandler_getOwnEnumerablePropertyKeys(CGAbstractExternMethod): body += dedent( """ for i in 0..(*unwrapped_proxy).Length() { - rooted!(in(cx) let rooted_jsid = int_to_jsid(i as i32)); + rooted!(in(*cx) let rooted_jsid = int_to_jsid(i as i32)); AppendToAutoIdVector(props, rooted_jsid.handle().get()); } """) body += dedent( """ - rooted!(in(cx) let mut expando = ptr::null_mut::()); + rooted!(in(*cx) let mut expando = ptr::null_mut::()); get_expando_object(proxy, expando.handle_mut()); if !expando.is_null() { - GetPropertyKeys(cx, expando.handle(), JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props); + GetPropertyKeys(*cx, expando.handle(), JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props); } return true; @@ -5279,17 +5285,16 @@ class CGDOMJSProxyHandler_hasOwn(CGAbstractExternMethod): def getBody(self): indexedGetter = self.descriptor.operations['IndexedGetter'] + indexed = "let cx = SafeJSContext::from_ptr(cx);\n" if indexedGetter: - indexed = ("let index = get_array_index_from_id(cx, Handle::from_raw(id));\n" + - "if let Some(index) = index {\n" + - " let this = UnwrapProxy(proxy);\n" + - " let this = &*this;\n" + - CGIndenter(CGProxyIndexedGetter(self.descriptor)).define() + "\n" + - " *bp = result.is_some();\n" + - " return true;\n" + - "}\n\n") - else: - indexed = "" + indexed += ("let index = get_array_index_from_id(*cx, Handle::from_raw(id));\n" + + "if let Some(index) = index {\n" + + " let this = UnwrapProxy(proxy);\n" + + " let this = &*this;\n" + + CGIndenter(CGProxyIndexedGetter(self.descriptor)).define() + "\n" + + " *bp = result.is_some();\n" + + " return true;\n" + + "}\n\n") namedGetter = self.descriptor.operations['NamedGetter'] condition = "RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id)" @@ -5299,7 +5304,7 @@ class CGDOMJSProxyHandler_hasOwn(CGAbstractExternMethod): named = """\ if %s { let mut has_on_proto = false; - if !has_property_on_prototype(cx, proxy_lt, id_lt, &mut has_on_proto) { + if !has_property_on_prototype(*cx, proxy_lt, id_lt, &mut has_on_proto) { return false; } if !has_on_proto { @@ -5314,12 +5319,12 @@ if %s { named = "" return indexed + """\ -rooted!(in(cx) let mut expando = ptr::null_mut::()); +rooted!(in(*cx) let mut expando = ptr::null_mut::()); let proxy_lt = Handle::from_raw(proxy); let id_lt = Handle::from_raw(id); get_expando_object(proxy, expando.handle_mut()); if !expando.is_null() { - let ok = JS_HasPropertyById(cx, expando.handle().into(), id, bp); + let ok = JS_HasPropertyById(*cx, expando.handle().into(), id, bp); if !ok || *bp { return ok; } @@ -5343,16 +5348,16 @@ class CGDOMJSProxyHandler_get(CGAbstractExternMethod): # https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty def getBody(self): getFromExpando = """\ -rooted!(in(cx) let mut expando = ptr::null_mut::()); +rooted!(in(*cx) let mut expando = ptr::null_mut::()); get_expando_object(proxy, expando.handle_mut()); if !expando.is_null() { let mut hasProp = false; - if !JS_HasPropertyById(cx, expando.handle().into(), id, &mut hasProp) { + if !JS_HasPropertyById(*cx, expando.handle().into(), id, &mut hasProp) { return false; } if hasProp { - return JS_ForwardGetPropertyTo(cx, expando.handle().into(), id, receiver, vp); + return JS_ForwardGetPropertyTo(*cx, expando.handle().into(), id, receiver, vp); } }""" @@ -5363,7 +5368,7 @@ if !expando.is_null() { indexedGetter = self.descriptor.operations['IndexedGetter'] if indexedGetter: - getIndexedOrExpando = ("let index = get_array_index_from_id(cx, id_lt);\n" + + getIndexedOrExpando = ("let index = get_array_index_from_id(*cx, id_lt);\n" + "if let Some(index) = index {\n" + " let this = UnwrapProxy(proxy);\n" + " let this = &*this;\n" + @@ -5396,6 +5401,7 @@ if !expando.is_null() { return """\ //MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy), //"Should not have a XrayWrapper here"); +let cx = SafeJSContext::from_ptr(cx); let proxy_lt = Handle::from_raw(proxy); let vp_lt = MutableHandle::from_raw(vp); let id_lt = Handle::from_raw(id); @@ -5403,7 +5409,7 @@ let receiver_lt = Handle::from_raw(receiver); %s let mut found = false; -if !get_property_on_prototype(cx, proxy_lt, receiver_lt, id_lt, &mut found, vp_lt) { +if !get_property_on_prototype(*cx, proxy_lt, receiver_lt, id_lt, &mut found, vp_lt) { return false; } @@ -5526,7 +5532,9 @@ class CGClassConstructHook(CGAbstractExternMethod): self.exposureSet = descriptor.interface.exposureSet def definition_body(self): - preamble = """let global = GlobalScope::from_object(JS_CALLEE(cx, vp).to_object());\n""" + preamble = """let cx = SafeJSContext::from_ptr(cx); +let global = GlobalScope::from_object(JS_CALLEE(*cx, vp).to_object()); +""" if len(self.exposureSet) == 1: preamble += """\ let global = DomRoot::downcast::(global).unwrap(); @@ -5542,24 +5550,24 @@ let global = DomRoot::downcast::(global).unwrap(); // The new_target might be a cross-compartment wrapper. Get the underlying object // so we can do the spec's object-identity checks. -rooted!(in(cx) let new_target = UnwrapObjectDynamic(args.new_target().to_object(), cx, 1)); +rooted!(in(*cx) let new_target = UnwrapObjectDynamic(args.new_target().to_object(), *cx, 1)); if new_target.is_null() { - throw_dom_exception(cx, global.upcast::(), Error::Type("new.target is null".to_owned())); + throw_dom_exception(*cx, global.upcast::(), Error::Type("new.target is null".to_owned())); return false; } if args.callee() == new_target.get() { - throw_dom_exception(cx, global.upcast::(), + throw_dom_exception(*cx, global.upcast::(), Error::Type("new.target must not be the active function object".to_owned())); return false; } // Step 6 -rooted!(in(cx) let mut prototype = ptr::null_mut::()); +rooted!(in(*cx) let mut prototype = ptr::null_mut::()); { - rooted!(in(cx) let mut proto_val = UndefinedValue()); - let _ac = JSAutoRealm::new(cx, new_target.get()); - if !JS_GetProperty(cx, new_target.handle(), b"prototype\\0".as_ptr() as *const _, proto_val.handle_mut()) { + rooted!(in(*cx) let mut proto_val = UndefinedValue()); + let _ac = JSAutoRealm::new(*cx, new_target.get()); + if !JS_GetProperty(*cx, new_target.handle(), b"prototype\\0".as_ptr() as *const _, proto_val.handle_mut()) { return false; } @@ -5573,8 +5581,8 @@ rooted!(in(cx) let mut prototype = ptr::null_mut::()); // whose target is not same-compartment with the proxy, or bound functions, etc). // https://bugzilla.mozilla.org/show_bug.cgi?id=1317658 - rooted!(in(cx) let global_object = CurrentGlobalOrNull(cx)); - GetProtoObject(SafeJSContext::from_ptr(cx), global_object.handle(), prototype.handle_mut()); + rooted!(in(*cx) let global_object = CurrentGlobalOrNull(*cx)); + GetProtoObject(cx, global_object.handle(), prototype.handle_mut()); } else { // Step 6 prototype.set(proto_val.to_object()); @@ -5582,7 +5590,7 @@ rooted!(in(cx) let mut prototype = ptr::null_mut::()); } // Wrap prototype in this context since it is from the newTarget compartment -if !JS_WrapObject(cx, prototype.handle_mut()) { +if !JS_WrapObject(*cx, prototype.handle_mut()) { return false; } @@ -5590,19 +5598,19 @@ let result: Result, Error> = html_constructor(&global, &args); let result = match result { Ok(result) => result, Err(e) => { - throw_dom_exception(cx, global.upcast::(), e); + throw_dom_exception(*cx, global.upcast::(), e); return false; }, }; -rooted!(in(cx) let mut element = result.reflector().get_jsobject().get()); -if !JS_WrapObject(cx, element.handle_mut()) { +rooted!(in(*cx) let mut element = result.reflector().get_jsobject().get()); +if !JS_WrapObject(*cx, element.handle_mut()) { return false; } -JS_SetPrototype(cx, element.handle(), prototype.handle()); +JS_SetPrototype(*cx, element.handle(), prototype.handle()); -(result).to_jsval(cx, MutableHandleValue::from_raw(args.rval())); +(result).to_jsval(*cx, MutableHandleValue::from_raw(args.rval())); return true; """ % self.descriptor.name) else: @@ -6290,7 +6298,7 @@ class CGDictionary(CGThing): " match r#try!(%s::%s::new(cx, val)) {\n" " ConversionResult::Success(v) => v,\n" " ConversionResult::Failure(error) => {\n" - " throw_type_error(cx, &error);\n" + " throw_type_error(*cx, &error);\n" " return Err(());\n" " }\n" " }\n" @@ -6344,7 +6352,7 @@ class CGDictionary(CGThing): return string.Template( "impl ${selfName} {\n" "${empty}\n" - " pub unsafe fn new(cx: *mut JSContext, val: HandleValue) \n" + " pub unsafe fn new(cx: SafeJSContext, val: HandleValue) \n" " -> Result, ()> {\n" " let object = if val.get().is_null_or_undefined() {\n" " ptr::null_mut()\n" @@ -6353,7 +6361,7 @@ class CGDictionary(CGThing): " } else {\n" " return Ok(ConversionResult::Failure(\"Value is not an object.\".into()));\n" " };\n" - " rooted!(in(cx) let object = object);\n" + " rooted!(in(*cx) let object = object);\n" "${preInitial}" "${initParent}" "${initMembers}" @@ -6366,7 +6374,7 @@ class CGDictionary(CGThing): " type Config = ();\n" " unsafe fn from_jsval(cx: *mut JSContext, value: HandleValue, _option: ())\n" " -> Result, ()> {\n" - " ${selfName}::new(cx, value)\n" + " ${selfName}::new(SafeJSContext::from_ptr(cx), value)\n" " }\n" "}\n" "\n" @@ -6424,7 +6432,7 @@ class CGDictionary(CGThing): assert (member.defaultValue is None) == (default is None) if not member.optional: assert default is None - default = ("throw_type_error(cx, \"Missing required member \\\"%s\\\".\");\n" + default = ("throw_type_error(*cx, \"Missing required member \\\"%s\\\".\");\n" "return Err(());") % member.identifier.name elif not default: default = "None" @@ -6432,8 +6440,8 @@ class CGDictionary(CGThing): conversion = ( "{\n" - " rooted!(in(cx) let mut rval = UndefinedValue());\n" - " if r#try!(get_dictionary_property(cx, object.handle(), \"%s\", rval.handle_mut()))" + " rooted!(in(*cx) let mut rval = UndefinedValue());\n" + " if r#try!(get_dictionary_property(*cx, object.handle(), \"%s\", rval.handle_mut()))" " && !rval.is_undefined() {\n" "%s\n" " } else {\n" @@ -6808,14 +6816,14 @@ class CGCallback(CGClass): args = list(method.args) # Strip out the JSContext*/JSObject* args # that got added. - assert args[0].name == "cx" and args[0].argType == "*mut JSContext" + assert args[0].name == "cx" and args[0].argType == "SafeJSContext" assert args[1].name == "aThisObj" and args[1].argType == "HandleObject" args = args[2:] # Record the names of all the arguments, so we can use them when we call # the private method. argnames = [arg.name for arg in args] - argnamesWithThis = ["s.get_context()", "thisObjJS.handle()"] + argnames - argnamesWithoutThis = ["s.get_context()", "thisObjJS.handle()"] + argnames + argnamesWithThis = ["SafeJSContext::from_ptr(s.get_context())", "thisObjJS.handle()"] + argnames + argnamesWithoutThis = ["SafeJSContext::from_ptr(s.get_context())", "thisObjJS.handle()"] + argnames # Now that we've recorded the argnames for our call to our private # method, insert our optional argument for deciding whether the # CallSetup should re-throw exceptions on aRv. @@ -7066,7 +7074,7 @@ class CallbackMember(CGNativeMember): "*arg = Heap::default();\n" + "arg.set(argv_root.get());\n" + "}") % jsvalIndex, - pre="rooted!(in(cx) let mut argv_root = UndefinedValue());") + pre="rooted!(in(*cx) let mut argv_root = UndefinedValue());") if arg.variadic: conversion = string.Template( "for idx in 0..${arg}.len() {\n" + @@ -7095,7 +7103,7 @@ class CallbackMember(CGNativeMember): return args # We want to allow the caller to pass in a "this" object, as # well as a JSContext. - return [Argument("*mut JSContext", "cx"), + return [Argument("SafeJSContext", "cx"), Argument("HandleObject", "aThisObj")] + args def getCallSetup(self): @@ -7136,7 +7144,7 @@ class CallbackMethod(CallbackMember): needThisHandling) def getRvalDecl(self): - return "rooted!(in(cx) let mut rval = UndefinedValue());\n" + return "rooted!(in(*cx) let mut rval = UndefinedValue());\n" def getCall(self): replacements = { @@ -7152,9 +7160,9 @@ class CallbackMethod(CallbackMember): replacements["argc"] = "0" return string.Template( "${getCallable}" - "rooted!(in(cx) let rootedThis = ${thisObj});\n" + "rooted!(in(*cx) let rootedThis = ${thisObj});\n" "let ok = ${callGuard}JS_CallFunctionValue(\n" - " cx, rootedThis.handle(), callable.handle(),\n" + " *cx, rootedThis.handle(), callable.handle(),\n" " &HandleValueArray {\n" " length_: ${argc} as ::libc::size_t,\n" " elements_: ${argv}\n" @@ -7175,7 +7183,7 @@ class CallCallback(CallbackMethod): return "aThisObj.get()" def getCallableDecl(self): - return "rooted!(in(cx) let callable = ObjectValue(self.callback()));\n" + return "rooted!(in(*cx) let callable = ObjectValue(self.callback()));\n" def getCallGuard(self): if self.callback._treatNonObjectAsNull: @@ -7205,13 +7213,13 @@ class CallbackOperationBase(CallbackMethod): "methodName": self.methodName } getCallableFromProp = string.Template( - 'r#try!(self.parent.get_callable_property(cx, "${methodName}"))' + 'r#try!(self.parent.get_callable_property(*cx, "${methodName}"))' ).substitute(replacements) if not self.singleOperation: - return 'rooted!(in(cx) let callable =\n' + getCallableFromProp + ');\n' + return 'rooted!(in(*cx) let callable =\n' + getCallableFromProp + ');\n' return ( 'let isCallable = IsCallable(self.callback());\n' - 'rooted!(in(cx) let callable =\n' + + 'rooted!(in(*cx) let callable =\n' + CGIndenter( CGIfElseWrapper('isCallable', CGGeneric('ObjectValue(self.callback())'), @@ -7246,21 +7254,21 @@ class CGIterableMethodGenerator(CGGeneric): CGGeneric.__init__(self, fill( """ if !IsCallable(arg0) { - throw_type_error(cx, "Argument 1 of ${ifaceName}.forEach is not callable."); + throw_type_error(*cx, "Argument 1 of ${ifaceName}.forEach is not callable."); return false; } - rooted!(in(cx) let arg0 = ObjectValue(arg0)); - rooted!(in(cx) let mut call_arg1 = UndefinedValue()); - rooted!(in(cx) let mut call_arg2 = UndefinedValue()); + rooted!(in(*cx) let arg0 = ObjectValue(arg0)); + rooted!(in(*cx) let mut call_arg1 = UndefinedValue()); + rooted!(in(*cx) let mut call_arg2 = UndefinedValue()); let mut call_args = vec![UndefinedValue(), UndefinedValue(), ObjectValue(*_obj)]; - rooted!(in(cx) let mut ignoredReturnVal = UndefinedValue()); + rooted!(in(*cx) let mut ignoredReturnVal = UndefinedValue()); for i in 0..(*this).get_iterable_length() { - (*this).get_value_at_index(i).to_jsval(cx, call_arg1.handle_mut()); - (*this).get_key_at_index(i).to_jsval(cx, call_arg2.handle_mut()); + (*this).get_value_at_index(i).to_jsval(*cx, call_arg1.handle_mut()); + (*this).get_key_at_index(i).to_jsval(*cx, call_arg2.handle_mut()); call_args[0] = call_arg1.handle().get(); call_args[1] = call_arg2.handle().get(); let call_args = HandleValueArray { length_: 3, elements_: call_args.as_ptr() }; - if !Call(cx, arg1, arg0.handle(), &call_args, + if !Call(*cx, arg1, arg0.handle(), &call_args, ignoredReturnVal.handle_mut()) { return false; } -- cgit v1.2.3 From 2c5d0a6ebc39ad263e2bbe623e357a11b4cec5aa Mon Sep 17 00:00:00 2001 From: marmeladema Date: Mon, 22 Jul 2019 01:09:24 +0100 Subject: Convert CGTraitInterface to use safe JSContext instead of raw JSContext --- components/script/dom/bindings/codegen/CodegenRust.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 70da52b765e..343b8e6596d 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -3332,7 +3332,7 @@ class CGCallGenerator(CGThing): needsCx = needCx(returnType, (a for (a, _) in arguments), True) if "cx" not in argsPre and needsCx: - args.prepend(CGGeneric("*cx")) + args.prepend(CGGeneric("cx")) if nativeMethodName in descriptor.inCompartmentMethods: args.append(CGGeneric("InCompartment::in_compartment(&AlreadyInCompartment::assert_for_cx(*cx))")) @@ -5649,7 +5649,7 @@ class CGInterfaceTrait(CGThing): def attribute_arguments(needCx, argument=None, inCompartment=False): if needCx: - yield "cx", "*mut JSContext" + yield "cx", "SafeJSContext" if argument: yield "value", argument_type(descriptor, argument) @@ -6720,7 +6720,7 @@ def argument_type(descriptorProvider, ty, optional=False, defaultValue=None, var def method_arguments(descriptorProvider, returnType, arguments, passJSBits=True, trailing=None, inCompartment=False): if needCx(returnType, arguments, passJSBits): - yield "cx", "*mut JSContext" + yield "cx", "SafeJSContext" for argument in arguments: ty = argument_type(descriptorProvider, argument.type, argument.optional, -- cgit v1.2.3 From 16b4e3446bc466c87327fac3402736d3636a5f73 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Wed, 24 Jul 2019 17:11:44 +0900 Subject: Support default toJSON in WebIDL --- .../script/dom/bindings/codegen/CodegenRust.py | 96 +++++++++++++++++++++- .../script/dom/bindings/codegen/Configuration.py | 4 + 2 files changed, 98 insertions(+), 2 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index e0c7725fa52..159ca3652b9 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2881,6 +2881,49 @@ class PropertyArrays(): return define +class CGCollectJSONAttributesMethod(CGAbstractMethod): + """ + Generate the CollectJSONAttributes method for an interface descriptor + """ + def __init__(self, descriptor, toJSONMethod): + args = [Argument('*mut JSContext', 'cx'), + Argument('HandleObject', 'obj'), + Argument('*const %s' % descriptor.concreteType, 'this'), + Argument('&RootedGuard<*mut JSObject>', 'result')] + CGAbstractMethod.__init__(self, descriptor, 'CollectJSONAttributes', + 'bool', args, pub=True, unsafe=True) + self.toJSONMethod = toJSONMethod + + def definition_body(self): + ret = '' + interface = self.descriptor.interface + for m in interface.members: + if m.isAttr() and not m.isStatic() and m.type.isJSONType(): + name = m.identifier.name + getAndDefine = fill( + """ + rooted!(in(cx) let mut temp = UndefinedValue()); + if !get_${name}(cx, obj, this, JSJitGetterCallArgs { _base: temp.handle_mut().into() }) { + return false; + } + if !JS_DefineProperty(cx, result.handle().into(), + ${nameAsArray} as *const u8 as *const libc::c_char, + temp.handle(), JSPROP_ENUMERATE as u32) { + return false; + } + """, + name=name, nameAsArray=str_to_const_array(name)) + ret += fill( + """ + { // scope for "temp" + $*{getAndDefine} + } + """, + getAndDefine=getAndDefine) + ret += 'return true;\n' + return CGGeneric(ret) + + class CGCreateInterfaceObjectsMethod(CGAbstractMethod): """ Generate the CreateInterfaceObjects method for an interface descriptor. @@ -3616,6 +3659,42 @@ class CGSpecializedMethod(CGAbstractExternMethod): return MakeNativeName(nativeName) +class CGDefaultToJSONMethod(CGSpecializedMethod): + def __init__(self, descriptor, method): + assert method.isDefaultToJSON() + CGSpecializedMethod.__init__(self, descriptor, method) + + def definition_body(self): + ret = dedent(""" + rooted!(in(cx) let result = JS_NewPlainObject(cx)); + if result.is_null() { + return false; + } + """) + + jsonDescriptors = [self.descriptor] + interface = self.descriptor.interface.parent + while interface: + descriptor = self.descriptor.getDescriptor(interface.identifier.name) + if descriptor.hasDefaultToJSON: + jsonDescriptors.append(descriptor) + interface = interface.parent + + form = """ + if !${parentclass}CollectJSONAttributes(cx, _obj, this, &result) { + return false; + } + """ + + # Iterate the array in reverse: oldest ancestor first + for descriptor in jsonDescriptors[:0:-1]: + ret += fill(form, parentclass=toBindingNamespace(descriptor.name) + "::") + ret += fill(form, parentclass="") + ret += ('(*args).rval().set(ObjectValue(*result));\n' + 'return true;\n') + return CGGeneric(ret) + + class CGStaticMethod(CGAbstractStaticBindingMethod): """ A class for generating the Rust code for an IDL static method. @@ -5653,7 +5732,8 @@ class CGInterfaceTrait(CGThing): for m in descriptor.interface.members: if (m.isMethod() and not m.isStatic() and not m.isMaplikeOrSetlikeOrIterableMethod() and - (not m.isIdentifierLess() or m.isStringifier())): + (not m.isIdentifierLess() or m.isStringifier()) and + not m.isDefaultToJSON()): name = CGSpecializedMethod.makeNativeName(descriptor, m) infallible = 'infallible' in descriptor.getExtendedAttributes(m) for idx, (rettype, arguments) in enumerate(m.signatures()): @@ -5844,7 +5924,9 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::jsapi::JS_HasProperty', 'js::jsapi::JS_HasPropertyById', 'js::rust::wrappers::JS_InitializePropertiesFromCompatibleNativeObject', + 'js::jsapi::JS_NewPlainObject', 'js::jsapi::JS_NewObject', + 'js::rust::RootedGuard', 'js::rust::wrappers::JS_NewObjectWithGivenProto', 'js::rust::wrappers::JS_NewObjectWithoutMetadata', 'js::rust::wrappers::ObjectIsDate', @@ -6041,6 +6123,7 @@ class CGDescriptor(CGThing): cgThings = [] + defaultToJSONMethod = None unscopableNames = [] for m in descriptor.interface.members: if (m.isMethod() and @@ -6048,7 +6131,9 @@ class CGDescriptor(CGThing): if m.getExtendedAttribute("Unscopable"): assert not m.isStatic() unscopableNames.append(m.identifier.name) - if m.isStatic(): + if m.isDefaultToJSON(): + defaultToJSONMethod = m + elif m.isStatic(): assert descriptor.interface.hasInterfaceObject() cgThings.append(CGStaticMethod(descriptor, m)) elif not descriptor.interface.isCallback(): @@ -6082,6 +6167,10 @@ class CGDescriptor(CGThing): if (not m.isStatic() and not descriptor.interface.isCallback()): cgThings.append(CGMemberJITInfo(descriptor, m)) + if defaultToJSONMethod: + cgThings.append(CGDefaultToJSONMethod(descriptor, defaultToJSONMethod)) + cgThings.append(CGMemberJITInfo(descriptor, defaultToJSONMethod)) + if descriptor.concrete: cgThings.append(CGClassFinalizeHook(descriptor)) cgThings.append(CGClassTraceHook(descriptor)) @@ -6099,6 +6188,9 @@ class CGDescriptor(CGThing): properties = PropertyArrays(descriptor) + if defaultToJSONMethod: + cgThings.append(CGCollectJSONAttributesMethod(descriptor, defaultToJSONMethod)) + if descriptor.concrete: if descriptor.proxy: # cgThings.append(CGProxyIsProxy(descriptor)) diff --git a/components/script/dom/bindings/codegen/Configuration.py b/components/script/dom/bindings/codegen/Configuration.py index 81f61a648f1..bde6e71bcfb 100644 --- a/components/script/dom/bindings/codegen/Configuration.py +++ b/components/script/dom/bindings/codegen/Configuration.py @@ -250,6 +250,8 @@ class Descriptor(DescriptorProvider): 'Stringifier': None, } + self.hasDefaultToJSON = False + def addOperation(operation, m): if not self.operations[operation]: self.operations[operation] = m @@ -259,6 +261,8 @@ class Descriptor(DescriptorProvider): for m in self.interface.members: if m.isMethod() and m.isStringifier(): addOperation('Stringifier', m) + if m.isMethod() and m.isDefaultToJSON(): + self.hasDefaultToJSON = True if self.concrete: iface = self.interface -- cgit v1.2.3 From 87cc409579a1ccdc81da8ceecf41125a302a39bc Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Thu, 25 Jul 2019 11:14:21 +0900 Subject: use SafeJSContext --- components/script/dom/bindings/codegen/CodegenRust.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 9700cb68191..5548bbdc07c 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2887,7 +2887,7 @@ class CGCollectJSONAttributesMethod(CGAbstractMethod): Generate the CollectJSONAttributes method for an interface descriptor """ def __init__(self, descriptor, toJSONMethod): - args = [Argument('*mut JSContext', 'cx'), + args = [Argument('SafeJSContext', 'cx'), Argument('HandleObject', 'obj'), Argument('*const %s' % descriptor.concreteType, 'this'), Argument('&RootedGuard<*mut JSObject>', 'result')] @@ -2903,11 +2903,11 @@ class CGCollectJSONAttributesMethod(CGAbstractMethod): name = m.identifier.name getAndDefine = fill( """ - rooted!(in(cx) let mut temp = UndefinedValue()); + rooted!(in(*cx) let mut temp = UndefinedValue()); if !get_${name}(cx, obj, this, JSJitGetterCallArgs { _base: temp.handle_mut().into() }) { return false; } - if !JS_DefineProperty(cx, result.handle().into(), + if !JS_DefineProperty(*cx, result.handle().into(), ${nameAsArray} as *const u8 as *const libc::c_char, temp.handle(), JSPROP_ENUMERATE as u32) { return false; @@ -3667,7 +3667,7 @@ class CGDefaultToJSONMethod(CGSpecializedMethod): def definition_body(self): ret = dedent(""" - rooted!(in(cx) let result = JS_NewPlainObject(cx)); + rooted!(in(*cx) let result = JS_NewPlainObject(*cx)); if result.is_null() { return false; } -- cgit v1.2.3 From bf70decdd308f24bfe58cebb8f529fbc9cd22001 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Thu, 25 Jul 2019 12:43:43 +0900 Subject: remove redundant extra scoping --- components/script/dom/bindings/codegen/CodegenRust.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 5548bbdc07c..df2f90742c9 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2901,7 +2901,7 @@ class CGCollectJSONAttributesMethod(CGAbstractMethod): for m in interface.members: if m.isAttr() and not m.isStatic() and m.type.isJSONType(): name = m.identifier.name - getAndDefine = fill( + ret += fill( """ rooted!(in(*cx) let mut temp = UndefinedValue()); if !get_${name}(cx, obj, this, JSJitGetterCallArgs { _base: temp.handle_mut().into() }) { @@ -2914,13 +2914,6 @@ class CGCollectJSONAttributesMethod(CGAbstractMethod): } """, name=name, nameAsArray=str_to_const_array(name)) - ret += fill( - """ - { // scope for "temp" - $*{getAndDefine} - } - """, - getAndDefine=getAndDefine) ret += 'return true;\n' return CGGeneric(ret) -- cgit v1.2.3 From 410d5bc772e0ad851692efe2a2131833312d3dd0 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 25 Jul 2019 12:12:33 -0400 Subject: Update SpiderMonkey bindings for Windows arm64 crash fix. --- .../script/dom/bindings/codegen/CodegenRust.py | 29 ++++++++++++---------- 1 file changed, 16 insertions(+), 13 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 343b8e6596d..c7b2c1fe5ef 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -3036,8 +3036,9 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); if aliasedMembers: def defineAlias(alias): if alias == "@@iterator": - symbolJSID = "RUST_SYMBOL_TO_JSID(GetWellKnownSymbol(*cx, SymbolCode::iterator))" - getSymbolJSID = CGGeneric(fill("rooted!(in(*cx) let iteratorId = ${symbolJSID});", + symbolJSID = "RUST_SYMBOL_TO_JSID(GetWellKnownSymbol(*cx, SymbolCode::iterator), \ + iteratorId.handle_mut())" + getSymbolJSID = CGGeneric(fill("rooted!(in(*cx) let mut iteratorId: jsid);\n${symbolJSID};\n", symbolJSID=symbolJSID)) defineFn = "JS_DefinePropertyById2" prop = "iteratorId.handle()" @@ -5197,8 +5198,9 @@ class CGDOMJSProxyHandler_ownPropertyKeys(CGAbstractExternMethod): body += dedent( """ for i in 0..(*unwrapped_proxy).Length() { - rooted!(in(*cx) let rooted_jsid = int_to_jsid(i as i32)); - AppendToAutoIdVector(props, rooted_jsid.handle().get()); + rooted!(in(*cx) let mut rooted_jsid: jsid); + int_to_jsid(i as i32, rooted_jsid.handle_mut()); + AppendToAutoIdVector(props, rooted_jsid.handle()); } """) @@ -5209,9 +5211,9 @@ class CGDOMJSProxyHandler_ownPropertyKeys(CGAbstractExternMethod): let cstring = CString::new(name).unwrap(); let jsstring = JS_AtomizeAndPinString(*cx, cstring.as_ptr()); rooted!(in(*cx) let rooted = jsstring); - let jsid = INTERNED_STRING_TO_JSID(*cx, rooted.handle().get()); - rooted!(in(*cx) let rooted_jsid = jsid); - AppendToAutoIdVector(props, rooted_jsid.handle().get()); + rooted!(in(*cx) let mut rooted_jsid: jsid); + RUST_INTERNED_STRING_TO_JSID(*cx, rooted.handle().get(), rooted_jsid.handle_mut()); + AppendToAutoIdVector(props, rooted_jsid.handle()); } """) @@ -5254,8 +5256,9 @@ class CGDOMJSProxyHandler_getOwnEnumerablePropertyKeys(CGAbstractExternMethod): body += dedent( """ for i in 0..(*unwrapped_proxy).Length() { - rooted!(in(*cx) let rooted_jsid = int_to_jsid(i as i32)); - AppendToAutoIdVector(props, rooted_jsid.handle().get()); + rooted!(in(*cx) let mut rooted_jsid: jsid); + int_to_jsid(i as i32, rooted_jsid.handle_mut()); + AppendToAutoIdVector(props, rooted_jsid.handle()); } """) @@ -5800,7 +5803,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::jsapi::HandleValue as RawHandleValue', 'js::jsapi::HandleValueArray', 'js::jsapi::Heap', - 'js::jsapi::INTERNED_STRING_TO_JSID', + 'js::rust::wrappers::RUST_INTERNED_STRING_TO_JSID', 'js::jsapi::IsCallable', 'js::jsapi::JSAutoRealm', 'js::jsapi::JSCLASS_FOREGROUND_FINALIZE', @@ -5884,7 +5887,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::jsval::PrivateValue', 'js::jsval::UndefinedValue', 'js::jsapi::UndefinedHandleValue', - 'js::glue::AppendToAutoIdVector', + 'js::rust::wrappers::AppendToAutoIdVector', 'js::glue::CallJitGetterOp', 'js::glue::CallJitMethodOp', 'js::glue::CallJitSetterOp', @@ -5895,8 +5898,8 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::glue::ProxyTraps', 'js::glue::RUST_JSID_IS_INT', 'js::glue::RUST_JSID_IS_STRING', - 'js::glue::RUST_SYMBOL_TO_JSID', - 'js::glue::int_to_jsid', + 'js::rust::wrappers::RUST_SYMBOL_TO_JSID', + 'js::rust::wrappers::int_to_jsid', 'js::glue::UnwrapObjectDynamic', 'js::panic::maybe_resume_unwind', 'js::panic::wrap_panic', -- cgit v1.2.3 From f1300bb98b0267b552a3f12e64e30f2f414213a3 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 26 Jul 2019 21:54:42 +0200 Subject: Auto-generate CSSStyleDeclaration.webidl for CSS properties based on the style crate --- .../script/dom/bindings/codegen/GlobalGen.py | 61 +++++++++++++++++++++- .../script/dom/bindings/codegen/parser/WebIDL.py | 2 +- 2 files changed, 60 insertions(+), 3 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/GlobalGen.py b/components/script/dom/bindings/codegen/GlobalGen.py index 20dea28a9d1..9fe736e71fd 100644 --- a/components/script/dom/bindings/codegen/GlobalGen.py +++ b/components/script/dom/bindings/codegen/GlobalGen.py @@ -7,6 +7,7 @@ import sys import os +import json sys.path.append(os.path.join(".", "parser")) sys.path.append(os.path.join(".", "ply")) import WebIDL @@ -28,7 +29,7 @@ def generate_file(config, name, filename): def main(): # Parse arguments. from optparse import OptionParser - usageString = "usage: %prog [options] configFile outputdir webidldir [files]" + usageString = "usage: %prog [options] configFile outputdir webidldir cssProperties.json [files]" o = OptionParser(usage=usageString) o.add_option("--cachedir", dest='cachedir', default=None, help="Directory in which to cache lex/parse tables.") @@ -44,8 +45,9 @@ def main(): configFile = args[0] outputdir = args[1] baseDir = args[2] + css_properties_json = args[3] if options.filelist is not None: - fileList = (l.strip() for l in open(options.filelist).xreadlines()) + fileList = [l.strip() for l in open(options.filelist).xreadlines()] else: fileList = args[3:] @@ -56,6 +58,9 @@ def main(): with open(fullPath, 'rb') as f: lines = f.readlines() parser.parse(''.join(lines), fullPath) + + add_css_properties_attributes(fileList, css_properties_json, parser) + parserResults = parser.finish() if not options.only_html: @@ -86,5 +91,57 @@ def main(): for name, filename in to_generate: generate_file(config, name, os.path.join(outputdir, filename)) + +def add_css_properties_attributes(webidl_files, css_properties_json, parser): + for filename in webidl_files: + if os.path.basename(filename) == "CSSStyleDeclaration.webidl": + break + else: + return + + css_properties = json.load(open(css_properties_json, "rb")) + idl = "partial interface CSSStyleDeclaration {\n%s\n};\n" % "\n".join( + " [%sCEReactions, SetterThrows] attribute [TreatNullAs=EmptyString] DOMString %s;" % ( + ('Pref="%s", ' % pref if pref else ""), + attribute_name + ) + for (property_name, pref) in css_properties + for attribute_name in attribute_names(property_name) + ) + parser.parse(idl.encode("utf-8"), "CSSStyleDeclaration_generated.webidl") + + +def attribute_names(property_name): + # https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-dashed-attribute + if property_name != "float": + yield property_name + else: + yield "_float" + + # https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-camel-cased-attribute + if "-" in property_name: + yield "".join(camel_case(property_name)) + + # https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-webkit-cased-attribute + if property_name.startswith("-webkit-"): + yield "".join(camel_case(property_name), True) + + +# https://drafts.csswg.org/cssom/#css-property-to-idl-attribute +def camel_case(chars, webkit_prefixed=False): + if webkit_prefixed: + chars = chars[1:] + next_is_uppercase = False + for c in chars: + if c == '-': + next_is_uppercase = True + elif next_is_uppercase: + next_is_uppercase = False + # Should be ASCII-uppercase, but all non-custom CSS property names are within ASCII + yield c.upper() + else: + yield c + + if __name__ == '__main__': main() diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index 7ea8423e860..edfdcf9d745 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.py @@ -3344,7 +3344,7 @@ class IDLBuiltinType(IDLType): [self.location, attribute.location]) assert not self.nullable() if not attribute.hasValue(): - raise WebIDLError("[TreatNullAs] must take an identifier argument" + raise WebIDLError("[TreatNullAs] must take an identifier argument", [attribute.location]) value = attribute.value() if value != 'EmptyString': -- cgit v1.2.3 From 0215d09ccbfed85c91605dedbb175dc9a96ba0ab Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 29 Jul 2019 18:57:20 +0200 Subject: =?UTF-8?q?Generate=20apis.html=20and=20css-properties.json=20for?= =?UTF-8?q?=20docs=20as=20part=20of=20crates=E2=80=99=20build=20scripts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … rather than as an extra step after `cargo doc`. This helps always using the correct set of CSS properties (for layout 2013 v.s. 2020). --- .../script/dom/bindings/codegen/CodegenRust.py | 2 +- .../script/dom/bindings/codegen/GlobalGen.py | 42 ++++++++++------------ 2 files changed, 20 insertions(+), 24 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index c7b2c1fe5ef..72f13335ac0 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -7550,7 +7550,7 @@ impl %(base)s { def SupportedDomApis(config): descriptors = config.getDescriptors(isExposedConditionally=False) - base_path = os.path.join('dom', 'bindings', 'codegen') + base_path = os.path.dirname(__file__) with open(os.path.join(base_path, 'apis.html.template')) as f: base_template = f.read() with open(os.path.join(base_path, 'api.html.template')) as f: diff --git a/components/script/dom/bindings/codegen/GlobalGen.py b/components/script/dom/bindings/codegen/GlobalGen.py index 9fe736e71fd..1850a41d5f3 100644 --- a/components/script/dom/bindings/codegen/GlobalGen.py +++ b/components/script/dom/bindings/codegen/GlobalGen.py @@ -29,12 +29,10 @@ def generate_file(config, name, filename): def main(): # Parse arguments. from optparse import OptionParser - usageString = "usage: %prog [options] configFile outputdir webidldir cssProperties.json [files]" + usageString = "usage: %prog [options] configFile outputdir webidldir cssProperties.json docServoDir [files]" o = OptionParser(usage=usageString) o.add_option("--cachedir", dest='cachedir', default=None, help="Directory in which to cache lex/parse tables.") - o.add_option("--only-html", dest='only_html', action="store_true", - help="Only generate HTML from WebIDL inputs") o.add_option("--filelist", dest='filelist', default=None, help="A file containing the list (one per line) of webidl files to process.") (options, args) = o.parse_args() @@ -46,6 +44,7 @@ def main(): outputdir = args[1] baseDir = args[2] css_properties_json = args[3] + doc_servo = args[4] if options.filelist is not None: fileList = [l.strip() for l in open(options.filelist).xreadlines()] else: @@ -63,34 +62,30 @@ def main(): parserResults = parser.finish() - if not options.only_html: - # Write the parser results out to a pickle. - resultsPath = os.path.join(outputdir, 'ParserResults.pkl') - with open(resultsPath, 'wb') as resultsFile: - cPickle.dump(parserResults, resultsFile, -1) + # Write the parser results out to a pickle. + resultsPath = os.path.join(outputdir, 'ParserResults.pkl') + with open(resultsPath, 'wb') as resultsFile: + cPickle.dump(parserResults, resultsFile, -1) # Load the configuration. config = Configuration(configFile, parserResults) to_generate = [ - ('SupportedDomApis', 'apis.html'), + ('PrototypeList', 'PrototypeList.rs'), + ('RegisterBindings', 'RegisterBindings.rs'), + ('InterfaceObjectMap', 'InterfaceObjectMap.rs'), + ('InterfaceObjectMapData', 'InterfaceObjectMapData.json'), + ('InterfaceTypes', 'InterfaceTypes.rs'), + ('InheritTypes', 'InheritTypes.rs'), + ('Bindings', os.path.join('Bindings', 'mod.rs')), + ('UnionTypes', 'UnionTypes.rs'), ] - if not options.only_html: - to_generate = [ - ('PrototypeList', 'PrototypeList.rs'), - ('RegisterBindings', 'RegisterBindings.rs'), - ('InterfaceObjectMap', 'InterfaceObjectMap.rs'), - ('InterfaceObjectMapData', 'InterfaceObjectMapData.json'), - ('InterfaceTypes', 'InterfaceTypes.rs'), - ('InheritTypes', 'InheritTypes.rs'), - ('Bindings', os.path.join('Bindings', 'mod.rs')), - ('UnionTypes', 'UnionTypes.rs'), - ] - for name, filename in to_generate: generate_file(config, name, os.path.join(outputdir, filename)) + generate_file(config, 'SupportedDomApis', os.path.join(doc_servo, 'apis.html')) + def add_css_properties_attributes(webidl_files, css_properties_json, parser): for filename in webidl_files: @@ -102,10 +97,11 @@ def add_css_properties_attributes(webidl_files, css_properties_json, parser): css_properties = json.load(open(css_properties_json, "rb")) idl = "partial interface CSSStyleDeclaration {\n%s\n};\n" % "\n".join( " [%sCEReactions, SetterThrows] attribute [TreatNullAs=EmptyString] DOMString %s;" % ( - ('Pref="%s", ' % pref if pref else ""), + ('Pref="%s", ' % data["pref"] if data["pref"] else ""), attribute_name ) - for (property_name, pref) in css_properties + for (kind, properties_list) in sorted(css_properties.items()) + for (property_name, data) in sorted(properties_list.items()) for attribute_name in attribute_names(property_name) ) parser.parse(idl.encode("utf-8"), "CSSStyleDeclaration_generated.webidl") -- cgit v1.2.3 From c38c964f1b1d2614f50863be0b896e1700b5fea8 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 31 Jul 2019 13:34:01 +0200 Subject: Upgrade to rustc 1.38.0-nightly (dddb7fca0 2019-07-30) --- components/script/dom/bindings/codegen/CodegenRust.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 72f13335ac0..ca041fdddeb 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -7301,9 +7301,9 @@ def process_arg(expr, arg): if arg.variadic or arg.type.isSequence(): expr += ".r()" elif arg.type.nullable() and arg.optional and not arg.defaultValue: - expr += ".as_ref().map(Option::deref)" + expr += ".as_ref().map(Option::as_deref)" elif arg.type.nullable() or arg.optional and not arg.defaultValue: - expr += ".deref()" + expr += ".as_deref()" else: expr = "&" + expr elif isinstance(arg.type, IDLPromiseType): -- cgit v1.2.3 From 51e22fbc2617dc0b8ccc98cc2b19c95c83daa652 Mon Sep 17 00:00:00 2001 From: marmeladema Date: Sat, 27 Jul 2019 15:20:51 +0100 Subject: Remove some usage of unsafe code in Promise --- components/script/dom/bindings/codegen/CodegenRust.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index ca041fdddeb..ef3beafb3f1 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -810,7 +810,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, if !JS_WrapValue(*cx, valueToResolve.handle_mut()) { $*{exceptionCode} } - match Promise::new_resolved(&promiseGlobal, *cx, valueToResolve.handle()) { + match Promise::new_resolved(&promiseGlobal, cx, valueToResolve.handle()) { Ok(value) => value, Err(error) => { throw_dom_exception(*cx, &promiseGlobal, error); -- cgit v1.2.3 From 8968286aa17ab413c072231aaebbd21428245e3e Mon Sep 17 00:00:00 2001 From: marmeladema Date: Sat, 27 Jul 2019 17:05:35 +0100 Subject: Don't mark new methods as unsafe in code generation --- .../script/dom/bindings/codegen/CodegenRust.py | 30 ++++++++++++---------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index ef3beafb3f1..49402ade3c7 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -6355,21 +6355,23 @@ class CGDictionary(CGThing): return string.Template( "impl ${selfName} {\n" "${empty}\n" - " pub unsafe fn new(cx: SafeJSContext, val: HandleValue) \n" + " pub fn new(cx: SafeJSContext, val: HandleValue) \n" " -> Result, ()> {\n" - " let object = if val.get().is_null_or_undefined() {\n" - " ptr::null_mut()\n" - " } else if val.get().is_object() {\n" - " val.get().to_object()\n" - " } else {\n" - " return Ok(ConversionResult::Failure(\"Value is not an object.\".into()));\n" - " };\n" - " rooted!(in(*cx) let object = object);\n" + " unsafe {\n" + " let object = if val.get().is_null_or_undefined() {\n" + " ptr::null_mut()\n" + " } else if val.get().is_object() {\n" + " val.get().to_object()\n" + " } else {\n" + " return Ok(ConversionResult::Failure(\"Value is not an object.\".into()));\n" + " };\n" + " rooted!(in(*cx) let object = object);\n" "${preInitial}" "${initParent}" "${initMembers}" "${postInitial}" - " Ok(ConversionResult::Success(dictionary))\n" + " Ok(ConversionResult::Success(dictionary))\n" + " }\n" " }\n" "}\n" "\n" @@ -6391,11 +6393,11 @@ class CGDictionary(CGThing): "selfName": selfName, "actualType": actualType, "empty": CGIndenter(CGGeneric(self.makeEmpty()), indentLevel=4).define(), - "initParent": CGIndenter(CGGeneric(initParent), indentLevel=12).define(), - "initMembers": CGIndenter(memberInits, indentLevel=12).define(), + "initParent": CGIndenter(CGGeneric(initParent), indentLevel=16).define(), + "initMembers": CGIndenter(memberInits, indentLevel=16).define(), "insertMembers": CGIndenter(memberInserts, indentLevel=8).define(), - "preInitial": CGIndenter(CGGeneric(preInitial), indentLevel=12).define(), - "postInitial": CGIndenter(CGGeneric(postInitial), indentLevel=12).define(), + "preInitial": CGIndenter(CGGeneric(preInitial), indentLevel=16).define(), + "postInitial": CGIndenter(CGGeneric(postInitial), indentLevel=16).define(), }) def membersNeedTracing(self): -- cgit v1.2.3 From b18fa8b8a78a32eb578bb53e7a48de8d371702a1 Mon Sep 17 00:00:00 2001 From: marmeladema Date: Sat, 27 Jul 2019 17:30:36 +0100 Subject: Use safe JSContext in compartments --- components/script/dom/bindings/codegen/CodegenRust.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 49402ade3c7..7daa7c2fd68 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -3335,7 +3335,7 @@ class CGCallGenerator(CGThing): if "cx" not in argsPre and needsCx: args.prepend(CGGeneric("cx")) if nativeMethodName in descriptor.inCompartmentMethods: - args.append(CGGeneric("InCompartment::in_compartment(&AlreadyInCompartment::assert_for_cx(*cx))")) + args.append(CGGeneric("InCompartment::in_compartment(&AlreadyInCompartment::assert_for_cx(cx))")) # Build up our actual call self.cgRoot = CGList([], "\n") -- cgit v1.2.3 From 78034a90d07470d50202b01457c4e18cf7c305fb Mon Sep 17 00:00:00 2001 From: marmeladema Date: Sat, 27 Jul 2019 18:52:12 +0100 Subject: Use safe JSContext when possible in interface.rs --- components/script/dom/bindings/codegen/CodegenRust.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 7daa7c2fd68..144a392b28d 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2651,8 +2651,8 @@ def InitUnforgeablePropertiesOnHolder(descriptor, properties): """ unforgeables = [] - defineUnforgeableAttrs = "define_guarded_properties(*cx, unforgeable_holder.handle(), %s, global);" - defineUnforgeableMethods = "define_guarded_methods(*cx, unforgeable_holder.handle(), %s, global);" + defineUnforgeableAttrs = "define_guarded_properties(cx, unforgeable_holder.handle(), %s, global);" + defineUnforgeableMethods = "define_guarded_methods(cx, unforgeable_holder.handle(), %s, global);" unforgeableMembers = [ (defineUnforgeableAttrs, properties.unforgeable_attrs), @@ -2762,7 +2762,7 @@ class CGWrapGlobalMethod(CGAbstractMethod): ("define_guarded_methods", self.properties.methods), ("define_guarded_constants", self.properties.consts) ] - members = ["%s(*cx, obj.handle(), %s, obj.handle());" % (function, array.variableName()) + members = ["%s(cx, obj.handle(), %s, obj.handle());" % (function, array.variableName()) for (function, array) in pairs if array.length() > 0] values["members"] = "\n".join(members) @@ -2772,7 +2772,7 @@ let _rt = RootedTraceable::new(&*raw); rooted!(in(*cx) let mut obj = ptr::null_mut::()); create_global_object( - *cx, + cx, &Class.base, raw as *const libc::c_void, _trace, @@ -2911,7 +2911,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): rooted!(in(*cx) let proto = %(proto)s); assert!(!proto.is_null()); rooted!(in(*cx) let mut namespace = ptr::null_mut::()); -create_namespace_object(*cx, global, proto.handle(), &NAMESPACE_OBJECT_CLASS, +create_namespace_object(cx, global, proto.handle(), &NAMESPACE_OBJECT_CLASS, %(methods)s, %(name)s, namespace.handle_mut()); assert!(!namespace.is_null()); assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); @@ -2924,7 +2924,7 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); assert not self.descriptor.interface.ctor() and self.descriptor.interface.hasConstants() return CGGeneric("""\ rooted!(in(*cx) let mut interface = ptr::null_mut::()); -create_callback_interface_object(*cx, global, sConstants, %(name)s, interface.handle_mut()); +create_callback_interface_object(cx, global, sConstants, %(name)s, interface.handle_mut()); assert!(!interface.is_null()); assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); (*cache)[PrototypeList::Constructor::%(id)s as usize] = interface.get(); @@ -2976,7 +2976,7 @@ assert!(!prototype_proto.is_null());""" % getPrototypeProto)] code.append(CGGeneric(""" rooted!(in(*cx) let mut prototype = ptr::null_mut::()); -create_interface_prototype_object(*cx, +create_interface_prototype_object(cx, global.into(), prototype_proto.handle().into(), &PrototypeClass, @@ -3011,7 +3011,7 @@ assert!((*cache)[PrototypeList::ID::%(id)s as usize].is_null()); assert!(!interface_proto.is_null()); rooted!(in(*cx) let mut interface = ptr::null_mut::()); -create_noncallback_interface_object(*cx, +create_noncallback_interface_object(cx, global.into(), interface_proto.handle(), &INTERFACE_OBJECT_CLASS, @@ -3093,7 +3093,7 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); specs.append(CGGeneric("(%s as ConstructorClassHook, %s, %d)" % (hook, name, length))) values = CGIndenter(CGList(specs, "\n"), 4) code.append(CGWrapper(values, pre="%s = [\n" % decl, post="\n];")) - code.append(CGGeneric("create_named_constructors(*cx, global, &named_constructors, prototype.handle());")) + code.append(CGGeneric("create_named_constructors(cx, global, &named_constructors, prototype.handle());")) if self.descriptor.hasUnforgeableMembers: # We want to use the same JSClass and prototype as the object we'll -- cgit v1.2.3 From 6c26518f61f016bf2a0bac9dced9d222880fbaec Mon Sep 17 00:00:00 2001 From: marmeladema Date: Sat, 27 Jul 2019 19:15:38 +0100 Subject: Remove usage of various unsafe keyword --- .../script/dom/bindings/codegen/CodegenRust.py | 29 +++++++++++----------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 144a392b28d..63a72cbec9e 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2588,8 +2588,7 @@ class CGConstructorEnabled(CGAbstractMethod): CGAbstractMethod.__init__(self, descriptor, 'ConstructorEnabled', 'bool', [Argument("SafeJSContext", "aCx"), - Argument("HandleObject", "aObj")], - unsafe=True) + Argument("HandleObject", "aObj")]) def definition_body(self): conditions = [] @@ -3137,23 +3136,25 @@ class CGGetPerInterfaceObject(CGAbstractMethod): Argument('HandleObject', 'global'), Argument('MutableHandleObject', 'mut rval')] CGAbstractMethod.__init__(self, descriptor, name, - 'void', args, pub=pub, unsafe=True) + 'void', args, pub=pub) self.id = idPrefix + "::" + MakeNativeName(self.descriptor.name) def definition_body(self): return CGGeneric(""" -assert!(((*get_object_class(global.get())).flags & JSCLASS_DOM_GLOBAL) != 0); +unsafe { + assert!(((*get_object_class(global.get())).flags & JSCLASS_DOM_GLOBAL) != 0); + + /* Check to see whether the interface objects are already installed */ + let proto_or_iface_array = get_proto_or_iface_array(global.get()); + rval.set((*proto_or_iface_array)[%(id)s as usize]); + if !rval.get().is_null() { + return; + } -/* Check to see whether the interface objects are already installed */ -let proto_or_iface_array = get_proto_or_iface_array(global.get()); -rval.set((*proto_or_iface_array)[%(id)s as usize]); -if !rval.get().is_null() { - return; + CreateInterfaceObjects(cx, global, proto_or_iface_array); + rval.set((*proto_or_iface_array)[%(id)s as usize]); + assert!(!rval.get().is_null()); } - -CreateInterfaceObjects(cx, global, proto_or_iface_array); -rval.set((*proto_or_iface_array)[%(id)s as usize]); -assert!(!rval.get().is_null()); """ % {"id": self.id}) @@ -3274,7 +3275,7 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod): Argument('HandleObject', 'global'), ] CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', - 'void', args, pub=True, unsafe=True) + 'void', args, pub=True) def define(self): return CGAbstractMethod.define(self) -- cgit v1.2.3 From 0703a1ad6d736796d467f5a028e5ab3c6d876268 Mon Sep 17 00:00:00 2001 From: marmeladema Date: Sat, 27 Jul 2019 19:36:21 +0100 Subject: Use safe JSContext as first argument for throw_dom_exception --- components/script/dom/bindings/codegen/CodegenRust.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 63a72cbec9e..ea27af3b5b6 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -813,7 +813,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, match Promise::new_resolved(&promiseGlobal, cx, valueToResolve.handle()) { Ok(value) => value, Err(error) => { - throw_dom_exception(*cx, &promiseGlobal, error); + throw_dom_exception(cx, &promiseGlobal, error); $*{exceptionCode} } } @@ -3372,7 +3372,7 @@ class CGCallGenerator(CGThing): "let result = match result {\n" " Ok(result) => result,\n" " Err(e) => {\n" - " throw_dom_exception(*cx, %s, e);\n" + " throw_dom_exception(cx, %s, e);\n" " return%s;\n" " },\n" "};" % (glob, errorResult))) @@ -5556,12 +5556,12 @@ let global = DomRoot::downcast::(global).unwrap(); // so we can do the spec's object-identity checks. rooted!(in(*cx) let new_target = UnwrapObjectDynamic(args.new_target().to_object(), *cx, 1)); if new_target.is_null() { - throw_dom_exception(*cx, global.upcast::(), Error::Type("new.target is null".to_owned())); + throw_dom_exception(cx, global.upcast::(), Error::Type("new.target is null".to_owned())); return false; } if args.callee() == new_target.get() { - throw_dom_exception(*cx, global.upcast::(), + throw_dom_exception(cx, global.upcast::(), Error::Type("new.target must not be the active function object".to_owned())); return false; } @@ -5602,7 +5602,7 @@ let result: Result, Error> = html_constructor(&global, &args); let result = match result { Ok(result) => result, Err(e) => { - throw_dom_exception(*cx, global.upcast::(), e); + throw_dom_exception(cx, global.upcast::(), e); return false; }, }; -- cgit v1.2.3 From 357b6c54ff053fdd9e17832c06d7acdcbcb07991 Mon Sep 17 00:00:00 2001 From: marmeladema Date: Sat, 27 Jul 2019 20:03:16 +0100 Subject: Use safe JSContext in callbacks --- components/script/dom/bindings/codegen/CodegenRust.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index ea27af3b5b6..4bea65388b6 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -6828,8 +6828,8 @@ class CGCallback(CGClass): # Record the names of all the arguments, so we can use them when we call # the private method. argnames = [arg.name for arg in args] - argnamesWithThis = ["SafeJSContext::from_ptr(s.get_context())", "thisObjJS.handle()"] + argnames - argnamesWithoutThis = ["SafeJSContext::from_ptr(s.get_context())", "thisObjJS.handle()"] + argnames + argnamesWithThis = ["s.get_context()", "thisObjJS.handle()"] + argnames + argnamesWithoutThis = ["s.get_context()", "thisObjJS.handle()"] + argnames # Now that we've recorded the argnames for our call to our private # method, insert our optional argument for deciding whether the # CallSetup should re-throw exceptions on aRv. @@ -6849,7 +6849,7 @@ class CGCallback(CGClass): bodyWithThis = string.Template( setupCall + - "rooted!(in(s.get_context()) let mut thisObjJS = ptr::null_mut::());\n" + "rooted!(in(*s.get_context()) let mut thisObjJS = ptr::null_mut::());\n" "wrap_call_this_object(s.get_context(), thisObj, thisObjJS.handle_mut());\n" "if thisObjJS.is_null() {\n" " return Err(JSFailed);\n" @@ -6860,7 +6860,7 @@ class CGCallback(CGClass): }) bodyWithoutThis = string.Template( setupCall + - "rooted!(in(s.get_context()) let thisObjJS = ptr::null_mut::());\n" + "rooted!(in(*s.get_context()) let thisObjJS = ptr::null_mut::());\n" "unsafe { ${methodName}(${callArgs}) }").substitute({ "callArgs": ", ".join(argnamesWithoutThis), "methodName": 'self.' + method.name, @@ -7118,7 +7118,7 @@ class CallbackMember(CGNativeMember): return "" return ( "CallSetup s(CallbackPreserveColor(), aRv, aExceptionHandling);\n" - "JSContext* cx = s.get_context();\n" + "JSContext* cx = *s.get_context();\n" "if (!cx) {\n" " return Err(JSFailed);\n" "}\n") @@ -7219,7 +7219,7 @@ class CallbackOperationBase(CallbackMethod): "methodName": self.methodName } getCallableFromProp = string.Template( - 'r#try!(self.parent.get_callable_property(*cx, "${methodName}"))' + 'r#try!(self.parent.get_callable_property(cx, "${methodName}"))' ).substitute(replacements) if not self.singleOperation: return 'rooted!(in(*cx) let callable =\n' + getCallableFromProp + ');\n' -- cgit v1.2.3 From 1806b9ede2f7e2b6d621900aa841a535c03a433a Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Fri, 16 Aug 2019 21:13:29 +0900 Subject: Update WebIDL parser --- .../script/dom/bindings/codegen/CodegenRust.py | 2 +- .../script/dom/bindings/codegen/parser/WebIDL.py | 496 ++++++++++++++++----- .../dom/bindings/codegen/parser/abstract.patch | 2 +- .../script/dom/bindings/codegen/parser/debug.patch | 2 +- .../bindings/codegen/parser/exposed-globals.patch | 27 -- .../dom/bindings/codegen/parser/inline.patch | 2 +- .../tests/test_conditional_dictionary_member.py | 12 +- .../codegen/parser/tests/test_interfacemixin.py | 373 ++++++++++++++++ .../bindings/codegen/parser/union-typedef.patch | 4 +- .../script/dom/bindings/codegen/parser/update.sh | 1 - 10 files changed, 758 insertions(+), 163 deletions(-) delete mode 100644 components/script/dom/bindings/codegen/parser/exposed-globals.patch create mode 100644 components/script/dom/bindings/codegen/parser/tests/test_interfacemixin.py (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 4bea65388b6..8b4e903d909 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1576,7 +1576,7 @@ class PropertyDefiner: "Pref"), PropertyDefiner.getStringAttr(interfaceMember, "Func"), - interfaceMember.exposedSet()) + interfaceMember.exposureSet) def generateGuardedArray(self, array, name, specTemplate, specTerminator, specType, getCondition, getDataTuple): diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index edfdcf9d745..b934c21db5b 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.py @@ -314,7 +314,7 @@ class IDLScope(IDLObject): newObject.location) raise WebIDLError( - "Multiple unresolvable definitions of identifier '%s' in scope '%s%s" + "Multiple unresolvable definitions of identifier '%s' in scope '%s'%s" % (identifier.name, str(self), conflictdesc), []) def _lookupIdentifier(self, identifier): @@ -605,7 +605,7 @@ class IDLPartialInterfaceOrNamespace(IDLObject): self._haveSecureContextExtendedAttribute = False self._nonPartialInterfaceOrNamespace = nonPartialInterfaceOrNamespace self._finished = False - nonPartialInterfaceOrNamespace.addPartialInterface(self) + nonPartialInterfaceOrNamespace.addPartial(self) def addExtendedAttributes(self, attrs): for attr in attrs: @@ -676,30 +676,212 @@ def globalNameSetToExposureSet(globalScope, nameSet, exposureSet): for name in nameSet: exposureSet.update(globalScope.globalNameMapping[name]) +class IDLInterfaceOrInterfaceMixinOrNamespace(IDLObjectWithScope, IDLExposureMixins): + def __init__(self, location, parentScope, name): + assert isinstance(parentScope, IDLScope) + assert isinstance(name, IDLUnresolvedIdentifier) + + self._finished = False + self.members = [] + self._partials = [] + self._extendedAttrDict = {} + self._isKnownNonPartial = False + + IDLObjectWithScope.__init__(self, location, parentScope, name) + IDLExposureMixins.__init__(self, location) + + def finish(self, scope): + if not self._isKnownNonPartial: + raise WebIDLError("%s does not have a non-partial declaration" % + str(self), [self.location]) + + IDLExposureMixins.finish(self, scope) + + # Now go ahead and merge in our partials. + for partial in self._partials: + partial.finish(scope) + self.addExtendedAttributes(partial.propagatedExtendedAttrs) + self.members.extend(partial.members) + + def resolveIdentifierConflict(self, scope, identifier, originalObject, newObject): + assert isinstance(scope, IDLScope) + assert isinstance(originalObject, IDLInterfaceMember) + assert isinstance(newObject, IDLInterfaceMember) + + retval = IDLScope.resolveIdentifierConflict(self, scope, identifier, + originalObject, newObject) + + # Might be a ctor, which isn't in self.members + if newObject in self.members: + self.members.remove(newObject) + return retval + + def typeName(self): + if self.isInterface(): + return "interface" + if self.isNamespace(): + return "namespace" + return "interface mixin" -class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): + def getExtendedAttribute(self, name): + return self._extendedAttrDict.get(name, None) + + def setNonPartial(self, location, members): + if self._isKnownNonPartial: + raise WebIDLError("Two non-partial definitions for the " + "same %s" % self.typeName(), + [location, self.location]) + self._isKnownNonPartial = True + # Now make it look like we were parsed at this new location, since + # that's the place where the interface is "really" defined + self.location = location + # Put the new members at the beginning + self.members = members + self.members + + def addPartial(self, partial): + assert self.identifier.name == partial.identifier.name + self._partials.append(partial) + + def getPartials(self): + # Don't let people mutate our guts. + return list(self._partials) + + def finishMembers(self, scope): + # Assuming we've merged in our partials, set the _exposureGlobalNames on + # any members that don't have it set yet. Note that any partial + # interfaces that had [Exposed] set have already set up + # _exposureGlobalNames on all the members coming from them, so this is + # just implementing the "members default to interface or interface mixin + # that defined them" and "partial interfaces or interface mixins default + # to interface or interface mixin they're a partial for" rules from the + # spec. + for m in self.members: + # If m, or the partial m came from, had [Exposed] + # specified, it already has a nonempty exposure global names set. + if len(m._exposureGlobalNames) == 0: + m._exposureGlobalNames.update(self._exposureGlobalNames) + + # resolve() will modify self.members, so we need to iterate + # over a copy of the member list here. + for member in list(self.members): + member.resolve(self) + + for member in self.members: + member.finish(scope) + + # Now that we've finished our members, which has updated their exposure + # sets, make sure they aren't exposed in places where we are not. + for member in self.members: + if not member.exposureSet.issubset(self.exposureSet): + raise WebIDLError("Interface or interface mixin member has" + "larger exposure set than its container", + [member.location, self.location]) + + +class IDLInterfaceMixin(IDLInterfaceOrInterfaceMixinOrNamespace): + def __init__(self, location, parentScope, name, members, isKnownNonPartial): + self.actualExposureGlobalNames = set() + + assert isKnownNonPartial or len(members) == 0 + IDLInterfaceOrInterfaceMixinOrNamespace.__init__(self, location, parentScope, name) + + if isKnownNonPartial: + self.setNonPartial(location, members) + + def __str__(self): + return "Interface mixin '%s'" % self.identifier.name + + def finish(self, scope): + if self._finished: + return + self._finished = True + + # Expose to the globals of interfaces that includes this mixin if this + # mixin has no explicit [Exposed] so that its members can be exposed + # based on the base interface exposure set. + # Make sure this is done before IDLExposureMixins.finish call to + # prevent exposing to PrimaryGlobal by default. + hasImplicitExposure = len(self._exposureGlobalNames) == 0 + if hasImplicitExposure: + self._exposureGlobalNames.update(self.actualExposureGlobalNames) + + IDLInterfaceOrInterfaceMixinOrNamespace.finish(self, scope) + + self.finishMembers(scope) + + def validate(self): + for member in self.members: + + if member.isAttr(): + if member.inherit: + raise WebIDLError("Interface mixin member cannot include " + "an inherited attribute", + [member.location, self.location]) + if member.isStatic(): + raise WebIDLError("Interface mixin member cannot include " + "a static member", + [member.location, self.location]) + + if member.isMethod(): + if member.isStatic(): + raise WebIDLError("Interface mixin member cannot include " + "a static operation", + [member.location, self.location]) + if (member.isGetter() or + member.isSetter() or + member.isDeleter() or + member.isLegacycaller()): + raise WebIDLError("Interface mixin member cannot include a " + "special operation", + [member.location, self.location]) + + def addExtendedAttributes(self, attrs): + for attr in attrs: + identifier = attr.identifier() + + if identifier == "SecureContext": + if not attr.noArguments(): + raise WebIDLError("[%s] must take no arguments" % identifier, + [attr.location]) + # This gets propagated to all our members. + for member in self.members: + if member.getExtendedAttribute("SecureContext"): + raise WebIDLError("[SecureContext] specified on both " + "an interface mixin member and on" + "the interface mixin itself", + [member.location, attr.location]) + member.addExtendedAttributes([attr]) + elif identifier == "Exposed": + convertExposedAttrToGlobalNameSet(attr, + self._exposureGlobalNames) + else: + raise WebIDLError("Unknown extended attribute %s on interface" % identifier, + [attr.location]) + + attrlist = attr.listValue() + self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True + + def _getDependentObjects(self): + return set(self.members) + + +class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): def __init__(self, location, parentScope, name, parent, members, isKnownNonPartial, toStringTag): - assert isinstance(parentScope, IDLScope) - assert isinstance(name, IDLUnresolvedIdentifier) assert isKnownNonPartial or not parent assert isKnownNonPartial or len(members) == 0 self.parent = None self._callback = False - self._finished = False - self.members = [] self.maplikeOrSetlikeOrIterable = None - self._partialInterfaces = [] - self._extendedAttrDict = {} # namedConstructors needs deterministic ordering because bindings code # outputs the constructs in the order that namedConstructors enumerates # them. self.namedConstructors = list() self.legacyWindowAliases = [] self.implementedInterfaces = set() + self.includedMixins = set() self._consequential = False - self._isKnownNonPartial = False # self.interfacesBasedOnSelf is the set of interfaces that inherit from # self or have self as a consequential interface, including self itself. # Used for distinguishability checking. @@ -720,8 +902,7 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): self.toStringTag = toStringTag - IDLObjectWithScope.__init__(self, location, parentScope, name) - IDLExposureMixins.__init__(self, location) + IDLInterfaceOrInterfaceMixinOrNamespace.__init__(self, location, parentScope, name) if isKnownNonPartial: self.setNonPartial(location, parent, members) @@ -741,31 +922,13 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): def isIteratorInterface(self): return self.iterableInterface is not None - def resolveIdentifierConflict(self, scope, identifier, originalObject, newObject): - assert isinstance(scope, IDLScope) - assert isinstance(originalObject, IDLInterfaceMember) - assert isinstance(newObject, IDLInterfaceMember) - - retval = IDLScope.resolveIdentifierConflict(self, scope, identifier, - originalObject, newObject) - - # Might be a ctor, which isn't in self.members - if newObject in self.members: - self.members.remove(newObject) - return retval - def finish(self, scope): if self._finished: return self._finished = True - if not self._isKnownNonPartial: - raise WebIDLError("Interface %s does not have a non-partial " - "declaration" % self.identifier.name, - [self.location]) - - IDLExposureMixins.finish(self, scope) + IDLInterfaceOrInterfaceMixinOrNamespace.finish(self, scope) if len(self.legacyWindowAliases) > 0: if not self.hasInterfaceObject(): @@ -777,12 +940,6 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): "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) - self.addExtendedAttributes(partial.propagatedExtendedAttrs) - self.members.extend(partial.members) - # Generate maplike/setlike interface members. Since generated members # need to be treated like regular interface members, do this before # things like exposure setting. @@ -804,19 +961,6 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): # our required methods in Codegen. Generate members now. 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 - # that any partial interfaces that had [Exposed] set have already set up - # _exposureGlobalNames on all the members coming from them, so this is - # just implementing the "members default to interface that defined them" - # and "partial interfaces default to interface they're a partial for" - # rules from the spec. - for m in self.members: - # If m, or the partial interface m came from, had [Exposed] - # specified, it already has a nonempty exposure global names set. - if len(m._exposureGlobalNames) == 0: - m._exposureGlobalNames.update(self._exposureGlobalNames) - assert not self.parent or isinstance(self.parent, IDLIdentifierPlaceholder) parent = self.parent.finish(scope) if self.parent else None if parent and isinstance(parent, IDLExternalInterface): @@ -912,6 +1056,8 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): for iface in self.implementedInterfaces: iface.finish(scope) + for mixin in self.includedMixins: + mixin.finish(scope) cycleInGraph = self.findInterfaceLoopPoint(self) if cycleInGraph: @@ -926,24 +1072,7 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): # And that we're not consequential. assert not self.isConsequential() - # Now resolve() and finish() our members before importing the - # ones from our implemented interfaces. - - # resolve() will modify self.members, so we need to iterate - # over a copy of the member list here. - for member in list(self.members): - member.resolve(self) - - for member in self.members: - member.finish(scope) - - # Now that we've finished our members, which has updated their exposure - # sets, make sure they aren't exposed in places where we are not. - for member in self.members: - if not member.exposureSet.issubset(self.exposureSet): - raise WebIDLError("Interface member has larger exposure set " - "than the interface itself", - [member.location, self.location]) + self.finishMembers(scope) ctor = self.ctor() if ctor is not None: @@ -996,6 +1125,10 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): self.members.extend(additionalMembers) iface.interfacesImplementingSelf.add(self) + for mixin in sorted(self.includedMixins, + key=lambda x: x.identifier.name): + self.members.extend(mixin.members) + for ancestor in self.getInheritedInterfaces(): ancestor.interfacesBasedOnSelf.add(self) if (ancestor.maplikeOrSetlikeOrIterable is not None and @@ -1430,6 +1563,10 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): assert(isinstance(implementedInterface, IDLInterface)) self.implementedInterfaces.add(implementedInterface) + def addIncludedMixin(self, includedMixin): + assert(isinstance(includedMixin, IDLInterfaceMixin)) + self.includedMixins.add(includedMixin) + def getInheritedInterfaces(self): """ Returns a list of the interfaces this interface inherits from @@ -1478,34 +1615,11 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): if loopPoint: return loopPoint return None - - def getExtendedAttribute(self, name): - return self._extendedAttrDict.get(name, None) - def setNonPartial(self, location, parent, members): assert not parent or isinstance(parent, IDLIdentifierPlaceholder) - if self._isKnownNonPartial: - raise WebIDLError("Two non-partial definitions for the " - "same %s" % - ("interface" if self.isInterface() - else "namespace"), - [location, self.location]) - self._isKnownNonPartial = True - # Now make it look like we were parsed at this new location, since - # that's the place where the interface is "really" defined - self.location = location + IDLInterfaceOrInterfaceMixinOrNamespace.setNonPartial(self, location, members) assert not self.parent self.parent = parent - # Put the new members at the beginning - self.members = members + self.members - - def addPartialInterface(self, partial): - assert self.identifier.name == partial.identifier.name - self._partialInterfaces.append(partial) - - def getPartialInterfaces(self): - # Don't let people mutate our guts. - return list(self._partialInterfaces) def getJSImplementation(self): classId = self.getExtendedAttribute("JSImplementation") @@ -1568,6 +1682,7 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): def _getDependentObjects(self): deps = set(self.members) deps.update(self.implementedInterfaces) + deps.update(self.includedMixins) if self.parent: deps.add(self.parent) return deps @@ -3344,7 +3459,7 @@ class IDLBuiltinType(IDLType): [self.location, attribute.location]) assert not self.nullable() if not attribute.hasValue(): - raise WebIDLError("[TreatNullAs] must take an identifier argument", + raise WebIDLError("[TreatNullAs] must take an identifier argument" [attribute.location]) value = attribute.value() if value != 'EmptyString': @@ -3723,7 +3838,6 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins): IDLObjectWithIdentifier.__init__(self, location, None, identifier) IDLExposureMixins.__init__(self, location) self.tag = tag - self.exposed = set() if extendedAttrDict is None: self._extendedAttrDict = {} else: @@ -3757,16 +3871,12 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins): def getExtendedAttribute(self, name): return self._extendedAttrDict.get(name, None) - def exposedSet(self): - return self.exposed - def finish(self, scope): # We better be exposed _somewhere_. if (len(self._exposureGlobalNames) == 0): print(self.identifier.name) assert len(self._exposureGlobalNames) != 0 IDLExposureMixins.finish(self, scope) - globalNameSetToExposureSet(scope, self._exposureGlobalNames, self.exposed) def validate(self): if self.isAttr() or self.isMethod(): @@ -5433,6 +5543,49 @@ class IDLImplementsStatement(IDLObject): "allowed on implements statements", [attrs[0].location, self.location]) +class IDLIncludesStatement(IDLObject): + def __init__(self, location, interface, mixin): + IDLObject.__init__(self, location) + self.interface = interface + self.mixin = mixin + self._finished = False + + def finish(self, scope): + if self._finished: + return + self._finished = True + assert(isinstance(self.interface, IDLIdentifierPlaceholder)) + assert(isinstance(self.mixin, IDLIdentifierPlaceholder)) + interface = self.interface.finish(scope) + mixin = self.mixin.finish(scope) + # NOTE: we depend on not setting self.interface and + # self.mixin here to keep track of the original + # locations. + if not isinstance(interface, IDLInterface): + raise WebIDLError("Left-hand side of 'includes' is not an " + "interface", + [self.interface.location]) + if interface.isCallback(): + raise WebIDLError("Left-hand side of 'includes' is a callback " + "interface", + [self.interface.location]) + if not isinstance(mixin, IDLInterfaceMixin): + raise WebIDLError("Right-hand side of 'includes' is not an " + "interface mixin", + [self.mixin.location]) + mixin.actualExposureGlobalNames.update(interface._exposureGlobalNames) + interface.addIncludedMixin(mixin) + self.interface = interface + self.mixin = mixin + + def validate(self): + pass + + def addExtendedAttributes(self, attrs): + if len(attrs) != 0: + raise WebIDLError("There are no extended attributes that are " + "allowed on includes statements", + [attrs[0].location, self.location]) class IDLExtendedAttribute(IDLObject): """ @@ -5529,12 +5682,14 @@ class Tokenizer(object): "module": "MODULE", "interface": "INTERFACE", "partial": "PARTIAL", + "mixin": "MIXIN", "dictionary": "DICTIONARY", "exception": "EXCEPTION", "enum": "ENUM", "callback": "CALLBACK", "typedef": "TYPEDEF", "implements": "IMPLEMENTS", + "includes": "INCLUDES", "const": "CONST", "null": "NULL", "true": "TRUE", @@ -5689,7 +5844,7 @@ class Parser(Tokenizer): def p_Definition(self, p): """ - Definition : CallbackOrInterface + Definition : CallbackOrInterfaceOrMixin | Namespace | Partial | Dictionary @@ -5697,13 +5852,14 @@ class Parser(Tokenizer): | Enum | Typedef | ImplementsStatement + | IncludesStatement """ p[0] = p[1] assert p[1] # We might not have implemented something ... - def p_CallbackOrInterfaceCallback(self, p): + def p_CallbackOrInterfaceOrMixinCallback(self, p): """ - CallbackOrInterface : CALLBACK CallbackRestOrInterface + CallbackOrInterfaceOrMixin : CALLBACK CallbackRestOrInterface """ if p[2].isInterface(): assert isinstance(p[2], IDLInterface) @@ -5711,17 +5867,17 @@ class Parser(Tokenizer): p[0] = p[2] - def p_CallbackOrInterfaceInterface(self, p): + def p_CallbackOrInterfaceOrMixinInterfaceOrMixin(self, p): """ - CallbackOrInterface : Interface + CallbackOrInterfaceOrMixin : INTERFACE InterfaceOrMixin """ - p[0] = p[1] + p[0] = p[2] def p_CallbackRestOrInterface(self, p): """ CallbackRestOrInterface : CallbackRest | CallbackConstructorRest - | Interface + | CallbackInterface """ assert p[1] p[0] = p[1] @@ -5762,14 +5918,27 @@ class Parser(Tokenizer): # True for isKnownNonPartial return constructor(*(constructorArgs + [True])) - def p_Interface(self, p): + def p_InterfaceOrMixin(self, p): """ - Interface : INTERFACE IDENTIFIER Inheritance LBRACE InterfaceMembers RBRACE SEMICOLON + InterfaceOrMixin : InterfaceRest + | MixinRest + """ + p[0] = p[1] + + def p_CallbackInterface(self, p): + """ + CallbackInterface : INTERFACE InterfaceRest + """ + p[0] = p[2] + + def p_InterfaceRest(self, p): + """ + InterfaceRest : IDENTIFIER Inheritance LBRACE InterfaceMembers RBRACE SEMICOLON """ location = self.getLocation(p, 1) - identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) - members = p[5] - parent = p[3] + identifier = IDLUnresolvedIdentifier(location, p[1]) + members = p[4] + parent = p[2] p[0] = self.handleNonPartialObject( location, identifier, IDLInterface, @@ -5778,10 +5947,10 @@ class Parser(Tokenizer): def p_InterfaceForwardDecl(self, p): """ - Interface : INTERFACE IDENTIFIER SEMICOLON + InterfaceRest : IDENTIFIER SEMICOLON """ location = self.getLocation(p, 1) - identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) + identifier = IDLUnresolvedIdentifier(location, p[1]) try: if self.globalScope()._lookupIdentifier(identifier): @@ -5799,6 +5968,19 @@ class Parser(Tokenizer): p[0] = IDLExternalInterface(location, self.globalScope(), identifier) + def p_MixinRest(self, p): + """ + MixinRest : MIXIN IDENTIFIER LBRACE MixinMembers RBRACE SEMICOLON + """ + location = self.getLocation(p, 1) + identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) + members = p[4] + + p[0] = self.handleNonPartialObject( + location, identifier, IDLInterfaceMixin, + [location, self.globalScope(), identifier, members], + [location, members]) + def p_Namespace(self, p): """ Namespace : NAMESPACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON @@ -5818,10 +6000,15 @@ class Parser(Tokenizer): """ p[0] = p[2] + def p_PartialDefinitionInterface(self, p): + """ + PartialDefinition : INTERFACE PartialInterfaceOrPartialMixin + """ + p[0] = p[2] + def p_PartialDefinition(self, p): """ - PartialDefinition : PartialInterface - | PartialNamespace + PartialDefinition : PartialNamespace | PartialDictionary """ p[0] = p[1] @@ -5864,34 +6051,55 @@ class Parser(Tokenizer): if not nonPartialObject: nonPartialObject = nonPartialConstructor( # No members, False for isKnownNonPartial - *(nonPartialConstructorArgs + [[], False])) + *(nonPartialConstructorArgs), members=[], isKnownNonPartial=False) partialObject = None if isinstance(nonPartialObject, IDLDictionary): partialObject = IDLPartialDictionary( *(partialConstructorArgs + [nonPartialObject])) - elif isinstance(nonPartialObject, (IDLInterface, IDLNamespace)): + elif isinstance(nonPartialObject, (IDLInterface, IDLInterfaceMixin, IDLNamespace)): partialObject = IDLPartialInterfaceOrNamespace( *(partialConstructorArgs + [nonPartialObject])) else: raise WebIDLError("Unknown partial object type %s" % - type(partialObject)) + type(partialObject), + [location]) return partialObject - def p_PartialInterface(self, p): + def p_PartialInterfaceOrPartialMixin(self, p): + """ + PartialInterfaceOrPartialMixin : PartialInterfaceRest + | PartialMixinRest + """ + p[0] = p[1] + + def p_PartialInterfaceRest(self, p): """ - PartialInterface : INTERFACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON + PartialInterfaceRest : IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON """ location = self.getLocation(p, 1) - identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) - members = p[4] + identifier = IDLUnresolvedIdentifier(location, p[1]) + members = p[3] p[0] = self.handlePartialObject( location, identifier, IDLInterface, [location, self.globalScope(), identifier, None], [location, identifier, members]) + def p_PartialMixinRest(self, p): + """ + PartialMixinRest : MIXIN IDENTIFIER LBRACE MixinMembers RBRACE SEMICOLON + """ + location = self.getLocation(p, 1) + identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) + members = p[4] + + p[0] = self.handlePartialObject( + location, identifier, IDLInterfaceMixin, + [location, self.globalScope(), identifier], + [location, identifier, members]) + def p_PartialNamespace(self, p): """ PartialNamespace : NAMESPACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON @@ -5934,7 +6142,7 @@ class Parser(Tokenizer): """ InterfaceMembers : ExtendedAttributeList InterfaceMember InterfaceMembers """ - p[0] = [p[2]] if p[2] else [] + p[0] = [p[2]] assert not p[1] or p[2] p[2].addExtendedAttributes(p[1]) @@ -5954,6 +6162,32 @@ class Parser(Tokenizer): """ p[0] = p[1] + + def p_MixinMembersEmpty(self, p): + """ + MixinMembers : + """ + p[0] = [] + + def p_MixinMembers(self, p): + """ + MixinMembers : ExtendedAttributeList MixinMember MixinMembers + """ + p[0] = [p[2]] + + assert not p[1] or p[2] + p[2].addExtendedAttributes(p[1]) + + p[0].extend(p[3]) + + def p_MixinMember(self, p): + """ + MixinMember : Const + | Attribute + | Operation + """ + p[0] = p[1] + def p_Dictionary(self, p): """ Dictionary : DICTIONARY IDENTIFIER Inheritance LBRACE DictionaryMembers RBRACE SEMICOLON @@ -6130,6 +6364,15 @@ class Parser(Tokenizer): p[0] = IDLImplementsStatement(self.getLocation(p, 1), implementor, implementee) + def p_IncludesStatement(self, p): + """ + IncludesStatement : ScopedName INCLUDES ScopedName SEMICOLON + """ + assert(p[2] == "includes") + interface = IDLIdentifierPlaceholder(self.getLocation(p, 1), p[1]) + mixin = IDLIdentifierPlaceholder(self.getLocation(p, 3), p[3]) + p[0] = IDLIncludesStatement(self.getLocation(p, 1), interface, mixin) + def p_Const(self, p): """ Const : CONST ConstType IDENTIFIER EQUALS ConstValue SEMICOLON @@ -7260,10 +7503,17 @@ class Parser(Tokenizer): # XXX khuey hates this bit and wants to nuke it from orbit. implementsStatements = [p for p in self._productions if isinstance(p, IDLImplementsStatement)] + # Make sure we finish IDLIncludesStatements before we finish the + # IDLInterfaces. + includesStatements = [p for p in self._productions if + isinstance(p, IDLIncludesStatement)] otherStatements = [p for p in self._productions if - not isinstance(p, IDLImplementsStatement)] + not isinstance(p, (IDLImplementsStatement, + IDLIncludesStatement))] for production in implementsStatements: production.finish(self.globalScope()) + for production in includesStatements: + production.finish(self.globalScope()) for production in otherStatements: production.finish(self.globalScope()) diff --git a/components/script/dom/bindings/codegen/parser/abstract.patch b/components/script/dom/bindings/codegen/parser/abstract.patch index e2db398a051..180e345b61b 100644 --- a/components/script/dom/bindings/codegen/parser/abstract.patch +++ b/components/script/dom/bindings/codegen/parser/abstract.patch @@ -1,6 +1,6 @@ --- WebIDL.py +++ WebIDL.py -@@ -1768,7 +1768,8 @@ class IDLInterface(IDLInterfaceOrNamespace): +@@ -1883,7 +1883,8 @@ class IDLInterface(IDLInterfaceOrNamespace): identifier == "LegacyUnenumerableNamedProperties" or identifier == "RunConstructorInCallerCompartment" or identifier == "WantsEventListenerHooks" or diff --git a/components/script/dom/bindings/codegen/parser/debug.patch b/components/script/dom/bindings/codegen/parser/debug.patch index f9b3d940399..a4f8739000d 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 -@@ -7123,7 +7123,8 @@ class Parser(Tokenizer): +@@ -7382,7 +7382,8 @@ class Parser(Tokenizer): self.parser = yacc.yacc(module=self, outputdir=outputdir, tabmodule='webidlyacc', diff --git a/components/script/dom/bindings/codegen/parser/exposed-globals.patch b/components/script/dom/bindings/codegen/parser/exposed-globals.patch deleted file mode 100644 index 02ad787f5e0..00000000000 --- a/components/script/dom/bindings/codegen/parser/exposed-globals.patch +++ /dev/null @@ -1,27 +0,0 @@ ---- WebIDL.py -+++ WebIDL.py -@@ -3653,6 +3653,7 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins): - IDLObjectWithIdentifier.__init__(self, location, None, identifier) - IDLExposureMixins.__init__(self, location) - self.tag = tag -+ self.exposed = set() - if extendedAttrDict is None: - self._extendedAttrDict = {} - else: -@@ -3686,12 +3687,16 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins): - def getExtendedAttribute(self, name): - return self._extendedAttrDict.get(name, None) - -+ def exposedSet(self): -+ return self.exposed -+ - def finish(self, scope): - # We better be exposed _somewhere_. - if (len(self._exposureGlobalNames) == 0): - print self.identifier.name - assert len(self._exposureGlobalNames) != 0 - IDLExposureMixins.finish(self, scope) -+ globalNameSetToExposureSet(scope, self._exposureGlobalNames, self.exposed) - - def validate(self): - if self.isAttr() or self.isMethod(): diff --git a/components/script/dom/bindings/codegen/parser/inline.patch b/components/script/dom/bindings/codegen/parser/inline.patch index 8337effd0f1..46971ce5067 100644 --- a/components/script/dom/bindings/codegen/parser/inline.patch +++ b/components/script/dom/bindings/codegen/parser/inline.patch @@ -1,6 +1,6 @@ --- WebIDL.py +++ WebIDL.py -@@ -1769,7 +1769,8 @@ class IDLInterface(IDLInterfaceOrNamespace): +@@ -1884,7 +1884,8 @@ class IDLInterface(IDLInterfaceOrNamespace): identifier == "RunConstructorInCallerCompartment" or identifier == "WantsEventListenerHooks" or identifier == "Serializable" or 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 066300e8bb4..8420f2ee4e0 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,8 +44,8 @@ def WebIDLTest(parser, harness): }; """) results = parser.finish() - except Exception as exception: - pass + except Exception as e: + exception = e harness.ok(exception, "Should have thrown.") harness.check(exception.message, @@ -70,8 +70,8 @@ def WebIDLTest(parser, harness): }; """) results = parser.finish() - except Exception as exception: - pass + except Exception as e: + exception = e harness.ok(exception, "Should have thrown (2).") harness.check(exception.message, @@ -100,8 +100,8 @@ def WebIDLTest(parser, harness): }; """) results = parser.finish() - except Exception as exception: - pass + except Exception as e: + exception = e harness.ok(exception, "Should have thrown (3).") harness.check(exception.message, diff --git a/components/script/dom/bindings/codegen/parser/tests/test_interfacemixin.py b/components/script/dom/bindings/codegen/parser/tests/test_interfacemixin.py new file mode 100644 index 00000000000..ae3400d2cdb --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_interfacemixin.py @@ -0,0 +1,373 @@ +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse("interface mixin Foo { };") + results = parser.finish() + harness.ok(True, "Empty interface mixin parsed without error.") + harness.check(len(results), 1, "Should be one production") + harness.ok(isinstance(results[0], WebIDL.IDLInterfaceMixin), + "Should be an IDLInterfaceMixin") + mixin = results[0] + harness.check(mixin.identifier.QName(), "::Foo", "Interface mixin has the right QName") + harness.check(mixin.identifier.name, "Foo", "Interface mixin has the right name") + + parser = parser.reset() + parser.parse(""" + interface mixin QNameBase { + const long foo = 3; + }; + """) + results = parser.finish() + harness.check(len(results), 1, "Should be one productions") + harness.ok(isinstance(results[0], WebIDL.IDLInterfaceMixin), + "Should be an IDLInterfaceMixin") + harness.check(len(results[0].members), 1, "Expect 1 productions") + mixin = results[0] + harness.check(mixin.members[0].identifier.QName(), "::QNameBase::foo", + "Member has the right QName") + + parser = parser.reset() + parser.parse(""" + interface mixin A { + readonly attribute boolean x; + void foo(); + }; + partial interface mixin A { + readonly attribute boolean y; + void foo(long arg); + }; + """) + results = parser.finish() + harness.check(len(results), 2, + "Should have two results with partial interface mixin") + mixin = results[0] + harness.check(len(mixin.members), 3, + "Should have three members with partial interface mixin") + harness.check(mixin.members[0].identifier.name, "x", + "First member should be x with partial interface mixin") + harness.check(mixin.members[1].identifier.name, "foo", + "Second member should be foo with partial interface mixin") + harness.check(len(mixin.members[1].signatures()), 2, + "Should have two foo signatures with partial interface mixin") + harness.check(mixin.members[2].identifier.name, "y", + "Third member should be y with partial interface mixin") + + parser = parser.reset() + parser.parse(""" + partial interface mixin A { + readonly attribute boolean y; + void foo(long arg); + }; + interface mixin A { + readonly attribute boolean x; + void foo(); + }; + """) + results = parser.finish() + harness.check(len(results), 2, + "Should have two results with reversed partial interface mixin") + mixin = results[1] + harness.check(len(mixin.members), 3, + "Should have three members with reversed partial interface mixin") + harness.check(mixin.members[0].identifier.name, "x", + "First member should be x with reversed partial interface mixin") + harness.check(mixin.members[1].identifier.name, "foo", + "Second member should be foo with reversed partial interface mixin") + harness.check(len(mixin.members[1].signatures()), 2, + "Should have two foo signatures with reversed partial interface mixin") + harness.check(mixin.members[2].identifier.name, "y", + "Third member should be y with reversed partial interface mixin") + + parser = parser.reset() + parser.parse(""" + interface Interface {}; + interface mixin Mixin { + attribute short x; + }; + Interface includes Mixin; + """) + results = parser.finish() + iface = results[0] + harness.check(len(iface.members), 1, "Should merge members from mixins") + harness.check(iface.members[0].identifier.name, "x", + "Should merge members from mixins") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface mixin A { + readonly attribute boolean x; + }; + interface mixin A { + readonly attribute boolean y; + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should not allow two non-partial interface mixins with the same name") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + partial interface mixin A { + readonly attribute boolean x; + }; + partial interface mixin A { + readonly attribute boolean y; + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Must have a non-partial interface mixin for a given name") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary A { + boolean x; + }; + partial interface mixin A { + readonly attribute boolean y; + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should not allow a name collision between partial interface " + "mixin and other object") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary A { + boolean x; + }; + interface mixin A { + readonly attribute boolean y; + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should not allow a name collision between interface mixin " + "and other object") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface mixin A { + readonly attribute boolean x; + }; + interface A; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should not allow a name collision between external interface " + "and interface mixin") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [SomeRandomAnnotation] + interface mixin A { + readonly attribute boolean y; + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should not allow unknown extended attributes on interface mixins") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface mixin A { + getter double (DOMString propertyName); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should not allow getters on interface mixins") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface mixin A { + setter void (DOMString propertyName, double propertyValue); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should not allow setters on interface mixins") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface mixin A { + deleter void (DOMString propertyName); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should not allow deleters on interface mixins") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface mixin A { + legacycaller double compute(double x); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should not allow legacycallers on interface mixins") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface mixin A { + inherit attribute x; + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should not allow inherited attribute on interface mixins") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Interface {}; + interface NotMixin { + attribute short x; + }; + Interface includes NotMixin; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should fail if the right side does not point an interface mixin") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface mixin NotInterface {}; + interface mixin Mixin { + attribute short x; + }; + NotInterface includes Mixin; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should fail if the left side does not point an interface") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface mixin Mixin { + iterable; + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should fail if an interface mixin includes iterable") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface mixin Mixin { + setlike; + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should fail if an interface mixin includes setlike") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface mixin Mixin { + maplike; + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should fail if an interface mixin includes maplike") + + parser = parser.reset() + parser.parse(""" + [Global] interface Window {}; + [Global] interface Worker {}; + [Exposed=Window] + interface Base {}; + interface mixin Mixin { + Base returnSelf(); + }; + Base includes Mixin; + """) + results = parser.finish() + base = results[2] + attr = base.members[0] + harness.check(attr.exposureSet, set(["Window"]), + "Should expose on globals where the base interfaces are exposed") + + parser = parser.reset() + parser.parse(""" + [Global] interface Window {}; + [Global] interface Worker {}; + [Exposed=Window] + interface Base {}; + [Exposed=Window] + interface mixin Mixin { + attribute short a; + }; + Base includes Mixin; + """) + results = parser.finish() + base = results[2] + attr = base.members[0] + harness.check(attr.exposureSet, set(["Window"]), + "Should follow [Exposed] on interface mixin") diff --git a/components/script/dom/bindings/codegen/parser/union-typedef.patch b/components/script/dom/bindings/codegen/parser/union-typedef.patch index ec045300b6d..20efea8e129 100644 --- a/components/script/dom/bindings/codegen/parser/union-typedef.patch +++ b/components/script/dom/bindings/codegen/parser/union-typedef.patch @@ -1,8 +1,8 @@ --- WebIDL.py +++ WebIDL.py -@@ -2613,10 +2613,18 @@ class IDLUnionType(IDLType): +@@ -2624,10 +2624,18 @@ class IDLUnionType(IDLType): return type.name - + for (i, type) in enumerate(self.memberTypes): - if not type.isComplete(): + # Exclude typedefs because if given "typedef (B or C) test", diff --git a/components/script/dom/bindings/codegen/parser/update.sh b/components/script/dom/bindings/codegen/parser/update.sh index 570b8b4506d..fee9720ab2d 100755 --- a/components/script/dom/bindings/codegen/parser/update.sh +++ b/components/script/dom/bindings/codegen/parser/update.sh @@ -4,7 +4,6 @@ patch < debug.patch patch < callback-location.patch patch < union-typedef.patch patch < inline.patch -patch < exposed-globals.patch wget https://hg.mozilla.org/mozilla-central/archive/tip.tar.gz/dom/bindings/parser/tests/ -O tests.tar.gz rm -r tests -- cgit v1.2.3 From 98e4a53b7241d562d127e0f7005ffb38f21d1380 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 16 Aug 2019 13:53:01 +0200 Subject: Upgrade to rustc 1.39.0-nightly (f7af19c27 2019-08-15) --- components/script/dom/bindings/codegen/CodegenRust.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 93856508e6e..4a8cc573416 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -6384,7 +6384,7 @@ class CGDictionary(CGThing): d = self.dictionary if d.parent: initParent = ("{\n" - " match r#try!(%s::%s::new(cx, val)) {\n" + " match %s::%s::new(cx, val)? {\n" " ConversionResult::Success(v) => v,\n" " ConversionResult::Failure(error) => {\n" " throw_type_error(*cx, &error);\n" @@ -6532,7 +6532,7 @@ class CGDictionary(CGThing): conversion = ( "{\n" " rooted!(in(*cx) let mut rval = UndefinedValue());\n" - " if r#try!(get_dictionary_property(*cx, object.handle(), \"%s\", rval.handle_mut()))" + " if get_dictionary_property(*cx, object.handle(), \"%s\", rval.handle_mut())?" " && !rval.is_undefined() {\n" "%s\n" " } else {\n" @@ -7304,7 +7304,7 @@ class CallbackOperationBase(CallbackMethod): "methodName": self.methodName } getCallableFromProp = string.Template( - 'r#try!(self.parent.get_callable_property(cx, "${methodName}"))' + 'self.parent.get_callable_property(cx, "${methodName}")?' ).substitute(replacements) if not self.singleOperation: return 'rooted!(in(*cx) let callable =\n' + getCallableFromProp + ');\n' -- cgit v1.2.3 From 5695ee94a570a41d34a69b396db042922f63f516 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Thu, 29 Aug 2019 21:33:03 +0900 Subject: Add [Default] toJSON() to performance interfaces --- components/script/dom/bindings/codegen/CodegenRust.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 4a8cc573416..d5b70f6c3d7 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2049,9 +2049,10 @@ class CGImports(CGWrapper): if name != 'GlobalScope': extras += [descriptor.path] parentName = descriptor.getParentName() - if parentName: + while parentName: descriptor = descriptorProvider.getDescriptor(parentName) extras += [descriptor.path, descriptor.bindingPath] + parentName = descriptor.getParentName() elif t.isType() and t.isRecord(): extras += ['crate::dom::bindings::mozmap::MozMap'] elif isinstance(t, IDLPromiseType): @@ -3662,6 +3663,7 @@ class CGDefaultToJSONMethod(CGSpecializedMethod): def definition_body(self): ret = dedent(""" + use crate::dom::bindings::inheritance::HasParent; rooted!(in(*cx) let result = JS_NewPlainObject(*cx)); if result.is_null() { return false; @@ -3676,16 +3678,19 @@ class CGDefaultToJSONMethod(CGSpecializedMethod): jsonDescriptors.append(descriptor) interface = interface.parent + parents = len(jsonDescriptors) - 1 form = """ - if !${parentclass}CollectJSONAttributes(cx, _obj, this, &result) { + if !${parentclass}CollectJSONAttributes(cx, _obj, this${asparent}, &result) { return false; } """ # Iterate the array in reverse: oldest ancestor first for descriptor in jsonDescriptors[:0:-1]: - ret += fill(form, parentclass=toBindingNamespace(descriptor.name) + "::") - ret += fill(form, parentclass="") + ret += fill(form, parentclass=toBindingNamespace(descriptor.name) + "::", + asparent=".as_ref().unwrap()" + ".as_parent()" * parents) + parents -= 1 + ret += fill(form, parentclass="", asparent="") ret += ('(*args).rval().set(ObjectValue(*result));\n' 'return true;\n') return CGGeneric(ret) -- cgit v1.2.3 From 5149aefd856042c70ca5034adad0bcf7def67e37 Mon Sep 17 00:00:00 2001 From: Gregory Terzian Date: Thu, 5 Sep 2019 00:18:58 +0800 Subject: codegen: throw type error when encountering an unknown argument --- components/script/dom/bindings/codegen/CodegenRust.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 4a8cc573416..46b48885c4b 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -492,7 +492,7 @@ class CGMethodCall(CGThing): else: # Just throw; we have no idea what we're supposed to # do with this. - caseBody.append(CGGeneric("throw_internal_error(*cx, \"Could not convert JavaScript argument\");\n" + caseBody.append(CGGeneric("throw_type_error(*cx, \"Could not convert JavaScript argument\");\n" "return false;")) argCountCases.append(CGCase(str(argCount), -- cgit v1.2.3 From 5c60023cb8ad6f07927bd53f30c90873d07b300f Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 27 Sep 2019 06:37:54 +0200 Subject: WebIDL codegen: Replace cmake with a single Python script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When playing around with Cargo’s new timing visualization: https://internals.rust-lang.org/t/exploring-crate-graph-build-times-with-cargo-build-ztimings/10975/21 … I was surprised to see the `script` crate’s build script take 76 seconds. I did not expect WebIDL bindings generation to be *that* computationally intensive. It turns out almost all of this time is overhead. The build script uses CMake to generate bindings for each WebIDL file in parallel, but that causes a lot of work to be repeated 366 times: * Starting up a Python VM * Importing (parts of) the Python standard library * Importing ~16k lines of our Python code * Recompiling the latter to bytecode, since we used `python -B` to disable writing `.pyc` file * Deserializing with `cPickle` and recreating in memory the results of parsing all WebIDL files ---- This commit remove the use of CMake and cPickle for the `script` crate. Instead, all WebIDL bindings generation is done sequentially in a single Python process. This takes 2 to 3 seconds. --- .../script/dom/bindings/codegen/BindingGen.py | 54 -------- .../script/dom/bindings/codegen/CodegenRust.py | 26 ---- .../script/dom/bindings/codegen/GlobalGen.py | 143 --------------------- .../script/dom/bindings/codegen/pythonpath.py | 61 --------- components/script/dom/bindings/codegen/run.py | 119 +++++++++++++++++ 5 files changed, 119 insertions(+), 284 deletions(-) delete mode 100644 components/script/dom/bindings/codegen/BindingGen.py delete mode 100644 components/script/dom/bindings/codegen/GlobalGen.py delete mode 100644 components/script/dom/bindings/codegen/pythonpath.py create mode 100644 components/script/dom/bindings/codegen/run.py (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/BindingGen.py b/components/script/dom/bindings/codegen/BindingGen.py deleted file mode 100644 index 63cc68e46e5..00000000000 --- a/components/script/dom/bindings/codegen/BindingGen.py +++ /dev/null @@ -1,54 +0,0 @@ -# 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/. - -import sys -import os -sys.path.append(os.path.join(".", "parser")) -sys.path.append(os.path.join(".", "ply")) -import cPickle -from Configuration import Configuration -from CodegenRust import CGBindingRoot, replaceFileIfChanged - - -def generate_binding_rs(config, outputprefix, webidlfile): - """ - |config| Is the configuration object. - |outputprefix| is a prefix to use for the header guards and filename. - """ - - filename = outputprefix + ".rs" - module = CGBindingRoot(config, outputprefix, webidlfile).define() - if not module: - print "Skipping empty module: %s" % (filename) - elif replaceFileIfChanged(filename, module): - print "Generating binding implementation: %s" % (filename) - - -def main(): - # Parse arguments. - from optparse import OptionParser - usagestring = "usage: %prog configFile outputdir outputPrefix webIDLFile" - o = OptionParser(usage=usagestring) - (options, args) = o.parse_args() - - if len(args) != 4: - o.error(usagestring) - configFile = os.path.normpath(args[0]) - outputdir = args[1] - outputPrefix = args[2] - webIDLFile = os.path.normpath(args[3]) - - # Load the parsing results - resultsPath = os.path.join(outputdir, 'ParserResults.pkl') - with open(resultsPath, 'rb') as f: - parserData = cPickle.load(f) - - # Create the configuration data. - config = Configuration(configFile, parserData) - - # Generate the prototype classes. - generate_binding_rs(config, outputPrefix, webIDLFile) - -if __name__ == '__main__': - main() diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 3cd4078814b..c02499f222f 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -54,32 +54,6 @@ RUST_KEYWORDS = {"abstract", "alignof", "as", "become", "box", "break", "const", "use", "virtual", "where", "while", "yield"} -def replaceFileIfChanged(filename, newContents): - """ - Read a copy of the old file, so that we don't touch it if it hasn't changed. - Returns True if the file was updated, false otherwise. - """ - # XXXjdm This doesn't play well with make right now. - # Force the file to always be updated, or else changing CodegenRust.py - # will cause many autogenerated bindings to be regenerated perpetually - # until the result is actually different. - - # oldFileContents = "" - # try: - # with open(filename, 'rb') as oldFile: - # oldFileContents = ''.join(oldFile.readlines()) - # except: - # pass - - # if newContents == oldFileContents: - # return False - - with open(filename, 'wb') as f: - f.write(newContents) - - return True - - def toStringBool(arg): return str(not not arg).lower() diff --git a/components/script/dom/bindings/codegen/GlobalGen.py b/components/script/dom/bindings/codegen/GlobalGen.py deleted file mode 100644 index 1850a41d5f3..00000000000 --- a/components/script/dom/bindings/codegen/GlobalGen.py +++ /dev/null @@ -1,143 +0,0 @@ -# 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/. - -# We do one global pass over all the WebIDL to generate our prototype enum -# and generate information for subsequent phases. - -import sys -import os -import json -sys.path.append(os.path.join(".", "parser")) -sys.path.append(os.path.join(".", "ply")) -import WebIDL -import cPickle -from Configuration import Configuration -from CodegenRust import GlobalGenRoots, replaceFileIfChanged - - -def generate_file(config, name, filename): - root = getattr(GlobalGenRoots, name)(config) - code = root.define() - - if replaceFileIfChanged(filename, code): - print "Generating %s" % (filename) - else: - print "%s hasn't changed - not touching it" % (filename) - - -def main(): - # Parse arguments. - from optparse import OptionParser - usageString = "usage: %prog [options] configFile outputdir webidldir cssProperties.json docServoDir [files]" - o = OptionParser(usage=usageString) - o.add_option("--cachedir", dest='cachedir', default=None, - help="Directory in which to cache lex/parse tables.") - o.add_option("--filelist", dest='filelist', default=None, - help="A file containing the list (one per line) of webidl files to process.") - (options, args) = o.parse_args() - - if len(args) < 2: - o.error(usageString) - - configFile = args[0] - outputdir = args[1] - baseDir = args[2] - css_properties_json = args[3] - doc_servo = args[4] - if options.filelist is not None: - fileList = [l.strip() for l in open(options.filelist).xreadlines()] - else: - fileList = args[3:] - - # Parse the WebIDL. - parser = WebIDL.Parser(options.cachedir) - for filename in fileList: - fullPath = os.path.normpath(os.path.join(baseDir, filename)) - with open(fullPath, 'rb') as f: - lines = f.readlines() - parser.parse(''.join(lines), fullPath) - - add_css_properties_attributes(fileList, css_properties_json, parser) - - parserResults = parser.finish() - - # Write the parser results out to a pickle. - resultsPath = os.path.join(outputdir, 'ParserResults.pkl') - with open(resultsPath, 'wb') as resultsFile: - cPickle.dump(parserResults, resultsFile, -1) - - # Load the configuration. - config = Configuration(configFile, parserResults) - - to_generate = [ - ('PrototypeList', 'PrototypeList.rs'), - ('RegisterBindings', 'RegisterBindings.rs'), - ('InterfaceObjectMap', 'InterfaceObjectMap.rs'), - ('InterfaceObjectMapData', 'InterfaceObjectMapData.json'), - ('InterfaceTypes', 'InterfaceTypes.rs'), - ('InheritTypes', 'InheritTypes.rs'), - ('Bindings', os.path.join('Bindings', 'mod.rs')), - ('UnionTypes', 'UnionTypes.rs'), - ] - - for name, filename in to_generate: - generate_file(config, name, os.path.join(outputdir, filename)) - - generate_file(config, 'SupportedDomApis', os.path.join(doc_servo, 'apis.html')) - - -def add_css_properties_attributes(webidl_files, css_properties_json, parser): - for filename in webidl_files: - if os.path.basename(filename) == "CSSStyleDeclaration.webidl": - break - else: - return - - css_properties = json.load(open(css_properties_json, "rb")) - idl = "partial interface CSSStyleDeclaration {\n%s\n};\n" % "\n".join( - " [%sCEReactions, SetterThrows] attribute [TreatNullAs=EmptyString] DOMString %s;" % ( - ('Pref="%s", ' % data["pref"] if data["pref"] else ""), - attribute_name - ) - for (kind, properties_list) in sorted(css_properties.items()) - for (property_name, data) in sorted(properties_list.items()) - for attribute_name in attribute_names(property_name) - ) - parser.parse(idl.encode("utf-8"), "CSSStyleDeclaration_generated.webidl") - - -def attribute_names(property_name): - # https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-dashed-attribute - if property_name != "float": - yield property_name - else: - yield "_float" - - # https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-camel-cased-attribute - if "-" in property_name: - yield "".join(camel_case(property_name)) - - # https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-webkit-cased-attribute - if property_name.startswith("-webkit-"): - yield "".join(camel_case(property_name), True) - - -# https://drafts.csswg.org/cssom/#css-property-to-idl-attribute -def camel_case(chars, webkit_prefixed=False): - if webkit_prefixed: - chars = chars[1:] - next_is_uppercase = False - for c in chars: - if c == '-': - next_is_uppercase = True - elif next_is_uppercase: - next_is_uppercase = False - # Should be ASCII-uppercase, but all non-custom CSS property names are within ASCII - yield c.upper() - else: - yield c - - -if __name__ == '__main__': - main() diff --git a/components/script/dom/bindings/codegen/pythonpath.py b/components/script/dom/bindings/codegen/pythonpath.py deleted file mode 100644 index 67739c3625f..00000000000 --- a/components/script/dom/bindings/codegen/pythonpath.py +++ /dev/null @@ -1,61 +0,0 @@ -# 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/. - -""" -Run a python script, adding extra directories to the python path. -""" - - -def main(args): - def usage(): - print >>sys.stderr, "pythonpath.py -I directory script.py [args...]" - sys.exit(150) - - paths = [] - - while True: - try: - arg = args[0] - except IndexError: - usage() - - if arg == '-I': - args.pop(0) - try: - path = args.pop(0) - except IndexError: - usage() - - paths.append(os.path.abspath(path)) - continue - - if arg.startswith('-I'): - paths.append(os.path.abspath(args.pop(0)[2:])) - continue - - if arg.startswith('-D'): - os.chdir(args.pop(0)[2:]) - continue - - break - - script = args[0] - - sys.path[0:0] = [os.path.abspath(os.path.dirname(script))] + paths - sys.argv = args - sys.argc = len(args) - - frozenglobals['__name__'] = '__main__' - frozenglobals['__file__'] = script - - execfile(script, frozenglobals) - -# Freeze scope here ... why this makes things work I have no idea ... -frozenglobals = globals() - -import sys -import os - -if __name__ == '__main__': - main(sys.argv[1:]) diff --git a/components/script/dom/bindings/codegen/run.py b/components/script/dom/bindings/codegen/run.py new file mode 100644 index 00000000000..fd43ac32bb7 --- /dev/null +++ b/components/script/dom/bindings/codegen/run.py @@ -0,0 +1,119 @@ +# 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/. + +import os +import sys +import json + + +def main(): + os.chdir(os.path.join(os.path.dirname(__file__))) + sys.path[0:0] = ["./parser", "./ply"] + + css_properties_json, out_dir, doc_servo = sys.argv[1:] + webidls_dir = "../../webidls" + config_file = "Bindings.conf" + + import WebIDL + from Configuration import Configuration + from CodegenRust import CGBindingRoot + + parser = WebIDL.Parser(make_dir(out_dir, "cache")) + webidls = [name for name in os.listdir(webidls_dir) if name.endswith(".webidl")] + for webidl in webidls: + filename = os.path.join(webidls_dir, webidl) + with open(filename, "rb") as f: + parser.parse(f.read(), filename) + + add_css_properties_attributes(css_properties_json, parser) + parser_results = parser.finish() + config = Configuration(config_file, parser_results) + make_dir(out_dir, "Bindings") + + for name, filename in [ + ("PrototypeList", "PrototypeList.rs"), + ("RegisterBindings", "RegisterBindings.rs"), + ("InterfaceObjectMap", "InterfaceObjectMap.rs"), + ("InterfaceObjectMapData", "InterfaceObjectMapData.json"), + ("InterfaceTypes", "InterfaceTypes.rs"), + ("InheritTypes", "InheritTypes.rs"), + ("Bindings", "Bindings/mod.rs"), + ("UnionTypes", "UnionTypes.rs"), + ]: + generate(config, name, os.path.join(out_dir, filename)) + make_dir(doc_servo) + generate(config, "SupportedDomApis", os.path.join(doc_servo, "apis.html")) + + for webidl in webidls: + filename = os.path.join(webidls_dir, webidl) + prefix = "Bindings/%sBinding" % webidl[:-len(".webidl")] + module = CGBindingRoot(config, prefix, filename).define() + if module: + with open(os.path.join(out_dir, prefix + ".rs"), "wb") as f: + f.write(module) + + +def make_dir(out_dir, nested=""): + path = os.path.join(out_dir, nested) + if not os.path.exists(path): + os.makedirs(path) + return path + + +def generate(config, name, filename): + from CodegenRust import GlobalGenRoots + root = getattr(GlobalGenRoots, name)(config) + code = root.define() + with open(filename, "wb") as f: + f.write(code) + + +def add_css_properties_attributes(css_properties_json, parser): + css_properties = json.load(open(css_properties_json, "rb")) + idl = "partial interface CSSStyleDeclaration {\n%s\n};\n" % "\n".join( + " [%sCEReactions, SetterThrows] attribute [TreatNullAs=EmptyString] DOMString %s;" % ( + ('Pref="%s", ' % data["pref"] if data["pref"] else ""), + attribute_name + ) + for (kind, properties_list) in sorted(css_properties.items()) + for (property_name, data) in sorted(properties_list.items()) + for attribute_name in attribute_names(property_name) + ) + parser.parse(idl.encode("utf-8"), "CSSStyleDeclaration_generated.webidl") + + +def attribute_names(property_name): + # https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-dashed-attribute + if property_name != "float": + yield property_name + else: + yield "_float" + + # https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-camel-cased-attribute + if "-" in property_name: + yield "".join(camel_case(property_name)) + + # https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-webkit-cased-attribute + if property_name.startswith("-webkit-"): + yield "".join(camel_case(property_name), True) + + +# https://drafts.csswg.org/cssom/#css-property-to-idl-attribute +def camel_case(chars, webkit_prefixed=False): + if webkit_prefixed: + chars = chars[1:] + next_is_uppercase = False + for c in chars: + if c == '-': + next_is_uppercase = True + elif next_is_uppercase: + next_is_uppercase = False + # Should be ASCII-uppercase, but all non-custom CSS property names are within ASCII + yield c.upper() + else: + yield c + + +if __name__ == "__main__": + main() -- cgit v1.2.3 From d2c299a6c79386fe91f3930914d1d3e7162112a3 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 30 Sep 2019 11:20:41 +0200 Subject: =?UTF-8?q?Don=E2=80=99t=20rely=20on=20`$CARGO=5FTARGET=5FDIR`=20i?= =?UTF-8?q?n=20build=20scripts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/script/dom/bindings/codegen/run.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/run.py b/components/script/dom/bindings/codegen/run.py index fd43ac32bb7..130d35e5268 100644 --- a/components/script/dom/bindings/codegen/run.py +++ b/components/script/dom/bindings/codegen/run.py @@ -11,7 +11,8 @@ def main(): os.chdir(os.path.join(os.path.dirname(__file__))) sys.path[0:0] = ["./parser", "./ply"] - css_properties_json, out_dir, doc_servo = sys.argv[1:] + css_properties_json, out_dir = sys.argv[1:] + doc_servo = "../../../../../target/doc/servo" webidls_dir = "../../webidls" config_file = "Bindings.conf" @@ -19,7 +20,7 @@ def main(): from Configuration import Configuration from CodegenRust import CGBindingRoot - parser = WebIDL.Parser(make_dir(out_dir, "cache")) + parser = WebIDL.Parser(make_dir(os.path.join(out_dir, "cache"))) webidls = [name for name in os.listdir(webidls_dir) if name.endswith(".webidl")] for webidl in webidls: filename = os.path.join(webidls_dir, webidl) @@ -29,7 +30,7 @@ def main(): add_css_properties_attributes(css_properties_json, parser) parser_results = parser.finish() config = Configuration(config_file, parser_results) - make_dir(out_dir, "Bindings") + make_dir(os.path.join(out_dir, "Bindings")) for name, filename in [ ("PrototypeList", "PrototypeList.rs"), @@ -54,8 +55,7 @@ def main(): f.write(module) -def make_dir(out_dir, nested=""): - path = os.path.join(out_dir, nested) +def make_dir(path): if not os.path.exists(path): os.makedirs(path) return path -- cgit v1.2.3 From 9ce82ea1aedfd3eddad0eed9fac6718599a25ec3 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Wed, 2 Oct 2019 21:45:01 +0900 Subject: Migrate to new constructor operation syntax --- .../script/dom/bindings/codegen/parser/WebIDL.py | 310 +++++++++++++-------- .../codegen/parser/tests/test_argument_keywords.py | 17 ++ .../parser/tests/test_attributes_on_types.py | 12 + .../codegen/parser/tests/test_constructor.py | 207 ++++++++++---- .../parser/tests/test_constructor_global.py | 18 +- .../tests/test_constructor_no_interface_object.py | 18 +- .../codegen/parser/tests/test_dictionary.py | 74 ++++- .../parser/tests/test_distinguishability.py | 8 +- .../codegen/parser/tests/test_interface.py | 8 +- .../tests/test_interface_maplikesetlikeiterable.py | 16 +- .../script/dom/bindings/codegen/parser/update.sh | 4 +- 11 files changed, 457 insertions(+), 235 deletions(-) create mode 100644 components/script/dom/bindings/codegen/parser/tests/test_argument_keywords.py (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index b934c21db5b..5e8b958e3de 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.py @@ -554,9 +554,6 @@ class IDLExternalInterface(IDLObjectWithIdentifier, IDLExposureMixins): def hasProbablyShortLivingWrapper(self): return False - def isNavigatorProperty(self): - return False - def isSerializable(self): return False @@ -611,7 +608,7 @@ class IDLPartialInterfaceOrNamespace(IDLObject): for attr in attrs: identifier = attr.identifier() - if identifier in ["Constructor", "NamedConstructor"]: + if identifier == "NamedConstructor": self.propagatedExtendedAttrs.append(attr) elif identifier == "SecureContext": self._haveSecureContextExtendedAttribute = True @@ -737,7 +734,7 @@ class IDLInterfaceOrInterfaceMixinOrNamespace(IDLObjectWithScope, IDLExposureMix self.location = location # Put the new members at the beginning self.members = members + self.members - + def addPartial(self, partial): assert self.identifier.name == partial.identifier.name self._partials.append(partial) @@ -790,7 +787,7 @@ class IDLInterfaceMixin(IDLInterfaceOrInterfaceMixinOrNamespace): def __str__(self): return "Interface mixin '%s'" % self.identifier.name - + def finish(self, scope): if self._finished: return @@ -969,7 +966,11 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): (self.identifier.name, self.parent.identifier.name), [self.location]) - assert not parent or isinstance(parent, IDLInterface) + if parent and not isinstance(parent, IDLInterface): + raise WebIDLError("%s inherits from %s which is not an interface " % + (self.identifier.name, + self.parent.identifier.name), + [self.location, parent.location]) self.parent = parent @@ -1076,11 +1077,34 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): ctor = self.ctor() if ctor is not None: - assert len(ctor._exposureGlobalNames) == 0 + if not self.hasInterfaceObject(): + raise WebIDLError( + "Can't have both a constructor and [NoInterfaceObject]", + [self.location, ctor.location]) + + if self.globalNames: + raise WebIDLError( + "Can't have both a constructor and [Global]", + [self.location, ctor.location]) + + assert(len(ctor._exposureGlobalNames) == 0 or + ctor._exposureGlobalNames == self._exposureGlobalNames) ctor._exposureGlobalNames.update(self._exposureGlobalNames) - ctor.finish(scope) + if ctor in self.members: + # constructor operation. + self.members.remove(ctor) + else: + # extended attribute. This can only happen with + # [HTMLConstructor] and this is the only way we can get into this + # code with len(ctor._exposureGlobalNames) != + # self._exposureGlobalNames. + ctor.finish(scope) for ctor in self.namedConstructors: + if self.globalNames: + raise WebIDLError( + "Can't have both a named constructor and [Global]", + [self.location, self.namedConstructors.location]) assert len(ctor._exposureGlobalNames) == 0 ctor._exposureGlobalNames.update(self._exposureGlobalNames) ctor.finish(scope) @@ -1462,12 +1486,11 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): # Conditional exposure makes no sense for interfaces with no - # interface object, unless they're navigator properties. + # interface object. # And SecureContext makes sense for interfaces with no interface object, # since it is also propagated to interface members. if (self.isExposedConditionally(exclusions=["SecureContext"]) and - not self.hasInterfaceObject() and - not self.isNavigatorProperty()): + not self.hasInterfaceObject()): raise WebIDLError("Interface with no interface object is " "exposed conditionally", [self.location]) @@ -1640,39 +1663,6 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): current = current.parent return False - def isNavigatorProperty(self): - naviProp = self.getExtendedAttribute("NavigatorProperty") - if not naviProp: - return False - assert len(naviProp) == 1 - assert isinstance(naviProp, list) - assert len(naviProp[0]) != 0 - return True - - def getNavigatorProperty(self): - naviProp = self.getExtendedAttribute("NavigatorProperty") - if not naviProp: - return None - assert len(naviProp) == 1 - assert isinstance(naviProp, list) - assert len(naviProp[0]) != 0 - conditionExtendedAttributes = self._extendedAttrDict.viewkeys() & IDLInterfaceOrNamespace.conditionExtendedAttributes - attr = IDLAttribute(self.location, - IDLUnresolvedIdentifier(BuiltinLocation(""), naviProp[0]), - IDLUnresolvedType(self.location, IDLUnresolvedIdentifier(self.location, self.identifier.name)), - True, - extendedAttrDict={ a: self._extendedAttrDict[a] for a in conditionExtendedAttributes }, - navigatorObjectGetter=True) - attr._exposureGlobalNames = self._exposureGlobalNames - # We're abusing Constant a little bit here, because we need Cached. The - # getter will create a new object every time, but we're never going to - # clear the cached value. - extendedAttrs = [ IDLExtendedAttribute(self.location, ("Throws", )), - IDLExtendedAttribute(self.location, ("Cached", )), - IDLExtendedAttribute(self.location, ("Constant", )) ] - attr.addExtendedAttributes(extendedAttrs) - return attr - def hasChildInterfaces(self): return self._hasChildInterfaces @@ -1731,67 +1721,39 @@ class IDLInterface(IDLInterfaceOrNamespace): raise WebIDLError("[NoInterfaceObject] must take no arguments", [attr.location]) - if self.ctor(): - raise WebIDLError("Constructor and NoInterfaceObject are incompatible", - [self.location]) - self._noInterfaceObject = True - elif identifier == "Constructor" or identifier == "NamedConstructor" or identifier == "ChromeConstructor" or identifier == "HTMLConstructor": - if identifier == "Constructor" and not self.hasInterfaceObject(): - raise WebIDLError(str(identifier) + " and NoInterfaceObject are incompatible", - [self.location]) - + elif identifier == "NamedConstructor" or identifier == "HTMLConstructor": if identifier == "NamedConstructor" and not attr.hasValue(): raise WebIDLError("NamedConstructor must either take an identifier or take a named argument list", [attr.location]) - if identifier == "ChromeConstructor" and not self.hasInterfaceObject(): - raise WebIDLError(str(identifier) + " and NoInterfaceObject are incompatible", - [self.location]) - if identifier == "HTMLConstructor": - if not self.hasInterfaceObject(): - raise WebIDLError(str(identifier) + " and NoInterfaceObject are incompatible", - [self.location]) - if not attr.noArguments(): 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) - if identifier == "Constructor" or identifier == "ChromeConstructor" or identifier == "HTMLConstructor": + if identifier == "HTMLConstructor": name = "constructor" allowForbidden = True else: name = attr.value() allowForbidden = False - methodIdentifier = IDLUnresolvedIdentifier(self.location, name, - allowForbidden=allowForbidden) + method = IDLConstructor( + attr.location, args, name, + htmlConstructor=(identifier == "HTMLConstructor")) + method.reallyInit(self) - method = IDLMethod(self.location, methodIdentifier, retType, - args, static=True, - htmlConstructor=(identifier == "HTMLConstructor")) - # Constructors are always NewObject and are always - # assumed to be able to throw (since there's no way to - # indicate otherwise) and never have any other - # extended attributes. + # Are always assumed to be able to throw (since there's no way to + # indicate otherwise). method.addExtendedAttributes( - [IDLExtendedAttribute(self.location, ("NewObject",)), - IDLExtendedAttribute(self.location, ("Throws",))]) - if identifier == "ChromeConstructor": - method.addExtendedAttributes( - [IDLExtendedAttribute(self.location, ("ChromeOnly",))]) + [IDLExtendedAttribute(self.location, ("Throws",))]) - if identifier == "Constructor" or identifier == "ChromeConstructor" or identifier == "HTMLConstructor": + if identifier == "HTMLConstructor": method.resolve(self) else: # We need to detect conflicts for NamedConstructors across @@ -1823,10 +1785,6 @@ 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(): @@ -1896,7 +1854,6 @@ class IDLInterface(IDLInterfaceOrNamespace): elif (identifier == "Pref" or identifier == "JSImplementation" or identifier == "HeaderFile" or - identifier == "NavigatorProperty" or identifier == "Func" or identifier == "Deprecated"): # Known extended attributes that take a string value @@ -1923,6 +1880,17 @@ class IDLInterface(IDLInterfaceOrNamespace): def isSerializable(self): return self.getExtendedAttribute("Serializable") + def setNonPartial(self, location, parent, members): + # Before we do anything else, finish initializing any constructors that + # might be in "members", so we don't have partially-initialized objects + # hanging around. We couldn't do it before now because we needed to have + # to have the IDLInterface on hand to properly set the return type. + for member in members: + if isinstance(member, IDLConstructor): + member.reallyInit(self) + + IDLInterfaceOrNamespace.setNonPartial(self, location, parent, members) + class IDLNamespace(IDLInterfaceOrNamespace): def __init__(self, location, parentScope, name, members, isKnownNonPartial): @@ -2193,6 +2161,7 @@ class IDLType(IDLObject): 'domstring', 'bytestring', 'usvstring', + 'jsstring', 'object', 'date', 'void', @@ -2254,6 +2223,9 @@ class IDLType(IDLObject): def isUSVString(self): return False + def isJSString(self): + return False + def isVoid(self): return self.name == "Void" @@ -2479,6 +2451,9 @@ class IDLNullableType(IDLParametrizedType): def isUSVString(self): return self.inner.isUSVString() + def isJSString(self): + return self.inner.isJSString() + def isFloat(self): return self.inner.isFloat() @@ -2600,6 +2575,9 @@ class IDLSequenceType(IDLParametrizedType): def isUSVString(self): return False + def isJSString(self): + return False + def isVoid(self): return False @@ -2861,6 +2839,9 @@ class IDLTypedefType(IDLType): def isUSVString(self): return self.inner.isUSVString() + def isJSString(self): + return self.inner.isJSString() + def isVoid(self): return self.inner.isVoid() @@ -2991,6 +2972,9 @@ class IDLWrapperType(IDLType): def isUSVString(self): return False + def isJSString(self): + return False + def isVoid(self): return False @@ -3190,6 +3174,7 @@ class IDLBuiltinType(IDLType): 'domstring', 'bytestring', 'usvstring', + 'jsstring', 'object', 'date', 'void', @@ -3227,6 +3212,7 @@ class IDLBuiltinType(IDLType): Types.domstring: IDLType.Tags.domstring, Types.bytestring: IDLType.Tags.bytestring, Types.usvstring: IDLType.Tags.usvstring, + Types.jsstring: IDLType.Tags.jsstring, Types.object: IDLType.Tags.object, Types.date: IDLType.Tags.date, Types.void: IDLType.Tags.void, @@ -3311,7 +3297,8 @@ class IDLBuiltinType(IDLType): def isString(self): return (self._typeTag == IDLBuiltinType.Types.domstring or self._typeTag == IDLBuiltinType.Types.bytestring or - self._typeTag == IDLBuiltinType.Types.usvstring) + self._typeTag == IDLBuiltinType.Types.usvstring or + self._typeTag == IDLBuiltinType.Types.jsstring) def isByteString(self): return self._typeTag == IDLBuiltinType.Types.bytestring @@ -3322,6 +3309,9 @@ class IDLBuiltinType(IDLType): def isUSVString(self): return self._typeTag == IDLBuiltinType.Types.usvstring + def isJSString(self): + return self._typeTag == IDLBuiltinType.Types.jsstring + def isInteger(self): return self._typeTag <= IDLBuiltinType.Types.unsigned_long_long @@ -3524,6 +3514,9 @@ BuiltinTypes = { IDLBuiltinType.Types.usvstring: IDLBuiltinType(BuiltinLocation(""), "USVString", IDLBuiltinType.Types.usvstring), + IDLBuiltinType.Types.jsstring: + IDLBuiltinType(BuiltinLocation(""), "JSString", + IDLBuiltinType.Types.jsstring), IDLBuiltinType.Types.object: IDLBuiltinType(BuiltinLocation(""), "Object", IDLBuiltinType.Types.object), @@ -3690,8 +3683,8 @@ class IDLValue(IDLObject): # TreatNullAsEmpty is a different type for resolution reasons, # however once you have a value it doesn't matter return self - elif self.type.isString() and type.isByteString(): - # Allow ByteStrings to use a default value like DOMString. + elif self.type.isString() and (type.isByteString() or type.isJSString()): + # Allow ByteStrings and JSStrings to use a default value like DOMString. # No coercion is required as Codegen.py will handle the # extra steps. We want to make sure that our string contains # only valid characters, so we check that here. @@ -4340,7 +4333,7 @@ class IDLConst(IDLInterfaceMember): class IDLAttribute(IDLInterfaceMember): def __init__(self, location, identifier, type, readonly, inherit=False, static=False, stringifier=False, maplikeOrSetlike=None, - extendedAttrDict=None, navigatorObjectGetter=False): + extendedAttrDict=None): IDLInterfaceMember.__init__(self, location, identifier, IDLInterfaceMember.Tags.Attr, extendedAttrDict=extendedAttrDict) @@ -4358,7 +4351,6 @@ class IDLAttribute(IDLInterfaceMember): self.maplikeOrSetlike = maplikeOrSetlike self.dependsOn = "Everything" self.affects = "Everything" - self.navigatorObjectGetter = navigatorObjectGetter self.bindingAliases = [] if static and identifier.name == "prototype": @@ -5239,7 +5231,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope): assert argument.type.isComplete() if ((argument.type.isDictionary() and - argument.type.inner.canBeEmpty())or + argument.type.unroll().inner.canBeEmpty()) or (argument.type.isUnion() and argument.type.unroll().hasPossiblyEmptyDictionaryType())): # Optional dictionaries and unions containing optional @@ -5263,12 +5255,16 @@ class IDLMethod(IDLInterfaceMember, IDLScope): "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 " - "dictionary or nullable union " - "containing a dictionary", - [argument.location]) + # An argument cannot be a nullable dictionary or a + # nullable union containing a dictionary. + if (argument.type.nullable() and + (argument.type.isDictionary() or + (argument.type.isUnion() and + argument.type.unroll().hasDictionaryType()))): + raise WebIDLError("An argument cannot be a nullable " + "dictionary or nullable union " + "containing a dictionary", + [argument.location]) # Only the last argument can be variadic if variadicArgument: @@ -5497,6 +5493,52 @@ class IDLMethod(IDLInterfaceMember, IDLScope): return deps +class IDLConstructor(IDLMethod): + def __init__(self, location, args, name, htmlConstructor=False): + # We can't actually init our IDLMethod yet, because we do not know the + # return type yet. Just save the info we have for now and we will init + # it later. + self._initLocation = location + self._initArgs = args + self._initName = name + self._htmlConstructor = htmlConstructor + self._inited = False + self._initExtendedAttrs = [] + + def addExtendedAttributes(self, attrs): + if self._inited: + return IDLMethod.addExtendedAttributes(self, attrs) + self._initExtendedAttrs.extend(attrs) + + def handleExtendedAttribute(self, attr): + identifier = attr.identifier() + if (identifier == "BinaryName" or + identifier == "ChromeOnly" or + identifier == "NewObject" or + identifier == "SecureContext" or + identifier == "Throws"): + IDLMethod.handleExtendedAttribute(self, attr) + else: + raise WebIDLError("Unknown extended attribute %s on method" % identifier, + [attr.location]) + + def reallyInit(self, parentInterface): + name = self._initName + location = self._initLocation + identifier = IDLUnresolvedIdentifier(location, name, allowForbidden=True) + retType = IDLWrapperType(parentInterface.location, parentInterface) + IDLMethod.__init__(self, location, identifier, retType, self._initArgs, + static=True, htmlConstructor=self._htmlConstructor) + self._inited = True; + # Propagate through whatever extended attributes we already had + self.addExtendedAttributes(self._initExtendedAttrs) + self._initExtendedAttrs = [] + # Constructors are always NewObject. Whether they throw or not is + # indicated by [Throws] annotations in the usual way. + self.addExtendedAttributes( + [IDLExtendedAttribute(self.location, ("NewObject",))]) + + class IDLImplementsStatement(IDLObject): def __init__(self, location, implementor, implementee): IDLObject.__init__(self, location) @@ -5712,6 +5754,7 @@ class Tokenizer(object): "DOMString": "DOMSTRING", "ByteString": "BYTESTRING", "USVString": "USVSTRING", + "JSString": "JSSTRING", "any": "ANY", "boolean": "BOOLEAN", "byte": "BYTE", @@ -6076,7 +6119,7 @@ class Parser(Tokenizer): def p_PartialInterfaceRest(self, p): """ - PartialInterfaceRest : IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON + PartialInterfaceRest : IDENTIFIER LBRACE PartialInterfaceMembers RBRACE SEMICOLON """ location = self.getLocation(p, 1) identifier = IDLUnresolvedIdentifier(location, p[1]) @@ -6157,12 +6200,42 @@ class Parser(Tokenizer): def p_InterfaceMember(self, p): """ - InterfaceMember : Const - | AttributeOrOperationOrMaplikeOrSetlikeOrIterable + InterfaceMember : PartialInterfaceMember + | Constructor """ p[0] = p[1] - + def p_Constructor(self, p): + """ + Constructor : CONSTRUCTOR LPAREN ArgumentList RPAREN SEMICOLON + """ + p[0] = IDLConstructor(self.getLocation(p, 1), p[3], "constructor") + + def p_PartialInterfaceMembers(self, p): + """ + PartialInterfaceMembers : ExtendedAttributeList PartialInterfaceMember PartialInterfaceMembers + """ + p[0] = [p[2]] + + assert not p[1] or p[2] + p[2].addExtendedAttributes(p[1]) + + p[0].extend(p[3]) + + def p_PartialInterfaceMembersEmpty(self, p): + """ + PartialInterfaceMembers : + """ + p[0] = [] + + def p_PartialInterfaceMember(self, p): + """ + PartialInterfaceMember : Const + | AttributeOrOperationOrMaplikeOrSetlikeOrIterable + """ + p[0] = p[1] + + def p_MixinMembersEmpty(self, p): """ MixinMembers : @@ -6778,7 +6851,9 @@ class Parser(Tokenizer): """ t = p[2] assert isinstance(t, IDLType) - identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3]) + # Arg names can be reserved identifiers + identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3], + allowForbidden=True) defaultValue = p[4] @@ -6795,7 +6870,9 @@ class Parser(Tokenizer): """ t = p[1] assert isinstance(t, IDLType) - identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3]) + # Arg names can be reserved identifiers + identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3], + allowForbidden=True) variadic = p[2] @@ -6934,6 +7011,7 @@ class Parser(Tokenizer): | DOMSTRING | BYTESTRING | USVSTRING + | JSSTRING | ANY | ATTRIBUTE | BOOLEAN @@ -7216,6 +7294,12 @@ class Parser(Tokenizer): """ p[0] = IDLBuiltinType.Types.usvstring + def p_BuiltinStringTypeJSString(self, p): + """ + BuiltinStringType : JSSTRING + """ + p[0] = IDLBuiltinType.Types.jsstring + def p_UnsignedIntegerTypeUnsigned(self, p): """ UnsignedIntegerType : UNSIGNED IntegerType @@ -7443,23 +7527,9 @@ class Parser(Tokenizer): for p in self._productions: if isinstance(p, IDLInterface): interfaceStatements.append(p) - if p.identifier.name == "Navigator": - navigatorInterface = p iterableIteratorIface = None for iface in interfaceStatements: - navigatorProperty = iface.getNavigatorProperty() - if navigatorProperty: - # We're generating a partial interface to add a readonly - # property to the Navigator interface for every interface - # annotated with NavigatorProperty. - partialInterface = IDLPartialInterfaceOrNamespace( - iface.location, - IDLUnresolvedIdentifier(iface.location, "Navigator"), - [ navigatorProperty ], - navigatorInterface) - self._productions.append(partialInterface) - 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 diff --git a/components/script/dom/bindings/codegen/parser/tests/test_argument_keywords.py b/components/script/dom/bindings/codegen/parser/tests/test_argument_keywords.py new file mode 100644 index 00000000000..e190f617e26 --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_argument_keywords.py @@ -0,0 +1,17 @@ +def WebIDLTest(parser, harness): + parser.parse(""" + interface Foo { + void foo(object constructor); + }; + """) + + results = parser.finish() + harness.check(len(results), 1, "Should have an interface"); + iface = results[0]; + harness.check(len(iface.members), 1, "Should have an operation"); + operation = iface.members[0]; + harness.check(len(operation.signatures()), 1, "Should have one signature"); + (retval, args) = operation.signatures()[0]; + harness.check(len(args), 1, "Should have an argument"); + harness.check(args[0].identifier.name, "constructor", + "Should have an identifier named 'constructor'"); diff --git a/components/script/dom/bindings/codegen/parser/tests/test_attributes_on_types.py b/components/script/dom/bindings/codegen/parser/tests/test_attributes_on_types.py index 1128d58317a..43daca3c453 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_attributes_on_types.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_attributes_on_types.py @@ -205,6 +205,18 @@ def WebIDLTest(parser, harness): harness.ok(threw, "Should not allow [TreatNullAs] on long") + parser = parser.reset() + threw = False + try: + parser.parse(""" + typedef [TreatNullAs=EmptyString] JSString Foo; + """) + parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow [TreatNullAs] on JSString") + parser = parser.reset() threw = False try: diff --git a/components/script/dom/bindings/codegen/parser/tests/test_constructor.py b/components/script/dom/bindings/codegen/parser/tests/test_constructor.py index c722d7bc5c7..20eb152cdab 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_constructor.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_constructor.py @@ -43,45 +43,55 @@ def WebIDLTest(parser, harness): (QName, name, type, optional, variadic) = expectedArgs[i] checkArgument(gotArgs[i], QName, name, type, optional, variadic) + def checkResults(results): + harness.check(len(results), 3, "Should be three productions") + harness.ok(isinstance(results[0], WebIDL.IDLInterface), + "Should be an IDLInterface") + harness.ok(isinstance(results[1], WebIDL.IDLInterface), + "Should be an IDLInterface") + harness.ok(isinstance(results[2], WebIDL.IDLInterface), + "Should be an IDLInterface") + + checkMethod(results[0].ctor(), "::TestConstructorNoArgs::constructor", + "constructor", [("TestConstructorNoArgs (Wrapper)", [])]) + harness.check(len(results[0].members), 0, + "TestConstructorNoArgs should not have members") + checkMethod(results[1].ctor(), "::TestConstructorWithArgs::constructor", + "constructor", + [("TestConstructorWithArgs (Wrapper)", + [("::TestConstructorWithArgs::constructor::name", "name", "String", False, False)])]) + harness.check(len(results[1].members), 0, + "TestConstructorWithArgs should not have members") + checkMethod(results[2].ctor(), "::TestConstructorOverloads::constructor", + "constructor", + [("TestConstructorOverloads (Wrapper)", + [("::TestConstructorOverloads::constructor::foo", "foo", "Object", False, False)]), + ("TestConstructorOverloads (Wrapper)", + [("::TestConstructorOverloads::constructor::bar", "bar", "Boolean", False, False)])]) + harness.check(len(results[2].members), 0, + "TestConstructorOverloads should not have members") + parser.parse(""" - [Constructor] interface TestConstructorNoArgs { + constructor(); }; - [Constructor(DOMString name)] interface TestConstructorWithArgs { + constructor(DOMString name); }; - [Constructor(object foo), Constructor(boolean bar)] interface TestConstructorOverloads { + constructor(object foo); + constructor(boolean bar); }; """) results = parser.finish() - harness.check(len(results), 3, "Should be three productions") - harness.ok(isinstance(results[0], WebIDL.IDLInterface), - "Should be an IDLInterface") - harness.ok(isinstance(results[1], WebIDL.IDLInterface), - "Should be an IDLInterface") - harness.ok(isinstance(results[2], WebIDL.IDLInterface), - "Should be an IDLInterface") - - checkMethod(results[0].ctor(), "::TestConstructorNoArgs::constructor", - "constructor", [("TestConstructorNoArgs (Wrapper)", [])]) - checkMethod(results[1].ctor(), "::TestConstructorWithArgs::constructor", - "constructor", - [("TestConstructorWithArgs (Wrapper)", - [("::TestConstructorWithArgs::constructor::name", "name", "String", False, False)])]) - checkMethod(results[2].ctor(), "::TestConstructorOverloads::constructor", - "constructor", - [("TestConstructorOverloads (Wrapper)", - [("::TestConstructorOverloads::constructor::foo", "foo", "Object", False, False)]), - ("TestConstructorOverloads (Wrapper)", - [("::TestConstructorOverloads::constructor::bar", "bar", "Boolean", False, False)])]) + checkResults(results) parser = parser.reset() parser.parse(""" - [ChromeConstructor()] - interface TestChromeConstructor { + interface TestChromeOnlyConstructor { + [ChromeOnly] constructor(); }; """) results = parser.finish() @@ -89,8 +99,8 @@ def WebIDLTest(parser, harness): harness.ok(isinstance(results[0], WebIDL.IDLInterface), "Should be an IDLInterface") - checkMethod(results[0].ctor(), "::TestChromeConstructor::constructor", - "constructor", [("TestChromeConstructor (Wrapper)", [])], + checkMethod(results[0].ctor(), "::TestChromeOnlyConstructor::constructor", + "constructor", [("TestChromeOnlyConstructor (Wrapper)", [])], chromeOnly=True) parser = parser.reset() @@ -112,16 +122,16 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - [Constructor(), - ChromeConstructor(DOMString a)] - interface TestChromeConstructor { + interface TestChromeOnlyConstructor { + constructor() + [ChromeOnly] constructor(DOMString a); }; """) results = parser.finish() except: threw = True - harness.ok(threw, "Can't have both a Constructor and a ChromeConstructor") + harness.ok(threw, "Can't have both a constructor and a ChromeOnly constructor") # Test HTMLConstructor with argument parser = parser.reset() @@ -153,120 +163,197 @@ def WebIDLTest(parser, harness): harness.ok(threw, "HTMLConstructor can't be used on a callback interface") - # Test HTMLConstructor and Constructor + # Test HTMLConstructor and constructor operation + parser = parser.reset() + threw = False + try: + parser.parse(""" + [HTMLConstructor] + interface TestHTMLConstructorAndConstructor { + constructor(); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Can't have both a constructor and a HTMLConstructor") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [HTMLConstructor] + interface TestHTMLConstructorAndConstructor { + [Throws] + constructor(); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Can't have both a throwing constructor and a HTMLConstructor") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [HTMLConstructor] + interface TestHTMLConstructorAndConstructor { + constructor(DOMString a); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Can't have both a HTMLConstructor and a constructor operation") + parser = parser.reset() threw = False try: parser.parse(""" - [Constructor, - HTMLConstructor] + [HTMLConstructor] interface TestHTMLConstructorAndConstructor { + [Throws] + constructor(DOMString a); }; """) results = parser.finish() except: threw = True - harness.ok(threw, "Can't have both a Constructor and a HTMLConstructor") + harness.ok(threw, + "Can't have both a HTMLConstructor and a throwing constructor " + "operation") + # Test HTMLConstructor and [ChromeOnly] constructor operation parser = parser.reset() threw = False try: parser.parse(""" - [HTMLConstructor, - Constructor] + [HTMLConstructor] interface TestHTMLConstructorAndConstructor { + [ChromeOnly] + constructor(); }; """) results = parser.finish() except: threw = True - harness.ok(threw, "Can't have both a HTMLConstructor and a Constructor") + harness.ok(threw, + "Can't have both a ChromeOnly constructor and a HTMLConstructor") parser = parser.reset() threw = False try: parser.parse(""" - [HTMLConstructor, - Constructor(DOMString a)] + [HTMLConstructor] interface TestHTMLConstructorAndConstructor { + [Throws, ChromeOnly] + constructor(); }; """) + results = parser.finish() except: threw = True - harness.ok(threw, "Can't have both a HTMLConstructor and a Constructor") + harness.ok(threw, + "Can't have both a throwing chromeonly constructor and a " + "HTMLConstructor") parser = parser.reset() threw = False try: parser.parse(""" - [Constructor(DOMString a), - HTMLConstructor] + [HTMLConstructor] interface TestHTMLConstructorAndConstructor { + [ChromeOnly] + constructor(DOMString a); }; """) + results = parser.finish() except: threw = True - harness.ok(threw, "Can't have both a HTMLConstructor and a Constructor") + harness.ok(threw, + "Can't have both a HTMLConstructor and a chromeonly constructor " + "operation") - # Test HTMLConstructor and ChromeConstructor parser = parser.reset() threw = False try: parser.parse(""" - [ChromeConstructor, - HTMLConstructor] - interface TestHTMLConstructorAndChromeConstructor { + [HTMLConstructor] + interface TestHTMLConstructorAndConstructor { + [Throws, ChromeOnly] + constructor(DOMString a); }; """) results = parser.finish() except: threw = True - harness.ok(threw, "Can't have both a HTMLConstructor and a ChromeConstructor") + harness.ok(threw, + "Can't have both a HTMLConstructor and a throwing chromeonly " + "constructor operation") parser = parser.reset() threw = False try: parser.parse(""" - [HTMLConstructor, - ChromeConstructor] - interface TestHTMLConstructorAndChromeConstructor { + [NoInterfaceObject] + interface InterfaceWithoutInterfaceObject { + constructor(); }; """) results = parser.finish() except: threw = True - harness.ok(threw, "Can't have both a HTMLConstructor and a ChromeConstructor") + harness.ok(threw, + "Can't have a constructor operation on a [NoInterfaceObject] " + "interface") parser = parser.reset() threw = False try: parser.parse(""" - [ChromeConstructor(DOMString a), - HTMLConstructor] - interface TestHTMLConstructorAndChromeConstructor { + interface InterfaceWithPartial { + }; + + partial interface InterfaceWithPartial { + constructor(); }; """) results = parser.finish() except: threw = True + harness.ok(threw, + "Can't have a constructor operation on a partial interface") + parser = parser.reset() threw = False try: parser.parse(""" - [HTMLConstructor, - ChromeConstructor(DOMString a)] - interface TestHTMLConstructorAndChromeConstructor { + interface InterfaceWithMixin { }; + + interface mixin Mixin { + constructor(); + }; + + InterfaceWithMixin includes Mixin """) results = parser.finish() except: threw = True - harness.ok(threw, "Can't have both a HTMLConstructor and a ChromeConstructor") + harness.ok(threw, + "Can't have a constructor operation on a mixin") + 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 index 14d42caf09c..c469d56e817 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_constructor_global.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_constructor_global.py @@ -2,23 +2,9 @@ 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] + [Global] interface TestConstructorGlobal { + constructor(); }; """) 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 e5413350a28..d4175094911 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 @@ -2,23 +2,9 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - [Constructor, NoInterfaceObject] - interface TestConstructorNoInterfaceObject { - }; - """) - - results = parser.finish() - except: - threw = True - - harness.ok(threw, "Should have thrown.") - - parser = parser.reset() - threw = False - try: - parser.parse(""" - [NoInterfaceObject, Constructor] + [NoInterfaceObject] interface TestConstructorNoInterfaceObject { + constructor(); }; """) 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 770f76b22f0..cff049bea15 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_dictionary.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_dictionary.py @@ -320,14 +320,36 @@ def WebIDLTest(parser, harness): dictionary A { }; interface X { - void doFoo(optional A? arg1); + void doFoo(optional A? arg1 = {}); }; """) results = parser.finish() - except: - threw = True + except Exception as x: + threw = x + + harness.ok(threw, "Optional dictionary arg must not be nullable") + harness.ok("nullable" in str(threw), + "Must have the expected exception for optional nullable dictionary arg") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary A { + required long x; + }; + interface X { + void doFoo(A? arg1); + }; + """) + results = parser.finish() + except Exception as x: + threw = x - harness.ok(threw, "Dictionary arg must not be nullable") + harness.ok(threw, "Required dictionary arg must not be nullable") + harness.ok("nullable" in str(threw), + "Must have the expected exception for required nullable " + "dictionary arg") parser = parser.reset() threw = False @@ -336,14 +358,54 @@ def WebIDLTest(parser, harness): dictionary A { }; interface X { - void doFoo(optional (A or long)? arg1); + void doFoo(optional (A or long)? arg1 = {}); + }; + """) + results = parser.finish() + except Exception as x: + threw = x + + harness.ok(threw, "Dictionary arg must not be in an optional nullable union") + harness.ok("nullable" in str(threw), + "Must have the expected exception for optional nullable union " + "arg containing dictionary") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary A { + required long x; + }; + interface X { + void doFoo((A or long)? arg1); + }; + """) + results = parser.finish() + except Exception as x: + threw = x + + harness.ok(threw, "Dictionary arg must not be in a required nullable union") + harness.ok("nullable" in str(threw), + "Must have the expected exception for required nullable union " + "arg containing dictionary") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + dictionary A { + }; + interface X { + void doFoo(sequence arg1); }; """) results = parser.finish() except: threw = True - harness.ok(threw, "Dictionary arg must not be in a nullable union") + harness.ok(not threw, + "Nullable union should be allowed in a sequence argument") parser = parser.reset() threw = False 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 e88c2b50d98..8d18b26cf2d 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_distinguishability.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_distinguishability.py @@ -166,7 +166,7 @@ def WebIDLTest(parser, harness): "record", "Date", "Date?", "any", "Promise", "Promise?", - "USVString", "ArrayBuffer", "ArrayBufferView", "SharedArrayBuffer", + "USVString", "JSString", "ArrayBuffer", "ArrayBufferView", "SharedArrayBuffer", "Uint8Array", "Uint16Array", "(long or Callback)", "(long or Dict)", ] @@ -183,7 +183,7 @@ def WebIDLTest(parser, harness): primitives = numerics + booleans nonNumerics = allBut(argTypes, numerics + unions) nonBooleans = allBut(argTypes, booleans) - strings = [ "DOMString", "ByteString", "Enum", "Enum2", "USVString" ] + strings = [ "DOMString", "ByteString", "Enum", "Enum2", "USVString", "JSString" ] nonStrings = allBut(argTypes, strings) nonObjects = primitives + strings objects = allBut(argTypes, nonObjects ) @@ -202,7 +202,7 @@ def WebIDLTest(parser, harness): notRelatedInterfaces = (nonObjects + ["UnrelatedInterface"] + otherObjects + dates + sequences + bufferSourceTypes + sharedBufferSourceTypes) records = [ "record", "record", - "record" ] + "record" ] # JSString not supported in records # Build a representation of the distinguishability table as a dict # of dicts, holding True values where needed, holes elsewhere. @@ -222,6 +222,7 @@ def WebIDLTest(parser, harness): setDistinguishable("DOMString", nonStrings) setDistinguishable("ByteString", nonStrings) setDistinguishable("USVString", nonStrings) + setDistinguishable("JSString", nonStrings) setDistinguishable("Enum", nonStrings) setDistinguishable("Enum2", nonStrings) setDistinguishable("Interface", notRelatedInterfaces) @@ -244,6 +245,7 @@ def WebIDLTest(parser, harness): allBut(argTypes, sequences + ["object"])) setDistinguishable("record", nonUserObjects) setDistinguishable("record", nonUserObjects) + # JSString not supported in records setDistinguishable("record", nonUserObjects) setDistinguishable("Date", allBut(argTypes, dates + ["object"])) setDistinguishable("Date?", allBut(argTypes, dates + nullables + ["object"])) 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 ea3e842907a..28e6af94597 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_interface.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_interface.py @@ -189,12 +189,12 @@ def WebIDLTest(parser, harness): parser = parser.reset() parser.parse(""" - [Constructor(long arg)] interface A { + constructor(); + constructor(long arg); readonly attribute boolean x; void foo(); }; - [Constructor] partial interface A { readonly attribute boolean y; void foo(long arg); @@ -219,13 +219,13 @@ def WebIDLTest(parser, harness): parser = parser.reset() parser.parse(""" - [Constructor] partial interface A { readonly attribute boolean y; void foo(long arg); }; - [Constructor(long arg)] interface A { + constructor(); + constructor(long arg); readonly attribute boolean x; void foo(); }; 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 72aa7617b84..5de2e02af7e 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 @@ -264,18 +264,18 @@ def WebIDLTest(parser, harness): shouldPass("JS Implemented maplike interface", """ - [JSImplementation="@mozilla.org/dom/test-interface-js-maplike;1", - Constructor()] + [JSImplementation="@mozilla.org/dom/test-interface-js-maplike;1"] interface Foo1 { + constructor(); setlike; }; """, setRWChromeMembers) shouldPass("JS Implemented maplike interface", """ - [JSImplementation="@mozilla.org/dom/test-interface-js-maplike;1", - Constructor()] + [JSImplementation="@mozilla.org/dom/test-interface-js-maplike;1"] interface Foo1 { + constructor(); maplike; }; """, mapRWChromeMembers) @@ -655,9 +655,9 @@ def WebIDLTest(parser, harness): shouldPass("JS Implemented read-only interface with readonly allowable overrides", """ - [JSImplementation="@mozilla.org/dom/test-interface-js-maplike;1", - Constructor()] + [JSImplementation="@mozilla.org/dom/test-interface-js-maplike;1"] interface Foo1 { + constructor(); readonly setlike; readonly attribute boolean clear; }; @@ -665,9 +665,9 @@ def WebIDLTest(parser, harness): shouldFail("JS Implemented read-write interface with non-readwrite allowable overrides", """ - [JSImplementation="@mozilla.org/dom/test-interface-js-maplike;1", - Constructor()] + [JSImplementation="@mozilla.org/dom/test-interface-js-maplike;1"] interface Foo1 { + constructor(); setlike; readonly attribute boolean clear; }; diff --git a/components/script/dom/bindings/codegen/parser/update.sh b/components/script/dom/bindings/codegen/parser/update.sh index fee9720ab2d..81b3d944a70 100755 --- a/components/script/dom/bindings/codegen/parser/update.sh +++ b/components/script/dom/bindings/codegen/parser/update.sh @@ -1,11 +1,11 @@ -wget https://hg.mozilla.org/mozilla-central/raw-file/tip/dom/bindings/parser/WebIDL.py -O WebIDL.py +wget https://hg.mozilla.org/mozilla-central/raw-file/e447e3d69684cf04a95a35b9708174a6538eb042/dom/bindings/parser/WebIDL.py -O WebIDL.py patch < abstract.patch patch < debug.patch patch < callback-location.patch patch < union-typedef.patch patch < inline.patch -wget https://hg.mozilla.org/mozilla-central/archive/tip.tar.gz/dom/bindings/parser/tests/ -O tests.tar.gz +wget https://hg.mozilla.org/mozilla-central/archive/e447e3d69684cf04a95a35b9708174a6538eb042.tar.gz/dom/bindings/parser/tests/ -O tests.tar.gz rm -r tests mkdir tests tar xvpf tests.tar.gz -C tests --strip-components=5 -- cgit v1.2.3 From 2660f359254e7543b7c91d14728b44ac01e438e5 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Wed, 2 Oct 2019 18:21:34 +0900 Subject: Remove [PrimaryGlobal] --- .../script/dom/bindings/codegen/CodegenRust.py | 4 - .../script/dom/bindings/codegen/Configuration.py | 5 - .../script/dom/bindings/codegen/parser/WebIDL.py | 315 +++++---------------- .../parser/tests/test_constructor_global.py | 14 +- .../codegen/parser/tests/test_dictionary.py | 14 + .../parser/tests/test_distinguishability.py | 13 +- .../tests/test_exposed_extended_attribute.py | 76 +++-- .../parser/tests/test_global_extended_attr.py | 16 +- .../codegen/parser/tests/test_implements.py | 216 -------------- .../codegen/parser/tests/test_interface.py | 104 +------ .../tests/test_interface_maplikesetlikeiterable.py | 71 +---- .../codegen/parser/tests/test_interfacemixin.py | 72 ++++- .../tests/test_securecontext_extended_attribute.py | 17 +- .../codegen/parser/tests/test_unforgeable.py | 26 +- .../script/dom/bindings/codegen/parser/update.sh | 4 +- 15 files changed, 261 insertions(+), 706 deletions(-) delete mode 100644 components/script/dom/bindings/codegen/parser/tests/test_implements.py (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index c02499f222f..103450f78f3 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -827,10 +827,6 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, elif isArgument: descriptorType = descriptor.argumentType - if descriptor.interface.isConsequential(): - raise TypeError("Consequential interface %s being used as an " - "argument" % descriptor.interface.identifier.name) - if failureCode is None: substitutions = { "sourceDescription": sourceDescription, diff --git a/components/script/dom/bindings/codegen/Configuration.py b/components/script/dom/bindings/codegen/Configuration.py index bde6e71bcfb..1d50c3ed4f7 100644 --- a/components/script/dom/bindings/codegen/Configuration.py +++ b/components/script/dom/bindings/codegen/Configuration.py @@ -38,11 +38,6 @@ class Configuration: iface = thing self.interfaces[iface.identifier.name] = iface if iface.identifier.name not in config: - # Completely skip consequential interfaces with no descriptor - # if they have no interface object because chances are we - # don't need to do anything interesting with them. - if iface.isConsequential() and not iface.hasInterfaceObject(): - continue entry = {} else: entry = config[iface.identifier.name] diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index 5e8b958e3de..a36b1b3ecfe 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.py @@ -154,6 +154,9 @@ class IDLObject(object): def isNamespace(self): return False + def isInterfaceMixin(self): + return False + def isEnum(self): return False @@ -233,8 +236,6 @@ class IDLScope(IDLObject): # A mapping from global name to the set of global interfaces # that have that global name. self.globalNameMapping = defaultdict(set) - self.primaryGlobalAttr = None - self.primaryGlobalName = None def __str__(self): return self.QName() @@ -462,8 +463,17 @@ class IDLExposureMixins(): raise WebIDLError("Unknown [Exposed] value %s" % globalName, [self._location]) - if len(self._exposureGlobalNames) == 0: - self._exposureGlobalNames.add(scope.primaryGlobalName) + # Verify that we are exposed _somwhere_ if we have some place to be + # exposed. We don't want to assert that we're definitely exposed + # because a lot of our parser tests have small-enough IDL snippets that + # they don't include any globals, and we don't really want to go through + # and add global interfaces and [Exposed] annotations to all those + # tests. + if len(scope.globalNames) != 0: + if (len(self._exposureGlobalNames) == 0): + raise WebIDLError(("'%s' is not exposed anywhere even though we have " + "globals to be exposed to") % self, + [self.location]) globalNameSetToExposureSet(scope, self._exposureGlobalNames, self.exposureSet) @@ -508,17 +518,15 @@ class IDLExposureMixins(): return workerDebuggerScopes.intersection(self.exposureSet) -class IDLExternalInterface(IDLObjectWithIdentifier, IDLExposureMixins): +class IDLExternalInterface(IDLObjectWithIdentifier): def __init__(self, location, parentScope, identifier): assert isinstance(identifier, IDLUnresolvedIdentifier) assert isinstance(parentScope, IDLScope) self.parent = None IDLObjectWithIdentifier.__init__(self, location, parentScope, identifier) - IDLExposureMixins.__init__(self, location) IDLObjectWithIdentifier.resolve(self, parentScope) def finish(self, scope): - IDLExposureMixins.finish(self, scope) pass def validate(self): @@ -533,9 +541,6 @@ class IDLExternalInterface(IDLObjectWithIdentifier, IDLExposureMixins): def isInterface(self): return True - def isConsequential(self): - return False - def addExtendedAttributes(self, attrs): if len(attrs) != 0: raise WebIDLError("There are no extended attributes that are " @@ -554,9 +559,6 @@ class IDLExternalInterface(IDLObjectWithIdentifier, IDLExposureMixins): def hasProbablyShortLivingWrapper(self): return False - def isSerializable(self): - return False - def _getDependentObjects(self): return set() @@ -718,6 +720,7 @@ class IDLInterfaceOrInterfaceMixinOrNamespace(IDLObjectWithScope, IDLExposureMix return "interface" if self.isNamespace(): return "namespace" + assert self.isInterfaceMixin() return "interface mixin" def getExtendedAttribute(self, name): @@ -770,10 +773,13 @@ class IDLInterfaceOrInterfaceMixinOrNamespace(IDLObjectWithScope, IDLExposureMix # sets, make sure they aren't exposed in places where we are not. for member in self.members: if not member.exposureSet.issubset(self.exposureSet): - raise WebIDLError("Interface or interface mixin member has" + raise WebIDLError("Interface or interface mixin member has " "larger exposure set than its container", [member.location, self.location]) + def isExternal(self): + return False + class IDLInterfaceMixin(IDLInterfaceOrInterfaceMixinOrNamespace): def __init__(self, location, parentScope, name, members, isKnownNonPartial): @@ -788,6 +794,9 @@ class IDLInterfaceMixin(IDLInterfaceOrInterfaceMixinOrNamespace): def __str__(self): return "Interface mixin '%s'" % self.identifier.name + def isInterfaceMixin(self): + return True + def finish(self, scope): if self._finished: return @@ -796,8 +805,10 @@ class IDLInterfaceMixin(IDLInterfaceOrInterfaceMixinOrNamespace): # Expose to the globals of interfaces that includes this mixin if this # mixin has no explicit [Exposed] so that its members can be exposed # based on the base interface exposure set. - # Make sure this is done before IDLExposureMixins.finish call to - # prevent exposing to PrimaryGlobal by default. + # + # Make sure this is done before IDLExposureMixins.finish call, since + # that converts our set of exposure global names to an actual exposure + # set. hasImplicitExposure = len(self._exposureGlobalNames) == 0 if hasImplicitExposure: self._exposureGlobalNames.update(self.actualExposureGlobalNames) @@ -876,16 +887,11 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): # them. self.namedConstructors = list() self.legacyWindowAliases = [] - self.implementedInterfaces = set() self.includedMixins = set() - self._consequential = False # self.interfacesBasedOnSelf is the set of interfaces that inherit from - # self or have self as a consequential interface, including self itself. + # self, including self itself. # Used for distinguishability checking. self.interfacesBasedOnSelf = set([self]) - # self.interfacesImplementingSelf is the set of interfaces that directly - # have self as a consequential interface - self.interfacesImplementingSelf = set() self._hasChildInterfaces = False self._isOnGlobalProtoChain = False # Tracking of the number of reserved slots we need for our @@ -896,6 +902,10 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): # 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 + # True if we have cross-origin members. + self.hasCrossOriginMembers = False + # True if some descendant (including ourselves) has cross-origin members + self.hasDescendantWithCrossOriginMembers = False self.toStringTag = toStringTag @@ -996,10 +1006,8 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): self.totalMembersInSlots = self.parent.totalMembersInSlots - # Interfaces with [Global] or [PrimaryGlobal] must not - # have anything inherit from them - if (self.parent.getExtendedAttribute("Global") or - self.parent.getExtendedAttribute("PrimaryGlobal")): + # Interfaces with [Global] must not have anything inherit from them + if self.parent.getExtendedAttribute("Global"): # Note: This is not a self.parent.isOnGlobalProtoChain() check # because ancestors of a [Global] interface can have other # descendants. @@ -1015,10 +1023,8 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): self.parent.identifier.name), [self.location, self.parent.location]) - # Callbacks must not inherit from non-callbacks or inherit from - # anything that has consequential interfaces. + # Callbacks must not inherit from non-callbacks. # XXXbz Can non-callbacks inherit from callbacks? Spec issue pending. - # XXXbz Can callbacks have consequential interfaces? Spec issue pending if self.isCallback(): if not self.parent.isCallback(): raise WebIDLError("Callback interface %s inheriting from " @@ -1055,23 +1061,14 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): self.parent.identifier.name), [self.location, self.parent.location]) - for iface in self.implementedInterfaces: - iface.finish(scope) for mixin in self.includedMixins: mixin.finish(scope) cycleInGraph = self.findInterfaceLoopPoint(self) if cycleInGraph: - raise WebIDLError("Interface %s has itself as ancestor or " - "implemented interface" % self.identifier.name, - [self.location, cycleInGraph.location]) - - if self.isCallback(): - # "implements" should have made sure we have no - # consequential interfaces. - assert len(self.getConsequentialInterfaces()) == 0 - # And that we're not consequential. - assert not self.isConsequential() + raise WebIDLError( + "Interface %s has itself as ancestor" % self.identifier.name, + [self.location, cycleInGraph.location]) self.finishMembers(scope) @@ -1104,7 +1101,7 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): if self.globalNames: raise WebIDLError( "Can't have both a named constructor and [Global]", - [self.location, self.namedConstructors.location]) + [self.location, ctor.location]) assert len(ctor._exposureGlobalNames) == 0 ctor._exposureGlobalNames.update(self._exposureGlobalNames) ctor.finish(scope) @@ -1114,43 +1111,15 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): # admixed. self.originalMembers = list(self.members) - # Import everything from our consequential interfaces into - # self.members. Sort our consequential interfaces by name - # just so we have a consistent order. - for iface in sorted(self.getConsequentialInterfaces(), + for mixin in sorted(self.includedMixins, key=lambda x: x.identifier.name): - # Flag the interface as being someone's consequential interface - iface.setIsConsequentialInterfaceOf(self) - # Verify that we're not exposed somewhere where iface is not exposed - if not self.exposureSet.issubset(iface.exposureSet): - raise WebIDLError("Interface %s is exposed in globals where its " - "consequential interface %s is not exposed." % - (self.identifier.name, iface.identifier.name), - [self.location, iface.location]) - - # If we have a maplike or setlike, and the consequential interface - # also does, throw an error. - 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.maplikeOrSetlikeOrIterable.location, - iface.maplikeOrSetlikeOrIterable.location]) - additionalMembers = iface.originalMembers - for additionalMember in additionalMembers: + for mixinMember in mixin.members: for member in self.members: - if additionalMember.identifier.name == member.identifier.name: + if mixinMember.identifier.name == member.identifier.name: raise WebIDLError( - "Multiple definitions of %s on %s coming from 'implements' statements" % + "Multiple definitions of %s on %s coming from 'includes' statements" % (member.identifier.name, self), - [additionalMember.location, member.location]) - self.members.extend(additionalMembers) - iface.interfacesImplementingSelf.add(self) - - for mixin in sorted(self.includedMixins, - key=lambda x: x.identifier.name): + [mixinMember.location, member.location]) self.members.extend(mixin.members) for ancestor in self.getInheritedInterfaces(): @@ -1164,8 +1133,6 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): ancestor.identifier.name), [self.maplikeOrSetlikeOrIterable.location, ancestor.maplikeOrSetlikeOrIterable.location]) - for ancestorConsequential in ancestor.getConsequentialInterfaces(): - ancestorConsequential.interfacesBasedOnSelf.add(self) # Deal with interfaces marked [Unforgeable], now that we have our full # member list, except unforgeables pulled in from parents. We want to @@ -1199,6 +1166,21 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): not hasattr(member, "originatingInterface")): member.originatingInterface = self + for member in self.members: + if ((member.isMethod() and + member.getExtendedAttribute("CrossOriginCallable")) or + (member.isAttr() and + (member.getExtendedAttribute("CrossOriginReadable") or + member.getExtendedAttribute("CrossOriginWritable")))): + self.hasCrossOriginMembers = True + break + + if self.hasCrossOriginMembers: + parent = self + while parent: + parent.hasDescendantWithCrossOriginMembers = True + parent = parent.parent + # Compute slot indices for our members before we pull in unforgeable # members from our parent. Also, maplike/setlike declarations get a # slot to hold their backing object. @@ -1221,13 +1203,12 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): self._ownMembersInSlots += 1 if self.parent: - # Make sure we don't shadow any of the [Unforgeable] attributes on - # our ancestor interfaces. We don't have to worry about - # consequential interfaces here, because those have already been - # imported into the relevant .members lists. And we don't have to - # worry about anything other than our parent, because it has already - # imported its ancestors unforgeable attributes into its member - # list. + # Make sure we don't shadow any of the [Unforgeable] attributes on our + # ancestor interfaces. We don't have to worry about mixins here, because + # those have already been imported into the relevant .members lists. And + # we don't have to worry about anything other than our parent, because it + # has already imported its ancestors' unforgeable attributes into its + # member list. for unforgeableMember in (member for member in self.parent.members if (member.isAttr() or member.isMethod()) and member.isUnforgeable()): @@ -1363,17 +1344,6 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): (attributeName, name), [member.location, m.location]) - # We don't support consequential unforgeable interfaces. Need to check - # this here, because in finish() an interface might not know yet that - # it's consequential. - if self.getExtendedAttribute("Unforgeable") and self.isConsequential(): - raise WebIDLError( - "%s is an unforgeable consequential interface" % - self.identifier.name, - [self.location] + - list(i.location for i in - (self.interfacesBasedOnSelf - {self}))) - # We also don't support inheriting from unforgeable interfaces. if self.getExtendedAttribute("Unforgeable") and self.hasChildInterfaces(): locations = ([self.location] + @@ -1529,16 +1499,6 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): 'an integer-typed "length" attribute', [self.location, indexedGetter.location]) - def isExternal(self): - return False - - def setIsConsequentialInterfaceOf(self, other): - self._consequential = True - self.interfacesBasedOnSelf.add(other) - - def isConsequential(self): - return self._consequential - def setCallback(self, value): self._callback = value @@ -1553,8 +1513,6 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): not self.isJSImplemented() and # Not inheriting from another interface not self.parent and - # No consequential interfaces - len(self.getConsequentialInterfaces()) == 0 and # No attributes of any kinds not any(m.isAttr() for m in self.members) and # There is at least one regular operation, and all regular @@ -1582,10 +1540,6 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): return (not self.isCallback() and not self.isNamespace() and self.getUserData('hasConcreteDescendant', False)) - def addImplementedInterface(self, implementedInterface): - assert(isinstance(implementedInterface, IDLInterface)) - self.implementedInterfaces.add(implementedInterface) - def addIncludedMixin(self, includedMixin): assert(isinstance(includedMixin, IDLInterfaceMixin)) self.includedMixins.add(includedMixin) @@ -1603,27 +1557,10 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): parentInterfaces.insert(0, self.parent) return parentInterfaces - def getConsequentialInterfaces(self): - assert(self._finished) - # The interfaces we implement directly - consequentialInterfaces = set(self.implementedInterfaces) - - # And their inherited interfaces - for iface in self.implementedInterfaces: - consequentialInterfaces |= set(iface.getInheritedInterfaces()) - - # And now collect up the consequential interfaces of all of those - temp = set() - for iface in consequentialInterfaces: - temp |= iface.getConsequentialInterfaces() - - return consequentialInterfaces | temp - def findInterfaceLoopPoint(self, otherInterface): """ - Finds an interface, amongst our ancestors and consequential interfaces, - that inherits from otherInterface or implements otherInterface - directly. If there is no such interface, returns None. + Finds an interface amongst our ancestors that inherits from otherInterface. + If there is no such interface, returns None. """ if self.parent: if self.parent == otherInterface: @@ -1631,13 +1568,8 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): loopPoint = self.parent.findInterfaceLoopPoint(otherInterface) if loopPoint: return loopPoint - if otherInterface in self.implementedInterfaces: - return self - for iface in self.implementedInterfaces: - loopPoint = iface.findInterfaceLoopPoint(otherInterface) - if loopPoint: - return loopPoint return None + def setNonPartial(self, location, parent, members): assert not parent or isinstance(parent, IDLIdentifierPlaceholder) IDLInterfaceOrInterfaceMixinOrNamespace.setNonPartial(self, location, members) @@ -1671,7 +1603,6 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): def _getDependentObjects(self): deps = set(self.members) - deps.update(self.implementedInterfaces) deps.update(self.includedMixins) if self.parent: deps.add(self.parent) @@ -1794,20 +1725,6 @@ class IDLInterface(IDLInterfaceOrNamespace): self.parentScope.addIfaceGlobalNames(self.identifier.name, self.globalNames) self._isOnGlobalProtoChain = True - elif identifier == "PrimaryGlobal": - if not attr.noArguments(): - raise WebIDLError("[PrimaryGlobal] must take no arguments", - [attr.location]) - if self.parentScope.primaryGlobalAttr is not None: - raise WebIDLError( - "[PrimaryGlobal] specified twice", - [attr.location, - self.parentScope.primaryGlobalAttr.location]) - self.parentScope.primaryGlobalAttr = attr - self.parentScope.primaryGlobalName = self.identifier.name - self.parentScope.addIfaceGlobalNames(self.identifier.name, - [self.identifier.name]) - self._isOnGlobalProtoChain = True elif identifier == "LegacyWindowAlias": if attr.hasValue(): self.legacyWindowAliases = [attr.value()] @@ -3081,8 +2998,9 @@ class IDLWrapperType(IDLType): return True iface = self.inner if iface.isExternal(): - # Let's say true, though ideally we'd only do this when - # exposureSet contains the primary global's name. + # Let's say true, so we don't have to implement exposure mixins on + # external interfaces and sprinkle [Exposed=Window] on every single + # external interface declaration. return True return iface.exposureSet.issuperset(exposureSet) @@ -3865,10 +3783,6 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins): return self._extendedAttrDict.get(name, None) def finish(self, scope): - # We better be exposed _somewhere_. - if (len(self._exposureGlobalNames) == 0): - print(self.identifier.name) - assert len(self._exposureGlobalNames) != 0 IDLExposureMixins.finish(self, scope) def validate(self): @@ -5539,52 +5453,6 @@ class IDLConstructor(IDLMethod): [IDLExtendedAttribute(self.location, ("NewObject",))]) -class IDLImplementsStatement(IDLObject): - def __init__(self, location, implementor, implementee): - IDLObject.__init__(self, location) - self.implementor = implementor - self.implementee = implementee - self._finished = False - - def finish(self, scope): - if self._finished: - return - assert(isinstance(self.implementor, IDLIdentifierPlaceholder)) - assert(isinstance(self.implementee, IDLIdentifierPlaceholder)) - implementor = self.implementor.finish(scope) - implementee = self.implementee.finish(scope) - # NOTE: we depend on not setting self.implementor and - # self.implementee here to keep track of the original - # locations. - if not isinstance(implementor, IDLInterface): - raise WebIDLError("Left-hand side of 'implements' is not an " - "interface", - [self.implementor.location]) - if implementor.isCallback(): - raise WebIDLError("Left-hand side of 'implements' is a callback " - "interface", - [self.implementor.location]) - if not isinstance(implementee, IDLInterface): - raise WebIDLError("Right-hand side of 'implements' is not an " - "interface", - [self.implementee.location]) - if implementee.isCallback(): - raise WebIDLError("Right-hand side of 'implements' is a callback " - "interface", - [self.implementee.location]) - implementor.addImplementedInterface(implementee) - self.implementor = implementor - self.implementee = implementee - - def validate(self): - pass - - def addExtendedAttributes(self, attrs): - if len(attrs) != 0: - raise WebIDLError("There are no extended attributes that are " - "allowed on implements statements", - [attrs[0].location, self.location]) - class IDLIncludesStatement(IDLObject): def __init__(self, location, interface, mixin): IDLObject.__init__(self, location) @@ -5606,16 +5474,18 @@ class IDLIncludesStatement(IDLObject): if not isinstance(interface, IDLInterface): raise WebIDLError("Left-hand side of 'includes' is not an " "interface", - [self.interface.location]) + [self.interface.location, interface.location]) if interface.isCallback(): raise WebIDLError("Left-hand side of 'includes' is a callback " "interface", - [self.interface.location]) + [self.interface.location, interface.location]) if not isinstance(mixin, IDLInterfaceMixin): raise WebIDLError("Right-hand side of 'includes' is not an " "interface mixin", - [self.mixin.location]) + [self.mixin.location, mixin.location]) + mixin.actualExposureGlobalNames.update(interface._exposureGlobalNames) + interface.addIncludedMixin(mixin) self.interface = interface self.mixin = mixin @@ -5721,7 +5591,6 @@ class Tokenizer(object): return t keywords = { - "module": "MODULE", "interface": "INTERFACE", "partial": "PARTIAL", "mixin": "MIXIN", @@ -5730,7 +5599,6 @@ class Tokenizer(object): "enum": "ENUM", "callback": "CALLBACK", "typedef": "TYPEDEF", - "implements": "IMPLEMENTS", "includes": "INCLUDES", "const": "CONST", "null": "NULL", @@ -5894,7 +5762,6 @@ class Parser(Tokenizer): | Exception | Enum | Typedef - | ImplementsStatement | IncludesStatement """ p[0] = p[1] @@ -6427,16 +6294,6 @@ class Parser(Tokenizer): p[2], p[3]) p[0] = typedef - def p_ImplementsStatement(self, p): - """ - ImplementsStatement : ScopedName IMPLEMENTS ScopedName SEMICOLON - """ - assert(p[2] == "implements") - implementor = IDLIdentifierPlaceholder(self.getLocation(p, 1), p[1]) - implementee = IDLIdentifierPlaceholder(self.getLocation(p, 3), p[3]) - p[0] = IDLImplementsStatement(self.getLocation(p, 1), implementor, - implementee) - def p_IncludesStatement(self, p): """ IncludesStatement : ScopedName INCLUDES ScopedName SEMICOLON @@ -6898,7 +6755,6 @@ class Parser(Tokenizer): | ENUM | EXCEPTION | GETTER - | IMPLEMENTS | INHERIT | INTERFACE | ITERABLE @@ -7025,11 +6881,9 @@ class Parser(Tokenizer): | FALSE | FLOAT | GETTER - | IMPLEMENTS | INHERIT | INTERFACE | LONG - | MODULE | NULL | OBJECT | OCTET @@ -7479,12 +7333,6 @@ class Parser(Tokenizer): self._globalScope = IDLScope(BuiltinLocation(""), None, None) - # To make our test harness work, pretend like we have a primary global already. - # Note that we _don't_ set _globalScope.primaryGlobalAttr, - # so we'll still be able to detect multiple PrimaryGlobal extended attributes. - self._globalScope.primaryGlobalName = "FakeTestPrimaryGlobal" - self._globalScope.addIfaceGlobalNames("FakeTestPrimaryGlobal", ["FakeTestPrimaryGlobal"]) - self._installBuiltins(self._globalScope) self._productions = [] @@ -7568,20 +7416,13 @@ class Parser(Tokenizer): 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 - isinstance(p, IDLImplementsStatement)] # Make sure we finish IDLIncludesStatements before we finish the # IDLInterfaces. + # XXX khuey hates this bit and wants to nuke it from orbit. includesStatements = [p for p in self._productions if isinstance(p, IDLIncludesStatement)] otherStatements = [p for p in self._productions if - not isinstance(p, (IDLImplementsStatement, - IDLIncludesStatement))] - for production in implementsStatements: - production.finish(self.globalScope()) + not isinstance(p, IDLIncludesStatement)] for production in includesStatements: production.finish(self.globalScope()) for production in otherStatements: 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 index c469d56e817..31c5d95317f 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_constructor_global.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_constructor_global.py @@ -1,8 +1,10 @@ +import traceback + def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - [Global] + [Global, Exposed=TestConstructorGlobal] interface TestConstructorGlobal { constructor(); }; @@ -18,7 +20,8 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - [Global, NamedConstructor=FooBar] + [Global, Exposed=TestNamedConstructorGlobal, + NamedConstructor=FooBar] interface TestNamedConstructorGlobal { }; """) @@ -32,7 +35,8 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - [NamedConstructor=FooBar, Global] + [NamedConstructor=FooBar, Global, + Exposed=TestNamedConstructorGlobal] interface TestNamedConstructorGlobal { }; """) @@ -46,7 +50,7 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - [Global, HTMLConstructor] + [Global, HTMLConstructor, Exposed=TestHTMLConstructorGlobal] interface TestHTMLConstructorGlobal { }; """) @@ -61,7 +65,7 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - [HTMLConstructor, Global] + [HTMLConstructor, Global, Exposed=TestHTMLConstructorGlobal] interface TestHTMLConstructorGlobal { }; """) 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 cff049bea15..3cad3022389 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_dictionary.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_dictionary.py @@ -736,3 +736,17 @@ def WebIDLTest(parser, harness): threw = True harness.ok(threw, "Only unrestricted values can be initialized to NaN") + + parser = parser.reset(); + threw = False + try: + parser.parse(""" + dictionary Foo { + long module; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(not threw, "Should be able to use 'module' as a dictionary member name") 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 8d18b26cf2d..bd9996e34c9 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_distinguishability.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_distinguishability.py @@ -59,8 +59,6 @@ def WebIDLTest(parser, harness): void passKid(Kid arg); void passParent(Parent arg); void passGrandparent(Grandparent arg); - void passImplemented(Implemented arg); - void passImplementedParent(ImplementedParent arg); void passUnrelated1(Unrelated1 arg); void passUnrelated2(Unrelated2 arg); void passArrayBuffer(ArrayBuffer arg); @@ -70,9 +68,6 @@ def WebIDLTest(parser, harness): interface Kid : Parent {}; interface Parent : Grandparent {}; interface Grandparent {}; - interface Implemented : ImplementedParent {}; - Parent implements Implemented; - interface ImplementedParent {}; interface Unrelated1 {}; interface Unrelated2 {}; """) @@ -156,8 +151,7 @@ def WebIDLTest(parser, harness): argTypes = [ "long", "short", "long?", "short?", "boolean", "boolean?", "DOMString", "ByteString", "Enum", "Enum2", "Interface", "Interface?", - "AncestorInterface", "UnrelatedInterface", - "ImplementedInterface", "CallbackInterface", + "AncestorInterface", "UnrelatedInterface", "CallbackInterface", "CallbackInterface?", "CallbackInterface2", "object", "Callback", "Callback2", "Dict", "Dict2", "sequence", "sequence", @@ -190,7 +184,7 @@ def WebIDLTest(parser, harness): bufferSourceTypes = ["ArrayBuffer", "ArrayBufferView", "Uint8Array", "Uint16Array"] sharedBufferSourceTypes = ["SharedArrayBuffer"] interfaces = [ "Interface", "Interface?", "AncestorInterface", - "UnrelatedInterface", "ImplementedInterface" ] + bufferSourceTypes + sharedBufferSourceTypes + "UnrelatedInterface" ] + bufferSourceTypes + sharedBufferSourceTypes nullables = (["long?", "short?", "boolean?", "Interface?", "CallbackInterface?", "Dict", "Dict2", "Date?", "any", "Promise?"] + @@ -230,7 +224,6 @@ def WebIDLTest(parser, harness): setDistinguishable("AncestorInterface", notRelatedInterfaces) setDistinguishable("UnrelatedInterface", allBut(argTypes, ["object", "UnrelatedInterface"])) - setDistinguishable("ImplementedInterface", notRelatedInterfaces) setDistinguishable("CallbackInterface", nonUserObjects) setDistinguishable("CallbackInterface?", allBut(nonUserObjects, nullables)) setDistinguishable("CallbackInterface2", nonUserObjects) @@ -272,8 +265,6 @@ def WebIDLTest(parser, harness): interface Interface : AncestorInterface {}; interface AncestorInterface {}; interface UnrelatedInterface {}; - interface ImplementedInterface {}; - Interface implements ImplementedInterface; callback interface CallbackInterface {}; callback interface CallbackInterface2 {}; callback Callback = any(); 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 a6c04e30caf..e0241a56426 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 @@ -2,9 +2,9 @@ import WebIDL def WebIDLTest(parser, harness): parser.parse(""" - [PrimaryGlobal] interface Foo {}; - [Global=(Bar1,Bar2)] interface Bar {}; - [Global=Baz2] interface Baz {}; + [Global, Exposed=Foo] interface Foo {}; + [Global=(Bar, Bar1,Bar2), Exposed=Bar] interface Bar {}; + [Global=(Baz, Baz2), Exposed=Baz] interface Baz {}; [Exposed=(Foo,Bar1)] interface Iface { @@ -51,10 +51,11 @@ def WebIDLTest(parser, harness): parser = parser.reset() parser.parse(""" - [PrimaryGlobal] interface Foo {}; - [Global=(Bar1,Bar2)] interface Bar {}; - [Global=Baz2] interface Baz {}; + [Global, Exposed=Foo] interface Foo {}; + [Global=(Bar, Bar1, Bar2), Exposed=Bar] interface Bar {}; + [Global=(Baz, Baz2), Exposed=Baz] interface Baz {}; + [Exposed=Foo] interface Iface2 { void method3(); }; @@ -80,9 +81,9 @@ def WebIDLTest(parser, harness): parser = parser.reset() parser.parse(""" - [PrimaryGlobal] interface Foo {}; - [Global=(Bar1,Bar2)] interface Bar {}; - [Global=Baz2] interface Baz {}; + [Global, Exposed=Foo] interface Foo {}; + [Global=(Bar, Bar1, Bar2), Exposed=Bar] interface Bar {}; + [Global=(Baz, Baz2), Exposed=Baz] interface Baz {}; [Exposed=Foo] interface Iface3 { @@ -90,11 +91,11 @@ def WebIDLTest(parser, harness): }; [Exposed=(Foo,Bar1)] - interface Mixin { + interface mixin Mixin { void method5(); }; - Iface3 implements Mixin; + Iface3 includes Mixin; """) results = parser.finish() harness.check(len(results), 6, "Should know about six things"); @@ -181,8 +182,8 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - [Global] interface Foo {}; - [Global] interface Bar {}; + [Global, Exposed=Foo] interface Foo {}; + [Global, Exposed=Bar] interface Bar {}; [Exposed=Foo] interface Baz { @@ -198,25 +199,40 @@ def WebIDLTest(parser, harness): harness.ok(threw, "Should have thrown on member exposed where its interface is not.") parser = parser.reset() - threw = False - try: - parser.parse(""" - [Global] interface Foo {}; - [Global] interface Bar {}; + parser.parse(""" + [Global, Exposed=Foo] interface Foo {}; + [Global, Exposed=Bar] interface Bar {}; - [Exposed=Foo] - interface Baz { - void method(); - }; + [Exposed=Foo] + interface Baz { + void method(); + }; - [Exposed=Bar] - interface Mixin {}; + [Exposed=Bar] + interface mixin Mixin { + void otherMethod(); + }; - Baz implements Mixin; - """) + Baz includes Mixin; + """) + + results = parser.finish() + + harness.check(len(results), 5, "Should know about five things"); + iface = results[2] + harness.ok(isinstance(iface, WebIDL.IDLInterface), + "Should have an interface here"); + members = iface.members + harness.check(len(members), 2, "Should have two members") + + harness.ok(members[0].exposureSet == set(["Foo"]), + "method should have the right exposure set") + harness.ok(members[0]._exposureGlobalNames == set(["Foo"]), + "method should have the right exposure global names") + + harness.ok(members[1].exposureSet == set(["Bar"]), + "otherMethod should have the right exposure set") + harness.ok(members[1]._exposureGlobalNames == set(["Bar"]), + "otherMethod should have the right exposure global names") - results = parser.finish() - 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_global_extended_attr.py b/components/script/dom/bindings/codegen/parser/tests/test_global_extended_attr.py index bc20da40bbe..28b79642d86 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_global_extended_attr.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_global_extended_attr.py @@ -1,9 +1,10 @@ def WebIDLTest(parser, harness): parser.parse(""" - [Global] + [Global, Exposed=Foo] interface Foo : Bar { getter any(DOMString name); }; + [Exposed=Foo] interface Bar {}; """) @@ -18,7 +19,7 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - [Global] + [Global, Exposed=Foo] interface Foo { getter any(DOMString name); setter void(DOMString name, any arg); @@ -36,7 +37,7 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - [Global] + [Global, Exposed=Foo] interface Foo { getter any(DOMString name); deleter void(DOMString name); @@ -54,7 +55,7 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - [Global, OverrideBuiltins] + [Global, OverrideBuiltins, Exposed=Foo] interface Foo { }; """) @@ -70,10 +71,10 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - [Global] + [Global, Exposed=Foo] interface Foo : Bar { }; - [OverrideBuiltins] + [OverrideBuiltins, Exposed=Foo] interface Bar { }; """) @@ -89,9 +90,10 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - [Global] + [Global, Exposed=Foo] interface Foo { }; + [Exposed=Foo] interface Bar : Foo { }; """) diff --git a/components/script/dom/bindings/codegen/parser/tests/test_implements.py b/components/script/dom/bindings/codegen/parser/tests/test_implements.py deleted file mode 100644 index 04c47d92abe..00000000000 --- a/components/script/dom/bindings/codegen/parser/tests/test_implements.py +++ /dev/null @@ -1,216 +0,0 @@ -# Import the WebIDL module, so we can do isinstance checks and whatnot -import WebIDL - -def WebIDLTest(parser, harness): - # Basic functionality - threw = False - try: - parser.parse(""" - A implements B; - interface B { - attribute long x; - }; - interface A { - attribute long y; - }; - """) - results = parser.finish() - except: - threw = True - - harness.ok(not threw, "Should not have thrown on implements statement " - "before interfaces") - harness.check(len(results), 3, "We have three statements") - harness.ok(isinstance(results[1], WebIDL.IDLInterface), "B is an interface") - harness.check(len(results[1].members), 1, "B has one member") - A = results[2] - harness.ok(isinstance(A, WebIDL.IDLInterface), "A is an interface") - harness.check(len(A.members), 2, "A has two members") - harness.check(A.members[0].identifier.name, "y", "First member is 'y'") - harness.check(A.members[1].identifier.name, "x", "Second member is 'x'") - - # Duplicated member names not allowed - threw = False - try: - parser.parse(""" - C implements D; - interface D { - attribute long x; - }; - interface C { - attribute long x; - }; - """) - parser.finish() - except: - threw = True - - harness.ok(threw, "Should have thrown on implemented interface duplicating " - "a name on base interface") - - # Same, but duplicated across implemented interfaces - threw = False - try: - parser.parse(""" - E implements F; - E implements G; - interface F { - attribute long x; - }; - interface G { - attribute long x; - }; - interface E {}; - """) - parser.finish() - except: - threw = True - - harness.ok(threw, "Should have thrown on implemented interfaces " - "duplicating each other's member names") - - # Same, but duplicated across indirectly implemented interfaces - threw = False - try: - parser.parse(""" - H implements I; - H implements J; - I implements K; - interface K { - attribute long x; - }; - interface L { - attribute long x; - }; - interface I {}; - interface J : L {}; - interface H {}; - """) - parser.finish() - except: - threw = True - - harness.ok(threw, "Should have thrown on indirectly implemented interfaces " - "duplicating each other's member names") - - # Same, but duplicated across an implemented interface and its parent - threw = False - try: - parser.parse(""" - M implements N; - interface O { - attribute long x; - }; - interface N : O { - attribute long x; - }; - interface M {}; - """) - parser.finish() - except: - threw = True - - harness.ok(threw, "Should have thrown on implemented interface and its " - "ancestor duplicating member names") - - # Reset the parser so we can actually find things where we expect - # them in the list - parser = parser.reset() - - # Diamonds should be allowed - threw = False - try: - parser.parse(""" - P implements Q; - P implements R; - Q implements S; - R implements S; - interface Q {}; - interface R {}; - interface S { - attribute long x; - }; - interface P {}; - """) - results = parser.finish() - except: - threw = True - - harness.ok(not threw, "Diamond inheritance is fine") - harness.check(results[6].identifier.name, "S", "We should be looking at 'S'") - harness.check(len(results[6].members), 1, "S should have one member") - harness.check(results[6].members[0].identifier.name, "x", - "S's member should be 'x'") - - parser = parser.reset() - threw = False - try: - parser.parse(""" - interface TestInterface { - }; - callback interface TestCallbackInterface { - }; - TestInterface implements TestCallbackInterface; - """) - results = parser.finish() - except: - threw = True - - harness.ok(threw, - "Should not allow callback interfaces on the right-hand side " - "of 'implements'") - - parser = parser.reset() - threw = False - try: - parser.parse(""" - interface TestInterface { - }; - callback interface TestCallbackInterface { - }; - TestCallbackInterface implements TestInterface; - """) - results = parser.finish() - except: - threw = True - - harness.ok(threw, - "Should not allow callback interfaces on the left-hand side of " - "'implements'") - - parser = parser.reset() - threw = False - try: - parser.parse(""" - interface TestInterface { - }; - dictionary Dict { - }; - Dict implements TestInterface; - """) - results = parser.finish() - except: - threw = True - - harness.ok(threw, - "Should not allow non-interfaces on the left-hand side " - "of 'implements'") - - parser = parser.reset() - threw = False - try: - parser.parse(""" - interface TestInterface { - }; - dictionary Dict { - }; - TestInterface implements Dict; - """) - results = parser.finish() - except: - threw = True - - harness.ok(threw, - "Should not allow non-interfaces on the right-hand side " - "of 'implements'") - 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 28e6af94597..47db3ae4cc9 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_interface.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_interface.py @@ -80,100 +80,6 @@ def WebIDLTest(parser, harness): harness.ok(threw, "Should not allow indirect cycles in interface inheritance chains") - parser = parser.reset() - threw = False - try: - parser.parse(""" - interface A {}; - interface B {}; - A implements B; - B implements A; - """) - results = parser.finish() - except: - threw = True - - harness.ok(threw, "Should not allow cycles via implements") - - parser = parser.reset() - threw = False - try: - parser.parse(""" - interface A {}; - interface C {}; - interface B {}; - A implements C; - C implements B; - B implements A; - """) - results = parser.finish() - except: - threw = True - - harness.ok(threw, "Should not allow indirect cycles via implements") - - parser = parser.reset() - threw = False - try: - parser.parse(""" - interface A : B {}; - interface B {}; - B implements A; - """) - results = parser.finish() - except: - threw = True - - harness.ok(threw, "Should not allow inheriting from an interface that implements us") - - parser = parser.reset() - threw = False - try: - parser.parse(""" - interface A : B {}; - interface B {}; - interface C {}; - B implements C; - C implements A; - """) - results = parser.finish() - except: - threw = True - - harness.ok(threw, "Should not allow inheriting from an interface that indirectly implements us") - - parser = parser.reset() - threw = False - try: - parser.parse(""" - interface A : B {}; - interface B : C {}; - interface C {}; - C implements A; - """) - results = parser.finish() - except: - threw = True - - harness.ok(threw, "Should not allow indirectly inheriting from an interface that implements us") - - parser = parser.reset() - threw = False - try: - parser.parse(""" - interface A : B {}; - interface B : C {}; - interface C {}; - interface D {}; - C implements D; - D implements A; - """) - results = parser.finish() - except: - threw = True - - harness.ok(threw, "Should not allow indirectly inheriting from an interface that indirectly implements us") - parser = parser.reset() threw = False try: @@ -377,7 +283,7 @@ def WebIDLTest(parser, harness): parser = parser.reset() parser.parse(""" - [Global] interface Window {}; + [Global, Exposed=Window] interface Window {}; [Exposed=Window, LegacyWindowAlias=A] interface B {}; [Exposed=Window, LegacyWindowAlias=(C, D)] @@ -419,7 +325,8 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - [Global] interface Window {}; + [Global, Exposed=Window] interface Window {}; + [Exposed=Window] interface A {}; [Exposed=Window, LegacyWindowAlias=A] interface B {}; @@ -434,9 +341,10 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - [Global] interface Window {}; + [Global, Exposed=Window] interface Window {}; [Exposed=Window, LegacyWindowAlias=A] interface B {}; + [Exposed=Window] interface A {}; """) results = parser.finish() @@ -449,7 +357,7 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - [Global] interface Window {}; + [Global, Exposed=Window] interface Window {}; [Exposed=Window, LegacyWindowAlias=A] interface B {}; [Exposed=Window, LegacyWindowAlias=A] 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 5de2e02af7e..e070adee7e6 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 @@ -252,16 +252,6 @@ def WebIDLTest(parser, harness): }; """, mapRWMembers, numProductions=2) - shouldPass("Implements with maplike/setlike", - """ - interface Foo1 { - maplike; - }; - interface Foo2 { - }; - Foo2 implements Foo1; - """, mapRWMembers, numProductions=3) - shouldPass("JS Implemented maplike interface", """ [JSImplementation="@mozilla.org/dom/test-interface-js-maplike;1"] @@ -350,31 +340,6 @@ def WebIDLTest(parser, harness): }; """) - shouldFail("Consequential interface with conflicting maplike/setlike", - """ - interface Foo1 { - maplike; - }; - interface Foo2 { - setlike; - }; - Foo2 implements Foo1; - """) - - shouldFail("Consequential interfaces with conflicting maplike/setlike", - """ - interface Foo1 { - maplike; - }; - interface Foo2 { - setlike; - }; - interface Foo3 { - }; - Foo3 implements Foo1; - Foo3 implements Foo2; - """) - # # Member name collision tests # @@ -477,52 +442,28 @@ def WebIDLTest(parser, harness): }; """, mapRWMembers, numProductions=3) - shouldFail("Interface with consequential maplike/setlike interface member collision", - """ - interface Foo1 { - void entries(); - }; - interface Foo2 { - maplike; - }; - Foo1 implements Foo2; - """) - - shouldFail("Maplike interface with consequential interface member collision", + shouldFail("Maplike interface with mixin member collision", """ interface Foo1 { maplike; }; - interface Foo2 { + interface mixin Foo2 { void entries(); }; - Foo1 implements Foo2; + Foo1 includes Foo2; """) - shouldPass("Consequential Maplike interface with inherited interface member collision", - """ - interface Foo1 { - maplike; - }; - interface Foo2 { - void entries(); - }; - interface Foo3 : Foo2 { - }; - Foo3 implements Foo1; - """, mapRWMembers, numProductions=4) - shouldPass("Inherited Maplike interface with consequential interface member collision", """ interface Foo1 { maplike; }; - interface Foo2 { + interface mixin Foo2 { void entries(); }; interface Foo3 : Foo1 { }; - Foo3 implements Foo2; + Foo3 includes Foo2; """, mapRWMembers, numProductions=4) shouldFail("Inheritance of name collision with child maplike/setlike", @@ -645,7 +586,7 @@ def WebIDLTest(parser, harness): }; """) - shouldPass("Implemented interface with readonly allowable overrides", + shouldPass("Interface with readonly allowable overrides", """ interface Foo1 { readonly setlike; diff --git a/components/script/dom/bindings/codegen/parser/tests/test_interfacemixin.py b/components/script/dom/bindings/codegen/parser/tests/test_interfacemixin.py index ae3400d2cdb..477a9f37799 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_interfacemixin.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_interfacemixin.py @@ -337,10 +337,48 @@ def WebIDLTest(parser, harness): harness.ok(threw, "Should fail if an interface mixin includes maplike") + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Interface { + attribute short attr; + }; + interface mixin Mixin { + attribute short attr; + }; + Interface includes Mixin; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should fail if the included mixin interface has duplicated member") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Interface {}; + interface mixin Mixin1 { + attribute short attr; + }; + interface mixin Mixin2 { + attribute short attr; + }; + Interface includes Mixin1; + Interface includes Mixin2; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should fail if the included mixin interfaces have duplicated member") + parser = parser.reset() parser.parse(""" - [Global] interface Window {}; - [Global] interface Worker {}; + [Global, Exposed=Window] interface Window {}; + [Global, Exposed=Worker] interface Worker {}; [Exposed=Window] interface Base {}; interface mixin Mixin { @@ -356,8 +394,8 @@ def WebIDLTest(parser, harness): parser = parser.reset() parser.parse(""" - [Global] interface Window {}; - [Global] interface Worker {}; + [Global, Exposed=Window] interface Window {}; + [Global, Exposed=Worker] interface Worker {}; [Exposed=Window] interface Base {}; [Exposed=Window] @@ -371,3 +409,29 @@ def WebIDLTest(parser, harness): attr = base.members[0] harness.check(attr.exposureSet, set(["Window"]), "Should follow [Exposed] on interface mixin") + + parser = parser.reset() + parser.parse(""" + [Global, Exposed=Window] interface Window {}; + [Global, Exposed=Worker] interface Worker {}; + [Exposed=Window] + interface Base1 {}; + [Exposed=Worker] + interface Base2 {}; + interface mixin Mixin { + attribute short a; + }; + Base1 includes Mixin; + Base2 includes Mixin; + """) + results = parser.finish() + base = results[2] + attr = base.members[0] + harness.check(attr.exposureSet, set(["Window", "Worker"]), + "Should expose on all globals where including interfaces are " + "exposed") + base = results[3] + attr = base.members[0] + harness.check(attr.exposureSet, set(["Window", "Worker"]), + "Should expose on all globals where including interfaces are " + "exposed") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_securecontext_extended_attribute.py b/components/script/dom/bindings/codegen/parser/tests/test_securecontext_extended_attribute.py index 084f19fa7f5..442dba45d76 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_securecontext_extended_attribute.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_securecontext_extended_attribute.py @@ -288,33 +288,32 @@ def WebIDLTest(parser, harness): threw = True harness.ok(threw, "[SecureContext] must appear on interfaces that inherit from another [SecureContext] interface") - # Test 'implements'. The behavior tested here may have to change depending - # on the resolution of https://github.com/heycam/webidl/issues/118 + # Test 'includes'. parser = parser.reset() parser.parse(""" [SecureContext] - interface TestSecureContextInterfaceThatImplementsNonSecureContextInterface { + interface TestSecureContextInterfaceThatIncludesNonSecureContextMixin { const octet TEST_CONSTANT = 0; }; - interface TestNonSecureContextInterface { + interface mixin TestNonSecureContextMixin { const octet TEST_CONSTANT_2 = 0; readonly attribute byte testAttribute2; void testMethod2(byte foo); }; - TestSecureContextInterfaceThatImplementsNonSecureContextInterface implements TestNonSecureContextInterface; + TestSecureContextInterfaceThatIncludesNonSecureContextMixin includes TestNonSecureContextMixin; """) results = parser.finish() - harness.check(len(results[0].members), 4, "TestSecureContextInterfaceThatImplementsNonSecureContextInterface should have two members") + harness.check(len(results[0].members), 4, "TestSecureContextInterfaceThatImplementsNonSecureContextInterface should have four members") harness.ok(results[0].getExtendedAttribute("SecureContext"), "Interface should have [SecureContext] extended attribute") harness.ok(results[0].members[0].getExtendedAttribute("SecureContext"), "[SecureContext] should propagate from interface to constant members even when other members are copied from a non-[SecureContext] interface") harness.ok(results[0].members[1].getExtendedAttribute("SecureContext") is None, - "Constants copied from non-[SecureContext] interface should not be [SecureContext]") + "Constants copied from non-[SecureContext] mixin should not be [SecureContext]") harness.ok(results[0].members[2].getExtendedAttribute("SecureContext") is None, - "Attributes copied from non-[SecureContext] interface should not be [SecureContext]") + "Attributes copied from non-[SecureContext] mixin should not be [SecureContext]") harness.ok(results[0].members[3].getExtendedAttribute("SecureContext") is None, - "Methods copied from non-[SecureContext] interface should not be [SecureContext]") + "Methods copied from non-[SecureContext] mixin should not be [SecureContext]") # Test SecureContext and NoInterfaceObject parser = parser.reset() 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 44a168670ed..770a9d3736f 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_unforgeable.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_unforgeable.py @@ -141,16 +141,16 @@ def WebIDLTest(parser, harness): interface Child : Parent { }; interface Parent {}; - interface Consequential { + interface mixin Mixin { [Unforgeable] readonly attribute long foo; }; - Parent implements Consequential; + Parent includes Mixin; """) results = parser.finish() harness.check(len(results), 4, "Should be able to inherit from an interface with a " - "consequential interface with [Unforgeable] properties.") + "mixin with [Unforgeable] properties.") parser = parser.reset(); threw = False @@ -160,10 +160,10 @@ def WebIDLTest(parser, harness): void foo(); }; interface Parent {}; - interface Consequential { + interface mixin Mixin { [Unforgeable] readonly attribute long foo; }; - Parent implements Consequential; + Parent includes Mixin; """) results = parser.finish() @@ -182,14 +182,14 @@ def WebIDLTest(parser, harness): }; interface Parent : GrandParent {}; interface GrandParent {}; - interface Consequential { + interface mixin Mixin { [Unforgeable] readonly attribute long foo; }; - GrandParent implements Consequential; - interface ChildConsequential { + GrandParent includes Mixin; + interface mixin ChildMixin { void foo(); }; - Child implements ChildConsequential; + Child includes ChildMixin; """) results = parser.finish() @@ -208,14 +208,14 @@ def WebIDLTest(parser, harness): }; interface Parent : GrandParent {}; interface GrandParent {}; - interface Consequential { + interface mixin Mixin { [Unforgeable] void foo(); }; - GrandParent implements Consequential; - interface ChildConsequential { + GrandParent includes Mixin; + interface mixin ChildMixin { void foo(); }; - Child implements ChildConsequential; + Child includes ChildMixin; """) results = parser.finish() diff --git a/components/script/dom/bindings/codegen/parser/update.sh b/components/script/dom/bindings/codegen/parser/update.sh index 81b3d944a70..fee9720ab2d 100755 --- a/components/script/dom/bindings/codegen/parser/update.sh +++ b/components/script/dom/bindings/codegen/parser/update.sh @@ -1,11 +1,11 @@ -wget https://hg.mozilla.org/mozilla-central/raw-file/e447e3d69684cf04a95a35b9708174a6538eb042/dom/bindings/parser/WebIDL.py -O WebIDL.py +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 < callback-location.patch patch < union-typedef.patch patch < inline.patch -wget https://hg.mozilla.org/mozilla-central/archive/e447e3d69684cf04a95a35b9708174a6538eb042.tar.gz/dom/bindings/parser/tests/ -O tests.tar.gz +wget https://hg.mozilla.org/mozilla-central/archive/tip.tar.gz/dom/bindings/parser/tests/ -O tests.tar.gz rm -r tests mkdir tests tar xvpf tests.tar.gz -C tests --strip-components=5 -- cgit v1.2.3 From 764f1a3724aa73755e6021aeddbba8a465b32423 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Sat, 12 Oct 2019 18:57:05 +0900 Subject: Return false when GetPropertyKeys fails --- components/script/dom/bindings/codegen/CodegenRust.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 103450f78f3..b9b86a45a91 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -5269,8 +5269,9 @@ class CGDOMJSProxyHandler_ownPropertyKeys(CGAbstractExternMethod): """ rooted!(in(*cx) let mut expando = ptr::null_mut::()); get_expando_object(proxy, expando.handle_mut()); - if !expando.is_null() { - GetPropertyKeys(*cx, expando.handle(), JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props); + if !expando.is_null() && + !GetPropertyKeys(*cx, expando.handle(), JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props) { + return false; } return true; @@ -5314,8 +5315,9 @@ class CGDOMJSProxyHandler_getOwnEnumerablePropertyKeys(CGAbstractExternMethod): """ rooted!(in(*cx) let mut expando = ptr::null_mut::()); get_expando_object(proxy, expando.handle_mut()); - if !expando.is_null() { - GetPropertyKeys(*cx, expando.handle(), JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props); + if !expando.is_null() && + !GetPropertyKeys(*cx, expando.handle(), JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props) { + return false; } return true; -- cgit v1.2.3 From b697621b05d5c0b741d377637cb9c16ef31986b9 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Tue, 15 Oct 2019 17:14:00 +0900 Subject: Support WebIDL `record<>` --- .../script/dom/bindings/codegen/CodegenRust.py | 37 ++++++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 103450f78f3..01b7fc698ba 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -77,14 +77,13 @@ def innerContainerType(type): def wrapInNativeContainerType(type, inner): if type.isSequence(): - containerType = "Vec" + return CGWrapper(inner, pre="Vec<", post=">") elif type.isRecord(): - containerType = "MozMap" + key = type.inner.keyType if type.nullable() else type.keyType + return CGRecord(key, inner) else: raise TypeError("Unexpected container type %s", type) - return CGWrapper(inner, pre=containerType + "<", post=">") - builtinNames = { IDLType.Tags.bool: 'bool', @@ -1905,6 +1904,30 @@ class CGWrapper(CGThing): return self.pre + defn + self.post +class CGRecord(CGThing): + """ + CGThing that wraps value CGThing in record with key type equal to keyType parameter + """ + def __init__(self, keyType, value): + CGThing.__init__(self) + assert keyType.isString() + self.keyType = keyType + self.value = value + + def define(self): + if self.keyType.isByteString(): + keyDef = "ByteString" + elif self.keyType.isDOMString(): + keyDef = "DOMString" + elif self.keyType.isUSVString(): + keyDef = "USVString" + else: + assert False + + defn = keyDef + ", " + self.value.define() + return "Record<" + defn + ">" + + class CGImports(CGWrapper): """ Generates the appropriate import/use statements. @@ -2024,7 +2047,7 @@ class CGImports(CGWrapper): extras += [descriptor.path, descriptor.bindingPath] parentName = descriptor.getParentName() elif t.isType() and t.isRecord(): - extras += ['crate::dom::bindings::mozmap::MozMap'] + extras += ['crate::dom::bindings::record::Record'] elif isinstance(t, IDLPromiseType): extras += ['crate::dom::promise::Promise'] else: @@ -2373,7 +2396,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config): 'crate::dom::bindings::conversions::StringificationBehavior', 'crate::dom::bindings::conversions::root_from_handlevalue', 'std::ptr::NonNull', - 'crate::dom::bindings::mozmap::MozMap', + 'crate::dom::bindings::record::Record', 'crate::dom::bindings::num::Finite', 'crate::dom::bindings::root::DomRoot', 'crate::dom::bindings::str::ByteString', @@ -6054,7 +6077,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'crate::dom::bindings::proxyhandler::ensure_expando_object', 'crate::dom::bindings::proxyhandler::fill_property_descriptor', 'crate::dom::bindings::proxyhandler::get_expando_object', - 'crate::dom::bindings::mozmap::MozMap', + 'crate::dom::bindings::record::Record', 'std::ptr::NonNull', 'crate::dom::bindings::num::Finite', 'crate::dom::bindings::str::ByteString', -- cgit v1.2.3 From e905a4606a089055be0f87afb62c1f4ccf2961c3 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Thu, 17 Oct 2019 12:06:41 +0900 Subject: Support USVString as default value of a union argument --- components/script/dom/bindings/codegen/CodegenRust.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 01b7fc698ba..5a6c453e0ce 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -732,6 +732,10 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, default = "%s::Boolean(%s)" % ( union_native_type(type), "true" if defaultValue.value else "false") + elif tag is IDLType.Tags.usvstring: + default = '%s::USVString(USVString("%s".to_owned()))' % ( + union_native_type(type), + defaultValue.value) else: raise("We don't currently support default values that aren't null, boolean or default dictionary") elif dictionaries: -- cgit v1.2.3 From 1c717bc086c7f464c743a8f054461b8c88b03444 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Thu, 17 Oct 2019 20:35:21 +0900 Subject: Mark @@iterator as nonenumerable --- .../script/dom/bindings/codegen/CodegenRust.py | 23 ++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 01b7fc698ba..fe436940e13 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1633,6 +1633,7 @@ class MethodDefiner(PropertyDefiner): self.regular = [{"name": m.identifier.name, "methodInfo": not m.isStatic(), "length": methodLength(m), + "flags": "JSPROP_ENUMERATE", "condition": PropertyDefiner.getControllingCondition(m, descriptor)} for m in methods] @@ -1642,6 +1643,7 @@ class MethodDefiner(PropertyDefiner): "methodInfo": False, "selfHostedName": "ArrayValues", "length": 0, + "flags": "0", # Not enumerable, per spec. "condition": "Condition::Satisfied"}) # Generate the keys/values/entries aliases for value iterables. @@ -1656,6 +1658,7 @@ class MethodDefiner(PropertyDefiner): "methodInfo": False, "selfHostedName": "ArrayKeys", "length": 0, + "flags": "JSPROP_ENUMERATE", "condition": PropertyDefiner.getControllingCondition(m, descriptor) }) @@ -1664,6 +1667,7 @@ class MethodDefiner(PropertyDefiner): "methodInfo": False, "selfHostedName": "ArrayValues", "length": 0, + "flags": "JSPROP_ENUMERATE", "condition": PropertyDefiner.getControllingCondition(m, descriptor) }) @@ -1672,6 +1676,7 @@ class MethodDefiner(PropertyDefiner): "methodInfo": False, "selfHostedName": "ArrayEntries", "length": 0, + "flags": "JSPROP_ENUMERATE", "condition": PropertyDefiner.getControllingCondition(m, descriptor) }) @@ -1680,6 +1685,7 @@ class MethodDefiner(PropertyDefiner): "methodInfo": False, "selfHostedName": "ArrayForEach", "length": 1, + "flags": "JSPROP_ENUMERATE", "condition": PropertyDefiner.getControllingCondition(m, descriptor) }) @@ -1692,6 +1698,7 @@ class MethodDefiner(PropertyDefiner): "name": "toString", "nativeName": stringifier.identifier.name, "length": 0, + "flags": "JSPROP_ENUMERATE", "condition": PropertyDefiner.getControllingCondition(stringifier, descriptor) }) self.unforgeable = unforgeable @@ -1703,13 +1710,10 @@ class MethodDefiner(PropertyDefiner): def condition(m, d): return m["condition"] - flags = "JSPROP_ENUMERATE" - if self.unforgeable: - flags += " | JSPROP_PERMANENT | JSPROP_READONLY" - def specData(m): - # TODO: Use something like JS_FNSPEC - # https://github.com/servo/servo/issues/6391 + flags = m["flags"] + if self.unforgeable: + flags += " | JSPROP_PERMANENT | JSPROP_READONLY" if "selfHostedName" in m: selfHostedName = '%s as *const u8 as *const libc::c_char' % str_to_const_array(m["selfHostedName"]) assert not m.get("methodInfo", True) @@ -3071,12 +3075,14 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); symbolJSID=symbolJSID)) defineFn = "JS_DefinePropertyById2" prop = "iteratorId.handle()" + enumFlags = "0" # Not enumerable, per spec. elif alias.startswith("@@"): raise TypeError("Can't handle any well-known Symbol other than @@iterator") else: getSymbolJSID = None defineFn = "JS_DefineProperty" prop = '"%s"' % alias + enumFlags = "JSPROP_ENUMERATE" return CGList([ getSymbolJSID, # XXX If we ever create non-enumerable properties that can @@ -3085,10 +3091,11 @@ assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null()); CGGeneric(fill( """ assert!(${defineFn}(*cx, prototype.handle(), ${prop}, aliasedVal.handle(), - JSPROP_ENUMERATE as u32)); + ${enumFlags} as u32)); """, defineFn=defineFn, - prop=prop)) + prop=prop, + enumFlags=enumFlags)) ], "\n") def defineAliasesFor(m): -- cgit v1.2.3 From e81b6786457b076a06c945835a3080fa33fa81ca Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Thu, 17 Oct 2019 19:41:47 +0900 Subject: Support [LegacyWindowAlias] --- .../script/dom/bindings/codegen/CodegenRust.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index ad76ef5d8d3..a644e352e7a 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2925,13 +2925,14 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): properties should be a PropertyArrays instance. """ - def __init__(self, descriptor, properties, haveUnscopables): + def __init__(self, descriptor, properties, haveUnscopables, haveLegacyWindowAliases): args = [Argument('SafeJSContext', 'cx'), Argument('HandleObject', 'global'), Argument('*mut ProtoOrIfaceArray', 'cache')] CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'void', args, unsafe=True) self.properties = properties self.haveUnscopables = haveUnscopables + self.haveLegacyWindowAliases = haveLegacyWindowAliases def definition_body(self): name = self.descriptor.interface.identifier.name @@ -2990,7 +2991,8 @@ assert!(!prototype_proto.is_null());""" % getPrototypeProto)] properties = { "id": name, - "unscopables": "unscopable_names" if self.haveUnscopables else "&[]" + "unscopables": "unscopable_names" if self.haveUnscopables else "&[]", + "legacyWindowAliases": "legacy_window_aliases" if self.haveLegacyWindowAliases else "&[]" } for arrayName in self.properties.arrayNames(): array = getattr(self.properties, arrayName) @@ -3058,6 +3060,7 @@ create_noncallback_interface_object(cx, prototype.handle(), %(name)s, %(length)s, + %(legacyWindowAliases)s, interface.handle_mut()); assert!(!interface.is_null());""" % properties)) if self.descriptor.shouldCacheConstructor(): @@ -6266,6 +6269,15 @@ class CGDescriptor(CGThing): if descriptor.weakReferenceable: cgThings.append(CGWeakReferenceableTrait(descriptor)) + legacyWindowAliases = descriptor.interface.legacyWindowAliases + haveLegacyWindowAliases = len(legacyWindowAliases) != 0 + if haveLegacyWindowAliases: + cgThings.append( + CGList([CGGeneric("const legacy_window_aliases: &'static [&'static [u8]] = &["), + CGIndenter(CGList([CGGeneric(str_to_const_array(name)) for + name in legacyWindowAliases], ",\n")), + CGGeneric("];\n")], "\n")) + cgThings.append(CGGeneric(str(properties))) if not descriptor.interface.getExtendedAttribute("Inline"): @@ -6287,7 +6299,8 @@ class CGDescriptor(CGThing): cgThings.append(CGDefineDOMInterfaceMethod(descriptor)) reexports.append('DefineDOMInterface') cgThings.append(CGConstructorEnabled(descriptor)) - cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties, haveUnscopables)) + cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties, haveUnscopables, + haveLegacyWindowAliases)) cgThings = generate_imports(config, CGList(cgThings, '\n'), [descriptor]) cgThings = CGWrapper(CGNamespace(toBindingNamespace(descriptor.name), @@ -7453,6 +7466,8 @@ class GlobalGenRoots(): for d in config.getDescriptors(hasInterfaceObject=True, isInline=False): binding = toBindingNamespace(d.name) pairs.append((d.name, binding, binding)) + for alias in d.interface.legacyWindowAliases: + pairs.append((alias, binding, binding)) for ctor in d.interface.namedConstructors: pairs.append((ctor.identifier.name, binding, binding)) pairs.sort(key=operator.itemgetter(0)) -- cgit v1.2.3 From 40ee701283310a505770023594f1f9d64b31e2a2 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Thu, 17 Oct 2019 16:10:39 +0900 Subject: Support enum value as a union default value --- .../script/dom/bindings/codegen/CodegenRust.py | 31 +++++++++++++++------- 1 file changed, 21 insertions(+), 10 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index ad76ef5d8d3..6e75460559e 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -736,6 +736,13 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, default = '%s::USVString(USVString("%s".to_owned()))' % ( union_native_type(type), defaultValue.value) + elif defaultValue.type.isEnum(): + enum = defaultValue.type.inner.identifier.name + default = "%s::%s(%s::%s)" % ( + union_native_type(type), + enum, + enum, + getEnumValueName(defaultValue.value)) else: raise("We don't currently support default values that aren't null, boolean or default dictionary") elif dictionaries: @@ -2373,20 +2380,19 @@ def getAllTypes(descriptors, dictionaries, callbacks, typedefs): """ Generate all the types we're dealing with. For each type, a tuple containing type, descriptor, dictionary is yielded. The - descriptor and dictionary can be None if the type does not come - from a descriptor or dictionary; they will never both be non-None. + descriptor can be None if the type does not come from a descriptor. """ for d in descriptors: for t in getTypesFromDescriptor(d): - yield (t, d, None) + yield (t, d) for dictionary in dictionaries: for t in getTypesFromDictionary(dictionary): - yield (t, None, dictionary) + yield (t, None) for callback in callbacks: for t in getTypesFromCallback(callback): - yield (t, None, None) + yield (t, None) for typedef in typedefs: - yield (typedef.innerType, None, None) + yield (typedef.innerType, None) def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config): @@ -2411,6 +2417,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config): 'crate::dom::bindings::str::DOMString', 'crate::dom::bindings::str::USVString', 'crate::dom::bindings::trace::RootedTraceableBox', + 'crate::dom::bindings::utils::find_enum_value', 'crate::dom::types::*', 'crate::script_runtime::JSContext as SafeJSContext', 'js::error::throw_type_error', @@ -2426,13 +2433,17 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config): # Now find all the things we'll need as arguments and return values because # we need to wrap or unwrap them. unionStructs = dict() - for (t, descriptor, dictionary) in getAllTypes(descriptors, dictionaries, callbacks, typedefs): - if dictionary: - imports.append("%s::%s" % (CGDictionary.makeModuleName(dictionary), - CGDictionary.makeDictionaryName(dictionary))) + for (t, descriptor) in getAllTypes(descriptors, dictionaries, callbacks, typedefs): t = t.unroll() if not t.isUnion(): continue + for memberType in t.flatMemberTypes: + if memberType.isDictionary() or memberType.isEnum(): + memberModule = getModuleFromObject(memberType) + memberName = memberType.inner.identifier.name + imports.append("%s::%s" % (memberModule, memberName)) + if memberType.isEnum(): + imports.append("%s::%sValues" % (memberModule, memberName)) name = str(t) if name not in unionStructs: provider = descriptor or config.getDescriptorProvider() -- cgit v1.2.3 From 2f8932a6a1e2666567435114383b3acd1899aca7 Mon Sep 17 00:00:00 2001 From: Gregory Terzian Date: Wed, 26 Jun 2019 00:25:48 +0800 Subject: continue messageport, transferable, postmessage options --- components/script/dom/bindings/codegen/Bindings.conf | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf index e3de60005bc..3ff7a044b53 100644 --- a/components/script/dom/bindings/codegen/Bindings.conf +++ b/components/script/dom/bindings/codegen/Bindings.conf @@ -30,6 +30,10 @@ DOMInterfaces = { 'weakReferenceable': True, }, +'MessagePort': { + 'weakReferenceable': True, +}, + #FIXME(jdm): This should be 'register': False, but then we don't generate enum types 'TestBinding': { 'inCompartments': ['PromiseAttribute', 'PromiseNativeHandler'], -- cgit v1.2.3 From e271edad927c6cfb304e9df8719d7ed5fe0309f9 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Sat, 19 Oct 2019 20:26:20 +0900 Subject: Convert [HTMLConstructor] as constructor extension --- .../script/dom/bindings/codegen/Configuration.py | 8 +- .../script/dom/bindings/codegen/parser/WebIDL.py | 199 +++++++++++---------- .../codegen/parser/tests/test_constructor.py | 22 +-- .../parser/tests/test_constructor_global.py | 18 +- .../tests/test_constructor_no_interface_object.py | 19 +- 5 files changed, 121 insertions(+), 145 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/Configuration.py b/components/script/dom/bindings/codegen/Configuration.py index 1d50c3ed4f7..71c988e5378 100644 --- a/components/script/dom/bindings/codegen/Configuration.py +++ b/components/script/dom/bindings/codegen/Configuration.py @@ -392,15 +392,19 @@ class Descriptor(DescriptorProvider): return (self.interface.getUserData("hasConcreteDescendant", False) or self.interface.getUserData("hasProxyDescendant", False)) + def hasHTMLConstructor(self): + ctor = self.interface.ctor() + return ctor and ctor.isHTMLConstructor() + def shouldHaveGetConstructorObjectMethod(self): assert self.interface.hasInterfaceObject() if self.interface.getExtendedAttribute("Inline"): return False return (self.interface.isCallback() or self.interface.isNamespace() or - self.hasDescendants() or self.interface.getExtendedAttribute("HTMLConstructor")) + self.hasDescendants() or self.hasHTMLConstructor()) def shouldCacheConstructor(self): - return self.hasDescendants() or self.interface.getExtendedAttribute("HTMLConstructor") + return self.hasDescendants() or self.hasHTMLConstructor() def isExposedConditionally(self): return self.interface.isExposedConditionally() diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index a36b1b3ecfe..215d9c1212f 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.py @@ -1084,18 +1084,11 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): "Can't have both a constructor and [Global]", [self.location, ctor.location]) - assert(len(ctor._exposureGlobalNames) == 0 or - ctor._exposureGlobalNames == self._exposureGlobalNames) + assert(ctor._exposureGlobalNames == self._exposureGlobalNames) ctor._exposureGlobalNames.update(self._exposureGlobalNames) - if ctor in self.members: - # constructor operation. - self.members.remove(ctor) - else: - # extended attribute. This can only happen with - # [HTMLConstructor] and this is the only way we can get into this - # code with len(ctor._exposureGlobalNames) != - # self._exposureGlobalNames. - ctor.finish(scope) + # Remove the constructor operation from our member list so + # it doesn't get in the way later. + self.members.remove(ctor) for ctor in self.namedConstructors: if self.globalNames: @@ -1653,60 +1646,45 @@ class IDLInterface(IDLInterfaceOrNamespace): [attr.location]) self._noInterfaceObject = True - elif identifier == "NamedConstructor" or identifier == "HTMLConstructor": - if identifier == "NamedConstructor" and not attr.hasValue(): + elif identifier == "NamedConstructor": + if not attr.hasValue(): raise WebIDLError("NamedConstructor must either take an identifier or take a named argument list", [attr.location]) - if identifier == "HTMLConstructor": - if not attr.noArguments(): - raise WebIDLError(str(identifier) + " must take no arguments", - [attr.location]) args = attr.args() if attr.hasArgs() else [] retType = IDLWrapperType(self.location, self) - if identifier == "HTMLConstructor": - name = "constructor" - allowForbidden = True - else: - name = attr.value() - allowForbidden = False - - method = IDLConstructor( - attr.location, args, name, - htmlConstructor=(identifier == "HTMLConstructor")) + method = IDLConstructor(attr.location, args, attr.value()) method.reallyInit(self) - # Are always assumed to be able to throw (since there's no way to - # indicate otherwise). + # Named constructors are always assumed to be able to + # throw (since there's no way to indicate otherwise). method.addExtendedAttributes( [IDLExtendedAttribute(self.location, ("Throws",))]) - if identifier == "HTMLConstructor": - method.resolve(self) - else: - # We need to detect conflicts for NamedConstructors across - # interfaces. We first call resolve on the parentScope, - # which will merge all NamedConstructors with the same - # identifier accross interfaces as overloads. - method.resolve(self.parentScope) - - # Then we look up the identifier on the parentScope. If the - # result is the same as the method we're adding then it - # hasn't been added as an overload and it's the first time - # we've encountered a NamedConstructor with that identifier. - # If the result is not the same as the method we're adding - # then it has been added as an overload and we need to check - # whether the result is actually one of our existing - # NamedConstructors. - newMethod = self.parentScope.lookupIdentifier(method.identifier) - if newMethod == method: - self.namedConstructors.append(method) - elif newMethod not in self.namedConstructors: - raise WebIDLError("NamedConstructor conflicts with a NamedConstructor of a different interface", - [method.location, newMethod.location]) + # We need to detect conflicts for NamedConstructors across + # interfaces. We first call resolve on the parentScope, + # which will merge all NamedConstructors with the same + # identifier accross interfaces as overloads. + method.resolve(self.parentScope) + + # Then we look up the identifier on the parentScope. If the + # result is the same as the method we're adding then it + # hasn't been added as an overload and it's the first time + # we've encountered a NamedConstructor with that identifier. + # If the result is not the same as the method we're adding + # then it has been added as an overload and we need to check + # whether the result is actually one of our existing + # NamedConstructors. + newMethod = self.parentScope.lookupIdentifier(method.identifier) + if newMethod == method: + self.namedConstructors.append(method) + elif newMethod not in self.namedConstructors: + raise WebIDLError("NamedConstructor conflicts with a " + "NamedConstructor of a different interface", + [method.location, newMethod.location]) elif (identifier == "ExceptionClass"): if not attr.noArguments(): raise WebIDLError("[ExceptionClass] must take no arguments", @@ -1777,6 +1755,11 @@ class IDLInterface(IDLInterfaceOrNamespace): if not attr.hasValue(): raise WebIDLError("[%s] must have a value" % identifier, [attr.location]) + elif identifier == "InstrumentedProps": + # Known extended attributes that take a list + if not attr.hasArgs(): + raise WebIDLError("[%s] must have arguments" % identifier, + [attr.location]) else: raise WebIDLError("Unknown extended attribute %s on interface" % identifier, [attr.location]) @@ -4884,7 +4867,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope): static=False, getter=False, setter=False, deleter=False, specialType=NamedOrIndexed.Neither, legacycaller=False, stringifier=False, - maplikeOrSetlikeOrIterable=None, htmlConstructor=False): + maplikeOrSetlikeOrIterable=None): # REVIEW: specialType is NamedOrIndexed -- wow, this is messed up. IDLInterfaceMember.__init__(self, location, identifier, IDLInterfaceMember.Tags.Method) @@ -4910,10 +4893,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope): self._stringifier = stringifier assert maplikeOrSetlikeOrIterable is None or isinstance(maplikeOrSetlikeOrIterable, IDLMaplikeOrSetlikeOrIterableBase) self.maplikeOrSetlikeOrIterable = maplikeOrSetlikeOrIterable - assert isinstance(htmlConstructor, bool) - # The identifier of a HTMLConstructor must be 'constructor'. - assert not htmlConstructor or identifier.name == "constructor" - self._htmlConstructor = htmlConstructor + self._htmlConstructor = False self._specialType = specialType self._unforgeable = False self.dependsOn = "Everything" @@ -5408,14 +5388,13 @@ class IDLMethod(IDLInterfaceMember, IDLScope): class IDLConstructor(IDLMethod): - def __init__(self, location, args, name, htmlConstructor=False): + def __init__(self, location, args, name): # We can't actually init our IDLMethod yet, because we do not know the # return type yet. Just save the info we have for now and we will init # it later. self._initLocation = location self._initArgs = args self._initName = name - self._htmlConstructor = htmlConstructor self._inited = False self._initExtendedAttrs = [] @@ -5432,6 +5411,18 @@ class IDLConstructor(IDLMethod): identifier == "SecureContext" or identifier == "Throws"): IDLMethod.handleExtendedAttribute(self, attr) + elif identifier == "HTMLConstructor": + if not attr.noArguments(): + raise WebIDLError("[HTMLConstructor] must take no arguments", + [attr.location]) + # We shouldn't end up here for named constructors. + assert(self.identifier.name == "constructor") + + if any(len(sig[1]) != 0 for sig in self.signatures()): + raise WebIDLError("[HTMLConstructor] must not be applied to a " + "constructor operation that has arguments.", + [attr.location]) + self._htmlConstructor = True else: raise WebIDLError("Unknown extended attribute %s on method" % identifier, [attr.location]) @@ -5442,7 +5433,7 @@ class IDLConstructor(IDLMethod): identifier = IDLUnresolvedIdentifier(location, name, allowForbidden=True) retType = IDLWrapperType(parentInterface.location, parentInterface) IDLMethod.__init__(self, location, identifier, retType, self._initArgs, - static=True, htmlConstructor=self._htmlConstructor) + static=True) self._inited = True; # Propagate through whatever extended attributes we already had self.addExtendedAttributes(self._initExtendedAttrs) @@ -5660,6 +5651,8 @@ class Tokenizer(object): "namespace": "NAMESPACE", "ReadableStream": "READABLESTREAM", "constructor": "CONSTRUCTOR", + "symbol": "SYMBOL", + "async": "ASYNC", } tokens.extend(keywords.values()) @@ -6746,37 +6739,54 @@ class Parser(Tokenizer): def p_ArgumentName(self, p): """ ArgumentName : IDENTIFIER - | ATTRIBUTE - | CALLBACK - | CONST - | CONSTRUCTOR - | DELETER - | DICTIONARY - | ENUM - | EXCEPTION - | GETTER - | INHERIT - | INTERFACE - | ITERABLE - | LEGACYCALLER - | MAPLIKE - | PARTIAL - | REQUIRED - | SERIALIZER - | SETLIKE - | SETTER - | STATIC - | STRINGIFIER - | TYPEDEF - | UNRESTRICTED - | NAMESPACE + | ArgumentNameKeyword + """ + p[0] = p[1] + + def p_ArgumentNameKeyword(self, p): + """ + ArgumentNameKeyword : ASYNC + | ATTRIBUTE + | CALLBACK + | CONST + | CONSTRUCTOR + | DELETER + | DICTIONARY + | ENUM + | EXCEPTION + | GETTER + | INCLUDES + | INHERIT + | INTERFACE + | ITERABLE + | LEGACYCALLER + | MAPLIKE + | MIXIN + | NAMESPACE + | PARTIAL + | READONLY + | REQUIRED + | SERIALIZER + | SETLIKE + | SETTER + | STATIC + | STRINGIFIER + | TYPEDEF + | UNRESTRICTED """ p[0] = p[1] def p_AttributeName(self, p): """ AttributeName : IDENTIFIER - | REQUIRED + | AttributeNameKeyword + """ + p[0] = p[1] + + def p_AttributeNameKeyword(self, p): + """ + AttributeNameKeyword : ASYNC + | REQUIRED """ p[0] = p[1] @@ -6868,36 +6878,27 @@ class Parser(Tokenizer): | BYTESTRING | USVSTRING | JSSTRING + | PROMISE | ANY - | ATTRIBUTE | BOOLEAN | BYTE - | LEGACYCALLER - | CONST - | CONSTRUCTOR - | DELETER | DOUBLE - | EXCEPTION | FALSE | FLOAT - | GETTER - | INHERIT - | INTERFACE | LONG | NULL | OBJECT | OCTET + | OR | OPTIONAL - | SEQUENCE | RECORD - | SETTER + | SEQUENCE | SHORT - | STATIC - | STRINGIFIER + | SYMBOL | TRUE - | TYPEDEF | UNSIGNED | VOID + | ArgumentNameKeyword """ pass diff --git a/components/script/dom/bindings/codegen/parser/tests/test_constructor.py b/components/script/dom/bindings/codegen/parser/tests/test_constructor.py index 20eb152cdab..721f9c2089e 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_constructor.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_constructor.py @@ -105,8 +105,8 @@ def WebIDLTest(parser, harness): parser = parser.reset() parser.parse(""" - [HTMLConstructor] interface TestHTMLConstructor { + [HTMLConstructor] constructor(); }; """) results = parser.finish() @@ -138,8 +138,8 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - [HTMLConstructor(DOMString a)] interface TestHTMLConstructorWithArgs { + [HTMLConstructor] constructor(DOMString a); }; """) results = parser.finish() @@ -153,8 +153,8 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - [HTMLConstructor] callback interface TestHTMLConstructorOnCallbackInterface { + [HTMLConstructor] constructor(); }; """) results = parser.finish() @@ -168,9 +168,9 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - [HTMLConstructor] interface TestHTMLConstructorAndConstructor { constructor(); + [HTMLConstructor] constructor(); }; """) results = parser.finish() @@ -183,10 +183,10 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - [HTMLConstructor] interface TestHTMLConstructorAndConstructor { [Throws] constructor(); + [HTMLConstructor] constructor(); }; """) results = parser.finish() @@ -200,9 +200,9 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - [HTMLConstructor] interface TestHTMLConstructorAndConstructor { constructor(DOMString a); + [HTMLConstructor] constructor(); }; """) results = parser.finish() @@ -216,10 +216,10 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - [HTMLConstructor] interface TestHTMLConstructorAndConstructor { [Throws] constructor(DOMString a); + [HTMLConstructor] constructor(); }; """) results = parser.finish() @@ -235,10 +235,10 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - [HTMLConstructor] interface TestHTMLConstructorAndConstructor { [ChromeOnly] constructor(); + [HTMLConstructor] constructor(); }; """) results = parser.finish() @@ -252,10 +252,10 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - [HTMLConstructor] interface TestHTMLConstructorAndConstructor { [Throws, ChromeOnly] constructor(); + [HTMLConstructor] constructor(); }; """) results = parser.finish() @@ -270,10 +270,10 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - [HTMLConstructor] interface TestHTMLConstructorAndConstructor { [ChromeOnly] constructor(DOMString a); + [HTMLConstructor] constructor(); }; """) results = parser.finish() @@ -288,10 +288,10 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - [HTMLConstructor] interface TestHTMLConstructorAndConstructor { [Throws, ChromeOnly] constructor(DOMString a); + [HTMLConstructor] constructor(); }; """) results = parser.finish() 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 index 31c5d95317f..b7eabb1e35b 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_constructor_global.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_constructor_global.py @@ -50,23 +50,9 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - [Global, HTMLConstructor, Exposed=TestHTMLConstructorGlobal] - interface TestHTMLConstructorGlobal { - }; - """) - - results = parser.finish() - except: - threw = True - - harness.ok(threw, "Should have thrown.") - - parser = parser.reset() - threw = False - try: - parser.parse(""" - [HTMLConstructor, Global, Exposed=TestHTMLConstructorGlobal] + [Global, Exposed=TestHTMLConstructorGlobal] interface TestHTMLConstructorGlobal { + [HTMLConstructor] constructor(); }; """) 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 d4175094911..24cc36066cd 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 @@ -28,24 +28,9 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - [NoInterfaceObject, HTMLConstructor] - interface TestHTMLConstructorNoInterfaceObject { - }; - """) - - results = parser.finish() - except: - threw = True - - harness.ok(threw, "Should have thrown.") - - parser = parser.reset() - - threw = False - try: - parser.parse(""" - [HTMLConstructor, NoInterfaceObject] + [NoInterfaceObject] interface TestHTMLConstructorNoInterfaceObject { + [HTMLConstructor] constructor(); }; """) -- cgit v1.2.3 From 97c01fc4792c6bc0edd2d588470f38a7f02d9661 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Fri, 25 Oct 2019 17:05:49 +0900 Subject: Update WebIDL.py --- .../script/dom/bindings/codegen/parser/WebIDL.py | 78 ++++++++++++++-- .../codegen/parser/tests/test_stringifier.py | 100 +++++++++++++++++++++ 2 files changed, 172 insertions(+), 6 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index 215d9c1212f..b2e56c9deaf 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.py @@ -760,6 +760,8 @@ class IDLInterfaceOrInterfaceMixinOrNamespace(IDLObjectWithScope, IDLExposureMix # specified, it already has a nonempty exposure global names set. if len(m._exposureGlobalNames) == 0: m._exposureGlobalNames.update(self._exposureGlobalNames) + if m.isAttr() and m.stringifier: + m.expand(self.members) # resolve() will modify self.members, so we need to iterate # over a copy of the member list here. @@ -1855,6 +1857,9 @@ class IDLDictionary(IDLObjectWithScope): self._finished = False self.members = list(members) self._partialDictionaries = [] + self._extendedAttrDict = {} + self.needsConversionToJS = False + self.needsConversionFromJS = False IDLObjectWithScope.__init__(self, location, parentScope, name) @@ -1988,11 +1993,34 @@ class IDLDictionary(IDLObjectWithScope): self.identifier.name, [member.location] + locations) + def getExtendedAttribute(self, name): + return self._extendedAttrDict.get(name, None) + def addExtendedAttributes(self, attrs): - if len(attrs) != 0: - raise WebIDLError("There are no extended attributes that are " - "allowed on dictionaries", - [attrs[0].location, self.location]) + for attr in attrs: + identifier = attr.identifier() + + if (identifier == "GenerateInitFromJSON" or + identifier == "GenerateInit"): + if not attr.noArguments(): + raise WebIDLError("[%s] must not have arguments" % identifier, + [attr.location]) + self.needsConversionFromJS = True + elif (identifier == "GenerateConversionToJS" or + identifier == "GenerateToJSON"): + if not attr.noArguments(): + raise WebIDLError("[%s] must not have arguments" % identifier, + [attr.location]) + # ToJSON methods require to-JS conversion, because we + # implement ToJSON by converting to a JS object and + # then using JSON.stringify. + self.needsConversionToJS = True + else: + raise WebIDLError("[%s] extended attribute not allowed on " + "dictionaries" % identifier, + [attr.location]) + + self._extendedAttrDict[identifier] = True def _getDependentObjects(self): deps = set(self.members) @@ -2004,6 +2032,7 @@ class IDLDictionary(IDLObjectWithScope): assert self.identifier.name == partial.identifier.name self._partialDictionaries.append(partial) + class IDLEnum(IDLObjectWithIdentifier): def __init__(self, location, parentScope, name, values): assert isinstance(parentScope, IDLScope) @@ -4622,6 +4651,40 @@ class IDLAttribute(IDLInterfaceMember): def _getDependentObjects(self): return set([self.type]) + def expand(self, members): + assert self.stringifier + if not self.type.isDOMString() and not self.type.isUSVString(): + raise WebIDLError("The type of a stringifer attribute must be " + "either DOMString or USVString", + [self.location]) + identifier = IDLUnresolvedIdentifier(self.location, "__stringifier", + allowDoubleUnderscore=True) + method = IDLMethod(self.location, + identifier, + returnType=self.type, arguments=[], + stringifier=True, underlyingAttr=self) + allowedExtAttrs = ["Throws", "NeedsSubjectPrincipal", "Pure"] + # Safe to ignore these as they are only meaningful for attributes + attributeOnlyExtAttrs = [ + "CEReactions", + "CrossOriginWritable", + "SetterThrows", + ] + for (key, value) in self._extendedAttrDict.items(): + if key in allowedExtAttrs: + if value is not True: + raise WebIDLError("[%s] with a value is currently " + "unsupported in stringifier attributes, " + "please file a bug to add support" % key, + [self.location]) + method.addExtendedAttributes([IDLExtendedAttribute(self.location, (key,))]) + elif not key in attributeOnlyExtAttrs: + raise WebIDLError("[%s] is currently unsupported in " + "stringifier attributes, please file a bug " + "to add support" % key, + [self.location]) + members.append(method) + class IDLArgument(IDLObjectWithIdentifier): def __init__(self, location, identifier, type, optional=False, defaultValue=None, variadic=False, dictionaryMember=False, allowTypeAttributes=False): @@ -4867,7 +4930,8 @@ class IDLMethod(IDLInterfaceMember, IDLScope): static=False, getter=False, setter=False, deleter=False, specialType=NamedOrIndexed.Neither, legacycaller=False, stringifier=False, - maplikeOrSetlikeOrIterable=None): + maplikeOrSetlikeOrIterable=None, + underlyingAttr=None): # REVIEW: specialType is NamedOrIndexed -- wow, this is messed up. IDLInterfaceMember.__init__(self, location, identifier, IDLInterfaceMember.Tags.Method) @@ -4894,6 +4958,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope): assert maplikeOrSetlikeOrIterable is None or isinstance(maplikeOrSetlikeOrIterable, IDLMaplikeOrSetlikeOrIterableBase) self.maplikeOrSetlikeOrIterable = maplikeOrSetlikeOrIterable self._htmlConstructor = False + self.underlyingAttr = underlyingAttr self._specialType = specialType self._unforgeable = False self.dependsOn = "Everything" @@ -4933,7 +4998,8 @@ class IDLMethod(IDLInterfaceMember, IDLScope): assert len(self._overloads) == 1 overload = self._overloads[0] assert len(overload.arguments) == 0 - assert overload.returnType == BuiltinTypes[IDLBuiltinType.Types.domstring] + if not self.underlyingAttr: + assert overload.returnType == BuiltinTypes[IDLBuiltinType.Types.domstring] def isStatic(self): return self._static diff --git a/components/script/dom/bindings/codegen/parser/tests/test_stringifier.py b/components/script/dom/bindings/codegen/parser/tests/test_stringifier.py index 14c2c5226fc..deabdc5ec81 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_stringifier.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_stringifier.py @@ -44,3 +44,103 @@ def WebIDLTest(parser, harness): harness.ok(threw, "Should not allow a 'stringifier;' and a 'stringifier()'") + parser = parser.reset() + parser.parse(""" + interface TestStringifier { + stringifier attribute DOMString foo; + }; + """) + results = parser.finish() + harness.ok(isinstance(results[0].members[0], WebIDL.IDLAttribute), + "Stringifier attribute should be an attribute") + stringifier = results[0].members[1] + harness.ok(isinstance(stringifier, WebIDL.IDLMethod), + "Stringifier attribute should insert a method") + harness.ok(stringifier.isStringifier(), + "Inserted method should be a stringifier") + + parser = parser.reset() + parser.parse(""" + interface TestStringifier {}; + interface mixin TestStringifierMixin { + stringifier attribute DOMString foo; + }; + TestStringifier includes TestStringifierMixin; + """) + results = parser.finish() + harness.ok(isinstance(results[0].members[0], WebIDL.IDLAttribute), + "Stringifier attribute should be an attribute") + stringifier = results[0].members[1] + harness.ok(isinstance(stringifier, WebIDL.IDLMethod), + "Stringifier attribute should insert a method") + harness.ok(stringifier.isStringifier(), + "Inserted method should be a stringifier") + + parser = parser.reset() + parser.parse(""" + interface TestStringifier { + stringifier attribute USVString foo; + }; + """) + results = parser.finish() + stringifier = results[0].members[1] + harness.ok(stringifier.signatures()[0][0].isUSVString(), + "Stringifier attributes should allow USVString") + + parser = parser.reset() + parser.parse(""" + interface TestStringifier { + [Throws, NeedsSubjectPrincipal] + stringifier attribute USVString foo; + }; + """) + results = parser.finish() + stringifier = results[0].members[1] + harness.ok(stringifier.getExtendedAttribute("Throws"), + "Stringifier attributes should support [Throws]") + harness.ok(stringifier.getExtendedAttribute("NeedsSubjectPrincipal"), + "Stringifier attributes should support [NeedsSubjectPrincipal]") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface TestStringifier { + stringifier attribute ByteString foo; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow ByteString") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface TestStringifier { + stringifier; + stringifier attribute DOMString foo; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow a 'stringifier;' and a stringifier attribute") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface TestStringifier { + stringifier attribute DOMString foo; + stringifier attribute DOMString bar; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow multiple stringifier attributes") -- cgit v1.2.3 From 691af0e98b95cb39a836319ecd10a35ce75b8db2 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Fri, 25 Oct 2019 15:46:52 +0900 Subject: Support stringifier attributes --- components/script/dom/bindings/codegen/CodegenRust.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index bb02119c406..86ee03d7ddd 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -3667,6 +3667,8 @@ class CGSpecializedMethod(CGAbstractExternMethod): @staticmethod def makeNativeName(descriptor, method): + if method.underlyingAttr: + return CGSpecializedGetter.makeNativeName(descriptor, method.underlyingAttr) name = method.identifier.name nativeName = descriptor.binaryNameFor(name) if nativeName == name: @@ -5762,7 +5764,7 @@ class CGInterfaceTrait(CGThing): for m in descriptor.interface.members: if (m.isMethod() and not m.isStatic() and not m.isMaplikeOrSetlikeOrIterableMethod() and - (not m.isIdentifierLess() or m.isStringifier()) and + (not m.isIdentifierLess() or (m.isStringifier() and not m.underlyingAttr)) and not m.isDefaultToJSON()): name = CGSpecializedMethod.makeNativeName(descriptor, m) infallible = 'infallible' in descriptor.getExtendedAttributes(m) @@ -6172,10 +6174,6 @@ class CGDescriptor(CGThing): cgThings.append(CGSpecializedMethod(descriptor, m)) cgThings.append(CGMemberJITInfo(descriptor, m)) elif m.isAttr(): - if m.stringifier: - raise TypeError("Stringifier attributes not supported yet. " - "See https://github.com/servo/servo/issues/7590\n" - "%s" % m.location) if m.getExtendedAttribute("Unscopable"): assert not m.isStatic() unscopableNames.append(m.identifier.name) -- cgit v1.2.3 From f8b61c031549cf9897451cadf3fb51804eaf98f7 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Sun, 3 Nov 2019 23:14:23 +0900 Subject: Use MessageEventSource on MessageEvent IDL --- components/script/dom/bindings/codegen/CodegenRust.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 86ee03d7ddd..7841fb48b7d 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -836,6 +836,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, descriptorType = descriptor.nativeType elif isArgument: descriptorType = descriptor.argumentType + elif descriptor.interface.identifier.name == "WindowProxy": + conversionFunction = "windowproxy_from_handlevalue" if failureCode is None: substitutions = { @@ -2409,6 +2411,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config): 'crate::dom::bindings::conversions::ConversionBehavior', 'crate::dom::bindings::conversions::StringificationBehavior', 'crate::dom::bindings::conversions::root_from_handlevalue', + 'crate::dom::bindings::conversions::windowproxy_from_handlevalue', 'std::ptr::NonNull', 'crate::dom::bindings::record::Record', 'crate::dom::bindings::num::Finite', @@ -2419,6 +2422,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config): 'crate::dom::bindings::trace::RootedTraceableBox', 'crate::dom::bindings::utils::find_enum_value', 'crate::dom::types::*', + 'crate::dom::windowproxy::WindowProxy', 'crate::script_runtime::JSContext as SafeJSContext', 'js::error::throw_type_error', 'js::rust::HandleValue', -- cgit v1.2.3 From 01e0b2cb5e47c28f7b85483f5ed82a09beb60bb5 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Mon, 4 Nov 2019 22:42:10 +0900 Subject: Use IDL sequence default value --- components/script/dom/bindings/codegen/CodegenRust.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 86ee03d7ddd..77c3c776c3e 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -6388,8 +6388,11 @@ class CGDictionary(CGThing): def struct(self): d = self.dictionary if d.parent: - inheritance = " pub parent: %s::%s,\n" % (self.makeModuleName(d.parent), - self.makeClassName(d.parent)) + typeName = "%s::%s" % (self.makeModuleName(d.parent), + self.makeClassName(d.parent)) + if type_needs_tracing(d.parent): + typeName = "RootedTraceableBox<%s>" % typeName + inheritance = " pub parent: %s,\n" % typeName else: inheritance = "" memberDecls = [" pub %s: %s," % @@ -6520,10 +6523,7 @@ class CGDictionary(CGThing): }) def membersNeedTracing(self): - for member, _ in self.memberInfo: - if type_needs_tracing(member.type): - return True - return False + return type_needs_tracing(self.dictionary) @staticmethod def makeDictionaryName(dictionary): -- cgit v1.2.3 From 1b22c10483d6c81fe9d186c9b50523ed55d5cfff Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Tue, 5 Nov 2019 23:55:15 +0900 Subject: Use TimerHandler IDL union type --- .../script/dom/bindings/codegen/CodegenRust.py | 32 +++++++++++++++++----- 1 file changed, 25 insertions(+), 7 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 86ee03d7ddd..62e0d7935a9 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2410,6 +2410,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config): 'crate::dom::bindings::conversions::StringificationBehavior', 'crate::dom::bindings::conversions::root_from_handlevalue', 'std::ptr::NonNull', + 'std::rc::Rc', 'crate::dom::bindings::record::Record', 'crate::dom::bindings::num::Finite', 'crate::dom::bindings::root::DomRoot', @@ -2423,6 +2424,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config): 'js::error::throw_type_error', 'js::rust::HandleValue', 'js::jsapi::Heap', + 'js::jsapi::IsCallable', 'js::jsapi::JSContext', 'js::jsapi::JSObject', 'js::rust::MutableHandleValue', @@ -2438,9 +2440,10 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config): if not t.isUnion(): continue for memberType in t.flatMemberTypes: - if memberType.isDictionary() or memberType.isEnum(): + if memberType.isDictionary() or memberType.isEnum() or memberType.isCallback(): memberModule = getModuleFromObject(memberType) - memberName = memberType.inner.identifier.name + memberName = (memberType.callback.identifier.name + if memberType.isCallback() else memberType.inner.identifier.name) imports.append("%s::%s" % (memberModule, memberName)) if memberType.isEnum(): imports.append("%s::%sValues" % (memberModule, memberName)) @@ -4380,6 +4383,9 @@ def getUnionTypeTemplateVars(type, descriptorProvider): elif is_typed_array(type): name = type.name typeName = "typedarray::Heap" + name + elif type.isCallback(): + name = type.name + typeName = name else: raise TypeError("Can't handle %s in unions yet" % type) @@ -4418,12 +4424,19 @@ class CGUnionStruct(CGThing): return False def define(self): + def getTypeWrapper(t): + if type_needs_tracing(t): + return "RootedTraceableBox" + if t.isCallback(): + return "Rc" + return "" + templateVars = map(lambda t: (getUnionTypeTemplateVars(t, self.descriptorProvider), - type_needs_tracing(t)), + getTypeWrapper(t)), self.type.flatMemberTypes) enumValues = [ - " %s(%s)," % (v["name"], "RootedTraceableBox<%s>" % v["typeName"] if trace else v["typeName"]) - for (v, trace) in templateVars + " %s(%s)," % (v["name"], "%s<%s>" % (wrapper, v["typeName"]) if wrapper else v["typeName"]) + for (v, wrapper) in templateVars ] enumConversions = [ " %s::%s(ref inner) => inner.to_jsval(cx, rval)," @@ -4506,7 +4519,8 @@ class CGUnionConversionStruct(CGThing): callbackMemberTypes = filter(lambda t: t.isCallback() or t.isCallbackInterface(), memberTypes) if len(callbackMemberTypes) > 0: assert len(callbackMemberTypes) == 1 - raise TypeError("Can't handle callbacks in unions.") + typeName = callbackMemberTypes[0].name + callbackObject = CGGeneric(get_match(typeName)) else: callbackObject = None @@ -4537,7 +4551,7 @@ class CGUnionConversionStruct(CGThing): else: mozMapObject = None - hasObjectTypes = object or interfaceObject or arrayObject or dateObject or mozMapObject + hasObjectTypes = object or interfaceObject or arrayObject or dateObject or callbackObject or mozMapObject if hasObjectTypes: # "object" is not distinguishable from other types assert not object or not (interfaceObject or arrayObject or dateObject or callbackObject or mozMapObject) @@ -4548,6 +4562,8 @@ class CGUnionConversionStruct(CGThing): templateBody.append(interfaceObject) if arrayObject: templateBody.append(arrayObject) + if callbackObject: + templateBody.append(callbackObject) if mozMapObject: templateBody.append(mozMapObject) conversions.append(CGIfWrapper("value.get().is_object()", templateBody)) @@ -4608,6 +4624,8 @@ class CGUnionConversionStruct(CGThing): actualType = templateVars["typeName"] if type_needs_tracing(t): actualType = "RootedTraceableBox<%s>" % actualType + if t.isCallback(): + actualType = "Rc<%s>" % actualType returnType = "Result, ()>" % actualType jsConversion = templateVars["jsConversion"] -- cgit v1.2.3 From bea73951db5a758f78842a0056daccba9d89a9c0 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 12 Nov 2019 22:16:08 +0100 Subject: Use `#![register_tool]` instead of `#![register_attr]` CC https://github.com/rust-lang/rust/issues/66079 --- components/script/dom/bindings/codegen/CodegenRust.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index e660471364e..0a1df6553fa 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -6406,7 +6406,7 @@ class CGDictionary(CGThing): derive = ["JSTraceable"] mustRoot = "" if self.membersNeedTracing(): - mustRoot = "#[must_root]\n" + mustRoot = "#[unrooted_must_root_lint::must_root]\n" derive += ["Default"] return (string.Template( @@ -6927,7 +6927,8 @@ class CGCallback(CGClass): bases=[ClassBase(baseName)], constructors=self.getConstructors(), methods=realMethods, - decorators="#[derive(JSTraceable, PartialEq)]\n#[allow_unrooted_interior]") + decorators="#[derive(JSTraceable, PartialEq)]\n" + "#[unrooted_must_root_lint::allow_unrooted_interior]") def getConstructors(self): return [ClassConstructor( -- cgit v1.2.3 From 12893aa0102f220f411b273a36ac1b4e25fa0ab7 Mon Sep 17 00:00:00 2001 From: Zakor Gyula Date: Sun, 10 Nov 2019 14:56:22 +0100 Subject: Initial implementation of WebGPU API --- components/script/dom/bindings/codegen/Bindings.conf | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf index 3ff7a044b53..5dc9e141ed5 100644 --- a/components/script/dom/bindings/codegen/Bindings.conf +++ b/components/script/dom/bindings/codegen/Bindings.conf @@ -134,7 +134,10 @@ DOMInterfaces = { 'XR': { 'inCompartments': ['SupportsSessionMode', 'RequestSession'], -} +}, +'GPU': { + 'inCompartments': ['RequestAdapter'], +} } -- cgit v1.2.3 From 22278a88953c4d7225de60e3c3c2a297273fe2d9 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Tue, 12 Nov 2019 12:04:00 +0900 Subject: Require PromiseRejectionEventInit dictionary --- components/script/dom/bindings/codegen/CodegenRust.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 7610b8442b4..fe3398417b2 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -6425,7 +6425,8 @@ class CGDictionary(CGThing): mustRoot = "" if self.membersNeedTracing(): mustRoot = "#[unrooted_must_root_lint::must_root]\n" - derive += ["Default"] + if not self.hasRequiredFields(self.dictionary): + derive += ["Default"] return (string.Template( "#[derive(${derive})]\n" @@ -6485,16 +6486,14 @@ class CGDictionary(CGThing): selfName = self.makeClassName(d) if self.membersNeedTracing(): actualType = "RootedTraceableBox<%s>" % selfName - preInitial = "let mut dictionary = RootedTraceableBox::new(%s::default());\n" % selfName - initParent = initParent = ("dictionary.parent = %s;\n" % initParent) if initParent else "" - memberInits = CGList([memberInit(m, False) for m in self.memberInfo]) - postInitial = "" + preInitial = "let dictionary = RootedTraceableBox::new(%s {\n" % selfName + postInitial = "});\n" else: actualType = selfName preInitial = "let dictionary = %s {\n" % selfName postInitial = "};\n" - initParent = ("parent: %s,\n" % initParent) if initParent else "" - memberInits = CGList([memberInit(m, True) for m in self.memberInfo]) + initParent = ("parent: %s,\n" % initParent) if initParent else "" + memberInits = CGList([memberInit(m, True) for m in self.memberInfo]) return string.Template( "impl ${selfName} {\n" @@ -6540,8 +6539,8 @@ class CGDictionary(CGThing): "initParent": CGIndenter(CGGeneric(initParent), indentLevel=16).define(), "initMembers": CGIndenter(memberInits, indentLevel=16).define(), "insertMembers": CGIndenter(memberInserts, indentLevel=8).define(), - "preInitial": CGIndenter(CGGeneric(preInitial), indentLevel=16).define(), - "postInitial": CGIndenter(CGGeneric(postInitial), indentLevel=16).define(), + "preInitial": CGIndenter(CGGeneric(preInitial), indentLevel=8).define(), + "postInitial": CGIndenter(CGGeneric(postInitial), indentLevel=8).define(), }) def membersNeedTracing(self): -- cgit v1.2.3 From d233558b9b2e33eaa236714a6c6c486e893a94d6 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 25 Nov 2019 16:37:48 -0800 Subject: Fix iterator invalidation in our forEach implementation. --- components/script/dom/bindings/codegen/CodegenRust.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index fe3398417b2..39e8bfa275d 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -7408,7 +7408,16 @@ class CGIterableMethodGenerator(CGGeneric): rooted!(in(*cx) let mut call_arg2 = UndefinedValue()); let mut call_args = vec![UndefinedValue(), UndefinedValue(), ObjectValue(*_obj)]; rooted!(in(*cx) let mut ignoredReturnVal = UndefinedValue()); - for i in 0..(*this).get_iterable_length() { + + // This has to be a while loop since get_iterable_length() may change during + // the callback, and we need to avoid iterator invalidation. + // + // It is possible for this to loop infinitely, but that matches the spec + // and other browsers. + // + // https://heycam.github.io/webidl/#es-forEach + let mut i = 0; + while i < (*this).get_iterable_length() { (*this).get_value_at_index(i).to_jsval(*cx, call_arg1.handle_mut()); (*this).get_key_at_index(i).to_jsval(*cx, call_arg2.handle_mut()); call_args[0] = call_arg1.handle().get(); @@ -7418,6 +7427,8 @@ class CGIterableMethodGenerator(CGGeneric): ignoredReturnVal.handle_mut()) { return false; } + + i += 1; } let result = (); -- cgit v1.2.3 From b15d2bb7d70870e26e1834099bf5fdcdcbb8d673 Mon Sep 17 00:00:00 2001 From: Istvan Miklos Date: Tue, 12 Nov 2019 12:56:57 +0100 Subject: Initial implementation of GPUDevice for WebGPU Added the WebIDL bindigs for GPUDevice, GPUObjectDescriptorBase, GPUDeviceDescriptor, GPUObjectBase Implemented the `requestDevice` function of `GPUAdapter` --- components/script/dom/bindings/codegen/Bindings.conf | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf index 5dc9e141ed5..31a041945fd 100644 --- a/components/script/dom/bindings/codegen/Bindings.conf +++ b/components/script/dom/bindings/codegen/Bindings.conf @@ -138,6 +138,10 @@ DOMInterfaces = { 'GPU': { 'inCompartments': ['RequestAdapter'], +}, + +'GPUAdapter': { + 'inCompartments': ['RequestDevice'], } } -- cgit v1.2.3 From 6e8a85482c2068d4dbccb992954271f725570f91 Mon Sep 17 00:00:00 2001 From: Gregory Terzian Date: Sun, 1 Sep 2019 03:18:42 +0800 Subject: re-structure blob, structured serialization --- components/script/dom/bindings/codegen/Bindings.conf | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf index 5dc9e141ed5..d1d55d462bf 100644 --- a/components/script/dom/bindings/codegen/Bindings.conf +++ b/components/script/dom/bindings/codegen/Bindings.conf @@ -14,6 +14,14 @@ DOMInterfaces = { +'Blob': { + 'weakReferenceable': True, +}, + +'File': { + 'weakReferenceable': True, +}, + 'MediaQueryList': { 'weakReferenceable': True, }, -- cgit v1.2.3 From 7b5fabe8552b9245a70961db9ec592a55102bb0e Mon Sep 17 00:00:00 2001 From: marmeladema Date: Tue, 10 Dec 2019 23:56:12 +0000 Subject: Fix tidiness errors for Python3 compatibility across whole repo --- components/script/dom/bindings/codegen/CodegenRust.py | 14 +++++++------- components/script/dom/bindings/codegen/Configuration.py | 6 ++++-- 2 files changed, 11 insertions(+), 9 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 39e8bfa275d..ec29a59c9d4 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -3943,8 +3943,8 @@ class CGMemberJITInfo(CGThing): depth=self.descriptor.interface.inheritanceDepth(), opType=opType, aliasSet=aliasSet, - returnType=reduce(CGMemberJITInfo.getSingleReturnType, returnTypes, - ""), + returnType=functools.reduce(CGMemberJITInfo.getSingleReturnType, returnTypes, + ""), isInfallible=toStringBool(infallible), isMovable=toStringBool(movable), # FIXME(nox): https://github.com/servo/servo/issues/10991 @@ -4131,8 +4131,8 @@ class CGMemberJITInfo(CGThing): if u.hasNullableType: # Might be null or not return "JSVAL_TYPE_UNKNOWN" - return reduce(CGMemberJITInfo.getSingleReturnType, - u.flatMemberTypes, "") + return functools.reduce(CGMemberJITInfo.getSingleReturnType, + u.flatMemberTypes, "") if t.isDictionary(): return "JSVAL_TYPE_OBJECT" if t.isDate(): @@ -4202,8 +4202,8 @@ class CGMemberJITInfo(CGThing): if t.isUnion(): u = t.unroll() type = "JSJitInfo::Null as i32" if u.hasNullableType else "" - return reduce(CGMemberJITInfo.getSingleArgType, - u.flatMemberTypes, type) + return functools.reduce(CGMemberJITInfo.getSingleArgType, + u.flatMemberTypes, type) if t.isDictionary(): return "JSJitInfo_ArgType::Object as i32" if t.isDate(): @@ -5858,7 +5858,7 @@ class CGInterfaceTrait(CGThing): def contains_unsafe_arg(arguments): if not arguments or len(arguments) == 0: return False - return reduce((lambda x, y: x or y[1] == '*mut JSContext'), arguments, False) + return functools.reduce((lambda x, y: x or y[1] == '*mut JSContext'), arguments, False) methods = [] for name, arguments, rettype in members(): diff --git a/components/script/dom/bindings/codegen/Configuration.py b/components/script/dom/bindings/codegen/Configuration.py index 71c988e5378..84d8bd974aa 100644 --- a/components/script/dom/bindings/codegen/Configuration.py +++ b/components/script/dom/bindings/codegen/Configuration.py @@ -2,6 +2,7 @@ # 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/. +import functools import os from WebIDL import IDLExternalInterface, IDLSequenceType, IDLWrapperType, WebIDLError @@ -15,7 +16,7 @@ class Configuration: def __init__(self, filename, parseData): # Read the configuration file. glbl = {} - execfile(filename, glbl) + exec(compile(open(filename).read(), filename, 'exec'), glbl) config = glbl['DOMInterfaces'] # Build descriptors for all the interfaces we have in the parse data. @@ -62,7 +63,8 @@ class Configuration: c.isCallback() and not c.isInterface()] # Keep the descriptor list sorted for determinism. - self.descriptors.sort(lambda x, y: cmp(x.name, y.name)) + cmp = lambda x, y: (x > y) - (x < y) + self.descriptors.sort(key=functools.cmp_to_key(lambda x, y: cmp(x.name, y.name))) def getInterface(self, ifname): return self.interfaces[ifname] -- cgit v1.2.3 From c1b71fcc4d842aa1df38d6ed36b73dc331508703 Mon Sep 17 00:00:00 2001 From: Patrick Shaughnessy Date: Mon, 6 Jan 2020 20:14:36 -0500 Subject: Implement HTMLSelectElement.add() and indexed setter, fix test that was relying on add to be a stub --- components/script/dom/bindings/codegen/CodegenRust.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index ec29a59c9d4..e0a5df68882 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -5263,7 +5263,7 @@ class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod): CGIndenter(CGProxyNamedSetter(self.descriptor)).define() + " return (*opresult).succeed();\n" + "}\n") - else: + elif self.descriptor.operations['NamedGetter']: set += ("if RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id) {\n" + CGIndenter(CGProxyNamedGetter(self.descriptor)).define() + " if result.is_some() {\n" -- cgit v1.2.3 From 111ede9c77a41ab353f12683a62cd4b4dabb65da Mon Sep 17 00:00:00 2001 From: Patrick Shaughnessy Date: Mon, 6 Jan 2020 14:20:51 -0500 Subject: Make property descriptors hold named/indexed property values --- components/script/dom/bindings/codegen/CodegenRust.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index ec29a59c9d4..9cdda2f3bf2 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -5147,8 +5147,7 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod): attrs = "JSPROP_ENUMERATE" if self.descriptor.operations['IndexedSetter'] is None: attrs += " | JSPROP_READONLY" - # FIXME(#11868) Should assign to desc.value, desc.get() is a copy. - fillDescriptor = ("desc.get().value = result_root.get();\n" + fillDescriptor = ("desc.value = result_root.get();\n" "fill_property_descriptor(MutableHandle::from_raw(desc), proxy.get(), (%s) as u32);\n" "return true;" % attrs) templateValues = { @@ -5173,8 +5172,7 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod): attrs = " | ".join(attrs) else: attrs = "0" - # FIXME(#11868) Should assign to desc.value, desc.get() is a copy. - fillDescriptor = ("desc.get().value = result_root.get();\n" + fillDescriptor = ("desc.value = result_root.get();\n" "fill_property_descriptor(MutableHandle::from_raw(desc), proxy.get(), (%s) as u32);\n" "return true;" % attrs) templateValues = { @@ -5221,7 +5219,7 @@ if !expando.is_null() { } } """ + namedGet + """\ -desc.get().obj = ptr::null_mut(); +desc.obj = ptr::null_mut(); return true;""" def definition_body(self): -- cgit v1.2.3 From 5a3e1b8e6903c825e50597a218532d417f1dfef9 Mon Sep 17 00:00:00 2001 From: Kunal Mohan Date: Fri, 24 Jan 2020 13:29:09 +0530 Subject: rename compartment to realm --- .../script/dom/bindings/codegen/Bindings.conf | 50 +++++++++++----------- .../script/dom/bindings/codegen/CodegenRust.py | 44 +++++++++---------- .../script/dom/bindings/codegen/Configuration.py | 2 +- 3 files changed, 48 insertions(+), 48 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf index 3a5f8576cef..b1e6f6823ff 100644 --- a/components/script/dom/bindings/codegen/Bindings.conf +++ b/components/script/dom/bindings/codegen/Bindings.conf @@ -44,7 +44,7 @@ DOMInterfaces = { #FIXME(jdm): This should be 'register': False, but then we don't generate enum types 'TestBinding': { - 'inCompartments': ['PromiseAttribute', 'PromiseNativeHandler'], + 'inRealms': ['PromiseAttribute', 'PromiseNativeHandler'], }, 'URL': { @@ -57,99 +57,99 @@ DOMInterfaces = { }, 'Window': { - 'inCompartments': ['Fetch'], + 'inRealms': ['Fetch'], }, 'WorkerGlobalScope': { - 'inCompartments': ['Fetch'], + 'inRealms': ['Fetch'], }, 'CustomElementRegistry': { - 'inCompartments': ['WhenDefined'], + 'inRealms': ['WhenDefined'], }, 'AudioContext': { - 'inCompartments': ['Suspend', 'Close'], + 'inRealms': ['Suspend', 'Close'], }, 'NavigationPreloadManager': { - 'inCompartments': ['Enable', 'Disable', 'SetHeaderValue', 'GetState'], + 'inRealms': ['Enable', 'Disable', 'SetHeaderValue', 'GetState'], }, 'HTMLMediaElement': { - 'inCompartments': ['Play'], + 'inRealms': ['Play'], }, 'BluetoothRemoteGATTDescriptor': { - 'inCompartments': ['ReadValue', 'WriteValue'], + 'inRealms': ['ReadValue', 'WriteValue'], }, 'OfflineAudioContext': { - 'inCompartments': ['StartRendering'], + 'inRealms': ['StartRendering'], }, 'BluetoothRemoteGATTServer': { - 'inCompartments': ['Connect'], + 'inRealms': ['Connect'], }, 'ServiceWorkerContainer': { - 'inCompartments': ['Register'], + 'inRealms': ['Register'], }, 'Navigator': { - 'inCompartments': ['GetVRDisplays'], + 'inRealms': ['GetVRDisplays'], }, 'MediaDevices': { - 'inCompartments': ['GetUserMedia'], + 'inRealms': ['GetUserMedia'], }, 'XRSession': { - 'inCompartments': ['UpdateRenderState', 'RequestReferenceSpace'], + 'inRealms': ['UpdateRenderState', 'RequestReferenceSpace'], }, 'Bluetooth': { - 'inCompartments': ['RequestDevice', 'GetAvailability'], + 'inRealms': ['RequestDevice', 'GetAvailability'], }, 'BaseAudioContext': { - 'inCompartments': ['Resume', 'DecodeAudioData'], + 'inRealms': ['Resume', 'DecodeAudioData'], }, 'RTCPeerConnection': { - 'inCompartments': ['AddIceCandidate', 'CreateOffer', 'CreateAnswer', 'SetLocalDescription', 'SetRemoteDescription'], + 'inRealms': ['AddIceCandidate', 'CreateOffer', 'CreateAnswer', 'SetLocalDescription', 'SetRemoteDescription'], }, 'BluetoothRemoteGATTCharacteristic': { - 'inCompartments': ['ReadValue', 'WriteValue', 'StartNotifications', 'StopNotifications'], + 'inRealms': ['ReadValue', 'WriteValue', 'StartNotifications', 'StopNotifications'], }, 'VRDisplay': { - 'inCompartments': ['RequestPresent', 'ExitPresent'], + 'inRealms': ['RequestPresent', 'ExitPresent'], }, 'Worklet': { - 'inCompartments': ['AddModule'], + 'inRealms': ['AddModule'], }, 'TestWorklet': { - 'inCompartments': ['AddModule'], + 'inRealms': ['AddModule'], }, 'BluetoothDevice': { - 'inCompartments': ['WatchAdvertisements'], + 'inRealms': ['WatchAdvertisements'], }, 'XR': { - 'inCompartments': ['SupportsSessionMode', 'RequestSession'], + 'inRealms': ['SupportsSessionMode', 'RequestSession'], }, 'GPU': { - 'inCompartments': ['RequestAdapter'], + 'inRealms': ['RequestAdapter'], }, 'GPUAdapter': { - 'inCompartments': ['RequestDevice'], + 'inRealms': ['RequestDevice'], } } diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index d79bc073e76..ce1487d5fa6 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -771,14 +771,14 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, # # 1) Normal call to API with a Promise argument. This is a case the # spec covers, and we should be using the current Realm's - # Promise. That means the current compartment. + # Promise. That means the current realm. # 2) Promise return value from a callback or callback interface. # This is in theory a case the spec covers but in practice it # really doesn't define behavior here because it doesn't define # what Realm we're in after the callback returns, which is when # the argument conversion happens. We will use the current - # compartment, which is the compartment of the callable (which - # may itself be a cross-compartment wrapper itself), which makes + # realm, which is the realm of the callable (which + # may itself be a cross-realm wrapper itself), which makes # as much sense as anything else. In practice, such an API would # once again be providing a Promise to signal completion of an # operation, which would then not be exposed to anyone other than @@ -3397,8 +3397,8 @@ class CGCallGenerator(CGThing): if "cx" not in argsPre and needsCx: args.prepend(CGGeneric("cx")) - if nativeMethodName in descriptor.inCompartmentMethods: - args.append(CGGeneric("InCompartment::in_compartment(&AlreadyInCompartment::assert_for_cx(cx))")) + if nativeMethodName in descriptor.inRealmMethods: + args.append(CGGeneric("InRealm::in_realm(&AlreadyInRealm::assert_for_cx(cx))")) # Build up our actual call self.cgRoot = CGList([], "\n") @@ -5671,7 +5671,7 @@ let global = DomRoot::downcast::(global).unwrap(); // Step 2 https://html.spec.whatwg.org/multipage/#htmlconstructor // The custom element definition cannot use an element interface as its constructor -// The new_target might be a cross-compartment wrapper. Get the underlying object +// The new_target might be a cross-realm wrapper. Get the underlying object // so we can do the spec's object-identity checks. rooted!(in(*cx) let new_target = UnwrapObjectDynamic(args.new_target().to_object(), *cx, 1)); if new_target.is_null() { @@ -5697,11 +5697,11 @@ rooted!(in(*cx) let mut prototype = ptr::null_mut::()); if !proto_val.is_object() { // Step 7 of https://html.spec.whatwg.org/multipage/#htmlconstructor. // This fallback behavior is designed to match analogous behavior for the - // JavaScript built-ins. So we enter the compartment of our underlying + // JavaScript built-ins. So we enter the realm of our underlying // newTarget object and fall back to the prototype object from that global. // XXX The spec says to use GetFunctionRealm(), which is not actually // the same thing as what we have here (e.g. in the case of scripted callable proxies - // whose target is not same-compartment with the proxy, or bound functions, etc). + // whose target is not same-realm with the proxy, or bound functions, etc). // https://bugzilla.mozilla.org/show_bug.cgi?id=1317658 rooted!(in(*cx) let global_object = CurrentGlobalOrNull(*cx)); @@ -5712,7 +5712,7 @@ rooted!(in(*cx) let mut prototype = ptr::null_mut::()); }; } -// Wrap prototype in this context since it is from the newTarget compartment +// Wrap prototype in this context since it is from the newTarget realm if !JS_WrapObject(*cx, prototype.handle_mut()) { return false; } @@ -5770,15 +5770,15 @@ class CGInterfaceTrait(CGThing): def __init__(self, descriptor): CGThing.__init__(self) - def attribute_arguments(needCx, argument=None, inCompartment=False): + def attribute_arguments(needCx, argument=None, inRealm=False): if needCx: yield "cx", "SafeJSContext" if argument: yield "value", argument_type(descriptor, argument) - if inCompartment: - yield "_comp", "InCompartment" + if inRealm: + yield "_comp", "InRealm" def members(): for m in descriptor.interface.members: @@ -5790,7 +5790,7 @@ class CGInterfaceTrait(CGThing): infallible = 'infallible' in descriptor.getExtendedAttributes(m) for idx, (rettype, arguments) in enumerate(m.signatures()): arguments = method_arguments(descriptor, rettype, arguments, - inCompartment=name in descriptor.inCompartmentMethods) + inRealm=name in descriptor.inRealmMethods) rettype = return_type(descriptor, rettype, infallible) yield name + ('_' * idx), arguments, rettype elif m.isAttr() and not m.isStatic(): @@ -5799,7 +5799,7 @@ class CGInterfaceTrait(CGThing): yield (name, attribute_arguments( typeNeedsCx(m.type, True), - inCompartment=name in descriptor.inCompartmentMethods + inRealm=name in descriptor.inRealmMethods ), return_type(descriptor, m.type, infallible)) @@ -5814,7 +5814,7 @@ class CGInterfaceTrait(CGThing): attribute_arguments( typeNeedsCx(m.type, False), m.type, - inCompartment=name in descriptor.inCompartmentMethods + inRealm=name in descriptor.inRealmMethods ), rettype) @@ -5831,7 +5831,7 @@ class CGInterfaceTrait(CGThing): if not rettype.nullable(): rettype = IDLNullableType(rettype.location, rettype) arguments = method_arguments(descriptor, rettype, arguments, - inCompartment=name in descriptor.inCompartmentMethods) + inRealm=name in descriptor.inRealmMethods) # If this interface 'supports named properties', then we # should be able to access 'supported property names' @@ -5842,7 +5842,7 @@ class CGInterfaceTrait(CGThing): yield "SupportedPropertyNames", [], "Vec" else: arguments = method_arguments(descriptor, rettype, arguments, - inCompartment=name in descriptor.inCompartmentMethods) + inRealm=name in descriptor.inRealmMethods) rettype = return_type(descriptor, rettype, infallible) yield name, arguments, rettype @@ -6138,8 +6138,8 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'crate::dom::windowproxy::WindowProxy', 'crate::dom::globalscope::GlobalScope', 'crate::mem::malloc_size_of_including_raw_self', - 'crate::compartments::InCompartment', - 'crate::compartments::AlreadyInCompartment', + 'crate::realms::InRealm', + 'crate::realms::AlreadyInRealm', 'crate::script_runtime::JSContext as SafeJSContext', 'libc', 'servo_config::pref', @@ -6861,7 +6861,7 @@ def argument_type(descriptorProvider, ty, optional=False, defaultValue=None, var return declType.define() -def method_arguments(descriptorProvider, returnType, arguments, passJSBits=True, trailing=None, inCompartment=False): +def method_arguments(descriptorProvider, returnType, arguments, passJSBits=True, trailing=None, inRealm=False): if needCx(returnType, arguments, passJSBits): yield "cx", "SafeJSContext" @@ -6873,8 +6873,8 @@ def method_arguments(descriptorProvider, returnType, arguments, passJSBits=True, if trailing: yield trailing - if inCompartment: - yield "_comp", "InCompartment" + if inRealm: + yield "_comp", "InRealm" def return_type(descriptorProvider, rettype, infallible): diff --git a/components/script/dom/bindings/codegen/Configuration.py b/components/script/dom/bindings/codegen/Configuration.py index 84d8bd974aa..b3e1e0c8289 100644 --- a/components/script/dom/bindings/codegen/Configuration.py +++ b/components/script/dom/bindings/codegen/Configuration.py @@ -220,7 +220,7 @@ class Descriptor(DescriptorProvider): self.concreteType = typeName self.register = desc.get('register', True) self.path = desc.get('path', pathDefault) - self.inCompartmentMethods = [name for name in desc.get('inCompartments', [])] + self.inRealmMethods = [name for name in desc.get('inRealms', [])] self.bindingPath = 'crate::dom::bindings::codegen::Bindings::%s' % ('::'.join([ifaceName + 'Binding'] * 2)) self.outerObjectHook = desc.get('outerObjectHook', 'None') self.proxy = False -- cgit v1.2.3 From 403ffcf1eb5c659626f70dec72f76aaf7782986d Mon Sep 17 00:00:00 2001 From: CYBAI Date: Fri, 24 Jan 2020 12:43:49 +0900 Subject: Always pass InRealm to GlobalScope::from_context to avoid getting null global --- components/script/dom/bindings/codegen/Bindings.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf index b1e6f6823ff..d60814f6191 100644 --- a/components/script/dom/bindings/codegen/Bindings.conf +++ b/components/script/dom/bindings/codegen/Bindings.conf @@ -57,7 +57,7 @@ DOMInterfaces = { }, 'Window': { - 'inRealms': ['Fetch'], + 'inRealms': ['Fetch', 'Opener'], }, 'WorkerGlobalScope': { -- cgit v1.2.3 From 14846d0567583d58510565c2223f81883f152262 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Mon, 17 Feb 2020 10:17:47 +0100 Subject: Introduce a new type MaybeUnreflectedDom (fixes #25701) --- .../script/dom/bindings/codegen/CodegenRust.py | 89 ++++++++++++---------- 1 file changed, 50 insertions(+), 39 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index ce1487d5fa6..7f56c3b2f15 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2632,35 +2632,6 @@ class CGConstructorEnabled(CGAbstractMethod): return CGList((CGGeneric(cond) for cond in conditions), " &&\n") -def CreateBindingJSObject(descriptor): - assert not descriptor.isGlobal() - create = "let raw = Box::into_raw(object);\nlet _rt = RootedTraceable::new(&*raw);\n" - if descriptor.proxy: - create += """ -let handler = RegisterBindings::PROXY_HANDLERS[PrototypeList::Proxies::%s as usize]; -rooted!(in(*cx) let private = PrivateValue(raw as *const libc::c_void)); -let obj = NewProxyObject(*cx, handler, - Handle::from_raw(UndefinedHandleValue), - proto.get()); -assert!(!obj.is_null()); -SetProxyReservedSlot(obj, 0, &private.get()); -rooted!(in(*cx) let obj = obj);\ -""" % (descriptor.name) - else: - create += ("rooted!(in(*cx) let obj = JS_NewObjectWithGivenProto(\n" - " *cx, &Class.base as *const JSClass, proto.handle()));\n" - "assert!(!obj.is_null());\n" - "\n" - "let val = PrivateValue(raw as *const libc::c_void);\n" - "\n" - "JS_SetReservedSlot(obj.get(), DOM_OBJECT_SLOT, &val);") - if descriptor.weakReferenceable: - create += """ -let val = PrivateValue(ptr::null()); -JS_SetReservedSlot(obj.get(), DOM_WEAK_SLOT, &val);""" - return create - - def InitUnforgeablePropertiesOnHolder(descriptor, properties): """ Define the unforgeable properties on the unforgeable holder for @@ -2738,23 +2709,62 @@ class CGWrapMethod(CGAbstractMethod): def definition_body(self): unforgeable = CopyUnforgeablePropertiesToInstance(self.descriptor) - create = CreateBindingJSObject(self.descriptor) + if self.descriptor.proxy: + create = """ +let handler = RegisterBindings::PROXY_HANDLERS[PrototypeList::Proxies::%(concreteType)s as usize]; +rooted!(in(*cx) let obj = NewProxyObject( + *cx, + handler, + Handle::from_raw(UndefinedHandleValue), + proto.get(), +)); +assert!(!obj.is_null()); +SetProxyReservedSlot( + obj.get(), + 0, + &PrivateValue(&*raw as *const %(concreteType)s as *const libc::c_void), +); +""" + else: + create = """ +rooted!(in(*cx) let obj = JS_NewObjectWithGivenProto( + *cx, + &Class.base, + proto.handle(), +)); +assert!(!obj.is_null()); +JS_SetReservedSlot( + obj.get(), + DOM_OBJECT_SLOT, + &PrivateValue(&*raw as *const %(concreteType)s as *const libc::c_void), +); +""" + create = create % {"concreteType": self.descriptor.concreteType} + if self.descriptor.weakReferenceable: + create += """ +let val = PrivateValue(ptr::null()); +JS_SetReservedSlot(obj.get(), DOM_WEAK_SLOT, &val); +""" + return CGGeneric("""\ +let raw = Root::new(MaybeUnreflectedDom::from_box(object)); + let scope = scope.reflector().get_jsobject(); assert!(!scope.get().is_null()); assert!(((*get_object_class(scope.get())).flags & JSCLASS_IS_GLOBAL) != 0); +let _ac = JSAutoRealm::new(*cx, scope.get()); rooted!(in(*cx) let mut proto = ptr::null_mut::()); -let _ac = JSAutoRealm::new(*cx, scope.get()); GetProtoObject(cx, scope, proto.handle_mut()); assert!(!proto.is_null()); %(createObject)s +raw.init_reflector(obj.get()); %(copyUnforgeable)s -(*raw).init_reflector(obj.get()); -DomRoot::from_ref(&*raw)""" % {'copyUnforgeable': unforgeable, 'createObject': create}) +DomRoot::from_ref(&*raw)\ +""" % {'copyUnforgeable': unforgeable, 'createObject': create}) class CGWrapGlobalMethod(CGAbstractMethod): @@ -2773,6 +2783,7 @@ class CGWrapGlobalMethod(CGAbstractMethod): def definition_body(self): values = { + "concreteType": self.descriptor.concreteType, "unforgeable": CopyUnforgeablePropertiesToInstance(self.descriptor) } @@ -2786,19 +2797,18 @@ class CGWrapGlobalMethod(CGAbstractMethod): values["members"] = "\n".join(members) return CGGeneric("""\ -let raw = Box::into_raw(object); -let _rt = RootedTraceable::new(&*raw); +let raw = Root::new(MaybeUnreflectedDom::from_box(object)); rooted!(in(*cx) let mut obj = ptr::null_mut::()); create_global_object( cx, &Class.base, - raw as *const libc::c_void, + &*raw as *const %(concreteType)s as *const libc::c_void, _trace, obj.handle_mut()); assert!(!obj.is_null()); -(*raw).init_reflector(obj.get()); +raw.init_reflector(obj.get()); let _ac = JSAutoRealm::new(*cx, obj.get()); rooted!(in(*cx) let mut proto = ptr::null_mut::()); @@ -6060,8 +6070,10 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'crate::dom::bindings::reflector::DomObject', 'crate::dom::bindings::root::Dom', 'crate::dom::bindings::root::DomRoot', - 'crate::dom::bindings::root::OptionalHeapSetter', 'crate::dom::bindings::root::DomSlice', + 'crate::dom::bindings::root::MaybeUnreflectedDom', + 'crate::dom::bindings::root::OptionalHeapSetter', + 'crate::dom::bindings::root::Root', 'crate::dom::bindings::utils::AsVoidPtr', 'crate::dom::bindings::utils::DOMClass', 'crate::dom::bindings::utils::DOMJSClass', @@ -6086,7 +6098,6 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'crate::dom::bindings::utils::set_dictionary_property', 'crate::dom::bindings::utils::trace_global', 'crate::dom::bindings::trace::JSTraceable', - 'crate::dom::bindings::trace::RootedTraceable', 'crate::dom::bindings::trace::RootedTraceableBox', 'crate::dom::bindings::callback::CallSetup', 'crate::dom::bindings::callback::CallbackContainer', -- cgit v1.2.3 From 30f474312ff9beb2b407fc35f1a93d65c8bbeaae Mon Sep 17 00:00:00 2001 From: JavaScript Joe Date: Tue, 11 Feb 2020 20:52:40 -0800 Subject: refactor: rename XR to XRSystem chore: fix formatting refactor: change filename and ref to xrsystem refactor: change filename XRSystem.webidl refactor: update crate in navigator refactor: use XRSystem instead of XR in navigator refactor: update Bindings.conf refactor: use XRSystemMethods fix: update assertions for XRSystem fix: update manifest json --- components/script/dom/bindings/codegen/Bindings.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf index d60814f6191..5f978f5d3c4 100644 --- a/components/script/dom/bindings/codegen/Bindings.conf +++ b/components/script/dom/bindings/codegen/Bindings.conf @@ -140,7 +140,7 @@ DOMInterfaces = { 'inRealms': ['WatchAdvertisements'], }, -'XR': { +'XRSystem': { 'inRealms': ['SupportsSessionMode', 'RequestSession'], }, -- cgit v1.2.3 From 2df4d9fce419505cf7c5305321d4135559534997 Mon Sep 17 00:00:00 2001 From: Istvan Miklos Date: Tue, 11 Feb 2020 22:35:11 +0100 Subject: Implement mapReadAsync function of GPUBuffer Implemented the `mapReadAsync` and fixed the `unmap` functions of `GPUBuffer`. Added `mapped` internal slot for tracking the ArrayBuffer/Promise. Added more states to the `GPUBufferState` enum. --- components/script/dom/bindings/codegen/Bindings.conf | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf index 5f978f5d3c4..7aa8ffa4c8b 100644 --- a/components/script/dom/bindings/codegen/Bindings.conf +++ b/components/script/dom/bindings/codegen/Bindings.conf @@ -150,6 +150,10 @@ DOMInterfaces = { 'GPUAdapter': { 'inRealms': ['RequestDevice'], +}, + +'GPUBuffer': { + 'inRealms': ['MapReadAsync'], } } -- cgit v1.2.3 From 5a4f8cf93f9f674a164a0a3cfc586accef3d06f9 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Mon, 2 Mar 2020 11:16:46 +0100 Subject: Update SpiderMonkey --- .../script/dom/bindings/codegen/CodegenRust.py | 157 ++++++++++++--------- 1 file changed, 88 insertions(+), 69 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 7f56c3b2f15..a06414c306e 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1654,7 +1654,7 @@ class MethodDefiner(PropertyDefiner): if any(m.isGetter() and m.isIndexed() for m in methods): self.regular.append({"name": '@@iterator', "methodInfo": False, - "selfHostedName": "ArrayValues", + "selfHostedName": "$ArrayValues", "length": 0, "flags": "0", # Not enumerable, per spec. "condition": "Condition::Satisfied"}) @@ -1678,7 +1678,7 @@ class MethodDefiner(PropertyDefiner): self.regular.append({ "name": "values", "methodInfo": False, - "selfHostedName": "ArrayValues", + "selfHostedName": "$ArrayValues", "length": 0, "flags": "JSPROP_ENUMERATE", "condition": PropertyDefiner.getControllingCondition(m, @@ -1731,7 +1731,7 @@ class MethodDefiner(PropertyDefiner): selfHostedName = '%s as *const u8 as *const libc::c_char' % str_to_const_array(m["selfHostedName"]) assert not m.get("methodInfo", True) accessor = "None" - jitinfo = "0 as *const JSJitInfo" + jitinfo = "ptr::null()" else: selfHostedName = "0 as *const libc::c_char" if m.get("methodInfo", True): @@ -1743,28 +1743,30 @@ class MethodDefiner(PropertyDefiner): jitinfo = "&%s_methodinfo as *const _ as *const JSJitInfo" % identifier accessor = "Some(generic_method)" else: - jitinfo = "0 as *const JSJitInfo" + jitinfo = "ptr::null()" accessor = 'Some(%s)' % m.get("nativeName", m["name"]) if m["name"].startswith("@@"): - return ('(SymbolCode::%s as i32 + 1)' - % m["name"][2:], accessor, jitinfo, m["length"], flags, selfHostedName) - return (str_to_const_array(m["name"]), accessor, jitinfo, m["length"], flags, selfHostedName) + name = 'JSPropertySpec_Name { symbol_: SymbolCode::%s as usize + 1 }' % m["name"][2:] + else: + name = ('JSPropertySpec_Name { string_: %s as *const u8 as *const libc::c_char }' + % str_to_const_array(m["name"])) + return (name, accessor, jitinfo, m["length"], flags, selfHostedName) return self.generateGuardedArray( array, name, ' JSFunctionSpec {\n' - ' name: %s as *const u8 as *const libc::c_char,\n' + ' name: %s,\n' ' call: JSNativeWrapper { op: %s, info: %s },\n' ' nargs: %s,\n' ' flags: (%s) as u16,\n' ' selfHostedName: %s\n' ' }', ' JSFunctionSpec {\n' - ' name: 0 as *const libc::c_char,\n' - ' call: JSNativeWrapper { op: None, info: 0 as *const JSJitInfo },\n' + ' name: JSPropertySpec_Name { string_: ptr::null() },\n' + ' call: JSNativeWrapper { op: None, info: ptr::null() },\n' ' nargs: 0,\n' ' flags: 0,\n' - ' selfHostedName: 0 as *const libc::c_char\n' + ' selfHostedName: ptr::null()\n' ' }', 'JSFunctionSpec', condition, specData) @@ -1834,14 +1836,14 @@ class AttrDefiner(PropertyDefiner): return self.generateGuardedArray( array, name, ' JSPropertySpec {\n' - ' name: %s as *const u8 as *const libc::c_char,\n' + ' name: JSPropertySpec_Name { string_: %s as *const u8 as *const libc::c_char },\n' ' flags: (%s) as u8,\n' - ' __bindgen_anon_1: JSPropertySpec__bindgen_ty_1 {\n' - ' accessors: JSPropertySpec__bindgen_ty_1__bindgen_ty_1 {\n' - ' getter: JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_1 {\n' + ' u: JSPropertySpec_AccessorsOrValue {\n' + ' accessors: JSPropertySpec_AccessorsOrValue_Accessors {\n' + ' getter: JSPropertySpec_Accessor {\n' ' native: %s,\n' ' },\n' - ' setter: JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_2 {\n' + ' setter: JSPropertySpec_Accessor {\n' ' native: %s,\n' ' }\n' ' }\n' @@ -2203,7 +2205,9 @@ static Class: DOMJSClass = DOMJSClass { (((%(slots)s) & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT) /* JSCLASS_HAS_RESERVED_SLOTS(%(slots)s) */, cOps: &CLASS_OPS, - reserved: [0 as *mut _; 3], + spec: ptr::null(), + ext: ptr::null(), + oOps: ptr::null(), }, dom_class: %(domClass)s }; @@ -2274,7 +2278,9 @@ static PrototypeClass: JSClass = JSClass { // JSCLASS_HAS_RESERVED_SLOTS(%(slotCount)s) (%(slotCount)s & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT, cOps: 0 as *const _, - reserved: [0 as *mut os::raw::c_void; 3] + spec: ptr::null(), + ext: ptr::null(), + oOps: ptr::null(), }; """ % {'name': name, 'slotCount': slotCount} @@ -2916,9 +2922,9 @@ class CGCollectJSONAttributesMethod(CGAbstractMethod): Generate the CollectJSONAttributes method for an interface descriptor """ def __init__(self, descriptor, toJSONMethod): - args = [Argument('SafeJSContext', 'cx'), - Argument('HandleObject', 'obj'), - Argument('*const %s' % descriptor.concreteType, 'this'), + args = [Argument('*mut JSContext', 'cx'), + Argument('RawHandleObject', 'obj'), + Argument('*mut libc::c_void', 'this'), Argument('&RootedGuard<*mut JSObject>', 'result')] CGAbstractMethod.__init__(self, descriptor, 'CollectJSONAttributes', 'bool', args, pub=True, unsafe=True) @@ -2932,11 +2938,11 @@ class CGCollectJSONAttributesMethod(CGAbstractMethod): name = m.identifier.name ret += fill( """ - rooted!(in(*cx) let mut temp = UndefinedValue()); + rooted!(in(cx) let mut temp = UndefinedValue()); if !get_${name}(cx, obj, this, JSJitGetterCallArgs { _base: temp.handle_mut().into() }) { return false; } - if !JS_DefineProperty(*cx, result.handle().into(), + if !JS_DefineProperty(cx, result.handle().into(), ${nameAsArray} as *const u8 as *const libc::c_char, temp.handle(), JSPROP_ENUMERATE as u32) { return false; @@ -3668,8 +3674,9 @@ class CGSpecializedMethod(CGAbstractExternMethod): def __init__(self, descriptor, method): self.method = method name = method.identifier.name - args = [Argument('SafeJSContext', 'cx'), Argument('HandleObject', '_obj'), - Argument('*const %s' % descriptor.concreteType, 'this'), + args = [Argument('*mut JSContext', 'cx'), + Argument('RawHandleObject', '_obj'), + Argument('*mut libc::c_void', 'this'), Argument('*const JSJitMethodCallArgs', 'args')] CGAbstractExternMethod.__init__(self, descriptor, name, 'bool', args) @@ -3678,7 +3685,8 @@ class CGSpecializedMethod(CGAbstractExternMethod): self.method) return CGWrapper(CGMethodCall([], nativeName, self.method.isStatic(), self.descriptor, self.method), - pre="let this = &*this;\n" + pre="let cx = SafeJSContext::from_ptr(cx);\n" + + ("let this = &*(this as *const %s);\n" % self.descriptor.concreteType) + "let args = &*args;\n" "let argc = args.argc_;\n") @@ -3701,7 +3709,7 @@ class CGDefaultToJSONMethod(CGSpecializedMethod): def definition_body(self): ret = dedent(""" use crate::dom::bindings::inheritance::HasParent; - rooted!(in(*cx) let result = JS_NewPlainObject(*cx)); + rooted!(in(cx) let result = JS_NewPlainObject(cx)); if result.is_null() { return false; } @@ -3717,17 +3725,16 @@ class CGDefaultToJSONMethod(CGSpecializedMethod): parents = len(jsonDescriptors) - 1 form = """ - if !${parentclass}CollectJSONAttributes(cx, _obj, this${asparent}, &result) { + if !${parentclass}CollectJSONAttributes(cx, _obj, this, &result) { return false; } """ # Iterate the array in reverse: oldest ancestor first for descriptor in jsonDescriptors[:0:-1]: - ret += fill(form, parentclass=toBindingNamespace(descriptor.name) + "::", - asparent=".as_ref().unwrap()" + ".as_parent()" * parents) + ret += fill(form, parentclass=toBindingNamespace(descriptor.name) + "::") parents -= 1 - ret += fill(form, parentclass="", asparent="") + ret += fill(form, parentclass="") ret += ('(*args).rval().set(ObjectValue(*result));\n' 'return true;\n') return CGGeneric(ret) @@ -3759,9 +3766,9 @@ class CGSpecializedGetter(CGAbstractExternMethod): def __init__(self, descriptor, attr): self.attr = attr name = 'get_' + descriptor.internalNameFor(attr.identifier.name) - args = [Argument('SafeJSContext', 'cx'), - Argument('HandleObject', '_obj'), - Argument('*const %s' % descriptor.concreteType, 'this'), + args = [Argument('*mut JSContext', 'cx'), + Argument('RawHandleObject', '_obj'), + Argument('*mut libc::c_void', 'this'), Argument('JSJitGetterCallArgs', 'args')] CGAbstractExternMethod.__init__(self, descriptor, name, "bool", args) @@ -3771,7 +3778,8 @@ class CGSpecializedGetter(CGAbstractExternMethod): return CGWrapper(CGGetterCall([], self.attr.type, nativeName, self.descriptor, self.attr), - pre="let this = &*this;\n") + pre="let cx = SafeJSContext::from_ptr(cx);\n" + + ("let this = &*(this as *const %s);\n" % self.descriptor.concreteType)) @staticmethod def makeNativeName(descriptor, attr): @@ -3815,9 +3823,9 @@ class CGSpecializedSetter(CGAbstractExternMethod): def __init__(self, descriptor, attr): self.attr = attr name = 'set_' + descriptor.internalNameFor(attr.identifier.name) - args = [Argument('SafeJSContext', 'cx'), - Argument('HandleObject', 'obj'), - Argument('*const %s' % descriptor.concreteType, 'this'), + args = [Argument('*mut JSContext', 'cx'), + Argument('RawHandleObject', 'obj'), + Argument('*mut libc::c_void', 'this'), Argument('JSJitSetterCallArgs', 'args')] CGAbstractExternMethod.__init__(self, descriptor, name, "bool", args) @@ -3826,7 +3834,8 @@ class CGSpecializedSetter(CGAbstractExternMethod): self.attr) return CGWrapper(CGSetterCall([], self.attr.type, nativeName, self.descriptor, self.attr), - pre="let this = &*this;\n") + pre="let cx = SafeJSContext::from_ptr(cx);\n" + + ("let this = &*(this as *const %s);\n" % self.descriptor.concreteType)) @staticmethod def makeNativeName(descriptor, attr): @@ -3875,8 +3884,9 @@ class CGSpecializedForwardingSetter(CGSpecializedSetter): assert all(ord(c) < 128 for c in attrName) assert all(ord(c) < 128 for c in forwardToAttrName) return CGGeneric("""\ +let cx = SafeJSContext::from_ptr(cx); rooted!(in(*cx) let mut v = UndefinedValue()); -if !JS_GetProperty(*cx, obj, %s as *const u8 as *const libc::c_char, v.handle_mut()) { +if !JS_GetProperty(*cx, HandleObject::from_raw(obj), %s as *const u8 as *const libc::c_char, v.handle_mut()) { return false; } if !v.is_object() { @@ -3901,7 +3911,7 @@ class CGSpecializedReplaceableSetter(CGSpecializedSetter): # JS_DefineProperty can only deal with ASCII. assert all(ord(c) < 128 for c in name) return CGGeneric("""\ -JS_DefineProperty(*cx, obj, %s as *const u8 as *const libc::c_char, +JS_DefineProperty(cx, HandleObject::from_raw(obj), %s as *const u8 as *const libc::c_char, HandleValue::from_raw(args.get(0)), JSPROP_ENUMERATE as u32)""" % name) @@ -3931,27 +3941,34 @@ class CGMemberJITInfo(CGThing): initializer = fill( """ JSJitInfo { - call: ${opName} as *const os::raw::c_void, - protoID: PrototypeList::ID::${name} as u16, - depth: ${depth}, - _bitfield_1: new_jsjitinfo_bitfield_1!( - JSJitInfo_OpType::${opType} as u8, - JSJitInfo_AliasSet::${aliasSet} as u8, - JSValueType::${returnType} as u8, - ${isInfallible}, - ${isMovable}, - ${isEliminatable}, - ${isAlwaysInSlot}, - ${isLazilyCachedInSlot}, - ${isTypedMethod}, - ${slotIndex}, - ), + __bindgen_anon_1: JSJitInfo__bindgen_ty_1 { + ${opKind}: Some(${opName}) + }, + __bindgen_anon_2: JSJitInfo__bindgen_ty_2 { + protoID: PrototypeList::ID::${name} as u16, + }, + __bindgen_anon_3: JSJitInfo__bindgen_ty_3 { depth: ${depth} }, + _bitfield_1: unsafe { + mem::transmute(new_jsjitinfo_bitfield_1!( + JSJitInfo_OpType::${opType} as u8, + JSJitInfo_AliasSet::${aliasSet} as u8, + JSValueType::${returnType} as u8, + ${isInfallible}, + ${isMovable}, + ${isEliminatable}, + ${isAlwaysInSlot}, + ${isLazilyCachedInSlot}, + ${isTypedMethod}, + ${slotIndex}, + )) + }, } """, opName=opName, name=self.descriptor.name, depth=self.descriptor.interface.inheritanceDepth(), opType=opType, + opKind=opType.lower(), aliasSet=aliasSet, returnType=functools.reduce(CGMemberJITInfo.getSingleReturnType, returnTypes, ""), @@ -4211,7 +4228,7 @@ class CGMemberJITInfo(CGThing): return "JSJitInfo_ArgType::Object as i32" if t.isUnion(): u = t.unroll() - type = "JSJitInfo::Null as i32" if u.hasNullableType else "" + type = "JSJitInfo_ArgType::Null as i32" if u.hasNullableType else "" return functools.reduce(CGMemberJITInfo.getSingleArgType, u.flatMemberTypes, type) if t.isDictionary(): @@ -5311,7 +5328,7 @@ class CGDOMJSProxyHandler_ownPropertyKeys(CGAbstractExternMethod): def __init__(self, descriptor): args = [Argument('*mut JSContext', 'cx'), Argument('RawHandleObject', 'proxy'), - Argument('*mut AutoIdVector', 'props')] + Argument('RawMutableHandleIdVector', 'props')] CGAbstractExternMethod.__init__(self, descriptor, "own_property_keys", "bool", args) self.descriptor = descriptor @@ -5328,7 +5345,7 @@ class CGDOMJSProxyHandler_ownPropertyKeys(CGAbstractExternMethod): for i in 0..(*unwrapped_proxy).Length() { rooted!(in(*cx) let mut rooted_jsid: jsid); int_to_jsid(i as i32, rooted_jsid.handle_mut()); - AppendToAutoIdVector(props, rooted_jsid.handle()); + AppendToIdVector(props, rooted_jsid.handle()); } """) @@ -5341,7 +5358,7 @@ class CGDOMJSProxyHandler_ownPropertyKeys(CGAbstractExternMethod): rooted!(in(*cx) let rooted = jsstring); rooted!(in(*cx) let mut rooted_jsid: jsid); RUST_INTERNED_STRING_TO_JSID(*cx, rooted.handle().get(), rooted_jsid.handle_mut()); - AppendToAutoIdVector(props, rooted_jsid.handle()); + AppendToIdVector(props, rooted_jsid.handle()); } """) @@ -5369,7 +5386,7 @@ class CGDOMJSProxyHandler_getOwnEnumerablePropertyKeys(CGAbstractExternMethod): descriptor.interface.getExtendedAttribute("LegacyUnenumerableNamedProperties")) args = [Argument('*mut JSContext', 'cx'), Argument('RawHandleObject', 'proxy'), - Argument('*mut AutoIdVector', 'props')] + Argument('RawMutableHandleIdVector', 'props')] CGAbstractExternMethod.__init__(self, descriptor, "getOwnEnumerablePropertyKeys", "bool", args) self.descriptor = descriptor @@ -5387,7 +5404,7 @@ class CGDOMJSProxyHandler_getOwnEnumerablePropertyKeys(CGAbstractExternMethod): for i in 0..(*unwrapped_proxy).Length() { rooted!(in(*cx) let mut rooted_jsid: jsid); int_to_jsid(i as i32, rooted_jsid.handle_mut()); - AppendToAutoIdVector(props, rooted_jsid.handle()); + AppendToIdVector(props, rooted_jsid.handle()); } """) @@ -5917,11 +5934,9 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::JS_CALLEE', 'js::error::throw_type_error', 'js::error::throw_internal_error', - 'js::jsapi::AutoIdVector', 'js::rust::wrappers::Call', 'js::jsapi::CallArgs', 'js::jsapi::CurrentGlobalOrNull', - 'js::jsapi::FreeOp', 'js::rust::wrappers::GetPropertyKeys', 'js::jsapi::GetWellKnownSymbol', 'js::rust::Handle', @@ -5948,6 +5963,9 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::jsapi::JSITER_SYMBOLS', 'js::jsapi::JSJitGetterCallArgs', 'js::jsapi::JSJitInfo', + 'js::jsapi::JSJitInfo__bindgen_ty_1', + 'js::jsapi::JSJitInfo__bindgen_ty_2', + 'js::jsapi::JSJitInfo__bindgen_ty_3', 'js::jsapi::JSJitInfo_AliasSet', 'js::jsapi::JSJitInfo_ArgType', 'js::jsapi::JSJitInfo_OpType', @@ -5960,10 +5978,10 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::jsapi::JSPROP_PERMANENT', 'js::jsapi::JSPROP_READONLY', 'js::jsapi::JSPropertySpec', - 'js::jsapi::JSPropertySpec__bindgen_ty_1', - 'js::jsapi::JSPropertySpec__bindgen_ty_1__bindgen_ty_1', - 'js::jsapi::JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_1', - 'js::jsapi::JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_2', + 'js::jsapi::JSPropertySpec_Accessor', + 'js::jsapi::JSPropertySpec_AccessorsOrValue', + 'js::jsapi::JSPropertySpec_AccessorsOrValue_Accessors', + 'js::jsapi::JSPropertySpec_Name', 'js::jsapi::JSString', 'js::jsapi::JSTracer', 'js::jsapi::JSType', @@ -6005,6 +6023,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::jsapi::MutableHandleObject as RawMutableHandleObject', 'js::rust::MutableHandleValue', 'js::jsapi::MutableHandleValue as RawMutableHandleValue', + 'js::jsapi::MutableHandleIdVector as RawMutableHandleIdVector', 'js::jsapi::ObjectOpResult', 'js::jsapi::PropertyDescriptor', 'js::jsapi::Rooted', @@ -6020,7 +6039,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::jsval::PrivateValue', 'js::jsval::UndefinedValue', 'js::jsapi::UndefinedHandleValue', - 'js::rust::wrappers::AppendToAutoIdVector', + 'js::rust::wrappers::AppendToIdVector', 'js::glue::CallJitGetterOp', 'js::glue::CallJitMethodOp', 'js::glue::CallJitSetterOp', -- cgit v1.2.3 From 05077d31c8083644d004c559a4cf8423dbd48d66 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Fri, 6 Mar 2020 18:45:29 +0100 Subject: Change how we reflect DOM objects in codegen We now go through >>::reflect_with, to decrease the amount of bad stuff we can end up doing. This avoids a source of vtable pointer instability that could cause issues down the road. --- components/script/dom/bindings/codegen/CodegenRust.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index a06414c306e..f7ce60cc80c 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2728,7 +2728,7 @@ assert!(!obj.is_null()); SetProxyReservedSlot( obj.get(), 0, - &PrivateValue(&*raw as *const %(concreteType)s as *const libc::c_void), + &PrivateValue(raw.as_ptr() as *const %(concreteType)s as *const libc::c_void), ); """ else: @@ -2742,7 +2742,7 @@ assert!(!obj.is_null()); JS_SetReservedSlot( obj.get(), DOM_OBJECT_SLOT, - &PrivateValue(&*raw as *const %(concreteType)s as *const libc::c_void), + &PrivateValue(raw.as_ptr() as *const %(concreteType)s as *const libc::c_void), ); """ create = create % {"concreteType": self.descriptor.concreteType} @@ -2765,11 +2765,11 @@ GetProtoObject(cx, scope, proto.handle_mut()); assert!(!proto.is_null()); %(createObject)s -raw.init_reflector(obj.get()); +let root = raw.reflect_with(obj.get()); %(copyUnforgeable)s -DomRoot::from_ref(&*raw)\ +DomRoot::from_ref(&*root)\ """ % {'copyUnforgeable': unforgeable, 'createObject': create}) @@ -2809,12 +2809,12 @@ rooted!(in(*cx) let mut obj = ptr::null_mut::()); create_global_object( cx, &Class.base, - &*raw as *const %(concreteType)s as *const libc::c_void, + raw.as_ptr() as *const %(concreteType)s as *const libc::c_void, _trace, obj.handle_mut()); assert!(!obj.is_null()); -raw.init_reflector(obj.get()); +let root = raw.reflect_with(obj.get()); let _ac = JSAutoRealm::new(*cx, obj.get()); rooted!(in(*cx) let mut proto = ptr::null_mut::()); @@ -2828,7 +2828,7 @@ assert!(immutable); %(unforgeable)s -DomRoot::from_ref(&*raw)\ +DomRoot::from_ref(&*root)\ """ % values) -- cgit v1.2.3 From 4930479ac813775a26acc21f7175bd06d10f5647 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 14 Mar 2020 10:54:04 +0100 Subject: Update the WebIDL parser Upstream doesn't allow downloading .tar.gz archives so update.sh was changed to use unzip. --- .../script/dom/bindings/codegen/CodegenRust.py | 32 +-- .../script/dom/bindings/codegen/parser/WebIDL.py | 315 +++++++++++++++------ .../parser/ext-attribute-no-value-error.patch | 11 + .../parser/tests/test_attributes_on_types.py | 221 +++++++++++++-- .../codegen/parser/tests/test_constructor.py | 71 ++++- .../dom/bindings/codegen/parser/tests/test_date.py | 15 - .../parser/tests/test_distinguishability.py | 27 +- .../parser/tests/test_extended_attributes.py | 8 +- .../parser/tests/test_nullable_equivalency.py | 2 +- .../bindings/codegen/parser/tests/test_toJSON.py | 11 +- .../script/dom/bindings/codegen/parser/update.sh | 6 +- 11 files changed, 524 insertions(+), 195 deletions(-) create mode 100644 components/script/dom/bindings/codegen/parser/ext-attribute-no-value-error.patch delete mode 100644 components/script/dom/bindings/codegen/parser/tests/test_date.py (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index f7ce60cc80c..a9515fb099d 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -427,17 +427,6 @@ class CGMethodCall(CGThing): (s[1][distinguishingIndex].type.isSequence() or s[1][distinguishingIndex].type.isObject())) - # Check for Date objects - # XXXbz Do we need to worry about security wrappers around the Date? - pickFirstSignature("%s.get().is_object() && " - "{ rooted!(in(*cx) let obj = %s.get().to_object()); " - "let mut is_date = false; " - "assert!(ObjectIsDate(*cx, obj.handle(), &mut is_date)); " - "is_date }" % - (distinguishingArg, distinguishingArg), - lambda s: (s[1][distinguishingIndex].type.isDate() or - s[1][distinguishingIndex].type.isObject())) - # Check for vanilla JS objects # XXXbz Do we need to worry about security wrappers? pickFirstSignature("%s.get().is_object() && !is_platform_object(%s.get().to_object(), *cx)" % @@ -596,8 +585,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, # We should not have a defaultValue if we know we're an object assert not isDefinitelyObject or defaultValue is None - isEnforceRange = type.enforceRange - isClamp = type.clamp + isEnforceRange = type.hasEnforceRange() + isClamp = type.hasClamp() if type.treatNullAsEmpty: treatNullAs = "EmptyString" else: @@ -4162,8 +4151,6 @@ class CGMemberJITInfo(CGThing): u.flatMemberTypes, "") if t.isDictionary(): return "JSVAL_TYPE_OBJECT" - if t.isDate(): - return "JSVAL_TYPE_OBJECT" if not t.isPrimitive(): raise TypeError("No idea what type " + str(t) + " is.") tag = t.tag() @@ -4233,8 +4220,6 @@ class CGMemberJITInfo(CGThing): u.flatMemberTypes, type) if t.isDictionary(): return "JSJitInfo_ArgType::Object as i32" - if t.isDate(): - return "JSJitInfo_ArgType::Object as i32" if not t.isPrimitive(): raise TypeError("No idea what type " + str(t) + " is.") tag = t.tag() @@ -4540,13 +4525,6 @@ class CGUnionConversionStruct(CGThing): else: arrayObject = None - dateObjectMemberTypes = filter(lambda t: t.isDate(), memberTypes) - if len(dateObjectMemberTypes) > 0: - assert len(dateObjectMemberTypes) == 1 - raise TypeError("Can't handle dates in unions.") - else: - dateObject = None - callbackMemberTypes = filter(lambda t: t.isCallback() or t.isCallbackInterface(), memberTypes) if len(callbackMemberTypes) > 0: assert len(callbackMemberTypes) == 1 @@ -4582,10 +4560,10 @@ class CGUnionConversionStruct(CGThing): else: mozMapObject = None - hasObjectTypes = object or interfaceObject or arrayObject or dateObject or callbackObject or mozMapObject + hasObjectTypes = object or interfaceObject or arrayObject or callbackObject or mozMapObject if hasObjectTypes: # "object" is not distinguishable from other types - assert not object or not (interfaceObject or arrayObject or dateObject or callbackObject or mozMapObject) + assert not object or not (interfaceObject or arrayObject or callbackObject or mozMapObject) templateBody = CGList([], "\n") if object: templateBody.append(object) @@ -6848,7 +6826,7 @@ def type_needs_tracing(t): def is_typed_array(t): assert isinstance(t, IDLObject), (t, type(t)) - return t.isTypedArray() or t.isArrayBuffer() or t.isArrayBufferView() or t.isSharedArrayBuffer() + return t.isTypedArray() or t.isArrayBuffer() or t.isArrayBufferView() def type_needs_auto_root(t): diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index b2e56c9deaf..223fd7efbb4 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.py @@ -481,9 +481,6 @@ class IDLExposureMixins(): def isExposedInWindow(self): return 'Window' in self.exposureSet - def isExposedOnMainThread(self): - return self.isExposedInWindow() - def isExposedInAnyWorker(self): return len(self.getWorkerExposureSet()) > 0 @@ -2090,9 +2087,9 @@ class IDLType(IDLObject): 'domstring', 'bytestring', 'usvstring', + 'utf8string', 'jsstring', 'object', - 'date', 'void', # Funny stuff 'interface', @@ -2109,15 +2106,17 @@ class IDLType(IDLObject): IDLObject.__init__(self, location) self.name = name self.builtin = False - self.clamp = False self.treatNullAsEmpty = False - self.enforceRange = False + self._clamp = False + self._enforceRange = False + self._allowShared = False self._extendedAttrDict = {} def __eq__(self, other): return (other and self.builtin == other.builtin and self.name == other.name and - self.clamp == other.clamp and self.enforceRange == other.enforceRange and - self.treatNullAsEmpty == other.treatNullAsEmpty) + self._clamp == other.hasClamp() and self._enforceRange == other.hasEnforceRange() and + self.treatNullAsEmpty == other.treatNullAsEmpty and + self._allowShared == other.hasAllowShared()) def __ne__(self, other): return not self == other @@ -2125,6 +2124,14 @@ class IDLType(IDLObject): def __str__(self): return str(self.name) + def prettyName(self): + """ + A name that looks like what this type is named in the IDL spec. By default + this is just our .name, but types that have more interesting spec + representations should override this. + """ + return str(self.name) + def isType(self): return True @@ -2152,6 +2159,9 @@ class IDLType(IDLObject): def isUSVString(self): return False + def isUTF8String(self): + return False + def isJSString(self): return False @@ -2173,12 +2183,12 @@ class IDLType(IDLObject): def isArrayBufferView(self): return False - def isSharedArrayBuffer(self): - return False - def isTypedArray(self): return False + def isBufferSource(self): + return self.isArrayBuffer() or self.isArrayBufferView() or self.isTypedArray() + def isCallbackInterface(self): return False @@ -2195,10 +2205,7 @@ class IDLType(IDLObject): def isSpiderMonkeyInterface(self): """ Returns a boolean indicating whether this type is an 'interface' type that is implemented in SpiderMonkey. """ - return self.isInterface() and (self.isArrayBuffer() or - self.isArrayBufferView() or - self.isSharedArrayBuffer() or - self.isTypedArray() or + return self.isInterface() and (self.isBufferSource() or self.isReadableStream()) def isDictionary(self): @@ -2210,9 +2217,6 @@ class IDLType(IDLObject): def isAny(self): return self.tag() == IDLType.Tags.any - def isDate(self): - return self.tag() == IDLType.Tags.date - def isObject(self): return self.tag() == IDLType.Tags.object @@ -2235,6 +2239,15 @@ class IDLType(IDLObject): def isJSONType(self): return False + def hasClamp(self): + return self._clamp + + def hasEnforceRange(self): + return self._enforceRange + + def hasAllowShared(self): + return self._allowShared + def tag(self): assert False # Override me! @@ -2342,10 +2355,7 @@ class IDLNullableType(IDLParametrizedType): assert not innerType.isVoid() assert not innerType == BuiltinTypes[IDLBuiltinType.Types.any] - name = innerType.name - if innerType.isComplete(): - name += "OrNull" - IDLParametrizedType.__init__(self, location, name, innerType) + IDLParametrizedType.__init__(self, location, None, innerType) def __eq__(self, other): return isinstance(other, IDLNullableType) and self.inner == other.inner @@ -2353,6 +2363,9 @@ class IDLNullableType(IDLParametrizedType): def __str__(self): return self.inner.__str__() + "OrNull" + def prettyName(self): + return self.inner.prettyName() + "?" + def nullable(self): return True @@ -2380,6 +2393,9 @@ class IDLNullableType(IDLParametrizedType): def isUSVString(self): return self.inner.isUSVString() + def isUTF8String(self): + return self.inner.isUTF8String() + def isJSString(self): return self.inner.isJSString() @@ -2410,9 +2426,6 @@ class IDLNullableType(IDLParametrizedType): def isArrayBufferView(self): return self.inner.isArrayBufferView() - def isSharedArrayBuffer(self): - return self.inner.isSharedArrayBuffer() - def isTypedArray(self): return self.inner.isTypedArray() @@ -2442,11 +2455,26 @@ class IDLNullableType(IDLParametrizedType): def isJSONType(self): return self.inner.isJSONType() + def hasClamp(self): + return self.inner.hasClamp() + + def hasEnforceRange(self): + return self.inner.hasEnforceRange() + + def hasAllowShared(self): + return self.inner.hasAllowShared() + + def isComplete(self): + return self.name is not None + def tag(self): return self.inner.tag() def complete(self, scope): - self.inner = self.inner.complete(scope) + if not self.inner.isComplete(): + self.inner = self.inner.complete(scope) + assert self.inner.isComplete() + if self.inner.nullable(): raise WebIDLError("The inner type of a nullable type must not be " "a nullable type", @@ -2456,6 +2484,10 @@ class IDLNullableType(IDLParametrizedType): raise WebIDLError("The inner type of a nullable type must not " "be a union type that itself has a nullable " "type as a member type", [self.location]) + if self.inner.isDOMString(): + if self.inner.treatNullAsEmpty: + raise WebIDLError("[TreatNullAs] not allowed on a nullable DOMString", + [self.location, self.inner.location]) self.name = self.inner.name + "OrNull" return self @@ -2469,6 +2501,13 @@ class IDLNullableType(IDLParametrizedType): return False return self.inner.isDistinguishableFrom(other) + def withExtendedAttributes(self, attrs): + # See https://github.com/heycam/webidl/issues/827#issuecomment-565131350 + # Allowing extended attributes to apply to a nullable type is an intermediate solution. + # A potential longer term solution is to introduce a null type and get rid of nullables. + # For example, we could do `([Clamp] long or null) foo` in the future. + return IDLNullableType(self.location, self.inner.withExtendedAttributes(attrs)) + class IDLSequenceType(IDLParametrizedType): def __init__(self, location, parameterType): @@ -2486,6 +2525,9 @@ class IDLSequenceType(IDLParametrizedType): def __str__(self): return self.inner.__str__() + "Sequence" + def prettyName(self): + return "sequence<%s>" % self.inner.prettyName() + def nullable(self): return False @@ -2504,6 +2546,9 @@ class IDLSequenceType(IDLParametrizedType): def isUSVString(self): return False + def isUTF8String(self): + return False + def isJSString(self): return False @@ -2540,8 +2585,7 @@ class IDLSequenceType(IDLParametrizedType): # Just forward to the union; it'll deal return other.isDistinguishableFrom(self) return (other.isPrimitive() or other.isString() or other.isEnum() or - other.isDate() or other.isInterface() or - other.isDictionary() or + other.isInterface() or other.isDictionary() or other.isCallback() or other.isRecord()) @@ -2565,6 +2609,9 @@ class IDLRecordType(IDLParametrizedType): def __str__(self): return self.keyType.__str__() + self.inner.__str__() + "Record" + def prettyName(self): + return "record<%s, %s>" % (self.keyType.prettyName(), self.inner.prettyName()) + def isRecord(self): return True @@ -2592,7 +2639,7 @@ class IDLRecordType(IDLParametrizedType): # Just forward to the union; it'll deal return other.isDistinguishableFrom(self) return (other.isPrimitive() or other.isString() or other.isEnum() or - other.isDate() or other.isNonCallbackInterface() or other.isSequence()) + other.isNonCallbackInterface() or other.isSequence()) def isExposedInAllOf(self, exposureSet): return self.inner.unroll().isExposedInAllOf(exposureSet) @@ -2614,6 +2661,9 @@ class IDLUnionType(IDLType): assert self.isComplete() return self.name.__hash__() + def prettyName(self): + return "(" + " or ".join(m.prettyName() for m in self.memberTypes) + ")" + def isVoid(self): return False @@ -2645,6 +2695,9 @@ class IDLUnionType(IDLType): return typeName(type._identifier.object()) if isinstance(type, IDLObjectWithIdentifier): return typeName(type.identifier) + if isinstance(type, IDLBuiltinType) and type.hasAllowShared(): + assert type.isBufferSource() + return "MaybeShared" + type.name return type.name for (i, type) in enumerate(self.memberTypes): @@ -2768,6 +2821,9 @@ class IDLTypedefType(IDLType): def isUSVString(self): return self.inner.isUSVString() + def isUTF8String(self): + return self.inner.isUTF8String() + def isJSString(self): return self.inner.isJSString() @@ -2795,9 +2851,6 @@ class IDLTypedefType(IDLType): def isArrayBufferView(self): return self.inner.isArrayBufferView() - def isSharedArrayBuffer(self): - return self.inner.isSharedArrayBuffer() - def isTypedArray(self): return self.inner.isTypedArray() @@ -2901,6 +2954,9 @@ class IDLWrapperType(IDLType): def isUSVString(self): return False + def isUTF8String(self): + return False + def isJSString(self): return False @@ -2976,11 +3032,11 @@ class IDLWrapperType(IDLType): if self.isEnum(): return (other.isPrimitive() or other.isInterface() or other.isObject() or other.isCallback() or other.isDictionary() or - other.isSequence() or other.isRecord() or other.isDate()) + other.isSequence() or other.isRecord()) if self.isDictionary() and other.nullable(): return False if (other.isPrimitive() or other.isString() or other.isEnum() or - other.isDate() or other.isSequence()): + other.isSequence()): return True if self.isDictionary(): return other.isNonCallbackInterface() @@ -3052,6 +3108,9 @@ class IDLPromiseType(IDLParametrizedType): def __str__(self): return self.inner.__str__() + "Promise" + def prettyName(self): + return "Promise<%s>" % self.inner.prettyName() + def isPromise(self): return True @@ -3104,14 +3163,13 @@ class IDLBuiltinType(IDLType): 'domstring', 'bytestring', 'usvstring', + 'utf8string', 'jsstring', 'object', - 'date', 'void', # Funny stuff 'ArrayBuffer', 'ArrayBufferView', - 'SharedArrayBuffer', 'Int8Array', 'Uint8Array', 'Uint8ClampedArray', @@ -3142,13 +3200,12 @@ class IDLBuiltinType(IDLType): Types.domstring: IDLType.Tags.domstring, Types.bytestring: IDLType.Tags.bytestring, Types.usvstring: IDLType.Tags.usvstring, + Types.utf8string: IDLType.Tags.utf8string, Types.jsstring: IDLType.Tags.jsstring, Types.object: IDLType.Tags.object, - Types.date: IDLType.Tags.date, Types.void: IDLType.Tags.void, Types.ArrayBuffer: IDLType.Tags.interface, Types.ArrayBufferView: IDLType.Tags.interface, - Types.SharedArrayBuffer: IDLType.Tags.interface, Types.Int8Array: IDLType.Tags.interface, Types.Uint8Array: IDLType.Tags.interface, Types.Uint8ClampedArray: IDLType.Tags.interface, @@ -3161,11 +3218,48 @@ class IDLBuiltinType(IDLType): Types.ReadableStream: IDLType.Tags.interface, } + PrettyNames = { + Types.byte: "byte", + Types.octet: "octet", + Types.short: "short", + Types.unsigned_short: "unsigned short", + Types.long: "long", + Types.unsigned_long: "unsigned long", + Types.long_long: "long long", + Types.unsigned_long_long: "unsigned long long", + Types.boolean: "boolean", + Types.unrestricted_float: "unrestricted float", + Types.float: "float", + Types.unrestricted_double: "unrestricted double", + Types.double: "double", + Types.any: "any", + Types.domstring: "DOMString", + Types.bytestring: "ByteString", + Types.usvstring: "USVString", + Types.utf8string: "USVString", # That's what it is in spec terms + Types.jsstring: "USVString", # Again, that's what it is in spec terms + Types.object: "object", + Types.void: "void", + Types.ArrayBuffer: "ArrayBuffer", + Types.ArrayBufferView: "ArrayBufferView", + Types.Int8Array: "Int8Array", + Types.Uint8Array: "Uint8Array", + Types.Uint8ClampedArray: "Uint8ClampedArray", + Types.Int16Array: "Int16Array", + Types.Uint16Array: "Uint16Array", + Types.Int32Array: "Int32Array", + Types.Uint32Array: "Uint32Array", + Types.Float32Array: "Float32Array", + Types.Float64Array: "Float64Array", + Types.ReadableStream: "ReadableStream", + } + def __init__(self, location, name, type, clamp=False, enforceRange=False, treatNullAsEmpty=False, - attrLocation=[]): + allowShared=False, attrLocation=[]): """ - The mutually exclusive clamp/enforceRange/treatNullAsEmpty arguments are used to create instances - of this type with the appropriate attributes attached. Use .clamped(), .rangeEnforced(), and .treatNullAs(). + The mutually exclusive clamp/enforceRange/treatNullAsEmpty/allowShared arguments are used + to create instances of this type with the appropriate attributes attached. Use .clamped(), + .rangeEnforced(), .withTreatNullAs() and .withAllowShared(). attrLocation is an array of source locations of these attributes for error reporting. """ @@ -3175,24 +3269,40 @@ class IDLBuiltinType(IDLType): self._clamped = None self._rangeEnforced = None self._withTreatNullAs = None - if self.isNumeric(): + self._withAllowShared = None; + if self.isInteger(): if clamp: - self.clamp = True + self._clamp = True self.name = "Clamped" + self.name self._extendedAttrDict["Clamp"] = True elif enforceRange: - self.enforceRange = True + self._enforceRange = True self.name = "RangeEnforced" + self.name self._extendedAttrDict["EnforceRange"] = True elif clamp or enforceRange: - raise WebIDLError("Non-numeric types cannot be [Clamp] or [EnforceRange]", attrLocation) - if self.isDOMString(): + raise WebIDLError("Non-integer types cannot be [Clamp] or [EnforceRange]", attrLocation) + if self.isDOMString() or self.isUTF8String(): if treatNullAsEmpty: self.treatNullAsEmpty = True self.name = "NullIsEmpty" + self.name self._extendedAttrDict["TreatNullAs"] = ["EmptyString"] elif treatNullAsEmpty: raise WebIDLError("Non-string types cannot be [TreatNullAs]", attrLocation) + if self.isBufferSource(): + if allowShared: + self._allowShared = True + self._extendedAttrDict["AllowShared"] = True + elif allowShared: + raise WebIDLError("Types that are not buffer source types cannot be [AllowShared]", attrLocation) + + def __str__(self): + if self._allowShared: + assert self.isBufferSource() + return "MaybeShared" + str(self.name) + return str(self.name) + + def prettyName(self): + return IDLBuiltinType.PrettyNames[self._typeTag] def clamped(self, attrLocation): if not self._clamped: @@ -3215,6 +3325,13 @@ class IDLBuiltinType(IDLType): attrLocation=attrLocation) return self._withTreatNullAs + def withAllowShared(self, attrLocation): + if not self._withAllowShared: + self._withAllowShared = IDLBuiltinType(self.location, self.name, + self._typeTag, allowShared=True, + attrLocation=attrLocation) + return self._withAllowShared + def isPrimitive(self): return self._typeTag <= IDLBuiltinType.Types.double @@ -3228,6 +3345,7 @@ class IDLBuiltinType(IDLType): return (self._typeTag == IDLBuiltinType.Types.domstring or self._typeTag == IDLBuiltinType.Types.bytestring or self._typeTag == IDLBuiltinType.Types.usvstring or + self._typeTag == IDLBuiltinType.Types.utf8string or self._typeTag == IDLBuiltinType.Types.jsstring) def isByteString(self): @@ -3239,6 +3357,9 @@ class IDLBuiltinType(IDLType): def isUSVString(self): return self._typeTag == IDLBuiltinType.Types.usvstring + def isUTF8String(self): + return self._typeTag == IDLBuiltinType.Types.utf8string + def isJSString(self): return self._typeTag == IDLBuiltinType.Types.jsstring @@ -3251,9 +3372,6 @@ class IDLBuiltinType(IDLType): def isArrayBufferView(self): return self._typeTag == IDLBuiltinType.Types.ArrayBufferView - def isSharedArrayBuffer(self): - return self._typeTag == IDLBuiltinType.Types.SharedArrayBuffer - def isTypedArray(self): return (self._typeTag >= IDLBuiltinType.Types.Int8Array and self._typeTag <= IDLBuiltinType.Types.Float64Array) @@ -3267,7 +3385,6 @@ class IDLBuiltinType(IDLType): # all of it internally. return (self.isArrayBuffer() or self.isArrayBufferView() or - self.isSharedArrayBuffer() or self.isTypedArray() or self.isReadableStream()) @@ -3305,27 +3422,22 @@ class IDLBuiltinType(IDLType): return (other.isNumeric() or other.isString() or other.isEnum() or other.isInterface() or other.isObject() or other.isCallback() or other.isDictionary() or - other.isSequence() or other.isRecord() or other.isDate()) + other.isSequence() or other.isRecord()) if self.isNumeric(): return (other.isBoolean() or other.isString() or other.isEnum() or other.isInterface() or other.isObject() or other.isCallback() or other.isDictionary() or - other.isSequence() or other.isRecord() or other.isDate()) + other.isSequence() or other.isRecord()) if self.isString(): return (other.isPrimitive() or other.isInterface() or other.isObject() or other.isCallback() or other.isDictionary() or - other.isSequence() or other.isRecord() or other.isDate()) + other.isSequence() or other.isRecord()) if self.isAny(): # Can't tell "any" apart from anything return False if self.isObject(): return other.isPrimitive() or other.isString() or other.isEnum() - if self.isDate(): - return (other.isPrimitive() or other.isString() or other.isEnum() or - other.isInterface() or other.isCallback() or - other.isDictionary() or other.isSequence() or - other.isRecord()) if self.isVoid(): return not other.isVoid() # Not much else we could be! @@ -3333,12 +3445,11 @@ class IDLBuiltinType(IDLType): # Like interfaces, but we know we're not a callback return (other.isPrimitive() or other.isString() or other.isEnum() or other.isCallback() or other.isDictionary() or - other.isSequence() or other.isRecord() or other.isDate() or + other.isSequence() or other.isRecord() or (other.isInterface() and ( # ArrayBuffer is distinguishable from everything # that's not an ArrayBuffer or a callback interface (self.isArrayBuffer() and not other.isArrayBuffer()) or - (self.isSharedArrayBuffer() and not other.isSharedArrayBuffer()) or (self.isReadableStream() and not other.isReadableStream()) or # ArrayBufferView is distinguishable from everything # that's not an ArrayBufferView or typed array. @@ -3361,7 +3472,7 @@ class IDLBuiltinType(IDLType): if not attribute.noArguments(): raise WebIDLError("[Clamp] must take no arguments", [attribute.location]) - if ret.enforceRange or self.enforceRange: + if ret.hasEnforceRange() or self._enforceRange: raise WebIDLError("[EnforceRange] and [Clamp] are mutually exclusive", [self.location, attribute.location]) ret = self.clamped([self.location, attribute.location]) @@ -3369,17 +3480,17 @@ class IDLBuiltinType(IDLType): if not attribute.noArguments(): raise WebIDLError("[EnforceRange] must take no arguments", [attribute.location]) - if ret.clamp or self.clamp: + if ret.hasClamp() or self._clamp: raise WebIDLError("[EnforceRange] and [Clamp] are mutually exclusive", [self.location, attribute.location]) ret = self.rangeEnforced([self.location, attribute.location]) elif identifier == "TreatNullAs": - if not self.isDOMString(): - raise WebIDLError("[TreatNullAs] only allowed on DOMStrings", + if not (self.isDOMString() or self.isUTF8String()): + raise WebIDLError("[TreatNullAs] only allowed on DOMStrings and UTF8Strings", [self.location, attribute.location]) assert not self.nullable() if not attribute.hasValue(): - raise WebIDLError("[TreatNullAs] must take an identifier argument" + raise WebIDLError("[TreatNullAs] must take an identifier argument", [attribute.location]) value = attribute.value() if value != 'EmptyString': @@ -3387,6 +3498,15 @@ class IDLBuiltinType(IDLType): "'EmptyString', not '%s'" % value, [attribute.location]) ret = self.withTreatNullAs([self.location, attribute.location]) + elif identifier == "AllowShared": + if not attribute.noArguments(): + raise WebIDLError("[AllowShared] must take no arguments", + [attribute.location]) + if not self.isBufferSource(): + raise WebIDLError("[AllowShared] only allowed on buffer source types", + [self.location, attribute.location]) + ret = self.withAllowShared([self.location, attribute.location]) + else: raise WebIDLError("Unhandled extended attribute on type", [self.location, attribute.location]) @@ -3444,15 +3564,15 @@ BuiltinTypes = { IDLBuiltinType.Types.usvstring: IDLBuiltinType(BuiltinLocation(""), "USVString", IDLBuiltinType.Types.usvstring), + IDLBuiltinType.Types.utf8string: + IDLBuiltinType(BuiltinLocation(""), "UTF8String", + IDLBuiltinType.Types.utf8string), IDLBuiltinType.Types.jsstring: IDLBuiltinType(BuiltinLocation(""), "JSString", IDLBuiltinType.Types.jsstring), IDLBuiltinType.Types.object: IDLBuiltinType(BuiltinLocation(""), "Object", IDLBuiltinType.Types.object), - IDLBuiltinType.Types.date: - IDLBuiltinType(BuiltinLocation(""), "Date", - IDLBuiltinType.Types.date), IDLBuiltinType.Types.void: IDLBuiltinType(BuiltinLocation(""), "Void", IDLBuiltinType.Types.void), @@ -3462,9 +3582,6 @@ BuiltinTypes = { IDLBuiltinType.Types.ArrayBufferView: IDLBuiltinType(BuiltinLocation(""), "ArrayBufferView", IDLBuiltinType.Types.ArrayBufferView), - IDLBuiltinType.Types.SharedArrayBuffer: - IDLBuiltinType(BuiltinLocation(""), "SharedArrayBuffer", - IDLBuiltinType.Types.SharedArrayBuffer), IDLBuiltinType.Types.Int8Array: IDLBuiltinType(BuiltinLocation(""), "Int8Array", IDLBuiltinType.Types.Int8Array), @@ -3613,8 +3730,9 @@ class IDLValue(IDLObject): # TreatNullAsEmpty is a different type for resolution reasons, # however once you have a value it doesn't matter return self - elif self.type.isString() and (type.isByteString() or type.isJSString()): - # Allow ByteStrings and JSStrings to use a default value like DOMString. + elif self.type.isString() and (type.isByteString() or type.isJSString() or type.isUTF8String()): + # Allow ByteStrings, UTF8String, and JSStrings to use a default + # value like DOMString. # No coercion is required as Codegen.py will handle the # extra steps. We want to make sure that our string contains # only valid characters, so we check that here. @@ -4307,8 +4425,9 @@ class IDLAttribute(IDLInterfaceMember): assert not isinstance(t.name, IDLUnresolvedIdentifier) self.type = t - if self.readonly and (self.type.clamp or self.type.enforceRange or self.type.treatNullAsEmpty): - raise WebIDLError("A readonly attribute cannot be [Clamp] or [EnforceRange]", + if self.readonly and (self.type.hasClamp() or self.type.hasEnforceRange() or + self.type.hasAllowShared() or self.type.treatNullAsEmpty): + raise WebIDLError("A readonly attribute cannot be [Clamp] or [EnforceRange] or [AllowShared]", [self.location]) if self.type.isDictionary() and not self.getExtendedAttribute("Cached"): raise WebIDLError("An attribute cannot be of a dictionary type", @@ -4709,7 +4828,7 @@ class IDLArgument(IDLObjectWithIdentifier): for attribute in attrs: identifier = attribute.identifier() if self.allowTypeAttributes and (identifier == "EnforceRange" or identifier == "Clamp" or - identifier == "TreatNullAs"): + identifier == "TreatNullAs" or identifier == "AllowShared"): self.type = self.type.withExtendedAttributes([attribute]) elif identifier == "TreatNonCallableAsNull": self._allowTreatNonCallableAsNull = True @@ -4879,8 +4998,7 @@ class IDLCallbackType(IDLType): # Just forward to the union; it'll deal return other.isDistinguishableFrom(self) return (other.isPrimitive() or other.isString() or other.isEnum() or - other.isNonCallbackInterface() or other.isDate() or - other.isSequence()) + other.isNonCallbackInterface() or other.isSequence()) def _getDependentObjects(self): return self.callback._getDependentObjects() @@ -5475,7 +5593,9 @@ class IDLConstructor(IDLMethod): identifier == "ChromeOnly" or identifier == "NewObject" or identifier == "SecureContext" or - identifier == "Throws"): + identifier == "Throws" or + identifier == "Func" or + identifier == "Pref"): IDLMethod.handleExtendedAttribute(self, attr) elif identifier == "HTMLConstructor": if not attr.noArguments(): @@ -5675,11 +5795,11 @@ class Tokenizer(object): "optional": "OPTIONAL", "...": "ELLIPSIS", "::": "SCOPE", - "Date": "DATE", "DOMString": "DOMSTRING", "ByteString": "BYTESTRING", "USVString": "USVSTRING", "JSString": "JSSTRING", + "UTF8String": "UTF8STRING", "any": "ANY", "boolean": "BOOLEAN", "byte": "BYTE", @@ -5709,7 +5829,6 @@ class Tokenizer(object): "<": "LT", ">": "GT", "ArrayBuffer": "ARRAYBUFFER", - "SharedArrayBuffer": "SHAREDARRAYBUFFER", "or": "OR", "maplike": "MAPLIKE", "setlike": "SETLIKE", @@ -6939,10 +7058,10 @@ class Parser(Tokenizer): | EQUALS | GT | QUESTIONMARK - | DATE | DOMSTRING | BYTESTRING | USVSTRING + | UTF8STRING | JSSTRING | PROMISE | ANY @@ -7050,7 +7169,6 @@ class Parser(Tokenizer): """ DistinguishableType : PrimitiveType Null | ARRAYBUFFER Null - | SHAREDARRAYBUFFER Null | READABLESTREAM Null | OBJECT Null """ @@ -7058,8 +7176,6 @@ class Parser(Tokenizer): type = BuiltinTypes[IDLBuiltinType.Types.object] elif p[1] == "ArrayBuffer": type = BuiltinTypes[IDLBuiltinType.Types.ArrayBuffer] - elif p[1] == "SharedArrayBuffer": - type = BuiltinTypes[IDLBuiltinType.Types.SharedArrayBuffer] elif p[1] == "ReadableStream": type = BuiltinTypes[IDLBuiltinType.Types.ReadableStream] else: @@ -7122,13 +7238,6 @@ class Parser(Tokenizer): type = IDLUnresolvedType(self.getLocation(p, 1), p[1]) p[0] = self.handleNullable(type, p[2]) - def p_DistinguishableTypeDate(self, p): - """ - DistinguishableType : DATE Null - """ - p[0] = self.handleNullable(BuiltinTypes[IDLBuiltinType.Types.date], - p[2]) - def p_ConstType(self, p): """ ConstType : PrimitiveType @@ -7215,6 +7324,12 @@ class Parser(Tokenizer): """ p[0] = IDLBuiltinType.Types.usvstring + def p_BuiltinStringTypeUTF8String(self, p): + """ + BuiltinStringType : UTF8STRING + """ + p[0] = IDLBuiltinType.Types.utf8string + def p_BuiltinStringTypeJSString(self, p): """ BuiltinStringType : JSSTRING @@ -7354,7 +7469,13 @@ class Parser(Tokenizer): IdentifierList : IDENTIFIER Identifiers """ idents = list(p[2]) - idents.insert(0, p[1]) + # This is only used for identifier-list-valued extended attributes, and if + # we're going to restrict to IDENTIFIER here we should at least allow + # escaping with leading '_' as usual for identifiers. + ident = p[1] + if ident[0] == '_': + ident = ident[1:] + idents.insert(0, ident) p[0] = idents def p_IdentifiersList(self, p): @@ -7362,7 +7483,13 @@ class Parser(Tokenizer): Identifiers : COMMA IDENTIFIER Identifiers """ idents = list(p[3]) - idents.insert(0, p[2]) + # This is only used for identifier-list-valued extended attributes, and if + # we're going to restrict to IDENTIFIER here we should at least allow + # escaping with leading '_' as usual for identifiers. + ident = p[2] + if ident[0] == '_': + ident = ident[1:] + idents.insert(0, ident) p[0] = idents def p_IdentifiersEmpty(self, p): diff --git a/components/script/dom/bindings/codegen/parser/ext-attribute-no-value-error.patch b/components/script/dom/bindings/codegen/parser/ext-attribute-no-value-error.patch new file mode 100644 index 00000000000..210134d8ca6 --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/ext-attribute-no-value-error.patch @@ -0,0 +1,11 @@ +--- WebIDL.py ++++ WebIDL.py +@@ -3490,7 +3490,7 @@ class IDLBuiltinType(IDLType): + [self.location, attribute.location]) + assert not self.nullable() + if not attribute.hasValue(): +- raise WebIDLError("[TreatNullAs] must take an identifier argument" ++ raise WebIDLError("[TreatNullAs] must take an identifier argument", + [attribute.location]) + value = attribute.value() + if value != 'EmptyString': diff --git a/components/script/dom/bindings/codegen/parser/tests/test_attributes_on_types.py b/components/script/dom/bindings/codegen/parser/tests/test_attributes_on_types.py index 43daca3c453..ff08791d16f 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_attributes_on_types.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_attributes_on_types.py @@ -25,6 +25,12 @@ def WebIDLTest(parser, harness): void method2(optional [EnforceRange] long foo, optional [Clamp] long bar, optional [TreatNullAs=EmptyString] DOMString baz); }; + interface C { + attribute [EnforceRange] long? foo; + attribute [Clamp] long? bar; + void method([EnforceRange] long? foo, [Clamp] long? bar); + void method2(optional [EnforceRange] long? foo, optional [Clamp] long? bar); + }; interface Setlike { setlike<[Clamp] long>; }; @@ -41,29 +47,105 @@ def WebIDLTest(parser, harness): harness.ok(not threw, "Should not have thrown on parsing normal") if not threw: - harness.check(results[0].innerType.enforceRange, True, "Foo is [EnforceRange]") - harness.check(results[1].innerType.clamp, True, "Bar is [Clamp]") + harness.check(results[0].innerType.hasEnforceRange(), True, "Foo is [EnforceRange]") + harness.check(results[1].innerType.hasClamp(), True, "Bar is [Clamp]") harness.check(results[2].innerType.treatNullAsEmpty, True, "Baz is [TreatNullAs=EmptyString]") A = results[3] - harness.check(A.members[0].type.enforceRange, True, "A.a is [EnforceRange]") - harness.check(A.members[1].type.clamp, True, "A.b is [Clamp]") - harness.check(A.members[2].type.enforceRange, True, "A.c is [EnforceRange]") - harness.check(A.members[3].type.enforceRange, True, "A.d is [EnforceRange]") + harness.check(A.members[0].type.hasEnforceRange(), True, "A.a is [EnforceRange]") + harness.check(A.members[1].type.hasClamp(), True, "A.b is [Clamp]") + harness.check(A.members[2].type.hasEnforceRange(), True, "A.c is [EnforceRange]") + harness.check(A.members[3].type.hasEnforceRange(), True, "A.d is [EnforceRange]") B = results[4] - harness.check(B.members[0].type.enforceRange, True, "B.typedefFoo is [EnforceRange]") - harness.check(B.members[1].type.enforceRange, True, "B.foo is [EnforceRange]") - harness.check(B.members[2].type.clamp, True, "B.bar is [Clamp]") + harness.check(B.members[0].type.hasEnforceRange(), True, "B.typedefFoo is [EnforceRange]") + harness.check(B.members[1].type.hasEnforceRange(), True, "B.foo is [EnforceRange]") + harness.check(B.members[2].type.hasClamp(), True, "B.bar is [Clamp]") harness.check(B.members[3].type.treatNullAsEmpty, True, "B.baz is [TreatNullAs=EmptyString]") method = B.members[4].signatures()[0][1] - harness.check(method[0].type.enforceRange, True, "foo argument of method is [EnforceRange]") - harness.check(method[1].type.clamp, True, "bar argument of method is [Clamp]") + harness.check(method[0].type.hasEnforceRange(), True, "foo argument of method is [EnforceRange]") + harness.check(method[1].type.hasClamp(), True, "bar argument of method is [Clamp]") harness.check(method[2].type.treatNullAsEmpty, True, "baz argument of method is [TreatNullAs=EmptyString]") method2 = B.members[5].signatures()[0][1] - harness.check(method[0].type.enforceRange, True, "foo argument of method2 is [EnforceRange]") - harness.check(method[1].type.clamp, True, "bar argument of method2 is [Clamp]") + harness.check(method[0].type.hasEnforceRange(), True, "foo argument of method2 is [EnforceRange]") + harness.check(method[1].type.hasClamp(), True, "bar argument of method2 is [Clamp]") harness.check(method[2].type.treatNullAsEmpty, True, "baz argument of method2 is [TreatNullAs=EmptyString]") + C = results[5] + harness.ok(C.members[0].type.nullable(), "C.foo is nullable") + harness.ok(C.members[0].type.hasEnforceRange(), "C.foo has [EnforceRange]") + harness.ok(C.members[1].type.nullable(), "C.bar is nullable") + harness.ok(C.members[1].type.hasClamp(), "C.bar has [Clamp]") + method = C.members[2].signatures()[0][1] + harness.ok(method[0].type.nullable(), "foo argument of method is nullable") + harness.ok(method[0].type.hasEnforceRange(), "foo argument of method has [EnforceRange]") + harness.ok(method[1].type.nullable(), "bar argument of method is nullable") + harness.ok(method[1].type.hasClamp(), "bar argument of method has [Clamp]") + method2 = C.members[3].signatures()[0][1] + harness.ok(method2[0].type.nullable(), "foo argument of method2 is nullable") + harness.ok(method2[0].type.hasEnforceRange(), "foo argument of method2 has [EnforceRange]") + harness.ok(method2[1].type.nullable(), "bar argument of method2 is nullable") + harness.ok(method2[1].type.hasClamp(), "bar argument of method2 has [Clamp]") + + # Test [AllowShared] + parser = parser.reset() + threw = False + try: + parser.parse(""" + typedef [AllowShared] ArrayBufferView Foo; + dictionary A { + required [AllowShared] ArrayBufferView a; + [ChromeOnly, AllowShared] ArrayBufferView b; + Foo c; + }; + interface B { + attribute Foo typedefFoo; + attribute [AllowShared] ArrayBufferView foo; + void method([AllowShared] ArrayBufferView foo); + void method2(optional [AllowShared] ArrayBufferView foo); + }; + interface C { + attribute [AllowShared] ArrayBufferView? foo; + void method([AllowShared] ArrayBufferView? foo); + void method2(optional [AllowShared] ArrayBufferView? foo); + }; + interface Setlike { + setlike<[AllowShared] ArrayBufferView>; + }; + interface Maplike { + maplike<[Clamp] long, [AllowShared] ArrayBufferView>; + }; + interface Iterable { + iterable<[Clamp] long, [AllowShared] ArrayBufferView>; + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(not threw, "Should not have thrown on parsing normal") + if not threw: + harness.ok(results[0].innerType.hasAllowShared(), "Foo is [AllowShared]") + A = results[1] + harness.ok(A.members[0].type.hasAllowShared(), "A.a is [AllowShared]") + harness.ok(A.members[1].type.hasAllowShared(), "A.b is [AllowShared]") + harness.ok(A.members[2].type.hasAllowShared(), "A.c is [AllowShared]") + B = results[2] + harness.ok(B.members[0].type.hasAllowShared(), "B.typedefFoo is [AllowShared]") + harness.ok(B.members[1].type.hasAllowShared(), "B.foo is [AllowShared]") + method = B.members[2].signatures()[0][1] + harness.ok(method[0].type.hasAllowShared(), "foo argument of method is [AllowShared]") + method2 = B.members[3].signatures()[0][1] + harness.ok(method2[0].type.hasAllowShared(), "foo argument of method2 is [AllowShared]") + C = results[3] + harness.ok(C.members[0].type.nullable(), "C.foo is nullable") + harness.ok(C.members[0].type.hasAllowShared(), "C.foo is [AllowShared]") + method = C.members[1].signatures()[0][1] + harness.ok(method[0].type.nullable(), "foo argument of method is nullable") + harness.ok(method[0].type.hasAllowShared(), "foo argument of method is [AllowShared]") + method2 = C.members[2].signatures()[0][1] + harness.ok(method2[0].type.nullable(), "foo argument of method2 is nullable") + harness.ok(method2[0].type.hasAllowShared(), "foo argument of method2 is [AllowShared]") - ATTRIBUTES = [("[Clamp]", "long"), ("[EnforceRange]", "long"), ("[TreatNullAs=EmptyString]", "DOMString")] + ATTRIBUTES = [("[Clamp]", "long"), ("[EnforceRange]", "long"), + ("[TreatNullAs=EmptyString]", "DOMString"), ("[AllowShared]", "ArrayBufferView")] TEMPLATES = [ ("required dictionary members", """ dictionary Foo { @@ -93,7 +175,54 @@ def WebIDLTest(parser, harness): readonly attribute Bar baz; }; typedef %s %s Bar; - """) + """), + ("method", """ + interface Foo { + %s %s foo(); + }; + """), + ("interface",""" + %s + interface Foo { + attribute %s foo; + }; + """), + ("partial interface",""" + interface Foo { + void foo(); + }; + %s + partial interface Foo { + attribute %s bar; + }; + """), + ("interface mixin",""" + %s + interface mixin Foo { + attribute %s foo; + }; + """), + ("namespace",""" + %s + namespace Foo { + attribute %s foo; + }; + """), + ("partial namespace",""" + namespace Foo { + void foo(); + }; + %s + partial namespace Foo { + attribute %s bar; + }; + """), + ("dictionary",""" + %s + dictionary Foo { + %s foo; + }; + """) ]; for (name, template) in TEMPLATES: @@ -167,55 +296,91 @@ def WebIDLTest(parser, harness): harness.ok(threw, "Should not allow mixing [Clamp] and [EnforceRange] via typedefs") + TYPES = ["DOMString", "unrestricted float", "float", "unrestricted double", "double"] + + for type in TYPES: + parser = parser.reset() + threw = False + try: + parser.parse(""" + typedef [Clamp] %s Foo; + """ % type) + parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow [Clamp] on %s" % type) + + parser = parser.reset() + threw = False + try: + parser.parse(""" + typedef [EnforceRange] %s Foo; + """ % type) + parser.finish() + except: + threw = True + + harness.ok(threw, "Should not allow [EnforceRange] on %s" % type) + + parser = parser.reset() threw = False try: parser.parse(""" - typedef [Clamp] DOMString Foo; + typedef [TreatNullAs=EmptyString] long Foo; """) parser.finish() except: threw = True - harness.ok(threw, "Should not allow [Clamp] on DOMString") - + harness.ok(threw, "Should not allow [TreatNullAs] on long") parser = parser.reset() threw = False try: parser.parse(""" - typedef [EnforceRange] DOMString Foo; + typedef [TreatNullAs=EmptyString] JSString Foo; """) parser.finish() except: threw = True - harness.ok(threw, "Should not allow [EnforceRange] on DOMString") - + harness.ok(threw, "Should not allow [TreatNullAs] on JSString") parser = parser.reset() threw = False try: parser.parse(""" - typedef [TreatNullAs=EmptyString] long Foo; + typedef [TreatNullAs=EmptyString] DOMString? Foo; """) parser.finish() except: threw = True - harness.ok(threw, "Should not allow [TreatNullAs] on long") + harness.ok(threw, "Should not allow [TreatNullAs] on nullable DOMString") parser = parser.reset() threw = False try: parser.parse(""" - typedef [TreatNullAs=EmptyString] JSString Foo; + typedef [AllowShared] DOMString Foo; """) - parser.finish() + results = parser.finish() except: threw = True + harness.ok(threw, "[AllowShared] only allowed on buffer source types") - harness.ok(threw, "Should not allow [TreatNullAs] on JSString") + parser = parser.reset() + threw = False + try: + parser.parse(""" + typedef [AllowShared=something] ArrayBufferView Foo; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "[AllowShared] must take no arguments") parser = parser.reset() threw = False @@ -230,7 +395,7 @@ def WebIDLTest(parser, harness): except: threw = True harness.ok(not threw, "Should allow type attributes on unresolved types") - harness.check(results[0].members[0].signatures()[0][1][0].type.clamp, True, + harness.check(results[0].members[0].signatures()[0][1][0].type.hasClamp(), True, "Unresolved types with type attributes should correctly resolve with attributes") parser = parser.reset() @@ -246,5 +411,5 @@ def WebIDLTest(parser, harness): except: threw = True harness.ok(not threw, "Should allow type attributes on typedefs") - harness.check(results[0].members[0].signatures()[0][1][0].type.clamp, True, + harness.check(results[0].members[0].signatures()[0][1][0].type.hasClamp(), True, "Unresolved types that resolve to typedefs with attributes should correctly resolve with attributes") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_constructor.py b/components/script/dom/bindings/codegen/parser/tests/test_constructor.py index 721f9c2089e..83e1f4fc34f 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_constructor.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_constructor.py @@ -11,9 +11,9 @@ def WebIDLTest(parser, harness): harness.check(argument.variadic, variadic, "Argument has the right variadic value") def checkMethod(method, QName, name, signatures, - static=True, getter=False, setter=False, - deleter=False, legacycaller=False, stringifier=False, - chromeOnly=False, htmlConstructor=False): + static=True, getter=False, setter=False, deleter=False, + legacycaller=False, stringifier=False, chromeOnly=False, + htmlConstructor=False, secureContext=False, pref=None, func=None): harness.ok(isinstance(method, WebIDL.IDLMethod), "Should be an IDLMethod") harness.ok(method.isMethod(), "Method is a method") @@ -30,6 +30,9 @@ def WebIDLTest(parser, harness): harness.check(method.getExtendedAttribute("ChromeOnly") is not None, chromeOnly, "Method has the correct value for ChromeOnly") harness.check(method.isHTMLConstructor(), htmlConstructor, "Method has the correct htmlConstructor value") harness.check(len(method.signatures()), len(signatures), "Method has the correct number of signatures") + harness.check(method.getExtendedAttribute("Pref"), pref, "Method has the correct pref value") + harness.check(method.getExtendedAttribute("Func"), func, "Method has the correct func value") + harness.check(method.getExtendedAttribute("SecureContext") is not None, secureContext, "Method has the correct SecureContext value") sigpairs = zip(method.signatures(), signatures) for (gotSignature, expectedSignature) in sigpairs: @@ -88,6 +91,21 @@ def WebIDLTest(parser, harness): results = parser.finish() checkResults(results) + parser = parser.reset() + parser.parse(""" + interface TestPrefConstructor { + [Pref="dom.webidl.test1"] constructor(); + }; + """) + results = parser.finish() + harness.check(len(results), 1, "Should be one production") + harness.ok(isinstance(results[0], WebIDL.IDLInterface), + "Should be an IDLInterface") + + checkMethod(results[0].ctor(), "::TestPrefConstructor::constructor", + "constructor", [("TestPrefConstructor (Wrapper)", [])], + pref=["dom.webidl.test1"]) + parser = parser.reset() parser.parse(""" interface TestChromeOnlyConstructor { @@ -103,6 +121,53 @@ def WebIDLTest(parser, harness): "constructor", [("TestChromeOnlyConstructor (Wrapper)", [])], chromeOnly=True) + parser = parser.reset() + parser.parse(""" + interface TestSCConstructor { + [SecureContext] constructor(); + }; + """) + results = parser.finish() + harness.check(len(results), 1, "Should be one production") + harness.ok(isinstance(results[0], WebIDL.IDLInterface), + "Should be an IDLInterface") + + checkMethod(results[0].ctor(), "::TestSCConstructor::constructor", + "constructor", [("TestSCConstructor (Wrapper)", [])], + secureContext=True) + + parser = parser.reset() + parser.parse(""" + interface TestFuncConstructor { + [Func="Document::IsWebAnimationsEnabled"] constructor(); + }; + """) + results = parser.finish() + harness.check(len(results), 1, "Should be one production") + harness.ok(isinstance(results[0], WebIDL.IDLInterface), + "Should be an IDLInterface") + + checkMethod(results[0].ctor(), "::TestFuncConstructor::constructor", + "constructor", [("TestFuncConstructor (Wrapper)", [])], + func=["Document::IsWebAnimationsEnabled"]) + + parser = parser.reset() + parser.parse(""" + interface TestPrefChromeOnlySCFuncConstructor { + [ChromeOnly, Pref="dom.webidl.test1", SecureContext, Func="Document::IsWebAnimationsEnabled"] + constructor(); + }; + """) + results = parser.finish() + harness.check(len(results), 1, "Should be one production") + harness.ok(isinstance(results[0], WebIDL.IDLInterface), + "Should be an IDLInterface") + + checkMethod(results[0].ctor(), "::TestPrefChromeOnlySCFuncConstructor::constructor", + "constructor", [("TestPrefChromeOnlySCFuncConstructor (Wrapper)", [])], + func=["Document::IsWebAnimationsEnabled"], pref=["dom.webidl.test1"], + chromeOnly=True, secureContext=True) + parser = parser.reset() parser.parse(""" interface TestHTMLConstructor { diff --git a/components/script/dom/bindings/codegen/parser/tests/test_date.py b/components/script/dom/bindings/codegen/parser/tests/test_date.py deleted file mode 100644 index 2bdfc95e14f..00000000000 --- a/components/script/dom/bindings/codegen/parser/tests/test_date.py +++ /dev/null @@ -1,15 +0,0 @@ -def WebIDLTest(parser, harness): - parser.parse(""" - interface WithDates { - attribute Date foo; - void bar(Date arg); - void baz(sequence arg); - }; - """) - - results = parser.finish() - harness.ok(results[0].members[0].type.isDate(), "Should have Date") - harness.ok(results[0].members[1].signatures()[0][1][0].type.isDate(), - "Should have Date argument") - harness.ok(not results[0].members[2].signatures()[0][1][0].type.isDate(), - "Should have non-Date argument") 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 bd9996e34c9..505b36468d6 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_distinguishability.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_distinguishability.py @@ -149,7 +149,7 @@ def WebIDLTest(parser, harness): # Now let's test our whole distinguishability table argTypes = [ "long", "short", "long?", "short?", "boolean", - "boolean?", "DOMString", "ByteString", "Enum", "Enum2", + "boolean?", "DOMString", "ByteString", "UTF8String", "Enum", "Enum2", "Interface", "Interface?", "AncestorInterface", "UnrelatedInterface", "CallbackInterface", "CallbackInterface?", "CallbackInterface2", @@ -158,14 +158,12 @@ def WebIDLTest(parser, harness): "record", "record", "record", - "Date", "Date?", "any", - "Promise", "Promise?", - "USVString", "JSString", "ArrayBuffer", "ArrayBufferView", "SharedArrayBuffer", + "record", + "any", "Promise", "Promise?", + "USVString", "JSString", "ArrayBuffer", "ArrayBufferView", "Uint8Array", "Uint16Array", "(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... # Try to categorize things a bit to keep list lengths down def allBut(list1, list2): @@ -177,26 +175,24 @@ def WebIDLTest(parser, harness): primitives = numerics + booleans nonNumerics = allBut(argTypes, numerics + unions) nonBooleans = allBut(argTypes, booleans) - strings = [ "DOMString", "ByteString", "Enum", "Enum2", "USVString", "JSString" ] + strings = [ "DOMString", "ByteString", "Enum", "Enum2", "USVString", "JSString", "UTF8String" ] nonStrings = allBut(argTypes, strings) nonObjects = primitives + strings objects = allBut(argTypes, nonObjects ) bufferSourceTypes = ["ArrayBuffer", "ArrayBufferView", "Uint8Array", "Uint16Array"] - sharedBufferSourceTypes = ["SharedArrayBuffer"] interfaces = [ "Interface", "Interface?", "AncestorInterface", - "UnrelatedInterface" ] + bufferSourceTypes + sharedBufferSourceTypes + "UnrelatedInterface" ] + bufferSourceTypes nullables = (["long?", "short?", "boolean?", "Interface?", "CallbackInterface?", "Dict", "Dict2", "Date?", "any", "Promise?"] + allBut(unions, [ "(long or Callback)" ])) - dates = [ "Date", "Date?" ] sequences = [ "sequence", "sequence" ] - nonUserObjects = nonObjects + interfaces + dates + sequences + nonUserObjects = nonObjects + interfaces + sequences otherObjects = allBut(argTypes, nonUserObjects + ["object"]) notRelatedInterfaces = (nonObjects + ["UnrelatedInterface"] + - otherObjects + dates + sequences + bufferSourceTypes + sharedBufferSourceTypes) + otherObjects + sequences + bufferSourceTypes) records = [ "record", "record", - "record" ] # JSString not supported in records + "record", "record" ] # JSString not supported in records # Build a representation of the distinguishability table as a dict # of dicts, holding True values where needed, holes elsewhere. @@ -215,6 +211,7 @@ def WebIDLTest(parser, harness): setDistinguishable("boolean?", allBut(nonBooleans, nullables)) setDistinguishable("DOMString", nonStrings) setDistinguishable("ByteString", nonStrings) + setDistinguishable("UTF8String", nonStrings) setDistinguishable("USVString", nonStrings) setDistinguishable("JSString", nonStrings) setDistinguishable("Enum", nonStrings) @@ -240,8 +237,7 @@ def WebIDLTest(parser, harness): setDistinguishable("record", nonUserObjects) # JSString not supported in records setDistinguishable("record", nonUserObjects) - setDistinguishable("Date", allBut(argTypes, dates + ["object"])) - setDistinguishable("Date?", allBut(argTypes, dates + nullables + ["object"])) + setDistinguishable("record", nonUserObjects) setDistinguishable("any", []) setDistinguishable("Promise", []) setDistinguishable("Promise?", []) @@ -249,7 +245,6 @@ def WebIDLTest(parser, harness): setDistinguishable("ArrayBufferView", allBut(argTypes, ["ArrayBufferView", "Uint8Array", "Uint16Array", "object"])) setDistinguishable("Uint8Array", allBut(argTypes, ["ArrayBufferView", "Uint8Array", "object"])) setDistinguishable("Uint16Array", allBut(argTypes, ["ArrayBufferView", "Uint16Array", "object"])) - setDistinguishable("SharedArrayBuffer", allBut(argTypes, ["SharedArrayBuffer", "object"])) setDistinguishable("(long or Callback)", allBut(nonUserObjects, numerics)) setDistinguishable("(long or Dict)", diff --git a/components/script/dom/bindings/codegen/parser/tests/test_extended_attributes.py b/components/script/dom/bindings/codegen/parser/tests/test_extended_attributes.py index 97184ec2478..144c945bc10 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_extended_attributes.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_extended_attributes.py @@ -56,9 +56,9 @@ def WebIDLTest(parser, harness): results = parser.finish() # Pull out the first argument out of the arglist of the first (and # only) signature. - harness.ok(results[0].members[0].signatures()[0][1][0].type.clamp, + harness.ok(results[0].members[0].signatures()[0][1][0].type.hasClamp(), "Should be clamped") - harness.ok(not results[0].members[1].signatures()[0][1][0].type.clamp, + harness.ok(not results[0].members[1].signatures()[0][1][0].type.hasClamp(), "Should not be clamped") parser = parser.reset() @@ -86,9 +86,9 @@ def WebIDLTest(parser, harness): results = parser.finish() # Pull out the first argument out of the arglist of the first (and # only) signature. - harness.ok(results[0].members[0].signatures()[0][1][0].type.enforceRange, + harness.ok(results[0].members[0].signatures()[0][1][0].type.hasEnforceRange(), "Should be enforceRange") - harness.ok(not results[0].members[1].signatures()[0][1][0].type.enforceRange, + harness.ok(not results[0].members[1].signatures()[0][1][0].type.hasEnforceRange(), "Should not be enforceRange") parser = parser.reset() diff --git a/components/script/dom/bindings/codegen/parser/tests/test_nullable_equivalency.py b/components/script/dom/bindings/codegen/parser/tests/test_nullable_equivalency.py index 2b48b615dd4..8ba6771677a 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_nullable_equivalency.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_nullable_equivalency.py @@ -80,7 +80,7 @@ def checkEquivalent(iface, harness): for attr in dir(type1): if attr.startswith('_') or \ attr in ['nullable', 'builtin', 'filename', 'location', - 'inner', 'QName', 'getDeps', 'name'] or \ + 'inner', 'QName', 'getDeps', 'name', 'prettyName'] or \ (hasattr(type(type1), attr) and not callable(getattr(type1, attr))): continue diff --git a/components/script/dom/bindings/codegen/parser/tests/test_toJSON.py b/components/script/dom/bindings/codegen/parser/tests/test_toJSON.py index b8b4f796ccb..ad01330e65a 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_toJSON.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_toJSON.py @@ -85,7 +85,7 @@ def WebIDLTest(parser, harness): JsonTypes = [ "byte", "octet", "short", "unsigned short", "long", "unsigned long", "long long", "unsigned long long", "float", "unrestricted float", "double", "unrestricted double", "boolean", - "DOMString", "ByteString", "USVString", "Enum", "InterfaceWithToJSON", "object" ] + "DOMString", "ByteString", "UTF8String", "USVString", "Enum", "InterfaceWithToJSON", "object" ] nonJsonTypes = [ "InterfaceWithoutToJSON", "any", "Int8Array", "Int16Array", "Int32Array","Uint8Array", "Uint16Array", "Uint32Array", "Uint8ClampedArray", "Float32Array", "Float64Array", "ArrayBuffer" ] @@ -129,9 +129,12 @@ def WebIDLTest(parser, harness): doTest("interface Test { record toJSON(); };" % type, False, "record should be a JSON type" % type) - doTest("interface Test { record toJSON(); };" % type, False, + doTest("interface Test { record toJSON(); };" % type, False, "record should be a JSON type" % type) + doTest("interface Test { record toJSON(); };" % type, False, + "record should be a JSON type" % type) + doTest("interface Test { record toJSON(); };" % type, False, "record should be a JSON type" % type) @@ -174,12 +177,12 @@ def WebIDLTest(parser, harness): doTest("interface Test { record toJSON(); };" % type, True, "record should not be a JSON type" % type) - + if type != "any": doTest("interface Foo { object toJSON(); }; " "interface Test { (Foo or %s) toJSON(); };" % type, True, "union containing a non-JSON type (%s) should not be a JSON type" % type) - + doTest("interface test { %s? toJSON(); };" % type, True, "Nullable type (%s) should not be a JSON type" % type) diff --git a/components/script/dom/bindings/codegen/parser/update.sh b/components/script/dom/bindings/codegen/parser/update.sh index fee9720ab2d..dd7803c940c 100755 --- a/components/script/dom/bindings/codegen/parser/update.sh +++ b/components/script/dom/bindings/codegen/parser/update.sh @@ -5,8 +5,8 @@ patch < callback-location.patch patch < union-typedef.patch patch < inline.patch -wget https://hg.mozilla.org/mozilla-central/archive/tip.tar.gz/dom/bindings/parser/tests/ -O tests.tar.gz +wget https://hg.mozilla.org/mozilla-central/archive/tip.zip/dom/bindings/parser/tests/ -O tests.zip rm -r tests mkdir tests -tar xvpf tests.tar.gz -C tests --strip-components=5 -rm tests.tar.gz WebIDL.py.orig +unzip -d tests -j tests.zip +rm tests.zip WebIDL.py.orig -- cgit v1.2.3 From 3f30c7d8be0c64d003a7e06ca044913801f2b1e0 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 14 Mar 2020 12:09:17 +0100 Subject: Do not do weird scope things in MethodDefiner Variable `m` comes from a previous list comprehension earlier in the function is not actually properly defined. --- components/script/dom/bindings/codegen/CodegenRust.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index a9515fb099d..fab5e1e713a 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1654,6 +1654,8 @@ class MethodDefiner(PropertyDefiner): (maplikeOrSetlikeOrIterable and maplikeOrSetlikeOrIterable.isIterable() and maplikeOrSetlikeOrIterable.isValueIterator())): + m = maplikeOrSetlikeOrIterable + # Add our keys/values/entries/forEach self.regular.append({ "name": "keys", -- cgit v1.2.3 From 3ea6d87bcc37167464e856949a4b9b77d0e9318a Mon Sep 17 00:00:00 2001 From: YUAN LYU Date: Fri, 20 Mar 2020 22:14:18 -0400 Subject: Add trait DomObjectWrap to provide WRAP function --- .../script/dom/bindings/codegen/CodegenRust.py | 54 ++++++++++++++++++++-- 1 file changed, 51 insertions(+), 3 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index fab5e1e713a..8f0281be802 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2858,6 +2858,50 @@ impl PartialEq for %(name)s { """ % {'check': check, 'name': name} +class CGDomObjectWrap(CGThing): + """ + Class for codegen of an implementation of the DomObjectWrap trait. + """ + def __init__(self, descriptor): + CGThing.__init__(self) + self.descriptor = descriptor + + def define(self): + name = self.descriptor.concreteType + name = "dom::%s::%s" % (name.lower(), name) + return """\ +impl DomObjectWrap for %s { + const WRAP: unsafe fn( + SafeJSContext, + &GlobalScope, + Box, + ) -> Root> = Wrap; +} +""" % (name) + + +class CGDomObjectIteratorWrap(CGThing): + """ + Class for codegen of an implementation of the DomObjectIteratorWrap trait. + """ + def __init__(self, descriptor): + CGThing.__init__(self) + self.descriptor = descriptor + + def define(self): + assert self.descriptor.interface.isIteratorInterface() + name = self.descriptor.interface.iterableInterface.identifier.name + return """\ +impl DomObjectIteratorWrap for %s { + const ITER_WRAP: unsafe fn( + SafeJSContext, + &GlobalScope, + Box>, + ) -> Root>> = Wrap; +} +""" % (name) + + class CGAbstractExternMethod(CGAbstractMethod): """ Abstract base class for codegen of implementation-only (no @@ -6067,6 +6111,8 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'crate::dom::bindings::namespace::create_namespace_object', 'crate::dom::bindings::reflector::MutDomObject', 'crate::dom::bindings::reflector::DomObject', + 'crate::dom::bindings::reflector::DomObjectWrap', + 'crate::dom::bindings::reflector::DomObjectIteratorWrap', 'crate::dom::bindings::root::Dom', 'crate::dom::bindings::root::DomRoot', 'crate::dom::bindings::root::DomSlice', @@ -6286,6 +6332,10 @@ class CGDescriptor(CGThing): cgThings.append(CGWrapGlobalMethod(descriptor, properties)) else: cgThings.append(CGWrapMethod(descriptor)) + if descriptor.interface.isIteratorInterface(): + cgThings.append(CGDomObjectIteratorWrap(descriptor)) + else: + cgThings.append(CGDomObjectWrap(descriptor)) reexports.append('Wrap') haveUnscopables = False @@ -7445,9 +7495,7 @@ class CGIterableMethodGenerator(CGGeneric): return CGGeneric.__init__(self, fill( """ - let result = ${iterClass}::new(&*this, - IteratorType::${itrMethod}, - super::${ifaceName}IteratorBinding::Wrap); + let result = ${iterClass}::new(&*this, IteratorType::${itrMethod}); """, iterClass=iteratorNativeType(descriptor, True), ifaceName=descriptor.interface.identifier.name, -- cgit v1.2.3 From 80b2a87be718d81032a14bc96d94bb37318c31d8 Mon Sep 17 00:00:00 2001 From: Shinichi Morimoto Date: Sat, 28 Mar 2020 20:17:16 +0900 Subject: fixed #25281 --- components/script/dom/bindings/codegen/CodegenRust.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 8f0281be802..3191a7acc4d 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2968,12 +2968,19 @@ class CGCollectJSONAttributesMethod(CGAbstractMethod): def definition_body(self): ret = '' interface = self.descriptor.interface + for m in interface.members: if m.isAttr() and not m.isStatic() and m.type.isJSONType(): name = m.identifier.name + conditions = MemberCondition(None, None, m.exposureSet) + ret_conditions = 'vec![' + ",".join(conditions) + "]" ret += fill( """ - rooted!(in(cx) let mut temp = UndefinedValue()); + let conditions = ${conditions}; + if !conditions.iter().any(|c| c.is_satisfied(SafeJSContext::from_ptr(cx), HandleObject::from_raw(obj), HandleObject::from_raw(obj))) { + return false; + } + rooted!(in(cx) let mut temp = UndefinedValue()); if !get_${name}(cx, obj, this, JSJitGetterCallArgs { _base: temp.handle_mut().into() }) { return false; } @@ -2983,7 +2990,7 @@ class CGCollectJSONAttributesMethod(CGAbstractMethod): return false; } """, - name=name, nameAsArray=str_to_const_array(name)) + name=name, nameAsArray=str_to_const_array(name), conditions=ret_conditions) ret += 'return true;\n' return CGGeneric(ret) -- cgit v1.2.3 From f7d4a37f784ad8ce5d904e125167e4e4ef6a2e2a Mon Sep 17 00:00:00 2001 From: Shinichi Morimoto Date: Sat, 28 Mar 2020 23:21:35 +0900 Subject: fixed fmt --- components/script/dom/bindings/codegen/CodegenRust.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 3191a7acc4d..30c33f47077 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2977,10 +2977,14 @@ class CGCollectJSONAttributesMethod(CGAbstractMethod): ret += fill( """ let conditions = ${conditions}; - if !conditions.iter().any(|c| c.is_satisfied(SafeJSContext::from_ptr(cx), HandleObject::from_raw(obj), HandleObject::from_raw(obj))) { + if !conditions.iter().any(|c| + c.is_satisfied( + SafeJSContext::from_ptr(cx), + HandleObject::from_raw(obj), + HandleObject::from_raw(obj))) { return false; } - rooted!(in(cx) let mut temp = UndefinedValue()); + rooted!(in(cx) let mut temp = UndefinedValue()); if !get_${name}(cx, obj, this, JSJitGetterCallArgs { _base: temp.handle_mut().into() }) { return false; } -- cgit v1.2.3 From d8c1dc60e8f48f05ecd3ec01fbc91d7743734460 Mon Sep 17 00:00:00 2001 From: Shinichi Morimoto Date: Mon, 30 Mar 2020 02:32:46 +0900 Subject: fixed is_satisfied condition --- .../script/dom/bindings/codegen/CodegenRust.py | 26 ++++++++++++---------- 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 30c33f47077..ed0e1223e72 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2976,22 +2976,24 @@ class CGCollectJSONAttributesMethod(CGAbstractMethod): ret_conditions = 'vec![' + ",".join(conditions) + "]" ret += fill( """ + let incumbent_global = GlobalScope::incumbent().expect("no incumbent global"); + let global = incumbent_global.reflector().get_jsobject(); let conditions = ${conditions}; - if !conditions.iter().any(|c| + let is_satisfied = conditions.iter().any(|c| c.is_satisfied( SafeJSContext::from_ptr(cx), HandleObject::from_raw(obj), - HandleObject::from_raw(obj))) { - return false; - } - rooted!(in(cx) let mut temp = UndefinedValue()); - if !get_${name}(cx, obj, this, JSJitGetterCallArgs { _base: temp.handle_mut().into() }) { - return false; - } - if !JS_DefineProperty(cx, result.handle().into(), - ${nameAsArray} as *const u8 as *const libc::c_char, - temp.handle(), JSPROP_ENUMERATE as u32) { - return false; + global)); + if is_satisfied { + rooted!(in(cx) let mut temp = UndefinedValue()); + if !get_${name}(cx, obj, this, JSJitGetterCallArgs { _base: temp.handle_mut().into() }) { + return false; + } + if !JS_DefineProperty(cx, result.handle().into(), + ${nameAsArray} as *const u8 as *const libc::c_char, + temp.handle(), JSPROP_ENUMERATE as u32) { + return false; + } } """, name=name, nameAsArray=str_to_const_array(name), conditions=ret_conditions) -- cgit v1.2.3 From 74995a5287dc0af8afe62e9b537db5141b854765 Mon Sep 17 00:00:00 2001 From: Shinichi Morimoto Date: Tue, 31 Mar 2020 09:37:07 +0900 Subject: fixed CGCollectJSONAttributesMethod --- components/script/dom/bindings/codegen/CodegenRust.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index ed0e1223e72..96947d83ec7 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2966,18 +2966,16 @@ class CGCollectJSONAttributesMethod(CGAbstractMethod): self.toJSONMethod = toJSONMethod def definition_body(self): - ret = '' + ret = """let incumbent_global = GlobalScope::incumbent().expect("no incumbent global"); +let global = incumbent_global.reflector().get_jsobject();\n""" interface = self.descriptor.interface - for m in interface.members: if m.isAttr() and not m.isStatic() and m.type.isJSONType(): name = m.identifier.name conditions = MemberCondition(None, None, m.exposureSet) - ret_conditions = 'vec![' + ",".join(conditions) + "]" + ret_conditions = '&[' + ", ".join(conditions) + "]" ret += fill( """ - let incumbent_global = GlobalScope::incumbent().expect("no incumbent global"); - let global = incumbent_global.reflector().get_jsobject(); let conditions = ${conditions}; let is_satisfied = conditions.iter().any(|c| c.is_satisfied( -- cgit v1.2.3 From c24481ab9c9a7e7e944c91673532578f8c121e0f Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 8 Apr 2020 23:13:59 -0700 Subject: Do not filter out platform objects when doing dictionary conversions https://heycam.github.io/webidl/#es-overloads In step 12, the platform object check is for substep 4, but importantly it only matters if `V` implements the matching interface. If not, it should be able to fall back to substep 10 and attempt conversion to a dictionary. --- components/script/dom/bindings/codegen/CodegenRust.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 96947d83ec7..d4b103cc21b 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -429,8 +429,8 @@ class CGMethodCall(CGThing): # Check for vanilla JS objects # XXXbz Do we need to worry about security wrappers? - pickFirstSignature("%s.get().is_object() && !is_platform_object(%s.get().to_object(), *cx)" % - (distinguishingArg, distinguishingArg), + pickFirstSignature("%s.get().is_object()" % + distinguishingArg, lambda s: (s[1][distinguishingIndex].type.isCallback() or s[1][distinguishingIndex].type.isCallbackInterface() or s[1][distinguishingIndex].type.isDictionary() or -- cgit v1.2.3 From 10a13ffa2016cb81419ae4aa622815f8645ad7f1 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 10 Apr 2020 15:46:28 -0700 Subject: Implement FromJSValConvertible on enums --- .../script/dom/bindings/codegen/CodegenRust.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 96947d83ec7..a9642250770 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -4347,8 +4347,12 @@ pub enum %s { pairs = ",\n ".join(['("%s", super::%s::%s)' % (val, ident, getEnumValueName(val)) for val in enum.values()]) inner = string.Template("""\ +use crate::dom::bindings::conversions::ConversionResult; +use crate::dom::bindings::conversions::FromJSValConvertible; use crate::dom::bindings::conversions::ToJSValConvertible; +use crate::dom::bindings::utils::find_enum_value; use js::jsapi::JSContext; +use js::rust::HandleValue; use js::rust::MutableHandleValue; use js::jsval::JSVal; @@ -4373,6 +4377,22 @@ impl ToJSValConvertible for super::${ident} { pairs[*self as usize].0.to_jsval(cx, rval); } } + +impl FromJSValConvertible for super::${ident} { + type Config = (); + unsafe fn from_jsval(cx: *mut JSContext, value: HandleValue, _option: ()) + -> Result, ()> { + match find_enum_value(cx, value, pairs) { + Err(_) => Err(()), + Ok((None, search)) => { + Ok(ConversionResult::Failure( + format!("'{}' is not a valid enum value for enumeration '${ident}'.", search).into() + )) + } + Ok((Some(&value), _)) => Ok(ConversionResult::Success(value)), + } + } +} """).substitute({ 'ident': ident, 'pairs': pairs -- cgit v1.2.3 From 242b7f8fdc58ec7388edaadc2e94bf2a110f4315 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 10 Apr 2020 16:10:14 -0700 Subject: Use FromJSValConvertible impls when converting arguments --- components/script/dom/bindings/codegen/CodegenRust.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index a9642250770..b32fcd03439 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1004,17 +1004,16 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, "yet") enum = type.inner.identifier.name if invalidEnumValueFatal: - handleInvalidEnumValueCode = onFailureInvalidEnumValue(failureCode, 'search').define() + handleInvalidEnumValueCode = failureCode or "throw_type_error(*cx, &error); %s" % exceptionCode else: handleInvalidEnumValueCode = "return true;" template = ( - "match find_enum_value(*cx, ${val}, %(pairs)s) {\n" + "match FromJSValConvertible::from_jsval(*cx, ${val}, ()) {" " Err(_) => { %(exceptionCode)s },\n" - " Ok((None, search)) => { %(handleInvalidEnumValueCode)s },\n" - " Ok((Some(&value), _)) => value,\n" - "}" % {"pairs": enum + "Values::pairs", - "exceptionCode": exceptionCode, + " Ok(ConversionResult::Success(v)) => v,\n" + " Ok(ConversionResult::Failure(error)) => { %(handleInvalidEnumValueCode)s },\n" + "}" % {"exceptionCode": exceptionCode, "handleInvalidEnumValueCode": handleInvalidEnumValueCode}) if defaultValue is not None: @@ -2418,7 +2417,6 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config): 'crate::dom::bindings::str::DOMString', 'crate::dom::bindings::str::USVString', 'crate::dom::bindings::trace::RootedTraceableBox', - 'crate::dom::bindings::utils::find_enum_value', 'crate::dom::types::*', 'crate::dom::windowproxy::WindowProxy', 'crate::script_runtime::JSContext as SafeJSContext', @@ -6158,7 +6156,6 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'crate::dom::bindings::utils::ProtoOrIfaceArray', 'crate::dom::bindings::utils::enumerate_global', 'crate::dom::bindings::utils::finalize_global', - 'crate::dom::bindings::utils::find_enum_value', 'crate::dom::bindings::utils::generic_getter', 'crate::dom::bindings::utils::generic_lenient_getter', 'crate::dom::bindings::utils::generic_lenient_setter', -- cgit v1.2.3 From 6175a68c102218d0de18b67343ad14cfc193b18d Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 15 Apr 2020 17:54:04 +0200 Subject: Replace a `transmute` with `.to_ne_bytes()` + constructor --- components/script/dom/bindings/codegen/CodegenRust.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 3c9555ba659..021757a4ad1 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -3992,8 +3992,8 @@ class CGMemberJITInfo(CGThing): protoID: PrototypeList::ID::${name} as u16, }, __bindgen_anon_3: JSJitInfo__bindgen_ty_3 { depth: ${depth} }, - _bitfield_1: unsafe { - mem::transmute(new_jsjitinfo_bitfield_1!( + _bitfield_1: __BindgenBitfieldUnit::new( + new_jsjitinfo_bitfield_1!( JSJitInfo_OpType::${opType} as u8, JSJitInfo_AliasSet::${aliasSet} as u8, JSValueType::${returnType} as u8, @@ -4004,8 +4004,8 @@ class CGMemberJITInfo(CGThing): ${isLazilyCachedInSlot}, ${isTypedMethod}, ${slotIndex}, - )) - }, + ).to_ne_bytes() + ), } """, opName=opName, @@ -5988,6 +5988,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::error::throw_type_error', 'js::error::throw_internal_error', 'js::rust::wrappers::Call', + 'js::jsapi::__BindgenBitfieldUnit', 'js::jsapi::CallArgs', 'js::jsapi::CurrentGlobalOrNull', 'js::rust::wrappers::GetPropertyKeys', -- cgit v1.2.3 From d103e06ba945030d2e5bfdb5a9f0f4b848cbf274 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 25 May 2020 20:29:18 +0200 Subject: Use dynamic dispatch in `mozjs::panic::wrap_panic` Pick up https://github.com/servo/rust-mozjs/pull/512 Fixes https://github.com/servo/servo/issues/26585 This diff is best viewed with "ignore whitespace changes", because of indentation change. --- components/script/dom/bindings/codegen/CodegenRust.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 021757a4ad1..d4ded28f397 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2573,9 +2573,19 @@ class CGAbstractMethod(CGThing): body = self.definition_body() if self.catchPanic: - body = CGWrapper(CGIndenter(body), - pre="return wrap_panic(panic::AssertUnwindSafe(|| {\n", - post=("""\n}), %s);""" % ("()" if self.returnType == "void" else "false"))) + if self.returnType == "void": + pre = "wrap_panic(&mut || {\n" + post = "\n})" + else: + pre = ( + "let mut result = false;\n" + "wrap_panic(&mut || result = (|| {\n" + ) + post = ( + "\n})());\n" + "return result" + ) + body = CGWrapper(CGIndenter(body), pre=pre, post=post) return CGWrapper(CGIndenter(body), pre=self.definition_prologue(), -- cgit v1.2.3 From c4f8167b6fa0d01c60deb9bb491a3565173db961 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Fri, 29 May 2020 15:16:55 -0400 Subject: dom: Improve precision of sequence types for WebIDL codegen. --- components/script/dom/bindings/codegen/CodegenRust.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 021757a4ad1..9247a0c0243 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -677,7 +677,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, if type.isSequence() or type.isRecord(): innerInfo = getJSToNativeConversionInfo(innerContainerType(type), descriptorProvider, - isMember=isMember, + isMember="Sequence", isAutoRooted=isAutoRooted) declType = wrapInNativeContainerType(type, innerInfo.declType) config = getConversionConfigForType(type, isEnforceRange, isClamp, treatNullAs) @@ -1075,7 +1075,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, assert not isEnforceRange and not isClamp assert isMember != "Union" - if isMember == "Dictionary" or isAutoRooted: + if isMember in ("Dictionary", "Sequence") or isAutoRooted: templateBody = "${val}.get()" if defaultValue is None: @@ -1087,7 +1087,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, else: raise TypeError("Can't handle non-null, non-undefined default value here") - if isMember == "Dictionary": + if not isAutoRooted: templateBody = "RootedTraceableBox::from_box(Heap::boxed(%s))" % templateBody if default is not None: default = "RootedTraceableBox::from_box(Heap::boxed(%s))" % default @@ -1117,7 +1117,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, templateBody = "${val}.get().to_object()" default = "ptr::null_mut()" - if isMember in ("Dictionary", "Union"): + if isMember in ("Dictionary", "Union", "Sequence") and not isAutoRooted: templateBody = "RootedTraceableBox::from_box(Heap::boxed(%s))" % templateBody default = "RootedTraceableBox::new(Heap::default())" declType = CGGeneric("RootedTraceableBox>") -- cgit v1.2.3 From f014f15d4eaeb52e38faee15dc9a4d0f700d1d7c Mon Sep 17 00:00:00 2001 From: Kunal Mohan Date: Fri, 29 May 2020 19:46:35 +0530 Subject: Allow sequence of nullable dictionary items in webidl of type "sequence x" --- components/script/dom/bindings/codegen/CodegenRust.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 597e5611f74..de97e2c9ea9 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1134,7 +1134,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, if type.isDictionary(): # There are no nullable dictionaries - assert not type.nullable() + assert not type.nullable() or (isMember and isMember != "Dictionary") typeName = "%s::%s" % (CGDictionary.makeModuleName(type.inner), CGDictionary.makeDictionaryName(type.inner)) @@ -6645,7 +6645,10 @@ class CGDictionary(CGThing): @staticmethod def makeDictionaryName(dictionary): - return dictionary.identifier.name + if isinstance(dictionary, IDLWrapperType): + return CGDictionary.makeDictionaryName(dictionary.inner) + else: + return dictionary.identifier.name def makeClassName(self, dictionary): return self.makeDictionaryName(dictionary) -- cgit v1.2.3 From d9db350df528628b1f7f2f1da711fc2da790ec49 Mon Sep 17 00:00:00 2001 From: Kunal Mohan Date: Mon, 1 Jun 2020 19:19:41 +0530 Subject: Improve webidl precision Allow enum variants staring with digit --- .../script/dom/bindings/codegen/CodegenRust.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index de97e2c9ea9..8c7eb3e7400 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -4328,7 +4328,7 @@ def getEnumValueName(value): if re.match("[^\x20-\x7E]", value): raise SyntaxError('Enum value "' + value + '" contains non-ASCII characters') if re.match("^[0-9]", value): - raise SyntaxError('Enum value "' + value + '" starts with a digit') + value = '_' + value value = re.sub(r'[^0-9A-Za-z_]', '_', value) if re.match("^_[A-Z]|__", value): raise SyntaxError('Enum value "' + value + '" is reserved by the C++ spec') @@ -4650,20 +4650,24 @@ class CGUnionConversionStruct(CGThing): # "object" is not distinguishable from other types assert not object or not (interfaceObject or arrayObject or callbackObject or mozMapObject) templateBody = CGList([], "\n") - if object: - templateBody.append(object) + if arrayObject or callbackObject: + # An object can be both an sequence object and a callback or + # dictionary, but we shouldn't have both in the union's members + # because they are not distinguishable. + assert not (arrayObject and callbackObject) + templateBody.append(arrayObject if arrayObject else callbackObject) if interfaceObject: + assert not object templateBody.append(interfaceObject) - if arrayObject: - templateBody.append(arrayObject) - if callbackObject: - templateBody.append(callbackObject) + elif object: + templateBody.append(object) if mozMapObject: templateBody.append(mozMapObject) + conversions.append(CGIfWrapper("value.get().is_object()", templateBody)) if dictionaryObject: - assert not hasObjectTypes + assert not object conversions.append(dictionaryObject) stringTypes = [t for t in memberTypes if t.isString() or t.isEnum()] -- cgit v1.2.3 From 2da07ed164b71c679813b4c319a6e069a2910b25 Mon Sep 17 00:00:00 2001 From: Warren Fisher Date: Tue, 14 Jan 2020 19:21:08 -0400 Subject: Reduce code duplication. Move some of CodegenRust.py to htmlconstructor.rs --- .../script/dom/bindings/codegen/CodegenRust.py | 76 ++-------------------- 1 file changed, 6 insertions(+), 70 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 021757a4ad1..47c7e925cb6 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -5747,75 +5747,12 @@ let global = DomRoot::downcast::(global).unwrap(); if self.constructor.isHTMLConstructor(): signatures = self.constructor.signatures() assert len(signatures) == 1 - constructorCall = CGGeneric("""\ -// Step 2 https://html.spec.whatwg.org/multipage/#htmlconstructor -// The custom element definition cannot use an element interface as its constructor - -// The new_target might be a cross-realm wrapper. Get the underlying object -// so we can do the spec's object-identity checks. -rooted!(in(*cx) let new_target = UnwrapObjectDynamic(args.new_target().to_object(), *cx, 1)); -if new_target.is_null() { - throw_dom_exception(cx, global.upcast::(), Error::Type("new.target is null".to_owned())); - return false; -} - -if args.callee() == new_target.get() { - throw_dom_exception(cx, global.upcast::(), - Error::Type("new.target must not be the active function object".to_owned())); - return false; -} - -// Step 6 -rooted!(in(*cx) let mut prototype = ptr::null_mut::()); -{ - rooted!(in(*cx) let mut proto_val = UndefinedValue()); - let _ac = JSAutoRealm::new(*cx, new_target.get()); - if !JS_GetProperty(*cx, new_target.handle(), b"prototype\\0".as_ptr() as *const _, proto_val.handle_mut()) { - return false; - } - - if !proto_val.is_object() { - // Step 7 of https://html.spec.whatwg.org/multipage/#htmlconstructor. - // This fallback behavior is designed to match analogous behavior for the - // JavaScript built-ins. So we enter the realm of our underlying - // newTarget object and fall back to the prototype object from that global. - // XXX The spec says to use GetFunctionRealm(), which is not actually - // the same thing as what we have here (e.g. in the case of scripted callable proxies - // whose target is not same-realm with the proxy, or bound functions, etc). - // https://bugzilla.mozilla.org/show_bug.cgi?id=1317658 - - rooted!(in(*cx) let global_object = CurrentGlobalOrNull(*cx)); - GetProtoObject(cx, global_object.handle(), prototype.handle_mut()); - } else { - // Step 6 - prototype.set(proto_val.to_object()); - }; -} - -// Wrap prototype in this context since it is from the newTarget realm -if !JS_WrapObject(*cx, prototype.handle_mut()) { - return false; -} - -let result: Result, Error> = html_constructor(&global, &args); -let result = match result { - Ok(result) => result, - Err(e) => { - throw_dom_exception(cx, global.upcast::(), e); - return false; - }, -}; - -rooted!(in(*cx) let mut element = result.reflector().get_jsobject().get()); -if !JS_WrapObject(*cx, element.handle_mut()) { - return false; -} - -JS_SetPrototype(*cx, element.handle(), prototype.handle()); - -(result).to_jsval(*cx, MutableHandleValue::from_raw(args.rval())); -return true; -""" % self.descriptor.name) + constructorCall = CGGeneric("""dom::bindings::htmlconstructor::call_html_constructor::( + cx, + &args, + &*global, + GetProtoObject, + )""" % self.descriptor.name) else: name = self.constructor.identifier.name nativeName = MakeNativeName(self.descriptor.binaryNameFor(name)) @@ -6131,7 +6068,6 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'crate::dom::bindings::interface::define_guarded_constants', 'crate::dom::bindings::interface::define_guarded_methods', 'crate::dom::bindings::interface::define_guarded_properties', - 'crate::dom::bindings::htmlconstructor::html_constructor', 'crate::dom::bindings::interface::is_exposed_in', 'crate::dom::bindings::htmlconstructor::pop_current_element_queue', 'crate::dom::bindings::htmlconstructor::push_new_element_queue', -- cgit v1.2.3 From bd5796c90b8e8e066a32e7da9cfa5251d1559046 Mon Sep 17 00:00:00 2001 From: Gregory Terzian Date: Sat, 29 Feb 2020 11:59:10 +0800 Subject: integrate readablestream with fetch and blob --- .../script/dom/bindings/codegen/CodegenRust.py | 37 ++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index b486806e562..0b1187a07fb 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -906,6 +906,40 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, return handleOptional(templateBody, declType, handleDefault("None")) + if type.isReadableStream(): + assert not isEnforceRange and not isClamp + + if failureCode is None: + unwrapFailureCode = '''throw_type_error(*cx, "This object is not \ + an instance of ReadableStream.");\n''' + else: + unwrapFailureCode = failureCode + + templateBody = fill( + """ + { + use crate::realms::{AlreadyInRealm, InRealm}; + let in_realm_proof = AlreadyInRealm::assert_for_cx(cx); + match ReadableStream::from_js(cx, $${val}.get().to_object(), InRealm::Already(&in_realm_proof)) { + Ok(val) => val, + Err(()) => { + $*{failureCode} + } + } + + } + """, + failureCode=unwrapFailureCode + "\n", + ) + + templateBody = wrapObjectTemplate(templateBody, "None", + isDefinitelyObject, type, failureCode) + + declType = CGGeneric("DomRoot") + + return handleOptional(templateBody, declType, + handleDefault("None")) + elif type.isSpiderMonkeyInterface(): raise TypeError("Can't handle SpiderMonkey interface arguments other than typed arrays yet") @@ -4481,6 +4515,9 @@ def getUnionTypeTemplateVars(type, descriptorProvider): elif type.isObject(): name = type.name typeName = "Heap<*mut JSObject>" + elif type.isReadableStream(): + name = type.name + typeName = "DomRoot" elif is_typed_array(type): name = type.name typeName = "typedarray::Heap" + name -- cgit v1.2.3 From 3367db6067a8d76061e7884e54cc61ce44012442 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 5 Jun 2020 00:04:47 +0200 Subject: Keep DOM proxy handlers as separate named items rather than in one array --- .../script/dom/bindings/codegen/CodegenRust.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 0b1187a07fb..5440884ab16 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2750,7 +2750,7 @@ class CGWrapMethod(CGAbstractMethod): unforgeable = CopyUnforgeablePropertiesToInstance(self.descriptor) if self.descriptor.proxy: create = """ -let handler = RegisterBindings::PROXY_HANDLERS[PrototypeList::Proxies::%(concreteType)s as usize]; +let handler = RegisterBindings::proxy_handlers::%(concreteType)s; rooted!(in(*cx) let obj = NewProxyObject( *cx, handler, @@ -6744,7 +6744,7 @@ class CGRegisterProxyHandlersMethod(CGAbstractMethod): def definition_body(self): return CGList([ - CGGeneric("PROXY_HANDLERS[Proxies::%s as usize] = Bindings::%s::DefineProxyHandler();" + CGGeneric("proxy_handlers::%s = Bindings::%s::DefineProxyHandler();" % (desc.name, '::'.join([desc.name + 'Binding'] * 2))) for desc in self.descriptors ], "\n") @@ -6753,10 +6753,17 @@ class CGRegisterProxyHandlersMethod(CGAbstractMethod): class CGRegisterProxyHandlers(CGThing): def __init__(self, config): descriptors = config.getDescriptors(proxy=True) - length = len(descriptors) self.root = CGList([ - CGGeneric("pub static mut PROXY_HANDLERS: [*const libc::c_void; %d] = [0 as *const libc::c_void; %d];" - % (length, length)), + CGGeneric( + "#[allow(non_upper_case_globals)]\n" + + "pub mod proxy_handlers {\n" + + "".join( + " pub static mut %s: *const libc::c_void = std::ptr::null();\n" + % desc.name + for desc in descriptors + ) + + "}\n" + ), CGRegisterProxyHandlersMethod(descriptors), ], "\n") @@ -7606,8 +7613,6 @@ class GlobalGenRoots(): for d in config.getDescriptors(hasInterfaceObject=True) if d.shouldHaveGetConstructorObjectMethod()]) - proxies = [d.name for d in config.getDescriptors(proxy=True)] - return CGList([ CGGeneric(AUTOGENERATED_WARNING_COMMENT), CGGeneric("pub const PROTO_OR_IFACE_LENGTH: usize = %d;\n" % (len(protos) + len(constructors))), @@ -7624,7 +7629,6 @@ class GlobalGenRoots(): " debug_assert!(proto_id < ID::Last as u16);\n" " INTERFACES[proto_id as usize]\n" "}\n\n"), - CGNonNamespacedEnum('Proxies', proxies, 0, deriving="PartialEq, Copy, Clone"), ]) @staticmethod @@ -7636,8 +7640,6 @@ class GlobalGenRoots(): return CGImports(code, descriptors=[], callbacks=[], dictionaries=[], enums=[], typedefs=[], imports=[ 'crate::dom::bindings::codegen::Bindings', - 'crate::dom::bindings::codegen::PrototypeList::Proxies', - 'libc', ], config=config, ignored_warnings=[]) @staticmethod -- cgit v1.2.3 From 57d89675b01b49c573b14c1fd0be413d52b8ccdd Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 5 Jun 2020 00:10:14 +0200 Subject: Use atomic pointers instead of `static mut` for DOM proxy handlers --- components/script/dom/bindings/codegen/CodegenRust.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 5440884ab16..b0361d6ca47 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2750,7 +2750,9 @@ class CGWrapMethod(CGAbstractMethod): unforgeable = CopyUnforgeablePropertiesToInstance(self.descriptor) if self.descriptor.proxy: create = """ -let handler = RegisterBindings::proxy_handlers::%(concreteType)s; +let handler: *const libc::c_void = + RegisterBindings::proxy_handlers::%(concreteType)s + .load(std::sync::atomic::Ordering::Acquire); rooted!(in(*cx) let obj = NewProxyObject( *cx, handler, @@ -6744,7 +6746,10 @@ class CGRegisterProxyHandlersMethod(CGAbstractMethod): def definition_body(self): return CGList([ - CGGeneric("proxy_handlers::%s = Bindings::%s::DefineProxyHandler();" + CGGeneric("proxy_handlers::%s.store(\n" + " Bindings::%s::DefineProxyHandler() as *mut _,\n" + " std::sync::atomic::Ordering::Release,\n" + ");" % (desc.name, '::'.join([desc.name + 'Binding'] * 2))) for desc in self.descriptors ], "\n") @@ -6758,7 +6763,8 @@ class CGRegisterProxyHandlers(CGThing): "#[allow(non_upper_case_globals)]\n" + "pub mod proxy_handlers {\n" + "".join( - " pub static mut %s: *const libc::c_void = std::ptr::null();\n" + " pub static %s: std::sync::atomic::AtomicPtr =\n" + " std::sync::atomic::AtomicPtr::new(std::ptr::null_mut());\n" % desc.name for desc in descriptors ) + -- cgit v1.2.3 From edf86d1bdcd501fc0f3c024f7296fbb3540cdfa6 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Mon, 15 Jun 2020 17:27:47 -0400 Subject: dom: Convert parent dictionary values when converting dictionaries to JS. --- components/script/dom/bindings/codegen/CodegenRust.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index b0361d6ca47..1f0e09639c8 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -6557,7 +6557,10 @@ class CGDictionary(CGThing): (name, name, varInsert(name, member.identifier.name).define())) return CGGeneric("%s\n" % insertion.define()) - memberInserts = CGList([memberInsert(m) for m in self.memberInfo]) + memberInserts = [memberInsert(m) for m in self.memberInfo] + + if d.parent: + memberInserts = [CGGeneric("self.parent.to_jsobject(cx, obj);\n")] + memberInserts selfName = self.makeClassName(d) if self.membersNeedTracing(): @@ -6602,10 +6605,16 @@ class CGDictionary(CGThing): " }\n" "}\n" "\n" + "impl ${selfName} {\n" + " pub(crate) unsafe fn to_jsobject(&self, cx: *mut JSContext, mut obj: MutableHandleObject) {\n" + "${insertMembers}" + " }\n" + "}\n" + "\n" "impl ToJSValConvertible for ${selfName} {\n" " unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {\n" - " rooted!(in(cx) let obj = JS_NewObject(cx, ptr::null()));\n" - "${insertMembers}" + " rooted!(in(cx) let mut obj = JS_NewObject(cx, ptr::null()));\n" + " self.to_jsobject(cx, obj.handle_mut());\n" " rval.set(ObjectOrNullValue(obj.get()))\n" " }\n" "}\n").substitute({ @@ -6614,7 +6623,7 @@ class CGDictionary(CGThing): "empty": CGIndenter(CGGeneric(self.makeEmpty()), indentLevel=4).define(), "initParent": CGIndenter(CGGeneric(initParent), indentLevel=16).define(), "initMembers": CGIndenter(memberInits, indentLevel=16).define(), - "insertMembers": CGIndenter(memberInserts, indentLevel=8).define(), + "insertMembers": CGIndenter(CGList(memberInserts), indentLevel=8).define(), "preInitial": CGIndenter(CGGeneric(preInitial), indentLevel=8).define(), "postInitial": CGIndenter(CGGeneric(postInitial), indentLevel=8).define(), }) -- cgit v1.2.3 From d01648d637a350af0cb81470f956cc5edd18a9a4 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Sun, 21 Jun 2020 03:34:22 +0200 Subject: Fix remaining flake8 warnings --- .../script/dom/bindings/codegen/CodegenRust.py | 337 +++++++++++---------- .../script/dom/bindings/codegen/Configuration.py | 77 +++-- 2 files changed, 213 insertions(+), 201 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 1f0e09639c8..610da4abdbd 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -359,17 +359,17 @@ class CGMethodCall(CGThing): # First check for null or undefined pickFirstSignature("%s.get().is_null_or_undefined()" % distinguishingArg, - lambda s: (s[1][distinguishingIndex].type.nullable() or - s[1][distinguishingIndex].type.isDictionary())) + lambda s: (s[1][distinguishingIndex].type.nullable() + or s[1][distinguishingIndex].type.isDictionary())) # Now check for distinguishingArg being an object that implements a # non-callback interface. That includes typed arrays and # arraybuffers. interfacesSigs = [ s for s in possibleSignatures - if (s[1][distinguishingIndex].type.isObject() or - s[1][distinguishingIndex].type.isUnion() or - s[1][distinguishingIndex].type.isNonCallbackInterface())] + if (s[1][distinguishingIndex].type.isObject() + or s[1][distinguishingIndex].type.isUnion() + or s[1][distinguishingIndex].type.isNonCallbackInterface())] # There might be more than one of these; we need to check # which ones we unwrap to. @@ -424,24 +424,24 @@ class CGMethodCall(CGThing): pickFirstSignature("%s.get().is_object() && is_array_like(*cx, %s)" % (distinguishingArg, distinguishingArg), lambda s: - (s[1][distinguishingIndex].type.isSequence() or - s[1][distinguishingIndex].type.isObject())) + (s[1][distinguishingIndex].type.isSequence() + or s[1][distinguishingIndex].type.isObject())) # Check for vanilla JS objects # XXXbz Do we need to worry about security wrappers? pickFirstSignature("%s.get().is_object()" % distinguishingArg, - lambda s: (s[1][distinguishingIndex].type.isCallback() or - s[1][distinguishingIndex].type.isCallbackInterface() or - s[1][distinguishingIndex].type.isDictionary() or - s[1][distinguishingIndex].type.isObject())) + lambda s: (s[1][distinguishingIndex].type.isCallback() + or s[1][distinguishingIndex].type.isCallbackInterface() + or s[1][distinguishingIndex].type.isDictionary() + or s[1][distinguishingIndex].type.isObject())) # The remaining cases are mutually exclusive. The # pickFirstSignature calls are what change caseBody # Check for strings or enums if pickFirstSignature(None, - lambda s: (s[1][distinguishingIndex].type.isString() or - s[1][distinguishingIndex].type.isEnum())): + lambda s: (s[1][distinguishingIndex].type.isString() + or s[1][distinguishingIndex].type.isEnum())): pass # Check for primitives elif pickFirstSignature(None, @@ -482,9 +482,9 @@ class CGMethodCall(CGThing): def dictionaryHasSequenceMember(dictionary): return (any(typeIsSequenceOrHasSequenceMember(m.type) for m in - dictionary.members) or - (dictionary.parent and - dictionaryHasSequenceMember(dictionary.parent))) + dictionary.members) + or (dictionary.parent + and dictionaryHasSequenceMember(dictionary.parent))) def typeIsSequenceOrHasSequenceMember(type): @@ -618,22 +618,22 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, def onFailureNotAnObject(failureCode): return CGWrapper( CGGeneric( - failureCode or - ('throw_type_error(*cx, "%s is not an object.");\n' - '%s' % (firstCap(sourceDescription), exceptionCode))), + failureCode + or ('throw_type_error(*cx, "%s is not an object.");\n' + '%s' % (firstCap(sourceDescription), exceptionCode))), post="\n") def onFailureInvalidEnumValue(failureCode, passedVarName): return CGGeneric( - failureCode or - ('throw_type_error(*cx, &format!("\'{}\' is not a valid enum value for enumeration \'%s\'.", %s)); %s' - % (type.name, passedVarName, exceptionCode))) + failureCode + or ('throw_type_error(*cx, &format!("\'{}\' is not a valid enum value for enumeration \'%s\'.", %s)); %s' + % (type.name, passedVarName, exceptionCode))) def onFailureNotCallable(failureCode): return CGGeneric( - failureCode or - ('throw_type_error(*cx, \"%s is not callable.\");\n' - '%s' % (firstCap(sourceDescription), exceptionCode))) + failureCode + or ('throw_type_error(*cx, \"%s is not callable.\");\n' + '%s' % (firstCap(sourceDescription), exceptionCode))) # A helper function for handling default values. def handleDefault(nullValue): @@ -660,16 +660,16 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, # Handle the non-object cases by wrapping up the whole # thing in an if cascade. templateBody = ( - "if ${val}.get().is_object() {\n" + - CGIndenter(CGGeneric(templateBody)).define() + "\n") + "if ${val}.get().is_object() {\n" + + CGIndenter(CGGeneric(templateBody)).define() + "\n") if type.nullable(): templateBody += ( "} else if ${val}.get().is_null_or_undefined() {\n" " %s\n") % nullValue templateBody += ( - "} else {\n" + - CGIndenter(onFailureNotAnObject(failureCode)).define() + - "}") + "} else {\n" + + CGIndenter(onFailureNotAnObject(failureCode)).define() + + "}") return templateBody assert not (isEnforceRange and isClamp) # These are mutually exclusive @@ -713,9 +713,9 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, for memberType in type.unroll().flatMemberTypes if memberType.isDictionary() ] - if (defaultValue and - not isinstance(defaultValue, IDLNullValue) and - not isinstance(defaultValue, IDLDefaultDictionaryValue)): + if (defaultValue + and not isinstance(defaultValue, IDLNullValue) + and not isinstance(defaultValue, IDLDefaultDictionaryValue)): tag = defaultValue.type.tag() if tag is IDLType.Tags.bool: default = "%s::Boolean(%s)" % ( @@ -1626,13 +1626,13 @@ class PropertyDefiner: prefableSpecs.append( prefableTemplate % (cond, name + "_specs", len(specs) - 1)) - specsArray = ("const %s_specs: &'static [&'static[%s]] = &[\n" + - ",\n".join(specs) + "\n" + - "];\n") % (name, specType) + specsArray = ("const %s_specs: &'static [&'static[%s]] = &[\n" + + ",\n".join(specs) + "\n" + + "];\n") % (name, specType) - prefArray = ("const %s: &'static [Guard<&'static [%s]>] = &[\n" + - ",\n".join(prefableSpecs) + "\n" + - "];\n") % (name, specType) + prefArray = ("const %s: &'static [Guard<&'static [%s]>] = &[\n" + + ",\n".join(prefableSpecs) + "\n" + + "];\n") % (name, specType) return specsArray + prefArray @@ -1660,9 +1660,9 @@ class MethodDefiner(PropertyDefiner): # Ignore non-static methods for callback interfaces if not descriptor.interface.isCallback() or static: methods = [m for m in descriptor.interface.members if - m.isMethod() and m.isStatic() == static and - not m.isIdentifierLess() and - MemberIsUnforgeable(m, descriptor) == unforgeable] + m.isMethod() and m.isStatic() == static + and not m.isIdentifierLess() + and MemberIsUnforgeable(m, descriptor) == unforgeable] else: methods = [] self.regular = [{"name": m.identifier.name, @@ -1683,10 +1683,10 @@ class MethodDefiner(PropertyDefiner): # Generate the keys/values/entries aliases for value iterables. maplikeOrSetlikeOrIterable = descriptor.interface.maplikeOrSetlikeOrIterable - if (not static and not unforgeable and - (maplikeOrSetlikeOrIterable and - maplikeOrSetlikeOrIterable.isIterable() and - maplikeOrSetlikeOrIterable.isValueIterator())): + if (not static and not unforgeable + and maplikeOrSetlikeOrIterable + and maplikeOrSetlikeOrIterable.isIterable() + and maplikeOrSetlikeOrIterable.isValueIterator()): m = maplikeOrSetlikeOrIterable # Add our keys/values/entries/forEach @@ -1805,8 +1805,8 @@ class AttrDefiner(PropertyDefiner): self.regular = [ m for m in descriptor.interface.members if - m.isAttr() and m.isStatic() == static and - MemberIsUnforgeable(m, descriptor) == unforgeable + m.isAttr() and m.isStatic() == static + and MemberIsUnforgeable(m, descriptor) == unforgeable ] self.static = static self.unforgeable = unforgeable @@ -1902,6 +1902,7 @@ class ConstDefiner(PropertyDefiner): 'ConstantSpec', PropertyDefiner.getControllingCondition, specData) + # We'll want to insert the indent at the beginnings of lines, but we # don't want to indent empty lines. So only indent lines that have a # non-newline character on them. @@ -2003,8 +2004,8 @@ class CGImports(CGWrapper): def isImportable(type): if not type.isType(): - assert (type.isInterface() or type.isDictionary() or - type.isEnum() or type.isNamespace()) + assert (type.isInterface() or type.isDictionary() + or type.isEnum() or type.isNamespace()) return True return not (type.builtin or type.isSequence() or type.isUnion()) @@ -2878,8 +2879,8 @@ class CGIDLInterface(CGThing): def define(self): interface = self.descriptor.interface name = self.descriptor.concreteType - if (interface.getUserData("hasConcreteDescendant", False) or - interface.getUserData("hasProxyDescendant", False)): + if (interface.getUserData("hasConcreteDescendant", False) + or interface.getUserData("hasProxyDescendant", False)): depth = self.descriptor.prototypeDepth check = "class.interface_chain[%s] == PrototypeList::ID::%s" % (depth, name) elif self.descriptor.proxy: @@ -3466,9 +3467,9 @@ assert!(!proto.is_null());""" % (function,)) def needCx(returnType, arguments, considerTypes): - return (considerTypes and - (typeNeedsCx(returnType, True) or - any(typeNeedsCx(a.type) for a in arguments))) + return (considerTypes + and (typeNeedsCx(returnType, True) + or any(typeNeedsCx(a.type) for a in arguments))) class CGCallGenerator(CGThing): @@ -3775,10 +3776,10 @@ class CGSpecializedMethod(CGAbstractExternMethod): self.method) return CGWrapper(CGMethodCall([], nativeName, self.method.isStatic(), self.descriptor, self.method), - pre="let cx = SafeJSContext::from_ptr(cx);\n" + - ("let this = &*(this as *const %s);\n" % self.descriptor.concreteType) + - "let args = &*args;\n" - "let argc = args.argc_;\n") + pre="let cx = SafeJSContext::from_ptr(cx);\n" + + ("let this = &*(this as *const %s);\n" % self.descriptor.concreteType) + + "let args = &*args;\n" + "let argc = args.argc_;\n") @staticmethod def makeNativeName(descriptor, method): @@ -3868,8 +3869,8 @@ class CGSpecializedGetter(CGAbstractExternMethod): return CGWrapper(CGGetterCall([], self.attr.type, nativeName, self.descriptor, self.attr), - pre="let cx = SafeJSContext::from_ptr(cx);\n" + - ("let this = &*(this as *const %s);\n" % self.descriptor.concreteType)) + pre="let cx = SafeJSContext::from_ptr(cx);\n" + + ("let this = &*(this as *const %s);\n" % self.descriptor.concreteType)) @staticmethod def makeNativeName(descriptor, attr): @@ -3924,8 +3925,8 @@ class CGSpecializedSetter(CGAbstractExternMethod): self.attr) return CGWrapper(CGSetterCall([], self.attr.type, nativeName, self.descriptor, self.attr), - pre="let cx = SafeJSContext::from_ptr(cx);\n" + - ("let this = &*(this as *const %s);\n" % self.descriptor.concreteType)) + pre="let cx = SafeJSContext::from_ptr(cx);\n" + + ("let this = &*(this as *const %s);\n" % self.descriptor.concreteType)) @staticmethod def makeNativeName(descriptor, attr): @@ -4191,8 +4192,8 @@ class CGMemberJITInfo(CGThing): # don't want them coalesced with each other or loop-hoisted, since # their return value can change even if nothing is going on from our # point of view. - return (affects == "Nothing" and - (dependsOn != "Everything" and dependsOn != "DeviceState")) + return (affects == "Nothing" + and (dependsOn != "Everything" and dependsOn != "DeviceState")) def aliasSet(self): """Returns the alias set to store in the jitinfo. This may not be the @@ -4282,10 +4283,10 @@ class CGMemberJITInfo(CGThing): if type == existingType: return existingType - if ((type == "JSVAL_TYPE_DOUBLE" and - existingType == "JSVAL_TYPE_INT32") or - (existingType == "JSVAL_TYPE_DOUBLE" and - type == "JSVAL_TYPE_INT32")): + if ((type == "JSVAL_TYPE_DOUBLE" + and existingType == "JSVAL_TYPE_INT32") + or (existingType == "JSVAL_TYPE_DOUBLE" + and type == "JSVAL_TYPE_INT32")): # Promote INT32 to DOUBLE as needed return "JSVAL_TYPE_DOUBLE" # Different types @@ -5206,8 +5207,8 @@ class CGProxyNamedOperation(CGProxySpecialOperation): argName = self.arguments[0].identifier.name return ("let %s = jsid_to_string(*cx, Handle::from_raw(id)).expect(\"Not a string-convertible JSID?\");\n" "let this = UnwrapProxy(proxy);\n" - "let this = &*this;\n" % argName + - CGProxySpecialOperation.define(self)) + "let this = &*this;\n" % argName + + CGProxySpecialOperation.define(self)) class CGProxyNamedGetter(CGProxyNamedOperation): @@ -5288,11 +5289,11 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod): 'successCode': fillDescriptor, 'pre': 'rooted!(in(*cx) let mut result_root = UndefinedValue());' } - get += ("if let Some(index) = index {\n" + - " let this = UnwrapProxy(proxy);\n" + - " let this = &*this;\n" + - CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define() + "\n" + - "}\n") + get += ("if let Some(index) = index {\n" + + " let this = UnwrapProxy(proxy);\n" + + " let this = &*this;\n" + + CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define() + "\n" + + "}\n") namedGetter = self.descriptor.operations['NamedGetter'] if namedGetter: @@ -5373,16 +5374,16 @@ class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod): indexedSetter = self.descriptor.operations['IndexedSetter'] if indexedSetter: - set += ("let index = get_array_index_from_id(*cx, Handle::from_raw(id));\n" + - "if let Some(index) = index {\n" + - " let this = UnwrapProxy(proxy);\n" + - " let this = &*this;\n" + - CGIndenter(CGProxyIndexedSetter(self.descriptor)).define() + - " return (*opresult).succeed();\n" + - "}\n") + set += ("let index = get_array_index_from_id(*cx, Handle::from_raw(id));\n" + + "if let Some(index) = index {\n" + + " let this = UnwrapProxy(proxy);\n" + + " let this = &*this;\n" + + CGIndenter(CGProxyIndexedSetter(self.descriptor)).define() + + " return (*opresult).succeed();\n" + + "}\n") elif self.descriptor.operations['IndexedGetter']: - set += ("if get_array_index_from_id(*cx, Handle::from_raw(id)).is_some() {\n" + - " return (*opresult).failNoIndexedSetter();\n" + + set += ("if get_array_index_from_id(*cx, Handle::from_raw(id)).is_some() {\n" + " return (*opresult).failNoIndexedSetter();\n" "}\n") namedSetter = self.descriptor.operations['NamedSetter'] @@ -5390,17 +5391,17 @@ class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod): if self.descriptor.hasUnforgeableMembers: raise TypeError("Can't handle a named setter on an interface that has " "unforgeables. Figure out how that should work!") - set += ("if RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id) {\n" + - CGIndenter(CGProxyNamedSetter(self.descriptor)).define() + - " return (*opresult).succeed();\n" + - "}\n") + set += ("if RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id) {\n" + + CGIndenter(CGProxyNamedSetter(self.descriptor)).define() + + " return (*opresult).succeed();\n" + + "}\n") elif self.descriptor.operations['NamedGetter']: - set += ("if RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id) {\n" + - CGIndenter(CGProxyNamedGetter(self.descriptor)).define() + - " if result.is_some() {\n" - " return (*opresult).failNoNamedSetter();\n" - " }\n" - "}\n") + set += ("if RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id) {\n" + + CGIndenter(CGProxyNamedGetter(self.descriptor)).define() + + " if result.is_some() {\n" + " return (*opresult).failNoNamedSetter();\n" + " }\n" + "}\n") set += "return proxyhandler::define_property(*cx, %s);" % ", ".join(a.name for a in self.args[1:]) return set @@ -5488,8 +5489,8 @@ class CGDOMJSProxyHandler_ownPropertyKeys(CGAbstractExternMethod): class CGDOMJSProxyHandler_getOwnEnumerablePropertyKeys(CGAbstractExternMethod): def __init__(self, descriptor): - assert (descriptor.operations["IndexedGetter"] and - descriptor.interface.getExtendedAttribute("LegacyUnenumerableNamedProperties")) + assert (descriptor.operations["IndexedGetter"] + and descriptor.interface.getExtendedAttribute("LegacyUnenumerableNamedProperties")) args = [Argument('*mut JSContext', 'cx'), Argument('RawHandleObject', 'proxy'), Argument('RawMutableHandleIdVector', 'props')] @@ -5543,14 +5544,14 @@ class CGDOMJSProxyHandler_hasOwn(CGAbstractExternMethod): indexedGetter = self.descriptor.operations['IndexedGetter'] indexed = "let cx = SafeJSContext::from_ptr(cx);\n" if indexedGetter: - indexed += ("let index = get_array_index_from_id(*cx, Handle::from_raw(id));\n" + - "if let Some(index) = index {\n" + - " let this = UnwrapProxy(proxy);\n" + - " let this = &*this;\n" + - CGIndenter(CGProxyIndexedGetter(self.descriptor)).define() + "\n" + - " *bp = result.is_some();\n" + - " return true;\n" + - "}\n\n") + indexed += ("let index = get_array_index_from_id(*cx, Handle::from_raw(id));\n" + + "if let Some(index) = index {\n" + + " let this = UnwrapProxy(proxy);\n" + + " let this = &*this;\n" + + CGIndenter(CGProxyIndexedGetter(self.descriptor)).define() + "\n" + + " *bp = result.is_some();\n" + + " return true;\n" + + "}\n\n") namedGetter = self.descriptor.operations['NamedGetter'] condition = "RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id)" @@ -5624,11 +5625,11 @@ if !expando.is_null() { indexedGetter = self.descriptor.operations['IndexedGetter'] if indexedGetter: - getIndexedOrExpando = ("let index = get_array_index_from_id(*cx, id_lt);\n" + - "if let Some(index) = index {\n" + - " let this = UnwrapProxy(proxy);\n" + - " let this = &*this;\n" + - CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define()) + getIndexedOrExpando = ("let index = get_array_index_from_id(*cx, id_lt);\n" + + "if let Some(index) = index {\n" + + " let this = UnwrapProxy(proxy);\n" + + " let this = &*this;\n" + + CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define()) getIndexedOrExpando += """\ // Even if we don't have this index, we don't forward the // get on to our expando object. @@ -5648,9 +5649,9 @@ if !expando.is_null() { # 3. Set ignoreNamedProps to true. if indexedGetter: condition = "index.is_none() && (%s)" % condition - getNamed = ("if %s {\n" + - CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() + - "}\n") % condition + getNamed = ("if %s {\n" + + CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() + + "}\n") % condition else: getNamed = "" @@ -5852,10 +5853,10 @@ class CGInterfaceTrait(CGThing): def members(): for m in descriptor.interface.members: - if (m.isMethod() and not m.isStatic() and - not m.isMaplikeOrSetlikeOrIterableMethod() and - (not m.isIdentifierLess() or (m.isStringifier() and not m.underlyingAttr)) and - not m.isDefaultToJSON()): + if (m.isMethod() and not m.isStatic() + and not m.isMaplikeOrSetlikeOrIterableMethod() + and (not m.isIdentifierLess() or (m.isStringifier() and not m.underlyingAttr)) + and not m.isDefaultToJSON()): name = CGSpecializedMethod.makeNativeName(descriptor, m) infallible = 'infallible' in descriptor.getExtendedAttributes(m) for idx, (rettype, arguments) in enumerate(m.signatures()): @@ -6254,8 +6255,8 @@ class CGDescriptor(CGThing): defaultToJSONMethod = None unscopableNames = [] for m in descriptor.interface.members: - if (m.isMethod() and - (not m.isIdentifierLess() or m == descriptor.operations["Stringifier"])): + if (m.isMethod() + and (not m.isIdentifierLess() or m == descriptor.operations["Stringifier"])): if m.getExtendedAttribute("Unscopable"): assert not m.isStatic() unscopableNames.append(m.identifier.name) @@ -6506,14 +6507,14 @@ class CGDictionary(CGThing): return (string.Template( "#[derive(${derive})]\n" - "${mustRoot}" + - "pub struct ${selfName} {\n" + - "${inheritance}" + - "\n".join(memberDecls) + "\n" + - "}").substitute({"selfName": self.makeClassName(d), - "inheritance": inheritance, - "mustRoot": mustRoot, - "derive": ', '.join(derive)})) + + "${mustRoot}" + + "pub struct ${selfName} {\n" + + "${inheritance}" + + "\n".join(memberDecls) + "\n" + + "}").substitute({"selfName": self.makeClassName(d), + "inheritance": inheritance, + "mustRoot": mustRoot, + "derive": ', '.join(derive)})) def impl(self): d = self.dictionary @@ -6769,15 +6770,15 @@ class CGRegisterProxyHandlers(CGThing): descriptors = config.getDescriptors(proxy=True) self.root = CGList([ CGGeneric( - "#[allow(non_upper_case_globals)]\n" + - "pub mod proxy_handlers {\n" + + "#[allow(non_upper_case_globals)]\n" + "pub mod proxy_handlers {\n" "".join( " pub static %s: std::sync::atomic::AtomicPtr =\n" " std::sync::atomic::AtomicPtr::new(std::ptr::null_mut());\n" % desc.name for desc in descriptors - ) + - "}\n" + ) + + "}\n" ), CGRegisterProxyHandlersMethod(descriptors), ], "\n") @@ -7004,8 +7005,8 @@ class CGNativeMember(ClassMethod): static=member.isStatic(), # Mark our getters, which are attrs that # have a non-void return type, as const. - const=(not member.isStatic() and member.isAttr() and - not signature[0].isVoid()), + const=(not member.isStatic() and member.isAttr() + and not signature[0].isVoid()), breakAfterSelf=breakAfterSelf, unsafe=unsafe, visibility=visibility) @@ -7087,23 +7088,23 @@ class CGCallback(CGClass): setupCall = "let s = CallSetup::new(self, aExceptionHandling);\n" bodyWithThis = string.Template( - setupCall + - "rooted!(in(*s.get_context()) let mut thisObjJS = ptr::null_mut::());\n" - "wrap_call_this_object(s.get_context(), thisObj, thisObjJS.handle_mut());\n" - "if thisObjJS.is_null() {\n" - " return Err(JSFailed);\n" - "}\n" - "unsafe { ${methodName}(${callArgs}) }").substitute({ - "callArgs": ", ".join(argnamesWithThis), - "methodName": 'self.' + method.name, - }) + setupCall + + "rooted!(in(*s.get_context()) let mut thisObjJS = ptr::null_mut::());\n" + "wrap_call_this_object(s.get_context(), thisObj, thisObjJS.handle_mut());\n" + "if thisObjJS.is_null() {\n" + " return Err(JSFailed);\n" + "}\n" + "unsafe { ${methodName}(${callArgs}) }").substitute({ + "callArgs": ", ".join(argnamesWithThis), + "methodName": 'self.' + method.name, + }) bodyWithoutThis = string.Template( - setupCall + - "rooted!(in(*s.get_context()) let thisObjJS = ptr::null_mut::());\n" - "unsafe { ${methodName}(${callArgs}) }").substitute({ - "callArgs": ", ".join(argnamesWithoutThis), - "methodName": 'self.' + method.name, - }) + setupCall + + "rooted!(in(*s.get_context()) let thisObjJS = ptr::null_mut::());\n" + "unsafe { ${methodName}(${callArgs}) }").substitute({ + "callArgs": ", ".join(argnamesWithoutThis), + "methodName": 'self.' + method.name, + }) return [ClassMethod(method.name + '_', method.returnType, args, bodyInHeader=True, templateArgs=["T: DomObject"], @@ -7314,28 +7315,28 @@ class CallbackMember(CGNativeMember): conversion = wrapForType( "argv_root.handle_mut()", result=argval, - successCode=("{\n" + - "let arg = &mut argv[%s];\n" + - "*arg = Heap::default();\n" + - "arg.set(argv_root.get());\n" + + successCode=("{\n" + "let arg = &mut argv[%s];\n" + "*arg = Heap::default();\n" + "arg.set(argv_root.get());\n" "}") % jsvalIndex, pre="rooted!(in(*cx) let mut argv_root = UndefinedValue());") if arg.variadic: conversion = string.Template( - "for idx in 0..${arg}.len() {\n" + - CGIndenter(CGGeneric(conversion)).define() + "\n" - "}" + "for idx in 0..${arg}.len() {\n" + + CGIndenter(CGGeneric(conversion)).define() + "\n" + + "}" ).substitute({"arg": arg.identifier.name}) elif arg.optional and not arg.defaultValue: conversion = ( CGIfWrapper("%s.is_some()" % arg.identifier.name, - CGGeneric(conversion)).define() + - " else if argc == %d {\n" - " // This is our current trailing argument; reduce argc\n" - " argc -= 1;\n" - "} else {\n" - " argv[%d] = Heap::default();\n" - "}" % (i + 1, i)) + CGGeneric(conversion)).define() + + " else if argc == %d {\n" + " // This is our current trailing argument; reduce argc\n" + " argc -= 1;\n" + "} else {\n" + " argv[%d] = Heap::default();\n" + "}" % (i + 1, i)) return conversion def getArgs(self, returnType, argList): @@ -7464,8 +7465,8 @@ class CallbackOperationBase(CallbackMethod): return 'rooted!(in(*cx) let callable =\n' + getCallableFromProp + ');\n' return ( 'let isCallable = IsCallable(self.callback());\n' - 'rooted!(in(*cx) let callable =\n' + - CGIndenter( + 'rooted!(in(*cx) let callable =\n' + + CGIndenter( CGIfElseWrapper('isCallable', CGGeneric('ObjectValue(self.callback())'), CGGeneric(getCallableFromProp))).define() + ');\n') @@ -7676,9 +7677,9 @@ class GlobalGenRoots(): return getModuleFromObject(d).split('::')[-1] descriptors = config.getDescriptors(register=True, isIteratorInterface=False) - descriptors = (set(toBindingNamespace(d.name) for d in descriptors) | - set(leafModule(d) for d in config.callbacks) | - set(leafModule(d) for d in config.getDictionaries())) + descriptors = (set(toBindingNamespace(d.name) for d in descriptors) + | set(leafModule(d) for d in config.callbacks) + | set(leafModule(d) for d in config.getDictionaries())) curr = CGList([CGGeneric("pub mod %s;\n" % name) for name in sorted(descriptors)]) curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT) return curr diff --git a/components/script/dom/bindings/codegen/Configuration.py b/components/script/dom/bindings/codegen/Configuration.py index b3e1e0c8289..98fce57afe4 100644 --- a/components/script/dom/bindings/codegen/Configuration.py +++ b/components/script/dom/bindings/codegen/Configuration.py @@ -63,7 +63,8 @@ class Configuration: c.isCallback() and not c.isInterface()] # Keep the descriptor list sorted for determinism. - cmp = lambda x, y: (x > y) - (x < y) + def cmp(x, y): + return (x > y) - (x < y) self.descriptors.sort(key=functools.cmp_to_key(lambda x, y: cmp(x.name, y.name))) def getInterface(self, ifname): @@ -74,25 +75,35 @@ class Configuration: curr = self.descriptors for key, val in filters.iteritems(): if key == 'webIDLFile': - getter = lambda x: x.interface.filename() + def getter(x): + return x.interface.filename() elif key == 'hasInterfaceObject': - getter = lambda x: x.interface.hasInterfaceObject() + def getter(x): + return x.interface.hasInterfaceObject() elif key == 'isCallback': - getter = lambda x: x.interface.isCallback() + def getter(x): + return x.interface.isCallback() elif key == 'isNamespace': - getter = lambda x: x.interface.isNamespace() + def getter(x): + return x.interface.isNamespace() elif key == 'isJSImplemented': - getter = lambda x: x.interface.isJSImplemented() + def getter(x): + return x.interface.isJSImplemented() elif key == 'isGlobal': - getter = lambda x: x.isGlobal() + def getter(x): + return x.isGlobal() elif key == 'isInline': - getter = lambda x: x.interface.getExtendedAttribute('Inline') is not None + def getter(x): + return x.interface.getExtendedAttribute('Inline') is not None elif key == 'isExposedConditionally': - getter = lambda x: x.interface.isExposedConditionally() + def getter(x): + return x.interface.isExposedConditionally() elif key == 'isIteratorInterface': - getter = lambda x: x.interface.isIteratorInterface() + def getter(x): + return x.interface.isIteratorInterface() else: - getter = lambda x: getattr(x, key) + def getter(x): + return getattr(x, key) curr = filter(lambda x: getter(x) == val, curr) return curr @@ -125,8 +136,8 @@ class Configuration: # We should have exactly one result. if len(descriptors) != 1: - raise NoSuchDescriptorError("For " + interfaceName + " found " + - str(len(descriptors)) + " matches") + raise NoSuchDescriptorError("For " + interfaceName + " found " + + str(len(descriptors)) + " matches") return descriptors[0] def getDescriptorProvider(self): @@ -157,10 +168,10 @@ class DescriptorProvider: def MemberIsUnforgeable(member, descriptor): - return ((member.isAttr() or member.isMethod()) and - not member.isStatic() and - (member.isUnforgeable() or - bool(descriptor.interface.getExtendedAttribute("Unforgeable")))) + return ((member.isAttr() or member.isMethod()) + and not member.isStatic() + and (member.isUnforgeable() + or bool(descriptor.interface.getExtendedAttribute("Unforgeable")))) class Descriptor(DescriptorProvider): @@ -228,14 +239,14 @@ class Descriptor(DescriptorProvider): # If we're concrete, we need to crawl our ancestor interfaces and mark # them as having a concrete descendant. - self.concrete = (not self.interface.isCallback() and - not self.interface.isNamespace() and - not self.interface.getExtendedAttribute("Abstract") and - not self.interface.getExtendedAttribute("Inline") and - not spiderMonkeyInterface) - self.hasUnforgeableMembers = (self.concrete and - any(MemberIsUnforgeable(m, self) for m in - self.interface.members)) + self.concrete = (not self.interface.isCallback() + and not self.interface.isNamespace() + and not self.interface.getExtendedAttribute("Abstract") + and not self.interface.getExtendedAttribute("Inline") + and not spiderMonkeyInterface) + self.hasUnforgeableMembers = (self.concrete + and any(MemberIsUnforgeable(m, self) for m in + self.interface.members)) self.operations = { 'IndexedGetter': None, @@ -391,8 +402,8 @@ class Descriptor(DescriptorProvider): return None def hasDescendants(self): - return (self.interface.getUserData("hasConcreteDescendant", False) or - self.interface.getUserData("hasProxyDescendant", False)) + return (self.interface.getUserData("hasConcreteDescendant", False) + or self.interface.getUserData("hasProxyDescendant", False)) def hasHTMLConstructor(self): ctor = self.interface.ctor() @@ -402,8 +413,8 @@ class Descriptor(DescriptorProvider): assert self.interface.hasInterfaceObject() if self.interface.getExtendedAttribute("Inline"): return False - return (self.interface.isCallback() or self.interface.isNamespace() or - self.hasDescendants() or self.hasHTMLConstructor()) + return (self.interface.isCallback() or self.interface.isNamespace() + or self.hasDescendants() or self.hasHTMLConstructor()) def shouldCacheConstructor(self): return self.hasDescendants() or self.hasHTMLConstructor() @@ -416,8 +427,8 @@ class Descriptor(DescriptorProvider): Returns true if this is the primary interface for a global object of some sort. """ - return bool(self.interface.getExtendedAttribute("Global") or - self.interface.getExtendedAttribute("PrimaryGlobal")) + return bool(self.interface.getExtendedAttribute("Global") + or self.interface.getExtendedAttribute("PrimaryGlobal")) # Some utility methods @@ -428,8 +439,8 @@ def MakeNativeName(name): def getModuleFromObject(object): - return ('crate::dom::bindings::codegen::Bindings::' + - os.path.basename(object.location.filename()).split('.webidl')[0] + 'Binding') + return ('crate::dom::bindings::codegen::Bindings::' + + os.path.basename(object.location.filename()).split('.webidl')[0] + 'Binding') def getTypesFromDescriptor(descriptor): -- cgit v1.2.3 From 2a2e037a4d559c5c98420da3b6eeefa6c3d5037c Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Sun, 21 Jun 2020 05:42:42 +0200 Subject: Fix incorrect string joining --- components/script/dom/bindings/codegen/CodegenRust.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 610da4abdbd..b078a8dac8a 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -6771,8 +6771,8 @@ class CGRegisterProxyHandlers(CGThing): self.root = CGList([ CGGeneric( "#[allow(non_upper_case_globals)]\n" - "pub mod proxy_handlers {\n" - "".join( + + "pub mod proxy_handlers {\n" + + "".join( " pub static %s: std::sync::atomic::AtomicPtr =\n" " std::sync::atomic::AtomicPtr::new(std::ptr::null_mut());\n" % desc.name -- cgit v1.2.3 From b74cea3a4698ca7e35a801b37b8b61479a46ede5 Mon Sep 17 00:00:00 2001 From: Kunal Mohan Date: Mon, 22 Jun 2020 19:52:02 +0530 Subject: Implement GPUBuffer.mapAsync and update wgpu-core --- components/script/dom/bindings/codegen/Bindings.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf index 7aa8ffa4c8b..e4d4c234262 100644 --- a/components/script/dom/bindings/codegen/Bindings.conf +++ b/components/script/dom/bindings/codegen/Bindings.conf @@ -153,7 +153,7 @@ DOMInterfaces = { }, 'GPUBuffer': { - 'inRealms': ['MapReadAsync'], + 'inRealms': ['MapAsync'], } } -- cgit v1.2.3 From aa80f9139909b451d434093e0ef38266f56bda3e Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 9 Jul 2020 20:01:01 -0400 Subject: dom: Use pref macro for IDL conditional guards. --- components/script/dom/bindings/codegen/CodegenRust.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index b078a8dac8a..c80fec57b5b 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2662,7 +2662,7 @@ class CGConstructorEnabled(CGAbstractMethod): pref = iface.getExtendedAttribute("Pref") if pref: assert isinstance(pref, list) and len(pref) == 1 - conditions.append('prefs::pref_map().get("%s").as_bool().unwrap_or(false)' % pref[0]) + conditions.append('pref!(%s)' % pref[0]) func = iface.getExtendedAttribute("Func") if func: -- cgit v1.2.3 From 63528f6fdf192542cd811a2a3ef5f0cb2fecbc6b Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 9 Jul 2020 20:03:03 -0400 Subject: dom: Generate iterator symbol for interfaces with indexed getters. --- .../script/dom/bindings/codegen/CodegenRust.py | 23 ++++++++++++++++++++-- .../script/dom/bindings/codegen/Configuration.py | 3 +++ 2 files changed, 24 insertions(+), 2 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index c80fec57b5b..4d1a3972d7b 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1672,8 +1672,27 @@ class MethodDefiner(PropertyDefiner): "condition": PropertyDefiner.getControllingCondition(m, descriptor)} for m in methods] - # FIXME Check for an existing iterator on the interface first. - if any(m.isGetter() and m.isIndexed() for m in methods): + # TODO: Once iterable is implemented, use tiebreak rules instead of + # failing. Also, may be more tiebreak rules to implement once spec bug + # is resolved. + # https://www.w3.org/Bugs/Public/show_bug.cgi?id=28592 + def hasIterator(methods, regular): + return (any("@@iterator" in m.aliases for m in methods) + or any("@@iterator" == r["name"] for r in regular)) + + # Check whether we need to output an @@iterator due to having an indexed + # getter. We only do this while outputting non-static and + # non-unforgeable methods, since the @@iterator function will be + # neither. + if (not static + and not unforgeable + and descriptor.supportsIndexedProperties()): # noqa + if hasIterator(methods, self.regular): # noqa + raise TypeError("Cannot have indexed getter/attr on " + "interface %s with other members " + "that generate @@iterator, such as " + "maplike/setlike or aliased functions." % + self.descriptor.interface.identifier.name) self.regular.append({"name": '@@iterator', "methodInfo": False, "selfHostedName": "$ArrayValues", diff --git a/components/script/dom/bindings/codegen/Configuration.py b/components/script/dom/bindings/codegen/Configuration.py index 98fce57afe4..4f47a737706 100644 --- a/components/script/dom/bindings/codegen/Configuration.py +++ b/components/script/dom/bindings/codegen/Configuration.py @@ -401,6 +401,9 @@ class Descriptor(DescriptorProvider): parent = parent.parent return None + def supportsIndexedProperties(self): + return self.operations['IndexedGetter'] is not None + def hasDescendants(self): return (self.interface.getUserData("hasConcreteDescendant", False) or self.interface.getUserData("hasProxyDescendant", False)) -- cgit v1.2.3 From 0dc1514d573260e736e3587f352a9663bd6be93b Mon Sep 17 00:00:00 2001 From: Kunal Mohan Date: Tue, 7 Jul 2020 14:37:42 +0530 Subject: Implement Async Error reporting for WebGPU and update wgpu-core --- components/script/dom/bindings/codegen/Bindings.conf | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf index e4d4c234262..ec8974b6cbd 100644 --- a/components/script/dom/bindings/codegen/Bindings.conf +++ b/components/script/dom/bindings/codegen/Bindings.conf @@ -154,6 +154,10 @@ DOMInterfaces = { 'GPUBuffer': { 'inRealms': ['MapAsync'], +}, + +'GPUDevice': { + 'inRealms': ['PopErrorScope', 'Lost'], } } -- cgit v1.2.3 From 0c7f08f74329313326e533d2e98ddc41874260ed Mon Sep 17 00:00:00 2001 From: CYBAI Date: Sat, 4 Jul 2020 17:55:30 +0900 Subject: Introduce DynamicModuleOwner dom struct --- components/script/dom/bindings/codegen/Bindings.conf | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf index e4d4c234262..9cca9647e94 100644 --- a/components/script/dom/bindings/codegen/Bindings.conf +++ b/components/script/dom/bindings/codegen/Bindings.conf @@ -47,6 +47,10 @@ DOMInterfaces = { 'inRealms': ['PromiseAttribute', 'PromiseNativeHandler'], }, +'DynamicModuleOwner': { + 'inRealms': ['PromiseAttribute'], +}, + 'URL': { 'weakReferenceable': True, }, -- cgit v1.2.3 From f8c9ee4eff1ae7a72037e16f2aa97ad6bb69da4e Mon Sep 17 00:00:00 2001 From: Sudarsan Date: Fri, 28 Aug 2020 20:54:18 +0800 Subject: Update mozjs to 0.14.1 This update pulls in improvements on mozjs that now removes the need to pass pointers to CompileOptionsWraper::new(), allows NewProxyObject to now accept a Singleton bool and JSClass and removes an unsafe Handle::new usage. --- components/script/dom/bindings/codegen/CodegenRust.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 4d1a3972d7b..83e68cdce76 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2778,6 +2778,8 @@ rooted!(in(*cx) let obj = NewProxyObject( handler, Handle::from_raw(UndefinedHandleValue), proto.get(), + ptr::null(), + false, )); assert!(!obj.is_null()); SetProxyReservedSlot( -- cgit v1.2.3 From 0e1479cc847333c81a37d11f0f65f0304972ba3c Mon Sep 17 00:00:00 2001 From: Jonathan Kingston Date: Tue, 24 Nov 2020 02:06:08 +0000 Subject: Add creation url and Secure Contexts --- components/script/dom/bindings/codegen/CodegenRust.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 83e68cdce76..13c295ef1a2 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1517,7 +1517,7 @@ def getRetvalDeclarationForType(returnType, descriptorProvider): returnType) -def MemberCondition(pref, func, exposed): +def MemberCondition(pref, func, exposed, secure): """ A string representing the condition for a member to actually be exposed. Any of the arguments can be None. If not None, they should have the @@ -1526,11 +1526,14 @@ def MemberCondition(pref, func, exposed): pref: The name of the preference. func: The name of the function. exposed: One or more names of an exposed global. + secure: Requires secure context. """ assert pref is None or isinstance(pref, str) assert func is None or isinstance(func, str) assert exposed is None or isinstance(exposed, set) - assert func is None or pref is None or exposed is None + assert func is None or pref is None or exposed is None or secure is None + if secure: + return 'Condition::SecureContext()' if pref: return 'Condition::Pref("%s")' % pref if func: @@ -1580,7 +1583,8 @@ class PropertyDefiner: "Pref"), PropertyDefiner.getStringAttr(interfaceMember, "Func"), - interfaceMember.exposureSet) + interfaceMember.exposureSet, + interfaceMember.getExtendedAttribute("SecureContext")) def generateGuardedArray(self, array, name, specTemplate, specTerminator, specType, getCondition, getDataTuple): @@ -3038,7 +3042,7 @@ let global = incumbent_global.reflector().get_jsobject();\n""" for m in interface.members: if m.isAttr() and not m.isStatic() and m.type.isJSONType(): name = m.identifier.name - conditions = MemberCondition(None, None, m.exposureSet) + conditions = MemberCondition(None, None, m.exposureSet, None) ret_conditions = '&[' + ", ".join(conditions) + "]" ret += fill( """ @@ -7838,6 +7842,7 @@ impl %(base)s { if PropertyDefiner.getStringAttr(m, 'Pref') or \ PropertyDefiner.getStringAttr(m, 'Func') or \ PropertyDefiner.getStringAttr(m, 'Exposed') or \ + m.getExtendedAttribute('SecureContext') or \ (m.isMethod() and m.isIdentifierLess()): continue display = m.identifier.name + ('()' if m.isMethod() else '') -- cgit v1.2.3 From 823cca30d65f58eaa80085ff2e40e99ba7bcb8ba Mon Sep 17 00:00:00 2001 From: Sean Joseph Date: Thu, 26 Nov 2020 18:30:52 -0500 Subject: Added is_platform_obj_static --- components/script/dom/bindings/codegen/CodegenRust.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 13c295ef1a2..7d2cfcdd31e 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -6182,7 +6182,8 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'crate::dom::bindings::utils::get_property_on_prototype', 'crate::dom::bindings::utils::get_proto_or_iface_array', 'crate::dom::bindings::utils::has_property_on_prototype', - 'crate::dom::bindings::utils::is_platform_object', + 'crate::dom::bindings::utils::is_platform_object_dynamic', + 'crate::dom::bindings::utils::is_platform_object_static', 'crate::dom::bindings::utils::resolve_global', 'crate::dom::bindings::utils::set_dictionary_property', 'crate::dom::bindings::utils::trace_global', -- cgit v1.2.3 From 5c4939599e2793154569b19db87be8cc05ca9269 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Sun, 24 Jan 2021 14:07:10 -0500 Subject: Update mozjs. --- components/script/dom/bindings/codegen/CodegenRust.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 7d2cfcdd31e..88ed2a2f456 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1884,7 +1884,7 @@ class AttrDefiner(PropertyDefiner): array, name, ' JSPropertySpec {\n' ' name: JSPropertySpec_Name { string_: %s as *const u8 as *const libc::c_char },\n' - ' flags: (%s) as u8,\n' + ' flags_: (%s) as u8,\n' ' u: JSPropertySpec_AccessorsOrValue {\n' ' accessors: JSPropertySpec_AccessorsOrValue_Accessors {\n' ' getter: JSPropertySpec_Accessor {\n' @@ -2741,7 +2741,7 @@ ensure_expando_object(*cx, obj.handle().into(), expando.handle_mut()); # unforgeable holder for those with the right JSClass. Luckily, there # aren't too many globals being created. if descriptor.isGlobal(): - copyFunc = "JS_CopyPropertiesFrom" + copyFunc = "JS_CopyOwnPropertiesAndPrivateFields" else: copyFunc = "JS_InitializePropertiesFromCompatibleNativeObject" copyCode += """\ @@ -2783,7 +2783,6 @@ rooted!(in(*cx) let obj = NewProxyObject( Handle::from_raw(UndefinedHandleValue), proto.get(), ptr::null(), - false, )); assert!(!obj.is_null()); SetProxyReservedSlot( @@ -6059,7 +6058,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::jsapi::JSValueType', 'js::jsapi::JS_AtomizeAndPinString', 'js::rust::wrappers::JS_CallFunctionValue', - 'js::rust::wrappers::JS_CopyPropertiesFrom', + 'js::rust::wrappers::JS_CopyOwnPropertiesAndPrivateFields', 'js::rust::wrappers::JS_DefineProperty', 'js::rust::wrappers::JS_DefinePropertyById2', 'js::jsapi::JS_ForwardGetPropertyTo', -- cgit v1.2.3 From 397b9b2601eec94059f2b6f61510eb42c0bc264f Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Sun, 31 Jan 2021 19:30:40 -0500 Subject: Implement toStringTag symbol for DOM objects. This symbol is now required for the expected stringification behaviour in WPT. --- .../script/dom/bindings/codegen/CodegenRust.py | 91 ++++++++++++++++------ 1 file changed, 69 insertions(+), 22 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 88ed2a2f456..dbf363d0fbc 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1616,9 +1616,12 @@ class PropertyDefiner: specs = [] prefableSpecs = [] prefableTemplate = ' Guard::new(%s, %s[%d])' + origTemplate = specTemplate + if isinstance(specTemplate, str): + specTemplate = lambda _: origTemplate # noqa for cond, members in groupby(array, lambda m: getCondition(m, self.descriptor)): - currentSpecs = [specTemplate % getDataTuple(m) for m in members] + currentSpecs = [specTemplate(m) % getDataTuple(m) for m in members] if specTerminator: currentSpecs.append(specTerminator) specs.append("&[\n" + ",\n".join(currentSpecs) + "]\n") @@ -1826,7 +1829,11 @@ class AttrDefiner(PropertyDefiner): self.name = name self.descriptor = descriptor self.regular = [ - m + { + "name": m.identifier.name, + "attr": m, + "flags": "JSPROP_ENUMERATE", + } for m in descriptor.interface.members if m.isAttr() and m.isStatic() == static and MemberIsUnforgeable(m, descriptor) == unforgeable @@ -1834,15 +1841,21 @@ class AttrDefiner(PropertyDefiner): self.static = static self.unforgeable = unforgeable + if not static and not unforgeable and not ( + descriptor.interface.isNamespace() or descriptor.interface.isCallback() + ): + self.regular.append({ + "name": "@@toStringTag", + "attr": None, + "flags": "JSPROP_READONLY | JSPROP_INTERNAL_USE_BIT" + }) + def generateArray(self, array, name): if len(array) == 0: return "" - flags = "JSPROP_ENUMERATE" - if self.unforgeable: - flags += " | JSPROP_PERMANENT" - def getter(attr): + attr = attr['attr'] if self.static: accessor = 'get_' + self.descriptor.internalNameFor(attr.identifier.name) jitinfo = "0 as *const JSJitInfo" @@ -1858,6 +1871,7 @@ class AttrDefiner(PropertyDefiner): "native": accessor}) def setter(attr): + attr = attr['attr'] if (attr.readonly and not attr.getExtendedAttribute("PutForwards") and not attr.getExtendedAttribute("Replaceable")): return "JSNativeWrapper { op: None, info: 0 as *const JSJitInfo }" @@ -1876,29 +1890,59 @@ class AttrDefiner(PropertyDefiner): % {"info": jitinfo, "native": accessor}) + def condition(m, d): + if m["name"] == "@@toStringTag": + return MemberCondition(pref=None, func=None, exposed=None, secure=None) + return PropertyDefiner.getControllingCondition(m["attr"], d) + def specData(attr): - return (str_to_const_array(attr.identifier.name), flags, getter(attr), + if attr["name"] == "@@toStringTag": + return (attr["name"][2:], attr["flags"], + str_to_const_array(self.descriptor.interface.getClassName())) + + flags = attr["flags"] + if self.unforgeable: + flags += " | JSPROP_PERMANENT" + return (str_to_const_array(attr["attr"].identifier.name), flags, getter(attr), setter(attr)) + def template(m): + if m["name"] == "@@toStringTag": + return """ JSPropertySpec { + name: JSPropertySpec_Name { symbol_: SymbolCode::%s as usize + 1 }, + flags_: (%s) as u8, + u: JSPropertySpec_AccessorsOrValue { + value: JSPropertySpec_ValueWrapper { + type_: JSValueType::JSVAL_TYPE_STRING as _, + __bindgen_anon_1: JSPropertySpec_ValueWrapper__bindgen_ty_1 { + string: %s as *const u8 as *const libc::c_char, + } + } + } + } +""" + return """ JSPropertySpec { + name: JSPropertySpec_Name { string_: %s as *const u8 as *const libc::c_char }, + flags_: (%s) as u8, + u: JSPropertySpec_AccessorsOrValue { + accessors: JSPropertySpec_AccessorsOrValue_Accessors { + getter: JSPropertySpec_Accessor { + native: %s, + }, + setter: JSPropertySpec_Accessor { + native: %s, + } + } + } + } +""" + return self.generateGuardedArray( array, name, - ' JSPropertySpec {\n' - ' name: JSPropertySpec_Name { string_: %s as *const u8 as *const libc::c_char },\n' - ' flags_: (%s) as u8,\n' - ' u: JSPropertySpec_AccessorsOrValue {\n' - ' accessors: JSPropertySpec_AccessorsOrValue_Accessors {\n' - ' getter: JSPropertySpec_Accessor {\n' - ' native: %s,\n' - ' },\n' - ' setter: JSPropertySpec_Accessor {\n' - ' native: %s,\n' - ' }\n' - ' }\n' - ' }\n' - ' }', + template, ' JSPropertySpec::ZERO', 'JSPropertySpec', - PropertyDefiner.getControllingCondition, specData) + condition, specData) class ConstDefiner(PropertyDefiner): @@ -6046,11 +6090,14 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::jsapi::JSPROP_ENUMERATE', 'js::jsapi::JSPROP_PERMANENT', 'js::jsapi::JSPROP_READONLY', + 'js::jsapi::JSPROP_INTERNAL_USE_BIT', 'js::jsapi::JSPropertySpec', 'js::jsapi::JSPropertySpec_Accessor', 'js::jsapi::JSPropertySpec_AccessorsOrValue', 'js::jsapi::JSPropertySpec_AccessorsOrValue_Accessors', 'js::jsapi::JSPropertySpec_Name', + 'js::jsapi::JSPropertySpec_ValueWrapper', + 'js::jsapi::JSPropertySpec_ValueWrapper__bindgen_ty_1', 'js::jsapi::JSString', 'js::jsapi::JSTracer', 'js::jsapi::JSType', -- cgit v1.2.3 From a627dde0d01e35a1cbdb62ca19ee0349757c34b0 Mon Sep 17 00:00:00 2001 From: Vincent Ricard Date: Mon, 28 Dec 2020 22:31:49 +0100 Subject: Port some code to Python3 --- .../script/dom/bindings/codegen/CodegenRust.py | 40 +- .../script/dom/bindings/codegen/Configuration.py | 12 +- .../script/dom/bindings/codegen/parser/WebIDL.py | 72 +- components/script/dom/bindings/codegen/ply/README | 2 +- .../dom/bindings/codegen/ply/ply/__init__.py | 2 + .../script/dom/bindings/codegen/ply/ply/lex.py | 853 +++---- .../script/dom/bindings/codegen/ply/ply/yacc.py | 2654 +++++++------------- components/script/dom/bindings/codegen/run.py | 4 +- 8 files changed, 1350 insertions(+), 2289 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index dbf363d0fbc..8573998ebb3 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -344,7 +344,7 @@ class CGMethodCall(CGThing): distinguishingArg = "HandleValue::from_raw(args.get(%d))" % distinguishingIndex def pickFirstSignature(condition, filterLambda): - sigs = filter(filterLambda, possibleSignatures) + sigs = list(filter(filterLambda, possibleSignatures)) assert len(sigs) < 2 if len(sigs) > 0: call = getPerSignatureCall(sigs[0], distinguishingIndex) @@ -2117,7 +2117,7 @@ class CGImports(CGWrapper): members += [constructor] if d.proxy: - members += [o for o in d.operations.values() if o] + members += [o for o in list(d.operations.values()) if o] for m in members: if m.isMethod(): @@ -2557,7 +2557,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config): ]) # Sort unionStructs by key, retrieve value - unionStructs = (i[1] for i in sorted(unionStructs.items(), key=operator.itemgetter(0))) + unionStructs = (i[1] for i in sorted(list(unionStructs.items()), key=operator.itemgetter(0))) return CGImports(CGList(unionStructs, "\n\n"), descriptors=[], @@ -4455,9 +4455,10 @@ class CGEnum(CGThing): pub enum %s { %s } -""" % (ident, ",\n ".join(map(getEnumValueName, enum.values()))) +""" % (ident, ",\n ".join(map(getEnumValueName, list(enum.values())))) - pairs = ",\n ".join(['("%s", super::%s::%s)' % (val, ident, getEnumValueName(val)) for val in enum.values()]) + pairs = ",\n ".join(['("%s", super::%s::%s)' % (val, ident, getEnumValueName(val)) + for val in list(enum.values())]) inner = string.Template("""\ use crate::dom::bindings::conversions::ConversionResult; @@ -4640,9 +4641,8 @@ class CGUnionStruct(CGThing): return "Rc" return "" - templateVars = map(lambda t: (getUnionTypeTemplateVars(t, self.descriptorProvider), - getTypeWrapper(t)), - self.type.flatMemberTypes) + templateVars = [(getUnionTypeTemplateVars(t, self.descriptorProvider), + getTypeWrapper(t)) for t in self.type.flatMemberTypes] enumValues = [ " %s(%s)," % (v["name"], "%s<%s>" % (wrapper, v["typeName"]) if wrapper else v["typeName"]) for (v, wrapper) in templateVars @@ -4701,7 +4701,7 @@ class CGUnionConversionStruct(CGThing): " Ok(None) => (),\n" "}\n") % (self.type, name, self.type, name) - interfaceMemberTypes = filter(lambda t: t.isNonCallbackInterface(), memberTypes) + interfaceMemberTypes = [t for t in memberTypes if t.isNonCallbackInterface()] if len(interfaceMemberTypes) > 0: typeNames = [get_name(memberType) for memberType in interfaceMemberTypes] interfaceObject = CGList(CGGeneric(get_match(typeName)) for typeName in typeNames) @@ -4709,7 +4709,7 @@ class CGUnionConversionStruct(CGThing): else: interfaceObject = None - arrayObjectMemberTypes = filter(lambda t: t.isSequence(), memberTypes) + arrayObjectMemberTypes = [t for t in memberTypes if t.isSequence()] if len(arrayObjectMemberTypes) > 0: assert len(arrayObjectMemberTypes) == 1 typeName = arrayObjectMemberTypes[0].name @@ -4718,7 +4718,7 @@ class CGUnionConversionStruct(CGThing): else: arrayObject = None - callbackMemberTypes = filter(lambda t: t.isCallback() or t.isCallbackInterface(), memberTypes) + callbackMemberTypes = [t for t in memberTypes if t.isCallback() or t.isCallbackInterface()] if len(callbackMemberTypes) > 0: assert len(callbackMemberTypes) == 1 typeName = callbackMemberTypes[0].name @@ -4726,7 +4726,7 @@ class CGUnionConversionStruct(CGThing): else: callbackObject = None - dictionaryMemberTypes = filter(lambda t: t.isDictionary(), memberTypes) + dictionaryMemberTypes = [t for t in memberTypes if t.isDictionary()] if len(dictionaryMemberTypes) > 0: assert len(dictionaryMemberTypes) == 1 typeName = dictionaryMemberTypes[0].name @@ -4735,7 +4735,7 @@ class CGUnionConversionStruct(CGThing): else: dictionaryObject = None - objectMemberTypes = filter(lambda t: t.isObject(), memberTypes) + objectMemberTypes = [t for t in memberTypes if t.isObject()] if len(objectMemberTypes) > 0: assert len(objectMemberTypes) == 1 typeName = objectMemberTypes[0].name @@ -4744,7 +4744,7 @@ class CGUnionConversionStruct(CGThing): else: object = None - mozMapMemberTypes = filter(lambda t: t.isRecord(), memberTypes) + mozMapMemberTypes = [t for t in memberTypes if t.isRecord()] if len(mozMapMemberTypes) > 0: assert len(mozMapMemberTypes) == 1 typeName = mozMapMemberTypes[0].name @@ -4790,9 +4790,9 @@ class CGUnionConversionStruct(CGThing): typename = get_name(memberType) return CGGeneric(get_match(typename)) other = [] - stringConversion = map(getStringOrPrimitiveConversion, stringTypes) - numericConversion = map(getStringOrPrimitiveConversion, numericTypes) - booleanConversion = map(getStringOrPrimitiveConversion, booleanTypes) + stringConversion = list(map(getStringOrPrimitiveConversion, stringTypes)) + numericConversion = list(map(getStringOrPrimitiveConversion, numericTypes)) + booleanConversion = list(map(getStringOrPrimitiveConversion, booleanTypes)) if stringConversion: if booleanConversion: other.append(CGIfWrapper("value.get().is_boolean()", booleanConversion[0])) @@ -5958,7 +5958,7 @@ class CGInterfaceTrait(CGThing): rettype) if descriptor.proxy: - for name, operation in descriptor.operations.iteritems(): + for name, operation in descriptor.operations.items(): if not operation or operation.isStringifier(): continue @@ -6488,7 +6488,7 @@ class CGDescriptor(CGThing): post='\n') if reexports: - reexports = ', '.join(map(lambda name: reexportedName(name), reexports)) + reexports = ', '.join([reexportedName(name) for name in reexports]) cgThings = CGList([CGGeneric('pub use self::%s::{%s};' % (toBindingNamespace(descriptor.name), reexports)), cgThings], '\n') @@ -7824,7 +7824,7 @@ impl Clone for TopTypeId { # TypeId enum. return "%s(%sTypeId)" % (name, name) if name in hierarchy else name - for base, derived in hierarchy.iteritems(): + for base, derived in hierarchy.items(): variants = [] if config.getDescriptor(base).concrete: variants.append(CGGeneric(base)) diff --git a/components/script/dom/bindings/codegen/Configuration.py b/components/script/dom/bindings/codegen/Configuration.py index 4f47a737706..b92f68af3b9 100644 --- a/components/script/dom/bindings/codegen/Configuration.py +++ b/components/script/dom/bindings/codegen/Configuration.py @@ -73,7 +73,7 @@ class Configuration: def getDescriptors(self, **filters): """Gets the descriptors that match the given filters.""" curr = self.descriptors - for key, val in filters.iteritems(): + for key, val in filters.items(): if key == 'webIDLFile': def getter(x): return x.interface.filename() @@ -104,14 +104,14 @@ class Configuration: else: def getter(x): return getattr(x, key) - curr = filter(lambda x: getter(x) == val, curr) + curr = [x for x in curr if getter(x) == val] return curr def getEnums(self, webIDLFile): - return filter(lambda e: e.filename() == webIDLFile, self.enums) + return [e for e in self.enums if e.filename() == webIDLFile] def getTypedefs(self, webIDLFile): - return filter(lambda e: e.filename() == webIDLFile, self.typedefs) + return [e for e in self.typedefs if e.filename() == webIDLFile] @staticmethod def _filterForFile(items, webIDLFile=""): @@ -119,7 +119,7 @@ class Configuration: if not webIDLFile: return items - return filter(lambda x: x.filename() == webIDLFile, items) + return [x for x in items if x.filename() == webIDLFile] def getDictionaries(self, webIDLFile=""): return self._filterForFile(self.dictionaries, webIDLFile=webIDLFile) @@ -327,7 +327,7 @@ class Descriptor(DescriptorProvider): if config == '*': iface = self.interface while iface: - add('all', map(lambda m: m.name, iface.members), attribute) + add('all', [m.name for m in iface.members], attribute) iface = iface.parent else: add('all', [config], attribute) diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index 223fd7efbb4..d74278c3e0c 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.py @@ -4,7 +4,7 @@ """ A WebIDL parser. """ -from __future__ import print_function + from ply import lex, yacc import re import os @@ -57,7 +57,7 @@ def enum(*names, **kw): if "base" not in kw: return Foo(names) - return Foo(chain(kw["base"].attrs.keys(), names)) + return Foo(chain(list(kw["base"].attrs.keys()), names)) class WebIDLError(Exception): @@ -124,6 +124,9 @@ class BuiltinLocation(object): return (isinstance(other, BuiltinLocation) and self.msg == other.msg) + def __hash__(self): + return hash(self.msg) + def filename(self): return '' @@ -2360,6 +2363,9 @@ class IDLNullableType(IDLParametrizedType): def __eq__(self, other): return isinstance(other, IDLNullableType) and self.inner == other.inner + def __hash__(self): + return hash(self.inner) + def __str__(self): return self.inner.__str__() + "OrNull" @@ -2522,6 +2528,9 @@ class IDLSequenceType(IDLParametrizedType): def __eq__(self, other): return isinstance(other, IDLSequenceType) and self.inner == other.inner + def __hash__(self): + return hash(self.inner) + def __str__(self): return self.inner.__str__() + "Sequence" @@ -2933,6 +2942,9 @@ class IDLWrapperType(IDLType): self._identifier == other._identifier and self.builtin == other.builtin) + def __hash__(self): + return hash((self._identifier, self.builtin)) + def __str__(self): return str(self.name) + " (Wrapper)" @@ -3301,6 +3313,12 @@ class IDLBuiltinType(IDLType): return "MaybeShared" + str(self.name) return str(self.name) + def __eq__(self, other): + return other and self.location == other.location and self.name == other.name and self._typeTag == other._typeTag + + def __hash__(self): + return hash((self.location, self.name, self._typeTag)) + def prettyName(self): return IDLBuiltinType.PrettyNames[self._typeTag] @@ -3628,7 +3646,7 @@ integerTypeSizes = { def matchIntegerValueToType(value): - for type, extremes in integerTypeSizes.items(): + for type, extremes in list(integerTypeSizes.items()): (min, max) = extremes if value <= max and value >= min: return BuiltinTypes[type] @@ -3707,7 +3725,7 @@ class IDLValue(IDLObject): elif self.type.isString() and type.isEnum(): # Just keep our string, but make sure it's a valid value for this enum enum = type.unroll().inner - if self.value not in enum.values(): + if self.value not in list(enum.values()): raise WebIDLError("'%s' is not a valid default value for enum %s" % (self.value, enum.identifier.name), [location, enum.location]) @@ -4789,7 +4807,7 @@ class IDLAttribute(IDLInterfaceMember): "CrossOriginWritable", "SetterThrows", ] - for (key, value) in self._extendedAttrDict.items(): + for (key, value) in list(self._extendedAttrDict.items()): if key in allowedExtAttrs: if value is not True: raise WebIDLError("[%s] with a value is currently " @@ -5479,7 +5497,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope): [attr.location]) if identifier == "CrossOriginCallable" and self.isStatic(): raise WebIDLError("[CrossOriginCallable] is only allowed on non-static " - "attributes" + "attributes", [attr.location, self.location]) elif identifier == "Pure": if not attr.noArguments(): @@ -5721,6 +5739,7 @@ class Tokenizer(object): "FLOATLITERAL", "IDENTIFIER", "STRING", + "COMMENTS", "WHITESPACE", "OTHER" ] @@ -5753,8 +5772,12 @@ class Tokenizer(object): t.value = t.value[1:-1] return t + def t_COMMENTS(self, t): + r'(\/\*(.|\n)*?\*\/)|(\/\/.*)' + pass + def t_WHITESPACE(self, t): - r'[\t\n\r ]+|[\t\n\r ]*((//[^\n]*|/\*.*?\*/)[\t\n\r ]*)+' + r'[\t\n\r ]+' pass def t_ELLIPSIS(self, t): @@ -5840,7 +5863,7 @@ class Tokenizer(object): "async": "ASYNC", } - tokens.extend(keywords.values()) + tokens.extend(list(keywords.values())) def t_error(self, t): raise WebIDLError("Unrecognized Input", @@ -5849,23 +5872,21 @@ class Tokenizer(object): lexpos=self.lexer.lexpos, filename=self.filename)]) - def __init__(self, outputdir, lexer=None): + def __init__(self, lexer=None): if lexer: self.lexer = lexer else: - self.lexer = lex.lex(object=self, - outputdir=outputdir, - lextab='webidllex', - reflags=re.DOTALL) + self.lexer = lex.lex(object=self) class SqueakyCleanLogger(object): errorWhitelist = [ - # Web IDL defines the WHITESPACE token, but doesn't actually + # Web IDL defines the WHITESPACE and COMMENTS token, but doesn't actually # use it ... so far. "Token 'WHITESPACE' defined, but not used", - # And that means we have an unused token - "There is 1 unused token", + "Token 'COMMENTS' defined, but not used", + # And that means we have unused tokens + "There are 2 unused tokens", # Web IDL defines a OtherOrComma rule that's only used in # ExtendedAttributeInner, which we don't use yet. "Rule 'OtherOrComma' defined, but not used", @@ -7506,22 +7527,11 @@ class Parser(Tokenizer): raise WebIDLError("invalid syntax", [Location(self.lexer, p.lineno, p.lexpos, self._filename)]) def __init__(self, outputdir='', lexer=None): - Tokenizer.__init__(self, outputdir, lexer) + Tokenizer.__init__(self, lexer) logger = SqueakyCleanLogger() try: - self.parser = yacc.yacc(module=self, - outputdir=outputdir, - tabmodule='webidlyacc', - errorlog=logger, - debug=False - # Pickling the grammar is a speedup in - # some cases (older Python?) but a - # significant slowdown in others. - # We're not pickling for now, until it - # becomes a speedup again. - # , picklefile='WebIDLGrammar.pkl' - ) + self.parser = yacc.yacc(module=self, errorlog=logger, debug=False) finally: logger.reportGrammarErrors() @@ -7553,12 +7563,12 @@ class Parser(Tokenizer): return type def parse(self, t, filename=None): - self.lexer.input(t) + self._filename = filename + self.lexer.input(t.decode(encoding = 'utf-8')) # for tok in iter(self.lexer.token, None): # print tok - self._filename = filename self._productions.extend(self.parser.parse(lexer=self.lexer, tracking=True)) self._filename = None diff --git a/components/script/dom/bindings/codegen/ply/README b/components/script/dom/bindings/codegen/ply/README index 2459c490197..d3de9993360 100644 --- a/components/script/dom/bindings/codegen/ply/README +++ b/components/script/dom/bindings/codegen/ply/README @@ -3,7 +3,7 @@ http://www.dabeaz.com/ply/ Licensed under BSD. -This directory contains just the code and license from PLY version 3.3; +This directory contains just the code and license from PLY version 4.0; the full distribution (see the URL) also contains examples, tests, documentation, and a longer README. diff --git a/components/script/dom/bindings/codegen/ply/ply/__init__.py b/components/script/dom/bindings/codegen/ply/ply/__init__.py index 853a985542b..87838622863 100644 --- a/components/script/dom/bindings/codegen/ply/ply/__init__.py +++ b/components/script/dom/bindings/codegen/ply/ply/__init__.py @@ -1,4 +1,6 @@ # PLY package # Author: David Beazley (dave@dabeaz.com) +# https://dabeaz.com/ply/index.html +__version__ = '4.0' __all__ = ['lex','yacc'] diff --git a/components/script/dom/bindings/codegen/ply/ply/lex.py b/components/script/dom/bindings/codegen/ply/ply/lex.py index 267ec100fc2..57b61f1779e 100644 --- a/components/script/dom/bindings/codegen/ply/ply/lex.py +++ b/components/script/dom/bindings/codegen/ply/ply/lex.py @@ -1,22 +1,24 @@ # ----------------------------------------------------------------------------- # ply: lex.py # -# Copyright (C) 2001-2009, +# Copyright (C) 2001-2020 # David M. Beazley (Dabeaz LLC) # All rights reserved. # +# Latest version: https://github.com/dabeaz/ply +# # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: -# +# # * Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# * Neither the name of the David Beazley or Dabeaz LLC may be used to +# and/or other materials provided with the distribution. +# * Neither the name of David Beazley or Dabeaz LLC may be used to # endorse or promote products derived from this software without -# specific prior written permission. +# specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT @@ -31,72 +33,50 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- -__version__ = "3.3" -__tabversion__ = "3.2" # Version of table file used - -import re, sys, types, copy, os - -# This tuple contains known string types -try: - # Python 2.6 - StringTypes = (types.StringType, types.UnicodeType) -except AttributeError: - # Python 3.0 - StringTypes = (str, bytes) - -# Extract the code attribute of a function. Different implementations -# are for Python 2/3 compatibility. +import re +import sys +import types +import copy +import os +import inspect -if sys.version_info[0] < 3: - def func_code(f): - return f.func_code -else: - def func_code(f): - return f.__code__ +# This tuple contains acceptable string types +StringTypes = (str, bytes) # This regular expression is used to match valid token names _is_identifier = re.compile(r'^[a-zA-Z0-9_]+$') # Exception thrown when invalid token encountered and no default error # handler is defined. - class LexError(Exception): - def __init__(self,message,s): - self.args = (message,) - self.text = s + def __init__(self, message, s): + self.args = (message,) + self.text = s # Token class. This class is used to represent the tokens produced. class LexToken(object): - def __str__(self): - return "LexToken(%s,%r,%d,%d)" % (self.type,self.value,self.lineno,self.lexpos) def __repr__(self): - return str(self) + return f'LexToken({self.type},{self.value!r},{self.lineno},{self.lexpos})' -# This object is a stand-in for a logging object created by the -# logging module. +# This object is a stand-in for a logging object created by the +# logging module. class PlyLogger(object): - def __init__(self,f): + def __init__(self, f): self.f = f - def critical(self,msg,*args,**kwargs): - self.f.write((msg % args) + "\n") - def warning(self,msg,*args,**kwargs): - self.f.write("WARNING: "+ (msg % args) + "\n") + def critical(self, msg, *args, **kwargs): + self.f.write((msg % args) + '\n') + + def warning(self, msg, *args, **kwargs): + self.f.write('WARNING: ' + (msg % args) + '\n') - def error(self,msg,*args,**kwargs): - self.f.write("ERROR: " + (msg % args) + "\n") + def error(self, msg, *args, **kwargs): + self.f.write('ERROR: ' + (msg % args) + '\n') info = critical debug = critical -# Null logger is used when no output is generated. Does nothing. -class NullLogger(object): - def __getattribute__(self,name): - return self - def __call__(self,*args,**kwargs): - return self - # ----------------------------------------------------------------------------- # === Lexing Engine === # @@ -114,31 +94,32 @@ class NullLogger(object): class Lexer: def __init__(self): self.lexre = None # Master regular expression. This is a list of - # tuples (re,findex) where re is a compiled - # regular expression and findex is a list - # mapping regex group numbers to rules + # tuples (re, findex) where re is a compiled + # regular expression and findex is a list + # mapping regex group numbers to rules self.lexretext = None # Current regular expression strings self.lexstatere = {} # Dictionary mapping lexer states to master regexs self.lexstateretext = {} # Dictionary mapping lexer states to regex strings self.lexstaterenames = {} # Dictionary mapping lexer states to symbol names - self.lexstate = "INITIAL" # Current lexer state + self.lexstate = 'INITIAL' # Current lexer state self.lexstatestack = [] # Stack of lexer states self.lexstateinfo = None # State information self.lexstateignore = {} # Dictionary of ignored characters for each state self.lexstateerrorf = {} # Dictionary of error functions for each state + self.lexstateeoff = {} # Dictionary of eof functions for each state self.lexreflags = 0 # Optional re compile flags self.lexdata = None # Actual input data (as a string) self.lexpos = 0 # Current position in input text self.lexlen = 0 # Length of the input text self.lexerrorf = None # Error rule (if any) + self.lexeoff = None # EOF rule (if any) self.lextokens = None # List of valid tokens - self.lexignore = "" # Ignored characters - self.lexliterals = "" # Literal characters that can be passed through + self.lexignore = '' # Ignored characters + self.lexliterals = '' # Literal characters that can be passed through self.lexmodule = None # Module self.lineno = 1 # Current line number - self.lexoptimize = 0 # Optimized mode - def clone(self,object=None): + def clone(self, object=None): c = copy.copy(self) # If the object parameter has been supplied, it means we are attaching the @@ -146,113 +127,29 @@ class Lexer: # the lexstatere and lexstateerrorf tables. if object: - newtab = { } + newtab = {} for key, ritem in self.lexstatere.items(): newre = [] for cre, findex in ritem: - newfindex = [] - for f in findex: - if not f or not f[0]: - newfindex.append(f) - continue - newfindex.append((getattr(object,f[0].__name__),f[1])) - newre.append((cre,newfindex)) + newfindex = [] + for f in findex: + if not f or not f[0]: + newfindex.append(f) + continue + newfindex.append((getattr(object, f[0].__name__), f[1])) + newre.append((cre, newfindex)) newtab[key] = newre c.lexstatere = newtab - c.lexstateerrorf = { } + c.lexstateerrorf = {} for key, ef in self.lexstateerrorf.items(): - c.lexstateerrorf[key] = getattr(object,ef.__name__) + c.lexstateerrorf[key] = getattr(object, ef.__name__) c.lexmodule = object return c - # ------------------------------------------------------------ - # writetab() - Write lexer information to a table file - # ------------------------------------------------------------ - def writetab(self,tabfile,outputdir=""): - if isinstance(tabfile,types.ModuleType): - return - basetabfilename = tabfile.split(".")[-1] - filename = os.path.join(outputdir,basetabfilename)+".py" - tf = open(filename,"w") - tf.write("# %s.py. This file automatically created by PLY (version %s). Don't edit!\n" % (tabfile,__version__)) - tf.write("_tabversion = %s\n" % repr(__version__)) - tf.write("_lextokens = %s\n" % repr(self.lextokens)) - tf.write("_lexreflags = %s\n" % repr(self.lexreflags)) - tf.write("_lexliterals = %s\n" % repr(self.lexliterals)) - tf.write("_lexstateinfo = %s\n" % repr(self.lexstateinfo)) - - tabre = { } - # Collect all functions in the initial state - initial = self.lexstatere["INITIAL"] - initialfuncs = [] - for part in initial: - for f in part[1]: - if f and f[0]: - initialfuncs.append(f) - - for key, lre in self.lexstatere.items(): - titem = [] - for i in range(len(lre)): - titem.append((self.lexstateretext[key][i],_funcs_to_names(lre[i][1],self.lexstaterenames[key][i]))) - tabre[key] = titem - - tf.write("_lexstatere = %s\n" % repr(tabre)) - tf.write("_lexstateignore = %s\n" % repr(self.lexstateignore)) - - taberr = { } - for key, ef in self.lexstateerrorf.items(): - if ef: - taberr[key] = ef.__name__ - else: - taberr[key] = None - tf.write("_lexstateerrorf = %s\n" % repr(taberr)) - tf.close() - - # ------------------------------------------------------------ - # readtab() - Read lexer information from a tab file - # ------------------------------------------------------------ - def readtab(self,tabfile,fdict): - if isinstance(tabfile,types.ModuleType): - lextab = tabfile - else: - if sys.version_info[0] < 3: - exec("import %s as lextab" % tabfile) - else: - env = { } - exec("import %s as lextab" % tabfile, env,env) - lextab = env['lextab'] - - if getattr(lextab,"_tabversion","0.0") != __version__: - raise ImportError("Inconsistent PLY version") - - self.lextokens = lextab._lextokens - self.lexreflags = lextab._lexreflags - self.lexliterals = lextab._lexliterals - self.lexstateinfo = lextab._lexstateinfo - self.lexstateignore = lextab._lexstateignore - self.lexstatere = { } - self.lexstateretext = { } - for key,lre in lextab._lexstatere.items(): - titem = [] - txtitem = [] - for i in range(len(lre)): - titem.append((re.compile(lre[i][0],lextab._lexreflags | re.VERBOSE),_names_to_funcs(lre[i][1],fdict))) - txtitem.append(lre[i][0]) - self.lexstatere[key] = titem - self.lexstateretext[key] = txtitem - self.lexstateerrorf = { } - for key,ef in lextab._lexstateerrorf.items(): - self.lexstateerrorf[key] = fdict[ef] - self.begin('INITIAL') - # ------------------------------------------------------------ # input() - Push a new string into the lexer # ------------------------------------------------------------ - def input(self,s): - # Pull off the first character to see if s looks like a string - c = s[:1] - if not isinstance(c,StringTypes): - raise ValueError("Expected a string") + def input(self, s): self.lexdata = s self.lexpos = 0 self.lexlen = len(s) @@ -260,19 +157,20 @@ class Lexer: # ------------------------------------------------------------ # begin() - Changes the lexing state # ------------------------------------------------------------ - def begin(self,state): - if not state in self.lexstatere: - raise ValueError("Undefined state") + def begin(self, state): + if state not in self.lexstatere: + raise ValueError(f'Undefined state {state!r}') self.lexre = self.lexstatere[state] self.lexretext = self.lexstateretext[state] - self.lexignore = self.lexstateignore.get(state,"") - self.lexerrorf = self.lexstateerrorf.get(state,None) + self.lexignore = self.lexstateignore.get(state, '') + self.lexerrorf = self.lexstateerrorf.get(state, None) + self.lexeoff = self.lexstateeoff.get(state, None) self.lexstate = state # ------------------------------------------------------------ # push_state() - Changes the lexing state and saves old on stack # ------------------------------------------------------------ - def push_state(self,state): + def push_state(self, state): self.lexstatestack.append(self.lexstate) self.begin(state) @@ -291,11 +189,11 @@ class Lexer: # ------------------------------------------------------------ # skip() - Skip ahead n characters # ------------------------------------------------------------ - def skip(self,n): + def skip(self, n): self.lexpos += n # ------------------------------------------------------------ - # opttoken() - Return the next token from the Lexer + # token() - Return the next token from the Lexer # # Note: This function has been carefully implemented to be as fast # as possible. Don't make changes unless you really know what @@ -315,9 +213,10 @@ class Lexer: continue # Look for a regular expression match - for lexre,lexindexfunc in self.lexre: - m = lexre.match(lexdata,lexpos) - if not m: continue + for lexre, lexindexfunc in self.lexre: + m = lexre.match(lexdata, lexpos) + if not m: + continue # Create a token for return tok = LexToken() @@ -326,16 +225,16 @@ class Lexer: tok.lexpos = lexpos i = m.lastindex - func,tok.type = lexindexfunc[i] + func, tok.type = lexindexfunc[i] if not func: - # If no token type was set, it's an ignored token - if tok.type: - self.lexpos = m.end() - return tok - else: - lexpos = m.end() - break + # If no token type was set, it's an ignored token + if tok.type: + self.lexpos = m.end() + return tok + else: + lexpos = m.end() + break lexpos = m.end() @@ -344,22 +243,15 @@ class Lexer: tok.lexer = self # Set additional attributes useful in token rules self.lexmatch = m self.lexpos = lexpos - newtok = func(tok) + del tok.lexer + del self.lexmatch # Every function must return a token, if nothing, we just move to next token if not newtok: lexpos = self.lexpos # This is here in case user has updated lexpos. lexignore = self.lexignore # This is here in case there was a state change break - - # Verify type of the token. If not in the token map, raise an error - if not self.lexoptimize: - if not newtok.type in self.lextokens: - raise LexError("%s:%d: Rule '%s' returned an unknown token type '%s'" % ( - func_code(func).co_filename, func_code(func).co_firstlineno, - func.__name__, newtok.type),lexdata[lexpos:]) - return newtok else: # No match, see if in literals @@ -377,38 +269,50 @@ class Lexer: tok = LexToken() tok.value = self.lexdata[lexpos:] tok.lineno = self.lineno - tok.type = "error" + tok.type = 'error' tok.lexer = self tok.lexpos = lexpos self.lexpos = lexpos newtok = self.lexerrorf(tok) if lexpos == self.lexpos: # Error method didn't change text position at all. This is an error. - raise LexError("Scanning error. Illegal character '%s'" % (lexdata[lexpos]), lexdata[lexpos:]) + raise LexError(f"Scanning error. Illegal character {lexdata[lexpos]!r}", + lexdata[lexpos:]) lexpos = self.lexpos - if not newtok: continue + if not newtok: + continue return newtok self.lexpos = lexpos - raise LexError("Illegal character '%s' at index %d" % (lexdata[lexpos],lexpos), lexdata[lexpos:]) + raise LexError(f"Illegal character {lexdata[lexpos]!r} at index {lexpos}", + lexdata[lexpos:]) + + if self.lexeoff: + tok = LexToken() + tok.type = 'eof' + tok.value = '' + tok.lineno = self.lineno + tok.lexpos = lexpos + tok.lexer = self + self.lexpos = lexpos + newtok = self.lexeoff(tok) + return newtok self.lexpos = lexpos + 1 if self.lexdata is None: - raise RuntimeError("No input string given with input()") + raise RuntimeError('No input string given with input()') return None # Iterator interface def __iter__(self): return self - def next(self): + def __next__(self): t = self.token() if t is None: raise StopIteration return t - __next__ = next - # ----------------------------------------------------------------------------- # ==== Lex Builder === # @@ -416,6 +320,15 @@ class Lexer: # and build a Lexer object from it. # ----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- +# _get_regex(func) +# +# Returns the regular expression assigned to a function either as a doc string +# or as a .regex attribute attached by the @TOKEN decorator. +# ----------------------------------------------------------------------------- +def _get_regex(func): + return getattr(func, 'regex', func.__doc__) + # ----------------------------------------------------------------------------- # get_caller_module_dict() # @@ -423,53 +336,9 @@ class Lexer: # a caller further down the call stack. This is used to get the environment # associated with the yacc() call if none was provided. # ----------------------------------------------------------------------------- - def get_caller_module_dict(levels): - try: - raise RuntimeError - except RuntimeError: - e,b,t = sys.exc_info() - f = t.tb_frame - while levels > 0: - f = f.f_back - levels -= 1 - ldict = f.f_globals.copy() - if f.f_globals != f.f_locals: - ldict.update(f.f_locals) - - return ldict - -# ----------------------------------------------------------------------------- -# _funcs_to_names() -# -# Given a list of regular expression functions, this converts it to a list -# suitable for output to a table file -# ----------------------------------------------------------------------------- - -def _funcs_to_names(funclist,namelist): - result = [] - for f,name in zip(funclist,namelist): - if f and f[0]: - result.append((name, f[1])) - else: - result.append(f) - return result - -# ----------------------------------------------------------------------------- -# _names_to_funcs() -# -# Given a list of regular expression function names, this converts it back to -# functions. -# ----------------------------------------------------------------------------- - -def _names_to_funcs(namelist,fdict): - result = [] - for n in namelist: - if n and n[0]: - result.append((fdict[n[0]],n[1])) - else: - result.append(n) - return result + f = sys._getframe(levels) + return { **f.f_globals, **f.f_locals } # ----------------------------------------------------------------------------- # _form_master_re() @@ -478,36 +347,35 @@ def _names_to_funcs(namelist,fdict): # form the master regular expression. Given limitations in the Python re # module, it may be necessary to break the master regex into separate expressions. # ----------------------------------------------------------------------------- - -def _form_master_re(relist,reflags,ldict,toknames): - if not relist: return [] - regex = "|".join(relist) +def _form_master_re(relist, reflags, ldict, toknames): + if not relist: + return [], [], [] + regex = '|'.join(relist) try: - lexre = re.compile(regex,re.VERBOSE | reflags) + lexre = re.compile(regex, reflags) # Build the index to function map for the matching engine - lexindexfunc = [ None ] * (max(lexre.groupindex.values())+1) + lexindexfunc = [None] * (max(lexre.groupindex.values()) + 1) lexindexnames = lexindexfunc[:] - for f,i in lexre.groupindex.items(): - handle = ldict.get(f,None) + for f, i in lexre.groupindex.items(): + handle = ldict.get(f, None) if type(handle) in (types.FunctionType, types.MethodType): - lexindexfunc[i] = (handle,toknames[f]) + lexindexfunc[i] = (handle, toknames[f]) lexindexnames[i] = f elif handle is not None: lexindexnames[i] = f - if f.find("ignore_") > 0: - lexindexfunc[i] = (None,None) + if f.find('ignore_') > 0: + lexindexfunc[i] = (None, None) else: lexindexfunc[i] = (None, toknames[f]) - - return [(lexre,lexindexfunc)],[regex],[lexindexnames] + + return [(lexre, lexindexfunc)], [regex], [lexindexnames] except Exception: - m = int(len(relist)/2) - if m == 0: m = 1 - llist, lre, lnames = _form_master_re(relist[:m],reflags,ldict,toknames) - rlist, rre, rnames = _form_master_re(relist[m:],reflags,ldict,toknames) - return llist+rlist, lre+rre, lnames+rnames + m = (len(relist) // 2) + 1 + llist, lre, lnames = _form_master_re(relist[:m], reflags, ldict, toknames) + rlist, rre, rnames = _form_master_re(relist[m:], reflags, ldict, toknames) + return (llist+rlist), (lre+rre), (lnames+rnames) # ----------------------------------------------------------------------------- # def _statetoken(s,names) @@ -517,22 +385,22 @@ def _form_master_re(relist,reflags,ldict,toknames): # is a tuple of state names and tokenname is the name of the token. For example, # calling this with s = "t_foo_bar_SPAM" might return (('foo','bar'),'SPAM') # ----------------------------------------------------------------------------- +def _statetoken(s, names): + parts = s.split('_') + for i, part in enumerate(parts[1:], 1): + if part not in names and part != 'ANY': + break -def _statetoken(s,names): - nonstate = 1 - parts = s.split("_") - for i in range(1,len(parts)): - if not parts[i] in names and parts[i] != 'ANY': break if i > 1: - states = tuple(parts[1:i]) + states = tuple(parts[1:i]) else: - states = ('INITIAL',) + states = ('INITIAL',) if 'ANY' in states: - states = tuple(names) + states = tuple(names) - tokenname = "_".join(parts[i:]) - return (states,tokenname) + tokenname = '_'.join(parts[i:]) + return (states, tokenname) # ----------------------------------------------------------------------------- @@ -542,19 +410,15 @@ def _statetoken(s,names): # user's input file. # ----------------------------------------------------------------------------- class LexerReflect(object): - def __init__(self,ldict,log=None,reflags=0): + def __init__(self, ldict, log=None, reflags=0): self.ldict = ldict self.error_func = None self.tokens = [] self.reflags = reflags - self.stateinfo = { 'INITIAL' : 'inclusive'} - self.files = {} - self.error = 0 - - if log is None: - self.log = PlyLogger(sys.stderr) - else: - self.log = log + self.stateinfo = {'INITIAL': 'inclusive'} + self.modules = set() + self.error = False + self.log = PlyLogger(sys.stderr) if log is None else log # Get all of the basic information def get_all(self): @@ -562,7 +426,7 @@ class LexerReflect(object): self.get_literals() self.get_states() self.get_rules() - + # Validate all of the information def validate_all(self): self.validate_tokens() @@ -572,20 +436,20 @@ class LexerReflect(object): # Get the tokens map def get_tokens(self): - tokens = self.ldict.get("tokens",None) + tokens = self.ldict.get('tokens', None) if not tokens: - self.log.error("No token list is defined") - self.error = 1 + self.log.error('No token list is defined') + self.error = True return - if not isinstance(tokens,(list, tuple)): - self.log.error("tokens must be a list or tuple") - self.error = 1 + if not isinstance(tokens, (list, tuple)): + self.log.error('tokens must be a list or tuple') + self.error = True return - + if not tokens: - self.log.error("tokens is empty") - self.error = 1 + self.log.error('tokens is empty') + self.error = True return self.tokens = tokens @@ -595,280 +459,270 @@ class LexerReflect(object): terminals = {} for n in self.tokens: if not _is_identifier.match(n): - self.log.error("Bad token name '%s'",n) - self.error = 1 + self.log.error(f"Bad token name {n!r}") + self.error = True if n in terminals: - self.log.warning("Token '%s' multiply defined", n) + self.log.warning(f"Token {n!r} multiply defined") terminals[n] = 1 # Get the literals specifier def get_literals(self): - self.literals = self.ldict.get("literals","") + self.literals = self.ldict.get('literals', '') + if not self.literals: + self.literals = '' # Validate literals def validate_literals(self): try: for c in self.literals: - if not isinstance(c,StringTypes) or len(c) > 1: - self.log.error("Invalid literal %s. Must be a single character", repr(c)) - self.error = 1 - continue + if not isinstance(c, StringTypes) or len(c) > 1: + self.log.error(f'Invalid literal {c!r}. Must be a single character') + self.error = True except TypeError: - self.log.error("Invalid literals specification. literals must be a sequence of characters") - self.error = 1 + self.log.error('Invalid literals specification. literals must be a sequence of characters') + self.error = True def get_states(self): - self.states = self.ldict.get("states",None) + self.states = self.ldict.get('states', None) # Build statemap if self.states: - if not isinstance(self.states,(tuple,list)): - self.log.error("states must be defined as a tuple or list") - self.error = 1 - else: - for s in self.states: - if not isinstance(s,tuple) or len(s) != 2: - self.log.error("Invalid state specifier %s. Must be a tuple (statename,'exclusive|inclusive')",repr(s)) - self.error = 1 - continue - name, statetype = s - if not isinstance(name,StringTypes): - self.log.error("State name %s must be a string", repr(name)) - self.error = 1 - continue - if not (statetype == 'inclusive' or statetype == 'exclusive'): - self.log.error("State type for state %s must be 'inclusive' or 'exclusive'",name) - self.error = 1 - continue - if name in self.stateinfo: - self.log.error("State '%s' already defined",name) - self.error = 1 - continue - self.stateinfo[name] = statetype + if not isinstance(self.states, (tuple, list)): + self.log.error('states must be defined as a tuple or list') + self.error = True + else: + for s in self.states: + if not isinstance(s, tuple) or len(s) != 2: + self.log.error("Invalid state specifier %r. Must be a tuple (statename,'exclusive|inclusive')", s) + self.error = True + continue + name, statetype = s + if not isinstance(name, StringTypes): + self.log.error('State name %r must be a string', name) + self.error = True + continue + if not (statetype == 'inclusive' or statetype == 'exclusive'): + self.log.error("State type for state %r must be 'inclusive' or 'exclusive'", name) + self.error = True + continue + if name in self.stateinfo: + self.log.error("State %r already defined", name) + self.error = True + continue + self.stateinfo[name] = statetype # Get all of the symbols with a t_ prefix and sort them into various # categories (functions, strings, error functions, and ignore characters) def get_rules(self): - tsymbols = [f for f in self.ldict if f[:2] == 't_' ] + tsymbols = [f for f in self.ldict if f[:2] == 't_'] # Now build up a list of functions and a list of strings - - self.toknames = { } # Mapping of symbols to token names - self.funcsym = { } # Symbols defined as functions - self.strsym = { } # Symbols defined as strings - self.ignore = { } # Ignore strings by state - self.errorf = { } # Error functions by state + self.toknames = {} # Mapping of symbols to token names + self.funcsym = {} # Symbols defined as functions + self.strsym = {} # Symbols defined as strings + self.ignore = {} # Ignore strings by state + self.errorf = {} # Error functions by state + self.eoff = {} # EOF functions by state for s in self.stateinfo: - self.funcsym[s] = [] - self.strsym[s] = [] + self.funcsym[s] = [] + self.strsym[s] = [] if len(tsymbols) == 0: - self.log.error("No rules of the form t_rulename are defined") - self.error = 1 + self.log.error('No rules of the form t_rulename are defined') + self.error = True return for f in tsymbols: t = self.ldict[f] - states, tokname = _statetoken(f,self.stateinfo) + states, tokname = _statetoken(f, self.stateinfo) self.toknames[f] = tokname - if hasattr(t,"__call__"): + if hasattr(t, '__call__'): if tokname == 'error': for s in states: self.errorf[s] = t + elif tokname == 'eof': + for s in states: + self.eoff[s] = t elif tokname == 'ignore': - line = func_code(t).co_firstlineno - file = func_code(t).co_filename - self.log.error("%s:%d: Rule '%s' must be defined as a string",file,line,t.__name__) - self.error = 1 + line = t.__code__.co_firstlineno + file = t.__code__.co_filename + self.log.error("%s:%d: Rule %r must be defined as a string", file, line, t.__name__) + self.error = True else: - for s in states: - self.funcsym[s].append((f,t)) + for s in states: + self.funcsym[s].append((f, t)) elif isinstance(t, StringTypes): if tokname == 'ignore': for s in states: self.ignore[s] = t - if "\\" in t: - self.log.warning("%s contains a literal backslash '\\'",f) + if '\\' in t: + self.log.warning("%s contains a literal backslash '\\'", f) elif tokname == 'error': - self.log.error("Rule '%s' must be defined as a function", f) - self.error = 1 + self.log.error("Rule %r must be defined as a function", f) + self.error = True else: - for s in states: - self.strsym[s].append((f,t)) + for s in states: + self.strsym[s].append((f, t)) else: - self.log.error("%s not defined as a function or string", f) - self.error = 1 + self.log.error('%s not defined as a function or string', f) + self.error = True # Sort the functions by line number for f in self.funcsym.values(): - if sys.version_info[0] < 3: - f.sort(lambda x,y: cmp(func_code(x[1]).co_firstlineno,func_code(y[1]).co_firstlineno)) - else: - # Python 3.0 - f.sort(key=lambda x: func_code(x[1]).co_firstlineno) + f.sort(key=lambda x: x[1].__code__.co_firstlineno) # Sort the strings by regular expression length for s in self.strsym.values(): - if sys.version_info[0] < 3: - s.sort(lambda x,y: (len(x[1]) < len(y[1])) - (len(x[1]) > len(y[1]))) - else: - # Python 3.0 - s.sort(key=lambda x: len(x[1]),reverse=True) + s.sort(key=lambda x: len(x[1]), reverse=True) - # Validate all of the t_rules collected + # Validate all of the t_rules collected def validate_rules(self): for state in self.stateinfo: # Validate all rules defined by functions - - for fname, f in self.funcsym[state]: - line = func_code(f).co_firstlineno - file = func_code(f).co_filename - self.files[file] = 1 + line = f.__code__.co_firstlineno + file = f.__code__.co_filename + module = inspect.getmodule(f) + self.modules.add(module) tokname = self.toknames[fname] if isinstance(f, types.MethodType): reqargs = 2 else: reqargs = 1 - nargs = func_code(f).co_argcount + nargs = f.__code__.co_argcount if nargs > reqargs: - self.log.error("%s:%d: Rule '%s' has too many arguments",file,line,f.__name__) - self.error = 1 + self.log.error("%s:%d: Rule %r has too many arguments", file, line, f.__name__) + self.error = True continue if nargs < reqargs: - self.log.error("%s:%d: Rule '%s' requires an argument", file,line,f.__name__) - self.error = 1 + self.log.error("%s:%d: Rule %r requires an argument", file, line, f.__name__) + self.error = True continue - if not f.__doc__: - self.log.error("%s:%d: No regular expression defined for rule '%s'",file,line,f.__name__) - self.error = 1 + if not _get_regex(f): + self.log.error("%s:%d: No regular expression defined for rule %r", file, line, f.__name__) + self.error = True continue try: - c = re.compile("(?P<%s>%s)" % (fname,f.__doc__), re.VERBOSE | self.reflags) - if c.match(""): - self.log.error("%s:%d: Regular expression for rule '%s' matches empty string", file,line,f.__name__) - self.error = 1 - except re.error: - _etype, e, _etrace = sys.exc_info() - self.log.error("%s:%d: Invalid regular expression for rule '%s'. %s", file,line,f.__name__,e) - if '#' in f.__doc__: - self.log.error("%s:%d. Make sure '#' in rule '%s' is escaped with '\\#'",file,line, f.__name__) - self.error = 1 + c = re.compile('(?P<%s>%s)' % (fname, _get_regex(f)), self.reflags) + if c.match(''): + self.log.error("%s:%d: Regular expression for rule %r matches empty string", file, line, f.__name__) + self.error = True + except re.error as e: + self.log.error("%s:%d: Invalid regular expression for rule '%s'. %s", file, line, f.__name__, e) + if '#' in _get_regex(f): + self.log.error("%s:%d. Make sure '#' in rule %r is escaped with '\\#'", file, line, f.__name__) + self.error = True # Validate all rules defined by strings - for name,r in self.strsym[state]: + for name, r in self.strsym[state]: tokname = self.toknames[name] if tokname == 'error': - self.log.error("Rule '%s' must be defined as a function", name) - self.error = 1 + self.log.error("Rule %r must be defined as a function", name) + self.error = True continue - if not tokname in self.tokens and tokname.find("ignore_") < 0: - self.log.error("Rule '%s' defined for an unspecified token %s",name,tokname) - self.error = 1 + if tokname not in self.tokens and tokname.find('ignore_') < 0: + self.log.error("Rule %r defined for an unspecified token %s", name, tokname) + self.error = True continue try: - c = re.compile("(?P<%s>%s)" % (name,r),re.VERBOSE | self.reflags) - if (c.match("")): - self.log.error("Regular expression for rule '%s' matches empty string",name) - self.error = 1 - except re.error: - _etype, e, _etrace = sys.exc_info() - self.log.error("Invalid regular expression for rule '%s'. %s",name,e) + c = re.compile('(?P<%s>%s)' % (name, r), self.reflags) + if (c.match('')): + self.log.error("Regular expression for rule %r matches empty string", name) + self.error = True + except re.error as e: + self.log.error("Invalid regular expression for rule %r. %s", name, e) if '#' in r: - self.log.error("Make sure '#' in rule '%s' is escaped with '\\#'",name) - self.error = 1 + self.log.error("Make sure '#' in rule %r is escaped with '\\#'", name) + self.error = True if not self.funcsym[state] and not self.strsym[state]: - self.log.error("No rules defined for state '%s'",state) - self.error = 1 + self.log.error("No rules defined for state %r", state) + self.error = True # Validate the error function - efunc = self.errorf.get(state,None) + efunc = self.errorf.get(state, None) if efunc: f = efunc - line = func_code(f).co_firstlineno - file = func_code(f).co_filename - self.files[file] = 1 + line = f.__code__.co_firstlineno + file = f.__code__.co_filename + module = inspect.getmodule(f) + self.modules.add(module) if isinstance(f, types.MethodType): reqargs = 2 else: reqargs = 1 - nargs = func_code(f).co_argcount + nargs = f.__code__.co_argcount if nargs > reqargs: - self.log.error("%s:%d: Rule '%s' has too many arguments",file,line,f.__name__) - self.error = 1 + self.log.error("%s:%d: Rule %r has too many arguments", file, line, f.__name__) + self.error = True if nargs < reqargs: - self.log.error("%s:%d: Rule '%s' requires an argument", file,line,f.__name__) - self.error = 1 - - for f in self.files: - self.validate_file(f) + self.log.error("%s:%d: Rule %r requires an argument", file, line, f.__name__) + self.error = True + for module in self.modules: + self.validate_module(module) # ----------------------------------------------------------------------------- - # validate_file() + # validate_module() # # This checks to see if there are duplicated t_rulename() functions or strings # in the parser input file. This is done using a simple regular expression - # match on each line in the given file. + # match on each line in the source code of the given module. # ----------------------------------------------------------------------------- - def validate_file(self,filename): - import os.path - base,ext = os.path.splitext(filename) - if ext != '.py': return # No idea what the file is. Return OK - + def validate_module(self, module): try: - f = open(filename) - lines = f.readlines() - f.close() + lines, linen = inspect.getsourcelines(module) except IOError: - return # Couldn't find the file. Don't worry about it + return fre = re.compile(r'\s*def\s+(t_[a-zA-Z_0-9]*)\(') sre = re.compile(r'\s*(t_[a-zA-Z_0-9]*)\s*=') - counthash = { } - linen = 1 - for l in lines: - m = fre.match(l) + counthash = {} + linen += 1 + for line in lines: + m = fre.match(line) if not m: - m = sre.match(l) + m = sre.match(line) if m: name = m.group(1) prev = counthash.get(name) if not prev: counthash[name] = linen else: - self.log.error("%s:%d: Rule %s redefined. Previously defined on line %d",filename,linen,name,prev) - self.error = 1 + filename = inspect.getsourcefile(module) + self.log.error('%s:%d: Rule %s redefined. Previously defined on line %d', filename, linen, name, prev) + self.error = True linen += 1 - + # ----------------------------------------------------------------------------- # lex(module) # # Build all of the regular expression rules from definitions in the supplied module # ----------------------------------------------------------------------------- -def lex(module=None,object=None,debug=0,optimize=0,lextab="lextab",reflags=0,nowarn=0,outputdir="", debuglog=None, errorlog=None): +def lex(*, module=None, object=None, debug=False, + reflags=int(re.VERBOSE), debuglog=None, errorlog=None): + global lexer + ldict = None - stateinfo = { 'INITIAL' : 'inclusive'} + stateinfo = {'INITIAL': 'inclusive'} lexobj = Lexer() - lexobj.lexoptimize = optimize - global token,input + global token, input if errorlog is None: errorlog = PlyLogger(sys.stderr) @@ -878,131 +732,124 @@ def lex(module=None,object=None,debug=0,optimize=0,lextab="lextab",reflags=0,now debuglog = PlyLogger(sys.stderr) # Get the module dictionary used for the lexer - if object: module = object + if object: + module = object + # Get the module dictionary used for the parser if module: - _items = [(k,getattr(module,k)) for k in dir(module)] + _items = [(k, getattr(module, k)) for k in dir(module)] ldict = dict(_items) + # If no __file__ attribute is available, try to obtain it from the __module__ instead + if '__file__' not in ldict: + ldict['__file__'] = sys.modules[ldict['__module__']].__file__ else: ldict = get_caller_module_dict(2) # Collect parser information from the dictionary - linfo = LexerReflect(ldict,log=errorlog,reflags=reflags) + linfo = LexerReflect(ldict, log=errorlog, reflags=reflags) linfo.get_all() - if not optimize: - if linfo.validate_all(): - raise SyntaxError("Can't build lexer") - - if optimize and lextab: - try: - lexobj.readtab(lextab,ldict) - token = lexobj.token - input = lexobj.input - lexer = lexobj - return lexobj - - except ImportError: - pass + if linfo.validate_all(): + raise SyntaxError("Can't build lexer") # Dump some basic debugging information if debug: - debuglog.info("lex: tokens = %r", linfo.tokens) - debuglog.info("lex: literals = %r", linfo.literals) - debuglog.info("lex: states = %r", linfo.stateinfo) + debuglog.info('lex: tokens = %r', linfo.tokens) + debuglog.info('lex: literals = %r', linfo.literals) + debuglog.info('lex: states = %r', linfo.stateinfo) # Build a dictionary of valid token names - lexobj.lextokens = { } + lexobj.lextokens = set() for n in linfo.tokens: - lexobj.lextokens[n] = 1 + lexobj.lextokens.add(n) # Get literals specification - if isinstance(linfo.literals,(list,tuple)): + if isinstance(linfo.literals, (list, tuple)): lexobj.lexliterals = type(linfo.literals[0])().join(linfo.literals) else: lexobj.lexliterals = linfo.literals + lexobj.lextokens_all = lexobj.lextokens | set(lexobj.lexliterals) + # Get the stateinfo dictionary stateinfo = linfo.stateinfo - regexs = { } + regexs = {} # Build the master regular expressions for state in stateinfo: regex_list = [] # Add rules defined by functions first for fname, f in linfo.funcsym[state]: - line = func_code(f).co_firstlineno - file = func_code(f).co_filename - regex_list.append("(?P<%s>%s)" % (fname,f.__doc__)) + regex_list.append('(?P<%s>%s)' % (fname, _get_regex(f))) if debug: - debuglog.info("lex: Adding rule %s -> '%s' (state '%s')",fname,f.__doc__, state) + debuglog.info("lex: Adding rule %s -> '%s' (state '%s')", fname, _get_regex(f), state) # Now add all of the simple rules - for name,r in linfo.strsym[state]: - regex_list.append("(?P<%s>%s)" % (name,r)) + for name, r in linfo.strsym[state]: + regex_list.append('(?P<%s>%s)' % (name, r)) if debug: - debuglog.info("lex: Adding rule %s -> '%s' (state '%s')",name,r, state) + debuglog.info("lex: Adding rule %s -> '%s' (state '%s')", name, r, state) regexs[state] = regex_list # Build the master regular expressions if debug: - debuglog.info("lex: ==== MASTER REGEXS FOLLOW ====") + debuglog.info('lex: ==== MASTER REGEXS FOLLOW ====') for state in regexs: - lexre, re_text, re_names = _form_master_re(regexs[state],reflags,ldict,linfo.toknames) + lexre, re_text, re_names = _form_master_re(regexs[state], reflags, ldict, linfo.toknames) lexobj.lexstatere[state] = lexre lexobj.lexstateretext[state] = re_text lexobj.lexstaterenames[state] = re_names if debug: - for i in range(len(re_text)): - debuglog.info("lex: state '%s' : regex[%d] = '%s'",state, i, re_text[i]) + for i, text in enumerate(re_text): + debuglog.info("lex: state '%s' : regex[%d] = '%s'", state, i, text) # For inclusive states, we need to add the regular expressions from the INITIAL state - for state,stype in stateinfo.items(): - if state != "INITIAL" and stype == 'inclusive': - lexobj.lexstatere[state].extend(lexobj.lexstatere['INITIAL']) - lexobj.lexstateretext[state].extend(lexobj.lexstateretext['INITIAL']) - lexobj.lexstaterenames[state].extend(lexobj.lexstaterenames['INITIAL']) + for state, stype in stateinfo.items(): + if state != 'INITIAL' and stype == 'inclusive': + lexobj.lexstatere[state].extend(lexobj.lexstatere['INITIAL']) + lexobj.lexstateretext[state].extend(lexobj.lexstateretext['INITIAL']) + lexobj.lexstaterenames[state].extend(lexobj.lexstaterenames['INITIAL']) lexobj.lexstateinfo = stateinfo - lexobj.lexre = lexobj.lexstatere["INITIAL"] - lexobj.lexretext = lexobj.lexstateretext["INITIAL"] + lexobj.lexre = lexobj.lexstatere['INITIAL'] + lexobj.lexretext = lexobj.lexstateretext['INITIAL'] lexobj.lexreflags = reflags # Set up ignore variables lexobj.lexstateignore = linfo.ignore - lexobj.lexignore = lexobj.lexstateignore.get("INITIAL","") + lexobj.lexignore = lexobj.lexstateignore.get('INITIAL', '') # Set up error functions lexobj.lexstateerrorf = linfo.errorf - lexobj.lexerrorf = linfo.errorf.get("INITIAL",None) + lexobj.lexerrorf = linfo.errorf.get('INITIAL', None) if not lexobj.lexerrorf: - errorlog.warning("No t_error rule is defined") + errorlog.warning('No t_error rule is defined') + + # Set up eof functions + lexobj.lexstateeoff = linfo.eoff + lexobj.lexeoff = linfo.eoff.get('INITIAL', None) # Check state information for ignore and error rules - for s,stype in stateinfo.items(): + for s, stype in stateinfo.items(): if stype == 'exclusive': - if not s in linfo.errorf: - errorlog.warning("No error rule is defined for exclusive state '%s'", s) - if not s in linfo.ignore and lexobj.lexignore: - errorlog.warning("No ignore rule is defined for exclusive state '%s'", s) + if s not in linfo.errorf: + errorlog.warning("No error rule is defined for exclusive state %r", s) + if s not in linfo.ignore and lexobj.lexignore: + errorlog.warning("No ignore rule is defined for exclusive state %r", s) elif stype == 'inclusive': - if not s in linfo.errorf: - linfo.errorf[s] = linfo.errorf.get("INITIAL",None) - if not s in linfo.ignore: - linfo.ignore[s] = linfo.ignore.get("INITIAL","") + if s not in linfo.errorf: + linfo.errorf[s] = linfo.errorf.get('INITIAL', None) + if s not in linfo.ignore: + linfo.ignore[s] = linfo.ignore.get('INITIAL', '') # Create global versions of the token() and input() functions token = lexobj.token input = lexobj.input lexer = lexobj - # If in optimize mode, we write the lextab - if lextab and optimize: - lexobj.writetab(lextab,outputdir) - return lexobj # ----------------------------------------------------------------------------- @@ -1011,15 +858,14 @@ def lex(module=None,object=None,debug=0,optimize=0,lextab="lextab",reflags=0,now # This runs the lexer as a main program # ----------------------------------------------------------------------------- -def runmain(lexer=None,data=None): +def runmain(lexer=None, data=None): if not data: try: filename = sys.argv[1] - f = open(filename) - data = f.read() - f.close() + with open(filename) as f: + data = f.read() except IndexError: - sys.stdout.write("Reading from standard input (type EOF to end):\n") + sys.stdout.write('Reading from standard input (type EOF to end):\n') data = sys.stdin.read() if lexer: @@ -1032,10 +878,11 @@ def runmain(lexer=None,data=None): else: _token = token - while 1: + while True: tok = _token() - if not tok: break - sys.stdout.write("(%s,%r,%d,%d)\n" % (tok.type, tok.value, tok.lineno,tok.lexpos)) + if not tok: + break + sys.stdout.write(f'({tok.type},{tok.value!r},{tok.lineno},{tok.lexpos})\n') # ----------------------------------------------------------------------------- # @TOKEN(regex) @@ -1045,14 +892,10 @@ def runmain(lexer=None,data=None): # ----------------------------------------------------------------------------- def TOKEN(r): - def set_doc(f): - if hasattr(r,"__call__"): - f.__doc__ = r.__doc__ + def set_regex(f): + if hasattr(r, '__call__'): + f.regex = _get_regex(r) else: - f.__doc__ = r + f.regex = r return f - return set_doc - -# Alternative spelling of the TOKEN decorator -Token = TOKEN - + return set_regex diff --git a/components/script/dom/bindings/codegen/ply/ply/yacc.py b/components/script/dom/bindings/codegen/ply/ply/yacc.py index e9f5c657551..bce63c18241 100644 --- a/components/script/dom/bindings/codegen/ply/ply/yacc.py +++ b/components/script/dom/bindings/codegen/ply/ply/yacc.py @@ -1,22 +1,24 @@ # ----------------------------------------------------------------------------- # ply: yacc.py # -# Copyright (C) 2001-2009, +# Copyright (C) 2001-2020 # David M. Beazley (Dabeaz LLC) # All rights reserved. # +# Latest version: https://github.com/dabeaz/ply +# # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: -# +# # * Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# * Neither the name of the David Beazley or Dabeaz LLC may be used to +# and/or other materials provided with the distribution. +# * Neither the name of David Beazley or Dabeaz LLC may be used to # endorse or promote products derived from this software without -# specific prior written permission. +# specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT @@ -32,7 +34,7 @@ # ----------------------------------------------------------------------------- # # This implements an LR parser that is constructed from grammar rules defined -# as Python functions. The grammer is specified by supplying the BNF inside +# as Python functions. The grammar is specified by supplying the BNF inside # Python documentation strings. The inspiration for this technique was borrowed # from John Aycock's Spark parsing system. PLY might be viewed as cross between # Spark and the GNU bison utility. @@ -59,8 +61,10 @@ # own risk! # ---------------------------------------------------------------------------- -__version__ = "3.3" -__tabversion__ = "3.2" # Table version +import re +import types +import sys +import inspect #----------------------------------------------------------------------------- # === User configurable parameters === @@ -68,95 +72,69 @@ __tabversion__ = "3.2" # Table version # Change these to modify the default behavior of yacc (if you wish) #----------------------------------------------------------------------------- -yaccdebug = 1 # Debugging mode. If set, yacc generates a - # a 'parser.out' file in the current directory +yaccdebug = False # Debugging mode. If set, yacc generates a +# a 'parser.out' file in the current directory debug_file = 'parser.out' # Default name of the debugging file -tab_module = 'parsetab' # Default name of the table module -default_lr = 'LALR' # Default LR table generation method - error_count = 3 # Number of symbols that must be shifted to leave recovery mode - -yaccdevel = 0 # Set to True if developing yacc. This turns off optimized - # implementations of certain functions. - resultlimit = 40 # Size limit of results when running in debug mode. -pickle_protocol = 0 # Protocol to use when writing pickle files - -import re, types, sys, os.path +MAXINT = sys.maxsize -# Compatibility function for python 2.6/3.0 -if sys.version_info[0] < 3: - def func_code(f): - return f.func_code -else: - def func_code(f): - return f.__code__ - -# Compatibility -try: - MAXINT = sys.maxint -except AttributeError: - MAXINT = sys.maxsize - -# Python 2.x/3.0 compatibility. -def load_ply_lex(): - if sys.version_info[0] < 3: - import lex - else: - import ply.lex as lex - return lex - -# This object is a stand-in for a logging object created by the +# This object is a stand-in for a logging object created by the # logging module. PLY will use this by default to create things # such as the parser.out file. If a user wants more detailed # information, they can create their own logging object and pass # it into PLY. class PlyLogger(object): - def __init__(self,f): + def __init__(self, f): self.f = f - def debug(self,msg,*args,**kwargs): - self.f.write((msg % args) + "\n") - info = debug - def warning(self,msg,*args,**kwargs): - self.f.write("WARNING: "+ (msg % args) + "\n") + def debug(self, msg, *args, **kwargs): + self.f.write((msg % args) + '\n') + + info = debug + + def warning(self, msg, *args, **kwargs): + self.f.write('WARNING: ' + (msg % args) + '\n') - def error(self,msg,*args,**kwargs): - self.f.write("ERROR: " + (msg % args) + "\n") + def error(self, msg, *args, **kwargs): + self.f.write('ERROR: ' + (msg % args) + '\n') critical = debug # Null logger is used when no output is generated. Does nothing. class NullLogger(object): - def __getattribute__(self,name): + def __getattribute__(self, name): return self - def __call__(self,*args,**kwargs): + + def __call__(self, *args, **kwargs): return self - + # Exception raised for yacc-related errors -class YaccError(Exception): pass +class YaccError(Exception): + pass # Format the result message that the parser produces when running in debug mode. def format_result(r): repr_str = repr(r) - if '\n' in repr_str: repr_str = repr(repr_str) + if '\n' in repr_str: + repr_str = repr(repr_str) if len(repr_str) > resultlimit: - repr_str = repr_str[:resultlimit]+" ..." - result = "<%s @ 0x%x> (%s)" % (type(r).__name__,id(r),repr_str) + repr_str = repr_str[:resultlimit] + ' ...' + result = '<%s @ 0x%x> (%s)' % (type(r).__name__, id(r), repr_str) return result - # Format stack entries when the parser is running in debug mode def format_stack_entry(r): repr_str = repr(r) - if '\n' in repr_str: repr_str = repr(repr_str) + if '\n' in repr_str: + repr_str = repr(repr_str) if len(repr_str) < 16: return repr_str else: - return "<%s @ 0x%x>" % (type(r).__name__,id(r)) + return '<%s @ 0x%x>' % (type(r).__name__, id(r)) #----------------------------------------------------------------------------- # === LR Parsing Engine === @@ -176,8 +154,11 @@ def format_stack_entry(r): # .endlexpos = Ending lex position (optional, set automatically) class YaccSymbol: - def __str__(self): return self.type - def __repr__(self): return str(self) + def __str__(self): + return self.type + + def __repr__(self): + return str(self) # This class is a wrapper around the objects actually passed to each # grammar rule. Index lookup and assignment actually assign the @@ -189,697 +170,128 @@ class YaccSymbol: # representing the range of positional information for a symbol. class YaccProduction: - def __init__(self,s,stack=None): + def __init__(self, s, stack=None): self.slice = s self.stack = stack - self.lexer = None - self.parser= None - def __getitem__(self,n): - if n >= 0: return self.slice[n].value - else: return self.stack[n].value - - def __setitem__(self,n,v): - self.slice[n].value = v - - def __getslice__(self,i,j): - return [s.value for s in self.slice[i:j]] - - def __len__(self): - return len(self.slice) - - def lineno(self,n): - return getattr(self.slice[n],"lineno",0) - - def set_lineno(self,n,lineno): - self.slice[n].lineno = lineno - - def linespan(self,n): - startline = getattr(self.slice[n],"lineno",0) - endline = getattr(self.slice[n],"endlineno",startline) - return startline,endline - - def lexpos(self,n): - return getattr(self.slice[n],"lexpos",0) - - def lexspan(self,n): - startpos = getattr(self.slice[n],"lexpos",0) - endpos = getattr(self.slice[n],"endlexpos",startpos) - return startpos,endpos - - def error(self): - raise SyntaxError - - -# ----------------------------------------------------------------------------- -# == LRParser == -# -# The LR Parsing engine. -# ----------------------------------------------------------------------------- - -class LRParser: - def __init__(self,lrtab,errorf): - self.productions = lrtab.lr_productions - self.action = lrtab.lr_action - self.goto = lrtab.lr_goto - self.errorfunc = errorf - - def errok(self): - self.errorok = 1 - - def restart(self): - del self.statestack[:] - del self.symstack[:] - sym = YaccSymbol() - sym.type = '$end' - self.symstack.append(sym) - self.statestack.append(0) - - def parse(self,input=None,lexer=None,debug=0,tracking=0,tokenfunc=None): - if debug or yaccdevel: - if isinstance(debug,int): - debug = PlyLogger(sys.stderr) - return self.parsedebug(input,lexer,debug,tracking,tokenfunc) - elif tracking: - return self.parseopt(input,lexer,debug,tracking,tokenfunc) - else: - return self.parseopt_notrack(input,lexer,debug,tracking,tokenfunc) - - - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - # parsedebug(). - # - # This is the debugging enabled version of parse(). All changes made to the - # parsing engine should be made here. For the non-debugging version, - # copy this code to a method parseopt() and delete all of the sections - # enclosed in: - # - # #--! DEBUG - # statements - # #--! DEBUG - # - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - def parsedebug(self,input=None,lexer=None,debug=None,tracking=0,tokenfunc=None): - lookahead = None # Current lookahead symbol - lookaheadstack = [ ] # Stack of lookahead symbols - actions = self.action # Local reference to action table (to avoid lookup on self.) - goto = self.goto # Local reference to goto table (to avoid lookup on self.) - prod = self.productions # Local reference to production list (to avoid lookup on self.) - pslice = YaccProduction(None) # Production object passed to grammar rules - errorcount = 0 # Used during error recovery - - # --! DEBUG - debug.info("PLY: PARSE DEBUG START") - # --! DEBUG - - # If no lexer was given, we will try to use the lex module - if not lexer: - lex = load_ply_lex() - lexer = lex.lexer - - # Set up the lexer and parser objects on pslice - pslice.lexer = lexer - pslice.parser = self - - # If input was supplied, pass to lexer - if input is not None: - lexer.input(input) - - if tokenfunc is None: - # Tokenize function - get_token = lexer.token - else: - get_token = tokenfunc - - # Set up the state and symbol stacks - - statestack = [ ] # Stack of parsing states - self.statestack = statestack - symstack = [ ] # Stack of grammar symbols - self.symstack = symstack - - pslice.stack = symstack # Put in the production - errtoken = None # Err token - - # The start state is assumed to be (0,$end) - - statestack.append(0) - sym = YaccSymbol() - sym.type = "$end" - symstack.append(sym) - state = 0 - while 1: - # Get the next symbol on the input. If a lookahead symbol - # is already set, we just use that. Otherwise, we'll pull - # the next token off of the lookaheadstack or from the lexer - - # --! DEBUG - debug.debug('') - debug.debug('State : %s', state) - # --! DEBUG - - if not lookahead: - if not lookaheadstack: - lookahead = get_token() # Get the next token - else: - lookahead = lookaheadstack.pop() - if not lookahead: - lookahead = YaccSymbol() - lookahead.type = "$end" - - # --! DEBUG - debug.debug('Stack : %s', - ("%s . %s" % (" ".join([xx.type for xx in symstack][1:]), str(lookahead))).lstrip()) - # --! DEBUG - - # Check the action table - ltype = lookahead.type - t = actions[state].get(ltype) - - if t is not None: - if t > 0: - # shift a symbol on the stack - statestack.append(t) - state = t - - # --! DEBUG - debug.debug("Action : Shift and goto state %s", t) - # --! DEBUG - - symstack.append(lookahead) - lookahead = None - - # Decrease error count on successful shift - if errorcount: errorcount -=1 - continue - - if t < 0: - # reduce a symbol on the stack, emit a production - p = prod[-t] - pname = p.name - plen = p.len - - # Get production function - sym = YaccSymbol() - sym.type = pname # Production name - sym.value = None - - # --! DEBUG - if plen: - debug.info("Action : Reduce rule [%s] with %s and goto state %d", p.str, "["+",".join([format_stack_entry(_v.value) for _v in symstack[-plen:]])+"]",-t) - else: - debug.info("Action : Reduce rule [%s] with %s and goto state %d", p.str, [],-t) - - # --! DEBUG - - if plen: - targ = symstack[-plen-1:] - targ[0] = sym - - # --! TRACKING - if tracking: - t1 = targ[1] - sym.lineno = t1.lineno - sym.lexpos = t1.lexpos - t1 = targ[-1] - sym.endlineno = getattr(t1,"endlineno",t1.lineno) - sym.endlexpos = getattr(t1,"endlexpos",t1.lexpos) - - # --! TRACKING - - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - # The code enclosed in this section is duplicated - # below as a performance optimization. Make sure - # changes get made in both locations. - - pslice.slice = targ - - try: - # Call the grammar rule with our special slice object - del symstack[-plen:] - del statestack[-plen:] - p.callable(pslice) - # --! DEBUG - debug.info("Result : %s", format_result(pslice[0])) - # --! DEBUG - symstack.append(sym) - state = goto[statestack[-1]][pname] - statestack.append(state) - except SyntaxError: - # If an error was set. Enter error recovery state - lookaheadstack.append(lookahead) - symstack.pop() - statestack.pop() - state = statestack[-1] - sym.type = 'error' - lookahead = sym - errorcount = error_count - self.errorok = 0 - continue - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - else: - - # --! TRACKING - if tracking: - sym.lineno = lexer.lineno - sym.lexpos = lexer.lexpos - # --! TRACKING - - targ = [ sym ] - - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - # The code enclosed in this section is duplicated - # above as a performance optimization. Make sure - # changes get made in both locations. - - pslice.slice = targ - - try: - # Call the grammar rule with our special slice object - p.callable(pslice) - # --! DEBUG - debug.info("Result : %s", format_result(pslice[0])) - # --! DEBUG - symstack.append(sym) - state = goto[statestack[-1]][pname] - statestack.append(state) - except SyntaxError: - # If an error was set. Enter error recovery state - lookaheadstack.append(lookahead) - symstack.pop() - statestack.pop() - state = statestack[-1] - sym.type = 'error' - lookahead = sym - errorcount = error_count - self.errorok = 0 - continue - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - if t == 0: - n = symstack[-1] - result = getattr(n,"value",None) - # --! DEBUG - debug.info("Done : Returning %s", format_result(result)) - debug.info("PLY: PARSE DEBUG END") - # --! DEBUG - return result - - if t == None: - - # --! DEBUG - debug.error('Error : %s', - ("%s . %s" % (" ".join([xx.type for xx in symstack][1:]), str(lookahead))).lstrip()) - # --! DEBUG - - # We have some kind of parsing error here. To handle - # this, we are going to push the current token onto - # the tokenstack and replace it with an 'error' token. - # If there are any synchronization rules, they may - # catch it. - # - # In addition to pushing the error token, we call call - # the user defined p_error() function if this is the - # first syntax error. This function is only called if - # errorcount == 0. - if errorcount == 0 or self.errorok: - errorcount = error_count - self.errorok = 0 - errtoken = lookahead - if errtoken.type == "$end": - errtoken = None # End of file! - if self.errorfunc: - global errok,token,restart - errok = self.errok # Set some special functions available in error recovery - token = get_token - restart = self.restart - if errtoken and not hasattr(errtoken,'lexer'): - errtoken.lexer = lexer - tok = self.errorfunc(errtoken) - del errok, token, restart # Delete special functions - - if self.errorok: - # User must have done some kind of panic - # mode recovery on their own. The - # returned token is the next lookahead - lookahead = tok - errtoken = None - continue - else: - if errtoken: - if hasattr(errtoken,"lineno"): lineno = lookahead.lineno - else: lineno = 0 - if lineno: - sys.stderr.write("yacc: Syntax error at line %d, token=%s\n" % (lineno, errtoken.type)) - else: - sys.stderr.write("yacc: Syntax error, token=%s" % errtoken.type) - else: - sys.stderr.write("yacc: Parse error in input. EOF\n") - return - - else: - errorcount = error_count - - # case 1: the statestack only has 1 entry on it. If we're in this state, the - # entire parse has been rolled back and we're completely hosed. The token is - # discarded and we just keep going. - - if len(statestack) <= 1 and lookahead.type != "$end": - lookahead = None - errtoken = None - state = 0 - # Nuke the pushback stack - del lookaheadstack[:] - continue - - # case 2: the statestack has a couple of entries on it, but we're - # at the end of the file. nuke the top entry and generate an error token - - # Start nuking entries on the stack - if lookahead.type == "$end": - # Whoa. We're really hosed here. Bail out - return - - if lookahead.type != 'error': - sym = symstack[-1] - if sym.type == 'error': - # Hmmm. Error is on top of stack, we'll just nuke input - # symbol and continue - lookahead = None - continue - t = YaccSymbol() - t.type = 'error' - if hasattr(lookahead,"lineno"): - t.lineno = lookahead.lineno - t.value = lookahead - lookaheadstack.append(lookahead) - lookahead = t - else: - symstack.pop() - statestack.pop() - state = statestack[-1] # Potential bug fix - - continue - - # Call an error function here - raise RuntimeError("yacc: internal parser error!!!\n") - - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - # parseopt(). - # - # Optimized version of parse() method. DO NOT EDIT THIS CODE DIRECTLY. - # Edit the debug version above, then copy any modifications to the method - # below while removing #--! DEBUG sections. - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - - def parseopt(self,input=None,lexer=None,debug=0,tracking=0,tokenfunc=None): - lookahead = None # Current lookahead symbol - lookaheadstack = [ ] # Stack of lookahead symbols - actions = self.action # Local reference to action table (to avoid lookup on self.) - goto = self.goto # Local reference to goto table (to avoid lookup on self.) - prod = self.productions # Local reference to production list (to avoid lookup on self.) - pslice = YaccProduction(None) # Production object passed to grammar rules - errorcount = 0 # Used during error recovery - - # If no lexer was given, we will try to use the lex module - if not lexer: - lex = load_ply_lex() - lexer = lex.lexer - - # Set up the lexer and parser objects on pslice - pslice.lexer = lexer - pslice.parser = self - - # If input was supplied, pass to lexer - if input is not None: - lexer.input(input) - - if tokenfunc is None: - # Tokenize function - get_token = lexer.token - else: - get_token = tokenfunc - - # Set up the state and symbol stacks - - statestack = [ ] # Stack of parsing states - self.statestack = statestack - symstack = [ ] # Stack of grammar symbols - self.symstack = symstack - - pslice.stack = symstack # Put in the production - errtoken = None # Err token - - # The start state is assumed to be (0,$end) - - statestack.append(0) - sym = YaccSymbol() - sym.type = '$end' - symstack.append(sym) - state = 0 - while 1: - # Get the next symbol on the input. If a lookahead symbol - # is already set, we just use that. Otherwise, we'll pull - # the next token off of the lookaheadstack or from the lexer - - if not lookahead: - if not lookaheadstack: - lookahead = get_token() # Get the next token - else: - lookahead = lookaheadstack.pop() - if not lookahead: - lookahead = YaccSymbol() - lookahead.type = '$end' - - # Check the action table - ltype = lookahead.type - t = actions[state].get(ltype) - - if t is not None: - if t > 0: - # shift a symbol on the stack - statestack.append(t) - state = t - - symstack.append(lookahead) - lookahead = None - - # Decrease error count on successful shift - if errorcount: errorcount -=1 - continue - - if t < 0: - # reduce a symbol on the stack, emit a production - p = prod[-t] - pname = p.name - plen = p.len - - # Get production function - sym = YaccSymbol() - sym.type = pname # Production name - sym.value = None - - if plen: - targ = symstack[-plen-1:] - targ[0] = sym - - # --! TRACKING - if tracking: - t1 = targ[1] - sym.lineno = t1.lineno - sym.lexpos = t1.lexpos - t1 = targ[-1] - sym.endlineno = getattr(t1,"endlineno",t1.lineno) - sym.endlexpos = getattr(t1,"endlexpos",t1.lexpos) - - # --! TRACKING - - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - # The code enclosed in this section is duplicated - # below as a performance optimization. Make sure - # changes get made in both locations. - - pslice.slice = targ - - try: - # Call the grammar rule with our special slice object - del symstack[-plen:] - del statestack[-plen:] - p.callable(pslice) - symstack.append(sym) - state = goto[statestack[-1]][pname] - statestack.append(state) - except SyntaxError: - # If an error was set. Enter error recovery state - lookaheadstack.append(lookahead) - symstack.pop() - statestack.pop() - state = statestack[-1] - sym.type = 'error' - lookahead = sym - errorcount = error_count - self.errorok = 0 - continue - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - else: - - # --! TRACKING - if tracking: - sym.lineno = lexer.lineno - sym.lexpos = lexer.lexpos - # --! TRACKING - - targ = [ sym ] - - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - # The code enclosed in this section is duplicated - # above as a performance optimization. Make sure - # changes get made in both locations. - - pslice.slice = targ - - try: - # Call the grammar rule with our special slice object - p.callable(pslice) - symstack.append(sym) - state = goto[statestack[-1]][pname] - statestack.append(state) - except SyntaxError: - # If an error was set. Enter error recovery state - lookaheadstack.append(lookahead) - symstack.pop() - statestack.pop() - state = statestack[-1] - sym.type = 'error' - lookahead = sym - errorcount = error_count - self.errorok = 0 - continue - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - if t == 0: - n = symstack[-1] - return getattr(n,"value",None) - - if t == None: - - # We have some kind of parsing error here. To handle - # this, we are going to push the current token onto - # the tokenstack and replace it with an 'error' token. - # If there are any synchronization rules, they may - # catch it. - # - # In addition to pushing the error token, we call call - # the user defined p_error() function if this is the - # first syntax error. This function is only called if - # errorcount == 0. - if errorcount == 0 or self.errorok: - errorcount = error_count - self.errorok = 0 - errtoken = lookahead - if errtoken.type == '$end': - errtoken = None # End of file! - if self.errorfunc: - global errok,token,restart - errok = self.errok # Set some special functions available in error recovery - token = get_token - restart = self.restart - if errtoken and not hasattr(errtoken,'lexer'): - errtoken.lexer = lexer - tok = self.errorfunc(errtoken) - del errok, token, restart # Delete special functions + self.lexer = None + self.parser = None - if self.errorok: - # User must have done some kind of panic - # mode recovery on their own. The - # returned token is the next lookahead - lookahead = tok - errtoken = None - continue - else: - if errtoken: - if hasattr(errtoken,"lineno"): lineno = lookahead.lineno - else: lineno = 0 - if lineno: - sys.stderr.write("yacc: Syntax error at line %d, token=%s\n" % (lineno, errtoken.type)) - else: - sys.stderr.write("yacc: Syntax error, token=%s" % errtoken.type) - else: - sys.stderr.write("yacc: Parse error in input. EOF\n") - return + def __getitem__(self, n): + if isinstance(n, slice): + return [s.value for s in self.slice[n]] + elif n >= 0: + return self.slice[n].value + else: + return self.stack[n].value - else: - errorcount = error_count + def __setitem__(self, n, v): + self.slice[n].value = v - # case 1: the statestack only has 1 entry on it. If we're in this state, the - # entire parse has been rolled back and we're completely hosed. The token is - # discarded and we just keep going. + def __getslice__(self, i, j): + return [s.value for s in self.slice[i:j]] - if len(statestack) <= 1 and lookahead.type != '$end': - lookahead = None - errtoken = None - state = 0 - # Nuke the pushback stack - del lookaheadstack[:] - continue + def __len__(self): + return len(self.slice) - # case 2: the statestack has a couple of entries on it, but we're - # at the end of the file. nuke the top entry and generate an error token + def lineno(self, n): + return getattr(self.slice[n], 'lineno', 0) - # Start nuking entries on the stack - if lookahead.type == '$end': - # Whoa. We're really hosed here. Bail out - return + def set_lineno(self, n, lineno): + self.slice[n].lineno = lineno - if lookahead.type != 'error': - sym = symstack[-1] - if sym.type == 'error': - # Hmmm. Error is on top of stack, we'll just nuke input - # symbol and continue - lookahead = None - continue - t = YaccSymbol() - t.type = 'error' - if hasattr(lookahead,"lineno"): - t.lineno = lookahead.lineno - t.value = lookahead - lookaheadstack.append(lookahead) - lookahead = t - else: - symstack.pop() - statestack.pop() - state = statestack[-1] # Potential bug fix + def linespan(self, n): + startline = getattr(self.slice[n], 'lineno', 0) + endline = getattr(self.slice[n], 'endlineno', startline) + return startline, endline - continue + def lexpos(self, n): + return getattr(self.slice[n], 'lexpos', 0) + + def set_lexpos(self, n, lexpos): + self.slice[n].lexpos = lexpos + + def lexspan(self, n): + startpos = getattr(self.slice[n], 'lexpos', 0) + endpos = getattr(self.slice[n], 'endlexpos', startpos) + return startpos, endpos + + def error(self): + raise SyntaxError + +# ----------------------------------------------------------------------------- +# == LRParser == +# +# The LR Parsing engine. +# ----------------------------------------------------------------------------- + +class LRParser: + def __init__(self, lrtab, errorf): + self.productions = lrtab.lr_productions + self.action = lrtab.lr_action + self.goto = lrtab.lr_goto + self.errorfunc = errorf + self.set_defaulted_states() + self.errorok = True + + def errok(self): + self.errorok = True - # Call an error function here - raise RuntimeError("yacc: internal parser error!!!\n") + def restart(self): + del self.statestack[:] + del self.symstack[:] + sym = YaccSymbol() + sym.type = '$end' + self.symstack.append(sym) + self.statestack.append(0) - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - # parseopt_notrack(). + # Defaulted state support. + # This method identifies parser states where there is only one possible reduction action. + # For such states, the parser can make a choose to make a rule reduction without consuming + # the next look-ahead token. This delayed invocation of the tokenizer can be useful in + # certain kinds of advanced parsing situations where the lexer and parser interact with + # each other or change states (i.e., manipulation of scope, lexer states, etc.). + # + # See: http://www.gnu.org/software/bison/manual/html_node/Default-Reductions.html#Default-Reductions + def set_defaulted_states(self): + self.defaulted_states = {} + for state, actions in self.action.items(): + rules = list(actions.values()) + if len(rules) == 1 and rules[0] < 0: + self.defaulted_states[state] = rules[0] + + def disable_defaulted_states(self): + self.defaulted_states = {} + + # parse(). # - # Optimized version of parseopt() with line number tracking removed. - # DO NOT EDIT THIS CODE DIRECTLY. Copy the optimized version and remove - # code in the #--! TRACKING sections - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - def parseopt_notrack(self,input=None,lexer=None,debug=0,tracking=0,tokenfunc=None): - lookahead = None # Current lookahead symbol - lookaheadstack = [ ] # Stack of lookahead symbols - actions = self.action # Local reference to action table (to avoid lookup on self.) - goto = self.goto # Local reference to goto table (to avoid lookup on self.) - prod = self.productions # Local reference to production list (to avoid lookup on self.) - pslice = YaccProduction(None) # Production object passed to grammar rules - errorcount = 0 # Used during error recovery + # This is the core parsing engine. To operate, it requires a lexer object. + # Two options are provided. The debug flag turns on debugging so that you can + # see the various rule reductions and parsing steps. tracking turns on position + # tracking. In this mode, symbols will record the starting/ending line number and + # character index. + + def parse(self, input=None, lexer=None, debug=False, tracking=False): + # If debugging has been specified as a flag, turn it into a logging object + if isinstance(debug, int) and debug: + debug = PlyLogger(sys.stderr) + + lookahead = None # Current lookahead symbol + lookaheadstack = [] # Stack of lookahead symbols + actions = self.action # Local reference to action table (to avoid lookup on self.) + goto = self.goto # Local reference to goto table (to avoid lookup on self.) + prod = self.productions # Local reference to production list (to avoid lookup on self.) + defaulted_states = self.defaulted_states # Local reference to defaulted states + pslice = YaccProduction(None) # Production object passed to grammar rules + errorcount = 0 # Used during error recovery + + if debug: + debug.info('PLY: PARSE DEBUG START') # If no lexer was given, we will try to use the lex module if not lexer: - lex = load_ply_lex() + from . import lex lexer = lex.lexer - + # Set up the lexer and parser objects on pslice pslice.lexer = lexer pslice.parser = self @@ -888,21 +300,14 @@ class LRParser: if input is not None: lexer.input(input) - if tokenfunc is None: - # Tokenize function - get_token = lexer.token - else: - get_token = tokenfunc + # Set the token function + get_token = self.token = lexer.token # Set up the state and symbol stacks - - statestack = [ ] # Stack of parsing states - self.statestack = statestack - symstack = [ ] # Stack of grammar symbols - self.symstack = symstack - - pslice.stack = symstack # Put in the production - errtoken = None # Err token + statestack = self.statestack = [] # Stack of parsing states + symstack = self.symstack = [] # Stack of grammar symbols + pslice.stack = symstack # Put in the production + errtoken = None # Err token # The start state is assumed to be (0,$end) @@ -911,23 +316,35 @@ class LRParser: sym.type = '$end' symstack.append(sym) state = 0 - while 1: + while True: # Get the next symbol on the input. If a lookahead symbol # is already set, we just use that. Otherwise, we'll pull # the next token off of the lookaheadstack or from the lexer - if not lookahead: - if not lookaheadstack: - lookahead = get_token() # Get the next token - else: - lookahead = lookaheadstack.pop() + if debug: + debug.debug('State : %s', state) + + if state not in defaulted_states: if not lookahead: - lookahead = YaccSymbol() - lookahead.type = '$end' + if not lookaheadstack: + lookahead = get_token() # Get the next token + else: + lookahead = lookaheadstack.pop() + if not lookahead: + lookahead = YaccSymbol() + lookahead.type = '$end' + + # Check the action table + ltype = lookahead.type + t = actions[state].get(ltype) + else: + t = defaulted_states[state] + if debug: + debug.debug('Defaulted state %s: Reduce using %d', state, -t) - # Check the action table - ltype = lookahead.type - t = actions[state].get(ltype) + if debug: + debug.debug('Stack : %s', + ('%s . %s' % (' '.join([xx.type for xx in symstack][1:]), str(lookahead))).lstrip()) if t is not None: if t > 0: @@ -935,11 +352,15 @@ class LRParser: statestack.append(t) state = t + if debug: + debug.debug('Action : Shift and goto state %s', t) + symstack.append(lookahead) lookahead = None # Decrease error count on successful shift - if errorcount: errorcount -=1 + if errorcount: + errorcount -= 1 continue if t < 0: @@ -953,44 +374,69 @@ class LRParser: sym.type = pname # Production name sym.value = None + if debug: + if plen: + debug.info('Action : Reduce rule [%s] with %s and goto state %d', p.str, + '['+','.join([format_stack_entry(_v.value) for _v in symstack[-plen:]])+']', + goto[statestack[-1-plen]][pname]) + else: + debug.info('Action : Reduce rule [%s] with %s and goto state %d', p.str, [], + goto[statestack[-1]][pname]) + if plen: targ = symstack[-plen-1:] targ[0] = sym + if tracking: + t1 = targ[1] + sym.lineno = t1.lineno + sym.lexpos = t1.lexpos + t1 = targ[-1] + sym.endlineno = getattr(t1, 'endlineno', t1.lineno) + sym.endlexpos = getattr(t1, 'endlexpos', t1.lexpos) + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - # The code enclosed in this section is duplicated + # The code enclosed in this section is duplicated # below as a performance optimization. Make sure # changes get made in both locations. pslice.slice = targ - + try: # Call the grammar rule with our special slice object del symstack[-plen:] - del statestack[-plen:] + self.state = state p.callable(pslice) + del statestack[-plen:] + if debug: + debug.info('Result : %s', format_result(pslice[0])) symstack.append(sym) state = goto[statestack[-1]][pname] statestack.append(state) except SyntaxError: # If an error was set. Enter error recovery state - lookaheadstack.append(lookahead) - symstack.pop() - statestack.pop() + lookaheadstack.append(lookahead) # Save the current lookahead token + symstack.extend(targ[1:-1]) # Put the production slice back on the stack + statestack.pop() # Pop back one state (before the reduce) state = statestack[-1] sym.type = 'error' + sym.value = 'error' lookahead = sym errorcount = error_count - self.errorok = 0 + self.errorok = False + continue - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - + else: - targ = [ sym ] + if tracking: + sym.lineno = lexer.lineno + sym.lexpos = lexer.lexpos + + targ = [sym] # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - # The code enclosed in this section is duplicated + # The code enclosed in this section is duplicated # above as a performance optimization. Make sure # changes get made in both locations. @@ -998,28 +444,41 @@ class LRParser: try: # Call the grammar rule with our special slice object + self.state = state p.callable(pslice) + if debug: + debug.info('Result : %s', format_result(pslice[0])) symstack.append(sym) state = goto[statestack[-1]][pname] statestack.append(state) except SyntaxError: # If an error was set. Enter error recovery state - lookaheadstack.append(lookahead) - symstack.pop() - statestack.pop() + lookaheadstack.append(lookahead) # Save the current lookahead token + statestack.pop() # Pop back one state (before the reduce) state = statestack[-1] sym.type = 'error' + sym.value = 'error' lookahead = sym errorcount = error_count - self.errorok = 0 + self.errorok = False + continue - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! if t == 0: n = symstack[-1] - return getattr(n,"value",None) + result = getattr(n, 'value', None) + + if debug: + debug.info('Done : Returning %s', format_result(result)) + debug.info('PLY: PARSE DEBUG END') + + return result - if t == None: + if t is None: + + if debug: + debug.error('Error : %s', + ('%s . %s' % (' '.join([xx.type for xx in symstack][1:]), str(lookahead))).lstrip()) # We have some kind of parsing error here. To handle # this, we are going to push the current token onto @@ -1033,20 +492,15 @@ class LRParser: # errorcount == 0. if errorcount == 0 or self.errorok: errorcount = error_count - self.errorok = 0 + self.errorok = False errtoken = lookahead if errtoken.type == '$end': errtoken = None # End of file! if self.errorfunc: - global errok,token,restart - errok = self.errok # Set some special functions available in error recovery - token = get_token - restart = self.restart - if errtoken and not hasattr(errtoken,'lexer'): + if errtoken and not hasattr(errtoken, 'lexer'): errtoken.lexer = lexer + self.state = state tok = self.errorfunc(errtoken) - del errok, token, restart # Delete special functions - if self.errorok: # User must have done some kind of panic # mode recovery on their own. The @@ -1056,14 +510,16 @@ class LRParser: continue else: if errtoken: - if hasattr(errtoken,"lineno"): lineno = lookahead.lineno - else: lineno = 0 + if hasattr(errtoken, 'lineno'): + lineno = lookahead.lineno + else: + lineno = 0 if lineno: - sys.stderr.write("yacc: Syntax error at line %d, token=%s\n" % (lineno, errtoken.type)) + sys.stderr.write('yacc: Syntax error at line %d, token=%s\n' % (lineno, errtoken.type)) else: - sys.stderr.write("yacc: Syntax error, token=%s" % errtoken.type) + sys.stderr.write('yacc: Syntax error, token=%s' % errtoken.type) else: - sys.stderr.write("yacc: Parse error in input. EOF\n") + sys.stderr.write('yacc: Parse error in input. EOF\n') return else: @@ -1094,34 +550,43 @@ class LRParser: if sym.type == 'error': # Hmmm. Error is on top of stack, we'll just nuke input # symbol and continue + if tracking: + sym.endlineno = getattr(lookahead, 'lineno', sym.lineno) + sym.endlexpos = getattr(lookahead, 'lexpos', sym.lexpos) lookahead = None continue + + # Create the error symbol for the first time and make it the new lookahead symbol t = YaccSymbol() t.type = 'error' - if hasattr(lookahead,"lineno"): - t.lineno = lookahead.lineno + + if hasattr(lookahead, 'lineno'): + t.lineno = t.endlineno = lookahead.lineno + if hasattr(lookahead, 'lexpos'): + t.lexpos = t.endlexpos = lookahead.lexpos t.value = lookahead lookaheadstack.append(lookahead) lookahead = t else: - symstack.pop() + sym = symstack.pop() + if tracking: + lookahead.lineno = sym.lineno + lookahead.lexpos = sym.lexpos statestack.pop() - state = statestack[-1] # Potential bug fix + state = statestack[-1] continue - # Call an error function here - raise RuntimeError("yacc: internal parser error!!!\n") + # If we'r here, something really bad happened + raise RuntimeError('yacc: internal parser error!!!\n') # ----------------------------------------------------------------------------- # === Grammar Representation === # # The following functions, classes, and variables are used to represent and -# manipulate the rules that make up a grammar. +# manipulate the rules that make up a grammar. # ----------------------------------------------------------------------------- -import re - # regex matching identifiers _is_identifier = re.compile(r'^[a-zA-Z0-9_-]+$') @@ -1131,7 +596,7 @@ _is_identifier = re.compile(r'^[a-zA-Z0-9_-]+$') # This class stores the raw information about a single production or grammar rule. # A grammar rule refers to a specification such as this: # -# expr : expr PLUS term +# expr : expr PLUS term # # Here are the basic attributes defined on all productions # @@ -1151,7 +616,7 @@ _is_identifier = re.compile(r'^[a-zA-Z0-9_-]+$') class Production(object): reduced = 0 - def __init__(self,number,name,prod,precedence=('right',0),func=None,file='',line=0): + def __init__(self, number, name, prod, precedence=('right', 0), func=None, file='', line=0): self.name = name self.prod = tuple(prod) self.number = number @@ -1162,11 +627,11 @@ class Production(object): self.prec = precedence # Internal settings used during table construction - + self.len = len(self.prod) # Length of the production # Create a list of unique production symbols used in the production - self.usyms = [ ] + self.usyms = [] for s in self.prod: if s not in self.usyms: self.usyms.append(s) @@ -1177,15 +642,15 @@ class Production(object): # Create a string representation if self.prod: - self.str = "%s -> %s" % (self.name," ".join(self.prod)) + self.str = '%s -> %s' % (self.name, ' '.join(self.prod)) else: - self.str = "%s -> " % self.name + self.str = '%s -> ' % self.name def __str__(self): return self.str def __repr__(self): - return "Production("+str(self)+")" + return 'Production(' + str(self) + ')' def __len__(self): return len(self.prod) @@ -1193,62 +658,37 @@ class Production(object): def __nonzero__(self): return 1 - def __getitem__(self,index): + def __getitem__(self, index): return self.prod[index] - - # Return the nth lr_item from the production (or None if at the end) - def lr_item(self,n): - if n > len(self.prod): return None - p = LRItem(self,n) - # Precompute the list of productions immediately following. Hack. Remove later + # Return the nth lr_item from the production (or None if at the end) + def lr_item(self, n): + if n > len(self.prod): + return None + p = LRItem(self, n) + # Precompute the list of productions immediately following. try: - p.lr_after = Prodnames[p.prod[n+1]] - except (IndexError,KeyError): + p.lr_after = self.Prodnames[p.prod[n+1]] + except (IndexError, KeyError): p.lr_after = [] try: p.lr_before = p.prod[n-1] except IndexError: p.lr_before = None - return p - - # Bind the production function name to a callable - def bind(self,pdict): - if self.func: - self.callable = pdict[self.func] - -# This class serves as a minimal standin for Production objects when -# reading table data from files. It only contains information -# actually used by the LR parsing engine, plus some additional -# debugging information. -class MiniProduction(object): - def __init__(self,str,name,len,func,file,line): - self.name = name - self.len = len - self.func = func - self.callable = None - self.file = file - self.line = line - self.str = str - def __str__(self): - return self.str - def __repr__(self): - return "MiniProduction(%s)" % self.str # Bind the production function name to a callable - def bind(self,pdict): + def bind(self, pdict): if self.func: self.callable = pdict[self.func] - # ----------------------------------------------------------------------------- # class LRItem # # This class represents a specific stage of parsing a production rule. For -# example: +# example: # -# expr : expr . PLUS term +# expr : expr . PLUS term # # In the above, the "." represents the current location of the parse. Here # basic attributes: @@ -1267,26 +707,26 @@ class MiniProduction(object): # ----------------------------------------------------------------------------- class LRItem(object): - def __init__(self,p,n): + def __init__(self, p, n): self.name = p.name self.prod = list(p.prod) self.number = p.number self.lr_index = n - self.lookaheads = { } - self.prod.insert(n,".") + self.lookaheads = {} + self.prod.insert(n, '.') self.prod = tuple(self.prod) self.len = len(self.prod) self.usyms = p.usyms def __str__(self): if self.prod: - s = "%s -> %s" % (self.name," ".join(self.prod)) + s = '%s -> %s' % (self.name, ' '.join(self.prod)) else: - s = "%s -> " % self.name + s = '%s -> ' % self.name return s def __repr__(self): - return "LRItem("+str(self)+")" + return 'LRItem(' + str(self) + ')' # ----------------------------------------------------------------------------- # rightmost_terminal() @@ -1309,41 +749,42 @@ def rightmost_terminal(symbols, terminals): # This data is used for critical parts of the table generation process later. # ----------------------------------------------------------------------------- -class GrammarError(YaccError): pass +class GrammarError(YaccError): + pass class Grammar(object): - def __init__(self,terminals): + def __init__(self, terminals): self.Productions = [None] # A list of all of the productions. The first - # entry is always reserved for the purpose of - # building an augmented grammar + # entry is always reserved for the purpose of + # building an augmented grammar - self.Prodnames = { } # A dictionary mapping the names of nonterminals to a list of all - # productions of that nonterminal. + self.Prodnames = {} # A dictionary mapping the names of nonterminals to a list of all + # productions of that nonterminal. - self.Prodmap = { } # A dictionary that is only used to detect duplicate - # productions. + self.Prodmap = {} # A dictionary that is only used to detect duplicate + # productions. - self.Terminals = { } # A dictionary mapping the names of terminal symbols to a - # list of the rules where they are used. + self.Terminals = {} # A dictionary mapping the names of terminal symbols to a + # list of the rules where they are used. for term in terminals: self.Terminals[term] = [] self.Terminals['error'] = [] - self.Nonterminals = { } # A dictionary mapping names of nonterminals to a list - # of rule numbers where they are used. + self.Nonterminals = {} # A dictionary mapping names of nonterminals to a list + # of rule numbers where they are used. - self.First = { } # A dictionary of precomputed FIRST(x) symbols + self.First = {} # A dictionary of precomputed FIRST(x) symbols - self.Follow = { } # A dictionary of precomputed FOLLOW(x) symbols + self.Follow = {} # A dictionary of precomputed FOLLOW(x) symbols - self.Precedence = { } # Precedence rules for each terminal. Contains tuples of the - # form ('right',level) or ('nonassoc', level) or ('left',level) + self.Precedence = {} # Precedence rules for each terminal. Contains tuples of the + # form ('right',level) or ('nonassoc', level) or ('left',level) - self.UsedPrecedence = { } # Precedence rules that were actually used by the grammer. - # This is only used to provide error checking and to generate - # a warning about unused precedence rules. + self.UsedPrecedence = set() # Precedence rules that were actually used by the grammer. + # This is only used to provide error checking and to generate + # a warning about unused precedence rules. self.Start = None # Starting symbol for the grammar @@ -1351,7 +792,7 @@ class Grammar(object): def __len__(self): return len(self.Productions) - def __getitem__(self,index): + def __getitem__(self, index): return self.Productions[index] # ----------------------------------------------------------------------------- @@ -1362,14 +803,14 @@ class Grammar(object): # # ----------------------------------------------------------------------------- - def set_precedence(self,term,assoc,level): - assert self.Productions == [None],"Must call set_precedence() before add_production()" + def set_precedence(self, term, assoc, level): + assert self.Productions == [None], 'Must call set_precedence() before add_production()' if term in self.Precedence: - raise GrammarError("Precedence already specified for terminal '%s'" % term) - if assoc not in ['left','right','nonassoc']: + raise GrammarError('Precedence already specified for terminal %r' % term) + if assoc not in ['left', 'right', 'nonassoc']: raise GrammarError("Associativity must be one of 'left','right', or 'nonassoc'") - self.Precedence[term] = (assoc,level) - + self.Precedence[term] = (assoc, level) + # ----------------------------------------------------------------------------- # add_production() # @@ -1387,72 +828,74 @@ class Grammar(object): # are valid and that %prec is used correctly. # ----------------------------------------------------------------------------- - def add_production(self,prodname,syms,func=None,file='',line=0): + def add_production(self, prodname, syms, func=None, file='', line=0): if prodname in self.Terminals: - raise GrammarError("%s:%d: Illegal rule name '%s'. Already defined as a token" % (file,line,prodname)) + raise GrammarError('%s:%d: Illegal rule name %r. Already defined as a token' % (file, line, prodname)) if prodname == 'error': - raise GrammarError("%s:%d: Illegal rule name '%s'. error is a reserved word" % (file,line,prodname)) + raise GrammarError('%s:%d: Illegal rule name %r. error is a reserved word' % (file, line, prodname)) if not _is_identifier.match(prodname): - raise GrammarError("%s:%d: Illegal rule name '%s'" % (file,line,prodname)) + raise GrammarError('%s:%d: Illegal rule name %r' % (file, line, prodname)) - # Look for literal tokens - for n,s in enumerate(syms): + # Look for literal tokens + for n, s in enumerate(syms): if s[0] in "'\"": - try: - c = eval(s) - if (len(c) > 1): - raise GrammarError("%s:%d: Literal token %s in rule '%s' may only be a single character" % (file,line,s, prodname)) - if not c in self.Terminals: - self.Terminals[c] = [] - syms[n] = c - continue - except SyntaxError: - pass + try: + c = eval(s) + if (len(c) > 1): + raise GrammarError('%s:%d: Literal token %s in rule %r may only be a single character' % + (file, line, s, prodname)) + if c not in self.Terminals: + self.Terminals[c] = [] + syms[n] = c + continue + except SyntaxError: + pass if not _is_identifier.match(s) and s != '%prec': - raise GrammarError("%s:%d: Illegal name '%s' in rule '%s'" % (file,line,s, prodname)) - + raise GrammarError('%s:%d: Illegal name %r in rule %r' % (file, line, s, prodname)) + # Determine the precedence level if '%prec' in syms: if syms[-1] == '%prec': - raise GrammarError("%s:%d: Syntax error. Nothing follows %%prec" % (file,line)) + raise GrammarError('%s:%d: Syntax error. Nothing follows %%prec' % (file, line)) if syms[-2] != '%prec': - raise GrammarError("%s:%d: Syntax error. %%prec can only appear at the end of a grammar rule" % (file,line)) + raise GrammarError('%s:%d: Syntax error. %%prec can only appear at the end of a grammar rule' % + (file, line)) precname = syms[-1] - prodprec = self.Precedence.get(precname,None) + prodprec = self.Precedence.get(precname) if not prodprec: - raise GrammarError("%s:%d: Nothing known about the precedence of '%s'" % (file,line,precname)) + raise GrammarError('%s:%d: Nothing known about the precedence of %r' % (file, line, precname)) else: - self.UsedPrecedence[precname] = 1 + self.UsedPrecedence.add(precname) del syms[-2:] # Drop %prec from the rule else: # If no %prec, precedence is determined by the rightmost terminal symbol - precname = rightmost_terminal(syms,self.Terminals) - prodprec = self.Precedence.get(precname,('right',0)) - + precname = rightmost_terminal(syms, self.Terminals) + prodprec = self.Precedence.get(precname, ('right', 0)) + # See if the rule is already in the rulemap - map = "%s -> %s" % (prodname,syms) + map = '%s -> %s' % (prodname, syms) if map in self.Prodmap: m = self.Prodmap[map] - raise GrammarError("%s:%d: Duplicate rule %s. " % (file,line, m) + - "Previous definition at %s:%d" % (m.file, m.line)) + raise GrammarError('%s:%d: Duplicate rule %s. ' % (file, line, m) + + 'Previous definition at %s:%d' % (m.file, m.line)) # From this point on, everything is valid. Create a new Production instance pnumber = len(self.Productions) - if not prodname in self.Nonterminals: - self.Nonterminals[prodname] = [ ] + if prodname not in self.Nonterminals: + self.Nonterminals[prodname] = [] # Add the production number to Terminals and Nonterminals for t in syms: if t in self.Terminals: self.Terminals[t].append(pnumber) else: - if not t in self.Nonterminals: - self.Nonterminals[t] = [ ] + if t not in self.Nonterminals: + self.Nonterminals[t] = [] self.Nonterminals[t].append(pnumber) # Create a production and add it to the list of productions - p = Production(pnumber,prodname,syms,prodprec,func,file,line) + p = Production(pnumber, prodname, syms, prodprec, func, file, line) self.Productions.append(p) self.Prodmap[map] = p @@ -1460,22 +903,21 @@ class Grammar(object): try: self.Prodnames[prodname].append(p) except KeyError: - self.Prodnames[prodname] = [ p ] - return 0 + self.Prodnames[prodname] = [p] # ----------------------------------------------------------------------------- # set_start() # - # Sets the starting symbol and creates the augmented grammar. Production + # Sets the starting symbol and creates the augmented grammar. Production # rule 0 is S' -> start where start is the start symbol. # ----------------------------------------------------------------------------- - def set_start(self,start=None): + def set_start(self, start=None): if not start: start = self.Productions[1].name if start not in self.Nonterminals: - raise GrammarError("start symbol %s undefined" % start) - self.Productions[0] = Production(0,"S'",[start]) + raise GrammarError('start symbol %s undefined' % start) + self.Productions[0] = Production(0, "S'", [start]) self.Nonterminals[start].append(0) self.Start = start @@ -1487,26 +929,20 @@ class Grammar(object): # ----------------------------------------------------------------------------- def find_unreachable(self): - + # Mark all symbols that are reachable from a symbol s def mark_reachable_from(s): - if reachable[s]: - # We've already reached symbol s. + if s in reachable: return - reachable[s] = 1 - for p in self.Prodnames.get(s,[]): + reachable.add(s) + for p in self.Prodnames.get(s, []): for r in p.prod: mark_reachable_from(r) - reachable = { } - for s in list(self.Terminals) + list(self.Nonterminals): - reachable[s] = 0 - - mark_reachable_from( self.Productions[0].prod[0] ) + reachable = set() + mark_reachable_from(self.Productions[0].prod[0]) + return [s for s in self.Nonterminals if s not in reachable] - return [s for s in list(self.Nonterminals) - if not reachable[s]] - # ----------------------------------------------------------------------------- # infinite_cycles() # @@ -1520,20 +956,20 @@ class Grammar(object): # Terminals: for t in self.Terminals: - terminates[t] = 1 + terminates[t] = True - terminates['$end'] = 1 + terminates['$end'] = True # Nonterminals: # Initialize to false: for n in self.Nonterminals: - terminates[n] = 0 + terminates[n] = False # Then propagate termination until no change: - while 1: - some_change = 0 - for (n,pl) in self.Prodnames.items(): + while True: + some_change = False + for (n, pl) in self.Prodnames.items(): # Nonterminal n terminates iff any of its productions terminates. for p in pl: # Production p terminates iff all of its rhs symbols terminate. @@ -1541,19 +977,19 @@ class Grammar(object): if not terminates[s]: # The symbol s does not terminate, # so production p does not terminate. - p_terminates = 0 + p_terminates = False break else: # didn't break from the loop, # so every symbol s terminates # so production p terminates. - p_terminates = 1 + p_terminates = True if p_terminates: # symbol n terminates! if not terminates[n]: - terminates[n] = 1 - some_change = 1 + terminates[n] = True + some_change = True # Don't need to consider any more productions for this n. break @@ -1561,9 +997,9 @@ class Grammar(object): break infinite = [] - for (s,term) in terminates.items(): + for (s, term) in terminates.items(): if not term: - if not s in self.Prodnames and not s in self.Terminals and s != 'error': + if s not in self.Prodnames and s not in self.Terminals and s != 'error': # s is used-but-not-defined, and we've already warned of that, # so it would be overkill to say that it's also non-terminating. pass @@ -1572,22 +1008,22 @@ class Grammar(object): return infinite - # ----------------------------------------------------------------------------- # undefined_symbols() # # Find all symbols that were used the grammar, but not defined as tokens or # grammar rules. Returns a list of tuples (sym, prod) where sym in the symbol - # and prod is the production where the symbol was used. + # and prod is the production where the symbol was used. # ----------------------------------------------------------------------------- def undefined_symbols(self): result = [] for p in self.Productions: - if not p: continue + if not p: + continue for s in p.prod: - if not s in self.Prodnames and not s in self.Terminals and s != 'error': - result.append((s,p)) + if s not in self.Prodnames and s not in self.Terminals and s != 'error': + result.append((s, p)) return result # ----------------------------------------------------------------------------- @@ -1598,7 +1034,7 @@ class Grammar(object): # ----------------------------------------------------------------------------- def unused_terminals(self): unused_tok = [] - for s,v in self.Terminals.items(): + for s, v in self.Terminals.items(): if s != 'error' and not v: unused_tok.append(s) @@ -1613,7 +1049,7 @@ class Grammar(object): def unused_rules(self): unused_prod = [] - for s,v in self.Nonterminals.items(): + for s, v in self.Nonterminals.items(): if not v: p = self.Prodnames[s][0] unused_prod.append(p) @@ -1625,15 +1061,15 @@ class Grammar(object): # Returns a list of tuples (term,precedence) corresponding to precedence # rules that were never used by the grammar. term is the name of the terminal # on which precedence was applied and precedence is a string such as 'left' or - # 'right' corresponding to the type of precedence. + # 'right' corresponding to the type of precedence. # ----------------------------------------------------------------------------- def unused_precedence(self): unused = [] for termname in self.Precedence: if not (termname in self.Terminals or termname in self.UsedPrecedence): - unused.append((termname,self.Precedence[termname][0])) - + unused.append((termname, self.Precedence[termname][0])) + return unused # ------------------------------------------------------------------------- @@ -1644,19 +1080,20 @@ class Grammar(object): # During execution of compute_first1, the result may be incomplete. # Afterward (e.g., when called from compute_follow()), it will be complete. # ------------------------------------------------------------------------- - def _first(self,beta): + def _first(self, beta): # We are computing First(x1,x2,x3,...,xn) - result = [ ] + result = [] for x in beta: - x_produces_empty = 0 + x_produces_empty = False # Add all the non- symbols of First[x] to the result. for f in self.First[x]: if f == '': - x_produces_empty = 1 + x_produces_empty = True else: - if f not in result: result.append(f) + if f not in result: + result.append(f) if x_produces_empty: # We have to consider the next x in beta, @@ -1695,17 +1132,17 @@ class Grammar(object): self.First[n] = [] # Then propagate symbols until no change: - while 1: - some_change = 0 + while True: + some_change = False for n in self.Nonterminals: for p in self.Prodnames[n]: for f in self._first(p.prod): if f not in self.First[n]: - self.First[n].append( f ) - some_change = 1 + self.First[n].append(f) + some_change = True if not some_change: break - + return self.First # --------------------------------------------------------------------- @@ -1715,7 +1152,7 @@ class Grammar(object): # follow set is the set of all symbols that might follow a given # non-terminal. See the Dragon book, 2nd Ed. p. 189. # --------------------------------------------------------------------- - def compute_follow(self,start=None): + def compute_follow(self, start=None): # If already computed, return the result if self.Follow: return self.Follow @@ -1726,36 +1163,36 @@ class Grammar(object): # Add '$end' to the follow list of the start symbol for k in self.Nonterminals: - self.Follow[k] = [ ] + self.Follow[k] = [] if not start: start = self.Productions[1].name - self.Follow[start] = [ '$end' ] + self.Follow[start] = ['$end'] - while 1: - didadd = 0 + while True: + didadd = False for p in self.Productions[1:]: # Here is the production set - for i in range(len(p.prod)): - B = p.prod[i] + for i, B in enumerate(p.prod): if B in self.Nonterminals: # Okay. We got a non-terminal in a production fst = self._first(p.prod[i+1:]) - hasempty = 0 + hasempty = False for f in fst: if f != '' and f not in self.Follow[B]: self.Follow[B].append(f) - didadd = 1 + didadd = True if f == '': - hasempty = 1 + hasempty = True if hasempty or i == (len(p.prod)-1): # Add elements of follow(a) to follow(b) for f in self.Follow[p.name]: if f not in self.Follow[B]: self.Follow[B].append(f) - didadd = 1 - if not didadd: break + didadd = True + if not didadd: + break return self.Follow @@ -1779,15 +1216,15 @@ class Grammar(object): lastlri = p i = 0 lr_items = [] - while 1: + while True: if i > len(p): lri = None else: - lri = LRItem(p,i) + lri = LRItem(p, i) # Precompute the list of productions immediately following try: lri.lr_after = self.Prodnames[lri.prod[i+1]] - except (IndexError,KeyError): + except (IndexError, KeyError): lri.lr_after = [] try: lri.lr_before = lri.prod[i-1] @@ -1795,86 +1232,17 @@ class Grammar(object): lri.lr_before = None lastlri.lr_next = lri - if not lri: break + if not lri: + break lr_items.append(lri) lastlri = lri i += 1 p.lr_items = lr_items -# ----------------------------------------------------------------------------- -# == Class LRTable == -# -# This basic class represents a basic table of LR parsing information. -# Methods for generating the tables are not defined here. They are defined -# in the derived class LRGeneratedTable. -# ----------------------------------------------------------------------------- - -class VersionError(YaccError): pass - -class LRTable(object): - def __init__(self): - self.lr_action = None - self.lr_goto = None - self.lr_productions = None - self.lr_method = None - - def read_table(self,module): - if isinstance(module,types.ModuleType): - parsetab = module - else: - if sys.version_info[0] < 3: - exec("import %s as parsetab" % module) - else: - env = { } - exec("import %s as parsetab" % module, env, env) - parsetab = env['parsetab'] - - if parsetab._tabversion != __tabversion__: - raise VersionError("yacc table file version is out of date") - - self.lr_action = parsetab._lr_action - self.lr_goto = parsetab._lr_goto - - self.lr_productions = [] - for p in parsetab._lr_productions: - self.lr_productions.append(MiniProduction(*p)) - - self.lr_method = parsetab._lr_method - return parsetab._lr_signature - - def read_pickle(self,filename): - try: - import cPickle as pickle - except ImportError: - import pickle - - in_f = open(filename,"rb") - - tabversion = pickle.load(in_f) - if tabversion != __tabversion__: - raise VersionError("yacc table file version is out of date") - self.lr_method = pickle.load(in_f) - signature = pickle.load(in_f) - self.lr_action = pickle.load(in_f) - self.lr_goto = pickle.load(in_f) - productions = pickle.load(in_f) - - self.lr_productions = [] - for p in productions: - self.lr_productions.append(MiniProduction(*p)) - - in_f.close() - return signature - - # Bind all production function names to callable objects in pdict - def bind_callables(self,pdict): - for p in self.lr_productions: - p.bind(pdict) - # ----------------------------------------------------------------------------- # === LR Generator === # -# The following classes and functions are used to generate LR parsing tables on +# The following classes and functions are used to generate LR parsing tables on # a grammar. # ----------------------------------------------------------------------------- @@ -1895,17 +1263,18 @@ class LRTable(object): # FP - Set-valued function # ------------------------------------------------------------------------------ -def digraph(X,R,FP): - N = { } +def digraph(X, R, FP): + N = {} for x in X: - N[x] = 0 + N[x] = 0 stack = [] - F = { } + F = {} for x in X: - if N[x] == 0: traverse(x,N,stack,F,X,R,FP) + if N[x] == 0: + traverse(x, N, stack, F, X, R, FP) return F -def traverse(x,N,stack,F,X,R,FP): +def traverse(x, N, stack, F, X, R, FP): stack.append(x) d = len(stack) N[x] = d @@ -1914,35 +1283,34 @@ def traverse(x,N,stack,F,X,R,FP): rel = R(x) # Get y's related to x for y in rel: if N[y] == 0: - traverse(y,N,stack,F,X,R,FP) - N[x] = min(N[x],N[y]) - for a in F.get(y,[]): - if a not in F[x]: F[x].append(a) + traverse(y, N, stack, F, X, R, FP) + N[x] = min(N[x], N[y]) + for a in F.get(y, []): + if a not in F[x]: + F[x].append(a) if N[x] == d: - N[stack[-1]] = MAXINT - F[stack[-1]] = F[x] - element = stack.pop() - while element != x: - N[stack[-1]] = MAXINT - F[stack[-1]] = F[x] - element = stack.pop() + N[stack[-1]] = MAXINT + F[stack[-1]] = F[x] + element = stack.pop() + while element != x: + N[stack[-1]] = MAXINT + F[stack[-1]] = F[x] + element = stack.pop() + +class LALRError(YaccError): + pass -class LALRError(YaccError): pass # ----------------------------------------------------------------------------- -# == LRGeneratedTable == +# == LRTable == # # This class implements the LR table generation algorithm. There are no -# public methods except for write() +# public methods. # ----------------------------------------------------------------------------- -class LRGeneratedTable(LRTable): - def __init__(self,grammar,method='LALR',log=None): - if method not in ['SLR','LALR']: - raise LALRError("Unsupported method %s" % method) - +class LRTable: + def __init__(self, grammar, log=None): self.grammar = grammar - self.lr_method = method # Set up the logger if not log: @@ -1958,7 +1326,7 @@ class LRGeneratedTable(LRTable): self._add_count = 0 # Internal counter used to detect cycles - # Diagonistic information filled in by the table generator + # Diagnostic information filled in by the table generator self.sr_conflict = 0 self.rr_conflict = 0 self.conflicts = [] # List of conflicts @@ -1972,23 +1340,29 @@ class LRGeneratedTable(LRTable): self.grammar.compute_follow() self.lr_parse_table() + # Bind all production function names to callable objects in pdict + def bind_callables(self, pdict): + for p in self.lr_productions: + p.bind(pdict) + # Compute the LR(0) closure operation on I, where I is a set of LR(0) items. - def lr0_closure(self,I): + def lr0_closure(self, I): self._add_count += 1 # Add everything in I to J J = I[:] - didadd = 1 + didadd = True while didadd: - didadd = 0 + didadd = False for j in J: for x in j.lr_after: - if getattr(x,"lr0_added",0) == self._add_count: continue + if getattr(x, 'lr0_added', 0) == self._add_count: + continue # Add B --> .G to J J.append(x.lr_next) x.lr0_added = self._add_count - didadd = 1 + didadd = True return J @@ -1999,43 +1373,43 @@ class LRGeneratedTable(LRTable): # objects). With uniqueness, we can later do fast set comparisons using # id(obj) instead of element-wise comparison. - def lr0_goto(self,I,x): + def lr0_goto(self, I, x): # First we look for a previously cached entry - g = self.lr_goto_cache.get((id(I),x),None) - if g: return g + g = self.lr_goto_cache.get((id(I), x)) + if g: + return g # Now we generate the goto set in a way that guarantees uniqueness # of the result - s = self.lr_goto_cache.get(x,None) + s = self.lr_goto_cache.get(x) if not s: - s = { } + s = {} self.lr_goto_cache[x] = s - gs = [ ] + gs = [] for p in I: n = p.lr_next if n and n.lr_before == x: - s1 = s.get(id(n),None) + s1 = s.get(id(n)) if not s1: - s1 = { } + s1 = {} s[id(n)] = s1 gs.append(n) s = s1 - g = s.get('$end',None) + g = s.get('$end') if not g: if gs: g = self.lr0_closure(gs) s['$end'] = g else: s['$end'] = gs - self.lr_goto_cache[(id(I),x)] = g + self.lr_goto_cache[(id(I), x)] = g return g # Compute the LR(0) sets of item function def lr0_items(self): - - C = [ self.lr0_closure([self.grammar.Productions[0].lr_next]) ] + C = [self.lr0_closure([self.grammar.Productions[0].lr_next])] i = 0 for I in C: self.lr0_cidhash[id(I)] = i @@ -2048,15 +1422,15 @@ class LRGeneratedTable(LRTable): i += 1 # Collect all of the symbols that could possibly be in the goto(I,X) sets - asyms = { } + asyms = {} for ii in I: for s in ii.usyms: asyms[s] = None for x in asyms: - g = self.lr0_goto(I,x) - if not g: continue - if id(g) in self.lr0_cidhash: continue + g = self.lr0_goto(I, x) + if not g or id(g) in self.lr0_cidhash: + continue self.lr0_cidhash[id(g)] = len(C) C.append(g) @@ -2091,19 +1465,21 @@ class LRGeneratedTable(LRTable): # ----------------------------------------------------------------------------- def compute_nullable_nonterminals(self): - nullable = {} + nullable = set() num_nullable = 0 - while 1: - for p in self.grammar.Productions[1:]: - if p.len == 0: - nullable[p.name] = 1 + while True: + for p in self.grammar.Productions[1:]: + if p.len == 0: + nullable.add(p.name) continue - for t in p.prod: - if not t in nullable: break - else: - nullable[p.name] = 1 - if len(nullable) == num_nullable: break - num_nullable = len(nullable) + for t in p.prod: + if t not in nullable: + break + else: + nullable.add(p.name) + if len(nullable) == num_nullable: + break + num_nullable = len(nullable) return nullable # ----------------------------------------------------------------------------- @@ -2117,16 +1493,16 @@ class LRGeneratedTable(LRTable): # The input C is the set of LR(0) items. # ----------------------------------------------------------------------------- - def find_nonterminal_transitions(self,C): - trans = [] - for state in range(len(C)): - for p in C[state]: - if p.lr_index < p.len - 1: - t = (state,p.prod[p.lr_index+1]) - if t[1] in self.grammar.Nonterminals: - if t not in trans: trans.append(t) - state = state + 1 - return trans + def find_nonterminal_transitions(self, C): + trans = [] + for stateno, state in enumerate(C): + for p in state: + if p.lr_index < p.len - 1: + t = (stateno, p.prod[p.lr_index+1]) + if t[1] in self.grammar.Nonterminals: + if t not in trans: + trans.append(t) + return trans # ----------------------------------------------------------------------------- # dr_relation() @@ -2137,21 +1513,21 @@ class LRGeneratedTable(LRTable): # Returns a list of terminals. # ----------------------------------------------------------------------------- - def dr_relation(self,C,trans,nullable): - dr_set = { } - state,N = trans + def dr_relation(self, C, trans, nullable): + state, N = trans terms = [] - g = self.lr0_goto(C[state],N) + g = self.lr0_goto(C[state], N) for p in g: - if p.lr_index < p.len - 1: - a = p.prod[p.lr_index+1] - if a in self.grammar.Terminals: - if a not in terms: terms.append(a) + if p.lr_index < p.len - 1: + a = p.prod[p.lr_index+1] + if a in self.grammar.Terminals: + if a not in terms: + terms.append(a) # This extra bit is to handle the start state if state == 0 and N == self.grammar.Productions[0].prod[0]: - terms.append('$end') + terms.append('$end') return terms @@ -2161,18 +1537,18 @@ class LRGeneratedTable(LRTable): # Computes the READS() relation (p,A) READS (t,C). # ----------------------------------------------------------------------------- - def reads_relation(self,C, trans, empty): + def reads_relation(self, C, trans, empty): # Look for empty transitions rel = [] state, N = trans - g = self.lr0_goto(C[state],N) - j = self.lr0_cidhash.get(id(g),-1) + g = self.lr0_goto(C[state], N) + j = self.lr0_cidhash.get(id(g), -1) for p in g: if p.lr_index < p.len - 1: - a = p.prod[p.lr_index + 1] - if a in empty: - rel.append((j,a)) + a = p.prod[p.lr_index + 1] + if a in empty: + rel.append((j, a)) return rel @@ -2204,8 +1580,7 @@ class LRGeneratedTable(LRTable): # # ----------------------------------------------------------------------------- - def compute_lookback_includes(self,C,trans,nullable): - + def compute_lookback_includes(self, C, trans, nullable): lookdict = {} # Dictionary of lookback relations includedict = {} # Dictionary of include relations @@ -2215,11 +1590,12 @@ class LRGeneratedTable(LRTable): dtrans[t] = 1 # Loop over all transitions and compute lookbacks and includes - for state,N in trans: + for state, N in trans: lookb = [] includes = [] for p in C[state]: - if p.name != N: continue + if p.name != N: + continue # Okay, we have a name match. We now follow the production all the way # through the state machine until we get the . on the right hand side @@ -2227,44 +1603,50 @@ class LRGeneratedTable(LRTable): lr_index = p.lr_index j = state while lr_index < p.len - 1: - lr_index = lr_index + 1 - t = p.prod[lr_index] - - # Check to see if this symbol and state are a non-terminal transition - if (j,t) in dtrans: - # Yes. Okay, there is some chance that this is an includes relation - # the only way to know for certain is whether the rest of the - # production derives empty - - li = lr_index + 1 - while li < p.len: - if p.prod[li] in self.grammar.Terminals: break # No forget it - if not p.prod[li] in nullable: break - li = li + 1 - else: - # Appears to be a relation between (j,t) and (state,N) - includes.append((j,t)) - - g = self.lr0_goto(C[j],t) # Go to next set - j = self.lr0_cidhash.get(id(g),-1) # Go to next state + lr_index = lr_index + 1 + t = p.prod[lr_index] + + # Check to see if this symbol and state are a non-terminal transition + if (j, t) in dtrans: + # Yes. Okay, there is some chance that this is an includes relation + # the only way to know for certain is whether the rest of the + # production derives empty + + li = lr_index + 1 + while li < p.len: + if p.prod[li] in self.grammar.Terminals: + break # No forget it + if p.prod[li] not in nullable: + break + li = li + 1 + else: + # Appears to be a relation between (j,t) and (state,N) + includes.append((j, t)) + + g = self.lr0_goto(C[j], t) # Go to next set + j = self.lr0_cidhash.get(id(g), -1) # Go to next state # When we get here, j is the final state, now we have to locate the production for r in C[j]: - if r.name != p.name: continue - if r.len != p.len: continue - i = 0 - # This look is comparing a production ". A B C" with "A B C ." - while i < r.lr_index: - if r.prod[i] != p.prod[i+1]: break - i = i + 1 - else: - lookb.append((j,r)) + if r.name != p.name: + continue + if r.len != p.len: + continue + i = 0 + # This look is comparing a production ". A B C" with "A B C ." + while i < r.lr_index: + if r.prod[i] != p.prod[i+1]: + break + i = i + 1 + else: + lookb.append((j, r)) for i in includes: - if not i in includedict: includedict[i] = [] - includedict[i].append((state,N)) - lookdict[(state,N)] = lookb + if i not in includedict: + includedict[i] = [] + includedict[i].append((state, N)) + lookdict[(state, N)] = lookb - return lookdict,includedict + return lookdict, includedict # ----------------------------------------------------------------------------- # compute_read_sets() @@ -2278,10 +1660,10 @@ class LRGeneratedTable(LRTable): # Returns a set containing the read sets # ----------------------------------------------------------------------------- - def compute_read_sets(self,C, ntrans, nullable): - FP = lambda x: self.dr_relation(C,x,nullable) - R = lambda x: self.reads_relation(C,x,nullable) - F = digraph(ntrans,R,FP) + def compute_read_sets(self, C, ntrans, nullable): + FP = lambda x: self.dr_relation(C, x, nullable) + R = lambda x: self.reads_relation(C, x, nullable) + F = digraph(ntrans, R, FP) return F # ----------------------------------------------------------------------------- @@ -2300,11 +1682,11 @@ class LRGeneratedTable(LRTable): # Returns a set containing the follow sets # ----------------------------------------------------------------------------- - def compute_follow_sets(self,ntrans,readsets,inclsets): - FP = lambda x: readsets[x] - R = lambda x: inclsets.get(x,[]) - F = digraph(ntrans,R,FP) - return F + def compute_follow_sets(self, ntrans, readsets, inclsets): + FP = lambda x: readsets[x] + R = lambda x: inclsets.get(x, []) + F = digraph(ntrans, R, FP) + return F # ----------------------------------------------------------------------------- # add_lookaheads() @@ -2318,15 +1700,16 @@ class LRGeneratedTable(LRTable): # in the lookbacks set # ----------------------------------------------------------------------------- - def add_lookaheads(self,lookbacks,followset): - for trans,lb in lookbacks.items(): + def add_lookaheads(self, lookbacks, followset): + for trans, lb in lookbacks.items(): # Loop over productions in lookback - for state,p in lb: - if not state in p.lookaheads: - p.lookaheads[state] = [] - f = followset.get(trans,[]) - for a in f: - if a not in p.lookaheads[state]: p.lookaheads[state].append(a) + for state, p in lb: + if state not in p.lookaheads: + p.lookaheads[state] = [] + f = followset.get(trans, []) + for a in f: + if a not in p.lookaheads[state]: + p.lookaheads[state].append(a) # ----------------------------------------------------------------------------- # add_lalr_lookaheads() @@ -2335,7 +1718,7 @@ class LRGeneratedTable(LRTable): # with LALR parsing # ----------------------------------------------------------------------------- - def add_lalr_lookaheads(self,C): + def add_lalr_lookaheads(self, C): # Determine all of the nullable nonterminals nullable = self.compute_nullable_nonterminals() @@ -2343,16 +1726,16 @@ class LRGeneratedTable(LRTable): trans = self.find_nonterminal_transitions(C) # Compute read sets - readsets = self.compute_read_sets(C,trans,nullable) + readsets = self.compute_read_sets(C, trans, nullable) # Compute lookback/includes relations - lookd, included = self.compute_lookback_includes(C,trans,nullable) + lookd, included = self.compute_lookback_includes(C, trans, nullable) # Compute LALR FOLLOW sets - followsets = self.compute_follow_sets(trans,readsets,included) + followsets = self.compute_follow_sets(trans, readsets, included) # Add all of the lookaheads - self.add_lookaheads(lookd,followsets) + self.add_lookaheads(lookd, followsets) # ----------------------------------------------------------------------------- # lr_parse_table() @@ -2366,324 +1749,179 @@ class LRGeneratedTable(LRTable): action = self.lr_action # Action array log = self.log # Logger for output - actionp = { } # Action production array (temporary) - - log.info("Parsing method: %s", self.lr_method) + actionp = {} # Action production array (temporary) # Step 1: Construct C = { I0, I1, ... IN}, collection of LR(0) items # This determines the number of states C = self.lr0_items() - - if self.lr_method == 'LALR': - self.add_lalr_lookaheads(C) + self.add_lalr_lookaheads(C) # Build the parser table, state by state st = 0 for I in C: # Loop over each production in I - actlist = [ ] # List of actions - st_action = { } - st_actionp = { } - st_goto = { } - log.info("") - log.info("state %d", st) - log.info("") + actlist = [] # List of actions + st_action = {} + st_actionp = {} + st_goto = {} + log.info('') + log.info('state %d', st) + log.info('') for p in I: - log.info(" (%d) %s", p.number, str(p)) - log.info("") + log.info(' (%d) %s', p.number, p) + log.info('') for p in I: - if p.len == p.lr_index + 1: - if p.name == "S'": - # Start symbol. Accept! - st_action["$end"] = 0 - st_actionp["$end"] = p - else: - # We are at the end of a production. Reduce! - if self.lr_method == 'LALR': - laheads = p.lookaheads[st] - else: - laheads = self.grammar.Follow[p.name] - for a in laheads: - actlist.append((a,p,"reduce using rule %d (%s)" % (p.number,p))) - r = st_action.get(a,None) - if r is not None: - # Whoa. Have a shift/reduce or reduce/reduce conflict - if r > 0: - # Need to decide on shift or reduce here - # By default we favor shifting. Need to add - # some precedence rules here. - sprec,slevel = Productions[st_actionp[a].number].prec - rprec,rlevel = Precedence.get(a,('right',0)) - if (slevel < rlevel) or ((slevel == rlevel) and (rprec == 'left')): - # We really need to reduce here. - st_action[a] = -p.number - st_actionp[a] = p - if not slevel and not rlevel: - log.info(" ! shift/reduce conflict for %s resolved as reduce",a) - self.sr_conflicts.append((st,a,'reduce')) - Productions[p.number].reduced += 1 - elif (slevel == rlevel) and (rprec == 'nonassoc'): - st_action[a] = None - else: - # Hmmm. Guess we'll keep the shift - if not rlevel: - log.info(" ! shift/reduce conflict for %s resolved as shift",a) - self.sr_conflicts.append((st,a,'shift')) - elif r < 0: - # Reduce/reduce conflict. In this case, we favor the rule - # that was defined first in the grammar file - oldp = Productions[-r] - pp = Productions[p.number] - if oldp.line > pp.line: - st_action[a] = -p.number - st_actionp[a] = p - chosenp,rejectp = pp,oldp - Productions[p.number].reduced += 1 - Productions[oldp.number].reduced -= 1 - else: - chosenp,rejectp = oldp,pp - self.rr_conflicts.append((st,chosenp,rejectp)) - log.info(" ! reduce/reduce conflict for %s resolved using rule %d (%s)", a,st_actionp[a].number, st_actionp[a]) + if p.len == p.lr_index + 1: + if p.name == "S'": + # Start symbol. Accept! + st_action['$end'] = 0 + st_actionp['$end'] = p + else: + # We are at the end of a production. Reduce! + laheads = p.lookaheads[st] + for a in laheads: + actlist.append((a, p, 'reduce using rule %d (%s)' % (p.number, p))) + r = st_action.get(a) + if r is not None: + # Whoa. Have a shift/reduce or reduce/reduce conflict + if r > 0: + # Need to decide on shift or reduce here + # By default we favor shifting. Need to add + # some precedence rules here. + + # Shift precedence comes from the token + sprec, slevel = Precedence.get(a, ('right', 0)) + + # Reduce precedence comes from rule being reduced (p) + rprec, rlevel = Productions[p.number].prec + + if (slevel < rlevel) or ((slevel == rlevel) and (rprec == 'left')): + # We really need to reduce here. + st_action[a] = -p.number + st_actionp[a] = p + if not slevel and not rlevel: + log.info(' ! shift/reduce conflict for %s resolved as reduce', a) + self.sr_conflicts.append((st, a, 'reduce')) + Productions[p.number].reduced += 1 + elif (slevel == rlevel) and (rprec == 'nonassoc'): + st_action[a] = None + else: + # Hmmm. Guess we'll keep the shift + if not rlevel: + log.info(' ! shift/reduce conflict for %s resolved as shift', a) + self.sr_conflicts.append((st, a, 'shift')) + elif r < 0: + # Reduce/reduce conflict. In this case, we favor the rule + # that was defined first in the grammar file + oldp = Productions[-r] + pp = Productions[p.number] + if oldp.line > pp.line: + st_action[a] = -p.number + st_actionp[a] = p + chosenp, rejectp = pp, oldp + Productions[p.number].reduced += 1 + Productions[oldp.number].reduced -= 1 else: - raise LALRError("Unknown conflict in state %d" % st) + chosenp, rejectp = oldp, pp + self.rr_conflicts.append((st, chosenp, rejectp)) + log.info(' ! reduce/reduce conflict for %s resolved using rule %d (%s)', + a, st_actionp[a].number, st_actionp[a]) else: - st_action[a] = -p.number - st_actionp[a] = p - Productions[p.number].reduced += 1 - else: - i = p.lr_index - a = p.prod[i+1] # Get symbol right after the "." - if a in self.grammar.Terminals: - g = self.lr0_goto(I,a) - j = self.lr0_cidhash.get(id(g),-1) - if j >= 0: - # We are in a shift state - actlist.append((a,p,"shift and go to state %d" % j)) - r = st_action.get(a,None) - if r is not None: - # Whoa have a shift/reduce or shift/shift conflict - if r > 0: - if r != j: - raise LALRError("Shift/shift conflict in state %d" % st) - elif r < 0: - # Do a precedence check. - # - if precedence of reduce rule is higher, we reduce. - # - if precedence of reduce is same and left assoc, we reduce. - # - otherwise we shift - rprec,rlevel = Productions[st_actionp[a].number].prec - sprec,slevel = Precedence.get(a,('right',0)) - if (slevel > rlevel) or ((slevel == rlevel) and (rprec == 'right')): - # We decide to shift here... highest precedence to shift - Productions[st_actionp[a].number].reduced -= 1 - st_action[a] = j - st_actionp[a] = p - if not rlevel: - log.info(" ! shift/reduce conflict for %s resolved as shift",a) - self.sr_conflicts.append((st,a,'shift')) - elif (slevel == rlevel) and (rprec == 'nonassoc'): - st_action[a] = None - else: - # Hmmm. Guess we'll keep the reduce - if not slevel and not rlevel: - log.info(" ! shift/reduce conflict for %s resolved as reduce",a) - self.sr_conflicts.append((st,a,'reduce')) - + raise LALRError('Unknown conflict in state %d' % st) + else: + st_action[a] = -p.number + st_actionp[a] = p + Productions[p.number].reduced += 1 + else: + i = p.lr_index + a = p.prod[i+1] # Get symbol right after the "." + if a in self.grammar.Terminals: + g = self.lr0_goto(I, a) + j = self.lr0_cidhash.get(id(g), -1) + if j >= 0: + # We are in a shift state + actlist.append((a, p, 'shift and go to state %d' % j)) + r = st_action.get(a) + if r is not None: + # Whoa have a shift/reduce or shift/shift conflict + if r > 0: + if r != j: + raise LALRError('Shift/shift conflict in state %d' % st) + elif r < 0: + # Do a precedence check. + # - if precedence of reduce rule is higher, we reduce. + # - if precedence of reduce is same and left assoc, we reduce. + # - otherwise we shift + + # Shift precedence comes from the token + sprec, slevel = Precedence.get(a, ('right', 0)) + + # Reduce precedence comes from the rule that could have been reduced + rprec, rlevel = Productions[st_actionp[a].number].prec + + if (slevel > rlevel) or ((slevel == rlevel) and (rprec == 'right')): + # We decide to shift here... highest precedence to shift + Productions[st_actionp[a].number].reduced -= 1 + st_action[a] = j + st_actionp[a] = p + if not rlevel: + log.info(' ! shift/reduce conflict for %s resolved as shift', a) + self.sr_conflicts.append((st, a, 'shift')) + elif (slevel == rlevel) and (rprec == 'nonassoc'): + st_action[a] = None else: - raise LALRError("Unknown conflict in state %d" % st) + # Hmmm. Guess we'll keep the reduce + if not slevel and not rlevel: + log.info(' ! shift/reduce conflict for %s resolved as reduce', a) + self.sr_conflicts.append((st, a, 'reduce')) + else: - st_action[a] = j - st_actionp[a] = p + raise LALRError('Unknown conflict in state %d' % st) + else: + st_action[a] = j + st_actionp[a] = p # Print the actions associated with each terminal - _actprint = { } - for a,p,m in actlist: + _actprint = {} + for a, p, m in actlist: if a in st_action: if p is st_actionp[a]: - log.info(" %-15s %s",a,m) - _actprint[(a,m)] = 1 - log.info("") + log.info(' %-15s %s', a, m) + _actprint[(a, m)] = 1 + log.info('') # Print the actions that were not used. (debugging) not_used = 0 - for a,p,m in actlist: + for a, p, m in actlist: if a in st_action: if p is not st_actionp[a]: - if not (a,m) in _actprint: - log.debug(" ! %-15s [ %s ]",a,m) + if not (a, m) in _actprint: + log.debug(' ! %-15s [ %s ]', a, m) not_used = 1 - _actprint[(a,m)] = 1 + _actprint[(a, m)] = 1 if not_used: - log.debug("") + log.debug('') # Construct the goto table for this state - nkeys = { } + nkeys = {} for ii in I: for s in ii.usyms: if s in self.grammar.Nonterminals: nkeys[s] = None for n in nkeys: - g = self.lr0_goto(I,n) - j = self.lr0_cidhash.get(id(g),-1) + g = self.lr0_goto(I, n) + j = self.lr0_cidhash.get(id(g), -1) if j >= 0: st_goto[n] = j - log.info(" %-30s shift and go to state %d",n,j) + log.info(' %-30s shift and go to state %d', n, j) action[st] = st_action actionp[st] = st_actionp goto[st] = st_goto st += 1 - - # ----------------------------------------------------------------------------- - # write() - # - # This function writes the LR parsing tables to a file - # ----------------------------------------------------------------------------- - - def write_table(self,modulename,outputdir='',signature=""): - basemodulename = modulename.split(".")[-1] - filename = os.path.join(outputdir,basemodulename) + ".py" - try: - f = open(filename,"w") - - f.write(""" -# %s -# This file is automatically generated. Do not edit. -_tabversion = %r - -_lr_method = %r - -_lr_signature = %r - """ % (filename, __tabversion__, self.lr_method, signature)) - - # Change smaller to 0 to go back to original tables - smaller = 1 - - # Factor out names to try and make smaller - if smaller: - items = { } - - for s,nd in self.lr_action.items(): - for name,v in nd.items(): - i = items.get(name) - if not i: - i = ([],[]) - items[name] = i - i[0].append(s) - i[1].append(v) - - f.write("\n_lr_action_items = {") - for k,v in items.items(): - f.write("%r:([" % k) - for i in v[0]: - f.write("%r," % i) - f.write("],[") - for i in v[1]: - f.write("%r," % i) - - f.write("]),") - f.write("}\n") - - f.write(""" -_lr_action = { } -for _k, _v in _lr_action_items.items(): - for _x,_y in zip(_v[0],_v[1]): - if not _x in _lr_action: _lr_action[_x] = { } - _lr_action[_x][_k] = _y -del _lr_action_items -""") - - else: - f.write("\n_lr_action = { "); - for k,v in self.lr_action.items(): - f.write("(%r,%r):%r," % (k[0],k[1],v)) - f.write("}\n"); - - if smaller: - # Factor out names to try and make smaller - items = { } - - for s,nd in self.lr_goto.items(): - for name,v in nd.items(): - i = items.get(name) - if not i: - i = ([],[]) - items[name] = i - i[0].append(s) - i[1].append(v) - - f.write("\n_lr_goto_items = {") - for k,v in items.items(): - f.write("%r:([" % k) - for i in v[0]: - f.write("%r," % i) - f.write("],[") - for i in v[1]: - f.write("%r," % i) - - f.write("]),") - f.write("}\n") - - f.write(""" -_lr_goto = { } -for _k, _v in _lr_goto_items.items(): - for _x,_y in zip(_v[0],_v[1]): - if not _x in _lr_goto: _lr_goto[_x] = { } - _lr_goto[_x][_k] = _y -del _lr_goto_items -""") - else: - f.write("\n_lr_goto = { "); - for k,v in self.lr_goto.items(): - f.write("(%r,%r):%r," % (k[0],k[1],v)) - f.write("}\n"); - - # Write production table - f.write("_lr_productions = [\n") - for p in self.lr_productions: - if p.func: - f.write(" (%r,%r,%d,%r,%r,%d),\n" % (p.str,p.name, p.len, p.func,p.file,p.line)) - else: - f.write(" (%r,%r,%d,None,None,None),\n" % (str(p),p.name, p.len)) - f.write("]\n") - f.close() - - except IOError: - e = sys.exc_info()[1] - sys.stderr.write("Unable to create '%s'\n" % filename) - sys.stderr.write(str(e)+"\n") - return - - - # ----------------------------------------------------------------------------- - # pickle_table() - # - # This function pickles the LR parsing tables to a supplied file object - # ----------------------------------------------------------------------------- - - def pickle_table(self,filename,signature=""): - try: - import cPickle as pickle - except ImportError: - import pickle - outf = open(filename,"wb") - pickle.dump(__tabversion__,outf,pickle_protocol) - pickle.dump(self.lr_method,outf,pickle_protocol) - pickle.dump(signature,outf,pickle_protocol) - pickle.dump(self.lr_action,outf,pickle_protocol) - pickle.dump(self.lr_goto,outf,pickle_protocol) - - outp = [] - for p in self.lr_productions: - if p.func: - outp.append((p.str,p.name, p.len, p.func,p.file,p.line)) - else: - outp.append((str(p),p.name,p.len,None,None,None)) - pickle.dump(outp,outf,pickle_protocol) - outf.close() - # ----------------------------------------------------------------------------- # === INTROSPECTION === # @@ -2700,26 +1938,18 @@ del _lr_goto_items # ----------------------------------------------------------------------------- def get_caller_module_dict(levels): - try: - raise RuntimeError - except RuntimeError: - e,b,t = sys.exc_info() - f = t.tb_frame - while levels > 0: - f = f.f_back - levels -= 1 - ldict = f.f_globals.copy() - if f.f_globals != f.f_locals: - ldict.update(f.f_locals) - - return ldict + f = sys._getframe(levels) + ldict = f.f_globals.copy() + if f.f_globals != f.f_locals: + ldict.update(f.f_locals) + return ldict # ----------------------------------------------------------------------------- # parse_grammar() # # This takes a raw grammar rule string and parses it into production data # ----------------------------------------------------------------------------- -def parse_grammar(doc,file,line): +def parse_grammar(doc, file, line): grammar = [] # Split the doc string into lines pstrings = doc.splitlines() @@ -2728,12 +1958,13 @@ def parse_grammar(doc,file,line): for ps in pstrings: dline += 1 p = ps.split() - if not p: continue + if not p: + continue try: if p[0] == '|': # This is a continuation of a previous rule if not lastp: - raise SyntaxError("%s:%d: Misplaced '|'" % (file,dline)) + raise SyntaxError("%s:%d: Misplaced '|'" % (file, dline)) prodname = lastp syms = p[1:] else: @@ -2742,13 +1973,13 @@ def parse_grammar(doc,file,line): syms = p[2:] assign = p[1] if assign != ':' and assign != '::=': - raise SyntaxError("%s:%d: Syntax error. Expected ':'" % (file,dline)) + raise SyntaxError("%s:%d: Syntax error. Expected ':'" % (file, dline)) - grammar.append((file,dline,prodname,syms)) + grammar.append((file, dline, prodname, syms)) except SyntaxError: raise except Exception: - raise SyntaxError("%s:%d: Syntax error in rule '%s'" % (file,dline,ps.strip())) + raise SyntaxError('%s:%d: Syntax error in rule %r' % (file, dline, ps.strip())) return grammar @@ -2760,14 +1991,14 @@ def parse_grammar(doc,file,line): # etc. # ----------------------------------------------------------------------------- class ParserReflect(object): - def __init__(self,pdict,log=None): + def __init__(self, pdict, log=None): self.pdict = pdict self.start = None self.error_func = None self.tokens = None - self.files = {} + self.modules = set() self.grammar = [] - self.error = 0 + self.error = False if log is None: self.log = PlyLogger(sys.stderr) @@ -2781,7 +2012,7 @@ class ParserReflect(object): self.get_tokens() self.get_precedence() self.get_pfunctions() - + # Validate all of the information def validate_all(self): self.validate_start() @@ -2789,32 +2020,28 @@ class ParserReflect(object): self.validate_tokens() self.validate_precedence() self.validate_pfunctions() - self.validate_files() + self.validate_modules() return self.error # Compute a signature over the grammar def signature(self): + parts = [] try: - from hashlib import md5 - except ImportError: - from md5 import md5 - try: - sig = md5() if self.start: - sig.update(self.start.encode('latin-1')) + parts.append(self.start) if self.prec: - sig.update("".join(["".join(p) for p in self.prec]).encode('latin-1')) + parts.append(''.join([''.join(p) for p in self.prec])) if self.tokens: - sig.update(" ".join(self.tokens).encode('latin-1')) + parts.append(' '.join(self.tokens)) for f in self.pfuncs: if f[3]: - sig.update(f[3].encode('latin-1')) - except (TypeError,ValueError): + parts.append(f[3]) + except (TypeError, ValueError): pass - return sig.digest() + return ''.join(parts) # ----------------------------------------------------------------------------- - # validate_file() + # validate_modules() # # This method checks to see if there are duplicated p_rulename() functions # in the parser module file. Without this function, it is really easy for @@ -2824,32 +2051,29 @@ class ParserReflect(object): # to try and detect duplicates. # ----------------------------------------------------------------------------- - def validate_files(self): + def validate_modules(self): # Match def p_funcname( fre = re.compile(r'\s*def\s+(p_[a-zA-Z_0-9]*)\(') - for filename in self.files.keys(): - base,ext = os.path.splitext(filename) - if ext != '.py': return 1 # No idea. Assume it's okay. - + for module in self.modules: try: - f = open(filename) - lines = f.readlines() - f.close() + lines, linen = inspect.getsourcelines(module) except IOError: continue - counthash = { } - for linen,l in enumerate(lines): + counthash = {} + for linen, line in enumerate(lines): linen += 1 - m = fre.match(l) + m = fre.match(line) if m: name = m.group(1) prev = counthash.get(name) if not prev: counthash[name] = linen else: - self.log.warning("%s:%d: Function %s redefined. Previously defined on line %d", filename,linen,name,prev) + filename = inspect.getsourcefile(module) + self.log.warning('%s:%d: Function %s redefined. Previously defined on line %d', + filename, linen, name, prev) # Get the start symbol def get_start(self): @@ -2858,7 +2082,7 @@ class ParserReflect(object): # Validate the start symbol def validate_start(self): if self.start is not None: - if not isinstance(self.start,str): + if not isinstance(self.start, str): self.log.error("'start' must be a string") # Look for error handler @@ -2868,162 +2092,173 @@ class ParserReflect(object): # Validate the error function def validate_error_func(self): if self.error_func: - if isinstance(self.error_func,types.FunctionType): + if isinstance(self.error_func, types.FunctionType): ismethod = 0 elif isinstance(self.error_func, types.MethodType): ismethod = 1 else: self.log.error("'p_error' defined, but is not a function or method") - self.error = 1 + self.error = True return - eline = func_code(self.error_func).co_firstlineno - efile = func_code(self.error_func).co_filename - self.files[efile] = 1 + eline = self.error_func.__code__.co_firstlineno + efile = self.error_func.__code__.co_filename + module = inspect.getmodule(self.error_func) + self.modules.add(module) - if (func_code(self.error_func).co_argcount != 1+ismethod): - self.log.error("%s:%d: p_error() requires 1 argument",efile,eline) - self.error = 1 + argcount = self.error_func.__code__.co_argcount - ismethod + if argcount != 1: + self.log.error('%s:%d: p_error() requires 1 argument', efile, eline) + self.error = True # Get the tokens map def get_tokens(self): - tokens = self.pdict.get("tokens",None) + tokens = self.pdict.get('tokens') if not tokens: - self.log.error("No token list is defined") - self.error = 1 + self.log.error('No token list is defined') + self.error = True return - if not isinstance(tokens,(list, tuple)): - self.log.error("tokens must be a list or tuple") - self.error = 1 + if not isinstance(tokens, (list, tuple)): + self.log.error('tokens must be a list or tuple') + self.error = True return - + if not tokens: - self.log.error("tokens is empty") - self.error = 1 + self.log.error('tokens is empty') + self.error = True return - self.tokens = tokens + self.tokens = sorted(tokens) # Validate the tokens def validate_tokens(self): # Validate the tokens. if 'error' in self.tokens: self.log.error("Illegal token name 'error'. Is a reserved word") - self.error = 1 + self.error = True return - terminals = {} + terminals = set() for n in self.tokens: if n in terminals: - self.log.warning("Token '%s' multiply defined", n) - terminals[n] = 1 + self.log.warning('Token %r multiply defined', n) + terminals.add(n) # Get the precedence map (if any) def get_precedence(self): - self.prec = self.pdict.get("precedence",None) + self.prec = self.pdict.get('precedence') # Validate and parse the precedence map def validate_precedence(self): preclist = [] if self.prec: - if not isinstance(self.prec,(list,tuple)): - self.log.error("precedence must be a list or tuple") - self.error = 1 + if not isinstance(self.prec, (list, tuple)): + self.log.error('precedence must be a list or tuple') + self.error = True return - for level,p in enumerate(self.prec): - if not isinstance(p,(list,tuple)): - self.log.error("Bad precedence table") - self.error = 1 + for level, p in enumerate(self.prec): + if not isinstance(p, (list, tuple)): + self.log.error('Bad precedence table') + self.error = True return if len(p) < 2: - self.log.error("Malformed precedence entry %s. Must be (assoc, term, ..., term)",p) - self.error = 1 + self.log.error('Malformed precedence entry %s. Must be (assoc, term, ..., term)', p) + self.error = True return assoc = p[0] - if not isinstance(assoc,str): - self.log.error("precedence associativity must be a string") - self.error = 1 + if not isinstance(assoc, str): + self.log.error('precedence associativity must be a string') + self.error = True return for term in p[1:]: - if not isinstance(term,str): - self.log.error("precedence items must be strings") - self.error = 1 + if not isinstance(term, str): + self.log.error('precedence items must be strings') + self.error = True return - preclist.append((term,assoc,level+1)) + preclist.append((term, assoc, level+1)) self.preclist = preclist # Get all p_functions from the grammar def get_pfunctions(self): p_functions = [] for name, item in self.pdict.items(): - if name[:2] != 'p_': continue - if name == 'p_error': continue - if isinstance(item,(types.FunctionType,types.MethodType)): - line = func_code(item).co_firstlineno - file = func_code(item).co_filename - p_functions.append((line,file,name,item.__doc__)) - - # Sort all of the actions by line number - p_functions.sort() + if not name.startswith('p_') or name == 'p_error': + continue + if isinstance(item, (types.FunctionType, types.MethodType)): + line = getattr(item, 'co_firstlineno', item.__code__.co_firstlineno) + module = inspect.getmodule(item) + p_functions.append((line, module, name, item.__doc__)) + + # Sort all of the actions by line number; make sure to stringify + # modules to make them sortable, since `line` may not uniquely sort all + # p functions + p_functions.sort(key=lambda p_function: ( + p_function[0], + str(p_function[1]), + p_function[2], + p_function[3])) self.pfuncs = p_functions - # Validate all of the p_functions def validate_pfunctions(self): grammar = [] # Check for non-empty symbols if len(self.pfuncs) == 0: - self.log.error("no rules of the form p_rulename are defined") - self.error = 1 - return - - for line, file, name, doc in self.pfuncs: + self.log.error('no rules of the form p_rulename are defined') + self.error = True + return + + for line, module, name, doc in self.pfuncs: + file = inspect.getsourcefile(module) func = self.pdict[name] if isinstance(func, types.MethodType): reqargs = 2 else: reqargs = 1 - if func_code(func).co_argcount > reqargs: - self.log.error("%s:%d: Rule '%s' has too many arguments",file,line,func.__name__) - self.error = 1 - elif func_code(func).co_argcount < reqargs: - self.log.error("%s:%d: Rule '%s' requires an argument",file,line,func.__name__) - self.error = 1 + if func.__code__.co_argcount > reqargs: + self.log.error('%s:%d: Rule %r has too many arguments', file, line, func.__name__) + self.error = True + elif func.__code__.co_argcount < reqargs: + self.log.error('%s:%d: Rule %r requires an argument', file, line, func.__name__) + self.error = True elif not func.__doc__: - self.log.warning("%s:%d: No documentation string specified in function '%s' (ignored)",file,line,func.__name__) + self.log.warning('%s:%d: No documentation string specified in function %r (ignored)', + file, line, func.__name__) else: try: - parsed_g = parse_grammar(doc,file,line) + parsed_g = parse_grammar(doc, file, line) for g in parsed_g: grammar.append((name, g)) - except SyntaxError: - e = sys.exc_info()[1] + except SyntaxError as e: self.log.error(str(e)) - self.error = 1 + self.error = True # Looks like a valid grammar rule # Mark the file in which defined. - self.files[file] = 1 + self.modules.add(module) # Secondary validation step that looks for p_ definitions that are not functions # or functions that look like they might be grammar rules. - for n,v in self.pdict.items(): - if n[0:2] == 'p_' and isinstance(v, (types.FunctionType, types.MethodType)): continue - if n[0:2] == 't_': continue - if n[0:2] == 'p_' and n != 'p_error': - self.log.warning("'%s' not defined as a function", n) - if ((isinstance(v,types.FunctionType) and func_code(v).co_argcount == 1) or - (isinstance(v,types.MethodType) and func_code(v).co_argcount == 2)): - try: - doc = v.__doc__.split(" ") - if doc[1] == ':': - self.log.warning("%s:%d: Possible grammar rule '%s' defined without p_ prefix", - func_code(v).co_filename, func_code(v).co_firstlineno,n) - except Exception: - pass + for n, v in self.pdict.items(): + if n.startswith('p_') and isinstance(v, (types.FunctionType, types.MethodType)): + continue + if n.startswith('t_'): + continue + if n.startswith('p_') and n != 'p_error': + self.log.warning('%r not defined as a function', n) + if ((isinstance(v, types.FunctionType) and v.__code__.co_argcount == 1) or + (isinstance(v, types.MethodType) and v.__func__.__code__.co_argcount == 2)): + if v.__doc__: + try: + doc = v.__doc__.split(' ') + if doc[1] == ':': + self.log.warning('%s:%d: Possible grammar rule %r defined without p_ prefix', + v.__code__.co_filename, v.__code__.co_firstlineno, n) + except IndexError: + pass self.grammar = grammar @@ -3033,76 +2268,61 @@ class ParserReflect(object): # Build a parser # ----------------------------------------------------------------------------- -def yacc(method='LALR', debug=yaccdebug, module=None, tabmodule=tab_module, start=None, - check_recursion=1, optimize=0, write_tables=1, debugfile=debug_file,outputdir='', - debuglog=None, errorlog = None, picklefile=None): - - global parse # Reference to the parsing method of the last built parser +def yacc(*, debug=yaccdebug, module=None, start=None, + check_recursion=True, optimize=False, debugfile=debug_file, + debuglog=None, errorlog=None): - # If pickling is enabled, table files are not created - - if picklefile: - write_tables = 0 + # Reference to the parsing method of the last built parser + global parse if errorlog is None: errorlog = PlyLogger(sys.stderr) # Get the module dictionary used for the parser if module: - _items = [(k,getattr(module,k)) for k in dir(module)] + _items = [(k, getattr(module, k)) for k in dir(module)] pdict = dict(_items) + # If no __file__ or __package__ attributes are available, try to obtain them + # from the __module__ instead + if '__file__' not in pdict: + pdict['__file__'] = sys.modules[pdict['__module__']].__file__ + if '__package__' not in pdict and '__module__' in pdict: + if hasattr(sys.modules[pdict['__module__']], '__package__'): + pdict['__package__'] = sys.modules[pdict['__module__']].__package__ else: pdict = get_caller_module_dict(2) + # Set start symbol if it's specified directly using an argument + if start is not None: + pdict['start'] = start + # Collect parser information from the dictionary - pinfo = ParserReflect(pdict,log=errorlog) + pinfo = ParserReflect(pdict, log=errorlog) pinfo.get_all() if pinfo.error: - raise YaccError("Unable to build parser") - - # Check signature against table files (if any) - signature = pinfo.signature() - - # Read the tables - try: - lr = LRTable() - if picklefile: - read_signature = lr.read_pickle(picklefile) - else: - read_signature = lr.read_table(tabmodule) - if optimize or (read_signature == signature): - try: - lr.bind_callables(pinfo.pdict) - parser = LRParser(lr,pinfo.error_func) - parse = parser.parse - return parser - except Exception: - e = sys.exc_info()[1] - errorlog.warning("There was a problem loading the table file: %s", repr(e)) - except VersionError: - e = sys.exc_info() - errorlog.warning(str(e)) - except Exception: - pass + raise YaccError('Unable to build parser') if debuglog is None: if debug: - debuglog = PlyLogger(open(debugfile,"w")) + try: + debuglog = PlyLogger(open(debugfile, 'w')) + except IOError as e: + errorlog.warning("Couldn't open %r. %s" % (debugfile, e)) + debuglog = NullLogger() else: debuglog = NullLogger() - debuglog.info("Created by PLY version %s (http://www.dabeaz.com/ply)", __version__) + debuglog.info('Created by PLY (http://www.dabeaz.com/ply)') - - errors = 0 + errors = False # Validate the parser information if pinfo.validate_all(): - raise YaccError("Unable to build parser") - + raise YaccError('Unable to build parser') + if not pinfo.error_func: - errorlog.warning("no p_error() function is defined") + errorlog.warning('no p_error() function is defined') # Create a grammar object grammar = Grammar(pinfo.tokens) @@ -3110,20 +2330,18 @@ def yacc(method='LALR', debug=yaccdebug, module=None, tabmodule=tab_module, star # Set precedence level for terminals for term, assoc, level in pinfo.preclist: try: - grammar.set_precedence(term,assoc,level) - except GrammarError: - e = sys.exc_info()[1] - errorlog.warning("%s",str(e)) + grammar.set_precedence(term, assoc, level) + except GrammarError as e: + errorlog.warning('%s', e) # Add productions to the grammar for funcname, gram in pinfo.grammar: file, line, prodname, syms = gram try: - grammar.add_production(prodname,syms,funcname,file,line) - except GrammarError: - e = sys.exc_info()[1] - errorlog.error("%s",str(e)) - errors = 1 + grammar.add_production(prodname, syms, funcname, file, line) + except GrammarError as e: + errorlog.error('%s', e) + errors = True # Set the grammar start symbols try: @@ -3131,146 +2349,134 @@ def yacc(method='LALR', debug=yaccdebug, module=None, tabmodule=tab_module, star grammar.set_start(pinfo.start) else: grammar.set_start(start) - except GrammarError: - e = sys.exc_info()[1] + except GrammarError as e: errorlog.error(str(e)) - errors = 1 + errors = True if errors: - raise YaccError("Unable to build parser") + raise YaccError('Unable to build parser') # Verify the grammar structure undefined_symbols = grammar.undefined_symbols() for sym, prod in undefined_symbols: - errorlog.error("%s:%d: Symbol '%s' used, but not defined as a token or a rule",prod.file,prod.line,sym) - errors = 1 + errorlog.error('%s:%d: Symbol %r used, but not defined as a token or a rule', prod.file, prod.line, sym) + errors = True unused_terminals = grammar.unused_terminals() if unused_terminals: - debuglog.info("") - debuglog.info("Unused terminals:") - debuglog.info("") + debuglog.info('') + debuglog.info('Unused terminals:') + debuglog.info('') for term in unused_terminals: - errorlog.warning("Token '%s' defined, but not used", term) - debuglog.info(" %s", term) + errorlog.warning('Token %r defined, but not used', term) + debuglog.info(' %s', term) # Print out all productions to the debug log if debug: - debuglog.info("") - debuglog.info("Grammar") - debuglog.info("") - for n,p in enumerate(grammar.Productions): - debuglog.info("Rule %-5d %s", n, p) + debuglog.info('') + debuglog.info('Grammar') + debuglog.info('') + for n, p in enumerate(grammar.Productions): + debuglog.info('Rule %-5d %s', n, p) # Find unused non-terminals unused_rules = grammar.unused_rules() for prod in unused_rules: - errorlog.warning("%s:%d: Rule '%s' defined, but not used", prod.file, prod.line, prod.name) + errorlog.warning('%s:%d: Rule %r defined, but not used', prod.file, prod.line, prod.name) if len(unused_terminals) == 1: - errorlog.warning("There is 1 unused token") + errorlog.warning('There is 1 unused token') if len(unused_terminals) > 1: - errorlog.warning("There are %d unused tokens", len(unused_terminals)) + errorlog.warning('There are %d unused tokens', len(unused_terminals)) if len(unused_rules) == 1: - errorlog.warning("There is 1 unused rule") + errorlog.warning('There is 1 unused rule') if len(unused_rules) > 1: - errorlog.warning("There are %d unused rules", len(unused_rules)) + errorlog.warning('There are %d unused rules', len(unused_rules)) if debug: - debuglog.info("") - debuglog.info("Terminals, with rules where they appear") - debuglog.info("") + debuglog.info('') + debuglog.info('Terminals, with rules where they appear') + debuglog.info('') terms = list(grammar.Terminals) terms.sort() for term in terms: - debuglog.info("%-20s : %s", term, " ".join([str(s) for s in grammar.Terminals[term]])) - - debuglog.info("") - debuglog.info("Nonterminals, with rules where they appear") - debuglog.info("") + debuglog.info('%-20s : %s', term, ' '.join([str(s) for s in grammar.Terminals[term]])) + + debuglog.info('') + debuglog.info('Nonterminals, with rules where they appear') + debuglog.info('') nonterms = list(grammar.Nonterminals) nonterms.sort() for nonterm in nonterms: - debuglog.info("%-20s : %s", nonterm, " ".join([str(s) for s in grammar.Nonterminals[nonterm]])) - debuglog.info("") + debuglog.info('%-20s : %s', nonterm, ' '.join([str(s) for s in grammar.Nonterminals[nonterm]])) + debuglog.info('') if check_recursion: unreachable = grammar.find_unreachable() for u in unreachable: - errorlog.warning("Symbol '%s' is unreachable",u) + errorlog.warning('Symbol %r is unreachable', u) infinite = grammar.infinite_cycles() for inf in infinite: - errorlog.error("Infinite recursion detected for symbol '%s'", inf) - errors = 1 - + errorlog.error('Infinite recursion detected for symbol %r', inf) + errors = True + unused_prec = grammar.unused_precedence() for term, assoc in unused_prec: - errorlog.error("Precedence rule '%s' defined for unknown symbol '%s'", assoc, term) - errors = 1 + errorlog.error('Precedence rule %r defined for unknown symbol %r', assoc, term) + errors = True if errors: - raise YaccError("Unable to build parser") - - # Run the LRGeneratedTable on the grammar - if debug: - errorlog.debug("Generating %s tables", method) - - lr = LRGeneratedTable(grammar,method,debuglog) + raise YaccError('Unable to build parser') + + # Run the LRTable on the grammar + lr = LRTable(grammar, debuglog) if debug: num_sr = len(lr.sr_conflicts) # Report shift/reduce and reduce/reduce conflicts if num_sr == 1: - errorlog.warning("1 shift/reduce conflict") + errorlog.warning('1 shift/reduce conflict') elif num_sr > 1: - errorlog.warning("%d shift/reduce conflicts", num_sr) + errorlog.warning('%d shift/reduce conflicts', num_sr) num_rr = len(lr.rr_conflicts) if num_rr == 1: - errorlog.warning("1 reduce/reduce conflict") + errorlog.warning('1 reduce/reduce conflict') elif num_rr > 1: - errorlog.warning("%d reduce/reduce conflicts", num_rr) + errorlog.warning('%d reduce/reduce conflicts', num_rr) # Write out conflicts to the output file if debug and (lr.sr_conflicts or lr.rr_conflicts): - debuglog.warning("") - debuglog.warning("Conflicts:") - debuglog.warning("") + debuglog.warning('') + debuglog.warning('Conflicts:') + debuglog.warning('') for state, tok, resolution in lr.sr_conflicts: - debuglog.warning("shift/reduce conflict for %s in state %d resolved as %s", tok, state, resolution) - - already_reported = {} + debuglog.warning('shift/reduce conflict for %s in state %d resolved as %s', tok, state, resolution) + + already_reported = set() for state, rule, rejected in lr.rr_conflicts: - if (state,id(rule),id(rejected)) in already_reported: + if (state, id(rule), id(rejected)) in already_reported: continue - debuglog.warning("reduce/reduce conflict in state %d resolved using rule (%s)", state, rule) - debuglog.warning("rejected rule (%s) in state %d", rejected,state) - errorlog.warning("reduce/reduce conflict in state %d resolved using rule (%s)", state, rule) - errorlog.warning("rejected rule (%s) in state %d", rejected, state) - already_reported[state,id(rule),id(rejected)] = 1 - + debuglog.warning('reduce/reduce conflict in state %d resolved using rule (%s)', state, rule) + debuglog.warning('rejected rule (%s) in state %d', rejected, state) + errorlog.warning('reduce/reduce conflict in state %d resolved using rule (%s)', state, rule) + errorlog.warning('rejected rule (%s) in state %d', rejected, state) + already_reported.add((state, id(rule), id(rejected))) + warned_never = [] for state, rule, rejected in lr.rr_conflicts: if not rejected.reduced and (rejected not in warned_never): - debuglog.warning("Rule (%s) is never reduced", rejected) - errorlog.warning("Rule (%s) is never reduced", rejected) + debuglog.warning('Rule (%s) is never reduced', rejected) + errorlog.warning('Rule (%s) is never reduced', rejected) warned_never.append(rejected) - # Write the table file if requested - if write_tables: - lr.write_table(tabmodule,outputdir,signature) - - # Write a pickled version of the tables - if picklefile: - lr.pickle_table(picklefile,signature) - # Build the parser lr.bind_callables(pinfo.pdict) - parser = LRParser(lr,pinfo.error_func) + parser = LRParser(lr, pinfo.error_func) parse = parser.parse return parser diff --git a/components/script/dom/bindings/codegen/run.py b/components/script/dom/bindings/codegen/run.py index 130d35e5268..7f58de15d69 100644 --- a/components/script/dom/bindings/codegen/run.py +++ b/components/script/dom/bindings/codegen/run.py @@ -52,7 +52,7 @@ def main(): module = CGBindingRoot(config, prefix, filename).define() if module: with open(os.path.join(out_dir, prefix + ".rs"), "wb") as f: - f.write(module) + f.write(module.encode("utf-8")) def make_dir(path): @@ -66,7 +66,7 @@ def generate(config, name, filename): root = getattr(GlobalGenRoots, name)(config) code = root.define() with open(filename, "wb") as f: - f.write(code) + f.write(code.encode("utf-8")) def add_css_properties_attributes(css_properties_json, parser): -- cgit v1.2.3 From 19be2cd3fa4b8fe2560dda9a62f1c2271f9fb41e Mon Sep 17 00:00:00 2001 From: sagudev Date: Wed, 14 Apr 2021 09:20:58 +0200 Subject: Update mozjs to 88 --- .../script/dom/bindings/codegen/CodegenRust.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 8573998ebb3..c1f79b1362d 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1833,6 +1833,7 @@ class AttrDefiner(PropertyDefiner): "name": m.identifier.name, "attr": m, "flags": "JSPROP_ENUMERATE", + "is_accessor": "true", } for m in descriptor.interface.members if m.isAttr() and m.isStatic() == static @@ -1847,7 +1848,8 @@ class AttrDefiner(PropertyDefiner): self.regular.append({ "name": "@@toStringTag", "attr": None, - "flags": "JSPROP_READONLY | JSPROP_INTERNAL_USE_BIT" + "flags": "JSPROP_READONLY", + "is_accessor": "false", }) def generateArray(self, array, name): @@ -1897,23 +1899,24 @@ class AttrDefiner(PropertyDefiner): def specData(attr): if attr["name"] == "@@toStringTag": - return (attr["name"][2:], attr["flags"], + return (attr["name"][2:], attr["flags"], attr["is_accessor"], str_to_const_array(self.descriptor.interface.getClassName())) flags = attr["flags"] if self.unforgeable: flags += " | JSPROP_PERMANENT" - return (str_to_const_array(attr["attr"].identifier.name), flags, getter(attr), + return (str_to_const_array(attr["attr"].identifier.name), flags, attr["is_accessor"], getter(attr), setter(attr)) def template(m): if m["name"] == "@@toStringTag": return """ JSPropertySpec { name: JSPropertySpec_Name { symbol_: SymbolCode::%s as usize + 1 }, - flags_: (%s) as u8, + attributes_: (%s) as u8, + isAccessor_: (%s), u: JSPropertySpec_AccessorsOrValue { value: JSPropertySpec_ValueWrapper { - type_: JSValueType::JSVAL_TYPE_STRING as _, + type_: JSPropertySpec_ValueWrapper_Type::String, __bindgen_anon_1: JSPropertySpec_ValueWrapper__bindgen_ty_1 { string: %s as *const u8 as *const libc::c_char, } @@ -1923,7 +1926,8 @@ class AttrDefiner(PropertyDefiner): """ return """ JSPropertySpec { name: JSPropertySpec_Name { string_: %s as *const u8 as *const libc::c_char }, - flags_: (%s) as u8, + attributes_: (%s) as u8, + isAccessor_: (%s), u: JSPropertySpec_AccessorsOrValue { accessors: JSPropertySpec_AccessorsOrValue_Accessors { getter: JSPropertySpec_Accessor { @@ -2923,7 +2927,7 @@ let root = raw.reflect_with(obj.get()); let _ac = JSAutoRealm::new(*cx, obj.get()); rooted!(in(*cx) let mut proto = ptr::null_mut::()); GetProtoObject(cx, obj.handle(), proto.handle_mut()); -assert!(JS_SplicePrototype(*cx, obj.handle(), proto.handle())); +assert!(JS_SetPrototype(*cx, obj.handle(), proto.handle())); let mut immutable = false; assert!(JS_SetImmutablePrototype(*cx, obj.handle(), &mut immutable)); assert!(immutable); @@ -6090,13 +6094,13 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::jsapi::JSPROP_ENUMERATE', 'js::jsapi::JSPROP_PERMANENT', 'js::jsapi::JSPROP_READONLY', - 'js::jsapi::JSPROP_INTERNAL_USE_BIT', 'js::jsapi::JSPropertySpec', 'js::jsapi::JSPropertySpec_Accessor', 'js::jsapi::JSPropertySpec_AccessorsOrValue', 'js::jsapi::JSPropertySpec_AccessorsOrValue_Accessors', 'js::jsapi::JSPropertySpec_Name', 'js::jsapi::JSPropertySpec_ValueWrapper', + 'js::jsapi::JSPropertySpec_ValueWrapper_Type', 'js::jsapi::JSPropertySpec_ValueWrapper__bindgen_ty_1', 'js::jsapi::JSString', 'js::jsapi::JSTracer', @@ -6130,7 +6134,6 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::rust::wrappers::JS_SetProperty', 'js::rust::wrappers::JS_SetPrototype', 'js::jsapi::JS_SetReservedSlot', - 'js::rust::wrappers::JS_SplicePrototype', 'js::rust::wrappers::JS_WrapValue', 'js::rust::wrappers::JS_WrapObject', 'js::rust::MutableHandle', -- cgit v1.2.3 From 13095741c577114b203d15910f19488ec3b7d3ed Mon Sep 17 00:00:00 2001 From: sagudev Date: Sat, 17 Apr 2021 17:53:11 +0200 Subject: Fix for bindgen --- components/script/dom/bindings/codegen/CodegenRust.py | 1 + 1 file changed, 1 insertion(+) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index c1f79b1362d..24f62ebe486 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -4111,6 +4111,7 @@ class CGMemberJITInfo(CGThing): protoID: PrototypeList::ID::${name} as u16, }, __bindgen_anon_3: JSJitInfo__bindgen_ty_3 { depth: ${depth} }, + _bitfield_align_1: Default::default(), _bitfield_1: __BindgenBitfieldUnit::new( new_jsjitinfo_bitfield_1!( JSJitInfo_OpType::${opType} as u8, -- cgit v1.2.3 From fd3bbc7ec928b13aff408665b6af7c163db07767 Mon Sep 17 00:00:00 2001 From: sagudev Date: Sat, 17 Apr 2021 18:19:02 +0200 Subject: Fix error --- components/script/dom/bindings/codegen/CodegenRust.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'components/script/dom/bindings/codegen') diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 24f62ebe486..1f7a43ba831 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -4111,7 +4111,7 @@ class CGMemberJITInfo(CGThing): protoID: PrototypeList::ID::${name} as u16, }, __bindgen_anon_3: JSJitInfo__bindgen_ty_3 { depth: ${depth} }, - _bitfield_align_1: Default::default(), + _bitfield_align_1: [], _bitfield_1: __BindgenBitfieldUnit::new( new_jsjitinfo_bitfield_1!( JSJitInfo_OpType::${opType} as u8, -- cgit v1.2.3