forked from mirrors/gecko-dev
		
	Source-Repo: https://github.com/servo/servo Source-Revision: 1dfc0481efd4687658ab34e68c883caeadd8b20f
		
			
				
	
	
		
			6019 lines
		
	
	
	
		
			229 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			6019 lines
		
	
	
	
		
			229 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
# 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.
 | 
						|
 | 
						|
from collections import defaultdict
 | 
						|
 | 
						|
import operator
 | 
						|
import re
 | 
						|
import string
 | 
						|
import textwrap
 | 
						|
import functools
 | 
						|
 | 
						|
from WebIDL import (
 | 
						|
    BuiltinTypes,
 | 
						|
    IDLBuiltinType,
 | 
						|
    IDLNullValue,
 | 
						|
    IDLType,
 | 
						|
    IDLInterfaceMember,
 | 
						|
    IDLUndefinedValue,
 | 
						|
)
 | 
						|
 | 
						|
from Configuration import getTypesFromDescriptor, getTypesFromDictionary, getTypesFromCallback
 | 
						|
 | 
						|
AUTOGENERATED_WARNING_COMMENT = \
 | 
						|
    "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n"
 | 
						|
FINALIZE_HOOK_NAME = '_finalize'
 | 
						|
TRACE_HOOK_NAME = '_trace'
 | 
						|
CONSTRUCT_HOOK_NAME = '_constructor'
 | 
						|
HASINSTANCE_HOOK_NAME = '_hasInstance'
 | 
						|
 | 
						|
 | 
						|
def replaceFileIfChanged(filename, newContents):
 | 
						|
    """
 | 
						|
    Read a copy of the old file, so that we don't touch it if it hasn't changed.
 | 
						|
    Returns True if the file was updated, false otherwise.
 | 
						|
    """
 | 
						|
    # XXXjdm This doesn't play well with make right now.
 | 
						|
    #       Force the file to always be updated, or else changing CodegenRust.py
 | 
						|
    #       will cause many autogenerated bindings to be regenerated perpetually
 | 
						|
    #       until the result is actually different.
 | 
						|
 | 
						|
    # oldFileContents = ""
 | 
						|
    # try:
 | 
						|
    #     with open(filename, 'rb') as oldFile:
 | 
						|
    #         oldFileContents = ''.join(oldFile.readlines())
 | 
						|
    # except:
 | 
						|
    #     pass
 | 
						|
 | 
						|
    # if newContents == oldFileContents:
 | 
						|
    #     return False
 | 
						|
 | 
						|
    with open(filename, 'wb') as f:
 | 
						|
        f.write(newContents)
 | 
						|
 | 
						|
    return True
 | 
						|
 | 
						|
 | 
						|
def toStringBool(arg):
 | 
						|
    return str(not not arg).lower()
 | 
						|
 | 
						|
 | 
						|
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.unrestricted_float: 'f32',
 | 
						|
    IDLType.Tags.float: 'Finite<f32>',
 | 
						|
    IDLType.Tags.unrestricted_double: 'f64',
 | 
						|
    IDLType.Tags.double: 'Finite<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.unrestricted_float,
 | 
						|
    IDLType.Tags.unrestricted_double
 | 
						|
]
 | 
						|
 | 
						|
 | 
						|
class CastableObjectUnwrapper():
 | 
						|
    """
 | 
						|
    A class for unwrapping an object named by the "source" argument
 | 
						|
    based on the passed-in descriptor. Stringifies to a Rust expression of
 | 
						|
    the appropriate type.
 | 
						|
 | 
						|
    codeOnFailure is the code to run if unwrapping fails.
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor, source, codeOnFailure, handletype):
 | 
						|
        self.substitution = {
 | 
						|
            "source": source,
 | 
						|
            "codeOnFailure": CGIndenter(CGGeneric(codeOnFailure), 8).define(),
 | 
						|
            "handletype": handletype,
 | 
						|
        }
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return string.Template("""\
 | 
						|
match native_from_handle${handletype}(${source}) {
 | 
						|
    Ok(val) => val,
 | 
						|
    Err(()) => {
 | 
						|
${codeOnFailure}
 | 
						|
    }
 | 
						|
}""").substitute(self.substitution)
 | 
						|
 | 
						|
 | 
						|
# 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)
 | 
						|
 | 
						|
 | 
						|
def indent(s, indentLevel=2):
 | 
						|
    """
 | 
						|
    Indent C++ code.
 | 
						|
 | 
						|
    Weird secret feature: this doesn't indent lines that start with # (such as
 | 
						|
    #include lines or #ifdef/#endif).
 | 
						|
    """
 | 
						|
    if s == "":
 | 
						|
        return s
 | 
						|
    return re.sub(lineStartDetector, indentLevel * " ", s)
 | 
						|
 | 
						|
 | 
						|
# dedent() and fill() are often called on the same string multiple
 | 
						|
# times.  We want to memoize their return values so we don't keep
 | 
						|
# recomputing them all the time.
 | 
						|
def memoize(fn):
 | 
						|
    """
 | 
						|
    Decorator to memoize a function of one argument.  The cache just
 | 
						|
    grows without bound.
 | 
						|
    """
 | 
						|
    cache = {}
 | 
						|
 | 
						|
    @functools.wraps(fn)
 | 
						|
    def wrapper(arg):
 | 
						|
        retval = cache.get(arg)
 | 
						|
        if retval is None:
 | 
						|
            retval = cache[arg] = fn(arg)
 | 
						|
        return retval
 | 
						|
    return wrapper
 | 
						|
 | 
						|
 | 
						|
@memoize
 | 
						|
def dedent(s):
 | 
						|
    """
 | 
						|
    Remove all leading whitespace from s, and remove a blank line
 | 
						|
    at the beginning.
 | 
						|
    """
 | 
						|
    if s.startswith('\n'):
 | 
						|
        s = s[1:]
 | 
						|
    return textwrap.dedent(s)
 | 
						|
 | 
						|
 | 
						|
# This works by transforming the fill()-template to an equivalent
 | 
						|
# string.Template.
 | 
						|
fill_multiline_substitution_re = re.compile(r"( *)\$\*{(\w+)}(\n)?")
 | 
						|
 | 
						|
 | 
						|
@memoize
 | 
						|
def compile_fill_template(template):
 | 
						|
    """
 | 
						|
    Helper function for fill().  Given the template string passed to fill(),
 | 
						|
    do the reusable part of template processing and return a pair (t,
 | 
						|
    argModList) that can be used every time fill() is called with that
 | 
						|
    template argument.
 | 
						|
 | 
						|
    argsModList is list of tuples that represent modifications to be
 | 
						|
    made to args.  Each modification has, in order: i) the arg name,
 | 
						|
    ii) the modified name, iii) the indent depth.
 | 
						|
    """
 | 
						|
    t = dedent(template)
 | 
						|
    assert t.endswith("\n") or "\n" not in t
 | 
						|
    argModList = []
 | 
						|
 | 
						|
    def replace(match):
 | 
						|
        """
 | 
						|
        Replaces a line like '  $*{xyz}\n' with '${xyz_n}',
 | 
						|
        where n is the indent depth, and add a corresponding entry to
 | 
						|
        argModList.
 | 
						|
 | 
						|
        Note that this needs to close over argModList, so it has to be
 | 
						|
        defined inside compile_fill_template().
 | 
						|
        """
 | 
						|
        indentation, name, nl = match.groups()
 | 
						|
        depth = len(indentation)
 | 
						|
 | 
						|
        # Check that $*{xyz} appears by itself on a line.
 | 
						|
        prev = match.string[:match.start()]
 | 
						|
        if (prev and not prev.endswith("\n")) or nl is None:
 | 
						|
            raise ValueError("Invalid fill() template: $*{%s} must appear by itself on a line" % name)
 | 
						|
 | 
						|
        # Now replace this whole line of template with the indented equivalent.
 | 
						|
        modified_name = name + "_" + str(depth)
 | 
						|
        argModList.append((name, modified_name, depth))
 | 
						|
        return "${" + modified_name + "}"
 | 
						|
 | 
						|
    t = re.sub(fill_multiline_substitution_re, replace, t)
 | 
						|
    return (string.Template(t), argModList)
 | 
						|
 | 
						|
 | 
						|
def fill(template, **args):
 | 
						|
    """
 | 
						|
    Convenience function for filling in a multiline template.
 | 
						|
 | 
						|
    `fill(template, name1=v1, name2=v2)` is a lot like
 | 
						|
    `string.Template(template).substitute({"name1": v1, "name2": v2})`.
 | 
						|
 | 
						|
    However, it's shorter, and has a few nice features:
 | 
						|
 | 
						|
      * If `template` is indented, fill() automatically dedents it!
 | 
						|
        This makes code using fill() with Python's multiline strings
 | 
						|
        much nicer to look at.
 | 
						|
 | 
						|
      * If `template` starts with a blank line, fill() strips it off.
 | 
						|
        (Again, convenient with multiline strings.)
 | 
						|
 | 
						|
      * fill() recognizes a special kind of substitution
 | 
						|
        of the form `$*{name}`.
 | 
						|
 | 
						|
        Use this to paste in, and automatically indent, multiple lines.
 | 
						|
        (Mnemonic: The `*` is for "multiple lines").
 | 
						|
 | 
						|
        A `$*` substitution must appear by itself on a line, with optional
 | 
						|
        preceding indentation (spaces only). The whole line is replaced by the
 | 
						|
        corresponding keyword argument, indented appropriately.  If the
 | 
						|
        argument is an empty string, no output is generated, not even a blank
 | 
						|
        line.
 | 
						|
    """
 | 
						|
 | 
						|
    t, argModList = compile_fill_template(template)
 | 
						|
    # Now apply argModList to args
 | 
						|
    for (name, modified_name, depth) in argModList:
 | 
						|
        if not (args[name] == "" or args[name].endswith("\n")):
 | 
						|
            raise ValueError("Argument %s with value %r is missing a newline" % (name, args[name]))
 | 
						|
        args[modified_name] = indent(args[name], depth)
 | 
						|
 | 
						|
    return t.substitute(args)
 | 
						|
 | 
						|
 | 
						|
class CGThing():
 | 
						|
    """
 | 
						|
    Abstract base class for things that spit out code.
 | 
						|
    """
 | 
						|
    def __init__(self):
 | 
						|
        pass  # Nothing for now
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        """Produce code for a Rust file."""
 | 
						|
        raise NotImplementedError  # Override me!
 | 
						|
 | 
						|
 | 
						|
class CGNativePropertyHooks(CGThing):
 | 
						|
    """
 | 
						|
    Generate a NativePropertyHooks for a given descriptor
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor, properties):
 | 
						|
        CGThing.__init__(self)
 | 
						|
        self.descriptor = descriptor
 | 
						|
        self.properties = properties
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        parent = self.descriptor.interface.parent
 | 
						|
        if parent:
 | 
						|
            parentHooks = ("Some(&::dom::bindings::codegen::Bindings::%sBinding::sNativePropertyHooks)"
 | 
						|
                           % parent.identifier.name)
 | 
						|
        else:
 | 
						|
            parentHooks = "None"
 | 
						|
 | 
						|
        substitutions = {
 | 
						|
            "parentHooks": parentHooks
 | 
						|
        }
 | 
						|
 | 
						|
        return string.Template(
 | 
						|
            "pub static sNativePropertyHooks: NativePropertyHooks = NativePropertyHooks {\n"
 | 
						|
            "    native_properties: &sNativeProperties,\n"
 | 
						|
            "    proto_hooks: ${parentHooks},\n"
 | 
						|
            "};\n").substitute(substitutions)
 | 
						|
 | 
						|
 | 
						|
class CGMethodCall(CGThing):
 | 
						|
    """
 | 
						|
    A class to generate selection of a method signature from a set of
 | 
						|
    signatures and generation of a call to that signature.
 | 
						|
    """
 | 
						|
    def __init__(self, argsPre, nativeMethodName, static, descriptor, method):
 | 
						|
        CGThing.__init__(self)
 | 
						|
 | 
						|
        methodName = '\\"%s.%s\\"' % (descriptor.interface.identifier.name, method.identifier.name)
 | 
						|
 | 
						|
        def requiredArgCount(signature):
 | 
						|
            arguments = signature[1]
 | 
						|
            if len(arguments) == 0:
 | 
						|
                return 0
 | 
						|
            requiredArgs = len(arguments)
 | 
						|
            while requiredArgs and arguments[requiredArgs - 1].optional:
 | 
						|
                requiredArgs -= 1
 | 
						|
            return requiredArgs
 | 
						|
 | 
						|
        signatures = method.signatures()
 | 
						|
 | 
						|
        def getPerSignatureCall(signature, argConversionStartsAt=0):
 | 
						|
            signatureIndex = signatures.index(signature)
 | 
						|
            return CGPerSignatureCall(signature[0], argsPre, signature[1],
 | 
						|
                                      nativeMethodName + '_' * signatureIndex,
 | 
						|
                                      static, descriptor,
 | 
						|
                                      method, argConversionStartsAt)
 | 
						|
 | 
						|
        if len(signatures) == 1:
 | 
						|
            # Special case: we can just do a per-signature method call
 | 
						|
            # here for our one signature and not worry about switching
 | 
						|
            # on anything.
 | 
						|
            signature = signatures[0]
 | 
						|
            self.cgRoot = CGList([getPerSignatureCall(signature)])
 | 
						|
            requiredArgs = requiredArgCount(signature)
 | 
						|
 | 
						|
            if requiredArgs > 0:
 | 
						|
                code = (
 | 
						|
                    "if argc < %d {\n"
 | 
						|
                    "    throw_type_error(cx, \"Not enough arguments to %s.\");\n"
 | 
						|
                    "    return false;\n"
 | 
						|
                    "}" % (requiredArgs, methodName))
 | 
						|
                self.cgRoot.prepend(
 | 
						|
                    CGWrapper(CGGeneric(code), pre="\n", post="\n"))
 | 
						|
 | 
						|
            return
 | 
						|
 | 
						|
        # Need to find the right overload
 | 
						|
        maxArgCount = method.maxArgCount
 | 
						|
        allowedArgCounts = method.allowedArgCounts
 | 
						|
 | 
						|
        argCountCases = []
 | 
						|
        for argCount in allowedArgCounts:
 | 
						|
            possibleSignatures = method.signaturesForArgCount(argCount)
 | 
						|
            if len(possibleSignatures) == 1:
 | 
						|
                # easy case!
 | 
						|
                signature = possibleSignatures[0]
 | 
						|
                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 = [
 | 
						|
                CGArgumentConverter(possibleSignatures[0][1][i],
 | 
						|
                                    i, "args", "argc", descriptor)
 | 
						|
                for i in range(0, distinguishingIndex)]
 | 
						|
 | 
						|
            # Select the right overload from our set.
 | 
						|
            distinguishingArg = "args.get(%d)" % distinguishingIndex
 | 
						|
 | 
						|
            def pickFirstSignature(condition, filterLambda):
 | 
						|
                sigs = filter(filterLambda, possibleSignatures)
 | 
						|
                assert len(sigs) < 2
 | 
						|
                if len(sigs) > 0:
 | 
						|
                    call = getPerSignatureCall(sigs[0], distinguishingIndex)
 | 
						|
                    if condition is None:
 | 
						|
                        caseBody.append(call)
 | 
						|
                    else:
 | 
						|
                        caseBody.append(CGGeneric("if " + condition + " {"))
 | 
						|
                        caseBody.append(CGIndenter(call))
 | 
						|
                        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.get().is_object() {" %
 | 
						|
                                          (distinguishingArg)))
 | 
						|
                for idx, sig in enumerate(interfacesSigs):
 | 
						|
                    caseBody.append(CGIndenter(CGGeneric("loop {")))
 | 
						|
                    type = sig[1][distinguishingIndex].type
 | 
						|
 | 
						|
                    # The argument at index distinguishingIndex can't possibly
 | 
						|
                    # be unset here, because we've already checked that argc is
 | 
						|
                    # large enough that we can examine this argument.
 | 
						|
                    info = getJSToNativeConversionInfo(
 | 
						|
                        type, descriptor, failureCode="break;", isDefinitelyObject=True)
 | 
						|
                    template = info.template
 | 
						|
                    declType = info.declType
 | 
						|
                    needsRooting = info.needsRooting
 | 
						|
 | 
						|
                    testCode = instantiateJSToNativeConversionTemplate(
 | 
						|
                        template,
 | 
						|
                        {"val": distinguishingArg},
 | 
						|
                        declType,
 | 
						|
                        "arg%d" % distinguishingIndex,
 | 
						|
                        needsRooting)
 | 
						|
 | 
						|
                    # Indent by 4, since we need to indent further than our "do" statement
 | 
						|
                    caseBody.append(CGIndenter(testCode, 4))
 | 
						|
                    # If we got this far, we know we unwrapped to the right
 | 
						|
                    # interface, so just do the call.  Start conversion with
 | 
						|
                    # distinguishingIndex + 1, since we already converted
 | 
						|
                    # distinguishingIndex.
 | 
						|
                    caseBody.append(CGIndenter(
 | 
						|
                        getPerSignatureCall(sig, distinguishingIndex + 1), 4))
 | 
						|
                    caseBody.append(CGIndenter(CGGeneric("}")))
 | 
						|
 | 
						|
                caseBody.append(CGGeneric("}"))
 | 
						|
 | 
						|
            # XXXbz Now we're supposed to check for distinguishingArg being
 | 
						|
            # an array or a platform object that supports indexed
 | 
						|
            # properties... skip that last for now.  It's a bit of a pain.
 | 
						|
            pickFirstSignature("%s.get().isObject() && IsArrayLike(cx, &%s.get().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.get().isObject() && JS_ObjectIsDate(cx, &%s.get().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.get().is_object() && !is_platform_object(%s.get().to_object())" %
 | 
						|
                               (distinguishingArg, distinguishingArg),
 | 
						|
                               lambda s: (s[1][distinguishingIndex].type.isCallback() or
 | 
						|
                                          s[1][distinguishingIndex].type.isCallbackInterface() or
 | 
						|
                                          s[1][distinguishingIndex].type.isDictionary() or
 | 
						|
                                          s[1][distinguishingIndex].type.isObject()))
 | 
						|
 | 
						|
            # The remaining cases are mutually exclusive.  The
 | 
						|
            # pickFirstSignature calls are what change caseBody
 | 
						|
            # Check for strings or enums
 | 
						|
            if pickFirstSignature(None,
 | 
						|
                                  lambda s: (s[1][distinguishingIndex].type.isString() or
 | 
						|
                                             s[1][distinguishingIndex].type.isEnum())):
 | 
						|
                pass
 | 
						|
            # Check for primitives
 | 
						|
            elif pickFirstSignature(None,
 | 
						|
                                    lambda s: s[1][distinguishingIndex].type.isPrimitive()):
 | 
						|
                pass
 | 
						|
            # Check for "any"
 | 
						|
            elif pickFirstSignature(None,
 | 
						|
                                    lambda s: s[1][distinguishingIndex].type.isAny()):
 | 
						|
                pass
 | 
						|
            else:
 | 
						|
                # Just throw; we have no idea what we're supposed to
 | 
						|
                # do with this.
 | 
						|
                caseBody.append(CGGeneric("return Throw(cx, NS_ERROR_XPC_BAD_CONVERT_JS);"))
 | 
						|
 | 
						|
            argCountCases.append(CGCase(str(argCount),
 | 
						|
                                        CGList(caseBody, "\n")))
 | 
						|
 | 
						|
        overloadCGThings = []
 | 
						|
        overloadCGThings.append(
 | 
						|
            CGGeneric("let argcount = cmp::min(argc, %d);" %
 | 
						|
                      maxArgCount))
 | 
						|
        overloadCGThings.append(
 | 
						|
            CGSwitch("argcount",
 | 
						|
                     argCountCases,
 | 
						|
                     CGGeneric("throw_type_error(cx, \"Not enough arguments to %s.\");\n"
 | 
						|
                               "return false;" % methodName)))
 | 
						|
        # XXXjdm Avoid unreachable statement warnings
 | 
						|
        # overloadCGThings.append(
 | 
						|
        #     CGGeneric('panic!("We have an always-returning default case");\n'
 | 
						|
        #               'return false;'))
 | 
						|
        self.cgRoot = CGWrapper(CGList(overloadCGThings, "\n"),
 | 
						|
                                pre="\n")
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        return self.cgRoot.define()
 | 
						|
 | 
						|
 | 
						|
def dictionaryHasSequenceMember(dictionary):
 | 
						|
    return (any(typeIsSequenceOrHasSequenceMember(m.type) for m in
 | 
						|
                dictionary.members) or
 | 
						|
            (dictionary.parent and
 | 
						|
             dictionaryHasSequenceMember(dictionary.parent)))
 | 
						|
 | 
						|
 | 
						|
def typeIsSequenceOrHasSequenceMember(type):
 | 
						|
    if type.nullable():
 | 
						|
        type = type.inner
 | 
						|
    if type.isSequence():
 | 
						|
        return True
 | 
						|
    if type.isArray():
 | 
						|
        elementType = type.inner
 | 
						|
        return typeIsSequenceOrHasSequenceMember(elementType)
 | 
						|
    if type.isDictionary():
 | 
						|
        return dictionaryHasSequenceMember(type.inner)
 | 
						|
    if type.isUnion():
 | 
						|
        return any(typeIsSequenceOrHasSequenceMember(m.type) for m in
 | 
						|
                   type.flatMemberTypes)
 | 
						|
    return False
 | 
						|
 | 
						|
 | 
						|
def typeNeedsRooting(type, descriptorProvider):
 | 
						|
    return (type.isGeckoInterface() and
 | 
						|
            descriptorProvider.getDescriptor(type.unroll().inner.identifier.name).needsRooting)
 | 
						|
 | 
						|
 | 
						|
def union_native_type(t):
 | 
						|
    name = t.unroll().name
 | 
						|
    return 'UnionTypes::%s' % name
 | 
						|
 | 
						|
 | 
						|
class JSToNativeConversionInfo():
 | 
						|
    """
 | 
						|
    An object representing information about a JS-to-native conversion.
 | 
						|
    """
 | 
						|
    def __init__(self, template, default=None, declType=None,
 | 
						|
                 needsRooting=False):
 | 
						|
        """
 | 
						|
        template: A string representing the conversion code.  This will have
 | 
						|
                  template substitution performed on it as follows:
 | 
						|
 | 
						|
          ${val} is a handle to the JS::Value in question
 | 
						|
 | 
						|
        default: A string or None representing rust code for default value(if any).
 | 
						|
 | 
						|
        declType: A CGThing representing the native C++ type we're converting
 | 
						|
                  to.  This is allowed to be None if the conversion code is
 | 
						|
                  supposed to be used as-is.
 | 
						|
 | 
						|
        needsRooting: A boolean indicating whether the caller has to root
 | 
						|
                      the result
 | 
						|
        """
 | 
						|
        assert isinstance(template, str)
 | 
						|
        assert declType is None or isinstance(declType, CGThing)
 | 
						|
        self.template = template
 | 
						|
        self.default = default
 | 
						|
        self.declType = declType
 | 
						|
        self.needsRooting = needsRooting
 | 
						|
 | 
						|
 | 
						|
def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
 | 
						|
                                isDefinitelyObject=False,
 | 
						|
                                isMember=False,
 | 
						|
                                isArgument=False,
 | 
						|
                                invalidEnumValueFatal=True,
 | 
						|
                                defaultValue=None,
 | 
						|
                                treatNullAs="Default",
 | 
						|
                                isEnforceRange=False,
 | 
						|
                                isClamp=False,
 | 
						|
                                exceptionCode=None,
 | 
						|
                                allowTreatNonObjectAsNull=False,
 | 
						|
                                isCallbackReturnValue=False,
 | 
						|
                                sourceDescription="value"):
 | 
						|
    """
 | 
						|
    Get a template for converting a JS value to a native object based on the
 | 
						|
    given type and descriptor.  If failureCode is given, then we're actually
 | 
						|
    testing whether we can convert the argument to the desired type.  That
 | 
						|
    means that failures to convert due to the JS value being the wrong type of
 | 
						|
    value need to use failureCode instead of throwing exceptions.  Failures to
 | 
						|
    convert that are due to JS exceptions (from toString or valueOf methods) or
 | 
						|
    out of memory conditions need to throw exceptions no matter what
 | 
						|
    failureCode is.
 | 
						|
 | 
						|
    If isDefinitelyObject is True, that means we know the value
 | 
						|
    isObject() and we have no need to recheck that.
 | 
						|
 | 
						|
    if isMember is True, we're being converted from a property of some
 | 
						|
    JS object, not from an actual method argument, so we can't rely on
 | 
						|
    our jsval being rooted or outliving us in any way.  Any caller
 | 
						|
    passing true needs to ensure that it is handled correctly in
 | 
						|
    typeIsSequenceOrHasSequenceMember.
 | 
						|
 | 
						|
    invalidEnumValueFatal controls whether an invalid enum value conversion
 | 
						|
    attempt will throw (if true) or simply return without doing anything (if
 | 
						|
    false).
 | 
						|
 | 
						|
    If defaultValue is not None, it's the IDL default value for this conversion
 | 
						|
 | 
						|
    If isEnforceRange is true, we're converting an integer and throwing if the
 | 
						|
    value is out of range.
 | 
						|
 | 
						|
    If isClamp is true, we're converting an integer and clamping if the
 | 
						|
    value is out of range.
 | 
						|
 | 
						|
    If allowTreatNonObjectAsNull is true, then [TreatNonObjectAsNull]
 | 
						|
    extended attributes on nullable callback functions will be honored.
 | 
						|
 | 
						|
    The return value from this function is an object of JSToNativeConversionInfo consisting of four things:
 | 
						|
 | 
						|
    1)  A string representing the conversion code.  This will have template
 | 
						|
        substitution performed on it as follows:
 | 
						|
 | 
						|
          ${val} replaced by an expression for the JS::Value in question
 | 
						|
 | 
						|
    2)  A string or None representing Rust code for the default value (if any).
 | 
						|
 | 
						|
    3)  A CGThing representing the native C++ type we're converting to
 | 
						|
        (declType).  This is allowed to be None if the conversion code is
 | 
						|
        supposed to be used as-is.
 | 
						|
 | 
						|
    4)  A boolean indicating whether the caller has to root the result.
 | 
						|
 | 
						|
    """
 | 
						|
    # We should not have a defaultValue if we know we're an object
 | 
						|
    assert not isDefinitelyObject or defaultValue is None
 | 
						|
 | 
						|
    # If exceptionCode is not set, we'll just rethrow the exception we got.
 | 
						|
    # Note that we can't just set failureCode to exceptionCode, because setting
 | 
						|
    # failureCode will prevent pending exceptions from being set in cases when
 | 
						|
    # they really should be!
 | 
						|
    if exceptionCode is None:
 | 
						|
        exceptionCode = "return false;"
 | 
						|
 | 
						|
    needsRooting = typeNeedsRooting(type, descriptorProvider)
 | 
						|
 | 
						|
    def handleOptional(template, declType, default):
 | 
						|
        assert (defaultValue is None) == (default is None)
 | 
						|
        return JSToNativeConversionInfo(template, default, declType, needsRooting=needsRooting)
 | 
						|
 | 
						|
    # Unfortunately, .capitalize() on a string will lowercase things inside the
 | 
						|
    # string, which we do not want.
 | 
						|
    def firstCap(string):
 | 
						|
        return string[0].upper() + string[1:]
 | 
						|
 | 
						|
    # Helper functions for dealing with failures due to the JS value being the
 | 
						|
    # wrong type of value.
 | 
						|
    def onFailureNotAnObject(failureCode):
 | 
						|
        return CGWrapper(
 | 
						|
            CGGeneric(
 | 
						|
                failureCode or
 | 
						|
                ('throw_type_error(cx, "%s is not an object.");\n'
 | 
						|
                 '%s' % (firstCap(sourceDescription), exceptionCode))),
 | 
						|
            post="\n")
 | 
						|
 | 
						|
    def onFailureNotCallable(failureCode):
 | 
						|
        return CGWrapper(
 | 
						|
            CGGeneric(
 | 
						|
                failureCode or
 | 
						|
                ('throw_type_error(cx, \"%s is not callable.\");\n'
 | 
						|
                 '%s' % (firstCap(sourceDescription), exceptionCode))))
 | 
						|
 | 
						|
    # A helper function for handling null default values. Checks that the
 | 
						|
    # default value, if it exists, is null.
 | 
						|
    def handleDefaultNull(nullValue):
 | 
						|
        if defaultValue is None:
 | 
						|
            return None
 | 
						|
 | 
						|
        if not isinstance(defaultValue, IDLNullValue):
 | 
						|
            raise TypeError("Can't handle non-null default value here")
 | 
						|
 | 
						|
        assert type.nullable() or type.isDictionary()
 | 
						|
        return nullValue
 | 
						|
 | 
						|
    # A helper function for wrapping up the template body for
 | 
						|
    # possibly-nullable objecty stuff
 | 
						|
    def wrapObjectTemplate(templateBody, nullValue, isDefinitelyObject, type,
 | 
						|
                           failureCode=None):
 | 
						|
        if not isDefinitelyObject:
 | 
						|
            # Handle the non-object cases by wrapping up the whole
 | 
						|
            # thing in an if cascade.
 | 
						|
            templateBody = (
 | 
						|
                "if ${val}.get().is_object() {\n" +
 | 
						|
                CGIndenter(CGGeneric(templateBody)).define() + "\n")
 | 
						|
            if type.nullable():
 | 
						|
                templateBody += (
 | 
						|
                    "} else if ${val}.get().is_null_or_undefined() {\n"
 | 
						|
                    "    %s\n") % nullValue
 | 
						|
            templateBody += (
 | 
						|
                "} else {\n" +
 | 
						|
                CGIndenter(onFailureNotAnObject(failureCode)).define() +
 | 
						|
                "}")
 | 
						|
        return templateBody
 | 
						|
 | 
						|
    assert not (isEnforceRange and isClamp)  # These are mutually exclusive
 | 
						|
 | 
						|
    if type.isArray():
 | 
						|
        raise TypeError("Can't handle array arguments yet")
 | 
						|
 | 
						|
    if type.isSequence():
 | 
						|
        raise TypeError("Can't handle sequence arguments yet")
 | 
						|
 | 
						|
    if type.isUnion():
 | 
						|
        declType = CGGeneric(union_native_type(type))
 | 
						|
        if type.nullable():
 | 
						|
            declType = CGWrapper(declType, pre="Option<", post=" >")
 | 
						|
 | 
						|
        templateBody = ("match FromJSValConvertible::from_jsval(cx, ${val}, ()) {\n"
 | 
						|
                        "    Ok(value) => value,\n"
 | 
						|
                        "    Err(()) => { %s },\n"
 | 
						|
                        "}" % exceptionCode)
 | 
						|
 | 
						|
        return handleOptional(templateBody, declType, handleDefaultNull("None"))
 | 
						|
 | 
						|
    if type.isGeckoInterface():
 | 
						|
        assert not isEnforceRange and not isClamp
 | 
						|
 | 
						|
        descriptor = descriptorProvider.getDescriptor(
 | 
						|
            type.unroll().inner.identifier.name)
 | 
						|
 | 
						|
        if descriptor.interface.isCallback():
 | 
						|
            name = descriptor.nativeType
 | 
						|
            declType = CGWrapper(CGGeneric(name), pre="Rc<", post=">")
 | 
						|
            template = "%s::new(${val}.get().to_object())" % name
 | 
						|
            if type.nullable():
 | 
						|
                declType = CGWrapper(declType, pre="Option<", post=">")
 | 
						|
                template = wrapObjectTemplate("Some(%s)" % template, "None",
 | 
						|
                                              isDefinitelyObject, type,
 | 
						|
                                              failureCode)
 | 
						|
 | 
						|
            return handleOptional(template, declType, handleDefaultNull("None"))
 | 
						|
 | 
						|
        if isMember:
 | 
						|
            descriptorType = descriptor.memberType
 | 
						|
        elif isArgument:
 | 
						|
            descriptorType = descriptor.argumentType
 | 
						|
        else:
 | 
						|
            descriptorType = descriptor.nativeType
 | 
						|
 | 
						|
        templateBody = ""
 | 
						|
        if descriptor.interface.isConsequential():
 | 
						|
            raise TypeError("Consequential interface %s being used as an "
 | 
						|
                            "argument" % descriptor.interface.identifier.name)
 | 
						|
 | 
						|
        if failureCode is None:
 | 
						|
            substitutions = {
 | 
						|
                "sourceDescription": sourceDescription,
 | 
						|
                "interface": descriptor.interface.identifier.name,
 | 
						|
                "exceptionCode": exceptionCode,
 | 
						|
            }
 | 
						|
            unwrapFailureCode = string.Template(
 | 
						|
                'throw_type_error(cx, "${sourceDescription} does not '
 | 
						|
                'implement interface ${interface}.");\n'
 | 
						|
                '${exceptionCode}').substitute(substitutions)
 | 
						|
        else:
 | 
						|
            unwrapFailureCode = failureCode
 | 
						|
 | 
						|
        templateBody = str(
 | 
						|
            CastableObjectUnwrapper(descriptor, "${val}", unwrapFailureCode, "value"))
 | 
						|
 | 
						|
        declType = CGGeneric(descriptorType)
 | 
						|
        if type.nullable():
 | 
						|
            templateBody = "Some(%s)" % templateBody
 | 
						|
            declType = CGWrapper(declType, pre="Option<", post=">")
 | 
						|
 | 
						|
        templateBody = wrapObjectTemplate(templateBody, "None",
 | 
						|
                                          isDefinitelyObject, type, failureCode)
 | 
						|
 | 
						|
        return handleOptional(templateBody, declType, handleDefaultNull("None"))
 | 
						|
 | 
						|
    if type.isSpiderMonkeyInterface():
 | 
						|
        raise TypeError("Can't handle SpiderMonkey interface arguments yet")
 | 
						|
 | 
						|
    if type.isDOMString():
 | 
						|
        assert not isEnforceRange and not isClamp
 | 
						|
 | 
						|
        treatAs = {
 | 
						|
            "Default": "StringificationBehavior::Default",
 | 
						|
            "EmptyString": "StringificationBehavior::Empty",
 | 
						|
        }
 | 
						|
        if treatNullAs not in treatAs:
 | 
						|
            raise TypeError("We don't support [TreatNullAs=%s]" % treatNullAs)
 | 
						|
        if type.nullable():
 | 
						|
            # Note: the actual behavior passed here doesn't matter for nullable
 | 
						|
            # strings.
 | 
						|
            nullBehavior = "StringificationBehavior::Default"
 | 
						|
        else:
 | 
						|
            nullBehavior = treatAs[treatNullAs]
 | 
						|
 | 
						|
        conversionCode = (
 | 
						|
            "match FromJSValConvertible::from_jsval(cx, ${val}, %s) {\n"
 | 
						|
            "    Ok(strval) => strval,\n"
 | 
						|
            "    Err(_) => { %s },\n"
 | 
						|
            "}" % (nullBehavior, exceptionCode))
 | 
						|
 | 
						|
        if defaultValue is None:
 | 
						|
            default = None
 | 
						|
        elif isinstance(defaultValue, IDLNullValue):
 | 
						|
            assert type.nullable()
 | 
						|
            default = "None"
 | 
						|
        else:
 | 
						|
            assert defaultValue.type.tag() == IDLType.Tags.domstring
 | 
						|
            default = '"%s".to_owned()' % defaultValue.value
 | 
						|
            if type.nullable():
 | 
						|
                default = "Some(%s)" % default
 | 
						|
 | 
						|
        declType = "DOMString"
 | 
						|
        if type.nullable():
 | 
						|
            declType = "Option<%s>" % declType
 | 
						|
 | 
						|
        return handleOptional(conversionCode, CGGeneric(declType), default)
 | 
						|
 | 
						|
    if type.isUSVString():
 | 
						|
        assert not isEnforceRange and not isClamp
 | 
						|
 | 
						|
        conversionCode = (
 | 
						|
            "match FromJSValConvertible::from_jsval(cx, ${val}, ()) {\n"
 | 
						|
            "    Ok(strval) => strval,\n"
 | 
						|
            "    Err(_) => { %s },\n"
 | 
						|
            "}" % exceptionCode)
 | 
						|
 | 
						|
        if defaultValue is None:
 | 
						|
            default = None
 | 
						|
        elif isinstance(defaultValue, IDLNullValue):
 | 
						|
            assert type.nullable()
 | 
						|
            default = "None"
 | 
						|
        else:
 | 
						|
            assert defaultValue.type.tag() in (IDLType.Tags.domstring, IDLType.Tags.usvstring)
 | 
						|
            default = 'USVString("%s".to_owned())' % defaultValue.value
 | 
						|
            if type.nullable():
 | 
						|
                default = "Some(%s)" % default
 | 
						|
 | 
						|
        declType = "USVString"
 | 
						|
        if type.nullable():
 | 
						|
            declType = "Option<%s>" % declType
 | 
						|
 | 
						|
        return handleOptional(conversionCode, CGGeneric(declType), default)
 | 
						|
 | 
						|
    if type.isByteString():
 | 
						|
        assert not isEnforceRange and not isClamp
 | 
						|
 | 
						|
        conversionCode = (
 | 
						|
            "match FromJSValConvertible::from_jsval(cx, ${val}, ()) {\n"
 | 
						|
            "    Ok(strval) => strval,\n"
 | 
						|
            "    Err(_) => { %s },\n"
 | 
						|
            "}" % exceptionCode)
 | 
						|
 | 
						|
        declType = CGGeneric("ByteString")
 | 
						|
        if type.nullable():
 | 
						|
            declType = CGWrapper(declType, pre="Option<", post=">")
 | 
						|
 | 
						|
        return handleOptional(conversionCode, declType, handleDefaultNull("None"))
 | 
						|
 | 
						|
    if type.isEnum():
 | 
						|
        assert not isEnforceRange and not isClamp
 | 
						|
 | 
						|
        if type.nullable():
 | 
						|
            raise TypeError("We don't support nullable enumerated arguments "
 | 
						|
                            "yet")
 | 
						|
        enum = type.inner.identifier.name
 | 
						|
        if invalidEnumValueFatal:
 | 
						|
            handleInvalidEnumValueCode = exceptionCode
 | 
						|
        else:
 | 
						|
            handleInvalidEnumValueCode = "return true;"
 | 
						|
 | 
						|
        transmute = "mem::transmute(index)"
 | 
						|
        if isMember == 'Dictionary':
 | 
						|
            transmute = 'unsafe { ' + transmute + ' }'
 | 
						|
 | 
						|
        template = (
 | 
						|
            "match find_enum_string_index(cx, ${val}, %(values)s) {\n"
 | 
						|
            "    Err(_) => { %(exceptionCode)s },\n"
 | 
						|
            "    Ok(None) => { %(handleInvalidEnumValueCode)s },\n"
 | 
						|
            "    Ok(Some(index)) => {\n"
 | 
						|
            "        //XXXjdm need some range checks up in here.\n"
 | 
						|
            "        %(transmute)s\n"
 | 
						|
            "    },\n"
 | 
						|
            "}" % {"values": enum + "Values::strings",
 | 
						|
                   "exceptionCode": exceptionCode,
 | 
						|
                   "transmute": transmute,
 | 
						|
                   "handleInvalidEnumValueCode": handleInvalidEnumValueCode})
 | 
						|
 | 
						|
        if defaultValue is not None:
 | 
						|
            assert defaultValue.type.tag() == IDLType.Tags.domstring
 | 
						|
            default = "%s::%s" % (enum, getEnumValueName(defaultValue.value))
 | 
						|
        else:
 | 
						|
            default = None
 | 
						|
 | 
						|
        return handleOptional(template, CGGeneric(enum), default)
 | 
						|
 | 
						|
    if type.isCallback():
 | 
						|
        assert not isEnforceRange and not isClamp
 | 
						|
        assert not type.treatNonCallableAsNull()
 | 
						|
        assert not type.treatNonObjectAsNull() or type.nullable()
 | 
						|
        assert not type.treatNonObjectAsNull() or not type.treatNonCallableAsNull()
 | 
						|
 | 
						|
        callback = type.unroll().callback
 | 
						|
        declType = CGGeneric('%s::%s' % (callback.module(), callback.identifier.name))
 | 
						|
        finalDeclType = CGTemplatedType("Rc", declType)
 | 
						|
 | 
						|
        conversion = CGCallbackTempRoot(declType.define())
 | 
						|
 | 
						|
        if type.nullable():
 | 
						|
            declType = CGTemplatedType("Option", declType)
 | 
						|
            finalDeclType = CGTemplatedType("Option", finalDeclType)
 | 
						|
            conversion = CGWrapper(conversion, pre="Some(", post=")")
 | 
						|
 | 
						|
        if allowTreatNonObjectAsNull and type.treatNonObjectAsNull():
 | 
						|
            if not isDefinitelyObject:
 | 
						|
                haveObject = "${val}.get().is_object()"
 | 
						|
                template = CGIfElseWrapper(haveObject,
 | 
						|
                                           conversion,
 | 
						|
                                           CGGeneric("None")).define()
 | 
						|
            else:
 | 
						|
                template = conversion
 | 
						|
        else:
 | 
						|
            template = CGIfElseWrapper("IsCallable(${val}.get().to_object())",
 | 
						|
                                       conversion,
 | 
						|
                                       onFailureNotCallable(failureCode)).define()
 | 
						|
            template = wrapObjectTemplate(
 | 
						|
                template,
 | 
						|
                "None",
 | 
						|
                isDefinitelyObject,
 | 
						|
                type,
 | 
						|
                failureCode)
 | 
						|
 | 
						|
        if defaultValue is not None:
 | 
						|
            assert allowTreatNonObjectAsNull
 | 
						|
            assert type.treatNonObjectAsNull()
 | 
						|
            assert type.nullable()
 | 
						|
            assert isinstance(defaultValue, IDLNullValue)
 | 
						|
            default = "None"
 | 
						|
        else:
 | 
						|
            default = None
 | 
						|
 | 
						|
        return JSToNativeConversionInfo(template, default, finalDeclType, needsRooting=needsRooting)
 | 
						|
 | 
						|
    if type.isAny():
 | 
						|
        assert not isEnforceRange and not isClamp
 | 
						|
 | 
						|
        declType = ""
 | 
						|
        default = ""
 | 
						|
        if isMember == "Dictionary":
 | 
						|
            # TODO: Need to properly root dictionaries
 | 
						|
            # https://github.com/servo/servo/issues/6381
 | 
						|
            declType = CGGeneric("JSVal")
 | 
						|
 | 
						|
            if defaultValue is None:
 | 
						|
                default = None
 | 
						|
            elif isinstance(defaultValue, IDLNullValue):
 | 
						|
                default = "NullValue()"
 | 
						|
            elif isinstance(defaultValue, IDLUndefinedValue):
 | 
						|
                default = "UndefinedValue()"
 | 
						|
            else:
 | 
						|
                raise TypeError("Can't handle non-null, non-undefined default value here")
 | 
						|
        else:
 | 
						|
            declType = CGGeneric("HandleValue")
 | 
						|
 | 
						|
            if defaultValue is None:
 | 
						|
                default = None
 | 
						|
            elif isinstance(defaultValue, IDLNullValue):
 | 
						|
                default = "HandleValue::null()"
 | 
						|
            elif isinstance(defaultValue, IDLUndefinedValue):
 | 
						|
                default = "HandleValue::undefined()"
 | 
						|
            else:
 | 
						|
                raise TypeError("Can't handle non-null, non-undefined default value here")
 | 
						|
 | 
						|
        return handleOptional("${val}", declType, default)
 | 
						|
 | 
						|
    if type.isObject():
 | 
						|
        assert not isEnforceRange and not isClamp
 | 
						|
 | 
						|
        # TODO: Need to root somehow
 | 
						|
        # https://github.com/servo/servo/issues/6382
 | 
						|
        declType = CGGeneric("*mut JSObject")
 | 
						|
        templateBody = wrapObjectTemplate("${val}.get().to_object()",
 | 
						|
                                          "ptr::null_mut()",
 | 
						|
                                          isDefinitelyObject, type, failureCode)
 | 
						|
 | 
						|
        return handleOptional(templateBody, declType,
 | 
						|
                              handleDefaultNull("ptr::null_mut()"))
 | 
						|
 | 
						|
    if type.isDictionary():
 | 
						|
        if failureCode is not None:
 | 
						|
            raise TypeError("Can't handle dictionaries when failureCode is not None")
 | 
						|
        # There are no nullable dictionaries
 | 
						|
        assert not type.nullable()
 | 
						|
 | 
						|
        typeName = CGDictionary.makeDictionaryName(type.inner)
 | 
						|
        declType = CGGeneric(typeName)
 | 
						|
        template = ("match %s::new(cx, ${val}) {\n"
 | 
						|
                    "    Ok(dictionary) => dictionary,\n"
 | 
						|
                    "    Err(_) => return false,\n"
 | 
						|
                    "}" % typeName)
 | 
						|
 | 
						|
        return handleOptional(template, declType, handleDefaultNull("%s::empty(cx)" % typeName))
 | 
						|
 | 
						|
    if type.isVoid():
 | 
						|
        # This one only happens for return values, and its easy: Just
 | 
						|
        # ignore the jsval.
 | 
						|
        return JSToNativeConversionInfo("", None, None, needsRooting=False)
 | 
						|
 | 
						|
    if not type.isPrimitive():
 | 
						|
        raise TypeError("Need conversion for argument type '%s'" % str(type))
 | 
						|
 | 
						|
    if type.isInteger():
 | 
						|
        if isEnforceRange:
 | 
						|
            conversionBehavior = "ConversionBehavior::EnforceRange"
 | 
						|
        elif isClamp:
 | 
						|
            conversionBehavior = "ConversionBehavior::Clamp"
 | 
						|
        else:
 | 
						|
            conversionBehavior = "ConversionBehavior::Default"
 | 
						|
    else:
 | 
						|
        assert not isEnforceRange and not isClamp
 | 
						|
        conversionBehavior = "()"
 | 
						|
 | 
						|
    if failureCode is None:
 | 
						|
        failureCode = 'return false'
 | 
						|
 | 
						|
    declType = CGGeneric(builtinNames[type.tag()])
 | 
						|
    if type.nullable():
 | 
						|
        declType = CGWrapper(declType, pre="Option<", post=">")
 | 
						|
 | 
						|
    template = (
 | 
						|
        "match FromJSValConvertible::from_jsval(cx, ${val}, %s) {\n"
 | 
						|
        "    Ok(v) => v,\n"
 | 
						|
        "    Err(_) => { %s }\n"
 | 
						|
        "}" % (conversionBehavior, exceptionCode))
 | 
						|
 | 
						|
    if defaultValue is not None:
 | 
						|
        if isinstance(defaultValue, IDLNullValue):
 | 
						|
            assert type.nullable()
 | 
						|
            defaultStr = "None"
 | 
						|
        else:
 | 
						|
            tag = defaultValue.type.tag()
 | 
						|
            if tag in [IDLType.Tags.float, IDLType.Tags.double]:
 | 
						|
                defaultStr = "Finite::wrap(%s)" % defaultValue.value
 | 
						|
            elif tag in numericTags:
 | 
						|
                defaultStr = str(defaultValue.value)
 | 
						|
            else:
 | 
						|
                assert tag == IDLType.Tags.bool
 | 
						|
                defaultStr = toStringBool(defaultValue.value)
 | 
						|
 | 
						|
            if type.nullable():
 | 
						|
                defaultStr = "Some(%s)" % defaultStr
 | 
						|
    else:
 | 
						|
        defaultStr = None
 | 
						|
 | 
						|
    return handleOptional(template, declType, defaultStr)
 | 
						|
 | 
						|
 | 
						|
