aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/script/dom/bindings/codegen/CodegenRust.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/script/dom/bindings/codegen/CodegenRust.py')
-rw-r--r--src/components/script/dom/bindings/codegen/CodegenRust.py5534
1 files changed, 0 insertions, 5534 deletions
diff --git a/src/components/script/dom/bindings/codegen/CodegenRust.py b/src/components/script/dom/bindings/codegen/CodegenRust.py
deleted file mode 100644
index 1666589940e..00000000000
--- a/src/components/script/dom/bindings/codegen/CodegenRust.py
+++ /dev/null
@@ -1,5534 +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 http://mozilla.org/MPL/2.0/.
-
-# Common codegen classes.
-
-import operator
-import os
-import re
-import string
-
-from WebIDL import (
- BuiltinTypes,
- IDLBuiltinType,
- IDLNullValue,
- IDLType,
- IDLUndefinedValue,
-)
-
-from Configuration import getTypesFromDescriptor, getTypesFromDictionary, getTypesFromCallback
-
-AUTOGENERATED_WARNING_COMMENT = \
- "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n"
-ADDPROPERTY_HOOK_NAME = '_addProperty'
-FINALIZE_HOOK_NAME = '_finalize'
-TRACE_HOOK_NAME = '_trace'
-CONSTRUCT_HOOK_NAME = '_constructor'
-HASINSTANCE_HOOK_NAME = '_hasInstance'
-
-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:
- # oldFile = open(filename, 'rb')
- # oldFileContents = ''.join(oldFile.readlines())
- # oldFile.close()
- #except:
- # pass
-
- #if newContents == oldFileContents:
- # return False
-
- f = open(filename, 'wb')
- f.write(newContents)
- f.close()
-
- return True
-
-def toStringBool(arg):
- return str(not not arg).lower()
-
-def toBindingNamespace(arg):
- return re.sub("((_workers)?$)", "Binding\\1", arg);
-
-def stripTrailingWhitespace(text):
- tail = '\n' if text.endswith('\n') else ''
- lines = text.splitlines()
- for i in range(len(lines)):
- lines[i] = lines[i].rstrip()
- return '\n'.join(lines) + tail
-
-def MakeNativeName(name):
- return name[0].upper() + name[1:]
-
-builtinNames = {
- IDLType.Tags.bool: 'bool',
- IDLType.Tags.int8: 'i8',
- IDLType.Tags.int16: 'i16',
- IDLType.Tags.int32: 'i32',
- IDLType.Tags.int64: 'i64',
- IDLType.Tags.uint8: 'u8',
- IDLType.Tags.uint16: 'u16',
- IDLType.Tags.uint32: 'u32',
- IDLType.Tags.uint64: 'u64',
- IDLType.Tags.float: 'f32',
- IDLType.Tags.double: 'f64'
-}
-
-numericTags = [
- IDLType.Tags.int8, IDLType.Tags.uint8,
- IDLType.Tags.int16, IDLType.Tags.uint16,
- IDLType.Tags.int32, IDLType.Tags.uint32,
- IDLType.Tags.int64, IDLType.Tags.uint64,
- IDLType.Tags.float, IDLType.Tags.double
- ]
-
-class CastableObjectUnwrapper():
- """
- A class for unwrapping an object named by the "source" argument
- based on the passed-in descriptor. Stringifies to a Rust expression of
- the appropriate type.
-
- codeOnFailure is the code to run if unwrapping fails.
- """
- def __init__(self, descriptor, source, codeOnFailure):
- self.substitution = {
- "type": descriptor.nativeType,
- "depth": descriptor.interface.inheritanceDepth(),
- "prototype": "PrototypeList::id::" + descriptor.name,
- "protoID": "PrototypeList::id::" + descriptor.name + " as uint",
- "source": source,
- "codeOnFailure": CGIndenter(CGGeneric(codeOnFailure), 4).define(),
- }
-
- def __str__(self):
- return string.Template(
-"""match unwrap_jsmanaged(${source}, ${prototype}, ${depth}) {
- Ok(val) => val,
- Err(()) => {
-${codeOnFailure}
- }
-}""").substitute(self.substitution)
-
-
-class CGThing():
- """
- Abstract base class for things that spit out code.
- """
- def __init__(self):
- pass # Nothing for now
-
- def define(self):
- """Produce code for a Rust file."""
- assert(False) # Override me!
-
-
-class CGNativePropertyHooks(CGThing):
- """
- Generate a NativePropertyHooks for a given descriptor
- """
- def __init__(self, descriptor, properties):
- CGThing.__init__(self)
- self.descriptor = descriptor
- self.properties = properties
-
- def define(self):
- parent = self.descriptor.interface.parent
- if parent:
- parentHooks = "Some(&::dom::bindings::codegen::Bindings::%sBinding::sNativePropertyHooks)" % parent.identifier.name
- else:
- parentHooks = "None"
-
- substitutions = {
- "parentHooks": parentHooks
- }
-
- return string.Template(
- "pub static sNativePropertyHooks: NativePropertyHooks = NativePropertyHooks {\n"
- " native_properties: &sNativeProperties,\n"
- " proto_hooks: ${parentHooks},\n"
- "};\n").substitute(substitutions)
-
-
-class CGMethodCall(CGThing):
- """
- A class to generate selection of a method signature from a set of
- signatures and generation of a call to that signature.
- """
- def __init__(self, argsPre, nativeMethodName, static, descriptor, method):
- CGThing.__init__(self)
-
- methodName = '\\"%s.%s\\"' % (descriptor.interface.identifier.name, method.identifier.name)
-
- def requiredArgCount(signature):
- arguments = signature[1]
- if len(arguments) == 0:
- return 0
- requiredArgs = len(arguments)
- while requiredArgs and arguments[requiredArgs-1].optional:
- requiredArgs -= 1
- return requiredArgs
-
- def getPerSignatureCall(signature, argConversionStartsAt=0, signatureIndex=0):
- return CGPerSignatureCall(signature[0], argsPre, signature[1],
- nativeMethodName + '_'*signatureIndex,
- static, descriptor,
- method, argConversionStartsAt)
-
-
- signatures = method.signatures()
- if len(signatures) == 1:
- # Special case: we can just do a per-signature method call
- # here for our one signature and not worry about switching
- # on anything.
- signature = signatures[0]
- self.cgRoot = CGList([getPerSignatureCall(signature)])
- requiredArgs = requiredArgCount(signature)
-
-
- if requiredArgs > 0:
- code = (
- "if argc < %d {\n"
- " throw_type_error(cx, \"Not enough arguments to %s.\");\n"
- " return 0;\n"
- "}" % (requiredArgs, methodName))
- self.cgRoot.prepend(
- CGWrapper(CGGeneric(code), pre="\n", post="\n"))
-
- return
-
- # Need to find the right overload
- maxArgCount = method.maxArgCount
- allowedArgCounts = method.allowedArgCounts
-
- argCountCases = []
- for argCount in allowedArgCounts:
- possibleSignatures = method.signaturesForArgCount(argCount)
- if len(possibleSignatures) == 1:
- # easy case!
- signature = possibleSignatures[0]
-
-
- sigIndex = signatures.index(signature)
- argCountCases.append(
- CGCase(str(argCount), getPerSignatureCall(signature,
- signatureIndex=sigIndex)))
- continue
-
- distinguishingIndex = method.distinguishingIndexForArgCount(argCount)
-
- # We can't handle unions 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)
-
- # Convert all our arguments up to the distinguishing index.
- # Doesn't matter which of the possible signatures we use, since
- # they all have the same types up to that point; just use
- # possibleSignatures[0]
- caseBody = [CGGeneric("let argv_start = JS_ARGV(cx, vp);")]
- caseBody.extend([ CGArgumentConverter(possibleSignatures[0][1][i],
- i, "argv_start", "argc",
- descriptor) for i in
- range(0, distinguishingIndex) ])
-
- # Select the right overload from our set.
- distinguishingArg = "(*argv_start.offset(%d))" % distinguishingIndex
-
- def pickFirstSignature(condition, filterLambda):
- sigs = filter(filterLambda, possibleSignatures)
- assert len(sigs) < 2
- if len(sigs) > 0:
- if condition is None:
- caseBody.append(
- getPerSignatureCall(sigs[0], distinguishingIndex,
- possibleSignatures.index(sigs[0])))
- else:
- caseBody.append(CGGeneric("if " + condition + " {"))
- caseBody.append(CGIndenter(
- getPerSignatureCall(sigs[0], distinguishingIndex,
- possibleSignatures.index(sigs[0]))))
- caseBody.append(CGGeneric("}"))
- return True
- return False
-
- # First check for null or undefined
- pickFirstSignature("%s.isNullOrUndefined()" % distinguishingArg,
- 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.isNonCallbackInterface()) ]
- # There might be more than one of these; we need to check
- # which ones we unwrap to.
-
- if len(interfacesSigs) > 0:
- # The spec says that we should check for "platform objects
- # implementing an interface", but it's enough to guard on these
- # being an object. The code for unwrapping non-callback
- # interfaces and typed arrays will just bail out and move on to
- # the next overload if the object fails to unwrap correctly. We
- # could even not do the isObject() check up front here, but in
- # cases where we have multiple object overloads it makes sense
- # to do it only once instead of for each overload. That will
- # also allow the unwrapping test to skip having to do codegen
- # for the null-or-undefined case, which we already handled
- # above.
- caseBody.append(CGGeneric("if (%s).is_object() {" %
- (distinguishingArg)))
- for idx, sig in enumerate(interfacesSigs):
- caseBody.append(CGIndenter(CGGeneric("loop {")));
- type = sig[1][distinguishingIndex].type
-
- # The argument at index distinguishingIndex can't possibly
- # be unset here, because we've already checked that argc is
- # large enough that we can examine this argument.
- template, _, declType, needsRooting = getJSToNativeConversionTemplate(
- type, descriptor, failureCode="break;", isDefinitelyObject=True)
-
- testCode = instantiateJSToNativeConversionTemplate(
- template,
- {"val": distinguishingArg},
- declType,
- "arg%d" % distinguishingIndex,
- needsRooting)
-
- # Indent by 4, since we need to indent further than our "do" statement
- caseBody.append(CGIndenter(testCode, 4));
- # If we got this far, we know we unwrapped to the right
- # interface, so just do the call. Start conversion with
- # distinguishingIndex + 1, since we already converted
- # distinguishingIndex.
- caseBody.append(CGIndenter(
- getPerSignatureCall(sig, distinguishingIndex + 1, idx), 4))
- caseBody.append(CGIndenter(CGGeneric("}")))
-
- caseBody.append(CGGeneric("}"))
-
- # 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.isObject() && IsArrayLike(cx, &%s.toObject())" %
- (distinguishingArg, distinguishingArg),
- lambda s:
- (s[1][distinguishingIndex].type.isArray() or
- 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.isObject() && JS_ObjectIsDate(cx, &%s.toObject())" %
- (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.isObject() && !IsPlatformObject(cx, &%s.toObject())" %
- (distinguishingArg, 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()))
-
- # 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())):
- pass
- # Check for primitives
- elif pickFirstSignature(None,
- lambda s: s[1][distinguishingIndex].type.isPrimitive()):
- pass
- # Check for "any"
- elif pickFirstSignature(None,
- lambda s: s[1][distinguishingIndex].type.isAny()):
- pass
- 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);"))
-
- argCountCases.append(CGCase(str(argCount),
- CGList(caseBody, "\n")))
-
- overloadCGThings = []
- overloadCGThings.append(
- CGGeneric("let argcount = cmp::min(argc, %d);" %
- maxArgCount))
- overloadCGThings.append(
- CGSwitch("argcount",
- argCountCases,
- CGGeneric("throw_type_error(cx, \"Not enough arguments to %s.\");\n"
- "return 0;\n" % methodName)))
- #XXXjdm Avoid unreachable statement warnings
- #overloadCGThings.append(
- # CGGeneric('fail!("We have an always-returning default case");\n'
- # 'return 0;'))
- self.cgRoot = CGWrapper(CGList(overloadCGThings, "\n"),
- pre="\n")
-
- def define(self):
- return self.cgRoot.define()
-
-class FakeCastableDescriptor():
- def __init__(self, descriptor):
- self.nativeType = "*const %s" % descriptor.concreteType
- self.name = descriptor.name
- class FakeInterface:
- def inheritanceDepth(self):
- return descriptor.interface.inheritanceDepth()
- self.interface = FakeInterface()
-
-def dictionaryHasSequenceMember(dictionary):
- return (any(typeIsSequenceOrHasSequenceMember(m.type) for m in
- dictionary.members) or
- (dictionary.parent and
- dictionaryHasSequenceMember(dictionary.parent)))
-
-def typeIsSequenceOrHasSequenceMember(type):
- if type.nullable():
- type = type.inner
- if type.isSequence():
- return True
- if type.isArray():
- elementType = type.inner
- return typeIsSequenceOrHasSequenceMember(elementType)
- if type.isDictionary():
- return dictionaryHasSequenceMember(type.inner)
- if type.isUnion():
- return any(typeIsSequenceOrHasSequenceMember(m.type) for m in
- type.flatMemberTypes)
- return False
-
-def typeNeedsRooting(type, descriptorProvider):
- return type.isGeckoInterface() and descriptorProvider.getDescriptor(type.name).needsRooting
-
-def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
- isDefinitelyObject=False,
- isMember=False,
- isArgument=False,
- invalidEnumValueFatal=True,
- defaultValue=None,
- treatNullAs="Default",
- isEnforceRange=False,
- isClamp=False,
- exceptionCode=None,
- allowTreatNonObjectAsNull=False,
- isCallbackReturnValue=False,
- sourceDescription="value"):
- """
- Get a template for converting a JS value to a native object based on the
- given type and descriptor. If failureCode is given, then we're actually
- testing whether we can convert the argument to the desired type. That
- means that failures to convert due to the JS value being the wrong type of
- value need to use failureCode instead of throwing exceptions. Failures to
- convert that are due to JS exceptions (from toString or valueOf methods) or
- out of memory conditions need to throw exceptions no matter what
- failureCode is.
-
- If isDefinitelyObject is True, that means we know the value
- isObject() and we have no need to recheck that.
-
- if isMember is True, we're being converted from a property of some
- JS object, not from an actual method argument, so we can't rely on
- our jsval being rooted or outliving us in any way. Any caller
- passing true needs to ensure that it is handled correctly in
- typeIsSequenceOrHasSequenceMember.
-
- invalidEnumValueFatal controls whether an invalid enum value conversion
- attempt will throw (if true) or simply return without doing anything (if
- false).
-
- 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.
-
- The return value from this function is a tuple consisting of four things:
-
- 1) A string representing the conversion code. This will have template
- substitution performed on it as follows:
-
- ${val} replaced by an expression for the JS::Value in question
-
- 2) A string or None representing Rust code for the default value (if any).
-
- 3) A CGThing representing the native C++ type we're converting to
- (declType). This is allowed to be None if the conversion code is
- supposed to be used as-is.
-
- 4) A boolean indicating whether the caller has to root the result.
-
- """
- # We should not have a defaultValue if we know we're an object
- assert(not isDefinitelyObject or defaultValue is None)
-
- # 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
- # they really should be!
- if exceptionCode is None:
- exceptionCode = "return 0;"
-
- needsRooting = typeNeedsRooting(type, descriptorProvider)
-
- def handleOptional(template, declType, default):
- assert (defaultValue is None) == (default is None)
- return (template, default, declType, needsRooting)
-
- # Unfortunately, .capitalize() on a string will lowercase things inside the
- # string, which we do not want.
- def firstCap(string):
- return string[0].upper() + string[1:]
-
- # Helper functions for dealing with failures due to the JS value being the
- # wrong type of value
- # Helper functions for dealing with failures due to the JS value being the
- # wrong type of value
- def onFailureNotAnObject(failureCode):
- return CGWrapper(
- CGGeneric(
- failureCode or
- ('throw_type_error(cx, "%s is not an object.");\n'
- '%s' % (firstCap(sourceDescription), exceptionCode))),
- post="\n")
- def onFailureBadType(failureCode, typeName):
- return CGWrapper(
- CGGeneric(
- failureCode or
- ('throw_type_error(cx, \"%s does not implement interface %s.\");\n'
- '%s' % (firstCap(sourceDescription), typeName,
- exceptionCode))),
- post="\n")
- def onFailureNotCallable(failureCode):
- return CGWrapper(
- CGGeneric(
- failureCode or
- ('throw_type_error(cx, \"%s is not callable.\");\n'
- '%s' % (firstCap(sourceDescription), exceptionCode))),
- post="\n")
-
-
- # A helper function for handling null default values. Checks that the
- # default value, if it exists, is null.
- def handleDefaultNull(nullValue):
- if defaultValue is None:
- return None
-
- if not isinstance(defaultValue, IDLNullValue):
- raise TypeError("Can't handle non-null default value here")
-
- assert type.nullable() or type.isDictionary()
- return nullValue
-
- # A helper function for wrapping up the template body for
- # possibly-nullable objecty stuff
- def wrapObjectTemplate(templateBody, isDefinitelyObject, type,
- failureCode=None):
- if not isDefinitelyObject:
- # Handle the non-object cases by wrapping up the whole
- # thing in an if cascade.
- templateBody = (
- "if (${val}).is_object() {\n" +
- CGIndenter(CGGeneric(templateBody)).define() + "\n")
- if type.nullable():
- templateBody += (
- "} else if (${val}).is_null_or_undefined() {\n"
- " None\n")
- templateBody += (
- "} else {\n" +
- CGIndenter(onFailureNotAnObject(failureCode)).define() +
- "}\n")
-
- return templateBody
-
- assert not (isEnforceRange and isClamp) # These are mutually exclusive
-
- if type.isArray():
- raise TypeError("Can't handle array arguments yet")
-
- if type.isSequence():
- raise TypeError("Can't handle sequence arguments yet")
-
- if type.isUnion():
- declType = CGGeneric(type.name + "::" + type.name)
- if type.nullable():
- declType = CGWrapper(declType, pre="Option<", post=" >")
-
- templateBody = ("match FromJSValConvertible::from_jsval(cx, ${val}, ()) {\n"
- " Ok(value) => value,\n"
- " Err(()) => { %s },\n"
- "}" % exceptionCode)
-
- return handleOptional(templateBody, declType, handleDefaultNull("None"))
-
- if type.isGeckoInterface():
- assert not isEnforceRange and not isClamp
-
- descriptor = descriptorProvider.getDescriptor(
- type.unroll().inner.identifier.name)
-
- if descriptor.interface.isCallback():
- name = descriptor.nativeType
- declType = CGGeneric("Option<%s>" % name);
- conversion = ("Some(%s::new((${val}).to_object()))" % name)
-
- template = wrapObjectTemplate(conversion, isDefinitelyObject, type,
- failureCode)
- return handleOptional(template, declType, handleDefaultNull("None"))
-
- if isMember:
- descriptorType = descriptor.memberType
- elif isArgument:
- descriptorType = descriptor.argumentType
- else:
- descriptorType = descriptor.nativeType
-
- templateBody = ""
- 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
-
- templateBody = str(CastableObjectUnwrapper(
- descriptor,
- "(${val}).to_object()",
- unwrapFailureCode))
-
- declType = CGGeneric(descriptorType)
- if type.nullable():
- templateBody = "Some(%s)" % templateBody
- declType = CGWrapper(declType, pre="Option<", post=">")
-
- if isMember:
- templateBody += ".root()"
-
- templateBody = wrapObjectTemplate(templateBody, isDefinitelyObject,
- type, failureCode)
-
- return handleOptional(templateBody, declType, handleDefaultNull("None"))
-
- if type.isSpiderMonkeyInterface():
- raise TypeError("Can't handle SpiderMonkey interface arguments yet")
-
- if type.isDOMString():
- assert not isEnforceRange and not isClamp
-
- treatAs = {
- "Default": "Default",
- "EmptyString": "Empty",
- }
- if treatNullAs not in treatAs:
- raise TypeError("We don't support [TreatNullAs=%s]" % treatNullAs)
- if type.nullable():
- nullBehavior = "()"
- else:
- nullBehavior = treatAs[treatNullAs]
-
- conversionCode = (
- "match FromJSValConvertible::from_jsval(cx, ${val}, %s) {\n"
- " Ok(strval) => strval,\n"
- " Err(_) => { %s },\n"
- "}" % (nullBehavior, exceptionCode))
-
- if defaultValue is None:
- default = None
- elif isinstance(defaultValue, IDLNullValue):
- assert type.nullable()
- default = "None"
- else:
- assert defaultValue.type.tag() == IDLType.Tags.domstring
- value = "str::from_utf8(data).unwrap().to_string()"
- if type.nullable():
- value = "Some(%s)" % value
-
- default = (
- "static data: [u8, ..%s] = [ %s ];\n"
- "%s" %
- (len(defaultValue.value) + 1,
- ", ".join(["'" + char + "' as u8" for char in defaultValue.value] + ["0"]),
- value))
-
- declType = "DOMString"
- if type.nullable():
- declType = "Option<%s>" % declType
-
- return handleOptional(conversionCode, CGGeneric(declType), default)
-
- if type.isByteString():
- assert not isEnforceRange and not isClamp
-
- conversionCode = (
- "match FromJSValConvertible::from_jsval(cx, ${val}, ()) {\n"
- " Ok(strval) => strval,\n"
- " Err(_) => { %s },\n"
- "}" % exceptionCode)
-
- declType = CGGeneric("ByteString")
- if type.nullable():
- declType = CGWrapper(declType, pre="Option<", post=">")
-
- return handleOptional(conversionCode, declType, handleDefaultNull("None"))
-
- if type.isEnum():
- assert not isEnforceRange and not isClamp
-
- if type.nullable():
- raise TypeError("We don't support nullable enumerated arguments "
- "yet")
- enum = type.inner.identifier.name
- if invalidEnumValueFatal:
- handleInvalidEnumValueCode = exceptionCode
- else:
- handleInvalidEnumValueCode = "return 1;"
-
- template = (
- "match FindEnumStringIndex(cx, ${val}, %(values)s) {\n"
- " Err(_) => { %(exceptionCode)s },\n"
- " Ok(None) => { %(handleInvalidEnumValueCode)s },\n"
- " Ok(Some(index)) => {\n"
- " //XXXjdm need some range checks up in here.\n"
- " unsafe { mem::transmute(index) }\n"
- " },\n"
- "}" % { "values" : enum + "Values::strings",
- "exceptionCode" : exceptionCode,
-"handleInvalidEnumValueCode" : handleInvalidEnumValueCode })
-
- if defaultValue is not None:
- assert(defaultValue.type.tag() == IDLType.Tags.domstring)
- default = "%sValues::%s" % (enum, getEnumValueName(defaultValue.value))
- else:
- default = None
-
- return handleOptional(template, CGGeneric(enum), default)
-
- if type.isCallback():
- assert not isEnforceRange and not isClamp
- assert not type.treatNonCallableAsNull()
- assert not type.treatNonObjectAsNull() or type.nullable()
- assert not type.treatNonObjectAsNull() or not type.treatNonCallableAsNull()
-
- declType = CGGeneric('%s::%s' % (type.unroll().module(), type.unroll().identifier.name))
-
- conversion = CGCallbackTempRoot(declType.define())
-
- if type.nullable():
- declType = CGTemplatedType("Option", declType)
- conversion = CGWrapper(conversion, pre="Some(", post=")")
-
- if allowTreatNonObjectAsNull and type.treatNonObjectAsNull():
- if not isDefinitelyObject:
- haveObject = "${val}.is_object()"
- template = CGIfElseWrapper(haveObject,
- conversion,
- CGGeneric("None")).define()
- else:
- template = conversion
- else:
- template = CGIfElseWrapper("JS_ObjectIsCallable(cx, ${val}.to_object()) != 0",
- conversion,
- onFailureNotCallable(failureCode)).define()
- template = wrapObjectTemplate(
- template,
- isDefinitelyObject,
- type,
- failureCode)
-
- if defaultValue is not None:
- assert allowTreatNonObjectAsNull
- assert type.treatNonObjectAsNull()
- assert type.nullable()
- assert isinstance(defaultValue, IDLNullValue)
- default = "None"
- else:
- default = None
-
- return (template, default, declType, needsRooting)
-
- if type.isAny():
- assert not isEnforceRange and not isClamp
-
- declType = CGGeneric("JSVal")
-
- if defaultValue is None:
- default = None
- elif isinstance(defaultValue, IDLNullValue):
- default = "NullValue()"
- elif isinstance(defaultValue, IDLUndefinedValue):
- default = "UndefinedValue()"
- else:
- raise TypeError("Can't handle non-null, non-undefined default value here")
-
- return handleOptional("${val}", declType, default)
-
- if type.isObject():
- raise TypeError("Can't handle object arguments yet")
-
- if type.isDictionary():
- if failureCode is not None:
- raise TypeError("Can't handle dictionaries when failureCode is not None")
- # There are no nullable dictionaries
- assert not type.nullable()
-
- typeName = CGDictionary.makeDictionaryName(type.inner)
- declType = CGGeneric(typeName)
- template = ("match %s::new(cx, ${val}) {\n"
- " Ok(dictionary) => dictionary,\n"
- " Err(_) => return 0,\n"
- "}" % typeName)
-
- return handleOptional(template, declType, handleDefaultNull("%s::empty()" % typeName))
-
- if type.isVoid():
- # This one only happens for return values, and its easy: Just
- # ignore the jsval.
- return ("", None, None, False)
-
- if not type.isPrimitive():
- raise TypeError("Need conversion for argument type '%s'" % str(type))
-
- assert not isEnforceRange and not isClamp
-
- if failureCode is None:
- failureCode = 'return 0'
-
- declType = CGGeneric(builtinNames[type.tag()])
- if type.nullable():
- declType = CGWrapper(declType, pre="Option<", post=">")
-
- #XXXjdm support conversionBehavior here
- template = (
- "match FromJSValConvertible::from_jsval(cx, ${val}, ()) {\n"
- " Ok(v) => v,\n"
- " Err(_) => { %s }\n"
- "}" % exceptionCode)
-
- if defaultValue is not None:
- if isinstance(defaultValue, IDLNullValue):
- assert type.nullable()
- defaultStr = "None"
- else:
- tag = defaultValue.type.tag()
- if tag in numericTags:
- defaultStr = str(defaultValue.value)
- else:
- assert(tag == IDLType.Tags.bool)
- defaultStr = toStringBool(defaultValue.value)
-
- if type.nullable():
- defaultStr = "Some(%s)" % defaultStr
- else:
- defaultStr = None
-
- return handleOptional(template, declType, defaultStr)
-
-def instantiateJSToNativeConversionTemplate(templateBody, replacements,
- declType, declName, needsRooting):
- """
- Take the templateBody and declType as returned by
- getJSToNativeConversionTemplate, a set of replacements as required by the
- strings in such a templateBody, and a declName, and generate code to
- convert into a stack Rust binding with that name.
- """
- result = CGList([], "\n")
-
- conversion = CGGeneric(
- string.Template(templateBody).substitute(replacements)
- )
-
- if declType is not None:
- newDecl = [
- CGGeneric("let "),
- CGGeneric(declName),
- CGGeneric(": "),
- declType,
- CGGeneric(" = "),
- conversion,
- CGGeneric(";"),
- ]
- result.append(CGList(newDecl))
- else:
- result.append(conversion)
-
- # Add an empty CGGeneric to get an extra newline after the argument
- # conversion.
- result.append(CGGeneric(""))
-
- if needsRooting:
- rootBody = "let %s = %s.root();" % (declName, declName)
- result.append(CGGeneric(rootBody))
- result.append(CGGeneric(""))
-
- return result;
-
-def convertConstIDLValueToJSVal(value):
- if isinstance(value, IDLNullValue):
- return "NullVal"
- tag = value.type.tag()
- if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16,
- IDLType.Tags.uint16, IDLType.Tags.int32]:
- return "IntVal(%s)" % (value.value)
- if tag == IDLType.Tags.uint32:
- return "UintVal(%s)" % (value.value)
- if tag in [IDLType.Tags.int64, IDLType.Tags.uint64]:
- return "DoubleVal(%s)" % (value.value)
- if tag == IDLType.Tags.bool:
- return "BoolVal(true)" if value.value else "BoolVal(false)"
- if tag in [IDLType.Tags.float, IDLType.Tags.double]:
- return "DoubleVal(%s)" % (value.value)
- raise TypeError("Const value of unhandled type: " + value.type)
-
-class CGArgumentConverter(CGThing):
- """
- A class that takes an IDL argument object, its index in the
- argument list, and the argv and argc strings and generates code to
- unwrap the argument to the right native type.
- """
- def __init__(self, argument, index, argv, argc, descriptorProvider,
- invalidEnumValueFatal=True):
- CGThing.__init__(self)
- assert(not argument.defaultValue or argument.optional)
-
- replacer = {
- "index": index,
- "argc": argc,
- "argv": argv
- }
- condition = string.Template("${index} < ${argc}").substitute(replacer)
-
- replacementVariables = {
- "val": string.Template("(*${argv}.offset(${index}))").substitute(replacer),
- }
-
- template, default, declType, needsRooting = getJSToNativeConversionTemplate(
- argument.type,
- descriptorProvider,
- invalidEnumValueFatal=invalidEnumValueFatal,
- defaultValue=argument.defaultValue,
- treatNullAs=argument.treatNullAs,
- isEnforceRange=argument.enforceRange,
- isClamp=argument.clamp,
- isMember="Variadic" if argument.variadic else False,
- allowTreatNonObjectAsNull=argument.allowTreatNonCallableAsNull())
-
- if not argument.variadic:
- if argument.optional:
- if argument.defaultValue:
- assert default
- template = CGIfElseWrapper(condition,
- CGGeneric(template),
- CGGeneric(default)).define()
- else:
- assert not default
- declType = CGWrapper(declType, pre="Option<", post=">")
- template = CGIfElseWrapper(condition,
- CGGeneric("Some(%s)" % template),
- CGGeneric("None")).define()
- else:
- assert not default
-
- self.converter = instantiateJSToNativeConversionTemplate(
- template, replacementVariables, declType, "arg%d" % index,
- needsRooting)
- else:
- assert argument.optional
- variadicConversion = {
- "val": string.Template("(*${argv}.offset(variadicArg as int))").substitute(replacer),
- }
- innerConverter = instantiateJSToNativeConversionTemplate(
- template, variadicConversion, declType, "slot",
- needsRooting)
-
- seqType = CGTemplatedType("Vec", declType)
- variadicConversion = string.Template(
- "{\n"
- " let mut vector: ${seqType} = Vec::with_capacity((${argc} - ${index}) as uint);\n"
- " for variadicArg in range(${index}, ${argc}) {\n"
- "${inner}\n"
- " vector.push(slot);\n"
- " }\n"
- " vector\n"
- "}"
- ).substitute({
- "index": index,
- "argc": argc,
- "seqType": seqType.define(),
- "inner": CGIndenter(innerConverter, 4).define(),
- })
-
- self.converter = instantiateJSToNativeConversionTemplate(
- variadicConversion, replacementVariables, seqType, "arg%d" % index,
- False)
-
- def define(self):
- return self.converter.define()
-
-
-def wrapForType(jsvalRef, result='result', successCode='return 1;'):
- """
- Reflect a Rust value into JS.
-
- * 'jsvalRef': a Rust reference to the JSVal in which to store the result
- of the conversion;
- * 'result': the name of the variable in which the Rust value is stored;
- * 'successCode': the code to run once we have done the conversion.
- """
- return "%s = (%s).to_jsval(cx);\n%s" % (jsvalRef, result, successCode)
-
-
-def typeNeedsCx(type, retVal=False):
- if type is None:
- return False
- if type.nullable():
- type = type.inner
- if type.isSequence() or type.isArray():
- type = type.inner
- if type.isUnion():
- return any(typeNeedsCx(t) for t in type.unroll().flatMemberTypes)
- if retVal and type.isSpiderMonkeyInterface():
- return True
- return type.isAny() or type.isObject()
-
-def typeRetValNeedsRooting(type):
- if type is None:
- return False
- if type.nullable():
- type = type.inner
- return type.isGeckoInterface() and not type.isCallback() and not type.isCallbackInterface()
-
-def memberIsCreator(member):
- return member.getExtendedAttribute("Creator") is not None
-
-# Returns a CGThing containing the type of the return value.
-def getRetvalDeclarationForType(returnType, descriptorProvider):
- if returnType is None or returnType.isVoid():
- # Nothing to declare
- return CGGeneric("()")
- if returnType.isPrimitive() and returnType.tag() in builtinNames:
- result = CGGeneric(builtinNames[returnType.tag()])
- if returnType.nullable():
- result = CGWrapper(result, pre="Option<", post=">")
- return result
- if returnType.isDOMString():
- result = CGGeneric("DOMString")
- if returnType.nullable():
- result = CGWrapper(result, pre="Option<", post=">")
- return result
- if returnType.isByteString():
- result = CGGeneric("ByteString")
- if returnType.nullable():
- result = CGWrapper(result, pre="Option<", post=">")
- return result
- if returnType.isEnum():
- result = CGGeneric(returnType.unroll().inner.identifier.name)
- if returnType.nullable():
- result = CGWrapper(result, pre="Option<", post=">")
- return result
- if returnType.isGeckoInterface():
- descriptor = descriptorProvider.getDescriptor(
- returnType.unroll().inner.identifier.name)
- result = CGGeneric(descriptor.returnType)
- if returnType.nullable():
- result = CGWrapper(result, pre="Option<", post=">")
- return result
- if returnType.isCallback():
- result = CGGeneric('%s::%s' % (returnType.unroll().module(),
- returnType.unroll().identifier.name))
- if returnType.nullable():
- result = CGWrapper(result, pre="Option<", post=">")
- return result
- if returnType.isUnion():
- result = CGGeneric('%s::%s' % (returnType.unroll().name, returnType.unroll().name))
- if returnType.nullable():
- result = CGWrapper(result, pre="Option<", post=">")
- return result
- if returnType.isAny():
- return CGGeneric("JSVal")
- if returnType.isObject() or returnType.isSpiderMonkeyInterface():
- return CGGeneric("*mut JSObject")
- if returnType.isSequence():
- raise TypeError("We don't support sequence return values")
-
- raise TypeError("Don't know how to declare return value for %s" %
- returnType)
-
-class PropertyDefiner:
- """
- A common superclass for defining things on prototype objects.
-
- Subclasses should implement generateArray to generate the actual arrays of
- things we're defining. They should also set self.regular to the list of
- things exposed to web pages.
- """
- def __init__(self, descriptor, name):
- self.descriptor = descriptor
- self.name = name
-
- def variableName(self):
- return "s" + self.name
-
- def length(self):
- return len(self.regular)
-
- def __str__(self):
- # We only need to generate id arrays for things that will end
- # up used via ResolveProperty or EnumerateProperties.
- return self.generateArray(self.regular, self.variableName())
-
- def generatePrefableArray(self, array, name, specTemplate, specTerminator,
- specType, getDataTuple):
- """
- This method generates our various arrays.
-
- array is an array of interface members as passed to generateArray
-
- name is the name as passed to generateArray
-
- specTemplate is a template for each entry of the spec array
-
- specTerminator is a terminator for the spec array (inserted at the end
- of the array), or None
-
- specType is the actual typename of our spec
-
- getDataTuple is a callback function that takes an array entry and
- returns a tuple suitable for substitution into specTemplate.
- """
-
- assert(len(array) is not 0)
- specs = []
-
- for member in array:
- specs.append(specTemplate % getDataTuple(member))
- if specTerminator:
- specs.append(specTerminator)
-
- return (("static %s: &'static [%s] = &[\n" +
- ",\n".join(specs) + "\n" +
- "];\n\n") % (name, specType))
-
-# The length of a method is the maximum of the lengths of the
-# argument lists of all its overloads.
-def methodLength(method):
- signatures = method.signatures()
- return max([len(arguments) for (retType, arguments) in signatures])
-
-class MethodDefiner(PropertyDefiner):
- """
- A class for defining methods on a prototype object.
- """
- def __init__(self, descriptor, name, static):
- PropertyDefiner.__init__(self, descriptor, name)
-
- # FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=772822
- # We should be able to check for special operations without an
- # identifier. For now we check if the name starts with __
- methods = [m for m in descriptor.interface.members if
- m.isMethod() and m.isStatic() == static and
- not m.isIdentifierLess()]
- self.regular = [{"name": m.identifier.name,
- "methodInfo": not m.isStatic(),
- "length": methodLength(m),
- "flags": "JSPROP_ENUMERATE" }
- 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):
- self.regular.append({"name": 'iterator',
- "methodInfo": False,
- "nativeName": "JS_ArrayIterator",
- "length": 0,
- "flags": "JSPROP_ENUMERATE" })
-
- def generateArray(self, array, name):
- if len(array) == 0:
- return ""
-
- def specData(m):
- if m.get("methodInfo", True):
- jitinfo = ("&%s_methodinfo" % m["name"])
- accessor = "genericMethod"
- else:
- jitinfo = "0 as *const JSJitInfo"
- accessor = m.get("nativeName", m["name"])
- return (m["name"], accessor, jitinfo, m["length"], m["flags"])
-
- def stringDecl(m):
- return "static %s_name: [u8, ..%i] = %s;\n" % (m["name"], len(m["name"]) + 1,
- str_to_const_array(m["name"]))
-
- decls = ''.join([stringDecl(m) for m in array])
- return decls + self.generatePrefableArray(
- array, name,
- ' JSFunctionSpec {name: &%s_name as *const u8 as *const libc::c_char, call: JSNativeWrapper {op: Some(%s), info: %s}, nargs: %s, flags: %s as u16, selfHostedName: 0 as *const libc::c_char }',
- ' JSFunctionSpec {name: 0 as *const libc::c_char, call: JSNativeWrapper {op: None, info: 0 as *const JSJitInfo}, nargs: 0, flags: 0, selfHostedName: 0 as *const libc::c_char }',
- 'JSFunctionSpec',
- specData)
-
-class AttrDefiner(PropertyDefiner):
- def __init__(self, descriptor, name, static):
- PropertyDefiner.__init__(self, descriptor, name)
- self.name = name
- self.regular = [
- m
- for m in descriptor.interface.members
- if m.isAttr() and m.isStatic() == static
- ]
- self.static = static
-
- def generateArray(self, array, name):
- if len(array) == 0:
- return ""
-
- def flags(attr):
- return "JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_NATIVE_ACCESSORS"
-
- def getter(attr):
- if self.static:
- accessor = 'get_' + attr.identifier.name
- jitinfo = "0"
- else:
- if attr.hasLenientThis():
- accessor = "genericLenientGetter"
- else:
- accessor = "genericGetter"
- jitinfo = "&%s_getterinfo" % attr.identifier.name
-
- return ("JSPropertyOpWrapper {op: Some(%(native)s), info: %(info)s as *const JSJitInfo}"
- % {"info" : jitinfo,
- "native" : accessor})
-
- def setter(attr):
- if attr.readonly:
- return "JSStrictPropertyOpWrapper {op: None, info: 0 as *const JSJitInfo}"
-
- if self.static:
- accessor = 'set_' + attr.identifier.name
- jitinfo = "0"
- else:
- if attr.hasLenientThis():
- accessor = "genericLenientSetter"
- else:
- accessor = "genericSetter"
- jitinfo = "&%s_setterinfo" % attr.identifier.name
-
- return ("JSStrictPropertyOpWrapper {op: Some(%(native)s), info: %(info)s as *const JSJitInfo}"
- % {"info" : jitinfo,
- "native" : accessor})
-
- def specData(attr):
- return (attr.identifier.name, flags(attr), getter(attr),
- setter(attr))
-
- def stringDecl(attr):
- name = attr.identifier.name
- return "static %s_name: [u8, ..%i] = %s;\n" % (name, len(name) + 1,
- str_to_const_array(name))
-
- decls = ''.join([stringDecl(m) for m in array])
-
- return decls + self.generatePrefableArray(
- array, name,
- ' JSPropertySpec { name: &%s_name as *const u8 as *const libc::c_char, tinyid: 0, flags: ((%s) & 0xFF) as u8, getter: %s, setter: %s }',
- ' JSPropertySpec { name: 0 as *const libc::c_char, tinyid: 0, flags: 0, getter: JSPropertyOpWrapper {op: None, info: 0 as *const JSJitInfo}, setter: JSStrictPropertyOpWrapper {op: None, info: 0 as *const JSJitInfo} }',
- 'JSPropertySpec',
- specData)
-
-class ConstDefiner(PropertyDefiner):
- """
- A class for definining constants on the interface object
- """
- def __init__(self, descriptor, name):
- PropertyDefiner.__init__(self, descriptor, name)
- self.name = name
- self.regular = [m for m in descriptor.interface.members if m.isConst()]
-
- def generateArray(self, array, name):
- if len(array) == 0:
- return ""
-
- def specData(const):
- return (const.identifier.name,
- convertConstIDLValueToJSVal(const.value))
-
- def stringDecl(const):
- name = const.identifier.name
- return "static %s_name: &'static [u8] = &%s;\n" % (name, str_to_const_array(name))
-
- decls = ''.join([stringDecl(m) for m in array])
-
- return decls + self.generatePrefableArray(
- array, name,
- ' ConstantSpec { name: %s_name, value: %s }',
- None,
- 'ConstantSpec',
- 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.
-lineStartDetector = re.compile("^(?=[^\n])", re.MULTILINE)
-class CGIndenter(CGThing):
- """
- A class that takes another CGThing and generates code that indents that
- CGThing by some number of spaces. The default indent is two spaces.
- """
- def __init__(self, child, indentLevel=2):
- CGThing.__init__(self)
- self.child = child
- self.indent = " " * indentLevel
-
- def define(self):
- defn = self.child.define()
- if defn is not "":
- return re.sub(lineStartDetector, self.indent, defn)
- else:
- return defn
-
-class CGWrapper(CGThing):
- """
- Generic CGThing that wraps other CGThings with pre and post text.
- """
- def __init__(self, child, pre="", post="", reindent=False):
- CGThing.__init__(self)
- self.child = child
- self.pre = pre
- self.post = post
- self.reindent = reindent
-
- def define(self):
- defn = self.child.define()
- if self.reindent:
- # We don't use lineStartDetector because we don't want to
- # insert whitespace at the beginning of our _first_ line.
- defn = stripTrailingWhitespace(
- defn.replace("\n", "\n" + (" " * len(self.pre))))
- return self.pre + defn + self.post
-
-class CGImports(CGWrapper):
- """
- Generates the appropriate import/use statements.
- """
- def __init__(self, child, descriptors, imports):
- """
- Adds a set of imports.
- """
- ignored_warnings = [
- # Allow unreachable_code because we use 'break' in a way that
- # sometimes produces two 'break's in a row. See for example
- # CallbackMember.getArgConversions.
- 'unreachable_code',
- 'non_camel_case_types',
- 'non_uppercase_statics',
- 'unnecessary_parens',
- 'unused_imports',
- 'unused_variable',
- 'unused_unsafe',
- 'unused_mut',
- 'dead_assignment',
- 'dead_code',
- ]
-
- statements = ['#![allow(%s)]' % ','.join(ignored_warnings)]
- statements.extend('use %s;' % i for i in sorted(imports))
-
- CGWrapper.__init__(self, child,
- pre='\n'.join(statements) + '\n\n')
-
- @staticmethod
- def getDeclarationFilename(decl):
- # Use our local version of the header, not the exported one, so that
- # test bindings, which don't export, will work correctly.
- basename = os.path.basename(decl.filename())
- return basename.replace('.webidl', 'Binding.rs')
-
-class CGIfWrapper(CGWrapper):
- def __init__(self, child, condition):
- pre = CGWrapper(CGGeneric(condition), pre="if ", post=" {\n",
- reindent=True)
- CGWrapper.__init__(self, CGIndenter(child), pre=pre.define(),
- post="\n}")
-
-class CGTemplatedType(CGWrapper):
- def __init__(self, templateName, child):
- CGWrapper.__init__(self, child, pre=templateName + "<", post=">")
-
-class CGNamespace(CGWrapper):
- def __init__(self, namespace, child, public=False):
- pre = "%smod %s {\n" % ("pub " if public else "", namespace)
- post = "} // mod %s\n" % namespace
- CGWrapper.__init__(self, child, pre=pre, post=post)
-
- @staticmethod
- def build(namespaces, child, public=False):
- """
- Static helper method to build multiple wrapped namespaces.
- """
- if not namespaces:
- return child
- inner = CGNamespace.build(namespaces[1:], child, public=public)
- return CGNamespace(namespaces[0], inner, public=public)
-
-def DOMClass(descriptor):
- protoList = ['PrototypeList::id::' + proto for proto in descriptor.prototypeChain]
- # Pad out the list to the right length with IDCount so we
- # guarantee that all the lists are the same length. IDCount
- # is never the ID of any prototype, so it's safe to use as
- # padding.
- protoList.extend(['PrototypeList::id::IDCount'] * (descriptor.config.maxProtoChainLength - len(protoList)))
- prototypeChainString = ', '.join(protoList)
- return """DOMClass {
- interface_chain: [ %s ],
- native_hooks: &sNativePropertyHooks,
-}""" % prototypeChainString
-
-class CGDOMJSClass(CGThing):
- """
- Generate a DOMJSClass for a given descriptor
- """
- def __init__(self, descriptor):
- CGThing.__init__(self)
- self.descriptor = descriptor
-
- def define(self):
- traceHook = "Some(%s)" % TRACE_HOOK_NAME
- if self.descriptor.isGlobal():
- flags = "JSCLASS_IS_GLOBAL | JSCLASS_DOM_GLOBAL"
- slots = "JSCLASS_GLOBAL_SLOT_COUNT + 1"
- else:
- flags = "0"
- slots = "1"
- return """
-static Class_name: [u8, ..%i] = %s;
-static Class: DOMJSClass = DOMJSClass {
- base: js::Class {
- name: &Class_name as *const u8 as *const libc::c_char,
- flags: JSCLASS_IS_DOMJSCLASS | %s | (((%s) & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT as uint), //JSCLASS_HAS_RESERVED_SLOTS(%s),
- addProperty: Some(JS_PropertyStub),
- delProperty: Some(JS_PropertyStub),
- getProperty: Some(JS_PropertyStub),
- setProperty: Some(JS_StrictPropertyStub),
- enumerate: Some(JS_EnumerateStub),
- resolve: Some(JS_ResolveStub),
- convert: Some(JS_ConvertStub),
- finalize: Some(%s),
- checkAccess: None,
- call: None,
- hasInstance: None,
- construct: None,
- trace: %s,
-
- ext: js::ClassExtension {
- equality: 0 as *const u8,
- outerObject: %s,
- innerObject: None,
- iteratorObject: 0 as *const u8,
- unused: 0 as *const u8,
- isWrappedNative: 0 as *const u8,
- },
-
- ops: js::ObjectOps {
- lookupGeneric: 0 as *const u8,
- lookupProperty: 0 as *const u8,
- lookupElement: 0 as *const u8,
- lookupSpecial: 0 as *const u8,
- defineGeneric: 0 as *const u8,
- defineProperty: 0 as *const u8,
- defineElement: 0 as *const u8,
- defineSpecial: 0 as *const u8,
- getGeneric: 0 as *const u8,
- getProperty: 0 as *const u8,
- getElement: 0 as *const u8,
- getElementIfPresent: 0 as *const u8,
- getSpecial: 0 as *const u8,
- setGeneric: 0 as *const u8,
- setProperty: 0 as *const u8,
- setElement: 0 as *const u8,
- setSpecial: 0 as *const u8,
- getGenericAttributes: 0 as *const u8,
- getPropertyAttributes: 0 as *const u8,
- getElementAttributes: 0 as *const u8,
- getSpecialAttributes: 0 as *const u8,
- setGenericAttributes: 0 as *const u8,
- setPropertyAttributes: 0 as *const u8,
- setElementAttributes: 0 as *const u8,
- setSpecialAttributes: 0 as *const u8,
- deleteProperty: 0 as *const u8,
- deleteElement: 0 as *const u8,
- deleteSpecial: 0 as *const u8,
-
- enumerate: 0 as *const u8,
- typeOf: 0 as *const u8,
- thisObject: %s,
- clear: 0 as *const u8,
- },
- },
- dom_class: %s
-};
-""" % (len(self.descriptor.interface.identifier.name) + 1,
- str_to_const_array(self.descriptor.interface.identifier.name),
- flags, slots, slots,
- FINALIZE_HOOK_NAME, traceHook,
- self.descriptor.outerObjectHook,
- self.descriptor.outerObjectHook,
- CGIndenter(CGGeneric(DOMClass(self.descriptor))).define())
-
-def str_to_const_array(s):
- return "[" + (", ".join(map(lambda x: "'" + x + "' as u8", list(s)) + ['0 as u8'])) + "]"
-
-class CGPrototypeJSClass(CGThing):
- def __init__(self, descriptor):
- CGThing.__init__(self)
- self.descriptor = descriptor
-
- def define(self):
- return """
-static PrototypeClassName__: [u8, ..%s] = %s;
-static PrototypeClass: JSClass = JSClass {
- name: &PrototypeClassName__ as *const u8 as *const libc::c_char,
- flags: (1 & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT as uint, //JSCLASS_HAS_RESERVED_SLOTS(1)
- addProperty: Some(JS_PropertyStub),
- delProperty: Some(JS_PropertyStub),
- getProperty: Some(JS_PropertyStub),
- setProperty: Some(JS_StrictPropertyStub),
- enumerate: Some(JS_EnumerateStub),
- resolve: Some(JS_ResolveStub),
- convert: Some(JS_ConvertStub),
- finalize: None,
- checkAccess: None,
- call: None,
- hasInstance: None,
- construct: None,
- trace: None,
- reserved: [0 as *mut libc::c_void, ..40]
-};
-""" % (len(self.descriptor.interface.identifier.name + "Prototype") + 1,
- str_to_const_array(self.descriptor.interface.identifier.name + "Prototype"))
-
-class CGInterfaceObjectJSClass(CGThing):
- def __init__(self, descriptor):
- CGThing.__init__(self)
- self.descriptor = descriptor
-
- def define(self):
- if True:
- return ""
- ctorname = "0 as *const u8" if not self.descriptor.interface.ctor() else CONSTRUCT_HOOK_NAME
- hasinstance = HASINSTANCE_HOOK_NAME
- return """
-static InterfaceObjectClass: JSClass = {
- %s, 0,
- JS_PropertyStub,
- JS_PropertyStub,
- JS_PropertyStub,
- JS_StrictPropertyStub,
- JS_EnumerateStub,
- JS_ResolveStub,
- JS_ConvertStub,
- 0 as *const u8,
- 0 as *const u8,
- %s,
- %s,
- %s,
- 0 as *const u8,
- JSCLASS_NO_INTERNAL_MEMBERS
-};
-""" % (str_to_const_array("Function"), ctorname, hasinstance, ctorname)
-
-class CGList(CGThing):
- """
- Generate code for a list of GCThings. Just concatenates them together, with
- an optional joiner string. "\n" is a common joiner.
- """
- def __init__(self, children, joiner=""):
- CGThing.__init__(self)
- self.children = children
- self.joiner = joiner
- def append(self, child):
- self.children.append(child)
- def prepend(self, child):
- self.children.insert(0, child)
- def join(self, generator):
- return self.joiner.join(filter(lambda s: len(s) > 0, (child for child in generator)))
-
- def define(self):
- return self.join(child.define() for child in self.children if child is not None)
-
-
-class CGIfElseWrapper(CGList):
- def __init__(self, condition, ifTrue, ifFalse):
- kids = [ CGIfWrapper(ifTrue, condition),
- CGWrapper(CGIndenter(ifFalse), pre=" else {\n", post="\n}") ]
- CGList.__init__(self, kids)
-
-
-class CGGeneric(CGThing):
- """
- A class that spits out a fixed string into the codegen. Can spit out a
- separate string for the declaration too.
- """
- def __init__(self, text):
- self.text = text
-
- def define(self):
- return self.text
-
-class CGCallbackTempRoot(CGGeneric):
- def __init__(self, name):
- val = "%s::new(tempRoot)" % name
- define = """{
- let tempRoot = ${val}.to_object();
- %s
-}""" % val
- CGGeneric.__init__(self, define)
-
-
-def getAllTypes(descriptors, dictionaries, callbacks):
- """
- 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.
- """
- for d in descriptors:
- for t in getTypesFromDescriptor(d):
- yield (t, d, None)
- for dictionary in dictionaries:
- for t in getTypesFromDictionary(dictionary):
- yield (t, None, dictionary)
- for callback in callbacks:
- for t in getTypesFromCallback(callback):
- yield (t, None, None)
-
-def SortedTuples(l):
- """
- Sort a list of tuples based on the first item in the tuple
- """
- return sorted(l, key=operator.itemgetter(0))
-
-def SortedDictValues(d):
- """
- Returns a list of values from the dict sorted by key.
- """
- # Create a list of tuples containing key and value, sorted on key.
- d = SortedTuples(d.items())
- # We're only interested in the values.
- return (i[1] for i in d)
-
-def UnionTypes(descriptors, dictionaries, callbacks, config):
- """
- Returns a CGList containing CGUnionStructs for every union.
- """
-
- imports = [
- 'dom::bindings::utils::unwrap_jsmanaged',
- 'dom::bindings::codegen::PrototypeList',
- 'dom::bindings::conversions::FromJSValConvertible',
- 'dom::bindings::conversions::ToJSValConvertible',
- 'dom::bindings::conversions::Default',
- 'dom::bindings::error::throw_not_in_union',
- 'dom::bindings::js::JS',
- 'dom::types::*',
- 'js::jsapi::JSContext',
- 'js::jsval::JSVal',
- 'servo_util::str::DOMString',
- ]
-
- # 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):
- assert not descriptor or not dictionary
- t = t.unroll()
- if not t.isUnion():
- continue
- name = str(t)
- if not name in unionStructs:
- provider = descriptor or config.getDescriptorProvider()
- unionStructs[name] = CGNamespace(name,
- CGImports(CGList([
- CGUnionStruct(t, provider),
- CGUnionConversionStruct(t, provider)
- ]), [], imports),
- public=True)
-
- return CGList(SortedDictValues(unionStructs), "\n\n")
-
-
-class Argument():
- """
- A class for outputting the type and name of an argument
- """
- def __init__(self, argType, name, default=None, mutable=False):
- self.argType = argType
- self.name = name
- self.default = default
- self.mutable = mutable
- def declare(self):
- string = ('mut ' if self.mutable else '') + self.name + ((': ' + self.argType) if self.argType else '')
- #XXXjdm Support default arguments somehow :/
- #if self.default is not None:
- # string += " = " + self.default
- return string
- def define(self):
- return self.argType + ' ' + self.name
-
-class CGAbstractMethod(CGThing):
- """
- An abstract class for generating code for a method. Subclasses
- should override definition_body to create the actual code.
-
- descriptor is the descriptor for the interface the method is associated with
-
- name is the name of the method as a string
-
- returnType is the IDLType of the return value
-
- args is a list of Argument objects
-
- inline should be True to generate an inline method, whose body is
- part of the declaration.
-
- alwaysInline should be True to generate an inline method annotated with
- MOZ_ALWAYS_INLINE.
-
- If templateArgs is not None it should be a list of strings containing
- template arguments, and the function will be templatized using those
- arguments.
- """
- def __init__(self, descriptor, name, returnType, args, inline=False, alwaysInline=False, extern=False, pub=False, templateArgs=None, unsafe=True):
- CGThing.__init__(self)
- self.descriptor = descriptor
- self.name = name
- self.returnType = returnType
- self.args = args
- self.alwaysInline = alwaysInline
- self.extern = extern
- self.templateArgs = templateArgs
- self.pub = pub;
- self.unsafe = unsafe
- def _argstring(self):
- return ', '.join([a.declare() for a in self.args])
- def _template(self):
- if self.templateArgs is None:
- return ''
- return '<%s>\n' % ', '.join(self.templateArgs)
-
- def _decorators(self):
- decorators = []
- if self.alwaysInline:
- decorators.append('#[inline(always)]')
-
- if self.extern:
- decorators.append('extern')
-
- if self.pub:
- decorators.append('pub')
-
- if not decorators:
- return ''
- return ' '.join(decorators) + ' '
-
- def _returnType(self):
- return (" -> %s" % self.returnType) if self.returnType != "void" else ""
-
- def define(self):
- body = self.definition_body()
- if self.unsafe:
- body = CGWrapper(body, pre="unsafe {\n", post="\n}")
-
- return CGWrapper(CGIndenter(body),
- pre=self.definition_prologue(),
- post=self.definition_epilogue()).define()
-
- def definition_prologue(self):
- return "%sfn %s%s(%s)%s {\n" % (self._decorators(), self.name, self._template(),
- self._argstring(), self._returnType())
- def definition_epilogue(self):
- return "\n}\n"
- def definition_body(self):
- assert(False) # Override me!
-
-def CreateBindingJSObject(descriptor, parent=None):
- create = "let mut raw: JS<%s> = JS::from_raw(&*aObject);\n" % descriptor.concreteType
- if descriptor.proxy:
- assert not descriptor.isGlobal()
- create += """
-let handler = RegisterBindings::proxy_handlers[PrototypeList::proxies::%s as uint];
-let mut private = PrivateValue(squirrel_away_unique(aObject) as *const libc::c_void);
-let obj = with_compartment(aCx, proto, || {
- NewProxyObject(aCx, handler,
- &private,
- proto, %s,
- ptr::mut_null(), ptr::mut_null())
-});
-assert!(obj.is_not_null());
-
-""" % (descriptor.name, parent)
- else:
- if descriptor.isGlobal():
- create += "let obj = CreateDOMGlobal(aCx, &Class.base as *const js::Class as *const JSClass);\n"
- else:
- create += ("let obj = with_compartment(aCx, proto, || {\n"
- " JS_NewObject(aCx, &Class.base as *const js::Class as *const JSClass, &*proto, &*%s)\n"
- "});\n" % parent)
- create += """assert!(obj.is_not_null());
-
-JS_SetReservedSlot(obj, DOM_OBJECT_SLOT as u32,
- PrivateValue(squirrel_away_unique(aObject) as *const libc::c_void));
-"""
- return create
-
-class CGWrapMethod(CGAbstractMethod):
- """
- Class that generates the FooBinding::Wrap function for non-callback
- interfaces.
- """
- def __init__(self, descriptor):
- assert not descriptor.interface.isCallback()
- if not descriptor.isGlobal():
- args = [Argument('*mut JSContext', 'aCx'), Argument('&GlobalRef', 'aScope'),
- Argument("Box<%s>" % descriptor.concreteType, 'aObject', mutable=True)]
- else:
- args = [Argument('*mut JSContext', 'aCx'),
- Argument("Box<%s>" % descriptor.concreteType, 'aObject', mutable=True)]
- retval = 'Temporary<%s>' % descriptor.concreteType
- CGAbstractMethod.__init__(self, descriptor, 'Wrap', retval, args, pub=True)
-
- def definition_body(self):
- if not self.descriptor.isGlobal():
- return CGGeneric("""\
-let scope = aScope.reflector().get_jsobject();
-assert!(scope.is_not_null());
-assert!(((*JS_GetClass(scope)).flags & JSCLASS_IS_GLOBAL) != 0);
-
-let proto = with_compartment(aCx, scope, || GetProtoObject(aCx, scope, scope));
-assert!(proto.is_not_null());
-
-%s
-
-raw.reflector().set_jsobject(obj);
-
-Temporary::new(raw)""" % CreateBindingJSObject(self.descriptor, "scope"))
- else:
- return CGGeneric("""\
-%s
-with_compartment(aCx, obj, || {
- let proto = GetProtoObject(aCx, obj, obj);
- JS_SetPrototype(aCx, obj, proto);
-
- raw.reflector().set_jsobject(obj);
-
- RegisterBindings::Register(aCx, obj);
-});
-
-Temporary::new(raw)""" % CreateBindingJSObject(self.descriptor))
-
-
-class CGIDLInterface(CGThing):
- """
- Class for codegen of an implementation of the IDLInterface trait.
- """
- def __init__(self, descriptor):
- CGThing.__init__(self)
- self.descriptor = descriptor
-
- def define(self):
- replacer = {
- 'type': self.descriptor.name,
- 'depth': self.descriptor.interface.inheritanceDepth(),
- }
- return string.Template("""
-impl IDLInterface for ${type} {
- fn get_prototype_id(_: Option<${type}>) -> PrototypeList::id::ID {
- PrototypeList::id::${type}
- }
- fn get_prototype_depth(_: Option<${type}>) -> uint {
- ${depth}
- }
-}
-""").substitute(replacer)
-
-
-class CGAbstractExternMethod(CGAbstractMethod):
- """
- Abstract base class for codegen of implementation-only (no
- declaration) static methods.
- """
- def __init__(self, descriptor, name, returnType, args):
- CGAbstractMethod.__init__(self, descriptor, name, returnType, args,
- inline=False, extern=True)
-
-class PropertyArrays():
- def __init__(self, descriptor):
- self.staticMethods = MethodDefiner(descriptor, "StaticMethods",
- static=True)
- self.staticAttrs = AttrDefiner(descriptor, "StaticAttributes",
- static=True)
- self.methods = MethodDefiner(descriptor, "Methods", static=False)
- self.attrs = AttrDefiner(descriptor, "Attributes", static=False)
- self.consts = ConstDefiner(descriptor, "Constants")
- pass
-
- @staticmethod
- def arrayNames():
- return [ "staticMethods", "staticAttrs", "methods", "attrs", "consts" ]
-
- def variableNames(self):
- names = {}
- for array in self.arrayNames():
- names[array] = getattr(self, array).variableName()
- return names
- def __str__(self):
- define = ""
- for array in self.arrayNames():
- define += str(getattr(self, array))
- return define
-
-
-class CGNativeProperties(CGThing):
- def __init__(self, descriptor, properties):
- CGThing.__init__(self)
- self.properties = properties
-
- def define(self):
- def getField(array):
- propertyArray = getattr(self.properties, array)
- if propertyArray.length() > 0:
- value = "Some(%s)" % propertyArray.variableName()
- else:
- value = "None"
-
- return CGGeneric(string.Template('${name}: ${value},').substitute({
- 'name': array,
- 'value': value,
- }))
-
- nativeProps = CGList([getField(array) for array in self.properties.arrayNames()], '\n')
- return CGWrapper(CGIndenter(nativeProps),
- pre="static sNativeProperties: NativeProperties = NativeProperties {\n",
- post="\n};\n").define()
-
-
-class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
- """
- Generate the CreateInterfaceObjects method for an interface descriptor.
-
- properties should be a PropertyArrays instance.
- """
- def __init__(self, descriptor, properties):
- assert not descriptor.interface.isCallback()
- args = [Argument('*mut JSContext', 'aCx'), Argument('*mut JSObject', 'aGlobal'),
- Argument('*mut JSObject', 'aReceiver')]
- CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', '*mut JSObject', args)
- self.properties = properties
- def definition_body(self):
- protoChain = self.descriptor.prototypeChain
- if len(protoChain) == 1:
- getParentProto = "JS_GetObjectPrototype(aCx, aGlobal)"
- else:
- parentProtoName = self.descriptor.prototypeChain[-2]
- getParentProto = ("%s::GetProtoObject(aCx, aGlobal, aReceiver)" %
- toBindingNamespace(parentProtoName))
-
- getParentProto = ("let parentProto: *mut JSObject = %s;\n"
- "assert!(parentProto.is_not_null());\n") % getParentProto
-
- if self.descriptor.concrete:
- if self.descriptor.proxy:
- domClass = "&Class"
- else:
- domClass = "&Class.dom_class"
- else:
- domClass = "ptr::null()"
-
- if self.descriptor.interface.hasInterfaceObject():
- if self.descriptor.interface.ctor():
- constructHook = CONSTRUCT_HOOK_NAME
- constructArgs = methodLength(self.descriptor.interface.ctor())
- else:
- constructHook = "ThrowingConstructor"
- constructArgs = 0
-
- constructor = 'Some((%s, "%s", %d))' % (
- constructHook, self.descriptor.interface.identifier.name,
- constructArgs)
- else:
- constructor = 'None'
-
- call = """return CreateInterfaceObjects2(aCx, aGlobal, aReceiver, parentProto,
- &PrototypeClass, %s,
- %s,
- &sNativeProperties);""" % (constructor, domClass)
-
- return CGList([
- CGGeneric(getParentProto),
- CGGeneric(call % self.properties.variableNames())
- ], "\n")
-
-class CGGetPerInterfaceObject(CGAbstractMethod):
- """
- A method for getting a per-interface object (a prototype object or interface
- constructor object).
- """
- def __init__(self, descriptor, name, idPrefix="", pub=False):
- args = [Argument('*mut JSContext', 'aCx'), Argument('*mut JSObject', 'aGlobal'),
- Argument('*mut JSObject', 'aReceiver')]
- CGAbstractMethod.__init__(self, descriptor, name,
- '*mut JSObject', args, pub=pub)
- self.id = idPrefix + "id::" + self.descriptor.name
- def definition_body(self):
- return CGGeneric("""
-
-/* aGlobal and aReceiver are usually the same, but they can be different
- too. For example a sandbox often has an xray wrapper for a window as the
- prototype of the sandbox's global. In that case aReceiver is the xray
- wrapper and aGlobal is the sandbox's global.
- */
-
-assert!(((*JS_GetClass(aGlobal)).flags & JSCLASS_DOM_GLOBAL) != 0);
-
-/* Check to see whether the interface objects are already installed */
-let protoOrIfaceArray = GetProtoOrIfaceArray(aGlobal);
-let cachedObject: *mut JSObject = *protoOrIfaceArray.offset(%s as int);
-if cachedObject.is_null() {
- let tmp: *mut JSObject = CreateInterfaceObjects(aCx, aGlobal, aReceiver);
- assert!(tmp.is_not_null());
- *protoOrIfaceArray.offset(%s as int) = tmp;
- tmp
-} else {
- cachedObject
-}""" % (self.id, self.id))
-
-class CGGetProtoObjectMethod(CGGetPerInterfaceObject):
- """
- A method for getting the interface prototype object.
- """
- def __init__(self, descriptor):
- CGGetPerInterfaceObject.__init__(self, descriptor, "GetProtoObject",
- "PrototypeList::", pub=True)
- def definition_body(self):
- return CGList([
- CGGeneric("""\
-/* Get the interface prototype object for this class. This will create the
- object as needed. */"""),
- CGGetPerInterfaceObject.definition_body(self),
- ])
-
-class CGGetConstructorObjectMethod(CGGetPerInterfaceObject):
- """
- A method for getting the interface constructor object.
- """
- def __init__(self, descriptor):
- CGGetPerInterfaceObject.__init__(self, descriptor, "GetConstructorObject",
- "constructors::")
- def definition_body(self):
- return CGList([
- CGGeneric("""\
-/* Get the interface object for this class. This will create the object as
- needed. */"""),
- CGGetPerInterfaceObject.definition_body(self),
- ])
-
-
-class CGDefineProxyHandler(CGAbstractMethod):
- """
- A method to create and cache the proxy trap for a given interface.
- """
- def __init__(self, descriptor):
- assert descriptor.proxy
- CGAbstractMethod.__init__(self, descriptor, 'DefineProxyHandler', '*const libc::c_void', [], pub=True)
-
- def define(self):
- return CGAbstractMethod.define(self)
-
- def definition_body(self):
- body = """\
-let traps = ProxyTraps {
- getPropertyDescriptor: Some(getPropertyDescriptor),
- getOwnPropertyDescriptor: Some(getOwnPropertyDescriptor),
- defineProperty: Some(defineProperty),
- getOwnPropertyNames: ptr::null(),
- delete_: Some(delete_),
- enumerate: ptr::null(),
-
- has: None,
- hasOwn: Some(hasOwn),
- get: Some(get),
- set: None,
- keys: ptr::null(),
- iterate: None,
-
- call: None,
- construct: None,
- nativeCall: ptr::null(),
- hasInstance: None,
- typeOf: None,
- objectClassIs: None,
- obj_toString: Some(obj_toString),
- fun_toString: None,
- //regexp_toShared: ptr::null(),
- defaultValue: None,
- iteratorNext: None,
- finalize: Some(%s),
- getElementIfPresent: None,
- getPrototypeOf: None,
- trace: Some(%s)
-};
-
-CreateProxyHandler(&traps, &Class as *const _ as *const _)
-""" % (FINALIZE_HOOK_NAME,
- TRACE_HOOK_NAME)
- return CGGeneric(body)
-
-
-
-class CGDefineDOMInterfaceMethod(CGAbstractMethod):
- """
- A method for resolve hooks to try to lazily define the interface object for
- a given interface.
- """
- def __init__(self, descriptor):
- assert descriptor.interface.hasInterfaceObject()
- args = [
- Argument('*mut JSContext', 'cx'),
- Argument('*mut JSObject', 'global'),
- ]
- CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', 'void', args, pub=True)
-
- def define(self):
- return CGAbstractMethod.define(self)
-
- def definition_body(self):
- return CGGeneric("""\
-assert!(global.is_not_null());
-assert!(GetProtoObject(cx, global, global).is_not_null());""")
-
-def needCx(returnType, arguments, considerTypes):
- return (considerTypes and
- (typeNeedsCx(returnType, True) or
- any(typeNeedsCx(a.type) for a in arguments)))
-
-class CGCallGenerator(CGThing):
- """
- A class to generate an actual call to a C++ object. Assumes that the C++
- object is stored in a variable whose name is given by the |object| argument.
-
- errorResult should be a string for the value to return in case of an
- exception from the native code, or None if no error reporting is needed.
- """
- def __init__(self, errorResult, arguments, argsPre, returnType,
- extendedAttributes, descriptorProvider, nativeMethodName,
- static, object="this"):
- CGThing.__init__(self)
-
- assert errorResult is None or isinstance(errorResult, str)
-
- isFallible = errorResult is not None
-
- result = getRetvalDeclarationForType(returnType, descriptorProvider)
- if isFallible:
- result = CGWrapper(result, pre="Result<", post=", Error>")
-
- args = CGList([CGGeneric(arg) for arg in argsPre], ", ")
- for (a, name) in arguments:
- #XXXjdm Perhaps we should pass all nontrivial types by borrowed pointer
- if a.type.isGeckoInterface():
- if not (a.type.nullable() or a.optional):
- name = "&" + name
- elif a.type.isDictionary():
- name = "&" + name
- args.append(CGGeneric(name))
-
- needsCx = needCx(returnType, (a for (a, _) in arguments), True)
-
- if not "cx" in argsPre and needsCx:
- args.prepend(CGGeneric("cx"))
-
- # Build up our actual call
- self.cgRoot = CGList([], "\n")
-
- call = CGGeneric(nativeMethodName)
- if static:
- call = CGWrapper(call, pre="%s::" % descriptorProvider.interface.identifier.name)
- else:
- call = CGWrapper(call, pre="(*%s)." % object)
- call = CGList([call, CGWrapper(args, pre="(", post=")")])
-
- self.cgRoot.append(CGList([
- CGGeneric("let result: "),
- result,
- CGGeneric(" = "),
- call,
- CGGeneric(";"),
- ]))
-
- if isFallible:
- if static:
- glob = ""
- else:
- glob = " let global = global_object_for_js_object(this.reflector().get_jsobject());\n"\
- " let global = global.root();\n"
-
- self.cgRoot.append(CGGeneric(
- "let result = match result {\n"
- " Ok(result) => result,\n"
- " Err(e) => {\n"
- "%s"
- " throw_dom_exception(cx, &global.root_ref(), e);\n"
- " return%s;\n"
- " },\n"
- "};\n" % (glob, errorResult)))
-
- if typeRetValNeedsRooting(returnType):
- self.cgRoot.append(CGGeneric("let result = result.root();"))
-
- def define(self):
- return self.cgRoot.define()
-
-class MethodNotCreatorError(Exception):
- def __init__(self, typename):
- self.typename = typename
-
-class CGPerSignatureCall(CGThing):
- """
- This class handles the guts of generating code for a particular
- call signature. A call signature consists of four things:
-
- 1) A return type, which can be None to indicate that there is no
- actual return value (e.g. this is an attribute setter) or an
- IDLType if there's an IDL type involved (including |void|).
- 2) An argument list, which is allowed to be empty.
- 3) A name of a native method to call.
- 4) Whether or not this method is static.
-
- We also need to know whether this is a method or a getter/setter
- to do error reporting correctly.
-
- The idlNode parameter can be either a method or an attr. We can query
- |idlNode.identifier| in both cases, so we can be agnostic between the two.
- """
- # XXXbz For now each entry in the argument list is either an
- # IDLArgument or a FakeArgument, but longer-term we may want to
- # have ways of flagging things like JSContext* or optional_argc in
- # there.
-
- def __init__(self, returnType, argsPre, arguments, nativeMethodName, static,
- descriptor, idlNode, argConversionStartsAt=0,
- getter=False, setter=False):
- CGThing.__init__(self)
- self.returnType = returnType
- self.descriptor = descriptor
- self.idlNode = idlNode
- self.extendedAttributes = descriptor.getExtendedAttributes(idlNode,
- getter=getter,
- setter=setter)
- self.argsPre = argsPre
- self.arguments = arguments
- self.argCount = len(arguments)
- if self.argCount > argConversionStartsAt:
- # Insert our argv in there
- cgThings = [CGGeneric(self.getArgvDecl())]
- else:
- cgThings = []
- cgThings.extend([CGArgumentConverter(arguments[i], i, self.getArgv(),
- self.getArgc(), self.descriptor,
- invalidEnumValueFatal=not setter) for
- i in range(argConversionStartsAt, self.argCount)])
-
- cgThings.append(CGCallGenerator(
- ' false as JSBool' if self.isFallible() else None,
- self.getArguments(), self.argsPre, returnType,
- self.extendedAttributes, descriptor, nativeMethodName,
- static))
- self.cgRoot = CGList(cgThings, "\n")
-
- def getArgv(self):
- return "argv" if self.argCount > 0 else ""
- def getArgvDecl(self):
- return "\nlet argv = JS_ARGV(cx, vp);\n"
- def getArgc(self):
- return "argc"
- def getArguments(self):
- def process(arg, i):
- argVal = "arg" + str(i)
- if arg.type.isGeckoInterface() and not arg.type.unroll().inner.isCallback():
- argVal += ".root_ref()"
- return argVal
- return [(a, process(a, i)) for (i, a) in enumerate(self.arguments)]
-
- def isFallible(self):
- return not 'infallible' in self.extendedAttributes
-
- def wrap_return_value(self):
- return wrapForType('*vp')
-
- def define(self):
- return (self.cgRoot.define() + "\n" + self.wrap_return_value())
-
-class CGSwitch(CGList):
- """
- A class to generate code for a switch statement.
-
- Takes three constructor arguments: an expression, a list of cases,
- and an optional default.
-
- Each case is a CGCase. The default is a CGThing for the body of
- the default case, if any.
- """
- def __init__(self, expression, cases, default=None):
- CGList.__init__(self, [CGIndenter(c) for c in cases], "\n")
- self.prepend(CGWrapper(CGGeneric(expression),
- pre="match ", post=" {"));
- if default is not None:
- self.append(
- CGIndenter(
- CGWrapper(
- CGIndenter(default),
- pre="_ => {\n",
- post="\n}"
- )
- )
- )
-
- self.append(CGGeneric("}"))
-
-class CGCase(CGList):
- """
- A class to generate code for a case statement.
-
- Takes three constructor arguments: an expression, a CGThing for
- the body (allowed to be None if there is no body), and an optional
- argument (defaulting to False) for whether to fall through.
- """
- def __init__(self, expression, body, fallThrough=False):
- CGList.__init__(self, [], "\n")
- self.append(CGWrapper(CGGeneric(expression), post=" => {"))
- bodyList = CGList([body], "\n")
- if fallThrough:
- raise TypeError("fall through required but unsupported")
- #bodyList.append(CGGeneric('fail!("fall through unsupported"); /* Fall through */'))
- self.append(CGIndenter(bodyList));
- self.append(CGGeneric("}"))
-
-class CGGetterCall(CGPerSignatureCall):
- """
- A class to generate a native object getter call for a particular IDL
- getter.
- """
- def __init__(self, argsPre, returnType, nativeMethodName, descriptor, attr):
- CGPerSignatureCall.__init__(self, returnType, argsPre, [],
- nativeMethodName, attr.isStatic(), descriptor,
- attr, getter=True)
-
-class FakeArgument():
- """
- A class that quacks like an IDLArgument. This is used to make
- setters look like method calls or for special operations.
- """
- def __init__(self, type, interfaceMember, allowTreatNonObjectAsNull=False):
- self.type = type
- self.optional = False
- 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
-
-class CGSetterCall(CGPerSignatureCall):
- """
- A class to generate a native object setter call for a particular IDL
- setter.
- """
- def __init__(self, argsPre, argType, nativeMethodName, descriptor, attr):
- CGPerSignatureCall.__init__(self, None, argsPre,
- [FakeArgument(argType, attr, allowTreatNonObjectAsNull=True)],
- nativeMethodName, attr.isStatic(), descriptor, attr,
- setter=True)
- def wrap_return_value(self):
- # We have no return value
- return "\nreturn 1;"
- def getArgc(self):
- return "1"
- def getArgvDecl(self):
- # We just get our stuff from our last arg no matter what
- return ""
-
-class CGAbstractBindingMethod(CGAbstractExternMethod):
- """
- Common class to generate the JSNatives for all our methods, getters, and
- setters. This will generate the function declaration and unwrap the
- |this| object. Subclasses are expected to override the generate_code
- function to do the rest of the work. This function should return a
- CGThing which is already properly indented.
- """
- def __init__(self, descriptor, name, args, unwrapFailureCode=None):
- CGAbstractExternMethod.__init__(self, descriptor, name, "JSBool", args)
-
- if unwrapFailureCode is None:
- self.unwrapFailureCode = (
- 'throw_type_error(cx, "\\"this\\" object does not '
- 'implement interface %s.");\n'
- 'return 0;' % descriptor.interface.identifier.name)
- else:
- self.unwrapFailureCode = unwrapFailureCode
-
- def definition_body(self):
- # Our descriptor might claim that we're not castable, simply because
- # we're someone's consequential interface. But for this-unwrapping, we
- # know that we're the real deal. So fake a descriptor here for
- # consumption by FailureFatalCastableObjectUnwrapper.
- unwrapThis = str(CastableObjectUnwrapper(
- FakeCastableDescriptor(self.descriptor),
- "obj", self.unwrapFailureCode))
- unwrapThis = CGGeneric(
- "let obj: *mut JSObject = JS_THIS_OBJECT(cx, vp as *mut JSVal);\n"
- "if obj.is_null() {\n"
- " return false as JSBool;\n"
- "}\n"
- "\n"
- "let this: JS<%s> = %s;\n" % (self.descriptor.concreteType, unwrapThis))
- return CGList([ unwrapThis, self.generate_code() ], "\n")
-
- def generate_code(self):
- assert(False) # Override me
-
-
-class CGAbstractStaticBindingMethod(CGAbstractMethod):
- """
- Common class to generate the JSNatives for all our static methods, getters
- and setters. This will generate the function declaration and unwrap the
- global object. Subclasses are expected to override the generate_code
- function to do the rest of the work. This function should return a
- CGThing which is already properly indented.
- """
- def __init__(self, descriptor, name):
- args = [
- Argument('*mut JSContext', 'cx'),
- Argument('libc::c_uint', 'argc'),
- Argument('*mut JSVal', 'vp'),
- ]
- CGAbstractMethod.__init__(self, descriptor, name, "JSBool", args, extern=True)
-
- def definition_body(self):
- return self.generate_code()
-
- def generate_code(self):
- assert False # Override me
-
-
-class CGGenericMethod(CGAbstractBindingMethod):
- """
- A class for generating the C++ code for an IDL method..
- """
- def __init__(self, descriptor):
- args = [Argument('*mut JSContext', 'cx'), Argument('libc::c_uint', 'argc'),
- Argument('*mut JSVal', 'vp')]
- CGAbstractBindingMethod.__init__(self, descriptor, 'genericMethod', args)
-
- def generate_code(self):
- return CGGeneric(
- "let _info: *const JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n"
- "return CallJitMethodOp(_info, cx, obj, this.unsafe_get() as *mut libc::c_void, argc, vp);")
-
-class CGSpecializedMethod(CGAbstractExternMethod):
- """
- A class for generating the C++ code for a specialized method that the JIT
- can call with lower overhead.
- """
- def __init__(self, descriptor, method):
- self.method = method
- name = method.identifier.name
- args = [Argument('*mut JSContext', 'cx'), Argument('JSHandleObject', '_obj'),
- Argument('*const %s' % descriptor.concreteType, 'this'),
- Argument('libc::c_uint', 'argc'), Argument('*mut JSVal', 'vp')]
- CGAbstractExternMethod.__init__(self, descriptor, name, 'JSBool', args)
-
- def definition_body(self):
- nativeName = CGSpecializedMethod.makeNativeName(self.descriptor,
- self.method)
- return CGWrapper(CGMethodCall([], nativeName, self.method.isStatic(),
- self.descriptor, self.method),
- pre="let this = JS::from_raw(this);\n"
- "let this = this.root();\n")
-
- @staticmethod
- def makeNativeName(descriptor, method):
- return MakeNativeName(method.identifier.name)
-
-class CGStaticMethod(CGAbstractStaticBindingMethod):
- """
- A class for generating the Rust code for an IDL static method.
- """
- def __init__(self, descriptor, method):
- self.method = method
- name = method.identifier.name
- CGAbstractStaticBindingMethod.__init__(self, descriptor, name)
-
- def generate_code(self):
- nativeName = CGSpecializedMethod.makeNativeName(self.descriptor,
- self.method)
- return CGMethodCall([], nativeName, True, self.descriptor, self.method)
-
-
-class CGGenericGetter(CGAbstractBindingMethod):
- """
- A class for generating the C++ code for an IDL attribute getter.
- """
- def __init__(self, descriptor, lenientThis=False):
- args = [Argument('*mut JSContext', 'cx'), Argument('libc::c_uint', 'argc'),
- Argument('*mut JSVal', 'vp')]
- if lenientThis:
- name = "genericLenientGetter"
- unwrapFailureCode = (
- "MOZ_ASSERT(!JS_IsExceptionPending(cx));\n"
- "JS_SET_RVAL(cx, vp, JS::UndefinedValue());\n"
- "return true;")
- else:
- name = "genericGetter"
- unwrapFailureCode = None
- CGAbstractBindingMethod.__init__(self, descriptor, name, args,
- unwrapFailureCode)
-
- def generate_code(self):
- return CGGeneric(
- "let info: *const JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n"
- "return CallJitPropertyOp(info, cx, obj, this.unsafe_get() as *mut libc::c_void, vp);\n")
-
-class CGSpecializedGetter(CGAbstractExternMethod):
- """
- A class for generating the code for a specialized attribute getter
- that the JIT can call with lower overhead.
- """
- def __init__(self, descriptor, attr):
- self.attr = attr
- name = 'get_' + attr.identifier.name
- args = [ Argument('*mut JSContext', 'cx'),
- Argument('JSHandleObject', '_obj'),
- Argument('*const %s' % descriptor.concreteType, 'this'),
- Argument('*mut JSVal', 'vp') ]
- CGAbstractExternMethod.__init__(self, descriptor, name, "JSBool", args)
-
- def definition_body(self):
- nativeName = CGSpecializedGetter.makeNativeName(self.descriptor,
- self.attr)
-
- return CGWrapper(CGGetterCall([], self.attr.type, nativeName,
- self.descriptor, self.attr),
- pre="let this = JS::from_raw(this);\n"
- "let this = this.root();\n")
-
- @staticmethod
- def makeNativeName(descriptor, attr):
- nativeName = MakeNativeName(attr.identifier.name)
- infallible = ('infallible' in
- descriptor.getExtendedAttributes(attr, getter=True))
- if attr.type.nullable() or not infallible:
- return "Get" + nativeName
-
- return nativeName
-
-
-class CGStaticGetter(CGAbstractStaticBindingMethod):
- """
- A class for generating the C++ code for an IDL static attribute getter.
- """
- def __init__(self, descriptor, attr):
- self.attr = attr
- name = 'get_' + attr.identifier.name
- CGAbstractStaticBindingMethod.__init__(self, descriptor, name)
-
- def generate_code(self):
- nativeName = CGSpecializedGetter.makeNativeName(self.descriptor,
- self.attr)
- return CGGetterCall([], self.attr.type, nativeName, self.descriptor,
- self.attr)
-
-
-class CGGenericSetter(CGAbstractBindingMethod):
- """
- A class for generating the Rust code for an IDL attribute setter.
- """
- def __init__(self, descriptor, lenientThis=False):
- args = [Argument('*mut JSContext', 'cx'), Argument('libc::c_uint', 'argc'),
- Argument('*mut JSVal', 'vp')]
- if lenientThis:
- name = "genericLenientSetter"
- unwrapFailureCode = (
- "MOZ_ASSERT(!JS_IsExceptionPending(cx));\n"
- "return true;")
- else:
- name = "genericSetter"
- unwrapFailureCode = None
- CGAbstractBindingMethod.__init__(self, descriptor, name, args,
- unwrapFailureCode)
-
- def generate_code(self):
- return CGGeneric(
- "let mut undef = UndefinedValue();\n"
- "let argv: *mut JSVal = if argc != 0 { JS_ARGV(cx, vp) } else { &mut undef as *mut JSVal };\n"
- "let info: *const JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n"
- "if CallJitPropertyOp(info, cx, obj, this.unsafe_get() as *mut libc::c_void, argv) == 0 {\n"
- " return 0;\n"
- "}\n"
- "*vp = UndefinedValue();\n"
- "return 1;")
-
-class CGSpecializedSetter(CGAbstractExternMethod):
- """
- A class for generating the code for a specialized attribute setter
- that the JIT can call with lower overhead.
- """
- def __init__(self, descriptor, attr):
- self.attr = attr
- name = 'set_' + attr.identifier.name
- args = [ Argument('*mut JSContext', 'cx'),
- Argument('JSHandleObject', '_obj'),
- Argument('*const %s' % descriptor.concreteType, 'this'),
- Argument('*mut JSVal', 'argv')]
- CGAbstractExternMethod.__init__(self, descriptor, name, "JSBool", args)
-
- def definition_body(self):
- nativeName = CGSpecializedSetter.makeNativeName(self.descriptor,
- self.attr)
- return CGWrapper(CGSetterCall([], self.attr.type, nativeName,
- self.descriptor, self.attr),
- pre="let this = JS::from_raw(this);\n"
- "let this = this.root();\n")
-
- @staticmethod
- def makeNativeName(descriptor, attr):
- return "Set" + MakeNativeName(attr.identifier.name)
-
-
-class CGStaticSetter(CGAbstractStaticBindingMethod):
- """
- A class for generating the C++ code for an IDL static attribute setter.
- """
- def __init__(self, descriptor, attr):
- self.attr = attr
- name = 'set_' + attr.identifier.name
- CGAbstractStaticBindingMethod.__init__(self, descriptor, name)
-
- def generate_code(self):
- nativeName = CGSpecializedSetter.makeNativeName(self.descriptor,
- self.attr)
- checkForArg = CGGeneric(
- "let argv = JS_ARGV(cx, vp);\n"
- "if (argc == 0) {\n"
- " throw_type_error(cx, \"Not enough arguments to %s setter.\");\n"
- " return 0;\n"
- "}\n" % self.attr.identifier.name)
- call = CGSetterCall([], self.attr.type, nativeName, self.descriptor,
- self.attr)
- return CGList([checkForArg, call])
-
-
-class CGMemberJITInfo(CGThing):
- """
- A class for generating the JITInfo for a property that points to
- our specialized getter and setter.
- """
- def __init__(self, descriptor, member):
- self.member = member
- self.descriptor = descriptor
-
- def defineJitInfo(self, infoName, opName, infallible):
- protoID = "PrototypeList::id::%s as u32" % self.descriptor.name
- depth = self.descriptor.interface.inheritanceDepth()
- failstr = "true" if infallible else "false"
- return ("\n"
- "static %s: JSJitInfo = JSJitInfo {\n"
- " op: %s as *const u8,\n"
- " protoID: %s,\n"
- " depth: %s,\n"
- " isInfallible: %s, /* False in setters. */\n"
- " isConstant: false /* Only relevant for getters. */\n"
- "};\n" % (infoName, opName, protoID, depth, failstr))
-
- def define(self):
- if self.member.isAttr():
- getterinfo = ("%s_getterinfo" % self.member.identifier.name)
- getter = ("get_%s" % self.member.identifier.name)
- getterinfal = "infallible" in self.descriptor.getExtendedAttributes(self.member, getter=True)
- result = self.defineJitInfo(getterinfo, getter, getterinfal)
- if not self.member.readonly:
- setterinfo = ("%s_setterinfo" % self.member.identifier.name)
- setter = ("set_%s" % self.member.identifier.name)
- # Setters are always fallible, since they have to do a typed unwrap.
- result += self.defineJitInfo(setterinfo, setter, False)
- return result
- if self.member.isMethod():
- methodinfo = ("%s_methodinfo" % self.member.identifier.name)
- # Actually a JSJitMethodOp, but JSJitPropertyOp by struct definition.
- method = ("%s" % self.member.identifier.name)
-
- # Methods are infallible if they are infallible, have no arguments
- # to unwrap, and have a return type that's infallible to wrap up for
- # return.
- methodInfal = False
- sigs = self.member.signatures()
- if len(sigs) == 1:
- # Don't handle overloading. If there's more than one signature,
- # one of them must take arguments.
- sig = sigs[0]
- if len(sig[1]) == 0:
- # No arguments and infallible return boxing
- methodInfal = True
-
- result = self.defineJitInfo(methodinfo, method, methodInfal)
- return result
- raise TypeError("Illegal member type to CGPropertyJITInfo")
-
-def getEnumValueName(value):
- # Some enum values can be empty strings. Others might have weird
- # characters in them. Deal with the former by returning "_empty",
- # deal with possible name collisions from that by throwing if the
- # enum value is actually "_empty", and throw on any value
- # containing non-ASCII chars for now. Replace all chars other than
- # [0-9A-Za-z_] with '_'.
- 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 = 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')
- if value == "_empty":
- raise SyntaxError('"_empty" is not an IDL enum value we support yet')
- if value == "":
- return "_empty"
- return MakeNativeName(value)
-
-class CGEnum(CGThing):
- def __init__(self, enum):
- CGThing.__init__(self)
- inner = """
-use dom::bindings::conversions::ToJSValConvertible;
-use js::jsapi::JSContext;
-use js::jsval::JSVal;
-
-#[repr(uint)]
-#[deriving(Encodable, PartialEq)]
-pub enum valuelist {
- %s
-}
-
-pub static strings: &'static [&'static str] = &[
- %s,
-];
-
-impl ToJSValConvertible for valuelist {
- fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
- strings[*self as uint].to_string().to_jsval(cx)
- }
-}
-""" % (",\n ".join(map(getEnumValueName, enum.values())),
- ",\n ".join(['"%s"' % val for val in enum.values()]))
-
- self.cgRoot = CGList([
- CGNamespace.build([enum.identifier.name + "Values"],
- CGIndenter(CGGeneric(inner)), public=True),
- CGGeneric("pub type %s = self::%sValues::valuelist;\n" %
- (enum.identifier.name, enum.identifier.name)),
- ])
-
- def define(self):
- return self.cgRoot.define()
-
-
-def convertConstIDLValueToRust(value):
- tag = value.type.tag()
- if tag in [IDLType.Tags.int8, IDLType.Tags.uint8,
- IDLType.Tags.int16, IDLType.Tags.uint16,
- IDLType.Tags.int32, IDLType.Tags.uint32,
- IDLType.Tags.int64, IDLType.Tags.uint64,
- IDLType.Tags.float, IDLType.Tags.double]:
- return str(value.value)
-
- if tag == IDLType.Tags.bool:
- return toStringBool(value.value)
-
- raise TypeError("Const value of unhandled type: " + value.type)
-
-class CGConstant(CGThing):
- def __init__(self, constants):
- CGThing.__init__(self)
- self.constants = constants
-
- def define(self):
- def stringDecl(const):
- name = const.identifier.name
- value = convertConstIDLValueToRust(const.value)
- return CGGeneric("pub static %s: %s = %s;\n" % (name, builtinNames[const.value.type.tag()], value))
-
- return CGIndenter(CGList(stringDecl(m) for m in self.constants)).define()
-
-def getUnionTypeTemplateVars(type, descriptorProvider):
- # For dictionaries and sequences we need to pass None as the failureCode
- # for getJSToNativeConversionTemplate.
- # Also, for dictionaries we would need to handle conversion of
- # null/undefined to the dictionary correctly.
- if type.isDictionary() or type.isSequence():
- raise TypeError("Can't handle dictionaries or sequences in unions")
-
- if type.isGeckoInterface():
- name = type.inner.identifier.name
- typeName = descriptorProvider.getDescriptor(name).nativeType
- elif type.isEnum():
- name = type.inner.identifier.name
- typeName = name
- elif type.isArray() or type.isSequence():
- name = str(type)
- #XXXjdm dunno about typeName here
- typeName = "/*" + type.name + "*/"
- elif type.isDOMString():
- name = type.name
- typeName = "DOMString"
- elif type.isPrimitive():
- name = type.name
- typeName = builtinNames[type.tag()]
- else:
- name = type.name
- typeName = "/*" + type.name + "*/"
-
- template, _, _, _ = getJSToNativeConversionTemplate(
- type, descriptorProvider, failureCode="return Ok(None);",
- exceptionCode='return Err(());',
- isDefinitelyObject=True)
-
- assert not type.isObject()
- jsConversion = string.Template(template).substitute({
- "val": "value",
- })
- jsConversion = CGWrapper(CGGeneric(jsConversion), pre="Ok(Some(", post="))")
-
- return {
- "name": name,
- "typeName": typeName,
- "jsConversion": jsConversion,
- }
-
-class CGUnionStruct(CGThing):
- def __init__(self, type, descriptorProvider):
- assert not type.nullable()
- assert not type.hasNullableType
-
- CGThing.__init__(self)
- self.type = type
- self.descriptorProvider = descriptorProvider
-
- def define(self):
- templateVars = map(lambda t: getUnionTypeTemplateVars(t, self.descriptorProvider),
- self.type.flatMemberTypes)
- enumValues = [
- " e%s(%s)," % (v["name"], v["typeName"]) for v in templateVars
- ]
- enumConversions = [
- " e%s(ref inner) => inner.to_jsval(cx)," % v["name"] for v in templateVars
- ]
- return ("""pub enum %s {
-%s
-}
-
-impl ToJSValConvertible for %s {
- fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
- match *self {
-%s
- }
- }
-}
-""") % (self.type, "\n".join(enumValues),
- self.type, "\n".join(enumConversions))
-
-
-class CGUnionConversionStruct(CGThing):
- def __init__(self, type, descriptorProvider):
- assert not type.nullable()
- assert not type.hasNullableType
-
- CGThing.__init__(self)
- self.type = type
- self.descriptorProvider = descriptorProvider
-
- def from_jsval(self):
- memberTypes = self.type.flatMemberTypes
- names = []
- conversions = []
-
- interfaceMemberTypes = filter(lambda t: t.isNonCallbackInterface(), memberTypes)
- if len(interfaceMemberTypes) > 0:
- def get_name(memberType):
- if self.type.isGeckoInterface():
- return memberType.inner.identifier.name
-
- return memberType.name
-
- def get_match(name):
- return (
- "match %s::TryConvertTo%s(cx, value) {\n"
- " Err(_) => return Err(()),\n"
- " Ok(Some(value)) => return Ok(e%s(value)),\n"
- " Ok(None) => (),\n"
- "}\n") % (self.type, name, name)
-
- typeNames = [get_name(memberType) for memberType in interfaceMemberTypes]
- interfaceObject = CGList(CGGeneric(get_match(typeName)) for typeName in typeNames)
- names.extend(typeNames)
- else:
- interfaceObject = None
-
- arrayObjectMemberTypes = filter(lambda t: t.isArray() or t.isSequence(), memberTypes)
- if len(arrayObjectMemberTypes) > 0:
- assert len(arrayObjectMemberTypes) == 1
- raise TypeError("Can't handle arrays or sequences in unions.")
- 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
- raise TypeError("Can't handle callbacks in unions.")
- else:
- callbackObject = None
-
- dictionaryMemberTypes = filter(lambda t: t.isDictionary(), memberTypes)
- if len(dictionaryMemberTypes) > 0:
- raise TypeError("No support for unwrapping dictionaries as member "
- "of a union")
- else:
- dictionaryObject = None
-
- if callbackObject or dictionaryObject:
- assert False, "Not currently supported"
- else:
- nonPlatformObject = None
-
- objectMemberTypes = filter(lambda t: t.isObject(), memberTypes)
- if len(objectMemberTypes) > 0:
- raise TypeError("Can't handle objects in unions.")
- else:
- object = None
-
- hasObjectTypes = interfaceObject or arrayObject or dateObject or nonPlatformObject or object
- if hasObjectTypes:
- assert interfaceObject
- templateBody = CGList([interfaceObject], "\n")
- conversions.append(CGIfWrapper(templateBody, "value.is_object()"))
-
- otherMemberTypes = [
- t for t in memberTypes if t.isPrimitive() or t.isString() or t.isEnum()
- ]
- if len(otherMemberTypes) > 0:
- assert len(otherMemberTypes) == 1
- memberType = otherMemberTypes[0]
- if memberType.isEnum():
- name = memberType.inner.identifier.name
- else:
- name = memberType.name
- match = (
- "match %s::TryConvertTo%s(cx, value) {\n"
- " Err(_) => return Err(()),\n"
- " Ok(Some(value)) => return Ok(e%s(value)),\n"
- " Ok(None) => (),\n"
- "}\n") % (self.type, name, name)
- conversions.append(CGGeneric(match))
- names.append(name)
-
- conversions.append(CGGeneric(
- "throw_not_in_union(cx, \"%s\");\n"
- "Err(())" % ", ".join(names)))
- method = CGWrapper(
- CGIndenter(CGList(conversions, "\n\n")),
- pre="fn from_jsval(cx: *mut JSContext, value: JSVal, _option: ()) -> Result<%s, ()> {\n" % self.type,
- post="\n}")
- return CGWrapper(
- CGIndenter(method),
- pre="impl FromJSValConvertible<()> for %s {\n" % self.type,
- post="\n}")
-
- def try_method(self, t):
- templateVars = getUnionTypeTemplateVars(t, self.descriptorProvider)
- returnType = "Result<Option<%s>, ()>" % templateVars["typeName"]
- jsConversion = templateVars["jsConversion"]
-
- return CGWrapper(
- CGIndenter(jsConversion, 4),
- pre="fn TryConvertTo%s(cx: *mut JSContext, value: JSVal) -> %s {\n" % (t.name, returnType),
- post="\n}")
-
- def define(self):
- from_jsval = self.from_jsval()
- methods = CGIndenter(CGList([
- self.try_method(t) for t in self.type.flatMemberTypes
- ], "\n\n"))
- return """
-%s
-
-impl %s {
-%s
-}
-""" % (from_jsval.define(), self.type, methods.define())
-
-
-class ClassItem:
- """ Use with CGClass """
- def __init__(self, name, visibility):
- self.name = name
- self.visibility = visibility
- def declare(self, cgClass):
- assert False
- def define(self, cgClass):
- assert False
-
-class ClassBase(ClassItem):
- def __init__(self, name, visibility='pub'):
- ClassItem.__init__(self, name, visibility)
- def declare(self, cgClass):
- return '%s %s' % (self.visibility, self.name)
- def define(self, cgClass):
- # Only in the header
- return ''
-
-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",
- breakAfterSelf="\n", override=False):
- """
- override indicates whether to flag the method as MOZ_OVERRIDE
- """
- assert not override or virtual
- self.returnType = returnType
- self.args = args
- self.inline = False
- self.static = static
- self.virtual = virtual
- self.const = const
- self.bodyInHeader = True
- self.templateArgs = templateArgs
- self.body = body
- self.breakAfterReturnDecl = breakAfterReturnDecl
- self.breakAfterSelf = breakAfterSelf
- self.override = override
- ClassItem.__init__(self, name, visibility)
-
- def getDecorators(self, declaring):
- decorators = []
- if self.inline:
- decorators.append('inline')
- if declaring:
- if self.static:
- decorators.append('static')
- if self.virtual:
- decorators.append('virtual')
- if decorators:
- return ' '.join(decorators) + ' '
- return ''
-
- def getBody(self):
- # Override me or pass a string to constructor
- assert self.body is not None
- return self.body
-
- def declare(self, cgClass):
- templateClause = '<%s>' % ', '.join(self.templateArgs) \
- if self.bodyInHeader and self.templateArgs else ''
- args = ', '.join([a.declare() for a in self.args])
- if self.bodyInHeader:
- body = CGIndenter(CGGeneric(self.getBody())).define()
- body = ' {\n' + body + '\n}'
- else:
- body = ';'
-
- return string.Template("${decorators}%s"
- "${visibility}fn ${name}${templateClause}(${args})${returnType}${const}${override}${body}%s" %
- (self.breakAfterReturnDecl, self.breakAfterSelf)
- ).substitute({
- 'templateClause': templateClause,
- 'decorators': self.getDecorators(True),
- 'returnType': (" -> %s" % self.returnType) if self.returnType else "",
- 'name': self.name,
- 'const': ' const' if self.const else '',
- 'override': ' MOZ_OVERRIDE' if self.override else '',
- 'args': args,
- 'body': body,
- 'visibility': self.visibility + ' ' if self.visibility is not 'priv' else ''
- })
-
- def define(self, cgClass):
- pass
-
-class ClassUsingDeclaration(ClassItem):
- """"
- Used for importing a name from a base class into a CGClass
-
- baseClass is the name of the base class to import the name from
-
- name is the name to import
-
- visibility determines the visibility of the name (public,
- protected, private), defaults to public.
- """
- def __init__(self, baseClass, name, visibility='public'):
- self.baseClass = baseClass
- ClassItem.__init__(self, name, visibility)
-
- def declare(self, cgClass):
- return string.Template("""using ${baseClass}::${name};
-""").substitute({ 'baseClass': self.baseClass,
- 'name': self.name })
-
- def define(self, cgClass):
- return ''
-
-class ClassConstructor(ClassItem):
- """
- Used for adding a constructor to a CGClass.
-
- args is a list of Argument objects that are the arguments taken by the
- constructor.
-
- inline should be True if the constructor should be marked inline.
-
- bodyInHeader should be True if the body should be placed in the class
- declaration in the header.
-
- visibility determines the visibility of the constructor (public,
- protected, private), defaults to private.
-
- explicit should be True if the constructor should be marked explicit.
-
- baseConstructors is a list of strings containing calls to base constructors,
- defaults to None.
-
- body contains a string with the code for the constructor, defaults to empty.
- """
- def __init__(self, args, inline=False, bodyInHeader=False,
- visibility="priv", explicit=False, baseConstructors=None,
- body=""):
- self.args = args
- self.inline = False
- self.bodyInHeader = bodyInHeader
- self.explicit = explicit
- self.baseConstructors = baseConstructors or []
- self.body = body
- ClassItem.__init__(self, None, visibility)
-
- def getDecorators(self, declaring):
- decorators = []
- if self.explicit:
- decorators.append('explicit')
- if self.inline and declaring:
- decorators.append('inline')
- if decorators:
- return ' '.join(decorators) + ' '
- return ''
-
- def getInitializationList(self, cgClass):
- items = [str(c) for c in self.baseConstructors]
- for m in cgClass.members:
- if not m.static:
- initialize = m.body
- if initialize:
- items.append(m.name + "(" + initialize + ")")
-
- if len(items) > 0:
- return '\n : ' + ',\n '.join(items)
- return ''
-
- def getBody(self, cgClass):
- initializers = [" parent: %s" % str(self.baseConstructors[0])]
- return (self.body + (
- "%s {\n"
- "%s\n"
- "}") % (cgClass.name, '\n'.join(initializers)))
-
- def declare(self, cgClass):
- args = ', '.join([a.declare() for a in self.args])
- body = ' ' + self.getBody(cgClass);
- body = stripTrailingWhitespace(body.replace('\n', '\n '))
- if len(body) > 0:
- body += '\n'
- body = ' {\n' + body + '}'
-
- return string.Template("""pub fn ${decorators}new(${args}) -> ${className}${body}
-""").substitute({ 'decorators': self.getDecorators(True),
- 'className': cgClass.getNameString(),
- 'args': args,
- 'body': body })
-
- def define(self, cgClass):
- if self.bodyInHeader:
- return ''
-
- args = ', '.join([a.define() for a in self.args])
-
- body = ' ' + self.getBody()
- body = '\n' + stripTrailingWhitespace(body.replace('\n', '\n '))
- if len(body) > 0:
- body += '\n'
-
- return string.Template("""${decorators}
-${className}::${className}(${args})${initializationList}
-{${body}}
-""").substitute({ 'decorators': self.getDecorators(False),
- 'className': cgClass.getNameString(),
- 'args': args,
- 'initializationList': self.getInitializationList(cgClass),
- 'body': body })
-
-class ClassDestructor(ClassItem):
- """
- Used for adding a destructor to a CGClass.
-
- inline should be True if the destructor should be marked inline.
-
- bodyInHeader should be True if the body should be placed in the class
- declaration in the header.
-
- visibility determines the visibility of the destructor (public,
- protected, private), defaults to private.
-
- body contains a string with the code for the destructor, defaults to empty.
-
- virtual determines whether the destructor is virtual, defaults to False.
- """
- def __init__(self, inline=False, bodyInHeader=False,
- visibility="private", body='', virtual=False):
- self.inline = inline or bodyInHeader
- self.bodyInHeader = bodyInHeader
- self.body = body
- self.virtual = virtual
- ClassItem.__init__(self, None, visibility)
-
- def getDecorators(self, declaring):
- decorators = []
- if self.virtual and declaring:
- decorators.append('virtual')
- if self.inline and declaring:
- decorators.append('inline')
- if decorators:
- return ' '.join(decorators) + ' '
- return ''
-
- def getBody(self):
- return self.body
-
- def declare(self, cgClass):
- if self.bodyInHeader:
- body = ' ' + self.getBody();
- body = stripTrailingWhitespace(body.replace('\n', '\n '))
- if len(body) > 0:
- body += '\n'
- body = '\n{\n' + body + '}'
- else:
- body = ';'
-
- return string.Template("""${decorators}~${className}()${body}
-""").substitute({ 'decorators': self.getDecorators(True),
- 'className': cgClass.getNameString(),
- 'body': body })
-
- def define(self, cgClass):
- if self.bodyInHeader:
- return ''
-
- body = ' ' + self.getBody()
- body = '\n' + stripTrailingWhitespace(body.replace('\n', '\n '))
- if len(body) > 0:
- body += '\n'
-
- return string.Template("""${decorators}
-${className}::~${className}()
-{${body}}
-""").substitute({ 'decorators': self.getDecorators(False),
- 'className': cgClass.getNameString(),
- 'body': body })
-
-class ClassMember(ClassItem):
- def __init__(self, name, type, visibility="priv", static=False,
- body=None):
- self.type = type;
- self.static = static
- self.body = body
- ClassItem.__init__(self, name, visibility)
-
- def declare(self, cgClass):
- return '%s %s: %s,\n' % (self.visibility, self.name, self.type)
-
- def define(self, cgClass):
- if not self.static:
- return ''
- if self.body:
- body = " = " + self.body
- else:
- body = ""
- return '%s %s::%s%s;\n' % (self.type, cgClass.getNameString(),
- self.name, body)
-
-class ClassTypedef(ClassItem):
- def __init__(self, name, type, visibility="public"):
- self.type = type
- ClassItem.__init__(self, name, visibility)
-
- def declare(self, cgClass):
- return 'typedef %s %s;\n' % (self.type, self.name)
-
- def define(self, cgClass):
- # Only goes in the header
- return ''
-
-class ClassEnum(ClassItem):
- def __init__(self, name, entries, values=None, visibility="public"):
- self.entries = entries
- self.values = values
- ClassItem.__init__(self, name, visibility)
-
- def declare(self, cgClass):
- entries = []
- for i in range(0, len(self.entries)):
- if not self.values or i >= len(self.values):
- entry = '%s' % self.entries[i]
- else:
- entry = '%s = %s' % (self.entries[i], self.values[i])
- entries.append(entry)
- name = '' if not self.name else ' ' + self.name
- return 'enum%s\n{\n %s\n};\n' % (name, ',\n '.join(entries))
-
- def define(self, cgClass):
- # Only goes in the header
- return ''
-
-class ClassUnion(ClassItem):
- def __init__(self, name, entries, visibility="public"):
- self.entries = [entry + ";" for entry in entries]
- ClassItem.__init__(self, name, visibility)
-
- def declare(self, cgClass):
- return 'union %s\n{\n %s\n};\n' % (self.name, '\n '.join(self.entries))
-
- def define(self, cgClass):
- # Only goes in the header
- return ''
-
-class CGClass(CGThing):
- def __init__(self, name, bases=[], members=[], constructors=[],
- destructor=None, methods=[],
- typedefs = [], enums=[], unions=[], templateArgs=[],
- templateSpecialization=[], isStruct=False,
- disallowCopyConstruction=False, indent='',
- decorators='',
- extradeclarations='',
- extradefinitions=''):
- CGThing.__init__(self)
- self.name = name
- self.bases = bases
- self.members = members
- self.constructors = constructors
- # We store our single destructor in a list, since all of our
- # code wants lists of members.
- self.destructors = [destructor] if destructor else []
- self.methods = methods
- self.typedefs = typedefs
- self.enums = enums
- self.unions = unions
- self.templateArgs = templateArgs
- self.templateSpecialization = templateSpecialization
- self.isStruct = isStruct
- self.disallowCopyConstruction = disallowCopyConstruction
- self.indent = indent
- self.decorators = decorators
- self.extradeclarations = extradeclarations
- self.extradefinitions = extradefinitions
-
- def getNameString(self):
- className = self.name
- if self.templateSpecialization:
- className = className + \
- '<%s>' % ', '.join([str(a) for a
- in self.templateSpecialization])
- return className
-
- def define(self):
- result = ''
- if self.templateArgs:
- templateArgs = [a.declare() for a in self.templateArgs]
- templateArgs = templateArgs[len(self.templateSpecialization):]
- result = result + self.indent + 'template <%s>\n' \
- % ','.join([str(a) for a in templateArgs])
-
- if self.templateSpecialization:
- specialization = \
- '<%s>' % ', '.join([str(a) for a in self.templateSpecialization])
- else:
- specialization = ''
-
- myself = ''
- if self.decorators != '':
- myself += self.decorators + '\n'
- myself += '%spub struct %s%s' % (self.indent, self.name, specialization)
- result += myself
-
- assert len(self.bases) == 1 #XXjdm Can we support multiple inheritance?
-
- result += '{\n%s\n' % self.indent
-
- if self.bases:
- self.members = [ClassMember("parent", self.bases[0].name, "pub")] + self.members
-
- result += CGIndenter(CGGeneric(self.extradeclarations),
- len(self.indent)).define()
-
- def declareMembers(cgClass, memberList):
- result = ''
-
- for member in memberList:
- declaration = member.declare(cgClass)
- declaration = CGIndenter(CGGeneric(declaration)).define()
- result = result + declaration
- return result
-
- if self.disallowCopyConstruction:
- class DisallowedCopyConstructor(object):
- def __init__(self):
- self.visibility = "private"
- def declare(self, cgClass):
- name = cgClass.getNameString()
- return ("%s(const %s&) MOZ_DELETE;\n"
- "void operator=(const %s) MOZ_DELETE;\n" % (name, name, name))
- disallowedCopyConstructors = [DisallowedCopyConstructor()]
- else:
- disallowedCopyConstructors = []
-
- order = [(self.enums, ''), (self.unions, ''),
- (self.typedefs, ''), (self.members, '')]
-
- for (memberList, separator) in order:
- memberString = declareMembers(self, memberList)
- if self.indent:
- memberString = CGIndenter(CGGeneric(memberString),
- len(self.indent)).define()
- result = result + memberString
-
- result += self.indent + '}\n\n'
- result += 'impl %s {\n' % self.name
-
- order = [(self.constructors + disallowedCopyConstructors, '\n'),
- (self.destructors, '\n'), (self.methods, '\n)')]
- for (memberList, separator) in order:
- memberString = declareMembers(self, memberList)
- if self.indent:
- memberString = CGIndenter(CGGeneric(memberString),
- len(self.indent)).define()
- result = result + memberString
-
- result += "}"
- return result
-
-class CGProxySpecialOperation(CGPerSignatureCall):
- """
- Base class for classes for calling an indexed or named special operation
- (don't use this directly, use the derived classes below).
- """
- def __init__(self, descriptor, operation):
- nativeName = MakeNativeName(operation)
- operation = descriptor.operations[operation]
- assert len(operation.signatures()) == 1
- signature = operation.signatures()[0]
-
- (returnType, arguments) = signature
-
- # We pass len(arguments) as the final argument so that the
- # CGPerSignatureCall won't do any argument conversion of its own.
- CGPerSignatureCall.__init__(self, returnType, "", arguments, nativeName,
- False, descriptor, operation,
- len(arguments))
-
- if operation.isSetter() or operation.isCreator():
- # arguments[0] is the index or name of the item that we're setting.
- argument = arguments[1]
- template, _, declType, needsRooting = getJSToNativeConversionTemplate(
- argument.type, descriptor, treatNullAs=argument.treatNullAs)
- templateValues = {
- "val": "(*desc).value",
- }
- self.cgRoot.prepend(instantiateJSToNativeConversionTemplate(
- template, templateValues, declType, argument.identifier.name,
- needsRooting))
- elif operation.isGetter():
- self.cgRoot.prepend(CGGeneric("let mut found = false;"))
-
- def getArguments(self):
- def process(arg):
- argVal = arg.identifier.name
- if arg.type.isGeckoInterface() and not arg.type.unroll().inner.isCallback():
- argVal += ".root_ref()"
- return argVal
- args = [(a, process(a)) for a in self.arguments]
- if self.idlNode.isGetter():
- args.append((FakeArgument(BuiltinTypes[IDLBuiltinType.Types.boolean],
- self.idlNode),
- "&mut found"))
- return args
-
- def wrap_return_value(self):
- if not self.idlNode.isGetter() or self.templateValues is None:
- return ""
-
- wrap = CGGeneric(wrapForType(**self.templateValues))
- wrap = CGIfWrapper(wrap, "found")
- return "\n" + wrap.define()
-
-class CGProxyIndexedGetter(CGProxySpecialOperation):
- """
- Class to generate a call to an indexed getter. If templateValues is not None
- the returned value will be wrapped with wrapForType using templateValues.
- """
- def __init__(self, descriptor, templateValues=None):
- self.templateValues = templateValues
- CGProxySpecialOperation.__init__(self, descriptor, 'IndexedGetter')
-
-class CGProxyIndexedSetter(CGProxySpecialOperation):
- """
- Class to generate a call to an indexed setter.
- """
- def __init__(self, descriptor):
- CGProxySpecialOperation.__init__(self, descriptor, 'IndexedSetter')
-
-class CGProxyNamedGetter(CGProxySpecialOperation):
- """
- Class to generate a call to an named getter. If templateValues is not None
- the returned value will be wrapped with wrapForType using templateValues.
- """
- def __init__(self, descriptor, templateValues=None):
- self.templateValues = templateValues
- CGProxySpecialOperation.__init__(self, descriptor, 'NamedGetter')
-
-class CGProxyNamedSetter(CGProxySpecialOperation):
- """
- Class to generate a call to a named setter.
- """
- def __init__(self, descriptor):
- CGProxySpecialOperation.__init__(self, descriptor, 'NamedSetter')
-
-class CGProxyUnwrap(CGAbstractMethod):
- def __init__(self, descriptor):
- args = [Argument('*mut JSObject', 'obj')]
- CGAbstractMethod.__init__(self, descriptor, "UnwrapProxy", '*const ' + descriptor.concreteType, args, alwaysInline=True)
-
- def definition_body(self):
- return CGGeneric("""/*if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
- obj = js::UnwrapObject(obj);
-}*/
-//MOZ_ASSERT(IsProxy(obj));
-let box_ = GetProxyPrivate(obj).to_private() as *const %s;
-return box_;""" % self.descriptor.concreteType)
-
-class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod):
- def __init__(self, descriptor):
- args = [Argument('*mut JSContext', 'cx'), Argument('*mut JSObject', 'proxy'),
- Argument('jsid', 'id'), Argument('bool', 'set'),
- Argument('*mut JSPropertyDescriptor', 'desc')]
- CGAbstractExternMethod.__init__(self, descriptor, "getOwnPropertyDescriptor",
- "bool", args)
- self.descriptor = descriptor
- def getBody(self):
- indexedGetter = self.descriptor.operations['IndexedGetter']
- indexedSetter = self.descriptor.operations['IndexedSetter']
-
- setOrIndexedGet = ""
- if indexedGetter or indexedSetter:
- setOrIndexedGet += "let index = GetArrayIndexFromId(cx, id);\n"
-
- if indexedGetter:
- readonly = toStringBool(self.descriptor.operations['IndexedSetter'] is None)
- fillDescriptor = "FillPropertyDescriptor(&mut *desc, proxy, %s);\nreturn true;" % readonly
- templateValues = {'jsvalRef': '(*desc).value', 'successCode': fillDescriptor}
- get = ("if index.is_some() {\n" +
- " let index = index.unwrap();\n" +
- " let this = UnwrapProxy(proxy);\n" +
- " let this = JS::from_raw(this);\n" +
- " let this = this.root();\n" +
- CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define() + "\n" +
- "}\n")
-
- if indexedSetter or self.descriptor.operations['NamedSetter']:
- setOrIndexedGet += "if set != 0 {\n"
- if indexedSetter:
- setOrIndexedGet += (" if index.is_some() {\n" +
- " let index = index.unwrap();\n")
- if not 'IndexedCreator' in self.descriptor.operations:
- # FIXME need to check that this is a 'supported property index'
- assert False
- setOrIndexedGet += (" FillPropertyDescriptor(&mut *desc, proxy, false);\n" +
- " return true;\n" +
- " }\n")
- if self.descriptor.operations['NamedSetter']:
- setOrIndexedGet += " if RUST_JSID_IS_STRING(id) {\n"
- if not 'NamedCreator' in self.descriptor.operations:
- # FIXME need to check that this is a 'supported property name'
- assert False
- setOrIndexedGet += (" FillPropertyDescriptor(&mut *desc, proxy, false);\n" +
- " return true;\n" +
- " }\n")
- setOrIndexedGet += "}"
- if indexedGetter:
- setOrIndexedGet += (" else {\n" +
- CGIndenter(CGGeneric(get)).define() +
- "}")
- setOrIndexedGet += "\n\n"
- elif indexedGetter:
- setOrIndexedGet += ("if !set {\n" +
- CGIndenter(CGGeneric(get)).define() +
- "}\n\n")
-
- namedGetter = self.descriptor.operations['NamedGetter']
- if namedGetter:
- readonly = toStringBool(self.descriptor.operations['NamedSetter'] is None)
- fillDescriptor = "FillPropertyDescriptor(&mut *desc, proxy, %s);\nreturn true;" % readonly
- templateValues = {'jsvalRef': '(*desc).value', 'successCode': fillDescriptor}
- # Once we start supporting OverrideBuiltins we need to make
- # ResolveOwnProperty or EnumerateOwnProperties filter out named
- # properties that shadow prototype properties.
- namedGet = ("\n" +
- "if !set && RUST_JSID_IS_STRING(id) != 0 && !HasPropertyOnPrototype(cx, proxy, id) {\n" +
- " let name = jsid_to_str(cx, id);\n" +
- " let this = UnwrapProxy(proxy);\n" +
- " let this = JS::from_raw(this);\n" +
- " let this = this.root();\n" +
- CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() + "\n" +
- "}\n")
- else:
- namedGet = ""
-
- return setOrIndexedGet + """let expando: *mut JSObject = GetExpandoObject(proxy);
-//if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) {
-if expando.is_not_null() {
- let flags = if set { JSRESOLVE_ASSIGNING } else { 0 } | JSRESOLVE_QUALIFIED;
- if JS_GetPropertyDescriptorById(cx, expando, id, flags, desc) == 0 {
- return false;
- }
- if (*desc).obj.is_not_null() {
- // Pretend the property lives on the wrapper.
- (*desc).obj = proxy;
- return true;
- }
-}
-""" + namedGet + """
-(*desc).obj = ptr::mut_null();
-return true;"""
-
- def definition_body(self):
- return CGGeneric(self.getBody())
-
-class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod):
- def __init__(self, descriptor):
- args = [Argument('*mut JSContext', 'cx'), Argument('*mut JSObject', 'proxy'),
- Argument('jsid', 'id'),
- Argument('*const JSPropertyDescriptor', 'desc')]
- CGAbstractExternMethod.__init__(self, descriptor, "defineProperty", "bool", args)
- self.descriptor = descriptor
- def getBody(self):
- set = ""
-
- indexedSetter = self.descriptor.operations['IndexedSetter']
- if indexedSetter:
- if not (self.descriptor.operations['IndexedCreator'] is indexedSetter):
- raise TypeError("Can't handle creator that's different from the setter")
- set += ("let index = GetArrayIndexFromId(cx, id);\n" +
- "if index.is_some() {\n" +
- " let index = index.unwrap();\n" +
- " let this = UnwrapProxy(proxy);\n" +
- " let this = JS::from_raw(this);\n" +
- " let this = this.root();\n" +
- CGIndenter(CGProxyIndexedSetter(self.descriptor)).define() +
- " return true;\n" +
- "}\n")
- elif self.descriptor.operations['IndexedGetter']:
- set += ("if GetArrayIndexFromId(cx, id).is_some() {\n" +
- " return false;\n" +
- " //return ThrowErrorMessage(cx, MSG_NO_PROPERTY_SETTER, \"%s\");\n" +
- "}\n") % self.descriptor.name
-
- namedSetter = self.descriptor.operations['NamedSetter']
- if namedSetter:
- if not self.descriptor.operations['NamedCreator'] is namedSetter:
- raise TypeError("Can't handle creator that's different from the setter")
- set += ("if RUST_JSID_IS_STRING(id) != 0 {\n" +
- " let name = jsid_to_str(cx, id);\n" +
- " let this = UnwrapProxy(proxy);\n" +
- " let this = JS::from_raw(this);\n" +
- " let this = this.root();\n" +
- CGIndenter(CGProxyNamedSetter(self.descriptor)).define() + "\n" +
- "}\n")
- elif self.descriptor.operations['NamedGetter']:
- set += ("if RUST_JSID_IS_STRING(id) {\n" +
- " let name = jsid_to_str(cx, id);\n" +
- " let this = UnwrapProxy(proxy);\n" +
- " let this = JS::from_raw(this);\n" +
- " let this = this.root();\n" +
- CGIndenter(CGProxyNamedGetter(self.descriptor)).define() +
- " if (found) {\n"
- " return false;\n" +
- " //return ThrowErrorMessage(cx, MSG_NO_PROPERTY_SETTER, \"%s\");\n" +
- " }\n" +
- " return true;\n"
- "}\n") % (self.descriptor.name)
- return set + """return proxyhandler::defineProperty_(%s);""" % ", ".join(a.name for a in self.args)
-
- def definition_body(self):
- return CGGeneric(self.getBody())
-
-class CGDOMJSProxyHandler_hasOwn(CGAbstractExternMethod):
- def __init__(self, descriptor):
- args = [Argument('*mut JSContext', 'cx'), Argument('*mut JSObject', 'proxy'),
- Argument('jsid', '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 = GetArrayIndexFromId(cx, id);\n" +
- "if index.is_some() {\n" +
- " let index = index.unwrap();\n" +
- " let this = UnwrapProxy(proxy);\n" +
- " let this = JS::from_raw(this);\n" +
- " let this = this.root();\n" +
- CGIndenter(CGProxyIndexedGetter(self.descriptor)).define() + "\n" +
- " *bp = found;\n" +
- " return true;\n" +
- "}\n\n")
- else:
- indexed = ""
-
- namedGetter = self.descriptor.operations['NamedGetter']
- if namedGetter:
- named = ("if RUST_JSID_IS_STRING(id) != 0 && !HasPropertyOnPrototype(cx, proxy, id) {\n" +
- " let name = jsid_to_str(cx, id);\n" +
- " let this = UnwrapProxy(proxy);\n" +
- " let this = JS::from_raw(this);\n" +
- " let this = this.root();\n" +
- CGIndenter(CGProxyNamedGetter(self.descriptor)).define() + "\n" +
- " *bp = found;\n"
- " return true;\n"
- "}\n" +
- "\n")
- else:
- named = ""
-
- return indexed + """let expando: *mut JSObject = GetExpandoObject(proxy);
-if expando.is_not_null() {
- let mut b: JSBool = 1;
- let ok = JS_HasPropertyById(cx, expando, id, &mut b) != 0;
- *bp = b != 0;
- if !ok || *bp {
- return ok;
- }
-}
-
-""" + named + """*bp = false;
-return true;"""
-
- def definition_body(self):
- return CGGeneric(self.getBody())
-
-class CGDOMJSProxyHandler_get(CGAbstractExternMethod):
- def __init__(self, descriptor):
- args = [Argument('*mut JSContext', 'cx'), Argument('*mut JSObject', 'proxy'),
- Argument('*mut JSObject', 'receiver'), Argument('jsid', 'id'),
- Argument('*mut JSVal', 'vp')]
- CGAbstractExternMethod.__init__(self, descriptor, "get", "bool", args)
- self.descriptor = descriptor
- def getBody(self):
- getFromExpando = """let expando = GetExpandoObject(proxy);
-if expando.is_not_null() {
- let mut hasProp = 0;
- if JS_HasPropertyById(cx, expando, id, &mut hasProp) == 0 {
- return false;
- }
-
- if hasProp != 0 {
- return JS_GetPropertyById(cx, expando, id, vp) != 0;
- }
-}"""
-
- templateValues = {
- 'jsvalRef': '*vp',
- 'successCode': 'return true;',
- }
-
- indexedGetter = self.descriptor.operations['IndexedGetter']
- if indexedGetter:
- getIndexedOrExpando = ("let index = GetArrayIndexFromId(cx, id);\n" +
- "if index.is_some() {\n" +
- " let index = index.unwrap();\n" +
- " let this = UnwrapProxy(proxy);\n" +
- " let this = JS::from_raw(this);\n" +
- " let this = this.root();\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.
-} else {
- %s
-}
-""" % (stripTrailingWhitespace(getFromExpando.replace('\n', '\n ')))
- else:
- getIndexedOrExpando = getFromExpando + "\n"
-
- namedGetter = self.descriptor.operations['NamedGetter']
- if namedGetter and False: #XXXjdm unfinished
- getNamed = ("if (JSID_IS_STRING(id)) {\n" +
- " let name = jsid_to_str(cx, id);\n" +
- " let this = UnwrapProxy(proxy);\n" +
- " let this = JS::from_raw(this);\n" +
- " let this = this.root();\n" +
- CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() +
- "}\n") % (self.descriptor.concreteType)
- else:
- getNamed = ""
-
- return """//MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
- //"Should not have a XrayWrapper here");
-
-%s
-let mut found = false;
-if !GetPropertyOnPrototype(cx, proxy, id, &mut found, vp) {
- return false;
-}
-
-if found {
- return true;
-}
-%s
-*vp = UndefinedValue();
-return true;""" % (getIndexedOrExpando, getNamed)
-
- def definition_body(self):
- return CGGeneric(self.getBody())
-
-class CGDOMJSProxyHandler_obj_toString(CGAbstractExternMethod):
- def __init__(self, descriptor):
- args = [Argument('*mut JSContext', 'cx'), Argument('*mut JSObject', 'proxy')]
- CGAbstractExternMethod.__init__(self, descriptor, "obj_toString", "*mut JSString", args)
- self.descriptor = descriptor
- def getBody(self):
- stringifier = self.descriptor.operations['Stringifier']
- if stringifier:
- nativeName = MakeNativeName(stringifier.identifier.name)
- signature = stringifier.signatures()[0]
- returnType = signature[0]
- extendedAttributes = self.descriptor.getExtendedAttributes(stringifier)
- infallible = 'infallible' in extendedAttributes
- if not infallible:
- error = CGGeneric(
- ('ThrowMethodFailedWithDetails(cx, rv, "%s", "toString");\n' +
- "return NULL;") % self.descriptor.interface.identifier.name)
- else:
- error = None
- call = CGCallGenerator(error, [], "", returnType, extendedAttributes, self.descriptor, nativeName, False, object="UnwrapProxy(proxy)")
- return call.define() + """
-
-JSString* jsresult;
-return xpc_qsStringToJsstring(cx, result, &jsresult) ? jsresult : NULL;"""
-
- return """let s = "%s".to_c_str();
- _obj_toString(cx, s.as_ptr())""" % self.descriptor.name
-
- def definition_body(self):
- return CGGeneric(self.getBody())
-
-class CGAbstractClassHook(CGAbstractExternMethod):
- """
- Meant for implementing JSClass hooks, like Finalize or Trace. Does very raw
- 'this' unwrapping as it assumes that the unwrapped type is always known.
- """
- def __init__(self, descriptor, name, returnType, args):
- CGAbstractExternMethod.__init__(self, descriptor, name, returnType,
- args)
-
- def definition_body_prologue(self):
- return CGGeneric("""\
-let this: *const %s = unwrap::<%s>(obj);
-""" % (self.descriptor.concreteType, self.descriptor.concreteType))
-
- def definition_body(self):
- return CGList([
- self.definition_body_prologue(),
- self.generate_code(),
- ])
-
- def generate_code(self):
- # Override me
- assert(False)
-
-def finalizeHook(descriptor, hookName, context):
- release = """let val = JS_GetReservedSlot(obj, dom_object_slot(obj));
-let _: Box<%s> = mem::transmute(val.to_private());
-debug!("%s finalize: {:p}", this);
-""" % (descriptor.concreteType, descriptor.concreteType)
- return release
-
-class CGClassTraceHook(CGAbstractClassHook):
- """
- A hook to trace through our native object; used for GC and CC
- """
- def __init__(self, descriptor):
- args = [Argument('*mut JSTracer', 'trc'), Argument('*mut JSObject', 'obj')]
- CGAbstractClassHook.__init__(self, descriptor, TRACE_HOOK_NAME, 'void',
- args)
-
- def generate_code(self):
- return CGGeneric("(*this).trace(%s);" % self.args[0].name)
-
-class CGClassConstructHook(CGAbstractExternMethod):
- """
- JS-visible constructor for our objects
- """
- def __init__(self, descriptor):
- args = [Argument('*mut JSContext', 'cx'), Argument('u32', 'argc'), Argument('*mut JSVal', 'vp')]
- CGAbstractExternMethod.__init__(self, descriptor, CONSTRUCT_HOOK_NAME,
- 'JSBool', args)
- self._ctor = self.descriptor.interface.ctor()
-
- def define(self):
- if not self._ctor:
- return ""
- return CGAbstractExternMethod.define(self)
-
- def definition_body(self):
- preamble = CGGeneric("""\
-let global = global_object_for_js_object(JS_CALLEE(cx, vp).to_object());
-let global = global.root();
-""")
- nativeName = MakeNativeName(self._ctor.identifier.name)
- callGenerator = CGMethodCall(["&global.root_ref()"], nativeName, True,
- self.descriptor, self._ctor)
- return CGList([preamble, callGenerator])
-
-class CGClassFinalizeHook(CGAbstractClassHook):
- """
- A hook for finalize, used to release our native object.
- """
- def __init__(self, descriptor):
- args = [Argument('*mut JSFreeOp', 'fop'), Argument('*mut JSObject', 'obj')]
- CGAbstractClassHook.__init__(self, descriptor, FINALIZE_HOOK_NAME,
- 'void', args)
-
- def generate_code(self):
- return CGGeneric(finalizeHook(self.descriptor, self.name, self.args[0].name))
-
-class CGDOMJSProxyHandlerDOMClass(CGThing):
- def __init__(self, descriptor):
- CGThing.__init__(self)
- self.descriptor = descriptor
-
- def define(self):
- return """
-static Class: DOMClass = """ + DOMClass(self.descriptor) + """;
-
-"""
-
-
-class CGInterfaceTrait(CGThing):
- def __init__(self, descriptor):
- CGThing.__init__(self)
-
- def argument_type(ty, optional=False, defaultValue=None, variadic=False):
- _, _, declType, _ = getJSToNativeConversionTemplate(
- ty, descriptor, isArgument=True)
-
- if variadic:
- declType = CGWrapper(declType, pre="Vec<", post=">")
- elif optional and not defaultValue:
- declType = CGWrapper(declType, pre="Option<", post=">")
-
- if ty.isGeckoInterface() and not (ty.nullable() or optional):
- declType = CGWrapper(declType, pre="&")
- elif ty.isDictionary():
- declType = CGWrapper(declType, pre="&")
-
- return declType.define()
-
- def attribute_arguments(needCx, argument=None):
- if needCx:
- yield "cx", "*mut JSContext"
-
- if argument:
- yield "value", argument_type(argument)
-
- def method_arguments(returnType, arguments, trailing=None):
- if needCx(returnType, arguments, True):
- yield "cx", "*mut JSContext"
-
- for argument in arguments:
- ty = argument_type(argument.type, argument.optional,
- argument.defaultValue, argument.variadic)
- yield CGDictionary.makeMemberName(argument.identifier.name), ty
-
- if trailing:
- yield trailing
-
- def return_type(rettype, infallible):
- result = getRetvalDeclarationForType(rettype, descriptor)
- if not infallible:
- result = CGWrapper(result, pre="Fallible<", post=">")
- return result.define()
-
- def members():
- for m in descriptor.interface.members:
- if m.isMethod() and not m.isStatic():
- name = CGSpecializedMethod.makeNativeName(descriptor, m)
- infallible = 'infallible' in descriptor.getExtendedAttributes(m)
- for idx, (rettype, arguments) in enumerate(m.signatures()):
- arguments = method_arguments(rettype, arguments)
- rettype = return_type(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)
- needCx = typeNeedsCx(m.type)
- yield name, attribute_arguments(needCx), return_type(m.type, infallible)
-
- if not m.readonly:
- name = CGSpecializedSetter.makeNativeName(descriptor, m)
- infallible = 'infallible' in descriptor.getExtendedAttributes(m, setter=True)
- if infallible:
- rettype = "()"
- else:
- rettype = "ErrorResult"
- yield name, attribute_arguments(needCx, m.type), rettype
-
- if descriptor.proxy:
- for name, operation in descriptor.operations.iteritems():
- if not operation:
- continue
-
- assert len(operation.signatures()) == 1
- rettype, arguments = operation.signatures()[0]
-
- infallible = 'infallible' in descriptor.getExtendedAttributes(operation)
- arguments = method_arguments(rettype, arguments, ("found", "&mut bool"))
- rettype = return_type(rettype, infallible)
- yield name, arguments, rettype
-
- def fmt(arguments):
- return "".join(", %s: %s" % argument for argument in arguments)
-
- methods = CGList([
- CGGeneric("fn %s(&self%s) -> %s;\n" % (name, fmt(arguments), rettype))
- for name, arguments, rettype in members()
- ], "")
- self.cgRoot = CGWrapper(CGIndenter(methods),
- pre="pub trait %sMethods {\n" % descriptor.interface.identifier.name,
- post="}")
-
- def define(self):
- return self.cgRoot.define()
-
-
-class CGDescriptor(CGThing):
- def __init__(self, descriptor):
- CGThing.__init__(self)
-
- assert not descriptor.interface.isCallback()
-
- cgThings = []
- cgThings.append(CGGetProtoObjectMethod(descriptor))
- if descriptor.interface.hasInterfaceObject():
- # https://github.com/mozilla/servo/issues/2665
- # cgThings.append(CGGetConstructorObjectMethod(descriptor))
- pass
-
- (hasMethod, hasGetter, hasLenientGetter,
- hasSetter, hasLenientSetter) = False, False, False, False, False
- for m in descriptor.interface.members:
- if m.isMethod() and not m.isIdentifierLess():
- if m.isStatic():
- assert descriptor.interface.hasInterfaceObject()
- cgThings.append(CGStaticMethod(descriptor, m))
- else:
- cgThings.append(CGSpecializedMethod(descriptor, m))
- cgThings.append(CGMemberJITInfo(descriptor, m))
- hasMethod = True
- elif m.isAttr():
- if m.isStatic():
- assert descriptor.interface.hasInterfaceObject()
- cgThings.append(CGStaticGetter(descriptor, m))
- else:
- cgThings.append(CGSpecializedGetter(descriptor, m))
- if m.hasLenientThis():
- hasLenientGetter = True
- else:
- hasGetter = True
-
- if not m.readonly:
- if m.isStatic():
- assert descriptor.interface.hasInterfaceObject()
- cgThings.append(CGStaticSetter(descriptor, m))
- else:
- cgThings.append(CGSpecializedSetter(descriptor, m))
- if m.hasLenientThis():
- hasLenientSetter = True
- else:
- hasSetter = True
-
- if not m.isStatic():
- cgThings.append(CGMemberJITInfo(descriptor, m))
- if hasMethod:
- cgThings.append(CGGenericMethod(descriptor))
- if hasGetter:
- cgThings.append(CGGenericGetter(descriptor))
- if hasLenientGetter:
- pass
- if hasSetter:
- cgThings.append(CGGenericSetter(descriptor))
- if hasLenientSetter:
- pass
-
- if descriptor.concrete:
- cgThings.append(CGClassFinalizeHook(descriptor))
- cgThings.append(CGClassTraceHook(descriptor))
-
- if descriptor.interface.hasInterfaceObject():
- cgThings.append(CGClassConstructHook(descriptor))
- cgThings.append(CGInterfaceObjectJSClass(descriptor))
-
- cgThings.append(CGPrototypeJSClass(descriptor))
-
- properties = PropertyArrays(descriptor)
- cgThings.append(CGGeneric(str(properties)))
- cgThings.append(CGNativeProperties(descriptor, properties))
- cgThings.append(CGNativePropertyHooks(descriptor, properties))
- cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties))
-
- cgThings.append(CGNamespace.build([descriptor.name + "Constants"],
- CGConstant(m for m in descriptor.interface.members if m.isConst()),
- public=True))
-
- if descriptor.interface.hasInterfaceObject():
- cgThings.append(CGDefineDOMInterfaceMethod(descriptor))
-
- if descriptor.proxy:
- cgThings.append(CGDefineProxyHandler(descriptor))
-
- if descriptor.concrete:
- if descriptor.proxy:
- #cgThings.append(CGProxyIsProxy(descriptor))
- cgThings.append(CGProxyUnwrap(descriptor))
- cgThings.append(CGDOMJSProxyHandlerDOMClass(descriptor))
- cgThings.append(CGDOMJSProxyHandler_getOwnPropertyDescriptor(descriptor))
- cgThings.append(CGDOMJSProxyHandler_obj_toString(descriptor))
- cgThings.append(CGDOMJSProxyHandler_get(descriptor))
- cgThings.append(CGDOMJSProxyHandler_hasOwn(descriptor))
- if descriptor.operations['IndexedSetter'] or descriptor.operations['NamedSetter']:
- cgThings.append(CGDOMJSProxyHandler_defineProperty(descriptor))
-
- #cgThings.append(CGDOMJSProxyHandler(descriptor))
- #cgThings.append(CGIsMethod(descriptor))
- pass
- else:
- cgThings.append(CGDOMJSClass(descriptor))
- pass
-
- cgThings.append(CGWrapMethod(descriptor))
-
- cgThings.append(CGIDLInterface(descriptor))
- cgThings.append(CGInterfaceTrait(descriptor))
-
- cgThings = CGList(cgThings, "\n")
- cgThings = CGWrapper(cgThings, pre='\n', post='\n')
- #self.cgRoot = CGWrapper(CGNamespace(toBindingNamespace(descriptor.name),
- # cgThings),
- # post='\n')
- self.cgRoot = cgThings
-
- def define(self):
- return self.cgRoot.define()
-
-class CGNamespacedEnum(CGThing):
- def __init__(self, namespace, enumName, names, values, comment="", deriving=""):
-
- if not values:
- values = []
-
- # Account for explicit enum values.
- entries = []
- for i in range(0, len(names)):
- if len(values) > i and values[i] is not None:
- entry = "%s = %s" % (names[i], values[i])
- else:
- entry = names[i]
- entries.append(entry)
-
- # Append a Count.
- entries.append(enumName + 'Count = ' + str(len(entries)))
-
- # Indent.
- entries = [' ' + e for e in entries]
-
- # Build the enum body.
- enumstr = comment + 'pub enum %s {\n%s\n}\n' % (enumName, ',\n'.join(entries))
- if deriving:
- enumstr = ('#[deriving(%s)]\n' % deriving) + enumstr
- curr = CGGeneric(enumstr)
-
- # Add some whitespace padding.
- curr = CGWrapper(curr, pre='\n',post='\n')
-
- # Add the namespace.
- curr = CGNamespace(namespace, curr, public=True)
-
- # Add the typedef
- #typedef = '\ntypedef %s::%s %s;\n\n' % (namespace, enumName, enumName)
- #curr = CGList([curr, CGGeneric(typedef)])
-
- # Save the result.
- self.node = curr
-
- def define(self):
- return self.node.define()
-
-class CGDictionary(CGThing):
- def __init__(self, dictionary, descriptorProvider):
- self.dictionary = dictionary;
- if all(CGDictionary(d, descriptorProvider).generatable for
- d in CGDictionary.getDictionaryDependencies(dictionary)):
- self.generatable = True
- else:
- self.generatable = False
- # Nothing else to do here
- return
- self.memberInfo = [
- (member,
- getJSToNativeConversionTemplate(member.type,
- descriptorProvider,
- isMember="Dictionary",
- defaultValue=member.defaultValue,
- failureCode="return Err(());",
- exceptionCode="return Err(());"))
- for member in dictionary.members ]
-
- def define(self):
- if not self.generatable:
- return ""
- return self.struct() + "\n" + self.impl()
-
- def struct(self):
- d = self.dictionary
- if d.parent:
- inheritance = " pub parent: %s::%s<'a, 'b>,\n" % (self.makeModuleName(d.parent),
- self.makeClassName(d.parent))
- else:
- inheritance = ""
- memberDecls = [" pub %s: %s," %
- (self.makeMemberName(m[0].identifier.name), self.getMemberType(m))
- for m in self.memberInfo]
-
- return (string.Template(
- "pub struct ${selfName}<'a, 'b> {\n" +
- "${inheritance}" +
- "\n".join(memberDecls) + "\n" +
- "}").substitute( { "selfName": self.makeClassName(d),
- "inheritance": inheritance }))
-
- def impl(self):
- d = self.dictionary
- if d.parent:
- initParent = ("parent: match %s::%s::new(cx, val) {\n"
- " Ok(parent) => parent,\n"
- " Err(_) => return Err(()),\n"
- "},\n") % (self.makeModuleName(d.parent),
- self.makeClassName(d.parent))
- else:
- initParent = ""
-
- def memberInit(memberInfo):
- member, _ = memberInfo
- name = self.makeMemberName(member.identifier.name)
- conversion = self.getMemberConversion(memberInfo)
- return CGGeneric("%s: %s,\n" % (name, conversion.define()))
-
- memberInits = CGList([memberInit(m) for m in self.memberInfo])
-
- return string.Template(
- "impl<'a, 'b> ${selfName}<'a, 'b> {\n"
- " pub fn empty() -> ${selfName}<'a, 'b> {\n"
- " ${selfName}::new(ptr::mut_null(), NullValue()).unwrap()\n"
- " }\n"
- " pub fn new(cx: *mut JSContext, val: JSVal) -> Result<${selfName}<'a, 'b>, ()> {\n"
- " let object = if val.is_null_or_undefined() {\n"
- " ptr::mut_null()\n"
- " } else if val.is_object() {\n"
- " val.to_object()\n"
- " } else {\n"
- " throw_type_error(cx, \"Value not an object.\");\n"
- " return Err(());\n"
- " };\n"
- " Ok(${selfName} {\n"
- "${initParent}"
- "${initMembers}"
- " })\n"
- " }\n"
- "}").substitute({
- "selfName": self.makeClassName(d),
- "initParent": CGIndenter(CGGeneric(initParent), indentLevel=6).define(),
- "initMembers": CGIndenter(memberInits, indentLevel=6).define(),
- })
-
- @staticmethod
- def makeDictionaryName(dictionary):
- return dictionary.identifier.name
-
- def makeClassName(self, dictionary):
- return self.makeDictionaryName(dictionary)
-
- @staticmethod
- def makeModuleName(dictionary):
- name = dictionary.identifier.name
- if name.endswith('Init'):
- return toBindingNamespace(name.replace('Init', ''))
- #XXXjdm This breaks on the test webidl files, sigh.
- #raise TypeError("No idea how to find this dictionary's definition: " + name)
- return "/* uh oh */ %s" % name
-
- def getMemberType(self, memberInfo):
- member, (_, _, declType, _) = memberInfo
- if not member.defaultValue:
- declType = CGWrapper(declType, pre="Option<", post=">")
- return declType.define()
-
- def getMemberConversion(self, memberInfo):
- def indent(s):
- return CGIndenter(CGGeneric(s), 8).define()
-
- member, (templateBody, default, declType, _) = memberInfo
- replacements = { "val": "value" }
- conversion = string.Template(templateBody).substitute(replacements)
-
- assert (member.defaultValue is None) == (default is None)
- if not default:
- default = "None"
- conversion = "Some(%s)" % conversion
-
- conversion = (
- "match get_dictionary_property(cx, object, \"%s\") {\n"
- " Err(()) => return Err(()),\n"
- " Ok(Some(value)) => {\n"
- "%s\n"
- " },\n"
- " Ok(None) => {\n"
- "%s\n"
- " },\n"
- "}") % (member.identifier.name, indent(conversion), indent(default))
-
- return CGGeneric(conversion)
-
- @staticmethod
- def makeIdName(name):
- return name + "_id"
-
- @staticmethod
- def makeMemberName(name):
- # Can't use Rust keywords as member names.
- if name == "type":
- return name + "_"
- return name
-
- @staticmethod
- def getDictionaryDependencies(dictionary):
- deps = set();
- if dictionary.parent:
- deps.add(dictionary.parent)
- for member in dictionary.members:
- if member.type.isDictionary():
- deps.add(member.type.unroll().inner)
- return deps
-
-class CGRegisterProtos(CGAbstractMethod):
- def __init__(self, config):
- arguments = [
- Argument('*mut JSContext', 'cx'),
- Argument('*mut JSObject', 'global'),
- ]
- CGAbstractMethod.__init__(self, None, 'Register', 'void', arguments,
- unsafe=False, pub=True)
- self.config = config
-
- def definition_body(self):
- return CGList([
- CGGeneric("codegen::Bindings::%sBinding::DefineDOMInterface(cx, global);" % desc.name)
- for desc in self.config.getDescriptors(hasInterfaceObject=True, register=True)
- ], "\n")
-
-
-class CGRegisterProxyHandlersMethod(CGAbstractMethod):
- def __init__(self, descriptors):
- CGAbstractMethod.__init__(self, None, 'RegisterProxyHandlers', 'void', [],
- unsafe=True, pub=True)
- self.descriptors = descriptors
-
- def definition_body(self):
- return CGList([
- CGGeneric("proxy_handlers[proxies::%s as uint] = codegen::Bindings::%sBinding::DefineProxyHandler();" % (desc.name, desc.name))
- for desc in self.descriptors
- ], "\n")
-
-
-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)),
- CGRegisterProxyHandlersMethod(descriptors),
- ], "\n")
-
- def define(self):
- return self.root.define()
-
-
-class CGBindingRoot(CGThing):
- """
- Root 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):
- descriptors = config.getDescriptors(webIDLFile=webIDLFile,
- isCallback=False)
- dictionaries = config.getDictionaries(webIDLFile=webIDLFile)
-
- cgthings = []
-
- mainCallbacks = config.getCallbacks(webIDLFile=webIDLFile)
- callbackDescriptors = config.getDescriptors(webIDLFile=webIDLFile,
- isCallback=True)
-
- # Do codegen for all the enums
- cgthings = [CGEnum(e) for e in config.getEnums(webIDLFile)]
-
- cgthings.extend([CGDictionary(d, config.getDescriptorProvider())
- for d in dictionaries])
-
- # Do codegen for all the callbacks.
- cgthings.extend(CGList([CGCallbackFunction(c, config.getDescriptorProvider()),
- CGCallbackFunctionImpl(c)], "\n")
- for c in mainCallbacks)
-
- # Do codegen for all the descriptors
- cgthings.extend([CGDescriptor(x) for x in descriptors])
-
- # Do codegen for all the callback interfaces.
- cgthings.extend(CGList([CGCallbackInterface(x),
- CGCallbackFunctionImpl(x)], "\n")
- for x in callbackDescriptors)
-
- # And make sure we have the right number of newlines at the end
- curr = CGWrapper(CGList(cgthings, "\n\n"), post="\n\n")
-
- # Wrap all of that in our namespaces.
- #curr = CGNamespace.build(['dom'],
- # CGWrapper(curr, pre="\n"))
-
- # Add imports
- #XXXjdm This should only import the namespace for the current binding,
- # not every binding ever.
- curr = CGImports(curr, descriptors, [
- 'js',
- 'js::{JS_ARGV, JS_CALLEE, JS_THIS_OBJECT}',
- 'js::{JSCLASS_GLOBAL_SLOT_COUNT, JSCLASS_IS_DOMJSCLASS}',
- 'js::{JSCLASS_IS_GLOBAL, JSCLASS_RESERVED_SLOTS_SHIFT}',
- 'js::{JSCLASS_RESERVED_SLOTS_MASK, JSID_VOID, JSJitInfo}',
- 'js::{JSPROP_ENUMERATE, JSPROP_NATIVE_ACCESSORS, JSPROP_SHARED}',
- 'js::{JSRESOLVE_ASSIGNING, JSRESOLVE_QUALIFIED}',
- 'js::jsapi::{JS_CallFunctionValue, JS_GetClass, JS_GetGlobalForObject}',
- 'js::jsapi::{JS_GetObjectPrototype, JS_GetProperty, JS_GetPropertyById}',
- 'js::jsapi::{JS_GetPropertyDescriptorById, JS_GetReservedSlot}',
- 'js::jsapi::{JS_HasProperty, JS_HasPropertyById, JS_IsExceptionPending}',
- 'js::jsapi::{JS_NewObject, JS_ObjectIsCallable, JS_SetPrototype}',
- 'js::jsapi::{JS_SetReservedSlot, JS_WrapValue, JSBool, JSContext}',
- 'js::jsapi::{JSClass, JSFreeOp, JSFunctionSpec, JSHandleObject, jsid}',
- 'js::jsapi::{JSNativeWrapper, JSObject, JSPropertyDescriptor, JS_ArrayIterator}',
- 'js::jsapi::{JSPropertyOpWrapper, JSPropertySpec, JS_PropertyStub}',
- 'js::jsapi::{JSStrictPropertyOpWrapper, JSString, JSTracer, JS_ConvertStub}',
- 'js::jsapi::{JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub}',
- 'js::jsval::JSVal',
- 'js::jsval::{ObjectValue, ObjectOrNullValue, PrivateValue}',
- 'js::jsval::{NullValue, UndefinedValue}',
- 'js::glue::{CallJitMethodOp, CallJitPropertyOp, CreateProxyHandler}',
- 'js::glue::{GetProxyPrivate, NewProxyObject, ProxyTraps}',
- 'js::glue::{RUST_FUNCTION_VALUE_TO_JITINFO}',
- 'js::glue::{RUST_JS_NumberValue, RUST_JSID_IS_STRING}',
- 'js::rust::with_compartment',
- 'dom::types::*',
- 'dom::bindings',
- 'dom::bindings::global::GlobalRef',
- 'dom::bindings::js::{JS, JSRef, Root, RootedReference, Temporary}',
- 'dom::bindings::js::{OptionalRootable, OptionalRootedRootable, ResultRootable}',
- 'dom::bindings::js::{OptionalRootedReference, OptionalOptionalRootedRootable}',
- 'dom::bindings::utils::{CreateDOMGlobal, CreateInterfaceObjects2}',
- 'dom::bindings::utils::{ConstantSpec, cx_for_dom_object}',
- 'dom::bindings::utils::{dom_object_slot, DOM_OBJECT_SLOT, DOMClass}',
- 'dom::bindings::utils::{DOMJSClass, JSCLASS_DOM_GLOBAL}',
- 'dom::bindings::utils::{FindEnumStringIndex, GetArrayIndexFromId}',
- 'dom::bindings::utils::{GetPropertyOnPrototype, GetProtoOrIfaceArray}',
- 'dom::bindings::utils::{HasPropertyOnPrototype, IntVal}',
- 'dom::bindings::utils::{jsid_to_str}',
- 'dom::bindings::utils::global_object_for_js_object',
- 'dom::bindings::utils::{Reflectable}',
- 'dom::bindings::utils::{squirrel_away_unique}',
- 'dom::bindings::utils::{ThrowingConstructor, unwrap, unwrap_jsmanaged}',
- 'dom::bindings::utils::VoidVal',
- 'dom::bindings::utils::get_dictionary_property',
- 'dom::bindings::utils::{NativeProperties, NativePropertyHooks}',
- 'dom::bindings::trace::JSTraceable',
- 'dom::bindings::callback::{CallbackContainer,CallbackInterface,CallbackFunction}',
- 'dom::bindings::callback::{CallSetup,ExceptionHandling}',
- 'dom::bindings::callback::{WrapCallThisObject}',
- 'dom::bindings::conversions::{FromJSValConvertible, ToJSValConvertible}',
- 'dom::bindings::conversions::IDLInterface',
- 'dom::bindings::conversions::{Default, Empty}',
- 'dom::bindings::codegen::*',
- 'dom::bindings::codegen::Bindings::*',
- 'dom::bindings::codegen::RegisterBindings',
- 'dom::bindings::codegen::UnionTypes::*',
- 'dom::bindings::error::{FailureUnknown, Fallible, Error, ErrorResult}',
- 'dom::bindings::error::throw_dom_exception',
- 'dom::bindings::error::throw_type_error',
- 'dom::bindings::proxyhandler',
- 'dom::bindings::proxyhandler::{_obj_toString, defineProperty}',
- 'dom::bindings::proxyhandler::{FillPropertyDescriptor, GetExpandoObject}',
- 'dom::bindings::proxyhandler::{delete_, getPropertyDescriptor}',
- 'dom::bindings::str::ByteString',
- 'page::JSPageInfo',
- 'libc',
- 'servo_util::str::DOMString',
- 'std::mem',
- 'std::cmp',
- 'std::ptr',
- 'std::str',
- 'std::num',
- ])
-
- # Add the auto-generated comment.
- curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
-
- # Store the final result.
- self.root = curr
-
- def define(self):
- return stripTrailingWhitespace(self.root.define())
-
-class CGNativeMember(ClassMethod):
- def __init__(self, descriptorProvider, member, name, signature, extendedAttrs,
- breakAfter=True, passJSBitsAsNeeded=True, visibility="public",
- jsObjectsArePtr=False, variadicIsSequence=False):
- """
- If jsObjectsArePtr is true, typed arrays and "object" will be
- passed as JSObject*.
-
- If passJSBitsAsNeeded is false, we don't automatically pass in a
- JSContext* or a JSObject* based on the return and argument types.
- """
- self.descriptorProvider = descriptorProvider
- self.member = member
- self.extendedAttrs = extendedAttrs
- self.passJSBitsAsNeeded = passJSBitsAsNeeded
- self.jsObjectsArePtr = jsObjectsArePtr
- self.variadicIsSequence = variadicIsSequence
- breakAfterSelf = "\n" if breakAfter else ""
- ClassMethod.__init__(self, name,
- self.getReturnType(signature[0], False),
- self.getArgs(signature[0], signature[1]),
- 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()),
- breakAfterReturnDecl=" ",
- breakAfterSelf=breakAfterSelf,
- visibility=visibility)
-
- def getReturnType(self, type, isMember):
- return self.getRetvalInfo(type, isMember)[0]
-
- def getRetvalInfo(self, type, isMember):
- """
- Returns a tuple:
-
- The first element is the type declaration for the retval
-
- The second element is a template for actually returning a value stored in
- "${declName}". This means actually returning it if
- we're not outparam, else assigning to the "retval" outparam. If
- isMember is true, this can be None, since in that case the caller will
- never examine this value.
- """
- if type.isVoid():
- typeDecl, template = "", ""
- elif type.isPrimitive() and type.tag() in builtinNames:
- result = CGGeneric(builtinNames[type.tag()])
- if type.nullable():
- raise TypeError("Nullable primitives are not supported here.")
-
- typeDecl, template = result.define(), "return Ok(${declName});"
- elif type.isDOMString():
- if isMember:
- # No need for a third element in the isMember case
- typeDecl, template = "nsString", None
- # Outparam
- else:
- typeDecl, template = "void", "retval = ${declName};"
- elif type.isByteString():
- if isMember:
- # No need for a third element in the isMember case
- typeDecl, template = "nsCString", None
- # Outparam
- typeDecl, template = "void", "retval = ${declName};"
- elif type.isEnum():
- enumName = type.unroll().inner.identifier.name
- if type.nullable():
- enumName = CGTemplatedType("Nullable",
- CGGeneric(enumName)).define()
- typeDecl, template = enumName, "return ${declName};"
- elif type.isGeckoInterface():
- iface = type.unroll().inner;
- nativeType = self.descriptorProvider.getDescriptor(
- iface.identifier.name).nativeType
- # Now trim off unnecessary namespaces
- nativeType = nativeType.split("::")
- if nativeType[0] == "mozilla":
- nativeType.pop(0)
- if nativeType[0] == "dom":
- nativeType.pop(0)
- result = CGWrapper(CGGeneric("::".join(nativeType)), post="*")
- # Since we always force an owning type for callback return values,
- # our ${declName} is an OwningNonNull or nsRefPtr. So we can just
- # .forget() to get our already_AddRefed.
- typeDecl, template = result.define(), "return ${declName}.forget();"
- elif type.isCallback():
- typeDecl, template = \
- ("already_AddRefed<%s>" % type.unroll().identifier.name,
- "return ${declName}.forget();")
- elif type.isAny():
- typeDecl, template = "JSVal", "return Ok(${declName});"
- elif type.isObject():
- typeDecl, template = "JSObject*", "return ${declName};"
- elif type.isSpiderMonkeyInterface():
- if type.nullable():
- returnCode = "return ${declName}.IsNull() ? nullptr : ${declName}.Value().Obj();"
- else:
- returnCode = "return ${declName}.Obj();"
- typeDecl, template = "JSObject*", returnCode
- elif type.isSequence():
- # If we want to handle sequence-of-sequences return values, we're
- # going to need to fix example codegen to not produce nsTArray<void>
- # for the relevant argument...
- assert not isMember
- # Outparam.
- if type.nullable():
- returnCode = ("if (${declName}.IsNull()) {\n"
- " retval.SetNull();\n"
- "} else {\n"
- " retval.SetValue().SwapElements(${declName}.Value());\n"
- "}")
- else:
- returnCode = "retval.SwapElements(${declName});"
- typeDecl, template = "void", returnCode
- elif type.isDate():
- result = CGGeneric("Date")
- if type.nullable():
- result = CGTemplatedType("Nullable", result)
- typeDecl, template = result.define(), "return ${declName};"
- else:
- raise TypeError("Don't know how to declare return value for %s" % type)
-
- if not 'infallible' in self.extendedAttrs:
- if typeDecl:
- typeDecl = "Fallible<%s>" % typeDecl
- else:
- typeDecl = "ErrorResult"
- if not template:
- template = "return Ok(());"
- return typeDecl, template
-
- def getArgs(self, returnType, argList):
- args = [self.getArg(arg) for arg in argList]
- # Now the outparams
- if returnType.isDOMString():
- args.append(Argument("nsString&", "retval"))
- if returnType.isByteString():
- args.append(Argument("nsCString&", "retval"))
- elif returnType.isSequence():
- nullable = returnType.nullable()
- if nullable:
- returnType = returnType.inner
- # And now the actual underlying type
- elementDecl = self.getReturnType(returnType.inner, True)
- type = CGTemplatedType("nsTArray", CGGeneric(elementDecl))
- if nullable:
- type = CGTemplatedType("Nullable", type)
- args.append(Argument("%s&" % type.define(), "retval"))
- # The legacycaller thisval
- if self.member.isMethod() and self.member.isLegacycaller():
- # If it has an identifier, we can't deal with it yet
- assert self.member.isIdentifierLess()
- args.insert(0, Argument("JS::Value", "aThisVal"))
- # And jscontext bits.
- if needCx(returnType, argList, self.passJSBitsAsNeeded):
- args.insert(0, Argument("JSContext*", "cx"))
- # And if we're static, a global
- if self.member.isStatic():
- args.insert(0, Argument("const GlobalObject&", "global"))
- return args
-
- def doGetArgType(self, type, optional, isMember):
- """
- The main work of getArgType. Returns a string type decl, whether this
- is a const ref, as well as whether the type should be wrapped in
- Nullable as needed.
-
- isMember can be false or one of the strings "Sequence" or "Variadic"
- """
- if type.isArray():
- raise TypeError("Can't handle array arguments yet")
-
- if type.isSequence():
- nullable = type.nullable()
- if nullable:
- type = type.inner
- elementType = type.inner
- argType = self.getArgType(elementType, False, "Sequence")[0]
- decl = CGTemplatedType("Sequence", argType)
- return decl.define(), True, True
-
- if type.isUnion():
- if type.nullable():
- type = type.inner
- return str(type) + "::" + str(type), False, True
-
- if type.isGeckoInterface() and not type.isCallbackInterface():
- iface = type.unroll().inner
- argIsPointer = type.nullable()
- forceOwningType = iface.isCallback() or isMember
- if argIsPointer:
- if (optional or isMember) and forceOwningType:
- typeDecl = "nsRefPtr<%s>"
- else:
- typeDecl = "*%s"
- else:
- if optional or isMember:
- if forceOwningType:
- typeDecl = "OwningNonNull<%s>"
- else:
- typeDecl = "NonNull<%s>"
- else:
- typeDecl = "%s"
- descriptor = self.descriptorProvider.getDescriptor(iface.identifier.name)
- return (typeDecl % descriptor.argumentType,
- False, False)
-
- if type.isSpiderMonkeyInterface():
- if self.jsObjectsArePtr:
- return "JSObject*", False, False
-
- return type.name, True, True
-
- if type.isDOMString():
- declType = "DOMString"
- return declType, True, False
-
- if type.isByteString():
- declType = "nsCString"
- return declType, True, False
-
- if type.isEnum():
- return type.unroll().inner.identifier.name, False, True
-
- if type.isCallback() or type.isCallbackInterface():
- forceOwningType = optional or isMember
- if type.nullable():
- if forceOwningType:
- declType = "nsRefPtr<%s>"
- else:
- declType = "%s*"
- else:
- if forceOwningType:
- declType = "OwningNonNull<%s>"
- else:
- declType = "%s&"
- if type.isCallback():
- name = type.unroll().identifier.name
- else:
- name = type.unroll().inner.identifier.name
- return declType % name, False, False
-
- if type.isAny():
- # Don't do the rooting stuff for variadics for now
- if isMember:
- declType = "JS::Value"
- else:
- declType = "JSVal"
- return declType, False, False
-
- if type.isObject():
- if isMember:
- declType = "JSObject*"
- else:
- declType = "JS::Handle<JSObject*>"
- return declType, False, False
-
- if type.isDictionary():
- typeName = CGDictionary.makeDictionaryName(type.inner)
- return typeName, True, True
-
- if type.isDate():
- return "Date", False, True
-
- assert type.isPrimitive()
-
- return builtinNames[type.tag()], False, True
-
- def getArgType(self, type, optional, isMember):
- """
- Get the type of an argument declaration. Returns the type CGThing, and
- whether this should be a const ref.
-
- isMember can be False, "Sequence", or "Variadic"
- """
- (decl, ref, handleNullable) = self.doGetArgType(type, optional,
- isMember)
- decl = CGGeneric(decl)
- if handleNullable and type.nullable():
- decl = CGTemplatedType("Nullable", decl)
- ref = True
- if isMember == "Variadic":
- arrayType = "Sequence" if self.variadicIsSequence else "nsTArray"
- decl = CGTemplatedType(arrayType, decl)
- ref = True
- elif optional:
- # Note: All variadic args claim to be optional, but we can just use
- # empty arrays to represent them not being present.
- decl = CGTemplatedType("Option", decl)
- ref = False
- return (decl, ref)
-
- def getArg(self, arg):
- """
- Get the full argument declaration for an argument
- """
- (decl, ref) = self.getArgType(arg.type,
- arg.optional and not arg.defaultValue,
- "Variadic" if arg.variadic else False)
- if ref:
- decl = CGWrapper(decl, pre="&")
-
- return Argument(decl.define(), arg.identifier.name)
-
-class CGCallback(CGClass):
- def __init__(self, idlObject, descriptorProvider, baseName, methods,
- getters=[], setters=[]):
- self.baseName = baseName
- self._deps = idlObject.getDeps()
- name = idlObject.identifier.name
- # For our public methods that needThisHandling we want most of the
- # same args and the same return type as what CallbackMember
- # generates. So we want to take advantage of all its
- # CGNativeMember infrastructure, but that infrastructure can't deal
- # with templates and most especially template arguments. So just
- # cheat and have CallbackMember compute all those things for us.
- realMethods = []
- for method in methods:
- if not method.needThisHandling:
- realMethods.append(method)
- else:
- realMethods.extend(self.getMethodImpls(method))
- CGClass.__init__(self, name,
- bases=[ClassBase(baseName)],
- constructors=self.getConstructors(),
- methods=realMethods+getters+setters,
- decorators="#[deriving(PartialEq,Clone,Encodable)]")
-
- def getConstructors(self):
- return [ClassConstructor(
- [Argument("*mut JSObject", "aCallback")],
- bodyInHeader=True,
- visibility="pub",
- explicit=False,
- baseConstructors=[
- "%s::new(aCallback)" % self.baseName
- ])]
-
- def getMethodImpls(self, method):
- assert method.needThisHandling
- 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[1].name == "aThisObj" and args[1].argType == "*mut JSObject"
- 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.GetContext()", "thisObjJS"] + argnames
- argnamesWithoutThis = ["s.GetContext()", "ptr::mut_null()"] + 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.
- args.append(Argument("ExceptionHandling", "aExceptionHandling",
- "ReportExceptions"))
-
- args[0] = Argument('&' + args[0].argType, args[0].name, args[0].default)
- method.args[2] = args[0]
-
- # And now insert our template argument.
- argsWithoutThis = list(args)
- args.insert(0, Argument("&JSRef<T>", "thisObj"))
-
- # And the self argument
- method.args.insert(0, Argument(None, "&self"))
- args.insert(0, Argument(None, "&self"))
- argsWithoutThis.insert(0, Argument(None, "&self"))
-
- setupCall = ("let s = CallSetup::new(self, aExceptionHandling);\n"
- "if s.GetContext().is_null() {\n"
- " return Err(FailureUnknown);\n"
- "}\n")
-
- bodyWithThis = string.Template(
- setupCall+
- "let thisObjJS = WrapCallThisObject(s.GetContext(), thisObj);\n"
- "if thisObjJS.is_null() {\n"
- " return Err(FailureUnknown);\n"
- "}\n"
- "return ${methodName}(${callArgs});").substitute({
- "callArgs" : ", ".join(argnamesWithThis),
- "methodName": 'self.' + method.name,
- })
- bodyWithoutThis = string.Template(
- setupCall +
- "return ${methodName}(${callArgs});").substitute({
- "callArgs" : ", ".join(argnamesWithoutThis),
- "methodName": 'self.' + method.name,
- })
- return [ClassMethod(method.name+'_', method.returnType, args,
- bodyInHeader=True,
- templateArgs=["T: Reflectable"],
- body=bodyWithThis,
- visibility='pub'),
- ClassMethod(method.name+'__', method.returnType, argsWithoutThis,
- bodyInHeader=True,
- body=bodyWithoutThis,
- visibility='pub'),
- method]
-
- def deps(self):
- return self._deps
-
-# We're always fallible
-def callbackGetterName(attr):
- return "Get" + MakeNativeName(attr.identifier.name)
-
-def callbackSetterName(attr):
- return "Set" + MakeNativeName(attr.identifier.name)
-
-class CGCallbackFunction(CGCallback):
- def __init__(self, callback, descriptorProvider):
- CGCallback.__init__(self, callback, descriptorProvider,
- "CallbackFunction",
- methods=[CallCallback(callback, descriptorProvider)])
-
- def getConstructors(self):
- return CGCallback.getConstructors(self)
-
-class CGCallbackFunctionImpl(CGGeneric):
- def __init__(self, callback):
- impl = string.Template("""impl CallbackContainer for ${type} {
- fn new(callback: *mut JSObject) -> ${type} {
- ${type}::new(callback)
- }
-
- fn callback(&self) -> *mut JSObject {
- self.parent.callback()
- }
-}
-
-impl ToJSValConvertible for ${type} {
- fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
- self.callback().to_jsval(cx)
- }
-}
-""").substitute({"type": callback.name})
- CGGeneric.__init__(self, impl)
-
-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]
- 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)
-
-class FakeMember():
- def __init__(self):
- self.treatNullAs = "Default"
- def isStatic(self):
- return False
- def isAttr(self):
- return False
- def isMethod(self):
- return False
- def getExtendedAttribute(self, name):
- return None
-
-class CallbackMember(CGNativeMember):
- def __init__(self, sig, name, descriptorProvider, needThisHandling, rethrowContentException=False):
- """
- needThisHandling is True if we need to be able to accept a specified
- thisObj, False otherwise.
- """
- assert not rethrowContentException or not needThisHandling
-
- self.retvalType = sig[0]
- self.originalSig = sig
- args = sig[1]
- self.argCount = len(args)
- if self.argCount > 0:
- # Check for variadic arguments
- lastArg = args[self.argCount-1]
- if lastArg.variadic:
- self.argCountStr = (
- "(%d - 1) + %s.Length()" % (self.argCount,
- lastArg.identifier.name))
- else:
- self.argCountStr = "%d" % self.argCount
- self.needThisHandling = needThisHandling
- # If needThisHandling, we generate ourselves as private and the caller
- # will handle generating public versions that handle the "this" stuff.
- visibility = "priv" if needThisHandling else "pub"
- self.rethrowContentException = rethrowContentException
- # We don't care, for callback codegen, whether our original member was
- # a method or attribute or whatnot. Just always pass FakeMember()
- # here.
- CGNativeMember.__init__(self, descriptorProvider, FakeMember(),
- name, (self.retvalType, args),
- extendedAttrs={},
- passJSBitsAsNeeded=False,
- visibility=visibility,
- jsObjectsArePtr=True)
- # We have to do all the generation of our body now, because
- # the caller relies on us throwing if we can't manage it.
- self.exceptionCode= "return Err(FailureUnknown);\n"
- self.body = self.getImpl()
-
- def getImpl(self):
- replacements = {
- "declRval": self.getRvalDecl(),
- "returnResult": self.getResultConversion(),
- "convertArgs": self.getArgConversions(),
- "doCall": self.getCall(),
- "setupCall": self.getCallSetup(),
- }
- if self.argCount > 0:
- replacements["argCount"] = self.argCountStr
- replacements["argvDecl"] = string.Template(
- "let mut argv = Vec::from_elem(${argCount}, UndefinedValue());\n"
- ).substitute(replacements)
- else:
- # Avoid weird 0-sized arrays
- replacements["argvDecl"] = ""
-
- # Newlines and semicolons are in the values
- pre = string.Template(
- "${setupCall}"
- "${declRval}"
- "${argvDecl}").substitute(replacements)
- body = string.Template(
- "${convertArgs}"
- "${doCall}"
- "${returnResult}").substitute(replacements)
- return CGList([
- CGGeneric(pre),
- CGWrapper(CGIndenter(CGGeneric(body)),
- pre="with_compartment(cx, self.parent.callback(), || {\n",
- post="})")
- ], "\n").define()
-
- def getResultConversion(self):
- replacements = {
- "val": "rval",
- "declName": "rvalDecl",
- }
-
- template, _, declType, needsRooting = getJSToNativeConversionTemplate(
- self.retvalType,
- self.descriptorProvider,
- exceptionCode=self.exceptionCode,
- isCallbackReturnValue="Callback",
- # XXXbz we should try to do better here
- sourceDescription="return value")
-
- convertType = instantiateJSToNativeConversionTemplate(
- template, replacements, declType, "rvalDecl", needsRooting)
-
- assignRetval = string.Template(
- self.getRetvalInfo(self.retvalType,
- False)[1]).substitute(replacements)
- return convertType.define() + "\n" + assignRetval + "\n"
-
- def getArgConversions(self):
- # Just reget the arglist from self.originalSig, because our superclasses
- # just have way to many members they like to clobber, so I can't find a
- # safe member name to store it in.
- argConversions = [self.getArgConversion(i, arg) for (i, arg)
- in enumerate(self.originalSig[1])]
- # Do them back to front, so our argc modifications will work
- # correctly, because we examine trailing arguments first.
- argConversions.reverse();
- # Wrap each one in a scope so that any locals it has don't leak out, and
- # also so that we can just "break;" for our successCode.
- argConversions = [CGWrapper(CGIndenter(CGGeneric(c)),
- pre="loop {\n",
- post="\nbreak;}\n")
- for c in argConversions]
- if self.argCount > 0:
- argConversions.insert(0, self.getArgcDecl())
- # And slap them together.
- return CGList(argConversions, "\n\n").define() + "\n\n"
-
- def getArgConversion(self, i, arg):
- argval = arg.identifier.name
-
- if arg.variadic:
- argval = argval + "[idx]"
- jsvalIndex = "%d + idx" % i
- else:
- jsvalIndex = "%d" % i
- if arg.optional and not arg.defaultValue:
- argval += ".clone().unwrap()"
-
- conversion = wrapForType("*argv.get_mut(%s)" % jsvalIndex,
- result=argval,
- successCode="continue;" if arg.variadic else "break;")
- if arg.variadic:
- conversion = string.Template(
- "for (uint32_t idx = 0; idx < ${arg}.Length(); ++idx) {\n" +
- CGIndenter(CGGeneric(conversion)).define() + "\n"
- "}\n"
- "break;").substitute({ "arg": arg.identifier.name })
- elif arg.optional and not arg.defaultValue:
- conversion = (
- CGIfWrapper(CGGeneric(conversion),
- "%s.is_some()" % arg.identifier.name).define() +
- " else if (argc == %d) {\n"
- " // This is our current trailing argument; reduce argc\n"
- " argc -= 1;\n"
- "} else {\n"
- " *argv.get_mut(%d) = UndefinedValue();\n"
- "}" % (i+1, i))
- return conversion
-
- def getArgs(self, returnType, argList):
- args = CGNativeMember.getArgs(self, returnType, argList)
- if not self.needThisHandling:
- # Since we don't need this handling, we're the actual method that
- # will be called, so we need an aRethrowExceptions argument.
- if self.rethrowContentException:
- args.append(Argument("JSCompartment*", "aCompartment", "nullptr"))
- else:
- args.append(Argument("ExceptionHandling", "aExceptionHandling",
- "ReportExceptions"))
- return args
- # We want to allow the caller to pass in a "this" object, as
- # well as a JSContext.
- return [Argument("*mut JSContext", "cx"),
- Argument("*mut JSObject", "aThisObj")] + args
-
- def getCallSetup(self):
- if self.needThisHandling:
- # It's been done for us already
- return ""
- callSetup = "CallSetup s(CallbackPreserveColor(), aRv"
- if self.rethrowContentException:
- # getArgs doesn't add the aExceptionHandling argument but does add
- # aCompartment for us.
- callSetup += ", RethrowContentExceptions, aCompartment"
- else:
- callSetup += ", aExceptionHandling"
- callSetup += ");"
- return string.Template(
- "${callSetup}\n"
- "JSContext* cx = s.GetContext();\n"
- "if (!cx) {\n"
- " return Err(FailureUnknown);\n"
- "}\n").substitute({
- "callSetup": callSetup,
- })
-
- def getArgcDecl(self):
- return CGGeneric("let mut argc = %su32;" % self.argCountStr);
-
- @staticmethod
- def ensureASCIIName(idlObject):
- type = "attribute" if idlObject.isAttr() else "operation"
- if re.match("[^\x20-\x7E]", idlObject.identifier.name):
- raise SyntaxError('Callback %s name "%s" contains non-ASCII '
- "characters. We can't handle that. %s" %
- (type, idlObject.identifier.name,
- idlObject.location))
- if re.match('"', idlObject.identifier.name):
- raise SyntaxError("Callback %s name '%s' contains "
- "double-quote character. We can't handle "
- "that. %s" %
- (type, idlObject.identifier.name,
- idlObject.location))
-
-class CallbackMethod(CallbackMember):
- def __init__(self, sig, name, descriptorProvider, needThisHandling, rethrowContentException=False):
- CallbackMember.__init__(self, sig, name, descriptorProvider,
- needThisHandling, rethrowContentException)
- def getRvalDecl(self):
- return "let mut rval = UndefinedValue();\n"
-
- def getCall(self):
- replacements = {
- "thisObj": self.getThisObj(),
- "getCallable": self.getCallableDecl()
- }
- if self.argCount > 0:
- replacements["argv"] = "argv.as_mut_ptr()"
- replacements["argc"] = "argc"
- else:
- replacements["argv"] = "nullptr"
- replacements["argc"] = "0"
- return string.Template("${getCallable}"
- "let ok = unsafe {\n"
- " JS_CallFunctionValue(cx, ${thisObj}, callable,\n"
- " ${argc}, ${argv}, &mut rval)\n"
- "};\n"
- "if ok == 0 {\n"
- " return Err(FailureUnknown);\n"
- "}\n").substitute(replacements)
-
-class CallCallback(CallbackMethod):
- def __init__(self, callback, descriptorProvider):
- CallbackMethod.__init__(self, callback.signatures()[0], "Call",
- descriptorProvider, needThisHandling=True)
-
- def getThisObj(self):
- return "aThisObj"
-
- def getCallableDecl(self):
- return "let callable = ObjectValue(unsafe {&*self.parent.callback()});\n";
-
-class CallbackOperationBase(CallbackMethod):
- """
- Common class for implementing various callback operations.
- """
- def __init__(self, signature, jsName, nativeName, descriptor, singleOperation, rethrowContentException=False):
- self.singleOperation = singleOperation
- self.methodName = jsName
- CallbackMethod.__init__(self, signature, nativeName, descriptor, singleOperation, rethrowContentException)
-
- def getThisObj(self):
- if not self.singleOperation:
- return "self.parent.callback()"
- # This relies on getCallableDecl declaring a boolean
- # isCallable in the case when we're a single-operation
- # interface.
- return "if isCallable { aThisObj } else { self.parent.callback() }"
-
- def getCallableDecl(self):
- replacements = {
- "methodName": self.methodName
- }
- getCallableFromProp = string.Template(
- 'match self.parent.GetCallableProperty(cx, "${methodName}") {\n'
- ' Err(_) => return Err(FailureUnknown),\n'
- ' Ok(callable) => callable,\n'
- '}').substitute(replacements)
- if not self.singleOperation:
- return 'JS::Rooted<JS::Value> callable(cx);\n' + getCallableFromProp
- return (
- 'let isCallable = unsafe { JS_ObjectIsCallable(cx, self.parent.callback()) != 0 };\n'
- 'let callable =\n' +
- CGIndenter(
- CGIfElseWrapper('isCallable',
- CGGeneric('unsafe { ObjectValue(&*self.parent.callback()) }'),
- CGGeneric(getCallableFromProp))).define() + ';\n')
-
-class CallbackOperation(CallbackOperationBase):
- """
- Codegen actual WebIDL operations on callback interfaces.
- """
- def __init__(self, method, signature, descriptor):
- self.ensureASCIIName(method)
- jsName = method.identifier.name
- CallbackOperationBase.__init__(self, signature,
- jsName, MakeNativeName(jsName),
- descriptor, descriptor.interface.isSingleOperationInterface(),
- rethrowContentException=descriptor.interface.isJSImplemented())
-
-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,
- rethrowContentException=descriptor.interface.isJSImplemented())
-
- def getRvalDecl(self):
- return "JS::Rooted<JS::Value> 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(FailureUnknown);\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,
- rethrowContentException=descriptor.interface.isJSImplemented())
-
- 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(FailureUnknown);\n'
- '}\n').substitute(replacements)
-
- def getArgcDecl(self):
- return None
-
-class GlobalGenRoots():
- """
- Roots for global codegen.
-
- To generate code, call the method associated with the target, and then
- call the appropriate define/declare method.
- """
-
- @staticmethod
- def PrototypeList(config):
- # Prototype ID enum.
- protos = [d.name for d in config.getDescriptors(isCallback=False)]
- proxies = [d.name for d in config.getDescriptors(proxy=True)]
-
- return CGList([
- CGGeneric(AUTOGENERATED_WARNING_COMMENT),
- CGGeneric("pub static MAX_PROTO_CHAIN_LENGTH: uint = %d;\n\n" % config.maxProtoChainLength),
- CGNamespacedEnum('id', 'ID', protos, [0], deriving="PartialEq"),
- CGNamespacedEnum('proxies', 'Proxy', proxies, [0], deriving="PartialEq"),
- ])
-
-
- @staticmethod
- def RegisterBindings(config):
- # TODO - Generate the methods we want
- code = CGList([
- CGRegisterProtos(config),
- CGRegisterProxyHandlers(config),
- ], "\n")
-
- return CGImports(code, [], [
- 'dom::bindings::codegen',
- 'dom::bindings::codegen::PrototypeList::proxies',
- 'js::jsapi::JSContext',
- 'js::jsapi::JSObject',
- 'libc',
- ])
-
- @staticmethod
- def InterfaceTypes(config):
- descriptors = [d.name for d in config.getDescriptors(register=True, isCallback=False)]
- curr = CGList([CGGeneric("pub use dom::%s::%s;\n" % (name.lower(), name)) for name in descriptors])
- curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
- return curr
-
- @staticmethod
- def Bindings(config):
-
- descriptors = (set(d.name + "Binding" for d in config.getDescriptors(register=True)) |
- set(d.unroll().module() for d in config.callbacks))
- curr = CGList([CGGeneric("pub mod %s;\n" % name) for name in sorted(descriptors)])
- curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
- return curr
-
- @staticmethod
- def InheritTypes(config):
-
- descriptors = config.getDescriptors(register=True, isCallback=False)
- allprotos = [CGGeneric("#![allow(unused_imports)]\n"),
- CGGeneric("use dom::types::*;\n"),
- CGGeneric("use dom::bindings::js::{JS, JSRef, Temporary};\n"),
- CGGeneric("use dom::bindings::trace::JSTraceable;\n"),
- CGGeneric("use dom::bindings::utils::Reflectable;\n"),
- CGGeneric("use serialize::{Encodable, Encoder};\n"),
- CGGeneric("use js::jsapi::JSTracer;\n\n")]
- for descriptor in descriptors:
- name = descriptor.name
- protos = [CGGeneric('pub trait %s {}\n' % (name + 'Base'))]
- for proto in descriptor.prototypeChain:
- protos += [CGGeneric('impl %s for %s {}\n' % (proto + 'Base',
- descriptor.concreteType))]
- derived = [CGGeneric('pub trait %s { fn %s(&self) -> bool; }\n' %
- (name + 'Derived', 'is_' + name.lower()))]
- for protoName in descriptor.prototypeChain[1:-1]:
- protoDescriptor = config.getDescriptor(protoName)
- delegate = string.Template('''impl ${selfName} for ${baseName} {
- fn ${fname}(&self) -> bool {
- self.${parentName}.${fname}()
- }
-}
-''').substitute({'fname': 'is_' + name.lower(),
- 'selfName': name + 'Derived',
- 'baseName': protoDescriptor.concreteType,
- 'parentName': protoDescriptor.prototypeChain[-2].lower()})
- derived += [CGGeneric(delegate)]
- derived += [CGGeneric('\n')]
-
- cast = [CGGeneric(string.Template('''pub trait ${castTraitName} {
- #[inline(always)]
- fn to_ref<'a, 'b, T: ${toBound}+Reflectable>(base: &'a JSRef<'b, T>) -> Option<&'a JSRef<'b, Self>> {
- match base.deref().${checkFn}() {
- true => unsafe { Some(base.transmute()) },
- false => None
- }
- }
-
- #[inline(always)]
- fn to_mut_ref<'a, 'b, T: ${toBound}+Reflectable>(base: &'a mut JSRef<'b, T>) -> Option<&'a mut JSRef<'b, Self>> {
- match base.deref().${checkFn}() {
- true => unsafe { Some(base.transmute_mut()) },
- false => None
- }
- }
-
- #[inline(always)]
- fn from_ref<'a, 'b, T: ${fromBound}>(derived: &'a JSRef<'b, T>) -> &'a JSRef<'b, Self> {
- unsafe { derived.transmute() }
- }
-
- #[inline(always)]
- fn from_mut_ref<'a, 'b, T: ${fromBound}>(derived: &'a mut JSRef<'b, T>) -> &'a mut JSRef<'b, Self> {
- unsafe { derived.transmute_mut() }
- }
-
- #[inline(always)]
- fn from_temporary<T: ${fromBound}+Reflectable>(derived: Temporary<T>) -> Temporary<Self> {
- unsafe { derived.transmute() }
- }
-}
-''').substitute({'checkFn': 'is_' + name.lower(),
- 'castTraitName': name + 'Cast',
- 'fromBound': name + 'Base',
- 'toBound': name + 'Derived'})),
- CGGeneric("impl %s for %s {}\n\n" % (name + 'Cast', name))]
-
- trace = [CGGeneric(string.Template('''impl JSTraceable for ${name} {
- fn trace(&self, tracer: *mut JSTracer) {
- unsafe {
- self.encode(&mut *tracer).ok().expect("failed to encode");
- }
- }
-}
-''').substitute({'name': name}))]
-
- allprotos += protos + derived + cast + trace
-
- curr = CGList(allprotos)
- curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
- return curr
-
- @staticmethod
- def UnionTypes(config):
-
- curr = UnionTypes(config.getDescriptors(),
- config.getDictionaries(),
- config.getCallbacks(),
- config)
-
- # Add the auto-generated comment.
- curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
-
- # Done.
- return curr