aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/servo/dom/bindings/codegen/CodegenRust.py
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2013-05-20 18:41:25 -0700
committerPatrick Walton <pcwalton@mimiga.net>2013-05-28 15:40:47 -0700
commitc7bce9823660106969e5d2c6b4e4c35f4003d360 (patch)
treed7dd76be49fa07db776fd4fb2576f492c4b97268 /src/components/servo/dom/bindings/codegen/CodegenRust.py
parentc658c6dea93db2769d1271edd5253f1653162a26 (diff)
downloadservo-c7bce9823660106969e5d2c6b4e4c35f4003d360.tar.gz
servo-c7bce9823660106969e5d2c6b4e4c35f4003d360.zip
Remove the `servo-` prefix from core components.
Diffstat (limited to 'src/components/servo/dom/bindings/codegen/CodegenRust.py')
-rw-r--r--src/components/servo/dom/bindings/codegen/CodegenRust.py4164
1 files changed, 0 insertions, 4164 deletions
diff --git a/src/components/servo/dom/bindings/codegen/CodegenRust.py b/src/components/servo/dom/bindings/codegen/CodegenRust.py
deleted file mode 100644
index 0fc99027ab1..00000000000
--- a/src/components/servo/dom/bindings/codegen/CodegenRust.py
+++ /dev/null
@@ -1,4164 +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 os
-import string
-import operator
-
-from WebIDL import *
-from Configuration import NoSuchDescriptorError
-
-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.
- """
- 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()
-
-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 and storing it in a variable
- called by the name in the "target" argument.
-
- codeOnFailure is the code to run if unwrapping fails.
- """
- def __init__(self, descriptor, source, target, codeOnFailure):
- assert descriptor.castable
-
- self.substitution = { "type" : descriptor.nativeType,
- "protoID" : "prototypes::id::" + descriptor.name + " as uint",
- "source" : source,
- "target" : target,
- "codeOnFailure" : CGIndenter(CGGeneric(codeOnFailure), 4).define() }
- if descriptor.hasXPConnectImpls:
- # We don't use xpc_qsUnwrapThis because it will always throw on
- # unwrap failure, whereas we want to control whether we throw or
- # not.
- self.substitution["codeOnFailure"] = CGIndenter(CGGeneric(string.Template(
- "${type} *objPtr;\n"
- "xpc_qsSelfRef objRef;\n"
- "JS::Value val = JS::ObjectValue(*${source});\n"
- "nsresult rv = xpc_qsUnwrapArg<${type}>(cx, val, &objPtr, &objRef.ptr, &val);\n"
- "if (NS_FAILED(rv)) {\n"
- "${codeOnFailure}\n"
- "}\n"
- "// We should be castable!\n"
- "MOZ_ASSERT(!objRef.ptr);\n"
- "// We should have an object, too!\n"
- "MOZ_ASSERT(objPtr);\n"
- "${target} = objPtr;").substitute(self.substitution)), 4).define()
-
- def __str__(self):
- return string.Template(
-"""${target} = unwrap(${source});
-""").substitute(self.substitution)
-#"""{
-# nsresult rv = UnwrapObject<${protoID}, ${type}>(cx, ${source}, ${target});
-# if (NS_FAILED(rv)) {
-#${codeOnFailure}
-# }
-#}""").substitute(self.substitution)
-
-class CGThing():
- """
- Abstract base class for things that spit out code.
- """
- def __init__(self):
- pass # Nothing for now
- def declare(self):
- """Produce code for a header file."""
- assert(False) # Override me!
- def define(self):
- """Produce code for a cpp file."""
- assert(False) # Override me!
-
-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):
- return CGPerSignatureCall(signature[0], argsPre, signature[1],
- nativeMethodName, 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([ CGIndenter(getPerSignatureCall(signature)) ])
- requiredArgs = requiredArgCount(signature)
-
-
- if requiredArgs > 0:
- code = (
- "if (argc < %d) {\n"
- " return 0; //XXXjdm throw exception\n"
- " //return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, %s);\n"
- "}" % (requiredArgs, methodName))
- self.cgRoot.prepend(
- CGWrapper(CGIndenter(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]
-
- # (possibly) important optimization: if signature[1] has >
- # argCount arguments and signature[1][argCount] is optional and
- # there is only one signature for argCount+1, then the
- # signature for argCount+1 is just ourselves and we can fall
- # through.
- if (len(signature[1]) > argCount and
- signature[1][argCount].optional and
- (argCount+1) in allowedArgCounts and
- len(method.signaturesForArgCount(argCount+1)) == 1):
- #XXXjdm unfinished
- pass
- #argCountCases.append(
- # CGCase(str(argCount), None, True))
- else:
- pass
- #XXXjdm unfinished
- #argCountCases.append(
- # CGCase(str(argCount), getPerSignatureCall(signature)))
- 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("JS::Value* 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[%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))
- else:
- caseBody.append(CGGeneric("if (" + condition + ") {"))
- caseBody.append(CGIndenter(
- getPerSignatureCall(sigs[0], distinguishingIndex)))
- 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.isObject()) {" %
- (distinguishingArg)))
- for sig in interfacesSigs:
- caseBody.append(CGIndenter(CGGeneric("do {")));
- 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.
- testCode = instantiateJSToNativeConversionTemplate(
- getJSToNativeConversionTemplate(type, descriptor,
- failureCode="break;",
- isDefinitelyObject=True),
- {
- "declName" : "arg%d" % distinguishingIndex,
- "holderName" : ("arg%d" % distinguishingIndex) + "_holder",
- "val" : distinguishingArg
- })
-
- # 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), 4))
- caseBody.append(CGIndenter(CGGeneric("} while (0);")))
-
- 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<%s>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);" %
- toStringBool(not descriptor.workers)))
-
- #XXXjdm unfinished
- #argCountCases.append(CGCase(str(argCount),
- # CGList(caseBody, "\n")))
-
- overloadCGThings = []
- overloadCGThings.append(
- CGGeneric("unsigned argcount = NS_MIN(argc, %du);" %
- maxArgCount))
- #XXXjdm unfinished
- #overloadCGThings.append(
- # CGSwitch("argcount",
- # argCountCases,
- # CGGeneric("return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, %s);\n" % methodName)))
- overloadCGThings.append(
- CGGeneric('MOZ_NOT_REACHED("We have an always-returning default case");\n'
- 'return false;'))
- self.cgRoot = CGWrapper(CGIndenter(CGList(overloadCGThings, "\n")),
- pre="\n")
-
- def define(self):
- return self.cgRoot.define()
-
-class FakeCastableDescriptor():
- def __init__(self, descriptor):
- self.castable = True
- self.workers = descriptor.workers
- self.nativeType = descriptor.nativeType
- self.pointerType = descriptor.pointerType
- self.name = descriptor.name
- self.hasXPConnectImpls = descriptor.hasXPConnectImpls
-
-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 getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
- isDefinitelyObject=False,
- isMember=False,
- isOptional=False,
- invalidEnumValueFatal=True,
- defaultValue=None,
- treatNullAs="Default",
- treatUndefinedAs="Default",
- isEnforceRange=False,
- isClamp=False):
- """
- 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.
-
- If isOptional is true, then we are doing conversion of an optional
- argument with no default value.
-
- 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.
-
- 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
- ${valPtr} is a pointer to the JS::Value in question
- ${holderName} replaced by the holder's name, if any
- ${declName} replaced by the declaration's name
- ${haveValue} replaced by an expression that evaluates to a boolean
- for whether we have a JS::Value. Only used when
- defaultValue is not None.
-
- 2) 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.
- 3) A CGThing representing the type of a "holder" (holderType) which will
- hold a possible reference to the C++ thing whose type we returned in #1,
- or None if no such holder is needed.
- 4) A boolean indicating whether the caller has to do optional-argument handling.
- This will only be true if isOptional is true and if the returned template
- expects both declType and holderType to be wrapped in Optional<>, with
- ${declName} and ${holderName} adjusted to point to the Value() of the
- Optional, and Construct() calls to be made on the Optional<>s as needed.
-
- ${declName} must be in scope before the generated code is entered.
-
- If holderType is not None then ${holderName} must be in scope
- before the generated code is entered.
- """
- # If we have a defaultValue then we're not actually optional for
- # purposes of what we need to be declared as.
- assert(defaultValue is None or not isOptional)
-
- # Also, we should not have a defaultValue if we know we're an object
- assert(not isDefinitelyObject or defaultValue is None)
-
- # 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
- 'return ThrowErrorMessage(cx, MSG_NOT_OBJECT);'), post="\n")
- def onFailureBadType(failureCode, typeName):
- return CGWrapper(CGGeneric(
- failureCode or
- 'return ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s");' % typeName), post="\n")
-
- # A helper function for handling default values. Takes a template
- # body and the C++ code to set the default value and wraps the
- # given template body in handling for the default value.
- def handleDefault(template, setDefault):
- if defaultValue is None:
- return template
- return CGWrapper(
- CGIndenter(CGGeneric(template)),
- pre="if ${haveValue} != 0 {\n",
- post=("\n"
- "} else {\n"
- "%s;\n"
- "}" %
- CGIndenter(CGGeneric(setDefault)).define())).define()
-
- # A helper function for handling null default values. Much like
- # handleDefault, but checks that the default value, if it exists, is null.
- def handleDefaultNull(template, codeToSetNull):
- if (defaultValue is not None and
- not isinstance(defaultValue, IDLNullValue)):
- raise TypeError("Can't handle non-null default value here")
- return handleDefault(template, codeToSetNull)
-
- # A helper function for wrapping up the template body for
- # possibly-nullable objecty stuff
- def wrapObjectTemplate(templateBody, isDefinitelyObject, type,
- codeToSetNull, failureCode=None):
- if not isDefinitelyObject:
- # Handle the non-object cases by wrapping up the whole
- # thing in an if cascade.
- templateBody = (
- "if (${val}.isObject()) {\n" +
- CGIndenter(CGGeneric(templateBody)).define() + "\n")
- if type.nullable():
- templateBody += (
- "} else if (${val}.isNullOrUndefined()) {\n"
- " %s;\n" % codeToSetNull)
- templateBody += (
- "} else {\n" +
- CGIndenter(onFailureNotAnObject(failureCode)).define() +
- "}")
- if type.nullable():
- templateBody = handleDefaultNull(templateBody, codeToSetNull)
- else:
- assert(defaultValue is None)
-
- 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():
- assert not isEnforceRange and not isClamp
-
- if failureCode is not None:
- raise TypeError("Can't handle sequences when failureCode is not None")
- nullable = type.nullable();
- # Be very careful not to change "type": we need it later
- if nullable:
- elementType = type.inner.inner
- else:
- elementType = type.inner
-
- # We have to be careful with reallocation behavior for arrays. In
- # particular, if we have a sequence of elements which are themselves
- # sequences (so nsAutoTArrays) or have sequences as members, we have a
- # problem. In that case, resizing the outermost nsAutoTarray to the
- # right size will memmove its elements, but nsAutoTArrays are not
- # memmovable and hence will end up with pointers to bogus memory, which
- # is bad. To deal with this, we disallow sequences, arrays,
- # dictionaries, and unions which contain sequences as sequence item
- # types. If WebIDL ever adds another container type, we'd have to
- # disallow it as well.
- if typeIsSequenceOrHasSequenceMember(elementType):
- raise TypeError("Can't handle a sequence containing another "
- "sequence as an element or member of an element. "
- "See the big comment explaining why.\n%s" %
- str(type.location))
-
- (elementTemplate, elementDeclType,
- elementHolderType, dealWithOptional) = getJSToNativeConversionTemplate(
- elementType, descriptorProvider, isMember=True)
- if dealWithOptional:
- raise TypeError("Shouldn't have optional things in sequences")
- if elementHolderType is not None:
- raise TypeError("Shouldn't need holders for sequences")
-
- typeName = CGWrapper(elementDeclType, pre="Sequence< ", post=" >")
- if nullable:
- typeName = CGWrapper(typeName, pre="Nullable< ", post=" >")
- arrayRef = "${declName}.Value()"
- else:
- arrayRef = "${declName}"
- # If we're optional, the const will come from the Optional
- mutableTypeName = typeName
- if not isOptional:
- typeName = CGWrapper(typeName, pre="const ")
-
- templateBody = ("""JSObject* seq = &${val}.toObject();\n
-if (!IsArrayLike(cx, seq)) {
- return Throw<%s>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
-}
-uint32_t length;
-// JS_GetArrayLength actually works on all objects
-if (!JS_GetArrayLength(cx, seq, &length)) {
- return false;
-}
-Sequence< %s > &arr = const_cast< Sequence< %s >& >(%s);
-if (!arr.SetCapacity(length)) {
- return Throw<%s>(cx, NS_ERROR_OUT_OF_MEMORY);
-}
-for (uint32_t i = 0; i < length; ++i) {
- jsval temp;
- if (!JS_GetElement(cx, seq, i, &temp)) {
- return false;
- }
-""" % (toStringBool(descriptorProvider.workers),
- elementDeclType.define(),
- elementDeclType.define(),
- arrayRef,
- toStringBool(descriptorProvider.workers)))
-
- templateBody += CGIndenter(CGGeneric(
- string.Template(elementTemplate).substitute(
- {
- "val" : "temp",
- "valPtr": "&temp",
- "declName" : "(*arr.AppendElement())"
- }
- ))).define()
-
- templateBody += "\n}"
- templateBody = wrapObjectTemplate(templateBody, isDefinitelyObject,
- type,
- "const_cast< %s & >(${declName}).SetNull()" % mutableTypeName.define())
- return (templateBody, typeName, None, isOptional)
-
- if type.isUnion():
- if isMember:
- raise TypeError("Can't handle unions as members, we have a "
- "holderType")
- nullable = type.nullable();
- if nullable:
- type = type.inner
-
- assert(defaultValue is None or
- (isinstance(defaultValue, IDLNullValue) and nullable))
-
- unionArgumentObj = "${holderName}"
- if isOptional or nullable:
- unionArgumentObj += ".ref()"
-
- memberTypes = type.flatMemberTypes
- names = []
-
- interfaceMemberTypes = filter(lambda t: t.isNonCallbackInterface(), memberTypes)
- if len(interfaceMemberTypes) > 0:
- interfaceObject = []
- for memberType in interfaceMemberTypes:
- if type.isGeckoInterface():
- name = memberType.inner.identifier.name
- else:
- name = memberType.name
- interfaceObject.append(CGGeneric("(failed = !%s.TrySetTo%s(cx, ${val}, ${valPtr}, tryNext)) || !tryNext" % (unionArgumentObj, name)))
- names.append(name)
- interfaceObject = CGWrapper(CGList(interfaceObject, " ||\n"), pre="done = ", post=";\n", reindent=True)
- else:
- interfaceObject = None
-
- arrayObjectMemberTypes = filter(lambda t: t.isArray() or t.isSequence(), memberTypes)
- if len(arrayObjectMemberTypes) > 0:
- assert len(arrayObjectMemberTypes) == 1
- memberType = arrayObjectMemberTypes[0]
- name = memberType.name
- arrayObject = CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${val}, ${valPtr}, tryNext)) || !tryNext;" % (unionArgumentObj, name))
- # XXX Now we're supposed to check for an array or a platform object
- # that supports indexed properties... skip that last for now. It's a
- # bit of a pain.
- arrayObject = CGWrapper(CGIndenter(arrayObject),
- pre="if (IsArrayLike(cx, &argObj)) {\n",
- post="}")
- names.append(name)
- else:
- arrayObject = None
-
- dateObjectMemberTypes = filter(lambda t: t.isDate(), memberTypes)
- if len(dateObjectMemberTypes) > 0:
- assert len(dateObjectMemberTypes) == 1
- memberType = dateObjectMemberTypes[0]
- name = memberType.name
- dateObject = CGGeneric("%s.SetTo%s(cx, ${val}, ${valPtr});\n"
- "done = true;" % (unionArgumentObj, name))
- dateObject = CGWrapper(CGIndenter(dateObject),
- pre="if (JS_ObjectIsDate(cx, &argObj)) {\n",
- post="\n}")
- names.append(name)
- else:
- dateObject = None
-
- callbackMemberTypes = filter(lambda t: t.isCallback() or t.isCallbackInterface(), memberTypes)
- if len(callbackMemberTypes) > 0:
- assert len(callbackMemberTypes) == 1
- memberType = callbackMemberTypes[0]
- name = memberType.name
- callbackObject = CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${val}, ${valPtr}, tryNext)) || !tryNext;" % (unionArgumentObj, name))
- names.append(name)
- 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:
- nonPlatformObject = CGList([callbackObject, dictionaryObject], "\n")
- nonPlatformObject = CGWrapper(CGIndenter(nonPlatformObject),
- pre="if (!IsPlatformObject(cx, &argObj)) {\n",
- post="\n}")
- else:
- nonPlatformObject = None
-
- objectMemberTypes = filter(lambda t: t.isObject(), memberTypes)
- if len(objectMemberTypes) > 0:
- object = CGGeneric("%s.SetToObject(&argObj);\n"
- "done = true;" % unionArgumentObj)
- else:
- object = None
-
- hasObjectTypes = interfaceObject or arrayObject or dateObject or nonPlatformObject or object
- if hasObjectTypes:
- # If we try more specific object types first then we need to check
- # whether that succeeded before converting to object.
- if object and (interfaceObject or arrayObject or dateObject or nonPlatformObject):
- object = CGWrapper(CGIndenter(object), pre="if (!done) {\n",
- post=("\n}"))
-
- if arrayObject or dateObject or nonPlatformObject:
- # An object can be both an array object and not a platform
- # object, but we shouldn't have both in the union's members
- # because they are not distinguishable.
- assert not (arrayObject and nonPlatformObject)
- templateBody = CGList([arrayObject, dateObject, nonPlatformObject], " else ")
- else:
- templateBody = None
- if interfaceObject:
- if templateBody:
- templateBody = CGList([templateBody, object], "\n")
- templateBody = CGWrapper(CGIndenter(templateBody),
- pre="if (!done) {\n", post=("\n}"))
- templateBody = CGList([interfaceObject, templateBody], "\n")
- else:
- templateBody = CGList([templateBody, object], "\n")
-
- if any([arrayObject, dateObject, nonPlatformObject, object]):
- templateBody.prepend(CGGeneric("JSObject& argObj = ${val}.toObject();"))
- templateBody = CGWrapper(CGIndenter(templateBody),
- pre="if (${val}.isObject()) {\n",
- post="\n}")
- else:
- templateBody = CGGeneric()
-
- otherMemberTypes = filter(lambda t: t.isString() or t.isEnum(),
- memberTypes)
- otherMemberTypes.extend(t for t in memberTypes if t.isPrimitive())
- if len(otherMemberTypes) > 0:
- assert len(otherMemberTypes) == 1
- memberType = otherMemberTypes[0]
- if memberType.isEnum():
- name = memberType.inner.identifier.name
- else:
- name = memberType.name
- other = CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${val}, ${valPtr}, tryNext)) || !tryNext;" % (unionArgumentObj, name))
- names.append(name)
- if hasObjectTypes:
- other = CGWrapper(CGIndenter(other), "{\n", post="\n}")
- if object:
- join = " else "
- else:
- other = CGWrapper(other, pre="if (!done) ")
- join = "\n"
- templateBody = CGList([templateBody, other], join)
- else:
- other = None
-
- templateBody = CGWrapper(templateBody, pre="bool done = false, failed = false, tryNext;\n")
- throw = CGGeneric("if (failed) {\n"
- " return false;\n"
- "}\n"
- "if (!done) {\n"
- " return ThrowErrorMessage(cx, MSG_NOT_IN_UNION, \"%s\");\n"
- "}" % ", ".join(names))
- templateBody = CGWrapper(CGIndenter(CGList([templateBody, throw], "\n")), pre="{\n", post="\n}")
-
- typeName = type.name
- argumentTypeName = typeName + "Argument"
- if nullable:
- typeName = "Nullable<" + typeName + " >"
- if isOptional:
- nonConstDecl = "const_cast<Optional<" + typeName + " >& >(${declName})"
- else:
- nonConstDecl = "const_cast<" + typeName + "& >(${declName})"
- typeName = "const " + typeName
-
- def handleNull(templateBody, setToNullVar, extraConditionForNull=""):
- null = CGGeneric("if (%s${val}.isNullOrUndefined()) {\n"
- " %s.SetNull();\n"
- "}" % (extraConditionForNull, setToNullVar))
- templateBody = CGWrapper(CGIndenter(templateBody), pre="{\n", post="\n}")
- return CGList([null, templateBody], " else ")
-
- if type.hasNullableType:
- templateBody = handleNull(templateBody, unionArgumentObj)
-
- declType = CGGeneric(typeName)
- holderType = CGGeneric(argumentTypeName)
- if isOptional:
- mutableDecl = nonConstDecl + ".Value()"
- declType = CGWrapper(declType, pre="const Optional<", post=" >")
- holderType = CGWrapper(holderType, pre="Maybe<", post=" >")
- constructDecl = CGGeneric(nonConstDecl + ".Construct();")
- if nullable:
- constructHolder = CGGeneric("${holderName}.construct(%s.SetValue());" % mutableDecl)
- else:
- constructHolder = CGGeneric("${holderName}.construct(${declName}.Value());")
- else:
- mutableDecl = nonConstDecl
- constructDecl = None
- if nullable:
- holderType = CGWrapper(holderType, pre="Maybe<", post=" >")
- constructHolder = CGGeneric("${holderName}.construct(%s.SetValue());" % mutableDecl)
- else:
- constructHolder = CGWrapper(holderType, post=" ${holderName}(${declName});")
- holderType = None
-
- templateBody = CGList([constructHolder, templateBody], "\n")
- if nullable:
- if defaultValue:
- assert(isinstance(defaultValue, IDLNullValue))
- valueMissing = "!(${haveValue}) || "
- else:
- valueMissing = ""
- templateBody = handleNull(templateBody, mutableDecl,
- extraConditionForNull=valueMissing)
- templateBody = CGList([constructDecl, templateBody], "\n")
-
- return templateBody.define(), declType, holderType, False
-
- if type.isGeckoInterface():
- assert not isEnforceRange and not isClamp
-
- descriptor = descriptorProvider.getDescriptor(
- type.unroll().inner.identifier.name)
- # This is an interface that we implement as a concrete class
- # or an XPCOM interface.
-
- # Allow null pointers for nullable types and old-binding classes
- argIsPointer = type.nullable() or type.unroll().inner.isExternal()
-
- # Sequences and non-worker callbacks have to hold a strong ref to the
- # thing being passed down.
- forceOwningType = (descriptor.interface.isCallback() and
- not descriptor.workers) or isMember
-
- typeName = descriptor.nativeType
- typePtr = typeName + "*"
-
- # Compute a few things:
- # - declType is the type we want to return as the first element of our
- # tuple.
- # - holderType is the type we want to return as the third element
- # of our tuple.
-
- # Set up some sensible defaults for these things insofar as we can.
- holderType = None
- if argIsPointer:
- if forceOwningType:
- declType = "nsRefPtr<" + typeName + ">"
- else:
- declType = typePtr
- else:
- if forceOwningType:
- declType = "OwningNonNull<" + typeName + ">"
- else:
- declType = "NonNull<" + typeName + ">"
-
- templateBody = ""
- if descriptor.castable:
- if descriptor.prefable:
- raise TypeError("We don't support prefable castable object "
- "arguments (like %s), because we don't know "
- "how to handle them being preffed off" %
- descriptor.interface.identifier.name)
- if descriptor.interface.isConsequential():
- raise TypeError("Consequential interface %s being used as an "
- "argument but flagged as castable" %
- descriptor.interface.identifier.name)
- if failureCode is not None:
- templateBody += str(CastableObjectUnwrapper(
- descriptor,
- "&${val}.toObject()",
- "${declName}",
- failureCode))
- else:
- pass
- #XXXjdm unfinished
- #templateBody += str(FailureFatalCastableObjectUnwrapper(
- # descriptor,
- # "&${val}.toObject()",
- # "${declName}"))
- elif descriptor.interface.isCallback() and False:
- #XXXjdm unfinished
- templateBody += str(CallbackObjectUnwrapper(
- descriptor,
- "&${val}.toObject()",
- "${declName}",
- codeOnFailure=failureCode))
- elif descriptor.workers:
- templateBody += "${declName} = &${val}.toObject();"
- else:
- # Either external, or new-binding non-castable. We always have a
- # holder for these, because we don't actually know whether we have
- # to addref when unwrapping or not. So we just pass an
- # getter_AddRefs(nsRefPtr) to XPConnect and if we'll need a release
- # it'll put a non-null pointer in there.
- if forceOwningType:
- # Don't return a holderType in this case; our declName
- # will just own stuff.
- templateBody += "nsRefPtr<" + typeName + "> ${holderName};\n"
- else:
- holderType = "nsRefPtr<" + typeName + ">"
- templateBody += (
- "jsval tmpVal = ${val};\n" +
- typePtr + " tmp;\n"
- "if (NS_FAILED(xpc_qsUnwrapArg<" + typeName + ">(cx, ${val}, &tmp, static_cast<" + typeName + "**>(getter_AddRefs(${holderName})), &tmpVal))) {\n")
- templateBody += CGIndenter(onFailureBadType(failureCode,
- descriptor.interface.identifier.name)).define()
- templateBody += ("}\n"
- "MOZ_ASSERT(tmp);\n")
-
- if not isDefinitelyObject:
- # Our tmpVal will go out of scope, so we can't rely on it
- # for rooting
- templateBody += (
- "if (tmpVal != ${val} && !${holderName}) {\n"
- " // We have to have a strong ref, because we got this off\n"
- " // some random object that might get GCed\n"
- " ${holderName} = tmp;\n"
- "}\n")
-
- # And store our tmp, before it goes out of scope.
- templateBody += "${declName} = tmp;"
-
- templateBody = wrapObjectTemplate(templateBody, isDefinitelyObject,
- type, "${declName} = NULL",
- failureCode)
-
- declType = CGGeneric(declType)
- if holderType is not None:
- holderType = CGGeneric(holderType)
- return (templateBody, declType, holderType, isOptional)
-
- if type.isSpiderMonkeyInterface():
- assert not isEnforceRange and not isClamp
- if isMember:
- raise TypeError("Can't handle member arraybuffers or "
- "arraybuffer views because making sure all the "
- "objects are properly rooted is hard")
- name = type.name
- # By default, we use a Maybe<> to hold our typed array. And in the optional
- # non-nullable case we want to pass Optional<TypedArray> to consumers, not
- # Optional<NonNull<TypedArray> >, so jump though some hoops to do that.
- holderType = "Maybe<%s>" % name
- constructLoc = "${holderName}"
- constructMethod = "construct"
- constructInternal = "ref"
- if type.nullable():
- if isOptional:
- declType = "const Optional<" + name + "*>"
- else:
- declType = name + "*"
- else:
- if isOptional:
- declType = "const Optional<" + name + ">"
- # We don't need a holder in this case
- holderType = None
- constructLoc = "(const_cast<Optional<" + name + ">& >(${declName}))"
- constructMethod = "Construct"
- constructInternal = "Value"
- else:
- declType = "NonNull<" + name + ">"
- template = (
- "%s.%s(cx, &${val}.toObject());\n"
- "if (!%s.%s().inited()) {\n"
- "%s" # No newline here because onFailureBadType() handles that
- "}\n" %
- (constructLoc, constructMethod, constructLoc, constructInternal,
- CGIndenter(onFailureBadType(failureCode, type.name)).define()))
- nullableTarget = ""
- if type.nullable():
- if isOptional:
- mutableDecl = "(const_cast<Optional<" + name + "*>& >(${declName}))"
- template += "%s.Construct();\n" % mutableDecl
- nullableTarget = "%s.Value()" % mutableDecl
- else:
- nullableTarget = "${declName}"
- template += "%s = ${holderName}.addr();" % nullableTarget
- elif not isOptional:
- template += "${declName} = ${holderName}.addr();"
- template = wrapObjectTemplate(template, isDefinitelyObject, type,
- "%s = NULL" % nullableTarget,
- failureCode)
-
- if holderType is not None:
- holderType = CGGeneric(holderType)
- # We handle all the optional stuff ourselves; no need for caller to do it.
- return (template, CGGeneric(declType), holderType, False)
-
- if type.isString():
- assert not isEnforceRange and not isClamp
-
- treatAs = {
- "Default": "eStringify",
- "EmptyString": "eEmpty",
- "Null": "eNull"
- }
- if type.nullable():
- # For nullable strings null becomes a null string.
- treatNullAs = "Null"
- # For nullable strings undefined becomes a null string unless
- # specified otherwise.
- if treatUndefinedAs == "Default":
- treatUndefinedAs = "Null"
- nullBehavior = treatAs[treatNullAs]
- if treatUndefinedAs == "Missing":
- raise TypeError("We don't support [TreatUndefinedAs=Missing]")
- undefinedBehavior = treatAs[treatUndefinedAs]
-
- def getConversionCode(varName):
- #conversionCode = (
- # "if (!ConvertJSValueToString(cx, ${val}, ${valPtr}, %s, %s, %s)) {\n"
- # " return false;\n"
- # "}" % (nullBehavior, undefinedBehavior, varName))
- conversionCode = (
- "let strval = jsval_to_str(cx, ${val});\n"
- "if strval.is_err() {\n"
- " return 0;\n"
- "}\n"
- "%s = str(strval.get());" % varName)
- if defaultValue is None:
- return conversionCode
-
- if isinstance(defaultValue, IDLNullValue):
- assert(type.nullable())
- return handleDefault(conversionCode,
- "%s.SetNull()" % varName)
- return handleDefault(
- conversionCode,
- ("static const PRUnichar data[] = { %s };\n"
- "%s.SetData(data, ArrayLength(data) - 1)" %
- (", ".join(["'" + char + "'" for char in defaultValue.value] + ["0"]),
- varName)))
-
- if isMember:
- # We have to make a copy, because our jsval may well not
- # live as long as our string needs to.
- declType = CGGeneric("nsString")
- return (
- "{\n"
- " FakeDependentString str;\n"
- "%s\n"
- " ${declName} = str;\n"
- "}\n" % CGIndenter(CGGeneric(getConversionCode("str"))).define(),
- declType, None, isOptional)
-
- if isOptional:
- declType = "Option<DOMString>"
- else:
- declType = "DOMString"
-
- return (
- "%s\n" %
- #"const_cast<%s&>(${declName}) = &${holderName};" %
- (getConversionCode("${declName}")),
- CGGeneric(declType), None, #CGGeneric("FakeDependentString"),
- # No need to deal with Optional here; we have handled it already
- False)
-
- 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 = " return 0;\n"
- else:
- handleInvalidEnumValueCode = " return 1;\n"
-
- template = (
- "{\n"
- #" int index = FindEnumStringIndex<%(invalidEnumValueFatal)s>(cx, ${val}, %(values)s, \"%(enumtype)s\", &ok);\n"
- " let result = FindEnumStringIndex(cx, ${val}, %(values)s);\n"
- " if result.is_err() {\n"
- "%(handleInvalidEnumValueCode)s"
- " }\n"
- " let index = result.get();\n"
- " ${declName} = cast::transmute(index); //XXXjdm need some range checks up in here\n"
- "}" % { "enumtype" : enum,
- "values" : enum + "Values::strings",
- "invalidEnumValueFatal" : toStringBool(invalidEnumValueFatal),
- "handleInvalidEnumValueCode" : handleInvalidEnumValueCode })
-
- if defaultValue is not None:
- assert(defaultValue.type.tag() == IDLType.Tags.domstring)
- template = "" #XXXjdm unfinished
- #template = handleDefault(template,
- # ("${declName} = %sValues::%s" %
- # (enum,
- # getEnumValueName(defaultValue.value))))
- return (template, CGGeneric(enum), None, isOptional)
-
- if type.isCallback():
- assert not isEnforceRange and not isClamp
-
- if isMember:
- raise TypeError("Can't handle member callbacks; need to sort out "
- "rooting issues")
- # XXXbz we're going to assume that callback types are always
- # nullable and always have [TreatNonCallableAsNull] for now.
- haveCallable = "${val}.isObject() && JS_ObjectIsCallable(cx, &${val}.toObject())"
- if defaultValue is not None:
- assert(isinstance(defaultValue, IDLNullValue))
- haveCallable = "${haveValue} && " + haveCallable
- return (
- "if (%s) {\n"
- " ${declName} = &${val}.toObject();\n"
- "} else {\n"
- " ${declName} = NULL;\n"
- "}" % haveCallable,
- CGGeneric("JSObject*"), None, isOptional)
-
- if type.isAny():
- assert not isEnforceRange and not isClamp
-
- if isMember:
- raise TypeError("Can't handle member 'any'; need to sort out "
- "rooting issues")
- templateBody = "${declName} = ${val};"
- templateBody = handleDefaultNull(templateBody,
- "${declName} = JS::NullValue()")
- return (templateBody, CGGeneric("JS::Value"), None, isOptional)
-
- if type.isObject():
- assert not isEnforceRange and not isClamp
-
- if isMember:
- raise TypeError("Can't handle member 'object'; need to sort out "
- "rooting issues")
- template = wrapObjectTemplate("${declName} = &${val}.toObject();",
- isDefinitelyObject, type,
- "${declName} = NULL",
- failureCode)
- if type.nullable():
- declType = CGGeneric("JSObject*")
- else:
- declType = CGGeneric("NonNull<JSObject>")
- return (template, declType, None, isOptional)
-
- 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()
- # All optional dictionaries always have default values, so we
- # should be able to assume not isOptional here.
- assert not isOptional
-
- typeName = CGDictionary.makeDictionaryName(type.inner,
- descriptorProvider.workers)
- actualTypeName = typeName
- selfRef = "${declName}"
-
- declType = CGGeneric(actualTypeName)
-
- # If we're a member of something else, the const
- # will come from the Optional or our container.
- if not isMember:
- selfRef = "%s" % selfRef
-
- # We do manual default value handling here, because we
- # actually do want a jsval, and we only handle null anyway
- if defaultValue is not None:
- assert(isinstance(defaultValue, IDLNullValue))
- val = "if ${haveValue} { ${val} } else { JSVAL_NULL }"
- else:
- val = "${val}"
-
- template = ("%s = %s::new();\n"
- "if %s.Init(cx, %s) == 0 {\n"
- " return 0;\n"
- "}" % (selfRef, actualTypeName, selfRef, val))
-
- return (template, declType, None, False)
-
- if not type.isPrimitive():
- raise TypeError("Need conversion for argument type '%s'" % str(type))
-
- typeName = builtinNames[type.tag()]
-
- conversionBehavior = "eDefault"
- if isEnforceRange:
- conversionBehavior = "eEnforceRange"
- elif isClamp:
- conversionBehavior = "eClamp"
-
- if type.nullable():
- dataLoc = "${declName}.SetValue()"
- nullCondition = "${val}.isNullOrUndefined()"
- if defaultValue is not None and isinstance(defaultValue, IDLNullValue):
- nullCondition = "!(${haveValue}) || " + nullCondition
- template = (
- "if (%s) {\n"
- " ${declName}.SetNull();\n"
- "} else if (!ValueToPrimitive<%s, %s>(cx, ${val}, &%s)) {\n"
- " return false;\n"
- "}" % (nullCondition, typeName, conversionBehavior, dataLoc))
- declType = CGGeneric("Nullable<" + typeName + ">")
- else:
- assert(defaultValue is None or
- not isinstance(defaultValue, IDLNullValue))
- dataLoc = "${declName}"
- #XXXjdm conversionBehavior should be used
- template = (
- "match JSValConvertible::from_jsval::<%s>(${val}) {\n"
- " None => return 0,\n"
- " Some(v) => %s = v\n"
- "}" % (typeName, dataLoc))
- declType = CGGeneric(typeName)
- if (defaultValue is not None and
- # We already handled IDLNullValue, so just deal with the other ones
- not isinstance(defaultValue, IDLNullValue)):
- tag = defaultValue.type.tag()
- if tag in numericTags:
- defaultStr = defaultValue.value
- else:
- assert(tag == IDLType.Tags.bool)
- defaultStr = toStringBool(defaultValue.value)
- template = CGWrapper(CGIndenter(CGGeneric(template)),
- pre="if ${haveValue} != 0 {\n",
- post=("\n"
- "} else {\n"
- " %s = %s;\n"
- "}" % (dataLoc, defaultStr))).define()
-
- return (template, declType, None, isOptional)
-
-def instantiateJSToNativeConversionTemplate(templateTuple, replacements,
- argcAndIndex=None):
- """
- Take a tuple as returned by getJSToNativeConversionTemplate and a set of
- replacements as required by the strings in such a tuple, and generate code
- to convert into stack C++ types.
-
- If argcAndIndex is not None it must be a dict that can be used to
- replace ${argc} and ${index}, where ${index} is the index of this
- argument (0-based) and ${argc} is the total number of arguments.
- """
- (templateBody, declType, holderType, dealWithOptional) = templateTuple
-
- if dealWithOptional and argcAndIndex is None:
- raise TypeError("Have to deal with optional things, but don't know how")
- if argcAndIndex is not None and declType is None:
- raise TypeError("Need to predeclare optional things, so they will be "
- "outside the check for big enough arg count!");
-
- result = CGList([], "\n")
- # Make a copy of "replacements" since we may be about to start modifying it
- replacements = dict(replacements)
- originalHolderName = replacements["holderName"]
- if holderType is not None:
- if dealWithOptional:
- replacements["holderName"] = (
- "const_cast< %s & >(%s.Value())" %
- (holderType.define(), originalHolderName))
- mutableHolderType = CGWrapper(holderType, pre="Optional< ", post=" >")
- holderType = CGWrapper(mutableHolderType, pre="const ")
- result.append(
- CGList([holderType, CGGeneric(" "),
- CGGeneric(originalHolderName),
- CGGeneric(";")]))
-
- originalDeclName = replacements["declName"]
- if declType is not None:
- if dealWithOptional:
- replacements["declName"] = (
- "const_cast< %s & >(%s.Value())" %
- (declType.define(), originalDeclName))
- mutableDeclType = CGWrapper(declType, pre="Optional< ", post=" >")
- declType = CGWrapper(mutableDeclType, pre="const ")
- result.append(
- CGList([CGGeneric("let mut "),
- CGGeneric(originalDeclName),
- CGGeneric(": "),
- declType,
- CGGeneric(";")]))
-
- conversion = CGGeneric(
- string.Template(templateBody).substitute(replacements)
- )
-
- if argcAndIndex is not None:
- if dealWithOptional:
- declConstruct = CGIndenter(
- CGGeneric("const_cast< %s &>(%s).Construct();" %
- (mutableDeclType.define(), originalDeclName)))
- if holderType is not None:
- holderConstruct = CGIndenter(
- CGGeneric("const_cast< %s &>(%s).Construct();" %
- (mutableHolderType.define(), originalHolderName)))
- else:
- holderConstruct = None
- else:
- declConstruct = None
- holderConstruct = None
-
- conversion = CGList(
- [CGGeneric(
- string.Template("if (${index} < ${argc}) {").substitute(
- argcAndIndex
- )),
- declConstruct,
- holderConstruct,
- CGIndenter(conversion),
- CGGeneric("}")],
- "\n")
-
- result.append(conversion)
- # Add an empty CGGeneric to get an extra newline after the argument
- # conversion.
- 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)
- self.argument = argument
- if argument.variadic:
- raise TypeError("We don't support variadic arguments yet " +
- str(argument.location))
- assert(not argument.defaultValue or argument.optional)
-
- replacer = {
- "index" : index,
- "argc" : argc,
- "argv" : argv
- }
- self.replacementVariables = {
- "declName" : "arg%d" % index,
- "holderName" : ("arg%d" % index) + "_holder"
- }
- self.replacementVariables["val"] = string.Template(
- "(*${argv}.offset(${index}))"
- ).substitute(replacer)
- self.replacementVariables["valPtr"] = (
- "&" + self.replacementVariables["val"])
- if argument.defaultValue:
- self.replacementVariables["haveValue"] = string.Template(
- "${index} < ${argc}").substitute(replacer)
- self.descriptorProvider = descriptorProvider
- if self.argument.optional and not self.argument.defaultValue:
- self.argcAndIndex = replacer
- else:
- self.argcAndIndex = None
- self.invalidEnumValueFatal = invalidEnumValueFatal
-
- def define(self):
- return instantiateJSToNativeConversionTemplate(
- getJSToNativeConversionTemplate(self.argument.type,
- self.descriptorProvider,
- isOptional=(self.argcAndIndex is not None),
- invalidEnumValueFatal=self.invalidEnumValueFatal,
- defaultValue=self.argument.defaultValue,
- treatNullAs=self.argument.treatNullAs,
- treatUndefinedAs=self.argument.treatUndefinedAs,
- isEnforceRange=self.argument.enforceRange,
- isClamp=self.argument.clamp),
- self.replacementVariables,
- self.argcAndIndex).define()
-
-def getWrapTemplateForType(type, descriptorProvider, result, successCode,
- isCreator):
- """
- Reflect a C++ value stored in "result", of IDL type "type" into JS. The
- "successCode" is the code to run once we have successfully done the
- conversion. The resulting string should be used with string.Template, it
- needs the following keys when substituting: jsvalPtr/jsvalRef/obj.
-
- Returns (templateString, infallibility of conversion template)
- """
- haveSuccessCode = successCode is not None
- if not haveSuccessCode:
- successCode = "return 1;"
-
- def setValue(value, callWrapValue=False):
- """
- Returns the code to set the jsval to value. If "callWrapValue" is true
- JS_WrapValue will be called on the jsval.
- """
- if not callWrapValue:
- tail = successCode
- elif haveSuccessCode:
- tail = ("if (!JS_WrapValue(cx, ${jsvalPtr})) {\n" +
- " return false;\n" +
- "}\n" +
- successCode)
- else:
- tail = "return JS_WrapValue(cx, cast::transmute(${jsvalPtr}));"
- return ("${jsvalRef} = %s;\n" +
- tail) % (value)
-
- def wrapAndSetPtr(wrapCall, failureCode=None):
- """
- Returns the code to set the jsval by calling "wrapCall". "failureCode"
- is the code to run if calling "wrapCall" fails
- """
- if failureCode is None:
- if not haveSuccessCode:
- return wrapCall + ";\n" + "return if (*vp).v != 0 { 1 } else { 0 };"
- failureCode = "return 0;"
- str = ("if !%s {\n" +
- CGIndenter(CGGeneric(failureCode)).define() + "\n" +
- "}\n" +
- successCode) % (wrapCall)
- return str
-
- if type is None or type.isVoid():
- return (setValue("JSVAL_VOID"), True)
-
- if type.isArray():
- raise TypeError("Can't handle array return values yet")
-
- if type.isSequence():
- if type.nullable():
- # Nullable sequences are Nullable< nsTArray<T> >
- (recTemplate, recInfall) = getWrapTemplateForType(type.inner, descriptorProvider,
- "%s.Value()" % result, successCode,
- isCreator)
- return ("""
-if (%s.IsNull()) {
-%s
-}
-%s""" % (result, CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define(), recTemplate), recInfall)
-
- # Now do non-nullable sequences. We use setting the element
- # in the array as our succcess code because when we succeed in
- # wrapping that's what we should do.
- innerTemplate = wrapForType(
- type.inner, descriptorProvider,
- {
- 'result' : "%s[i]" % result,
- 'successCode': ("if (!JS_DefineElement(cx, returnArray, i, tmp,\n"
- " NULL, NULL, JSPROP_ENUMERATE)) {\n"
- " return false;\n"
- "}"),
- 'jsvalRef': "tmp",
- 'jsvalPtr': "&tmp",
- 'isCreator': isCreator
- }
- )
- innerTemplate = CGIndenter(CGGeneric(innerTemplate)).define()
- return (("""
-uint32_t length = %s.Length();
-JSObject *returnArray = JS_NewArrayObject(cx, length, NULL);
-if (!returnArray) {
- return false;
-}
-jsval tmp;
-for (uint32_t i = 0; i < length; ++i) {
-%s
-}\n""" % (result, innerTemplate)) + setValue("JS::ObjectValue(*returnArray)"), False)
-
- if type.isGeckoInterface():
- descriptor = descriptorProvider.getDescriptor(type.unroll().inner.identifier.name)
- if type.nullable():
- wrappingCode = ("if %s.is_none() {\n" % (result) +
- CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define() + "\n" +
- "}\n" +
- "let mut %s = %s.get();\n" % (result, result))
- else:
- wrappingCode = ""
- if (not descriptor.interface.isExternal() and
- not descriptor.interface.isCallback()):
- if descriptor.wrapperCache:
- wrapMethod = "WrapNewBindingObject"
- else:
- if not isCreator:
- raise MethodNotCreatorError(descriptor.interface.identifier.name)
- wrapMethod = "WrapNewBindingNonWrapperCachedObject"
- wrap = "%s(cx, ${obj}, %s as @mut CacheableWrapper, ${jsvalPtr})" % (wrapMethod, result)
- # We don't support prefable stuff in workers.
- assert(not descriptor.prefable or not descriptor.workers)
- if not descriptor.prefable:
- # Non-prefable bindings can only fail to wrap as a new-binding object
- # if they already threw an exception. Same thing for
- # non-prefable bindings.
- failed = ("//MOZ_ASSERT(JS_IsExceptionPending(cx));\n" +
- "return 0;")
- else:
- if descriptor.notflattened:
- raise TypeError("%s is prefable but not flattened; "
- "fallback won't work correctly" %
- descriptor.interface.identifier.name)
- # Try old-style wrapping for bindings which might be preffed off.
- failed = wrapAndSetPtr("HandleNewBindingWrappingFailure(cx, ${obj}, %s, ${jsvalPtr})" % result)
- wrappingCode += wrapAndSetPtr(wrap, failed)
- else:
- #wrap = "WrapObject(cx, ${obj}, %s, %s${jsvalPtr})" % (result, getIID)
- if descriptor.pointerType == '':
- wrap = "%s.wrap(cx, ${obj}, ${jsvalPtr})" % result
- else:
- wrap = "if WrapNewBindingObject(cx, ${obj}, %s as @mut CacheableWrapper, ${jsvalPtr}) { 1 } else { 0 };" % result
- wrappingCode += wrapAndSetPtr(wrap)
- return (wrappingCode, False)
-
- if type.isString():
- if type.nullable():
- return (wrapAndSetPtr("*${jsvalPtr} = domstring_to_jsval(cx, &%s)" % result), False)
- else:
- #XXXjdm Can we be smarter when we know it's not nullable?
- return (wrapAndSetPtr("*${jsvalPtr} = domstring_to_jsval(cx, &%s)" % result), False)
-
- if type.isEnum():
- if type.nullable():
- raise TypeError("We don't support nullable enumerated return types "
- "yet")
- return ("""MOZ_ASSERT(uint32_t(%(result)s) < ArrayLength(%(strings)s));
-JSString* %(resultStr)s = JS_NewStringCopyN(cx, %(strings)s[uint32_t(%(result)s)].value, %(strings)s[uint32_t(%(result)s)].length);
-if (!%(resultStr)s) {
- return false;
-}
-""" % { "result" : result,
- "resultStr" : result + "_str",
- "strings" : type.inner.identifier.name + "Values::strings" } +
- setValue("JS::StringValue(%s_str)" % result), False)
-
- if type.isCallback():
- assert not type.isInterface()
- # XXXbz we're going to assume that callback types are always
- # nullable and always have [TreatNonCallableAsNull] for now.
- # See comments in WrapNewBindingObject explaining why we need
- # to wrap here.
- # NB: setValue(..., True) calls JS_WrapValue(), so is fallible
- return (setValue("JS::ObjectOrNullValue(%s)" % result, True), False)
-
- if type.tag() == IDLType.Tags.any:
- # See comments in WrapNewBindingObject explaining why we need
- # to wrap here.
- # NB: setValue(..., True) calls JS_WrapValue(), so is fallible
- return (setValue(result, True), False)
-
- if type.isObject() or type.isSpiderMonkeyInterface():
- # See comments in WrapNewBindingObject explaining why we need
- # to wrap here.
- if type.nullable():
- toValue = "RUST_OBJECT_TO_JSVAL(%s)"
- else:
- toValue = "JS::ObjectValue(*%s)"
- # NB: setValue(..., True) calls JS_WrapValue(), so is fallible
- return (setValue(toValue % result, True), False)
-
- if not type.isPrimitive():
- raise TypeError("Need to learn to wrap %s" % type)
-
- if type.nullable():
- (recTemplate, recInfal) = getWrapTemplateForType(type.inner, descriptorProvider,
- "%s.Value()" % result, successCode,
- isCreator)
- return ("if (%s.IsNull()) {\n" % result +
- CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define() + "\n" +
- "}\n" + recTemplate, recInfal)
-
- tag = type.tag()
-
- if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16,
- IDLType.Tags.uint16, IDLType.Tags.int32]:
- return (setValue("RUST_INT_TO_JSVAL(%s as i32)" % result), True)
-
- elif tag in [IDLType.Tags.int64, IDLType.Tags.uint64, IDLType.Tags.float,
- IDLType.Tags.double]:
- # XXXbz will cast to double do the "even significand" thing that webidl
- # calls for for 64-bit ints? Do we care?
- return (setValue("RUST_JS_NumberValue(%s as f64)" % result), True)
-
- elif tag == IDLType.Tags.uint32:
- return (setValue("RUST_UINT_TO_JSVAL(%s)" % result), True)
-
- elif tag == IDLType.Tags.bool:
- return (setValue("RUST_BOOLEAN_TO_JSVAL(%s as JSBool)" % result), True)
-
- else:
- raise TypeError("Need to learn to wrap primitive: %s" % type)
-
-def wrapForType(type, descriptorProvider, templateValues):
- """
- Reflect a C++ value of IDL type "type" into JS. TemplateValues is a dict
- that should contain:
-
- * 'jsvalRef': a C++ reference to the jsval in which to store the result of
- the conversion
- * 'jsvalPtr': a C++ pointer to the jsval in which to store the result of
- the conversion
- * 'obj' (optional): the name of the variable that contains the JSObject to
- use as a scope when wrapping, if not supplied 'obj'
- will be used as the name
- * 'result' (optional): the name of the variable in which the C++ value is
- stored, if not supplied 'result' will be used as
- the name
- * 'successCode' (optional): the code to run once we have successfully done
- the conversion, if not supplied 'return true;'
- will be used as the code
- * 'isCreator' (optional): If true, we're wrapping for the return value of
- a [Creator] method. Assumed false if not set.
- """
- wrap = getWrapTemplateForType(type, descriptorProvider,
- templateValues.get('result', 'result'),
- templateValues.get('successCode', None),
- templateValues.get('isCreator', False))[0]
-
- defaultValues = {'obj': 'obj'}
- return string.Template(wrap).substitute(defaultValues, **templateValues)
-
-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.isCallback() or type.isAny() or type.isObject()
-
-def memberIsCreator(member):
- return member.getExtendedAttribute("Creator") is not None
-
-# Returns a tuple consisting of a CGThing containing the type of the return
-# value, or None if there is no need for a return value, and a boolean signaling
-# whether the return value is passed in an out parameter.
-def getRetvalDeclarationForType(returnType, descriptorProvider,
- resultAlreadyAddRefed):
- if returnType is None or returnType.isVoid():
- # Nothing to declare
- return None, False
- if returnType.isPrimitive() and returnType.tag() in builtinNames:
- result = CGGeneric(builtinNames[returnType.tag()])
- if returnType.nullable():
- result = CGWrapper(result, pre="Nullable<", post=">")
- return result, False
- if returnType.isString():
- return CGGeneric("DOMString"), False
- if returnType.isEnum():
- if returnType.nullable():
- raise TypeError("We don't support nullable enum return values")
- return CGGeneric(returnType.inner.identifier.name), False
- if returnType.isGeckoInterface():
- descriptor = descriptorProvider.getDescriptor(
- returnType.unroll().inner.identifier.name)
- result = CGGeneric(descriptor.nativeType)
- if returnType.nullable():
- result = CGWrapper(result, pre=("Option<" + descriptor.pointerType), post=">")
- else:
- result = CGWrapper(result, pre=descriptor.pointerType)
- return result, False
- if returnType.isCallback():
- # XXXbz we're going to assume that callback types are always
- # nullable for now.
- return CGGeneric("*JSObject"), False
- if returnType.isAny():
- return CGGeneric("JSVal"), False
- if returnType.isObject() or returnType.isSpiderMonkeyInterface():
- return CGGeneric("*JSObject"), False
- if returnType.isSequence():
- nullable = returnType.nullable()
- if nullable:
- returnType = returnType.inner
- # If our result is already addrefed, use the right type in the
- # sequence argument here.
- (result, _) = getRetvalDeclarationForType(returnType.inner,
- descriptorProvider,
- resultAlreadyAddRefed)
- result = CGWrapper(result, pre="nsTArray< ", post=" >")
- if nullable:
- result = CGWrapper(result, pre="Nullable< ", post=" >")
- return result, True
- raise TypeError("Don't know how to declare return value for %s" %
- returnType)
-
-def isChromeOnly(m):
- return m.getExtendedAttribute("ChromeOnly")
-
-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.chrome to the list of
- things exposed to chrome and self.regular to the list of things exposed to
- web pages. self.chrome must be a superset of self.regular but also include
- all the ChromeOnly stuff.
- """
- def __init__(self, descriptor, name):
- self.descriptor = descriptor
- self.name = name
- # self.prefCacheData will store an array of (prefname, bool*)
- # pairs for our bool var caches. generateArray will fill it
- # in as needed.
- self.prefCacheData = []
- def hasChromeOnly(self):
- return len(self.chrome) > len(self.regular)
- def hasNonChromeOnly(self):
- return len(self.regular) > 0
- def variableName(self, chrome):
- if chrome and self.hasChromeOnly():
- return "sChrome" + self.name
- if self.hasNonChromeOnly():
- return "s" + self.name
- return "ptr::null()"
- def usedForXrays(self, chrome):
- # We only need Xrays for methods, attributes and constants. And we only
- # need them for the non-chrome ones if we have no chromeonly things.
- # Otherwise (we have chromeonly attributes) we need Xrays for the chrome
- # methods/attributes/constants. Finally, in workers there are no Xrays.
- return ((self.name is "Methods" or self.name is "Attributes" or
- self.name is "Constants") and
- chrome == self.hasChromeOnly() and
- not self.descriptor.workers)
-
- def __str__(self):
- # We only need to generate id arrays for things that will end
- # up used via ResolveProperty or EnumerateProperties.
- str = self.generateArray(self.regular, self.variableName(False),
- self.usedForXrays(False))
- if self.hasChromeOnly():
- str += self.generateArray(self.chrome, self.variableName(True),
- self.usedForXrays(True))
- return str
-
- @staticmethod
- def getControllingPref(interfaceMember):
- prefName = interfaceMember.getExtendedAttribute("Pref")
- if prefName is None:
- return None
- # It's a list of strings
- assert(len(prefName) is 1)
- assert(prefName[0] is not None)
- return prefName[0]
-
- def generatePrefableArray(self, array, name, specTemplate, specTerminator,
- specType, getPref, getDataTuple, doIdArrays):
- """
- 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 every time
- our controlling pref changes and at the end of the array)
-
- specType is the actual typename of our spec
-
- getPref is a callback function that takes an array entry and returns
- the corresponding pref value.
-
- getDataTuple is a callback function that takes an array entry and
- returns a tuple suitable for substitution into specTemplate.
- """
-
- # We want to generate a single list of specs, but with specTerminator
- # inserted at every point where the pref name controlling the member
- # changes. That will make sure the order of the properties as exposed
- # on the interface and interface prototype objects does not change when
- # pref control is added to members while still allowing us to define all
- # the members in the smallest number of JSAPI calls.
- assert(len(array) is not 0)
- lastPref = getPref(array[0]) # So we won't put a specTerminator
- # at the very front of the list.
- specs = []
- prefableSpecs = []
- if doIdArrays:
- prefableIds = []
-
- prefableTemplate = ' { true, &%s[%d] }'
- prefCacheTemplate = '&%s[%d].enabled'
- def switchToPref(props, pref):
- # Remember the info about where our pref-controlled
- # booleans live.
- if pref is not None:
- props.prefCacheData.append(
- (pref, prefCacheTemplate % (name, len(prefableSpecs)))
- )
- # Set up pointers to the new sets of specs and ids
- # inside prefableSpecs and prefableIds
- prefableSpecs.append(prefableTemplate %
- (name + "_specs", len(specs)))
-
- switchToPref(self, lastPref)
-
- for member in array:
- curPref = getPref(member)
- if lastPref != curPref:
- # Terminate previous list
- specs.append(specTerminator)
- # And switch to our new pref
- switchToPref(self, curPref)
- lastPref = curPref
- # And the actual spec
- specs.append(specTemplate % getDataTuple(member))
- specs.append(specTerminator)
- prefableSpecs.append(" { false, NULL }");
-
- arrays = (("static %s: [%s, ..%i] = [\n" +
- ',\n'.join(specs) + "\n" +
- "];\n\n") % (name, specType, len(specs)))
- #+
- #"static Prefable<%s> %s[] = [\n" +
- #',\n'.join(prefableSpecs) + "\n" +
- #"];\n\n")
- if doIdArrays:
- arrays += ("static %s_ids: [jsid, ..%i] = [" % (name, len(specs))) + ", ".join(["JSID_VOID"] * len(specs)) + "];\n\n"
- return arrays
-
-# 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.chrome = [{"name": m.identifier.name,
- "length": methodLength(m),
- "flags": "JSPROP_ENUMERATE",
- "pref": PropertyDefiner.getControllingPref(m) }
- for m in methods]
- self.regular = [{"name": m.identifier.name,
- "length": methodLength(m),
- "flags": "JSPROP_ENUMERATE",
- "pref": PropertyDefiner.getControllingPref(m) }
- for m in methods if not isChromeOnly(m)]
-
- # FIXME Check for an existing iterator on the interface first.
- if any(m.isGetter() and m.isIndexed() for m in methods):
- self.chrome.append({"name": 'iterator',
- "methodInfo": False,
- "nativeName": "crust::JS_ArrayIterator",
- "length": 0,
- "flags": "JSPROP_ENUMERATE",
- "pref": None })
- self.regular.append({"name": 'iterator',
- "methodInfo": False,
- "nativeName": "crust::JS_ArrayIterator",
- "length": 0,
- "flags": "JSPROP_ENUMERATE",
- "pref": None })
-
- #if not descriptor.interface.parent and not static and not descriptor.workers:
- # self.chrome.append({"name": 'QueryInterface',
- # "methodInfo": False,
- # "length": 1,
- # "flags": "0",
- # "pref": None })
-
- if static:
- if not descriptor.interface.hasInterfaceObject():
- # static methods go on the interface object
- assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
- else:
- if not descriptor.interface.hasInterfacePrototypeObject():
- # non-static methods go on the interface prototype object
- assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
-
- def generateArray(self, array, name, doIdArrays):
- if len(array) == 0:
- return ""
-
- def pref(m):
- return m["pref"]
-
- def specData(m):
- if m.get("methodInfo", True):
- jitinfo = ("&%s_methodinfo" % m["name"])
- accessor = "genericMethod"
- else:
- jitinfo = "0 as *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 *u8 as *libc::c_char, call: JSNativeWrapper {op: %s, info: %s}, nargs: %s, flags: %s as u16, selfHostedName: 0 as *libc::c_char }',
- ' JSFunctionSpec {name: 0 as *libc::c_char, call: JSNativeWrapper {op: 0 as *u8, info: 0 as *JSJitInfo}, nargs: 0, flags: 0, selfHostedName: 0 as *libc::c_char }',
- 'JSFunctionSpec',
- pref, specData, doIdArrays)
-
-class AttrDefiner(PropertyDefiner):
- def __init__(self, descriptor, name):
- PropertyDefiner.__init__(self, descriptor, name)
- self.name = name
- self.chrome = [m for m in descriptor.interface.members if m.isAttr()]
- self.regular = [m for m in self.chrome if not isChromeOnly(m)]
-
- def generateArray(self, array, name, doIdArrays):
- if len(array) == 0:
- return ""
-
- def flags(attr):
- return "JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_NATIVE_ACCESSORS"
-
- def getter(attr):
- native = ("genericLenientGetter" if attr.hasLenientThis()
- else "genericGetter")
- return ("JSPropertyOpWrapper {op: %(native)s, info: &%(name)s_getterinfo as *JSJitInfo}"
- % {"name" : attr.identifier.name,
- "native" : native})
-
- def setter(attr):
- if attr.readonly:
- return "JSStrictPropertyOpWrapper {op: 0 as *u8, info: 0 as *JSJitInfo}"
- native = ("genericLenientSetter" if attr.hasLenientThis()
- else "genericSetter")
- return ("JSStrictPropertyOpWrapper {op: %(native)s, info: &%(name)s_setterinfo as *JSJitInfo}"
- % {"name" : attr.identifier.name,
- "native" : native})
-
- 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 *u8 as *libc::c_char, tinyid: 0, flags: ((%s) & 0xFF) as u8, getter: %s, setter: %s }',
- ' JSPropertySpec { name: 0 as *libc::c_char, tinyid: 0, flags: 0, getter: JSPropertyOpWrapper {op: 0 as *u8, info: 0 as *JSJitInfo}, setter: JSStrictPropertyOpWrapper {op: 0 as *u8, info: 0 as *JSJitInfo} }',
- 'JSPropertySpec',
- PropertyDefiner.getControllingPref, specData, doIdArrays)
-
-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.chrome = [m for m in descriptor.interface.members if m.isConst()]
- self.regular = [m for m in self.chrome if not isChromeOnly(m)]
-
- def generateArray(self, array, name, doIdArrays):
- 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: [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,
- ' ConstantSpec { name: &%s_name as *u8 as *libc::c_char, value: %s }',
- ' ConstantSpec { name: 0 as *libc::c_char, value: VoidVal }',
- 'ConstantSpec',
- PropertyDefiner.getControllingPref, specData, doIdArrays)
-
-class CGNativePropertyHooks(CGThing):
- """
- Generate a NativePropertyHooks for a given descriptor
- """
- def __init__(self, descriptor):
- CGThing.__init__(self)
- self.descriptor = descriptor
- def declare(self):
- if self.descriptor.workers:
- return ""
- #return "extern const NativePropertyHooks NativeHooks;\n"
- return ""
- def define(self):
- if self.descriptor.workers:
- return ""
- if self.descriptor.concrete and self.descriptor.proxy:
- resolveOwnProperty = "ResolveOwnProperty"
- enumerateOwnProperties = "EnumerateOwnProperties"
- else:
- enumerateOwnProperties = resolveOwnProperty = "0 as *u8"
- parent = self.descriptor.interface.parent
- parentHooks = ("&" + toBindingNamespace(parent.identifier.name) + "::NativeHooks"
- if parent else '0 as *NativePropertyHooks')
- return """
-static NativeHooks: NativePropertyHooks = NativePropertyHooks { resolve_own_property: /*%s*/ 0 as *u8, resolve_property: ResolveProperty, enumerate_own_properties: /*%s*/ 0 as *u8, enumerate_properties: /*EnumerateProperties*/ 0 as *u8, proto_hooks: %s };
-""" % (resolveOwnProperty, enumerateOwnProperties, parentHooks)
-
-# 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, declareOnly=False):
- CGThing.__init__(self)
- self.child = child
- self.indent = " " * indentLevel
- self.declareOnly = declareOnly
- def declare(self):
- decl = self.child.declare()
- if decl is not "":
- return re.sub(lineStartDetector, self.indent, decl)
- else:
- return ""
- def define(self):
- defn = self.child.define()
- if defn is not "" and not self.declareOnly:
- 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="", declarePre=None,
- declarePost=None, definePre=None, definePost=None,
- declareOnly=False, defineOnly=False, reindent=False):
- CGThing.__init__(self)
- self.child = child
- self.declarePre = declarePre or pre
- self.declarePost = declarePost or post
- self.definePre = definePre or pre
- self.definePost = definePost or post
- self.declareOnly = declareOnly
- self.defineOnly = defineOnly
- self.reindent = reindent
- def declare(self):
- if self.defineOnly:
- return ''
- decl = self.child.declare()
- if self.reindent:
- # We don't use lineStartDetector because we don't want to
- # insert whitespace at the beginning of our _first_ line.
- decl = stripTrailingWhitespace(
- decl.replace("\n", "\n" + (" " * len(self.declarePre))))
- return self.declarePre + decl + self.declarePost
- def define(self):
- if self.declareOnly:
- return ''
- 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.definePre))))
- return self.definePre + defn + self.definePost
-
-class CGImports(CGWrapper):
- """
- Generates the appropriate import/use statements.
- """
- def __init__(self, descriptors, dictionaries, declareImports, defineImports, child):
- """
- Builds a set of imports to cover |descriptors|.
-
- Also includes the files in |declareIncludes| in the header
- file and the files in |defineIncludes| in the .cpp.
- """
-
- # TODO imports to cover descriptors, etc.
-
- def _useString(imports):
- return '#[allow(unused_imports,unused_variable,unused_unsafe,unused_mut)];' + ''.join(['use %s;\n' % i for i in imports]) + '\n'
- CGWrapper.__init__(self, child,
- declarePre=_useString(sorted(declareImports)))
-
-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 CGNamespace(CGWrapper):
- def __init__(self, namespace, child, declareOnly=False, public=False):
- pre = "%smod %s {\n" % ("pub " if public else "", namespace)
- post = "} // mod %s\n" % namespace
- CGWrapper.__init__(self, child, pre=pre, post=post,
- declareOnly=declareOnly)
- @staticmethod
- def build(namespaces, child, declareOnly=False, public=False):
- """
- Static helper method to build multiple wrapped namespaces.
- """
- if not namespaces:
- return CGWrapper(child, declareOnly=declareOnly)
- inner = CGNamespace.build(namespaces[1:], child, declareOnly=declareOnly, public=public)
- return CGNamespace(namespaces[0], inner, declareOnly=declareOnly, public=public)
-
- def declare(self):
- return ""
-
-def DOMClass(descriptor):
- protoList = ['prototypes::id::' + proto for proto in descriptor.prototypeChain]
- # Pad out the list to the right length with _ID_Count so we
- # guarantee that all the lists are the same length. _ID_Count
- # is never the ID of any prototype, so it's safe to use as
- # padding.
- protoList.extend(['prototypes::id::_ID_Count'] * (descriptor.config.maxProtoChainLength - len(protoList)))
- prototypeChainString = ', '.join(protoList)
- nativeHooks = "0 as *NativePropertyHooks" if descriptor.workers else "&NativeHooks as *NativePropertyHooks"
- return """DOMClass {
- interface_chain: [ %s ] ,
- unused: %s, native_hooks: %s
-}""" % (prototypeChainString, "false", #toStringBool(descriptor.nativeIsISupports),
- nativeHooks)
-
-class CGDOMJSClass(CGThing):
- """
- Generate a DOMJSClass for a given descriptor
- """
- def __init__(self, descriptor):
- CGThing.__init__(self)
- self.descriptor = descriptor
- def declare(self):
- #return "extern DOMJSClass Class;\n"
- return ""
- def define(self):
- traceHook = TRACE_HOOK_NAME if self.descriptor.customTrace else '0 as *u8'
- return """
-static Class_name: [u8, ..%i] = %s;
-static Class: DOMJSClass = DOMJSClass {
- base: JSClass { name: &Class_name as *u8 as *libc::c_char,
- flags: JSCLASS_IS_DOMJSCLASS | ((1 & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT), //JSCLASS_HAS_RESERVED_SLOTS(1),
- addProperty: %s, /* addProperty */
- delProperty: crust::JS_PropertyStub, /* delProperty */
- getProperty: crust::JS_PropertyStub, /* getProperty */
- setProperty: crust::JS_StrictPropertyStub, /* setProperty */
- enumerate: crust::JS_EnumerateStub,
- resolve: crust::JS_ResolveStub,
- convert: crust::JS_ConvertStub,
- finalize: %s, /* finalize */
- checkAccess: 0 as *u8, /* checkAccess */
- call: 0 as *u8, /* call */
- hasInstance: 0 as *u8, /* hasInstance */
- construct: 0 as *u8, /* construct */
- trace: %s, /* trace */
- reserved: (0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, // 05
- 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, // 10
- 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, // 15
- 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, // 20
- 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, // 25
- 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, // 30
- 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, // 35
- 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void) // 40
- },
- dom_class: %s
-};
-""" % (len(self.descriptor.interface.identifier.name) + 1,
- str_to_const_array(self.descriptor.interface.identifier.name),
- #ADDPROPERTY_HOOK_NAME if self.descriptor.concrete and not self.descriptor.workers and self.descriptor.wrapperCache else 'crust::JS_PropertyStub',
- 'crust::JS_PropertyStub',
- FINALIZE_HOOK_NAME, traceHook,
- 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 declare(self):
- # We're purely for internal consumption
- return ""
- def define(self):
- return """
-static PrototypeClassName__: [u8, ..%s] = %s;
-static PrototypeClass: JSClass = JSClass {
- name: &PrototypeClassName__ as *u8 as *libc::c_char,
- flags: (1 & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT, //JSCLASS_HAS_RESERVED_SLOTS(1)
- addProperty: crust::JS_PropertyStub, /* addProperty */
- delProperty: crust::JS_PropertyStub, /* delProperty */
- getProperty: crust::JS_PropertyStub, /* getProperty */
- setProperty: crust::JS_StrictPropertyStub, /* setProperty */
- enumerate: crust::JS_EnumerateStub,
- resolve: crust::JS_ResolveStub,
- convert: crust::JS_ConvertStub,
- finalize: 0 as *u8, /* finalize */
- checkAccess: 0 as *u8, /* checkAccess */
- call: 0 as *u8, /* call */
- hasInstance: 0 as *u8, /* hasInstance */
- construct: 0 as *u8, /* construct */
- trace: 0 as *u8, /* trace */
- reserved: (0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, // 05
- 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, // 10
- 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, // 15
- 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, // 20
- 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, // 25
- 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, // 30
- 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, // 35
- 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *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 declare(self):
- # We're purely for internal consumption
- return ""
- def define(self):
- if not self.descriptor.hasInstanceInterface:
- return ""
- ctorname = "0 as *u8" if not self.descriptor.interface.ctor() else CONSTRUCT_HOOK_NAME
- hasinstance = HASINSTANCE_HOOK_NAME
- return """
-static InterfaceObjectClass: JSClass = {
- %s, 0,
- crust::JS_PropertyStub, /* addProperty */
- crust::JS_PropertyStub, /* delProperty */
- crust::JS_PropertyStub, /* getProperty */
- crust::JS_StrictPropertyStub, /* setProperty */
- crust::JS_EnumerateStub,
- crust::JS_ResolveStub,
- crust::JS_ConvertStub,
- 0 as *u8, /* finalize */
- 0 as *u8, /* checkAccess */
- %s, /* call */
- %s, /* hasInstance */
- %s, /* construct */
- 0 as *u8, /* trace */
- 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 declare(self):
- return self.join(child.declare() for child in self.children if child is not None)
- def define(self):
- return self.join(child.define() for child in self.children if child is not None)
-
-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, define="", declare=""):
- self.declareText = declare
- self.defineText = define
- def declare(self):
- return self.declareText
- def define(self):
- return self.defineText
-
-class Argument():
- """
- A class for outputting the type and name of an argument
- """
- def __init__(self, argType, name):
- self.argType = argType
- self.name = name
- def __str__(self):
- return self.name + ': ' + self.argType
-
-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.
-
- static should be True to generate a static method, which only has
- a definition.
-
- 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, static=False, extern=False, pub=False, templateArgs=None):
- CGThing.__init__(self)
- self.descriptor = descriptor
- self.name = name
- self.returnType = returnType
- self.args = args
- self.inline = inline
- self.alwaysInline = alwaysInline
- self.static = static
- self.extern = extern
- self.templateArgs = templateArgs
- self.pub = pub;
- def _argstring(self):
- return ', '.join([str(a) 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)]')
- elif self.inline:
- #decorators.append('inline')
- pass
- if self.extern:
- decorators.append('extern')
- if self.static:
- #decorators.append('static')
- pass
- if self.pub:
- decorators.append('pub')
- if not decorators:
- return ''
- #maybeNewline = " " if self.inline else "\n"
- maybeNewline = " "
- return ' '.join(decorators) + maybeNewline
- def _returnType(self):
- return (" -> %s" % self.returnType) if self.returnType != "void" else ""
- def declare(self):
- if self.inline:
- return self._define()
- #return "%sfn %s%s(%s)%s;\n" % (self._decorators(), self.name, self._template(),
- # self._argstring(), self._returnType())
- return ""
-
- def _define(self):
- return self.definition_prologue() + "\n" + self.definition_body() + self.definition_epilogue()
- def define(self):
- return "" if self.inline else self._define()
- def definition_prologue(self):
- return "%sfn %s%s(%s)%s {\n unsafe {" % (self._decorators(), self.name, self._template(),
- self._argstring(), self._returnType())
- def definition_epilogue(self):
- return "\n }\n}\n"
- def definition_body(self):
- assert(False) # Override me!
-
-def CreateBindingJSObject(descriptor, parent):
- if descriptor.proxy:
- handler = """ //let cache = ptr::to_unsafe_ptr(aObject.get_wrappercache());
-
- let script_context = task_from_context(aCx);
- let handler = (*script_context).dom_static.proxy_handlers.get(&(prototypes::id::%s as uint));
-""" % descriptor.name
- create = handler + """ let obj = NewProxyObject(aCx, *handler,
- ptr::to_unsafe_ptr(&RUST_PRIVATE_TO_JSVAL(squirrel_away(aObject) as *libc::c_void)),
- proto, %s,
- ptr::null(), ptr::null());
- if obj.is_null() {
- return ptr::null();
- }
-
-"""
- else:
- create = """ let obj = JS_NewObject(aCx, &Class.base, proto, %s);
- if obj.is_null() {
- return ptr::null();
- }
-
- JS_SetReservedSlot(obj, DOM_OBJECT_SLOT as u32,
- RUST_PRIVATE_TO_JSVAL(squirrel_away(aObject) as *libc::c_void));
-"""
- return create % parent
-
-class CGWrapWithCacheMethod(CGAbstractMethod):
- def __init__(self, descriptor):
- assert descriptor.interface.hasInterfacePrototypeObject()
- args = [Argument('*JSContext', 'aCx'), Argument('*JSObject', 'aScope'),
- Argument('@mut ' + descriptor.nativeType, 'aObject'),
- Argument('*mut bool', 'aTriedToWrap')]
- CGAbstractMethod.__init__(self, descriptor, 'Wrap_', '*JSObject', args)
-
- def definition_body(self):
- if self.descriptor.workers:
- return """ *aTriedToWrap = true;
- return aObject->GetJSObject();"""
-
- return """ *aTriedToWrap = true;
- let mut parent = aObject.GetParentObject(aCx);
- let parent = WrapNativeParent(aCx, aScope, parent);
- if parent.is_null() {
- return ptr::null();
- }
-
- //JSAutoCompartment ac(aCx, parent);
- let global = JS_GetGlobalForObject(aCx, parent);
- let proto = GetProtoObject(aCx, global, global);
- if proto.is_null() {
- return ptr::null();
- }
-
- let cache = ptr::to_mut_unsafe_ptr(aObject.get_wrappercache());
-%s
-
- //NS_ADDREF(aObject);
-
- (*cache).set_wrapper(obj);
-
- return obj;""" % (CreateBindingJSObject(self.descriptor, "parent"))
-
-class CGWrapMethod(CGAbstractMethod):
- def __init__(self, descriptor):
- # XXX can we wrap if we don't have an interface prototype object?
- assert descriptor.interface.hasInterfacePrototypeObject()
- args = [Argument('*JSContext', 'aCx'), Argument('*JSObject', 'aScope'),
- Argument(descriptor.pointerType + descriptor.nativeType, 'aObject'), Argument('*mut bool', 'aTriedToWrap')]
- CGAbstractMethod.__init__(self, descriptor, 'Wrap', '*JSObject', args, inline=True, pub=True)
-
- def definition_body(self):
- return "return Wrap_(aCx, aScope, aObject, aTriedToWrap);"
-
-class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
- def __init__(self, descriptor):
- # XXX can we wrap if we don't have an interface prototype object?
- assert descriptor.interface.hasInterfacePrototypeObject()
- args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aScope'),
- Argument('@' + descriptor.nativeType, 'aObject')]
- CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
-
- def definition_body(self):
- return """
- JSObject* global = JS_GetGlobalForObject(aCx, aScope);
- JSObject* proto = GetProtoObject(aCx, global, global);
- if (!proto) {
- return NULL;
- }
-
-%s
- NS_ADDREF(aObject);
-
- return obj;""" % CreateBindingJSObject(self.descriptor, "global")
-
-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)
- def declare(self):
- # We only have implementation
- return ""
-
-class PropertyArrays():
- def __init__(self, descriptor):
- self.staticMethods = MethodDefiner(descriptor, "StaticMethods", True)
- self.methods = MethodDefiner(descriptor, "Methods", False)
- self.attrs = AttrDefiner(descriptor, "Attributes")
- self.consts = ConstDefiner(descriptor, "Constants")
- pass
-
- @staticmethod
- def arrayNames():
- return [ "staticMethods", "methods", "attrs", "consts" ]
-
- @staticmethod
- def xrayRelevantArrayNames():
- return [ "methods", "attrs", "consts" ]
-
- def hasChromeOnly(self):
- return reduce(lambda b, a: b or getattr(self, a).hasChromeOnly(),
- self.arrayNames(), False)
- def variableNames(self, chrome):
- names = {}
- for array in self.arrayNames():
- names[array] = getattr(self, array).variableName(chrome)
- return names
- def __str__(self):
- define = ""
- for array in self.arrayNames():
- define += str(getattr(self, array))
- return define
-
-class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
- """
- Generate the CreateInterfaceObjects method for an interface descriptor.
-
- properties should be a PropertyArrays instance.
- """
- def __init__(self, descriptor, properties):
- args = [Argument('*JSContext', 'aCx'), Argument('*JSObject', 'aGlobal'),
- Argument('*JSObject', 'aReceiver')]
- CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', '*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))
-
- needInterfaceObject = self.descriptor.interface.hasInterfaceObject()
- needInterfacePrototypeObject = self.descriptor.interface.hasInterfacePrototypeObject()
-
- # if we don't need to create anything, why are we generating this?
- assert needInterfaceObject or needInterfacePrototypeObject
-
- idsToInit = []
- # There is no need to init any IDs in workers, because worker bindings
- # don't have Xrays.
- if False and not self.descriptor.workers: #XXXjdm don't need xray stuff yet
- for var in self.properties.xrayRelevantArrayNames():
- props = getattr(self.properties, var)
- # We only have non-chrome ids to init if we have no chrome ids.
- if props.hasChromeOnly():
- idsToInit.append(props.variableName(True))
- elif props.hasNonChromeOnly():
- idsToInit.append(props.variableName(False))
- if len(idsToInit) > 0:
- setup = CGList([CGGeneric("let script_context = task_from_context(aCx);"),
- CGList([CGGeneric("let %s_ids_mut = (*script_context).dom_static.attribute_ids.get(&(prototypes::id::%s as uint));" % (varname, self.descriptor.name)) for varname in idsToInit], '\n')], '\n')
- initIds = CGList(
- [CGGeneric("!InitIds(aCx, %s, *%s_ids_mut)" % (varname, varname)) for
- varname in idsToInit], ' ||\n')
- if len(idsToInit) > 1:
- initIds = CGWrapper(initIds, pre="(", post=")", reindent=True)
- initIds = CGList(
- [CGGeneric("%s_ids_mut[0] == JSID_VOID &&" % idsToInit[0]), initIds],
- "\n")
- initIds = CGWrapper(initIds, pre="if ", post=" {", reindent=True)
- initIds = CGList(
- [setup,
- initIds,
- CGGeneric((" %s_ids_mut[0] = JSID_VOID;\n"
- " return ptr::null();") % idsToInit[0]),
- CGGeneric("}")],
- "\n")
- else:
- initIds = None
-
- prefCacheData = []
- for var in self.properties.arrayNames():
- props = getattr(self.properties, var)
- prefCacheData.extend(props.prefCacheData)
- if len(prefCacheData) is not 0:
- prefCacheData = [
- CGGeneric('Preferences::AddBoolVarCache(%s, "%s");' % (ptr, pref)) for
- (pref, ptr) in prefCacheData]
- prefCache = CGWrapper(CGIndenter(CGList(prefCacheData, "\n")),
- pre=("static bool sPrefCachesInited = false;\n"
- "if (!sPrefCachesInited) {\n"
- " sPrefCachesInited = true;\n"),
- post="\n}")
- else:
- prefCache = None
-
- getParentProto = ("let parentProto: *JSObject = %s;\n" +
- "if parentProto.is_null() {\n" +
- " return ptr::null();\n" +
- "}\n") % getParentProto
-
- needInterfaceObjectClass = (needInterfaceObject and
- self.descriptor.hasInstanceInterface)
- needConstructor = (needInterfaceObject and
- not self.descriptor.hasInstanceInterface)
- if self.descriptor.interface.ctor():
- constructHook = CONSTRUCT_HOOK_NAME
- constructArgs = methodLength(self.descriptor.interface.ctor())
- else:
- constructHook = "ThrowingConstructor"
- constructArgs = 0
-
- if self.descriptor.concrete:
- if self.descriptor.proxy:
- domClass = "&Class"
- else:
- domClass = "&Class.dom_class"
- else:
- domClass = "ptr::null()"
-
- def arrayPtr(name):
- val = ('%(' + name + ')s') % self.properties.variableNames(False)
- if val == "ptr::null()":
- return val
- return "ptr::to_unsafe_ptr(&%s[0])" % val
-
- call = """return CreateInterfaceObjects2(aCx, aGlobal, aReceiver, parentProto,
- %s, %s, %s, %d,
- %s,
- %s,
- %s,
- %s,
- %s,
- %s);""" % (
- "&PrototypeClass" if needInterfacePrototypeObject else "ptr::null()",
- "&InterfaceObjectClass" if needInterfaceObjectClass else "ptr::null()",
- constructHook if needConstructor else "ptr::null()",
- constructArgs,
- domClass,
- arrayPtr("methods"), arrayPtr("attrs"),
- arrayPtr("consts"), arrayPtr("staticMethods"),
- '"' + self.descriptor.interface.identifier.name + '"' if needInterfaceObject else "ptr::null()")
- if self.properties.hasChromeOnly():
- if self.descriptor.workers:
- accessCheck = "mozilla::dom::workers::GetWorkerPrivateFromContext(aCx)->IsChromeWorker()"
- else:
- accessCheck = "xpc::AccessCheck::isChrome(js::GetObjectCompartment(aGlobal))"
- chrome = CGIfWrapper(CGGeneric(call % self.properties.variableNames(True)),
- accessCheck)
- chrome = CGWrapper(chrome, pre="\n\n")
- else:
- chrome = None
-
- functionBody = CGList(
- [CGGeneric(getParentProto), initIds, prefCache, chrome,
- CGGeneric(call % self.properties.variableNames(False))],
- "\n\n")
- #return CGIndenter(CGWrapper(functionBody, pre="/*", post="*/return ptr::null()")).define()
- return CGIndenter(functionBody).define()
-
-class CGGetPerInterfaceObject(CGAbstractMethod):
- """
- A method for getting a per-interface object (a prototype object or interface
- constructor object).
- """
- def __init__(self, descriptor, name, idPrefix=""):
- args = [Argument('*JSContext', 'aCx'), Argument('*JSObject', 'aGlobal'),
- Argument('*JSObject', 'aReceiver')]
- CGAbstractMethod.__init__(self, descriptor, name,
- '*JSObject', args, inline=True)
- self.id = idPrefix + "id::" + self.descriptor.name
- def definition_body(self):
- return """
-
- /* 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.
- */
-
- /* Make sure our global is sane. Hopefully we can remove this sometime */
- /*if ((*JS_GetClass(aGlobal)).flags & JSCLASS_DOM_GLOBAL) == 0 {
- return ptr::null();
- }*/
- /* Check to see whether the interface objects are already installed */
- let protoOrIfaceArray: *mut *JSObject = cast::transmute(GetProtoOrIfaceArray(aGlobal));
- let cachedObject: *JSObject = *protoOrIfaceArray.offset(%s as uint);
- if cachedObject.is_null() {
- let tmp: *JSObject = CreateInterfaceObjects(aCx, aGlobal, aReceiver);
- *protoOrIfaceArray.offset(%s as uint) = 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",
- "prototypes::")
- def definition_body(self):
- return """
- /* 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 """
- /* Get the interface object for this class. This will create the object as
- needed. */""" + CGGetPerInterfaceObject.definition_body(self)
-
-class CGDefineDOMInterfaceMethod(CGAbstractMethod):
- """
- A method for resolve hooks to try to lazily define the interface object for
- a given interface.
- """
- def __init__(self, descriptor):
- args = [Argument('*JSContext', 'aCx'), Argument('*JSObject', 'aReceiver'),
- Argument('*mut bool', 'aEnabled')]
- CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', 'bool', args, pub=True)
-
- def declare(self):
- if self.descriptor.workers:
- return ''
- #return CGAbstractMethod.declare(self)
- return ""
-
- def define(self):
- if self.descriptor.workers:
- return ''
- return CGAbstractMethod.define(self)
-
- def definition_body(self):
- if self.descriptor.interface.hasInterfacePrototypeObject():
- # We depend on GetProtoObject defining an interface constructor
- # object as needed.
- getter = "GetProtoObject"
- else:
- getter = "GetConstructorObject"
-
- body = " let script_context = task_from_context(aCx);\n"
- #XXXjdm This self.descriptor.concrete check shouldn't be necessary
- if not self.descriptor.concrete or self.descriptor.proxy:
- body += """ let traps = ProxyTraps {
- getPropertyDescriptor: getPropertyDescriptor,
- getOwnPropertyDescriptor: getOwnPropertyDescriptor,
- defineProperty: ptr::null(),
- getOwnPropertyNames: ptr::null(),
- delete_: ptr::null(),
- enumerate: ptr::null(),
-
- has: ptr::null(),
- hasOwn: ptr::null(),
- get: get,
- set: ptr::null(),
- keys: ptr::null(),
- iterate: ptr::null(),
-
- call: ptr::null(),
- construct: ptr::null(),
- nativeCall: ptr::null(),
- hasInstance: ptr::null(),
- typeOf: ptr::null(),
- objectClassIs: ptr::null(),
- obj_toString: obj_toString,
- fun_toString: ptr::null(),
- //regexp_toShared: ptr::null(),
- defaultValue: ptr::null(),
- iteratorNext: ptr::null(),
- finalize: ptr::null(),
- getElementIfPresent: ptr::null(),
- getPrototypeOf: ptr::null()
- };
- (*script_context).dom_static.proxy_handlers.insert(prototypes::id::%s as uint,
- CreateProxyHandler(ptr::to_unsafe_ptr(&traps)));
-
-""" % self.descriptor.name
- else:
- body += """ (*script_context).dom_static.attribute_ids.insert(prototypes::id::%s as uint,
- vec::cast_to_mut(vec::from_slice(sAttributes_ids)));
-""" % self.descriptor.name
- body = "" #XXXjdm xray stuff isn't necessary yet
-
- return (body + " let global: *JSObject = JS_GetGlobalForObject(aCx, aReceiver);\n" +
- """
- *aEnabled = true;
- return %s(aCx, global, aReceiver).is_not_null();""" % (getter))
-
-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.
-
- errorReport should be a CGThing for an error report or None if no
- error reporting is needed.
- """
- def __init__(self, errorReport, arguments, argsPre, returnType,
- extendedAttributes, descriptorProvider, nativeMethodName,
- static, object="self", declareResult=True):
- CGThing.__init__(self)
-
- assert errorReport is None or isinstance(errorReport, CGThing)
-
- isFallible = errorReport is not None
-
- #resultAlreadyAddRefed = isResultAlreadyAddRefed(descriptorProvider,
- # extendedAttributes)
- resultAlreadyAddRefed = True
- (result, resultOutParam) = getRetvalDeclarationForType(returnType,
- descriptorProvider,
- resultAlreadyAddRefed)
-
- args = CGList([CGGeneric(arg) for arg in argsPre], ", ")
- for (a, name) in arguments:
- # This is a workaround for a bug in Apple's clang.
- if a.type.isObject() and not a.type.nullable() and not a.optional:
- name = "(JSObject&)" + name
- #XXXjdm Perhaps we should pass all nontrivial types by borrowed pointer
- if a.type.isDictionary():
- name = "&" + name
- args.append(CGGeneric(name))
-
- # Return values that go in outparams go here
- if resultOutParam:
- args.append(CGGeneric("result"))
- if isFallible:
- args.append(CGGeneric("&mut rv"))
-
- needsCx = (typeNeedsCx(returnType, True) or
- any(typeNeedsCx(a.type) for (a, _) in arguments) or
- 'implicitJSContext' in extendedAttributes)
-
- 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.nativeType)
- else:
- call = CGWrapper(call, pre="(*%s)." % object)
- call = CGList([call, CGWrapper(args, pre="(", post=");")])
- if result is not None:
- if declareResult:
- result = CGWrapper(result, pre="let result: ", post=";")
- self.cgRoot.prepend(result)
- if not resultOutParam:
- call = CGWrapper(call, pre="result = ")
-
- call = CGWrapper(call)
- self.cgRoot.append(call)
-
- if isFallible:
- self.cgRoot.prepend(CGGeneric("let mut rv: ErrorResult = Ok(());"))
- self.cgRoot.append(CGGeneric("if (rv.is_err()) {"))
- self.cgRoot.append(CGIndenter(errorReport))
- self.cgRoot.append(CGGeneric("}"))
-
- 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(
- self.getErrorReport() 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, cast::transmute(vp));\n"
- def getArgc(self):
- return "argc"
- def getArguments(self):
- return [(a, "arg" + str(i)) for (i, a) in enumerate(self.arguments)]
-
- def isFallible(self):
- return not 'infallible' in self.extendedAttributes
-
- def wrap_return_value(self):
- isCreator = memberIsCreator(self.idlNode)
- if isCreator:
- # We better be returning addrefed things!
- #assert(isResultAlreadyAddRefed(self.descriptor,
- # self.extendedAttributes) or
- # Workers use raw pointers for new-object return
- # values or something
- # self.descriptor.workers)
- pass
-
- resultTemplateValues = { 'jsvalRef': '*vp', 'jsvalPtr': 'vp',
- 'isCreator': isCreator}
- try:
- return wrapForType(self.returnType, self.descriptor,
- resultTemplateValues)
- except MethodNotCreatorError, err:
- assert not isCreator
- raise TypeError("%s being returned from non-creator method or property %s.%s" %
- (err.typename,
- self.descriptor.interface.identifier.name,
- self.idlNode.identifier.name))
-
- def getErrorReport(self):
- #return CGGeneric('return ThrowMethodFailedWithDetails<%s>(cx, rv, "%s", "%s");'
- # % (toStringBool(not self.descriptor.workers),
- # self.descriptor.interface.identifier.name,
- # self.idlNode.identifier.name))
- return CGGeneric('return 0'); #XXXjdm
-
- def define(self):
- return (self.cgRoot.define() + "\n" + self.wrap_return_value())
-
-class CGGetterCall(CGPerSignatureCall):
- """
- A class to generate a native object getter call for a particular IDL
- getter.
- """
- def __init__(self, returnType, nativeMethodName, descriptor, attr):
- CGPerSignatureCall.__init__(self, returnType, [], [],
- nativeMethodName, False, 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):
- self.type = type
- self.optional = False
- self.variadic = False
- self.defaultValue = None
- self.treatNullAs = interfaceMember.treatNullAs
- self.treatUndefinedAs = interfaceMember.treatUndefinedAs
- self.enforceRange = False
- self.clamp = False
-
-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 = ("return Throw<%s>(cx, rv);" %
- toStringBool(not descriptor.workers))
- 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 = CGIndenter(CGGeneric(
- str(CastableObjectUnwrapper(
- FakeCastableDescriptor(self.descriptor),
- "obj", "self", self.unwrapFailureCode))))
- return CGList([ self.getThis(), unwrapThis,
- self.generate_code() ], "\n").define()
-
- def getThis(self):
- return CGIndenter(
- CGGeneric("let obj: *JSObject = JS_THIS_OBJECT(cx, vp);\n"
- "if obj.is_null() {\n"
- " return false as JSBool;\n"
- "}\n"
- "\n"
- "let self: *rust_box<%s>;" % self.descriptor.nativeType))
-
- 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('*JSContext', 'cx'), Argument('libc::c_uint', 'argc'),
- Argument('*JSVal', 'vp')]
- CGAbstractBindingMethod.__init__(self, descriptor, 'genericMethod', args)
-
- def generate_code(self):
- return CGIndenter(CGGeneric(
- "let _info: *JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n"
- "return CallJitMethodOp(_info, cx, obj, ptr::to_unsafe_ptr(&(*self).payload) as *libc::c_void, argc, vp);"))
-
-class CGAbstractStaticMethod(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, static=True)
- def declare(self):
- # We only have implementation
- return ""
-
-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('*JSContext', 'cx'), Argument('JSHandleObject', 'obj'),
- Argument('*mut %s' % descriptor.nativeType, 'self'),
- Argument('libc::c_uint', 'argc'), Argument('*mut JSVal', 'vp')]
- CGAbstractExternMethod.__init__(self, descriptor, name, 'JSBool', args)
-
- def definition_body(self):
- name = self.method.identifier.name
- nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name))
- return CGWrapper(CGMethodCall([], nativeName, self.method.isStatic(),
- self.descriptor, self.method),
- pre=" let obj = (*obj.unnamed);\n").define()
-
-class CGGenericGetter(CGAbstractBindingMethod):
- """
- A class for generating the C++ code for an IDL attribute getter.
- """
- def __init__(self, descriptor, lenientThis=False):
- args = [Argument('*JSContext', 'cx'), Argument('uint', 'argc'),
- Argument('*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 CGIndenter(CGGeneric(
- "let _info: *JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n"
- "return CallJitPropertyOp(_info, cx, obj, ptr::to_unsafe_ptr(&(*self).payload) as *libc::c_void, vp);"))
-
-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('*JSContext', 'cx'),
- Argument('JSHandleObject', 'obj'),
- Argument('*%s' % descriptor.nativeType, 'self'),
- Argument('*mut JSVal', 'vp') ]
- CGAbstractExternMethod.__init__(self, descriptor, name, "JSBool", args)
-
- def definition_body(self):
- name = self.attr.identifier.name
- nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name))
- # resultOutParam does not depend on whether resultAlreadyAddRefed is set
- (_, resultOutParam) = getRetvalDeclarationForType(self.attr.type,
- self.descriptor,
- False)
- infallible = ('infallible' in
- self.descriptor.getExtendedAttributes(self.attr,
- getter=True))
- if resultOutParam or self.attr.type.nullable() or not infallible:
- nativeName = "Get" + nativeName
- return CGWrapper(CGIndenter(CGGetterCall(self.attr.type, nativeName,
- self.descriptor, self.attr)),
- pre=" let obj = (*obj.unnamed);\n").define()
-
-def infallibleForMember(member, type, descriptorProvider):
- """
- Determine the fallibility of changing a C++ value of IDL type "type" into
- JS for the given attribute. Apart from isCreator, all the defaults are used,
- since the fallbility does not change based on the boolean values,
- and the template will be discarded.
-
- CURRENT ASSUMPTIONS:
- We assume that successCode for wrapping up return values cannot contain
- failure conditions.
- """
- return getWrapTemplateForType(type, descriptorProvider, 'result', None,\
- memberIsCreator(member))[1]
-
-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 declare(self):
- return ""
-
- def defineJitInfo(self, infoName, opName, infallible):
- protoID = "prototypes::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,\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)
- getterinfal = getterinfal and infallibleForMember(self.member, self.member.type, self.descriptor)
- 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 and infallibleForMember(self.member, sig[0], self.descriptor):
- # 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)
- self.enum = enum
-
- def declare(self):
- return ""
-
- def define(self):
- return """
- pub enum valuelist {
- %s
- }
-
- pub static strings: &'static [EnumEntry] = &[
- %s,
- ];
-""" % (",\n ".join(map(getEnumValueName, self.enum.values())),
- ",\n ".join(['EnumEntry {value: &"' + val + '", length: ' + str(len(val)) + '}' for val in self.enum.values()]))
-
-class CGXrayHelper(CGAbstractExternMethod):
- def __init__(self, descriptor, name, args, properties):
- CGAbstractExternMethod.__init__(self, descriptor, name, "bool", args)
- self.properties = properties
-
- def definition_body(self):
- varNames = self.properties.variableNames(True)
-
- setup = "let script_context = task_from_context(cx);\n"
-
- methods = self.properties.methods
- if methods.hasNonChromeOnly() or methods.hasChromeOnly():
- methodArgs = "Some(vec::zip_slice(%(methods)s, *method_ids))" % varNames
- setup += "let method_ids = (*script_context).dom_static.method_ids.get(&(prototypes::id::ClientRect as uint));\n"
- else:
- methodArgs = "None"
- methodArgs = CGGeneric(methodArgs)
-
- attrs = self.properties.attrs
- if attrs.hasNonChromeOnly() or attrs.hasChromeOnly():
- attrArgs = "Some(vec::zip_slice(%(attrs)s, *attr_ids))" % varNames
- setup += "let attr_ids = (*script_context).dom_static.attribute_ids.get(&(prototypes::id::ClientRect as uint));\n"
- else:
- attrArgs = "None"
- attrArgs = CGGeneric(attrArgs)
-
- consts = self.properties.consts
- if consts.hasNonChromeOnly() or consts.hasChromeOnly():
- constArgs = "Some(vec::zip_slice(%(consts)s, *const_ids))" % varNames
- setup += "let const_ids = (*script_context).dom_static.constant_ids.get(&(prototypes::id::ClientRect as uint));\n"
- else:
- constArgs = "None"
- constArgs = CGGeneric(constArgs)
-
- prefixArgs = CGGeneric(self.getPrefixArgs())
-
- return CGIndenter(
- CGWrapper(CGList([prefixArgs, methodArgs, attrArgs, constArgs], ", "),
- pre=(setup + "return Xray%s(" % self.name),
- post=");",
- reindent=True)).define()
-
-class CGResolveProperty(CGXrayHelper):
- def __init__(self, descriptor, properties):
- args = [Argument('*JSContext', 'cx'), Argument('*JSObject', 'wrapper'),
- Argument('jsid', 'id'), Argument('bool', 'set'),
- Argument('*mut JSPropertyDescriptor', 'desc')]
- CGXrayHelper.__init__(self, descriptor, "ResolveProperty", args,
- properties)
-
- def getPrefixArgs(self):
- return "cx, wrapper, id, desc"
-
-
-class CGEnumerateProperties(CGXrayHelper):
- def __init__(self, descriptor, properties):
- args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'wrapper'),
- Argument('JS::AutoIdVector&', 'props')]
- CGXrayHelper.__init__(self, descriptor, "EnumerateProperties", args,
- properties)
-
- def getPrefixArgs(self):
- return "props"
-
-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(descriptor.binaryNames.get(operation, operation))
- operation = descriptor.operations[operation]
- assert len(operation.signatures()) == 1
- signature = operation.signatures()[0]
- extendedAttributes = descriptor.getExtendedAttributes(operation)
-
- (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 = getJSToNativeConversionTemplate(argument.type, descriptor,
- treatNullAs=argument.treatNullAs,
- treatUndefinedAs=argument.treatUndefinedAs)
- templateValues = {
- "declName": argument.identifier.name,
- "holderName": argument.identifier.name + "_holder",
- "val": "desc->value",
- "valPtr": "&desc->value"
- }
- self.cgRoot.prepend(instantiateJSToNativeConversionTemplate(template, templateValues))
- elif operation.isGetter():
- self.cgRoot.prepend(CGGeneric("let mut found = false;"))
-
- def getArguments(self):
- args = [(a, a.identifier.name) 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.returnType, self.descriptor, 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 CGProxyUnwrap(CGAbstractMethod):
- def __init__(self, descriptor):
- args = [Argument('*JSObject', 'obj')]
- CGAbstractMethod.__init__(self, descriptor, "UnwrapProxy", '*' + descriptor.nativeType, args, alwaysInline=True)
- def declare(self):
- return ""
- def definition_body(self):
- return """ /*if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
- obj = js::UnwrapObject(obj);
- }*/
- //MOZ_ASSERT(IsProxy(obj));
- let box: *rust_box<%s> = cast::transmute(RUST_JSVAL_TO_PRIVATE(GetProxyPrivate(obj)));
- return ptr::to_unsafe_ptr(&(*box).payload);""" % (self.descriptor.nativeType)
-
-class CGDOMJSProxyHandler_get(CGAbstractExternMethod):
- def __init__(self, descriptor):
- args = [Argument('*JSContext', 'cx'), Argument('*JSObject', 'proxy'),
- Argument('*JSObject', 'receiver'), Argument('jsid', 'id'),
- Argument('*mut JSVal', 'vp')]
- CGAbstractExternMethod.__init__(self, descriptor, "get", "JSBool", args)
- self.descriptor = descriptor
- def getBody(self):
- getFromExpando = """let expando = GetExpandoObject(proxy);
-if expando.is_not_null() {
- let hasProp = 0;
- if JS_HasPropertyById(cx, expando, id, ptr::to_unsafe_ptr(&hasProp)) == 0 {
- return 0;
- }
-
- if hasProp != 0 {
- return JS_GetPropertyById(cx, expando, id, cast::transmute(vp));
- }
-}"""
-
- templateValues = {'jsvalRef': '*vp', 'jsvalPtr': 'vp', 'obj': 'proxy'}
-
- indexedGetter = self.descriptor.operations['IndexedGetter']
- if indexedGetter:
- getIndexedOrExpando = ("let index = GetArrayIndexFromId(cx, id);\n" +
- "if index.is_some() {\n" +
- " let index = index.get();\n" +
- " let self = UnwrapProxy(proxy);\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" +
- " JS::Value nameVal = STRING_TO_JSVAL(JSID_TO_STRING(id));\n" +
- " FakeDependentString name;\n"
- " if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" +
- " eStringify, eStringify, name)) {\n" +
- " return false;\n" +
- " }\n" +
- "\n" +
- " let self = UnwrapProxy(proxy);\n" +
- CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() +
- "}\n") % (self.descriptor.nativeType)
- 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, cast::transmute(vp)) {
- return 0;
-}
-
-if found {
- return 1;
-}
-%s
-*vp = JSVAL_VOID;
-return 1;""" % (getIndexedOrExpando, getNamed)
-
- def definition_body(self):
- return self.getBody()
-
-class CGDOMJSProxyHandler_obj_toString(CGAbstractExternMethod):
- def __init__(self, descriptor):
- args = [Argument('*JSContext', 'cx'), Argument('*JSObject', 'proxy')]
- CGAbstractExternMethod.__init__(self, descriptor, "obj_toString", "*JSString", args)
- self.descriptor = descriptor
- def getBody(self):
- stringifier = self.descriptor.operations['Stringifier']
- if stringifier:
- name = stringifier.identifier.name
- nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, 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 """ do str::as_c_str("%s") |s| {
- _obj_toString(cx, s)
- }""" % self.descriptor.name
-
- def definition_body(self):
- return 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 "" #XXXjdm we may want to do a proper unwrap here
- return """
- let self: *%s = &(unwrap::<*rust_box<%s>>(obj).payload);
-""" % (self.descriptor.nativeType, self.descriptor.nativeType)
-
- def definition_body(self):
- return self.definition_body_prologue() + self.generate_code()
-
- def generate_code(self):
- # Override me
- assert(False)
-
-def finalizeHook(descriptor, hookName, context):
- if descriptor.customFinalize:
- return """if (self) {
- self->%s(%s);
-}""" % (hookName, context)
- #clearWrapper = "ClearWrapper(self, self);\n" if descriptor.wrapperCache else ""
- if descriptor.workers:
- #release = "self->Release();"
- pass
- else:
- assert descriptor.nativeIsISupports
- release = """let val = JS_GetReservedSlot(obj, 0);
-let _: %s = cast::transmute(RUST_JSVAL_TO_PRIVATE(val));
-""" % (descriptor.pointerType + descriptor.nativeType)
- #return clearWrapper + release
- return release
-
-class CGClassConstructHook(CGAbstractExternMethod):
- """
- JS-visible constructor for our objects
- """
- def __init__(self, descriptor):
- args = [Argument('*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):
- return self.generate_code()
-
- def generate_code(self):
- preamble = """
- //JSObject* obj = JS_GetGlobalForObject(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)));
-"""
- if self.descriptor.workers:
- preArgs = ["cx", "obj"]
- else:
- preamble += """
- //XXXjdm Gecko obtains a GlobalObject from the global (maybe from the private value,
- // or through unwrapping a slot or something). We'll punt and get the Window
- // from the context for now.
- let script_context = task_from_context(cx);
- let global = (*script_context).root_frame.get_ref().window;
- let obj = global.get_wrappercache().get_wrapper();
-"""
- preArgs = ["global"]
-
- name = self._ctor.identifier.name
- nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name))
- callGenerator = CGMethodCall(preArgs, nativeName, True,
- self.descriptor, self._ctor)
- return preamble + callGenerator.define();
-
-class CGClassHasInstanceHook(CGAbstractStaticMethod):
- def __init__(self, descriptor):
- args = [Argument('*JSContext', 'cx'), Argument('JSHandleObject', 'obj'),
- Argument('JSMutableHandleValue', 'vp'), Argument('*JSBool', 'bp')]
- CGAbstractStaticMethod.__init__(self, descriptor, HASINSTANCE_HOOK_NAME,
- 'JSBool', args)
-
- def define(self):
- if not self.descriptor.hasInstanceInterface:
- return ""
- return CGAbstractStaticMethod.define(self)
-
- def definition_body(self):
- return self.generate_code()
-
- def generate_code(self):
- return """ if (!vp.isObject()) {
- *bp = false;
- return true;
- }
-
- jsval protov;
- if (!JS_GetProperty(cx, obj, "prototype", &protov))
- return false;
- if (!protov.isObject()) {
- JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PROTOTYPE,
- "%s");
- return false;
- }
- JSObject *objProto = &protov.toObject();
-
- JSObject* instance = &vp.toObject();
- JSObject* proto;
- if (!JS_GetPrototype(cx, instance, &proto))
- return false;
- while (proto) {
- if (proto == objProto) {
- *bp = true;
- return true;
- }
- if (!JS_GetPrototype(cx, proto, &proto))
- return false;
- }
-
- nsISupports* native =
- nsContentUtils::XPConnect()->GetNativeOfWrapper(cx, instance);
- nsCOMPtr<%s> qiResult = do_QueryInterface(native);
- *bp = !!qiResult;
- return true;
-""" % (self.descriptor.name, self.descriptor.hasInstanceInterface)
-
-class CGClassFinalizeHook(CGAbstractClassHook):
- """
- A hook for finalize, used to release our native object.
- """
- def __init__(self, descriptor):
- args = [Argument('*JSFreeOp', 'fop'), Argument('*JSObject', 'obj')]
- CGAbstractClassHook.__init__(self, descriptor, FINALIZE_HOOK_NAME,
- 'void', args)
-
- def generate_code(self):
- return CGIndenter(CGGeneric(finalizeHook(self.descriptor, self.name, self.args[0].name))).define()
-
-class CGDOMJSProxyHandlerDOMClass(CGThing):
- def __init__(self, descriptor):
- CGThing.__init__(self)
- self.descriptor = descriptor
- def declare(self):
- #return "extern const DOMClass Class;\n"
- return ""
- def define(self):
- return """
-static Class: DOMClass = """ + DOMClass(self.descriptor) + """;
-
-"""
-
-class CGDescriptor(CGThing):
- def __init__(self, descriptor):
- CGThing.__init__(self)
-
- assert not descriptor.concrete or descriptor.interface.hasInterfacePrototypeObject()
-
- cgThings = []
- if descriptor.interface.hasInterfacePrototypeObject():
- (hasMethod, hasGetter, hasLenientGetter,
- hasSetter, hasLenientSetter) = False, False, False, False, False
- for m in descriptor.interface.members:
- if m.isMethod() and not m.isStatic() and not m.isIdentifierLess():
- cgThings.append(CGSpecializedMethod(descriptor, m))
- cgThings.append(CGMemberJITInfo(descriptor, m))
- hasMethod = True
- elif m.isAttr():
- cgThings.append(CGSpecializedGetter(descriptor, m))
- if m.hasLenientThis():
- hasLenientGetter = True
- else:
- hasGetter = True
- if not m.readonly:
- #cgThings.append(CGSpecializedSetter(descriptor, m))
- if m.hasLenientThis():
- hasLenientSetter = True
- else:
- hasSetter = True
- cgThings.append(CGMemberJITInfo(descriptor, m))
- if hasMethod: cgThings.append(CGGenericMethod(descriptor))
- if hasGetter: cgThings.append(CGGenericGetter(descriptor))
- #if hasLenientGetter: cgThings.append(CGGenericGetter(descriptor,
- # lenientThis=True))
- #if hasSetter: cgThings.append(CGGenericSetter(descriptor))
- #if hasLenientSetter: cgThings.append(CGGenericSetter(descriptor,
- # lenientThis=True))
-
- if descriptor.concrete and not descriptor.proxy:
- if not descriptor.workers and descriptor.wrapperCache:
- #cgThings.append(CGAddPropertyHook(descriptor))
- pass
-
- # Always have a finalize hook, regardless of whether the class wants a
- # custom hook.
- cgThings.append(CGClassFinalizeHook(descriptor))
-
- # Only generate a trace hook if the class wants a custom hook.
- if (descriptor.customTrace):
- #cgThings.append(CGClassTraceHook(descriptor))
- pass
-
- if descriptor.interface.hasInterfaceObject():
- cgThings.append(CGClassConstructHook(descriptor))
- cgThings.append(CGClassHasInstanceHook(descriptor))
- cgThings.append(CGInterfaceObjectJSClass(descriptor))
- pass
-
- if descriptor.interface.hasInterfacePrototypeObject():
- cgThings.append(CGPrototypeJSClass(descriptor))
- pass
-
- properties = PropertyArrays(descriptor)
- cgThings.append(CGGeneric(define=str(properties)))
- cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties))
- if descriptor.interface.hasInterfacePrototypeObject():
- cgThings.append(CGGetProtoObjectMethod(descriptor))
- pass
- else:
- cgThings.append(CGGetConstructorObjectMethod(descriptor))
- pass
-
- # Set up our Xray callbacks as needed. Note that we don't need to do
- # it in workers.
- if (descriptor.interface.hasInterfacePrototypeObject() and
- not descriptor.workers):
- if descriptor.concrete and descriptor.proxy:
- #cgThings.append(CGResolveOwnProperty(descriptor))
- #cgThings.append(CGEnumerateOwnProperties(descriptor))
- pass
- cgThings.append(CGResolveProperty(descriptor, properties))
- #cgThings.append(CGEnumerateProperties(descriptor, properties))
-
- if descriptor.interface.hasInterfaceObject():
- cgThings.append(CGDefineDOMInterfaceMethod(descriptor))
- if (not descriptor.interface.isExternal() and
- # Workers stuff is never pref-controlled
- not descriptor.workers and
- descriptor.interface.getExtendedAttribute("PrefControlled") is not None):
- #cgThings.append(CGPrefEnabled(descriptor))
- pass
-
- if descriptor.interface.hasInterfacePrototypeObject():
- cgThings.append(CGNativePropertyHooks(descriptor))
- pass
-
- if descriptor.concrete:
- if descriptor.proxy:
- #cgThings.append(CGProxyIsProxy(descriptor))
- cgThings.append(CGProxyUnwrap(descriptor))
- cgThings.append(CGDOMJSProxyHandlerDOMClass(descriptor))
- cgThings.append(CGDOMJSProxyHandler_obj_toString(descriptor))
- cgThings.append(CGDOMJSProxyHandler_get(descriptor))
- #cgThings.append(CGDOMJSProxyHandler(descriptor))
- #cgThings.append(CGIsMethod(descriptor))
- pass
- else:
- cgThings.append(CGDOMJSClass(descriptor))
- pass
-
- if descriptor.wrapperCache:
- cgThings.append(CGWrapWithCacheMethod(descriptor))
- cgThings.append(CGWrapMethod(descriptor))
- pass
- else:
- cgThings.append(CGWrapNonWrapperCacheMethod(descriptor))
- pass
-
- cgThings = CGList((CGIndenter(t, declareOnly=True) for t in cgThings), "\n")
- cgThings = CGWrapper(cgThings, pre='\n', post='\n')
- #self.cgRoot = CGWrapper(CGNamespace(toBindingNamespace(descriptor.name),
- # cgThings),
- # post='\n')
- self.cgRoot = cgThings
-
- def declare(self):
- return self.cgRoot.declare()
- def define(self):
- return self.cgRoot.define()
-
-class CGDictionary(CGThing):
- def __init__(self, dictionary, descriptorProvider):
- self.dictionary = dictionary;
- self.workers = descriptorProvider.workers
- 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
- # Getting a conversion template for interface types can fail
- # if we don't have a relevant descriptor when self.workers is True.
- # If that happens, just mark ourselves as not being
- # generatable and move on.
- try:
- self.memberInfo = [
- (member,
- getJSToNativeConversionTemplate(member.type,
- descriptorProvider,
- isMember=True,
- isOptional=(not member.defaultValue),
- defaultValue=member.defaultValue))
- for member in dictionary.members ]
- except NoSuchDescriptorError, err:
- if not self.workers:
- raise err
- self.generatable = False
-
- def declare(self):
- if not self.generatable:
- return ""
- d = self.dictionary
- if d.parent:
- inheritance = ": public %s " % self.makeClassName(d.parent) #XXXjdm
- else:
- inheritance = ""
- memberDecls = [" %s: %s," %
- (m[0].identifier.name, self.getMemberType(m))
- for m in self.memberInfo]
-
- return (string.Template(
- "pub struct ${selfName} {\n" + #XXXjdm deal with inheritance
- "\n".join(memberDecls) + "\n" +
- # NOTE: jsids are per-runtime, so don't use them in workers
- "\n".join(" //static jsid " +
- self.makeIdName(m.identifier.name) + ";" for
- m in d.members) + "\n"
- "}").substitute( { "selfName": self.makeClassName(d),
- "inheritance": inheritance }))
-
- def define(self):
- if not self.generatable:
- return ""
- d = self.dictionary
- if d.parent:
- initParent = ("// Per spec, we init the parent's members first\n"
- "if (!%s::Init(cx, val)) {\n"
- " return false;\n"
- "}\n" % self.makeClassName(d.parent))
- else:
- initParent = ""
-
- memberInits = [CGIndenter(self.getMemberConversion(m)).define()
- for m in self.memberInfo]
- idinit = [CGGeneric('!InternJSString(cx, %s, "%s")' %
- (m.identifier.name + "_id", m.identifier.name))
- for m in d.members]
- idinit = CGList(idinit, " ||\n")
- idinit = CGWrapper(idinit, pre="if (",
- post=(") {\n"
- " return false;\n"
- "}"),
- reindent=True)
-
- def defaultValue(ty):
- if ty is "bool":
- return "false"
- elif ty in ["i32", "u32"]:
- return "0"
- elif ty is "nsString":
- return "\"\""
- elif ty.startswith("Optional"):
- return "None"
- else:
- return "/* uh oh: %s */" % ty
-
- return string.Template(
- # NOTE: jsids are per-runtime, so don't use them in workers
- ("static initedIds: bool = false;\n" +
- "\n".join("static %s: jsid = JSID_VOID;" %
- self.makeIdName(m.identifier.name)
- for m in d.members) + "\n"
- "\n"
- "impl ${selfName} {\n"
- "fn new() -> ${selfName} {\n"
- " ${selfName} {\n" +
- "\n".join(" %s: %s," % (m[0].identifier.name, defaultValue(self.getMemberType(m))) for m in self.memberInfo) + "\n"
- " }\n"
- "}\n"
- "\n"
- "fn InitIds(cx: *JSContext) -> bool {\n"
- " //MOZ_ASSERT(!initedIds);\n"
- "/*${idInit}\n"
- " initedIds = true;*/ //XXXjdm\n"
- " return true;\n"
- "}\n"
- "\n" if not self.workers else "") +
- "fn Init(&mut self, cx: *JSContext, val: JSVal) -> JSBool\n"
- "{\n"
- " unsafe {\n" +
- # NOTE: jsids are per-runtime, so don't use them in workers
- (" if (!initedIds && !${selfName}::InitIds(cx)) {\n"
- " return 0;\n"
- " }\n" if not self.workers else "") +
- "${initParent}"
- " let mut found: JSBool = 0;\n"
- " let temp: JSVal = JSVAL_NULL;\n"
- " let isNull = RUST_JSVAL_IS_NULL(val) != 0 || RUST_JSVAL_IS_VOID(val) != 0;\n"
- " if !isNull && RUST_JSVAL_IS_PRIMITIVE(val) != 0 {\n"
- " return 0; //XXXjdm throw properly here\n"
- " //return Throw<${isMainThread}>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);\n"
- " }\n"
- "\n"
- "${initMembers}\n"
- " return 1;\n"
- " }\n"
- "}\n"
- "}").substitute({
- "selfName": self.makeClassName(d),
- "initParent": CGIndenter(CGGeneric(initParent)).define(),
- "initMembers": "\n\n".join(memberInits),
- "idInit": CGIndenter(idinit).define(),
- "isMainThread": toStringBool(not self.workers)
- })
-
- @staticmethod
- def makeDictionaryName(dictionary, workers):
- suffix = "Workers" if workers else ""
- return dictionary.identifier.name + suffix
-
- def makeClassName(self, dictionary):
- return self.makeDictionaryName(dictionary, self.workers)
-
- def getMemberType(self, memberInfo):
- (member, (templateBody, declType,
- holderType, dealWithOptional)) = memberInfo
- # We can't handle having a holderType here
- assert holderType is None
- if dealWithOptional:
- declType = CGWrapper(declType, pre="Optional< ", post=" >")
- return declType.define()
-
- def getMemberConversion(self, memberInfo):
- (member, (templateBody, declType,
- holderType, dealWithOptional)) = memberInfo
- replacements = { "val": "temp",
- "valPtr": "&temp",
- "declName": ("self.%s" % member.identifier.name),
- # We need a holder name for external interfaces, but
- # it's scoped down to the conversion so we can just use
- # anything we want.
- "holderName": "holder"}
- # We can't handle having a holderType here
- assert holderType is None
- if dealWithOptional:
- replacements["declName"] = "(" + replacements["declName"] + ".Value())"
- if member.defaultValue:
- replacements["haveValue"] = "found"
-
- # NOTE: jsids are per-runtime, so don't use them in workers
- if True or self.workers: #XXXjdm hack until 'static mut' exists for global jsids
- propName = member.identifier.name
- propCheck = ('str::as_c_str("%s", |s| { JS_HasProperty(cx, RUST_JSVAL_TO_OBJECT(val), s, ptr::to_unsafe_ptr(&found)) })' %
- propName)
- propGet = ('str::as_c_str("%s", |s| { JS_GetProperty(cx, RUST_JSVAL_TO_OBJECT(val), s, ptr::to_unsafe_ptr(&temp)) })' %
- propName)
- else:
- propId = self.makeIdName(member.identifier.name);
- propCheck = ("JS_HasPropertyById(cx, RUST_JSVAL_TO_OBJECT(val), %s, ptr::to_unsafe_ptr(&found))" %
- propId)
- propGet = ("JS_GetPropertyById(cx, RUST_JSVAL_TO_OBJECT(val), %s, ptr::to_unsafe_ptr(&temp))" %
- propId)
-
- conversionReplacements = {
- "prop": "(this->%s)" % member.identifier.name,
- "convert": string.Template(templateBody).substitute(replacements),
- "propCheck": propCheck,
- "propGet": propGet
- }
- conversion = ("if isNull {\n"
- " found = 0;\n"
- "} else if ${propCheck} == 0 {\n"
- " return 0;\n"
- "}\n")
- if member.defaultValue:
- conversion += (
- "if found != 0 {\n"
- " if ${propGet} == 0 {\n"
- " return 0;\n"
- " }\n"
- "}\n"
- "${convert}")
- else:
- conversion += (
- "if found != 0 {\n"
- " ${prop}.Construct();\n"
- " if ${propGet} == 0 {\n"
- " return 0;\n"
- " }\n"
- "${convert}\n"
- "}")
- conversionReplacements["convert"] = CGIndenter(
- CGGeneric(conversionReplacements["convert"])).define()
-
- return CGGeneric(
- string.Template(conversion).substitute(conversionReplacements)
- )
-
- @staticmethod
- def makeIdName(name):
- return name + "_id"
-
- @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 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,
- hasInterfaceOrInterfacePrototypeObject=True)
- dictionaries = config.getDictionaries(webIDLFile)
-
- cgthings = []
-
- # Do codegen for all the enums
- def makeEnum(e):
- return CGNamespace.build([e.identifier.name + "Values"],
- CGList([CGGeneric(" use dom::bindings::utils::EnumEntry;"),
- CGEnum(e)]), public=True)
- def makeEnumTypedef(e):
- return CGGeneric(declare=("pub type %s = self::%sValues::valuelist;\n" %
- (e.identifier.name, e.identifier.name)))
- cgthings = [ fun(e) for e in config.getEnums(webIDLFile)
- for fun in [makeEnum, makeEnumTypedef] ]
-
- # Do codegen for all the dictionaries. We have to be a bit careful
- # here, because we have to generate these in order from least derived
- # to most derived so that class inheritance works out. We also have to
- # generate members before the dictionary that contains them.
- #
- # XXXbz this will fail if we have two webidl files A and B such that A
- # declares a dictionary which inherits from a dictionary in B and B
- # declares a dictionary (possibly a different one!) that inherits from a
- # dictionary in A. The good news is that I expect this to never happen.
- reSortedDictionaries = []
- dictionaries = set(dictionaries)
- while len(dictionaries) != 0:
- # Find the dictionaries that don't depend on anything else anymore
- # and move them over.
- toMove = [d for d in dictionaries if
- len(CGDictionary.getDictionaryDependencies(d) &
- dictionaries) == 0]
- if len(toMove) == 0:
- raise TypeError("Loop in dictionary dependency graph")
- dictionaries = dictionaries - set(toMove)
- reSortedDictionaries.extend(toMove)
-
- dictionaries = reSortedDictionaries
- #XXXjdm No codegen for workers right now.
- #cgthings.extend([CGDictionary(d, config.getDescriptorProvider(True))
- # for d in dictionaries])
- cgthings.extend([CGDictionary(d, config.getDescriptorProvider(False))
- for d in dictionaries])
-
- # Do codegen for all the descriptors
- cgthings.extend([CGDescriptor(x) for x in descriptors])
-
- # 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(descriptors,
- dictionaries,
- ['js::*',
- 'js::jsapi::*',
- 'js::jsapi::bindgen::*',
- 'js::jsfriendapi::bindgen::*',
- 'js::glue::bindgen::*',
- 'js::glue::*',
- 'dom::node::AbstractNode', #XXXjdm
- 'dom::document::Document', #XXXjdm
- 'dom::bindings::utils::*',
- 'dom::bindings::conversions::*',
- 'dom::clientrect::*', #XXXjdm
- 'dom::clientrectlist::*', #XXXjdm
- 'dom::htmlcollection::*', #XXXjdm
- 'dom::bindings::proxyhandler::*',
- 'dom::domparser::*', #XXXjdm
- 'dom::event::*', #XXXjdm
- 'dom::eventtarget::*', #XXXjdm
- 'scripting::script_task::task_from_context',
- 'dom::bindings::utils::EnumEntry',
- ],
- [],
- curr)
-
- # Add the auto-generated comment.
- curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
-
- # Store the final result.
- self.root = curr
- def declare(self):
- return stripTrailingWhitespace(self.root.declare())
- def define(self):
- return stripTrailingWhitespace(self.root.define())