def instantiateJSToNativeConversionTemplate(templateBody, replacements,
 | 
						|
                                            declType, declName, needsRooting):
 | 
						|
    """
 | 
						|
    Take the templateBody and declType as returned by
 | 
						|
    getJSToNativeConversionInfo, a set of replacements as required by the
 | 
						|
    strings in such a templateBody, and a declName, and generate code to
 | 
						|
    convert into a stack Rust binding with that name.
 | 
						|
    """
 | 
						|
    result = CGList([], "\n")
 | 
						|
 | 
						|
    conversion = CGGeneric(string.Template(templateBody).substitute(replacements))
 | 
						|
 | 
						|
    if declType is not None:
 | 
						|
        newDecl = [
 | 
						|
            CGGeneric("let "),
 | 
						|
            CGGeneric(declName),
 | 
						|
            CGGeneric(": "),
 | 
						|
            declType,
 | 
						|
            CGGeneric(" = "),
 | 
						|
            conversion,
 | 
						|
            CGGeneric(";"),
 | 
						|
        ]
 | 
						|
        result.append(CGList(newDecl))
 | 
						|
    else:
 | 
						|
        result.append(conversion)
 | 
						|
 | 
						|
    # Add an empty CGGeneric to get an extra newline after the argument
 | 
						|
    # conversion.
 | 
						|
    result.append(CGGeneric(""))
 | 
						|
 | 
						|
    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.unrestricted_float, IDLType.Tags.float,
 | 
						|
               IDLType.Tags.unrestricted_double, 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, args, argc, descriptorProvider,
 | 
						|
                 invalidEnumValueFatal=True):
 | 
						|
        CGThing.__init__(self)
 | 
						|
        assert not argument.defaultValue or argument.optional
 | 
						|
 | 
						|
        replacer = {
 | 
						|
            "index": index,
 | 
						|
            "argc": argc,
 | 
						|
            "args": args
 | 
						|
        }
 | 
						|
        condition = string.Template("${index} < ${argc}").substitute(replacer)
 | 
						|
 | 
						|
        replacementVariables = {
 | 
						|
            "val": string.Template("${args}.get(${index})").substitute(replacer),
 | 
						|
        }
 | 
						|
 | 
						|
        info = getJSToNativeConversionInfo(
 | 
						|
            argument.type,
 | 
						|
            descriptorProvider,
 | 
						|
            invalidEnumValueFatal=invalidEnumValueFatal,
 | 
						|
            defaultValue=argument.defaultValue,
 | 
						|
            treatNullAs=argument.treatNullAs,
 | 
						|
            isEnforceRange=argument.enforceRange,
 | 
						|
            isClamp=argument.clamp,
 | 
						|
            isMember="Variadic" if argument.variadic else False,
 | 
						|
            allowTreatNonObjectAsNull=argument.allowTreatNonCallableAsNull())
 | 
						|
        template = info.template
 | 
						|
        default = info.default
 | 
						|
        declType = info.declType
 | 
						|
        needsRooting = info.needsRooting
 | 
						|
 | 
						|
        if not argument.variadic:
 | 
						|
            if argument.optional:
 | 
						|
                if argument.defaultValue:
 | 
						|
                    assert default
 | 
						|
                    template = CGIfElseWrapper(condition,
 | 
						|
                                               CGGeneric(template),
 | 
						|
                                               CGGeneric(default)).define()
 | 
						|
                else:
 | 
						|
                    assert not default
 | 
						|
                    declType = CGWrapper(declType, pre="Option<", post=">")
 | 
						|
                    template = CGIfElseWrapper(condition,
 | 
						|
                                               CGGeneric("Some(%s)" % template),
 | 
						|
                                               CGGeneric("None")).define()
 | 
						|
            else:
 | 
						|
                assert not default
 | 
						|
 | 
						|
            self.converter = instantiateJSToNativeConversionTemplate(
 | 
						|
                template, replacementVariables, declType, "arg%d" % index,
 | 
						|
                needsRooting)
 | 
						|
        else:
 | 
						|
            assert argument.optional
 | 
						|
            variadicConversion = {
 | 
						|
                "val": string.Template("${args}.get(variadicArg)").substitute(replacer),
 | 
						|
            }
 | 
						|
            innerConverter = instantiateJSToNativeConversionTemplate(
 | 
						|
                template, variadicConversion, declType, "slot",
 | 
						|
                needsRooting)
 | 
						|
 | 
						|
            seqType = CGTemplatedType("Vec", declType)
 | 
						|
 | 
						|
            variadicConversion = string.Template(
 | 
						|
                "let mut vector: ${seqType} = Vec::with_capacity((${argc} - ${index}) as usize);\n"
 | 
						|
                "for variadicArg in ${index}..${argc} {\n"
 | 
						|
                "${inner}\n"
 | 
						|
                "    vector.push(slot);\n"
 | 
						|
                "}\n"
 | 
						|
                "vector"
 | 
						|
            ).substitute({
 | 
						|
                "index": index,
 | 
						|
                "argc": argc,
 | 
						|
                "seqType": seqType.define(),
 | 
						|
                "inner": CGIndenter(innerConverter, 4).define(),
 | 
						|
            })
 | 
						|
 | 
						|
            variadicConversion = CGIfElseWrapper(condition,
 | 
						|
                                                 CGGeneric(variadicConversion),
 | 
						|
                                                 CGGeneric("Vec::new()")).define()
 | 
						|
 | 
						|
            self.converter = instantiateJSToNativeConversionTemplate(
 | 
						|
                variadicConversion, replacementVariables, seqType, "arg%d" % index,
 | 
						|
                False)
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        return self.converter.define()
 | 
						|
 | 
						|
 | 
						|
def wrapForType(jsvalRef, result='result', successCode='return true;', pre=''):
 | 
						|
    """
 | 
						|
    Reflect a Rust value into JS.
 | 
						|
 | 
						|
      * 'jsvalRef': a MutableHandleValue in which to store the result
 | 
						|
                    of the conversion;
 | 
						|
      * 'result': the name of the variable in which the Rust value is stored;
 | 
						|
      * 'successCode': the code to run once we have done the conversion.
 | 
						|
      * 'pre': code to run before the conversion if rooting is necessary
 | 
						|
    """
 | 
						|
    wrap = "%s\n(%s).to_jsval(cx, %s);" % (pre, result, jsvalRef)
 | 
						|
    if successCode:
 | 
						|
        wrap += "\n%s" % successCode
 | 
						|
    return wrap
 | 
						|
 | 
						|
 | 
						|
def typeNeedsCx(type, retVal=False):
 | 
						|
    if type is None:
 | 
						|
        return False
 | 
						|
    if type.nullable():
 | 
						|
        type = type.inner
 | 
						|
    if type.isSequence() or type.isArray():
 | 
						|
        type = type.inner
 | 
						|
    if type.isUnion():
 | 
						|
        return any(typeNeedsCx(t) for t in type.unroll().flatMemberTypes)
 | 
						|
    if retVal and type.isSpiderMonkeyInterface():
 | 
						|
        return True
 | 
						|
    return type.isAny() or type.isObject()
 | 
						|
 | 
						|
 | 
						|
# Returns a CGThing containing the type of the return value.
 | 
						|
def getRetvalDeclarationForType(returnType, descriptorProvider):
 | 
						|
    if returnType is None or returnType.isVoid():
 | 
						|
        # Nothing to declare
 | 
						|
        return CGGeneric("()")
 | 
						|
    if returnType.isPrimitive() and returnType.tag() in builtinNames:
 | 
						|
        result = CGGeneric(builtinNames[returnType.tag()])
 | 
						|
        if returnType.nullable():
 | 
						|
            result = CGWrapper(result, pre="Option<", post=">")
 | 
						|
        return result
 | 
						|
    if returnType.isDOMString():
 | 
						|
        result = CGGeneric("DOMString")
 | 
						|
        if returnType.nullable():
 | 
						|
            result = CGWrapper(result, pre="Option<", post=">")
 | 
						|
        return result
 | 
						|
    if returnType.isUSVString():
 | 
						|
        result = CGGeneric("USVString")
 | 
						|
        if returnType.nullable():
 | 
						|
            result = CGWrapper(result, pre="Option<", post=">")
 | 
						|
        return result
 | 
						|
    if returnType.isByteString():
 | 
						|
        result = CGGeneric("ByteString")
 | 
						|
        if returnType.nullable():
 | 
						|
            result = CGWrapper(result, pre="Option<", post=">")
 | 
						|
        return result
 | 
						|
    if returnType.isEnum():
 | 
						|
        result = CGGeneric(returnType.unroll().inner.identifier.name)
 | 
						|
        if returnType.nullable():
 | 
						|
            result = CGWrapper(result, pre="Option<", post=">")
 | 
						|
        return result
 | 
						|
    if returnType.isGeckoInterface():
 | 
						|
        descriptor = descriptorProvider.getDescriptor(
 | 
						|
            returnType.unroll().inner.identifier.name)
 | 
						|
        result = CGGeneric(descriptor.returnType)
 | 
						|
        if returnType.nullable():
 | 
						|
            result = CGWrapper(result, pre="Option<", post=">")
 | 
						|
        return result
 | 
						|
    if returnType.isCallback():
 | 
						|
        callback = returnType.unroll().callback
 | 
						|
        result = CGGeneric('Rc<%s::%s>' % (callback.module(), callback.identifier.name))
 | 
						|
        if returnType.nullable():
 | 
						|
            result = CGWrapper(result, pre="Option<", post=">")
 | 
						|
        return result
 | 
						|
    if returnType.isUnion():
 | 
						|
        result = CGGeneric(union_native_type(returnType))
 | 
						|
        if returnType.nullable():
 | 
						|
            result = CGWrapper(result, pre="Option<", post=">")
 | 
						|
        return result
 | 
						|
    # TODO: Return the value through a MutableHandleValue outparam
 | 
						|
    # https://github.com/servo/servo/issues/6307
 | 
						|
    if returnType.isAny():
 | 
						|
        return CGGeneric("JSVal")
 | 
						|
    if returnType.isObject() or returnType.isSpiderMonkeyInterface():
 | 
						|
        return CGGeneric("*mut JSObject")
 | 
						|
    if returnType.isSequence():
 | 
						|
        raise TypeError("We don't support sequence return values")
 | 
						|
    if returnType.isDictionary():
 | 
						|
        nullable = returnType.nullable()
 | 
						|
        dictName = returnType.inner.name if nullable else returnType.name
 | 
						|
        result = CGGeneric(dictName)
 | 
						|
        if typeNeedsRooting(returnType, descriptorProvider):
 | 
						|
            raise TypeError("We don't support rootable dictionaries return values")
 | 
						|
        if nullable:
 | 
						|
            result = CGWrapper(result, pre="Option<", post=">")
 | 
						|
        return result
 | 
						|
 | 
						|
    raise TypeError("Don't know how to declare return value for %s" %
 | 
						|
                    returnType)
 | 
						|
 | 
						|
 | 
						|
class PropertyDefiner:
 | 
						|
    """
 | 
						|
    A common superclass for defining things on prototype objects.
 | 
						|
 | 
						|
    Subclasses should implement generateArray to generate the actual arrays of
 | 
						|
    things we're defining. They should also set self.regular to the list of
 | 
						|
    things exposed to web pages.
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor, name):
 | 
						|
        self.descriptor = descriptor
 | 
						|
        self.name = name
 | 
						|
 | 
						|
    def variableName(self):
 | 
						|
        return "s" + self.name
 | 
						|
 | 
						|
    def length(self):
 | 
						|
        return len(self.regular)
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        # We only need to generate id arrays for things that will end
 | 
						|
        # up used via ResolveProperty or EnumerateProperties.
 | 
						|
        return self.generateArray(self.regular, self.variableName())
 | 
						|
 | 
						|
    def generatePrefableArray(self, array, name, specTemplate, specTerminator,
 | 
						|
                              specType, getDataTuple):
 | 
						|
        """
 | 
						|
        This method generates our various arrays.
 | 
						|
 | 
						|
        array is an array of interface members as passed to generateArray
 | 
						|
 | 
						|
        name is the name as passed to generateArray
 | 
						|
 | 
						|
        specTemplate is a template for each entry of the spec array
 | 
						|
 | 
						|
        specTerminator is a terminator for the spec array (inserted at the end
 | 
						|
          of the array), or None
 | 
						|
 | 
						|
        specType is the actual typename of our spec
 | 
						|
 | 
						|
        getDataTuple is a callback function that takes an array entry and
 | 
						|
          returns a tuple suitable for substitution into specTemplate.
 | 
						|
        """
 | 
						|
 | 
						|
        assert len(array) != 0
 | 
						|
        specs = []
 | 
						|
 | 
						|
        for member in array:
 | 
						|
            specs.append(specTemplate % getDataTuple(member))
 | 
						|
        if specTerminator:
 | 
						|
            specs.append(specTerminator)
 | 
						|
 | 
						|
        return (("const %s: &'static [%s] = &[\n" +
 | 
						|
                 ",\n".join(specs) + "\n" +
 | 
						|
                 "];\n") % (name, specType))
 | 
						|
 | 
						|
 | 
						|
# The length of a method is the minimum of the lengths of the
 | 
						|
# argument lists of all its overloads.
 | 
						|
def methodLength(method):
 | 
						|
    signatures = method.signatures()
 | 
						|
    return min(
 | 
						|
        len([arg for arg in arguments if not arg.optional and not arg.variadic])
 | 
						|
        for (_, 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 __
 | 
						|
 | 
						|
        # Ignore non-static methods for callback interfaces
 | 
						|
        if not descriptor.interface.isCallback() or static:
 | 
						|
            methods = [m for m in descriptor.interface.members if
 | 
						|
                       m.isMethod() and m.isStatic() == static and
 | 
						|
                       not m.isIdentifierLess()]
 | 
						|
        else:
 | 
						|
            methods = []
 | 
						|
        self.regular = [{"name": m.identifier.name,
 | 
						|
                         "methodInfo": not m.isStatic(),
 | 
						|
                         "length": methodLength(m),
 | 
						|
                         "flags": "JSPROP_ENUMERATE"} for m in methods]
 | 
						|
 | 
						|
        # FIXME Check for an existing iterator on the interface first.
 | 
						|
        if any(m.isGetter() and m.isIndexed() for m in methods):
 | 
						|
            self.regular.append({"name": '@@iterator',
 | 
						|
                                 "methodInfo": False,
 | 
						|
                                 "selfHostedName": "ArrayValues",
 | 
						|
                                 "length": 0,
 | 
						|
                                 "flags": "JSPROP_ENUMERATE"})
 | 
						|
 | 
						|
        if not static:
 | 
						|
            stringifier = descriptor.operations['Stringifier']
 | 
						|
            if stringifier:
 | 
						|
                self.regular.append({
 | 
						|
                    "name": "toString",
 | 
						|
                    "nativeName": stringifier.identifier.name,
 | 
						|
                    "length": 0,
 | 
						|
                    "flags": "JSPROP_ENUMERATE"
 | 
						|
                })
 | 
						|
 | 
						|
    def generateArray(self, array, name):
 | 
						|
        if len(array) == 0:
 | 
						|
            return ""
 | 
						|
 | 
						|
        def specData(m):
 | 
						|
            # TODO: Use something like JS_FNSPEC
 | 
						|
            # https://github.com/servo/servo/issues/6391
 | 
						|
            if "selfHostedName" in m:
 | 
						|
                selfHostedName = '%s as *const u8 as *const libc::c_char' % str_to_const_array(m["selfHostedName"])
 | 
						|
                assert not m.get("methodInfo", True)
 | 
						|
                accessor = "None"
 | 
						|
                jitinfo = "0 as *const JSJitInfo"
 | 
						|
            else:
 | 
						|
                selfHostedName = "0 as *const libc::c_char"
 | 
						|
                if m.get("methodInfo", True):
 | 
						|
                    identifier = m.get("nativeName", m["name"])
 | 
						|
                    # Go through an intermediate type here, because it's not
 | 
						|
                    # easy to tell whether the methodinfo is a JSJitInfo or
 | 
						|
                    # a JSTypedMethodJitInfo here.  The compiler knows, though,
 | 
						|
                    # so let it do the work.
 | 
						|
                    jitinfo = "&%s_methodinfo as *const _ as *const JSJitInfo" % identifier
 | 
						|
                    accessor = "Some(generic_method)"
 | 
						|
                else:
 | 
						|
                    jitinfo = "0 as *const JSJitInfo"
 | 
						|
                    accessor = 'Some(%s)' % m.get("nativeName", m["name"])
 | 
						|
            if m["name"].startswith("@@"):
 | 
						|
                return ('(SymbolCode::%s as i32 + 1)'
 | 
						|
                        % m["name"][2:], accessor, jitinfo, m["length"], m["flags"], selfHostedName)
 | 
						|
            return (str_to_const_array(m["name"]), accessor, jitinfo, m["length"], m["flags"], selfHostedName)
 | 
						|
 | 
						|
        return self.generatePrefableArray(
 | 
						|
            array, name,
 | 
						|
            '    JSFunctionSpec {\n'
 | 
						|
            '        name: %s as *const u8 as *const libc::c_char,\n'
 | 
						|
            '        call: JSNativeWrapper {op: %s, info: %s},\n'
 | 
						|
            '        nargs: %s,\n'
 | 
						|
            '        flags: %s as u16,\n'
 | 
						|
            '        selfHostedName: %s\n'
 | 
						|
            '    }',
 | 
						|
            '    JSFunctionSpec {\n'
 | 
						|
            '        name: 0 as *const libc::c_char,\n'
 | 
						|
            '        call: JSNativeWrapper { op: None, info: 0 as *const JSJitInfo },\n'
 | 
						|
            '        nargs: 0,\n'
 | 
						|
            '        flags: 0,\n'
 | 
						|
            '        selfHostedName: 0 as *const libc::c_char\n'
 | 
						|
            '    }',
 | 
						|
            'JSFunctionSpec',
 | 
						|
            specData)
 | 
						|
 | 
						|
 | 
						|
class AttrDefiner(PropertyDefiner):
 | 
						|
    def __init__(self, descriptor, name, static):
 | 
						|
        PropertyDefiner.__init__(self, descriptor, name)
 | 
						|
        self.name = name
 | 
						|
        self.descriptor = descriptor
 | 
						|
        self.regular = [
 | 
						|
            m
 | 
						|
            for m in descriptor.interface.members
 | 
						|
            if m.isAttr() and m.isStatic() == static
 | 
						|
        ]
 | 
						|
        self.static = static
 | 
						|
 | 
						|
    def generateArray(self, array, name):
 | 
						|
        if len(array) == 0:
 | 
						|
            return ""
 | 
						|
 | 
						|
        def flags(attr):
 | 
						|
            return "JSPROP_SHARED | JSPROP_ENUMERATE"
 | 
						|
 | 
						|
        def getter(attr):
 | 
						|
            if self.static:
 | 
						|
                accessor = 'get_' + self.descriptor.internalNameFor(attr.identifier.name)
 | 
						|
                jitinfo = "0 as *const JSJitInfo"
 | 
						|
            else:
 | 
						|
                if attr.hasLenientThis():
 | 
						|
                    accessor = "generic_lenient_getter"
 | 
						|
                else:
 | 
						|
                    accessor = "generic_getter"
 | 
						|
                jitinfo = "&%s_getterinfo" % self.descriptor.internalNameFor(attr.identifier.name)
 | 
						|
 | 
						|
            return ("JSNativeWrapper { op: Some(%(native)s), info: %(info)s }"
 | 
						|
                    % {"info": jitinfo,
 | 
						|
                       "native": accessor})
 | 
						|
 | 
						|
        def setter(attr):
 | 
						|
            if attr.readonly and not attr.getExtendedAttribute("PutForwards"):
 | 
						|
                return "JSNativeWrapper { op: None, info: 0 as *const JSJitInfo }"
 | 
						|
 | 
						|
            if self.static:
 | 
						|
                accessor = 'set_' + self.descriptor.internalNameFor(attr.identifier.name)
 | 
						|
                jitinfo = "0 as *const JSJitInfo"
 | 
						|
            else:
 | 
						|
                if attr.hasLenientThis():
 | 
						|
                    accessor = "generic_lenient_setter"
 | 
						|
                else:
 | 
						|
                    accessor = "generic_setter"
 | 
						|
                jitinfo = "&%s_setterinfo" % self.descriptor.internalNameFor(attr.identifier.name)
 | 
						|
 | 
						|
            return ("JSNativeWrapper { op: Some(%(native)s), info: %(info)s }"
 | 
						|
                    % {"info": jitinfo,
 | 
						|
                       "native": accessor})
 | 
						|
 | 
						|
        def specData(attr):
 | 
						|
            return (str_to_const_array(attr.identifier.name), flags(attr), getter(attr),
 | 
						|
                    setter(attr))
 | 
						|
 | 
						|
        return self.generatePrefableArray(
 | 
						|
            array, name,
 | 
						|
            '    JSPropertySpec {\n'
 | 
						|
            '        name: %s as *const u8 as *const libc::c_char,\n'
 | 
						|
            '        flags: ((%s) & 0xFF) as u8,\n'
 | 
						|
            '        getter: %s,\n'
 | 
						|
            '        setter: %s\n'
 | 
						|
            '    }',
 | 
						|
            '    JSPropertySpec {\n'
 | 
						|
            '        name: 0 as *const libc::c_char,\n'
 | 
						|
            '        flags: 0,\n'
 | 
						|
            '        getter: JSNativeWrapper { op: None, info: 0 as *const JSJitInfo },\n'
 | 
						|
            '        setter: JSNativeWrapper { op: None, info: 0 as *const JSJitInfo }\n'
 | 
						|
            '    }',
 | 
						|
            'JSPropertySpec',
 | 
						|
            specData)
 | 
						|
 | 
						|
 | 
						|
class ConstDefiner(PropertyDefiner):
 | 
						|
    """
 | 
						|
    A class for definining constants on the interface object
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor, name):
 | 
						|
        PropertyDefiner.__init__(self, descriptor, name)
 | 
						|
        self.name = name
 | 
						|
        self.regular = [m for m in descriptor.interface.members if m.isConst()]
 | 
						|
 | 
						|
    def generateArray(self, array, name):
 | 
						|
        if len(array) == 0:
 | 
						|
            return ""
 | 
						|
 | 
						|
        def specData(const):
 | 
						|
            return (str_to_const_array(const.identifier.name),
 | 
						|
                    convertConstIDLValueToJSVal(const.value))
 | 
						|
 | 
						|
        return self.generatePrefableArray(
 | 
						|
            array, name,
 | 
						|
            '    ConstantSpec { name: %s, value: %s }',
 | 
						|
            None,
 | 
						|
            'ConstantSpec',
 | 
						|
            specData)
 | 
						|
 | 
						|
# We'll want to insert the indent at the beginnings of lines, but we
 | 
						|
# don't want to indent empty lines.  So only indent lines that have a
 | 
						|
# non-newline character on them.
 | 
						|
lineStartDetector = re.compile("^(?=[^\n])", re.MULTILINE)
 | 
						|
 | 
						|
 | 
						|
class CGIndenter(CGThing):
 | 
						|
    """
 | 
						|
    A class that takes another CGThing and generates code that indents that
 | 
						|
    CGThing by some number of spaces.  The default indent is two spaces.
 | 
						|
    """
 | 
						|
    def __init__(self, child, indentLevel=4):
 | 
						|
        CGThing.__init__(self)
 | 
						|
        self.child = child
 | 
						|
        self.indent = " " * indentLevel
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        defn = self.child.define()
 | 
						|
        if defn != "":
 | 
						|
            return re.sub(lineStartDetector, self.indent, defn)
 | 
						|
        else:
 | 
						|
            return defn
 | 
						|
 | 
						|
 | 
						|
class CGWrapper(CGThing):
 | 
						|
    """
 | 
						|
    Generic CGThing that wraps other CGThings with pre and post text.
 | 
						|
    """
 | 
						|
    def __init__(self, child, pre="", post="", reindent=False):
 | 
						|
        CGThing.__init__(self)
 | 
						|
        self.child = child
 | 
						|
        self.pre = pre
 | 
						|
        self.post = post
 | 
						|
        self.reindent = reindent
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        defn = self.child.define()
 | 
						|
        if self.reindent:
 | 
						|
            # We don't use lineStartDetector because we don't want to
 | 
						|
            # insert whitespace at the beginning of our _first_ line.
 | 
						|
            defn = stripTrailingWhitespace(
 | 
						|
                defn.replace("\n", "\n" + (" " * len(self.pre))))
 | 
						|
        return self.pre + defn + self.post
 | 
						|
 | 
						|
 | 
						|
