diff options
author | Patrick Walton <pcwalton@mimiga.net> | 2013-05-20 18:41:25 -0700 |
---|---|---|
committer | Patrick Walton <pcwalton@mimiga.net> | 2013-05-28 15:40:47 -0700 |
commit | c7bce9823660106969e5d2c6b4e4c35f4003d360 (patch) | |
tree | d7dd76be49fa07db776fd4fb2576f492c4b97268 /src/components/servo/dom/bindings/codegen/CodegenRust.py | |
parent | c658c6dea93db2769d1271edd5253f1653162a26 (diff) | |
download | servo-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.py | 4164 |
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()) |