diff options
author | Anthony Ramine <n.oxyde@gmail.com> | 2017-06-09 13:57:30 +0200 |
---|---|---|
committer | Anthony Ramine <n.oxyde@gmail.com> | 2017-06-09 13:57:30 +0200 |
commit | e566bc7b1c65e54601f5420bfa071bab9c1b83a3 (patch) | |
tree | 2abe85bfa380bcdc594f83f1898012d33d8147bf /components/script/dom/bindings/codegen/CodegenRust.py | |
parent | 243967298312efa892bed42c421e74f221a99ddd (diff) | |
download | servo-e566bc7b1c65e54601f5420bfa071bab9c1b83a3.tar.gz servo-e566bc7b1c65e54601f5420bfa071bab9c1b83a3.zip |
Update the WebIDL parser
Diffstat (limited to 'components/script/dom/bindings/codegen/CodegenRust.py')
-rw-r--r-- | components/script/dom/bindings/codegen/CodegenRust.py | 175 |
1 files changed, 95 insertions, 80 deletions
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<Promise>") + 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<Promise>") 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 |