class CGImports(CGWrapper):
 | 
						|
    """
 | 
						|
    Generates the appropriate import/use statements.
 | 
						|
    """
 | 
						|
    def __init__(self, child, descriptors, callbacks, imports, ignored_warnings=None):
 | 
						|
        """
 | 
						|
        Adds a set of imports.
 | 
						|
        """
 | 
						|
        if ignored_warnings is None:
 | 
						|
            ignored_warnings = [
 | 
						|
                'non_camel_case_types',
 | 
						|
                'non_upper_case_globals',
 | 
						|
                'unused_imports',
 | 
						|
                'unused_variables',
 | 
						|
                'unused_assignments',
 | 
						|
            ]
 | 
						|
 | 
						|
        def componentTypes(type):
 | 
						|
            if type.nullable():
 | 
						|
                type = type.unroll()
 | 
						|
            if type.isUnion():
 | 
						|
                return type.flatMemberTypes
 | 
						|
            return [type]
 | 
						|
 | 
						|
        def isImportable(type):
 | 
						|
            if not type.isType():
 | 
						|
                assert type.isInterface()
 | 
						|
                return not type.isCallback()
 | 
						|
            return type.isNonCallbackInterface() and not type.builtin
 | 
						|
 | 
						|
        def relatedTypesForSignatures(method):
 | 
						|
            types = []
 | 
						|
            for (returnType, arguments) in method.signatures():
 | 
						|
                types += componentTypes(returnType)
 | 
						|
                for arg in arguments:
 | 
						|
                    types += componentTypes(arg.type)
 | 
						|
            return types
 | 
						|
 | 
						|
        def getIdentifier(t):
 | 
						|
            if t.isType():
 | 
						|
                return t.inner.identifier
 | 
						|
            assert t.isInterface()
 | 
						|
            return t.identifier
 | 
						|
 | 
						|
        types = []
 | 
						|
        for d in descriptors:
 | 
						|
            types += [d.interface]
 | 
						|
 | 
						|
            members = d.interface.members + d.interface.namedConstructors
 | 
						|
            constructor = d.interface.ctor()
 | 
						|
            if constructor:
 | 
						|
                members += [constructor]
 | 
						|
 | 
						|
            if d.proxy:
 | 
						|
                members += [o for o in d.operations.values() if o]
 | 
						|
 | 
						|
            for m in members:
 | 
						|
                if m.isMethod():
 | 
						|
                    types += relatedTypesForSignatures(m)
 | 
						|
                elif m.isAttr():
 | 
						|
                    types += componentTypes(m.type)
 | 
						|
 | 
						|
        for c in callbacks:
 | 
						|
            types += relatedTypesForSignatures(c)
 | 
						|
 | 
						|
        imports += ['dom::types::%s' % getIdentifier(t).name for t in types if isImportable(t)]
 | 
						|
 | 
						|
        statements = []
 | 
						|
        if len(ignored_warnings) > 0:
 | 
						|
            statements.append('#![allow(%s)]' % ','.join(ignored_warnings))
 | 
						|
        statements.extend('use %s;' % i for i in sorted(set(imports)))
 | 
						|
 | 
						|
        CGWrapper.__init__(self, child,
 | 
						|
                           pre='\n'.join(statements) + '\n\n')
 | 
						|
 | 
						|
 | 
						|
class CGIfWrapper(CGWrapper):
 | 
						|
    def __init__(self, child, condition):
 | 
						|
        pre = CGWrapper(CGGeneric(condition), pre="if ", post=" {\n",
 | 
						|
                        reindent=True)
 | 
						|
        CGWrapper.__init__(self, CGIndenter(child), pre=pre.define(),
 | 
						|
                           post="\n}")
 | 
						|
 | 
						|
 | 
						|
class CGTemplatedType(CGWrapper):
 | 
						|
    def __init__(self, templateName, child):
 | 
						|
        CGWrapper.__init__(self, child, pre=templateName + "<", post=">")
 | 
						|
 | 
						|
 | 
						|
class CGNamespace(CGWrapper):
 | 
						|
    def __init__(self, namespace, child, public=False):
 | 
						|
        pre = "%smod %s {\n" % ("pub " if public else "", namespace)
 | 
						|
        post = "} // mod %s" % namespace
 | 
						|
        CGWrapper.__init__(self, child, pre=pre, post=post)
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def build(namespaces, child, public=False):
 | 
						|
        """
 | 
						|
        Static helper method to build multiple wrapped namespaces.
 | 
						|
        """
 | 
						|
        if not namespaces:
 | 
						|
            return child
 | 
						|
        inner = CGNamespace.build(namespaces[1:], child, public=public)
 | 
						|
        return CGNamespace(namespaces[0], inner, public=public)
 | 
						|
 | 
						|
 | 
						|
def DOMClassTypeId(desc):
 | 
						|
    protochain = desc.prototypeChain
 | 
						|
    inner = ""
 | 
						|
    if desc.hasDescendants():
 | 
						|
        if desc.interface.getExtendedAttribute("Abstract"):
 | 
						|
            return "::dom::bindings::codegen::InheritTypes::TopTypeId::Abstract"
 | 
						|
        name = desc.interface.identifier.name
 | 
						|
        inner = "(::dom::bindings::codegen::InheritTypes::%sTypeId::%s)" % (name, name)
 | 
						|
    elif len(protochain) == 1:
 | 
						|
        return "::dom::bindings::codegen::InheritTypes::TopTypeId::Alone"
 | 
						|
    reversed_protochain = list(reversed(protochain))
 | 
						|
    for (child, parent) in zip(reversed_protochain, reversed_protochain[1:]):
 | 
						|
        inner = "(::dom::bindings::codegen::InheritTypes::%sTypeId::%s%s)" % (parent, child, inner)
 | 
						|
    return "::dom::bindings::codegen::InheritTypes::TopTypeId::%s%s" % (protochain[0], inner)
 | 
						|
 | 
						|
 | 
						|
def DOMClass(descriptor):
 | 
						|
        protoList = ['PrototypeList::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(['PrototypeList::ID::Count'] * (descriptor.config.maxProtoChainLength - len(protoList)))
 | 
						|
        prototypeChainString = ', '.join(protoList)
 | 
						|
        heapSizeOf = 'heap_size_of_raw_self_and_children::<%s>' % descriptor.interface.identifier.name
 | 
						|
        return """\
 | 
						|
DOMClass {
 | 
						|
    interface_chain: [ %s ],
 | 
						|
    native_hooks: &sNativePropertyHooks,
 | 
						|
    type_id: %s,
 | 
						|
    heap_size_of: %s as unsafe fn(_) -> _,
 | 
						|
}""" % (prototypeChainString, DOMClassTypeId(descriptor), heapSizeOf)
 | 
						|
 | 
						|
 | 
						|
class CGDOMJSClass(CGThing):
 | 
						|
    """
 | 
						|
    Generate a DOMJSClass for a given descriptor
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        CGThing.__init__(self)
 | 
						|
        self.descriptor = descriptor
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        traceHook = 'Some(%s)' % TRACE_HOOK_NAME
 | 
						|
        if self.descriptor.isGlobal():
 | 
						|
            traceHook = "Some(js::jsapi::JS_GlobalObjectTraceHook)"
 | 
						|
            flags = "JSCLASS_IS_GLOBAL | JSCLASS_DOM_GLOBAL"
 | 
						|
            slots = "JSCLASS_GLOBAL_SLOT_COUNT + 1"
 | 
						|
        else:
 | 
						|
            flags = "0"
 | 
						|
            slots = "1"
 | 
						|
        return """\
 | 
						|
static Class: DOMJSClass = DOMJSClass {
 | 
						|
    base: js::jsapi::Class {
 | 
						|
        name: %s as *const u8 as *const libc::c_char,
 | 
						|
        flags: JSCLASS_IS_DOMJSCLASS | JSCLASS_IMPLEMENTS_BARRIERS | %s |
 | 
						|
               (((%s) & JSCLASS_RESERVED_SLOTS_MASK) <<
 | 
						|
                   JSCLASS_RESERVED_SLOTS_SHIFT), //JSCLASS_HAS_RESERVED_SLOTS(%s),
 | 
						|
        addProperty: None,
 | 
						|
        delProperty: None,
 | 
						|
        getProperty: None,
 | 
						|
        setProperty: None,
 | 
						|
        enumerate: None,
 | 
						|
        resolve: None,
 | 
						|
        convert: None,
 | 
						|
        finalize: Some(%s),
 | 
						|
        call: None,
 | 
						|
        hasInstance: None,
 | 
						|
        construct: None,
 | 
						|
        trace: %s,
 | 
						|
 | 
						|
        spec: js::jsapi::ClassSpec {
 | 
						|
            createConstructor: None,
 | 
						|
            createPrototype: None,
 | 
						|
            constructorFunctions: 0 as *const js::jsapi::JSFunctionSpec,
 | 
						|
            constructorProperties: 0 as *const js::jsapi::JSPropertySpec,
 | 
						|
            prototypeFunctions: 0 as *const js::jsapi::JSFunctionSpec,
 | 
						|
            prototypeProperties: 0 as *const js::jsapi::JSPropertySpec,
 | 
						|
            finishInit: None,
 | 
						|
            flags: 0,
 | 
						|
        },
 | 
						|
 | 
						|
        ext: js::jsapi::ClassExtension {
 | 
						|
            outerObject: %s,
 | 
						|
            innerObject: None,
 | 
						|
            isWrappedNative: false,
 | 
						|
            weakmapKeyDelegateOp: None,
 | 
						|
            objectMovedOp: None,
 | 
						|
        },
 | 
						|
 | 
						|
        ops: js::jsapi::ObjectOps {
 | 
						|
            lookupProperty: None,
 | 
						|
            defineProperty: None,
 | 
						|
            hasProperty: None,
 | 
						|
            getProperty: None,
 | 
						|
            setProperty: None,
 | 
						|
            getOwnPropertyDescriptor: None,
 | 
						|
            deleteProperty: None,
 | 
						|
            watch: None,
 | 
						|
            unwatch: None,
 | 
						|
            getElements: None,
 | 
						|
            enumerate: None,
 | 
						|
            thisObject: %s,
 | 
						|
        },
 | 
						|
    },
 | 
						|
    dom_class: %s
 | 
						|
};""" % (str_to_const_array(self.descriptor.interface.identifier.name),
 | 
						|
         flags, slots, slots,
 | 
						|
         FINALIZE_HOOK_NAME, traceHook,
 | 
						|
         self.descriptor.outerObjectHook,
 | 
						|
         self.descriptor.outerObjectHook,
 | 
						|
         CGGeneric(DOMClass(self.descriptor)).define())
 | 
						|
 | 
						|
 | 
						|
def str_to_const_array(s):
 | 
						|
    return "b\"%s\\0\"" % s
 | 
						|
 | 
						|
 | 
						|
class CGPrototypeJSClass(CGThing):
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        CGThing.__init__(self)
 | 
						|
        self.descriptor = descriptor
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        return """\
 | 
						|
static PrototypeClass: JSClass = JSClass {
 | 
						|
    name: %s as *const u8 as *const libc::c_char,
 | 
						|
    flags: (1 & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT, //JSCLASS_HAS_RESERVED_SLOTS(1)
 | 
						|
    addProperty: None,
 | 
						|
    delProperty: None,
 | 
						|
    getProperty: None,
 | 
						|
    setProperty: None,
 | 
						|
    enumerate: None,
 | 
						|
    resolve: None,
 | 
						|
    convert: None,
 | 
						|
    finalize: None,
 | 
						|
    call: None,
 | 
						|
    hasInstance: None,
 | 
						|
    construct: None,
 | 
						|
    trace: None,
 | 
						|
    reserved: [0 as *mut libc::c_void; 25]
 | 
						|
};
 | 
						|
""" % str_to_const_array(self.descriptor.interface.identifier.name + "Prototype")
 | 
						|
 | 
						|
 | 
						|
class CGInterfaceObjectJSClass(CGThing):
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        CGThing.__init__(self)
 | 
						|
        self.descriptor = descriptor
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        if True:
 | 
						|
            return ""
 | 
						|
        ctorname = "0 as *const u8" if not self.descriptor.interface.ctor() else CONSTRUCT_HOOK_NAME
 | 
						|
        hasinstance = HASINSTANCE_HOOK_NAME
 | 
						|
        return """\
 | 
						|
const InterfaceObjectClass: JSClass = {
 | 
						|
    %s, 0,
 | 
						|
    JS_PropertyStub,
 | 
						|
    JS_PropertyStub,
 | 
						|
    JS_PropertyStub,
 | 
						|
    JS_StrictPropertyStub,
 | 
						|
    JS_EnumerateStub,
 | 
						|
    JS_ResolveStub,
 | 
						|
    JS_ConvertStub,
 | 
						|
    0 as *const u8,
 | 
						|
    0 as *const u8,
 | 
						|
    %s,
 | 
						|
    %s,
 | 
						|
    %s,
 | 
						|
    0 as *const u8,
 | 
						|
    JSCLASS_NO_INTERNAL_MEMBERS
 | 
						|
};
 | 
						|
""" % (str_to_const_array("Function"), ctorname, hasinstance, ctorname)
 | 
						|
 | 
						|
 | 
						|
class CGList(CGThing):
 | 
						|
    """
 | 
						|
    Generate code for a list of GCThings.  Just concatenates them together, with
 | 
						|
    an optional joiner string.  "\n" is a common joiner.
 | 
						|
    """
 | 
						|
    def __init__(self, children, joiner=""):
 | 
						|
        CGThing.__init__(self)
 | 
						|
        self.children = children
 | 
						|
        self.joiner = joiner
 | 
						|
 | 
						|
    def append(self, child):
 | 
						|
        self.children.append(child)
 | 
						|
 | 
						|
    def prepend(self, child):
 | 
						|
        self.children.insert(0, child)
 | 
						|
 | 
						|
    def join(self, generator):
 | 
						|
        return self.joiner.join(filter(lambda s: len(s) > 0, (child for child in generator)))
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        return self.join(child.define() for child in self.children if child is not None)
 | 
						|
 | 
						|
 | 
						|
class CGIfElseWrapper(CGList):
 | 
						|
    def __init__(self, condition, ifTrue, ifFalse):
 | 
						|
        kids = [CGIfWrapper(ifTrue, condition),
 | 
						|
                CGWrapper(CGIndenter(ifFalse), pre=" else {\n", post="\n}")]
 | 
						|
        CGList.__init__(self, kids)
 | 
						|
 | 
						|
 | 
						|
class CGGeneric(CGThing):
 | 
						|
    """
 | 
						|
    A class that spits out a fixed string into the codegen.  Can spit out a
 | 
						|
    separate string for the declaration too.
 | 
						|
    """
 | 
						|
    def __init__(self, text):
 | 
						|
        self.text = text
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        return self.text
 | 
						|
 | 
						|
 | 
						|
class CGCallbackTempRoot(CGGeneric):
 | 
						|
    def __init__(self, name):
 | 
						|
        CGGeneric.__init__(self, "%s::new(${val}.get().to_object())" % name)
 | 
						|
 | 
						|
 | 
						|
def getAllTypes(descriptors, dictionaries, callbacks):
 | 
						|
    """
 | 
						|
    Generate all the types we're dealing with.  For each type, a tuple
 | 
						|
    containing type, descriptor, dictionary is yielded.  The
 | 
						|
    descriptor and dictionary can be None if the type does not come
 | 
						|
    from a descriptor or dictionary; they will never both be non-None.
 | 
						|
    """
 | 
						|
    for d in descriptors:
 | 
						|
        for t in getTypesFromDescriptor(d):
 | 
						|
            yield (t, d, None)
 | 
						|
    for dictionary in dictionaries:
 | 
						|
        for t in getTypesFromDictionary(dictionary):
 | 
						|
            yield (t, None, dictionary)
 | 
						|
    for callback in callbacks:
 | 
						|
        for t in getTypesFromCallback(callback):
 | 
						|
            yield (t, None, None)
 | 
						|
 | 
						|
 | 
						|
def SortedTuples(l):
 | 
						|
    """
 | 
						|
    Sort a list of tuples based on the first item in the tuple
 | 
						|
    """
 | 
						|
    return sorted(l, key=operator.itemgetter(0))
 | 
						|
 | 
						|
 | 
						|
def SortedDictValues(d):
 | 
						|
    """
 | 
						|
    Returns a list of values from the dict sorted by key.
 | 
						|
    """
 | 
						|
    # Create a list of tuples containing key and value, sorted on key.
 | 
						|
    d = SortedTuples(d.items())
 | 
						|
    # We're only interested in the values.
 | 
						|
    return (i[1] for i in d)
 | 
						|
 | 
						|
 | 
						|
def UnionTypes(descriptors, dictionaries, callbacks, config):
 | 
						|
    """
 | 
						|
    Returns a CGList containing CGUnionStructs for every union.
 | 
						|
    """
 | 
						|
 | 
						|
    imports = [
 | 
						|
        'dom::bindings::codegen::PrototypeList',
 | 
						|
        'dom::bindings::conversions::FromJSValConvertible',
 | 
						|
        'dom::bindings::conversions::ToJSValConvertible',
 | 
						|
        'dom::bindings::conversions::ConversionBehavior',
 | 
						|
        'dom::bindings::conversions::native_from_handlevalue',
 | 
						|
        'dom::bindings::conversions::StringificationBehavior',
 | 
						|
        'dom::bindings::error::throw_not_in_union',
 | 
						|
        'dom::bindings::js::Root',
 | 
						|
        'dom::bindings::str::USVString',
 | 
						|
        'dom::types::*',
 | 
						|
        'js::jsapi::JSContext',
 | 
						|
        'js::jsapi::{HandleValue, MutableHandleValue}',
 | 
						|
        'js::jsval::JSVal',
 | 
						|
        'util::str::DOMString',
 | 
						|
    ]
 | 
						|
 | 
						|
    # Now find all the things we'll need as arguments and return values because
 | 
						|
    # we need to wrap or unwrap them.
 | 
						|
    unionStructs = dict()
 | 
						|
    for (t, descriptor, dictionary) in getAllTypes(descriptors, dictionaries, callbacks):
 | 
						|
        assert not descriptor or not dictionary
 | 
						|
        t = t.unroll()
 | 
						|
        if not t.isUnion():
 | 
						|
            continue
 | 
						|
        name = str(t)
 | 
						|
        if name not in unionStructs:
 | 
						|
            provider = descriptor or config.getDescriptorProvider()
 | 
						|
            unionStructs[name] = CGList([
 | 
						|
                CGUnionStruct(t, provider),
 | 
						|
                CGUnionConversionStruct(t, provider)
 | 
						|
            ])
 | 
						|
 | 
						|
    return CGImports(CGList(SortedDictValues(unionStructs), "\n\n"), [], [], imports, ignored_warnings=[])
 | 
						|
 | 
						|
 | 
						|
class Argument():
 | 
						|
    """
 | 
						|
    A class for outputting the type and name of an argument
 | 
						|
    """
 | 
						|
    def __init__(self, argType, name, default=None, mutable=False):
 | 
						|
        self.argType = argType
 | 
						|
        self.name = name
 | 
						|
        self.default = default
 | 
						|
        self.mutable = mutable
 | 
						|
 | 
						|
    def declare(self):
 | 
						|
        string = ('mut ' if self.mutable else '') + self.name + ((': ' + self.argType) if self.argType else '')
 | 
						|
        # XXXjdm Support default arguments somehow :/
 | 
						|
        # if self.default is not None:
 | 
						|
        #     string += " = " + self.default
 | 
						|
        return string
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        return self.argType + ' ' + self.name
 | 
						|
 | 
						|
 | 
						|
class CGAbstractMethod(CGThing):
 | 
						|
    """
 | 
						|
    An abstract class for generating code for a method.  Subclasses
 | 
						|
    should override definition_body to create the actual code.
 | 
						|
 | 
						|
    descriptor is the descriptor for the interface the method is associated with
 | 
						|
 | 
						|
    name is the name of the method as a string
 | 
						|
 | 
						|
    returnType is the IDLType of the return value
 | 
						|
 | 
						|
    args is a list of Argument objects
 | 
						|
 | 
						|
    inline should be True to generate an inline method, whose body is
 | 
						|
    part of the declaration.
 | 
						|
 | 
						|
    alwaysInline should be True to generate an inline method annotated with
 | 
						|
    MOZ_ALWAYS_INLINE.
 | 
						|
 | 
						|
    If templateArgs is not None it should be a list of strings containing
 | 
						|
    template arguments, and the function will be templatized using those
 | 
						|
    arguments.
 | 
						|
 | 
						|
    docs is None or documentation for the method in a string.
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor, name, returnType, args, inline=False,
 | 
						|
                 alwaysInline=False, extern=False, pub=False, templateArgs=None,
 | 
						|
                 unsafe=False, docs=None):
 | 
						|
        CGThing.__init__(self)
 | 
						|
        self.descriptor = descriptor
 | 
						|
        self.name = name
 | 
						|
        self.returnType = returnType
 | 
						|
        self.args = args
 | 
						|
        self.alwaysInline = alwaysInline
 | 
						|
        self.extern = extern
 | 
						|
        self.templateArgs = templateArgs
 | 
						|
        self.pub = pub
 | 
						|
        self.unsafe = unsafe
 | 
						|
        self.docs = docs
 | 
						|
 | 
						|
    def _argstring(self):
 | 
						|
        return ', '.join([a.declare() for a in self.args])
 | 
						|
 | 
						|
    def _template(self):
 | 
						|
        if self.templateArgs is None:
 | 
						|
            return ''
 | 
						|
        return '<%s>\n' % ', '.join(self.templateArgs)
 | 
						|
 | 
						|
    def _docs(self):
 | 
						|
        if self.docs is None:
 | 
						|
            return ''
 | 
						|
 | 
						|
        lines = self.docs.splitlines()
 | 
						|
        return ''.join('/// %s\n' % line for line in lines)
 | 
						|
 | 
						|
    def _decorators(self):
 | 
						|
        decorators = []
 | 
						|
        if self.alwaysInline:
 | 
						|
            decorators.append('#[inline]')
 | 
						|
 | 
						|
        if self.extern:
 | 
						|
            decorators.append('unsafe')
 | 
						|
            decorators.append('extern')
 | 
						|
 | 
						|
        if self.pub:
 | 
						|
            decorators.append('pub')
 | 
						|
 | 
						|
        if not decorators:
 | 
						|
            return ''
 | 
						|
        return ' '.join(decorators) + ' '
 | 
						|
 | 
						|
    def _returnType(self):
 | 
						|
        return (" -> %s" % self.returnType) if self.returnType != "void" else ""
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        body = self.definition_body()
 | 
						|
 | 
						|
        # Method will already be marked `unsafe` if `self.extern == True`
 | 
						|
        if self.unsafe and not self.extern:
 | 
						|
            body = CGWrapper(CGIndenter(body), pre="unsafe {\n", post="\n}")
 | 
						|
 | 
						|
        return CGWrapper(CGIndenter(body),
 | 
						|
                         pre=self.definition_prologue(),
 | 
						|
                         post=self.definition_epilogue()).define()
 | 
						|
 | 
						|
    def definition_prologue(self):
 | 
						|
        return "%s%sfn %s%s(%s)%s {\n" % (self._docs(), self._decorators(),
 | 
						|
                                          self.name, self._template(),
 | 
						|
                                          self._argstring(), self._returnType())
 | 
						|
 | 
						|
    def definition_epilogue(self):
 | 
						|
        return "\n}\n"
 | 
						|
 | 
						|
    def definition_body(self):
 | 
						|
        raise NotImplementedError  # Override me!
 | 
						|
 | 
						|
 | 
						|
def CreateBindingJSObject(descriptor, parent=None):
 | 
						|
    create = "let raw = Box::into_raw(object);\nlet _rt = RootedTraceable::new(&*raw);\n"
 | 
						|
    if descriptor.proxy:
 | 
						|
        assert not descriptor.isGlobal()
 | 
						|
        create += """
 | 
						|
let handler = RegisterBindings::proxy_handlers[PrototypeList::Proxies::%s as usize];
 | 
						|
let private = RootedValue::new(cx, PrivateValue(raw as *const libc::c_void));
 | 
						|
let obj = {
 | 
						|
    let _ac = JSAutoCompartment::new(cx, proto.ptr);
 | 
						|
    NewProxyObject(cx, handler,
 | 
						|
                   private.handle(),
 | 
						|
                   proto.ptr, %s.get(),
 | 
						|
                   ptr::null_mut(), ptr::null_mut())
 | 
						|
};
 | 
						|
assert!(!obj.is_null());
 | 
						|
let obj = RootedObject::new(cx, obj);\
 | 
						|
""" % (descriptor.name, parent)
 | 
						|
    elif descriptor.isGlobal():
 | 
						|
        create += ("let obj = RootedObject::new(\n"
 | 
						|
                   "    cx,\n"
 | 
						|
                   "    create_dom_global(\n"
 | 
						|
                   "        cx,\n"
 | 
						|
                   "        &Class.base as *const js::jsapi::Class as *const JSClass,\n"
 | 
						|
                   "        raw as *const libc::c_void,\n"
 | 
						|
                   "        Some(%s))\n"
 | 
						|
                   ");\n"
 | 
						|
                   "assert!(!obj.ptr.is_null());" % TRACE_HOOK_NAME)
 | 
						|
    else:
 | 
						|
        create += ("let obj = {\n"
 | 
						|
                   "    let _ac = JSAutoCompartment::new(cx, proto.ptr);\n"
 | 
						|
                   "    JS_NewObjectWithGivenProto(\n"
 | 
						|
                   "        cx, &Class.base as *const js::jsapi::Class as *const JSClass, proto.handle())\n"
 | 
						|
                   "};\n"
 | 
						|
                   "let obj = RootedObject::new(cx, obj);\n"
 | 
						|
                   "assert!(!obj.ptr.is_null());\n"
 | 
						|
                   "\n"
 | 
						|
                   "JS_SetReservedSlot(obj.ptr, DOM_OBJECT_SLOT,\n"
 | 
						|
                   "                   PrivateValue(raw as *const libc::c_void));")
 | 
						|
    return create
 | 
						|
 | 
						|
 | 
						|
class CGWrapMethod(CGAbstractMethod):
 | 
						|
    """
 | 
						|
    Class that generates the FooBinding::Wrap function for non-callback
 | 
						|
    interfaces.
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        assert not descriptor.interface.isCallback()
 | 
						|
        if not descriptor.isGlobal():
 | 
						|
            args = [Argument('*mut JSContext', 'cx'), Argument('GlobalRef', 'scope'),
 | 
						|
                    Argument("Box<%s>" % descriptor.concreteType, 'object')]
 | 
						|
        else:
 | 
						|
            args = [Argument('*mut JSContext', 'cx'),
 | 
						|
                    Argument("Box<%s>" % descriptor.concreteType, 'object')]
 | 
						|
        retval = 'Root<%s>' % descriptor.concreteType
 | 
						|
        CGAbstractMethod.__init__(self, descriptor, 'Wrap', retval, args,
 | 
						|
                                  pub=True, unsafe=True)
 | 
						|
 | 
						|
    def definition_body(self):
 | 
						|
        if not self.descriptor.isGlobal():
 | 
						|
            return CGGeneric("""\
 | 
						|
let _ar = JSAutoRequest::new(cx);
 | 
						|
let scope = scope.reflector().get_jsobject();
 | 
						|
assert!(!scope.get().is_null());
 | 
						|
assert!(((*JS_GetClass(scope.get())).flags & JSCLASS_IS_GLOBAL) != 0);
 | 
						|
 | 
						|
let mut proto = RootedObject::new(cx, ptr::null_mut());
 | 
						|
{
 | 
						|
    let _ac = JSAutoCompartment::new(cx, scope.get());
 | 
						|
    GetProtoObject(cx, scope, scope, proto.handle_mut())
 | 
						|
}
 | 
						|
assert!(!proto.ptr.is_null());
 | 
						|
 | 
						|
%s
 | 
						|
 | 
						|
(*raw).init_reflector(obj.ptr);
 | 
						|
 | 
						|
Root::from_ref(&*raw)""" % CreateBindingJSObject(self.descriptor, "scope"))
 | 
						|
        else:
 | 
						|
            return CGGeneric("""\
 | 
						|
let _ar = JSAutoRequest::new(cx);
 | 
						|
%s
 | 
						|
 | 
						|
let _ac = JSAutoCompartment::new(cx, obj.ptr);
 | 
						|
let mut proto = RootedObject::new(cx, ptr::null_mut());
 | 
						|
GetProtoObject(cx, obj.handle(), obj.handle(), proto.handle_mut());
 | 
						|
JS_SetPrototype(cx, obj.handle(), proto.handle());
 | 
						|
 | 
						|
(*raw).init_reflector(obj.ptr);
 | 
						|
 | 
						|
let ret = Root::from_ref(&*raw);
 | 
						|
 | 
						|
RegisterBindings::Register(cx, obj.handle());
 | 
						|
 | 
						|
ret""" % CreateBindingJSObject(self.descriptor))
 | 
						|
 | 
						|
 | 
						|
class CGIDLInterface(CGThing):
 | 
						|
    """
 | 
						|
    Class for codegen of an implementation of the IDLInterface trait.
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        CGThing.__init__(self)
 | 
						|
        self.descriptor = descriptor
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        interface = self.descriptor.interface
 | 
						|
        name = self.descriptor.name
 | 
						|
        if (interface.getUserData("hasConcreteDescendant", False) or
 | 
						|
                interface.getUserData("hasProxyDescendant", False)):
 | 
						|
            depth = len(self.descriptor.prototypeChain)
 | 
						|
            check = "class.interface_chain[%s] == PrototypeList::ID::%s" % (depth - 1, name)
 | 
						|
        elif self.descriptor.proxy:
 | 
						|
            check = "class as *const _ == &Class as *const _"
 | 
						|
        else:
 | 
						|
            check = "class as *const _ == &Class.dom_class as *const _"
 | 
						|
        return """\
 | 
						|
impl IDLInterface for %(name)s {
 | 
						|
    #[inline]
 | 
						|
    fn derives(class: &'static DOMClass) -> bool {
 | 
						|
        %(check)s
 | 
						|
    }
 | 
						|
}
 | 
						|
""" % {'check': check, 'name': name}
 | 
						|
 | 
						|
 | 
						|
class CGAbstractExternMethod(CGAbstractMethod):
 | 
						|
    """
 | 
						|
    Abstract base class for codegen of implementation-only (no
 | 
						|
    declaration) static methods.
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor, name, returnType, args):
 | 
						|
        CGAbstractMethod.__init__(self, descriptor, name, returnType, args,
 | 
						|
                                  inline=False, extern=True)
 | 
						|
 | 
						|
 | 
						|
class PropertyArrays():
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        self.static_methods = MethodDefiner(descriptor, "StaticMethods",
 | 
						|
                                            static=True)
 | 
						|
        self.static_attrs = AttrDefiner(descriptor, "StaticAttributes",
 | 
						|
                                        static=True)
 | 
						|
        self.methods = MethodDefiner(descriptor, "Methods", static=False)
 | 
						|
        self.attrs = AttrDefiner(descriptor, "Attributes", static=False)
 | 
						|
        self.consts = ConstDefiner(descriptor, "Constants")
 | 
						|
        pass
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def arrayNames():
 | 
						|
        return ["static_methods", "static_attrs", "methods", "attrs", "consts"]
 | 
						|
 | 
						|
    def variableNames(self):
 | 
						|
        names = {}
 | 
						|
        for array in self.arrayNames():
 | 
						|
            names[array] = getattr(self, array).variableName()
 | 
						|
        return names
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        define = ""
 | 
						|
        for array in self.arrayNames():
 | 
						|
            define += str(getattr(self, array))
 | 
						|
        return define
 | 
						|
 | 
						|
 | 
						|
class CGNativeProperties(CGThing):
 | 
						|
    def __init__(self, descriptor, properties):
 | 
						|
        CGThing.__init__(self)
 | 
						|
        self.properties = properties
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        def getField(array):
 | 
						|
            propertyArray = getattr(self.properties, array)
 | 
						|
            if propertyArray.length() > 0:
 | 
						|
                value = "Some(%s)" % propertyArray.variableName()
 | 
						|
            else:
 | 
						|
                value = "None"
 | 
						|
 | 
						|
            return CGGeneric(string.Template('${name}: ${value},').substitute({
 | 
						|
                'name': array,
 | 
						|
                'value': value,
 | 
						|
            }))
 | 
						|
 | 
						|
        nativeProps = CGList([getField(array) for array in self.properties.arrayNames()], '\n')
 | 
						|
        return CGWrapper(CGIndenter(nativeProps),
 | 
						|
                         pre="static sNativeProperties: NativeProperties = NativeProperties {\n",
 | 
						|
                         post="\n};\n").define()
 | 
						|
 | 
						|
 | 
						|
class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
 | 
						|
    """
 | 
						|
    Generate the CreateInterfaceObjects method for an interface descriptor.
 | 
						|
 | 
						|
    properties should be a PropertyArrays instance.
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor, properties):
 | 
						|
        args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'global'),
 | 
						|
                Argument('HandleObject', 'receiver'),
 | 
						|
                Argument('MutableHandleObject', 'rval')]
 | 
						|
        CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'void', args)
 | 
						|
        self.properties = properties
 | 
						|
 | 
						|
    def definition_body(self):
 | 
						|
        protoChain = self.descriptor.prototypeChain
 | 
						|
        if len(protoChain) == 1:
 | 
						|
            self.unsafe = True
 | 
						|
            getParentProto = "parent_proto.ptr = JS_GetObjectPrototype(cx, global)"
 | 
						|
        else:
 | 
						|
            parentProtoName = self.descriptor.prototypeChain[-2]
 | 
						|
            getParentProto = ("%s::GetProtoObject(cx, global, receiver, parent_proto.handle_mut())" %
 | 
						|
                              toBindingNamespace(parentProtoName))
 | 
						|
 | 
						|
        getParentProto = ("let mut parent_proto = RootedObject::new(cx, ptr::null_mut());\n"
 | 
						|
                          "%s;\n"
 | 
						|
                          "assert!(!parent_proto.ptr.is_null());\n") % getParentProto
 | 
						|
 | 
						|
        if self.descriptor.interface.isCallback():
 | 
						|
            protoClass = "None"
 | 
						|
        else:
 | 
						|
            protoClass = "Some(&PrototypeClass)"
 | 
						|
 | 
						|
        if self.descriptor.concrete:
 | 
						|
            if self.descriptor.proxy:
 | 
						|
                domClass = "Some(&Class)"
 | 
						|
            else:
 | 
						|
                domClass = "Some(&Class.dom_class)"
 | 
						|
        else:
 | 
						|
            domClass = "None"
 | 
						|
 | 
						|
        if self.descriptor.interface.hasInterfaceObject():
 | 
						|
            if self.descriptor.interface.ctor():
 | 
						|
                constructHook = CONSTRUCT_HOOK_NAME
 | 
						|
                constructArgs = methodLength(self.descriptor.interface.ctor())
 | 
						|
            else:
 | 
						|
                constructHook = "throwing_constructor"
 | 
						|
                constructArgs = 0
 | 
						|
 | 
						|
            constructor = 'Some((%s as NonNullJSNative, "%s", %d))' % (
 | 
						|
                constructHook, self.descriptor.interface.identifier.name,
 | 
						|
                constructArgs)
 | 
						|
        else:
 | 
						|
            constructor = 'None'
 | 
						|
 | 
						|
        call = """\
 | 
						|
do_create_interface_objects(cx, receiver, parent_proto.handle(),
 | 
						|
                            %s, %s,
 | 
						|
                            &named_constructors,
 | 
						|
                            %s,
 | 
						|
                            &sNativeProperties, rval);""" % (protoClass, constructor, domClass)
 | 
						|
 | 
						|
        createArray = """\
 | 
						|
let named_constructors: [(NonNullJSNative, &'static str, u32); %d] = [
 | 
						|
""" % len(self.descriptor.interface.namedConstructors)
 | 
						|
        for ctor in self.descriptor.interface.namedConstructors:
 | 
						|
            constructHook = CONSTRUCT_HOOK_NAME + "_" + ctor.identifier.name
 | 
						|
            constructArgs = methodLength(ctor)
 | 
						|
            constructor = '(%s as NonNullJSNative, "%s", %d)' % (
 | 
						|
                constructHook, ctor.identifier.name, constructArgs)
 | 
						|
            createArray += constructor
 | 
						|
            createArray += ","
 | 
						|
        createArray += "];"
 | 
						|
 | 
						|
        return CGList([
 | 
						|
            CGGeneric(getParentProto),
 | 
						|
            CGGeneric(createArray),
 | 
						|
            CGGeneric(call % self.properties.variableNames())
 | 
						|
        ], "\n")
 | 
						|
 | 
						|
 | 
						|
class CGGetPerInterfaceObject(CGAbstractMethod):
 | 
						|
    """
 | 
						|
    A method for getting a per-interface object (a prototype object or interface
 | 
						|
    constructor object).
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor, name, idPrefix="", pub=False):
 | 
						|
        args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'global'),
 | 
						|
                Argument('HandleObject', 'receiver'),
 | 
						|
                Argument('MutableHandleObject', 'rval')]
 | 
						|
        CGAbstractMethod.__init__(self, descriptor, name,
 | 
						|
                                  'void', args, pub=pub, unsafe=True)
 | 
						|
        self.id = idPrefix + "ID::" + self.descriptor.name
 | 
						|
 | 
						|
    def definition_body(self):
 | 
						|
        return CGGeneric("""
 | 
						|
 | 
						|
/* global and receiver 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 receiver is the xray
 | 
						|
   wrapper and global is the sandbox's global.
 | 
						|
 */
 | 
						|
 | 
						|
assert!(((*JS_GetClass(global.get())).flags & JSCLASS_DOM_GLOBAL) != 0);
 | 
						|
 | 
						|
/* Check to see whether the interface objects are already installed */
 | 
						|
let proto_or_iface_array = get_proto_or_iface_array(global.get());
 | 
						|
rval.set((*proto_or_iface_array)[%s as usize]);
 | 
						|
if !rval.get().is_null() {
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
CreateInterfaceObjects(cx, global, receiver, rval);
 | 
						|
assert!(!rval.get().is_null());
 | 
						|
(*proto_or_iface_array)[%s as usize] = rval.get();
 | 
						|
if <*mut JSObject>::needs_post_barrier(rval.get()) {
 | 
						|
    <*mut JSObject>::post_barrier((*proto_or_iface_array).as_mut_ptr().offset(%s as isize))
 | 
						|
}
 | 
						|
""" % (self.id, self.id, self.id))
 | 
						|
 | 
						|
 | 
						|
class CGGetProtoObjectMethod(CGGetPerInterfaceObject):
 | 
						|
    """
 | 
						|
    A method for getting the interface prototype object.
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        CGGetPerInterfaceObject.__init__(self, descriptor, "GetProtoObject",
 | 
						|
                                         "PrototypeList::", pub=True)
 | 
						|
 | 
						|
    def definition_body(self):
 | 
						|
        return CGList([
 | 
						|
            CGGeneric("""\
 | 
						|
/* Get the interface prototype object for this class.  This will create the
 | 
						|
   object as needed. */"""),
 | 
						|
            CGGetPerInterfaceObject.definition_body(self),
 | 
						|
        ])
 | 
						|
 | 
						|
 | 
						|
class CGGetConstructorObjectMethod(CGGetPerInterfaceObject):
 | 
						|
    """
 | 
						|
    A method for getting the interface constructor object.
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        CGGetPerInterfaceObject.__init__(self, descriptor, "GetConstructorObject",
 | 
						|
                                         "constructors::")
 | 
						|
 | 
						|
    def definition_body(self):
 | 
						|
        return CGList([
 | 
						|
            CGGeneric("""\
 | 
						|
/* Get the interface object for this class.  This will create the object as
 | 
						|
   needed. */"""),
 | 
						|
            CGGetPerInterfaceObject.definition_body(self),
 | 
						|
        ])
 | 
						|
 | 
						|
 | 
						|
class CGDefineProxyHandler(CGAbstractMethod):
 | 
						|
    """
 | 
						|
    A method to create and cache the proxy trap for a given interface.
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        assert descriptor.proxy
 | 
						|
        CGAbstractMethod.__init__(self, descriptor, 'DefineProxyHandler',
 | 
						|
                                  '*const libc::c_void', [],
 | 
						|
                                  pub=True, unsafe=True)
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        return CGAbstractMethod.define(self)
 | 
						|
 | 
						|
    def definition_body(self):
 | 
						|
        customDefineProperty = 'proxyhandler::define_property'
 | 
						|
        if self.descriptor.operations['IndexedSetter'] or self.descriptor.operations['NamedSetter']:
 | 
						|
            customDefineProperty = 'defineProperty'
 | 
						|
 | 
						|
        customDelete = 'proxyhandler::delete'
 | 
						|
        if self.descriptor.operations['NamedDeleter']:
 | 
						|
            customDelete = 'delete'
 | 
						|
 | 
						|
        body = """\
 | 
						|
let traps = ProxyTraps {
 | 
						|
    enter: None,
 | 
						|
    getOwnPropertyDescriptor: Some(getOwnPropertyDescriptor),
 | 
						|
    defineProperty: Some(%s),
 | 
						|
    ownPropertyKeys: Some(own_property_keys),
 | 
						|
    delete_: Some(%s),
 | 
						|
    enumerate: None,
 | 
						|
    preventExtensions: Some(proxyhandler::prevent_extensions),
 | 
						|
    isExtensible: Some(proxyhandler::is_extensible),
 | 
						|
    has: None,
 | 
						|
    get: Some(get),
 | 
						|
    set: None,
 | 
						|
    call: None,
 | 
						|
    construct: None,
 | 
						|
    getPropertyDescriptor: Some(get_property_descriptor),
 | 
						|
    hasOwn: Some(hasOwn),
 | 
						|
    getOwnEnumerablePropertyKeys: None,
 | 
						|
    nativeCall: None,
 | 
						|
    hasInstance: None,
 | 
						|
    objectClassIs: None,
 | 
						|
    className: Some(className),
 | 
						|
    fun_toString: None,
 | 
						|
    boxedValue_unbox: None,
 | 
						|
    defaultValue: None,
 | 
						|
    trace: Some(%s),
 | 
						|
    finalize: Some(%s),
 | 
						|
    objectMoved: None,
 | 
						|
    isCallable: None,
 | 
						|
    isConstructor: None,
 | 
						|
};
 | 
						|
 | 
						|
CreateProxyHandler(&traps, &Class as *const _ as *const _)\
 | 
						|
""" % (customDefineProperty, customDelete, TRACE_HOOK_NAME, FINALIZE_HOOK_NAME)
 | 
						|
        return CGGeneric(body)
 | 
						|
 | 
						|
 | 
						|
class CGDefineDOMInterfaceMethod(CGAbstractMethod):
 | 
						|
    """
 | 
						|
    A method for resolve hooks to try to lazily define the interface object for
 | 
						|
    a given interface.
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        assert descriptor.interface.hasInterfaceObject()
 | 
						|
        args = [
 | 
						|
            Argument('*mut JSContext', 'cx'),
 | 
						|
            Argument('HandleObject', 'global'),
 | 
						|
        ]
 | 
						|
        CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', 'void', args, pub=True)
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        return CGAbstractMethod.define(self)
 | 
						|
 | 
						|
    def definition_body(self):
 | 
						|
        if self.descriptor.interface.isCallback():
 | 
						|
            code = """\
 | 
						|
let mut obj = RootedObject::new(cx, ptr::null_mut());
 | 
						|
CreateInterfaceObjects(cx, global, global, obj.handle_mut());
 | 
						|
"""
 | 
						|
        else:
 | 
						|
            code = """\
 | 
						|
let mut proto = RootedObject::new(cx, ptr::null_mut());
 | 
						|
GetProtoObject(cx, global, global, proto.handle_mut());
 | 
						|
assert!(!proto.ptr.is_null());
 | 
						|
"""
 | 
						|
        return CGGeneric("assert!(!global.get().is_null());\n" + code)
 | 
						|
 | 
						|
 | 
						|
def needCx(returnType, arguments, considerTypes):
 | 
						|
    return (considerTypes and
 | 
						|
            (typeNeedsCx(returnType, True) or
 | 
						|
             any(typeNeedsCx(a.type) for a in arguments)))
 | 
						|
 | 
						|
 | 
						|
class CGCallGenerator(CGThing):
 | 
						|
    """
 | 
						|
    A class to generate an actual call to a C++ object.  Assumes that the C++
 | 
						|
    object is stored in a variable whose name is given by the |object| argument.
 | 
						|
 | 
						|
    errorResult should be a string for the value to return in case of an
 | 
						|
    exception from the native code, or None if no error reporting is needed.
 | 
						|
    """
 | 
						|
    def __init__(self, errorResult, arguments, argsPre, returnType,
 | 
						|
                 extendedAttributes, descriptorProvider, nativeMethodName,
 | 
						|
                 static, object="this"):
 | 
						|
        CGThing.__init__(self)
 | 
						|
 | 
						|
        assert errorResult is None or isinstance(errorResult, str)
 | 
						|
 | 
						|
        isFallible = errorResult is not None
 | 
						|
 | 
						|
        result = getRetvalDeclarationForType(returnType, descriptorProvider)
 | 
						|
        if isFallible:
 | 
						|
            result = CGWrapper(result, pre="Result<", post=", Error>")
 | 
						|
 | 
						|
        args = CGList([CGGeneric(arg) for arg in argsPre], ", ")
 | 
						|
        for (a, name) in arguments:
 | 
						|
            # XXXjdm Perhaps we should pass all nontrivial types by borrowed pointer
 | 
						|
            if a.type.isDictionary():
 | 
						|
                name = "&" + name
 | 
						|
            args.append(CGGeneric(name))
 | 
						|
 | 
						|
        needsCx = needCx(returnType, (a for (a, _) in arguments), True)
 | 
						|
 | 
						|
        if "cx" not in argsPre and needsCx:
 | 
						|
            args.prepend(CGGeneric("cx"))
 | 
						|
 | 
						|
        # Build up our actual call
 | 
						|
        self.cgRoot = CGList([], "\n")
 | 
						|
 | 
						|
        call = CGGeneric(nativeMethodName)
 | 
						|
        if static:
 | 
						|
            call = CGWrapper(call, pre="%s::" % descriptorProvider.interface.identifier.name)
 | 
						|
        else:
 | 
						|
            call = CGWrapper(call, pre="%s." % object)
 | 
						|
        call = CGList([call, CGWrapper(args, pre="(", post=")")])
 | 
						|
 | 
						|
        self.cgRoot.append(CGList([
 | 
						|
            CGGeneric("let result: "),
 | 
						|
            result,
 | 
						|
            CGGeneric(" = "),
 | 
						|
            call,
 | 
						|
            CGGeneric(";"),
 | 
						|
        ]))
 | 
						|
 | 
						|
        if isFallible:
 | 
						|
            if static:
 | 
						|
                glob = ""
 | 
						|
            else:
 | 
						|
                glob = "        let global = global_object_for_js_object(this.reflector().get_jsobject().get());\n"
 | 
						|
 | 
						|
            self.cgRoot.append(CGGeneric(
 | 
						|
                "let result = match result {\n"
 | 
						|
                "    Ok(result) => result,\n"
 | 
						|
                "    Err(e) => {\n"
 | 
						|
                "%s"
 | 
						|
                "        throw_dom_exception(cx, global.r(), e);\n"
 | 
						|
                "        return%s;\n"
 | 
						|
                "    },\n"
 | 
						|
                "};" % (glob, errorResult)))
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        return self.cgRoot.define()
 | 
						|
 | 
						|
 | 
						|
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)
 | 
						|
        cgThings = []
 | 
						|
        cgThings.extend([CGArgumentConverter(arguments[i], i, self.getArgs(),
 | 
						|
                                             self.getArgc(), self.descriptor,
 | 
						|
                                             invalidEnumValueFatal=not setter) for
 | 
						|
                         i in range(argConversionStartsAt, self.argCount)])
 | 
						|
 | 
						|
        errorResult = None
 | 
						|
        if self.isFallible():
 | 
						|
            errorResult = " false"
 | 
						|
 | 
						|
        cgThings.append(CGCallGenerator(
 | 
						|
            errorResult,
 | 
						|
            self.getArguments(), self.argsPre, returnType,
 | 
						|
            self.extendedAttributes, descriptor, nativeMethodName,
 | 
						|
            static))
 | 
						|
        self.cgRoot = CGList(cgThings, "\n")
 | 
						|
 | 
						|
    def getArgs(self):
 | 
						|
        return "args" if self.argCount > 0 else ""
 | 
						|
 | 
						|
    def getArgc(self):
 | 
						|
        return "argc"
 | 
						|
 | 
						|
    def getArguments(self):
 | 
						|
        def process(arg, i):
 | 
						|
            argVal = "arg" + str(i)
 | 
						|
            if arg.type.isGeckoInterface() and not arg.type.unroll().inner.isCallback():
 | 
						|
                argVal += ".r()"
 | 
						|
            return argVal
 | 
						|
        return [(a, process(a, i)) for (i, a) in enumerate(self.arguments)]
 | 
						|
 | 
						|
    def isFallible(self):
 | 
						|
        return 'infallible' not in self.extendedAttributes
 | 
						|
 | 
						|
    def wrap_return_value(self):
 | 
						|
        return wrapForType('args.rval()')
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        return (self.cgRoot.define() + "\n" + self.wrap_return_value())
 | 
						|
 | 
						|
 | 
						|
class CGSwitch(CGList):
 | 
						|
    """
 | 
						|
    A class to generate code for a switch statement.
 | 
						|
 | 
						|
    Takes three constructor arguments: an expression, a list of cases,
 | 
						|
    and an optional default.
 | 
						|
 | 
						|
    Each case is a CGCase.  The default is a CGThing for the body of
 | 
						|
    the default case, if any.
 | 
						|
    """
 | 
						|
    def __init__(self, expression, cases, default=None):
 | 
						|
        CGList.__init__(self, [CGIndenter(c) for c in cases], "\n")
 | 
						|
        self.prepend(CGWrapper(CGGeneric(expression),
 | 
						|
                               pre="match ", post=" {"))
 | 
						|
        if default is not None:
 | 
						|
            self.append(
 | 
						|
                CGIndenter(
 | 
						|
                    CGWrapper(
 | 
						|
                        CGIndenter(default),
 | 
						|
                        pre="_ => {\n",
 | 
						|
                        post="\n}"
 | 
						|
                    )
 | 
						|
                )
 | 
						|
            )
 | 
						|
 | 
						|
        self.append(CGGeneric("}"))
 | 
						|
 | 
						|
 | 
						|
class CGCase(CGList):
 | 
						|
    """
 | 
						|
    A class to generate code for a case statement.
 | 
						|
 | 
						|
    Takes three constructor arguments: an expression, a CGThing for
 | 
						|
    the body (allowed to be None if there is no body), and an optional
 | 
						|
    argument (defaulting to False) for whether to fall through.
 | 
						|
    """
 | 
						|
    def __init__(self, expression, body, fallThrough=False):
 | 
						|
        CGList.__init__(self, [], "\n")
 | 
						|
        self.append(CGWrapper(CGGeneric(expression), post=" => {"))
 | 
						|
        bodyList = CGList([body], "\n")
 | 
						|
        if fallThrough:
 | 
						|
            raise TypeError("fall through required but unsupported")
 | 
						|
            # bodyList.append(CGGeneric('panic!("fall through unsupported"); /* Fall through */'))
 | 
						|
        self.append(CGIndenter(bodyList))
 | 
						|
        self.append(CGGeneric("}"))
 | 
						|
 | 
						|
 | 
						|
class CGGetterCall(CGPerSignatureCall):
 | 
						|
    """
 | 
						|
    A class to generate a native object getter call for a particular IDL
 | 
						|
    getter.
 | 
						|
    """
 | 
						|
    def __init__(self, argsPre, returnType, nativeMethodName, descriptor, attr):
 | 
						|
        CGPerSignatureCall.__init__(self, returnType, argsPre, [],
 | 
						|
                                    nativeMethodName, attr.isStatic(), descriptor,
 | 
						|
                                    attr, getter=True)
 | 
						|
 | 
						|
 | 
						|
class FakeArgument():
 | 
						|
    """
 | 
						|
    A class that quacks like an IDLArgument.  This is used to make
 | 
						|
    setters look like method calls or for special operations.
 | 
						|
    """
 | 
						|
    def __init__(self, type, interfaceMember, allowTreatNonObjectAsNull=False):
 | 
						|
        self.type = type
 | 
						|
        self.optional = False
 | 
						|
        self.variadic = False
 | 
						|
        self.defaultValue = None
 | 
						|
        self._allowTreatNonObjectAsNull = allowTreatNonObjectAsNull
 | 
						|
        self.treatNullAs = interfaceMember.treatNullAs
 | 
						|
        self.enforceRange = False
 | 
						|
        self.clamp = False
 | 
						|
 | 
						|
    def allowTreatNonCallableAsNull(self):
 | 
						|
        return self._allowTreatNonObjectAsNull
 | 
						|
 | 
						|
 | 
						|
class CGSetterCall(CGPerSignatureCall):
 | 
						|
    """
 | 
						|
    A class to generate a native object setter call for a particular IDL
 | 
						|
    setter.
 | 
						|
    """
 | 
						|
    def __init__(self, argsPre, argType, nativeMethodName, descriptor, attr):
 | 
						|
        CGPerSignatureCall.__init__(self, None, argsPre,
 | 
						|
                                    [FakeArgument(argType, attr, allowTreatNonObjectAsNull=True)],
 | 
						|
                                    nativeMethodName, attr.isStatic(), descriptor, attr,
 | 
						|
                                    setter=True)
 | 
						|
 | 
						|
    def wrap_return_value(self):
 | 
						|
        # We have no return value
 | 
						|
        return "\nreturn true;"
 | 
						|
 | 
						|
    def getArgc(self):
 | 
						|
        return "1"
 | 
						|
 | 
						|
 | 
						|
class CGAbstractStaticBindingMethod(CGAbstractMethod):
 | 
						|
    """
 | 
						|
    Common class to generate the JSNatives for all our static methods, getters
 | 
						|
    and setters.  This will generate the function declaration and unwrap the
 | 
						|
    global object.  Subclasses are expected to override the generate_code
 | 
						|
    function to do the rest of the work.  This function should return a
 | 
						|
    CGThing which is already properly indented.
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor, name):
 | 
						|
        args = [
 | 
						|
            Argument('*mut JSContext', 'cx'),
 | 
						|
            Argument('libc::c_uint', 'argc'),
 | 
						|
            Argument('*mut JSVal', 'vp'),
 | 
						|
        ]
 | 
						|
        CGAbstractMethod.__init__(self, descriptor, name, "bool", args, extern=True)
 | 
						|
 | 
						|
    def definition_body(self):
 | 
						|
        preamble = CGGeneric("""\
 | 
						|
let global = global_object_for_js_object(JS_CALLEE(cx, vp).to_object());
 | 
						|
""")
 | 
						|
        return CGList([preamble, self.generate_code()])
 | 
						|
 | 
						|
    def generate_code(self):
 | 
						|
        raise NotImplementedError  # Override me!
 | 
						|
 | 
						|
 | 
						|
class CGSpecializedMethod(CGAbstractExternMethod):
 | 
						|
    """
 | 
						|
    A class for generating the C++ code for a specialized method that the JIT
 | 
						|
    can call with lower overhead.
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor, method):
 | 
						|
        self.method = method
 | 
						|
        name = method.identifier.name
 | 
						|
        args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', '_obj'),
 | 
						|
                Argument('*const %s' % descriptor.concreteType, 'this'),
 | 
						|
                Argument('*const JSJitMethodCallArgs', 'args')]
 | 
						|
        CGAbstractExternMethod.__init__(self, descriptor, name, 'bool', args)
 | 
						|
 | 
						|
    def definition_body(self):
 | 
						|
        nativeName = CGSpecializedMethod.makeNativeName(self.descriptor,
 | 
						|
                                                        self.method)
 | 
						|
        return CGWrapper(CGMethodCall([], nativeName, self.method.isStatic(),
 | 
						|
                                      self.descriptor, self.method),
 | 
						|
                         pre="let this = &*this;\n"
 | 
						|
                             "let args = &*args;\n"
 | 
						|
                             "let argc = args._base.argc_;\n")
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def makeNativeName(descriptor, method):
 | 
						|
        name = method.identifier.name
 | 
						|
        nativeName = descriptor.binaryNameFor(name)
 | 
						|
        if nativeName == name:
 | 
						|
            nativeName = descriptor.internalNameFor(name)
 | 
						|
        return MakeNativeName(nativeName)
 | 
						|
 | 
						|
 | 
						|
class CGStaticMethod(CGAbstractStaticBindingMethod):
 | 
						|
    """
 | 
						|
    A class for generating the Rust code for an IDL static method.
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor, method):
 | 
						|
        self.method = method
 | 
						|
        name = method.identifier.name
 | 
						|
        CGAbstractStaticBindingMethod.__init__(self, descriptor, name)
 | 
						|
 | 
						|
    def generate_code(self):
 | 
						|
        nativeName = CGSpecializedMethod.makeNativeName(self.descriptor,
 | 
						|
                                                        self.method)
 | 
						|
        setupArgs = CGGeneric("let args = CallArgs::from_vp(vp, argc);\n")
 | 
						|
        call = CGMethodCall(["global.r()"], nativeName, True, self.descriptor, self.method)
 | 
						|
        return CGList([setupArgs, call])
 | 
						|
 | 
						|
 | 
						|
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_' + descriptor.internalNameFor(attr.identifier.name)
 | 
						|
        args = [Argument('*mut JSContext', 'cx'),
 | 
						|
                Argument('HandleObject', '_obj'),
 | 
						|
                Argument('*const %s' % descriptor.concreteType, 'this'),
 | 
						|
                Argument('JSJitGetterCallArgs', 'args')]
 | 
						|
        CGAbstractExternMethod.__init__(self, descriptor, name, "bool", args)
 | 
						|
 | 
						|
    def definition_body(self):
 | 
						|
        nativeName = CGSpecializedGetter.makeNativeName(self.descriptor,
 | 
						|
                                                        self.attr)
 | 
						|
 | 
						|
        return CGWrapper(CGGetterCall([], self.attr.type, nativeName,
 | 
						|
                                      self.descriptor, self.attr),
 | 
						|
                         pre="let this = &*this;\n")
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def makeNativeName(descriptor, attr):
 | 
						|
        name = attr.identifier.name
 | 
						|
        nativeName = descriptor.binaryNameFor(name)
 | 
						|
        if nativeName == name:
 | 
						|
            nativeName = descriptor.internalNameFor(name)
 | 
						|
        nativeName = MakeNativeName(nativeName)
 | 
						|
        infallible = ('infallible' in
 | 
						|
                      descriptor.getExtendedAttributes(attr, getter=True))
 | 
						|
        if attr.type.nullable() or not infallible:
 | 
						|
            return "Get" + nativeName
 | 
						|
 | 
						|
        return nativeName
 | 
						|
 | 
						|
 | 
						|
class CGStaticGetter(CGAbstractStaticBindingMethod):
 | 
						|
    """
 | 
						|
    A class for generating the C++ code for an IDL static attribute getter.
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor, attr):
 | 
						|
        self.attr = attr
 | 
						|
        name = 'get_' + attr.identifier.name
 | 
						|
        CGAbstractStaticBindingMethod.__init__(self, descriptor, name)
 | 
						|
 | 
						|
    def generate_code(self):
 | 
						|
        nativeName = CGSpecializedGetter.makeNativeName(self.descriptor,
 | 
						|
                                                        self.attr)
 | 
						|
        setupArgs = CGGeneric("let args = CallArgs::from_vp(vp, argc);\n")
 | 
						|
        call = CGGetterCall(["global.r()"], self.attr.type, nativeName, self.descriptor,
 | 
						|
                            self.attr)
 | 
						|
        return CGList([setupArgs, call])
 | 
						|
 | 
						|
 | 
						|
class CGSpecializedSetter(CGAbstractExternMethod):
 | 
						|
    """
 | 
						|
    A class for generating the code for a specialized attribute setter
 | 
						|
    that the JIT can call with lower overhead.
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor, attr):
 | 
						|
        self.attr = attr
 | 
						|
        name = 'set_' + descriptor.internalNameFor(attr.identifier.name)
 | 
						|
        args = [Argument('*mut JSContext', 'cx'),
 | 
						|
                Argument('HandleObject', 'obj'),
 | 
						|
                Argument('*const %s' % descriptor.concreteType, 'this'),
 | 
						|
                Argument('JSJitSetterCallArgs', 'args')]
 | 
						|
        CGAbstractExternMethod.__init__(self, descriptor, name, "bool", args)
 | 
						|
 | 
						|
    def definition_body(self):
 | 
						|
        nativeName = CGSpecializedSetter.makeNativeName(self.descriptor,
 | 
						|
                                                        self.attr)
 | 
						|
        return CGWrapper(CGSetterCall([], self.attr.type, nativeName,
 | 
						|
                                      self.descriptor, self.attr),
 | 
						|
                         pre="let this = &*this;\n")
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def makeNativeName(descriptor, attr):
 | 
						|
        name = attr.identifier.name
 | 
						|
        nativeName = descriptor.binaryNameFor(name)
 | 
						|
        if nativeName == name:
 | 
						|
            nativeName = descriptor.internalNameFor(name)
 | 
						|
        return "Set" + MakeNativeName(nativeName)
 | 
						|
 | 
						|
 | 
						|
class CGStaticSetter(CGAbstractStaticBindingMethod):
 | 
						|
    """
 | 
						|
    A class for generating the C++ code for an IDL static attribute setter.
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor, attr):
 | 
						|
        self.attr = attr
 | 
						|
        name = 'set_' + attr.identifier.name
 | 
						|
        CGAbstractStaticBindingMethod.__init__(self, descriptor, name)
 | 
						|
 | 
						|
    def generate_code(self):
 | 
						|
        nativeName = CGSpecializedSetter.makeNativeName(self.descriptor,
 | 
						|
                                                        self.attr)
 | 
						|
        checkForArg = CGGeneric(
 | 
						|
            "let args = CallArgs::from_vp(vp, argc);\n"
 | 
						|
            "if argc == 0 {\n"
 | 
						|
            "    throw_type_error(cx, \"Not enough arguments to %s setter.\");\n"
 | 
						|
            "    return false;\n"
 | 
						|
            "}" % self.attr.identifier.name)
 | 
						|
        call = CGSetterCall(["global.r()"], self.attr.type, nativeName, self.descriptor,
 | 
						|
                            self.attr)
 | 
						|
        return CGList([checkForArg, call])
 | 
						|
 | 
						|
 | 
						|
class CGSpecializedForwardingSetter(CGSpecializedSetter):
 | 
						|
    """
 | 
						|
    A class for generating the code for an IDL attribute forwarding setter.
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor, attr):
 | 
						|
        CGSpecializedSetter.__init__(self, descriptor, attr)
 | 
						|
 | 
						|
    def definition_body(self):
 | 
						|
        attrName = self.attr.identifier.name
 | 
						|
        forwardToAttrName = self.attr.getExtendedAttribute("PutForwards")[0]
 | 
						|
        # JS_GetProperty and JS_SetProperty can only deal with ASCII
 | 
						|
        assert all(ord(c) < 128 for c in attrName)
 | 
						|
        assert all(ord(c) < 128 for c in forwardToAttrName)
 | 
						|
        return CGGeneric("""\
 | 
						|
let mut v = RootedValue::new(cx, UndefinedValue());
 | 
						|
if !JS_GetProperty(cx, obj, %s as *const u8 as *const libc::c_char, v.handle_mut()) {
 | 
						|
    return false;
 | 
						|
}
 | 
						|
if !v.ptr.is_object() {
 | 
						|
    throw_type_error(cx, "Value.%s is not an object.");
 | 
						|
    return false;
 | 
						|
}
 | 
						|
let target_obj = RootedObject::new(cx, v.ptr.to_object());
 | 
						|
JS_SetProperty(cx, target_obj.handle(), %s as *const u8 as *const libc::c_char, args.get(0))
 | 
						|
""" % (str_to_const_array(attrName), attrName, str_to_const_array(forwardToAttrName)))
 | 
						|
 | 
						|
 | 
						|
class CGMemberJITInfo(CGThing):
 | 
						|
    """
 | 
						|
    A class for generating the JITInfo for a property that points to
 | 
						|
    our specialized getter and setter.
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor, member):
 | 
						|
        self.member = member
 | 
						|
        self.descriptor = descriptor
 | 
						|
 | 
						|
    def defineJitInfo(self, infoName, opName, opType, infallible, movable,
 | 
						|
                      aliasSet, alwaysInSlot, lazilyInSlot, slotIndex,
 | 
						|
                      returnTypes, args):
 | 
						|
        """
 | 
						|
        aliasSet is a JSJitInfo::AliasSet value, without the "JSJitInfo::" bit.
 | 
						|
 | 
						|
        args is None if we don't want to output argTypes for some
 | 
						|
        reason (e.g. we have overloads or we're not a method) and
 | 
						|
        otherwise an iterable of the arguments for this method.
 | 
						|
        """
 | 
						|
        assert not movable or aliasSet != "AliasEverything"  # Can't move write-aliasing things
 | 
						|
        assert not alwaysInSlot or movable  # Things always in slots had better be movable
 | 
						|
 | 
						|
        def jitInfoInitializer(isTypedMethod):
 | 
						|
            initializer = fill(
 | 
						|
                """
 | 
						|
                JSJitInfo {
 | 
						|
                    call: ${opName} as *const ::libc::c_void,
 | 
						|
                    protoID: PrototypeList::ID::${name} as u16,
 | 
						|
                    depth: ${depth},
 | 
						|
                    _bitfield_1:
 | 
						|
                        JSJitInfo::new_bitfield_1(
 | 
						|
                            OpType::${opType} as u8,
 | 
						|
                            AliasSet::${aliasSet} as u8,
 | 
						|
                            JSValueType::${returnType} as u8,
 | 
						|
                            ${isInfallible},
 | 
						|
                            ${isMovable},
 | 
						|
                            ${isAlwaysInSlot},
 | 
						|
                            ${isLazilyCachedInSlot},
 | 
						|
                            ${isTypedMethod},
 | 
						|
                            ${slotIndex} as u16,
 | 
						|
                        )
 | 
						|
                }
 | 
						|
                """,
 | 
						|
                opName=opName,
 | 
						|
                name=self.descriptor.name,
 | 
						|
                depth=self.descriptor.interface.inheritanceDepth(),
 | 
						|
                opType=opType,
 | 
						|
                aliasSet=aliasSet,
 | 
						|
                returnType=reduce(CGMemberJITInfo.getSingleReturnType, returnTypes,
 | 
						|
                                  ""),
 | 
						|
                isInfallible=toStringBool(infallible),
 | 
						|
                isMovable=toStringBool(movable),
 | 
						|
                isAlwaysInSlot=toStringBool(alwaysInSlot),
 | 
						|
                isLazilyCachedInSlot=toStringBool(lazilyInSlot),
 | 
						|
                isTypedMethod=toStringBool(isTypedMethod),
 | 
						|
                slotIndex=slotIndex)
 | 
						|
            return initializer.rstrip()
 | 
						|
 | 
						|
        if args is not None:
 | 
						|
            argTypes = "%s_argTypes" % infoName
 | 
						|
            args = [CGMemberJITInfo.getJSArgType(arg.type) for arg in args]
 | 
						|
            args.append("ArgType::ArgTypeListEnd as i32")
 | 
						|
            argTypesDecl = (
 | 
						|
                "const %s: [i32; %d] = [ %s ];\n" %
 | 
						|
                (argTypes, len(args), ", ".join(args)))
 | 
						|
            return fill(
 | 
						|
                """
 | 
						|
                $*{argTypesDecl}
 | 
						|
                const ${infoName}: JSTypedMethodJitInfo = JSTypedMethodJitInfo {
 | 
						|
                    base: ${jitInfo},
 | 
						|
                    argTypes: &${argTypes} as *const _ as *const ArgType,
 | 
						|
                };
 | 
						|
                """,
 | 
						|
                argTypesDecl=argTypesDecl,
 | 
						|
                infoName=infoName,
 | 
						|
                jitInfo=indent(jitInfoInitializer(True)),
 | 
						|
                argTypes=argTypes)
 | 
						|
 | 
						|
        return ("\n"
 | 
						|
                "const %s: JSJitInfo = %s;\n"
 | 
						|
                % (infoName, jitInfoInitializer(False)))
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        if self.member.isAttr():
 | 
						|
            internalMemberName = self.descriptor.internalNameFor(self.member.identifier.name)
 | 
						|
            getterinfo = ("%s_getterinfo" % internalMemberName)
 | 
						|
            getter = ("get_%s" % internalMemberName)
 | 
						|
            getterinfal = "infallible" in self.descriptor.getExtendedAttributes(self.member, getter=True)
 | 
						|
 | 
						|
            movable = self.mayBeMovable() and getterinfal
 | 
						|
            aliasSet = self.aliasSet()
 | 
						|
 | 
						|
            isAlwaysInSlot = self.member.getExtendedAttribute("StoreInSlot")
 | 
						|
            if self.member.slotIndex is not None:
 | 
						|
                assert isAlwaysInSlot or self.member.getExtendedAttribute("Cached")
 | 
						|
                isLazilyCachedInSlot = not isAlwaysInSlot
 | 
						|
                slotIndex = memberReservedSlot(self.member)  # noqa:FIXME: memberReservedSlot is not defined
 | 
						|
                # We'll statically assert that this is not too big in
 | 
						|
                # CGUpdateMemberSlotsMethod, in the case when
 | 
						|
                # isAlwaysInSlot is true.
 | 
						|
            else:
 | 
						|
                isLazilyCachedInSlot = False
 | 
						|
                slotIndex = "0"
 | 
						|
 | 
						|
            result = self.defineJitInfo(getterinfo, getter, "Getter",
 | 
						|
                                        getterinfal, movable, aliasSet,
 | 
						|
                                        isAlwaysInSlot, isLazilyCachedInSlot,
 | 
						|
                                        slotIndex,
 | 
						|
                                        [self.member.type], None)
 | 
						|
            if (not self.member.readonly or self.member.getExtendedAttribute("PutForwards")):
 | 
						|
                setterinfo = ("%s_setterinfo" % internalMemberName)
 | 
						|
                setter = ("set_%s" % internalMemberName)
 | 
						|
                # Setters are always fallible, since they have to do a typed unwrap.
 | 
						|
                result += self.defineJitInfo(setterinfo, setter, "Setter",
 | 
						|
                                             False, False, "AliasEverything",
 | 
						|
                                             False, False, "0",
 | 
						|
                                             [BuiltinTypes[IDLBuiltinType.Types.void]],
 | 
						|
                                             None)
 | 
						|
            return result
 | 
						|
        if self.member.isMethod():
 | 
						|
            methodinfo = ("%s_methodinfo" % self.member.identifier.name)
 | 
						|
            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.
 | 
						|
            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.
 | 
						|
                methodInfal = False
 | 
						|
                args = None
 | 
						|
                movable = False
 | 
						|
            else:
 | 
						|
                sig = sigs[0]
 | 
						|
                # For methods that affect nothing, it's OK to set movable to our
 | 
						|
                # notion of infallible on the C++ side, without considering
 | 
						|
                # argument conversions, since argument conversions that can
 | 
						|
                # reliably throw would be effectful anyway and the jit doesn't
 | 
						|
                # move effectful things.
 | 
						|
                hasInfallibleImpl = "infallible" in self.descriptor.getExtendedAttributes(self.member)
 | 
						|
                movable = self.mayBeMovable() and hasInfallibleImpl
 | 
						|
                # XXXbz can we move the smarts about fallibility due to arg
 | 
						|
                # conversions into the JIT, using our new args stuff?
 | 
						|
                if (len(sig[1]) != 0):
 | 
						|
                    # We have arguments or our return-value boxing can fail
 | 
						|
                    methodInfal = False
 | 
						|
                else:
 | 
						|
                    methodInfal = hasInfallibleImpl
 | 
						|
                # For now, only bother to output args if we're side-effect-free.
 | 
						|
                if self.member.affects == "Nothing":
 | 
						|
                    args = sig[1]
 | 
						|
                else:
 | 
						|
                    args = None
 | 
						|
 | 
						|
            aliasSet = self.aliasSet()
 | 
						|
            result = self.defineJitInfo(methodinfo, method, "Method",
 | 
						|
                                        methodInfal, movable, aliasSet,
 | 
						|
                                        False, False, "0",
 | 
						|
                                        [s[0] for s in sigs], args)
 | 
						|
            return result
 | 
						|
        raise TypeError("Illegal member type to CGPropertyJITInfo")
 | 
						|
 | 
						|
    def mayBeMovable(self):
 | 
						|
        """
 | 
						|
        Returns whether this attribute or method may be movable, just
 | 
						|
        based on Affects/DependsOn annotations.
 | 
						|
        """
 | 
						|
        affects = self.member.affects
 | 
						|
        dependsOn = self.member.dependsOn
 | 
						|
        assert affects in IDLInterfaceMember.AffectsValues
 | 
						|
        assert dependsOn in IDLInterfaceMember.DependsOnValues
 | 
						|
        # Things that are DependsOn=DeviceState are not movable, because we
 | 
						|
        # don't want them coalesced with each other or loop-hoisted, since
 | 
						|
        # their return value can change even if nothing is going on from our
 | 
						|
        # point of view.
 | 
						|
        return (affects == "Nothing" and
 | 
						|
                (dependsOn != "Everything" and dependsOn != "DeviceState"))
 | 
						|
 | 
						|
    def aliasSet(self):
 | 
						|
        """Returns the alias set to store in the jitinfo.  This may not be the
 | 
						|
        effective alias set the JIT uses, depending on whether we have enough
 | 
						|
        information about our args to allow the JIT to prove that effectful
 | 
						|
        argument conversions won't happen.
 | 
						|
 | 
						|
        """
 | 
						|
        dependsOn = self.member.dependsOn
 | 
						|
        assert dependsOn in IDLInterfaceMember.DependsOnValues
 | 
						|
 | 
						|
        if dependsOn == "Nothing" or dependsOn == "DeviceState":
 | 
						|
            assert self.member.affects == "Nothing"
 | 
						|
            return "AliasNone"
 | 
						|
 | 
						|
        if dependsOn == "DOMState":
 | 
						|
            assert self.member.affects == "Nothing"
 | 
						|
            return "AliasDOMSets"
 | 
						|
 | 
						|
        return "AliasEverything"
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def getJSReturnTypeTag(t):
 | 
						|
        if t.nullable():
 | 
						|
            # Sometimes it might return null, sometimes not
 | 
						|
            return "JSVAL_TYPE_UNKNOWN"
 | 
						|
        if t.isVoid():
 | 
						|
            # No return, every time
 | 
						|
            return "JSVAL_TYPE_UNDEFINED"
 | 
						|
        if t.isArray():
 | 
						|
            # No idea yet
 | 
						|
            assert False
 | 
						|
        if t.isSequence():
 | 
						|
            return "JSVAL_TYPE_OBJECT"
 | 
						|
        if t.isMozMap():
 | 
						|
            return "JSVAL_TYPE_OBJECT"
 | 
						|
        if t.isGeckoInterface():
 | 
						|
            return "JSVAL_TYPE_OBJECT"
 | 
						|
        if t.isString():
 | 
						|
            return "JSVAL_TYPE_STRING"
 | 
						|
        if t.isEnum():
 | 
						|
            return "JSVAL_TYPE_STRING"
 | 
						|
        if t.isCallback():
 | 
						|
            return "JSVAL_TYPE_OBJECT"
 | 
						|
        if t.isAny():
 | 
						|
            # The whole point is to return various stuff
 | 
						|
            return "JSVAL_TYPE_UNKNOWN"
 | 
						|
        if t.isObject():
 | 
						|
            return "JSVAL_TYPE_OBJECT"
 | 
						|
        if t.isSpiderMonkeyInterface():
 | 
						|
            return "JSVAL_TYPE_OBJECT"
 | 
						|
        if t.isUnion():
 | 
						|
            u = t.unroll()
 | 
						|
            if u.hasNullableType:
 | 
						|
                # Might be null or not
 | 
						|
                return "JSVAL_TYPE_UNKNOWN"
 | 
						|
            return reduce(CGMemberJITInfo.getSingleReturnType,
 | 
						|
                          u.flatMemberTypes, "")
 | 
						|
        if t.isDictionary():
 | 
						|
            return "JSVAL_TYPE_OBJECT"
 | 
						|
        if t.isDate():
 | 
						|
            return "JSVAL_TYPE_OBJECT"
 | 
						|
        if not t.isPrimitive():
 | 
						|
            raise TypeError("No idea what type " + str(t) + " is.")
 | 
						|
        tag = t.tag()
 | 
						|
        if tag == IDLType.Tags.bool:
 | 
						|
            return "JSVAL_TYPE_BOOLEAN"
 | 
						|
        if tag in [IDLType.Tags.int8, IDLType.Tags.uint8,
 | 
						|
                   IDLType.Tags.int16, IDLType.Tags.uint16,
 | 
						|
                   IDLType.Tags.int32]:
 | 
						|
            return "JSVAL_TYPE_INT32"
 | 
						|
        if tag in [IDLType.Tags.int64, IDLType.Tags.uint64,
 | 
						|
                   IDLType.Tags.unrestricted_float, IDLType.Tags.float,
 | 
						|
                   IDLType.Tags.unrestricted_double, IDLType.Tags.double]:
 | 
						|
            # These all use JS_NumberValue, which can return int or double.
 | 
						|
            # But TI treats "double" as meaning "int or double", so we're
 | 
						|
            # good to return JSVAL_TYPE_DOUBLE here.
 | 
						|
            return "JSVAL_TYPE_DOUBLE"
 | 
						|
        if tag != IDLType.Tags.uint32:
 | 
						|
            raise TypeError("No idea what type " + str(t) + " is.")
 | 
						|
        # uint32 is sometimes int and sometimes double.
 | 
						|
        return "JSVAL_TYPE_DOUBLE"
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def getSingleReturnType(existingType, t):
 | 
						|
        type = CGMemberJITInfo.getJSReturnTypeTag(t)
 | 
						|
        if existingType == "":
 | 
						|
            # First element of the list; just return its type
 | 
						|
            return type
 | 
						|
 | 
						|
        if type == existingType:
 | 
						|
            return existingType
 | 
						|
        if ((type == "JSVAL_TYPE_DOUBLE" and
 | 
						|
             existingType == "JSVAL_TYPE_INT32") or
 | 
						|
            (existingType == "JSVAL_TYPE_DOUBLE" and
 | 
						|
             type == "JSVAL_TYPE_INT32")):
 | 
						|
            # Promote INT32 to DOUBLE as needed
 | 
						|
            return "JSVAL_TYPE_DOUBLE"
 | 
						|
        # Different types
 | 
						|
        return "JSVAL_TYPE_UNKNOWN"
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def getJSArgType(t):
 | 
						|
        assert not t.isVoid()
 | 
						|
        if t.nullable():
 | 
						|
            # Sometimes it might return null, sometimes not
 | 
						|
            return "ArgType::Null as i32 | %s" % CGMemberJITInfo.getJSArgType(t.inner)
 | 
						|
        if t.isArray():
 | 
						|
            # No idea yet
 | 
						|
            assert False
 | 
						|
        if t.isSequence():
 | 
						|
            return "ArgType::Object as i32"
 | 
						|
        if t.isGeckoInterface():
 | 
						|
            return "ArgType::Object as i32"
 | 
						|
        if t.isString():
 | 
						|
            return "ArgType::String as i32"
 | 
						|
        if t.isEnum():
 | 
						|
            return "ArgType::String as i32"
 | 
						|
        if t.isCallback():
 | 
						|
            return "ArgType::Object as i32"
 | 
						|
        if t.isAny():
 | 
						|
            # The whole point is to return various stuff
 | 
						|
            return "ArgType::Any as i32"
 | 
						|
        if t.isObject():
 | 
						|
            return "ArgType::Object as i32"
 | 
						|
        if t.isSpiderMonkeyInterface():
 | 
						|
            return "ArgType::Object as i32"
 | 
						|
        if t.isUnion():
 | 
						|
            u = t.unroll()
 | 
						|
            type = "JSJitInfo::Null as i32" if u.hasNullableType else ""
 | 
						|
            return reduce(CGMemberJITInfo.getSingleArgType,
 | 
						|
                          u.flatMemberTypes, type)
 | 
						|
        if t.isDictionary():
 | 
						|
            return "ArgType::Object as i32"
 | 
						|
        if t.isDate():
 | 
						|
            return "ArgType::Object as i32"
 | 
						|
        if not t.isPrimitive():
 | 
						|
            raise TypeError("No idea what type " + str(t) + " is.")
 | 
						|
        tag = t.tag()
 | 
						|
        if tag == IDLType.Tags.bool:
 | 
						|
            return "ArgType::Boolean as i32"
 | 
						|
        if tag in [IDLType.Tags.int8, IDLType.Tags.uint8,
 | 
						|
                   IDLType.Tags.int16, IDLType.Tags.uint16,
 | 
						|
                   IDLType.Tags.int32]:
 | 
						|
            return "ArgType::Integer as i32"
 | 
						|
        if tag in [IDLType.Tags.int64, IDLType.Tags.uint64,
 | 
						|
                   IDLType.Tags.unrestricted_float, IDLType.Tags.float,
 | 
						|
                   IDLType.Tags.unrestricted_double, IDLType.Tags.double]:
 | 
						|
            # These all use JS_NumberValue, which can return int or double.
 | 
						|
            # But TI treats "double" as meaning "int or double", so we're
 | 
						|
            # good to return JSVAL_TYPE_DOUBLE here.
 | 
						|
            return "ArgType::Double as i32"
 | 
						|
        if tag != IDLType.Tags.uint32:
 | 
						|
            raise TypeError("No idea what type " + str(t) + " is.")
 | 
						|
        # uint32 is sometimes int and sometimes double.
 | 
						|
        return "ArgType::Double as i32"
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def getSingleArgType(existingType, t):
 | 
						|
        type = CGMemberJITInfo.getJSArgType(t)
 | 
						|
        if existingType == "":
 | 
						|
            # First element of the list; just return its type
 | 
						|
            return type
 | 
						|
 | 
						|
        if type == existingType:
 | 
						|
            return existingType
 | 
						|
        return "%s | %s" % (existingType, type)
 | 
						|
 | 
						|
 | 
						|
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)
 | 
						|
 | 
						|
        decl = """\
 | 
						|
#[repr(usize)]
 | 
						|
#[derive(JSTraceable, PartialEq, Copy, Clone, HeapSizeOf)]
 | 
						|
pub enum %s {
 | 
						|
    %s
 | 
						|
}
 | 
						|
""" % (enum.identifier.name, ",\n    ".join(map(getEnumValueName, enum.values())))
 | 
						|
 | 
						|
        inner = """\
 | 
						|
use dom::bindings::conversions::ToJSValConvertible;
 | 
						|
use js::jsapi::{JSContext, MutableHandleValue};
 | 
						|
use js::jsval::JSVal;
 | 
						|
 | 
						|
pub const strings: &'static [&'static str] = &[
 | 
						|
    %s,
 | 
						|
];
 | 
						|
 | 
						|
impl ToJSValConvertible for super::%s {
 | 
						|
    fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
 | 
						|
        strings[*self as usize].to_jsval(cx, rval);
 | 
						|
    }
 | 
						|
}
 | 
						|
""" % (",\n    ".join(['"%s"' % val for val in enum.values()]), enum.identifier.name)
 | 
						|
 | 
						|
        self.cgRoot = CGList([
 | 
						|
            CGGeneric(decl),
 | 
						|
            CGNamespace.build([enum.identifier.name + "Values"],
 | 
						|
                              CGIndenter(CGGeneric(inner)), public=True),
 | 
						|
        ])
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        return self.cgRoot.define()
 | 
						|
 | 
						|
 | 
						|
def convertConstIDLValueToRust(value):
 | 
						|
    tag = value.type.tag()
 | 
						|
    if tag in [IDLType.Tags.int8, IDLType.Tags.uint8,
 | 
						|
               IDLType.Tags.int16, IDLType.Tags.uint16,
 | 
						|
               IDLType.Tags.int32, IDLType.Tags.uint32,
 | 
						|
               IDLType.Tags.int64, IDLType.Tags.uint64,
 | 
						|
               IDLType.Tags.unrestricted_float, IDLType.Tags.float,
 | 
						|
               IDLType.Tags.unrestricted_double, IDLType.Tags.double]:
 | 
						|
        return str(value.value)
 | 
						|
 | 
						|
    if tag == IDLType.Tags.bool:
 | 
						|
        return toStringBool(value.value)
 | 
						|
 | 
						|
    raise TypeError("Const value of unhandled type: " + value.type)
 | 
						|
 | 
						|
 | 
						|
class CGConstant(CGThing):
 | 
						|
    def __init__(self, constants):
 | 
						|
        CGThing.__init__(self)
 | 
						|
        self.constants = constants
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        def stringDecl(const):
 | 
						|
            name = const.identifier.name
 | 
						|
            value = convertConstIDLValueToRust(const.value)
 | 
						|
            return CGGeneric("pub const %s: %s = %s;\n" % (name, builtinNames[const.value.type.tag()], value))
 | 
						|
 | 
						|
        return CGIndenter(CGList(stringDecl(m) for m in self.constants)).define()
 | 
						|
 | 
						|
 | 
						|
def getUnionTypeTemplateVars(type, descriptorProvider):
 | 
						|
    # For dictionaries and sequences we need to pass None as the failureCode
 | 
						|
    # for getJSToNativeConversionInfo.
 | 
						|
    # Also, for dictionaries we would need to handle conversion of
 | 
						|
    # null/undefined to the dictionary correctly.
 | 
						|
    if type.isDictionary() or type.isSequence():
 | 
						|
        raise TypeError("Can't handle dictionaries or sequences in unions")
 | 
						|
 | 
						|
    if type.isGeckoInterface():
 | 
						|
        name = type.inner.identifier.name
 | 
						|
        typeName = descriptorProvider.getDescriptor(name).nativeType
 | 
						|
    elif type.isEnum():
 | 
						|
        name = type.inner.identifier.name
 | 
						|
        typeName = name
 | 
						|
    elif type.isArray() or type.isSequence():
 | 
						|
        name = str(type)
 | 
						|
        # XXXjdm dunno about typeName here
 | 
						|
        typeName = "/*" + type.name + "*/"
 | 
						|
    elif type.isDOMString():
 | 
						|
        name = type.name
 | 
						|
        typeName = "DOMString"
 | 
						|
    elif type.isUSVString():
 | 
						|
        name = type.name
 | 
						|
        typeName = "USVString"
 | 
						|
    elif type.isPrimitive():
 | 
						|
        name = type.name
 | 
						|
        typeName = builtinNames[type.tag()]
 | 
						|
    else:
 | 
						|
        name = type.name
 | 
						|
        typeName = "/*" + type.name + "*/"
 | 
						|
 | 
						|
    info = getJSToNativeConversionInfo(
 | 
						|
        type, descriptorProvider, failureCode="return Ok(None);",
 | 
						|
        exceptionCode='return Err(());',
 | 
						|
        isDefinitelyObject=True)
 | 
						|
    template = info.template
 | 
						|
 | 
						|
    assert not type.isObject()
 | 
						|
    jsConversion = string.Template(template).substitute({
 | 
						|
        "val": "value",
 | 
						|
    })
 | 
						|
    jsConversion = CGWrapper(CGGeneric(jsConversion), pre="Ok(Some(", post="))")
 | 
						|
 | 
						|
    return {
 | 
						|
        "name": name,
 | 
						|
        "typeName": typeName,
 | 
						|
        "jsConversion": jsConversion,
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
class CGUnionStruct(CGThing):
 | 
						|
    def __init__(self, type, descriptorProvider):
 | 
						|
        assert not type.nullable()
 | 
						|
        assert not type.hasNullableType
 | 
						|
 | 
						|
        CGThing.__init__(self)
 | 
						|
        self.type = type
 | 
						|
        self.descriptorProvider = descriptorProvider
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        templateVars = map(lambda t: getUnionTypeTemplateVars(t, self.descriptorProvider),
 | 
						|
                           self.type.flatMemberTypes)
 | 
						|
        enumValues = [
 | 
						|
            "    e%s(%s)," % (v["name"], v["typeName"]) for v in templateVars
 | 
						|
        ]
 | 
						|
        enumConversions = [
 | 
						|
            "            %s::e%s(ref inner) => inner.to_jsval(cx, rval),"
 | 
						|
            % (self.type, v["name"]) for v in templateVars
 | 
						|
        ]
 | 
						|
        return ("""\
 | 
						|
pub enum %s {
 | 
						|
%s
 | 
						|
}
 | 
						|
 | 
						|
impl ToJSValConvertible for %s {
 | 
						|
    fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
 | 
						|
        match *self {
 | 
						|
%s
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
""") % (self.type, "\n".join(enumValues), self.type, "\n".join(enumConversions))
 | 
						|
 | 
						|
 | 
						|
class CGUnionConversionStruct(CGThing):
 | 
						|
    def __init__(self, type, descriptorProvider):
 | 
						|
        assert not type.nullable()
 | 
						|
        assert not type.hasNullableType
 | 
						|
 | 
						|
        CGThing.__init__(self)
 | 
						|
        self.type = type
 | 
						|
        self.descriptorProvider = descriptorProvider
 | 
						|
 | 
						|
    def from_jsval(self):
 | 
						|
        memberTypes = self.type.flatMemberTypes
 | 
						|
        names = []
 | 
						|
        conversions = []
 | 
						|
 | 
						|
        interfaceMemberTypes = filter(lambda t: t.isNonCallbackInterface(), memberTypes)
 | 
						|
        if len(interfaceMemberTypes) > 0:
 | 
						|
            def get_name(memberType):
 | 
						|
                if self.type.isGeckoInterface():
 | 
						|
                    return memberType.inner.identifier.name
 | 
						|
 | 
						|
                return memberType.name
 | 
						|
 | 
						|
            def get_match(name):
 | 
						|
                return (
 | 
						|
                    "match %s::TryConvertTo%s(cx, value) {\n"
 | 
						|
                    "    Err(_) => return Err(()),\n"
 | 
						|
                    "    Ok(Some(value)) => return Ok(%s::e%s(value)),\n"
 | 
						|
                    "    Ok(None) => (),\n"
 | 
						|
                    "}\n") % (self.type, name, self.type, name)
 | 
						|
 | 
						|
            typeNames = [get_name(memberType) for memberType in interfaceMemberTypes]
 | 
						|
            interfaceObject = CGList(CGGeneric(get_match(typeName)) for typeName in typeNames)
 | 
						|
            names.extend(typeNames)
 | 
						|
        else:
 | 
						|
            interfaceObject = None
 | 
						|
 | 
						|
        arrayObjectMemberTypes = filter(lambda t: t.isArray() or t.isSequence(), memberTypes)
 | 
						|
        if len(arrayObjectMemberTypes) > 0:
 | 
						|
            assert len(arrayObjectMemberTypes) == 1
 | 
						|
            raise TypeError("Can't handle arrays or sequences in unions.")
 | 
						|
        else:
 | 
						|
            arrayObject = None
 | 
						|
 | 
						|
        dateObjectMemberTypes = filter(lambda t: t.isDate(), memberTypes)
 | 
						|
        if len(dateObjectMemberTypes) > 0:
 | 
						|
            assert len(dateObjectMemberTypes) == 1
 | 
						|
            raise TypeError("Can't handle dates in unions.")
 | 
						|
        else:
 | 
						|
            dateObject = None
 | 
						|
 | 
						|
        callbackMemberTypes = filter(lambda t: t.isCallback() or t.isCallbackInterface(), memberTypes)
 | 
						|
        if len(callbackMemberTypes) > 0:
 | 
						|
            assert len(callbackMemberTypes) == 1
 | 
						|
            raise TypeError("Can't handle callbacks in unions.")
 | 
						|
        else:
 | 
						|
            callbackObject = None
 | 
						|
 | 
						|
        dictionaryMemberTypes = filter(lambda t: t.isDictionary(), memberTypes)
 | 
						|
        if len(dictionaryMemberTypes) > 0:
 | 
						|
            raise TypeError("No support for unwrapping dictionaries as member "
 | 
						|
                            "of a union")
 | 
						|
        else:
 | 
						|
            dictionaryObject = None
 | 
						|
 | 
						|
        if callbackObject or dictionaryObject:
 | 
						|
            assert False, "Not currently supported"
 | 
						|
        else:
 | 
						|
            nonPlatformObject = None
 | 
						|
 | 
						|
        objectMemberTypes = filter(lambda t: t.isObject(), memberTypes)
 | 
						|
        if len(objectMemberTypes) > 0:
 | 
						|
            raise TypeError("Can't handle objects in unions.")
 | 
						|
        else:
 | 
						|
            object = None
 | 
						|
 | 
						|
        hasObjectTypes = interfaceObject or arrayObject or dateObject or nonPlatformObject or object
 | 
						|
        if hasObjectTypes:
 | 
						|
            assert interfaceObject
 | 
						|
            templateBody = CGList([interfaceObject], "\n")
 | 
						|
            conversions.append(CGIfWrapper(templateBody, "value.get().is_object()"))
 | 
						|
 | 
						|
        otherMemberTypes = [
 | 
						|
            t for t in memberTypes if t.isPrimitive() or t.isString() or t.isEnum()
 | 
						|
        ]
 | 
						|
        if len(otherMemberTypes) > 0:
 | 
						|
            assert len(otherMemberTypes) == 1
 | 
						|
            memberType = otherMemberTypes[0]
 | 
						|
            if memberType.isEnum():
 | 
						|
                name = memberType.inner.identifier.name
 | 
						|
            else:
 | 
						|
                name = memberType.name
 | 
						|
            match = (
 | 
						|
                "match %s::TryConvertTo%s(cx, value) {\n"
 | 
						|
                "    Err(_) => return Err(()),\n"
 | 
						|
                "    Ok(Some(value)) => return Ok(%s::e%s(value)),\n"
 | 
						|
                "    Ok(None) => (),\n"
 | 
						|
                "}\n") % (self.type, name, self.type, name)
 | 
						|
            conversions.append(CGGeneric(match))
 | 
						|
            names.append(name)
 | 
						|
 | 
						|
        conversions.append(CGGeneric(
 | 
						|
            "throw_not_in_union(cx, \"%s\");\n"
 | 
						|
            "Err(())" % ", ".join(names)))
 | 
						|
        method = CGWrapper(
 | 
						|
            CGIndenter(CGList(conversions, "\n\n")),
 | 
						|
            pre="fn from_jsval(cx: *mut JSContext,\n"
 | 
						|
                "              value: HandleValue, _option: ()) -> Result<%s, ()> {\n" % self.type,
 | 
						|
            post="\n}")
 | 
						|
        return CGWrapper(
 | 
						|
            CGIndenter(CGList([
 | 
						|
                CGGeneric("type Config = ();"),
 | 
						|
                method,
 | 
						|
            ], "\n")),
 | 
						|
            pre="impl FromJSValConvertible for %s {\n" % self.type,
 | 
						|
            post="\n}")
 | 
						|
 | 
						|
    def try_method(self, t):
 | 
						|
        templateVars = getUnionTypeTemplateVars(t, self.descriptorProvider)
 | 
						|
        returnType = "Result<Option<%s>, ()>" % templateVars["typeName"]
 | 
						|
        jsConversion = templateVars["jsConversion"]
 | 
						|
 | 
						|
        return CGWrapper(
 | 
						|
            CGIndenter(jsConversion, 4),
 | 
						|
            pre="fn TryConvertTo%s(cx: *mut JSContext, value: HandleValue) -> %s {\n" % (t.name, returnType),
 | 
						|
            post="\n}")
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        from_jsval = self.from_jsval()
 | 
						|
        methods = CGIndenter(CGList([
 | 
						|
            self.try_method(t) for t in self.type.flatMemberTypes
 | 
						|
        ], "\n\n"))
 | 
						|
        return """
 | 
						|
%s
 | 
						|
 | 
						|
impl %s {
 | 
						|
%s
 | 
						|
}
 | 
						|
""" % (from_jsval.define(), self.type, methods.define())
 | 
						|
 | 
						|
 | 
						|
class ClassItem:
 | 
						|
    """ Use with CGClass """
 | 
						|
    def __init__(self, name, visibility):
 | 
						|
        self.name = name
 | 
						|
        self.visibility = visibility
 | 
						|
 | 
						|
    def declare(self, cgClass):
 | 
						|
        assert False
 | 
						|
 | 
						|
    def define(self, cgClass):
 | 
						|
        assert False
 | 
						|
 | 
						|
 | 
						|
class ClassBase(ClassItem):
 | 
						|
    def __init__(self, name, visibility='pub'):
 | 
						|
        ClassItem.__init__(self, name, visibility)
 | 
						|
 | 
						|
    def declare(self, cgClass):
 | 
						|
        return '%s %s' % (self.visibility, self.name)
 | 
						|
 | 
						|
    def define(self, cgClass):
 | 
						|
        # Only in the header
 | 
						|
        return ''
 | 
						|
 | 
						|
 | 
						|
class ClassMethod(ClassItem):
 | 
						|
    def __init__(self, name, returnType, args, inline=False, static=False,
 | 
						|
                 virtual=False, const=False, bodyInHeader=False,
 | 
						|
                 templateArgs=None, visibility='public', body=None,
 | 
						|
                 breakAfterReturnDecl="\n",
 | 
						|
                 breakAfterSelf="\n", override=False):
 | 
						|
        """
 | 
						|
        override indicates whether to flag the method as MOZ_OVERRIDE
 | 
						|
        """
 | 
						|
        assert not override or virtual
 | 
						|
        assert not (override and static)
 | 
						|
        self.returnType = returnType
 | 
						|
        self.args = args
 | 
						|
        self.inline = False
 | 
						|
        self.static = static
 | 
						|
        self.virtual = virtual
 | 
						|
        self.const = const
 | 
						|
        self.bodyInHeader = True
 | 
						|
        self.templateArgs = templateArgs
 | 
						|
        self.body = body
 | 
						|
        self.breakAfterReturnDecl = breakAfterReturnDecl
 | 
						|
        self.breakAfterSelf = breakAfterSelf
 | 
						|
        self.override = override
 | 
						|
        ClassItem.__init__(self, name, visibility)
 | 
						|
 | 
						|
    def getDecorators(self, declaring):
 | 
						|
        decorators = []
 | 
						|
        if self.inline:
 | 
						|
            decorators.append('inline')
 | 
						|
        if declaring:
 | 
						|
            if self.static:
 | 
						|
                decorators.append('static')
 | 
						|
            if self.virtual:
 | 
						|
                decorators.append('virtual')
 | 
						|
        if decorators:
 | 
						|
            return ' '.join(decorators) + ' '
 | 
						|
        return ''
 | 
						|
 | 
						|
    def getBody(self):
 | 
						|
        # Override me or pass a string to constructor
 | 
						|
        assert self.body is not None
 | 
						|
        return self.body
 | 
						|
 | 
						|
    def declare(self, cgClass):
 | 
						|
        templateClause = '<%s>' % ', '.join(self.templateArgs) \
 | 
						|
                         if self.bodyInHeader and self.templateArgs else ''
 | 
						|
        args = ', '.join([a.declare() for a in self.args])
 | 
						|
        if self.bodyInHeader:
 | 
						|
            body = CGIndenter(CGGeneric(self.getBody())).define()
 | 
						|
            body = ' {\n' + body + '\n}'
 | 
						|
        else:
 | 
						|
            body = ';'
 | 
						|
 | 
						|
        return string.Template(
 | 
						|
            "${decorators}%s"
 | 
						|
            "${visibility}fn ${name}${templateClause}(${args})${returnType}${const}${override}${body}%s" %
 | 
						|
            (self.breakAfterReturnDecl, self.breakAfterSelf)
 | 
						|
        ).substitute({
 | 
						|
            'templateClause': templateClause,
 | 
						|
            'decorators': self.getDecorators(True),
 | 
						|
            'returnType': (" -> %s" % self.returnType) if self.returnType else "",
 | 
						|
            'name': self.name,
 | 
						|
            'const': ' const' if self.const else '',
 | 
						|
            'override': ' MOZ_OVERRIDE' if self.override else '',
 | 
						|
            'args': args,
 | 
						|
            'body': body,
 | 
						|
            'visibility': self.visibility + ' ' if self.visibility != 'priv' else ''
 | 
						|
        })
 | 
						|
 | 
						|
    def define(self, cgClass):
 | 
						|
        pass
 | 
						|
 | 
						|
 | 
						|
class ClassConstructor(ClassItem):
 | 
						|
    """
 | 
						|
    Used for adding a constructor to a CGClass.
 | 
						|
 | 
						|
    args is a list of Argument objects that are the arguments taken by the
 | 
						|
    constructor.
 | 
						|
 | 
						|
    inline should be True if the constructor should be marked inline.
 | 
						|
 | 
						|
    bodyInHeader should be True if the body should be placed in the class
 | 
						|
    declaration in the header.
 | 
						|
 | 
						|
    visibility determines the visibility of the constructor (public,
 | 
						|
    protected, private), defaults to private.
 | 
						|
 | 
						|
    explicit should be True if the constructor should be marked explicit.
 | 
						|
 | 
						|
    baseConstructors is a list of strings containing calls to base constructors,
 | 
						|
    defaults to None.
 | 
						|
 | 
						|
    body contains a string with the code for the constructor, defaults to empty.
 | 
						|
    """
 | 
						|
    def __init__(self, args, inline=False, bodyInHeader=False,
 | 
						|
                 visibility="priv", explicit=False, baseConstructors=None,
 | 
						|
                 body=""):
 | 
						|
        self.args = args
 | 
						|
        self.inline = False
 | 
						|
        self.bodyInHeader = bodyInHeader
 | 
						|
        self.explicit = explicit
 | 
						|
        self.baseConstructors = baseConstructors or []
 | 
						|
        self.body = body
 | 
						|
        ClassItem.__init__(self, None, visibility)
 | 
						|
 | 
						|
    def getDecorators(self, declaring):
 | 
						|
        decorators = []
 | 
						|
        if self.explicit:
 | 
						|
            decorators.append('explicit')
 | 
						|
        if self.inline and declaring:
 | 
						|
            decorators.append('inline')
 | 
						|
        if decorators:
 | 
						|
            return ' '.join(decorators) + ' '
 | 
						|
        return ''
 | 
						|
 | 
						|
    def getInitializationList(self, cgClass):
 | 
						|
        items = [str(c) for c in self.baseConstructors]
 | 
						|
        for m in cgClass.members:
 | 
						|
            if not m.static:
 | 
						|
                initialize = m.body
 | 
						|
                if initialize:
 | 
						|
                    items.append(m.name + "(" + initialize + ")")
 | 
						|
 | 
						|
        if len(items) > 0:
 | 
						|
            return '\n  : ' + ',\n    '.join(items)
 | 
						|
        return ''
 | 
						|
 | 
						|
    def getBody(self, cgClass):
 | 
						|
        initializers = ["    parent: %s" % str(self.baseConstructors[0])]
 | 
						|
        return (self.body + (
 | 
						|
                "let mut ret = Rc::new(%s {\n"
 | 
						|
                "%s\n"
 | 
						|
                "});\n"
 | 
						|
                "// Note: callback cannot be moved after calling init.\n"
 | 
						|
                "match Rc::get_mut(&mut ret) {\n"
 | 
						|
                "    Some(ref mut callback) => callback.parent.init(%s),\n"
 | 
						|
                "    None => unreachable!(),\n"
 | 
						|
                "};\n"
 | 
						|
                "ret") % (cgClass.name, '\n'.join(initializers), self.args[0].name))
 | 
						|
 | 
						|
    def declare(self, cgClass):
 | 
						|
        args = ', '.join([a.declare() for a in self.args])
 | 
						|
        body = '    ' + self.getBody(cgClass)
 | 
						|
        body = stripTrailingWhitespace(body.replace('\n', '\n    '))
 | 
						|
        if len(body) > 0:
 | 
						|
            body += '\n'
 | 
						|
        body = ' {\n' + body + '}'
 | 
						|
 | 
						|
        return string.Template("""\
 | 
						|
pub fn ${decorators}new(${args}) -> Rc<${className}>${body}
 | 
						|
""").substitute({'decorators': self.getDecorators(True),
 | 
						|
                 'className': cgClass.getNameString(),
 | 
						|
                 'args': args,
 | 
						|
                 'body': body})
 | 
						|
 | 
						|
    def define(self, cgClass):
 | 
						|
        if self.bodyInHeader:
 | 
						|
            return ''
 | 
						|
 | 
						|
        args = ', '.join([a.define() for a in self.args])
 | 
						|
 | 
						|
        body = '    ' + self.getBody()
 | 
						|
        body = '\n' + stripTrailingWhitespace(body.replace('\n', '\n    '))
 | 
						|
        if len(body) > 0:
 | 
						|
            body += '\n'
 | 
						|
 | 
						|
        return string.Template("""\
 | 
						|
${decorators}
 | 
						|
${className}::${className}(${args})${initializationList}
 | 
						|
{${body}}
 | 
						|
""").substitute({'decorators': self.getDecorators(False),
 | 
						|
                 'className': cgClass.getNameString(),
 | 
						|
                 'args': args,
 | 
						|
                 'initializationList': self.getInitializationList(cgClass),
 | 
						|
                 'body': body})
 | 
						|
 | 
						|
 | 
						|
class ClassMember(ClassItem):
 | 
						|
    def __init__(self, name, type, visibility="priv", static=False,
 | 
						|
                 body=None):
 | 
						|
        self.type = type
 | 
						|
        self.static = static
 | 
						|
        self.body = body
 | 
						|
        ClassItem.__init__(self, name, visibility)
 | 
						|
 | 
						|
    def declare(self, cgClass):
 | 
						|
        return '%s %s: %s,\n' % (self.visibility, self.name, self.type)
 | 
						|
 | 
						|
    def define(self, cgClass):
 | 
						|
        if not self.static:
 | 
						|
            return ''
 | 
						|
        if self.body:
 | 
						|
            body = " = " + self.body
 | 
						|
        else:
 | 
						|
            body = ""
 | 
						|
        return '%s %s::%s%s;\n' % (self.type, cgClass.getNameString(),
 | 
						|
                                   self.name, body)
 | 
						|
 | 
						|
 | 
						|
class CGClass(CGThing):
 | 
						|
    def __init__(self, name, bases=[], members=[], constructors=[],
 | 
						|
                 destructor=None, methods=[],
 | 
						|
                 typedefs=[], enums=[], unions=[], templateArgs=[],
 | 
						|
                 templateSpecialization=[],
 | 
						|
                 disallowCopyConstruction=False, indent='',
 | 
						|
                 decorators='',
 | 
						|
                 extradeclarations=''):
 | 
						|
        CGThing.__init__(self)
 | 
						|
        self.name = name
 | 
						|
        self.bases = bases
 | 
						|
        self.members = members
 | 
						|
        self.constructors = constructors
 | 
						|
        # We store our single destructor in a list, since all of our
 | 
						|
        # code wants lists of members.
 | 
						|
        self.destructors = [destructor] if destructor else []
 | 
						|
        self.methods = methods
 | 
						|
        self.typedefs = typedefs
 | 
						|
        self.enums = enums
 | 
						|
        self.unions = unions
 | 
						|
        self.templateArgs = templateArgs
 | 
						|
        self.templateSpecialization = templateSpecialization
 | 
						|
        self.disallowCopyConstruction = disallowCopyConstruction
 | 
						|
        self.indent = indent
 | 
						|
        self.decorators = decorators
 | 
						|
        self.extradeclarations = extradeclarations
 | 
						|
 | 
						|
    def getNameString(self):
 | 
						|
        className = self.name
 | 
						|
        if self.templateSpecialization:
 | 
						|
            className = className + \
 | 
						|
                '<%s>' % ', '.join([str(a) for a
 | 
						|
                                    in self.templateSpecialization])
 | 
						|
        return className
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        result = ''
 | 
						|
        if self.templateArgs:
 | 
						|
            templateArgs = [a.declare() for a in self.templateArgs]
 | 
						|
            templateArgs = templateArgs[len(self.templateSpecialization):]
 | 
						|
            result = result + self.indent + 'template <%s>\n' % ','.join([str(a) for a in templateArgs])
 | 
						|
 | 
						|
        if self.templateSpecialization:
 | 
						|
            specialization = \
 | 
						|
                '<%s>' % ', '.join([str(a) for a in self.templateSpecialization])
 | 
						|
        else:
 | 
						|
            specialization = ''
 | 
						|
 | 
						|
        myself = ''
 | 
						|
        if self.decorators != '':
 | 
						|
            myself += self.decorators + '\n'
 | 
						|
        myself += '%spub struct %s%s' % (self.indent, self.name, specialization)
 | 
						|
        result += myself
 | 
						|
 | 
						|
        assert len(self.bases) == 1  # XXjdm Can we support multiple inheritance?
 | 
						|
 | 
						|
        result += ' {\n'
 | 
						|
 | 
						|
        if self.bases:
 | 
						|
            self.members = [ClassMember("parent", self.bases[0].name, "pub")] + self.members
 | 
						|
 | 
						|
        result += CGIndenter(CGGeneric(self.extradeclarations),
 | 
						|
                             len(self.indent)).define()
 | 
						|
 | 
						|
        def declareMembers(cgClass, memberList):
 | 
						|
            result = ''
 | 
						|
 | 
						|
            for member in memberList:
 | 
						|
                declaration = member.declare(cgClass)
 | 
						|
                declaration = CGIndenter(CGGeneric(declaration)).define()
 | 
						|
                result = result + declaration
 | 
						|
            return result
 | 
						|
 | 
						|
        if self.disallowCopyConstruction:
 | 
						|
            class DisallowedCopyConstructor(object):
 | 
						|
                def __init__(self):
 | 
						|
                    self.visibility = "private"
 | 
						|
 | 
						|
                def declare(self, cgClass):
 | 
						|
                    name = cgClass.getNameString()
 | 
						|
                    return ("%s(const %s&) MOZ_DELETE;\n"
 | 
						|
                            "void operator=(const %s) MOZ_DELETE;\n" % (name, name, name))
 | 
						|
            disallowedCopyConstructors = [DisallowedCopyConstructor()]
 | 
						|
        else:
 | 
						|
            disallowedCopyConstructors = []
 | 
						|
 | 
						|
        order = [(self.enums, ''), (self.unions, ''),
 | 
						|
                 (self.typedefs, ''), (self.members, '')]
 | 
						|
 | 
						|
        for (memberList, separator) in order:
 | 
						|
            memberString = declareMembers(self, memberList)
 | 
						|
            if self.indent:
 | 
						|
                memberString = CGIndenter(CGGeneric(memberString),
 | 
						|
                                          len(self.indent)).define()
 | 
						|
            result = result + memberString
 | 
						|
 | 
						|
        result += self.indent + '}\n\n'
 | 
						|
        result += 'impl %s {\n' % self.name
 | 
						|
 | 
						|
        order = [(self.constructors + disallowedCopyConstructors, '\n'),
 | 
						|
                 (self.destructors, '\n'), (self.methods, '\n)')]
 | 
						|
        for (memberList, separator) in order:
 | 
						|
            memberString = declareMembers(self, memberList)
 | 
						|
            if self.indent:
 | 
						|
                memberString = CGIndenter(CGGeneric(memberString),
 | 
						|
                                          len(self.indent)).define()
 | 
						|
            result = result + memberString
 | 
						|
 | 
						|
        result += "}"
 | 
						|
        return result
 | 
						|
 | 
						|
 | 
						|
class CGProxySpecialOperation(CGPerSignatureCall):
 | 
						|
    """
 | 
						|
    Base class for classes for calling an indexed or named special operation
 | 
						|
    (don't use this directly, use the derived classes below).
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor, operation):
 | 
						|
        nativeName = MakeNativeName(descriptor.binaryNameFor(operation))
 | 
						|
        operation = descriptor.operations[operation]
 | 
						|
        assert len(operation.signatures()) == 1
 | 
						|
        signature = operation.signatures()[0]
 | 
						|
 | 
						|
        (returnType, arguments) = signature
 | 
						|
 | 
						|
        # We pass len(arguments) as the final argument so that the
 | 
						|
        # CGPerSignatureCall won't do any argument conversion of its own.
 | 
						|
        CGPerSignatureCall.__init__(self, returnType, "", arguments, nativeName,
 | 
						|
                                    False, descriptor, operation,
 | 
						|
                                    len(arguments))
 | 
						|
 | 
						|
        if operation.isSetter() or operation.isCreator():
 | 
						|
            # arguments[0] is the index or name of the item that we're setting.
 | 
						|
            argument = arguments[1]
 | 
						|
            info = getJSToNativeConversionInfo(
 | 
						|
                argument.type, descriptor, treatNullAs=argument.treatNullAs,
 | 
						|
                exceptionCode="return false;")
 | 
						|
            template = info.template
 | 
						|
            declType = info.declType
 | 
						|
            needsRooting = info.needsRooting
 | 
						|
 | 
						|
            templateValues = {
 | 
						|
                "val": "value.handle()",
 | 
						|
            }
 | 
						|
            self.cgRoot.prepend(instantiateJSToNativeConversionTemplate(
 | 
						|
                template, templateValues, declType, argument.identifier.name,
 | 
						|
                needsRooting))
 | 
						|
            self.cgRoot.prepend(CGGeneric("let value = RootedValue::new(cx, desc.get().value);"))
 | 
						|
        elif operation.isGetter():
 | 
						|
            self.cgRoot.prepend(CGGeneric("let mut found = false;"))
 | 
						|
 | 
						|
    def getArguments(self):
 | 
						|
        def process(arg):
 | 
						|
            argVal = arg.identifier.name
 | 
						|
            if arg.type.isGeckoInterface() and not arg.type.unroll().inner.isCallback():
 | 
						|
                argVal += ".r()"
 | 
						|
            return argVal
 | 
						|
        args = [(a, process(a)) for a in self.arguments]
 | 
						|
        if self.idlNode.isGetter():
 | 
						|
            args.append((FakeArgument(BuiltinTypes[IDLBuiltinType.Types.boolean],
 | 
						|
                                      self.idlNode),
 | 
						|
                         "&mut found"))
 | 
						|
        return args
 | 
						|
 | 
						|
    def wrap_return_value(self):
 | 
						|
        if not self.idlNode.isGetter() or self.templateValues is None:
 | 
						|
            return ""
 | 
						|
 | 
						|
        wrap = CGGeneric(wrapForType(**self.templateValues))
 | 
						|
        wrap = CGIfWrapper(wrap, "found")
 | 
						|
        return "\n" + wrap.define()
 | 
						|
 | 
						|
 | 
						|
class CGProxyIndexedGetter(CGProxySpecialOperation):
 | 
						|
    """
 | 
						|
    Class to generate a call to an indexed getter. If templateValues is not None
 | 
						|
    the returned value will be wrapped with wrapForType using templateValues.
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor, templateValues=None):
 | 
						|
        self.templateValues = templateValues
 | 
						|
        CGProxySpecialOperation.__init__(self, descriptor, 'IndexedGetter')
 | 
						|
 | 
						|
 | 
						|
class CGProxyIndexedSetter(CGProxySpecialOperation):
 | 
						|
    """
 | 
						|
    Class to generate a call to an indexed setter.
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        CGProxySpecialOperation.__init__(self, descriptor, 'IndexedSetter')
 | 
						|
 | 
						|
 | 
						|
class CGProxyNamedOperation(CGProxySpecialOperation):
 | 
						|
    """
 | 
						|
    Class to generate a call to a named operation.
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor, name):
 | 
						|
        CGProxySpecialOperation.__init__(self, descriptor, name)
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        # Our first argument is the id we're getting.
 | 
						|
        argName = self.arguments[0].identifier.name
 | 
						|
        return ("let %s = jsid_to_str(cx, id);\n"
 | 
						|
                "let this = UnwrapProxy(proxy);\n"
 | 
						|
                "let this = &*this;\n" % argName +
 | 
						|
                CGProxySpecialOperation.define(self))
 | 
						|
 | 
						|
 | 
						|
class CGProxyNamedGetter(CGProxyNamedOperation):
 | 
						|
    """
 | 
						|
    Class to generate a call to an named getter. If templateValues is not None
 | 
						|
    the returned value will be wrapped with wrapForType using templateValues.
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor, templateValues=None):
 | 
						|
        self.templateValues = templateValues
 | 
						|
        CGProxySpecialOperation.__init__(self, descriptor, 'NamedGetter')
 | 
						|
 | 
						|
 | 
						|
class CGProxyNamedPresenceChecker(CGProxyNamedGetter):
 | 
						|
    """
 | 
						|
    Class to generate a call that checks whether a named property exists.
 | 
						|
    For now, we just delegate to CGProxyNamedGetter
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        CGProxyNamedGetter.__init__(self, descriptor)
 | 
						|
 | 
						|
 | 
						|
class CGProxyNamedSetter(CGProxyNamedOperation):
 | 
						|
    """
 | 
						|
    Class to generate a call to a named setter.
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        CGProxySpecialOperation.__init__(self, descriptor, 'NamedSetter')
 | 
						|
 | 
						|
 | 
						|
class CGProxyNamedDeleter(CGProxyNamedOperation):
 | 
						|
    """
 | 
						|
    Class to generate a call to a named deleter.
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        CGProxySpecialOperation.__init__(self, descriptor, 'NamedDeleter')
 | 
						|
 | 
						|
 | 
						|
class CGProxyUnwrap(CGAbstractMethod):
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        args = [Argument('HandleObject', 'obj')]
 | 
						|
        CGAbstractMethod.__init__(self, descriptor, "UnwrapProxy",
 | 
						|
                                  '*const ' + descriptor.concreteType, args,
 | 
						|
                                  alwaysInline=True, unsafe=True)
 | 
						|
 | 
						|
    def definition_body(self):
 | 
						|
        return CGGeneric("""\
 | 
						|
/*if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
 | 
						|
    obj = js::UnwrapObject(obj);
 | 
						|
}*/
 | 
						|
//MOZ_ASSERT(IsProxy(obj));
 | 
						|
let box_ = GetProxyPrivate(*obj.ptr).to_private() as *const %s;
 | 
						|
return box_;""" % self.descriptor.concreteType)
 | 
						|
 | 
						|
 | 
						|
class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod):
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'),
 | 
						|
                Argument('HandleId', 'id'),
 | 
						|
                Argument('MutableHandle<JSPropertyDescriptor>', 'desc')]
 | 
						|
        CGAbstractExternMethod.__init__(self, descriptor, "getOwnPropertyDescriptor",
 | 
						|
                                        "bool", args)
 | 
						|
        self.descriptor = descriptor
 | 
						|
 | 
						|
    def getBody(self):
 | 
						|
        indexedGetter = self.descriptor.operations['IndexedGetter']
 | 
						|
        indexedSetter = self.descriptor.operations['IndexedSetter']
 | 
						|
 | 
						|
        get = ""
 | 
						|
        if indexedGetter or indexedSetter:
 | 
						|
            get = "let index = get_array_index_from_id(cx, id);\n"
 | 
						|
 | 
						|
        if indexedGetter:
 | 
						|
            readonly = toStringBool(self.descriptor.operations['IndexedSetter'] is None)
 | 
						|
            fillDescriptor = ("desc.get().value = result_root.ptr;\n"
 | 
						|
                              "fill_property_descriptor(&mut *desc.ptr, *proxy.ptr, %s);\n"
 | 
						|
                              "return true;" % readonly)
 | 
						|
            templateValues = {
 | 
						|
                'jsvalRef': 'result_root.handle_mut()',
 | 
						|
                'successCode': fillDescriptor,
 | 
						|
                'pre': 'let mut result_root = RootedValue::new(cx, UndefinedValue());'
 | 
						|
            }
 | 
						|
            get += ("if let Some(index) = index {\n" +
 | 
						|
                    "    let this = UnwrapProxy(proxy);\n" +
 | 
						|
                    "    let this = &*this;\n" +
 | 
						|
                    CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define() + "\n" +
 | 
						|
                    "}\n")
 | 
						|
 | 
						|
        namedGetter = self.descriptor.operations['NamedGetter']
 | 
						|
        if namedGetter:
 | 
						|
            readonly = toStringBool(self.descriptor.operations['NamedSetter'] is None)
 | 
						|
            fillDescriptor = ("desc.get().value = result_root.ptr;\n"
 | 
						|
                              "fill_property_descriptor(&mut *desc.ptr, *proxy.ptr, %s);\n"
 | 
						|
                              "return true;" % readonly)
 | 
						|
            templateValues = {
 | 
						|
                'jsvalRef': 'result_root.handle_mut()',
 | 
						|
                'successCode': fillDescriptor,
 | 
						|
                'pre': 'let mut result_root = RootedValue::new(cx, UndefinedValue());'
 | 
						|
            }
 | 
						|
            # Once we start supporting OverrideBuiltins we need to make
 | 
						|
            # ResolveOwnProperty or EnumerateOwnProperties filter out named
 | 
						|
            # properties that shadow prototype properties.
 | 
						|
            namedGet = ("\n" +
 | 
						|
                        "if RUST_JSID_IS_STRING(id) && !has_property_on_prototype(cx, proxy, id) {\n" +
 | 
						|
                        CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() + "\n" +
 | 
						|
                        "}\n")
 | 
						|
        else:
 | 
						|
            namedGet = ""
 | 
						|
 | 
						|
        return get + """\
 | 
						|
let expando = RootedObject::new(cx, get_expando_object(proxy));
 | 
						|
//if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) {
 | 
						|
if !expando.ptr.is_null() {
 | 
						|
    if !JS_GetPropertyDescriptorById(cx, expando.handle(), id, desc) {
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
    if !desc.get().obj.is_null() {
 | 
						|
        // Pretend the property lives on the wrapper.
 | 
						|
        desc.get().obj = *proxy.ptr;
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
}
 | 
						|
""" + namedGet + """\
 | 
						|
desc.get().obj = ptr::null_mut();
 | 
						|
return true;"""
 | 
						|
 | 
						|
    def definition_body(self):
 | 
						|
        return CGGeneric(self.getBody())
 | 
						|
 | 
						|
 | 
						|
# TODO(Issue 5876)
 | 
						|
class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod):
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'),
 | 
						|
                Argument('HandleId', 'id'),
 | 
						|
                Argument('Handle<JSPropertyDescriptor>', 'desc'),
 | 
						|
                Argument('*mut ObjectOpResult', 'opresult')]
 | 
						|
        CGAbstractExternMethod.__init__(self, descriptor, "defineProperty", "bool", args)
 | 
						|
        self.descriptor = descriptor
 | 
						|
 | 
						|
    def getBody(self):
 | 
						|
        set = ""
 | 
						|
 | 
						|
        indexedSetter = self.descriptor.operations['IndexedSetter']
 | 
						|
        if indexedSetter:
 | 
						|
            set += ("let index = get_array_index_from_id(cx, id);\n" +
 | 
						|
                    "if let Some(index) = index {\n" +
 | 
						|
                    "    let this = UnwrapProxy(proxy);\n" +
 | 
						|
                    "    let this = &*this;\n" +
 | 
						|
                    CGIndenter(CGProxyIndexedSetter(self.descriptor)).define() +
 | 
						|
                    "    return true;\n" +
 | 
						|
                    "}\n")
 | 
						|
        elif self.descriptor.operations['IndexedGetter']:
 | 
						|
            set += ("if get_array_index_from_id(cx, id).is_some() {\n" +
 | 
						|
                    "    return false;\n" +
 | 
						|
                    "    //return ThrowErrorMessage(cx, MSG_NO_PROPERTY_SETTER, \"%s\");\n" +
 | 
						|
                    "}\n") % self.descriptor.name
 | 
						|
 | 
						|
        namedSetter = self.descriptor.operations['NamedSetter']
 | 
						|
        if namedSetter:
 | 
						|
            set += ("if RUST_JSID_IS_STRING(id) {\n" +
 | 
						|
                    CGIndenter(CGProxyNamedSetter(self.descriptor)).define() +
 | 
						|
                    "    (*opresult).code_ = 0; /* SpecialCodes::OkCode */\n" +
 | 
						|
                    "    return true;\n" +
 | 
						|
                    "} else {\n" +
 | 
						|
                    "    return false;\n" +
 | 
						|
                    "}\n")
 | 
						|
        else:
 | 
						|
            set += ("if RUST_JSID_IS_STRING(id) {\n" +
 | 
						|
                    CGIndenter(CGProxyNamedGetter(self.descriptor)).define() +
 | 
						|
                    "    if (found) {\n"
 | 
						|
                    # TODO(Issue 5876)
 | 
						|
                    "        //return js::IsInNonStrictPropertySet(cx)\n" +
 | 
						|
                    "        //       ? opresult.succeed()\n" +
 | 
						|
                    "        //       : ThrowErrorMessage(cx, MSG_NO_NAMED_SETTER, \"${name}\");\n" +
 | 
						|
                    "        (*opresult).code_ = 0; /* SpecialCodes::OkCode */\n" +
 | 
						|
                    "        return true;\n" +
 | 
						|
                    "    }\n" +
 | 
						|
                    "    (*opresult).code_ = 0; /* SpecialCodes::OkCode */\n" +
 | 
						|
                    "    return true;\n"
 | 
						|
                    "}\n") % (self.descriptor.name, self.descriptor.name)
 | 
						|
            set += "return proxyhandler::define_property(%s);" % ", ".join(a.name for a in self.args)
 | 
						|
        return set
 | 
						|
 | 
						|
    def definition_body(self):
 | 
						|
        return CGGeneric(self.getBody())
 | 
						|
 | 
						|
 | 
						|
class CGDOMJSProxyHandler_delete(CGAbstractExternMethod):
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'),
 | 
						|
                Argument('HandleId', 'id'),
 | 
						|
                Argument('*mut ObjectOpResult', 'res')]
 | 
						|
        CGAbstractExternMethod.__init__(self, descriptor, "delete", "bool", args)
 | 
						|
        self.descriptor = descriptor
 | 
						|
 | 
						|
    def getBody(self):
 | 
						|
        set = ""
 | 
						|
        if self.descriptor.operations['NamedDeleter']:
 | 
						|
            set += CGProxyNamedDeleter(self.descriptor).define()
 | 
						|
        set += "return proxyhandler::delete(%s);" % ", ".join(a.name for a in self.args)
 | 
						|
        return set
 | 
						|
 | 
						|
    def definition_body(self):
 | 
						|
        return CGGeneric(self.getBody())
 | 
						|
 | 
						|
 | 
						|
class CGDOMJSProxyHandler_ownPropertyKeys(CGAbstractExternMethod):
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        args = [Argument('*mut JSContext', 'cx'),
 | 
						|
                Argument('HandleObject', 'proxy'),
 | 
						|
                Argument('*mut AutoIdVector', 'props')]
 | 
						|
        CGAbstractExternMethod.__init__(self, descriptor, "own_property_keys", "bool", args)
 | 
						|
        self.descriptor = descriptor
 | 
						|
 | 
						|
    def getBody(self):
 | 
						|
        body = dedent(
 | 
						|
            """
 | 
						|
            let unwrapped_proxy = UnwrapProxy(proxy);
 | 
						|
            """)
 | 
						|
 | 
						|
        if self.descriptor.operations['IndexedGetter']:
 | 
						|
            body += dedent(
 | 
						|
                """
 | 
						|
                for i in 0..(*unwrapped_proxy).Length() {
 | 
						|
                    let rooted_jsid = RootedId::new(cx, int_to_jsid(i as i32));
 | 
						|
                    AppendToAutoIdVector(props, rooted_jsid.handle().get());
 | 
						|
                }
 | 
						|
                """)
 | 
						|
 | 
						|
        if self.descriptor.operations['NamedGetter']:
 | 
						|
            body += dedent(
 | 
						|
                """
 | 
						|
                for name in (*unwrapped_proxy).SupportedPropertyNames() {
 | 
						|
                    let cstring = CString::new(name).unwrap();
 | 
						|
                    let jsstring = JS_InternString(cx, cstring.as_ptr());
 | 
						|
                    let rooted = RootedString::new(cx, jsstring);
 | 
						|
                    let jsid = INTERNED_STRING_TO_JSID(cx, rooted.handle().get());
 | 
						|
                    let rooted_jsid = RootedId::new(cx, jsid);
 | 
						|
                    AppendToAutoIdVector(props, rooted_jsid.handle().get());
 | 
						|
                }
 | 
						|
                """)
 | 
						|
 | 
						|
        body += dedent(
 | 
						|
            """
 | 
						|
            let expando = get_expando_object(proxy);
 | 
						|
            if !expando.is_null() {
 | 
						|
                let rooted_expando = RootedObject::new(cx, expando);
 | 
						|
                GetPropertyKeys(cx, rooted_expando.handle(), JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props);
 | 
						|
            }
 | 
						|
 | 
						|
            return true;
 | 
						|
            """)
 | 
						|
 | 
						|
        return body
 | 
						|
 | 
						|
    def definition_body(self):
 | 
						|
        return CGGeneric(self.getBody())
 | 
						|
 | 
						|
 | 
						|
class CGDOMJSProxyHandler_hasOwn(CGAbstractExternMethod):
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'),
 | 
						|
                Argument('HandleId', 'id'), Argument('*mut bool', 'bp')]
 | 
						|
        CGAbstractExternMethod.__init__(self, descriptor, "hasOwn", "bool", args)
 | 
						|
        self.descriptor = descriptor
 | 
						|
 | 
						|
    def getBody(self):
 | 
						|
        indexedGetter = self.descriptor.operations['IndexedGetter']
 | 
						|
        if indexedGetter:
 | 
						|
            indexed = ("let index = get_array_index_from_id(cx, id);\n" +
 | 
						|
                       "if let Some(index) = index {\n" +
 | 
						|
                       "    let this = UnwrapProxy(proxy);\n" +
 | 
						|
                       "    let this = &*this;\n" +
 | 
						|
                       CGIndenter(CGProxyIndexedGetter(self.descriptor)).define() + "\n" +
 | 
						|
                       "    *bp = found;\n" +
 | 
						|
                       "    return true;\n" +
 | 
						|
                       "}\n\n")
 | 
						|
        else:
 | 
						|
            indexed = ""
 | 
						|
 | 
						|
        namedGetter = self.descriptor.operations['NamedGetter']
 | 
						|
        if namedGetter:
 | 
						|
            named = ("if RUST_JSID_IS_STRING(id) && !has_property_on_prototype(cx, proxy, id) {\n" +
 | 
						|
                     CGIndenter(CGProxyNamedGetter(self.descriptor)).define() + "\n" +
 | 
						|
                     "    *bp = found;\n"
 | 
						|
                     "    return true;\n"
 | 
						|
                     "}\n" +
 | 
						|
                     "\n")
 | 
						|
        else:
 | 
						|
            named = ""
 | 
						|
 | 
						|
        return indexed + """\
 | 
						|
let expando = RootedObject::new(cx, get_expando_object(proxy));
 | 
						|
if !expando.ptr.is_null() {
 | 
						|
    let mut b = true;
 | 
						|
    let ok = JS_HasPropertyById(cx, expando.handle(), id, &mut b);
 | 
						|
    *bp = b;
 | 
						|
    if !ok || *bp {
 | 
						|
        return ok;
 | 
						|
    }
 | 
						|
}
 | 
						|
""" + named + """\
 | 
						|
*bp = false;
 | 
						|
return true;"""
 | 
						|
 | 
						|
    def definition_body(self):
 | 
						|
        return CGGeneric(self.getBody())
 | 
						|
 | 
						|
 | 
						|
class CGDOMJSProxyHandler_get(CGAbstractExternMethod):
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'),
 | 
						|
                Argument('HandleObject', '_receiver'), Argument('HandleId', 'id'),
 | 
						|
                Argument('MutableHandleValue', 'vp')]
 | 
						|
        CGAbstractExternMethod.__init__(self, descriptor, "get", "bool", args)
 | 
						|
        self.descriptor = descriptor
 | 
						|
 | 
						|
    def getBody(self):
 | 
						|
        getFromExpando = """\
 | 
						|
let expando = RootedObject::new(cx, get_expando_object(proxy));
 | 
						|
if !expando.ptr.is_null() {
 | 
						|
    let mut hasProp = false;
 | 
						|
    if !JS_HasPropertyById(cx, expando.handle(), id, &mut hasProp) {
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    if hasProp {
 | 
						|
        return JS_GetPropertyById(cx, expando.handle(), id, vp);
 | 
						|
    }
 | 
						|
}"""
 | 
						|
 | 
						|
        templateValues = {
 | 
						|
            'jsvalRef': 'vp',
 | 
						|
            'successCode': 'return true;',
 | 
						|
        }
 | 
						|
 | 
						|
        indexedGetter = self.descriptor.operations['IndexedGetter']
 | 
						|
        if indexedGetter:
 | 
						|
            getIndexedOrExpando = ("let index = get_array_index_from_id(cx, id);\n" +
 | 
						|
                                   "if let Some(index) = index {\n" +
 | 
						|
                                   "    let this = UnwrapProxy(proxy);\n" +
 | 
						|
                                   "    let this = &*this;\n" +
 | 
						|
                                   CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define())
 | 
						|
            getIndexedOrExpando += """\
 | 
						|
    // Even if we don't have this index, we don't forward the
 | 
						|
    // get on to our expando object.
 | 
						|
} else {
 | 
						|
    %s
 | 
						|
}
 | 
						|
""" % (stripTrailingWhitespace(getFromExpando.replace('\n', '\n    ')))
 | 
						|
        else:
 | 
						|
            getIndexedOrExpando = getFromExpando + "\n"
 | 
						|
 | 
						|
        namedGetter = self.descriptor.operations['NamedGetter']
 | 
						|
        if namedGetter:
 | 
						|
            getNamed = ("if RUST_JSID_IS_STRING(id) {\n" +
 | 
						|
                        CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() +
 | 
						|
                        "}\n")
 | 
						|
        else:
 | 
						|
            getNamed = ""
 | 
						|
 | 
						|
        return """\
 | 
						|
//MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
 | 
						|
//"Should not have a XrayWrapper here");
 | 
						|
 | 
						|
%s
 | 
						|
let mut found = false;
 | 
						|
if !get_property_on_prototype(cx, proxy, id, &mut found, vp) {
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
if found {
 | 
						|
    return true;
 | 
						|
}
 | 
						|
%s
 | 
						|
*vp.ptr = UndefinedValue();
 | 
						|
return true;""" % (getIndexedOrExpando, getNamed)
 | 
						|
 | 
						|
    def definition_body(self):
 | 
						|
        return CGGeneric(self.getBody())
 | 
						|
 | 
						|
 | 
						|
class CGDOMJSProxyHandler_className(CGAbstractExternMethod):
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', '_proxy')]
 | 
						|
        CGAbstractExternMethod.__init__(self, descriptor, "className", "*const i8", args)
 | 
						|
        self.descriptor = descriptor
 | 
						|
 | 
						|
    def getBody(self):
 | 
						|
        return '%s as *const u8 as *const i8' % str_to_const_array(self.descriptor.name)
 | 
						|
 | 
						|
    def definition_body(self):
 | 
						|
        return CGGeneric(self.getBody())
 | 
						|
 | 
						|
 | 
						|
class CGAbstractClassHook(CGAbstractExternMethod):
 | 
						|
    """
 | 
						|
    Meant for implementing JSClass hooks, like Finalize or Trace. Does very raw
 | 
						|
    'this' unwrapping as it assumes that the unwrapped type is always known.
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor, name, returnType, args):
 | 
						|
        CGAbstractExternMethod.__init__(self, descriptor, name, returnType,
 | 
						|
                                        args)
 | 
						|
 | 
						|
    def definition_body_prologue(self):
 | 
						|
        return CGGeneric("""\
 | 
						|
let this: *const %s = native_from_reflector::<%s>(obj);
 | 
						|
""" % (self.descriptor.concreteType, self.descriptor.concreteType))
 | 
						|
 | 
						|
    def definition_body(self):
 | 
						|
        return CGList([
 | 
						|
            self.definition_body_prologue(),
 | 
						|
            self.generate_code(),
 | 
						|
        ])
 | 
						|
 | 
						|
    def generate_code(self):
 | 
						|
        raise NotImplementedError  # Override me!
 | 
						|
 | 
						|
 | 
						|
def finalizeHook(descriptor, hookName, context):
 | 
						|
    release = ""
 | 
						|
    if descriptor.isGlobal():
 | 
						|
        release += """\
 | 
						|
finalize_global(obj);
 | 
						|
"""
 | 
						|
    release += """\
 | 
						|
let _ = Box::from_raw(this as *mut %s);
 | 
						|
debug!("%s finalize: {:p}", this);\
 | 
						|
""" % (descriptor.concreteType, descriptor.concreteType)
 | 
						|
    return release
 | 
						|
 | 
						|
 | 
						|
class CGClassTraceHook(CGAbstractClassHook):
 | 
						|
    """
 | 
						|
    A hook to trace through our native object; used for GC and CC
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        args = [Argument('*mut JSTracer', 'trc'), Argument('*mut JSObject', 'obj')]
 | 
						|
        CGAbstractClassHook.__init__(self, descriptor, TRACE_HOOK_NAME, 'void',
 | 
						|
                                     args)
 | 
						|
        self.traceGlobal = descriptor.isGlobal()
 | 
						|
 | 
						|
    def generate_code(self):
 | 
						|
        body = [CGGeneric("if this.is_null() { return; } // GC during obj creation\n"
 | 
						|
                          "(*this).trace(%s);" % self.args[0].name)]
 | 
						|
        if self.traceGlobal:
 | 
						|
            body += [CGGeneric("trace_global(trc, obj);")]
 | 
						|
        return CGList(body, "\n")
 | 
						|
 | 
						|
 | 
						|
class CGClassConstructHook(CGAbstractExternMethod):
 | 
						|
    """
 | 
						|
    JS-visible constructor for our objects
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        args = [Argument('*mut JSContext', 'cx'), Argument('u32', 'argc'), Argument('*mut JSVal', 'vp')]
 | 
						|
        CGAbstractExternMethod.__init__(self, descriptor, CONSTRUCT_HOOK_NAME,
 | 
						|
                                        'bool', args)
 | 
						|
        self._ctor = self.descriptor.interface.ctor()
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        if not self._ctor:
 | 
						|
            return ""
 | 
						|
        return CGAbstractExternMethod.define(self)
 | 
						|
 | 
						|
    def definition_body(self):
 | 
						|
        preamble = CGGeneric("""\
 | 
						|
let global = global_object_for_js_object(JS_CALLEE(cx, vp).to_object());
 | 
						|
let args = CallArgs::from_vp(vp, argc);
 | 
						|
""")
 | 
						|
        name = self._ctor.identifier.name
 | 
						|
        nativeName = MakeNativeName(self.descriptor.binaryNameFor(name))
 | 
						|
        callGenerator = CGMethodCall(["global.r()"], nativeName, True,
 | 
						|
                                     self.descriptor, self._ctor)
 | 
						|
        return CGList([preamble, callGenerator])
 | 
						|
 | 
						|
 | 
						|
class CGClassNameConstructHook(CGAbstractExternMethod):
 | 
						|
    """
 | 
						|
    JS-visible named constructor for our objects
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor, ctor):
 | 
						|
        args = [Argument('*mut JSContext', 'cx'), Argument('u32', 'argc'), Argument('*mut JSVal', 'vp')]
 | 
						|
        self._ctor = ctor
 | 
						|
        CGAbstractExternMethod.__init__(self, descriptor,
 | 
						|
                                        CONSTRUCT_HOOK_NAME + "_" +
 | 
						|
                                        self._ctor.identifier.name,
 | 
						|
                                        'bool', args)
 | 
						|
 | 
						|
    def definition_body(self):
 | 
						|
        preamble = CGGeneric("""\
 | 
						|
let global = global_object_for_js_object(JS_CALLEE(cx, vp).to_object());
 | 
						|
let args = CallArgs::from_vp(vp, argc);
 | 
						|
""")
 | 
						|
        name = self._ctor.identifier.name
 | 
						|
        nativeName = MakeNativeName(self.descriptor.binaryNameFor(name))
 | 
						|
        callGenerator = CGMethodCall(["global.r()"], nativeName, True,
 | 
						|
                                     self.descriptor, self._ctor)
 | 
						|
        return CGList([preamble, callGenerator])
 | 
						|
 | 
						|
 | 
						|
class CGClassFinalizeHook(CGAbstractClassHook):
 | 
						|
    """
 | 
						|
    A hook for finalize, used to release our native object.
 | 
						|
    """
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        args = [Argument('*mut FreeOp', '_fop'), Argument('*mut JSObject', 'obj')]
 | 
						|
        CGAbstractClassHook.__init__(self, descriptor, FINALIZE_HOOK_NAME,
 | 
						|
                                     'void', args)
 | 
						|
 | 
						|
    def generate_code(self):
 | 
						|
        return CGGeneric(finalizeHook(self.descriptor, self.name, self.args[0].name))
 | 
						|
 | 
						|
 | 
						|
class CGDOMJSProxyHandlerDOMClass(CGThing):
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        CGThing.__init__(self)
 | 
						|
        self.descriptor = descriptor
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        return "static Class: DOMClass = " + DOMClass(self.descriptor) + ";\n"
 | 
						|
 | 
						|
 | 
						|
class CGInterfaceTrait(CGThing):
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        CGThing.__init__(self)
 | 
						|
 | 
						|
        def attribute_arguments(needCx, argument=None):
 | 
						|
            if needCx:
 | 
						|
                yield "cx", "*mut JSContext"
 | 
						|
 | 
						|
            if argument:
 | 
						|
                yield "value", argument_type(descriptor, argument)
 | 
						|
 | 
						|
        def members():
 | 
						|
            for m in descriptor.interface.members:
 | 
						|
                if (m.isMethod() and not m.isStatic() and
 | 
						|
                        (not m.isIdentifierLess() or m.isStringifier())):
 | 
						|
                    name = CGSpecializedMethod.makeNativeName(descriptor, m)
 | 
						|
                    infallible = 'infallible' in descriptor.getExtendedAttributes(m)
 | 
						|
                    for idx, (rettype, arguments) in enumerate(m.signatures()):
 | 
						|
                        arguments = method_arguments(descriptor, rettype, arguments)
 | 
						|
                        rettype = return_type(descriptor, rettype, infallible)
 | 
						|
                        yield name + ('_' * idx), arguments, rettype
 | 
						|
                elif m.isAttr() and not m.isStatic():
 | 
						|
                    name = CGSpecializedGetter.makeNativeName(descriptor, m)
 | 
						|
                    infallible = 'infallible' in descriptor.getExtendedAttributes(m, getter=True)
 | 
						|
                    yield (name,
 | 
						|
                           attribute_arguments(typeNeedsCx(m.type, True)),
 | 
						|
                           return_type(descriptor, m.type, infallible))
 | 
						|
 | 
						|
                    if not m.readonly:
 | 
						|
                        name = CGSpecializedSetter.makeNativeName(descriptor, m)
 | 
						|
                        infallible = 'infallible' in descriptor.getExtendedAttributes(m, setter=True)
 | 
						|
                        if infallible:
 | 
						|
                            rettype = "()"
 | 
						|
                        else:
 | 
						|
                            rettype = "ErrorResult"
 | 
						|
                        yield name, attribute_arguments(typeNeedsCx(m.type, False), m.type), rettype
 | 
						|
 | 
						|
            if descriptor.proxy:
 | 
						|
                for name, operation in descriptor.operations.iteritems():
 | 
						|
                    if not operation or operation.isStringifier():
 | 
						|
                        continue
 | 
						|
 | 
						|
                    assert len(operation.signatures()) == 1
 | 
						|
                    rettype, arguments = operation.signatures()[0]
 | 
						|
 | 
						|
                    infallible = 'infallible' in descriptor.getExtendedAttributes(operation)
 | 
						|
                    if operation.isGetter():
 | 
						|
                        arguments = method_arguments(descriptor, rettype, arguments, trailing=("found", "&mut bool"))
 | 
						|
 | 
						|
                        # If this interface 'supports named properties', then we
 | 
						|
                        # should be able to access 'supported property names'
 | 
						|
                        #
 | 
						|
                        # WebIDL, Second Draft, section 3.2.4.5
 | 
						|
                        # https://heycam.github.io/webidl/#idl-named-properties
 | 
						|
                        if operation.isNamed():
 | 
						|
                            yield "SupportedPropertyNames", [], "Vec<DOMString>"
 | 
						|
                    else:
 | 
						|
                        arguments = method_arguments(descriptor, rettype, arguments)
 | 
						|
                    rettype = return_type(descriptor, rettype, infallible)
 | 
						|
                    yield name, arguments, rettype
 | 
						|
 | 
						|
        def fmt(arguments):
 | 
						|
            return "".join(", %s: %s" % argument for argument in arguments)
 | 
						|
 | 
						|
        methods = [
 | 
						|
            CGGeneric("fn %s(&self%s) -> %s;\n" % (name, fmt(arguments), rettype))
 | 
						|
            for name, arguments, rettype in members()
 | 
						|
        ]
 | 
						|
        if methods:
 | 
						|
            self.cgRoot = CGWrapper(CGIndenter(CGList(methods, "")),
 | 
						|
                                    pre="pub trait %sMethods {\n" % descriptor.interface.identifier.name,
 | 
						|
                                    post="}")
 | 
						|
        else:
 | 
						|
            self.cgRoot = CGGeneric("")
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        return self.cgRoot.define()
 | 
						|
 | 
						|
 | 
						|
class CGDescriptor(CGThing):
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        CGThing.__init__(self)
 | 
						|
 | 
						|
        assert not descriptor.concrete or not descriptor.interface.isCallback()
 | 
						|
 | 
						|
        cgThings = []
 | 
						|
        if not descriptor.interface.isCallback():
 | 
						|
            cgThings.append(CGGetProtoObjectMethod(descriptor))
 | 
						|
        if descriptor.interface.hasInterfaceObject():
 | 
						|
            # https://github.com/mozilla/servo/issues/2665
 | 
						|
            # cgThings.append(CGGetConstructorObjectMethod(descriptor))
 | 
						|
            pass
 | 
						|
 | 
						|
        for m in descriptor.interface.members:
 | 
						|
            if (m.isMethod() and
 | 
						|
                    (not m.isIdentifierLess() or m == descriptor.operations["Stringifier"])):
 | 
						|
                if m.isStatic():
 | 
						|
                    assert descriptor.interface.hasInterfaceObject()
 | 
						|
                    cgThings.append(CGStaticMethod(descriptor, m))
 | 
						|
                elif not descriptor.interface.isCallback():
 | 
						|
                    cgThings.append(CGSpecializedMethod(descriptor, m))
 | 
						|
                    cgThings.append(CGMemberJITInfo(descriptor, m))
 | 
						|
            elif m.isAttr():
 | 
						|
                if m.stringifier:
 | 
						|
                    raise TypeError("Stringifier attributes not supported yet. "
 | 
						|
                                    "See https://github.com/servo/servo/issues/7590\n"
 | 
						|
                                    "%s" % m.location)
 | 
						|
 | 
						|
                if m.isStatic():
 | 
						|
                    assert descriptor.interface.hasInterfaceObject()
 | 
						|
                    cgThings.append(CGStaticGetter(descriptor, m))
 | 
						|
                elif not descriptor.interface.isCallback():
 | 
						|
                    cgThings.append(CGSpecializedGetter(descriptor, m))
 | 
						|
 | 
						|
                if not m.readonly:
 | 
						|
                    if m.isStatic():
 | 
						|
                        assert descriptor.interface.hasInterfaceObject()
 | 
						|
                        cgThings.append(CGStaticSetter(descriptor, m))
 | 
						|
                    elif not descriptor.interface.isCallback():
 | 
						|
                        cgThings.append(CGSpecializedSetter(descriptor, m))
 | 
						|
                elif m.getExtendedAttribute("PutForwards"):
 | 
						|
                    cgThings.append(CGSpecializedForwardingSetter(descriptor, m))
 | 
						|
 | 
						|
                if (not m.isStatic() and not descriptor.interface.isCallback()):
 | 
						|
                    cgThings.append(CGMemberJITInfo(descriptor, m))
 | 
						|
 | 
						|
        if descriptor.concrete:
 | 
						|
            cgThings.append(CGClassFinalizeHook(descriptor))
 | 
						|
            cgThings.append(CGClassTraceHook(descriptor))
 | 
						|
 | 
						|
        if descriptor.interface.hasInterfaceObject():
 | 
						|
            cgThings.append(CGClassConstructHook(descriptor))
 | 
						|
            for ctor in descriptor.interface.namedConstructors:
 | 
						|
                cgThings.append(CGClassNameConstructHook(descriptor, ctor))
 | 
						|
            cgThings.append(CGInterfaceObjectJSClass(descriptor))
 | 
						|
 | 
						|
        if not descriptor.interface.isCallback():
 | 
						|
            cgThings.append(CGPrototypeJSClass(descriptor))
 | 
						|
 | 
						|
        properties = PropertyArrays(descriptor)
 | 
						|
        cgThings.append(CGGeneric(str(properties)))
 | 
						|
        cgThings.append(CGNativeProperties(descriptor, properties))
 | 
						|
        cgThings.append(CGNativePropertyHooks(descriptor, properties))
 | 
						|
        cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties))
 | 
						|
 | 
						|
        cgThings.append(CGNamespace.build([descriptor.name + "Constants"],
 | 
						|
                                          CGConstant(m for m in descriptor.interface.members if m.isConst()),
 | 
						|
                                          public=True))
 | 
						|
 | 
						|
        if descriptor.interface.hasInterfaceObject():
 | 
						|
            cgThings.append(CGDefineDOMInterfaceMethod(descriptor))
 | 
						|
 | 
						|
        if descriptor.proxy:
 | 
						|
            cgThings.append(CGDefineProxyHandler(descriptor))
 | 
						|
 | 
						|
        if descriptor.concrete:
 | 
						|
            if descriptor.proxy:
 | 
						|
                # cgThings.append(CGProxyIsProxy(descriptor))
 | 
						|
                cgThings.append(CGProxyUnwrap(descriptor))
 | 
						|
                cgThings.append(CGDOMJSProxyHandlerDOMClass(descriptor))
 | 
						|
                cgThings.append(CGDOMJSProxyHandler_ownPropertyKeys(descriptor))
 | 
						|
                cgThings.append(CGDOMJSProxyHandler_getOwnPropertyDescriptor(descriptor))
 | 
						|
                cgThings.append(CGDOMJSProxyHandler_className(descriptor))
 | 
						|
                cgThings.append(CGDOMJSProxyHandler_get(descriptor))
 | 
						|
                cgThings.append(CGDOMJSProxyHandler_hasOwn(descriptor))
 | 
						|
 | 
						|
                if descriptor.operations['IndexedSetter'] or descriptor.operations['NamedSetter']:
 | 
						|
                    cgThings.append(CGDOMJSProxyHandler_defineProperty(descriptor))
 | 
						|
 | 
						|
                # We want to prevent indexed deleters from compiling at all.
 | 
						|
                assert not descriptor.operations['IndexedDeleter']
 | 
						|
 | 
						|
                if descriptor.operations['NamedDeleter']:
 | 
						|
                    cgThings.append(CGDOMJSProxyHandler_delete(descriptor))
 | 
						|
 | 
						|
                # cgThings.append(CGDOMJSProxyHandler(descriptor))
 | 
						|
                # cgThings.append(CGIsMethod(descriptor))
 | 
						|
                pass
 | 
						|
            else:
 | 
						|
                cgThings.append(CGDOMJSClass(descriptor))
 | 
						|
                pass
 | 
						|
 | 
						|
            cgThings.append(CGWrapMethod(descriptor))
 | 
						|
 | 
						|
        if not descriptor.interface.isCallback():
 | 
						|
            cgThings.append(CGIDLInterface(descriptor))
 | 
						|
            cgThings.append(CGInterfaceTrait(descriptor))
 | 
						|
 | 
						|
        cgThings = CGList(cgThings, "\n")
 | 
						|
        # self.cgRoot = CGWrapper(CGNamespace(toBindingNamespace(descriptor.name),
 | 
						|
        #                                     cgThings),
 | 
						|
        #                         post='\n')
 | 
						|
        self.cgRoot = cgThings
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        return self.cgRoot.define()
 | 
						|
 | 
						|
 | 
						|
class CGNonNamespacedEnum(CGThing):
 | 
						|
    def __init__(self, enumName, names, values, comment="", deriving="", repr=""):
 | 
						|
 | 
						|
        if not values:
 | 
						|
            values = []
 | 
						|
 | 
						|
        # Account for explicit enum values.
 | 
						|
        entries = []
 | 
						|
        for i in range(0, len(names)):
 | 
						|
            if len(values) > i and values[i] is not None:
 | 
						|
                entry = "%s = %s" % (names[i], values[i])
 | 
						|
            else:
 | 
						|
                entry = names[i]
 | 
						|
            entries.append(entry)
 | 
						|
 | 
						|
        # Append a Count.
 | 
						|
        entries.append('Count = ' + str(len(entries)))
 | 
						|
 | 
						|
        # Indent.
 | 
						|
        entries = ['    ' + e for e in entries]
 | 
						|
 | 
						|
        # Build the enum body.
 | 
						|
        enumstr = comment + 'pub enum %s {\n%s\n}\n' % (enumName, ',\n'.join(entries))
 | 
						|
        if repr:
 | 
						|
            enumstr = ('#[repr(%s)]\n' % repr) + enumstr
 | 
						|
        if deriving:
 | 
						|
            enumstr = ('#[derive(%s)]\n' % deriving) + enumstr
 | 
						|
        curr = CGGeneric(enumstr)
 | 
						|
 | 
						|
        # Add some whitespace padding.
 | 
						|
        curr = CGWrapper(curr, pre='\n', post='\n')
 | 
						|
 | 
						|
        # Add the typedef
 | 
						|
        # typedef = '\ntypedef %s::%s %s;\n\n' % (namespace, enumName, enumName)
 | 
						|
        # curr = CGList([curr, CGGeneric(typedef)])
 | 
						|
 | 
						|
        # Save the result.
 | 
						|
        self.node = curr
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        return self.node.define()
 | 
						|
 | 
						|
 | 
						|
class CGDictionary(CGThing):
 | 
						|
    def __init__(self, dictionary, descriptorProvider):
 | 
						|
        self.dictionary = dictionary
 | 
						|
        if all(CGDictionary(d, descriptorProvider).generatable for
 | 
						|
               d in CGDictionary.getDictionaryDependencies(dictionary)):
 | 
						|
            self.generatable = True
 | 
						|
        else:
 | 
						|
            self.generatable = False
 | 
						|
            # Nothing else to do here
 | 
						|
            return
 | 
						|
 | 
						|
        self.memberInfo = [
 | 
						|
            (member,
 | 
						|
             getJSToNativeConversionInfo(member.type,
 | 
						|
                                         descriptorProvider,
 | 
						|
                                         isMember="Dictionary",
 | 
						|
                                         defaultValue=member.defaultValue,
 | 
						|
                                         exceptionCode="return Err(());"))
 | 
						|
            for member in dictionary.members]
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        if not self.generatable:
 | 
						|
            return ""
 | 
						|
        return self.struct() + "\n" + self.impl()
 | 
						|
 | 
						|
    def struct(self):
 | 
						|
        d = self.dictionary
 | 
						|
        if d.parent:
 | 
						|
            inheritance = "    pub parent: %s::%s,\n" % (self.makeModuleName(d.parent),
 | 
						|
                                                         self.makeClassName(d.parent))
 | 
						|
        else:
 | 
						|
            inheritance = ""
 | 
						|
        memberDecls = ["    pub %s: %s," %
 | 
						|
                       (self.makeMemberName(m[0].identifier.name), self.getMemberType(m))
 | 
						|
                       for m in self.memberInfo]
 | 
						|
 | 
						|
        return (string.Template(
 | 
						|
                "#[no_move]\n" +
 | 
						|
                "pub struct ${selfName} {\n" +
 | 
						|
                "${inheritance}" +
 | 
						|
                "\n".join(memberDecls) + "\n" +
 | 
						|
                "}").substitute({"selfName": self.makeClassName(d),
 | 
						|
                                 "inheritance": inheritance}))
 | 
						|
 | 
						|
    def impl(self):
 | 
						|
        d = self.dictionary
 | 
						|
        if d.parent:
 | 
						|
            initParent = "parent: try!(%s::%s::new(cx, val)),\n" % (
 | 
						|
                self.makeModuleName(d.parent),
 | 
						|
                self.makeClassName(d.parent))
 | 
						|
        else:
 | 
						|
            initParent = ""
 | 
						|
 | 
						|
        def memberInit(memberInfo):
 | 
						|
            member, _ = memberInfo
 | 
						|
            name = self.makeMemberName(member.identifier.name)
 | 
						|
            conversion = self.getMemberConversion(memberInfo, member.type)
 | 
						|
            return CGGeneric("%s: %s,\n" % (name, conversion.define()))
 | 
						|
 | 
						|
        def memberInsert(memberInfo):
 | 
						|
            member, _ = memberInfo
 | 
						|
            name = self.makeMemberName(member.identifier.name)
 | 
						|
            insertion = ("let mut %s = RootedValue::new(cx, UndefinedValue());\n"
 | 
						|
                         "self.%s.to_jsval(cx, %s.handle_mut());\n"
 | 
						|
                         "set_dictionary_property(cx, obj.handle(), \"%s\", %s.handle()).unwrap();"
 | 
						|
                         % (name, name, name, name, name))
 | 
						|
            return CGGeneric("%s\n" % insertion)
 | 
						|
 | 
						|
        memberInits = CGList([memberInit(m) for m in self.memberInfo])
 | 
						|
        memberInserts = CGList([memberInsert(m) for m in self.memberInfo])
 | 
						|
 | 
						|
        return string.Template(
 | 
						|
            "impl ${selfName} {\n"
 | 
						|
            "    pub fn empty(cx: *mut JSContext) -> ${selfName} {\n"
 | 
						|
            "        ${selfName}::new(cx, HandleValue::null()).unwrap()\n"
 | 
						|
            "    }\n"
 | 
						|
            "    pub fn new(cx: *mut JSContext, val: HandleValue) -> Result<${selfName}, ()> {\n"
 | 
						|
            "        let object = if val.get().is_null_or_undefined() {\n"
 | 
						|
            "            RootedObject::new(cx, ptr::null_mut())\n"
 | 
						|
            "        } else if val.get().is_object() {\n"
 | 
						|
            "            RootedObject::new(cx, val.get().to_object())\n"
 | 
						|
            "        } else {\n"
 | 
						|
            "            throw_type_error(cx, \"Value not an object.\");\n"
 | 
						|
            "            return Err(());\n"
 | 
						|
            "        };\n"
 | 
						|
            "        Ok(${selfName} {\n"
 | 
						|
            "${initParent}"
 | 
						|
            "${initMembers}"
 | 
						|
            "        })\n"
 | 
						|
            "    }\n"
 | 
						|
            "}\n"
 | 
						|
            "\n"
 | 
						|
            "impl ToJSValConvertible for ${selfName} {\n"
 | 
						|
            "    fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {\n"
 | 
						|
            "        let obj = unsafe { RootedObject::new(cx, JS_NewObject(cx, ptr::null())) };\n"
 | 
						|
            "${insertMembers}"
 | 
						|
            "        rval.set(ObjectOrNullValue(obj.ptr))\n"
 | 
						|
            "    }\n"
 | 
						|
            "}\n").substitute({
 | 
						|
                "selfName": self.makeClassName(d),
 | 
						|
                "initParent": CGIndenter(CGGeneric(initParent), indentLevel=12).define(),
 | 
						|
                "initMembers": CGIndenter(memberInits, indentLevel=12).define(),
 | 
						|
                "insertMembers": CGIndenter(memberInserts, indentLevel=8).define(),
 | 
						|
            })
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def makeDictionaryName(dictionary):
 | 
						|
        return dictionary.identifier.name
 | 
						|
 | 
						|
    def makeClassName(self, dictionary):
 | 
						|
        return self.makeDictionaryName(dictionary)
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def makeModuleName(dictionary):
 | 
						|
        return dictionary.module()
 | 
						|
 | 
						|
    def getMemberType(self, memberInfo):
 | 
						|
        member, info = memberInfo
 | 
						|
        declType = info.declType
 | 
						|
        if member.optional and not member.defaultValue:
 | 
						|
            declType = CGWrapper(info.declType, pre="Option<", post=">")
 | 
						|
        return declType.define()
 | 
						|
 | 
						|
    def getMemberConversion(self, memberInfo, memberType):
 | 
						|
        def indent(s):
 | 
						|
            return CGIndenter(CGGeneric(s), 8).define()
 | 
						|
 | 
						|
        member, info = memberInfo
 | 
						|
        templateBody = info.template
 | 
						|
        default = info.default
 | 
						|
        replacements = {"val": "rval.handle()"}
 | 
						|
        conversion = string.Template(templateBody).substitute(replacements)
 | 
						|
        if memberType.isAny():
 | 
						|
            conversion = "%s.get()" % conversion
 | 
						|
 | 
						|
        assert (member.defaultValue is None) == (default is None)
 | 
						|
        if not member.optional:
 | 
						|
            assert default is None
 | 
						|
            default = ("throw_type_error(cx, \"Missing required member \\\"%s\\\".\");\n"
 | 
						|
                       "return Err(());") % member.identifier.name
 | 
						|
        elif not default:
 | 
						|
            default = "None"
 | 
						|
            conversion = "Some(%s)" % conversion
 | 
						|
 | 
						|
        conversion = (
 | 
						|
            "{\n"
 | 
						|
            "let mut rval = RootedValue::new(cx, UndefinedValue());\n"
 | 
						|
            "match try!(get_dictionary_property(cx, object.handle(), \"%s\", rval.handle_mut())) {\n"
 | 
						|
            "    true => {\n"
 | 
						|
            "%s\n"
 | 
						|
            "    },\n"
 | 
						|
            "    false => {\n"
 | 
						|
            "%s\n"
 | 
						|
            "    },\n"
 | 
						|
            "}\n}") % (member.identifier.name, indent(conversion), indent(default))
 | 
						|
 | 
						|
        return CGGeneric(conversion)
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def makeMemberName(name):
 | 
						|
        # Can't use Rust keywords as member names.
 | 
						|
        if name == "type":
 | 
						|
            return name + "_"
 | 
						|
        return name
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def getDictionaryDependencies(dictionary):
 | 
						|
        deps = set()
 | 
						|
        if dictionary.parent:
 | 
						|
            deps.add(dictionary.parent)
 | 
						|
        for member in dictionary.members:
 | 
						|
            if member.type.isDictionary():
 | 
						|
                deps.add(member.type.unroll().inner)
 | 
						|
        return deps
 | 
						|
 | 
						|
 | 
						|
class CGRegisterProtos(CGAbstractMethod):
 | 
						|
    def __init__(self, config):
 | 
						|
        arguments = [
 | 
						|
            Argument('*mut JSContext', 'cx'),
 | 
						|
            Argument('HandleObject', 'global'),
 | 
						|
        ]
 | 
						|
        CGAbstractMethod.__init__(self, None, 'Register', 'void', arguments,
 | 
						|
                                  unsafe=False, pub=True)
 | 
						|
        self.config = config
 | 
						|
 | 
						|
    def definition_body(self):
 | 
						|
        return CGList([
 | 
						|
            CGGeneric("codegen::Bindings::%sBinding::DefineDOMInterface(cx, global);" % desc.name)
 | 
						|
            for desc in self.config.getDescriptors(hasInterfaceObject=True, register=True)
 | 
						|
        ], "\n")
 | 
						|
 | 
						|
 | 
						|
class CGRegisterProxyHandlersMethod(CGAbstractMethod):
 | 
						|
    def __init__(self, descriptors):
 | 
						|
        docs = "Create the global vtables used by the generated DOM bindings to implement JS proxies."
 | 
						|
        CGAbstractMethod.__init__(self, None, 'RegisterProxyHandlers', 'void', [],
 | 
						|
                                  unsafe=True, pub=True, docs=docs)
 | 
						|
        self.descriptors = descriptors
 | 
						|
 | 
						|
    def definition_body(self):
 | 
						|
        return CGList([
 | 
						|
            CGGeneric("proxy_handlers[Proxies::%s as usize] = codegen::Bindings::%sBinding::DefineProxyHandler();"
 | 
						|
                      % (desc.name, desc.name))
 | 
						|
            for desc in self.descriptors
 | 
						|
        ], "\n")
 | 
						|
 | 
						|
 | 
						|
class CGRegisterProxyHandlers(CGThing):
 | 
						|
    def __init__(self, config):
 | 
						|
        descriptors = config.getDescriptors(proxy=True)
 | 
						|
        length = len(descriptors)
 | 
						|
        self.root = CGList([
 | 
						|
            CGGeneric("pub static mut proxy_handlers: [*const libc::c_void; %d] = [0 as *const libc::c_void; %d];"
 | 
						|
                      % (length, length)),
 | 
						|
            CGRegisterProxyHandlersMethod(descriptors),
 | 
						|
        ], "\n")
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        return self.root.define()
 | 
						|
 | 
						|
 | 
						|
class CGBindingRoot(CGThing):
 | 
						|
    """
 | 
						|
    Root codegen class for binding generation. Instantiate the class, and call
 | 
						|
    declare or define to generate header or cpp code (respectively).
 | 
						|
    """
 | 
						|
    def __init__(self, config, prefix, webIDLFile):
 | 
						|
        descriptors = config.getDescriptors(webIDLFile=webIDLFile,
 | 
						|
                                            hasInterfaceObject=True)
 | 
						|
        # We also want descriptors that have an interface prototype object
 | 
						|
        # (isCallback=False), but we don't want to include a second copy
 | 
						|
        # of descriptors that we also matched in the previous line
 | 
						|
        # (hence hasInterfaceObject=False).
 | 
						|
        descriptors.extend(config.getDescriptors(webIDLFile=webIDLFile,
 | 
						|
                                                 hasInterfaceObject=False,
 | 
						|
                                                 isCallback=False))
 | 
						|
        dictionaries = config.getDictionaries(webIDLFile=webIDLFile)
 | 
						|
 | 
						|
        cgthings = []
 | 
						|
 | 
						|
        mainCallbacks = config.getCallbacks(webIDLFile=webIDLFile)
 | 
						|
        callbackDescriptors = config.getDescriptors(webIDLFile=webIDLFile,
 | 
						|
                                                    isCallback=True)
 | 
						|
 | 
						|
        # Do codegen for all the enums
 | 
						|
        cgthings = [CGEnum(e) for e in config.getEnums(webIDLFile)]
 | 
						|
 | 
						|
        cgthings.extend([CGDictionary(d, config.getDescriptorProvider())
 | 
						|
                         for d in dictionaries])
 | 
						|
 | 
						|
        # Do codegen for all the callbacks.
 | 
						|
        cgthings.extend(CGList([CGCallbackFunction(c, config.getDescriptorProvider()),
 | 
						|
                                CGCallbackFunctionImpl(c)], "\n")
 | 
						|
                        for c in mainCallbacks)
 | 
						|
 | 
						|
        # Do codegen for all the descriptors
 | 
						|
        cgthings.extend([CGDescriptor(x) for x in descriptors])
 | 
						|
 | 
						|
        # Do codegen for all the callback interfaces.
 | 
						|
        cgthings.extend(CGList([CGCallbackInterface(x),
 | 
						|
                                CGCallbackFunctionImpl(x.interface)], "\n")
 | 
						|
                        for x in callbackDescriptors)
 | 
						|
 | 
						|
        # And make sure we have the right number of newlines at the end
 | 
						|
        curr = CGWrapper(CGList(cgthings, "\n\n"), post="\n\n")
 | 
						|
 | 
						|
        # Wrap all of that in our namespaces.
 | 
						|
        # curr = CGNamespace.build(['dom'],
 | 
						|
        #                          CGWrapper(curr, pre="\n"))
 | 
						|
 | 
						|
        # Add imports
 | 
						|
        curr = CGImports(curr, descriptors + callbackDescriptors, mainCallbacks, [
 | 
						|
            'js',
 | 
						|
            'js::JS_CALLEE',
 | 
						|
            'js::{JSCLASS_GLOBAL_SLOT_COUNT, JSCLASS_IS_DOMJSCLASS, JSCLASS_IMPLEMENTS_BARRIERS}',
 | 
						|
            'js::{JSCLASS_IS_GLOBAL, JSCLASS_RESERVED_SLOTS_SHIFT}',
 | 
						|
            'js::{JSCLASS_RESERVED_SLOTS_MASK}',
 | 
						|
            'js::{JSPROP_ENUMERATE, JSPROP_SHARED}',
 | 
						|
            'js::{JSITER_OWNONLY, JSITER_HIDDEN, JSITER_SYMBOLS}',
 | 
						|
            'js::jsapi::{JS_CallFunctionValue, JS_GetClass, JS_GetGlobalForObject}',
 | 
						|
            'js::jsapi::{JS_GetObjectPrototype, JS_GetProperty, JS_GetPropertyById}',
 | 
						|
            'js::jsapi::{JS_GetPropertyDescriptorById, JS_GetReservedSlot}',
 | 
						|
            'js::jsapi::{JS_HasProperty, JS_HasPropertyById, JS_IsExceptionPending}',
 | 
						|
            'js::jsapi::{JS_NewObjectWithGivenProto, JS_NewObject, IsCallable, JS_SetProperty, JS_SetPrototype}',
 | 
						|
            'js::jsapi::{JS_SetReservedSlot, JS_WrapValue, JSContext}',
 | 
						|
            'js::jsapi::{JSClass, FreeOp, JSFreeOp, JSFunctionSpec, jsid}',
 | 
						|
            'js::jsapi::{MutableHandleValue, MutableHandleObject, HandleObject, HandleValue, RootedObject}',
 | 
						|
            'js::jsapi::{RootedValue, JSNativeWrapper, JSNative, JSObject, JSPropertyDescriptor}',
 | 
						|
            'js::jsapi::{RootedId, JS_InternString, RootedString, INTERNED_STRING_TO_JSID}',
 | 
						|
            'js::jsapi::{JSPropertySpec}',
 | 
						|
            'js::jsapi::{JSString, JSTracer, JSJitInfo, JSTypedMethodJitInfo, OpType, AliasSet, ArgType}',
 | 
						|
            'js::jsapi::{MutableHandle, Handle, HandleId, JSType, JSValueType}',
 | 
						|
            'js::jsapi::{SymbolCode, ObjectOpResult, HandleValueArray}',
 | 
						|
            'js::jsapi::{JSJitGetterCallArgs, JSJitSetterCallArgs, JSJitMethodCallArgs, CallArgs}',
 | 
						|
            'js::jsapi::{JSAutoCompartment, JSAutoRequest, JS_ComputeThis}',
 | 
						|
            'js::jsapi::{GetGlobalForObjectCrossCompartment, AutoIdVector, GetPropertyKeys}',
 | 
						|
            'js::jsval::JSVal',
 | 
						|
            'js::jsval::{ObjectValue, ObjectOrNullValue, PrivateValue}',
 | 
						|
            'js::jsval::{NullValue, UndefinedValue}',
 | 
						|
            'js::glue::{CallJitMethodOp, CallJitGetterOp, CallJitSetterOp, CreateProxyHandler}',
 | 
						|
            'js::glue::{GetProxyPrivate, NewProxyObject, ProxyTraps}',
 | 
						|
            'js::glue::{RUST_FUNCTION_VALUE_TO_JITINFO}',
 | 
						|
            'js::glue::{RUST_JS_NumberValue, RUST_JSID_IS_STRING, int_to_jsid}',
 | 
						|
            'js::glue::AppendToAutoIdVector',
 | 
						|
            'js::rust::GCMethods',
 | 
						|
            'dom::bindings',
 | 
						|
            'dom::bindings::global::GlobalRef',
 | 
						|
            'dom::bindings::global::global_object_for_js_object',
 | 
						|
            'dom::bindings::js::{JS, Root, RootedReference}',
 | 
						|
            'dom::bindings::js::{OptionalRootedReference}',
 | 
						|
            'dom::bindings::utils::{create_dom_global, do_create_interface_objects}',
 | 
						|
            'dom::bindings::utils::ConstantSpec',
 | 
						|
            'dom::bindings::utils::{DOMClass}',
 | 
						|
            'dom::bindings::utils::{DOMJSClass, JSCLASS_DOM_GLOBAL}',
 | 
						|
            'dom::bindings::utils::{find_enum_string_index, get_array_index_from_id}',
 | 
						|
            'dom::bindings::utils::{get_property_on_prototype, get_proto_or_iface_array}',
 | 
						|
            'dom::bindings::utils::{finalize_global, trace_global}',
 | 
						|
            'dom::bindings::utils::has_property_on_prototype',
 | 
						|
            'dom::bindings::utils::is_platform_object',
 | 
						|
            'dom::bindings::utils::{Reflectable}',
 | 
						|
            'dom::bindings::utils::throwing_constructor',
 | 
						|
            'dom::bindings::utils::get_dictionary_property',
 | 
						|
            'dom::bindings::utils::set_dictionary_property',
 | 
						|
            'dom::bindings::utils::{NativeProperties, NativePropertyHooks}',
 | 
						|
            'dom::bindings::utils::ConstantVal::{IntVal, UintVal}',
 | 
						|
            'dom::bindings::utils::NonNullJSNative',
 | 
						|
            'dom::bindings::utils::{generic_getter, generic_lenient_getter}',
 | 
						|
            'dom::bindings::utils::{generic_lenient_setter, generic_method}',
 | 
						|
            'dom::bindings::utils::generic_setter',
 | 
						|
            'dom::bindings::trace::{JSTraceable, RootedTraceable}',
 | 
						|
            'dom::bindings::callback::{CallbackContainer,CallbackInterface,CallbackFunction}',
 | 
						|
            'dom::bindings::callback::{CallSetup,ExceptionHandling}',
 | 
						|
            'dom::bindings::callback::wrap_call_this_object',
 | 
						|
            'dom::bindings::conversions::{FromJSValConvertible, ToJSValConvertible, ConversionBehavior}',
 | 
						|
            'dom::bindings::conversions::{native_from_reflector, native_from_handlevalue, native_from_handleobject}',
 | 
						|
            'dom::bindings::conversions::DOM_OBJECT_SLOT',
 | 
						|
            'dom::bindings::conversions::IDLInterface',
 | 
						|
            'dom::bindings::conversions::jsid_to_str',
 | 
						|
            'dom::bindings::conversions::StringificationBehavior',
 | 
						|
            'dom::bindings::codegen::{PrototypeList, RegisterBindings, UnionTypes}',
 | 
						|
            'dom::bindings::codegen::Bindings::*',
 | 
						|
            'dom::bindings::error::{Fallible, Error, ErrorResult}',
 | 
						|
            'dom::bindings::error::Error::JSFailed',
 | 
						|
            'dom::bindings::error::throw_dom_exception',
 | 
						|
            'dom::bindings::error::throw_type_error',
 | 
						|
            'dom::bindings::proxyhandler',
 | 
						|
            'dom::bindings::proxyhandler::{fill_property_descriptor, get_expando_object}',
 | 
						|
            'dom::bindings::proxyhandler::{get_property_descriptor}',
 | 
						|
            'dom::bindings::num::Finite',
 | 
						|
            'dom::bindings::str::ByteString',
 | 
						|
            'dom::bindings::str::USVString',
 | 
						|
            'mem::heap_size_of_raw_self_and_children',
 | 
						|
            'libc',
 | 
						|
            'util::str::DOMString',
 | 
						|
            'std::borrow::ToOwned',
 | 
						|
            'std::cmp',
 | 
						|
            'std::mem',
 | 
						|
            'std::num',
 | 
						|
            'std::ptr',
 | 
						|
            'std::str',
 | 
						|
            'std::rc',
 | 
						|
            'std::rc::Rc',
 | 
						|
            'std::default::Default',
 | 
						|
            'std::ffi::CString',
 | 
						|
        ])
 | 
						|
 | 
						|
        # Add the auto-generated comment.
 | 
						|
        curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
 | 
						|
 | 
						|
        # Store the final result.
 | 
						|
        self.root = curr
 | 
						|
 | 
						|
    def define(self):
 | 
						|
        return stripTrailingWhitespace(self.root.define())
 | 
						|
 | 
						|
 | 
						|
def argument_type(descriptorProvider, ty, optional=False, defaultValue=None, variadic=False):
 | 
						|
    info = getJSToNativeConversionInfo(
 | 
						|
        ty, descriptorProvider, isArgument=True)
 | 
						|
    declType = info.declType
 | 
						|
 | 
						|
    if variadic:
 | 
						|
        declType = CGWrapper(declType, pre="Vec<", post=">")
 | 
						|
    elif optional and not defaultValue:
 | 
						|
        declType = CGWrapper(declType, pre="Option<", post=">")
 | 
						|
 | 
						|
    if ty.isDictionary():
 | 
						|
        declType = CGWrapper(declType, pre="&")
 | 
						|
 | 
						|
    return declType.define()
 | 
						|
 | 
						|
 | 
						|
def method_arguments(descriptorProvider, returnType, arguments, passJSBits=True, trailing=None):
 | 
						|
    if needCx(returnType, arguments, passJSBits):
 | 
						|
        yield "cx", "*mut JSContext"
 | 
						|
 | 
						|
    for argument in arguments:
 | 
						|
        ty = argument_type(descriptorProvider, argument.type, argument.optional,
 | 
						|
                           argument.defaultValue, argument.variadic)
 | 
						|
        yield CGDictionary.makeMemberName(argument.identifier.name), ty
 | 
						|
 | 
						|
    if trailing:
 | 
						|
        yield trailing
 | 
						|
 | 
						|
 | 
						|
def return_type(descriptorProvider, rettype, infallible):
 | 
						|
    result = getRetvalDeclarationForType(rettype, descriptorProvider)
 | 
						|
    if not infallible:
 | 
						|
        result = CGWrapper(result, pre="Fallible<", post=">")
 | 
						|
    return result.define()
 | 
						|
 | 
						|
 | 
						|
class CGNativeMember(ClassMethod):
 | 
						|
    def __init__(self, descriptorProvider, member, name, signature, extendedAttrs,
 | 
						|
                 breakAfter=True, passJSBitsAsNeeded=True, visibility="public"):
 | 
						|
        """
 | 
						|
        If passJSBitsAsNeeded is false, we don't automatically pass in a
 | 
						|
        JSContext* or a JSObject* based on the return and argument types.
 | 
						|
        """
 | 
						|
        self.descriptorProvider = descriptorProvider
 | 
						|
        self.member = member
 | 
						|
        self.extendedAttrs = extendedAttrs
 | 
						|
        self.passJSBitsAsNeeded = passJSBitsAsNeeded
 | 
						|
        breakAfterSelf = "\n" if breakAfter else ""
 | 
						|
        ClassMethod.__init__(self, name,
 | 
						|
                             self.getReturnType(signature[0]),
 | 
						|
                             self.getArgs(signature[0], signature[1]),
 | 
						|
                             static=member.isStatic(),
 | 
						|
                             # Mark our getters, which are attrs that
 | 
						|
                             # have a non-void return type, as const.
 | 
						|
                             const=(not member.isStatic() and member.isAttr() and
 | 
						|
                                    not signature[0].isVoid()),
 | 
						|
                             breakAfterSelf=breakAfterSelf,
 | 
						|
                             visibility=visibility)
 | 
						|
 | 
						|
    def getReturnType(self, type):
 | 
						|
        infallible = 'infallible' in self.extendedAttrs
 | 
						|
        typeDecl = return_type(self.descriptorProvider, type, infallible)
 | 
						|
        return typeDecl
 | 
						|
 | 
						|
    def getArgs(self, returnType, argList):
 | 
						|
        return [Argument(arg[1], arg[0]) for arg in method_arguments(self.descriptorProvider,
 | 
						|
                                                                     returnType,
 | 
						|
                                                                     argList,
 | 
						|
                                                                     self.passJSBitsAsNeeded)]
 | 
						|
 | 
						|
 | 
						|
class CGCallback(CGClass):
 | 
						|
    def __init__(self, idlObject, descriptorProvider, baseName, methods,
 | 
						|
                 getters=[], setters=[]):
 | 
						|
        self.baseName = baseName
 | 
						|
        self._deps = idlObject.getDeps()
 | 
						|
        name = idlObject.identifier.name
 | 
						|
        # For our public methods that needThisHandling we want most of the
 | 
						|
        # same args and the same return type as what CallbackMember
 | 
						|
        # generates.  So we want to take advantage of all its
 | 
						|
        # CGNativeMember infrastructure, but that infrastructure can't deal
 | 
						|
        # with templates and most especially template arguments.  So just
 | 
						|
        # cheat and have CallbackMember compute all those things for us.
 | 
						|
        realMethods = []
 | 
						|
        for method in methods:
 | 
						|
            if not method.needThisHandling:
 | 
						|
                realMethods.append(method)
 | 
						|
            else:
 | 
						|
                realMethods.extend(self.getMethodImpls(method))
 | 
						|
        CGClass.__init__(self, name,
 | 
						|
                         bases=[ClassBase(baseName)],
 | 
						|
                         constructors=self.getConstructors(),
 | 
						|
                         methods=realMethods + getters + setters,
 | 
						|
                         decorators="#[derive(JSTraceable, PartialEq)]")
 | 
						|
 | 
						|
    def getConstructors(self):
 | 
						|
        return [ClassConstructor(
 | 
						|
            [Argument("*mut JSObject", "aCallback")],
 | 
						|
            bodyInHeader=True,
 | 
						|
            visibility="pub",
 | 
						|
            explicit=False,
 | 
						|
            baseConstructors=[
 | 
						|
                "%s::new()" % self.baseName
 | 
						|
            ])]
 | 
						|
 | 
						|
    def getMethodImpls(self, method):
 | 
						|
        assert method.needThisHandling
 | 
						|
        args = list(method.args)
 | 
						|
        # Strip out the JSContext*/JSObject* args
 | 
						|
        # that got added.
 | 
						|
        assert args[0].name == "cx" and args[0].argType == "*mut JSContext"
 | 
						|
        assert args[1].name == "aThisObj" and args[1].argType == "HandleObject"
 | 
						|
        args = args[2:]
 | 
						|
        # Record the names of all the arguments, so we can use them when we call
 | 
						|
        # the private method.
 | 
						|
        argnames = [arg.name for arg in args]
 | 
						|
        argnamesWithThis = ["s.get_context()", "thisObjJS.handle()"] + argnames
 | 
						|
        argnamesWithoutThis = ["s.get_context()", "thisObjJS.handle()"] + argnames
 | 
						|
        # Now that we've recorded the argnames for our call to our private
 | 
						|
        # method, insert our optional argument for deciding whether the
 | 
						|
        # CallSetup should re-throw exceptions on aRv.
 | 
						|
        args.append(Argument("ExceptionHandling", "aExceptionHandling",
 | 
						|
                             "ReportExceptions"))
 | 
						|
 | 
						|
        # And now insert our template argument.
 | 
						|
        argsWithoutThis = list(args)
 | 
						|
        args.insert(0, Argument("&T", "thisObj"))
 | 
						|
 | 
						|
        # And the self argument
 | 
						|
        method.args.insert(0, Argument(None, "&self"))
 | 
						|
        args.insert(0, Argument(None, "&self"))
 | 
						|
        argsWithoutThis.insert(0, Argument(None, "&self"))
 | 
						|
 | 
						|
        setupCall = ("let s = CallSetup::new(self, aExceptionHandling);\n"
 | 
						|
                     "if s.get_context().is_null() {\n"
 | 
						|
                     "    return Err(JSFailed);\n"
 | 
						|
                     "}\n")
 | 
						|
 | 
						|
        bodyWithThis = string.Template(
 | 
						|
            setupCall +
 | 
						|
            "let mut thisObjJS = RootedObject::new(s.get_context(), ptr::null_mut());\n"
 | 
						|
            "wrap_call_this_object(s.get_context(), thisObj, thisObjJS.handle_mut());\n"
 | 
						|
            "if thisObjJS.ptr.is_null() {\n"
 | 
						|
            "    return Err(JSFailed);\n"
 | 
						|
            "}\n"
 | 
						|
            "return ${methodName}(${callArgs});").substitute({
 | 
						|
                "callArgs": ", ".join(argnamesWithThis),
 | 
						|
                "methodName": 'self.' + method.name,
 | 
						|
            })
 | 
						|
        bodyWithoutThis = string.Template(
 | 
						|
            setupCall +
 | 
						|
            "let thisObjJS = RootedObject::new(s.get_context(), ptr::null_mut());"
 | 
						|
            "return ${methodName}(${callArgs});").substitute({
 | 
						|
                "callArgs": ", ".join(argnamesWithoutThis),
 | 
						|
                "methodName": 'self.' + method.name,
 | 
						|
            })
 | 
						|
        return [ClassMethod(method.name + '_', method.returnType, args,
 | 
						|
                            bodyInHeader=True,
 | 
						|
                            templateArgs=["T: Reflectable"],
 | 
						|
                            body=bodyWithThis,
 | 
						|
                            visibility='pub'),
 | 
						|
                ClassMethod(method.name + '__', method.returnType, argsWithoutThis,
 | 
						|
                            bodyInHeader=True,
 | 
						|
                            body=bodyWithoutThis,
 | 
						|
                            visibility='pub'),
 | 
						|
                method]
 | 
						|
 | 
						|
    def deps(self):
 | 
						|
        return self._deps
 | 
						|
 | 
						|
 | 
						|
# We're always fallible
 | 
						|
def callbackGetterName(attr, descriptor):
 | 
						|
    return "Get" + MakeNativeName(
 | 
						|
        descriptor.binaryNameFor(attr.identifier.name))
 | 
						|
 | 
						|
 | 
						|
def callbackSetterName(attr, descriptor):
 | 
						|
    return "Set" + MakeNativeName(
 | 
						|
        descriptor.binaryNameFor(attr.identifier.name))
 | 
						|
 | 
						|
 | 
						|
class CGCallbackFunction(CGCallback):
 | 
						|
    def __init__(self, callback, descriptorProvider):
 | 
						|
        CGCallback.__init__(self, callback, descriptorProvider,
 | 
						|
                            "CallbackFunction",
 | 
						|
                            methods=[CallCallback(callback, descriptorProvider)])
 | 
						|
 | 
						|
    def getConstructors(self):
 | 
						|
        return CGCallback.getConstructors(self)
 | 
						|
 | 
						|
 | 
						|
class CGCallbackFunctionImpl(CGGeneric):
 | 
						|
    def __init__(self, callback):
 | 
						|
        impl = string.Template("""\
 | 
						|
impl CallbackContainer for ${type} {
 | 
						|
    fn new(callback: *mut JSObject) -> Rc<${type}> {
 | 
						|
        ${type}::new(callback)
 | 
						|
    }
 | 
						|
 | 
						|
    fn callback(&self) -> *mut JSObject {
 | 
						|
        self.parent.callback()
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl ToJSValConvertible for ${type} {
 | 
						|
    fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
 | 
						|
        self.callback().to_jsval(cx, rval);
 | 
						|
    }
 | 
						|
}\
 | 
						|
""").substitute({"type": callback.identifier.name})
 | 
						|
        CGGeneric.__init__(self, impl)
 | 
						|
 | 
						|
 | 
						|
class CGCallbackInterface(CGCallback):
 | 
						|
    def __init__(self, descriptor):
 | 
						|
        iface = descriptor.interface
 | 
						|
        attrs = [m for m in iface.members if m.isAttr() and not m.isStatic()]
 | 
						|
        getters = [CallbackGetter(a, descriptor) for a in attrs]
 | 
						|
        setters = [CallbackSetter(a, descriptor) for a in attrs
 | 
						|
                   if not a.readonly]
 | 
						|
        methods = [m for m in iface.members
 | 
						|
                   if m.isMethod() and not m.isStatic() and not m.isIdentifierLess()]
 | 
						|
        methods = [CallbackOperation(m, sig, descriptor) for m in methods
 | 
						|
                   for sig in m.signatures()]
 | 
						|
        assert not iface.isJSImplemented() or not iface.ctor()
 | 
						|
        CGCallback.__init__(self, iface, descriptor, "CallbackInterface",
 | 
						|
                            methods, getters=getters, setters=setters)
 | 
						|
 | 
						|
 | 
						|
class FakeMember():
 | 
						|
    def __init__(self):
 | 
						|
        self.treatNullAs = "Default"
 | 
						|
 | 
						|
    def isStatic(self):
 | 
						|
        return False
 | 
						|
 | 
						|
    def isAttr(self):
 | 
						|
        return False
 | 
						|
 | 
						|
    def isMethod(self):
 | 
						|
        return False
 | 
						|
 | 
						|
    def getExtendedAttribute(self, name):
 | 
						|
        return None
 | 
						|
 | 
						|
 | 
						|
class CallbackMember(CGNativeMember):
 | 
						|
    def __init__(self, sig, name, descriptorProvider, needThisHandling):
 | 
						|
        """
 | 
						|
        needThisHandling is True if we need to be able to accept a specified
 | 
						|
        thisObj, False otherwise.
 | 
						|
        """
 | 
						|
 | 
						|
        self.retvalType = sig[0]
 | 
						|
        self.originalSig = sig
 | 
						|
        args = sig[1]
 | 
						|
        self.argCount = len(args)
 | 
						|
        if self.argCount > 0:
 | 
						|
            # Check for variadic arguments
 | 
						|
            lastArg = args[self.argCount - 1]
 | 
						|
            if lastArg.variadic:
 | 
						|
                self.argCountStr = (
 | 
						|
                    "(%d - 1) + %s.len()" % (self.argCount,
 | 
						|
                                             lastArg.identifier.name))
 | 
						|
            else:
 | 
						|
                self.argCountStr = "%d" % self.argCount
 | 
						|
        self.needThisHandling = needThisHandling
 | 
						|
        # If needThisHandling, we generate ourselves as private and the caller
 | 
						|
        # will handle generating public versions that handle the "this" stuff.
 | 
						|
        visibility = "priv" if needThisHandling else "pub"
 | 
						|
        # We don't care, for callback codegen, whether our original member was
 | 
						|
        # a method or attribute or whatnot.  Just always pass FakeMember()
 | 
						|
        # here.
 | 
						|
        CGNativeMember.__init__(self, descriptorProvider, FakeMember(),
 | 
						|
                                name, (self.retvalType, args),
 | 
						|
                                extendedAttrs={},
 | 
						|
                                passJSBitsAsNeeded=False,
 | 
						|
                                visibility=visibility)
 | 
						|
        # We have to do all the generation of our body now, because
 | 
						|
        # the caller relies on us throwing if we can't manage it.
 | 
						|
        self.exceptionCode = "return Err(JSFailed);"
 | 
						|
        self.body = self.getImpl()
 | 
						|
 | 
						|
    def getImpl(self):
 | 
						|
        replacements = {
 | 
						|
            "declRval": self.getRvalDecl(),
 | 
						|
            "returnResult": self.getResultConversion(),
 | 
						|
            "convertArgs": self.getArgConversions(),
 | 
						|
            "doCall": self.getCall(),
 | 
						|
            "setupCall": self.getCallSetup(),
 | 
						|
        }
 | 
						|
        if self.argCount > 0:
 | 
						|
            replacements["argCount"] = self.argCountStr
 | 
						|
            replacements["argvDecl"] = string.Template(
 | 
						|
                "let mut argv = vec![UndefinedValue(); ${argCount}];\n"
 | 
						|
            ).substitute(replacements)
 | 
						|
        else:
 | 
						|
            # Avoid weird 0-sized arrays
 | 
						|
            replacements["argvDecl"] = ""
 | 
						|
 | 
						|
        # Newlines and semicolons are in the values
 | 
						|
        pre = string.Template(
 | 
						|
            "${setupCall}"
 | 
						|
            "${declRval}"
 | 
						|
            "${argvDecl}").substitute(replacements)
 | 
						|
        body = string.Template(
 | 
						|
            "${convertArgs}"
 | 
						|
            "${doCall}"
 | 
						|
            "${returnResult}").substitute(replacements)
 | 
						|
        return CGList([
 | 
						|
            CGGeneric(pre),
 | 
						|
            CGGeneric(body),
 | 
						|
        ], "\n").define()
 | 
						|
 | 
						|
    def getResultConversion(self):
 | 
						|
        replacements = {
 | 
						|
            "val": "rval.handle()",
 | 
						|
        }
 | 
						|
 | 
						|
        info = getJSToNativeConversionInfo(
 | 
						|
            self.retvalType,
 | 
						|
            self.descriptorProvider,
 | 
						|
            exceptionCode=self.exceptionCode,
 | 
						|
            isCallbackReturnValue="Callback",
 | 
						|
            # XXXbz we should try to do better here
 | 
						|
            sourceDescription="return value")
 | 
						|
        template = info.template
 | 
						|
        declType = info.declType
 | 
						|
        needsRooting = info.needsRooting
 | 
						|
 | 
						|
        convertType = instantiateJSToNativeConversionTemplate(
 | 
						|
            template, replacements, declType, "rvalDecl", needsRooting)
 | 
						|
 | 
						|
        if self.retvalType is None or self.retvalType.isVoid():
 | 
						|
            retval = "()"
 | 
						|
        elif self.retvalType.isAny():
 | 
						|
            retval = "rvalDecl.get()"
 | 
						|
        else:
 | 
						|
            retval = "rvalDecl"
 | 
						|
 | 
						|
        return "%s\nOk(%s)\n" % (convertType.define(), retval)
 | 
						|
 | 
						|
    def getArgConversions(self):
 | 
						|
        # Just reget the arglist from self.originalSig, because our superclasses
 | 
						|
        # just have way to many members they like to clobber, so I can't find a
 | 
						|
        # safe member name to store it in.
 | 
						|
        argConversions = [self.getArgConversion(i, arg) for (i, arg)
 | 
						|
                          in enumerate(self.originalSig[1])]
 | 
						|
        # Do them back to front, so our argc modifications will work
 | 
						|
        # correctly, because we examine trailing arguments first.
 | 
						|
        argConversions.reverse()
 | 
						|
        argConversions = [CGGeneric(c) for c in argConversions]
 | 
						|
        if self.argCount > 0:
 | 
						|
            argConversions.insert(0, self.getArgcDecl())
 | 
						|
        # And slap them together.
 | 
						|
        return CGList(argConversions, "\n\n").define() + "\n\n"
 | 
						|
 | 
						|
    def getArgConversion(self, i, arg):
 | 
						|
        argval = arg.identifier.name
 | 
						|
 | 
						|
        if arg.variadic:
 | 
						|
            argval = argval + "[idx].get()"
 | 
						|
            jsvalIndex = "%d + idx" % i
 | 
						|
        else:
 | 
						|
            jsvalIndex = "%d" % i
 | 
						|
            if arg.optional and not arg.defaultValue:
 | 
						|
                argval += ".clone().unwrap()"
 | 
						|
 | 
						|
        conversion = wrapForType(
 | 
						|
            "argv_root.handle_mut()", result=argval,
 | 
						|
            successCode="argv[%s] = argv_root.ptr;" % jsvalIndex,
 | 
						|
            pre="let mut argv_root = RootedValue::new(cx, UndefinedValue());")
 | 
						|
        if arg.variadic:
 | 
						|
            conversion = string.Template(
 | 
						|
                "for idx in 0..${arg}.len() {\n" +
 | 
						|
                CGIndenter(CGGeneric(conversion)).define() + "\n"
 | 
						|
                "}"
 | 
						|
            ).substitute({"arg": arg.identifier.name})
 | 
						|
        elif arg.optional and not arg.defaultValue:
 | 
						|
            conversion = (
 | 
						|
                CGIfWrapper(CGGeneric(conversion),
 | 
						|
                            "%s.is_some()" % arg.identifier.name).define() +
 | 
						|
                " else if argc == %d {\n"
 | 
						|
                "    // This is our current trailing argument; reduce argc\n"
 | 
						|
                "    argc -= 1;\n"
 | 
						|
                "} else {\n"
 | 
						|
                "    argv[%d] = UndefinedValue();\n"
 | 
						|
                "}" % (i + 1, i))
 | 
						|
        return conversion
 | 
						|
 | 
						|
    def getArgs(self, returnType, argList):
 | 
						|
        args = CGNativeMember.getArgs(self, returnType, argList)
 | 
						|
        if not self.needThisHandling:
 | 
						|
            # Since we don't need this handling, we're the actual method that
 | 
						|
            # will be called, so we need an aRethrowExceptions argument.
 | 
						|
            args.append(Argument("ExceptionHandling", "aExceptionHandling",
 | 
						|
                                 "ReportExceptions"))
 | 
						|
            return args
 | 
						|
        # We want to allow the caller to pass in a "this" object, as
 | 
						|
        # well as a JSContext.
 | 
						|
        return [Argument("*mut JSContext", "cx"),
 | 
						|
                Argument("HandleObject", "aThisObj")] + args
 | 
						|
 | 
						|
    def getCallSetup(self):
 | 
						|
        if self.needThisHandling:
 | 
						|
            # It's been done for us already
 | 
						|
            return ""
 | 
						|
        return (
 | 
						|
            "CallSetup s(CallbackPreserveColor(), aRv, aExceptionHandling);\n"
 | 
						|
            "JSContext* cx = s.get_context();\n"
 | 
						|
            "if (!cx) {\n"
 | 
						|
            "    return Err(JSFailed);\n"
 | 
						|
            "}\n")
 | 
						|
 | 
						|
    def getArgcDecl(self):
 | 
						|
        if self.argCount <= 1:
 | 
						|
            return CGGeneric("let argc = %s;" % self.argCountStr)
 | 
						|
        return CGGeneric("let mut argc = %s;" % self.argCountStr)
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def ensureASCIIName(idlObject):
 | 
						|
        type = "attribute" if idlObject.isAttr() else "operation"
 | 
						|
        if re.match("[^\x20-\x7E]", idlObject.identifier.name):
 | 
						|
            raise SyntaxError('Callback %s name "%s" contains non-ASCII '
 | 
						|
                              "characters.  We can't handle that.  %s" %
 | 
						|
                              (type, idlObject.identifier.name,
 | 
						|
                               idlObject.location))
 | 
						|
        if re.match('"', idlObject.identifier.name):
 | 
						|
            raise SyntaxError("Callback %s name '%s' contains "
 | 
						|
                              "double-quote character.  We can't handle "
 | 
						|
                              "that.  %s" %
 | 
						|
                              (type, idlObject.identifier.name,
 | 
						|
                               idlObject.location))
 | 
						|
 | 
						|
 | 
						|
class CallbackMethod(CallbackMember):
 | 
						|
    def __init__(self, sig, name, descriptorProvider, needThisHandling):
 | 
						|
        CallbackMember.__init__(self, sig, name, descriptorProvider,
 | 
						|
                                needThisHandling)
 | 
						|
 | 
						|
    def getRvalDecl(self):
 | 
						|
        return "let mut rval = RootedValue::new(cx, UndefinedValue());\n"
 | 
						|
 | 
						|
    def getCall(self):
 | 
						|
        replacements = {
 | 
						|
            "thisObj": self.getThisObj(),
 | 
						|
            "getCallable": self.getCallableDecl()
 | 
						|
        }
 | 
						|
        if self.argCount > 0:
 | 
						|
            replacements["argv"] = "argv.as_ptr()"
 | 
						|
            replacements["argc"] = "argc"
 | 
						|
        else:
 | 
						|
            replacements["argv"] = "ptr::null_mut()"
 | 
						|
            replacements["argc"] = "0"
 | 
						|
        return string.Template(
 | 
						|
            "${getCallable}"
 | 
						|
            "let ok = unsafe {\n"
 | 
						|
            "    let rootedThis = RootedObject::new(cx, ${thisObj});\n"
 | 
						|
            "    JS_CallFunctionValue(\n"
 | 
						|
            "        cx, rootedThis.handle(), callable.handle(),\n"
 | 
						|
            "        &HandleValueArray {\n"
 | 
						|
            "            length_: ${argc} as ::libc::size_t,\n"
 | 
						|
            "            elements_: ${argv}\n"
 | 
						|
            "        }, rval.handle_mut())\n"
 | 
						|
            "};\n"
 | 
						|
            "if !ok {\n"
 | 
						|
            "    return Err(JSFailed);\n"
 | 
						|
            "}\n").substitute(replacements)
 | 
						|
 | 
						|
 | 
						|
class CallCallback(CallbackMethod):
 | 
						|
    def __init__(self, callback, descriptorProvider):
 | 
						|
        CallbackMethod.__init__(self, callback.signatures()[0], "Call",
 | 
						|
                                descriptorProvider, needThisHandling=True)
 | 
						|
 | 
						|
    def getThisObj(self):
 | 
						|
        return "aThisObj.get()"
 | 
						|
 | 
						|
    def getCallableDecl(self):
 | 
						|
        return "let callable = RootedValue::new(cx, ObjectValue(unsafe {&*self.parent.callback()}));\n"
 | 
						|
 | 
						|
 | 
						|
class CallbackOperationBase(CallbackMethod):
 | 
						|
    """
 | 
						|
    Common class for implementing various callback operations.
 | 
						|
    """
 | 
						|
    def __init__(self, signature, jsName, nativeName, descriptor, singleOperation):
 | 
						|
        self.singleOperation = singleOperation
 | 
						|
        self.methodName = jsName
 | 
						|
        CallbackMethod.__init__(self, signature, nativeName, descriptor, singleOperation)
 | 
						|
 | 
						|
    def getThisObj(self):
 | 
						|
        if not self.singleOperation:
 | 
						|
            return "self.parent.callback()"
 | 
						|
        # This relies on getCallableDecl declaring a boolean
 | 
						|
        # isCallable in the case when we're a single-operation
 | 
						|
        # interface.
 | 
						|
        return "if isCallable { aThisObj.get() } else { self.parent.callback() }"
 | 
						|
 | 
						|
    def getCallableDecl(self):
 | 
						|
        replacements = {
 | 
						|
            "methodName": self.methodName
 | 
						|
        }
 | 
						|
        getCallableFromProp = string.Template(
 | 
						|
            'RootedValue::new(cx, try!(self.parent.get_callable_property(cx, "${methodName}")))'
 | 
						|
        ).substitute(replacements)
 | 
						|
        if not self.singleOperation:
 | 
						|
            return 'JS::Rooted<JS::Value> callable(cx);\n' + getCallableFromProp
 | 
						|
        return (
 | 
						|
            'let isCallable = unsafe { IsCallable(self.parent.callback()) };\n'
 | 
						|
            'let callable =\n' +
 | 
						|
            CGIndenter(
 | 
						|
                CGIfElseWrapper('isCallable',
 | 
						|
                                CGGeneric('unsafe { RootedValue::new(cx, ObjectValue(&*self.parent.callback())) }'),
 | 
						|
                                CGGeneric(getCallableFromProp))).define() + ';\n')
 | 
						|
 | 
						|
 | 
						|
class CallbackOperation(CallbackOperationBase):
 | 
						|
    """
 | 
						|
    Codegen actual WebIDL operations on callback interfaces.
 | 
						|
    """
 | 
						|
    def __init__(self, method, signature, descriptor):
 | 
						|
        self.ensureASCIIName(method)
 | 
						|
        jsName = method.identifier.name
 | 
						|
        CallbackOperationBase.__init__(self, signature,
 | 
						|
                                       jsName,
 | 
						|
                                       MakeNativeName(descriptor.binaryNameFor(jsName)),
 | 
						|
                                       descriptor, descriptor.interface.isSingleOperationInterface())
 | 
						|
 | 
						|
 | 
						|
class CallbackGetter(CallbackMember):
 | 
						|
    def __init__(self, attr, descriptor):
 | 
						|
        self.ensureASCIIName(attr)
 | 
						|
        self.attrName = attr.identifier.name
 | 
						|
        CallbackMember.__init__(self,
 | 
						|
                                (attr.type, []),
 | 
						|
                                callbackGetterName(attr),
 | 
						|
                                descriptor,
 | 
						|
                                needThisHandling=False)
 | 
						|
 | 
						|
    def getRvalDecl(self):
 | 
						|
        return "JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());\n"
 | 
						|
 | 
						|
    def getCall(self):
 | 
						|
        replacements = {
 | 
						|
            "attrName": self.attrName
 | 
						|
        }
 | 
						|
        return string.Template(
 | 
						|
            'if (!JS_GetProperty(cx, mCallback, "${attrName}", &rval)) {\n'
 | 
						|
            '    return Err(JSFailed);\n'
 | 
						|
            '}\n').substitute(replacements)
 | 
						|
 | 
						|
 | 
						|
class CallbackSetter(CallbackMember):
 | 
						|
    def __init__(self, attr, descriptor):
 | 
						|
        self.ensureASCIIName(attr)
 | 
						|
        self.attrName = attr.identifier.name
 | 
						|
        CallbackMember.__init__(self,
 | 
						|
                                (BuiltinTypes[IDLBuiltinType.Types.void],
 | 
						|
                                 [FakeArgument(attr.type, attr)]),
 | 
						|
                                callbackSetterName(attr),
 | 
						|
                                descriptor,
 | 
						|
                                needThisHandling=False)
 | 
						|
 | 
						|
    def getRvalDecl(self):
 | 
						|
        # We don't need an rval
 | 
						|
        return ""
 | 
						|
 | 
						|
    def getCall(self):
 | 
						|
        replacements = {
 | 
						|
            "attrName": self.attrName,
 | 
						|
            "argv": "argv.handleAt(0)",
 | 
						|
        }
 | 
						|
        return string.Template(
 | 
						|
            'MOZ_ASSERT(argv.length() == 1);\n'
 | 
						|
            'if (!JS_SetProperty(cx, mCallback, "${attrName}", ${argv})) {\n'
 | 
						|
            '    return Err(JSFailed);\n'
 | 
						|
            '}\n').substitute(replacements)
 | 
						|
 | 
						|
    def getArgcDecl(self):
 | 
						|
        return None
 | 
						|
 | 
						|
 | 
						|
class GlobalGenRoots():
 | 
						|
    """
 | 
						|
    Roots for global codegen.
 | 
						|
 | 
						|
    To generate code, call the method associated with the target, and then
 | 
						|
    call the appropriate define/declare method.
 | 
						|
    """
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def PrototypeList(config):
 | 
						|
        # Prototype ID enum.
 | 
						|
        protos = [d.name for d in config.getDescriptors(isCallback=False)]
 | 
						|
        proxies = [d.name for d in config.getDescriptors(proxy=True)]
 | 
						|
 | 
						|
        return CGList([
 | 
						|
            CGGeneric(AUTOGENERATED_WARNING_COMMENT),
 | 
						|
            CGGeneric("pub const MAX_PROTO_CHAIN_LENGTH: usize = %d;\n\n" % config.maxProtoChainLength),
 | 
						|
            CGNonNamespacedEnum('ID', protos, [0], deriving="PartialEq, Copy, Clone", repr="u16"),
 | 
						|
            CGWrapper(CGIndenter(CGList([CGGeneric('"' + name + '"') for name in protos],
 | 
						|
                                        ",\n"),
 | 
						|
                                 indentLevel=4),
 | 
						|
                      pre="static INTERFACES: [&'static str; %d] = [\n" % len(protos),
 | 
						|
                      post="\n];\n\n"),
 | 
						|
            CGGeneric("pub fn proto_id_to_name(proto_id: u16) -> &'static str {\n"
 | 
						|
                      "    debug_assert!(proto_id < ID::Count as u16);\n"
 | 
						|
                      "    INTERFACES[proto_id as usize]\n"
 | 
						|
                      "}\n\n"),
 | 
						|
            CGNonNamespacedEnum('Proxies', proxies, [0], deriving="PartialEq, Copy, Clone"),
 | 
						|
        ])
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def RegisterBindings(config):
 | 
						|
        # TODO - Generate the methods we want
 | 
						|
        code = CGList([
 | 
						|
            CGRegisterProtos(config),
 | 
						|
            CGRegisterProxyHandlers(config),
 | 
						|
        ], "\n")
 | 
						|
 | 
						|
        return CGImports(code, [], [], [
 | 
						|
            'dom::bindings::codegen',
 | 
						|
            'dom::bindings::codegen::PrototypeList::Proxies',
 | 
						|
            'js::jsapi::JSContext',
 | 
						|
            'js::jsapi::HandleObject',
 | 
						|
            'libc',
 | 
						|
        ], ignored_warnings=[])
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def InterfaceTypes(config):
 | 
						|
        descriptors = [d.name for d in config.getDescriptors(register=True, isCallback=False)]
 | 
						|
        curr = CGList([CGGeneric("pub use dom::%s::%s;\n" % (name.lower(), name)) for name in descriptors])
 | 
						|
        curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
 | 
						|
        return curr
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def Bindings(config):
 | 
						|
 | 
						|
        descriptors = (set(d.name + "Binding" for d in config.getDescriptors(register=True)) |
 | 
						|
                       set(d.module() for d in config.callbacks) |
 | 
						|
                       set(d.module() for d in config.getDictionaries()))
 | 
						|
        curr = CGList([CGGeneric("pub mod %s;\n" % name) for name in sorted(descriptors)])
 | 
						|
        curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
 | 
						|
        return curr
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def InheritTypes(config):
 | 
						|
 | 
						|
        descriptors = config.getDescriptors(register=True, isCallback=False)
 | 
						|
        imports = [CGGeneric("use dom::types::*;\n"),
 | 
						|
                   CGGeneric("use dom::bindings::conversions::{Castable, DerivedFrom, get_dom_class};\n"),
 | 
						|
                   CGGeneric("use dom::bindings::js::{JS, LayoutJS, Root};\n"),
 | 
						|
                   CGGeneric("use dom::bindings::trace::JSTraceable;\n"),
 | 
						|
                   CGGeneric("use dom::bindings::utils::Reflectable;\n"),
 | 
						|
                   CGGeneric("use js::jsapi::JSTracer;\n\n"),
 | 
						|
                   CGGeneric("use std::mem;\n\n")]
 | 
						|
        allprotos = []
 | 
						|
        topTypes = []
 | 
						|
        hierarchy = defaultdict(list)
 | 
						|
        for descriptor in descriptors:
 | 
						|
            name = descriptor.name
 | 
						|
            chain = descriptor.prototypeChain
 | 
						|
            upcast = descriptor.hasDescendants()
 | 
						|
            downcast = len(chain) != 1
 | 
						|
 | 
						|
            if upcast and not downcast:
 | 
						|
                topTypes.append(name)
 | 
						|
 | 
						|
            if not upcast:
 | 
						|
                # No other interface will implement DeriveFrom<Foo> for this Foo, so avoid
 | 
						|
                # implementing it for itself.
 | 
						|
                chain = chain[:-1]
 | 
						|
 | 
						|
            # Implement `DerivedFrom<Bar>` for `Foo`, for all `Bar` that `Foo` inherits from.
 | 
						|
            if chain:
 | 
						|
                allprotos.append(CGGeneric("impl Castable for %s {}\n" % name))
 | 
						|
            for baseName in chain:
 | 
						|
                allprotos.append(CGGeneric("impl DerivedFrom<%s> for %s {}\n" % (baseName, name)))
 | 
						|
            if chain:
 | 
						|
                allprotos.append(CGGeneric("\n"))
 | 
						|
 | 
						|
            if downcast:
 | 
						|
                hierarchy[descriptor.getParentName()].append(name)
 | 
						|
 | 
						|
        typeIdCode = []
 | 
						|
        topTypeVariants = [
 | 
						|
            ("ID used by abstract interfaces.", "Abstract"),
 | 
						|
            ("ID used by interfaces that are not castable.", "Alone"),
 | 
						|
        ]
 | 
						|
        topTypeVariants += [
 | 
						|
            ("ID used by interfaces that derive from %s." % name, "%s(%sTypeId)" % (name, name))
 | 
						|
            for name in topTypes
 | 
						|
        ]
 | 
						|
        topTypeVariantsAsStrings = [CGGeneric("/// %s\n%s," % variant) for variant in topTypeVariants]
 | 
						|
        typeIdCode.append(CGWrapper(CGIndenter(CGList(topTypeVariantsAsStrings, "\n"), 4),
 | 
						|
                                    pre="#[derive(Clone, Copy, Debug)]\npub enum TopTypeId {\n",
 | 
						|
                                    post="\n}\n\n"))
 | 
						|
 | 
						|
        def type_id_variant(name):
 | 
						|
            # If `name` is present in the hierarchy keys', that means some other interfaces
 | 
						|
            # derive from it and this enum variant should have an argument with its own
 | 
						|
            # TypeId enum.
 | 
						|
            return "%s(%sTypeId)" % (name, name) if name in hierarchy else name
 | 
						|
 | 
						|
        for base, derived in hierarchy.iteritems():
 | 
						|
            variants = []
 | 
						|
            if not config.getInterface(base).getExtendedAttribute("Abstract"):
 | 
						|
                variants.append(CGGeneric(base))
 | 
						|
            variants += [CGGeneric(type_id_variant(name)) for name in derived]
 | 
						|
            derives = "Clone, Copy, Debug"
 | 
						|
            if base != 'EventTarget' and base != 'HTMLElement':
 | 
						|
                derives += ", PartialEq"
 | 
						|
            typeIdCode.append(CGWrapper(CGIndenter(CGList(variants, ",\n"), 4),
 | 
						|
                                        pre="#[derive(%s)]\npub enum %sTypeId {\n" % (derives, base),
 | 
						|
                                        post="\n}\n\n"))
 | 
						|
            if base in topTypes:
 | 
						|
                typeIdCode.append(CGGeneric("""\
 | 
						|
impl %(base)s {
 | 
						|
    pub fn type_id(&self) -> &'static %(base)sTypeId {
 | 
						|
        let domclass = unsafe {
 | 
						|
            get_dom_class(self.reflector().get_jsobject().get()).unwrap()
 | 
						|
        };
 | 
						|
        match domclass.type_id {
 | 
						|
            TopTypeId::%(base)s(ref type_id) => type_id,
 | 
						|
            _ => unreachable!(),
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
""" % {'base': base}))
 | 
						|
 | 
						|
        curr = CGList(imports + typeIdCode + allprotos)
 | 
						|
        curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
 | 
						|
        return curr
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def UnionTypes(config):
 | 
						|
 | 
						|
        curr = UnionTypes(config.getDescriptors(),
 | 
						|
                          config.getDictionaries(),
 | 
						|
                          config.getCallbacks(),
 | 
						|
                          config)
 | 
						|
 | 
						|
        # Add the auto-generated comment.
 | 
						|
        curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
 | 
						|
 | 
						|
        # Done.
 | 
						|
        return curr
 |